blob: 3447815a52b58dacdfdbea5b4c49badc81fb64d0 [file] [log] [blame]
Philipp Schrader94305722022-03-13 12:59:21 -07001"""This library is here to run the various servers involved in the scouting app.
2
3The servers are:
4 - The fake TBA server
5 - The actual web server
6"""
7
8import argparse
9import json
10import os
11from pathlib import Path
12import shutil
13import signal
14import socket
15import subprocess
16import sys
17import time
18from typing import List
19
20def wait_for_server(port: int):
21 """Waits for the server at the specified port to respond to TCP connections."""
22 while True:
23 try:
24 connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
25 connection.connect(("localhost", port))
26 connection.close()
27 break
28 except ConnectionRefusedError:
29 connection.close()
30 time.sleep(0.01)
31
32def create_tba_config(tmpdir: Path) -> Path:
33 # Configure the scouting webserver to scrape data from our fake TBA
34 # server.
35 config = tmpdir / "scouting_config.json"
36 config.write_text(json.dumps({
37 "api_key": "dummy_key_that_is_not_actually_used_in_this_test",
38 "base_url": "http://localhost:7000",
39 }))
40 return config
41
42def set_up_tba_api_dir(tmpdir: Path, year: int, event_code: str):
43 tba_api_dir = tmpdir / "api" / "v3" / "event" / f"{year}{event_code}"
44 tba_api_dir.mkdir(parents=True, exist_ok=True)
45 (tba_api_dir / "matches").write_text(
46 Path(f"scouting/scraping/test_data/{year}_{event_code}.json").read_text()
47 )
48
49class Runner:
50 """Helps manage the services we need for testing the scouting app."""
51
52 def start(self, port: int):
53 """Starts the services needed for testing the scouting app."""
54 self.tmpdir = Path(os.environ["TEST_TMPDIR"]) / "servers"
55 self.tmpdir.mkdir(exist_ok=True)
56
57 db_path = self.tmpdir / "scouting.db"
58 tba_config = create_tba_config(self.tmpdir)
59
60 self.webserver = subprocess.Popen([
61 "scouting/scouting",
62 f"--port={port}",
63 f"--database={db_path}",
64 f"--tba_config={tba_config}",
65 ])
66
67 # Create a fake TBA server to serve the static match list.
68 set_up_tba_api_dir(self.tmpdir, year=2016, event_code="nytr")
69 set_up_tba_api_dir(self.tmpdir, year=2020, event_code="fake")
70 self.fake_tba_api = subprocess.Popen(
71 ["python3", "-m", "http.server", "7000"],
72 cwd=self.tmpdir,
73 )
74
75 # Wait for the TBA server and the scouting webserver to start up.
76 wait_for_server(7000)
77 wait_for_server(port)
78
79 def stop(self):
80 """Stops the services needed for testing the scouting app."""
81 servers = (self.webserver, self.fake_tba_api)
82 for server in servers:
83 server.terminate()
84 for server in servers:
85 server.wait()
86
87 try:
88 shutil.rmtree(self.tmpdir)
89 except FileNotFoundError:
90 pass
91
92
93def main(argv: List[str]):
94 parser = argparse.ArgumentParser()
95 parser.add_argument("--port", type=int, help="The port for the actual web server.")
96 args = parser.parse_args(argv[1:])
97
98 runner = Runner()
99 runner.start(args.port)
100
101 # Wait until we're asked to shut down via CTRL-C or SIGTERM.
102 signal.pause()
103
104 runner.stop()
105
106
107if __name__ == "__main__":
108 sys.exit(main(sys.argv))