Browse Source

add test on decorator and processor error management

Bastien Sevajol 6 years ago
parent
commit
0b50b96fc1
4 changed files with 53 additions and 19 deletions
  1. 12 0
      hapic/decorator.py
  2. 12 10
      hapic/processor.py
  3. 27 0
      tests/unit/test_decorator.py
  4. 2 9
      tests/unit/test_processor.py

+ 12 - 0
hapic/decorator.py View File

@@ -123,6 +123,18 @@ class InputControllerWrapper(ControllerWrapper):
123 123
 
124 124
 
125 125
 class OutputControllerWrapper(ControllerWrapper):
126
+    def __init__(
127
+        self,
128
+        context: ContextInterface,
129
+        processor: ProcessorInterface,
130
+        error_http_code: HTTPStatus=HTTPStatus.INTERNAL_SERVER_ERROR,
131
+        default_http_code: HTTPStatus=HTTPStatus.OK,
132
+    ) -> None:
133
+        self.context = context
134
+        self.processor = processor
135
+        self.error_http_code = error_http_code
136
+        self.default_http_code = default_http_code
137
+
126 138
     def get_error_response(
127 139
         self,
128 140
         response: typing.Any,

+ 12 - 10
hapic/processor.py View File

@@ -54,23 +54,25 @@ class OutputProcessor(ProcessorInterface):
54 54
 
55 55
 class MarshmallowOutputProcessor(OutputProcessor):
56 56
     def process(self, data: typing.Any):
57
-        unmarshall = self.schema.dump(data)
58
-        # TODO: Il n'y a jamais rien dans le error au dump. il faut check le
59
-        # data au travers de .validate
60
-        if unmarshall.errors:
61
-            raise InputValidationException(
57
+        data = self.schema.dump(data).data
58
+        self.validate(data)
59
+        return data
60
+
61
+    def validate(self, data: typing.Any) -> None:
62
+        errors = self.schema.load(data).errors
63
+        if errors:
64
+            raise OutputValidationException(
62 65
                 'Error when validate input: {}'.format(
63
-                    str(unmarshall.errors),
66
+                    str(errors),
64 67
                 )
65 68
             )
66 69
 
67
-        return unmarshall.data
68
-
69 70
     def get_validation_error(self, data: dict) -> ProcessValidationError:
70
-        marshmallow_errors = self.schema.dump(data).errors
71
+        data = self.schema.dump(data).data
72
+        errors = self.schema.load(data).errors
71 73
         return ProcessValidationError(
72 74
             error_message='Validation error of output data',
73
-            error_details=marshmallow_errors,
75
+            error_details=errors,
74 76
         )
75 77
 
76 78
 

+ 27 - 0
tests/unit/test_decorator.py View File

@@ -2,12 +2,15 @@
2 2
 import typing
3 3
 from http import HTTPStatus
4 4
 
5
+import marshmallow
6
+
5 7
 from hapic.context import ContextInterface
6 8
 from hapic.data import HapicData
7 9
 from hapic.decorator import ControllerWrapper
8 10
 from hapic.decorator import InputControllerWrapper
9 11
 from hapic.decorator import OutputControllerWrapper
10 12
 from hapic.processor import RequestParameters
13
+from hapic.processor import MarshmallowOutputProcessor
11 14
 from hapic.processor import ProcessValidationError
12 15
 from hapic.processor import ProcessorInterface
13 16
 from tests.base import Base
@@ -92,6 +95,10 @@ class MyInputControllerWrapper(InputControllerWrapper):
92 95
         hapic_data.query = processed_data
93 96
 
94 97
 
98
+class MySchema(marshmallow.Schema):
99
+    name = marshmallow.fields.String(required=True)
100
+
101
+
95 102
 class TestControllerWrapper(Base):
96 103
     def test_unit__base_controller_wrapper__ok__no_behaviour(self):
97 104
         context = MyContext()
@@ -171,3 +178,23 @@ class TestOutputControllerWrapper(Base):
171 178
                    'http_code': HTTPStatus.OK,
172 179
                    'original_response': 43,
173 180
                } == result
181
+
182
+    def test_unit__output_data_wrapping__fail__error_response(self):
183
+        context = MyContext()
184
+        processor = MarshmallowOutputProcessor()
185
+        processor.schema = MySchema()
186
+        wrapper = OutputControllerWrapper(context, processor)
187
+
188
+        @wrapper.get_wrapper
189
+        def func(foo):
190
+            return 'wrong result format'
191
+
192
+        result = func(42)
193
+        # see MyProcessor#process
194
+        assert isinstance(result, dict)
195
+        assert 'http_code' in result
196
+        assert result['http_code'] == HTTPStatus.INTERNAL_SERVER_ERROR
197
+        assert 'original_error' in result
198
+        assert result['original_error'].error_details == {
199
+            'name': ['Missing data for required field.']
200
+        }

+ 2 - 9
tests/unit/test_processor.py View File

@@ -27,11 +27,6 @@ class TestProcessor(Base):
27 27
         assert data == tested_data
28 28
 
29 29
     def test_unit__marshmallow_output_processor__ok__missing_data(self):
30
-        """
31
-        Important note: Actually marshmallow don't validate when deserialize.
32
-        But we think about make it possible:
33
-        https://github.com/marshmallow-code/marshmallow/issues/684
34
-        """
35 30
         processor = MarshmallowOutputProcessor()
36 31
         processor.schema = MySchema()
37 32
 
@@ -39,10 +34,8 @@ class TestProcessor(Base):
39 34
             'last_name': 'Turing',
40 35
         }
41 36
 
42
-        data = processor.process(tested_data)
43
-        assert {
44
-            'last_name': 'Turing',
45
-        } == data
37
+        with pytest.raises(OutputValidationException):
38
+            processor.process(tested_data)
46 39
 
47 40
     def test_unit__marshmallow_input_processor__ok__process_success(self):
48 41
         processor = MarshmallowInputProcessor()