From 339ce9db98c1e6dfb1c8d69f81806680b1efa666 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Fri, 4 Jan 2019 01:56:04 -0500 Subject: Convert global continuations to completable deferred --- .../com/pitchedapps/frost/kotlin/FlyweightTest.kt | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'app/src/test') diff --git a/app/src/test/kotlin/com/pitchedapps/frost/kotlin/FlyweightTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/kotlin/FlyweightTest.kt index 0eee530e..79f81002 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/kotlin/FlyweightTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/kotlin/FlyweightTest.kt @@ -54,7 +54,7 @@ class FlyweightTest { @Test fun basic() { - assertEquals(2, runBlocking { flyweight.fetch(1) }, "Invalid result") + assertEquals(2, runBlocking { flyweight.fetch(1).await() }, "Invalid result") assertEquals(1, callCount.get(), "1 call expected") } @@ -62,9 +62,7 @@ class FlyweightTest { fun multipleWithOneKey() { val results: List = runBlocking { (0..1000).map { - flyweight.scope.async { - flyweight.fetch(1) - } + flyweight.fetch(1) }.map { it.await() } } assertEquals(1, callCount.get(), "1 call expected") @@ -75,12 +73,12 @@ class FlyweightTest { @Test fun consecutiveReuse() { runBlocking { - flyweight.fetch(1) + flyweight.fetch(1).await() assertEquals(1, callCount.get(), "1 call expected") - flyweight.fetch(1) + flyweight.fetch(1).await() assertEquals(1, callCount.get(), "Reuse expected") Thread.sleep(300) - flyweight.fetch(1) + flyweight.fetch(1).await() assertEquals(2, callCount.get(), "Refetch expected") } } @@ -88,10 +86,10 @@ class FlyweightTest { @Test fun invalidate() { runBlocking { - flyweight.fetch(1) + flyweight.fetch(1).await() assertEquals(1, callCount.get(), "1 call expected") flyweight.invalidate(1) - flyweight.fetch(1) + flyweight.fetch(1).await() assertEquals(2, callCount.get(), "New call expected") } } @@ -100,10 +98,10 @@ class FlyweightTest { fun destroy() { runBlocking { val longRunningResult = async { flyweight.fetch(LONG_RUNNING_KEY) } - flyweight.fetch(1) + flyweight.fetch(1).await() flyweight.cancel() try { - flyweight.fetch(1) + flyweight.fetch(1).await() fail("Flyweight should not be fulfilled after it is destroyed") } catch (e: Exception) { assertEquals("Flyweight is not active", e.message, "Incorrect error found on fetch after destruction") -- cgit v1.2.3 From 535004b8a28d1b227fa0673f80f6086ca8f4be41 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Fri, 4 Jan 2019 13:32:58 -0500 Subject: Fix flyweight tests --- .../frost/facebook/requests/FbRequest.kt | 2 +- .../com/pitchedapps/frost/kotlin/Flyweight.kt | 46 +++++++++++----------- .../com/pitchedapps/frost/kotlin/FlyweightTest.kt | 18 ++++----- 3 files changed, 31 insertions(+), 35 deletions(-) (limited to 'app/src/test') diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt index 16ddb7e1..67a03ad4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt @@ -40,7 +40,7 @@ import java.lang.Exception /** * Created by Allan Wang on 21/12/17. */ -val fbAuth = Flyweight(GlobalScope, 100, 3600000 /* an hour */) { +val fbAuth = Flyweight(GlobalScope, 3600000 /* an hour */) { it.getAuth() } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/kotlin/Flyweight.kt b/app/src/main/kotlin/com/pitchedapps/frost/kotlin/Flyweight.kt index e5edce24..914ce151 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/kotlin/Flyweight.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/kotlin/Flyweight.kt @@ -36,19 +36,16 @@ import java.util.concurrent.ConcurrentHashMap */ class Flyweight( val scope: CoroutineScope, - capacity: Int, val maxAge: Long, private val fetcher: suspend (K) -> V ) { // Receives a key and a pending request - private val actionChannel = Channel>>(capacity) + private val actionChannel = Channel>>(Channel.UNLIMITED) // Receives a key to invalidate the associated value - private val invalidatorChannel = Channel(capacity) - // Receives a key to fetch the value - private val requesterChannel = Channel(capacity) + private val invalidatorChannel = Channel(Channel.UNLIMITED) // Receives a key and the resulting value - private val receiverChannel = Channel>>(capacity) + private val receiverChannel = Channel>>(Channel.UNLIMITED) // Keeps track of keys and associated update times private val conditionMap: MutableMap = mutableMapOf() @@ -85,7 +82,7 @@ class Flyweight( val valueRequestPending = key in pendingMap pendingMap.getOrPut(key) { mutableListOf() }.add(completable) if (!valueRequestPending) - requesterChannel.send(key) + fulfill(key) } } /* @@ -102,7 +99,7 @@ class Flyweight( resultMap.remove(key) if (pendingMap[key]?.isNotEmpty() == true) // Refetch value for pending requests - requesterChannel.send(key) + fulfill(key) } /* * Value request fulfilled. Should now fulfill pending requests @@ -117,28 +114,32 @@ class Flyweight( } } } - launch { - /* - * Value request received. Should fetch new value using supplied fetcher - */ - for (key in requesterChannel) { - val result = runCatching { - fetcher(key) - } - receiverChannel.send(key to result) - } + } + } + + /* + * Value request received. Should fetch new value using supplied fetcher + */ + private fun fulfill(key: K) { + scope.launch { + val result = runCatching { + fetcher(key) } + receiverChannel.send(key to result) } } /** * Queues the request, and returns a completable once it is sent to a channel. - * The fetcher will only be suspended if the channels are full + * The fetcher will only be suspended if the channels are full. + * + * Note that if the job is already inactive, a cancellation exception will be thrown. + * The message may default to the message for all completables under a cancelled job */ - suspend fun fetch(key: K): CompletableDeferred { + fun fetch(key: K): CompletableDeferred { val completable = CompletableDeferred(job) - if (!job.isActive) completable.completeExceptionally(IllegalStateException("Flyweight is not active")) - else actionChannel.send(key to completable) + if (!job.isActive) completable.completeExceptionally(CancellationException("Flyweight is not active")) + else actionChannel.offer(key to completable) return completable } @@ -155,7 +156,6 @@ class Flyweight( } actionChannel.close() invalidatorChannel.close() - requesterChannel.close() receiverChannel.close() conditionMap.clear() resultMap.clear() diff --git a/app/src/test/kotlin/com/pitchedapps/frost/kotlin/FlyweightTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/kotlin/FlyweightTest.kt index 79f81002..d1d976b6 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/kotlin/FlyweightTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/kotlin/FlyweightTest.kt @@ -16,8 +16,8 @@ */ package com.pitchedapps.frost.kotlin +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.rules.Timeout @@ -25,6 +25,7 @@ import java.util.concurrent.atomic.AtomicInteger import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertTrue import kotlin.test.fail @@ -42,7 +43,7 @@ class FlyweightTest { @BeforeTest fun before() { callCount = AtomicInteger(0) - flyweight = Flyweight(GlobalScope, 100, 200L) { + flyweight = Flyweight(GlobalScope, 200L) { callCount.incrementAndGet() when (it) { LONG_RUNNING_KEY -> Thread.sleep(100000) @@ -97,24 +98,19 @@ class FlyweightTest { @Test fun destroy() { runBlocking { - val longRunningResult = async { flyweight.fetch(LONG_RUNNING_KEY) } + val longRunningResult = flyweight.fetch(LONG_RUNNING_KEY) flyweight.fetch(1).await() flyweight.cancel() try { flyweight.fetch(1).await() fail("Flyweight should not be fulfilled after it is destroyed") - } catch (e: Exception) { - assertEquals("Flyweight is not active", e.message, "Incorrect error found on fetch after destruction") + } catch (ignore: CancellationException) { } try { + assertFalse(longRunningResult.isActive, "Long running result should no longer be active") longRunningResult.await() fail("Flyweight should have cancelled previously running requests") - } catch (e: Exception) { - assertEquals( - "Flyweight cancelled", - e.message, - "Incorrect error found on fetch cancelled by destruction" - ) + } catch (ignore: CancellationException) { } } } -- cgit v1.2.3 From 96418eb38691b634bb176435b72b49971dc07c27 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Fri, 4 Jan 2019 13:53:45 -0500 Subject: Prepare new test for unique only --- .../com/pitchedapps/frost/utils/CoroutineTest.kt | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'app/src/test') diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt index 72eb6076..32a781df 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt @@ -16,8 +16,10 @@ */ package com.pitchedapps.frost.utils +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.async import kotlinx.coroutines.channels.BroadcastChannel @@ -31,6 +33,7 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import java.util.concurrent.Executors import kotlin.coroutines.EmptyCoroutineContext +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -206,4 +209,40 @@ class CoroutineTest { ) } } + + /** + * When using [uniqueOnly] for channels with limited capacity, + * the duplicates should not count towards the actual capacity + */ + @Ignore("Not yet working as unique only buffered removes the capacity limitation of the channel") + @Test + fun uniqueOnlyBuffer() { + val completable = CompletableDeferred() + val channel = Channel(3) + runBlocking { + + val deferred = async { + listen(channel.uniqueOnly(GlobalScope)) { + // Throttle consumer + delay(50) + return@listen false + } + } + + listOf(0, 1, 1, 1, 1, 1, 2, 2, 2).forEach { + delay(10) + channel.offer(it) + } + + channel.close() + + val data = deferred.await() + + assertEquals( + listOf(0, 1, 2), + data, + "Unique receiver should not have two consecutive events that are equal" + ) + } + } } -- cgit v1.2.3 From a1cf58e0eee8d16576380e05a8d87e128242bf05 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Fri, 4 Jan 2019 13:56:12 -0500 Subject: Use coroutine version in kau --- app/build.gradle | 2 +- app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt | 2 -- gradle.properties | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'app/src/test') diff --git a/app/build.gradle b/app/build.gradle index 562de936..0cb401fb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -204,7 +204,7 @@ dependencies { // androidTestImplementation "io.mockk:mockk:${MOCKK}" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${COROUTINES}" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${kau.coroutines}" implementation "org.apache.commons:commons-text:${COMMONS_TEXT}" diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt index 32a781df..e7520794 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt @@ -16,7 +16,6 @@ */ package com.pitchedapps.frost.utils -import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.GlobalScope @@ -217,7 +216,6 @@ class CoroutineTest { @Ignore("Not yet working as unique only buffered removes the capacity limitation of the channel") @Test fun uniqueOnlyBuffer() { - val completable = CompletableDeferred() val channel = Channel(3) runBlocking { diff --git a/gradle.properties b/gradle.properties index 11127a3e..dcdb5630 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,8 +23,6 @@ ANDROID_GRADLE=3.2.1 # https://github.com/diffplug/spotless/blob/master/plugin-gradle/CHANGES.md SPOTLESS=3.17.0 -# https://github.com/Kotlin/kotlinx.coroutines/releases -COROUTINES=1.0.1 # https://github.com/bugsnag/bugsnag-android/releases BUGSNAG=4.9.3 # https://github.com/bugsnag/bugsnag-android-gradle-plugin/releases -- cgit v1.2.3 From 5d2722b2205e404ee90cbb7e141ac63ca6570e1a Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Fri, 4 Jan 2019 23:59:30 -0500 Subject: Remove unused dependencies and remove reactivex from username fetcher --- app/build.gradle | 4 +-- .../com/pitchedapps/frost/dbflow/CookiesDb.kt | 28 +++++++----------- .../frost/facebook/requests/FbRequestTest.kt | 2 +- .../com/pitchedapps/frost/internal/Internal.kt | 34 ---------------------- gradle.properties | 6 ++-- 5 files changed, 16 insertions(+), 58 deletions(-) (limited to 'app/src/test') diff --git a/app/build.gradle b/app/build.gradle index 0cb401fb..23d26fd8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -253,8 +253,8 @@ dependencies { //Reactive Libs implementation "io.reactivex.rxjava2:rxjava:${RX_JAVA}" - implementation "io.reactivex.rxjava2:rxkotlin:${RX_KOTLIN}" - implementation "io.reactivex.rxjava2:rxandroid:${RX_ANDROID}" +// implementation "io.reactivex.rxjava2:rxkotlin:${RX_KOTLIN}" +// implementation "io.reactivex.rxjava2:rxandroid:${RX_ANDROID}" implementation "com.github.pwittchen:reactivenetwork-rx2:${RX_NETWORK}" } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt index f7d97833..d7dd71ed 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt @@ -17,7 +17,7 @@ package com.pitchedapps.frost.dbflow import android.os.Parcelable -import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork +import com.pitchedapps.frost.dbflow.CookieModel_Table.cookie import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.frostJsoup @@ -34,11 +34,10 @@ import com.raizlabs.android.dbflow.kotlinextensions.save import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.kotlinextensions.where import com.raizlabs.android.dbflow.structure.BaseModel -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers import kotlinx.android.parcel.Parcelize import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeoutOrNull import java.net.UnknownHostException /** @@ -98,25 +97,20 @@ fun removeCookie(id: Long) { } } -inline fun CookieModel.fetchUsername(crossinline callback: (String) -> Unit): Disposable = - ReactiveNetwork.checkInternetConnectivity().subscribeOn(Schedulers.io()).subscribe { yes, _ -> - if (!yes) return@subscribe callback("") - var result = "" +suspend fun CookieModel.fetchUsername(): String? = withContext(Dispatchers.IO) { + withTimeoutOrNull(5000) { + var result: String? = null try { result = frostJsoup(cookie, FbItem.PROFILE.url).title() L.d { "Fetch username found" } } catch (e: Exception) { if (e !is UnknownHostException) e.logFrostEvent("Fetch username failed") - } finally { - if (result.isBlank() && (name?.isNotBlank() == true)) { - callback(name!!) - return@subscribe - } - if (name != result) { - name = result - saveFbCookie(this@fetchUsername) - } - callback(result) } + if (name?.isNotBlank() == false && result != null && result != name) { + name = result + saveFbCookie(this@fetchUsername) + } + result } +} \ No newline at end of file diff --git a/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbRequestTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbRequestTest.kt index ec765448..8610436a 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbRequestTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbRequestTest.kt @@ -84,7 +84,7 @@ class FbRequestTest { val data = AUTH.getMenuData().invoke() assertNotNull(data) println(ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(data)) - assertTrue(data!!.data.isNotEmpty()) + assertTrue(data.data.isNotEmpty()) assertTrue(data.footer.hasContent, "Footer may be badly parsed") val items = data.flatMapValid() assertTrue(items.size > 15, "Something may be badly parsed") diff --git a/app/src/test/kotlin/com/pitchedapps/frost/internal/Internal.kt b/app/src/test/kotlin/com/pitchedapps/frost/internal/Internal.kt index 061e7c38..b8d9635a 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/internal/Internal.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/internal/Internal.kt @@ -22,13 +22,10 @@ import com.pitchedapps.frost.facebook.get import com.pitchedapps.frost.facebook.requests.RequestAuth import com.pitchedapps.frost.facebook.requests.getAuth import com.pitchedapps.frost.utils.frostJsoup -import io.reactivex.Completable import org.junit.Assume -import org.junit.Test import java.io.File import java.io.FileInputStream import java.util.Properties -import java.util.concurrent.TimeUnit import kotlin.reflect.full.starProjectedType import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -97,34 +94,3 @@ fun Any.assertComponentsNotEmpty() { fun > List.assertDescending(tag: String) { assertEquals(sortedDescending(), this, "$tag not sorted in descending order") } - -interface CompletableCallback { - fun onComplete() - fun onError(message: String) -} - -inline fun concurrentTest(crossinline caller: (callback: CompletableCallback) -> Unit) { - val result = Completable.create { emitter -> - caller(object : CompletableCallback { - override fun onComplete() = emitter.onComplete() - override fun onError(message: String) = emitter.onError(Throwable(message)) - }) - }.blockingGet(5, TimeUnit.SECONDS) - if (result != null) - throw RuntimeException("Concurrent fail: ${result.message}") -} - -class InternalTest { - @Test - fun concurrentTest() = try { - concurrentTest { result -> - Thread().run { - Thread.sleep(100) - result.onError("Intentional fail") - } - } - fail("Did not throw exception") - } catch (e: Exception) { - // pass - } -} diff --git a/gradle.properties b/gradle.properties index dcdb5630..691544bc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro APP_ID=Frost APP_GROUP=com.pitchedapps -KAU=af43e82 +KAU=72d6461 KOTLIN=1.3.11 # https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google @@ -28,7 +28,7 @@ BUGSNAG=4.9.3 # https://github.com/bugsnag/bugsnag-android-gradle-plugin/releases BUGSNAG_PLUGIN=3.6.0 # https://github.com/KeepSafe/dexcount-gradle-plugin/releases -DEX_PLUGIN=0.8.4 +DEX_PLUGIN=0.8.5 # https://github.com/gladed/gradle-android-git-version/releases GIT_PLUGIN=0.4.7 # https://mvnrepository.com/artifact/org.apache.commons/commons-text @@ -59,8 +59,6 @@ OKHTTP=3.12.1 ROBOELECTRIC=4.1 # https://github.com/ReactiveX/RxAndroid/releases RX_ANDROID=2.1.0 -# https://github.com/JakeWharton/RxBinding/releases -RX_BINDING=2.2.0 # https://github.com/ReactiveX/RxJava/releases RX_JAVA=2.2.4 # https://github.com/ReactiveX/RxKotlin/releases -- cgit v1.2.3 From 765c74196042430bb2c5b1a0d522da20a4485dc4 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Fri, 4 Jan 2019 23:59:55 -0500 Subject: Remove unnecessary zip function with reactivex --- .../test/kotlin/com/pitchedapps/frost/MiscTest.kt | 48 ---------------------- 1 file changed, 48 deletions(-) delete mode 100644 app/src/test/kotlin/com/pitchedapps/frost/MiscTest.kt (limited to 'app/src/test') diff --git a/app/src/test/kotlin/com/pitchedapps/frost/MiscTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/MiscTest.kt deleted file mode 100644 index 20610b2a..00000000 --- a/app/src/test/kotlin/com/pitchedapps/frost/MiscTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018 Allan Wang - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.pitchedapps.frost - -import com.pitchedapps.frost.facebook.requests.zip -import org.junit.Test -import kotlin.test.assertTrue - -/** - * Created by Allan Wang on 2017-06-14. - */ -class MiscTest { - - /** - * Spin off 15 threads - * Pause each for 1 - 2s - * Ensure that total zipped process does not take over 5s - */ - @Test - fun zip() { - val now = System.currentTimeMillis() - val base = 1 - val data: LongArray = (0..15).map { Math.random() + base } - .toTypedArray().zip(List::toLongArray) { - Thread.sleep((it * 1000).toLong()) - System.currentTimeMillis() - now - }.blockingGet() - println(data.contentToString()) - assertTrue( - data.all { it >= base * 1000 && it < base * 1000 * 5 }, - "zip did not seem to work on different threads" - ) - } -} -- cgit v1.2.3