Пример #1
0
    def setUp(self):
        self.config = testing.setUp()

        self.request = Request()
        self.storage = push.storage.mem.Storage()
        self.queuey = MockQueuey()
        self.request.registry['storage'] = self.storage
        self.request.registry['queuey'] = self.queuey
Пример #2
0
    def setUp(self):
        self.mq = MockQueuey()

        patcher = mock.patch('push.tests.mock_queuey.time')
        self.time_mock = patcher.start()
        self.time_mock.time = [3, 2, 1].pop
        self.addCleanup(patcher.stop)

        patcher = mock.patch('push.tests.mock_queuey.uuid')
        self.uuid_mock = patcher.start()
        self.uuid_mock.uuid4.return_value.hex = 'uuid'
        self.addCleanup(patcher.stop)
Пример #3
0
    def setUp(self):
        self.config = testing.setUp()

        self.request = Request()
        self.storage = push.storage.mem.Storage()
        self.queuey = MockQueuey()
        self.request.registry['storage'] = self.storage
        self.request.registry['queuey'] = self.queuey
Пример #4
0
    def setUp(self):
        self.mq = MockQueuey()

        patcher = mock.patch('push.tests.mock_queuey.time')
        self.time_mock = patcher.start()
        self.time_mock.time = [3, 2, 1].pop
        self.addCleanup(patcher.stop)

        patcher = mock.patch('push.tests.mock_queuey.uuid')
        self.uuid_mock = patcher.start()
        self.uuid_mock.uuid4.return_value.hex = 'uuid'
        self.addCleanup(patcher.stop)
Пример #5
0
class TestMockQueuey(unittest2.TestCase):

    def setUp(self):
        self.mq = MockQueuey()

        patcher = mock.patch('push.tests.mock_queuey.time')
        self.time_mock = patcher.start()
        self.time_mock.time = [3, 2, 1].pop
        self.addCleanup(patcher.stop)

        patcher = mock.patch('push.tests.mock_queuey.uuid')
        self.uuid_mock = patcher.start()
        self.uuid_mock.uuid4.return_value.hex = 'uuid'
        self.addCleanup(patcher.stop)

    def test_new_queue(self):
        eq_(self.mq.new_queue(), 'uuid')
        eq_(self.mq.new_queue(), 'uuid')

    def test_delete_queue(self):
        self.mq.new_queue(queue_name='x')
        assert 'x' in self.mq.db
        self.mq.delete_queue('x')
        assert 'x' not in self.mq.db

    def test_new_message(self):
        queue = self.mq.new_queue()
        eq_(self.mq.new_message(queue, 'one'),
            {'messages': [{'timestamp': '1', 'key': 'uuid'}],
             'partition': 1,
             'status': 'ok'})

    def test_get_messages(self):
        queue = self.mq.new_queue()
        self.mq.new_message(queue, 'one')
        self.mq.new_message(queue, 'two')
        eq_(self.mq.get_messages(queue), [
            {'body': 'two',
             'message_id': 'uuid',
             'partition': 1,
             'timestamp': '2'},
            {'body': 'one',
             'partition': 1,
             'message_id': 'uuid',
             'timestamp': '1'},
        ])

    def test_get_messages_limit(self):
        queue = self.mq.new_queue()
        self.mq.new_message(queue, 'one')
        self.mq.new_message(queue, 'two')
        eq_(self.mq.get_messages(queue, limit=1), [
            {'body': 'two',
             'message_id': 'uuid',
             'partition': 1,
             'timestamp': '2'},
        ])

    def test_get_messages_since(self):
        queue = self.mq.new_queue()
        self.mq.new_message(queue, 'one')
        self.mq.new_message(queue, 'two')
        eq_(self.mq.get_messages(queue, since=1), [
            {'body': 'two',
             'message_id': 'uuid',
             'partition': 1,
             'timestamp': '2'},
        ])

    def test_get_messages_order(self):
        queue = self.mq.new_queue()
        self.mq.new_message(queue, 'one')
        self.mq.new_message(queue, 'two')
        eq_(self.mq.get_messages(queue, order='ascending'), [
            {'body': 'one',
             'message_id': 'uuid',
             'partition': 1,
             'timestamp': '1'},
            {'body': 'two',
             'message_id': 'uuid',
             'partition': 1,
             'timestamp': '2'},
        ])
