2017-01-13 01:09:52 +01:00
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
from contextlib import contextmanager
|
2019-02-02 23:53:29 +01:00
|
|
|
from typing import Iterator, Optional
|
2017-01-13 01:09:52 +01:00
|
|
|
|
2017-04-03 11:48:57 +02:00
|
|
|
# Verify the Zulip venv is available.
|
|
|
|
from tools.lib import sanity_check
|
2020-06-11 00:54:34 +02:00
|
|
|
|
2017-04-03 11:48:57 +02:00
|
|
|
sanity_check.check_venv(__file__)
|
|
|
|
|
|
|
|
import django
|
|
|
|
import requests
|
2017-01-13 01:09:52 +01:00
|
|
|
|
2020-06-21 20:05:43 +02:00
|
|
|
MAX_SERVER_WAIT = 180
|
2020-03-28 21:39:20 +01:00
|
|
|
|
2017-01-13 01:09:52 +01:00
|
|
|
TOOLS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
if TOOLS_DIR not in sys.path:
|
|
|
|
sys.path.insert(0, os.path.dirname(TOOLS_DIR))
|
|
|
|
|
2019-07-16 08:10:29 +02:00
|
|
|
from scripts.lib.zulip_tools import get_or_create_dev_uuid_var_path
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.lib.test_fixtures import update_test_databases_if_required
|
|
|
|
|
2017-01-13 01:09:52 +01:00
|
|
|
|
python: Convert function type annotations to Python 3 style.
Generated by com2ann (slightly patched to avoid also converting
assignment type annotations, which require Python 3.6), followed by
some manual whitespace adjustment, and six fixes for runtime issues:
- def __init__(self, token: Token, parent: Optional[Node]) -> None:
+ def __init__(self, token: Token, parent: "Optional[Node]") -> None:
-def main(options: argparse.Namespace) -> NoReturn:
+def main(options: argparse.Namespace) -> "NoReturn":
-def fetch_request(url: str, callback: Any, **kwargs: Any) -> Generator[Callable[..., Any], Any, None]:
+def fetch_request(url: str, callback: Any, **kwargs: Any) -> "Generator[Callable[..., Any], Any, None]":
-def assert_server_running(server: subprocess.Popen[bytes], log_file: Optional[str]) -> None:
+def assert_server_running(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> None:
-def server_is_up(server: subprocess.Popen[bytes], log_file: Optional[str]) -> bool:
+def server_is_up(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> bool:
- method_kwarg_pairs: List[FuncKwargPair],
+ method_kwarg_pairs: "List[FuncKwargPair]",
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-19 03:48:37 +02:00
|
|
|
def set_up_django(external_host: str) -> None:
|
2017-01-13 01:09:52 +01:00
|
|
|
os.environ['EXTERNAL_HOST'] = external_host
|
|
|
|
os.environ["TORNADO_SERVER"] = "http://127.0.0.1:9983"
|
2019-07-16 08:10:29 +02:00
|
|
|
os.environ["LOCAL_UPLOADS_DIR"] = get_or_create_dev_uuid_var_path(
|
|
|
|
'test-backend/test_uploads')
|
2017-01-13 01:09:52 +01:00
|
|
|
os.environ['DJANGO_SETTINGS_MODULE'] = 'zproject.test_settings'
|
|
|
|
django.setup()
|
|
|
|
os.environ['PYTHONUNBUFFERED'] = 'y'
|
|
|
|
|
python: Convert function type annotations to Python 3 style.
Generated by com2ann (slightly patched to avoid also converting
assignment type annotations, which require Python 3.6), followed by
some manual whitespace adjustment, and six fixes for runtime issues:
- def __init__(self, token: Token, parent: Optional[Node]) -> None:
+ def __init__(self, token: Token, parent: "Optional[Node]") -> None:
-def main(options: argparse.Namespace) -> NoReturn:
+def main(options: argparse.Namespace) -> "NoReturn":
-def fetch_request(url: str, callback: Any, **kwargs: Any) -> Generator[Callable[..., Any], Any, None]:
+def fetch_request(url: str, callback: Any, **kwargs: Any) -> "Generator[Callable[..., Any], Any, None]":
-def assert_server_running(server: subprocess.Popen[bytes], log_file: Optional[str]) -> None:
+def assert_server_running(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> None:
-def server_is_up(server: subprocess.Popen[bytes], log_file: Optional[str]) -> bool:
+def server_is_up(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> bool:
- method_kwarg_pairs: List[FuncKwargPair],
+ method_kwarg_pairs: "List[FuncKwargPair]",
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-19 03:48:37 +02:00
|
|
|
def assert_server_running(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> None:
|
2017-01-13 01:09:52 +01:00
|
|
|
"""Get the exit code of the server, or None if it is still running."""
|
|
|
|
if server.poll() is not None:
|
2017-01-25 18:31:51 +01:00
|
|
|
message = 'Server died unexpectedly!'
|
|
|
|
if log_file:
|
2020-06-10 06:41:04 +02:00
|
|
|
message += f'\nSee {log_file}\n'
|
2017-01-25 18:31:51 +01:00
|
|
|
raise RuntimeError(message)
|
|
|
|
|
python: Convert function type annotations to Python 3 style.
Generated by com2ann (slightly patched to avoid also converting
assignment type annotations, which require Python 3.6), followed by
some manual whitespace adjustment, and six fixes for runtime issues:
- def __init__(self, token: Token, parent: Optional[Node]) -> None:
+ def __init__(self, token: Token, parent: "Optional[Node]") -> None:
-def main(options: argparse.Namespace) -> NoReturn:
+def main(options: argparse.Namespace) -> "NoReturn":
-def fetch_request(url: str, callback: Any, **kwargs: Any) -> Generator[Callable[..., Any], Any, None]:
+def fetch_request(url: str, callback: Any, **kwargs: Any) -> "Generator[Callable[..., Any], Any, None]":
-def assert_server_running(server: subprocess.Popen[bytes], log_file: Optional[str]) -> None:
+def assert_server_running(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> None:
-def server_is_up(server: subprocess.Popen[bytes], log_file: Optional[str]) -> bool:
+def server_is_up(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> bool:
- method_kwarg_pairs: List[FuncKwargPair],
+ method_kwarg_pairs: "List[FuncKwargPair]",
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-19 03:48:37 +02:00
|
|
|
def server_is_up(server: "subprocess.Popen[bytes]", log_file: Optional[str]) -> bool:
|
2017-01-25 18:31:51 +01:00
|
|
|
assert_server_running(server, log_file)
|
2017-01-13 01:09:52 +01:00
|
|
|
try:
|
|
|
|
# We could get a 501 error if the reverse proxy is up but the Django app isn't.
|
2020-03-28 21:16:52 +01:00
|
|
|
# Note that zulipdev.com is mapped via DNS to 127.0.0.1.
|
|
|
|
return requests.get('http://zulipdev.com:9981/accounts/home').status_code == 200
|
2017-03-05 10:25:27 +01:00
|
|
|
except Exception:
|
2017-01-13 01:09:52 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
@contextmanager
|
2017-12-30 08:52:28 +01:00
|
|
|
def test_server_running(force: bool=False, external_host: str='testserver',
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
log_file: Optional[str]=None, dots: bool=False, use_db: bool=True,
|
2017-12-30 08:52:28 +01:00
|
|
|
) -> Iterator[None]:
|
2017-08-07 02:01:59 +02:00
|
|
|
log = sys.stdout
|
2017-01-25 18:31:51 +01:00
|
|
|
if log_file:
|
|
|
|
if os.path.exists(log_file) and os.path.getsize(log_file) < 100000:
|
|
|
|
log = open(log_file, 'a')
|
|
|
|
log.write('\n\n')
|
|
|
|
else:
|
|
|
|
log = open(log_file, 'w')
|
|
|
|
|
2017-01-13 01:09:52 +01:00
|
|
|
set_up_django(external_host)
|
|
|
|
|
2017-01-25 18:44:17 +01:00
|
|
|
if use_db:
|
2019-05-29 00:15:11 +02:00
|
|
|
update_test_databases_if_required(rebuild_test_database=True)
|
2017-01-13 01:09:52 +01:00
|
|
|
|
|
|
|
# Run this not through the shell, so that we have the actual PID.
|
tests: Use streamlined server for api/casper tests.
We now use the `--streamlined` options for `run-dev.py`
when we use `test_server_running` for `test-api` and
`test-js-with-casper` (and its experimental
replacement, `test-js-with-puppeteer`).
This means we don't slow anything down with
processes like thumbor, process_fts_updates, etc.,
which aren't meaningfully exercised by these tests.
We may eventually want some tests to meaningfully
exercise those processes, and when that day comes,
we will need to add an extra argument to
`test_server_running`, probably, but until then,
we just always set `--streamlined` in that codepath.
There is actually a tool called `./tools/test-run-dev`
that we run in CI, and it will use the full mode.
It just doesn't verify much stuff--it mostly polls
the server without testing specific features.
This seems to save about 1s of the startup time on a system I use
(~10.6s -> ~9.7s).
2020-05-01 00:11:25 +02:00
|
|
|
run_dev_server_command = ['tools/run-dev.py', '--test', '--streamlined']
|
2017-01-13 01:09:52 +01:00
|
|
|
if force:
|
|
|
|
run_dev_server_command.append('--force')
|
|
|
|
server = subprocess.Popen(run_dev_server_command,
|
|
|
|
stdout=log, stderr=log)
|
|
|
|
|
|
|
|
try:
|
|
|
|
# Wait for the server to start up.
|
2018-01-11 16:53:46 +01:00
|
|
|
sys.stdout.write('\nWaiting for test server (may take a while)')
|
|
|
|
if not dots:
|
|
|
|
sys.stdout.write('\n\n')
|
2020-03-28 21:39:20 +01:00
|
|
|
t = time.time()
|
2017-01-25 18:31:51 +01:00
|
|
|
while not server_is_up(server, log_file):
|
2017-01-13 01:09:52 +01:00
|
|
|
if dots:
|
|
|
|
sys.stdout.write('.')
|
|
|
|
sys.stdout.flush()
|
2020-03-28 21:25:29 +01:00
|
|
|
time.sleep(0.4)
|
2020-03-28 21:39:20 +01:00
|
|
|
if time.time() - t > MAX_SERVER_WAIT:
|
|
|
|
raise Exception('Timeout waiting for server')
|
2018-01-11 16:53:46 +01:00
|
|
|
sys.stdout.write('\n\n--- SERVER IS UP! ---\n\n')
|
2017-01-13 01:09:52 +01:00
|
|
|
|
|
|
|
# DO OUR ACTUAL TESTING HERE!!!
|
|
|
|
yield
|
|
|
|
|
|
|
|
finally:
|
2017-01-25 18:31:51 +01:00
|
|
|
assert_server_running(server, log_file)
|
2017-01-13 01:09:52 +01:00
|
|
|
server.terminate()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
# The code below is for testing this module works
|
|
|
|
with test_server_running():
|
|
|
|
print('\n\n SERVER IS UP!\n\n')
|