def check_json_path(tolerance: Tolerance): """ Check the JSON path of a tolerance and raise :exc:`InvalidActivity` when the path is missing or invalid. See: https://github.com/h2non/jsonpath-ng """ if not HAS_JSONPATH: raise InvalidActivity( "Install the `jsonpath_ng` package to use a JSON path tolerance: " "`pip install chaostoolkit-lib[jsonpath]`.") if "path" not in tolerance: raise InvalidActivity( "hypothesis jsonpath probe tolerance must have a `path` key") try: path = tolerance.get("path") jparse.parse(path) except TypeError as t: raise InvalidActivity( "hypothesis probe tolerance path {} has an invalid type".format( path)) except JsonPathLexerError as e: raise InvalidActivity( "hypothesis probe tolerance JSON path '{}' is invalid: {}".format( str(e)))
def test_fields_value(self): jsonpath.auto_id_field = None result = parser.parse(self.string, debug=True).find(self.data) if isinstance(self.target, list): self.assertEqual(self.target, [r.value for r in result]) elif isinstance(self.target, set): self.assertEqual(self.target, set([r.value for r in result])) elif isinstance(self.target, (int, float)): self.assertEqual(self.target, result[0].value) else: self.assertEqual(self.target, result[0].value)
def check_paths(self, test_cases): # Note that just manually building an AST would avoid this dep and # isolate the tests, but that would suck a bit # Also, we coerce iterables, etc, into the desired target type for string, data, target in test_cases: print('parse("%s").find(%s).paths =?= %s' % (string, data, target)) result = parser.parse(string).find(data) if isinstance(target, list): assert [str(r.full_path) for r in result] == target elif isinstance(target, set): assert set([str(r.full_path) for r in result]) == target else: assert str(result.path) == target
def _(tolerance: dict, value: Any, secrets: Secrets = None) -> bool: tolerance_type = tolerance.get("type") if tolerance_type == "probe": tolerance["arguments"]["value"] = value run = run_activity(tolerance, secrets) return run["status"] == "succeeded" elif tolerance_type == "regex": target = tolerance.get("target") pattern = tolerance.get("pattern") rx = re.compile(pattern) if target: value = value.get(target, value) return rx.search(value) is not None elif tolerance_type == "jsonpath": target = tolerance.get("target") path = tolerance.get("path") count_value = tolerance.get("count", None) px = jparse.parse(path) if target: # if no target was provided, we use the tested value as-is value = value.get(target, value) if isinstance(value, bytes): value = value.decode('utf-8') if isinstance(value, str): try: value = json.loads(value) except json.decoder.JSONDecodeError: pass items = px.find(value) result = len(items) > 0 if count_value is not None: result = len(items) == count_value if "expect" in tolerance: expect = tolerance["expect"] values = [item.value for item in items] if len(values) == 1: result = expect in [values[0], values] else: result = values == expect return result
def _(tolerance: dict, value: Any, configuration: Configuration = None, secrets: Secrets = None) -> bool: tolerance_type = tolerance.get("type") if tolerance_type == "probe": tolerance["provider"]["arguments"]["value"] = value try: run_activity(tolerance, configuration, secrets) return True except ActivityFailed: return False elif tolerance_type == "regex": target = tolerance.get("target") pattern = tolerance.get("pattern") rx = re.compile(pattern) if target: value = value.get(target, value) return rx.search(value) is not None elif tolerance_type == "jsonpath": target = tolerance.get("target") path = tolerance.get("path") count_value = tolerance.get("count", None) px = jparse.parse(path) if target: # if no target was provided, we use the tested value as-is value = value.get(target, value) if isinstance(value, bytes): value = value.decode('utf-8') if isinstance(value, str): try: value = json.loads(value) except json.decoder.JSONDecodeError: pass items = px.find(value) result = len(items) > 0 if count_value is not None: result = len(items) == count_value if "expect" in tolerance: expect = tolerance["expect"] values = [item.value for item in items] if len(values) == 1: result = expect in [values[0], values] else: result = values == expect return result elif tolerance_type == "range": target = tolerance.get("target") if target: value = value.get(target, value) try: value = Decimal(value) except InvalidOperation: logger.debug("range check expects a number value") return False the_range = tolerance.get("range") min_value = the_range[0] max_value = the_range[1] return Decimal(min_value) <= value <= Decimal(max_value)
def json_path(path: str) -> JSONPath: return parser.parse(path, debug=settings.DEBUG)