1#!/usr/bin/env python3
  2
  3import os
  4import sys
  5import subprocess
  6import socket
  7import atexit
  8import signal
  9import time
 10import urllib
 11
 12import pytest
 13
 14RUNNER = "charteps"
 15# MODULE = 'charteps'
 16
 17FIRST_PORT = 39000
 18LAST_PORT = 39999
 19
 20LOCALHOST = "127.0.0.1"
 21
 22# Number of seconds to wait for the internal web server process to start up
 23MAX_SERVER_START_TIME = 15
 24
 25
 26def pytest_runtest_setup():
 27    """Hackish way to ensure the project and core can be imported.
 28
 29    Otherwise you have to manually set PYTHONPATH before running pytest."""
 30    # always add current project location to interpreter path
 31    proj_root = os.path.dirname(os.path.dirname(__file__))
 32    # print('pre adding {p} to sys path'.format(p=proj_root))
 33    sys.path.insert(0, proj_root)
 34
 35    # the user might have pointed PYTHONPATH to a core install so look for it
 36    # we cannot, for caching reasons, look for it using "import chart"
 37    found_core = False
 38    for dirname in sys.path:
 39        if os.path.exists(os.path.join(dirname, "chart", "__init__.py")):
 40            found_core = True
 41            break
 42
 43    if not found_core:
 44        core_root = os.path.join(proj_root, "chart")
 45        # print('adding {p} to sys path'.format(p=core_root))
 46        sys.path.insert(0, core_root)
 47
 48    # from chart.common.shell import spawn
 49
 50
 51# there is a neat way of naming and placing a function so pytest always calls it first
 52# but I can't find a proper way so we rely on the fact this module at least gets imported
 53pytest_runtest_setup()
 54
 55
 56def pytest_addoption(parser):
 57    group = parser.getgroup("server")
 58    group.addoption(
 59        "--local",
 60        action="store_true",
 61        default=True,
 62        help="Run local webserver (default)",
 63    )
 64    group.addoption("--url", help="Test against remote server")
 65    group.addoption("--env", help="Test against OPE/VAL/TST/EPP/EPPVAL system")
 66
 67
 68@pytest.fixture(scope="session")
 69def webserver(request):
 70    """Spawn a webserver, finding a free socket to run on. Return (how?) the socket number.
 71
 72    Automatic shutdown. Test fails on any server error code or empty ."""
 73    config_local = request.config.getoption("local")
 74    config_url = request.config.getoption("url")
 75    config_env = request.config.getoption("env")
 76    if config_url:
 77        print("webserver remote url", config_url)
 78        url = config_url
 79
 80    elif config_env:
 81        print("webserver env", config_env)
 82        url = {
 83            "OPE": "http://chart/eps/",
 84            "VAL": "http://chart/val/eps/",
 85            "TST": "http://chart/tst/eps/",
 86        }[config_env.upper()]
 87    else:
 88        print("webserver spawn")
 89        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 90        # sock.settimeout(1)
 91        port = None
 92        for p in range(FIRST_PORT, LAST_PORT):
 93            # res = sock.connect_ex((LOCALHOST, p))
 94            try:
 95                sock.bind((LOCALHOST, p))
 96                sock.listen(1)
 97                sock.close()
 98                port = p
 99                break
100
101            except socket.error as e:
102                pass
103            # print('sock port',p,'res',res)
104            # if res == 0:
105            # break
106
107        if not port:
108            raise ValueError("Cannot find free port to run local server")
109
110        url = "http://{host}:{port}/test/".format(host=LOCALHOST, port=p)
111        from chart.common.shell import spawn
112
113        cmd = "charteps serve -p {port} --prefix test/".format(port=p)
114        # print('spawning')
115        os.setpgrp()
116
117        def ending():
118            os.killpg(0, signal.SIGKILL)
119
120        atexit.register(ending)
121        spawn(cmd.split(" "), linger=True)
122        # print('donespawn')
123        tries = 0
124        while True:
125            # print('try',url)
126            try:
127                res = urllib.request.urlopen(url)
128                break
129            except IOError as e:
130                print(e)
131                pass
132
133            if tries > MAX_SERVER_START_TIME:
134                raise ValueError("Cannot start internal web server")
135
136            tries += 1
137            time.sleep(1)
138
139    return {"base_url": url}
140
141
142# webserver.port = None
143
144
145@pytest.fixture
146def temp_dir():
147    pass
148
149
150@pytest.fixture
151def test_database():
152    # read from settings system including environment variables and command line parameters
153    pass
154
155
156@pytest.fixture
157def operational_database():
158    # read from settings system including environment variables and command line parameters
159    pass
160
161
162@pytest.fixture
163def product():
164    # parmeterised with product filename
165    pass
166
167
168@pytest.fixture
169def ts():
170    # parameterised with 1+ table(s), sid and time range
171    pass
172
173
174@pytest.fixture
175def tool():
176    def run(cmd, expect_fail=False):
177        command = [RUNNER] + cmd.split(" \t")  # + ' ' + cmd  #  [str(i) for i in cmd]
178        # command = ['charteps', 'info']
179        child = subprocess.Popen(command)
180        # stdout=stdout,
181        # stderr=stderr)
182        res = child.communicate()
183        retcode = child.returncode
184        assert retcode == 0
185
186    return run