mirror of
https://github.com/InsanusMokrassar/krontab.git
synced 2024-11-26 20:18:54 +00:00
Merge branch '0.2.1' of InsanusMokrassar/krontab into master
This commit is contained in:
commit
394522db6b
@ -6,3 +6,7 @@
|
|||||||
* Updates in libraries:
|
* Updates in libraries:
|
||||||
* Coroutines `1.3.2` -> `1.3.3`
|
* Coroutines `1.3.2` -> `1.3.3`
|
||||||
* Klock `1.7.3` -> `1.8.6`
|
* Klock `1.7.3` -> `1.8.6`
|
||||||
|
|
||||||
|
## 0.2.1
|
||||||
|
|
||||||
|
* Added support of flows: now any `KronScheduler` can be convert to `Flow<DateTime>` using `asFlow` extension
|
||||||
|
26
README.md
26
README.md
@ -11,6 +11,7 @@ runtime of applications.
|
|||||||
| [ How to use: Including in project ](#including-in-project) |
|
| [ How to use: Including in project ](#including-in-project) |
|
||||||
| [ How to use: Config from string ](#config-from-string) |
|
| [ How to use: Config from string ](#config-from-string) |
|
||||||
| [ How to use: Config via builder (DSL preview) ](#config-via-builder) |
|
| [ How to use: Config via builder (DSL preview) ](#config-via-builder) |
|
||||||
|
| [ How to use: KronScheduler as a Flow ](#KronScheduler-as-a-Flow) |
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
@ -124,3 +125,28 @@ kronScheduler.doInfinity {
|
|||||||
```
|
```
|
||||||
|
|
||||||
All of these examples will do the same things: print `Called` message every five seconds.
|
All of these examples will do the same things: print `Called` message every five seconds.
|
||||||
|
|
||||||
|
### KronScheduler as a Flow
|
||||||
|
|
||||||
|
Any `KronScheduler`can e converted to a `Flow<DateTime` using extension `asFlow`:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val kronScheduler = buildSchedule {
|
||||||
|
seconds {
|
||||||
|
0 every 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val flow = kronScheduler.asFlow()
|
||||||
|
```
|
||||||
|
|
||||||
|
So, in this case any operations related to flow are available and it is expected tt th will work correctly. For example,
|
||||||
|
it is possible to use this flow with `takeWhile`:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
flow.takeWhile {
|
||||||
|
condition()
|
||||||
|
}.collect {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -17,7 +17,7 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
|
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
project.version = "0.2.0"
|
project.version = "0.2.1"
|
||||||
project.group = "com.insanusmokrassar"
|
project.group = "com.insanusmokrassar"
|
||||||
|
|
||||||
apply from: "publish.gradle"
|
apply from: "publish.gradle"
|
||||||
@ -47,6 +47,7 @@ kotlin {
|
|||||||
implementation kotlin('test-common')
|
implementation kotlin('test-common')
|
||||||
implementation kotlin('test-annotations-common')
|
implementation kotlin('test-annotations-common')
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_coroutines_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jvmMain {
|
jvmMain {
|
||||||
|
@ -2,9 +2,30 @@ apply plugin: 'com.jfrog.bintray'
|
|||||||
|
|
||||||
apply from: "maven.publish.gradle"
|
apply from: "maven.publish.gradle"
|
||||||
|
|
||||||
|
ext {
|
||||||
|
projectBintrayDir = "${project.group}/".replace(".", "/") + "${project.name}/${project.version}"
|
||||||
|
}
|
||||||
|
|
||||||
bintray {
|
bintray {
|
||||||
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
|
||||||
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
|
||||||
|
filesSpec {
|
||||||
|
from "${buildDir}/publications/"
|
||||||
|
eachFile {
|
||||||
|
if (it.getName() == "module.json") {
|
||||||
|
File file = it.getFile()
|
||||||
|
String directorySubname = file.parentFile.name
|
||||||
|
if (directorySubname == "kotlinMultiplatform") {
|
||||||
|
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
|
||||||
|
} else {
|
||||||
|
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
it.exclude()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
into "${project.group}".replace(".", "/")
|
||||||
|
}
|
||||||
pkg {
|
pkg {
|
||||||
repo = "InsanusMokrassar"
|
repo = "InsanusMokrassar"
|
||||||
name = "${project.name}"
|
name = "${project.name}"
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.insanusmokrassar.krontab.utils
|
||||||
|
|
||||||
|
import com.insanusmokrassar.krontab.KronScheduler
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
|
@FlowPreview
|
||||||
|
fun KronScheduler.asFlow(): Flow<DateTime> = SchedulerFlow(this)
|
||||||
|
|
||||||
|
@FlowPreview
|
||||||
|
class SchedulerFlow(
|
||||||
|
private val scheduler: KronScheduler
|
||||||
|
) : AbstractFlow<DateTime>() {
|
||||||
|
@FlowPreview
|
||||||
|
override suspend fun collectSafely(collector: FlowCollector<DateTime>) {
|
||||||
|
while (true) {
|
||||||
|
val now = DateTime.now()
|
||||||
|
val nextTime = scheduler.next(now)
|
||||||
|
val sleepDelay = (nextTime - now).millisecondsLong
|
||||||
|
delay(sleepDelay)
|
||||||
|
collector.emit(nextTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.insanusmokrassar.krontab.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
fun CoroutineScope.createFailJob(forTimeMillis: Long) = launch {
|
||||||
|
delay(forTimeMillis)
|
||||||
|
throw IllegalStateException("This job must be completed at before this exception happen")
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.insanusmokrassar.krontab.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Workaround to use suspending functions in unit tests
|
||||||
|
*/
|
||||||
|
expect fun runTest(block: suspend (scope : CoroutineScope) -> Unit)
|
@ -0,0 +1,69 @@
|
|||||||
|
package com.insanusmokrassar.krontab.utils
|
||||||
|
|
||||||
|
import com.insanusmokrassar.krontab.builder.buildSchedule
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.flow.takeWhile
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
@FlowPreview
|
||||||
|
class SchedulerFlowTests {
|
||||||
|
@Test
|
||||||
|
fun testThatFlowIsCorrectlyWorkEverySecond() {
|
||||||
|
val kronScheduler = buildSchedule {
|
||||||
|
seconds {
|
||||||
|
0 every 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val flow = kronScheduler.asFlow()
|
||||||
|
|
||||||
|
runTest {
|
||||||
|
val mustBeCollected = 10
|
||||||
|
var collected = 0
|
||||||
|
flow.takeWhile {
|
||||||
|
collected < mustBeCollected
|
||||||
|
}.collect {
|
||||||
|
collected++
|
||||||
|
}
|
||||||
|
assertEquals(mustBeCollected, collected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testThatFlowIsCorrectlyWorkEverySecondWithMuchOfEmitters() {
|
||||||
|
val kronScheduler = buildSchedule {
|
||||||
|
seconds {
|
||||||
|
0 every 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val flow = kronScheduler.asFlow()
|
||||||
|
|
||||||
|
runTest {
|
||||||
|
val testsCount = 10
|
||||||
|
val failJob = it.createFailJob((testsCount * 2) * 1000L)
|
||||||
|
val mustBeCollected = 10
|
||||||
|
val answers = (0 until testsCount).map { _ ->
|
||||||
|
it.async {
|
||||||
|
var collected = 0
|
||||||
|
flow.takeWhile {
|
||||||
|
collected < mustBeCollected
|
||||||
|
}.collect {
|
||||||
|
collected++
|
||||||
|
}
|
||||||
|
collected
|
||||||
|
}
|
||||||
|
}.awaitAll()
|
||||||
|
|
||||||
|
failJob.cancel()
|
||||||
|
|
||||||
|
answers.forEach {
|
||||||
|
assertEquals(mustBeCollected, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.insanusmokrassar.krontab.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
actual fun runTest(block: suspend (scope : CoroutineScope) -> Unit): dynamic = GlobalScope.promise { block(this) }
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.insanusmokrassar.krontab.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Workaround to use suspending functions in unit tests
|
||||||
|
*/
|
||||||
|
actual fun runTest(block: suspend (scope: CoroutineScope) -> Unit) = runBlocking(block = block)
|
Loading…
Reference in New Issue
Block a user