5 Коміти f788614484 ... a203d95ea9

Автор SHA1 Опис Дата
  Wiliam Souza a203d95ea9 Removed path from expectation 9 роки тому
  Wiliam Souza 285d0e51ec Adds more mock tests 9 роки тому
  Wiliam Souza 449d24a7e0 Updated example 9 роки тому
  Wiliam Souza 8ae7866a31 Removes asyncio from mock client 9 роки тому
  Wiliam Souza 8e3982275e WIP 9 роки тому
5 змінених файлів з 99 додано та 58 видалено
  1. 8 20
      README.md
  2. 1 2
      echod/api.py
  3. 25 32
      echod/mock.py
  4. 11 1
      echod/utils.py
  5. 54 3
      tests/test_mock.py

+ 8 - 20
README.md

@@ -24,33 +24,21 @@ Mock
 ----
 
 ```python
-import echod
+from echod.mock import Mock
 
+# This will create a mock that accepts `POST` in the path `/v1/users/`.
 expectation = {
     'method': 'POST',
-    'path': '/v1/users/',
     'response': {'body': {'email': 'john@doe.com', 'name': 'John Doe'},
                  'headers': {'content_type': 'application/json'},
                  'status_code': 201}
 }
 
+with Mock(expectation) as client:
+    # The mock URL is available to use
+    client.mock_url  # 'http://127.0.0.1:9876/mock/fbf01f94169640de9e585fe5e30a0958/'
 
-with echod.mock(**expectation) as client:
-    response = client.post()
-    response.status_code == 200
-```
-
-
-callback
---------
-
-```python
-import requests
-
-
-with echod.callback() as webhook:
-    settings.callback_url = webhook.url
-    requests.post()
-    webhook.wait_callback(timeout=10)
-    webhook.response.data == {...}
+    # This method will make a request to the mock
+    response = client.response()
+    assert response.status_code == 201
 ```

+ 1 - 2
echod/api.py

@@ -30,8 +30,7 @@ def get_mock(request):
 def put_mock(request):
     data = yield from request.json()
     uuid_hex = uuid.uuid4().hex
