diff --git a/client/src/it/scala/skuber/CustomResourceSpec.scala b/client/src/it/scala/skuber/CustomResourceSpec.scala index d6ed0c74..c46584c1 100644 --- a/client/src/it/scala/skuber/CustomResourceSpec.scala +++ b/client/src/it/scala/skuber/CustomResourceSpec.scala @@ -41,7 +41,7 @@ import org.scalatest.matchers.should.Matchers * CustomResourceSpec tests are supported for k8s versions: 1.19,1.20,1.21 */ -class CustomResourceSpec extends K8SFixture with Eventually with Matchers with Futures with BeforeAndAfterAll with ScalaFutures { +class CustomResourceSpec extends K8SFixture with Eventually with Matchers with Futures with BeforeAndAfterAll with ScalaFutures with TestRetry { // Tagging the tests in order to exclude them in later CI k8s versions (1.22, 1.23, etc) object CustomResourceTag extends Tag("CustomResourceTag") diff --git a/client/src/it/scala/skuber/CustomResourceV1Spec.scala b/client/src/it/scala/skuber/CustomResourceV1Spec.scala index d30b6f4a..1803f451 100644 --- a/client/src/it/scala/skuber/CustomResourceV1Spec.scala +++ b/client/src/it/scala/skuber/CustomResourceV1Spec.scala @@ -33,7 +33,7 @@ import scala.concurrent.duration._ * * @author David O'Riordan */ -class CustomResourceV1Spec extends K8SFixture with Eventually with Matchers with ScalaFutures with BeforeAndAfterAll { +class CustomResourceV1Spec extends K8SFixture with Eventually with Matchers with ScalaFutures with BeforeAndAfterAll with TestRetry { // Convenient aliases for the custom object and list resource types to be passed to the skuber API methods type TestResource = CustomResource[TestResource.Spec, TestResource.Status] diff --git a/client/src/it/scala/skuber/DeploymentSpec.scala b/client/src/it/scala/skuber/DeploymentSpec.scala index 956ae0dd..96a67df8 100644 --- a/client/src/it/scala/skuber/DeploymentSpec.scala +++ b/client/src/it/scala/skuber/DeploymentSpec.scala @@ -14,7 +14,7 @@ import scala.language.postfixOps import scala.util.Try -class DeploymentSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures { +class DeploymentSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures with TestRetry { val deploymentName1: String = randomUUID().toString diff --git a/client/src/it/scala/skuber/DynamicKubernetesClientImplTest.scala b/client/src/it/scala/skuber/DynamicKubernetesClientImplTest.scala index 78afca22..0ba218e6 100644 --- a/client/src/it/scala/skuber/DynamicKubernetesClientImplTest.scala +++ b/client/src/it/scala/skuber/DynamicKubernetesClientImplTest.scala @@ -11,7 +11,7 @@ import skuber.apps.v1.Deployment import scala.concurrent.Future import scala.concurrent.duration._ -class DynamicKubernetesClientImplTest extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures { +class DynamicKubernetesClientImplTest extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures with TestRetry { val deploymentName1: String = randomUUID().toString val deploymentName2: String = randomUUID().toString diff --git a/client/src/it/scala/skuber/ExecSpec.scala b/client/src/it/scala/skuber/ExecSpec.scala index 4ef9eb4e..e8e46616 100644 --- a/client/src/it/scala/skuber/ExecSpec.scala +++ b/client/src/it/scala/skuber/ExecSpec.scala @@ -12,7 +12,7 @@ import scala.concurrent.duration.{Duration, _} import scala.concurrent.{Future, Promise} -class ExecSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures { +class ExecSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures with TestRetry { def getPodName: String = randomUUID().toString val namespace1: String = randomUUID().toString override implicit val patienceConfig: PatienceConfig = PatienceConfig(10.second) diff --git a/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Beta1Spec.scala b/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Beta1Spec.scala index ce6c2e82..0f8a9e48 100644 --- a/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Beta1Spec.scala +++ b/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Beta1Spec.scala @@ -11,7 +11,7 @@ import scala.concurrent.Future import scala.concurrent.duration._ import skuber.FutureUtil.FutureOps -class HorizontalPodAutoscalerV2Beta1Spec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures { +class HorizontalPodAutoscalerV2Beta1Spec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures with TestRetry { val horizontalPodAutoscaler1: String = randomUUID().toString val horizontalPodAutoscaler2: String = randomUUID().toString diff --git a/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Spec.scala b/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Spec.scala index 9ae72885..b6c27fea 100644 --- a/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Spec.scala +++ b/client/src/it/scala/skuber/HorizontalPodAutoscalerV2Spec.scala @@ -12,7 +12,7 @@ import java.util.UUID.randomUUID import scala.concurrent.Future import scala.concurrent.duration._ -class HorizontalPodAutoscalerV2Spec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures { +class HorizontalPodAutoscalerV2Spec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures with TestRetry { // Tagging the tests in order to exclude them in earlier CI k8s versions (before 1.23) object HorizontalPodAutoscalerV2Tag extends Tag("HorizontalPodAutoscalerV2Tag") diff --git a/client/src/it/scala/skuber/NamespaceSpec.scala b/client/src/it/scala/skuber/NamespaceSpec.scala index 280b402a..d06d4e85 100644 --- a/client/src/it/scala/skuber/NamespaceSpec.scala +++ b/client/src/it/scala/skuber/NamespaceSpec.scala @@ -12,7 +12,7 @@ import scala.concurrent.duration._ /** * @author David O'Riordan */ -class NamespaceSpec extends K8SFixture with Eventually with Matchers with ScalaFutures with BeforeAndAfterAll { +class NamespaceSpec extends K8SFixture with Eventually with Matchers with ScalaFutures with BeforeAndAfterAll with TestRetry { def nginxPodName1: String = randomUUID().toString diff --git a/client/src/it/scala/skuber/PatchSpec.scala b/client/src/it/scala/skuber/PatchSpec.scala index 21d6fbc1..36bfe6fd 100644 --- a/client/src/it/scala/skuber/PatchSpec.scala +++ b/client/src/it/scala/skuber/PatchSpec.scala @@ -11,7 +11,7 @@ import scala.concurrent.Future import scala.concurrent.duration._ -class PatchSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures { +class PatchSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures with TestRetry { val pod1: String = randomUUID().toString val pod2: String = randomUUID().toString diff --git a/client/src/it/scala/skuber/PodDisruptionBudgetSpec.scala b/client/src/it/scala/skuber/PodDisruptionBudgetSpec.scala index 78d96fd0..00d361d3 100644 --- a/client/src/it/scala/skuber/PodDisruptionBudgetSpec.scala +++ b/client/src/it/scala/skuber/PodDisruptionBudgetSpec.scala @@ -12,7 +12,7 @@ import skuber.policy.v1beta1.PodDisruptionBudget._ import scala.concurrent.Future import scala.concurrent.duration._ -class PodDisruptionBudgetSpec extends K8SFixture with Matchers with BeforeAndAfterAll with ScalaFutures with Eventually { +class PodDisruptionBudgetSpec extends K8SFixture with Matchers with BeforeAndAfterAll with ScalaFutures with Eventually with TestRetry { behavior of "PodDisruptionBudget" val budget1: String = randomUUID().toString val budget2: String = randomUUID().toString diff --git a/client/src/it/scala/skuber/PodLogSpec.scala b/client/src/it/scala/skuber/PodLogSpec.scala index f47195f8..642758c5 100644 --- a/client/src/it/scala/skuber/PodLogSpec.scala +++ b/client/src/it/scala/skuber/PodLogSpec.scala @@ -10,7 +10,7 @@ import skuber.Pod.LogQueryParams import skuber.json.format._ import scala.concurrent.duration._ -class PodLogSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures { +class PodLogSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures with TestRetry { val podName: String = randomUUID().toString override implicit val patienceConfig: PatienceConfig = PatienceConfig(10.second) diff --git a/client/src/it/scala/skuber/PodSpec.scala b/client/src/it/scala/skuber/PodSpec.scala index d5318cd6..2b5bbbea 100644 --- a/client/src/it/scala/skuber/PodSpec.scala +++ b/client/src/it/scala/skuber/PodSpec.scala @@ -8,7 +8,7 @@ import scala.concurrent.duration._ import java.util.UUID.randomUUID import skuber.FutureUtil.FutureOps -class PodSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures { +class PodSpec extends K8SFixture with Eventually with Matchers with BeforeAndAfterAll with ScalaFutures with TestRetry { val defaultLabels = Map("PodSpec" -> this.suiteName) override implicit val patienceConfig: PatienceConfig = PatienceConfig(10.second) diff --git a/client/src/it/scala/skuber/ServiceAccountSpec.scala b/client/src/it/scala/skuber/ServiceAccountSpec.scala index 8f51a543..19d156ab 100644 --- a/client/src/it/scala/skuber/ServiceAccountSpec.scala +++ b/client/src/it/scala/skuber/ServiceAccountSpec.scala @@ -12,7 +12,7 @@ import scala.util.Random import LabelSelector.dsl._ import skuber.LabelSelector.IsEqualRequirement -class ServiceAccountSpec extends K8SFixture with Eventually with BeforeAndAfterAll with ScalaFutures with Matchers { +class ServiceAccountSpec extends K8SFixture with Eventually with BeforeAndAfterAll with ScalaFutures with Matchers with TestRetry { override implicit val patienceConfig: PatienceConfig = PatienceConfig(10.second) diff --git a/client/src/it/scala/skuber/ServiceSpec.scala b/client/src/it/scala/skuber/ServiceSpec.scala index 2b7d8cd4..525dd61a 100644 --- a/client/src/it/scala/skuber/ServiceSpec.scala +++ b/client/src/it/scala/skuber/ServiceSpec.scala @@ -12,7 +12,7 @@ import scala.util.Random import LabelSelector.dsl._ import skuber.LabelSelector.IsEqualRequirement -class ServiceSpec extends K8SFixture with Eventually with BeforeAndAfterAll with ScalaFutures with Matchers { +class ServiceSpec extends K8SFixture with Eventually with BeforeAndAfterAll with ScalaFutures with Matchers with TestRetry { override implicit val patienceConfig: PatienceConfig = PatienceConfig(10.second) diff --git a/client/src/it/scala/skuber/TestRetry.scala b/client/src/it/scala/skuber/TestRetry.scala new file mode 100644 index 00000000..fbff69ed --- /dev/null +++ b/client/src/it/scala/skuber/TestRetry.scala @@ -0,0 +1,22 @@ +package skuber + +import org.scalatest.{Canceled, Failed, Outcome, TestSuite} +import scala.annotation.tailrec + +trait TestRetry extends TestSuite { + + //override retries to modify the number of retries + val retries = 3 + override def withFixture(test: NoArgTest): Outcome = { + retry(test, retries) + } + + @tailrec + private def retry(test: NoArgTest, count: Int): Outcome = { + val outcome = super.withFixture(test) + outcome match { + case Failed(_) | Canceled(_) => if (count == 1) super.withFixture(test) else retry(test, count - 1) + case other => other + } + } +} diff --git a/client/src/it/scala/skuber/WatchContinuouslySpec.scala b/client/src/it/scala/skuber/WatchContinuouslySpec.scala index b866e04c..d4dc86d3 100644 --- a/client/src/it/scala/skuber/WatchContinuouslySpec.scala +++ b/client/src/it/scala/skuber/WatchContinuouslySpec.scala @@ -13,7 +13,7 @@ import scala.concurrent.Future import scala.concurrent.duration._ import scala.language.postfixOps -class WatchContinuouslySpec extends K8SFixture with Eventually with Matchers with ScalaFutures with BeforeAndAfterAll { +class WatchContinuouslySpec extends K8SFixture with Eventually with Matchers with ScalaFutures with BeforeAndAfterAll with TestRetry { implicit val defaultPatience: PatienceConfig = PatienceConfig(timeout = Span(200, Seconds), interval = Span(5, Seconds)) behavior of "WatchContinuously"