diff --git a/Makefile b/Makefile index 6423f21..9cf44b2 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,12 @@ EXTRA_SELECTORS ?= ANOPE_SELECTORS := \ and not testPlainLarge +BAHAMUT_SELECTORS := \ + not Ergo \ + and not deprecated \ + and not strict \ + $(EXTRA_SELECTORS) + # testQuitErrors is very flaky # AccountTagTestCase.testInvite fails because https://github.com/solanum-ircd/solanum/issues/166 CHARYBDIS_SELECTORS := \ @@ -93,13 +99,33 @@ UNREALIRCD_SELECTORS := \ and not (testChathistory and (between or around)) \ $(EXTRA_SELECTORS) -.PHONY: all flakes charybdis ergo inspircd mammon limnoria sopel solanum unrealircd +.PHONY: all flakes bahamut charybdis ergo inspircd mammon limnoria sopel solanum unrealircd -all: flakes charybdis ergo inspircd mammon limnoria sopel solanum unrealircd +all: flakes bahamut charybdis ergo inspircd mammon limnoria sopel solanum unrealircd flakes: find irctest/ -name "*.py" -not -path "irctest/scram/*" -print0 | xargs -0 pyflakes3 +bahamut: + $(PYTEST) $(PYTEST_ARGS) \ + --controller=irctest.controllers.bahamut \ + -m 'not services' \ + -k '$(BAHAMUT_SELECTORS)' + +bahamut-atheme: + $(PYTEST) $(PYTEST_ARGS) \ + --controller=irctest.controllers.bahamut \ + --services-controller=irctest.controllers.atheme_services \ + -m 'services' \ + -k '$(BAHAMUT_SELECTORS)' + +bahamut-anope: + $(PYTEST) $(PYTEST_ARGS) \ + --controller=irctest.controllers.bahamut \ + --services-controller=irctest.controllers.anope_services \ + -m 'services' \ + -k '$(BAHAMUT_SELECTORS) $(ANOPE_SELECTORS)' + charybdis: $(PYTEST) $(PYTEST_ARGS) \ --controller=irctest.controllers.charybdis \ diff --git a/irctest/controllers/anope_services.py b/irctest/controllers/anope_services.py index e41203c..3ccdb29 100644 --- a/irctest/controllers/anope_services.py +++ b/irctest/controllers/anope_services.py @@ -76,7 +76,14 @@ class AnopeController(BaseServicesController, DirectoryBasedController): def run(self, protocol: str, server_hostname: str, server_port: int) -> None: self.create_config() - assert protocol in ("inspircd3", "charybdis", "hybrid", "plexus", "unreal4") + assert protocol in ( + "bahamut", + "inspircd3", + "charybdis", + "hybrid", + "plexus", + "unreal4", + ) with self.open_file("conf/services.conf") as fd: fd.write( diff --git a/irctest/controllers/atheme_services.py b/irctest/controllers/atheme_services.py index a3c490a..6877c9f 100644 --- a/irctest/controllers/atheme_services.py +++ b/irctest/controllers/atheme_services.py @@ -61,7 +61,7 @@ class AthemeController(BaseServicesController, DirectoryBasedController): if protocol == "inspircd3": # That's the name used by Anope protocol = "inspircd" - assert protocol in ("inspircd", "charybdis", "unreal4") + assert protocol in ("bahamut", "inspircd", "charybdis", "unreal4") with self.open_file("services.conf") as fd: fd.write( @@ -86,7 +86,7 @@ class AthemeController(BaseServicesController, DirectoryBasedController): "-D", self.directory, ], - stdout=subprocess.DEVNULL, + # stdout=subprocess.DEVNULL, # stderr=subprocess.DEVNULL, ) diff --git a/irctest/controllers/bahamut.py b/irctest/controllers/bahamut.py new file mode 100644 index 0000000..62a26ef --- /dev/null +++ b/irctest/controllers/bahamut.py @@ -0,0 +1,154 @@ +import os +import shutil +import subprocess +from typing import Optional, Set, Type + +from irctest.basecontrollers import ( + BaseServerController, + DirectoryBasedController, + NotImplementedByController, +) +from irctest.irc_utils.junkdrawer import find_hostname_and_port + +TEMPLATE_CONFIG = """ +global {{ + name My.Little.Server; # IRC name of the server + info "located on earth"; # A short info line +}}; + +options {{ + network_name unconfigured; + allow_split_ops; # Give ops in empty channels + + services_name services.example.org; + + // if you need to link more than 1 server, uncomment the following line + # servtype hub; +}}; + +/* where to listen for connections */ +port {{ + port {port}; + bind {hostname}; +}}; + +/* allow clients to connect */ +allow {{ + host *@*; # Allow anyone + class users; # Place them in the users class + flags T; # No throttling + {password_field} +}}; + +/* connection class for users */ +class {{ + name users; # Class name + maxusers 100; # Maximum connections + pingfreq 90; # Check idle connections every N seconds + maxsendq 100000; # 100KB send buffer limit +}}; + +/* for services */ +super {{ + "services.example.org"; +}}; + + +/* class for services */ +class {{ + name services; + pingfreq 60; # Idle check every minute + maxsendq 5000000; # 5MB backlog buffer +}}; + +/* our services */ +connect {{ + name services.example.org; + host *@*; + apasswd password; + cpasswd password; + class services; +}}; +""" + + +class UnrealircdController(BaseServerController, DirectoryBasedController): + software_name = "Bahamut" + supported_sasl_mechanisms = {"PLAIN"} + supports_sts = False + + def create_config(self) -> None: + super().create_config() + with self.open_file("server.conf"): + pass + + def run( + self, + hostname: str, + port: int, + *, + password: Optional[str], + ssl: bool, + run_services: bool, + valid_metadata_keys: Optional[Set[str]] = None, + invalid_metadata_keys: Optional[Set[str]] = None, + restricted_metadata_keys: Optional[Set[str]] = None, + ) -> None: + if valid_metadata_keys or invalid_metadata_keys: + raise NotImplementedByController( + "Defining valid and invalid METADATA keys." + ) + assert self.proc is None + self.port = port + self.hostname = hostname + self.create_config() + (unused_hostname, unused_port) = find_hostname_and_port() + (services_hostname, services_port) = find_hostname_and_port() + + password_field = "passwd {};".format(password) if password else "" + + self.gen_ssl() + + assert self.directory + + # they are hardcoded... thankfully Bahamut reads them from the CWD. + shutil.copy(self.pem_path, os.path.join(self.directory, "ircd.crt")) + shutil.copy(self.key_path, os.path.join(self.directory, "ircd.key")) + + with self.open_file("server.conf") as fd: + fd.write( + TEMPLATE_CONFIG.format( + hostname=hostname, + port=port, + services_hostname=services_hostname, + services_port=services_port, + password_field=password_field, + # key_path=self.key_path, + # pem_path=self.pem_path, + ) + ) + self.proc = subprocess.Popen( + [ + # "strace", "-f", "-e", "file", + "ircd", + "-t", # don't fork + "-f", + os.path.join(self.directory, "server.conf"), + ], + # stdout=subprocess.DEVNULL, + ) + + if run_services: + self.wait_for_port() + self.services_controller = self.services_controller_class( + self.test_config, self + ) + self.services_controller.run( + protocol="bahamut", + server_hostname=hostname, + server_port=port, + ) + + +def get_irctest_controller_class() -> Type[UnrealircdController]: + return UnrealircdController diff --git a/irctest/server_tests/test_register_verify.py b/irctest/server_tests/test_register_verify.py index f094f5b..c91c6c4 100644 --- a/irctest/server_tests/test_register_verify.py +++ b/irctest/server_tests/test_register_verify.py @@ -4,6 +4,7 @@ from irctest.patma import ANYSTR REGISTER_CAP_NAME = "draft/account-registration" +@cases.mark_specifications("IRCv3") class TestRegisterBeforeConnect(cases.BaseServerTestCase): @staticmethod def config() -> cases.TestCaseControllerConfig: @@ -27,6 +28,7 @@ class TestRegisterBeforeConnect(cases.BaseServerTestCase): self.assertMessageMatch(register_response, params=["SUCCESS", ANYSTR, ANYSTR]) +@cases.mark_specifications("IRCv3") class TestRegisterBeforeConnectDisallowed(cases.BaseServerTestCase): @staticmethod def config() -> cases.TestCaseControllerConfig: @@ -53,6 +55,7 @@ class TestRegisterBeforeConnectDisallowed(cases.BaseServerTestCase): ) +@cases.mark_specifications("IRCv3") class TestRegisterEmailVerified(cases.BaseServerTestCase): @staticmethod def config() -> cases.TestCaseControllerConfig: @@ -102,6 +105,7 @@ class TestRegisterEmailVerified(cases.BaseServerTestCase): ) +@cases.mark_specifications("IRCv3") class TestRegisterNoLandGrabs(cases.BaseServerTestCase): @staticmethod def config() -> cases.TestCaseControllerConfig: