Best Kotest code snippet using io.kotest.matchers.future.matchers.cancelled
RecordEventsReadableSpanTest.kt
Source:RecordEventsReadableSpanTest.kt  
1/*2 * Copyright The OpenTelemetry Authors3 * SPDX-License-Identifier: Apache-2.04 */5package io.opentelemetry.kotlin.sdk.trace6import io.kotest.matchers.booleans.shouldBeFalse7import io.kotest.matchers.booleans.shouldBeTrue8import io.kotest.matchers.collections.shouldBeEmpty9import io.kotest.matchers.collections.shouldHaveSize10import io.kotest.matchers.longs.shouldBeGreaterThan11import io.kotest.matchers.nulls.shouldBeNull12import io.kotest.matchers.nulls.shouldNotBeNull13import io.kotest.matchers.shouldBe14import io.opentelemetry.kotlin.api.common.AttributeKey15import io.opentelemetry.kotlin.api.common.AttributeKey.Companion.booleanArrayKey16import io.opentelemetry.kotlin.api.common.AttributeKey.Companion.booleanKey17import io.opentelemetry.kotlin.api.common.AttributeKey.Companion.doubleArrayKey18import io.opentelemetry.kotlin.api.common.AttributeKey.Companion.doubleKey19import io.opentelemetry.kotlin.api.common.AttributeKey.Companion.longArrayKey20import io.opentelemetry.kotlin.api.common.AttributeKey.Companion.longKey21import io.opentelemetry.kotlin.api.common.AttributeKey.Companion.stringArrayKey22import io.opentelemetry.kotlin.api.common.AttributeKey.Companion.stringKey23import io.opentelemetry.kotlin.api.common.Attributes24import io.opentelemetry.kotlin.api.common.normalizeToNanos25import io.opentelemetry.kotlin.api.trace.Span26import io.opentelemetry.kotlin.api.trace.SpanContext27import io.opentelemetry.kotlin.api.trace.SpanId28import io.opentelemetry.kotlin.api.trace.SpanKind29import io.opentelemetry.kotlin.api.trace.StatusCode30import io.opentelemetry.kotlin.api.trace.TraceFlags31import io.opentelemetry.kotlin.api.trace.TraceState32import io.opentelemetry.kotlin.context.Context33import io.opentelemetry.kotlin.sdk.common.InstrumentationLibraryInfo34import io.opentelemetry.kotlin.sdk.resources.Resource35import io.opentelemetry.kotlin.sdk.testing.time.TestClock36import io.opentelemetry.kotlin.sdk.trace.data.EventData37import io.opentelemetry.kotlin.sdk.trace.data.LinkData38import io.opentelemetry.kotlin.sdk.trace.data.SpanData39import io.opentelemetry.kotlin.sdk.trace.data.StatusData40import io.opentelemetry.kotlin.semconv.trace.attributes.SemanticAttributes41import kotlinx.datetime.DateTimeUnit42import kotlinx.datetime.Instant43import kotlin.test.Test44import kotlin.time.Duration.Companion.milliseconds45import kotlin.time.Duration.Companion.nanoseconds46import kotlin.time.Duration.Companion.seconds47class RecordEventsReadableSpanTest {48    private val idsGenerator = IdGenerator.random()49    private val traceId = idsGenerator.generateTraceId()50    private val spanId = idsGenerator.generateSpanId()51    private val parentSpanId = idsGenerator.generateSpanId()52    private val spanContext: SpanContext =53        SpanContext.create(traceId, spanId, TraceFlags.default, TraceState.default)54    private val resource = Resource.empty()55    private val instrumentationLibraryInfo: InstrumentationLibraryInfo =56        InstrumentationLibraryInfo.create("theName", null)57    private val attributes: MutableMap<AttributeKey<*>, Any> = HashMap<AttributeKey<*>, Any>()58    private var expectedAttributes: Attributes? = null59    private val link: LinkData = LinkData.create(spanContext)60    private val testClock: TestClock61    private val spanProcessor = MockFactory.createSpanProcessor()62    init {63        attributes[stringKey("MyStringAttributeKey")] = "MyStringAttributeValue"64        attributes[longKey("MyLongAttributeKey")] = 123L65        attributes[booleanKey("MyBooleanAttributeKey")] = false66        val builder =67            Attributes.builder().put("MySingleStringAttributeKey", "MySingleStringAttributeValue")68        for ((key, value) in attributes) {69            builder.put(key as AttributeKey<Any>, value)70        }71        expectedAttributes = builder.build()72        testClock = TestClock.create(Instant.fromEpochSeconds(0, START_EPOCH_NANOS))73    }74    @Test75    fun nothingChangedAfterEnd() {76        val span = createTestSpan(SpanKind.INTERNAL)77        span.end()78        // Check that adding trace events or update fields after Span#end() does not throw any79        // thrown80        // and are ignored.81        spanDoWork(span, StatusCode.ERROR, "CANCELLED")82        val spanData: SpanData = span.toSpanData()83        verifySpanData(84            spanData,85            Attributes.empty(),86            emptyList(),87            listOf(link),88            SPAN_NAME,89            START_EPOCH_NANOS,90            START_EPOCH_NANOS,91            StatusData.unset(),92            true93        )94    }95    @Test96    fun endSpanTwice_DoNotCrash() {97        val span = createTestSpan(SpanKind.INTERNAL)98        span.hasEnded().shouldBeFalse()99        span.end()100        span.hasEnded().shouldBeTrue()101        span.end()102        span.hasEnded().shouldBeTrue()103    }104    @Test105    fun toSpanData_ActiveSpan() {106        val span = createTestSpan(SpanKind.INTERNAL)107        try {108            span.hasEnded().shouldBeFalse()109            spanDoWork(span, null, null)110            val spanData: SpanData = span.toSpanData()111            val event: EventData =112                EventData.create(113                    START_EPOCH_NANOS + NANOS_PER_SECOND,114                    "event2",115                    Attributes.empty(),116                    0117                )118            verifySpanData(119                spanData,120                expectedAttributes,121                listOf<EventData>(event),122                listOf<LinkData>(link),123                SPAN_NEW_NAME,124                START_EPOCH_NANOS,125                0,126                StatusData.unset(),127                /*hasEnded=*/ false128            )129            span.hasEnded().shouldBeFalse()130            span.isRecording().shouldBeTrue()131        } finally {132            span.end()133        }134        span.hasEnded().shouldBeTrue()135        span.isRecording().shouldBeFalse()136    }137    @Test138    fun toSpanData_EndedSpan() {139        val span = createTestSpan(SpanKind.INTERNAL)140        try {141            spanDoWork(span, StatusCode.ERROR, "CANCELLED")142        } finally {143            span.end()144        }145        spanProcessor.endSpan shouldBe span146        val spanData: SpanData = span.toSpanData()147        val event: EventData =148            EventData.create(START_EPOCH_NANOS + NANOS_PER_SECOND, "event2", Attributes.empty(), 0)149        verifySpanData(150            spanData,151            expectedAttributes,152            listOf(event),153            listOf(link),154            SPAN_NEW_NAME,155            START_EPOCH_NANOS,156            testClock.now(),157            StatusData.create(StatusCode.ERROR, "CANCELLED"),158            /*hasEnded=*/ true159        )160    }161    @Test162    fun toSpanData_RootSpan() {163        val span = createTestRootSpan()164        try {165            spanDoWork(span, null, null)166        } finally {167            span.end()168        }169        span.parentSpanContext.isValid.shouldBeFalse()170        val spanData: SpanData = span.toSpanData()171        SpanId.isValid(spanData.parentSpanId).shouldBeFalse()172    }173    @Test174    fun toSpanData_ChildSpan() {175        val span = createTestSpan(SpanKind.INTERNAL)176        try {177            spanDoWork(span, null, null)178        } finally {179            span.end()180        }181        span.parentSpanContext.isValid.shouldBeTrue()182        span.parentSpanContext.traceId shouldBe traceId183        span.parentSpanContext.spanId shouldBe parentSpanId184        val spanData: SpanData = span.toSpanData()185        spanData.parentSpanId shouldBe parentSpanId186    }187    @Test188    fun toSpanData_WithInitialAttributes() {189        val span = createTestSpanWithAttributes(attributes)190        span.setAttribute("anotherKey", "anotherValue")191        span.end()192        val spanData: SpanData = span.toSpanData()193        spanData.attributes.size shouldBe attributes.size + 1194        spanData.totalAttributeCount shouldBe attributes.size + 1195    }196    @Test197    fun toSpanData_SpanDataDoesNotChangeWhenModifyingSpan() {198        // Create a span199        val span = createTestSpanWithAttributes(attributes)200        // Convert it to a SpanData object -- this should be an immutable snapshot.201        var spanData: SpanData = span.toSpanData()202        // Now modify the span after creating the snapshot.203        span.setAttribute("anotherKey", "anotherValue")204        span.updateName("changedName")205        span.addEvent("newEvent")206        span.end()207        // Assert that the snapshot does not reflect the modified state, but the state of the time208        // when209        // toSpanData was called.210        spanData.attributes.size shouldBe attributes.size211        spanData.attributes[stringKey("anotherKey")].shouldBeNull()212        spanData.hasEnded().shouldBeFalse()213        spanData.endEpochNanos shouldBe 0214        spanData.name shouldBe SPAN_NAME215        spanData.events.shouldBeEmpty()216        // Sanity check: Calling toSpanData again after modifying the span should get us the217        // modified218        // state.219        spanData = span.toSpanData()220        spanData.attributes.size shouldBe attributes.size + 1221        spanData.attributes[stringKey("anotherKey")] shouldBe "anotherValue"222        spanData.hasEnded().shouldBeTrue()223        spanData.endEpochNanos.shouldBeGreaterThan(0)224        spanData.name shouldBe "changedName"225        spanData.events.shouldHaveSize(1)226    }227    @Test228    fun toSpanData_Status() {229        val span = createTestSpan(SpanKind.CONSUMER)230        try {231            testClock.advance(1.seconds)232            span.toSpanData().status shouldBe StatusData.unset()233            span.setStatus(StatusCode.ERROR, "CANCELLED")234            span.toSpanData().status shouldBe StatusData.create(StatusCode.ERROR, "CANCELLED")235        } finally {236            span.end()237        }238        span.toSpanData().status shouldBe StatusData.create(StatusCode.ERROR, "CANCELLED")239    }240    @Test241    fun toSpanData_Kind() {242        val span = createTestSpan(SpanKind.SERVER)243        try {244            span.toSpanData().kind shouldBe SpanKind.SERVER245        } finally {246            span.end()247        }248    }249    @Test250    fun kind() {251        val span = createTestSpan(SpanKind.SERVER)252        try {253            span.kind shouldBe SpanKind.SERVER254        } finally {255            span.end()256        }257    }258    @Test259    fun attribute() {260        val span = createTestSpanWithAttributes(attributes)261        try {262            span.getAttribute(longKey("MyLongAttributeKey")) shouldBe 123L263        } finally {264            span.end()265        }266    }267    @Test268    fun getInstrumentationLibraryInfo() {269        val span = createTestSpan(SpanKind.CLIENT)270        try {271            span.instrumentationLibraryInfo shouldBe instrumentationLibraryInfo272        } finally {273            span.end()274        }275    }276    @Test277    fun andUpdateSpanName() {278        val span = createTestRootSpan()279        try {280            span.name shouldBe SPAN_NAME281            span.updateName(SPAN_NEW_NAME)282            span.name shouldBe SPAN_NEW_NAME283        } finally {284            span.end()285        }286    }287    @Test288    fun latencyNs_ActiveSpan() {289        val span = createTestSpan(SpanKind.INTERNAL)290        try {291            testClock.advance(1.seconds)292            val elapsedTimeNanos1 = testClock.now() - START_EPOCH_NANOS293            span.latencyNanos shouldBe elapsedTimeNanos1294            testClock.advance(1.seconds)295            val elapsedTimeNanos2 = testClock.now() - START_EPOCH_NANOS296            span.latencyNanos shouldBe elapsedTimeNanos2297        } finally {298            span.end()299        }300    }301    @Test302    fun latencyNs_EndedSpan() {303        val span = createTestSpan(SpanKind.INTERNAL)304        testClock.advance(1.seconds)305        span.end()306        val elapsedTimeNanos = testClock.now() - START_EPOCH_NANOS307        span.latencyNanos shouldBe elapsedTimeNanos308        testClock.advance(1.seconds)309        span.latencyNanos shouldBe elapsedTimeNanos310    }311    @Test312    fun setAttribute() {313        val span = createTestRootSpan()314        try {315            span.setAttribute("StringKey", "StringVal")316            span.setAttribute("EmptyStringKey", "")317            span.setAttribute(stringKey("EmptyStringAttributeValue"), "")318            span.setAttribute("LongKey", 1000L)319            span.setAttribute(longKey("LongKey2"), 5)320            span.setAttribute(longKey("LongKey3"), 6L)321            span.setAttribute("DoubleKey", 10.0)322            span.setAttribute("BooleanKey", false)323            span.setAttribute(324                stringArrayKey("ArrayStringKey"),325                listOf("StringVal", "", "StringVal2")326            )327            span.setAttribute(longArrayKey("ArrayLongKey"), listOf(1L, 2L, 3L, 4L, 5L))328            span.setAttribute(doubleArrayKey("ArrayDoubleKey"), listOf(0.1, 2.3, 4.5, 6.7, 8.9))329            span.setAttribute(booleanArrayKey("ArrayBooleanKey"), listOf(true, false, false, true))330        } finally {331            span.end()332        }333        val spanData: SpanData = span.toSpanData()334        spanData.attributes.size shouldBe 12335        spanData.attributes[stringKey("StringKey")].shouldNotBeNull()336        spanData.attributes[stringKey("EmptyStringKey")].shouldNotBeNull()337        spanData.attributes[stringKey("EmptyStringAttributeValue")].shouldNotBeNull()338        spanData.attributes[longKey("LongKey")].shouldNotBeNull()339        spanData.attributes[longKey("LongKey2")] shouldBe 5L340        spanData.attributes[longKey("LongKey3")] shouldBe 6L341        spanData.attributes[doubleKey("DoubleKey")].shouldNotBeNull()342        spanData.attributes[booleanKey("BooleanKey")].shouldNotBeNull()343        spanData.attributes[stringArrayKey("ArrayStringKey")].shouldNotBeNull()344        spanData.attributes[longArrayKey("ArrayLongKey")].shouldNotBeNull()345        spanData.attributes[doubleArrayKey("ArrayDoubleKey")].shouldNotBeNull()346        spanData.attributes[booleanArrayKey("ArrayBooleanKey")].shouldNotBeNull()347        spanData.attributes[stringArrayKey("ArrayStringKey")]!!.size shouldBe 3348        spanData.attributes[longArrayKey("ArrayLongKey")]!!.size shouldBe 5349        spanData.attributes[doubleArrayKey("ArrayDoubleKey")]!!.size shouldBe 5350        spanData.attributes[booleanArrayKey("ArrayBooleanKey")]!!.size shouldBe 4351    }352    @Test353    fun setAttribute_emptyKeys() {354        val span = createTestRootSpan()355        span.setAttribute("", "")356        span.setAttribute("", 1000L)357        span.setAttribute("", 10.0)358        span.setAttribute("", false)359        span.setAttribute(stringArrayKey(""), emptyList())360        span.setAttribute(booleanArrayKey(""), emptyList())361        span.setAttribute(longArrayKey(""), emptyList())362        span.setAttribute(doubleArrayKey(""), emptyList())363        span.toSpanData().attributes.size shouldBe 0364    }365    @Test366    fun setAttribute_emptyArrayAttributeValue() {367        val span = createTestRootSpan()368        span.setAttribute(stringArrayKey("stringArrayAttribute"), emptyList())369        span.toSpanData().attributes.size shouldBe 1370        span.setAttribute(booleanArrayKey("boolArrayAttribute"), emptyList())371        span.toSpanData().attributes.size shouldBe 2372        span.setAttribute(longArrayKey("longArrayAttribute"), emptyList())373        span.toSpanData().attributes.size shouldBe 3374        span.setAttribute(doubleArrayKey("doubleArrayAttribute"), emptyList())375        span.toSpanData().attributes.size shouldBe 4376    }377    @Test378    fun setAttribute_nullStringValue() {379        val span = createTestRootSpan()380        span.setAttribute("emptyString", "")381        span.setAttribute(stringKey("emptyStringAttributeValue"), "")382        span.toSpanData().attributes.size shouldBe 2383    }384    @Test385    fun setAttribute_nullAttributeValue() {386        val span = createTestRootSpan()387        span.setAttribute("emptyString", "")388        span.setAttribute(stringKey("emptyStringAttributeValue"), "")389        span.setAttribute("longAttribute", 0L)390        span.setAttribute("boolAttribute", false)391        span.setAttribute("doubleAttribute", 0.12345)392        span.setAttribute(stringArrayKey("stringArrayAttribute"), listOf(""))393        span.setAttribute(booleanArrayKey("boolArrayAttribute"), listOf(true))394        span.setAttribute(longArrayKey("longArrayAttribute"), listOf(12345L))395        span.setAttribute(doubleArrayKey("doubleArrayAttribute"), listOf(1.2345))396        span.toSpanData().attributes.size shouldBe 9397    }398    @Test399    fun setAllAttributes() {400        val span = createTestRootSpan()401        val attributes: Attributes =402            Attributes.builder()403                .put("StringKey", "StringVal")404                .put("EmptyStringKey", "")405                .put(stringKey("EmptyStringAttributeValue"), "")406                .put("LongKey", 1000L)407                .put(longKey("LongKey2"), 5)408                .put(longKey("LongKey3"), 6L)409                .put("DoubleKey", 10.0)410                .put("BooleanKey", false)411                .put(stringArrayKey("ArrayStringKey"), listOf("StringVal", "", "StringVal2"))412                .put(longArrayKey("ArrayLongKey"), listOf(1L, 2L, 3L, 4L, 5L))413                .put(doubleArrayKey("ArrayDoubleKey"), listOf(0.1, 2.3, 4.5, 6.7, 8.9))414                .put(booleanArrayKey("ArrayBooleanKey"), listOf(true, false, false, true))415                .build()416        try {417            span.setAllAttributes(attributes)418        } finally {419            span.end()420        }421        val spanData: SpanData = span.toSpanData()422        spanData.attributes.size shouldBe 12423        spanData.attributes[stringKey("StringKey")].shouldNotBeNull()424        spanData.attributes[stringKey("EmptyStringKey")].shouldNotBeNull()425        spanData.attributes[stringKey("EmptyStringAttributeValue")].shouldNotBeNull()426        spanData.attributes[longKey("LongKey")].shouldNotBeNull()427        spanData.attributes[longKey("LongKey2")] shouldBe 5L428        spanData.attributes[longKey("LongKey3")] shouldBe 6L429        spanData.attributes[doubleKey("DoubleKey")].shouldNotBeNull()430        spanData.attributes[booleanKey("BooleanKey")].shouldNotBeNull()431        spanData.attributes[stringArrayKey("ArrayStringKey")].shouldNotBeNull()432        spanData.attributes[longArrayKey("ArrayLongKey")].shouldNotBeNull()433        spanData.attributes[doubleArrayKey("ArrayDoubleKey")].shouldNotBeNull()434        spanData.attributes[booleanArrayKey("ArrayBooleanKey")].shouldNotBeNull()435        spanData.attributes[stringArrayKey("ArrayStringKey")]!!.size shouldBe 3436        spanData.attributes[longArrayKey("ArrayLongKey")]!!.size shouldBe 5437        spanData.attributes[doubleArrayKey("ArrayDoubleKey")]!!.size shouldBe 5438        spanData.attributes[booleanArrayKey("ArrayBooleanKey")]!!.size shouldBe 4439    }440    @Test441    fun setAllAttributes_mergesAttributes() {442        val span = createTestRootSpan()443        val attributes =444            Attributes.builder()445                .put("StringKey", "StringVal")446                .put("LongKey", 1000L)447                .put("DoubleKey", 10.0)448                .put("BooleanKey", false)449                .build()450        try {451            span.setAttribute("StringKey", "OtherStringVal")452                .setAttribute("ExistingStringKey", "ExistingStringVal")453                .setAttribute("LongKey", 2000L)454                .setAllAttributes(attributes)455        } finally {456            span.end()457        }458        val spanData: SpanData = span.toSpanData()459        spanData.attributes.size shouldBe 5460        spanData.attributes[stringKey("StringKey")] shouldBe "StringVal"461        spanData.attributes[stringKey("ExistingStringKey")] shouldBe "ExistingStringVal"462        spanData.attributes[longKey("LongKey")] shouldBe 1000L463        spanData.attributes[doubleKey("DoubleKey")] shouldBe 10.0464        spanData.attributes[booleanKey("BooleanKey")] shouldBe false465    }466    @Test467    fun setAllAttributes_emptyAttributes() {468        val span = createTestRootSpan()469        span.setAllAttributes(Attributes.empty())470        span.toSpanData().attributes.size shouldBe 0471    }472    @Test473    fun addEvent() {474        val span = createTestRootSpan()475        try {476            span.addEvent("event1")477            span.addEvent("event2", Attributes.of(stringKey("e1key"), "e1Value"))478            span.addEvent("event3", 10, DateTimeUnit.SECOND)479            span.addEvent("event4", Instant.fromEpochSeconds(20, 0))480            span.addEvent(481                "event5",482                Attributes.builder().put("foo", "bar").build(),483                30,484                DateTimeUnit.MILLISECOND485            )486            span.addEvent(487                "event6",488                Attributes.builder().put("foo", "bar").build(),489                Instant.fromEpochMilliseconds(1000)490            )491        } finally {492            span.end()493        }494        val events: List<EventData> = span.toSpanData().events495        events shouldHaveSize 6496        events[0].also { event ->497            event.name shouldBe "event1"498            event.attributes shouldBe Attributes.empty()499            event.epochNanos shouldBe START_EPOCH_NANOS500        }501        events[1].also { event ->502            event.name shouldBe "event2"503            event.attributes shouldBe Attributes.of(stringKey("e1key"), "e1Value")504            event.epochNanos shouldBe START_EPOCH_NANOS505        }506        events[2].also { event ->507            event.name shouldBe "event3"508            event.attributes shouldBe Attributes.empty()509            event.epochNanos shouldBe DateTimeUnit.SECOND.normalizeToNanos(10)510        }511        events[3].also { event ->512            event.name shouldBe "event4"513            event.attributes shouldBe Attributes.empty()514            event.epochNanos shouldBe DateTimeUnit.SECOND.normalizeToNanos(20)515        }516        events[4].also { event ->517            event.name shouldBe "event5"518            event.attributes shouldBe Attributes.builder().put("foo", "bar").build()519            event.epochNanos shouldBe DateTimeUnit.MILLISECOND.normalizeToNanos(30)520        }521        events[5].also { event ->522            event.name shouldBe "event6"523            event.attributes shouldBe Attributes.builder().put("foo", "bar").build()524            event.epochNanos shouldBe DateTimeUnit.MILLISECOND.normalizeToNanos(1000)525        }526    }527    @Test528    fun attributeLength() {529        val maxLength = 25530        val span =531            createTestSpan(SpanLimits.builder().setMaxAttributeValueLength(maxLength).build())532        try {533            val strVal: String = (0 until maxLength).joinToString(separator = "") { "a" }534            val tooLongStrVal = strVal + strVal535            var attributes: Attributes =536                Attributes.builder()537                    .put("string", tooLongStrVal)538                    .put("boolean", true)539                    .put("long", 1L)540                    .put("double", 1.0)541                    .put(stringArrayKey("stringArray"), listOf(strVal, tooLongStrVal))542                    .put(booleanArrayKey("booleanArray"), listOf(true, false))543                    .put(longArrayKey("longArray"), listOf(1L, 2L))544                    .put(doubleArrayKey("doubleArray"), listOf(1.0, 2.0))545                    .build()546            span.setAllAttributes(attributes)547            attributes = span.toSpanData().attributes548            attributes[stringKey("string")] shouldBe strVal549            attributes[booleanKey("boolean")] shouldBe true550            attributes[longKey("long")] shouldBe 1L551            attributes[doubleKey("double")] shouldBe 1.0552            attributes[stringArrayKey("stringArray")] shouldBe listOf(strVal, strVal)553            attributes[booleanArrayKey("booleanArray")] shouldBe listOf(true, false)554            attributes[longArrayKey("longArray")] shouldBe listOf(1L, 2L)555            attributes[doubleArrayKey("doubleArray")] shouldBe listOf(1.0, 2.0)556        } finally {557            span.end()558        }559    }560    @Test561    fun eventAttributeLength() {562        val maxLength = 25563        val span =564            createTestSpan(SpanLimits.builder().setMaxAttributeValueLength(maxLength).build())565        try {566            val strVal: String = (0 until maxLength).joinToString(separator = "") { "a" }567            val tooLongStrVal = strVal + strVal568            var attributes: Attributes =569                Attributes.builder()570                    .put("string", tooLongStrVal)571                    .put("boolean", true)572                    .put("long", 1L)573                    .put("double", 1.0)574                    .put(stringArrayKey("stringArray"), listOf(strVal, tooLongStrVal))575                    .put(booleanArrayKey("booleanArray"), listOf(true, false))576                    .put(longArrayKey("longArray"), listOf(1L, 2L))577                    .put(doubleArrayKey("doubleArray"), listOf(1.0, 2.0))578                    .build()579            span.setAllAttributes(attributes)580            attributes = span.toSpanData().attributes581            attributes[stringKey("string")] shouldBe strVal582            attributes[booleanKey("boolean")] shouldBe true583            attributes[longKey("long")] shouldBe 1L584            attributes[doubleKey("double")] shouldBe 1.0585            attributes[stringArrayKey("stringArray")] shouldBe listOf(strVal, strVal)586            attributes[booleanArrayKey("booleanArray")] shouldBe listOf(true, false)587            attributes[longArrayKey("longArray")] shouldBe listOf(1L, 2L)588            attributes[doubleArrayKey("doubleArray")] shouldBe listOf(1.0, 2.0)589        } finally {590            span.end()591        }592    }593    @Test594    fun droppingAttributes() {595        val maxNumberOfAttributes = 8596        val spanLimits =597            SpanLimits.builder().setMaxNumberOfAttributes(maxNumberOfAttributes).build()598        val span = createTestSpan(spanLimits)599        try {600            for (i in 0 until 2 * maxNumberOfAttributes) {601                span.setAttribute(longKey("MyStringAttributeKey$i"), i.toLong())602            }603            val spanData: SpanData = span.toSpanData()604            spanData.attributes.size shouldBe maxNumberOfAttributes605            spanData.totalAttributeCount shouldBe 2 * maxNumberOfAttributes606        } finally {607            span.end()608        }609        val spanData: SpanData = span.toSpanData()610        spanData.attributes.size shouldBe maxNumberOfAttributes611        spanData.totalAttributeCount shouldBe 2 * maxNumberOfAttributes612    }613    @Test614    fun endWithTimestamp_numeric() {615        val span1 = createTestRootSpan()616        span1.end(10, DateTimeUnit.NANOSECOND)617        span1.toSpanData().endEpochNanos shouldBe 10618    }619    @Test620    fun endWithTimestamp_instant() {621        val span1 = createTestRootSpan()622        span1.end(Instant.fromEpochMilliseconds(10))623        span1.toSpanData().endEpochNanos shouldBe DateTimeUnit.MILLISECOND.normalizeToNanos(10)624    }625    @Test626    fun droppingAndAddingAttributes() {627        val maxNumberOfAttributes = 8628        val spanLimits =629            SpanLimits.builder().setMaxNumberOfAttributes(maxNumberOfAttributes).build()630        val span = createTestSpan(spanLimits)631        try {632            for (i in 0 until 2 * maxNumberOfAttributes) {633                span.setAttribute(longKey("MyStringAttributeKey$i"), i.toLong())634            }635            var spanData: SpanData = span.toSpanData()636            spanData.attributes.size shouldBe maxNumberOfAttributes637            spanData.totalAttributeCount shouldBe 2 * maxNumberOfAttributes638            for (i in 0 until maxNumberOfAttributes / 2) {639                val value = i + maxNumberOfAttributes * 3 / 2640                span.setAttribute(longKey("MyStringAttributeKey$i"), value.toLong())641            }642            spanData = span.toSpanData()643            spanData.attributes.size shouldBe maxNumberOfAttributes644            // Test that we still have in the attributes map the latest maxNumberOfAttributes / 2645            // entries.646            for (i in 0 until maxNumberOfAttributes / 2) {647                val value = i + maxNumberOfAttributes * 3 / 2648                spanData.attributes[longKey("MyStringAttributeKey$i")] shouldBe value649            }650            // Test that we have the newest re-added initial entries.651            for (i in maxNumberOfAttributes / 2 until maxNumberOfAttributes) {652                spanData.attributes[longKey("MyStringAttributeKey$i")] shouldBe i653            }654        } finally {655            span.end()656        }657    }658    @Test659    fun droppingEvents() {660        val maxNumberOfEvents = 8661        val spanLimits = SpanLimits.builder().setMaxNumberOfEvents(maxNumberOfEvents).build()662        val span = createTestSpan(spanLimits)663        try {664            for (i in 0 until 2 * maxNumberOfEvents) {665                span.addEvent("event2", Attributes.empty())666                testClock.advance(1.seconds)667            }668            val spanData: SpanData = span.toSpanData()669            spanData.events.size shouldBe maxNumberOfEvents670            for (i in 0 until maxNumberOfEvents) {671                val expectedEvent: EventData =672                    EventData.create(673                        START_EPOCH_NANOS + i * NANOS_PER_SECOND,674                        "event2",675                        Attributes.empty(),676                        0677                    )678                spanData.events[i] shouldBe expectedEvent679                spanData.totalRecordedEvents shouldBe 2 * maxNumberOfEvents680            }681            spanData.totalRecordedEvents shouldBe 2 * maxNumberOfEvents682        } finally {683            span.end()684        }685        val spanData: SpanData = span.toSpanData()686        spanData.events.size shouldBe maxNumberOfEvents687        for (i in 0 until maxNumberOfEvents) {688            val expectedEvent: EventData =689                EventData.create(690                    START_EPOCH_NANOS + i * NANOS_PER_SECOND,691                    "event2",692                    Attributes.empty(),693                    0694                )695            spanData.events[i] shouldBe expectedEvent696        }697    }698    @Test699    fun recordException() {700        val exception = IllegalStateException("there was an exception")701        val span = createTestRootSpan()702        val stacktrace: String = exception.stackTraceToString()703        testClock.advance(1000.nanoseconds)704        val timestamp = testClock.now()705        span.recordException(exception)706        val events: List<EventData> = span.toSpanData().events707        events.shouldHaveSize(1)708        val event: EventData = events[0]709        event.name shouldBe "exception"710        event.epochNanos shouldBe timestamp711        event.attributes shouldBe712            Attributes.builder()713                .put(SemanticAttributes.EXCEPTION_TYPE, "IllegalStateException")714                .put(SemanticAttributes.EXCEPTION_MESSAGE, "there was an exception")715                .put(SemanticAttributes.EXCEPTION_STACKTRACE, stacktrace)716                .build()717    }718    @Test719    fun recordException_noMessage() {720        val exception = IllegalStateException()721        val span = createTestRootSpan()722        span.recordException(exception)723        val events: List<EventData> = span.toSpanData().events724        events.shouldHaveSize(1)725        val event: EventData = events[0]726        event.attributes[SemanticAttributes.EXCEPTION_MESSAGE].shouldBeNull()727    }728    private class InnerClassException : Exception()729    @Test730    fun recordException_innerClassException() {731        val exception = InnerClassException()732        val span = createTestRootSpan()733        span.recordException(exception)734        val events: List<EventData> = span.toSpanData().events735        events.shouldHaveSize(1)736        val event: EventData = events[0]737        event.attributes[SemanticAttributes.EXCEPTION_TYPE] shouldBe738            InnerClassException::class.simpleName!!739    }740    @Test741    fun recordException_additionalAttributes() {742        val exception = IllegalStateException("there was an exception")743        val stacktrace: String = exception.stackTraceToString()744        testClock.advance(1000.nanoseconds)745        val timestamp = testClock.now()746        val span = createTestSpan(SpanKind.INTERNAL)747        span.recordException(748            exception,749            Attributes.of(750                stringKey("key1"),751                "this is an additional attribute",752                stringKey("exception.message"),753                "this is a precedence attribute"754            )755        )756        val events: List<EventData> = span.toSpanData().events757        events.shouldHaveSize(1)758        val event: EventData = events[0]759        event.name shouldBe "exception"760        event.epochNanos shouldBe timestamp761        event.attributes shouldBe762            Attributes.builder()763                .put("key1", "this is an additional attribute")764                .put("exception.type", "IllegalStateException")765                .put("exception.message", "this is a precedence attribute")766                .put("exception.stacktrace", stacktrace)767                .build()768    }769    @Test770    fun badArgsIgnored() {771        val span = createTestRootSpan()772        // Should be no exceptions773        span.end(0, DateTimeUnit.NANOSECOND)774        // Ignored the bad calls775        val data: SpanData = span.toSpanData()776        data.attributes.isEmpty().shouldBeTrue()777        data.status shouldBe StatusData.unset()778        data.name shouldBe SPAN_NAME779    }780    private fun createTestSpanWithAttributes(781        attributes: Map<AttributeKey<*>, Any>782    ): RecordEventsReadableSpan {783        val spanLimits: SpanLimits = SpanLimits.default784        val attributesMap =785            AttributesMap(spanLimits.maxNumberOfAttributes, spanLimits.maxAttributeValueLength)786        attributes.forEach { pair -> attributesMap.put(pair.key, pair.value) }787        return createTestSpan(788            SpanKind.INTERNAL,789            SpanLimits.default,790            null,791            attributesMap,792            listOf(link)793        )794    }795    private fun createTestRootSpan(): RecordEventsReadableSpan {796        return createTestSpan(797            SpanKind.INTERNAL,798            SpanLimits.default,799            SpanId.invalid,800            null,801            listOf(link)802        )803    }804    private fun createTestSpan(config: SpanLimits): RecordEventsReadableSpan {805        return createTestSpan(SpanKind.INTERNAL, config, parentSpanId, null, listOf(link))806    }807    private fun createTestSpan(808        kind: SpanKind,809        config: SpanLimits = SpanLimits.default,810        parentSpanId: String? = this.parentSpanId,811        attributes: AttributesMap? = null,812        links: List<LinkData> = listOf(link)813    ): RecordEventsReadableSpan {814        val span =815            RecordEventsReadableSpan.startSpan(816                spanContext,817                SPAN_NAME,818                instrumentationLibraryInfo,819                kind,820                if (parentSpanId != null)821                    Span.wrap(822                        SpanContext.create(823                            traceId,824                            parentSpanId,825                            TraceFlags.default,826                            TraceState.default827                        )828                    )829                else Span.invalid(),830                Context.root(),831                config,832                spanProcessor,833                testClock,834                resource,835                attributes,836                links,837                1,838                0839            )840        spanProcessor.startSpan shouldBe span841        spanProcessor.startContext shouldBe Context.root()842        return span843    }844    private fun spanDoWork(845        span: RecordEventsReadableSpan,846        canonicalCode: StatusCode?,847        descriptio: String?848    ) {849        span.setAttribute("MySingleStringAttributeKey", "MySingleStringAttributeValue")850        attributes.forEach { pair -> span.setAttribute(pair.key as AttributeKey<Any>, pair.value) }851        testClock.advance(1.seconds)852        span.addEvent("event2", Attributes.empty())853        testClock.advance(1.seconds)854        span.updateName(SPAN_NEW_NAME)855        if (canonicalCode != null) {856            span.setStatus(canonicalCode, descriptio!!)857        }858    }859    private fun verifySpanData(860        spanData: SpanData,861        attributes: Attributes?,862        eventData: List<EventData>,863        links: List<LinkData>,864        spanName: String,865        startEpochNanos: Long,866        endEpochNanos: Long,867        status: StatusData,868        hasEnded: Boolean869    ) {870        spanData.traceId shouldBe traceId871        spanData.spanId shouldBe spanId872        spanData.parentSpanId shouldBe parentSpanId873        spanData.spanContext.traceState shouldBe TraceState.default874        spanData.resource shouldBe resource875        spanData.instrumentationLibraryInfo shouldBe instrumentationLibraryInfo876        spanData.name shouldBe spanName877        spanData.events shouldBe eventData878        spanData.links shouldBe links879        spanData.startEpochNanos shouldBe startEpochNanos880        spanData.endEpochNanos shouldBe endEpochNanos881        spanData.status.statusCode shouldBe status.statusCode882        spanData.hasEnded() shouldBe hasEnded883        // verify equality manually, since the implementations don't all equals with each other.884        val spanDataAttributes: Attributes = spanData.attributes885        spanDataAttributes.size shouldBe attributes!!.size886        spanDataAttributes.forEach { key, value ->887            attributes[key as AttributeKey<Any>] shouldBe value888        }889    }890    @Test891    fun testAsSpanData() {892        val name = "GreatSpan"893        val kind: SpanKind = SpanKind.SERVER894        val traceId = traceId895        val spanId = spanId896        val parentSpanId = parentSpanId897        val spanLimits: SpanLimits = SpanLimits.default898        val spanProcessor: SpanProcessor = NoopSpanProcessor.instance899        val resource = resource900        val attributes: Attributes = TestUtils.generateRandomAttributes()901        val attributesWithCapacity = AttributesMap(32, Int.MAX_VALUE)902        attributes.forEach { key, value -> attributesWithCapacity.put(key, value) }903        val event1Attributes: Attributes = TestUtils.generateRandomAttributes()904        val event2Attributes: Attributes = TestUtils.generateRandomAttributes()905        val context: SpanContext =906            SpanContext.create(traceId, spanId, TraceFlags.default, TraceState.default)907        val link1: LinkData = LinkData.create(context, TestUtils.generateRandomAttributes())908        val clock = testClock909        val readableSpan =910            RecordEventsReadableSpan.startSpan(911                context,912                name,913                instrumentationLibraryInfo,914                kind,915                if (parentSpanId != null)916                    Span.wrap(917                        SpanContext.create(918                            traceId,919                            parentSpanId,920                            TraceFlags.default,921                            TraceState.default922                        )923                    )924                else Span.invalid(),925                Context.root(),926                spanLimits,927                spanProcessor,928                clock,929                resource,930                attributesWithCapacity,931                listOf(link1),932                1,933                0934            )935        val startEpochNanos = clock.now()936        clock.advance(4.milliseconds)937        val firstEventEpochNanos = clock.now()938        readableSpan.addEvent("event1", event1Attributes)939        clock.advance(6.milliseconds)940        val secondEventTimeNanos = clock.now()941        readableSpan.addEvent("event2", event2Attributes)942        clock.advance(100.milliseconds)943        readableSpan.end()944        val endEpochNanos = clock.now()945        val events: List<EventData> =946            listOf(947                EventData.create(948                    firstEventEpochNanos,949                    "event1",950                    event1Attributes,951                    event1Attributes.size952                ),953                EventData.create(954                    secondEventTimeNanos,955                    "event2",956                    event2Attributes,957                    event2Attributes.size958                )959            )960        val result: SpanData = readableSpan.toSpanData()961        verifySpanData(962            result,963            attributesWithCapacity,964            events,965            listOf(link1),966            name,967            startEpochNanos,968            endEpochNanos,969            StatusData.unset(),970            true971        )972        result.totalRecordedLinks shouldBe 1973        result.spanContext.isSampled() shouldBe false974    }975    /*   @Test976    @Throws(ExecutionException::class, InterruptedException::class)977    fun testConcurrentModification() {978        val span = createTestSpan(SpanKind.INTERNAL)979        val es: ExecutorService = Executors.newSingleThreadExecutor()980        val modifierFuture: Future<*> = es.submit(981            Runnable {982                for (i in 0 until 5096 * 5) {983                    span.setAttribute("hey$i", "")984                }985            })986        try {987            for (i in 0 until 5096 * 5) {988                span.toSpanData()989            }990        } catch (t: Throwable) {991            modifierFuture.cancel(true)992            throw t993        }994        modifierFuture.get()995    }*/996    companion object {997        private const val SPAN_NAME = "MySpanName"998        private const val SPAN_NEW_NAME = "NewName"999        private val NANOS_PER_SECOND: Long = (1.seconds).inWholeNanoseconds1000        private const val START_EPOCH_NANOS = 1000123789654L1001    }1002}...ShowApiTest.kt
Source:ShowApiTest.kt  
...225                shouldThrow<HttpClientResponseException> {226                    httpClient.delete<Int, Int?>("/shows/1", null)227                }228            exception.status shouldBe HttpStatus.BAD_REQUEST229            exception.message shouldBe "Show can not be cancelled"230        }231        "should return list of past shows" {232            dataSource.connection.use { connection ->233                connection.executeCommand("INSERT INTO movies(title,duration_in_minutes) VALUES ('Avengers',85)")234                connection.executeCommand(235                    "INSERT INTO movies\n" +236                        "(title, duration_in_minutes) VALUES\n" +237                        "('Avengers EndGame', 80);\n"238                )239                connection.executeCommand(240                    "INSERT INTO shows\n" +241                        "(start_time, end_time,movie_id) VALUES\n" +242                        "('2021-08-05 09:15:00', '2021-08-05 11:30:11',1);\n"243                )...ShowServiceTest.kt
Source:ShowServiceTest.kt  
...234            } returns show1235            val exception = shouldThrow<InvalidInputException> {236                showService.deleteShowById(DeleteShowRequest(show1.id))237            }238            exception.message shouldBe "Show can not be cancelled"239        }240        "should return a show with available tickets if show exists" {241            val requiredShow = Show(242                1,243                Timestamp.valueOf("2021-09-06 09:15:00").toLocalDateTime(),244                Timestamp.valueOf("2021-09-06 11:30:00").toLocalDateTime(),245                1,246                null,247                100,248                44249            )250            every {251                mockShowRepository.findShowById(1)252            } returns requiredShow...FutureMatcherTest.kt
Source:FutureMatcherTest.kt  
...14   "test future is not completed" {15      val completableFuture = CompletableFuture<Int>()16      completableFuture.shouldNotBeCompleted()17   }18   "test future is cancelled" {19      val completableFuture = CompletableFuture<Int>()20      completableFuture.cancel(true)21      completableFuture.shouldBeCancelled()22   }23   "test future is not cancelled" {24      val completableFuture = CompletableFuture<Int>()25      completableFuture.shouldNotBeCancelled()26   }27   "test future is completed exceptionally" {28      val completableFuture = CompletableFuture<Int>()29      Executors.newFixedThreadPool(1).submit {30         completableFuture.cancel(false)31      }32      delay(200)33      completableFuture.shouldBeCompletedExceptionally()34   }35   "test future is not completed exceptionally" {36      val completableFuture = CompletableFuture<Int>()37      completableFuture.complete(2)...matchers.kt
Source:matchers.kt  
...27         {28            "Future should not be completed"29         })30}31fun <T> CompletableFuture<T>.shouldBeCancelled() = this shouldBe cancelled<T>()32fun <T> CompletableFuture<T>.shouldNotBeCancelled() = this shouldNotBe cancelled<T>()33fun <T> cancelled() = object : Matcher<CompletableFuture<T>> {34   override fun test(value: CompletableFuture<T>): MatcherResult =35      MatcherResult(36         value.isCancelled,37         { "Future should be completed" },38         {39            "Future should not be completed"40         })41}42infix fun CompletableFuture<*>.shouldCompleteExceptionallyWith(throwable: Throwable) =43   this should completeExceptionallyWith(throwable)44infix fun CompletableFuture<*>.shouldNotCompleteExceptionallyWith(throwable: Throwable) =45   this shouldNot completeExceptionallyWith(throwable)46internal fun completeExceptionallyWith(throwable: Throwable) = object : Matcher<CompletableFuture<*>> {47   override fun test(value: CompletableFuture<*>): MatcherResult {...PeriodicFlushStrategyTest.kt
Source:PeriodicFlushStrategyTest.kt  
1package rawhttp.cookies.persistence2import io.kotest.matchers.shouldBe3import io.kotest.matchers.shouldNotBe4import org.junit.jupiter.api.Test5import rawhttp.cookies.persist.PeriodicFlushStrategy6import java.time.Duration7import java.util.concurrent.Delayed8import java.util.concurrent.Executors9import java.util.concurrent.Future10import java.util.concurrent.ScheduledExecutorService11import java.util.concurrent.ScheduledFuture12import java.util.concurrent.TimeUnit13class PeriodicFlushStrategyTest {14    @Test15    fun flushesPeriodically() {16        var count = 017        var flushAction: Runnable? = null18        val executor = object : ScheduledExecutorService by Executors.newSingleThreadScheduledExecutor() {19            override fun scheduleAtFixedRate(command: Runnable, initialDelay: Long, period: Long, unit: TimeUnit): ScheduledFuture<*> {20                flushAction = command21                initialDelay shouldBe 1000L22                period shouldBe 1000L23                unit shouldBe TimeUnit.MILLISECONDS24                return MockScheduledFuture25            }26            override fun submit(task: Runnable): Future<*> {27                task.run()28                return MockScheduledFuture29            }30        }31        val strategy = PeriodicFlushStrategy(Duration.ofSeconds(1), executor)32        strategy.init { count++ }33        // make sure the flushAction was set34        flushAction shouldNotBe null35        // and the flush action has never run36        count shouldBe 037        // WHEN the flush action is executed by the scheduler38        flushAction?.run()39        // THEN flush is not called because there has been no updates to the cookie store40        count shouldBe 041        // WHEN we update the cookie store42        strategy.onUpdate(MockCookieStore)43        // AND run the flush action44        flushAction?.run()45        // THEN flush should be called46        count shouldBe 147    }48}49object MockScheduledFuture: ScheduledFuture<Unit> {50    override fun compareTo(other: Delayed?): Int {51        return -152    }53    override fun getDelay(unit: TimeUnit): Long {54        return 0L55    }56    override fun cancel(mayInterruptIfRunning: Boolean): Boolean {57        return false58    }59    override fun isCancelled(): Boolean {60        return false61    }62    override fun isDone(): Boolean {63        return false64    }65    override fun get() {66    }67    override fun get(timeout: Long, unit: TimeUnit) {68    }69}...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
