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!!
