Run Atheme with Charybdis, to enable tests depending on SASL

This commit is contained in:
2021-06-27 16:48:21 +02:00
committed by Val Lorentz
parent 76db5758e9
commit 3d2399f62e
7 changed files with 84 additions and 26 deletions

View File

@ -28,6 +28,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get install atheme-services
python -m pip install --upgrade pip
pip install pytest -r requirements.txt
@ -49,5 +50,6 @@ jobs:
- name: Test with pytest
run: |
# testQuitErrors is very flaky
PATH=~/.local/bin:$PATH pytest --controller=irctest.controllers.charybdis -k 'not Ergo and not deprecated and not strict and not testDoubleKickMessages and not testQuitErrors'
# AccountTagTestCase.testInvite fails because https://github.com/solanum-ircd/solanum/issues/166
PATH=~/.local/bin:$PATH pytest --controller=irctest.controllers.charybdis -k 'not Ergo and not deprecated and not strict and not testDoubleKickMessages and not testQuitErrors and not (AccountTagTestCase and testInvite)'

View File

@ -28,12 +28,10 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get install atheme-services
python -m pip install --upgrade pip
pip install pytest -r requirements.txt
- name: Install atheme
run: sudo apt-get install atheme-services
- name: Checkout InspIRCd
uses: actions/checkout@v2
with:

View File

@ -28,6 +28,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get install atheme-services
python -m pip install --upgrade pip
pip install pytest -r requirements.txt
@ -35,7 +36,7 @@ jobs:
uses: actions/checkout@v2
with:
repository: solanum-ircd/solanum
ref: 2e8a889fc94313acf53c430cec1bd044850769a0
ref: e370888264da666a1bd9faac86cd5f2aa06084f4
path: solanum
- name: Build Solanum

View File

@ -177,6 +177,7 @@ class BaseClientController(_BaseController):
class BaseServerController(_BaseController):
"""Base controller for IRC server."""
software_name: str # Class property
_port_wait_interval = 0.1
port_open = False
port: int
@ -250,19 +251,31 @@ class BaseServicesController(_BaseController):
c.sendLine("NICK chkNS")
c.sendLine("USER chk chk chk chk")
c.getMessages(synchronize=False)
c.getMessages()
msgs: List[Message] = []
while not msgs:
timeout = time.time() + 5
while True:
c.sendLine("PRIVMSG NickServ :HELP")
msgs = self.getNickServResponse(c)
if msgs[0].command == "401":
for msg in msgs:
if msg.command == "401":
# NickServ not available yet
pass
elif msgs[0].command == "NOTICE":
elif msg.command == "NOTICE":
# NickServ is available
assert "nickserv" in (msgs[0].prefix or "").lower(), msgs
assert "nickserv" in (msg.prefix or "").lower(), msg
print("breaking")
break
else:
assert False, f"unexpected reply from NickServ: {msgs[0]}"
assert False, f"unexpected reply from NickServ: {msg}"
else:
if time.time() > timeout:
raise Exception("Timeout while waiting for NickServ")
continue
# If we're here, it means we broke from the for loop, so NickServ
# is available and we can break again
break
c.sendLine("QUIT")
c.getMessages()
@ -296,6 +309,8 @@ class BaseServicesController(_BaseController):
case.getMessages(client)
case.sendLine(client, f"PRIVMSG NickServ :REGISTER {password} foo@example.org")
msgs = self.getNickServResponse(case.clients[client])
if self.server_controller.software_name == "inspircd":
assert "900" in {msg.command for msg in msgs}, msgs
assert "NOTICE" in {msg.command for msg in msgs}, msgs
case.sendLine(client, "QUIT")
case.assertDisconnected(client)

View File

