Best Kotest code snippet using io.kotest.matchers.collections.matchers.Array.shouldNotContainAnyOf
CollectionMatchersTest.kt
Source:CollectionMatchersTest.kt
1package com.sksamuel.kotest.matchers.collections2import io.kotest.assertions.shouldFail3import io.kotest.assertions.throwables.shouldNotThrow4import io.kotest.assertions.throwables.shouldThrow5import io.kotest.assertions.withClue6import io.kotest.core.spec.style.WordSpec7import io.kotest.equals.Equality8import io.kotest.equals.types.byObjectEquality9import io.kotest.matchers.collections.atLeastSize10import io.kotest.matchers.collections.atMostSize11import io.kotest.matchers.collections.beLargerThan12import io.kotest.matchers.collections.beSameSizeAs13import io.kotest.matchers.collections.beSmallerThan14import io.kotest.matchers.collections.contain15import io.kotest.matchers.collections.containDuplicates16import io.kotest.matchers.collections.containNoNulls17import io.kotest.matchers.collections.containNull18import io.kotest.matchers.collections.containOnlyNulls19import io.kotest.matchers.collections.matchInOrder20import io.kotest.matchers.collections.existInOrder21import io.kotest.matchers.collections.haveElementAt22import io.kotest.matchers.collections.haveSize23import io.kotest.matchers.collections.matchEach24import io.kotest.matchers.collections.matchInOrderSubset25import io.kotest.matchers.collections.monotonicallyDecreasing26import io.kotest.matchers.collections.monotonicallyDecreasingWith27import io.kotest.matchers.collections.monotonicallyIncreasing28import io.kotest.matchers.collections.monotonicallyIncreasingWith29import io.kotest.matchers.collections.shouldBeIn30import io.kotest.matchers.collections.shouldBeLargerThan31import io.kotest.matchers.collections.shouldBeMonotonicallyDecreasing32import io.kotest.matchers.collections.shouldBeMonotonicallyDecreasingWith33import io.kotest.matchers.collections.shouldBeMonotonicallyIncreasing34import io.kotest.matchers.collections.shouldBeMonotonicallyIncreasingWith35import io.kotest.matchers.collections.shouldBeSameSizeAs36import io.kotest.matchers.collections.shouldBeSingleton37import io.kotest.matchers.collections.shouldBeSmallerThan38import io.kotest.matchers.collections.shouldBeSorted39import io.kotest.matchers.collections.shouldBeSortedBy40import io.kotest.matchers.collections.shouldBeSortedWith41import io.kotest.matchers.collections.shouldBeStrictlyDecreasing42import io.kotest.matchers.collections.shouldBeStrictlyDecreasingWith43import io.kotest.matchers.collections.shouldBeStrictlyIncreasing44import io.kotest.matchers.collections.shouldBeStrictlyIncreasingWith45import io.kotest.matchers.collections.shouldContainAnyOf46import io.kotest.matchers.collections.shouldContainDuplicates47import io.kotest.matchers.collections.shouldContainNoNulls48import io.kotest.matchers.collections.shouldContainNull49import io.kotest.matchers.collections.shouldContainOnlyNulls50import io.kotest.matchers.collections.shouldExist51import io.kotest.matchers.collections.shouldHaveAtLeastSize52import io.kotest.matchers.collections.shouldHaveAtMostSize53import io.kotest.matchers.collections.shouldHaveElementAt54import io.kotest.matchers.collections.shouldHaveSingleElement55import io.kotest.matchers.collections.shouldHaveSize56import io.kotest.matchers.collections.shouldMatchInOrder57import io.kotest.matchers.collections.shouldMatchInOrderSubset58import io.kotest.matchers.collections.shouldNotBeIn59import io.kotest.matchers.collections.shouldNotBeMonotonicallyDecreasing60import io.kotest.matchers.collections.shouldNotBeMonotonicallyDecreasingWith61import io.kotest.matchers.collections.shouldNotBeMonotonicallyIncreasing62import io.kotest.matchers.collections.shouldNotBeMonotonicallyIncreasingWith63import io.kotest.matchers.collections.shouldNotBeSingleton64import io.kotest.matchers.collections.shouldNotBeSorted65import io.kotest.matchers.collections.shouldNotBeSortedBy66import io.kotest.matchers.collections.shouldNotBeSortedWith67import io.kotest.matchers.collections.shouldNotBeStrictlyDecreasing68import io.kotest.matchers.collections.shouldNotBeStrictlyDecreasingWith69import io.kotest.matchers.collections.shouldNotBeStrictlyIncreasing70import io.kotest.matchers.collections.shouldNotBeStrictlyIncreasingWith71import io.kotest.matchers.collections.shouldNotContainAnyOf72import io.kotest.matchers.collections.shouldNotContainDuplicates73import io.kotest.matchers.collections.shouldNotContainNoNulls74import io.kotest.matchers.collections.shouldNotContainNull75import io.kotest.matchers.collections.shouldNotContainOnlyNulls76import io.kotest.matchers.collections.shouldNotHaveElementAt77import io.kotest.matchers.collections.shouldNotHaveSize78import io.kotest.matchers.collections.shouldNotMatchEach79import io.kotest.matchers.collections.shouldNotMatchInOrder80import io.kotest.matchers.collections.shouldNotMatchInOrderSubset81import io.kotest.matchers.collections.singleElement82import io.kotest.matchers.collections.sorted83import io.kotest.matchers.collections.strictlyDecreasing84import io.kotest.matchers.collections.strictlyDecreasingWith85import io.kotest.matchers.collections.strictlyIncreasing86import io.kotest.matchers.collections.strictlyIncreasingWith87import io.kotest.matchers.ints.shouldBeGreaterThan88import io.kotest.matchers.ints.shouldBeInRange89import io.kotest.matchers.should90import io.kotest.matchers.shouldBe91import io.kotest.matchers.shouldHave92import io.kotest.matchers.shouldNot93import io.kotest.matchers.shouldNotBe94import io.kotest.matchers.shouldNotHave95import io.kotest.matchers.throwable.shouldHaveMessage96class CollectionMatchersTest : WordSpec() {97 private val countdown = (10 downTo 0).toList()98 private val asc = { a: Int, b: Int -> a - b }99 private val desc = { a: Int, b: Int -> b - a }100 init {101 "a descending non-empty list" should {102 "fail to ascend" {103 shouldFail {104 countdown.shouldBeSortedWith(asc)105 }106 }107 "descend" {108 countdown.shouldBeSortedWith(desc)109 }110 "not ascend" {111 countdown.shouldNotBeSortedWith(asc)112 }113 "fail not to descend" {114 shouldFail {115 countdown.shouldNotBeSortedWith(desc)116 }117 }118 }119 "sortedWith" should {120 val items = listOf(121 1 to "I",122 2 to "II",123 4 to "IV",124 5 to "V",125 6 to "VI",126 9 to "IX",127 10 to "X"128 )129 "work on non-Comparable given a Comparator" {130 items.shouldBeSortedWith(Comparator { a, b -> asc(a.first, b.first) })131 }132 "work on non-Comparable given a compare function" {133 items.shouldBeSortedWith { a, b -> asc(a.first, b.first) }134 }135 }136 "haveElementAt" should {137 "test that a collection contains the specified element at the given index" {138 listOf("a", "b", "c") should haveElementAt(1, "b")139 listOf("a", "b", "c") shouldNot haveElementAt(1, "c")140 listOf("a", "b", null) should haveElementAt(2, null)141 listOf("a", "b", null) shouldNot haveElementAt(3, null)142 listOf("a", "b", "c").shouldHaveElementAt(1, "b")143 listOf("a", "b", "c").shouldNotHaveElementAt(1, "c")144 listOf("a", "b", null).shouldHaveElementAt(2, null)145 }146 "support type inference for subtypes of collection" {147 val tests = listOf(148 TestSealed.Test1("test1"),149 TestSealed.Test2(2)150 )151 tests should haveElementAt(0, TestSealed.Test1("test1"))152 tests.shouldHaveElementAt(1, TestSealed.Test2(2))153 }154 }155 "containNull()" should {156 "test that a collection contains at least one null" {157 listOf(1, 2, null) should containNull()158 listOf(null) should containNull()159 listOf(1, 2) shouldNot containNull()160 listOf(1, 2, null).shouldContainNull()161 listOf(null).shouldContainNull()162 listOf(1, 2).shouldNotContainNull()163 }164 }165 "sorted" should {166 "test that a collection is sorted" {167 emptyList<Int>() shouldBe sorted<Int>()168 listOf(1) shouldBe sorted<Int>()169 listOf(1, 2, 3, 4) shouldBe sorted<Int>()170 shouldThrow<AssertionError> {171 listOf(2, 1) shouldBe sorted<Int>()172 }.shouldHaveMessage("List [2, 1] should be sorted. Element 2 at index 0 was greater than element 1")173 listOf(1, 2, 6, 9).shouldBeSorted()174 shouldThrow<AssertionError> {175 listOf(2, 1).shouldBeSorted()176 }.shouldHaveMessage("List [2, 1] should be sorted. Element 2 at index 0 was greater than element 1")177 shouldThrow<AssertionError> {178 listOf(1, 2, 3).shouldNotBeSorted()179 }.shouldHaveMessage("List [1, 2, 3] should not be sorted")180 }181 "restrict items at the error message" {182 val longList = (1..1000).toList()183 shouldThrow<AssertionError> {184 longList.shouldNotBeSorted()185 }.shouldHaveMessage("List [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...and 980 more (set the 'kotest.assertions.collection.print.size' JVM property to see more / less items)] should not be sorted")186 }187 }188 "sortedBy" should {189 val items = listOf(190 1 to "I",191 2 to "II",192 4 to "IV",193 5 to "V",194 6 to "VI",195 9 to "IX",196 10 to "X"197 )198 "compare by the tranformed value" {199 items.shouldBeSortedBy { it.first }200 items.shouldNotBeSortedBy { it.second }201 }202 }203 "shouldBeIncreasing" should {204 "test that a collection is monotonically increasing" {205 listOf(1, 2, 2, 3) shouldBe monotonicallyIncreasing<Int>()206 listOf(6, 5) shouldNotBe monotonicallyIncreasing<Int>()207 listOf(1, 2, 2, 3).shouldBeMonotonicallyIncreasing()208 listOf(6, 5).shouldNotBeMonotonicallyIncreasing()209 }210 "test that a collection is monotonically increasing according to comparator" {211 val comparator = Comparator(desc)212 listOf(3, 2, 2, 1) shouldBe monotonicallyIncreasingWith(comparator)213 listOf(5, 6) shouldNotBe monotonicallyIncreasingWith(comparator)214 listOf(3, 2, 2, 1).shouldBeMonotonicallyIncreasingWith(comparator)215 listOf(5, 6).shouldNotBeMonotonicallyIncreasingWith(comparator)216 }217 "test that a collection is strictly increasing" {218 listOf(1, 2, 3) shouldBe strictlyIncreasing<Int>()219 listOf(1, 2, 2, 3) shouldNotBe strictlyIncreasing<Int>()220 listOf(6, 5) shouldNotBe strictlyIncreasing<Int>()221 listOf(1, 2, 3).shouldBeStrictlyIncreasing()222 listOf(1, 2, 2, 3).shouldNotBeStrictlyIncreasing()223 listOf(6, 5).shouldNotBeStrictlyIncreasing()224 }225 "test that a collection is strictly increasing according to comparator" {226 val comparator = Comparator(desc)227 listOf(3, 2, 1) shouldBe strictlyIncreasingWith(comparator)228 listOf(3, 2, 2, 1) shouldNotBe strictlyIncreasingWith(comparator)229 listOf(5, 6) shouldNotBe strictlyIncreasingWith(comparator)230 listOf(3, 2, 1).shouldBeStrictlyIncreasingWith(comparator)231 listOf(3, 2, 2, 1).shouldNotBeStrictlyIncreasingWith(comparator)232 listOf(5, 6).shouldNotBeStrictlyIncreasingWith(comparator)233 }234 }235 "shouldBeDecreasing" should {236 "test that a collection is monotonically decreasing" {237 listOf(3, 2, 2, -4) shouldBe monotonicallyDecreasing<Int>()238 listOf(5, 6) shouldNotBe monotonicallyDecreasing<Int>()239 listOf(3, 2, 2, -4).shouldBeMonotonicallyDecreasing()240 listOf(5, 6).shouldNotBeMonotonicallyDecreasing()241 }242 "test that a collection is monotonically decreasing according to comparator" {243 val comparator = Comparator(desc)244 listOf(-4, 2, 2, 3) shouldBe monotonicallyDecreasingWith(comparator)245 listOf(6, 5) shouldNotBe monotonicallyDecreasingWith(comparator)246 listOf(-4, 2, 2, 3).shouldBeMonotonicallyDecreasingWith(comparator)247 listOf(6, 5).shouldNotBeMonotonicallyDecreasingWith(comparator)248 }249 "test that a collection is strictly decreasing" {250 listOf(3, 2, -4) shouldBe strictlyDecreasing<Int>()251 listOf(3, 2, 2, -4) shouldNotBe strictlyDecreasing<Int>()252 listOf(5, 6) shouldNotBe strictlyDecreasing<Int>()253 listOf(3, 2, -4).shouldBeStrictlyDecreasing()254 listOf(3, 2, 2, -4).shouldNotBeStrictlyDecreasing()255 listOf(5, 6).shouldNotBeStrictlyDecreasing()256 }257 "test that a collection is strictly decreasing according to comparator" {258 val comparator = Comparator(desc)259 listOf(-4, 2, 3) shouldBe strictlyDecreasingWith(comparator)260 listOf(-4, 2, 2, 3) shouldNotBe strictlyDecreasingWith(comparator)261 listOf(6, 5) shouldNotBe strictlyDecreasingWith(comparator)262 listOf(-4, 2, 3).shouldBeStrictlyDecreasingWith(comparator)263 listOf(-4, 2, 2, 3).shouldNotBeStrictlyDecreasingWith(comparator)264 listOf(6, 5).shouldNotBeStrictlyDecreasingWith(comparator)265 }266 }267 "haveDuplicates" should {268 "test that a collection is unique" {269 listOf(1, 2, 3, 3) should containDuplicates()270 listOf(1, 2, 3, 4) shouldNot containDuplicates()271 listOf(1, 2, 3, 3).shouldContainDuplicates()272 listOf(1, 2, 3, 4).shouldNotContainDuplicates()273 }274 }275 "singleElement" should {276 "test that a collection contains a single given element" {277 listOf(1) shouldBe singleElement(1)278 listOf(1).shouldHaveSingleElement(1)279 shouldThrow<AssertionError> {280 listOf(1) shouldBe singleElement(2)281 }.shouldHaveMessage("Collection should be a single element of 2 but has 1 elements: [1]")282 shouldThrow<AssertionError> {283 listOf(1, 2) shouldBe singleElement(2)284 }.shouldHaveMessage("Collection should be a single element of 2 but has 2 elements: [1, 2]")285 }286 }287 "singleElement with predicate" should {288 "test that a collection contains a single element by given predicate" {289 listOf(1) shouldHave singleElement { e -> e == 1 }290 listOf(1).shouldHaveSingleElement { e -> e == 1 }291 shouldThrow<AssertionError> {292 listOf(1) shouldHave singleElement { e -> e == 2 }293 }.shouldHaveMessage("Collection should have a single element by a given predicate but has 0 elements: [1]")294 shouldThrow<AssertionError> {295 listOf(2, 2) shouldHave singleElement { e -> e == 2 }296 }.shouldHaveMessage("Collection should have a single element by a given predicate but has 2 elements: [2, 2]")297 }298 }299 "should contain element" should {300 "test that a collection contains an element" {301 val col = listOf(1, 2, 3)302 col should contain(2)303 col should contain(2.0) // uses strict num equality = false304 shouldThrow<AssertionError> {305 col should contain(4)306 }.shouldHaveMessage("Collection should contain element 4 based on object equality; but the collection is [1, 2, 3]")307 }308 }309 "should contain element based on a custom equality object" should {310 "test that a collection contains an element" {311 val col = listOf(1, 2, 3.0)312 val verifier = Equality.byObjectEquality<Number>(strictNumberEquality = true)313 col should contain(2, verifier)314 col should contain(3.0, verifier)315 shouldThrow<AssertionError> {316 col should contain(3, verifier)317 }.shouldHaveMessage("Collection should contain element 3 based on object equality; but the collection is [1, 2, 3.0]")318 }319 }320 "shouldBeLargerThan" should {321 "test that a collection is larger than another collection" {322 val col1 = listOf(1, 2, 3)323 val col2 = setOf(1, 2, 3, 4)324 col2.shouldBeLargerThan(col1)325 col2 should beLargerThan(col1)326 col1 shouldNot beLargerThan(col2)327 shouldThrow<AssertionError> {328 col1.shouldBeLargerThan(col2)329 }.shouldHaveMessage("Collection of size 3 should be larger than collection of size 4")330 }331 }332 "shouldBeSmallerThan" should {333 "test that a collection is smaller than another collection" {334 val col1 = listOf(1, 2, 3)335 val col2 = setOf(1, 2, 3, 4)336 col1.shouldBeSmallerThan(col2)337 col1 should beSmallerThan(col2)338 col2 shouldNot beSmallerThan(col1)339 shouldThrow<AssertionError> {340 col2.shouldBeSmallerThan(col1)341 }.shouldHaveMessage("Collection of size 4 should be smaller than collection of size 3")342 }343 }344 "shouldBeSameSizeAs" should {345 "test that a collection is the same size as another collection" {346 val col1 = listOf(1, 2, 3)347 val col2 = setOf(1, 2, 3)348 val col3 = listOf(1, 2, 3, 4)349 col1.shouldBeSameSizeAs(col2)350 col1 should beSameSizeAs(col2)351 col1 shouldNot beSameSizeAs(col3)352 shouldThrow<AssertionError> {353 col1.shouldBeSameSizeAs(col3)354 }.shouldHaveMessage("Collection of size 3 should be the same size as collection of size 4")355 }356 }357 "haveSize" should {358 "test that a collection has a certain size" {359 val col1 = listOf(1, 2, 3)360 col1 should haveSize(3)361 col1.shouldHaveSize(3)362 shouldThrow<AssertionError> {363 col1 should haveSize(2)364 }365 val col2 = emptyList<String>()366 col2 should haveSize(0)367 shouldThrow<AssertionError> {368 col2 should haveSize(1)369 }370 listOf(1, 2, 3).shouldNotHaveSize(1)371 listOf(1, 2, 3).shouldNotHaveSize(4)372 shouldThrow<AssertionError> {373 listOf(1, 2, 3).shouldNotHaveSize(3)374 }.shouldHaveMessage("Collection should not have size 3. Values: [1, 2, 3]")375 }376 }377 "should be singleton" should {378 "pass for collection with a single element" {379 listOf(1).shouldBeSingleton()380 }381 "fail for collection with 0 elements" {382 shouldThrow<AssertionError> {383 listOf<Int>().shouldBeSingleton()384 }.shouldHaveMessage("Collection should have size 1 but has size 0. Values: []")385 }386 "fail for collection with 2+ elements" {387 shouldThrow<AssertionError> {388 listOf(1, 2).shouldBeSingleton()389 }.shouldHaveMessage("Collection should have size 1 but has size 2. Values: [1, 2]")390 shouldThrow<AssertionError> {391 listOf(1, 2, 3, 4).shouldBeSingleton()392 }.shouldHaveMessage("Collection should have size 1 but has size 4. Values: [1, 2, 3, 4]")393 }394 }395 "should be singleton with block" should {396 "pass for collection with a single element" {397 listOf(1).shouldBeSingleton { it shouldBe 1 }398 }399 "fail for collection with 0 elements" {400 shouldThrow<AssertionError> {401 listOf<Int>().shouldBeSingleton { it shouldBe 1 }402 }.shouldHaveMessage("Collection should have size 1 but has size 0. Values: []")403 }404 "fail for collection with a single incorrect elements" {405 shouldThrow<AssertionError> {406 listOf(2).shouldBeSingleton { it shouldBe 1 }407 }.shouldHaveMessage("expected:<1> but was:<2>")408 }409 "fail for collection with 2+ elements" {410 shouldThrow<AssertionError> {411 listOf(1, 2).shouldBeSingleton { it shouldBe 1 }412 }.shouldHaveMessage("Collection should have size 1 but has size 2. Values: [1, 2]")413 shouldThrow<AssertionError> {414 listOf(1, 2, 3, 4).shouldBeSingleton { it shouldBe 1 }415 }.shouldHaveMessage("Collection should have size 1 but has size 4. Values: [1, 2, 3, 4]")416 }417 }418 "should not be singleton" should {419 "pass for collection with 0 elements" {420 listOf<Int>().shouldNotBeSingleton()421 }422 "pass for collection with 2+ elements" {423 listOf(1, 2).shouldNotBeSingleton()424 listOf(1, 2, 3, 4).shouldNotBeSingleton()425 }426 "fail for collection with a single element" {427 shouldThrow<AssertionError> {428 listOf(1).shouldNotBeSingleton()429 }.shouldHaveMessage("Collection should not have size 1. Values: [1]")430 }431 }432 "shouldExist" should {433 "test that a collection contains at least one element that matches a predicate" {434 val list = listOf(1, 2, 3)435 list.shouldExist { it == 2 }436 }437 }438 "shouldHaveAtLeastSize" should {439 "test that a collection has at least a certain number of elements" {440 val list = listOf(1, 2, 3)441 list.shouldHaveAtLeastSize(2)442 list shouldHave atLeastSize(2)443 val set = setOf(1, 2, 3)444 set.shouldHaveAtLeastSize(3)445 set shouldHave atLeastSize(3)446 shouldThrow<AssertionError> {447 list.shouldHaveAtLeastSize(4)448 }.shouldHaveMessage("Collection [1, 2, 3] should contain at least 4 elements")449 shouldThrow<AssertionError> {450 list shouldHave atLeastSize(4)451 }.shouldHaveMessage("Collection [1, 2, 3] should contain at least 4 elements")452 shouldThrow<AssertionError> {453 list shouldNotHave atLeastSize(2)454 }.shouldHaveMessage("Collection [1, 2, 3] should contain less than 2 elements")455 }456 }457 "shouldHaveAtMostSize" should {458 "test that a collection has at least a certain number of elements" {459 val list = listOf(1, 2, 3)460 list.shouldHaveAtMostSize(3)461 list shouldHave atMostSize(3)462 list.shouldHaveAtMostSize(4)463 list shouldHave atMostSize(4)464 val set = setOf(1, 2, 3)465 set.shouldHaveAtMostSize(3)466 set shouldHave atMostSize(3)467 set.shouldHaveAtMostSize(4)468 set shouldHave atMostSize(4)469 shouldThrow<AssertionError> {470 list.shouldHaveAtMostSize(2)471 }.shouldHaveMessage("Collection [1, 2, 3] should contain at most 2 elements")472 shouldThrow<AssertionError> {473 list shouldHave atMostSize(2)474 }.shouldHaveMessage("Collection [1, 2, 3] should contain at most 2 elements")475 shouldThrow<AssertionError> {476 list shouldNotHave atMostSize(4)477 }.shouldHaveMessage("Collection [1, 2, 3] should contain more than 4 elements")478 }479 }480 "containNoNulls" should {481 "test that a collection contains zero nulls" {482 emptyList<String>() should containNoNulls()483 listOf(1, 2, 3) should containNoNulls()484 listOf(null, null, null) shouldNot containNoNulls()485 listOf(1, null, null) shouldNot containNoNulls()486 emptyList<String>().shouldContainNoNulls()487 listOf(1, 2, 3).shouldContainNoNulls()488 listOf(null, null, null).shouldNotContainNoNulls()489 listOf(1, null, null).shouldNotContainNoNulls()490 shouldThrow<AssertionError> {491 listOf(null, null, null).shouldContainNoNulls()492 }.shouldHaveMessage("Collection should not contain nulls")493 shouldThrow<AssertionError> {494 listOf(1, 2, 3).shouldNotContainNoNulls()495 }.shouldHaveMessage("Collection should have at least one null")496 }497 "support type inference for subtypes of collection" {498 val tests = listOf(499 TestSealed.Test1("test1"),500 TestSealed.Test2(2)501 )502 tests should containNoNulls()503 tests.shouldContainNoNulls()504 }505 }506 "containOnlyNulls" should {507 "test that a collection contains only nulls" {508 emptyList<String>() should containOnlyNulls()509 listOf(null, null, null) should containOnlyNulls()510 listOf(1, null, null) shouldNot containOnlyNulls()511 listOf(1, 2, 3) shouldNot containOnlyNulls()512 listOf(null, 1, 2, 3).shouldNotContainOnlyNulls()513 listOf(1, 2, 3).shouldNotContainOnlyNulls()514 listOf(null, null, null).shouldContainOnlyNulls()515 }516 }517 "matchInOrder" should {518 "test that a collection matches the assertions in the given order, duplicates permitted" {519 withClue("Gaps not allowed") {520 shouldFail {521 listOf(1, 2, 2, 3) should matchInOrder(522 { it shouldBe 1 },523 { it shouldBe 2 },524 { it shouldBe 3 }525 )526 }527 }528 arrayOf(2, 2, 3).shouldMatchInOrder(529 { it shouldBe 2 },530 { it shouldBe 2 },531 { it shouldBe 3 },532 )533 }534 "failure shows best result" {535 shouldFail {536 listOf(1, 2, 3, 1, 2, 1, 2).shouldMatchInOrder(537 { it shouldBe 1 },538 { it shouldBe 2 },539 { it shouldBe 1 },540 { it shouldBe 3 },541 )542 }.message shouldBe """543 Expected a sequence of elements to pass the assertions, but failed to match all assertions544 Best result when comparing from index [3], where 3 elements passed, but the following elements failed:545 6 => expected:<3> but was:<2>546 """.trimIndent()547 }548 "Non existing element causes error" {549 shouldThrow<AssertionError> {550 listOf(1, 2, 3).shouldMatchInOrder(551 { it shouldBe 1 },552 { it shouldBe 2 },553 { it shouldBe 6 }554 )555 }556 }557 "out-of-order elements cause error" {558 shouldThrow<AssertionError> {559 listOf(1, 2, 3) should matchInOrder(560 { it shouldBe 2 },561 { it shouldBe 1 },562 { it shouldBe 3 }563 )564 }565 }566 "work with unsorted collections" {567 val actual = listOf(5, 3, 1, 2, 4, 2)568 withClue("should match 4th, 5th and 6th elements ([.., 2, 4, 2])") {569 actual should matchInOrder(570 { it shouldBe 2 },571 { it shouldBeGreaterThan 3 },572 { it shouldBeInRange 2..2 }573 )574 }575 }576 "negation should work" {577 shouldFail {578 listOf(1, 2, 3, 4).shouldNotMatchInOrder(579 { it shouldBe 2 },580 { it shouldBe 3 },581 )582 }.message shouldBe """583 Expected some assertion to fail but all passed584 """.trimIndent()585 listOf(1, 2, 3, 4).shouldNotMatchInOrder(586 { it shouldBe 2 },587 { it shouldBe 4 }588 )589 }590 }591 "matchInOrderSubset" should {592 "test that a collection matches the assertions in the given order without gaps" {593 listOf(1, 1, 2, 2, 3, 3) should matchInOrderSubset(594 { it shouldBe 1 },595 { it shouldBe 2 },596 { it shouldBe 2 },597 { it shouldBe 3 }598 )599 arrayOf(1, 1, 1).shouldMatchInOrderSubset(600 { it shouldBe 1 }601 )602 }603 "Negation should work" {604 shouldFail {605 listOf(1, 2, 3, 4).shouldNotMatchInOrderSubset(606 { it shouldBe 2 },607 { it shouldBe 4 },608 )609 }.message shouldBe """610 Expected some assertion to fail but all passed611 """.trimIndent()612 arrayOf(1, 2, 3, 4).shouldNotMatchInOrder(613 { it shouldBe 4 },614 { it shouldBe 1 }615 )616 }617 "Non existing element causes error" {618 shouldThrow<AssertionError> {619 listOf(1, 1, 2, 2, 3, 3) should matchInOrderSubset(620 { it shouldBe 1 },621 { it shouldBe 2 },622 { it shouldBe 6 }623 )624 }.message shouldBe """625 Expected a sequence of elements to pass the assertions, possibly with gaps between but failed to match all assertions626 Best result when comparing from index [0], where 2 elements passed, but the following elements failed:627 3 => expected:<6> but was:<2>628 4 => expected:<6> but was:<3>629 5 => expected:<6> but was:<3>630 """.trimIndent()631 }632 "out-of-order elements cause error" {633 shouldThrow<AssertionError> {634 listOf(1, 2, 3) should matchInOrderSubset(635 { it shouldBe 2 },636 { it shouldBe 1 },637 { it shouldBe 3 }638 )639 }640 }641 "gaps should be ok" {642 listOf(1, 1, 2, 2, 3, 3) should matchInOrderSubset(643 { it shouldBe 1 },644 { it shouldBe 2 },645 { it shouldBe 3 }646 )647 }648 "work with unsorted collections" {649 val actual = listOf(5, 3, 1, 2, 4, 2)650 withClue("should match 4th, 5th and 6th elements ([.., 2, 4, 2])") {651 actual should matchInOrderSubset(652 { it shouldBe 2 },653 { it shouldBeGreaterThan 3 },654 { it shouldBeInRange 2..2 }655 )656 }657 }658 }659 "matchEach" should {660 "test that a collection matches the assertions in the given order without gaps" {661 listOf(1, 3, 7) should matchEach(662 { it shouldBe 1 },663 { it shouldBeInRange 2..4 },664 { it shouldBeGreaterThan 2 }665 )666 }667 "Negation should work" {668 shouldFail{669 listOf(1, 2).shouldNotMatchEach(670 { it shouldBe 1 },671 { it shouldBe 2 },672 )673 }.message shouldBe """674 Expected some element to fail its assertion, but all passed.675 """.trimIndent()676 arrayOf(1, 2).shouldNotMatchEach(677 { it shouldBe 2 },678 { it shouldBe 1 }679 )680 }681 "No assertion exists for each element" {682 shouldFail {683 listOf(1, -1, 999) should matchEach(684 { it shouldBe 1 }685 )686 }.message shouldBe """687 Expected each element to pass its assertion, but found issues at indexes: [1, 2]688 1 => Element has no corresponding assertion. Only 1 assertions provided689 2 => Element has no corresponding assertion. Only 1 assertions provided690 """.trimIndent()691 }692 "Too many assertions cause error" {693 shouldFail {694 listOf(1, 3, 7) should matchEach(695 { it shouldBe 1 },696 { it shouldBe 3 },697 { it shouldBe 7 },698 { it shouldBe 7 },699 { it shouldBe 7 },700 )701 }.message shouldBe """702 Expected each element to pass its assertion, but found issues at indexes: [3, 4]703 3 => No actual element for assertion at index 3704 4 => No actual element for assertion at index 4705 """.trimIndent()706 }707 "Non matching element causes error" {708 shouldFail {709 listOf(1, 3, 7) should matchEach(710 { it shouldBe 1 },711 { it shouldBeInRange 2..4 },712 { it shouldBeGreaterThan 7 }713 )714 }.message shouldBe """715 Expected each element to pass its assertion, but found issues at indexes: [2]716 2 => 7 should be > 7717 """.trimIndent()718 }719 "out-of-order elements cause error" {720 shouldThrow<AssertionError> {721 setOf(2, 3, 1) should matchEach(722 { it shouldBe 2 },723 { it shouldBe 1 },724 { it shouldBe 3 }725 )726 }.message shouldBe """727 Expected each element to pass its assertion, but found issues at indexes: [1, 2]728 1 => expected:<1> but was:<3>729 2 => expected:<3> but was:<1>730 """.trimIndent()731 }732 "gaps cause errors" {733 shouldThrow<AssertionError> {734 listOf(1, 1, 2, 2, 3, 3) should matchEach(735 { it shouldBe 1 },736 { it shouldBe 2 },737 { it shouldBe 3 }738 )739 }.message shouldBe """740 Expected each element to pass its assertion, but found issues at indexes: [1, 2, 3, 4, 5]741 1 => expected:<2> but was:<1>742 2 => expected:<3> but was:<2>743 3 => Element has no corresponding assertion. Only 3 assertions provided744 4 => Element has no corresponding assertion. Only 3 assertions provided745 5 => Element has no corresponding assertion. Only 3 assertions provided746 """.trimIndent()747 }748 }749 "existInOrder" should {750 "test that a collection matches the predicates in the given order, duplicates permitted" {751 val col = listOf(1, 1, 2, 2, 3, 3)752 col should existInOrder(753 { it == 1 },754 { it == 2 },755 { it == 3 }756 )757 col should existInOrder({ it == 1 })758 shouldThrow<AssertionError> {759 col should existInOrder(760 { it == 1 },761 { it == 2 },762 { it == 6 }763 )764 }765 shouldThrow<AssertionError> {766 col should existInOrder({ it == 4 })767 }768 shouldThrow<AssertionError> {769 col should existInOrder(770 { it == 2 },771 { it == 1 },772 { it == 3 }773 )774 }775 }776 "work with unsorted collections" {777 val actual = listOf(5, 3, 1, 2, 4, 2)778 actual should existInOrder(779 { it == 3 },780 { it == 2 },781 { it == 2 }782 )783 }784 }785 "Contain any" should {786 "Fail when the list is empty" {787 shouldThrow<AssertionError> {788 listOf(1, 2, 3).shouldContainAnyOf(emptyList())789 }.shouldHaveMessage("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")790 }791 "Pass when one element is in the list" {792 listOf(1, 2, 3).shouldContainAnyOf(1)793 }794 "Pass when all elements are in the list" {795 listOf(1, 2, 3).shouldContainAnyOf(1, 2, 3)796 }797 "Fail when no element is in the list" {798 shouldThrow<AssertionError> {799 listOf(1, 2, 3).shouldContainAnyOf(4)800 }.shouldHaveMessage("Collection [1, 2, 3] should contain any of [4]")801 }802 }803 "Contain any (negative)" should {804 "Fail when the list is empty" {805 shouldThrow<AssertionError> {806 listOf(1, 2, 3).shouldNotContainAnyOf(emptyList())807 }.shouldHaveMessage("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")808 }809 "Pass when no element is present in the list" {810 listOf(1, 2, 3).shouldNotContainAnyOf(4)811 }812 "Fail when one element is in the list" {813 shouldThrow<AssertionError> {814 listOf(1, 2, 3).shouldNotContainAnyOf(1)815 }.shouldHaveMessage("Collection [1, 2, 3] should not contain any of [1]")816 }817 "Fail when all elements are in the list" {818 shouldThrow<AssertionError> {819 listOf(1, 2, 3).shouldNotContainAnyOf(1, 2, 3)820 }.shouldHaveMessage("Collection [1, 2, 3] should not contain any of [1, 2, 3]")821 }822 }823 "Be in" should {824 "Pass when the element is in the list" {825 val foo = Foo("Bar")826 val list = listOf(foo)827 foo shouldBeIn list828 }829 "Fail when the element is not in the list" {830 val foo1 = Foo("Bar")831 val foo2 = Foo("Booz")832 val list = listOf(foo1)833 shouldThrow<AssertionError> {834 foo2.shouldBeIn(list)835 }.shouldHaveMessage("Collection should contain Foo(bar=Booz), but doesn't. Possible values: [Foo(bar=Bar)]")836 }837 "Pass when there's an equal element, but not the same instance in the list" {838 val foo1 = Foo("Bar")839 val foo2 = Foo("Bar")840 val list = listOf(foo1)841 shouldNotThrow<AssertionError> { foo2 shouldBeIn list }842 }843 "Pass when there's an equal element, but not the same instance in the array" {844 val foo1 = Foo("Bar")845 val foo2 = Foo("Bar")846 val list = arrayOf(foo1)847 shouldNotThrow<AssertionError> { foo2 shouldBeIn list }848 }849 "Fail when the list is empty" {850 val foo = Foo("Bar")851 val list = emptyList<Foo>()852 shouldThrow<AssertionError> {853 foo shouldBeIn list854 }.shouldHaveMessage("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")855 }856 }857 "Be in (negative)" should {858 "Fail when the element is in the list" {859 val foo = Foo("Bar")860 val list = listOf(foo)861 shouldThrow<AssertionError> {862 foo shouldNotBeIn list863 }.shouldHaveMessage("Collection should not contain Foo(bar=Bar), but does. Forbidden values: [Foo(bar=Bar)]")864 }865 "Pass when the element is not in the list" {866 val foo1 = Foo("Bar")867 val foo2 = Foo("Booz")868 val list = listOf(foo1)869 shouldNotThrow<AssertionError> {870 foo2.shouldNotBeIn(list)871 }872 }873 "Fail when there's an equal element, but not the same instance in the list" {874 val foo1 = Foo("Bar")875 val foo2 = Foo("Bar")876 val list = listOf(foo1)877 shouldThrow<AssertionError> {878 foo2 shouldNotBeIn list879 }.shouldHaveMessage("Collection should not contain Foo(bar=Bar), but does. Forbidden values: [Foo(bar=Bar)]")880 }881 "Fail when the list is empty" {882 val foo = Foo("Bar")883 val list = emptyList<Foo>()884 shouldThrow<AssertionError> {885 foo shouldNotBeIn list886 }.shouldHaveMessage("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")887 }888 }889 }890}891private data class Foo(val bar: String)892sealed class TestSealed {893 data class Test1(val value: String) : TestSealed()894 data class Test2(val value: Int) : TestSealed()895}...
PersistentArrayMapTest.kt
Source:PersistentArrayMapTest.kt
1package com.github.whyrising.y.collections.map.arraymap2import com.github.whyrising.y.collections.concretions.list.PersistentList.Empty3import com.github.whyrising.y.collections.concretions.map.MapEntry4import com.github.whyrising.y.collections.concretions.map.PersistentArrayMap5import com.github.whyrising.y.collections.concretions.map.PersistentArrayMap.Companion.EmptyArrayMap6import com.github.whyrising.y.collections.concretions.map.PersistentArrayMap.Companion.createWithCheck7import com.github.whyrising.y.collections.concretions.map.PersistentArrayMap.TransientArrayMap8import com.github.whyrising.y.collections.concretions.map.PersistentHashMap9import com.github.whyrising.y.collections.concretions.map.PersistentHashMap.TransientLeanMap10import com.github.whyrising.y.l11import com.github.whyrising.y.m12import com.github.whyrising.y.utils.runAction13import com.github.whyrising.y.v14import io.kotest.assertions.throwables.shouldThrowExactly15import io.kotest.assertions.timing.continually16import io.kotest.common.ExperimentalKotest17import io.kotest.core.spec.style.FreeSpec18import io.kotest.matchers.booleans.shouldBeFalse19import io.kotest.matchers.booleans.shouldBeTrue20import io.kotest.matchers.collections.shouldContainAll21import io.kotest.matchers.collections.shouldNotContainAnyOf22import io.kotest.matchers.ints.shouldBeExactly23import io.kotest.matchers.nulls.shouldBeNull24import io.kotest.matchers.shouldBe25import io.kotest.matchers.types.shouldBeInstanceOf26import io.kotest.matchers.types.shouldBeSameInstanceAs27import io.kotest.matchers.types.shouldNotBeSameInstanceAs28import kotlinx.coroutines.Dispatchers29import kotlinx.coroutines.withContext30import kotlinx.serialization.ExperimentalSerializationApi31import kotlin.time.Duration.Companion.seconds32@ExperimentalKotest33@ExperimentalSerializationApi34class PersistentArrayMapTest : FreeSpec({35 "TransientArrayMap" - {36 val array: Array<Any?> = arrayOf("a", 1, "b", 2, "c", 3)37 "doPersistent()" {38 val tam = TransientArrayMap<String, Int>(array)39 val map = tam.doPersistent() as PersistentArrayMap<String, Int>40 tam.edit.shouldBeNull()41 map.count shouldBeExactly array.size / 242 map.array shouldNotBeSameInstanceAs array43 map shouldBe mapOf("a" to 1, "b" to 2, "c" to 3)44 shouldThrowExactly<IllegalStateException> {45 tam.doPersistent()46 }.message shouldBe "Transient used after persistent() call."47 }48 "persistent()" {49 val tam = TransientArrayMap<String, Int>(array)50 val map = tam.persistent() as PersistentArrayMap<String, Int>51 tam.edit.shouldBeNull()52 map.count shouldBeExactly array.size / 253 map.array shouldNotBeSameInstanceAs array54 map shouldBe m("a" to 1, "b" to 2, "c" to 3)55 shouldThrowExactly<IllegalStateException> {56 tam.persistent()57 }.message shouldBe "Transient used after persistent() call."58 }59 "doAssoc(k,v)" - {60 "when called after calling persistent, it should throw" {61 val tam = TransientArrayMap<String, Int>(array)62 tam.persistent()63 shouldThrowExactly<IllegalStateException> {64 tam.doAssoc("x", 99)65 }.message shouldBe "Transient used after persistent() call."66 }67 "when the key is new, it should add it to the map" - {68 "when length < array.length, return a TransientArrayMap" {69 val tam = TransientArrayMap<String, Int>(array)70 val newTam = tam.doAssoc("d", 4) as71 TransientArrayMap<String, Int>72 val pairs = newTam.array73 pairs[0] shouldBe "a"74 pairs[1] shouldBe 175 pairs[6] shouldBe "d"76 pairs[7] shouldBe 477 }78 @Suppress("UNCHECKED_CAST")79 "when length >= array.length, return TransientLeanMap" {80 val size = 1681 val a: Array<Any?> = arrayOfNulls(size)82 for (i in 0 until size step 2) {83 a[i] = "$i"84 a[i + 1] = i85 }86 val tam = TransientArrayMap<String, Int>(a)87 val newTam = tam.doAssoc("a", 74)88 as TransientLeanMap<String, Int>89 newTam.count shouldBeExactly tam.count + 190 newTam.containsKey("a")91 }92 }93 """when map already has the key but different value,94 it should update the value""" {95 val key = 296 val value = "78"97 val a: Array<Any?> = arrayOf(1L, "1", 2L, "2", 3, "3")98 val tam = TransientArrayMap<Number, String>(a)99 val newTam = tam.doAssoc(key, value)100 as TransientArrayMap<Any, String>101 val pairs = newTam.array102 tam.length shouldBeExactly a.size103 pairs[0] shouldBe 1L104 pairs[1] shouldBe "1"105 pairs[2] shouldBe key106 pairs[3] shouldBe value107 pairs[4] shouldBe 3108 pairs[5] shouldBe "3"109 }110 """when map already has the same key/value,111 it should return the same map""" {112 val key = 2113 val value = "2"114 val a: Array<Any?> = arrayOf(1L, "1", 2L, "2", 3, "3")115 val tam = TransientArrayMap<Number, String>(a)116 val newTam = tam.doAssoc(key, value)117 as TransientArrayMap<Any, String>118 tam shouldBeSameInstanceAs newTam119 newTam.array[0].shouldBeInstanceOf<Long>()120 newTam.array[2].shouldBeInstanceOf<Long>()121 }122 }123 "assoc(k,v)" - {124 "when called after calling persistent, it should throw" {125 val tam = TransientArrayMap<String, Int>(array)126 tam.persistent()127 shouldThrowExactly<IllegalStateException> {128 tam.assoc("x", 99)129 }.message shouldBe "Transient used after persistent() call."130 }131 "when the key is new, it should add it to the map" - {132 "when length < array.length, return a TransientArrayMap" {133 val tam = TransientArrayMap<String, Int>(array)134 val newTam = tam.assoc("d", 4) as135 TransientArrayMap<String, Int>136 val pairs = newTam.array137 pairs[0] shouldBe "a"138 pairs[1] shouldBe 1139 pairs[6] shouldBe "d"140 pairs[7] shouldBe 4141 }142 @Suppress("UNCHECKED_CAST")143 "when length >= array.length, return PersistentHashMap" {144 val size = 16145 val a: Array<Any?> = arrayOfNulls(size)146 var i = 0147 while (i < size) {148 a[i] = Pair("$i", i)149 i++150 }151 val tam = TransientArrayMap<String, Int>(a)152 val newTam = tam.assoc("a", 74)153 as TransientLeanMap<String, Int>154 newTam.count shouldBeExactly tam.count + 1155 newTam.containsKey("a")156 }157 }158 """when map already has the key but different value,159 it should update the value""" {160 val key = 2161 val value = "78"162 val a: Array<Any?> = arrayOf(1L, "1", 2L, "2", 3, "3")163 val tam = TransientArrayMap<Number, String>(a)164 val newTam = tam.assoc(key, value)165 as TransientArrayMap<Any, String>166 val pairs = newTam.array167 tam.length shouldBeExactly a.size168 pairs[0] shouldBe 1L169 pairs[1] shouldBe "1"170 pairs[2] shouldBe key171 pairs[3] shouldBe value172 pairs[4] shouldBe 3173 pairs[5] shouldBe "3"174 }175 """when map already has the same key/value,176 it should return the same map""" {177 val key = 2178 val value = "2"179 val a: Array<Any?> = arrayOf(1L, "1", 2L, "2", 3, "3")180 val tam = TransientArrayMap<Any, String>(a)181 val newTam = tam.assoc(key, value)182 as TransientArrayMap<Any, String>183 tam shouldBeSameInstanceAs newTam184 newTam.array[0].shouldBeInstanceOf<Long>()185 newTam.array[2].shouldBeInstanceOf<Long>()186 newTam.array[4].shouldBeInstanceOf<Int>()187 }188 }189 @Suppress("UNCHECKED_CAST")190 "conj(e)" - {191 "when called after calling persistent, it should throw" {192 val tam = TransientArrayMap<String, Int>(array)193 tam.persistent()194 shouldThrowExactly<IllegalStateException> {195 tam.conj(Pair("x", 99))196 }.message shouldBe "Transient used after persistent() call."197 }198 "when entry is a Map.Entry, it should call assoc() on it" {199 val tam = TransientArrayMap<String, Int>(array)200 val newTam = tam.conj(MapEntry("a", 99))201 as TransientArrayMap<String, Int>202 newTam.length shouldBeExactly array.size203 newTam.array[1] shouldBe 99204 newTam.array[3] shouldBe 2205 newTam.array[5] shouldBe 3206 }207 "when entry is a IPersistentVector" - {208 "when count != 2, it should throw" {209 val tam = TransientArrayMap<String, Int>(array)210 shouldThrowExactly<IllegalArgumentException> {211 tam.conj(v("a", 99, 75))212 }.message shouldBe213 "Vector [a 99 75] count must be 2 to conj in a map."214 }215 "when count == 2, it should call assoc() on it" {216 val tam = TransientArrayMap<String, Int>(array)217 val newMap = tam.conj(v("a", 99))218 as TransientArrayMap<String, Int>219 newMap.length shouldBeExactly array.size220 newMap.array[1] shouldBe 99221 newMap.array[3] shouldBe 2222 }223 }224 "when entry is null, it should return this" {225 val tam = TransientArrayMap<String, Int>(array)226 tam.conj(null) shouldBeSameInstanceAs tam227 }228 "when entry is a seq of MapEntry" - {229 "when an element is not a MapEntry, it should throw" {230 val tam = TransientArrayMap<String, Int>(array)231 shouldThrowExactly<IllegalArgumentException> {232 tam.conj(l(MapEntry("x", 42), "item"))233 }.message shouldBe234 "All elements of the seq must be of type " +235 "Map.Entry to conj: item"236 }237 "when all elements are MapEntry, it should assoc() all" {238 val tam = TransientArrayMap<String, Int>(array)239 val entries = l(MapEntry("x", 42), MapEntry("y", 47))240 val newTam = tam.conj(entries)241 as TransientArrayMap<String, Int>242 newTam.length shouldBeExactly243 array.size + (entries.count * 2)244 newTam.array[0] shouldBe "a"245 newTam.array[1] shouldBe 1246 newTam.array[2] shouldBe "b"247 newTam.array[3] shouldBe 2248 newTam.array[6] shouldBe "x"249 newTam.array[7] shouldBe 42250 newTam.array[8] shouldBe "y"251 newTam.array[9] shouldBe 47252 }253 }254 }255 @Suppress("UNCHECKED_CAST")256 "doDissoc(key)" - {257 "when key doesn't exit, it should return the same instance" {258 val a: Array<Any?> = arrayOf(1, "a", 2, "b", 3, "c")259 val tam = TransientArrayMap<Int, String>(a)260 val dissoc = tam.doDissoc(10)261 dissoc shouldBeSameInstanceAs tam262 }263 "when key exists and size is 1, it returns an empty transient" {264 val a: Array<Any?> = arrayOf(2L, "b")265 val tam = TransientArrayMap<Number, String>(a)266 val rTam = tam.doDissoc(2) as TransientArrayMap<Int, String>267 rTam.length shouldBeExactly 0268 }269 "when key exists, it should return a new map without that key" {270 val a: Array<Any?> = arrayOf(1L, "1", 2L, "2", 3, "3")271 val tam = TransientArrayMap<Number, String>(a)272 val rTam = tam.doDissoc(1) as TransientArrayMap<Any?, String>273 rTam.length shouldBeExactly a.size - 2274 rTam.array[0] shouldBe 3275 rTam.array[1] shouldBe "3"276 rTam.array[2] shouldBe 2L277 rTam.array[3] shouldBe "2"278 }279 }280 @Suppress("UNCHECKED_CAST")281 "dissoc(key)" - {282 "when called after calling persistent, it should throw" {283 val tam = TransientArrayMap<String, Int>(array)284 tam.persistent()285 shouldThrowExactly<IllegalStateException> {286 tam.dissoc("a")287 }.message shouldBe "Transient used after persistent() call."288 }289 "when key doesn't exit, it should return the same instance" {290 val a: Array<Any?> = arrayOf(1, "a", 2, "b", 3, "c")291 val tam = TransientArrayMap<Int, String>(a)292 val dissoc = tam.dissoc(10)293 dissoc shouldBeSameInstanceAs tam294 }295 "when key exists and size is 1, it returns an empty transient" {296 val a: Array<Any?> = arrayOf(2L, "b")297 val tam = TransientArrayMap<Number, String>(a)298 val rTam = tam.dissoc(2) as TransientArrayMap<Int, String>299 rTam.length shouldBeExactly 0300// for (i in rTam.array.indices)301// rTam.array[i].shouldBeNull()302 }303 "when key exists, it should return a new map without that key" {304 val a: Array<Any?> = arrayOf(1L, "1", 2L, "2", 3, "3")305 val tam = TransientArrayMap<Number, String>(a)306 val rTam = tam.dissoc(1) as TransientArrayMap<Any?, String>307 val pairs = rTam.array308 rTam.length shouldBeExactly a.size - 2309 pairs[0] shouldBe 3310 pairs[1] shouldBe "3"311 pairs[2] shouldBe 2L312 pairs[3] shouldBe "2"313 }314 }315 "doCount" {316 val a: Array<Any?> = emptyArray()317 val b: Array<Any?> = arrayOf(1L, "1", 2L, "2", 3, "3")318 val tam = TransientArrayMap<Number, String>(b)319 .dissoc(1) as TransientArrayMap<*, *>320 TransientArrayMap<Number, String>(a).doCount shouldBeExactly 0321 TransientArrayMap<Number, String>(b).doCount shouldBeExactly322 b.size / 2323 tam.doCount shouldBeExactly 2324 }325 "count" - {326 "when called after calling persistent, it should throw" {327 val tam = TransientArrayMap<String, Int>(array)328 tam.persistent()329 shouldThrowExactly<IllegalStateException> {330 tam.count331 }.message shouldBe "Transient used after persistent() call."332 }333 "assertions" {334 val a: Array<Any?> = arrayOf()335 val b: Array<Any?> = arrayOf(1L, "1", 2L, "2", 3, "3")336 TransientArrayMap<Number, String>(a).count shouldBeExactly 0337 TransientArrayMap<Number, String>(b)338 .count shouldBeExactly b.size / 2339 TransientArrayMap<Number, String>(b)340 .dissoc(1).count shouldBeExactly 2341 }342 }343 "doValAt(key, default)" - {344 val tam = TransientArrayMap<String, Int>(array)345 "when key exists, it should return the assoc value" {346 tam.doValAt("a", -1) shouldBe 1347 }348 "when key doesn't exist, it should return the default value" {349 tam.doValAt("z", -1) shouldBe -1350 }351 }352 "valAt(key, default)" - {353 "when called after calling persistent, it should throw" {354 val tam = TransientArrayMap<String, Int>(array)355 tam.persistent()356 shouldThrowExactly<IllegalStateException> {357 tam.valAt("a", -1)358 }.message shouldBe "Transient used after persistent() call."359 }360 "when key exists, it should return the assoc value" {361 val tam = TransientArrayMap<String, Int>(array)362 tam.valAt("a", -1) shouldBe 1363 }364 "when key doesn't exist, it should return the default value" {365 val tam = TransientArrayMap<String, Int>(array)366 tam.valAt("z", -1) shouldBe -1367 }368 }369 "valAt(key)" - {370 "when called after calling persistent, it should throw" {371 val tam = TransientArrayMap<String, Int>(array)372 tam.persistent()373 shouldThrowExactly<IllegalStateException> {374 tam.valAt("a")375 }.message shouldBe "Transient used after persistent() call."376 }377 "when key exists, it should return the assoc value" {378 val tam = TransientArrayMap<String, Int>(array)379 tam.valAt("a") shouldBe 1380 }381 "when key doesn't exist, it should return the default value" {382 val tam = TransientArrayMap<String, Int>(array)383 tam.valAt("z").shouldBeNull()384 }385 }386 "containsKey(key)" - {387 "when called after calling persistent, it should throw" {388 val tam = TransientArrayMap<String, Int>(array)389 tam.persistent()390 shouldThrowExactly<IllegalStateException> {391 tam.containsKey("a")392 }.message shouldBe "Transient used after persistent() call."393 }394 "assertions" {395 val tam = TransientArrayMap<String, Int>(array)396 tam.containsKey("a").shouldBeTrue()397 tam.containsKey("b").shouldBeTrue()398 tam.containsKey("d").shouldBeFalse()399 }400 }401 "entryAt(key)" - {402 "when called after calling persistent, it should throw" {403 val tam = TransientArrayMap<String, Int>(array)404 tam.persistent()405 shouldThrowExactly<IllegalStateException> {406 tam.entryAt("a")407 }.message shouldBe "Transient used after persistent() call."408 }409 "when key doesn't exit, it should return null" {410 val tam = TransientArrayMap<String?, Int>(array)411 tam.entryAt(null).shouldBeNull()412 }413 "when key does exist, it should return a MapEntry" {414 val tam = TransientArrayMap<String, Int>(array)415 val mapEntry = tam.entryAt("a") as MapEntry<String, Int>416 mapEntry.key shouldBe "a"417 mapEntry.value shouldBe 1418 }419 }420 "invoke() operator" - {421 "when called after calling persistent, it should throw" {422 val tam = TransientArrayMap<String, Int>(array)423 tam.persistent()424 shouldThrowExactly<IllegalStateException> {425 tam.entryAt("a")426 }.message shouldBe "Transient used after persistent() call."427 }428 val a = arrayOf("a" to 1, "b" to 2, "c" to 3)429 val tam = TransientArrayMap<String, Int>(array)430 "invoke(key, default)" {431 tam("a", -1) shouldBe 1432 tam("z", -1) shouldBe -1433 }434 "invoke(key)" {435 tam("a") shouldBe 1436 tam("z").shouldBeNull()437 }438 }439 "concurrency" - {440 val l = (1..8).map { MapEntry(it, "$it") }441 "assoc(key, val) under 16 entries-" {442 continually(10.seconds) {443 val t1 = EmptyArrayMap.asTransient()444 as TransientArrayMap<Int, String>445 withContext(Dispatchers.Default) {446 runAction(16, 3) {447 for (entry in l)448 t1.assoc(entry.key, entry.value)449 }450 }451 t1.count shouldBeExactly 8452 val m = t1.persistent() as PersistentArrayMap<Int, String>453 m.shouldContainAll(l)454 }455 }456 "dissoc(key)" {457 continually(10.seconds) {458 val initial = m<Int, String>()459 val transientMap = l.fold(initial) { map, entry ->460 map.assoc(461 entry.key,462 entry.value463 ) as PersistentArrayMap<Int, String>464 }.asTransient()465 withContext(Dispatchers.Default) {466 runAction(16, 3) {467 for (entry in l)468 transientMap.dissoc(entry.key)469 }470 }471 val persistent = transientMap.persistent()472 persistent.count shouldBeExactly 0473 persistent.shouldNotContainAnyOf(l)474 }475 }476 }477 }478 "asTransient()" {479 val a = arrayOf("a" to 1, "b" to 2, "c" to 3)480 val map = createWithCheck(*a)481 val tr = map.asTransient() as TransientArrayMap<String, Int>482 val array = tr.array483 tr.length shouldBeExactly a.size * 2484 array.size shouldBeExactly 16485 array[0] shouldBe "a"486 array[1] shouldBe 1487 array[2] shouldBe "b"488 array[3] shouldBe 2489 array[4] shouldBe "c"490 array[5] shouldBe 3491 }492 "ArrayMap" - {493 "assoc(key, val)" - {494 "when map is empty, it should add the new entry" {495 val map = m<String, Int>()496 val newMap =497 map.assoc("a", 1) as PersistentArrayMap<String, Int>498 val pairs = newMap.array499 pairs[0] shouldBe "a"500 pairs[1] shouldBe 1501 }502 "when the key is new, it should add it to the map" - {503 "when size < threshold, it should return a PersistentArrayMap" {504 val map = m("a" to 1, "b" to 2, "c" to 3)505 val newMap = map.assoc("d", 4)506 as PersistentArrayMap<String, Int>507 newMap.array[0] shouldBe "a"508 newMap.array[1] shouldBe 1509 newMap.array[6] shouldBe "d"510 newMap.array[7] shouldBe 4511 }512 @Suppress("UNCHECKED_CAST")513 "when size >= THRESHOLD, it should return LeanMap" {514 val size = 16515 val array: Array<Pair<String, Int>?> = arrayOfNulls(size)516 var i = 0517 while (i < size) {518 array[i] = Pair("$i", i)519 i++520 }521 val m = m(*(array as Array<Pair<String, Int>>))522 val map = m.assoc("a", 863)523 as PersistentHashMap<String, Int>524 m.containsKey("a").shouldBeFalse()525 map.count shouldBeExactly size + 1526 map.containsKey("a").shouldBeTrue()527 }528 }529 """when map already has the key and different value,530 it should replace it in a new map""" {531 val key = 2532 val value = "78"533 val array = arrayOf(1L to "1", 2L to "2", 3 to "3")534 val map = m(*array)535 val newMap = map.assoc(key, value)536 as PersistentArrayMap<String, Int>537 newMap.array.size shouldBeExactly array.size * 2538 array[1].first shouldBe key539 array[1].second shouldBe "2"540 newMap.array[0] shouldBe 1L541 newMap.array[1] shouldBe "1"542 newMap.array[2] shouldBe key543 newMap.array[3] shouldBe value544 newMap.array[4] shouldBe 3545 newMap.array[5] shouldBe "3"546 }547 """when map already has the same key/value,548 it should return the same map""" {549 val key = 2550 val value = "2"551 val map = m(1L to "1", 2L to "2", 3 to "3")552 val newMap = map.assoc(key, value)553 as PersistentArrayMap<String, Int>554 newMap shouldBeSameInstanceAs map555 newMap.array[2].shouldBeInstanceOf<Long>()556 }557 }558 "assocNew(key, val)" - {559 "when map already has the key, it should throw" {560 val value = "78"561 val array = arrayOf(1L to "1", 2L to "2", 3 to "3")562 val map = m(*array)563 shouldThrowExactly<RuntimeException> {564 map.assocNew(2, value)565 }.message shouldBe "The key 2 is already present."566 }567 "when new key, it should add the association to the new map" {568 val key = 4569 val value = "4"570 val array = arrayOf(1L to "1", 2L to "2", 3 to "3")571 val map = m(*array)572 val newMap = map.assocNew(key, value)573 as PersistentArrayMap<String, Int>574 newMap.array.size shouldBeExactly (array.size * 2) + 2575 newMap.array[0] shouldBe key576 newMap.array[1] shouldBe value577 newMap.array[2] shouldBe 1L578 newMap.array[3] shouldBe "1"579 newMap.array[6] shouldBe 3580 newMap.array[7] shouldBe "3"581 }582 @Suppress("UNCHECKED_CAST")583 "when size >= THRESHOLD, it should return LeanMap" {584 val size = 16585 val array: Array<Pair<String, Int>?> = arrayOfNulls(size)586 for (i in 0 until size) {587 array[i] = Pair("$i", i)588 }589 val m = m(*(array as Array<Pair<String, Int>>))590 val map = m.assocNew("a", 863) as PersistentHashMap<String, Int>591 m.containsKey("a").shouldBeFalse()592 map.count shouldBeExactly size + 1593 map.containsKey("a").shouldBeTrue()594 shouldThrowExactly<RuntimeException> {595 map.assocNew("a", -1)596 }.message shouldBe "The key a is already present."597 }598 }599 "dissoc(key)" - {600 "when key doesn't exit, it should return the same instance" {601 val array = arrayOf(1L to "1", 2L to "2", 3 to "3")602 val map = m(*array)603 map.dissoc(9) shouldBeSameInstanceAs map604 }605 "when key exists and size is 1, it should return the empty map" {606 val map = m(2L to "2")607 map.dissoc(2) shouldBeSameInstanceAs EmptyArrayMap608 }609 "when key exists, it should return a new map without that key" {610 val array = arrayOf(1L to "1", 2L to "2", 3 to "3")611 val map = m(*array)612 val newMap = map.dissoc(2) as PersistentArrayMap<Any?, String>613 newMap.array.size shouldBeExactly 4614 newMap.array[0] shouldBe array[0].first615 newMap.array[1] shouldBe array[0].second616 newMap.array[2] shouldBe array[2].first617 newMap.array[3] shouldBe array[2].second618 }619 }620 "containsKey(key)" {621 val array = arrayOf("a" to 1, "b" to 2, "c" to 3)622 val map = m(*array)623 map.containsKey("a").shouldBeTrue()624 map.containsKey("b").shouldBeTrue()625 map.containsKey("d").shouldBeFalse()626 }627 "entryAt(key)" - {628 val array = arrayOf("a" to 1, "b" to 2, "c" to 3)629 val map = m(*array)630 "when key doesn't exit, it should return null" {631 map.entryAt("d").shouldBeNull()632 }633 "when key does exist, it should return a MapEntry" {634 val mapEntry = map.entryAt("a") as MapEntry<String, Int>635 mapEntry.key shouldBe "a"636 mapEntry.value shouldBe 1637 }638 }639 "valAt(key, default)" - {640 val array = arrayOf("a" to 1, "b" to 2, "c" to 3)641 val map = m(*array)642 "when key exists, it should return the assoc value" {643 map.valAt("a", -1) shouldBe 1644 }645 "when key doesn't exist, it should return the default value" {646 map.valAt("z", -1) shouldBe -1647 }648 }649 "valAt(key)" - {650 val array = arrayOf("a" to 1, "b" to 2, "c" to 3)651 val map = m(*array)652 "when key exists, it should return the assoc value" {653 map.valAt("a") shouldBe 1654 }655 "when key doesn't exist, it should return the default value" {656 map.valAt("z").shouldBeNull()657 }658 }659 "seq()" - {660 "when map is empty, it should return an empty seq" {661 m<String, Int>().seq() shouldBeSameInstanceAs662 Empty663 }664 "when map is populated, it should return a seq of entries" {665 val array = arrayOf("a" to 1)666 val map = createWithCheck(*array)667 val seq = map.seq()668 val rest = seq.rest()669 seq.toString() shouldBe "([a 1])"670 seq.count shouldBeExactly map.size671 seq.first() shouldBe MapEntry("a", 1)672 rest shouldBeSameInstanceAs Empty673 }674 }675 "count" {676 val array = arrayOf("a" to 1, "b" to 2, "c" to 3)677 m<String, Int>().count shouldBeExactly 0678 m(*array).count shouldBeExactly array.size679 }680 "empty()" {681 val array = arrayOf("a" to 1, "b" to 2, "c" to 3)682 m(*array).empty() shouldBeSameInstanceAs683 EmptyArrayMap684 }685 "iterator()" {686 val array = arrayOf("a" to 1, "b" to 2, "c" to 3)687 val map = m(*array)688 val iter = map.iterator()689 iter.hasNext().shouldBeTrue()690 iter.next() shouldBe MapEntry("a", 1)691 iter.next() shouldBe MapEntry("b", 2)692 iter.next() shouldBe MapEntry("c", 3)693 iter.hasNext().shouldBeFalse()694 shouldThrowExactly<NoSuchElementException> { iter.next() }695 }696 "keyIterator()" {697 val map = createWithCheck("a" to 1, "b" to 2, "c" to 3)698 val iter: Iterator<String> = map.keyIterator()699 iter.hasNext().shouldBeTrue()700 iter.next() shouldBe "a"701 iter.next() shouldBe "b"702 iter.next() shouldBe "c"703 iter.hasNext().shouldBeFalse()704 shouldThrowExactly<NoSuchElementException> { iter.next() }705 }706 "valIterator()" {707 val map = createWithCheck("a" to 1, "b" to 2, "c" to 3)708 val iter: Iterator<Int> = map.valIterator()709 iter.hasNext().shouldBeTrue()710 iter.next() shouldBeExactly 1711 iter.next() shouldBeExactly 2712 iter.next() shouldBeExactly 3713 iter.hasNext().shouldBeFalse()714 shouldThrowExactly<NoSuchElementException> { iter.next() }715 }716 }717 "EmptyArrayMap" - {718 "toString() should return `{}`" {719 m<String, Int>().toString() shouldBe "{}"720 }721 "hashCode()" {722 m<String, Int>().hashCode() shouldBeExactly 0723 }724 }725})...
BalancingVerticleTest.kt
Source:BalancingVerticleTest.kt
1package ch.sourcemotion.vertx.kinesis.consumer.orchestra.impl.balancing2import ch.sourcemotion.vertx.kinesis.consumer.orchestra.impl.OrchestraClusterNodeId3import ch.sourcemotion.vertx.kinesis.consumer.orchestra.impl.ShardId4import ch.sourcemotion.vertx.kinesis.consumer.orchestra.impl.cluster.RedisNodeScoreVerticle5import ch.sourcemotion.vertx.kinesis.consumer.orchestra.impl.ext.okResponseAsBoolean6import ch.sourcemotion.vertx.kinesis.consumer.orchestra.internal.service.*7import ch.sourcemotion.vertx.kinesis.consumer.orchestra.testing.AbstractRedisTest8import io.kotest.matchers.booleans.shouldBeFalse9import io.kotest.matchers.booleans.shouldBeTrue10import io.kotest.matchers.collections.*11import io.kotest.matchers.longs.shouldBeGreaterThan12import io.kotest.matchers.shouldBe13import io.vertx.core.CompositeFuture14import io.vertx.core.Future15import io.vertx.core.Promise16import io.vertx.core.Vertx17import io.vertx.core.json.JsonObject18import io.vertx.junit5.VertxTestContext19import io.vertx.kotlin.core.deploymentOptionsOf20import io.vertx.kotlin.coroutines.await21import io.vertx.redis.client.Command22import io.vertx.redis.client.Request23import kotlinx.coroutines.delay24import kotlinx.coroutines.launch25import org.junit.jupiter.api.AfterEach26import org.junit.jupiter.api.Test27import java.util.*28internal class BalancingVerticleTest : AbstractRedisTest() {29 private companion object {30 const val DEFAULT_ACTIVE_BALANCER_CHECK_INTERVAL_MILLIS = 1000L31 const val DEFAULT_INITIAL_BALANCING_DELAY_MILLIS = 1000L32 const val DEFAULT_BALANCING_INTERVAL_MILLIS = 1000L33 const val DEFAULT_BALANCING_COMMAND_TIMEOUT_MILLIS = 1000L34 const val DEFAULT_NODE_KEEP_ALIVE_MILLIS = 1000L35 const val CLUSTER_NAME = "test-cluster"36 }37 private val additionalVertxInstances = ArrayList<Vertx>()38 @AfterEach39 internal fun closeAdditionalVertxInstances() = asyncBeforeOrAfter {40 CompositeFuture.all(additionalVertxInstances.map { it.close() }).await()41 }42 @Test43 internal fun active_passive_balancer_rollover(testContext: VertxTestContext) = testContext.async {44 val activeOptions = verticleOptionsOf()45 val passiveOptions = verticleOptionsOf()46 ConsumerControlService.exposeService(vertx, NoopConsumerControlService)47 ConsumableShardDetectionService.exposeService(vertx, NoopConsumableShardDetectionService)48 deployNodeStateService(activeOptions.clusterNodeId)49 deployNodeStateService(passiveOptions.clusterNodeId)50 val activeDeploymentId = deployBalancingVerticle(activeOptions)51 delay(1000)52 deployBalancingVerticle(passiveOptions)53 repeat(5) {54 verifyActiveBalancerNode(activeOptions.clusterNodeId)55 delay(DEFAULT_ACTIVE_BALANCER_CHECK_INTERVAL_MILLIS)56 }57 // Undeploy active balancer node, so passive will become active58 vertx.undeploy(activeDeploymentId).await()59 // Give passive enough time for rollover to active before we verify60 delay(DEFAULT_ACTIVE_BALANCER_CHECK_INTERVAL_MILLIS * 2)61 repeat(5) {62 verifyActiveBalancerNode(passiveOptions.clusterNodeId)63 delay(DEFAULT_ACTIVE_BALANCER_CHECK_INTERVAL_MILLIS)64 }65 }66 @Test67 internal fun re_balancing_single_node_start_consumers(testContext: VertxTestContext) =68 testContext.async(1) { checkpoint ->69 val balancerOptions = verticleOptionsOf()70 val expectedShardIdsToStart = listOf(ShardId("1"), ShardId("2"), ShardId("3"))71 val startConsumerCheckpoint = testContext.checkpoint()72 val detectConsumableShardsCheckpoint = testContext.checkpoint()73 deployNodeStateService(balancerOptions.clusterNodeId)74 ConsumerControlService.exposeService(vertx, object : ConsumerControlService {75 override fun stopConsumer(shardId: ShardId): Future<Void> =76 Future.failedFuture("stopConsumer unsupported")77 override fun stopConsumers(consumerCount: Int): Future<StopConsumersCmdResult> {78 val msg = "Stop consumers is not expected"79 testContext.failNow(Exception(msg))80 return Future.failedFuture(msg)81 }82 override fun startConsumers(shardIds: List<ShardId>): Future<Int> {83 shardIds.shouldContainExactly(expectedShardIdsToStart)84 startConsumerCheckpoint.flag()85 return Future.succeededFuture(shardIds.size)86 }87 })88 ConsumableShardDetectionService.exposeService(vertx, object : ConsumableShardDetectionService {89 override fun getConsumableShards(): Future<List<ShardId>> {90 detectConsumableShardsCheckpoint.flag()91 return Future.succeededFuture(expectedShardIdsToStart)92 }93 })94 deployBalancingVerticle(balancerOptions)95 checkpoint.flag()96 }97 @Test98 internal fun re_balancing_additional_node_delayed(testContext: VertxTestContext) =99 testContext.async(1) { checkpoint ->100 val firstNodeBalancerOptions = verticleOptionsOf()101 val allShards = IntRange(0, 3).map { ShardId("$it") }102 val shardsToBalance = allShards.take(2)103 val startConsumersCheckpoint = testContext.checkpoint(2)104 val stopConsumersCheckpoint = testContext.checkpoint()105 val detectConsumableShardsCheckpoint = testContext.checkpoint()106 val nodeScoreService = deployNodeStateService(firstNodeBalancerOptions.clusterNodeId)107 ConsumerControlService.exposeService(vertx, object : ConsumerControlService {108 private var consumerStarts = 0109 override fun stopConsumer(shardId: ShardId): Future<Void> =110 Future.failedFuture("stopConsumer unsupported")111 override fun stopConsumers(consumerCount: Int): Future<StopConsumersCmdResult> {112 // Stop should get called one time, after the second node was coming up and the re-balancing happens113 testContext.verify { consumerCount.shouldBe(shardsToBalance.size) }114 stopConsumersCheckpoint.flag()115 return Future.succeededFuture(116 StopConsumersCmdResult(117 shardsToBalance,118 allShards.size - shardsToBalance.size119 )120 )121 }122 override fun startConsumers(shardIds: List<ShardId>): Future<Int> {123 // Start consumers should happen 2 times. One time on each node124 testContext.verify {125 if (++consumerStarts == 1) {126 shardIds.shouldContainExactly(allShards)127 // Deploy second node right after first was balanced128 defaultTestScope.launch {129 val secondNodeBalancerOptions = verticleOptionsOf()130 deployNodeStateService(secondNodeBalancerOptions.clusterNodeId)131 deployBalancingVerticle(secondNodeBalancerOptions)132 }133 } else {134 shardsToBalance.shouldContainExactly(shardsToBalance)135 }136 nodeScoreService.setThisNodeScore(shardIds.size)137 }138 startConsumersCheckpoint.flag()139 return Future.succeededFuture(shardIds.size)140 }141 })142 ConsumableShardDetectionService.exposeService(vertx, object : ConsumableShardDetectionService {143 private var detected = false144 override fun getConsumableShards(): Future<List<ShardId>> {145 if (!detected) {146 detected = true147 detectConsumableShardsCheckpoint.flag()148 return Future.succeededFuture(allShards)149 }150 return Future.succeededFuture(emptyList())151 }152 })153 deployBalancingVerticle(firstNodeBalancerOptions)154 checkpoint.flag()155 }156 @Test157 internal fun re_balancing_two_nodes_immediate(testContext: VertxTestContext) = testContext.async {158 val expectedNodeCount = 2159 val allShards = IntRange(0, 3).map { ShardId("$it") }160 val sharedConsumableShardDetection = SharedConsumableShardDetectionService(allShards)161 val nodeInstances = deployNodeInstances(expectedNodeCount, CLUSTER_NAME, sharedConsumableShardDetection)162 val nodeScoreService = NodeScoreService.createService(additionalVertxInstances.last())163 delay(5000)164 val nodeScores = nodeScoreService.getNodeScores().await()165 nodeScores.shouldHaveSize(expectedNodeCount)166 nodeScores.shouldContainExactlyInAnyOrder(nodeInstances.map { NodeScoreDto(it.nodeId, 2) })167 }168 @Test169 internal fun re_balancing_ten_nodes_even(testContext: VertxTestContext) = testContext.async {170 val expectedNodeCount = 10171 val allShards = IntRange(1, expectedNodeCount * 2).map { ShardId("$it") }172 val sharedConsumableShardDetection = SharedConsumableShardDetectionService(allShards)173 val nodeInstances = deployNodeInstances(expectedNodeCount, CLUSTER_NAME, sharedConsumableShardDetection)174 val nodeScoreService = NodeScoreService.createService(additionalVertxInstances.first())175 delay(5000)176 val nodeScores = nodeScoreService.getNodeScores().await()177 nodeScores.shouldHaveSize(expectedNodeCount)178 nodeScores.map { it.clusterNodeId }.shouldContainExactlyInAnyOrder(nodeInstances.map { it.nodeId })179 nodeScores.map { it.score }.shouldContain(2)180 }181 @Test182 internal fun re_balancing_ten_nodes_uneven(testContext: VertxTestContext) = testContext.async {183 val expectedNodeCount = 10184 val twoScoredNodesCheckpoint = testContext.checkpoint(8)185 val threeScoredNodesCheckpoint = testContext.checkpoint(8)186 val allShards = IntRange(1, expectedNodeCount * 2 + 2).map { ShardId("$it") }187 val sharedConsumableShardDetection = SharedConsumableShardDetectionService(allShards)188 val nodeInstances = deployNodeInstances(expectedNodeCount, CLUSTER_NAME, sharedConsumableShardDetection)189 val nodeScoreService = NodeScoreService.createService(additionalVertxInstances.first())190 delay(5000)191 val nodeScores = nodeScoreService.getNodeScores().await()192 nodeScores.shouldHaveSize(expectedNodeCount)193 nodeScores.map { it.clusterNodeId }.shouldContainExactlyInAnyOrder(nodeInstances.map { it.nodeId })194 nodeScores.map { it.score }.forEach { score ->195 if (score == 2) {196 twoScoredNodesCheckpoint.flag()197 }198 if (score == 3) {199 threeScoredNodesCheckpoint.flag()200 }201 }202 }203 @Test204 internal fun re_balancing_initial_ten_nodes_than_shutdown_five(testContext: VertxTestContext) = testContext.async {205 val clusterName = "test-cluster"206 val expectedNodeCount = 10207 // 20 shards208 val allShards = IntRange(1, expectedNodeCount * 2).map { ShardId("$it") }209 val sharedConsumableShardDetection = SharedConsumableShardDetectionService(allShards)210 val nodeInstances = deployNodeInstances(expectedNodeCount, clusterName, sharedConsumableShardDetection)211 delay(5000)212 val nodeScores = NodeScoreService.createService(additionalVertxInstances.last()).getNodeScores().await()213 nodeScores.shouldHaveSize(expectedNodeCount)214 nodeScores.map { it.clusterNodeId }.shouldContainExactlyInAnyOrder(nodeInstances.map { it.nodeId })215 // Close the half of Vert.x instances and summarize the no more consumed shards216 val noMoreConsumedShards = nodeInstances.takeAndRemove(5).map {217 it.vertxInstance.close().await()218 it.consumerControlService219 }.map { it.activeConsumedShards }.flatten()220 sharedConsumableShardDetection.noMoreConsumed(noMoreConsumedShards)221 delay(5000)222 NodeScoreService.createService(additionalVertxInstances.last()).getNodeScores().await().map { it.score }223 .shouldContain(4)224 }225 @Test226 internal fun re_balancing_redeployment_scenario(testContext: VertxTestContext) = testContext.async {227 val clusterName = "test-cluster"228 val expectedNodeCount = 10229 // 20 shards230 val allShards = IntRange(1, expectedNodeCount * 2).map { ShardId("$it") }231 val sharedConsumableShardDetection = SharedConsumableShardDetectionService(allShards)232 // Initial deployment233 val nodeInstances = deployNodeInstances(expectedNodeCount, clusterName, sharedConsumableShardDetection)234 val initialNodeIds = nodeInstances.map { it.nodeId }235 delay(5000)236 val nodeScores = NodeScoreService.createService(additionalVertxInstances.last()).getNodeScores().await()237 nodeScores.shouldHaveSize(expectedNodeCount)238 nodeScores.map { it.clusterNodeId }.shouldContainExactlyInAnyOrder(initialNodeIds)239 val redeployedNodeInstances = ArrayList<TestNodeInstanceInfo>()240 val nodeCountRedeploymentCycle = 2241 // We replace each node instance242 repeat(5) {243 val noMoreConsumedShards = nodeInstances.takeAndRemove(nodeCountRedeploymentCycle).map {244 it.vertxInstance.close().await()245 it.consumerControlService246 }.map { it.activeConsumedShards }.flatten()247 sharedConsumableShardDetection.noMoreConsumed(noMoreConsumedShards)248 redeployedNodeInstances.addAll(249 deployNodeInstances(250 nodeCountRedeploymentCycle,251 clusterName,252 sharedConsumableShardDetection253 )254 )255 }256 delay(5000)257 redeployedNodeInstances.shouldHaveSize(expectedNodeCount)258 redeployedNodeInstances.map { it.nodeId }259 .shouldNotContainAnyOf(initialNodeIds) // Verify all instances are replaced260 NodeScoreService.createService(additionalVertxInstances.last()).getNodeScores().await().map { it.score }261 .shouldContain(2)262 }263 @Test264 internal fun stop_during_balancing(testContext: VertxTestContext) = testContext.async(1) { checkpoint ->265 val sharedConsumableShardDetection = SharedConsumableShardDetectionService(listOf(ShardId("0")))266 val startDelay = 1000L267 var started = false268 var startInProgressCallback: (() -> Unit)? = null269 // Will called when consumer control verticle has received command to start consumers270 val startConsumerCmdInterceptor: (Vertx) -> Future<Void> = {271 startInProgressCallback?.invoke()272 val p = Promise.promise<Void>()273 vertx.setTimer(startDelay) {274 started = true275 p.complete()276 }277 p.future()278 }279 val nodeInstanceInfo = deployNodeInstances(1, CLUSTER_NAME, sharedConsumableShardDetection, startConsumersInterceptor = startConsumerCmdInterceptor).first()280 // Called by interceptor above. So we can stop the whole Vert.x instance during start (balancing) process.281 startInProgressCallback = {282 val startProgressStart = System.currentTimeMillis()283 testContext.verify { started.shouldBeFalse() }284 nodeInstanceInfo.vertxInstance.close().onSuccess {285 val vertxClosedEnd = System.currentTimeMillis()286 testContext.verify {287 started.shouldBeTrue()288 (vertxClosedEnd - startProgressStart).shouldBeGreaterThan(startDelay)289 }290 checkpoint.flag()291 }.onFailure { cause -> testContext.failNow(cause) }292 }293 }294 @Test295 internal fun remote_active_balancer_job(testContext: VertxTestContext) = testContext.async(2) { checkpoint ->296 val sharedConsumableShardDetection = SharedConsumableShardDetectionService(listOf(ShardId("0")))297 // We flag from start on that another node has active balancing job (e.g. deployment edge case)298 var balancingActiveOnRemoteNode = true299 var nodeId: OrchestraClusterNodeId? = null300 val nodeInstanceInfo = deployNodeInstances(1, CLUSTER_NAME, sharedConsumableShardDetection) {301 // Called when this node has active balancer job and consumer control received start consumer command302 // The remote node balancing job must be done before303 testContext.verify { balancingActiveOnRemoteNode.shouldBeFalse() }304 verifyClusterWideActiveBalancingJobFlag(nodeId!!, testContext).compose {305 checkpoint.flag()306 Future.succeededFuture()307 }308 }.first().also { nodeId = it.nodeId }309 // Obtain active balancing job, wait some balancing check intervals and unset flag, so test node can start balancing310 setClusterWideActiveBalancingJobFlag(nodeInstanceInfo.nodeId, testContext).await()311 delay((DEFAULT_INITIAL_BALANCING_DELAY_MILLIS + DEFAULT_BALANCING_INTERVAL_MILLIS) * 2)312 balancingActiveOnRemoteNode = false313 unsetClusterWideActiveBalancingJobFlag(nodeInstanceInfo.nodeId, testContext).await()314 // We stop consumer to enforce balancing twice315 delay(DEFAULT_BALANCING_INTERVAL_MILLIS * 2)316 nodeInstanceInfo.consumerControlService.stopConsumers(1)317 }318 private fun startVertxInstances(expectedNodeCount: Int): List<Vertx> {319 return IntRange(1, expectedNodeCount).map { Vertx.vertx().also { additionalVertxInstances.add(it) } }320 }321 private suspend fun deployNodeInstances(322 expectedInstances: Int,323 clusterName: String,324 sharedConsumableShardDetection: SharedConsumableShardDetectionService,325 startConsumersInterceptor: ((Vertx) -> Future<Void>)? = null326 ) = (startVertxInstances(expectedInstances)).map { additionalVertx ->327 val nodeId = OrchestraClusterNodeId(clusterName, "${UUID.randomUUID()}")328 val verticleOptions = verticleOptionsOf(nodeId)329 val nodeScoreService = deployNodeStateService(nodeId, additionalVertx)330 val consumerControlService =331 TestConsumerControlService(332 additionalVertx,333 sharedConsumableShardDetection,334 nodeScoreService,335 startConsumersInterceptor336 )337 ConsumerControlService.exposeService(additionalVertx, consumerControlService)338 ConsumableShardDetectionService.exposeService(additionalVertx, sharedConsumableShardDetection)339 val balancingVerticleDeploymentId = deployBalancingVerticle(verticleOptions, additionalVertx)340 TestNodeInstanceInfo(nodeId, additionalVertx, consumerControlService, balancingVerticleDeploymentId)341 }.toMutableList()342 private suspend fun deployBalancingVerticle(options: BalancingVerticle.Options, vertx: Vertx = this.vertx): String {343 return vertx.deployVerticle(BalancingVerticle::class.java, options.toDeploymentOptions()).await()344 }345 private suspend fun deployNodeStateService(346 nodeId: OrchestraClusterNodeId,347 vertx: Vertx = this.vertx,348 nodeKeepAliveMillis: Long = DEFAULT_NODE_KEEP_ALIVE_MILLIS,349 ): NodeScoreService {350 val options = RedisNodeScoreVerticle.Options(nodeId, redisHeimdallOptions, nodeKeepAliveMillis)351 vertx.deployVerticle(352 RedisNodeScoreVerticle::class.java,353 deploymentOptionsOf(config = JsonObject.mapFrom(options))354 ).await()355 return NodeScoreService.createService(vertx)356 }357 private suspend fun verifyActiveBalancerNode(nodeId: OrchestraClusterNodeId) {358 redisClient.send(Request.cmd(Command.GET).arg("${nodeId.clusterName}-balancer")).await()359 .toString().shouldBe("$nodeId")360 }361 private fun setClusterWideActiveBalancingJobFlag(nodeId: OrchestraClusterNodeId, testContext: VertxTestContext): Future<Boolean> {362 val cmd = Request.cmd(Command.SET).apply {363 arg("${nodeId.clusterName}-balancing-job-active").arg("$nodeId").arg("NX")364 }365 return redisClient.send(cmd).compose {366 val successful = it.okResponseAsBoolean()367 testContext.verify { successful.shouldBeTrue() }368 Future.succeededFuture(successful)369 }370 }371 private fun verifyClusterWideActiveBalancingJobFlag(nodeId: OrchestraClusterNodeId, testContext: VertxTestContext): Future<Boolean> {372 val cmd = Request.cmd(Command.GET).apply {373 arg("${nodeId.clusterName}-balancing-job-active")374 }375 return redisClient.send(cmd).compose {376 val successful = it.toString() == "$nodeId"377 testContext.verify { successful.shouldBeTrue() }378 Future.succeededFuture(successful)379 }380 }381 private fun unsetClusterWideActiveBalancingJobFlag(nodeId: OrchestraClusterNodeId, testContext: VertxTestContext): Future<Boolean> {382 val cmd = Request.cmd(Command.DEL).apply {383 arg("${nodeId.clusterName}-balancing-job-active")384 }385 return redisClient.send(cmd).compose {386 val successful = it.toInteger() == 1387 testContext.verify { successful.shouldBeTrue() }388 Future.succeededFuture(successful)389 }390 }391 private fun verticleOptionsOf(392 nodeId: OrchestraClusterNodeId = OrchestraClusterNodeId("test-cluster", "${UUID.randomUUID()}"),393 activeBalancerCheckIntervalMillis: Long = DEFAULT_ACTIVE_BALANCER_CHECK_INTERVAL_MILLIS,394 initialBalancingDelayMillis: Long = DEFAULT_INITIAL_BALANCING_DELAY_MILLIS,395 balancingIntervalMillis: Long = DEFAULT_BALANCING_INTERVAL_MILLIS,396 balancingCommandTimeoutMillis: Long = DEFAULT_BALANCING_COMMAND_TIMEOUT_MILLIS,397 ) = BalancingVerticle.Options(398 nodeId,399 redisHeimdallOptions,400 activeBalancerCheckIntervalMillis,401 initialBalancingDelayMillis,402 balancingIntervalMillis,403 balancingCommandTimeoutMillis404 )405}406private data class TestNodeInstanceInfo(407 val nodeId: OrchestraClusterNodeId,408 val vertxInstance: Vertx,409 val consumerControlService: TestConsumerControlService,410 val balancerDeploymentId: String411)412private class SharedConsumableShardDetectionService(allShardIds: List<ShardId>) : ConsumableShardDetectionService {413 private val consumableShards = ArrayList(allShardIds)414 override fun getConsumableShards(): Future<List<ShardId>> = Future.succeededFuture(ArrayList(consumableShards))415 @Synchronized416 fun nowConsumed(shardIds: List<ShardId>) {417 consumableShards.removeAll(shardIds.toSet())418 }419 @Synchronized420 fun noMoreConsumed(shardIds: List<ShardId>) {421 consumableShards.addAll(shardIds)422 }423}424private class TestConsumerControlService(425 private val vertx: Vertx,426 private val consumableDetection: SharedConsumableShardDetectionService,427 private val nodeScoreService: NodeScoreService,428 private val startConsumersInterceptor: ((Vertx) -> Future<Void>)? = null429) : ConsumerControlService {430 val activeConsumedShards = ArrayList<ShardId>()431 override fun stopConsumer(shardId: ShardId): Future<Void> = Future.failedFuture("stopConsumer unsupported")432 override fun stopConsumers(consumerCount: Int): Future<StopConsumersCmdResult> {433 val stoppedShardIds = activeConsumedShards.takeAndRemove(consumerCount)434 consumableDetection.noMoreConsumed(stoppedShardIds)435 return nodeScoreService.setThisNodeScore(activeConsumedShards.size)436 .compose { Future.succeededFuture(StopConsumersCmdResult(stoppedShardIds, activeConsumedShards.size)) }437 }438 override fun startConsumers(shardIds: List<ShardId>): Future<Int> {439 activeConsumedShards.addAll(shardIds)440 consumableDetection.nowConsumed(shardIds)441 return nodeScoreService.setThisNodeScore(activeConsumedShards.size)442 .compose {443 if (startConsumersInterceptor != null) {444 startConsumersInterceptor.invoke(vertx)445 .compose { Future.succeededFuture(activeConsumedShards.size) }446 } else Future.succeededFuture(activeConsumedShards.size)447 }448 }449}450private object NoopConsumerControlService : ConsumerControlService {451 override fun stopConsumer(shardId: ShardId): Future<Void> = Future.failedFuture("stopConsumer unsupported")452 override fun stopConsumers(consumerCount: Int): Future<StopConsumersCmdResult> = Future.succeededFuture(453 StopConsumersCmdResult(454 emptyList(), 1455 )456 )457 override fun startConsumers(shardIds: List<ShardId>): Future<Int> = Future.succeededFuture(0)458}459private object NoopConsumableShardDetectionService : ConsumableShardDetectionService {460 override fun getConsumableShards(): Future<List<ShardId>> = Future.succeededFuture(emptyList())461}462internal fun BalancingVerticle.Options.toDeploymentOptions() = deploymentOptionsOf(config = JsonObject.mapFrom(this))...
matchers.kt
Source:matchers.kt
1package io.kotest.matchers.collections2import io.kotest.assertions.print.print3import io.kotest.matchers.*4fun <T> Iterable<T>.shouldHaveElementAt(index: Int, element: T) = toList().shouldHaveElementAt(index, element)5fun <T> Array<T>.shouldHaveElementAt(index: Int, element: T) = asList().shouldHaveElementAt(index, element)6fun <T> List<T>.shouldHaveElementAt(index: Int, element: T) = this should haveElementAt(index, element)7fun <T> Iterable<T>.shouldNotHaveElementAt(index: Int, element: T) = toList().shouldNotHaveElementAt(index, element)8fun <T> Array<T>.shouldNotHaveElementAt(index: Int, element: T) = asList().shouldNotHaveElementAt(index, element)9fun <T> List<T>.shouldNotHaveElementAt(index: Int, element: T) = this shouldNot haveElementAt(index, element)10fun <T, L : List<T>> haveElementAt(index: Int, element: T) = object : Matcher<L> {11 override fun test(value: L) =12 MatcherResult(13 index < value.size && value[index] == element,14 { "Collection ${value.print().value} should contain ${element.print().value} at index $index" },15 { "Collection ${value.print().value} should not contain ${element.print().value} at index $index" }16 )17}18infix fun <T> Iterable<T>.shouldHaveSingleElement(t: T): Iterable<T> {19 toList().shouldHaveSingleElement(t)20 return this21}22infix fun <T> Array<T>.shouldHaveSingleElement(t: T): Array<T> {23 asList().shouldHaveSingleElement(t)24 return this25}26infix fun <T> Iterable<T>.shouldHaveSingleElement(p: (T) -> Boolean): Iterable<T> {27 toList().shouldHaveSingleElement(p)28 return this29}30infix fun <T> Array<T>.shouldHaveSingleElement(p: (T) -> Boolean) = asList().shouldHaveSingleElement(p)31infix fun <T> Collection<T>.shouldHaveSingleElement(t: T) = this should singleElement(t)32infix fun <T> Collection<T>.shouldHaveSingleElement(p: (T) -> Boolean) = this should singleElement(p)33infix fun <T> Iterable<T>.shouldNotHaveSingleElement(t: T) = toList().shouldNotHaveSingleElement(t)34infix fun <T> Array<T>.shouldNotHaveSingleElement(t: T) = asList().shouldNotHaveSingleElement(t)35infix fun <T> Collection<T>.shouldNotHaveSingleElement(t: T) = this shouldNot singleElement(t)36infix fun <T> Iterable<T>.shouldExist(p: (T) -> Boolean) = toList().shouldExist(p)37infix fun <T> Array<T>.shouldExist(p: (T) -> Boolean) = asList().shouldExist(p)38infix fun <T> Collection<T>.shouldExist(p: (T) -> Boolean) = this should exist(p)39fun <T> exist(p: (T) -> Boolean) = object : Matcher<Collection<T>> {40 override fun test(value: Collection<T>) = MatcherResult(41 value.any { p(it) },42 { "Collection ${value.print().value} should contain an element that matches the predicate $p" },43 {44 "Collection ${value.print().value} should not contain an element that matches the predicate $p"45 })46}47fun <T> Iterable<T>.shouldMatchInOrder(vararg assertions: (T) -> Unit) = toList().shouldMatchInOrder(assertions.toList())48fun <T> Array<T>.shouldMatchInOrder(vararg assertions: (T) -> Unit) = asList().shouldMatchInOrder(assertions.toList())49fun <T> List<T>.shouldMatchInOrder(vararg assertions: (T) -> Unit) = this.shouldMatchInOrder(assertions.toList())50infix fun <T> Iterable<T>.shouldMatchInOrder(assertions: List<(T) -> Unit>) = toList().shouldMatchInOrder(assertions)51infix fun <T> Array<T>.shouldMatchInOrder(assertions: List<(T) -> Unit>) = asList().shouldMatchInOrder(assertions)52infix fun <T> List<T>.shouldMatchInOrder(assertions: List<(T) -> Unit>) = this should matchInOrder(assertions.toList(), allowGaps = false)53fun <T> Iterable<T>.shouldNotMatchInOrder(vararg assertions: (T) -> Unit) = toList().shouldNotMatchInOrder(assertions.toList())54fun <T> Array<T>.shouldNotMatchInOrder(vararg assertions: (T) -> Unit) = asList().shouldNotMatchInOrder(assertions.toList())55fun <T> List<T>.shouldNotMatchInOrder(vararg assertions: (T) -> Unit) = this.shouldNotMatchInOrder(assertions.toList())56infix fun <T> Iterable<T>.shouldNotMatchInOrder(assertions: List<(T) -> Unit>) = toList().shouldNotMatchInOrder(assertions)57infix fun <T> Array<T>.shouldNotMatchInOrder(assertions: List<(T) -> Unit>) = asList().shouldNotMatchInOrder(assertions)58infix fun <T> List<T>.shouldNotMatchInOrder(assertions: List<(T) -> Unit>) = this shouldNot matchInOrder(assertions.toList(), allowGaps = false)59fun <T> Iterable<T>.shouldMatchInOrderSubset(vararg assertions: (T) -> Unit) = toList().shouldMatchInOrderSubset(assertions.toList())60fun <T> Array<T>.shouldMatchInOrderSubset(vararg assertions: (T) -> Unit) = asList().shouldMatchInOrderSubset(assertions.toList())61fun <T> List<T>.shouldMatchInOrderSubset(vararg assertions: (T) -> Unit) = this.shouldMatchInOrderSubset(assertions.toList())62infix fun <T> Iterable<T>.shouldMatchInOrderSubset(assertions: List<(T) -> Unit>) = toList().shouldMatchInOrderSubset(assertions)63infix fun <T> Array<T>.shouldMatchInOrderSubset(assertions: List<(T) -> Unit>) = asList().shouldMatchInOrderSubset(assertions)64infix fun <T> List<T>.shouldMatchInOrderSubset(assertions: List<(T) -> Unit>) = this should matchInOrder(assertions.toList(), allowGaps = true)65fun <T> Iterable<T>.shouldNotMatchInOrderSubset(vararg assertions: (T) -> Unit) = toList().shouldNotMatchInOrderSubset(assertions.toList())66fun <T> Array<T>.shouldNotMatchInOrderSubset(vararg assertions: (T) -> Unit) = asList().shouldNotMatchInOrderSubset(assertions.toList())67fun <T> List<T>.shouldNotMatchInOrderSubset(vararg assertions: (T) -> Unit) = this.shouldNotMatchInOrderSubset(assertions.toList())68infix fun <T> Iterable<T>.shouldNotMatchInOrderSubset(assertions: List<(T) -> Unit>) = toList().shouldNotMatchInOrderSubset(assertions)69infix fun <T> Array<T>.shouldNotMatchInOrderSubset(assertions: List<(T) -> Unit>) = asList().shouldNotMatchInOrderSubset(assertions)70infix fun <T> List<T>.shouldNotMatchInOrderSubset(assertions: List<(T) -> Unit>) = this shouldNot matchInOrder(assertions.toList(), allowGaps = true)71fun <T> Iterable<T>.shouldMatchEach(vararg assertions: (T) -> Unit) = toList().shouldMatchEach(assertions.toList())72fun <T> Array<T>.shouldMatchEach(vararg assertions: (T) -> Unit) = asList().shouldMatchEach(assertions.toList())73fun <T> List<T>.shouldMatchEach(vararg assertions: (T) -> Unit) = this.shouldMatchEach(assertions.toList())74infix fun <T> Iterable<T>.shouldMatchEach(assertions: List<(T) -> Unit>) = toList().shouldMatchEach(assertions)75infix fun <T> Array<T>.shouldMatchEach(assertions: List<(T) -> Unit>) = asList().shouldMatchEach(assertions)76infix fun <T> List<T>.shouldMatchEach(assertions: List<(T) -> Unit>) = this should matchEach(assertions.toList())77fun <T> Iterable<T>.shouldNotMatchEach(vararg assertions: (T) -> Unit) = toList().shouldNotMatchEach(assertions.toList())78fun <T> Array<T>.shouldNotMatchEach(vararg assertions: (T) -> Unit) = asList().shouldNotMatchEach(assertions.toList())79fun <T> List<T>.shouldNotMatchEach(vararg assertions: (T) -> Unit) = this.shouldNotMatchEach(assertions.toList())80infix fun <T> Iterable<T>.shouldNotMatchEach(assertions: List<(T) -> Unit>) = toList().shouldNotMatchEach(assertions)81infix fun <T> Array<T>.shouldNotMatchEach(assertions: List<(T) -> Unit>) = asList().shouldNotMatchEach(assertions)82infix fun <T> List<T>.shouldNotMatchEach(assertions: List<(T) -> Unit>) = this shouldNot matchEach(assertions.toList())83fun <T> Iterable<T>.shouldExistInOrder(vararg ps: (T) -> Boolean) = toList().shouldExistInOrder(ps.toList())84fun <T> Array<T>.shouldExistInOrder(vararg ps: (T) -> Boolean) = asList().shouldExistInOrder(ps.toList())85fun <T> List<T>.shouldExistInOrder(vararg ps: (T) -> Boolean) = this.shouldExistInOrder(ps.toList())86infix fun <T> Iterable<T>.shouldExistInOrder(expected: List<(T) -> Boolean>) = toList().shouldExistInOrder(expected)87infix fun <T> Array<T>.shouldExistInOrder(expected: List<(T) -> Boolean>) = asList().shouldExistInOrder(expected)88infix fun <T> List<T>.shouldExistInOrder(expected: List<(T) -> Boolean>) = this should existInOrder(expected)89infix fun <T> Iterable<T>.shouldNotExistInOrder(expected: Iterable<(T) -> Boolean>) =90 toList().shouldNotExistInOrder(expected.toList())91infix fun <T> Array<T>.shouldNotExistInOrder(expected: Array<(T) -> Boolean>) =92 asList().shouldNotExistInOrder(expected.asList())93infix fun <T> Iterable<T>.shouldNotExistInOrder(expected: List<(T) -> Boolean>) =94 toList().shouldNotExistInOrder(expected)95infix fun <T> Array<T>.shouldNotExistInOrder(expected: List<(T) -> Boolean>) = asList().shouldNotExistInOrder(expected)96infix fun <T> List<T>.shouldNotExistInOrder(expected: List<(T) -> Boolean>) = this shouldNot existInOrder(expected)97fun <T> Iterable<T>.shouldContainAnyOf(vararg ts: T) = toList().shouldContainAnyOf(ts)98fun <T> Array<T>.shouldContainAnyOf(vararg ts: T) = asList().shouldContainAnyOf(ts)99fun <T> Collection<T>.shouldContainAnyOf(vararg ts: T) = this should containAnyOf(ts.asList())100fun <T> Iterable<T>.shouldNotContainAnyOf(vararg ts: T) = toList().shouldNotContainAnyOf(ts)101fun <T> Array<T>.shouldNotContainAnyOf(vararg ts: T) = asList().shouldNotContainAnyOf(ts)102fun <T> Collection<T>.shouldNotContainAnyOf(vararg ts: T) = this shouldNot containAnyOf(ts.asList())103infix fun <T> Iterable<T>.shouldContainAnyOf(ts: Collection<T>) = toList().shouldContainAnyOf(ts)104infix fun <T> Array<T>.shouldContainAnyOf(ts: Collection<T>) = asList().shouldContainAnyOf(ts)105infix fun <T> Collection<T>.shouldContainAnyOf(ts: Collection<T>) = this should containAnyOf(ts)106infix fun <T> Iterable<T>.shouldNotContainAnyOf(ts: Collection<T>) = toList().shouldNotContainAnyOf(ts)107infix fun <T> Array<T>.shouldNotContainAnyOf(ts: Collection<T>) = asList().shouldNotContainAnyOf(ts)108infix fun <T> Collection<T>.shouldNotContainAnyOf(ts: Collection<T>) = this shouldNot containAnyOf(ts)109fun <T> containAnyOf(ts: Collection<T>) = object : Matcher<Collection<T>> {110 override fun test(value: Collection<T>): MatcherResult {111 if (ts.isEmpty()) throwEmptyCollectionError()112 return MatcherResult(113 ts.any { it in value },114 { "Collection ${value.print().value} should contain any of ${ts.print().value}" },115 { "Collection ${value.print().value} should not contain any of ${ts.print().value}" }116 )117 }118}119internal fun throwEmptyCollectionError(): Nothing {120 throw AssertionError("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")121}...
AssignmentStrategyUsageTest.kt
Source:AssignmentStrategyUsageTest.kt
1package ru.fix.distributed.job.manager.strategy2import io.kotest.matchers.booleans.shouldBeTrue3import io.kotest.matchers.collections.shouldNotContainAnyOf4import io.kotest.matchers.shouldBe5import org.apache.logging.log4j.kotlin.Logging6import org.junit.jupiter.api.Test7import ru.fix.distributed.job.manager.JobId8import ru.fix.distributed.job.manager.model.AssignmentState9import ru.fix.distributed.job.manager.model.Availability10import ru.fix.distributed.job.manager.model.WorkItem11class AssignmentStrategyUsageTest {12 companion object : Logging13 private val ussdJobId = JobId("ussd")14 private val ussdWorkItems = setOf(WorkItem("ussd", ussdJobId))15 private val smsJobId = JobId("sms")16 private val smsWorkItems = (1..3).map { WorkItem("sms$it", smsJobId) }.toSet()17 private val rebillJobId = JobId("rebill")18 private val rebillWorkItems = (1..7).map { WorkItem("rebill$it", rebillJobId) }.toSet()19 private val workers = arrayOf("worker-0", "worker-1", "worker-2", "worker-3")20 private val singleUssdItemAssignedToOneOfWorkers = object : AbstractAssignmentStrategy() {21 override fun reassignAndBalance(22 availability: Availability,23 prevAssignment: AssignmentState,24 currentAssignment: AssignmentState,25 itemsToAssign: MutableSet<WorkItem>26 ) {27 val ussdItem = ussdWorkItems.single()28 itemsToAssign.remove(ussdItem)29 if (prevAssignment.containsWorkItem(ussdItem)) {30 val workerFromPrevious = prevAssignment.getWorkerOfWorkItem(ussdItem)31 currentAssignment.addWorkItem(workerFromPrevious!!, ussdItem)32 } else {33 val lessBusyWorker = currentAssignment.getLessBusyWorker(availability[ussdItem.jobId])34 currentAssignment.addWorkItem(lessBusyWorker!!, ussdItem)35 }36 }37 }38 // Strategy assign work items on workers, which doesn't contains of any work item of ussd job39 private val multipleSmsItemsAssignedToWorkersWithoutUssd = object : AbstractAssignmentStrategy() {40 override fun reassignAndBalance(41 availability: Availability,42 prevAssignment: AssignmentState,43 currentAssignment: AssignmentState,44 itemsToAssign: MutableSet<WorkItem>45 ) {46 for ((jobId, workers) in availability) {47 val itemsToAssignForJob = getWorkItemsByJob(jobId, itemsToAssign)48 val availableWorkers = HashSet(workers)49 workers.forEach { workerId ->50 currentAssignment.putIfAbsent(workerId!!, HashSet<WorkItem>())51 // ignore worker, where ussd job was launched52 if (currentAssignment.containsAnyWorkItemOfJob(workerId, ussdJobId)) {53 availableWorkers.remove(workerId)54 }55 }56 for (item in itemsToAssignForJob) {57 if (currentAssignment.containsWorkItem(item)) {58 continue59 }60 val lessBusyWorker = currentAssignment61 .getLessBusyWorker(availableWorkers)62 currentAssignment.addWorkItem(lessBusyWorker, item)63 itemsToAssign.remove(item)64 }65 }66 }67 }68 @Test69 fun `assign single ussd and multiple sms on 4 workers`() {70 val customStrategy = object : AbstractAssignmentStrategy() {71 override fun reassignAndBalance(72 availability: Availability,73 prevAssignment: AssignmentState,74 currentAssignment: AssignmentState,75 itemsToAssign: MutableSet<WorkItem>76 ) {77 val ussdItemsToAssign = itemsToAssign.filter { it.jobId == ussdJobId }.toMutableSet()78 singleUssdItemAssignedToOneOfWorkers.reassignAndBalance(79 availability,80 prevAssignment,81 currentAssignment,82 ussdItemsToAssign83 )84 val smsItemsToAssign = itemsToAssign.filter { it.jobId == smsJobId }.toMutableSet()85 multipleSmsItemsAssignedToWorkersWithoutUssd.reassignAndBalance(86 availability,87 prevAssignment,88 currentAssignment,89 smsItemsToAssign90 )91 itemsToAssign.removeIf { it.jobId in setOf(ussdJobId, smsJobId) }92 // reassign items of other jobs using evenly spread strategy93 AssignmentStrategies.EVENLY_SPREAD.reassignAndBalance(94 availability,95 prevAssignment,96 currentAssignment,97 itemsToAssign98 )99 }100 }101 val currentAssignment = AssignmentState()102 customStrategy.reassignAndBalance(103 availability = availability {104 ussdJobId.id(*workers)105 smsJobId.id(*workers)106 rebillJobId.id(*workers)107 },108 prevAssignment = AssignmentState(),109 currentAssignment = currentAssignment,110 itemsToAssign = (ussdWorkItems + smsWorkItems + rebillWorkItems).toMutableSet()111 )112 logger.info(currentAssignment)113 val workersWithUssdItem = currentAssignment.filter { it.value.contains(ussdWorkItems.single()) }114 workersWithUssdItem.size.shouldBe(1)115 workersWithUssdItem.values.single().shouldNotContainAnyOf(smsWorkItems)116 currentAssignment.isBalanced().shouldBeTrue()117 }118}...
Array.shouldNotContainAnyOf
Using AI Code Generation
1val list = listOf(1, 2, 3)2list.shouldNotContainAnyOf(4, 5, 6)3list.shouldNotContainAnyOf(listOf(4, 5, 6))4val list = listOf(1, 2, 3)5list.shouldNotContainNoneOf(1, 2, 3)6list.shouldNotContainNoneOf(listOf(1, 2, 3))7val list = listOf(1, 2, 3)8list.shouldNotContainNoneOf(1, 2, 3)9list.shouldNotContainNoneOf(listOf(1, 2, 3))10val list = listOf(1, 2, 3)11list.shouldNotHaveDuplicates()12val list = listOf(1, 2, 3)13list.shouldNotHaveDuplicates()14val list = listOf(1, 2, 3)15list.shouldNotHaveDuplicates()16val list = listOf(1, 2, 3)17list.shouldNotHaveDuplicates()18val list = listOf(1, 2, 3)19list.shouldNotHaveDuplicates()20val list = listOf(1, 2, 3)21list.shouldNotHaveDuplicates()22val list = listOf(1, 2, 3)23list.shouldNotHaveDuplicates()24val list = listOf(1,
Array.shouldNotContainAnyOf
Using AI Code Generation
1import io.kotest.matchers.collections.shouldNotContainAnyOf2arrayOf(1, 2, 3, 4, 5).shouldNotContainAnyOf(6, 7, 8)3import io.kotest.matchers.collections.shouldNotContain4arrayOf(1, 2, 3, 4, 5).shouldNotContain(6)5import io.kotest.matchers.collections.shouldNotHaveDuplicates6arrayOf(1, 2, 3, 4, 5).shouldNotHaveDuplicates()7import io.kotest.matchers.collections.shouldNotHaveDuplicates8arrayOf(1, 2, 3, 4, 5).shouldNotHaveDuplicates()9import io.kotest.matchers.collections.shouldNotHaveSameElementsAs10arrayOf(1, 2, 3, 4, 5).shouldNotHaveSameElementsAs(arrayOf(1, 2, 3, 4, 5))11import io.kotest.matchers.collections.shouldNotHaveTheSameElementsAs12arrayOf(1, 2, 3, 4, 5).shouldNotHaveTheSameElementsAs(arrayOf(1, 2, 3, 4, 5))13import io.kotest.matchers.collections.shouldNotStartWith14arrayOf(1, 2, 3, 4, 5).shouldNotStartWith(arrayOf(1, 2, 3, 4, 5))15import io.kotest.matchers.collections.shouldOnlyHaveElementsOfType16arrayOf(1, 2, 3,
Array.shouldNotContainAnyOf
Using AI Code Generation
1val list = listOf(1, 2, 3, 4, 5)2list.shouldNotContainAnyOf(6, 7, 8, 9)3list.shouldNotContainAnyOf(6, 7, 8, 9)4list.shouldNotContainAnyOf(1, 2, 3, 4, 5)5val list = listOf(1, 2, 3, 4, 5)6list.shouldContainAllOf(1, 2, 3)7list.shouldContainAllOf(1, 2, 3, 4, 5)8list.shouldContainAllOf(1, 2, 3, 4, 5, 6)9val list = listOf(1, 2, 3, 4, 5)10list.shouldNotContainAllOf(1, 2, 3, 4, 5, 6)11list.shouldNotContainAllOf(1, 2, 3)12list.shouldNotContainAllOf(6, 7, 8, 9)13val list = listOf(1, 2, 3, 4, 5)14list.shouldBeSorted()15list.shouldBeSorted()16list.shouldBeSorted()17val list = listOf(1, 2, 3, 4, 5)18list.shouldBeSortedWith(compareBy { it })19list.shouldBeSortedWith(compareBy { it })20list.shouldBeSortedWith(compareBy { it })21val list = listOf(5, 4, 3, 2, 1)22list.shouldBeSortedDescending()23list.shouldBeSortedDescending()24list.shouldBeSortedDescending()25val list = listOf(5, 4, 3, 2,
Array.shouldNotContainAnyOf
Using AI Code Generation
1@DisplayName("shouldNotContainAnyOf Test")2class ShouldNotContainAnyOfTest {3 fun `shouldNotContainAnyOf Test`() {4 val list = listOf("A", "B", "C", "D", "E")5 list.shouldNotContainAnyOf("F", "G")6 }7}8@DisplayName("shouldNotContainAll Test")9class ShouldNotContainAllTest {10 fun `shouldNotContainAll Test`() {11 val list = listOf("A", "B", "C", "D", "E")12 list.shouldNotContainAll("F", "G")13 }14}15@DisplayName("shouldNotContainDuplicates Test")16class ShouldNotContainDuplicatesTest {17 fun `shouldNotContainDuplicates Test`() {18 val list = listOf("A", "B", "C", "D", "E")19 list.shouldNotContainDuplicates()20 }21}
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!!