All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmTest.com.sksamuel.kotest.assertions.RetryTest.kt Maven / Gradle / Ivy

package com.sksamuel.kotest.assertions

import io.kotest.assertions.retry
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.longs.shouldBeGreaterThanOrEqual
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.delay
import kotlin.time.Duration.Companion.milliseconds

class RetryTest : StringSpec() {
   init {

      "should allow execution of suspend functions" {
          retry(5, 500.milliseconds, 100.milliseconds) {
              dummySuspend()
          }

          retry(5, 500.milliseconds, 20.milliseconds, 1, IllegalArgumentException::class) {
              dummySuspend()
          }
      }

      "should call given assertion when until it pass in given number of times" {
         val testClass = TestClass(4)
          retry(5, 500.milliseconds, 100.milliseconds) {
              testClass.isReady() shouldBe true
          }
      }

      "should not call given assertion beyond given number of times" {
         val testClass = TestClass(4)
         runSafely {
             retry(2, 500.milliseconds, 100.milliseconds, 1) {
                 testClass.isReady() shouldBe true
             }
         }
         testClass.times shouldBe 2
      }

      "should not call given assertion beyond given max duration" {
         val testClass = TestClass(4)
         runSafely {
             retry(5, 500.milliseconds, 400.milliseconds, 1) {
                 testClass.isReady() shouldBe true
             }
         }
         testClass.times shouldBe 2
      }

      "should call given assertion exponentially" {
         val testClass = TestClass(4)
         runSafely {
             retry(5, 500.milliseconds, 100.milliseconds, 2) {
                 testClass.isReady() shouldBe true
             }
         }
         val calledAt = testClass.calledAtTimeInstance
         val delayInFirstRetry = (calledAt[1] - calledAt[0])
         val delayInSecondRetry = calledAt[2] - calledAt[1]
         delayInFirstRetry shouldBeGreaterThanOrEqual 100
         delayInSecondRetry shouldBeGreaterThanOrEqual 200
      }

      "should not retry in case of unexpected exception" {
         val testClass = TestClass(2)
         runSafely {
             retry(5, 500.milliseconds, 20.milliseconds, 1, IllegalArgumentException::class) {
                 testClass.throwUnexpectedException()
             }
         }

         testClass.times shouldBe 1
      }
   }

   private class TestClass(private val readyAfter: Int) {
      var calledAtTimeInstance = listOf()
      var times = 0
      fun isReady(): Boolean {
         calledAtTimeInstance = calledAtTimeInstance.plus(System.currentTimeMillis())
         times += 1
         return readyAfter == times
      }

      fun throwUnexpectedException() {
         times += 1
         throw NullPointerException("")
      }
   }

   private suspend fun runSafely(block: suspend () -> Unit) {
      try {
         block()
      } catch (assertionError: AssertionError) {
         // Eating assertion error
      } catch (exception: Exception) {
         // Eating other exception
      }
   }

   private suspend fun dummySuspend() {
      delay(0)
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy