Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Implement a new test baseclass to cut down on boilerplate #3684

Merged
merged 7 commits into from
Aug 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/3684.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implemented a new testing base class to reduce test boilerplate.
66 changes: 29 additions & 37 deletions tests/rest/client/v1/test_typing.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2014-2016 OpenMarket Ltd
# Copyright 2018 New Vector
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -17,41 +18,32 @@

from mock import Mock, NonCallableMock

# twisted imports
from twisted.internet import defer

import synapse.rest.client.v1.room
from synapse.rest.client.v1 import room
from synapse.types import UserID

from ....utils import MockClock, MockHttpResource, setup_test_homeserver
from .utils import RestTestCase
from tests import unittest

PATH_PREFIX = "/_matrix/client/api/v1"


class RoomTypingTestCase(RestTestCase):
class RoomTypingTestCase(unittest.HomeserverTestCase):
""" Tests /rooms/$room_id/typing/$user_id REST API. """

user_id = "@sid:red"

user = UserID.from_string(user_id)
servlets = [room.register_servlets]

@defer.inlineCallbacks
def setUp(self):
self.clock = MockClock()
def make_homeserver(self, reactor, clock):

self.mock_resource = MockHttpResource(prefix=PATH_PREFIX)
self.auth_user_id = self.user_id

hs = yield setup_test_homeserver(
self.addCleanup,
hs = self.setup_test_homeserver(
"red",
clock=self.clock,
http_client=None,
federation_client=Mock(),
ratelimiter=NonCallableMock(spec_set=["send_message"]),
)
self.hs = hs

self.event_source = hs.get_event_sources().sources["typing"]

Expand Down Expand Up @@ -100,25 +92,24 @@ def fetch_room_distributions_into(
fetch_room_distributions_into
)

synapse.rest.client.v1.room.register_servlets(hs, self.mock_resource)
return hs

self.room_id = yield self.create_room_as(self.user_id)
def prepare(self, reactor, clock, hs):
self.room_id = self.helper.create_room_as(self.user_id)
# Need another user to make notifications actually work
yield self.join(self.room_id, user="@jim:red")
self.helper.join(self.room_id, user="@jim:red")

@defer.inlineCallbacks
def test_set_typing(self):
(code, _) = yield self.mock_resource.trigger(
request, channel = self.make_request(
"PUT",
"/rooms/%s/typing/%s" % (self.room_id, self.user_id),
'{"typing": true, "timeout": 30000}',
b'{"typing": true, "timeout": 30000}',
)
self.assertEquals(200, code)
self.render(request)
self.assertEquals(200, channel.code)

self.assertEquals(self.event_source.get_current_key(), 1)
events = yield self.event_source.get_new_events(
from_key=0, room_ids=[self.room_id]
)
events = self.event_source.get_new_events(from_key=0, room_ids=[self.room_id])
self.assertEquals(
events[0],
[
Expand All @@ -130,35 +121,36 @@ def test_set_typing(self):
],
)

@defer.inlineCallbacks
def test_set_not_typing(self):
(code, _) = yield self.mock_resource.trigger(
request, channel = self.make_request(
"PUT",
"/rooms/%s/typing/%s" % (self.room_id, self.user_id),
'{"typing": false}',
b'{"typing": false}',
)
self.assertEquals(200, code)
self.render(request)
self.assertEquals(200, channel.code)

@defer.inlineCallbacks
def test_typing_timeout(self):
(code, _) = yield self.mock_resource.trigger(
request, channel = self.make_request(
"PUT",
"/rooms/%s/typing/%s" % (self.room_id, self.user_id),
'{"typing": true, "timeout": 30000}',
b'{"typing": true, "timeout": 30000}',
)
self.assertEquals(200, code)
self.render(request)
self.assertEquals(200, channel.code)

self.assertEquals(self.event_source.get_current_key(), 1)

self.clock.advance_time(36)
self.reactor.advance(36)

self.assertEquals(self.event_source.get_current_key(), 2)

(code, _) = yield self.mock_resource.trigger(
request, channel = self.make_request(
"PUT",
"/rooms/%s/typing/%s" % (self.room_id, self.user_id),
'{"typing": true, "timeout": 30000}',
b'{"typing": true, "timeout": 30000}',
)
self.assertEquals(200, code)
self.render(request)
self.assertEquals(200, channel.code)

self.assertEquals(self.event_source.get_current_key(), 3)
144 changes: 144 additions & 0 deletions tests/unittest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2014-2016 OpenMarket Ltd
# Copyright 2018 New Vector
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -15,12 +16,19 @@

import logging

from mock import Mock

import twisted
import twisted.logger
from twisted.trial import unittest

from synapse.http.server import JsonResource
from synapse.server import HomeServer
from synapse.types import UserID, create_requester
from synapse.util.logcontext import LoggingContextFilter

from tests.server import get_clock, make_request, render, setup_test_homeserver

# Set up putting Synapse's logs into Trial's.
rootLogger = logging.getLogger()

Expand Down Expand Up @@ -129,3 +137,139 @@ def DEBUG(target):
Can apply to either a TestCase or an individual test method."""
target.loglevel = logging.DEBUG
return target


class HomeserverTestCase(TestCase):
"""
A base TestCase that reduces boilerplate for HomeServer-using test cases.

Attributes:
servlets (list[function]): List of servlet registration function.
user_id (str): The user ID to assume if auth is hijacked.
hijack_auth (bool): Whether to hijack auth to return the user specified
in user_id.
"""
servlets = []
hijack_auth = True

def setUp(self):
"""
Set up the TestCase by calling the homeserver constructor, optionally
hijacking the authentication system to return a fixed user, and then
calling the prepare function.
"""
self.reactor, self.clock = get_clock()
self._hs_args = {"clock": self.clock, "reactor": self.reactor}
self.hs = self.make_homeserver(self.reactor, self.clock)

if self.hs is None:
raise Exception("No homeserver returned from make_homeserver.")

if not isinstance(self.hs, HomeServer):
raise Exception("A homeserver wasn't returned, but %r" % (self.hs,))

# Register the resources
self.resource = JsonResource(self.hs)

for servlet in self.servlets:
servlet(self.hs, self.resource)

if hasattr(self, "user_id"):
from tests.rest.client.v1.utils import RestHelper

self.helper = RestHelper(self.hs, self.resource, self.user_id)

if self.hijack_auth:

def get_user_by_access_token(token=None, allow_guest=False):
return {
"user": UserID.from_string(self.helper.auth_user_id),
"token_id": 1,
"is_guest": False,
}

def get_user_by_req(request, allow_guest=False, rights="access"):
return create_requester(
UserID.from_string(self.helper.auth_user_id), 1, False, None
)

self.hs.get_auth().get_user_by_req = get_user_by_req
self.hs.get_auth().get_user_by_access_token = get_user_by_access_token
self.hs.get_auth().get_access_token_from_request = Mock(
return_value="1234"
)

if hasattr(self, "prepare"):
self.prepare(self.reactor, self.clock, self.hs)

def make_homeserver(self, reactor, clock):
"""
Make and return a homeserver.

Args:
reactor: A Twisted Reactor, or something that pretends to be one.
clock (synapse.util.Clock): The Clock, associated with the reactor.

Returns:
A homeserver (synapse.server.HomeServer) suitable for testing.

Function to be overridden in subclasses.
"""
raise NotImplementedError()

def prepare(self, reactor, clock, homeserver):
"""
Prepare for the test. This involves things like mocking out parts of
the homeserver, or building test data common across the whole test
suite.

Args:
reactor: A Twisted Reactor, or something that pretends to be one.
clock (synapse.util.Clock): The Clock, associated with the reactor.
homeserver (synapse.server.HomeServer): The HomeServer to test
against.

Function to optionally be overridden in subclasses.
"""

def make_request(self, method, path, content=b""):
"""
Create a SynapseRequest at the path using the method and containing the
given content.

Args:
method (bytes/unicode): The HTTP request method ("verb").
path (bytes/unicode): The HTTP path, suitably URL encoded (e.g.
escaped UTF-8 & spaces and such).
content (bytes): The body of the request.

Returns:
A synapse.http.site.SynapseRequest.
"""
return make_request(method, path, content)

def render(self, request):
"""
Render a request against the resources registered by the test class's
servlets.

Args:
request (synapse.http.site.SynapseRequest): The request to render.
"""
render(request, self.resource, self.reactor)

def setup_test_homeserver(self, *args, **kwargs):
"""
Set up the test homeserver, meant to be called by the overridable
make_homeserver. It automatically passes through the test class's
clock & reactor.

Args:
See tests.utils.setup_test_homeserver.

Returns:
synapse.server.HomeServer
"""
kwargs = dict(kwargs)
kwargs.update(self._hs_args)
return setup_test_homeserver(self.addCleanup, *args, **kwargs)