From c07638601b042531f906de120e9c2e046e98c990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Tue, 20 Aug 2019 10:59:26 +0200 Subject: [PATCH 01/10] Implementing poc spec behavior in append route. --- poc/bin/kapow | 29 +++++++--- poc/dist/kapow-0.0.1-py3.7.egg | Bin 0 -> 6929 bytes .../append/error_unprocessable.feature | 4 +- spec/test/features/steps/steps.py | 50 ++++++++++++++---- 4 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 poc/dist/kapow-0.0.1-py3.7.egg diff --git a/poc/bin/kapow b/poc/bin/kapow index 0dd3b0c..bd3c16f 100755 --- a/poc/bin/kapow +++ b/poc/bin/kapow @@ -16,11 +16,12 @@ # limitations under the License. # -from urllib.parse import urlparse from itertools import repeat +from urllib.parse import urlparse from uuid import uuid4 import asyncio import io +import json import logging import os import shlex @@ -280,13 +281,25 @@ def append_route(app): app.router._frozen = False content = await request.json() name = "ROUTE_" + str(uuid4()).replace('-', '_') - app.router.add_route(content["method"], - content["url_pattern"], - handle_route(content["entrypoint"], - content["command"]), - name=name) - print(f'Route created {content["method"]} {content["url_pattern"]}') - return web.json_response(name) + try: + app.router.add_route(content["method"], + content["url_pattern"], + handle_route(content["entrypoint"], + content["command"]), + name=name) + except KeyError as exc: + missing = list() + for field in ("method", "url_pattern", "entrypoint", "command"): + if field not in content: + missing.append(field) + return web.Response(status=422, + reason="Missing Mandatory Field", + body=json.dumps({"missing_mandatory_fields": missing})) + except ValueError as exc: + return web.Response(status=422, reason="Invalid Route Spec") + else: + print(f'Route created {content["method"]} {content["url_pattern"]}') + return web.json_response(name) return _append_route diff --git a/poc/dist/kapow-0.0.1-py3.7.egg b/poc/dist/kapow-0.0.1-py3.7.egg new file mode 100644 index 0000000000000000000000000000000000000000..4bc98c7d5180a29fc69960fcc70dc7bb23778d7b GIT binary patch literal 6929 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 TXup1lb@%zz<7oYAauEIp$R-B0 literal 0 HcmV?d00001 diff --git a/spec/test/features/control/append/error_unprocessable.feature b/spec/test/features/control/append/error_unprocessable.feature index 933cf07..2025918 100644 --- a/spec/test/features/control/append/error_unprocessable.feature +++ b/spec/test/features/control/append/error_unprocessable.feature @@ -15,8 +15,8 @@ Feature: Kapow! server reject responses with semantic errors. Then I get 422 as response code And I get "Missing Mandatory Field" as response reason phrase And I get the following entity as response body: - | missing_mandatory_fields | - | "url_pattern", "method" | + | missing_mandatory_fields | + | ["url_pattern", "method"] | Scenario: Error because of wrong route specification. If a request contains an invalid expression in the diff --git a/spec/test/features/steps/steps.py b/spec/test/features/steps/steps.py index c95a2d1..25fce6e 100644 --- a/spec/test/features/steps/steps.py +++ b/spec/test/features/steps/steps.py @@ -1,12 +1,14 @@ -import subprocess +from contextlib import suppress from time import sleep +import json import shlex import socket -from contextlib import suppress +import subprocess import requests -from environconfig import EnvironConfig, StringVar, IntVar +from environconfig import EnvironConfig, StringVar, IntVar, BooleanVar +import logging class Env(EnvironConfig): #: How to run Kapow! server @@ -20,6 +22,30 @@ class Env(EnvironConfig): KAPOW_BOOT_TIMEOUT = IntVar(default=10) + KAPOW_DEBUG_TESTS = BooleanVar(default=True) + + +if Env.KAPOW_DEBUG_TESTS: + # These two lines enable debugging at httplib level + # (requests->urllib3->http.client) You will see the REQUEST, + # including HEADERS and DATA, and RESPONSE with HEADERS but without + # DATA. The only thing missing will be the response.body which is + # not logged. + try: + import http.client as http_client + except ImportError: + # Python 2 + import httplib as http_client + http_client.HTTPConnection.debuglevel = 1 + + # You must initialize logging, otherwise you'll not see debug output. + logging.basicConfig() + logging.getLogger().setLevel(logging.DEBUG) + requests_log = logging.getLogger("requests.packages.urllib3") + requests_log.setLevel(logging.DEBUG) + requests_log.propagate = True + + @given('I have a just started Kapow! server') @given('I have a running Kapow! server') def step_impl(context): @@ -97,30 +123,32 @@ def step_impl(context): if not hasattr(context, 'table'): raise RuntimeError("A table must be set for this step.") - for row in context.table: - response = requests.post(f"{Env.KAPOW_CONTROLAPI_URL}/routes", - json={h: row[h] for h in row.headings}) - response.raise_for_status() + row = context.table[0] + context.response = requests.post(f"{Env.KAPOW_CONTROLAPI_URL}/routes", + json={h: row[h] for h in row.headings}) @then('I get {code} as response code') def step_impl(context, code): - raise NotImplementedError('STEP: Then I get unprocessable entity as response code') + assert context.response.status_code == int(code), f"Got {context.response.status_code} instead" @then('I get "{reason}" as response reason phrase') def step_impl(context, reason): - raise NotImplementedError('STEP: Then I get "Missing Mandatory Field" as response phrase') + assert context.response.reason == reason, f"Got {context.response.reason} instead" @then('I get the following entity as response body') def step_impl(context): - raise NotImplementedError('STEP: Then I get the following entity as response body') + for row in context.table: + for name, value in row.items(): + assert name in context.response.json(), f"Field {name} not present in {context.response.json()}" + assert set(json.loads(value)) == set(context.response.json()[name]) @then('I get an empty response body') def step_impl(context): - raise NotImplementedError('STEP: Then I get an empty response body') + assert context.response.content == b'', f"Response body is not empty. Got {context.response.content} instead." @when('I delete the route with id "{id}"') From 226ac5b90a5eef55e617e92d1e08750ac817959a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Tue, 20 Aug 2019 11:09:05 +0200 Subject: [PATCH 02/10] Reason phrase instead of phrase. --- spec/test/features/control/append/error_malformed.feature | 2 +- spec/test/features/control/insert/error_malformed.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/test/features/control/append/error_malformed.feature b/spec/test/features/control/append/error_malformed.feature index 1cf657f..f0120ee 100644 --- a/spec/test/features/control/append/error_malformed.feature +++ b/spec/test/features/control/append/error_malformed.feature @@ -20,5 +20,5 @@ Feature: Kapow! server reject append requests with malformed JSON bodies. } """ Then I get 400 as response code - And I get "Malformed JSON" as response phrase + And I get "Malformed JSON" as response reason phrase And I get an empty response body diff --git a/spec/test/features/control/insert/error_malformed.feature b/spec/test/features/control/insert/error_malformed.feature index 40e50b2..c5951dd 100644 --- a/spec/test/features/control/insert/error_malformed.feature +++ b/spec/test/features/control/insert/error_malformed.feature @@ -21,5 +21,5 @@ Feature: Kapow! server reject insert requests with malformed JSON bodies. } """ Then I get bad request as response code - And I get "Malformed JSON" as response phrase + And I get "Malformed JSON" as response reason phrase And I get an empty response body From be49120511f2c56f62b9dc05755a91045c0162b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Tue, 20 Aug 2019 11:10:40 +0200 Subject: [PATCH 03/10] Missing step. --- spec/test/features/steps/steps.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/test/features/steps/steps.py b/spec/test/features/steps/steps.py index 25fce6e..f2247c3 100644 --- a/spec/test/features/steps/steps.py +++ b/spec/test/features/steps/steps.py @@ -160,6 +160,12 @@ def step_impl(context, id): def step_impl(context, id): raise NotImplementedError('STEP: Given It has a route with id "xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx"') + @when('I insert the route') def step_impl(context): raise NotImplementedError('STEP: When I insert the route') + + +@when('I try to append with this JSON document') +def step_impl(context): + raise NotImplementedError('STEP: When I try to append with this JSON document') From 0cfc55c1751458fea97e907034b79288a470bfed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Wed, 21 Aug 2019 08:23:20 +0200 Subject: [PATCH 04/10] Helper function to compare nested structures in tests. --- spec/test/features/steps/comparedict.py | 38 +++++++++++++++++++++++++ spec/test/features/steps/steps.py | 1 + 2 files changed, 39 insertions(+) create mode 100644 spec/test/features/steps/comparedict.py diff --git a/spec/test/features/steps/comparedict.py b/spec/test/features/steps/comparedict.py new file mode 100644 index 0000000..7b5f968 --- /dev/null +++ b/spec/test/features/steps/comparedict.py @@ -0,0 +1,38 @@ +from functools import singledispatch + + +def assert_same_type(f): + def wrapper(a, b): + if type(a) != type(b): + raise TypeError("Non-matching types") + return f(a, b) + return wrapper + + +@singledispatch +@assert_same_type +def is_subset(model, obj): + return model == obj + + +@is_subset.register(dict) +@assert_same_type +def _(model, obj): + for key, value in model.items(): + if key not in obj or not is_subset(value, obj[key]): + return False + return True + + +@is_subset.register(list) +@assert_same_type +def _(model, obj): + if type(model) != type(obj): + raise TypeError("Non-matching types") + return is_subset(set(model), set(obj)) + + +@is_subset.register(set) +@assert_same_type +def _(model, obj): + return model <= obj diff --git a/spec/test/features/steps/steps.py b/spec/test/features/steps/steps.py index f2247c3..16edd2d 100644 --- a/spec/test/features/steps/steps.py +++ b/spec/test/features/steps/steps.py @@ -7,6 +7,7 @@ import subprocess import requests from environconfig import EnvironConfig, StringVar, IntVar, BooleanVar +from comparedict import is_subset import logging From f6014ab4036fbfba47855828d7b899bfd2ae7a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Wed, 21 Aug 2019 08:38:13 +0200 Subject: [PATCH 05/10] Step alias for JSON document. --- spec/test/features/control/append/error_malformed.feature | 2 +- spec/test/features/steps/steps.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/test/features/control/append/error_malformed.feature b/spec/test/features/control/append/error_malformed.feature index f0120ee..4c4f9f0 100644 --- a/spec/test/features/control/append/error_malformed.feature +++ b/spec/test/features/control/append/error_malformed.feature @@ -8,7 +8,7 @@ Feature: Kapow! server reject append requests with malformed JSON bodies. the server will respond with a bad request error. Given I have a running Kapow! server - When I try to append with this JSON document: + When I try to append with this malformed JSON document: """ { "method" "GET", diff --git a/spec/test/features/steps/steps.py b/spec/test/features/steps/steps.py index 16edd2d..191d927 100644 --- a/spec/test/features/steps/steps.py +++ b/spec/test/features/steps/steps.py @@ -167,6 +167,7 @@ def step_impl(context): raise NotImplementedError('STEP: When I insert the route') +@when('I try to append with this malformed JSON document') @when('I try to append with this JSON document') def step_impl(context): raise NotImplementedError('STEP: When I try to append with this JSON document') From 7a93c16deca463c6ca33b05172f4abf08a4cdbba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Wed, 21 Aug 2019 08:52:13 +0200 Subject: [PATCH 06/10] Implement JSON validation in append. --- poc/bin/kapow | 7 ++++++- spec/test/features/steps/steps.py | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/poc/bin/kapow b/poc/bin/kapow index bd3c16f..fa85b16 100755 --- a/poc/bin/kapow +++ b/poc/bin/kapow @@ -279,7 +279,12 @@ def append_route(app): async def _append_route(request): """Create a new Kapow! route.""" app.router._frozen = False - content = await request.json() + + try: + content = await request.json() + except Exception as exc: + return web.Response(status=400, reason="Malformed JSON") + name = "ROUTE_" + str(uuid4()).replace('-', '_') try: app.router.add_route(content["method"], diff --git a/spec/test/features/steps/steps.py b/spec/test/features/steps/steps.py index 191d927..eaf73c9 100644 --- a/spec/test/features/steps/steps.py +++ b/spec/test/features/steps/steps.py @@ -170,4 +170,7 @@ def step_impl(context): @when('I try to append with this malformed JSON document') @when('I try to append with this JSON document') def step_impl(context): - raise NotImplementedError('STEP: When I try to append with this JSON document') + context.response = requests.post( + f"{Env.KAPOW_CONTROLAPI_URL}/routes", + headers={"Content-Type": "application/json"}, + data=context.text) From 6257db82ddb3ab4b5a166a66eebef3d20586e9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Wed, 21 Aug 2019 08:56:24 +0200 Subject: [PATCH 07/10] Add wip target to test wip marked scenarios. --- spec/test/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/test/Makefile b/spec/test/Makefile index 49b8678..f028874 100644 --- a/spec/test/Makefile +++ b/spec/test/Makefile @@ -1,3 +1,5 @@ +wip: + pipenv run behave --no-capture --stop --wip test: gherkin-lint pipenv run behave --no-capture --stop From 443aa0f39c4f3c4e4a90a48bc3a389a86908da8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Wed, 21 Aug 2019 09:08:22 +0200 Subject: [PATCH 08/10] Use 201 for successfule route append response. --- poc/bin/kapow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poc/bin/kapow b/poc/bin/kapow index fa85b16..93ddd68 100755 --- a/poc/bin/kapow +++ b/poc/bin/kapow @@ -304,7 +304,7 @@ def append_route(app): return web.Response(status=422, reason="Invalid Route Spec") else: print(f'Route created {content["method"]} {content["url_pattern"]}') - return web.json_response(name) + return web.json_response(name, status=201) return _append_route From 126beca86eae0f9076cfcfa047ab78a8db646d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Wed, 21 Aug 2019 09:10:42 +0200 Subject: [PATCH 09/10] More appropiate defaults for testing targets. --- spec/test/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/test/Makefile b/spec/test/Makefile index f028874..f90954f 100644 --- a/spec/test/Makefile +++ b/spec/test/Makefile @@ -1,7 +1,7 @@ wip: - pipenv run behave --no-capture --stop --wip + pipenv run behave --stop --wip test: gherkin-lint - pipenv run behave --no-capture --stop + pipenv run behave --no-capture catalog: pipenv run behave --steps-catalog From 7d83432500ac2d91faee0c04a526b1973cfd01ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Wed, 21 Aug 2019 09:11:10 +0200 Subject: [PATCH 10/10] Factorized run_kapow_server function to allow reuse. --- spec/test/features/steps/steps.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/spec/test/features/steps/steps.py b/spec/test/features/steps/steps.py index eaf73c9..f8c4df9 100644 --- a/spec/test/features/steps/steps.py +++ b/spec/test/features/steps/steps.py @@ -46,10 +46,7 @@ if Env.KAPOW_DEBUG_TESTS: requests_log.setLevel(logging.DEBUG) requests_log.propagate = True - -@given('I have a just started Kapow! server') -@given('I have a running Kapow! server') -def step_impl(context): +def run_kapow_server(context): context.server = subprocess.Popen( shlex.split(Env.KAPOW_SERVER_CMD), stdout=subprocess.DEVNULL, @@ -71,6 +68,11 @@ def step_impl(context): assert open_ports, "API is unreachable after KAPOW_BOOT_TIMEOUT" +@given('I have a just started Kapow! server') +@given('I have a running Kapow! server') +def step_impl(context): + run_kapow_server(context) + @when('I request a routes listing') def step_impl(context): @@ -85,13 +87,7 @@ def step_impl(context): @given('I have a Kapow! server whith the following routes') def step_impl(context): - context.server = subprocess.Popen( - Env.KAPOW_SERVER_CMD, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - shell=True) - is_running = context.server.poll() is None - assert is_running, "Server is not running!" + run_kapow_server(context) if not hasattr(context, 'table'): raise RuntimeError("A table must be set for this step.")