Пример #6
0
class ViewTest(unittest2.TestCase):
    def setUp(self):
        self.config = testing.setUp()

        self.request = Request()
        self.storage = push.storage.mem.Storage()
        self.queuey = MockQueuey()
        self.request.registry['storage'] = self.storage
        self.request.registry['queuey'] = self.queuey

    def tearDown(self):
        testing.tearDown()

    def test_new_token(self):
        # POSTing gets a new token.
        storage_mock = mock.Mock()
        self.request.registry['storage'] = storage_mock
        storage_mock.new_token.return_value = 'TOKEN'

        response = views.new_token(self.request)
        eq_(response, {'token': 'TOKEN', 'queue': '/queue/TOKEN/'})

    def test_has_token_and_domain(self):
        # Check the validator for various problems.
        request = Request(post={'token': ''})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 2)
        eq_(request.errors[0][:2], ('body', 'token'))
        eq_(request.errors[1][:2], ('body', 'domain'))

        request = Request(post={'token': 'ok'})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:2], ('body', 'domain'))

        request = Request(post={'domain': 'ok'})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:2], ('body', 'token'))

        request = Request(post={'token': 'ok', 'domain': ''})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:2], ('body', 'domain'))

        request = Request(post={'token': 't', 'domain': 'r'})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 0)

    def test_new_queue(self):
        # A new queue should be available in storage.
        self.storage.new_token = lambda: 'new-queue'
        request = Request(post={'token': 't', 'domain': 'x.com'})
        response = views.new_queue(request)
        eq_(response, {'queue': '/queue/new-queue/'})

        assert self.storage.user_owns_queue('t', 'new-queue')
        eq_(self.storage.get_user_for_queue('new-queue'), 't')

    def test_delete_queue(self):
        request = Request(post={'token': 't', 'domain': 'x.com'})
        queue = filter(None, views.new_queue(request)['queue'].split('/'))[-1]

        request = Request(params={'token': 't'}, matchdict={'queue': queue})
        views.delete_queue(request)
        eq_(views.get_queues(Request(params={'token': 't'})), {})

    def test_delete_queue_404(self):
        request = Request(post={'token': 't', 'domain': 'x.com'})
        queue = filter(None, views.new_queue(request)['queue'].split('/'))[-1]

        # A valid token with an invalid queue gets a 404.
        request = Request(params={'token': 't'}, matchdict={'queue': 'x'})
        eq_(views.delete_queue(request).code, 404)

        # An invalid token with a valid queue gets a 404.
        request = Request(params={'token': 'x'}, matchdict={'queue': queue})
        eq_(views.delete_queue(request).code, 404)

    def test_has_token(self):
        request = Request(params={'token': 't'})
        eq_(None, views.has_token(request))

        request = Request()
        views.has_token(request)
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:2], ('body', 'token'))

    def test_get_queues(self):
        token = views.new_token(Request())['token']
        request = Request(post={'token': token, 'domain': 'domain'})
        queue = views.new_queue(request)['queue']

        request = Request(params={'token': token})
        response = views.get_queues(request)
        eq_(response, {'domain': queue})

    @mock.patch('push.views.publish')
    @mock.patch('push.tests.mock_queuey.time')
    def test_new_message(self, time_mock, publish_mock):
        # New messages should be in queuey and pubsub.
        token = views.new_token(Request(post={}))['token']
        time_mock.time.return_value = 1
        queue = self.queuey.new_queue()
        self.storage.new_queue(queue, token, 'domain')

        body = {'title': 'title', 'body': 'body'}
        request = Request(matchdict={'queue': queue}, post=body)
        views.message_validator(request)
        response = views.new_message(request)

        # The body is in JSON since queuey just deals with strings.
        self.assertDictEqual(
            self.queuey.get_messages(token)[0], {
                u'body': json.dumps({
                    'queue': queue,
                    'body': body
                }),
                u'timestamp': '1',
                u'partition': 1,
                u'message_id': response['messages'][0]['key']
            })

        publish_mock.assert_called_with(
            request, token, {
                'queue': '/queue/%s/' % queue,
                'timestamp': '1',
                'body': body,
                'key': response['messages'][0]['key']
            })

    @mock.patch('push.views.publish')
    def test_new_message_json(self, publish_mock):
        # A new message coming through as JSON works fine.
        token = views.new_token(Request(post={}))['token']
        queue = self.storage.new_token()
        self.storage.new_queue(queue, token, 'domain')

        body = {'title': 'title', 'body': 'body'}
        request = Request(matchdict={'queue': queue}, body=json.dumps(body))

        views.message_validator(request)
        response = views.new_message(request)
        message = response['messages'][0]
        publish_mock.assert_called_with(
            request, token, {
                'queue': '/queue/%s/' % queue,
                'timestamp': message['timestamp'],
                'body': body,
                'key': message['key']
            })

    def test_message_validator_urlencoded(self):
        # Messages can be form-urlencoded.
        request = Request(post={'title': 'hi'})
        views.message_validator(request)
        eq_(request.validated['message'], {'title': 'hi'})
        eq_(request.errors, [])

    def test_message_validator_json(self):
        # Messages can be JSON.
        request = Request(body=json.dumps({'title': 'hi'}))
        views.message_validator(request)
        eq_(request.validated['message'], {'title': 'hi'})
        eq_(request.errors, [])

    def test_message_validator_no_body(self):
        # A message with no body is invalid.
        request = Request(post={})
        views.message_validator(request)
        assert 'message' not in request.validated
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:-1], ('body', 'body'))

    def test_message_validator_action_read(self):
        # No validation happens if action=read.
        request = Request(post={'action': 'read', 'key': 'k'})
        views.message_validator(request)
        assert 'message' not in request.validated
        eq_(request.errors, [])

    def test_message_validator_invalid_key(self):
        # Only valid keys are passed to the view.
        valid = {
            'title': 'title',
            'body': 'body',
            'actionUrl': 'actionUrl',
            'replaceId': 'replaceId'
        }

        # All our valid keys make it through.
        request = Request(post=valid)
        views.message_validator(request)
        eq_(request.validated['message'], valid)
        eq_(request.errors, [])

        # Invalid keys are silently discarded.
        invalid = dict(valid)
        invalid['bad'] = 'bad'
        request = Request(post=invalid)
        views.message_validator(request)
        eq_(request.validated['message'], valid)
        eq_(request.errors, [])

    def test_new_message_404(self):
        # POSTing to a queue without an associated token returns a 404.
        request = Request(post={}, matchdict={'queue': 'queue'})
        eq_(views.new_message(request).code, 404)

    @mock.patch('push.views.publish')
    def test_mark_message_read(self, publish_mock):
        # Check that we can mark a message as read.
        token = views.new_token(Request(post={}))['token']
        request = Request(post={
            'action': 'read',
            'key': 'key'
        },
                          matchdict={'queue': token})
        eq_(views.new_message(request)['status'], 'ok')

    def test_mark_message_read_no_key(self):
        request = Request(post={'action': 'read'})
        eq_(views.new_message(request).code, 404)

    @mock.patch('push.views.publish')
    def test_get_message_read(self, publish_mock):
        # Check the format of the read message marker.
        token = views.new_token(Request(post={}))['token']
        request = Request(post={
            'action': 'read',
            'key': 'key'
        },
                          matchdict={'queue': token})
        response = views.new_message(request)['messages'][0]

        req = Request(matchdict={'queue': token})
        self.assertListEqual(
            views.get_messages(req)['messages'],
            [{
                'body': {
                    'read': 'key'
                },
                'queue': '/queue/%s/' % token,
                'key': response['key'],
                'timestamp': str(response['timestamp'])
            }])

        # The format should match the pubsub'd message.
        expected = views.get_messages(req)['messages'][0]
        publish_mock.assert_called_with(request, token, expected)

    @mock.patch('push.tests.mock_queuey.time')
    def test_get_messages(self, time_mock):
        # Check that we can get both of the messages back.
        time_mock.time = [3, 2, 1].pop

        queue = self.queuey.new_queue()
        self.storage.new_queue(queue, 'user', 'domain')

        msg = json.dumps({'queue': queue, 'body': {}})
        key1 = self.queuey.new_message(queue, msg)['messages'][0]['key']
        key2 = self.queuey.new_message(queue, msg)['messages'][0]['key']

        request = Request(params={'token': 'user'}, matchdict={'queue': queue})
        eq_(
            views.get_messages(request), {
                'messages': [{
                    'body': {},
                    'timestamp': '1',
                    'queue': '/queue/%s/' % queue,
                    'key': key1
                }, {
                    'body': {},
                    'queue': '/queue/%s/' % queue,
                    'timestamp': '2',
                    'key': key2
                }]
            })

    def test_get_messages_404(self):
        # Asking for a queue without a matching token returns a 404.
        request = Request(params={'token': 'ok'}, matchdict={'queue': 'queue'})
        eq_(views.get_messages(request).code, 404)

    @mock.patch('push.tests.mock_queuey.time')
    def test_get_messages_since(self, time_mock):
        # Check that we honor the since parameter.
        time_mock.time = [3, 2, 1].pop

        queue = self.queuey.new_queue()
        self.storage.new_queue(queue, 'user', 'domain')

        msg = json.dumps({'queue': queue, 'body': {}})
        key1 = self.queuey.new_message(queue, msg)['messages'][0]['key']
        key2 = self.queuey.new_message(queue, msg)['messages'][0]['key']

        request = Request(params={
            'since': 1,
            'token': 'user'
        },
                          matchdict={'queue': queue})
        eq_(
            views.get_messages(request), {
                'messages': [{
                    'body': {},
                    'timestamp': '2',
                    'queue': '/queue/%s/' % queue,
                    'key': key2
                }]
            })

    def test_get_nodes(self):
        self.storage.add_edge_node('a', 8)
        self.storage.add_edge_node('b', 6)
        self.storage.add_edge_node('c', 7)
        eq_(views.get_nodes(Request()), {'nodes': ['b', 'c', 'a']})
