def setUp(self): self.reactor = ThreadedMemoryReactorClock() self.mock_resolver = Mock() config_dict = default_config("test", parse=False) config_dict["federation_custom_ca_list"] = [get_test_ca_cert_file()] self._config = config = HomeServerConfig() config.parse_config_dict(config_dict, "", "") self.tls_factory = FederationPolicyForHTTPS(config) self.well_known_cache = TTLCache("test_cache", timer=self.reactor.seconds) self.had_well_known_cache = TTLCache("test_cache", timer=self.reactor.seconds) self.well_known_resolver = WellKnownResolver( self.reactor, Agent(self.reactor, contextFactory=self.tls_factory), b"test-agent", well_known_cache=self.well_known_cache, had_well_known_cache=self.had_well_known_cache, ) self.agent = MatrixFederationAgent( reactor=self.reactor, tls_client_options_factory=self.tls_factory, user_agent= "test-agent", # Note that this is unused since _well_known_resolver is provided. ip_blacklist=IPSet(), _srv_resolver=self.mock_resolver, _well_known_resolver=self.well_known_resolver, )
def setUp(self): self.db_pool = Mock(spec=["runInteraction"]) self.mock_txn = Mock() self.mock_conn = Mock(spec_set=["cursor", "rollback", "commit"]) self.mock_conn.cursor.return_value = self.mock_txn self.mock_conn.rollback.return_value = None # Our fake runInteraction just runs synchronously inline def runInteraction(func, *args, **kwargs): return defer.succeed(func(self.mock_txn, *args, **kwargs)) self.db_pool.runInteraction = runInteraction def runWithConnection(func, *args, **kwargs): return defer.succeed(func(self.mock_conn, *args, **kwargs)) self.db_pool.runWithConnection = runWithConnection config = default_config(name="test", parse=True) hs = TestHomeServer("test", config=config) sqlite_config = {"name": "sqlite3"} engine = create_engine(sqlite_config) fake_engine = Mock(wraps=engine) fake_engine.can_native_upsert = False fake_engine.in_transaction.return_value = False db = DatabasePool(Mock(), Mock(config=sqlite_config), fake_engine) db._db_pool = self.db_pool self.datastore = SQLBaseStore(db, None, hs)
def setUp(self): self.reactor = ThreadedMemoryReactorClock() self.mock_resolver = Mock() config_dict = default_config("test", parse=False) config_dict["federation_custom_ca_list"] = [get_test_ca_cert_file()] self._config = config = HomeServerConfig() config.parse_config_dict(config_dict, "", "") self.tls_factory = ClientTLSOptionsFactory(config) self.well_known_cache = TTLCache("test_cache", timer=self.reactor.seconds) self.had_well_known_cache = TTLCache("test_cache", timer=self.reactor.seconds) self.well_known_resolver = WellKnownResolver( self.reactor, Agent(self.reactor, contextFactory=self.tls_factory), well_known_cache=self.well_known_cache, had_well_known_cache=self.had_well_known_cache, ) self.agent = MatrixFederationAgent( reactor=self.reactor, tls_client_options_factory=self.tls_factory, _srv_resolver=self.mock_resolver, _well_known_resolver=self.well_known_resolver, )
async def make_homeserver(reactor, config=None): """ Make a Homeserver suitable for running benchmarks against. Args: reactor: A Twisted reactor to run under. config: A HomeServerConfig to use, or None. """ cleanup_tasks = [] clock = Clock(reactor) if not config: config = default_config("test") config_obj = HomeServerConfig() config_obj.parse_config_dict(config, "", "") hs = await setup_test_homeserver(cleanup_tasks.append, config=config_obj, reactor=reactor, clock=clock) stor = hs.get_datastore() # Run the database background updates. if hasattr(stor.db.updates, "do_next_background_update"): while not await stor.db.updates.has_completed_background_updates(): await stor.db.updates.do_next_background_update(1) def cleanup(): for i in cleanup_tasks: i() return hs, clock.sleep, cleanup
def default_config(self, name="test"): """ Get a default HomeServer config dict. Args: name (str): The homeserver name/domain. """ return default_config(name)
def default_config(self, name="test"): """ Get a default HomeServer config object. Args: name (str): The homeserver name/domain. """ return default_config(name)
def test_session_lifetime_must_not_be_exceeded_by_smaller_lifetimes(self): """ session_lifetime should logically be larger than, or at least as large as, all the different token lifetimes. Test that the user is faced with configuration errors if they make it smaller, as that configuration doesn't make sense. """ config_dict = default_config("test") # First test all the error conditions with self.assertRaises(ConfigError): HomeServerConfig().parse_config_dict({ "session_lifetime": "30m", "nonrefreshable_access_token_lifetime": "31m", **config_dict, }) with self.assertRaises(ConfigError): HomeServerConfig().parse_config_dict({ "session_lifetime": "30m", "refreshable_access_token_lifetime": "31m", **config_dict, }) with self.assertRaises(ConfigError): HomeServerConfig().parse_config_dict({ "session_lifetime": "30m", "refresh_token_lifetime": "31m", **config_dict, }) # Then test all the fine conditions HomeServerConfig().parse_config_dict({ "session_lifetime": "31m", "nonrefreshable_access_token_lifetime": "31m", **config_dict, }) HomeServerConfig().parse_config_dict({ "session_lifetime": "31m", "refreshable_access_token_lifetime": "31m", **config_dict, }) HomeServerConfig().parse_config_dict({ "session_lifetime": "31m", "refresh_token_lifetime": "31m", **config_dict })
def test_get_well_known_unsigned_cert(self): """Test the behaviour when the .well-known server presents a cert not signed by a CA """ # we use the same test server as the other tests, but use an agent with # the config left to the default, which will not trust it (since the # presented cert is signed by a test CA) self.mock_resolver.resolve_service.side_effect = generate_resolve_service( []) self.reactor.lookups["testserv"] = "1.2.3.4" config = default_config("test", parse=True) # Build a new agent and WellKnownResolver with a different tls factory tls_factory = FederationPolicyForHTTPS(config) agent = MatrixFederationAgent( reactor=self.reactor, tls_client_options_factory=tls_factory, user_agent= b"test-agent", # This is unused since _well_known_resolver is passed below. ip_blacklist=IPSet(), _srv_resolver=self.mock_resolver, _well_known_resolver=WellKnownResolver( self.reactor, Agent(self.reactor, contextFactory=tls_factory), b"test-agent", well_known_cache=self.well_known_cache, had_well_known_cache=self.had_well_known_cache, ), ) test_d = agent.request(b"GET", b"matrix://testserv/foo/bar") # Nothing happened yet self.assertNoResult(test_d) # there should be an attempt to connect on port 443 for the .well-known clients = self.reactor.tcpClients self.assertEqual(len(clients), 1) (host, port, client_factory, _timeout, _bindAddress) = clients[0] self.assertEqual(host, "1.2.3.4") self.assertEqual(port, 443) http_proto = self._make_connection(client_factory, expected_sni=b"testserv") # there should be no requests self.assertEqual(len(http_proto.requests), 0) # and there should be a SRV lookup instead self.mock_resolver.resolve_service.assert_called_once_with( b"_matrix._tcp.testserv")
def default_config(self) -> Dict[str, Any]: config = default_config("test") config.update({ "spam_checker": [{ "module": TestSpamChecker.__module__ + ".TestSpamChecker", "config": {}, }] }) return config
def default_config(self): """ Get a default HomeServer config dict. """ config = default_config("test") # apply any additional config which was specified via the override_config # decorator. if self._extra_config is not None: config.update(self._extra_config) return config
def default_config(self, name="test"): """ Get a default HomeServer config dict. Args: name (str): The homeserver name/domain. """ config = default_config(name) # apply any additional config which was specified via the override_config # decorator. if self._extra_config is not None: config.update(self._extra_config) return config
def setUp(self): self.reactor = ThreadedMemoryReactorClock() self.mock_resolver = Mock() self.well_known_cache = TTLCache("test_cache", timer=self.reactor.seconds) self.agent = MatrixFederationAgent( reactor=self.reactor, tls_client_options_factory=ClientTLSOptionsFactory( default_config("test", parse=True) ), _well_known_tls_policy=TrustingTLSPolicyForHTTPS(), _srv_resolver=self.mock_resolver, _well_known_cache=self.well_known_cache, )
def prepare(self, reactor, clock, homeserver): # make a second homeserver, configured to use the first one as a key notary self.http_client2 = Mock() config = default_config(name="keyclient") config["trusted_key_servers"] = [ { "server_name": self.hs.hostname, "verify_keys": { "ed25519:%s" % ( self.hs_signing_key.version, ): signedjson.key.encode_verify_key_base64( self.hs_signing_key.verify_key ) }, } ] self.hs2 = self.setup_test_homeserver( federation_http_client=self.http_client2, config=config ) # wire up outbound POST /key/v2/query requests from hs2 so that they # will be forwarded to hs1 async def post_json(destination, path, data): self.assertEqual(destination, self.hs.hostname) self.assertEqual( path, "/_matrix/key/v2/query", ) channel = FakeChannel(self.site, self.reactor) req = SynapseRequest(channel) req.content = BytesIO(encode_canonical_json(data)) req.requestReceived( b"POST", path.encode("utf-8"), b"1.1", ) channel.await_result() self.assertEqual(channel.code, 200) resp = channel.json_body return resp self.http_client2.post_json.side_effect = post_json
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: # make a second homeserver, configured to use the first one as a key notary self.http_client2 = Mock() config = default_config(name="keyclient") config["trusted_key_servers"] = [{ "server_name": self.hs.hostname, "verify_keys": { "ed25519:%s" % (self.hs_signing_key.version, ): signedjson.key.encode_verify_key_base64( signedjson.key.get_verify_key(self.hs_signing_key)) }, }] self.hs2 = self.setup_test_homeserver( federation_http_client=self.http_client2, config=config) # wire up outbound POST /key/v2/query requests from hs2 so that they # will be forwarded to hs1 async def post_json( destination: str, path: str, data: Optional[JsonDict] = None) -> Union[JsonDict, list]: self.assertEqual(destination, self.hs.hostname) self.assertEqual( path, "/_matrix/key/v2/query", ) channel = FakeChannel(self.site, self.reactor) # channel is a `FakeChannel` but `HTTPChannel` is expected req = SynapseRequest(channel, self.site) # type: ignore[arg-type] req.content = BytesIO(encode_canonical_json(data)) req.requestReceived( b"POST", path.encode("utf-8"), b"1.1", ) channel.await_result() self.assertEqual(channel.code, 200) resp = channel.json_body return resp self.http_client2.post_json.side_effect = post_json
def test_parse_rc_federation(self): config_dict = default_config("test") config_dict["rc_federation"] = { "window_size": 20000, "sleep_limit": 693, "sleep_delay": 252, "reject_limit": 198, "concurrent": 7, } config = HomeServerConfig() config.parse_config_dict(config_dict, "", "") config_obj = config.rc_federation self.assertEqual(config_obj.window_size, 20000) self.assertEqual(config_obj.sleep_limit, 693) self.assertEqual(config_obj.sleep_delay, 252) self.assertEqual(config_obj.reject_limit, 198) self.assertEqual(config_obj.concurrent, 7)
def test_get_well_known_unsigned_cert(self): """Test the behaviour when the .well-known server presents a cert not signed by a CA """ # we use the same test server as the other tests, but use an agent with # the config left to the default, which will not trust it (since the # presented cert is signed by a test CA) self.mock_resolver.resolve_service.side_effect = lambda _: [] self.reactor.lookups["testserv"] = "1.2.3.4" config = default_config("test", parse=True) agent = MatrixFederationAgent( reactor=self.reactor, tls_client_options_factory=ClientTLSOptionsFactory(config), _srv_resolver=self.mock_resolver, _well_known_cache=self.well_known_cache, ) test_d = agent.request(b"GET", b"matrix://testserv/foo/bar") # Nothing happened yet self.assertNoResult(test_d) # there should be an attempt to connect on port 443 for the .well-known clients = self.reactor.tcpClients self.assertEqual(len(clients), 1) (host, port, client_factory, _timeout, _bindAddress) = clients[0] self.assertEqual(host, "1.2.3.4") self.assertEqual(port, 443) http_proto = self._make_connection(client_factory, expected_sni=b"testserv") # there should be no requests self.assertEqual(len(http_proto.requests), 0) # and there should be a SRV lookup instead self.mock_resolver.resolve_service.assert_called_once_with( b"_matrix._tcp.testserv" )
def default_config(self): config = default_config("test") config.update({ "admin_contact": "mailto:[email protected]", "limit_usage_by_mau": True, "server_notices": { "system_mxid_localpart": "server", "system_mxid_display_name": "test display name", "system_mxid_avatar_url": None, "room_name": "Server Notices", }, }) # apply any additional config which was specified via the override_config # decorator. if self._extra_config is not None: config.update(self._extra_config) return config
def default_config(self): config = default_config("test") config.update({ "registrations_require_3pid": [], "limit_usage_by_mau": True, "max_mau_value": 2, "mau_trial_days": 0, "server_notices": { "system_mxid_localpart": "server", "room_name": "Test Server Notice Room", }, }) # apply any additional config which was specified via the override_config # decorator. if self._extra_config is not None: config.update(self._extra_config) return config
def setUp(self): self.reactor = ThreadedMemoryReactorClock() self.mock_resolver = Mock() self.well_known_cache = TTLCache("test_cache", timer=self.reactor.seconds) config_dict = default_config("test", parse=False) config_dict["federation_custom_ca_list"] = [get_test_ca_cert_file()] # config_dict["trusted_key_servers"] = [] self._config = config = HomeServerConfig() config.parse_config_dict(config_dict) self.agent = MatrixFederationAgent( reactor=self.reactor, tls_client_options_factory=ClientTLSOptionsFactory(config), _well_known_tls_policy=TrustingTLSPolicyForHTTPS(), _srv_resolver=self.mock_resolver, _well_known_cache=self.well_known_cache, )
def build_rc_config(settings={}): config_dict = default_config("test") config_dict.update(settings) config = HomeServerConfig() config.parse_config_dict(config_dict, "", "") return config.rc_federation
def setup_test_homeserver( cleanup_func, name="test", config=None, reactor=None, homeserver_to_use: Type[HomeServer] = TestHomeServer, **kwargs, ): """ Setup a homeserver suitable for running tests against. Keyword arguments are passed to the Homeserver constructor. If no datastore is supplied, one is created and given to the homeserver. Args: cleanup_func : The function used to register a cleanup routine for after the test. Calling this method directly is deprecated: you should instead derive from HomeserverTestCase. """ if reactor is None: from twisted.internet import reactor if config is None: config = default_config(name, parse=True) config.ldap_enabled = False if "clock" not in kwargs: kwargs["clock"] = MockClock() if USE_POSTGRES_FOR_TESTS: test_db = "synapse_test_%s" % uuid.uuid4().hex database_config = { "name": "psycopg2", "args": { "database": test_db, "host": POSTGRES_HOST, "password": POSTGRES_PASSWORD, "user": POSTGRES_USER, "cp_min": 1, "cp_max": 5, }, } else: if SQLITE_PERSIST_DB: # The current working directory is in _trial_temp, so this gets created within that directory. test_db_location = os.path.abspath("test.db") logger.debug("Will persist db to %s", test_db_location) # Ensure each test gets a clean database. try: os.remove(test_db_location) except FileNotFoundError: pass else: logger.debug("Removed existing DB at %s", test_db_location) else: test_db_location = ":memory:" database_config = { "name": "sqlite3", "args": { "database": test_db_location, "cp_min": 1, "cp_max": 1 }, } if "db_txn_limit" in kwargs: database_config["txn_limit"] = kwargs["db_txn_limit"] database = DatabaseConnectionConfig("master", database_config) config.database.databases = [database] db_engine = create_engine(database.config) # Create the database before we actually try and connect to it, based off # the template database we generate in setupdb() if isinstance(db_engine, PostgresEngine): db_conn = db_engine.module.connect( database=POSTGRES_BASE_DB, user=POSTGRES_USER, host=POSTGRES_HOST, password=POSTGRES_PASSWORD, ) db_conn.autocommit = True cur = db_conn.cursor() cur.execute("DROP DATABASE IF EXISTS %s;" % (test_db, )) cur.execute("CREATE DATABASE %s WITH TEMPLATE %s;" % (test_db, POSTGRES_BASE_DB)) cur.close() db_conn.close() hs = homeserver_to_use( name, config=config, version_string="Synapse/tests", reactor=reactor, ) # Install @cache_in_self attributes for key, val in kwargs.items(): setattr(hs, "_" + key, val) # Mock TLS hs.tls_server_context_factory = Mock() hs.tls_client_options_factory = Mock() hs.setup() if homeserver_to_use == TestHomeServer: hs.setup_background_tasks() if isinstance(db_engine, PostgresEngine): database = hs.get_datastores().databases[0] # We need to do cleanup on PostgreSQL def cleanup(): import psycopg2 # Close all the db pools database._db_pool.close() dropped = False # Drop the test database db_conn = db_engine.module.connect( database=POSTGRES_BASE_DB, user=POSTGRES_USER, host=POSTGRES_HOST, password=POSTGRES_PASSWORD, ) db_conn.autocommit = True cur = db_conn.cursor() # Try a few times to drop the DB. Some things may hold on to the # database for a few more seconds due to flakiness, preventing # us from dropping it when the test is over. If we can't drop # it, warn and move on. for _ in range(5): try: cur.execute("DROP DATABASE IF EXISTS %s;" % (test_db, )) db_conn.commit() dropped = True except psycopg2.OperationalError as e: warnings.warn("Couldn't drop old db: " + str(e), category=UserWarning) time.sleep(0.5) cur.close() db_conn.close() if not dropped: warnings.warn("Failed to drop old DB.", category=UserWarning) if not LEAVE_DB: # Register the cleanup hook cleanup_func(cleanup) # bcrypt is far too slow to be doing in unit tests # Need to let the HS build an auth handler and then mess with it # because AuthHandler's constructor requires the HS, so we can't make one # beforehand and pass it in to the HS's constructor (chicken / egg) async def hash(p): return hashlib.md5(p.encode("utf8")).hexdigest() hs.get_auth_handler().hash = hash async def validate_hash(p, h): return hashlib.md5(p.encode("utf8")).hexdigest() == h hs.get_auth_handler().validate_hash = validate_hash # Make the threadpool and database transactions synchronous for testing. _make_test_homeserver_synchronous(hs) return hs
def build_rc_config(settings: Optional[dict] = None): config_dict = default_config("test") config_dict.update(settings or {}) config = HomeServerConfig() config.parse_config_dict(config_dict, "", "") return config.ratelimiting.rc_federation