Skip to content

Commit

Permalink
ergo: Create MySQL subprocess instead of using external DB
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
progval committed Jun 14, 2022
1 parent 5371077 commit 0e1ea42
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 12 deletions.
77 changes: 67 additions & 10 deletions irctest/controllers/ergo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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()
Expand Down
2 changes: 0 additions & 2 deletions irctest/server_tests/chathistory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0e1ea42

Please sign in to comment.