def test_walk_array_items_with_primitive(primitive_type):
    test_schema = {"type": "array", "items": primitive_type}
    flattener = JsonSchemaFlattener({})
    result = flattener._walk(test_schema, ())

    assert result == test_schema
    assert not flattener._schema_map
def test_flatten_combiners_no_clobber(combiner):
    # https://github.com/awslabs/aws-cloudformation-rpdk/pull/92#discussion_r231348534
    ref = ("properties", "p2", combiner, 0)
    test_schema = {
        "typeName": "AWS::Valid::TypeName",
        "properties": {
            "p1": {
                "$ref": fragment_encode(ref)
            },
            "p2": {
                combiner: [
                    {
                        "properties": {
                            "a2": {
                                "type": "integer"
                            }
                        }
                    },
                    {
                        "properties": {
                            "b1": {
                                "type": "integer"
                            }
                        }
                    },
                ]
            },
        },
    }

    flattener = JsonSchemaFlattener(test_schema)
    flattener.flatten_schema()
    assert ref in flattener._schema_map
def test_flattener_full_example():
    test_schema = resource_json(__name__, "data/area_definition.json")

    flattener = JsonSchemaFlattener(test_schema)
    flattened = flattener.flatten_schema()

    assert flattened == AREA_DEFINITION_FLATTENED
def test_walk_pattern_properties_with_primitive(primitive_type):
    test_schema = {"patternProperties": {"a": primitive_type}}
    flattener = JsonSchemaFlattener({})
    result = flattener._walk(test_schema, ())

    assert result == test_schema
    assert not flattener._schema_map
def test_circular_reference_nested():
    test_schema = {
        "properties": {
            "a": {
                "properties": {
                    "b": {
                        "type": "string"
                    },
                    "c": {
                        "$ref": "#/properties/a"
                    }
                }
            }
        }
    }
    flattener = JsonSchemaFlattener(test_schema)
    flattened = flattener._walk({"$ref": "#/properties/a"}, ())

    assert flattened == {"$ref": ("properties", "a")}
    assert flattener._schema_map[("properties", "a")] == {
        "properties": {
            "b": {
                "type": "string"
            },
            "c": {
                "$ref": ("properties", "a")
            }
        }
    }
def test_walk_path_already_processed(path):
    flattener = JsonSchemaFlattener({})
    flattener._schema_map = {path: {}}
    result = flattener._walk({}, path)

    assert result == {"$ref": path}
    assert len(flattener._schema_map) == 1
def test_walk_ref_to_ref_to_primitive(primitive_type):
    test_schema = {"b": {"$ref": "#/c"}, "c": primitive_type}
    flattener = JsonSchemaFlattener(test_schema)
    result = flattener._walk({"$ref": "#/b"}, ())

    assert result == primitive_type
    assert not flattener._schema_map
def test_flatten_combiners_resolve_types_object_by_default(combiner):
    # this should fail, since we declare an object type and string type
    # https://github.com/aws-cloudformation/aws-cloudformation-rpdk/issues/333
    ref = ("definitions", "obj")
    test_schema = {
        "typeName": "AWS::Valid::TypeName",
        "definitions": {
            "obj": {
                "properties": {
                    "Foo": {
                        "type": "object"
                    }
                }
            }
        },
        "properties": {
            "p": {
                combiner: [{
                    "type": "string"
                }, {
                    "$ref": fragment_encode(ref)
                }]
            }
        },
    }

    flattener = JsonSchemaFlattener(test_schema)
    flattener.flatten_schema()
    assert ref in flattener._schema_map
def test_walk_ref_to_ref_object():
    test_schema = {"b": {"$ref": "#/c"}, "c": {"properties": {"a": {}}}}
    flattener = JsonSchemaFlattener(test_schema)
    result = flattener._walk({"$ref": "#/b"}, ())

    assert result == {"$ref": ("c", )}
    assert len(flattener._schema_map) == 1
    assert flattener._schema_map[("c", )] == {"properties": {"a": {}}}
