Skip to content

Commit 6a35c24

Browse files
authored
#235 Support for kotlin.time.Duration in Kotlin DSL (#285)
1 parent 925506c commit 6a35c24

2 files changed

Lines changed: 117 additions & 2 deletions

File tree

awaitility-kotlin/src/main/kotlin/org/awaitility/kotlin/AwaitilityKt.kt

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import java.time.Duration
1717
import java.util.concurrent.ExecutorService
1818
import java.util.concurrent.atomic.AtomicBoolean
1919
import kotlin.reflect.KClass
20+
import kotlin.time.toJavaDuration
2021

2122
/**
2223
* This is typically the starting point of the Kotlin "DSL". Allows you to write `await` instead of `await()`. For example:
@@ -164,6 +165,15 @@ infix fun ConditionFactory.untilAsserted(fn: () -> Unit): Unit = untilAsserted(f
164165
*/
165166
infix fun ConditionFactory.atMost(duration: Duration): ConditionFactory = atMost(duration)
166167

168+
/**
169+
* Await at most `timeout` before throwing a timeout exception.
170+
*
171+
* @param duration the duration
172+
* @return the condition factory
173+
* @since 4.2.3
174+
*/
175+
infix fun ConditionFactory.atMost(duration: kotlin.time.Duration): ConditionFactory = atMost(duration.toJavaDuration())
176+
167177
/**
168178
* Condition has to be evaluated not earlier than `timeout` before throwing a timeout exception.
169179
*
@@ -173,6 +183,15 @@ infix fun ConditionFactory.atMost(duration: Duration): ConditionFactory = atMost
173183
*/
174184
infix fun ConditionFactory.atLeast(timeout: Duration): ConditionFactory = atLeast(timeout)
175185

186+
/**
187+
* Condition has to be evaluated not earlier than `timeout` before throwing a timeout exception.
188+
*
189+
* @param timeout the timeout
190+
* @return the condition factory
191+
* @since 4.2.3
192+
*/
193+
infix fun ConditionFactory.atLeast(timeout: kotlin.time.Duration): ConditionFactory = atLeast(timeout.toJavaDuration())
194+
176195
/**
177196
* Await forever until the condition is satisfied. Caution: You can block
178197
* subsequent tests and the entire build can hang indefinitely, it's
@@ -249,6 +268,17 @@ infix fun ConditionFactory.withAlias(alias: String): ConditionFactory = alias(al
249268
*/
250269
infix fun ConditionFactory.withPollDelay(pollDelay: Duration): ConditionFactory = pollDelay(pollDelay)
251270

271+
/**
272+
* Specify the delay that will be used before Awaitility starts polling for
273+
* the result the first time. If you don't specify a poll delay explicitly
274+
* it'll be the same as the poll interval.
275+
*
276+
* @param pollDelay the poll delay
277+
* @return the condition factory
278+
* @since 4.2.3
279+
*/
280+
infix fun ConditionFactory.withPollDelay(pollDelay: kotlin.time.Duration): ConditionFactory = withPollDelay(pollDelay.toJavaDuration())
281+
252282
/**
253283
* Specify the polling interval Awaitility will use for this await
254284
* statement. This means the frequency in which the condition is checked for
@@ -261,6 +291,18 @@ infix fun ConditionFactory.withPollDelay(pollDelay: Duration): ConditionFactory
261291
*/
262292
infix fun ConditionFactory.withPollInterval(pollInterval: Duration): ConditionFactory = pollInterval(pollInterval)
263293