Пример #7
0
class TestMockQueuey(unittest2.TestCase):
    def setUp(self):
        self.mq = MockQueuey()

        patcher = mock.patch('push.tests.mock_queuey.time')
        self.time_mock = patcher.start()
        self.time_mock.time = [3, 2, 1].pop
        self.addCleanup(patcher.stop)

        patcher = mock.patch('push.tests.mock_queuey.uuid')
        self.uuid_mock = patcher.start()
        self.uuid_mock.uuid4.return_value.hex = 'uuid'
        self.addCleanup(patcher.stop)

    def test_new_queue(self):
        eq_(self.mq.new_queue(), 'uuid')
        eq_(self.mq.new_queue(), 'uuid')

    def test_delete_queue(self):
        self.mq.new_queue(queue_name='x')
        assert 'x' in self.mq.db
        self.mq.delete_queue('x')
        assert 'x' not in self.mq.db

    def test_new_message(self):
        queue = self.mq.new_queue()
        eq_(
            self.mq.new_message(queue, 'one'), {
                'messages': [{
                    'timestamp': '1',
                    'key': 'uuid'
                }],
                'partition': 1,
                'status': 'ok'
            })

    def test_get_messages(self):
        queue = self.mq.new_queue()
        self.mq.new_message(queue, 'one')
        self.mq.new_message(queue, 'two')
        eq_(self.mq.get_messages(queue), [
            {
                'body': 'two',
                'message_id': 'uuid',
                'partition': 1,
                'timestamp': '2'
            },
            {
                'body': 'one',
                'partition': 1,
                'message_id': 'uuid',
                'timestamp': '1'
            },
        ])

    def test_get_messages_limit(self):
        queue = self.mq.new_queue()
        self.mq.new_message(queue, 'one')
        self.mq.new_message(queue, 'two')
        eq_(self.mq.get_messages(queue, limit=1), [
            {
                'body': 'two',
                'message_id': 'uuid',
                'partition': 1,
                'timestamp': '2'
            },
        ])

    def test_get_messages_since(self):
        queue = self.mq.new_queue()
        self.mq.new_message(queue, 'one')
        self.mq.new_message(queue, 'two')
        eq_(self.mq.get_messages(queue, since=1), [
            {
                'body': 'two',
                'message_id': 'uuid',
                'partition': 1,
                'timestamp': '2'
            },
        ])

    def test_get_messages_order(self):
        queue = self.mq.new_queue()
        self.mq.new_message(queue, 'one')
        self.mq.new_message(queue, 'two')
        eq_(self.mq.get_messages(queue, order='ascending'), [
            {
                'body': 'one',
                'message_id': 'uuid',
                'partition': 1,
                'timestamp': '1'
            },
            {
                'body': 'two',
                'message_id': 'uuid',
                'partition': 1,
                'timestamp': '2'
            },
        ])
