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
 
123
 
124
 
124
 
125
 class OutputControllerWrapper(ControllerWrapper):
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
     def get_error_response(
138
     def get_error_response(
127
         self,
139
         self,
128
         response: typing.Any,
140
         response: typing.Any,

+ 12 - 10
hapic/processor.py View File

54
 
54
 
55
 class MarshmallowOutputProcessor(OutputProcessor):
55
 class MarshmallowOutputProcessor(OutputProcessor):
56
     def process(self, data: typing.Any):
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
                 'Error when validate input: {}'.format(
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
     def get_validation_error(self, data: dict) -> ProcessValidationError:
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
         return ProcessValidationError(
73
         return ProcessValidationError(
72
             error_message='Validation error of output data',
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
 import typing
2
 import typing
3
 from http import HTTPStatus
3
 from http import HTTPStatus
4
 
4
 
5
+import marshmallow
6
+
5
 from hapic.context import ContextInterface
7
 from hapic.context import ContextInterface
6
 from hapic.data import HapicData
8
 from hapic.data import HapicData
7
 from hapic.decorator import ControllerWrapper
9
 from hapic.decorator import ControllerWrapper
8
 from hapic.decorator import InputControllerWrapper
10
 from hapic.decorator import InputControllerWrapper
9
 from hapic.decorator import OutputControllerWrapper
11
 from hapic.decorator import OutputControllerWrapper
10
 from hapic.processor import RequestParameters
12
 from hapic.processor import RequestParameters
13
+from hapic.processor import MarshmallowOutputProcessor
11
 from hapic.processor import ProcessValidationError
14
 from hapic.processor import ProcessValidationError
12
 from hapic.processor import ProcessorInterface
15
 from hapic.processor import ProcessorInterface
13
 from tests.base import Base
16
 from tests.base import Base
92
         hapic_data.query = processed_data
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
 class TestControllerWrapper(Base):
102
 class TestControllerWrapper(Base):
96
     def test_unit__base_controller_wrapper__ok__no_behaviour(self):
103
     def test_unit__base_controller_wrapper__ok__no_behaviour(self):
97
         context = MyContext()
104
         context = MyContext()
171
                    'http_code': HTTPStatus.OK,
178
                    'http_code': HTTPStatus.OK,
172
                    'original_response': 43,
179
                    'original_response': 43,
173
                } == result
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
         assert data == tested_data
27
         assert data == tested_data
28
 
28
 
29
     def test_unit__marshmallow_output_processor__ok__missing_data(self):
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
         processor = MarshmallowOutputProcessor()
30
         processor = MarshmallowOutputProcessor()
36
         processor.schema = MySchema()
31
         processor.schema = MySchema()
37
 
32
 
39
             'last_name': 'Turing',
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
     def test_unit__marshmallow_input_processor__ok__process_success(self):
40
     def test_unit__marshmallow_input_processor__ok__process_success(self):
48
         processor = MarshmallowInputProcessor()
41
         processor = MarshmallowInputProcessor()