294+
/**
295+
* Specify the polling interval Awaitility will use for this await
296+
* statement. This means the frequency in which the condition is checked for
297+
* completion.
298+
*
299+
* @param pollInterval the poll interval
300+
* @return the condition factory
301+
* @since 4.2.3
302+
* @see [ConditionFactory.pollInterval]
303+
*/
304+
infix fun ConditionFactory.withPollInterval(pollInterval: kotlin.time.Duration): ConditionFactory = withPollInterval(pollInterval.toJavaDuration())
305+
264306
/**
265307
* Specify the polling interval Awaitility will use for this await
266308
* statement. For example [org.awaitility.pollinterval.FibonacciPollInterval.fibonacci].
@@ -371,4 +413,22 @@ infix fun <T> ConditionFactory.conditionEvaluationListener(conditionEvaluationLi
371413
* @return the condition factory
372414
* @since 4.2.1
373415
*/
374-
infix fun ConditionFactory.logging(logPrinter: (String) -> Unit) = logging(logPrinter)
416+
infix fun ConditionFactory.logging(logPrinter: (String) -> Unit) = logging(logPrinter)
417+
418+
/**
419+
* Await at the predicate holds during at least <code>timeout</code>
420+
*
421+
* @param timeout the timeout
422+
* @return the condition factory
423+
* @since 4.2.3
424+
*/
425+
infix fun ConditionFactory.during(duration: Duration): ConditionFactory = during(duration)
426+
427+
/**
428+
* Await at the predicate holds during at least <code>timeout</code>
429+
*
430+
* @param timeout the timeout
431+
* @return the condition factory
432+
* @since 4.2.3
433+
*/
434+
infix fun ConditionFactory.during(duration: kotlin.time.Duration): ConditionFactory = during(duration.toJavaDuration())

awaitility-kotlin/src/test/kotlin/org/awaitility/kotlin/KotlinTest.kt

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ import org.junit.rules.ExpectedException
3535
import java.time.Duration
3636
import java.util.concurrent.TimeUnit.MILLISECONDS
3737
import java.util.concurrent.TimeUnit.SECONDS
38+
import java.util.concurrent.atomic.AtomicInteger
39+
import java.util.concurrent.atomic.AtomicReference
40+
import kotlin.system.measureTimeMillis
41+
import kotlin.time.Duration.Companion.milliseconds
42+
import kotlin.time.Duration.Companion.seconds
3843

3944
class KotlinTest {
4045

@@ -125,7 +130,7 @@ class KotlinTest {
125130
fun untilAssertedWithConditionEvaluationListener() {
126131
var value = false
127132
Asynch(fakeRepository).perform()
128-
133+
129134
await withPollInterval ONE_HUNDRED_MILLISECONDS ignoreException IllegalArgumentException::class conditionEvaluationListener ConditionEvaluationListener<Unit> { value = true } untilAsserted {
130135
assertThat(fakeRepository.value).isEqualTo(1)
131136
}
@@ -182,6 +187,56 @@ class KotlinTest {
182187
}
183188
assertThat(data.state).isEqualTo("After")
184189
}
190+
191+
@Test
192+
fun atMostWithKotlinDuration() {
193+
await() atMost 1.seconds untilNull { null }
194+
}
195+
196+
@Test
197+
fun atLeastWithKotlinDuration() {
198+
await() atLeast 1.seconds untilNull {
199+
Thread.sleep((1.seconds + 500.milliseconds).inWholeMilliseconds)
200+
null
201+
}
202+
}
203+
204+
@Test
205+
fun withPollDelayAndWithPollIntervalWithKotlinDuration() {
206+
val ref = AtomicReference("value")
207+
208+
Thread() {
209+
Thread.sleep((1.seconds + 500.milliseconds).inWholeMilliseconds)
210+
ref.set(null)
211+
}.start()
212+
213+
val count = AtomicInteger()
214+
await() withPollDelay 1.seconds withPollInterval 100.milliseconds untilNull {
215+
count.incrementAndGet()
216+
ref.get()
217+
}
218+
// Mathematically we have 100ms in 500ms 5 times,
219+
// invocation count should be 5 times -> safe assertion interval of invocation is [4, 6] times
220+
assertThat(count).hasValueBetween(4, 6)
221+
}
222+
223+
@Test(timeout = 2000)
224+
fun awaitDuringTimeOnCondition() {
225+
val duration = measureTimeMillis {
226+
await() during ONE_SECOND until { true }
227+
}
228+
229+
assertThat(duration).isGreaterThan(1000)
230+
}
231+
232+
@Test(timeout = 2000)
233+
fun awaitDuringTimeOnConditionWithKotlinDuration() {
234+
val duration = measureTimeMillis {
235+
await() during 1.seconds until { true }
236+
}
237+
238+
assertThat(duration).isGreaterThan(1000)
239+
}
185240
}
186241

187242
class AsynchObject<T>(private val repository: FakeGenericRepository<T>, private val changeTo: T) {

0 commit comments

Comments
 (0)