コード例 #1
0
 def test_wrong_duplicate(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(
         self.load_file("markdown/parameter_wrong_duplicate/http.yaml"))
     semconv.parse(
         self.load_file("markdown/parameter_wrong_duplicate/faas.yaml"))
     semconv.parse(
         self.load_file("markdown/parameter_wrong_duplicate/general.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 7)
     with open(
             self.load_file("markdown/parameter_wrong_duplicate/input.md"),
             "r") as markdown:
         content = markdown.read()
     expected = ""
     with self.assertRaises(ValueError) as ex:
         self.check_render(
             semconv,
             "markdown/parameter_wrong_duplicate/",
             "markdown/parameter_wrong_duplicate/input.md",
             content,
             expected,
         )
         self.fail()
     e = ex.exception
     msg = e.args[0]
     self.assertIn("Parameter", msg)
     self.assertIn("already defined", msg)
コード例 #2
0
 def test_event(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(self.load_file("yaml/event.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 1)
     event = list(semconv.models.values())[0]
     expected = {
         "id":
         "exception",
         "prefix":
         "exception",
         "extends":
         "",
         "n_constraints":
         1,
         "attributes": [
             "exception.type",
             "exception.message",
             "exception.stacktrace",
             "exception.escaped",
         ],
     }
     self.semantic_convention_check(event, expected)
     constraint = event.constraints[0]
     self.assertIsInstance(constraint, AnyOf)
     constraint: AnyOf
     for choice_index, attr_list in enumerate(constraint.choice_list_ids):
         for attr_index, attr in enumerate(attr_list):
             self.assertEqual(
                 event.attrs_by_name.get(attr),
                 constraint.choice_list_attributes[choice_index]
                 [attr_index],
             )
コード例 #3
0
    def test_populate_other_attributes(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/http.yaml"))
        semconv.parse(self.load_file("yaml/faas.yaml"))
        semconv.parse(self.load_file("yaml/general.yaml"))
        semconv.finish()
        models = sorted(semconv.models.values(), key=lambda m: m.semconv_id)
        self.assertEqual(len(models), 10)
        self.assertEqual(len(models[0].constraints), 0)
        self.assertEqual(len(models[1].constraints), 0)

        self.assertEqual(len(models[2].constraints), 2)
        self.assertTrue(isinstance(models[2].constraints[0], Include))
        self.assertEqual(len(models[2].constraints[1].choice_list_attributes),
                         4)

        self.assertEqual(len(models[3].constraints), 0)
        self.assertEqual(len(models[4].constraints), 0)
        self.assertEqual(len(models[5].constraints), 0)

        self.assertEqual(len(models[6].constraints), 1)
        self.assertEqual(len(models[6].constraints[0].choice_list_attributes),
                         4)

        self.assertEqual(len(models[7].constraints), 1)
        self.assertEqual(len(models[6].constraints[0].choice_list_attributes),
                         4)

        self.assertEqual(len(models[8].constraints), 0)
        self.assertEqual(len(models[9].constraints), 0)
コード例 #4
0
 def test_id_clash(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(self.load_file("yaml/errors/id_clash/span_faas.yaml"))
     semconv.parse(
         self.load_file("yaml/errors/id_clash/resource_faas.yaml"))
     semconv.finish()
     self.assertTrue(semconv.errors)
コード例 #5
0
 def test_parameter_remove_constraint(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(
         self.load_file(
             "markdown/parameter_remove_constraint/database.yaml"))
     semconv.parse(
         self.load_file(
             "markdown/parameter_remove_constraint/general.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 6)
     with open(
             self.load_file(
                 "markdown/parameter_remove_constraint/input.md"),
             "r") as markdown:
         content = markdown.read()
     with open(
             self.load_file(
                 "markdown/parameter_remove_constraint/expected.md"),
             "r") as markdown:
         expected = markdown.read()
     self.check_render(
         semconv,
         "markdown/parameter_remove_constraint/",
         "markdown/parameter_remove_constraint/input.md",
         content,
         expected,
     )
コード例 #6
0
    def test_include(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/http.yaml"))
        semconv.parse(self.load_file("yaml/faas.yaml"))
        semconv.parse(self.load_file("yaml/general.yaml"))
        semconv.finish()
        self.assertEqual(len(semconv.models), 10)

        faas_http = [s for s in semconv.models.values() if s.semconv_id == "faas.http"][
            0
        ]
        expected = {
            "id": "faas.http",
            "prefix": "faas",
            "extends": "faas",
            "n_constraints": 2,
            "attributes": [
                # Parent
                "faas.trigger",
                "faas.execution",
                # Include
                "http.method",
                "http.url",
                "http.target",
                "http.host",
                "http.scheme",
                "http.status_code",
                "http.status_text",
                "http.flavor",
                "http.user_agent",
                "http.server_name",
            ],
        }
        self.semantic_convention_check(faas_http, expected)
コード例 #7
0
 def test_markdown_link(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(self.load_file("yaml/links.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 1)
     s = list(semconv.models.values())[0]
     for attr in s.attributes:
         brief = attr.brief
         self.assertEqual(brief.raw_text, brief.__str__())
コード例 #8
0
 def test_missing_event(self):
     with self.assertRaises(ValidationError) as ex:
         semconv = SemanticConventionSet(debug=False)
         semconv.parse(
             self.load_file("yaml/errors/events/missing_event.yaml"))
         semconv.finish()
     e = ex.exception
     msg = e.message.lower()
     self.assertIn("as event but the latter cannot be found!", msg)
     self.assertEqual(e.line, 2)
コード例 #9
0
 def test_validate_anyof_attributes(self):
     with self.assertRaises(ValidationError) as ex:
         semconv = SemanticConventionSet(debug=False)
         semconv.parse(self.load_file("yaml/errors/validate_anyof.yaml"))
         semconv.finish()
     e = ex.exception
     msg = e.message.lower()
     self.assertIn("any_of attribute", msg)
     self.assertIn("does not exists", msg)
     self.assertEqual(e.line, 15)
コード例 #10
0
def parse_semconv(args, parser) -> SemanticConventionSet:
    semconv = SemanticConventionSet(args.debug)
    find_yaml(args)
    for file in sorted(args.files):
        if not file.endswith(".yaml") and not file.endswith(".yml"):
            parser.error("{} is not a yaml file.".format(file))
        semconv.parse(file)
    semconv.finish()
    if semconv.has_error():
        sys.exit(1)
    return semconv
コード例 #11
0
    def test_units(self):
        semconv = SemanticConventionSet(debug=True)
        semconv.parse(self.load_file("yaml/metrics/units.yaml"))
        semconv.finish()

        assert len(semconv.models) == 1

        content = self.read_file("markdown/metrics/units_input.md")
        expected = self.read_file("markdown/metrics/units_output.md")
        self.check_render(semconv, "markdown/metrics/",
                          "markdown/metrics/units_input.md", content, expected)
コード例 #12
0
    def test_extends_prefix(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/extends/http.yaml"))
        semconv.parse(self.load_file("yaml/extends/child.http.yaml"))
        semconv.finish()
        self.assertEqual(len(semconv.models), 3)

        base = list(semconv.models.values())[1]
        child = list(semconv.models.values())[2]
        self.assertEqual(base.prefix, "http")
        self.assertEqual(child.prefix, "child.http")
コード例 #13
0
    def test_deprecation(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/deprecated/http.yaml"))
        semconv.finish()
        self.assertEqual(len(semconv.models), 1)

        self.assertIsNotNone(list(semconv.models.values())[0].attributes[0].deprecated)
        self.assertEqual(
            list(semconv.models.values())[0].attributes[0].deprecated,
            "Use attribute `nonDepecrated`.",
        )
        self.assertIsNone(list(semconv.models.values())[0].attributes[3].deprecated)
コード例 #14
0
 def test_wrong_event_type(self):
     with self.assertRaises(ValidationError) as ex:
         semconv = SemanticConventionSet(debug=False)
         semconv.parse(
             self.load_file("yaml/errors/events/no_event_type.yaml"))
         semconv.finish()
     e = ex.exception
     msg = e.message.lower()
     self.assertIn(
         "as event but the latter is not a semantic convention for events",
         msg)
     self.assertEqual(e.line, 2)
コード例 #15
0
 def testExampleArray(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(self.load_file("markdown/example_array/http.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 1)
     with open(self.load_file("markdown/example_array/input.md"),
               "r") as markdown:
         content = markdown.read()
     with open(self.load_file("markdown/example_array/expected.md"),
               "r") as markdown:
         expected = markdown.read()
     self.check_render(semconv, "markdown/example_array/",
                       "markdown/example_array/input.md", content, expected)
コード例 #16
0
    def test_ref(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/rpc.yaml"))
        semconv.parse(self.load_file("yaml/general.yaml"))
        semconv.finish()
        self.assertEqual(len(semconv.models), 5)

        client = list(semconv.models.values())[1]
        server = list(semconv.models.values())[2]
        self.assertIsNotNone(client.attributes[1].ref)
        self.assertIsNotNone(client.attributes[1].attr_type)

        self.assertIsNotNone(server.attributes[1].ref)
        self.assertIsNotNone(server.attributes[1].attr_type)
コード例 #17
0
    def test_numeric_attributes(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/numeric_attributes.yml"))
        semconv.finish()
        self.assertEqual(len(semconv.models), 1)

        expected = {
            "id": "test",
            "prefix": "test",
            "extends": "",
            "n_constraints": 0,
            "attributes": ["test.one", "test.two"],
        }
        self.semantic_convention_check(
            list(semconv.models.values())[0], expected)
コード例 #18
0
def test_codegen_units(test_file_path, read_test_file):
    semconv = SemanticConventionSet(debug=False)
    semconv.parse(test_file_path("yaml", "metrics", "units.yaml"))
    semconv.finish()

    template_path = test_file_path("jinja", "metrics", "units_template")
    renderer = CodeRenderer({})

    output = io.StringIO()
    renderer.render(semconv, template_path, output, None)
    result = output.getvalue()

    expected = read_test_file("jinja", "metrics", "expected.java")

    assert result == expected
コード例 #19
0
    def testRef(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("markdown/ref/general.yaml"))
        semconv.parse(self.load_file("markdown/ref/rpc.yaml"))
        semconv.finish()
        self.assertEqual(len(semconv.models), 5)
        md = self.load_file("markdown/ref/input/input_rpc.md")
        with open(md, "r") as markdown:
            content = markdown.read()
        renderer = MarkdownRenderer(self.load_file("markdown/ref/input"),
                                    semconv)
        output = io.StringIO()
        renderer._render_single_file(content, md, output)
        with open(self.load_file("markdown/ref/expected.md"), "r") as markdown:
            expected = markdown.read()

        assert output.getvalue() == expected
コード例 #20
0
 def test_error_missing_end(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(self.load_file("markdown/missing_end_tag/http.yaml"))
     semconv.parse(self.load_file("markdown/missing_end_tag/general.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 5)
     with open(self.load_file("markdown/missing_end_tag/input.md"),
               "r") as markdown:
         content = markdown.read()
     with self.assertRaises(Exception) as ex:
         renderer = MarkdownRenderer(
             self.load_file("markdown/missing_end_tag/"), semconv)
         renderer._render_single_file(content,
                                      "markdown/missing_end_tag/input.md",
                                      io.StringIO())
     self.assertEqual("Missing ending <!-- endsemconv --> tag",
                      ex.exception.args[0])
コード例 #21
0
 def test_error_wrong_id(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(self.load_file("markdown/wrong_semconv_id/http.yaml"))
     semconv.parse(self.load_file("markdown/wrong_semconv_id/general.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 5)
     with open(self.load_file("markdown/wrong_semconv_id/input.md"),
               "r") as markdown:
         content = markdown.read()
     with self.assertRaises(Exception) as ex:
         renderer = MarkdownRenderer(
             self.load_file("markdown/wrong_semconv_id/"), semconv)
         renderer._render_single_file(content,
                                      "markdown/wrong_semconv_id/input.md",
                                      io.StringIO())
     self.assertEqual("Semantic Convention ID db not found",
                      ex.exception.args[0])
コード例 #22
0
    def test_stability(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/stability.yaml"))
        semconv.finish()
        self.assertEqual(len(semconv.models), 6)

        model = list(semconv.models.values())[0]
        self.assertEqual(len(model.attributes), 4)
        self.assertEqual(model.stability, None)

        attr = model.attributes[0]
        self.assertEqual(attr.attr_id, "exp_attr")
        self.assertEqual(attr.stability, StabilityLevel.EXPERIMENTAL)

        attr = model.attributes[1]
        self.assertEqual(attr.attr_id, "stable_attr")
        self.assertEqual(attr.stability, StabilityLevel.STABLE)

        attr = model.attributes[2]
        self.assertEqual(attr.attr_id, "deprecated_attr")
        self.assertEqual(attr.stability, StabilityLevel.DEPRECATED)

        attr = model.attributes[3]
        self.assertEqual(attr.attr_id, "def_stability")
        self.assertEqual(attr.stability, StabilityLevel.STABLE)

        model = list(semconv.models.values())[1]
        self.assertEqual(len(model.attributes), 2)
        self.assertEqual(model.stability, StabilityLevel.EXPERIMENTAL)

        attr = model.attributes[0]
        self.assertEqual(attr.attr_id, "test_attr")
        self.assertEqual(attr.stability, StabilityLevel.EXPERIMENTAL)

        attr = model.attributes[1]
        self.assertEqual(attr.attr_id, "dep")
        self.assertEqual(attr.stability, StabilityLevel.DEPRECATED)

        model = list(semconv.models.values())[2]
        self.assertEqual(len(model.attributes), 1)
        self.assertEqual(model.stability, StabilityLevel.DEPRECATED)

        attr = model.attributes[0]
        self.assertEqual(attr.attr_id, "test_attr")
        self.assertEqual(attr.stability, StabilityLevel.DEPRECATED)
コード例 #23
0
 def testSingle(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(self.load_file("markdown/single/http.yaml"))
     semconv.parse(self.load_file("markdown/single/general.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 5)
     with open(self.load_file("markdown/single/input.md"), "r") as markdown:
         content = markdown.read()
     with open(self.load_file("markdown/single/expected.md"),
               "r") as markdown:
         expected = markdown.read()
     self.check_render(
         semconv,
         "markdown/single/",
         "markdown/single/input.md",
         content,
         expected,
     )
コード例 #24
0
 def test_span_with_event(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(self.load_file("yaml/event.yaml"))
     semconv.parse(self.load_file("yaml/span_event.yaml"))
     semconv.finish()
     self.assertEqual(len(semconv.models), 3)
     semconvs = list(semconv.models.values())
     self.assertTrue(isinstance(semconvs[0], EventSemanticConvention))
     self.assertTrue(isinstance(semconvs[1], SpanSemanticConvention))
     self.assertTrue(isinstance(semconvs[2], EventSemanticConvention))
     event_semconv = semconvs[1]
     self.assertEqual(2, len(event_semconv.events))
     self.assertTrue(
         isinstance(event_semconv.events[0], EventSemanticConvention))
     self.assertTrue(
         isinstance(event_semconv.events[1], EventSemanticConvention))
     self.assertEqual("exception", event_semconv.events[0].semconv_id)
     self.assertEqual("random.event", event_semconv.events[1].semconv_id)
コード例 #25
0
    def check(
        self,
        input_dir: str,
        options=MarkdownOptions(),
        *,
        expected_name="expected.md",
        extra_yaml_dirs: Sequence[str] = (),
        assert_raises=None
    ) -> Optional[BaseException]:
        dirpath = Path(self.get_file_path(input_dir))
        if not dirpath.is_dir():
            raise ValueError(
                "Input dir does not exist (or is not a dir): " + str(dirpath)
            )
        semconv = SemanticConventionSet(debug=True)
        for fname in dirpath.glob("*.yaml"):
            print("Parsing", fname)
            semconv.parse(fname)
        for extra_dir in extra_yaml_dirs:
            for fname in Path(self.get_file_path(extra_dir)).glob("*.yaml"):
                print("Parsing", fname)
                semconv.parse(fname)

        semconv.finish()

        inputpath = dirpath / "input.md"

        output = io.StringIO()

        def do_render():
            renderer = MarkdownRenderer(str(dirpath), semconv, options)
            renderer._render_single_file(
                inputpath.read_text(encoding="utf-8"), str(inputpath), output
            )

        if assert_raises:
            with self.assertRaises(assert_raises) as ex:
                do_render()
            return ex.exception
        do_render()
        result = output.getvalue()
        assert result == (dirpath / expected_name).read_text(encoding="utf-8")
        return None
コード例 #26
0
 def test_attribute_id_clash_inherited(self):
     semconv = SemanticConventionSet(debug=False)
     semconv.parse(
         self.load_file("yaml/errors/id_clash/httpInherited.yaml"))
     semconv.finish()
     self.assertTrue(semconv.errors)
コード例 #27
0
    def test_extends(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/http.yaml"))
        semconv.parse(self.load_file("yaml/general.yaml"))
        semconv.finish()
        self.assertEqual(len(semconv.models), 5)

        expected = {
            "id":
            "http",
            "prefix":
            "http",
            "extends":
            "",
            "n_constraints":
            0,
            "attributes": [
                "http.method",
                "http.url",
                "http.target",
                "http.host",
                "http.scheme",
                "http.status_code",
                "http.status_text",
                "http.flavor",
                "http.user_agent",
            ],
        }
        self.semantic_convention_check(
            list(semconv.models.values())[0], expected)
        expected = {
            "id":
            "http.client",
            "prefix":
            "http",
            "extends":
            "http",
            "n_constraints":
            1,
            "attributes": [
                "http.method",
                "http.url",
                "http.target",
                "http.host",
                "http.scheme",
                "http.status_code",
                "http.status_text",
                "http.flavor",
                "http.user_agent",
            ],
        }
        self.semantic_convention_check(
            list(semconv.models.values())[1], expected)
        expected = {
            "id":
            "http.server",
            "prefix":
            "http",
            "extends":
            "http",
            "n_constraints":
            1,
            "attributes": [
                "http.method",
                "http.url",
                "http.target",
                "http.host",
                "http.scheme",
                "http.status_code",
                "http.status_text",
                "http.flavor",
                "http.user_agent",
                "http.server_name",
            ],
        }
        self.semantic_convention_check(
            list(semconv.models.values())[2], expected)
コード例 #28
0
    def test_inherited_imported(self):
        semconv = SemanticConventionSet(debug=False)
        semconv.parse(self.load_file("yaml/imported-inherited.yaml"))
        semconv.finish()
        models = sorted(semconv.models.values(), key=lambda m: m.semconv_id)
        self.assertEqual(len(models), 6)
        # HTTP
        attrs = models[0].attributes
        self.assertEqual(models[0].semconv_id, "http")
        self.assertEqual(len(attrs), 2)

        self.assertEqual(attrs[0].fqn, "http.method")
        self.assertEqual(attrs[0].imported, False)
        self.assertEqual(attrs[0].inherited, False)
        self.assertEqual(attrs[0].ref, None)

        self.assertEqual(attrs[1].fqn, "net.peer.port")
        self.assertEqual(attrs[1].imported, False)
        self.assertEqual(attrs[1].inherited, False)
        self.assertEqual(attrs[1].ref, "net.peer.port")

        # Network
        attrs = models[1].attributes
        self.assertEqual(models[1].semconv_id, "network")
        self.assertEqual(len(attrs), 3)

        self.assertEqual(attrs[0].fqn, "net.peer.ip")
        self.assertEqual(attrs[0].imported, False)
        self.assertEqual(attrs[0].inherited, False)
        self.assertEqual(attrs[0].ref, None)

        self.assertEqual(attrs[1].fqn, "net.peer.port")
        self.assertEqual(attrs[1].imported, False)
        self.assertEqual(attrs[1].inherited, False)
        self.assertEqual(attrs[1].ref, None)
        self.assertEqual(attrs[1].note, "not override")

        self.assertEqual(attrs[2].fqn, "net.peer.name")
        self.assertEqual(attrs[2].imported, False)
        self.assertEqual(attrs[2].inherited, False)
        self.assertEqual(attrs[2].ref, None)

        # Base - rpc
        attrs = models[2].attributes
        self.assertEqual(models[2].semconv_id, "rpc")
        self.assertEqual(len(attrs), 4)
        # Included attributes
        self.assertEqual(attrs[0].fqn, "net.peer.ip")
        self.assertEqual(attrs[0].imported, True)
        self.assertEqual(attrs[0].inherited, False)
        self.assertEqual(attrs[0].ref, None)

        self.assertEqual(attrs[1].fqn, "net.peer.port")
        self.assertEqual(attrs[1].imported, True)
        self.assertEqual(attrs[1].inherited, False)
        self.assertEqual(attrs[1].ref, None)
        self.assertEqual(attrs[1].note, "not override")

        self.assertEqual(attrs[2].fqn, "net.peer.name")
        self.assertEqual(attrs[2].imported, True)
        self.assertEqual(attrs[2].inherited, False)
        self.assertEqual(attrs[2].ref, None)
        # Defined attributes
        self.assertEqual(attrs[3].fqn, "rpc.service")
        self.assertEqual(attrs[3].imported, False)
        self.assertEqual(attrs[3].inherited, False)
        self.assertEqual(attrs[3].ref, None)

        # Extended - rpc.client
        attrs = models[3].attributes
        self.assertEqual(models[3].semconv_id, "rpc.client")
        self.assertEqual(len(attrs), 6)
        # Parent attributes
        self.assertEqual(attrs[0].fqn, "net.peer.ip")
        self.assertEqual(attrs[0].imported, True)
        self.assertEqual(attrs[0].inherited, True)
        self.assertEqual(attrs[0].ref, None)

        self.assertEqual(attrs[1].fqn, "net.peer.port")
        self.assertEqual(attrs[1].imported, False)
        self.assertEqual(attrs[1].inherited, False)
        self.assertEqual(attrs[1].ref, "net.peer.port")
        self.assertEqual(attrs[1].brief, "override")
        self.assertEqual(attrs[1].note, "not override")

        self.assertEqual(attrs[2].fqn, "net.peer.name")
        self.assertEqual(attrs[2].imported, True)
        self.assertEqual(attrs[2].inherited, True)
        self.assertEqual(attrs[2].ref, None)

        self.assertEqual(attrs[3].fqn, "rpc.service")
        self.assertEqual(attrs[3].imported, False)
        self.assertEqual(attrs[3].inherited, True)
        self.assertEqual(attrs[3].ref, None)
        # Included attributes
        self.assertEqual(attrs[4].fqn, "http.method")
        self.assertEqual(attrs[4].imported, True)
        self.assertEqual(attrs[4].inherited, False)
        self.assertEqual(attrs[4].ref, None)
        # Defined attributes
        self.assertEqual(attrs[5].fqn, "rpc.client.name")
        self.assertEqual(attrs[5].imported, False)
        self.assertEqual(attrs[5].inherited, False)
        self.assertEqual(attrs[5].ref, None)

        # Include on Extended - zother
        attrs = models[4].attributes
        self.assertEqual(models[4].semconv_id, "zother")
        self.assertEqual(len(attrs), 1)
        # Defined attributes
        self.assertEqual(attrs[0].fqn, "zother.hostname")
        self.assertEqual(attrs[0].imported, False)
        self.assertEqual(attrs[0].inherited, False)
        self.assertEqual(attrs[0].ref, None)

        # Include on Extended - zz.rpc.client
        attrs = models[5].attributes
        self.assertEqual(models[5].semconv_id, "zz.rpc.client")
        self.assertEqual(len(attrs), 8)
        # Parent attributes
        self.assertEqual(attrs[0].fqn, "net.peer.ip")
        self.assertEqual(attrs[0].imported, True)
        self.assertEqual(attrs[0].inherited, True)
        self.assertEqual(attrs[0].ref, None)

        self.assertEqual(attrs[1].fqn, "net.peer.port")
        self.assertEqual(attrs[1].imported, False)
        self.assertEqual(attrs[1].inherited, True)
        self.assertEqual(attrs[1].ref, "net.peer.port")
        self.assertEqual(attrs[1].brief, "override")
        self.assertEqual(attrs[1].note, "not override")

        self.assertEqual(attrs[2].fqn, "net.peer.name")
        self.assertEqual(attrs[2].imported, True)
        self.assertEqual(attrs[2].inherited, True)
        self.assertEqual(attrs[2].ref, None)

        self.assertEqual(attrs[3].fqn, "rpc.service")
        self.assertEqual(attrs[3].imported, False)
        self.assertEqual(attrs[3].inherited, True)
        self.assertEqual(attrs[3].ref, None)

        self.assertEqual(attrs[4].fqn, "http.method")
        self.assertEqual(attrs[4].imported, True)
        self.assertEqual(attrs[4].inherited, True)
        self.assertEqual(attrs[4].ref, None)

        self.assertEqual(attrs[5].fqn, "rpc.client.name")
        self.assertEqual(attrs[5].imported, False)
        self.assertEqual(attrs[5].inherited, True)
        self.assertEqual(attrs[5].ref, None)
        # Included attributes
        self.assertEqual(attrs[6].fqn, "zother.hostname")
        self.assertEqual(attrs[6].imported, True)
        self.assertEqual(attrs[6].inherited, False)
        self.assertEqual(attrs[6].ref, None)
        # Defined attributes
        self.assertEqual(attrs[7].fqn, "rpc.client.zz.attr")
        self.assertEqual(attrs[7].imported, False)
        self.assertEqual(attrs[7].inherited, False)
        self.assertEqual(attrs[7].ref, None)