예제 #1
0
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)))
예제 #2
0
 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)
예제 #3
0
    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
예제 #4
0
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
예제 #5
0
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)
예제 #6
0
 def json_path(path: str) -> JSONPath:
     return parser.parse(path, debug=settings.DEBUG)