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)
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], )
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)
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)
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, )
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)
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__())
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)
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)
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
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)
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")
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)
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)
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)
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)
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)
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
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
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])
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])
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)
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, )
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)
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
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)
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)
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)