-    path = yield from normalize_path('/mock/{}/{}/'.format(uuid_hex,
-                                                           data['path']))
+    path = normalize_path('/mock/{}/'.format(uuid_hex))
     request.app.router.add_route(data['method'], path, mock)
     request.app['mock_db'][path] = data
     return web.Response(text=json.dumps({'path': path}),

+ 25 - 32
echod/mock.py

@@ -1,16 +1,15 @@
 # coding: utf-8
 
 import json
-import asyncio
-
-import requests
 
 from wtforms.validators import ValidationError
 
 from prettyconf import config
 
-from echod import api
+import requests
+
 from echod.forms import MockForm
+from echod.utils import url_path_join
 
 request_headers = {
     'content_type': 'application/json',
@@ -26,45 +25,39 @@ class Mock(object):
 
         self.expectation = expectation
 
-        self.loop = asyncio.get_event_loop()
         self.host = host or config('ECHOD_API_HOST', default='127.0.0.1')
         self.port = port or config('ECHOD_API_PORT', default=9876)
 
-        self.server_url = None
-        self.address = (self.host, self.port)
+        self.base_url = 'http://{}:{}'.format(self.host, self.port)
+        self._session = requests.Session()
 
-    @asyncio.coroutine
-    def _start_api(self):
-        # TODO: Search for a way to start the API server here.
-        self.loop.run_until_complete(
-            api.start(self.loop, self.host, self.port))
+        self._urls = {
+            'health': url_path_join(self.base_url, 'health', '/'),
+            'mocks': url_path_join(self.base_url, 'mocks', '/'),
+            'response': None,
+        }
+        self.mock_url = None
 
     def __enter__(self):
-        # Start API
-        asyncio.async(api.start(self.loop, self.host, self.port),
-                      loop=self.loop)
-
-        import ipdb; ipdb.set_trace()  # Breakpoint
-        # Configure the mock
-        self.server_url = 'http://{}:{}/mocks/'.format(*self.address)
-        response = requests.put(self.server_url,
-                                data=json.dumps(self.expectation),
-                                headers=request_headers)
+        response = self._session.request(method='PUT', url=self._urls['mocks'],
+                                         headers=request_headers,
+                                         data=json.dumps(self.expectation),
+                                         timeout=1)
+
         if response.status_code != 201:
             raise Exception('Erro creating mock.')
-        self.mock_path = response.json()['path']
+
+        self.mock_url = url_path_join(self.base_url, response.json()['path'], '/')
+        self._urls['response'] = self.mock_url
+
         return self
 
-    def __exit__(self, *args):
+    def __exit__(self, exec_type, exc, tb):
         # Clean up
-        self.loop.run_until_complete(self.handler.finish_connections(1.0))
-        self.loop.run_until_complete(self.redis_pool.clear())
-        api.stop(self.loop)
-        self.loop.close()
+        pass
 
     def health(self):
-        health_url = 'http://{}:{}/health/'.format(*self.address)
-        return requests.get(health_url)
+        return self._session.request(method='GET', url=self._urls['health'])
 
     def response(self):
         body = ''
@@ -75,5 +68,5 @@ class Mock(object):
             headers = self.expectation['request']['headers']
             body = self.expectation['request']['body']
 
-        request = getattr(requests, method)
-        return request(self.mock_path, headers=headers, data=json.dumps(body))
+        return self._session.request(method=method, url=self._urls['response'],
+                                     headers=headers, data=json.dumps(body))

+ 11 - 1
echod/utils.py

@@ -3,6 +3,7 @@
 import json
 import hashlib
 import asyncio
+from urllib.parse import urlsplit, urlunsplit
 
 
 @asyncio.coroutine
@@ -40,7 +41,6 @@ def decode_json(data):
 
 # TODO: Changes to use https://github.com/rbaier/python-urltools/
 #       do not forget PUBLIC_SUFFIX_LIST env var!
-@asyncio.coroutine
 def normalize_path(path):
     """ Normalize path
 
@@ -65,3 +65,13 @@ def hash_dict(dictionary):
 
 def compare_hash(expected_hash, received_hash):
     return expected_hash == received_hash
+
+
+def url_path_join(*parts):
+    def first_of_each(*sequences):
+        return (next((x for x in sequence if x), '') for sequence in sequences)
+    schemes, netlocs, paths, queries, fragments = zip(*(urlsplit(part) for part in parts))
+    scheme, netloc, query, fragment = first_of_each(schemes, netlocs, queries,
+                                                    fragments)
+    path = '/'.join(x.strip('/') for x in paths if x)
+    return urlunsplit((scheme, netloc, path, query, fragment))

+ 54 - 3
tests/test_mock.py

@@ -1,12 +1,23 @@
 # coding: utf-8
+import json
+from urllib.parse import urlsplit, splitport
+
+import pytest
+
+import aiohttp
 
 from echod.mock import Mock
 
+request_headers = {
+    'content_type': 'application/json',
+    'accept': 'application/json',
+}
+
 
-def test_mock_client():
+@pytest.mark.asyncio
+def test_mock_client(api_server):
     expectation = {
         'method': 'POST',
-        'path': '/v1/users/',
         'request': {'body': {'email': 'john@doe.com',
                              'name': 'John Doe',
                              'password': 'secret'},
@@ -16,5 +27,45 @@ def test_mock_client():
                      'headers': {'content_type': 'application/json'},
                      'status_code': 201}
     }
+
+    netloc = urlsplit(api_server).netloc
+    host, port = splitport(netloc)
+
+    with Mock(expectation) as client:
+        health = client.health()
+        response = client.response()
+
+        assert health.status_code == 200
+        assert response.status_code == 201
+
+        data = json.dumps(expectation['request']['body'])
+        response = yield from aiohttp.request('POST', client.mock_url,
+                                              data=data,
+                                              headers=request_headers)
+        assert response.status == 201
+
+
+@pytest.mark.asyncio
+def test_mock_client_without_request(api_server):
+    expectation = {
+        'method': 'POST',
+        'response': {'body': {'email': 'john@doe.com', 'name': 'John Doe'},
+                     'headers': {'content_type': 'application/json'},
+                     'status_code': 201}
+    }
+
+    netloc = urlsplit(api_server).netloc
+    host, port = splitport(netloc)
+
     with Mock(expectation) as client:
-        assert client.response() == 'Ok'
+        health = client.health()
+        response = client.response()
+
+        assert health.status_code == 200
+        assert response.status_code == 201
+
+        data = json.dumps('')
+        response = yield from aiohttp.request('POST', client.mock_url,
+                                              data=data,
+                                              headers=request_headers)
+        assert response.status == 201