From 342560e8f252e52dde853fa828f6e4a6cc2a9553 Mon Sep 17 00:00:00 2001 From: "Antoine R. Dumont (@ardumont)" <antoine.romain.dumont@gmail.com> Date: Tue, 24 Nov 2015 13:57:42 +0100 Subject: [PATCH] Demonstrate via tests that our api deals with client's accept header Accepted types: application/json, application/yaml, text/html In browser, this means that our api is only browsable. With curl (or other similar tools) however, you can ask with the Accept headers For example: $ curl -v -H 'Accept:application/yaml' -X GET http://localhost:6543/api/1/revision/edfbd9e840cc82e879d9aae8ecc29c7121ff750 Note: Unnecessary use of -X or --request, GET is already inferred. * Trying ::1... * connect to ::1 port 6543 failed: Connection refused * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 6543 (#0) > GET /api/1/revision/edfbd9e840cc82e879d9aae8ecc29c7121ff750 HTTP/1.1 > Host: localhost:6543 > User-Agent: curl/7.45.0 > Accept:application/yaml > * HTTP 1.0, assume close after body < HTTP/1.0 400 BAD REQUEST < Content-Type: application/yaml < Content-Length: 39 < Server: Werkzeug/0.10.4 Python/3.4.3+ < Date: Tue, 24 Nov 2015 13:00:23 GMT < {error: invalid checksum query string} * Closing connection 0 $ curl -v -H 'Accept:application/json' -X GET http://localhost:6543/api/1/revision/edfbd9e840cc82e879d9aae8ecc29c7121ff750 Note: Unnecessary use of -X or --request, GET is already inferred. * Trying ::1... * connect to ::1 port 6543 failed: Connection refused * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 6543 (#0) > GET /api/1/revision/edfbd9e840cc82e879d9aae8ecc29c7121ff750 HTTP/1.1 > Host: localhost:6543 > User-Agent: curl/7.45.0 > Accept:application/json > * HTTP 1.0, assume close after body < HTTP/1.0 400 BAD REQUEST < Content-Type: application/json < Content-Length: 42 < Server: Werkzeug/0.10.4 Python/3.4.3+ < Date: Tue, 24 Nov 2015 13:00:28 GMT < * Closing connection 0 {"error": "invalid checksum query string"}% --- swh/web/ui/main.py | 9 ++++++ swh/web/ui/tests/test_app.py | 6 +++- swh/web/ui/tests/test_controller.py | 48 ++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/swh/web/ui/main.py b/swh/web/ui/main.py index 594ca43ff..b1e4b665e 100644 --- a/swh/web/ui/main.py +++ b/swh/web/ui/main.py @@ -60,6 +60,15 @@ def storage(): return app.config['conf']['storage'] +def setup_app(app, conf): + app.secret_key = conf['secret_key'] + app.config['conf'] = conf + app.config['MAX_CONTENT_LENGTH'] = conf['max_upload_size'] + app.config['DEFAULT_RENDERERS'] = RENDERERS + + return app + + def run_from_webserver(environ, start_response): """Run the WSGI app from the webserver, loading the configuration.""" diff --git a/swh/web/ui/tests/test_app.py b/swh/web/ui/tests/test_app.py index 57b43c1dd..4811d8e8d 100644 --- a/swh/web/ui/tests/test_app.py +++ b/swh/web/ui/tests/test_app.py @@ -8,6 +8,7 @@ from swh.web.ui import controller from swh.storage.api.client import RemoteStorage as Storage +from swh.web.ui import renderers # Because the Storage's __init__ function does side effect at startup... @@ -44,10 +45,13 @@ def init_app(base_url='https://somewhere.org:4321'): # inject the mock data conf = {'storage': storage, 'upload_folder': '/some/upload-dir', - 'upload_allowed_extensions': ['txt']} + 'upload_allowed_extensions': ['txt'], + 'max_upload_size': 1024} controller.app.config['TESTING'] = True controller.app.config.update({'conf': conf}) + controller.app.config['MAX_CONTENT_LENGTH'] = conf['max_upload_size'] + controller.app.config['DEFAULT_RENDERERS'] = renderers.RENDERERS app = controller.app.test_client() return app, controller.app.config, storage diff --git a/swh/web/ui/tests/test_controller.py b/swh/web/ui/tests/test_controller.py index d2cd3e667..ad3925966 100644 --- a/swh/web/ui/tests/test_controller.py +++ b/swh/web/ui/tests/test_controller.py @@ -5,6 +5,7 @@ import unittest import json +import yaml from nose.tools import istest from unittest.mock import patch, MagicMock @@ -136,7 +137,7 @@ class ApiTestCase(unittest.TestCase): @patch('swh.web.ui.controller.service') @istest - def api_content_not_found(self, mock_service): + def api_content_not_found_as_json(self, mock_service): # given mock_service.lookup_content.return_value = None mock_service.lookup_hash_origin = MagicMock() @@ -159,6 +160,33 @@ class ApiTestCase(unittest.TestCase): 'be4735637006560c') mock_service.lookup_hash_origin.called = False + @patch('swh.web.ui.controller.service') + @istest + def api_content_not_found_as_yaml(self, mock_service): + # given + mock_service.lookup_content.return_value = None + mock_service.lookup_hash_origin = MagicMock() + + # when + rv = self.app.get( + '/api/1/content/sha256:83c0e67cc80f60caf1fcbec2d84b0ccd7968b3' + 'be4735637006560c/', + headers={'accept': 'application/yaml'}) + + self.assertEquals(rv.status_code, 404) + self.assertEquals(rv.mimetype, 'application/yaml') + + response_data = yaml.load(rv.data.decode('utf-8')) + self.assertEquals(response_data, { + 'error': 'Content with sha256:83c0e67cc80f60caf1fcbec2d84b0ccd79' + '68b3be4735637006560c not found.' + }) + + mock_service.lookup_content.assert_called_once_with( + 'sha256:83c0e67cc80f60caf1fcbec2d84b0ccd7968b3' + 'be4735637006560c') + mock_service.lookup_hash_origin.called = False + @patch('swh.web.ui.controller.service') @istest def api_search(self, mock_service): @@ -175,6 +203,24 @@ class ApiTestCase(unittest.TestCase): mock_service.lookup_hash.assert_called_once_with('sha1:blah') + @patch('swh.web.ui.controller.service') + @istest + def api_search_as_yaml(self, mock_service): + # given + mock_service.lookup_hash.return_value = True + + # when + rv = self.app.get('/api/1/search/sha1:halb/', + headers={'Accept': 'application/yaml'}) + + self.assertEquals(rv.status_code, 200) + self.assertEquals(rv.mimetype, 'application/yaml') + + response_data = yaml.load(rv.data.decode('utf-8')) + self.assertEquals(response_data, {'found': True}) + + mock_service.lookup_hash.assert_called_once_with('sha1:halb') + @patch('swh.web.ui.controller.service') @istest def api_search_not_found(self, mock_service): -- GitLab