@ -8,7 +8,7 @@ import irctest.cases
import irctest.runner
TEMPLATE_CONFIG = """
loadmodule "modules/protocol/inspircd";
loadmodule "modules/protocol/{protocol}";
loadmodule "modules/backend/opensex";
loadmodule "modules/crypto/pbkdf2";
@ -39,7 +39,7 @@ general {{
commit_interval = 5;
}};
uplink "irc.example.com" {{
uplink "My.Little.Server" {{
host = "{server_hostname}";
port = {server_port};
send_password = "password";
@ -55,12 +55,15 @@ saslserv {{
class AthemeServices(BaseServicesController, DirectoryBasedController):
"""Mixin for server controllers that rely on Atheme"""
def run(self, server_hostname: str, server_port: int) -> None:
def run(self, protocol: str, server_hostname: str, server_port: int) -> None:
self.create_config()
assert protocol in ("inspircd", "charybdis")
with self.open_file("services.conf") as fd:
fd.write(
TEMPLATE_CONFIG.format(
protocol=protocol,
server_hostname=server_hostname,
server_port=server_port,
)
@ -81,7 +84,7 @@ class AthemeServices(BaseServicesController, DirectoryBasedController):
self.directory,
],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL,
)
def registerUser(

View File

@ -7,6 +7,8 @@ from irctest.basecontrollers import (
DirectoryBasedController,
NotImplementedByController,
)
from irctest.controllers.atheme_services import AthemeServices
from irctest.irc_utils.junkdrawer import find_hostname_and_port
TEMPLATE_CONFIG = """
serverinfo {{
@ -15,23 +17,48 @@ serverinfo {{
description = "test server";
{ssl_config}
}};
general {{
throttle_count = 100; # We need to connect lots of clients quickly
sasl_service = "SaslServ";
}};
class "server" {{
ping_time = 5 minutes;
connectfreq = 5 minutes;
}};
listen {{
defer_accept = yes;
host = "{hostname}";
port = {port};
}};
auth {{
user = "*";
flags = exceed_limit;
{password_field}
}};
channel {{
disable_local_channels = no;
no_create_on_split = no;
no_join_on_split = no;
displayed_usercount = 0;
}};
connect "services.example.org" {{
host = "localhost"; # Used to validate incoming connection
port = 0; # We don't want the servers to connect to services
send_password = "password";
accept_password = "password";
class = "server";
flags = topicburst;
}};
service {{
name = "services.example.org";
}};
"""
TEMPLATE_SSL_CONFIG = """
@ -44,7 +71,7 @@ TEMPLATE_SSL_CONFIG = """
class CharybdisController(BaseServerController, DirectoryBasedController):
software_name = "Charybdis"
binary_name = "charybdis"
supported_sasl_mechanisms: Set[str] = set()
supported_sasl_mechanisms = {"PLAIN"}
supports_sts = False
def create_config(self) -> None:
@ -67,11 +94,11 @@ class CharybdisController(BaseServerController, DirectoryBasedController):
raise NotImplementedByController(
"Defining valid and invalid METADATA keys."
)
if run_services:
raise NotImplementedByController("Registration services")
assert self.proc is None
self.create_config()
self.port = port
self.hostname = hostname
self.create_config()
(services_hostname, services_port) = find_hostname_and_port()
password_field = 'password = "{}";'.format(password) if password else ""
if ssl:
self.gen_ssl()
@ -85,6 +112,8 @@ class CharybdisController(BaseServerController, DirectoryBasedController):
TEMPLATE_CONFIG.format(
hostname=hostname,
port=port,
services_hostname=services_hostname,
services_port=services_port,
password_field=password_field,
ssl_config=ssl_config,
)
@ -102,6 +131,13 @@ class CharybdisController(BaseServerController, DirectoryBasedController):
# stderr=subprocess.DEVNULL,
)
if run_services:
self.wait_for_port()
self.services_controller = AthemeServices(self.test_config, self)
self.services_controller.run(
protocol="charybdis", server_hostname=hostname, server_port=port
)
def get_irctest_controller_class() -> Type[CharybdisController]:
return CharybdisController

View File

@ -54,7 +54,7 @@ TEMPLATE_CONFIG = """
# Misc:
<log method="file" type="*" level="debug" target="/tmp/ircd-{port}.log">
<server name="irc.example.com" description="testnet" id="000" network="testnet">
<server name="My.Little.Server" description="testnet" id="000" network="testnet">
"""
TEMPLATE_SSL_CONFIG = """
@ -128,9 +128,12 @@ class InspircdController(BaseServerController, DirectoryBasedController):
)
if run_services:
self.wait_for_port()
self.services_controller = AthemeServices(self.test_config, self)
self.services_controller.run(
server_hostname=services_hostname, server_port=services_port
protocol="inspircd",
server_hostname=services_hostname,
server_port=services_port,
)