Example #1
0
 def test_update_db_fresh(self) -> None:
     files_path = str(Path(gettempdir(), randstr()))
     app = CatApp(redis_url='15', files_path=files_path)
     app.r.flushdb()
     app.update() # type: ignore[no-untyped-call]
     self.assertEqual(app.settings.title, 'CatApp')
     self.assertTrue(Path(files_path).is_dir())
Example #2
0
 def setUp(self) -> None:
     super().setUp()
     self.app = CatApp(redis_url='15', files_path=mkdtemp())
     self.app.r.flushdb()
     self.app.update() # type: ignore
     self.staff_member = self.app.login() # type: ignore
     self.user = self.app.login() # type: ignore
Example #3
0
 def setUp(self):
     super().setUp()
     self.app = CatApp(redis_url='15', files_path=mkdtemp())
     self.app.r.flushdb()
     handlers = [
         (r'/api/cats$', CollectionEndpoint, {'get_collection': lambda: self.app.cats}),
         *make_orderable_endpoints(r'/api/cats', lambda: self.app.cats),
         *make_trashable_endpoints(r'/api/cats/([^/]+)', lambda i: self.app.cats[i])
     ]
     self.server = Server(self.app, handlers, client_path='hello',
                          client_modules_path='node_modules', port=16160)
     self.server.start()
     self.staff_member = self.app.login()
     self.user = self.app.login()
     self.client_user = self.user
Example #4
0
    async def test_update_db_version_first(self):
        Trashable.RETENTION = timedelta(seconds=0.2)
        # NOTE: Tag tmp can be removed on next database update
        self.setup_db('tmp')
        await sleep(1)
        app = CatApp(redis_url='15', files_path=mkdtemp())
        app.update()

        # Update to version 3
        self.assertFalse(app.settings.provider_description)
        # Update to version 4
        self.assertNotIn('trashed', app.settings.json())
        self.assertFalse(app.cats[0].trashed)
        # Update to version 5
        self.assertFalse(hasattr(app.settings, 'favicon'))
        self.assertIsNone(app.settings.icon_small)
        self.assertIsNone(app.settings.icon_large)
        # Update to version 6
        user = app.settings.staff[0]
        self.assertTrue(app.settings.push_vapid_private_key)
        self.assertTrue(app.settings.push_vapid_public_key)
        self.assertIsNotNone(app.activity.subscribers)
        self.assertEqual(user.device_notification_status, 'off')
        self.assertIsNone(user.push_subscription)
        # Update to version 7
        app.user = app.settings.staff[0]
        self.assertEqual([event.type for event in app.activity],
                         ['editable-edit', 'editable-edit', 'meow'])
        # Update to version 8
        cats = list(app.cats.values())
        app.start_empty_trash()
        await sleep(0.1)
        self.assertEqual(list(app.cats.values()), cats)
        await sleep(0.3)
        self.assertEqual(list(app.cats.values()), cats[:1])
        # Update to version 9
        first = app.activity[-1].time.replace(tzinfo=timezone.utc)
        last = app.activity[0].time.replace(tzinfo=timezone.utc)
        self.assertEqual(app.user.create_time, first)
        self.assertEqual(app.user.authenticate_time, last)
        user = app.users[1]
        self.assertEqual(user.create_time, user.authenticate_time)
        self.assertAlmostEqual(user.create_time, app.now(), delta=timedelta(minutes=1))
        self.assertGreater(user.create_time, last)
Example #5
0
    async def test_update_db_version_previous(self):
        self.setup_db('0.38.1')
        await sleep(1)
        app = CatApp(redis_url='15', files_path=mkdtemp())
        app.update() # type: ignore

        app.user = app.settings.staff[0]
        first = app.activity[-1].time.replace(tzinfo=timezone.utc)
        last = app.cats[1].activity[0].time.replace(tzinfo=timezone.utc)
        self.assertEqual(app.user.create_time, first)
        self.assertEqual(app.user.authenticate_time, last)
        user = app.users[1]
        self.assertEqual(user.create_time, user.authenticate_time)
        self.assertAlmostEqual(user.create_time, app.now(), delta=timedelta(minutes=1))
        self.assertGreater(user.create_time, last)
Example #6
0
 def test_init_redis_url_invalid(self):
     with self.assertRaisesRegex(micro.ValueError, 'redis_url_invalid'):
         CatApp(redis_url='//localhost:foo')
Example #7
0
 def test_login_no_redis(self):
     app = CatApp(redis_url='//localhost:16160')
     with self.assertRaises(RedisError):
         app.login()