Exemplo n.º 10
0
def test_walk_object(path):
    test_schema = {"properties": {"a": {}}}
    flattener = JsonSchemaFlattener({})
    result = flattener._walk(test_schema, path)

    assert result == {"$ref": path}
    assert len(flattener._schema_map) == 1
    assert flattener._schema_map[path] == test_schema
Exemplo n.º 11
0
def test_walk_ref_to_object():
    test_schema = {"a": {"properties": {"b": {}}}}

    flattener = JsonSchemaFlattener(test_schema)
    flattened = flattener._walk({"$ref": "#/a"}, ())

    assert flattened == {"$ref": ("a", )}
    assert len(flattener._schema_map) == 1
    assert flattener._schema_map[("a", )] == {"properties": {"b": {}}}
Exemplo n.º 12
0
def test_flatten_multiple_combiners():
    test_schema = {"z": None}
    expected = test_schema.copy()
    for letter, combiner in zip(string.ascii_lowercase, COMBINERS):
        test_schema[combiner] = [{letter: None}]
        expected[letter] = None

    flattener = JsonSchemaFlattener({})
    flattened = flattener._flatten_combiners(test_schema, ())
    assert flattened == expected
Exemplo n.º 13
0
def test_walk_pattern_properties_with_object(path):
    test_schema = {"patternProperties": {"a": {"properties": {"b": {}}}}}
    flattener = JsonSchemaFlattener({})
    result = flattener._walk(test_schema, path)

    ref_path = path + ("patternProperties", "a")

    assert result == {"patternProperties": {"a": {"$ref": ref_path}}}
    assert len(flattener._schema_map) == 1
    assert flattener._schema_map[ref_path] == {"properties": {"b": {}}}
Exemplo n.º 14
0
def test__flatten_ref_type_invalid():
    flattener = JsonSchemaFlattener({})
    patch_decode = patch(
        "rpdk.core.jsonutils.flattener.fragment_decode",
        autospec=True,
        side_effect=ValueError,
    )
    with patch_decode as mock_decode, pytest.raises(FlatteningError):
        flattener._flatten_ref_type("!")

    mock_decode.assert_called_once_with("!")
Exemplo n.º 15
0
def test_walk_array_items_with_object(path):
    test_schema = {"type": "array", "items": {"properties": {"b": {}}}}
    flattener = JsonSchemaFlattener({})
    result = flattener._walk(test_schema, path)

    ref_path = path + ("items", )

    expected_schema = {"type": "array", "items": {"$ref": ref_path}}

    assert result == expected_schema
    assert len(flattener._schema_map) == 1
    assert flattener._schema_map[ref_path] == {"properties": {"b": {}}}
Exemplo n.º 16
0
def test_flatten_combiners_single_level(combiner):
    test_schema = {
        "a": None,
        combiner: [{
            "b": None
        }, {
            "c": None
        }, {
            "d": None
        }]
    }
    flattener = JsonSchemaFlattener({})
    flattened = flattener._flatten_combiners(test_schema, ())
    assert flattened == {"a": None, "b": None, "c": None, "d": None}
Exemplo n.º 17
0
def test_contraint_object_properties_and_pattern_properties():
    flattener = JsonSchemaFlattener({})
    schema = {
        "properties": {
            "foo": {
                "type": "string"
            }
        },
        "patternProperties": {
            "type": "string"
        },
    }
    with pytest.raises(ConstraintError) as excinfo:
        flattener._flatten_object_type(schema, (UNIQUE_KEY, ))
    assert UNIQUE_KEY in str(excinfo.value)
Exemplo n.º 18
0
def test_walk_nested_properties(path):
    test_schema = {"properties": {"a": {"properties": {"b": {}}}}}
    flattener = JsonSchemaFlattener({})
    result = flattener._walk(test_schema, path)

    ref_path = path + ("properties", "a")

    assert result == {"$ref": path}
    assert len(flattener._schema_map) == 2
    assert flattener._schema_map[path] == {
        "properties": {
            "a": {
                "$ref": ref_path
            }
        }
    }
    assert flattener._schema_map[ref_path] == {"properties": {"b": {}}}
