diff options
Diffstat (limited to 'kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala')
-rw-r--r-- | kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala b/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala new file mode 100644 index 00000000..fcddfe24 --- /dev/null +++ b/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala @@ -0,0 +1,159 @@ +package kamon.context + +import com.typesafe.config.ConfigFactory +import kamon.Kamon +import kamon.context.HttpPropagation.{HeaderReader, HeaderWriter} +import kamon.context.Propagation.{EntryReader, EntryWriter} +import org.scalatest.{Matchers, OptionValues, WordSpec} + +import scala.collection.mutable + +class HttpPropagationSpec extends WordSpec with Matchers with OptionValues { + + "The HTTP Context Propagation" when { + "reading from incoming requests" should { + "return an empty context if there are no tags nor keys" in { + val context = httpPropagation.read(headerReaderFromMap(Map.empty)) + context.isEmpty() shouldBe true + } + + "read tags from an HTTP message when they are available" in { + val headers = Map( + "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" + ) + } + + "handle errors when reading HTTP headers" in { + val headers = Map("fail" -> "") + val context = httpPropagation.read(headerReaderFromMap(headers)) + context.tags shouldBe empty + context.entries shouldBe empty + } + + "read context with entries and tags" in { + val headers = Map( + "x-content-tags" -> "hello=world;correlation=1234", + "string-header" -> "hey", + "integer-header" -> "123" + ) + + val context = httpPropagation.read(headerReaderFromMap(headers)) + 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 + } + } + + + "writing to outgoing requests" should { + "not write anything if the context is empty" in { + val headers = mutable.Map.empty[String, String] + httpPropagation.write(Context.Empty, headerWriterFromMap(headers)) + headers shouldBe empty + } + + "write context tags when available" in { + val headers = mutable.Map.empty[String, String] + val context = Context.of(Map( + "hello" -> "world", + "mappedTag" -> "value" + )) + + httpPropagation.write(context, headerWriterFromMap(headers)) + headers should contain only( + "x-content-tags" -> "hello=world;", + "x-mapped-tag" -> "value" + ) + } + + "write context entries when available" in { + val headers = mutable.Map.empty[String, String] + val context = Context.of( + HttpPropagationSpec.StringKey, "out-we-go", + HttpPropagationSpec.IntegerKey, 42 + ) + + httpPropagation.write(context, headerWriterFromMap(headers)) + headers should contain only( + "string-header" -> "out-we-go" + ) + } + } + } + + + val httpPropagation = HttpPropagation.from( + ConfigFactory.parseString( + """ + |tags { + | header-name = "x-content-tags" + | + | mappings { + | mappedTag = "x-mapped-tag" + | } + |} + | + |entries.incoming.string = "kamon.context.HttpPropagationSpec$StringEntryCodec" + |entries.incoming.integer = "kamon.context.HttpPropagationSpec$IntegerEntryCodec" + |entries.outgoing.string = "kamon.context.HttpPropagationSpec$StringEntryCodec" + | + """.stripMargin + ).withFallback(ConfigFactory.load().getConfig("kamon.propagation")), Kamon) + + + def headerReaderFromMap(map: Map[String, String]): HttpPropagation.HeaderReader = new HttpPropagation.HeaderReader { + override def read(header: String): Option[String] = { + if(map.get("fail").nonEmpty) + sys.error("failing on purpose") + + map.get(header) + } + + override def readAll(): Map[String, String] = map + } + + def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = new HttpPropagation.HeaderWriter { + override def write(header: String, value: String): Unit = map.put(header, value) + } +} + +object HttpPropagationSpec { + + val StringKey = Context.key[String]("string", null) + val IntegerKey = Context.key[Int]("integer", 0) + val OptionalKey = Context.key[Option[String]]("optional", None) + + + class StringEntryCodec extends EntryReader[HeaderReader] with EntryWriter[HeaderWriter] { + private val HeaderName = "string-header" + + override def read(reader: HttpPropagation.HeaderReader, context: Context): Context = { + reader.read(HeaderName) + .map(v => context.withKey(StringKey, v)) + .getOrElse(context) + } + + override def write(context: Context, writer: HttpPropagation.HeaderWriter): Unit = { + Option(context.get(StringKey)).foreach(v => writer.write(HeaderName, v)) + } + } + + class IntegerEntryCodec extends EntryReader[HeaderReader] { + override def read(reader: HttpPropagation.HeaderReader, context: Context): Context = { + reader.read("integer-header") + .map(v => context.withKey(IntegerKey, v.toInt)) + .getOrElse(context) + + } + } +}
\ No newline at end of file |