From 91575b8db60ca4fc6df9f44fa720929d8c3868ac Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Mon, 25 Feb 2019 00:21:40 +0100 Subject: use TagSet as the implementation for Context tags --- .../kamon/context/BinaryPropagationSpec.scala | 12 +- .../scala/kamon/context/HttpPropagationSpec.scala | 21 +-- .../HttpServerInstrumentationSpec.scala | 13 +- .../src/test/scala/kamon/tag/TagSetSpec.scala | 180 +++++++++++++++++++++ .../src/test/scala/kamon/tag/TagsSpec.scala | 180 --------------------- 5 files changed, 204 insertions(+), 202 deletions(-) create mode 100644 kamon-core-tests/src/test/scala/kamon/tag/TagSetSpec.scala delete mode 100644 kamon-core-tests/src/test/scala/kamon/tag/TagsSpec.scala (limited to 'kamon-core-tests') diff --git a/kamon-core-tests/src/test/scala/kamon/context/BinaryPropagationSpec.scala b/kamon-core-tests/src/test/scala/kamon/context/BinaryPropagationSpec.scala index 5681d300..4fa7116d 100644 --- a/kamon-core-tests/src/test/scala/kamon/context/BinaryPropagationSpec.scala +++ b/kamon-core-tests/src/test/scala/kamon/context/BinaryPropagationSpec.scala @@ -6,6 +6,8 @@ import com.typesafe.config.ConfigFactory import kamon.Kamon import kamon.context.BinaryPropagation.{ByteStreamReader, ByteStreamWriter} import kamon.context.Propagation.{EntryReader, EntryWriter} +import kamon.tag.TagSet +import kamon.tag.Lookups._ import org.scalatest.{Matchers, OptionValues, WordSpec} import scala.util.Random @@ -70,13 +72,14 @@ class BinaryPropagationSpec extends WordSpec with Matchers with OptionValues { } "round trip a Context that only has tags" in { - val context = Context.of(Map("hello" -> "world", "kamon" -> "rulez")) + val context = Context.of(TagSet.from(Map("hello" -> "world", "kamon" -> "rulez"))) val writer = inspectableByteStreamWriter() binaryPropagation.write(context, writer) val rtContext = binaryPropagation.read(ByteStreamReader.of(writer.toByteArray)) rtContext.entries shouldBe empty - rtContext.tags should contain theSameElementsAs (context.tags) + rtContext.tags.get(plain("hello")) shouldBe "world" + rtContext.tags.get(plain("kamon")) shouldBe "rulez" } "round trip a Context that only has entries" in { @@ -91,7 +94,7 @@ class BinaryPropagationSpec extends WordSpec with Matchers with OptionValues { } "round trip a Context that with tags and entries" in { - val context = Context.of(Map("hello" -> "world", "kamon" -> "rulez")) + val context = Context.of(TagSet.from(Map("hello" -> "world", "kamon" -> "rulez"))) .withKey(BinaryPropagationSpec.StringKey, "string-value") .withKey(BinaryPropagationSpec.IntegerKey, 42) @@ -99,7 +102,8 @@ class BinaryPropagationSpec extends WordSpec with Matchers with OptionValues { binaryPropagation.write(context, writer) val rtContext = binaryPropagation.read(ByteStreamReader.of(writer.toByteArray)) - rtContext.tags should contain theSameElementsAs (context.tags) + rtContext.tags.get(plain("hello")) shouldBe "world" + rtContext.tags.get(plain("kamon")) shouldBe "rulez" rtContext.get(BinaryPropagationSpec.StringKey) shouldBe "string-value" rtContext.get(BinaryPropagationSpec.IntegerKey) shouldBe 0 // there is no entry configuration for the integer key } diff --git a/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala b/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala index fcddfe24..0cd10672 100644 --- a/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala +++ b/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala @@ -5,6 +5,8 @@ import kamon.Kamon import kamon.context.HttpPropagation.{HeaderReader, HeaderWriter} import kamon.context.Propagation.{EntryReader, EntryWriter} import org.scalatest.{Matchers, OptionValues, WordSpec} +import kamon.tag.Lookups._ +import kamon.tag.TagSet import scala.collection.mutable @@ -22,12 +24,11 @@ class HttpPropagationSpec extends WordSpec with Matchers with OptionValues { "x-content-tags" -> "hello=world;correlation=1234", "x-mapped-tag" -> "value" ) + val context = httpPropagation.read(headerReaderFromMap(headers)) - context.tags should contain only( - "hello" -> "world", - "correlation" -> "1234", - "mappedTag" -> "value" - ) + context.tags.get(plain("hello")) shouldBe "world" + context.tags.get(plain("correlation")) shouldBe "1234" + context.tags.get(plain("mappedTag")) shouldBe "value" } "handle errors when reading HTTP headers" in { @@ -48,9 +49,9 @@ class HttpPropagationSpec extends WordSpec with Matchers with OptionValues { context.get(HttpPropagationSpec.StringKey) shouldBe "hey" context.get(HttpPropagationSpec.IntegerKey) shouldBe 123 context.get(HttpPropagationSpec.OptionalKey) shouldBe empty - context.getTag("hello").value shouldBe "world" - context.getTag("correlation").value shouldBe "1234" - context.getTag("unknown") shouldBe empty + context.getTag(plain("hello")) shouldBe "world" + context.getTag(option("correlation")).value shouldBe "1234" + context.getTag(option("unknown")) shouldBe empty } } @@ -64,10 +65,10 @@ class HttpPropagationSpec extends WordSpec with Matchers with OptionValues { "write context tags when available" in { val headers = mutable.Map.empty[String, String] - val context = Context.of(Map( + val context = Context.of(TagSet.from(Map( "hello" -> "world", "mappedTag" -> "value" - )) + ))) httpPropagation.write(context, headerWriterFromMap(headers)) headers should contain only( diff --git a/kamon-core-tests/src/test/scala/kamon/instrumentation/HttpServerInstrumentationSpec.scala b/kamon-core-tests/src/test/scala/kamon/instrumentation/HttpServerInstrumentationSpec.scala index 62eae45b..c7e856d0 100644 --- a/kamon-core-tests/src/test/scala/kamon/instrumentation/HttpServerInstrumentationSpec.scala +++ b/kamon-core-tests/src/test/scala/kamon/instrumentation/HttpServerInstrumentationSpec.scala @@ -4,6 +4,7 @@ import java.time.Duration import kamon.context.Context import kamon.metric.{Counter, Histogram, RangeSampler} +import kamon.tag.Lookups._ import kamon.testkit.{MetricInspection, SpanInspection} import org.scalatest.concurrent.Eventually import org.scalatest.{Matchers, OptionValues, WordSpec} @@ -20,10 +21,8 @@ class HttpServerInstrumentationSpec extends WordSpec with Matchers with SpanInsp "custom-trace-id" -> "0011223344556677" ))) - handler.context.tags should contain only( - "tag" -> "value", - "none" -> "0011223344556677" - ) + handler.context.tags.get(plain("tag")) shouldBe "value" + handler.context.tags.get(plain("none")) shouldBe "0011223344556677" handler.send(fakeResponse(200, mutable.Map.empty), Context.Empty) handler.doneSending(0L) @@ -35,10 +34,8 @@ class HttpServerInstrumentationSpec extends WordSpec with Matchers with SpanInsp "custom-trace-id" -> "0011223344556677" ))) - handler.context.tags should contain only( - "tag" -> "value", - "none" -> "0011223344556677" - ) + handler.context.tags.get(plain("tag")) shouldBe "value" + handler.context.tags.get(plain("none")) shouldBe "0011223344556677" val span = inspect(handler.span) span.context().traceID.string shouldNot be("0011223344556677") diff --git a/kamon-core-tests/src/test/scala/kamon/tag/TagSetSpec.scala b/kamon-core-tests/src/test/scala/kamon/tag/TagSetSpec.scala new file mode 100644 index 00000000..cd23c58d --- /dev/null +++ b/kamon-core-tests/src/test/scala/kamon/tag/TagSetSpec.scala @@ -0,0 +1,180 @@ +package kamon.tag + +import java.util.Optional + +import org.scalatest.{Matchers, WordSpec} + +import scala.collection.JavaConverters.mapAsJavaMapConverter + +class TagSetSpec extends WordSpec with Matchers { + import Lookups._ + + "Tags" should { + "silently drop null and unacceptable keys and/or values when constructed from the companion object builders" in { + TagSet.from(NullString, NullString).all().size shouldBe 0 + TagSet.from(EmptyString, NullString).all().size shouldBe 0 + TagSet.from(EmptyString, "value").all().size shouldBe 0 + TagSet.from(NullString, "value").all().size shouldBe 0 + TagSet.from("key", NullString).all().size shouldBe 0 + TagSet.from("key", NullBoolean).all().size shouldBe 0 + TagSet.from("key", NullLong).all().size shouldBe 0 + + TagSet.from(BadScalaTagMap).all().size shouldBe 0 + TagSet.from(BadJavaTagMap).all().size shouldBe 0 + } + + "silently drop null keys and/or values when created with the .withTag, withTags or .and methods" in { + val tags = TagSet.from("initialKey", "initialValue") + .withTag(NullString, NullString) + .withTag(EmptyString, NullString) + .withTag(EmptyString, "value") + .withTag(NullString, "value") + .withTag("key", NullString) + .withTag("key", NullBoolean) + .withTag("key", NullLong) + .and(NullString, NullString) + .and(EmptyString, NullString) + .and(EmptyString, "value") + .and(NullString, "value") + .and("key", NullString) + .and("key", NullBoolean) + .and("key", NullLong) + + tags.all().length shouldBe 1 + tags.all().head.asInstanceOf[Tag.String].key shouldBe "initialKey" + tags.all().head.asInstanceOf[Tag.String].value shouldBe "initialValue" + } + + "create a properly populated instance when valid pairs are provided" in { + TagSet.from("isAwesome", true).all().size shouldBe 1 + TagSet.from("name", "kamon").all().size shouldBe 1 + TagSet.from("age", 5L).all().size shouldBe 1 + + TagSet.from(GoodScalaTagMap).all().size shouldBe 3 + TagSet.from(GoodJavaTagMap).all().size shouldBe 3 + + TagSet.from("initial", "initial") + .withTag("isAwesome", true) + .withTag("name", "Kamon") + .withTag("age", 5L) + .and("isAvailable", true) + .and("website", "kamon.io") + .and("supportedPlatforms", 1L) + .all().size shouldBe 7 + } + + "override pre-existent tags when merging with other Tags instance" in { + val leftTags = TagSet.from(GoodScalaTagMap) + val rightTags = TagSet + .from("name", "New Kamon") + .and("age", 42L) + .and("isAwesome", false) // just for testing :) + + val tags = leftTags.withTags(rightTags) + tags.get(plain("name")) shouldBe "New Kamon" + tags.get(plainLong("age")) shouldBe 42L + tags.get(plainBoolean("isAwesome")) shouldBe false + + val andTags = tags and leftTags + andTags.get(plain("name")) shouldBe "Kamon" + andTags.get(plainLong("age")) shouldBe 5L + andTags.get(plainBoolean("isAwesome")) shouldBe true + } + + "provide typed access to the contained pairs when looking up values" in { + val tags = TagSet.from(GoodScalaTagMap) + + tags.get(plain("name")) shouldBe "Kamon" + tags.get(plain("none")) shouldBe null + tags.get(option("name")) shouldBe Option("Kamon") + tags.get(option("none")) shouldBe None + tags.get(optional("name")) shouldBe Optional.of("Kamon") + tags.get(optional("none")) shouldBe Optional.empty() + + tags.get(plainLong("age")) shouldBe 5L + tags.get(plainLong("nil")) shouldBe null + tags.get(longOption("age")) shouldBe Option(5L) + tags.get(longOption("nil")) shouldBe None + tags.get(longOptional("age")) shouldBe Optional.of(5L) + tags.get(longOptional("nil")) shouldBe Optional.empty() + + tags.get(plainBoolean("isAwesome")) shouldBe true + tags.get(plainBoolean("isUnknown")) shouldBe null + tags.get(booleanOption("isAwesome")) shouldBe Some(true) + tags.get(booleanOption("isUnknown")) shouldBe None + tags.get(booleanOptional("isAwesome")) shouldBe Optional.of(true) + tags.get(booleanOptional("isUnknown")) shouldBe Optional.empty() + + tags.get(coerce("age")) shouldBe "5" + tags.get(coerce("isAwesome")) shouldBe "true" + tags.get(coerce("unknown")) shouldBe "unknown" + } + + "allow iterating over all contained tags" in { + val tags = TagSet.from(Map( + "age" -> 5L, + "name" -> "Kamon", + "isAwesome" -> true, + "hasTracing" -> true, + "website" -> "kamon.io", + "luckyNumber" -> 7L + )) + + tags.iterator().length shouldBe 6 + tags.iterator().find(matchPair("age", 5L)) shouldBe defined + tags.iterator().find(matchPair("luckyNumber", 7L)) shouldBe defined + tags.iterator().find(matchPair("hasTracing", true)) shouldBe defined + tags.iterator().find(matchPair("isAwesome", true)) shouldBe defined + tags.iterator().find(matchPair("website", "kamon.io")) shouldBe defined + tags.iterator().find(matchPair("name", "Kamon")) shouldBe defined + } + + "be equal to other Tags instance with the same tags" in { + TagSet.from(GoodScalaTagMap) shouldBe TagSet.from(GoodScalaTagMap) + TagSet.from(GoodJavaTagMap) shouldBe TagSet.from(GoodJavaTagMap) + } + + "have a readable toString implementation" in { + TagSet.from(GoodScalaTagMap).toString() should include("age=5") + TagSet.from(GoodScalaTagMap).toString() should include("name=Kamon") + TagSet.from(GoodScalaTagMap).toString() should include("isAwesome=true") + } + } + + def matchPair(key: String, value: Any) = { tag: Tag => { + tag match { + case t: Tag.String => t.key == key && t.value == value + case t: Tag.Long => t.key == key && t.value == value + case t: Tag.Boolean => t.key == key && t.value == value + } + + }} + + + val NullString: java.lang.String = null + val NullBoolean: java.lang.Boolean = NullString.asInstanceOf[java.lang.Boolean] + val NullLong: java.lang.Long = null + val EmptyString: java.lang.String = "" + + val GoodScalaTagMap: Map[String, Any] = Map( + "age" -> 5L, + "name" -> "Kamon", + "isAwesome" -> true + ) + + val BadScalaTagMap: Map[String, Any] = Map( + NullString -> NullString, + EmptyString -> NullString, + NullString -> NullString, + EmptyString -> NullString, + EmptyString -> "value", + NullString -> "value", + "key" -> NullString, + "key" -> NullBoolean, + "key" -> NullLong + ) + + val GoodJavaTagMap = GoodScalaTagMap.asJava + val BadJavaTagMap = BadScalaTagMap.asJava + +} diff --git a/kamon-core-tests/src/test/scala/kamon/tag/TagsSpec.scala b/kamon-core-tests/src/test/scala/kamon/tag/TagsSpec.scala deleted file mode 100644 index 1a83e1c9..00000000 --- a/kamon-core-tests/src/test/scala/kamon/tag/TagsSpec.scala +++ /dev/null @@ -1,180 +0,0 @@ -package kamon.tag - -import java.util.Optional - -import org.scalatest.{Matchers, WordSpec} - -import scala.collection.JavaConverters.mapAsJavaMapConverter - -class TagsSpec extends WordSpec with Matchers { - import Lookups._ - - "Tags" should { - "silently drop null and unacceptable keys and/or values when constructed from the companion object builders" in { - Tags.from(NullString, NullString).all().size shouldBe 0 - Tags.from(EmptyString, NullString).all().size shouldBe 0 - Tags.from(EmptyString, "value").all().size shouldBe 0 - Tags.from(NullString, "value").all().size shouldBe 0 - Tags.from("key", NullString).all().size shouldBe 0 - Tags.from("key", NullBoolean).all().size shouldBe 0 - Tags.from("key", NullLong).all().size shouldBe 0 - - Tags.from(BadScalaTagMap).all().size shouldBe 0 - Tags.from(BadJavaTagMap).all().size shouldBe 0 - } - - "silently drop null keys and/or values when created with the .withTag, withTags or .and methods" in { - val tags = Tags.from("initialKey", "initialValue") - .withTag(NullString, NullString) - .withTag(EmptyString, NullString) - .withTag(EmptyString, "value") - .withTag(NullString, "value") - .withTag("key", NullString) - .withTag("key", NullBoolean) - .withTag("key", NullLong) - .and(NullString, NullString) - .and(EmptyString, NullString) - .and(EmptyString, "value") - .and(NullString, "value") - .and("key", NullString) - .and("key", NullBoolean) - .and("key", NullLong) - - tags.all().length shouldBe 1 - tags.all().head.asInstanceOf[Tag.String].key shouldBe "initialKey" - tags.all().head.asInstanceOf[Tag.String].value shouldBe "initialValue" - } - - "create a properly populated instance when valid pairs are provided" in { - Tags.from("isAwesome", true).all().size shouldBe 1 - Tags.from("name", "kamon").all().size shouldBe 1 - Tags.from("age", 5L).all().size shouldBe 1 - - Tags.from(GoodScalaTagMap).all().size shouldBe 3 - Tags.from(GoodJavaTagMap).all().size shouldBe 3 - - Tags.from("initial", "initial") - .withTag("isAwesome", true) - .withTag("name", "Kamon") - .withTag("age", 5L) - .and("isAvailable", true) - .and("website", "kamon.io") - .and("supportedPlatforms", 1L) - .all().size shouldBe 7 - } - - "override pre-existent tags when merging with other Tags instance" in { - val leftTags = Tags.from(GoodScalaTagMap) - val rightTags = Tags - .from("name", "New Kamon") - .and("age", 42L) - .and("isAwesome", false) // just for testing :) - - val tags = leftTags.withTags(rightTags) - tags.get(plain("name")) shouldBe "New Kamon" - tags.get(plainLong("age")) shouldBe 42L - tags.get(plainBoolean("isAwesome")) shouldBe false - - val andTags = tags and leftTags - andTags.get(plain("name")) shouldBe "Kamon" - andTags.get(plainLong("age")) shouldBe 5L - andTags.get(plainBoolean("isAwesome")) shouldBe true - } - - "provide typed access to the contained pairs when looking up values" in { - val tags = Tags.from(GoodScalaTagMap) - - tags.get(plain("name")) shouldBe "Kamon" - tags.get(plain("none")) shouldBe null - tags.get(option("name")) shouldBe Option("Kamon") - tags.get(option("none")) shouldBe None - tags.get(optional("name")) shouldBe Optional.of("Kamon") - tags.get(optional("none")) shouldBe Optional.empty() - - tags.get(plainLong("age")) shouldBe 5L - tags.get(plainLong("nil")) shouldBe null - tags.get(longOption("age")) shouldBe Option(5L) - tags.get(longOption("nil")) shouldBe None - tags.get(longOptional("age")) shouldBe Optional.of(5L) - tags.get(longOptional("nil")) shouldBe Optional.empty() - - tags.get(plainBoolean("isAwesome")) shouldBe true - tags.get(plainBoolean("isUnknown")) shouldBe null - tags.get(booleanOption("isAwesome")) shouldBe Some(true) - tags.get(booleanOption("isUnknown")) shouldBe None - tags.get(booleanOptional("isAwesome")) shouldBe Optional.of(true) - tags.get(booleanOptional("isUnknown")) shouldBe Optional.empty() - - tags.get(coerce("age")) shouldBe "5" - tags.get(coerce("isAwesome")) shouldBe "true" - tags.get(coerce("unknown")) shouldBe "unknown" - } - - "allow iterating over all contained tags" in { - val tags = Tags.from(Map( - "age" -> 5L, - "name" -> "Kamon", - "isAwesome" -> true, - "hasTracing" -> true, - "website" -> "kamon.io", - "luckyNumber" -> 7L - )) - - tags.iterator().length shouldBe 6 - tags.iterator().find(matchPair("age", 5L)) shouldBe defined - tags.iterator().find(matchPair("luckyNumber", 7L)) shouldBe defined - tags.iterator().find(matchPair("hasTracing", true)) shouldBe defined - tags.iterator().find(matchPair("isAwesome", true)) shouldBe defined - tags.iterator().find(matchPair("website", "kamon.io")) shouldBe defined - tags.iterator().find(matchPair("name", "Kamon")) shouldBe defined - } - - "be equal to other Tags instance with the same tags" in { - Tags.from(GoodScalaTagMap) shouldBe Tags.from(GoodScalaTagMap) - Tags.from(GoodJavaTagMap) shouldBe Tags.from(GoodJavaTagMap) - } - - "have a readable toString implementation" in { - Tags.from(GoodScalaTagMap).toString() should include("age=5") - Tags.from(GoodScalaTagMap).toString() should include("name=Kamon") - Tags.from(GoodScalaTagMap).toString() should include("isAwesome=true") - } - } - - def matchPair(key: String, value: Any) = { tag: Tag => { - tag match { - case t: Tag.String => t.key == key && t.value == value - case t: Tag.Long => t.key == key && t.value == value - case t: Tag.Boolean => t.key == key && t.value == value - } - - }} - - - val NullString: java.lang.String = null - val NullBoolean: java.lang.Boolean = NullString.asInstanceOf[java.lang.Boolean] - val NullLong: java.lang.Long = null - val EmptyString: java.lang.String = "" - - val GoodScalaTagMap: Map[String, Any] = Map( - "age" -> 5L, - "name" -> "Kamon", - "isAwesome" -> true - ) - - val BadScalaTagMap: Map[String, Any] = Map( - NullString -> NullString, - EmptyString -> NullString, - NullString -> NullString, - EmptyString -> NullString, - EmptyString -> "value", - NullString -> "value", - "key" -> NullString, - "key" -> NullBoolean, - "key" -> NullLong - ) - - val GoodJavaTagMap = GoodScalaTagMap.asJava - val BadJavaTagMap = BadScalaTagMap.asJava - -} -- cgit v1.2.3