Exemplo n.º 19
0
def test_flatten_combiners_resolve_types(combiner):
    ref_type = ("definitions", "obj_type")
    ref = ("definitions", "obj")
    test_schema = {
        "typeName": "AWS::Valid::TypeName",
        "definitions": {
            "obj_type": {
                "type": "object"
            },
            "obj": {
                "properties": {
                    "Foo": {
                        "type": "object"
                    }
                }
            },
        },
        "properties": {
            "p": {
                combiner: [
                    {
                        "type": "string"
                    },
                    {
                        "type": "integer"
                    },
                    {
                        "$ref": fragment_encode(ref_type)
                    },
                ]
            },
            "p2": {
                combiner: [{
                    "type": "string"
                }, {
                    "$ref": fragment_encode(ref)
                }]
            },
        },
    }

    flattener = JsonSchemaFlattener(test_schema)
    flattener.flatten_schema()

    assert ref in flattener._schema_map
Exemplo n.º 20
0
def test_flatten_combiners_flattened_before_merge_failed_but_should_not(
        combiner):
    # this should not fail, since the refs are actually compatible with each other
    # https://github.com/aws-cloudformation/aws-cloudformation-rpdk/issues/333
    ref = ("definitions", "obj")
    ref2 = ("definitions", "obj2")
    test_schema = {
        "typeName": "AWS::Valid::TypeName",
        "definitions": {
            "obj": {
                "properties": {
                    "a": {
                        "type": "object"
                    }
                }
            },
            "obj2": {
                "properties": {
                    "a": {
                        "type": "object"
                    }
                }
            },
        },
        "properties": {
            "p": {
                combiner: [
                    {
                        "$ref": fragment_encode(ref)
                    },
                    {
                        "$ref": fragment_encode(ref2)
                    },
                ]
            }
        },
    }

    flattener = JsonSchemaFlattener(test_schema)
    with pytest.raises(ConstraintError) as excinfo:
        flattener.flatten_schema()
    assert "declared multiple values for '$ref'" in str(excinfo.value)
Exemplo n.º 21
0
def test_circular_reference_indirect():
    test_schema = {
        "properties": {
            "a": {
                "$ref": "#/properties/b"
            },
            "b": {
                "$ref": "#/properties/c"
            },
            "c": {
                "$ref": "#/properties/a"
            },
        }
    }
    flattener = JsonSchemaFlattener(test_schema)
    flattened_a = flattener._walk({"$ref": "#/properties/a"}, ())
    flattened_b = flattener._walk({"$ref": "#/properties/b"}, ())
    flattened_c = flattener._walk({"$ref": "#/properties/c"}, ())

    assert flattened_a == {"$ref": ("properties", "a")}
    assert flattened_b == {"$ref": ("properties", "b")}
    assert flattened_c == {"$ref": ("properties", "c")}
Exemplo n.º 22
0
def test_flattener_double_processed_refs():
    """The flattener uses references to indicate objects, but these
    references are not JSON pointer URI fragments. In some cases, such references
    may be fed back into the flattener, like if object B is nested inside
    object A with a combiner (``oneOf``).

    When the combiner is processed, B is (correctly) flattened into a distinct
    object and placed in the schema map. A reference to B is returned, as a tuple
    (``{'$ref': ('properties', 'A', 'oneOf', 0, 'properties', 'B')}``), from
    ``_flatten_object_type``. So when the combiners are flattened, the result is:
    ``{'properties': {'B': {'$ref': ('properties', 'A', 'oneOf', 0, 'properties',
    'B')}}}``.

    So when `_flatten_object_type` hits the `$ref`, it's important that
    ``_flatten_ref_type`` understands tuples, which is also tested, so this test
    is for showing that such a situation occurs in a normal, well-formed schema.
    """
    test_schema = resource_json(__name__,
                                "data/valid_refs_flattened_twice.json")

    flattener = JsonSchemaFlattener(test_schema)
    flattener.flatten_schema()
