Browse Source

Sanitize data when git it to schema. Closes #22

Bastien Sevajol 6 years ago
parent
commit
7fecf1a1eb
3 changed files with 68 additions and 12 deletions
  1. 24 11
      hapic/processor.py
  2. 1 1
      setup.py
  3. 43 0
      tests/unit/test_processor.py

+ 24 - 11
hapic/processor.py View File

44
         raise NotImplementedError
44
         raise NotImplementedError
45
 
45
 
46
 
46
 
47
-class InputProcessor(ProcessorInterface):
47
+class Processor(ProcessorInterface):
48
+    @classmethod
49
+    def clean_data(cls, data: typing.Any) -> dict:
50
+        # Fixes #22: Schemas make not validation if None is given
51
+        if data is None:
52
+            return {}
53
+        return data
54
+
55
+
56
+class InputProcessor(Processor):
48
     pass
57
     pass
49
 
58
 
50
 
59
 
51
-class OutputProcessor(ProcessorInterface):
60
+class OutputProcessor(Processor):
52
     pass
61
     pass
53
 
62
 
54
 
63
 
55
 class MarshmallowOutputProcessor(OutputProcessor):
64
 class MarshmallowOutputProcessor(OutputProcessor):
56
     def process(self, data: typing.Any):
65
     def process(self, data: typing.Any):
57
-        data = self.schema.dump(data).data
58
-        self.validate(data)
59
-        return data
66
+        clean_data = self.clean_data(data)
67
+        dump_data = self.schema.dump(clean_data).data
68
+        self.validate(dump_data)
69
+        return dump_data
60
 
70
 
61
     def validate(self, data: typing.Any) -> None:
71
     def validate(self, data: typing.Any) -> None:
62
-        errors = self.schema.load(data).errors
72
+        clean_data = self.clean_data(data)
73
+        errors = self.schema.load(clean_data).errors
63
         if errors:
74
         if errors:
64
             raise OutputValidationException(
75
             raise OutputValidationException(
65
                 'Error when validate input: {}'.format(
76
                 'Error when validate input: {}'.format(
68
             )
79
             )
69
 
80
 
70
     def get_validation_error(self, data: dict) -> ProcessValidationError:
81
     def get_validation_error(self, data: dict) -> ProcessValidationError:
71
-        data = self.schema.dump(data).data
72
-        errors = self.schema.load(data).errors
82
+        clean_data = self.clean_data(data)
83
+        dump_data = self.schema.dump(clean_data).data
84
+        errors = self.schema.load(dump_data).errors
73
         return ProcessValidationError(
85
         return ProcessValidationError(
74
             message='Validation error of output data',
86
             message='Validation error of output data',
75
             details=errors,
87
             details=errors,
78
 
90
 
79
 class MarshmallowInputProcessor(InputProcessor):
91
 class MarshmallowInputProcessor(InputProcessor):
80
     def process(self, data: dict):
92
     def process(self, data: dict):
81
-        unmarshall = self.schema.load(data)
93
+        clean_data = self.clean_data(data)
94
+        unmarshall = self.schema.load(clean_data)
82
         if unmarshall.errors:
95
         if unmarshall.errors:
83
             raise OutputValidationException(
96
             raise OutputValidationException(
84
                 'Error when validate ouput: {}'.format(
97
                 'Error when validate ouput: {}'.format(
89
         return unmarshall.data
102
         return unmarshall.data
90
 
103
 
91
     def get_validation_error(self, data: dict) -> ProcessValidationError:
104
     def get_validation_error(self, data: dict) -> ProcessValidationError:
92
-        marshmallow_errors = self.schema.load(data).errors
105
+        clean_data = self.clean_data(data)
106
+        marshmallow_errors = self.schema.load(clean_data).errors
93
         return ProcessValidationError(
107
         return ProcessValidationError(
94
             message='Validation error of input data',
108
             message='Validation error of input data',
95
             details=marshmallow_errors,
109
             details=marshmallow_errors,
96
         )
110
         )
97
-

+ 1 - 1
setup.py View File

23
     # Versions should comply with PEP440.  For a discussion on single-sourcing
23
     # Versions should comply with PEP440.  For a discussion on single-sourcing
24
     # the version across setup.py and the project code, see
24
     # the version across setup.py and the project code, see
25
     # https://packaging.python.org/en/latest/single_source_version.html
25
     # https://packaging.python.org/en/latest/single_source_version.html
26
-    version='0.0.4.1',
26
+    version='0.4.2',
27
 
27
 
28
     description='HTTP api input/output manager',
28
     description='HTTP api input/output manager',
29
     # long_description=long_description,
29
     # long_description=long_description,

+ 43 - 0
tests/unit/test_processor.py View File

54
         processor.schema = MySchema()
54
         processor.schema = MySchema()
55
 
55
 
56
         tested_data = {
56
         tested_data = {
57
+            # Missing 'first_name' key
57
             'last_name': 'Turing',
58
             'last_name': 'Turing',
58
         }
59
         }
59
 
60
 
64
         assert errors.details
65
         assert errors.details
65
         assert 'first_name' in errors.details
66
         assert 'first_name' in errors.details
66
 
67
 
68
+    def test_unit__marshmallow_input_processor__error__validation_error_no_data(self):  # nopep8
69
+        processor = MarshmallowInputProcessor()
70
+        processor.schema = MySchema()
71
+
72
+        # Schema will not valid it because require first_name field
73
+        tested_data = {}
74
+
75
+        with pytest.raises(OutputValidationException):
76
+            processor.process(tested_data)
77
+
78
+        errors = processor.get_validation_error(tested_data)
79
+        assert errors.details
80
+        assert 'first_name' in errors.details
81
+
82
+    def test_unit__marshmallow_input_processor__error__validation_error_no_data_none(self):  # nopep8
83
+        processor = MarshmallowInputProcessor()
84
+        processor.schema = MySchema()
85
+
86
+        # Schema will not valid it because require first_name field
87
+        tested_data = None
88
+
89
+        with pytest.raises(OutputValidationException):
90
+            processor.process(tested_data)
91
+
92
+        errors = processor.get_validation_error(tested_data)
93
+        assert errors.details
94
+        assert 'first_name' in errors.details
95
+
96
+    def test_unit__marshmallow_input_processor__error__validation_error_no_data_empty_string(self):  # nopep8
97
+        processor = MarshmallowInputProcessor()
98
+        processor.schema = MySchema()
99
+
100
+        # Schema will not valid it because require first_name field
101
+        tested_data = ''
102
+
103
+        with pytest.raises(OutputValidationException):
104
+            processor.process(tested_data)
105
+
106
+        errors = processor.get_validation_error(tested_data)
107
+        assert errors.details
108
+        assert {'_schema': ['Invalid input type.']} == errors.details
109
+
67
     def test_unit__marshmallow_input_processor__ok__completed_data(self):
110
     def test_unit__marshmallow_input_processor__ok__completed_data(self):
68
         processor = MarshmallowInputProcessor()
111
         processor = MarshmallowInputProcessor()
69
         processor.schema = MySchema()
112
         processor.schema = MySchema()