Пример #8
0
class ViewTest(unittest2.TestCase):

    def setUp(self):
        self.config = testing.setUp()

        self.request = Request()
        self.storage = push.storage.mem.Storage()
        self.queuey = MockQueuey()
        self.request.registry['storage'] = self.storage
        self.request.registry['queuey'] = self.queuey

    def tearDown(self):
        testing.tearDown()

    def test_new_token(self):
        # POSTing gets a new token.
        storage_mock = mock.Mock()
        self.request.registry['storage'] = storage_mock
        storage_mock.new_token.return_value = 'TOKEN'

        response = views.new_token(self.request)
        eq_(response, {'token': 'TOKEN', 'queue': '/queue/TOKEN/'})

    def test_has_token_and_domain(self):
        # Check the validator for various problems.
        request = Request(post={'token': ''})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 2)
        eq_(request.errors[0][:2], ('body', 'token'))
        eq_(request.errors[1][:2], ('body', 'domain'))

        request = Request(post={'token': 'ok'})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:2], ('body', 'domain'))

        request = Request(post={'domain': 'ok'})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:2], ('body', 'token'))

        request = Request(post={'token': 'ok', 'domain': ''})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:2], ('body', 'domain'))

        request = Request(post={'token': 't', 'domain': 'r'})
        views.has_token_and_domain(request)
        eq_(len(request.errors), 0)

    def test_new_queue(self):
        # A new queue should be available in storage.
        self.storage.new_token = lambda: 'new-queue'
        request = Request(post={'token': 't', 'domain': 'x.com'})
        response = views.new_queue(request)
        eq_(response, {'queue': '/queue/new-queue/'})

        assert self.storage.user_owns_queue('t', 'new-queue')
        eq_(self.storage.get_user_for_queue('new-queue'), 't')

    def test_delete_queue(self):
        request = Request(post={'token': 't', 'domain': 'x.com'})
        queue = filter(None, views.new_queue(request)['queue'].split('/'))[-1]

        request = Request(params={'token': 't'}, matchdict={'queue': queue})
        views.delete_queue(request)
        eq_(views.get_queues(Request(params={'token': 't'})), {})

    def test_delete_queue_404(self):
        request = Request(post={'token': 't', 'domain': 'x.com'})
        queue = filter(None, views.new_queue(request)['queue'].split('/'))[-1]

        # A valid token with an invalid queue gets a 404.
        request = Request(params={'token': 't'}, matchdict={'queue': 'x'})
        eq_(views.delete_queue(request).code, 404)

        # An invalid token with a valid queue gets a 404.
        request = Request(params={'token': 'x'}, matchdict={'queue': queue})
        eq_(views.delete_queue(request).code, 404)

    def test_has_token(self):
        request = Request(params={'token': 't'})
        eq_(None, views.has_token(request))

        request = Request()
        views.has_token(request)
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:2], ('body', 'token'))

    def test_get_queues(self):
        token = views.new_token(Request())['token']
        request = Request(post={'token': token, 'domain': 'domain'})
        queue = views.new_queue(request)['queue']

        request = Request(params={'token': token})
        response = views.get_queues(request)
        eq_(response, {'domain': queue})

    @mock.patch('push.views.publish')
    @mock.patch('push.tests.mock_queuey.time')
    def test_new_message(self, time_mock, publish_mock):
        # New messages should be in queuey and pubsub.
        token = views.new_token(Request(post={}))['token']
        time_mock.time.return_value = 1
        queue = self.queuey.new_queue()
        self.storage.new_queue(queue, token, 'domain')

        body = {'title': 'title', 'body': 'body'}
        request = Request(matchdict={'queue': queue}, post=body)
        views.message_validator(request)
        response = views.new_message(request)

        # The body is in JSON since queuey just deals with strings.
        self.assertDictEqual(
            self.queuey.get_messages(token)[0],
            {u'body': json.dumps({'queue': queue, 'body': body}),
             u'timestamp': '1',
             u'partition': 1,
             u'message_id': response['messages'][0]['key']})

        publish_mock.assert_called_with(
            request, token, {'queue': '/queue/%s/' % queue,
                             'timestamp': '1',
                             'body': body,
                             'key': response['messages'][0]['key']})

    @mock.patch('push.views.publish')
    def test_new_message_json(self, publish_mock):
        # A new message coming through as JSON works fine.
        token = views.new_token(Request(post={}))['token']
        queue = self.storage.new_token()
        self.storage.new_queue(queue, token, 'domain')

        body = {'title': 'title', 'body': 'body'}
        request = Request(matchdict={'queue': queue},
                          body=json.dumps(body))

        views.message_validator(request)
        response = views.new_message(request)
        message = response['messages'][0]
        publish_mock.assert_called_with(
            request, token, {'queue': '/queue/%s/' % queue,
                             'timestamp': message['timestamp'],
                             'body': body,
                             'key': message['key']})

    def test_message_validator_urlencoded(self):
        # Messages can be form-urlencoded.
        request = Request(post={'title': 'hi'})
        views.message_validator(request)
        eq_(request.validated['message'], {'title': 'hi'})
        eq_(request.errors, [])

    def test_message_validator_json(self):
        # Messages can be JSON.
        request = Request(body=json.dumps({'title': 'hi'}))
        views.message_validator(request)
        eq_(request.validated['message'], {'title': 'hi'})
        eq_(request.errors, [])

    def test_message_validator_no_body(self):
        # A message with no body is invalid.
        request = Request(post={})
        views.message_validator(request)
        assert 'message' not in request.validated
        eq_(len(request.errors), 1)
        eq_(request.errors[0][:-1], ('body', 'body'))

    def test_message_validator_action_read(self):
        # No validation happens if action=read.
        request = Request(post={'action': 'read', 'key': 'k'})
        views.message_validator(request)
        assert 'message' not in request.validated
        eq_(request.errors, [])

    def test_message_validator_invalid_key(self):
        # Only valid keys are passed to the view.
        valid = {'title': 'title',
                 'body': 'body',
                 'actionUrl': 'actionUrl',
                 'replaceId': 'replaceId'}

        # All our valid keys make it through.
        request = Request(post=valid)
        views.message_validator(request)
        eq_(request.validated['message'], valid)
        eq_(request.errors, [])

        # Invalid keys are silently discarded.
        invalid = dict(valid)
        invalid['bad'] = 'bad'
        request = Request(post=invalid)
        views.message_validator(request)
        eq_(request.validated['message'], valid)
        eq_(request.errors, [])

    def test_new_message_404(self):
        # POSTing to a queue without an associated token returns a 404.
        request = Request(post={}, matchdict={'queue': 'queue'})
        eq_(views.new_message(request).code, 404)

    @mock.patch('push.views.publish')
    def test_mark_message_read(self, publish_mock):
        # Check that we can mark a message as read.
        token = views.new_token(Request(post={}))['token']
        request = Request(post={'action': 'read', 'key': 'key'},
                          matchdict={'queue': token})
        eq_(views.new_message(request)['status'], 'ok')

    def test_mark_message_read_no_key(self):
        request = Request(post={'action': 'read'})
        eq_(views.new_message(request).code, 404)

    @mock.patch('push.views.publish')
    def test_get_message_read(self, publish_mock):
        # Check the format of the read message marker.
        token = views.new_token(Request(post={}))['token']
        request = Request(post={'action': 'read', 'key': 'key'},
                          matchdict={'queue': token})
        response = views.new_message(request)['messages'][0]

        req = Request(matchdict={'queue': token})
        self.assertListEqual(views.get_messages(req)['messages'],
                             [{'body': {'read': 'key'},
                               'queue': '/queue/%s/' % token,
                               'key': response['key'],
                               'timestamp': str(response['timestamp'])}])

        # The format should match the pubsub'd message.
        expected = views.get_messages(req)['messages'][0]
        publish_mock.assert_called_with(request, token, expected)

    @mock.patch('push.tests.mock_queuey.time')
    def test_get_messages(self, time_mock):
        # Check that we can get both of the messages back.
        time_mock.time = [3, 2, 1].pop

        queue = self.queuey.new_queue()
        self.storage.new_queue(queue, 'user', 'domain')

        msg = json.dumps({'queue': queue, 'body': {}})
        key1 = self.queuey.new_message(queue, msg)['messages'][0]['key']
        key2 = self.queuey.new_message(queue, msg)['messages'][0]['key']

        request = Request(params={'token': 'user'},
                          matchdict={'queue': queue})
        eq_(views.get_messages(request), {
            'messages': [{'body': {},
                          'timestamp': '1',
                          'queue': '/queue/%s/' % queue,
                          'key': key1},
                         {'body': {},
                          'queue': '/queue/%s/' % queue,
                          'timestamp': '2',
                          'key': key2}]})

    def test_get_messages_404(self):
        # Asking for a queue without a matching token returns a 404.
        request = Request(params={'token': 'ok'}, matchdict={'queue': 'queue'})
        eq_(views.get_messages(request).code, 404)

    @mock.patch('push.tests.mock_queuey.time')
    def test_get_messages_since(self, time_mock):
        # Check that we honor the since parameter.
        time_mock.time = [3, 2, 1].pop

        queue = self.queuey.new_queue()
        self.storage.new_queue(queue, 'user', 'domain')

        msg = json.dumps({'queue': queue, 'body': {}})
        key1 = self.queuey.new_message(queue, msg)['messages'][0]['key']
        key2 = self.queuey.new_message(queue, msg)['messages'][0]['key']

        request = Request(params={'since': 1, 'token': 'user'},
                          matchdict={'queue': queue})
        eq_(views.get_messages(request), {
            'messages': [{'body': {},
                          'timestamp': '2',
                          'queue': '/queue/%s/' % queue,
                          'key': key2}]})

    def test_get_nodes(self):
        self.storage.add_edge_node('a', 8)
        self.storage.add_edge_node('b', 6)
        self.storage.add_edge_node('c', 7)
        eq_(views.get_nodes(Request()), {'nodes': ['b', 'c', 'a']})