Exemplo n.º 23
0
def test_flatten_combiners_resolve_types(combiner):
    ref = ("definitions", "obj")
    test_schema = {
        "typeName": "AWS::Valid::TypeName",
        "definitions": {
            "obj": {
                "type": "object"
            }
        },
        "properties": {
            "p": {
                combiner: [{
                    "type": "string"
                }, {
                    "$ref": fragment_encode(ref)
                }]
            }
        },
    }

    flattener = JsonSchemaFlattener(test_schema)
    with pytest.raises(ConstraintError) as excinfo:
        flattener.flatten_schema()
    assert "declared multiple values for 'type'" in str(excinfo.value)
    def generate_docs(self):
        if (self.artifact_type == ARTIFACT_TYPE_MODULE
                or self.artifact_type == ARTIFACT_TYPE_HOOK):
            return

        # generate the docs folder that contains documentation based on the schema
        docs_path = self.root / "docs"

        if not self.type_info or not self.schema or "properties" not in self.schema:
            LOG.warning(
                "Could not generate schema docs due to missing type info or schema"
            )
            return

        LOG.debug("Removing generated docs: %s", docs_path)
        shutil.rmtree(docs_path, ignore_errors=True)
        docs_path.mkdir(exist_ok=True)

        LOG.debug("Writing generated docs")

        # take care not to modify the master schema
        docs_schema = json.loads(json.dumps(self.schema))
        self._flattened_schema = JsonSchemaFlattener(
            json.loads(json.dumps(self.schema))).flatten_schema()

        docs_schema["properties"] = {
            name: self._set_docs_properties(name, value, (name, ))
            for name, value in self._flattened_schema[(
            )]["properties"].items()
        }

        LOG.debug("Finished documenting nested properties")

        ref = self._get_docs_primary_identifier(docs_schema)
        getatt = self._get_docs_gettable_atts(docs_schema)

        readme_path = docs_path / "README.md"
        LOG.debug("Writing docs README: %s", readme_path)
        template = self.env.get_template("docs-readme.md")
        contents = template.render(type_name=self.type_name,
                                   schema=docs_schema,
                                   ref=ref,
                                   getatt=getatt)
        self.safewrite(readme_path, contents)
Exemplo n.º 25
0
def test_contraint_object_additional_properties_invalid():
    flattener = JsonSchemaFlattener({})
    schema = {"additionalProperties": {"type": "string"}}
    with pytest.raises(ConstraintError) as excinfo:
        flattener._flatten_object_type(schema, (UNIQUE_KEY, ))
    assert UNIQUE_KEY in str(excinfo.value)
Exemplo n.º 26
0
def test_contraint_array_additional_items_valid():
    flattener = JsonSchemaFlattener({})
    schema = {}
    result = flattener._flatten_array_type(schema, (UNIQUE_KEY, ))
    assert result == schema
Exemplo n.º 27
0
def test_contraint_object_additional_properties_valid():
    flattener = JsonSchemaFlattener({})
    schema = {}
    result = flattener._flatten_object_type(schema, (UNIQUE_KEY, ))
    assert result == schema
Exemplo n.º 28
0
def test_circular_reference_self():
    test_schema = {"properties": {"a": {"$ref": "#/properties/a"}}}
    flattener = JsonSchemaFlattener(test_schema)
    flattened = flattener._walk({"$ref": "#/properties/a"}, ())
    assert flattened == {"$ref": ("properties", "a")}
Exemplo n.º 29
0
def test__flatten_ref_type_string():
    sub_schema = {"type": "string"}
    flattener = JsonSchemaFlattener({"a": sub_schema})
    ret = flattener._flatten_ref_type("#/a")
    assert ret == sub_schema
Exemplo n.º 30
0
def test__flatten_ref_type_tuple():
    sub_schema = {"type": "string"}
    flattener = JsonSchemaFlattener({"a": sub_schema})
    ret = flattener._flatten_ref_type(("a", ))
    assert ret == sub_schema