Example #8
0
class ServerTest(ServerTestCase):
    def setUp(self):
        super().setUp()
        self.app = CatApp(redis_url='15', files_path=mkdtemp())
        self.app.r.flushdb()
        handlers = [
            (r'/api/cats$', CollectionEndpoint, {'get_collection': lambda: self.app.cats}),
            *make_orderable_endpoints(r'/api/cats', lambda: self.app.cats),
            *make_trashable_endpoints(r'/api/cats/([^/]+)', lambda i: self.app.cats[i])
        ]
        self.server = Server(self.app, handlers, client_path='hello',
                             client_modules_path='node_modules', port=16160)
        self.server.start()
        self.staff_member = self.app.login()
        self.user = self.app.login()
        self.client_user = self.user

    @gen_test
    async def test_availability(self):
        file_url = await self.app.files.write(b'Meow!', 'text/plain')

        # UI
        await self.request('/')
        await self.request('/manifest.webmanifest')
        await self.request(
            '/log-client-error', method='POST',
            body='{"type": "Error", "stack": "micro.UI.prototype.createdCallback", "url": "/"}')

        # API
        await self.request('/api/login', method='POST', body='')
        await self.request('/api/users/' + self.user.id)
        await self.request('/api/users/' + self.user.id, method='POST', body='{"name": "Happy"}')
        await self.request('/api/users/{}'.format(self.app.user.id), method='PATCH',
                           body='{"op": "disable_notifications"}')
        await self.request('/api/settings')
        await self.request('/api/analytics/referrals', method='POST',
                           body='{"url": "https://example.org/"}')
        await self.request(self.server.rewrite(file_url))
        await self.request('/files', method='POST', body=b'<svg />',
                           headers={'Content-Type': 'image/svg+xml'})

        # API (generic)
        cat = self.app.cats.create()
        await self.request('/api/cats/move', method='POST',
                           body='{{"item_id": "{}", "to_id": null}}'.format(cat.id))
        await self.request('/api/cats/{}/trash'.format(cat.id), method='POST', body='')
        await self.request('/api/cats/{}/restore'.format(cat.id), method='POST', body='')

        # API (as staff member)
        self.client_user = self.staff_member
        await self.request(
            '/api/settings', method='POST',
            body='{"title": "CatzApp", "icon": "http://example.org/static/icon.svg"}')
        await self.request('/api/activity/v2')
        await self.request('/api/activity/v2', method='PATCH', body='{"op": "subscribe"}')
        await self.request('/api/activity/v2', method='PATCH', body='{"op": "unsubscribe"}')
        await self.request('/api/analytics/stats/users')
        await self.request('/api/analytics/referrals')

    @gen_test
    def test_endpoint_request(self):
        response = yield self.request('/api/users/' + self.user.id)
        user = json.loads(response.body.decode())
        self.assertEqual(user.get('__type__'), 'User')
        self.assertEqual(user.get('id'), self.user.id)

    @gen_test
    def test_endpoint_request_invalid_body(self):
        with self.assertRaises(HTTPClientError) as cm:
            yield self.request('/api/users/' + self.user.id, method='POST', body='foo')
        e = cm.exception
        self.assertEqual(e.code, http.client.BAD_REQUEST)

    @gen_test
    def test_endpoint_request_key_error(self):
        with self.assertRaises(HTTPClientError) as cm:
            yield self.request('/api/users/foo')
        self.assertEqual(cm.exception.code, http.client.NOT_FOUND)

    @gen_test
    def test_endpoint_request_input_error(self):
        with self.assertRaises(HTTPClientError) as cm:
            yield self.request('/api/users/' + self.user.id, method='POST', body='{"name": 42}')
        self.assertEqual(cm.exception.code, http.client.BAD_REQUEST)
        error = json.loads(cm.exception.response.body.decode())
        self.assertEqual(error.get('__type__'), 'InputError')

    @gen_test
    def test_endpoint_request_value_error(self):
        with self.assertRaises(HTTPClientError) as cm:
            yield self.request('/api/settings', method='POST',
                               body='{"provider_description": {"en": " "}}')
        self.assertEqual(cm.exception.code, http.client.BAD_REQUEST)
        self.assertIn('provider_description_bad_type', cm.exception.response.body.decode())

    @gen_test
    async def test_collection_endpoint_get(self):
        self.app.cats.create(name='Happy')
        self.app.cats.create(name='Grumpy')
        self.app.cats.create(name='Long')
        response = await self.request('/api/cats?slice=1:')
        cats = json.loads(response.body.decode())
        self.assertEqual(cats.get('count'), 3)
        self.assertEqual([cat.get('name') for cat in cats.get('items', [])], ['Grumpy', 'Long'])
        self.assertEqual(cats.get('slice'), [1, 3])