diff options
Diffstat (limited to '')
| -rw-r--r-- | .coveragerc | 14 | ||||
| -rw-r--r-- | Pipfile | 2 | ||||
| -rw-r--r-- | app_test.py | 519 | ||||
| -rw-r--r-- | tests/__init__.py | 43 | ||||
| -rw-r--r-- | tests/test_api.py | 25 | ||||
| -rw-r--r-- | tests/test_api_bot_snake.py | 42 | ||||
| -rw-r--r-- | tests/test_api_bot_tags.py | 72 | ||||
| -rw-r--r-- | tests/test_api_bot_users.py | 18 | ||||
| -rw-r--r-- | tests/test_database.py | 31 | ||||
| -rw-r--r-- | tests/test_decorators.py | 25 | ||||
| -rw-r--r-- | tests/test_jams.py | 11 | ||||
| -rw-r--r-- | tests/test_mixins.py | 66 | ||||
| -rw-r--r-- | tests/test_oauth_backend.py | 39 | ||||
| -rw-r--r-- | tests/test_roots.py | 84 | ||||
| -rw-r--r-- | tests/test_rst.py | 11 | ||||
| -rw-r--r-- | tests/test_staff.py | 16 | ||||
| -rw-r--r-- | tests/test_utilities.py | 25 | ||||
| -rw-r--r-- | tests/test_websocket.py | 12 | ||||
| -rw-r--r-- | tests/test_wiki.py | 34 | ||||
| -rw-r--r-- | tox.ini | 2 | 
20 files changed, 568 insertions, 523 deletions
| diff --git a/.coveragerc b/.coveragerc index aee4d336..60ef892f 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,15 @@  [run] -omit = /usr/*, gunicorn_config.py, deploy.py, app_test.py, app.py, pysite/websockets.py, pysite/views/*__init__.py, pysite/route_manager.py +omit = /usr/*, +       gunicorn_config.py, +       deploy.py, +       app_test.py, +       app.py, +       pysite/websockets.py, +       pysite/views/*__init__.py, +       pysite/route_manager.py, +       pysite/migrations/runner.py  [report] -exclude_lines = return jsonify +exclude_lines = return jsonify, +                raise RuntimeError, +                return @@ -39,7 +39,7 @@ python_version = "3.6"  [scripts]  start = "gunicorn -w 12 -b 0.0.0.0:10012 -c gunicorn_config.py --log-level info -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker app:app"  lint = "python -m flake8" -test = "py.test app_test.py --cov pysite --cov-report term-missing -v" +test = "py.test tests --cov pysite --cov-report term-missing -v"  clean = "rm -rf __pycache__ htmlcov .coverage .pytest_cache"  build = "docker build -t pythondiscord/site:latest -f docker/Dockerfile ."  push = "docker push pythondiscord/site:latest" diff --git a/app_test.py b/app_test.py deleted file mode 100644 index bc565112..00000000 --- a/app_test.py +++ /dev/null @@ -1,519 +0,0 @@ - -import json -import os - -from flask import Blueprint -from flask_testing import TestCase - -os.environ["BOT_API_KEY"] = "abcdefg"  # This is a constant, must be done first -try: -    del os.environ["FLASK_DEBUG"]  # Some unit tests fail if this is set -except KeyError: -    pass - -from app import manager -from gunicorn_config import _when_ready as when_ready - -from pysite.constants import DISCORD_OAUTH_REDIRECT, DISCORD_OAUTH_AUTHORIZED - -when_ready() - -manager.app.tests_blueprint = Blueprint("tests", __name__) -manager.load_views(manager.app.tests_blueprint, "pysite/views/tests") -manager.app.register_blueprint(manager.app.tests_blueprint) -app = manager.app - -app.config["WTF_CSRF_CHECK_DEFAULT"] = False - - -class SiteTest(TestCase): -    """ Extend TestCase with flask app instantiation """ - -    def create_app(self): -        """ Add flask app configuration settings """ -        server_name = 'pytest.local' - -        app.config['TESTING'] = True -        app.config['LIVESERVER_TIMEOUT'] = 10 -        app.config['SERVER_NAME'] = server_name -        app.config['API_SUBDOMAIN'] = f'http://api.{server_name}' -        app.config['STAFF_SUBDOMAIN'] = f'http://staff.{server_name}' -        app.config['WIKI_SUBDOMAIN'] = f'http://wiki.{server_name}' -        app.allow_subdomain_redirects = True - -        return app - - -class RootEndpoint(SiteTest): -    """ Test cases for the root endpoint and error handling """ - -    def test_index(self): -        """ Check the root path responds with 200 OK """ -        response = self.client.get('/', 'http://pytest.local') -        self.assertEqual(response.status_code, 200) - -    def test_info_index(self): -        """ Check the info index path responds with a 301 """ -        response = self.client.get('/info') -        self.assertEqual(response.status_code, 301) - -    def test_info_help(self): -        """ Check the info help path responds with 200 OK """ -        response = self.client.get('/info/help') -        self.assertEqual(response.status_code, 200) - -    def test_info_resources(self): -        """ Check the info resources path responds with 200 OK """ -        response = self.client.get('/info/resources') -        self.assertEqual(response.status_code, 200) - -    def test_info_resources_json(self): -        """ Check the resources JSON loads correctly """ -        response = self.client.get('/static/resources.json') -        self.assertEqual(response.status_code, 200) -        self.assertIsInstance(json.loads(response.data), dict) - -    def test_info_rules(self): -        """ Check the info rules path responds with 200 OK """ -        response = self.client.get('/info/help') -        self.assertEqual(response.status_code, 200) - -    def test_not_found(self): -        """ Check paths without handlers returns 404 Not Found """ -        response = self.client.get('/nonexistentpath') -        self.assertEqual(response.status_code, 404) - -    def test_error(self): -        """ Check the /error/XYZ page """ -        response = self.client.get('/error/418') -        self.assertEqual(response.status_code, 418) - -    def test_invite(self): -        """ Check invite redirects """ -        response = self.client.get('/invite') -        self.assertEqual(response.status_code, 302) - -    def test_ws_test(self): -        """ Check ws_test responds """ -        response = self.client.get('/ws_test') -        self.assertEqual(response.status_code, 200) - -    def test_oauth_redirects(self): -        """ Check oauth redirects """ -        response = self.client.get(DISCORD_OAUTH_REDIRECT) -        self.assertEqual(response.status_code, 302) - -    def test_oauth_logout(self): -        """ Check oauth redirects """ -        response = self.client.get('/auth/logout') -        self.assertEqual(response.status_code, 302) - -    def test_oauth_authorized(self): -        """ Check oauth authorization """ -        response = self.client.get(DISCORD_OAUTH_AUTHORIZED) -        self.assertEqual(response.status_code, 302) - -    def test_stats_redirect(self): -        """ Check stats path redirects """ -        response = self.client.get('/stats') -        self.assertEqual(response.status_code, 302) - -    def test_500_easter_egg(self): -        """ Check the status of the /500 page""" -        response = self.client.get("/500") -        self.assertEqual(response.status_code, 500) - - -class WikiEndpoints(SiteTest): -    """ Test cases for the wiki subdomain """ -    def test_wiki_edit(self): -        """Test that the wiki edit page redirects to login""" -        response = self.client.get("/edit/page", app.config['WIKI_SUBDOMAIN']) -        self.assertEqual(response.status_code, 302) - -    def test_wiki_edit_post_empty_request(self): -        """Empty request should redirect to login""" -        response = self.client.post("/edit/page", app.config['WIKI_SUBDOMAIN']) -        self.assertEqual(response.status_code, 302) - -    def test_wiki_history(self): -        """Test the history show""" -        response = self.client.get("/history/show/blahblah-non-existant-page", app.config['WIKI_SUBDOMAIN']) -        self.assertEqual(response.status_code, 404) # Test that unknown routes 404 - -    def test_wiki_diff(self): -        """Test whether invalid revision IDs error""" -        response = self.client.get("/history/compare/ABC/XYZ", app.config['WIKI_SUBDOMAIN']) -        self.assertEqual(response.status_code, 404) # Test that unknown revisions 404 - - -class ApiEndpoints(SiteTest): -    """ Test cases for the api subdomain """ -    def test_api_unknown_route(self): -        """ Check api unknown route """ -        response = self.client.get('/', app.config['API_SUBDOMAIN']) -        self.assertEqual(response.json, {'error_code': 0, 'error_message': 'Unknown API route'}) -        self.assertEqual(response.status_code, 404) - -    def test_api_healthcheck(self): -        """ Check healthcheck url responds """ -        response = self.client.get('/healthcheck', app.config['API_SUBDOMAIN']) -        self.assertEqual(response.json, {'status': 'ok'}) -        self.assertEqual(response.status_code, 200) - -    def test_snake_endpoints(self): -        """ -        Tests the following endpoints: -            - snake_movies -            - snake_quiz -            - snake_names -            - snake_idioms -            - snake_facts -        """ - -        os.environ['BOT_API_KEY'] = 'abcdefg' -        headers = {'X-API-Key': 'abcdefg', 'Content-Type': 'application/json'} - -        # GET method - get snake fact -        response = self.client.get('/bot/snake_facts', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 200) -        self.assertEqual(type(response.json), str) - -        # GET method - get snake idiom -        response = self.client.get('/bot/snake_idioms', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 200) -        self.assertEqual(type(response.json), str) - -        # GET method - get snake quiz -        response = self.client.get('/bot/snake_quiz', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 200) -        self.assertEqual(type(response.json), dict) - -        # GET method - get snake name -        response = self.client.get('/bot/snake_names', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 200) -        self.assertEqual(type(response.json), dict) - -        # GET method - get all snake names -        response = self.client.get('/bot/snake_names?get_all=True', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 200) -        self.assertEqual(type(response.json), list) - -    def test_api_tags(self): -        """ Check tag API """ -        os.environ['BOT_API_KEY'] = 'abcdefg' -        headers = {'X-API-Key': 'abcdefg', 'Content-Type': 'application/json'} - -        post_data = json.dumps({ -            'tag_name': 'testing', -            'tag_content': 'testing' -        }) - -        get_data = json.dumps({ -            'tag_name': 'testing' -        }) - -        bad_data = json.dumps({ -            'not_a_valid_key': 'gross_faceman' -        }) - -        # POST method - no headers -        response = self.client.post('/bot/tags', app.config['API_SUBDOMAIN']) -        self.assertEqual(response.status_code, 401) - -        # POST method - no data -        response = self.client.post('/bot/tags', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 400) - -        # POST method - bad data -        response = self.client.post('/bot/tags', app.config['API_SUBDOMAIN'], headers=headers, data=bad_data) -        self.assertEqual(response.status_code, 400) - -        # POST method - save tag -        response = self.client.post('/bot/tags', app.config['API_SUBDOMAIN'], headers=headers, data=post_data) -        self.assertEqual(response.status_code, 200) -        self.assertEqual(response.json, {"success": True}) - -        # GET method - no headers -        response = self.client.get('/bot/tags', app.config['API_SUBDOMAIN']) -        self.assertEqual(response.status_code, 401) - -        # GET method - get all tags -        response = self.client.get('/bot/tags', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 200) -        self.assertEqual(type(response.json), list) - -        # GET method - get specific tag -        response = self.client.get('/bot/tags?tag_name=testing', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.json, { -            'tag_content': 'testing', -            'tag_name': 'testing' -        }) -        self.assertEqual(response.status_code, 200) - -        # DELETE method - no headers -        response = self.client.delete('/bot/tags', app.config['API_SUBDOMAIN']) -        self.assertEqual(response.status_code, 401) - -        # DELETE method - no data -        response = self.client.delete('/bot/tags', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 400) - -        # DELETE method - bad data -        response = self.client.delete('/bot/tags', app.config['API_SUBDOMAIN'], headers=headers, data=bad_data) -        self.assertEqual(response.status_code, 400) - -        # DELETE method - delete the testing tag -        response = self.client.delete('/bot/tags', app.config['API_SUBDOMAIN'], headers=headers, data=get_data) -        self.assertEqual(response.status_code, 200) -        self.assertEqual(response.json, {"success": True}) - -    def test_api_user(self): -        """ Check insert user """ - -        os.environ['BOT_API_KEY'] = 'abcdefg' -        headers = {'X-API-Key': 'abcdefg', 'Content-Type': 'application/json'} -        single_data = json.dumps({'user_id': "1234", 'roles': ["5678"], "username": "test", "discriminator": "0000"}) -        list_data = json.dumps([{'user_id': "1234", 'roles': ["5678"], "username": "test", "discriminator": "0000"}]) - -        response = self.client.get('/bot/users', app.config['API_SUBDOMAIN'], headers=headers) -        self.assertEqual(response.status_code, 405) - -        response = self.client.post('/bot/users', app.config['API_SUBDOMAIN'], headers=headers, data=single_data) -        self.assertTrue("inserted" in response.json) - -        response = self.client.post('/bot/users', app.config['API_SUBDOMAIN'], headers=headers, data=list_data) -        self.assertTrue("inserted" in response.json) - -    def test_api_route_errors(self): -        """ Check api route errors """ -        from pysite.base_route import APIView -        from pysite.constants import ErrorCodes - -        av = APIView() -        av.error(ErrorCodes.unauthorized) -        av.error(ErrorCodes.bad_data_format) - -    def test_not_found(self): -        """ Check paths without handlers returns 404 Not Found """ -        response = self.client.get('/nonexistentpath') -        self.assertEqual(response.status_code, 404) - - -class StaffEndpoints(SiteTest): -    """ Test cases for staff subdomain """ -    def test_staff_view(self): -        """ Check staff view redirects """ -        response = self.client.get('/', app.config['STAFF_SUBDOMAIN']) -        self.assertEqual(response.status_code, 302) - - -class Utilities(SiteTest): -    """ Test cases for internal utility code """ -    def test_error_view_runtime_error(self): -        """ Check that wrong values for error view setup raises runtime error """ -        import pysite.base_route - -        ev = pysite.base_route.ErrorView() -        try: -            ev.setup(manager, 'sdfsdf') -        except RuntimeError: -            return True -        raise Exception('Expected runtime error on setup() when giving wrongful arguments') - -    def test_websocket_callback(self): -        """ Check that websocket default callbacks work """ -        import pysite.websockets - -        class TestWS(pysite.websockets.WS): -            pass - -        try: -            TestWS(None).on_message("test") -            return False -        except NotImplementedError: -            return True - - -class MixinTests(SiteTest): -    """ Test cases for mixins """ - -    def test_handler_5xx(self): -        """ Check error view returns error message """ -        from werkzeug.exceptions import InternalServerError -        from pysite.views.error_handlers import http_5xx - -        error_view = http_5xx.Error500View() -        error_message = error_view.get(InternalServerError) -        self.assertEqual(error_message[1], 500) - -    def test_route_view_runtime_error(self): -        """ Check that wrong values for route view setup raises runtime error """ -        from pysite.base_route import RouteView - -        rv = RouteView() -        try: -            rv.setup(manager, 'sdfsdf') -        except RuntimeError: -            return True -        raise Exception('Expected runtime error on setup() when giving wrongful arguments') - -    def test_route_manager(self): -        """ Check route manager """ -        from pysite.route_manager import RouteManager - -        os.environ['WEBPAGE_SECRET_KEY'] = 'super_secret' -        rm = RouteManager() -        self.assertEqual(rm.app.secret_key, 'super_secret') - -    def test_oauth_property(self): -        """ Make sure the oauth property works""" -        from flask import Blueprint - -        from pysite.route_manager import RouteView -        from pysite.oauth import OauthBackend - -        class TestRoute(RouteView): -            name = "test" -            path = "/test" - -        tr = TestRoute() -        tr.setup(manager, Blueprint("test", "test_name")) -        self.assertIsInstance(tr.oauth, OauthBackend) - -    def test_user_data_property(self): -        """ Make sure the user_data property works""" -        from flask import Blueprint - -        from pysite.route_manager import RouteView - -        class TestRoute(RouteView): -            name = "test" -            path = "/test" - -        tr = TestRoute() -        tr.setup(manager, Blueprint("test", "test_name")) -        self.assertIs(tr.user_data, None) - -    def test_logged_in_property(self): -        """ Make sure the user_data property works""" -        from flask import Blueprint - -        from pysite.route_manager import RouteView - -        class TestRoute(RouteView): -            name = "test" -            path = "/test" - -        tr = TestRoute() -        tr.setup(manager, Blueprint("test", "test_name")) -        self.assertIs(tr.logged_in, False) - - -class DecoratorTests(SiteTest): -    def test_decorator_api_json(self): -        """ Check the json validation decorator """ -        from pysite.decorators import api_params -        from pysite.constants import ValidationTypes -        from schema import Schema - -        SCHEMA = Schema([{"user_id": int, "role": int}]) - -        @api_params(schema=SCHEMA, validation_type=ValidationTypes.json) -        def try_json_type(data): -            return data - -        try: -            try_json_type("not json") -        except Exception as error_message: -            self.assertEqual(type(error_message), AttributeError) - -    def test_decorator_params(self): -        """ Check the params validation decorator """ - -        response = self.client.post('/testparams?test=params') - -        self.assertEqual(response.status_code, 200) -        self.assertEqual(response.json, [{'test': 'params'}]) - - -class DatabaseTests(SiteTest): -    """ Test cases for the database module """ -    def test_table_actions(self): -        import string -        import secrets -        from pysite.database import RethinkDB - -        alphabet = string.ascii_letters -        generated_table_name = ''.join(secrets.choice(alphabet) for i in range(8)) - -        rdb = RethinkDB() -        # Create table name and expect it to work -        result = rdb.create_table(generated_table_name) -        self.assertEqual(result, True) - -        # Create the same table name and expect it to already exist -        result = rdb.create_table(generated_table_name) -        self.assertEqual(result, False) - -        # Drop table and expect it to work -        result = rdb.drop_table(generated_table_name) -        self.assertEqual(result, True) - -        # Drop the same table and expect it to already be gone -        result = rdb.drop_table(generated_table_name) -        self.assertEqual(result, False) - -        # This is to get some more code coverage -        self.assertEqual(rdb.teardown_request('_'), None) - - -class TestWebsocketEcho(SiteTest): -    """ Test cases for the echo endpoint """ -    def testEcho(self): -        """ Check rudimentary websockets handlers work """ -        from geventwebsocket.websocket import WebSocket -        from pysite.views.ws.echo import EchoWebsocket -        ew = EchoWebsocket(WebSocket) -        ew.on_open() -        ew.on_message('message') -        ew.on_close() - - -class TestOauthBackend(SiteTest): -    """ Test cases for the oauth.py file """ - -    def test_get(self): -        """ Make sure the get function returns nothing """ -        self.assertIs(manager.oauth_backend.get(), None) - -    def test_delete(self): -        """ Make sure the delete function returns nothing """ -        self.assertIs(manager.oauth_backend.delete(None), None) - -    def test_logout(self): -        """ Make sure at least apart of logout is working :/ """ -        self.assertIs(manager.oauth_backend.logout(), None) - -    def test_add_user(self): -        """ Make sure function adds values to database and session """ -        from flask import session - -        from pysite.constants import OAUTH_DATABASE - -        sess_id = "hey bro wazup" -        fake_token = {"access_token": "access_token", "id": sess_id, "refresh_token": "refresh_token", "expires_at": 5} -        fake_user = {"id": 1235678987654321, "username": "Zwacky", "discriminator": "#6660", "email": "[email protected]"} -        manager.db.conn = manager.db.get_connection() -        manager.oauth_backend.add_user(fake_token, fake_user, sess_id) - -        self.assertEqual(sess_id, session["session_id"]) -        fake_token["snowflake"] = fake_user["id"] -        fake_user["user_id"] = fake_user["id"] -        del fake_user["id"] -        self.assertEqual(fake_token, manager.db.get(OAUTH_DATABASE, sess_id)) -        self.assertEqual(fake_user, manager.db.get("users", fake_user["user_id"])) - -        manager.db.delete(OAUTH_DATABASE, sess_id) -        manager.db.delete("users", fake_user["user_id"]) -        manager.db.teardown_request(None) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..84e69105 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,43 @@ +import json +import os + +from flask import Blueprint +from flask_testing import TestCase + +os.environ["BOT_API_KEY"] = "abcdefg"  # This is a constant, must be done first +os.environ["PAPERTRAIL_ADDRESS"] = 'localhost'  # satisfies coverage +os.environ["DATADOG_ADDRESS"] = 'localhost'  # satisfies coverage + +if "FLASK_DEBUG" in os.environ: +    del os.environ["FLASK_DEBUG"]  # Some unit tests fail if this is set + +from app import manager +from gunicorn_config import _when_ready as when_ready + +when_ready() + +manager.app.tests_blueprint = Blueprint("tests", __name__) +manager.load_views(manager.app.tests_blueprint, "pysite/views/tests") +manager.app.register_blueprint(manager.app.tests_blueprint) +app = manager.app + +app.config["WTF_CSRF_CHECK_DEFAULT"] = False + + +class SiteTest(TestCase): +    """ Extend TestCase with flask app instantiation """ + +    def create_app(self): +        """ Add flask app configuration settings """ +        server_name = 'pytest.local' + +        app.config['TESTING'] = True +        app.config['LIVESERVER_TIMEOUT'] = 10 +        app.config['SERVER_NAME'] = server_name +        app.config['API_SUBDOMAIN'] = f'http://api.{server_name}' +        app.config['STAFF_SUBDOMAIN'] = f'http://staff.{server_name}' +        app.config['WIKI_SUBDOMAIN'] = f'http://wiki.{server_name}' +        app.config['TEST_HEADER'] = {'X-API-Key': 'abcdefg', 'Content-Type': 'application/json'} +        app.allow_subdomain_redirects = True + +        return app diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 00000000..a0b22846 --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,25 @@ +from tests import SiteTest, app + +class ApiEndpointsRootEndpoints(SiteTest): +    """ Test cases for the api subdomain """ +    def test_api_unknown_route(self): +        """ Check api unknown route """ +        response = self.client.get('/', app.config['API_SUBDOMAIN']) +        self.assertEqual(response.json, {'error_code': 0, 'error_message': 'Unknown API route'}) +        self.assertEqual(response.status_code, 404) + +    def test_api_healthcheck(self): +        """ Check healthcheck url responds """ +        response = self.client.get('/healthcheck', app.config['API_SUBDOMAIN']) +        self.assertEqual(response.json, {'status': 'ok'}) +        self.assertEqual(response.status_code, 200) + +    def test_api_route_errors(self): +        """ Check api route errors """ +        from pysite.base_route import APIView +        from pysite.constants import ErrorCodes + +        av = APIView() +        av.error(ErrorCodes.unauthorized) +        av.error(ErrorCodes.bad_data_format) + diff --git a/tests/test_api_bot_snake.py b/tests/test_api_bot_snake.py new file mode 100644 index 00000000..b5aa3bab --- /dev/null +++ b/tests/test_api_bot_snake.py @@ -0,0 +1,42 @@ +import os +from tests import SiteTest, app + +class ApiBotSnakeEndpoints(SiteTest): +    """ +    Tests the following endpoints: +        - snake_movies +        - snake_quiz +        - snake_names +        - snake_idioms +        - snake_facts +    """ + +    def test_snake_facts(self): +        # GET method - get snake fact +        response = self.client.get('/bot/snake_facts', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(type(response.json), str) + +    def test_snake_idiom(self): +        # GET method - get snake idiom +        response = self.client.get('/bot/snake_idioms', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(type(response.json), str) + +    def test_snake_quiz(self): +        # GET method - get snake quiz +        response = self.client.get('/bot/snake_quiz', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(type(response.json), dict) + +    def test_snake_names(self): +        # GET method - get snake name +        response = self.client.get('/bot/snake_names', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(type(response.json), dict) + +    def test_snake_names_all(self): +        # GET method - get all snake names +        response = self.client.get('/bot/snake_names?get_all=True', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(type(response.json), list) diff --git a/tests/test_api_bot_tags.py b/tests/test_api_bot_tags.py new file mode 100644 index 00000000..66940f7e --- /dev/null +++ b/tests/test_api_bot_tags.py @@ -0,0 +1,72 @@ +import os +import json +from tests import SiteTest, app + +class ApiBotTagsEndpoint(SiteTest): + +    def test_api_tags(self): +        """ Check tag API """ + +        post_data = json.dumps({ +            'tag_name': 'testing', +            'tag_content': 'testing' +        }) + +        get_data = json.dumps({ +            'tag_name': 'testing' +        }) + +        bad_data = json.dumps({ +            'not_a_valid_key': 'gross_faceman' +        }) + +        # POST method - no headers +        response = self.client.post('/bot/tags', app.config['API_SUBDOMAIN']) +        self.assertEqual(response.status_code, 401) + +        # POST method - no data +        response = self.client.post('/bot/tags', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 400) + +        # POST method - bad data +        response = self.client.post('/bot/tags', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER'], data=bad_data) +        self.assertEqual(response.status_code, 400) + +        # POST method - save tag +        response = self.client.post('/bot/tags', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER'], data=post_data) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(response.json, {"success": True}) + +        # GET method - no headers +        response = self.client.get('/bot/tags', app.config['API_SUBDOMAIN']) +        self.assertEqual(response.status_code, 401) + +        # GET method - get all tags +        response = self.client.get('/bot/tags', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(type(response.json), list) + +        # GET method - get specific tag +        response = self.client.get('/bot/tags?tag_name=testing', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.json, { +            'tag_content': 'testing', +            'tag_name': 'testing' +        }) +        self.assertEqual(response.status_code, 200) + +        # DELETE method - no headers +        response = self.client.delete('/bot/tags', app.config['API_SUBDOMAIN']) +        self.assertEqual(response.status_code, 401) + +        # DELETE method - no data +        response = self.client.delete('/bot/tags', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 400) + +        # DELETE method - bad data +        response = self.client.delete('/bot/tags', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER'], data=bad_data) +        self.assertEqual(response.status_code, 400) + +        # DELETE method - delete the testing tag +        response = self.client.delete('/bot/tags', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER'], data=get_data) +        self.assertEqual(response.status_code, 200) +        self.assertEqual(response.json, {"success": True}) diff --git a/tests/test_api_bot_users.py b/tests/test_api_bot_users.py new file mode 100644 index 00000000..85390210 --- /dev/null +++ b/tests/test_api_bot_users.py @@ -0,0 +1,18 @@ +import os +import json +from tests import SiteTest, app + +class ApiBotUsersEndpoint(SiteTest): +    def test_api_user(self): +        """ Check insert user """ +        single_data = json.dumps({'user_id': "1234", 'roles': ["5678"], "username": "test", "discriminator": "0000"}) +        list_data = json.dumps([{'user_id': "1234", 'roles': ["5678"], "username": "test", "discriminator": "0000"}]) + +        response = self.client.get('/bot/users', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER']) +        self.assertEqual(response.status_code, 405) + +        response = self.client.post('/bot/users', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER'], data=single_data) +        self.assertTrue("inserted" in response.json) + +        response = self.client.post('/bot/users', app.config['API_SUBDOMAIN'], headers=app.config['TEST_HEADER'], data=list_data) +        self.assertTrue("inserted" in response.json) diff --git a/tests/test_database.py b/tests/test_database.py new file mode 100644 index 00000000..237cd68d --- /dev/null +++ b/tests/test_database.py @@ -0,0 +1,31 @@ +from tests import SiteTest + +class DatabaseTests(SiteTest): +    """ Test cases for the database module """ +    def test_table_actions(self): +        import string +        import secrets +        from pysite.database import RethinkDB + +        alphabet = string.ascii_letters +        generated_table_name = ''.join(secrets.choice(alphabet) for i in range(8)) + +        rdb = RethinkDB() +        # Create table name and expect it to work +        result = rdb.create_table(generated_table_name) +        self.assertEqual(result, True) + +        # Create the same table name and expect it to already exist +        result = rdb.create_table(generated_table_name) +        self.assertEqual(result, False) + +        # Drop table and expect it to work +        result = rdb.drop_table(generated_table_name) +        self.assertEqual(result, True) + +        # Drop the same table and expect it to already be gone +        result = rdb.drop_table(generated_table_name) +        self.assertEqual(result, False) + +        # This is to get some more code coverage +        self.assertEqual(rdb.teardown_request('_'), None) diff --git a/tests/test_decorators.py b/tests/test_decorators.py new file mode 100644 index 00000000..a73052e4 --- /dev/null +++ b/tests/test_decorators.py @@ -0,0 +1,25 @@ +from tests import SiteTest + +class DecoratorTests(SiteTest): +    def test_decorator_api_json(self): +        """ Check the json validation decorator """ +        from pysite.decorators import api_params +        from pysite.constants import ValidationTypes +        from schema import Schema + +        SCHEMA = Schema([{"user_id": int, "role": int}]) + +        @api_params(schema=SCHEMA, validation_type=ValidationTypes.json) +        def try_json_type(data): +            return data + +        with self.assertRaises(AttributeError): +            try_json_type("not json") + +    def test_decorator_params(self): +        """ Check the params validation decorator """ + +        response = self.client.post('/testparams?test=params') + +        self.assertEqual(response.status_code, 200) +        self.assertEqual(response.json, [{'test': 'params'}]) diff --git a/tests/test_jams.py b/tests/test_jams.py new file mode 100644 index 00000000..cf0d8952 --- /dev/null +++ b/tests/test_jams.py @@ -0,0 +1,11 @@ +from tests import SiteTest, app + +class JamsEndpoint(SiteTest): +    """ Test cases for the root endpoint and error handling """ + +    def test_jams_page(self): +        """ Check the jams path responds with 200 OK """ +        response = self.client.get('/jams', 'http://'+app.config['SERVER_NAME']) +        self.assertEqual(response.status_code, 200) + + diff --git a/tests/test_mixins.py b/tests/test_mixins.py new file mode 100644 index 00000000..58118ae0 --- /dev/null +++ b/tests/test_mixins.py @@ -0,0 +1,66 @@ +import os +from tests import SiteTest, manager + +class MixinTests(SiteTest): +    """ Test cases for mixins """ + +    def test_handler_5xx(self): +        """ Check error view returns error message """ +        from werkzeug.exceptions import InternalServerError +        from pysite.views.error_handlers import http_5xx + +        error_view = http_5xx.Error500View() +        error_message = error_view.get(InternalServerError) +        self.assertEqual(error_message[1], 500) + +    def test_route_view_runtime_error(self): +        """ Check that wrong values for route view setup raises runtime error """ +        from pysite.base_route import RouteView + +        rv = RouteView() + +        with self.assertRaises(RuntimeError): +            rv.setup(manager, 'sdfsdf') + +    def test_oauth_property(self): +        """ Make sure the oauth property works""" +        from flask import Blueprint + +        from pysite.route_manager import RouteView +        from pysite.oauth import OauthBackend + +        class TestRoute(RouteView): +            name = "test" +            path = "/test" + +        tr = TestRoute() +        tr.setup(manager, Blueprint("test", "test_name")) +        self.assertIsInstance(tr.oauth, OauthBackend) + +    def test_user_data_property(self): +        """ Make sure the user_data property works""" +        from flask import Blueprint + +        from pysite.route_manager import RouteView + +        class TestRoute(RouteView): +            name = "test" +            path = "/test" + +        tr = TestRoute() +        tr.setup(manager, Blueprint("test", "test_name")) +        self.assertIsNone(tr.user_data) + +    def test_logged_in_property(self): +        """ Make sure the user_data property works""" +        from flask import Blueprint + +        from pysite.route_manager import RouteView + +        class TestRoute(RouteView): +            name = "test" +            path = "/test" + +        tr = TestRoute() +        tr.setup(manager, Blueprint("test", "test_name")) +        self.assertFalse(tr.logged_in) diff --git a/tests/test_oauth_backend.py b/tests/test_oauth_backend.py new file mode 100644 index 00000000..58e40c25 --- /dev/null +++ b/tests/test_oauth_backend.py @@ -0,0 +1,39 @@ +from tests import SiteTest, manager + +class TestOauthBackend(SiteTest): +    """ Test cases for the oauth.py file """ + +    def test_get(self): +        """ Make sure the get function returns nothing """ +        self.assertIsNone(manager.oauth_backend.get()) + +    def test_delete(self): +        """ Make sure the delete function returns nothing """ +        self.assertIsNone(manager.oauth_backend.delete(None)) + +    def test_logout(self): +        """ Make sure at least apart of logout is working :/ """ +        self.assertIsNone(manager.oauth_backend.logout()) + +    def test_add_user(self): +        """ Make sure function adds values to database and session """ +        from flask import session + +        from pysite.constants import OAUTH_DATABASE + +        sess_id = "hey bro wazup" +        fake_token = {"access_token": "access_token", "id": sess_id, "refresh_token": "refresh_token", "expires_at": 5} +        fake_user = {"id": 1235678987654321, "username": "Zwacky", "discriminator": "#6660", "email": "[email protected]"} +        manager.db.conn = manager.db.get_connection() +        manager.oauth_backend.add_user(fake_token, fake_user, sess_id) + +        self.assertEqual(sess_id, session["session_id"]) +        fake_token["snowflake"] = fake_user["id"] +        fake_user["user_id"] = fake_user["id"] +        del fake_user["id"] +        self.assertEqual(fake_token, manager.db.get(OAUTH_DATABASE, sess_id)) +        self.assertEqual(fake_user, manager.db.get("users", fake_user["user_id"])) + +        manager.db.delete(OAUTH_DATABASE, sess_id) +        manager.db.delete("users", fake_user["user_id"]) +        manager.db.teardown_request(None) diff --git a/tests/test_roots.py b/tests/test_roots.py new file mode 100644 index 00000000..0b7b129c --- /dev/null +++ b/tests/test_roots.py @@ -0,0 +1,84 @@ +from tests import SiteTest +from pysite.constants import DISCORD_OAUTH_REDIRECT +from pysite.constants import DISCORD_OAUTH_AUTHORIZED +from pysite.constants import ERROR_DESCRIPTIONS + +class RootEndpoint(SiteTest): +    """ Test cases for the root endpoint and error handling """ + +    def test_index(self): +        """ Check the root path responds with 200 OK """ +        response = self.client.get('/', 'http://pytest.local') +        self.assertEqual(response.status_code, 200) + +    def test_info_index(self): +        """ Check the info index path responds with a 301 """ +        response = self.client.get('/info') +        self.assertEqual(response.status_code, 301) + +    def test_info_help(self): +        """ Check the info help path responds with 200 OK """ +        response = self.client.get('/info/help') +        self.assertEqual(response.status_code, 200) + +    def test_info_resources(self): +        """ Check the info resources path responds with 200 OK """ +        response = self.client.get('/info/resources') +        self.assertEqual(response.status_code, 200) + +    def test_info_resources_json(self): +        """ Check the resources JSON loads correctly """ +        response = self.client.get('/static/resources.json') +        self.assertEqual(response.status_code, 200) +        self.assertIsInstance(response.json, dict) + +    def test_info_rules(self): +        """ Check the info rules path responds with 200 OK """ +        response = self.client.get('/info/help') +        self.assertEqual(response.status_code, 200) + +    def test_not_found(self): +        """ Check paths without handlers returns 404 Not Found """ +        response = self.client.get('/nonexistentpath') +        self.assertEqual(response.status_code, 404) + +    def test_error(self): +        """ Check the error pages """ +        for code in ERROR_DESCRIPTIONS.keys(): +            response = self.client.get(f'/error/{code}') +            self.assertEqual(response.status_code, code) + +    def test_invite(self): +        """ Check invite redirects """ +        response = self.client.get('/invite') +        self.assertEqual(response.status_code, 302) + +    def test_ws_test(self): +        """ Check ws_test responds """ +        response = self.client.get('/ws_test') +        self.assertEqual(response.status_code, 200) + +    def test_oauth_redirects(self): +        """ Check oauth redirects """ +        response = self.client.get(DISCORD_OAUTH_REDIRECT) +        self.assertEqual(response.status_code, 302) + +    def test_oauth_logout(self): +        """ Check oauth redirects """ +        response = self.client.get('/auth/logout') +        self.assertEqual(response.status_code, 302) + +    def test_oauth_authorized(self): +        """ Check oauth authorization """ +        response = self.client.get(DISCORD_OAUTH_AUTHORIZED) +        self.assertEqual(response.status_code, 302) + +    def test_stats_redirect(self): +        """ Check stats path redirects """ +        response = self.client.get('/stats') +        self.assertEqual(response.status_code, 302) + +    def test_500_easter_egg(self): +        """ Check the status of the /500 page""" +        response = self.client.get("/500") +        self.assertEqual(response.status_code, 500) diff --git a/tests/test_rst.py b/tests/test_rst.py new file mode 100644 index 00000000..d6328bc4 --- /dev/null +++ b/tests/test_rst.py @@ -0,0 +1,11 @@ +import os +import json +from tests import SiteTest, app + +class RstEndpoints(SiteTest): +    """ Test cases for staff subdomain """ + +    def test_staff_view(self): +        """ Check staff view redirects """ +        response = self.client.get('/', "http://"+app.config['SERVER_NAME']) +        self.assertEqual(response.status_code, 200) diff --git a/tests/test_staff.py b/tests/test_staff.py new file mode 100644 index 00000000..68c182b5 --- /dev/null +++ b/tests/test_staff.py @@ -0,0 +1,16 @@ +import os +import json +from tests import SiteTest, app + +class StaffEndpoints(SiteTest): +    """ Test cases for staff subdomain """ + +    def test_staff_view(self): +        """ Check staff view redirects """ +        response = self.client.get('/', app.config['STAFF_SUBDOMAIN']) +        self.assertEqual(response.status_code, 302) + +    def test_jams_infractions(self): +        """ Check staff jams infractions view redirects """ +        response = self.client.get('/jams/infractions', app.config['STAFF_SUBDOMAIN']) +        self.assertEqual(response.status_code, 302) diff --git a/tests/test_utilities.py b/tests/test_utilities.py new file mode 100644 index 00000000..61a480e2 --- /dev/null +++ b/tests/test_utilities.py @@ -0,0 +1,25 @@ +from tests import SiteTest, manager + +class Utilities(SiteTest): +    """ Test cases for internal utility code """ +    def test_error_view_runtime_error(self): +        """ Check that wrong values for error view setup raises runtime error """ +        import pysite.base_route + +        ev = pysite.base_route.ErrorView() + +        with self.assertRaises(RuntimeError): +            ev.setup(manager, 'sdfsdf') + +    def test_websocket_callback(self): +        """ Check that websocket default callbacks work """ +        import pysite.websockets + +        class TestWS(pysite.websockets.WS): +            pass + +        try: +            TestWS(None).on_message("test") +            return False +        except NotImplementedError: +            return True diff --git a/tests/test_websocket.py b/tests/test_websocket.py new file mode 100644 index 00000000..d8a616bf --- /dev/null +++ b/tests/test_websocket.py @@ -0,0 +1,12 @@ +from tests import SiteTest + +class TestWebsocketEcho(SiteTest): +    """ Test cases for the echo endpoint """ +    def testEcho(self): +        """ Check rudimentary websockets handlers work """ +        from geventwebsocket.websocket import WebSocket +        from pysite.views.ws.echo import EchoWebsocket +        ew = EchoWebsocket(WebSocket) +        ew.on_open() +        ew.on_message('message') +        ew.on_close() diff --git a/tests/test_wiki.py b/tests/test_wiki.py new file mode 100644 index 00000000..e16152a1 --- /dev/null +++ b/tests/test_wiki.py @@ -0,0 +1,34 @@ +import os +from tests import SiteTest, app + +class WikiEndpoints(SiteTest): +    """ Test cases for the wiki subdomain """ +    def test_wiki_edit(self): +        """Test that the wiki edit page redirects to login""" +        response = self.client.get("/edit/page", app.config['WIKI_SUBDOMAIN']) +        self.assertEqual(response.status_code, 302) + +    def test_wiki_edit_post_empty_request(self): +        """Empty request should redirect to login""" +        response = self.client.post("/edit/page", app.config['WIKI_SUBDOMAIN']) +        self.assertEqual(response.status_code, 302) + +    def test_wiki_history(self): +        """Test the history show""" +        response = self.client.get("/history/show/blahblah-non-existant-page", app.config['WIKI_SUBDOMAIN']) +        self.assertEqual(response.status_code, 404) # Test that unknown routes 404 + +    def test_wiki_diff(self): +        """Test whether invalid revision IDs error""" +        response = self.client.get("/history/compare/ABC/XYZ", app.config['WIKI_SUBDOMAIN']) +        self.assertEqual(response.status_code, 404) # Test that unknown revisions 404 + +    def test_wiki_special(self): +        """Test whether invalid revision IDs error""" +        response = self.client.get("/special", app.config['WIKI_SUBDOMAIN']) +        self.assertEqual(response.status_code, 200) + +    def test_wiki_special_all_pages(self): +        """Test whether invalid revision IDs error""" +        response = self.client.get("/special/all_pages", app.config['WIKI_SUBDOMAIN']) +        self.assertEqual(response.status_code, 200) @@ -2,5 +2,5 @@  max-line-length=120  application_import_names=pysite  ignore=P102,B311,W503,E226,S311 -exclude=__pycache__, venv, app_test.py, .venv +exclude=__pycache__, venv, .venv, tests  import-order-style=pycharm | 
