From 0e1ea42c8700806c66b3b55e1552baa0511b29b3 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Tue, 14 Jun 2022 10:50:16 +0200 Subject: [PATCH] ergo: Create MySQL subprocess instead of using external DB This starts each test with a clean database, so we can remove chan/nick randomization from stateful tests (chathistory and roleplay). It will also allow testing Ergo with a MySQL backend for the KV store instead of buntdb. Additionally, this makes it much easier to run these tests, than having to manually configure such a database. --- irctest/controllers/ergo.py | 77 +++++++++++++++++++++++++---- irctest/server_tests/chathistory.py | 2 - 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/irctest/controllers/ergo.py b/irctest/controllers/ergo.py index 3878e7b9..54792669 100644 --- a/irctest/controllers/ergo.py +++ b/irctest/controllers/ergo.py @@ -3,7 +3,7 @@ import os import shutil import subprocess -from typing import Any, Dict, Optional, Set, Type, Union +from typing import Any, Dict, List, Optional, Set, Type, Union from irctest.basecontrollers import ( BaseServerController, @@ -139,6 +139,7 @@ class ErgoController(BaseServerController, DirectoryBasedController): supported_sasl_mechanisms = {"PLAIN", "SCRAM-SHA-256"} supports_sts = True extban_mute_char = "m" + mysql_proc: Optional[subprocess.Popen] = None def create_config(self) -> None: super().create_config() @@ -215,6 +216,16 @@ def run( [*faketime_cmd, "ergo", "run", "--conf", self._config_path, "--quiet"] ) + def terminate(self) -> None: + if self.mysql_proc is not None: + self.mysql_proc.terminate() + super().terminate() + + def kill(self) -> None: + if self.mysql_proc is not None: + self.mysql_proc.kill() + super().kill() + def wait_for_services(self) -> None: # Nothing to wait for, they start at the same time as Ergo. pass @@ -266,20 +277,16 @@ def addLoggingToConfig(self, config: Optional[Dict] = None) -> Dict: config.update(LOGGING_CONFIG) return config - def addMysqlToConfig(self, config: Optional[Dict] = None) -> Dict: - mysql_password = os.getenv("MYSQL_PASSWORD") - if config is None: - config = self.baseConfig() - if not mysql_password: - return config + def addMysqlToConfig(self, config: Dict) -> Dict: + socket_path = self.startMysql() + self.createMysqlDatabase(socket_path, "ergo_history") config["datastore"]["mysql"] = { "enabled": True, - "host": "localhost", - "user": "ergo", - "password": mysql_password, + "socket-path": socket_path, "history-database": "ergo_history", "timeout": "3s", } + config["accounts"]["multiclient"] = { "enabled": True, "allowed-by-default": True, @@ -293,6 +300,56 @@ def addMysqlToConfig(self, config: Optional[Dict] = None) -> Dict: } return config + def startMysql(self) -> str: + """Starts a new MySQL server listening on a UNIX socket, returns the socket + path""" + assert self.directory + mysql_dir = os.path.join(self.directory, "mysql") + socket_path = os.path.join(mysql_dir, "mysql.socket") + os.mkdir(mysql_dir) + + print("Starting MySQL...") + self.mysql_proc = subprocess.Popen( + [ + "mysqld", + "--no-defaults", + "--tmpdir=" + mysql_dir, + "--datadir=" + mysql_dir, + "--socket=" + socket_path, + "--skip-networking", + "--skip-grant-tables", + ], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + + mysql_stdout = self.mysql_proc.stdout + assert mysql_stdout is not None # for mypy... + lines: List[bytes] = [] + while self.mysql_proc.returncode is None: + line = mysql_stdout.readline() + lines.append(lines) + if b"mysqld: ready for connections." in line: + break + assert self.mysql_proc.returncode is None, ( + "MySQL unexpected stopped: " + b"\n".join(lines).decode() + ) + print("MySQL started") + + return socket_path + + def createMysqlDatabase(self, socket_path: str, database_name: str) -> None: + subprocess.check_call( + [ + "mysql", + "--no-defaults", + "-S", + socket_path, + "-e", + f"CREATE DATABASE {database_name};", + ] + ) + def rehash(self, case: BaseServerTestCase, config: Dict) -> None: self._config = config self._write_config() diff --git a/irctest/server_tests/chathistory.py b/irctest/server_tests/chathistory.py index 28a201a4..8da89b8b 100644 --- a/irctest/server_tests/chathistory.py +++ b/irctest/server_tests/chathistory.py @@ -18,8 +18,6 @@ # Keep this in sync with validate_chathistory() SUBCOMMANDS = ["LATEST", "BEFORE", "AFTER", "BETWEEN", "AROUND"] -MYSQL_PASSWORD = "" - def validate_chathistory_batch(msgs): batch_tag = None