diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index e38a1fcb30..052da88031 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -31,13 +31,15 @@ tasks.withType(ScalaCompile).configureEach { // Add whatever flags you typically add parameters += [ - "-unchecked", - "-Ywarn-macros:after", "-feature", - "-Ymacro-annotations", "-Xfatal-warnings", - "-Ywarn-unused", - "-Wunused:nowarn" + "-Wunused:implicits", + "-Wunused:explicits", + "-Wunused:imports", + "-Wunused:locals", + "-Wunused:params", + "-Wunused:privates", + "-Wunused:nowarn", ] // Finally set the additionalParameters @@ -68,8 +70,8 @@ dependencies { testImplementation group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.3.2' testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3' testRuntimeOnly group: 'org.pegdown', name: 'pegdown', version: '1.4.2' - testImplementation group: 'org.scala-lang', name: 'scala-library', version: '2.13.13' - testImplementation group: 'org.scalatest', name: 'scalatest_2.13', version: '3.2.15' + testImplementation group: 'org.scala-lang', name: 'scala3-library_3', version: '3.3.3' + testImplementation group: 'org.scalatest', name: 'scalatest_3', version: '3.2.18' } tasks.register('ldapserver', JavaExec) { diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/AdminApiAuthMockSuite.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/AdminApiAuthMockSuite.scala index 17e4bcc791..6497ca94d1 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/AdminApiAuthMockSuite.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/AdminApiAuthMockSuite.scala @@ -17,14 +17,15 @@ package tech.beshu.ror.integration.suites import cats.data.NonEmptyList -import eu.timepit.refined.auto._ +import eu.timepit.refined.auto.* import org.scalatest.concurrent.Eventually import org.scalatest.wordspec.AnyWordSpec import org.scalatest.{BeforeAndAfterEach, OptionValues} import tech.beshu.ror.integration.suites.base.support.BaseManyEsClustersIntegrationTest import tech.beshu.ror.integration.utils.{ESVersionSupportForAnyWordSpecLike, PluginTestSupport, SingletonLdapContainers} import tech.beshu.ror.utils.containers.SecurityType.RorWithXpackSecurity -import tech.beshu.ror.utils.containers._ +import tech.beshu.ror.utils.containers.* +import tech.beshu.ror.utils.containers.EsClusterSettings.positiveInt import tech.beshu.ror.utils.containers.dependencies.{ldap, wiremock} import tech.beshu.ror.utils.containers.images.domain.Enabled import tech.beshu.ror.utils.containers.images.ReadonlyRestWithEnabledXpackSecurityPlugin @@ -35,7 +36,7 @@ import ujson.Value.Value import java.time.{Instant, ZoneOffset} import java.time.temporal.ChronoUnit -import scala.concurrent.duration._ +import scala.concurrent.duration.* import scala.language.postfixOps class AdminApiAuthMockSuite @@ -59,7 +60,7 @@ class AdminApiAuthMockSuite def esClusterSettingsCreator(securityType: SecurityType) = EsClusterSettings.create( clusterName = "ROR1", - numberOfInstances = 2, + numberOfInstances = positiveInt(2), securityType = securityType, nodeDataInitializer = NoOpElasticsearchNodeDataInitializer, dependentServicesContainers = clusterDependencies diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/AdminApiWithDefaultRorIndexSuite.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/AdminApiWithDefaultRorIndexSuite.scala index f07358f752..c16acb7cfa 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/AdminApiWithDefaultRorIndexSuite.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/AdminApiWithDefaultRorIndexSuite.scala @@ -16,9 +16,9 @@ */ package tech.beshu.ror.integration.suites -import eu.timepit.refined.auto._ import tech.beshu.ror.integration.suites.base.BaseAdminApiSuite import tech.beshu.ror.integration.utils.PluginTestSupport +import tech.beshu.ror.utils.containers.EsClusterSettings.positiveInt import tech.beshu.ror.utils.containers.SecurityType.RorWithXpackSecurity import tech.beshu.ror.utils.containers.images.ReadonlyRestWithEnabledXpackSecurityPlugin import tech.beshu.ror.utils.containers.images.domain.Enabled @@ -35,7 +35,7 @@ class AdminApiWithDefaultRorIndexSuite def esClusterSettingsCreator(securityType: SecurityType) = EsClusterSettings.create( clusterName = "ROR1", - numberOfInstances = 2, + numberOfInstances = positiveInt(2), securityType = securityType, nodeDataInitializer = nodeDataInitializer() ) diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/ClusterApiSuite.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/ClusterApiSuite.scala index 7285617ec7..71cbc817a2 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/ClusterApiSuite.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/ClusterApiSuite.scala @@ -16,10 +16,11 @@ */ package tech.beshu.ror.integration.suites -import eu.timepit.refined.auto._ +import eu.timepit.refined.auto.* import org.scalatest.wordspec.AnyWordSpec import tech.beshu.ror.integration.suites.base.support.{BaseEsClusterIntegrationTest, SingleClientSupport} import tech.beshu.ror.integration.utils.{ESVersionSupportForAnyWordSpecLike, PluginTestSupport} +import tech.beshu.ror.utils.containers.EsClusterSettings.positiveInt import tech.beshu.ror.utils.containers.SecurityType.RorWithXpackSecurity import tech.beshu.ror.utils.containers.images.ReadonlyRestWithEnabledXpackSecurityPlugin import tech.beshu.ror.utils.containers.{ElasticsearchNodeDataInitializer, EsClusterContainer, EsClusterSettings, SecurityType} @@ -42,7 +43,7 @@ class ClusterApiSuite override lazy val clusterContainer: EsClusterContainer = { def esClusterSettingsCreator(securityType: SecurityType) = EsClusterSettings.create( clusterName = "ROR1", - numberOfInstances = 2, + numberOfInstances = positiveInt(2), securityType = securityType, nodeDataInitializer = ClusterApiSuite.nodeDataInitializer() ) diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/FipsSslSuite.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/FipsSslSuite.scala index 5469bfc50b..2126d91776 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/FipsSslSuite.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/FipsSslSuite.scala @@ -16,13 +16,13 @@ */ package tech.beshu.ror.integration.suites -import eu.timepit.refined.auto._ import org.scalatest.BeforeAndAfterAll import org.scalatest.wordspec.AnyWordSpec import tech.beshu.ror.integration.suites.base.support.{BaseEsClusterIntegrationTest, SingleClientSupport} import tech.beshu.ror.integration.utils.{ESVersionSupportForAnyWordSpecLike, PluginTestSupport} +import tech.beshu.ror.utils.containers.* +import tech.beshu.ror.utils.containers.EsClusterSettings.positiveInt import tech.beshu.ror.utils.containers.SecurityType.RorSecurity -import tech.beshu.ror.utils.containers._ import tech.beshu.ror.utils.containers.images.ReadonlyRestPlugin.Config.{Attributes, InternodeSsl, RestSsl} import tech.beshu.ror.utils.containers.images.domain.{Enabled, SourceFile} import tech.beshu.ror.utils.elasticsearch.CatManager @@ -46,7 +46,7 @@ class FipsSslSuite lazy val generalClusterContainer: EsClusterContainer = createLocalClusterContainer( EsClusterSettings.create( clusterName = "fips_cluster", - numberOfInstances = 2, + numberOfInstances = positiveInt(2), securityType = RorSecurity(Attributes.default.copy( rorConfigFileName = rorConfigFileName, restSsl = Enabled.Yes(RestSsl.RorFips(SourceFile.RorFile)), diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/IndexLifecycleManagementApiSuite.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/IndexLifecycleManagementApiSuite.scala index d557c23ef4..75a6e39bf1 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/IndexLifecycleManagementApiSuite.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/IndexLifecycleManagementApiSuite.scala @@ -16,7 +16,6 @@ */ package tech.beshu.ror.integration.suites -import eu.timepit.refined.auto._ import monix.execution.atomic.Atomic import org.scalatest.BeforeAndAfterEach import org.scalatest.concurrent.Eventually @@ -25,8 +24,9 @@ import org.scalatest.wordspec.AnyWordSpec import tech.beshu.ror.integration.suites.IndexLifecycleManagementApiSuite.{ExamplePolicies, PolicyGenerator} import tech.beshu.ror.integration.suites.base.support.{BaseEsClusterIntegrationTest, SingleClientSupport} import tech.beshu.ror.integration.utils.{ESVersionSupportForAnyWordSpecLike, PluginTestSupport} +import tech.beshu.ror.utils.containers.* +import tech.beshu.ror.utils.containers.EsClusterSettings.positiveInt import tech.beshu.ror.utils.containers.SecurityType.RorWithXpackSecurity -import tech.beshu.ror.utils.containers._ import tech.beshu.ror.utils.containers.images.ReadonlyRestWithEnabledXpackSecurityPlugin import tech.beshu.ror.utils.elasticsearch.BaseManager.JSON import tech.beshu.ror.utils.elasticsearch.{ClusterManager, DocumentManager, IndexLifecycleManager, IndexManager} @@ -54,9 +54,10 @@ class IndexLifecycleManagementApiSuite def esClusterSettingsCreator(securityType: SecurityType) = EsClusterSettings.create( clusterName = "ROR1", securityType = securityType, - numberOfInstances = 2, + numberOfInstances = positiveInt(2), nodeDataInitializer = IndexLifecycleManagementApiSuite.nodeDataInitializer() ) + createLocalClusterContainer( esClusterSettingsCreator( RorWithXpackSecurity(ReadonlyRestWithEnabledXpackSecurityPlugin.Config.Attributes.default.copy( diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/JwtAuthSuite.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/JwtAuthSuite.scala index 66826f98c9..30dd1ff668 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/JwtAuthSuite.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/JwtAuthSuite.scala @@ -23,8 +23,10 @@ import tech.beshu.ror.integration.suites.base.support.BaseSingleNodeEsClusterTes import tech.beshu.ror.integration.utils.{ESVersionSupportForAnyWordSpecLike, SingletonPluginTestSupport} import tech.beshu.ror.utils.elasticsearch.CatManager import tech.beshu.ror.utils.misc.CustomScalaTestMatchers -import tech.beshu.ror.utils.misc.JwtUtils._ -import scala.jdk.CollectionConverters._ +import tech.beshu.ror.utils.misc.JwtUtils.* + +import scala.jdk.CollectionConverters.* +import scala.language.implicitConversions //TODO change test names. Current names are copies from old java integration tests class JwtAuthSuite diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/RorStartingSuite.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/RorStartingSuite.scala index de45c84b86..a87a1f9d7d 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/RorStartingSuite.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/RorStartingSuite.scala @@ -48,15 +48,15 @@ class RorStartingSuite extends AnyWordSpec with ESVersionSupportForAnyWordSpecLi "ROR does not started yet" should { "return not started response with http code 403" when { "403 configured" in withTestEsContainerManager(Map(notStartedResponseCodeKey -> "403")) { esContainer => - testRorStartup(using = esContainer, expectedResponseCode = 403) + testRorStartup(usingManager = esContainer, expectedResponseCode = 403) } "no option configured" in withTestEsContainerManager(Map.empty) { esContainer => - testRorStartup(using = esContainer, expectedResponseCode = 403) + testRorStartup(usingManager = esContainer, expectedResponseCode = 403) } } "return not started response with http code 503" when { "503 configured" in withTestEsContainerManager(Map(notStartedResponseCodeKey -> "503")) { esContainer => - testRorStartup(using = esContainer, expectedResponseCode = 503) + testRorStartup(usingManager = esContainer, expectedResponseCode = 503) } } } @@ -80,9 +80,9 @@ class RorStartingSuite extends AnyWordSpec with ESVersionSupportForAnyWordSpecLi } } - private def testRorStartup(using: TestEsContainerManager, expectedResponseCode: Int): Task[Unit] = { + private def testRorStartup(usingManager: TestEsContainerManager, expectedResponseCode: Int): Task[Unit] = { for { - restClient <- using.createRestClient + restClient <- usingManager.createRestClient searchTestResults <- searchTest(client = restClient, searchAttemptsCount = 200) result <- handleResults(searchTestResults, expectedResponseCode) } yield result diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/base/XpackClusterWithRorNodesAndInternodeSslSuite.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/base/XpackClusterWithRorNodesAndInternodeSslSuite.scala index 2b63c4bc18..a0d8b9b054 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/base/XpackClusterWithRorNodesAndInternodeSslSuite.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/suites/base/XpackClusterWithRorNodesAndInternodeSslSuite.scala @@ -17,19 +17,18 @@ package tech.beshu.ror.integration.suites.base import cats.data.NonEmptyList -import eu.timepit.refined.auto._ import org.scalatest.BeforeAndAfterAll import org.scalatest.concurrent.Eventually import org.scalatest.wordspec.AnyWordSpec import tech.beshu.ror.integration.suites.base.support.{BaseEsClusterIntegrationTest, SingleClientSupport} import tech.beshu.ror.integration.utils.{ESVersionSupportForAnyWordSpecLike, PluginTestSupport} -import tech.beshu.ror.utils.containers.EsClusterSettings.NodeType +import tech.beshu.ror.utils.containers.* +import tech.beshu.ror.utils.containers.EsClusterSettings.{NodeType, positiveInt} import tech.beshu.ror.utils.containers.SecurityType.{RorSecurity, XPackSecurity} -import tech.beshu.ror.utils.containers._ -import tech.beshu.ror.utils.containers.images.{ReadonlyRestPlugin, XpackSecurityPlugin} import tech.beshu.ror.utils.containers.images.ReadonlyRestPlugin.Config.{InternodeSsl, RestSsl} import tech.beshu.ror.utils.containers.images.domain.{Enabled, SourceFile} -import tech.beshu.ror.utils.elasticsearch._ +import tech.beshu.ror.utils.containers.images.{ReadonlyRestPlugin, XpackSecurityPlugin} +import tech.beshu.ror.utils.elasticsearch.* import tech.beshu.ror.utils.misc.CustomScalaTestMatchers import tech.beshu.ror.utils.misc.Resources.getResourceContent @@ -57,14 +56,14 @@ trait XpackClusterWithRorNodesAndInternodeSslSuite restSsl = Enabled.Yes(RestSsl.Ror(SourceFile.RorFile)), internodeSsl = Enabled.Yes(InternodeSsl.Ror(SourceFile.RorFile)) )), - numberOfInstances = 1 + numberOfInstances = positiveInt(1) ), NodeType( securityType = XPackSecurity(XpackSecurityPlugin.Config.Attributes.default.copy( restSslEnabled = true, internodeSslEnabled = true )), - numberOfInstances = 2 + numberOfInstances = positiveInt(2) ) ) ) diff --git a/integration-tests/src/test/scala/tech/beshu/ror/integration/utils/ESVersionSupport.scala b/integration-tests/src/test/scala/tech/beshu/ror/integration/utils/ESVersionSupport.scala index 50c73447fe..1a81b6d840 100644 --- a/integration-tests/src/test/scala/tech/beshu/ror/integration/utils/ESVersionSupport.scala +++ b/integration-tests/src/test/scala/tech/beshu/ror/integration/utils/ESVersionSupport.scala @@ -34,8 +34,7 @@ trait ESVersionSupportForAnyWordSpecLike extends ESVersionSupport { string.taggedAs(firstTestTag, otherTestTags: _*) } -trait ESVersionSupportForAnyFreeSpecLike extends ESVersionSupport { - this: AnyFreeSpecLike => +trait ESVersionSupportForAnyFreeSpecLike extends ESVersionSupport with AnyFreeSpecLike { override type T = ResultOfTaggedAsInvocationOnString diff --git a/tests-utils/build.gradle b/tests-utils/build.gradle index 5391dc34f1..d15f339d88 100644 --- a/tests-utils/build.gradle +++ b/tests-utils/build.gradle @@ -31,12 +31,14 @@ tasks.withType(ScalaCompile).configureEach { // Add whatever flags you typically add parameters += [ - "-unchecked", - "-Ywarn-macros:after", "-feature", - "-Ymacro-annotations", "-Xfatal-warnings", - "-Ywarn-unused", + "-Wunused:implicits", + "-Wunused:explicits", + "-Wunused:imports", + "-Wunused:locals", + "-Wunused:params", + "-Wunused:privates", "-Wunused:nowarn" ] @@ -45,8 +47,7 @@ tasks.withType(ScalaCompile).configureEach { } dependencies { - api group: 'com.github.pathikrit', name: 'better-files_2.13', version: '3.9.2' - api group: 'com.github.cb372', name: 'cats-retry-core_2.13', version: '0.3.2' + api group: 'com.github.pathikrit', name: 'better-files_3', version: '3.9.2' api group: 'commons-io', name: 'commons-io', version: '2.6' api group: 'org.apache.commons', name: 'commons-lang3', version: '3.9' api group: 'commons-lang', name: 'commons-lang', version: '2.6' @@ -62,17 +63,17 @@ dependencies { api group: 'io.jsonwebtoken', name: 'jjwt-orgjson', version: '0.11.2' api group: 'org.jooq', name: 'joor-java-8', version: '0.9.13' api group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' - api group: 'io.monix', name: 'monix_2.13', version: '3.4.1' - api group: 'com.lihaoyi', name: 'os-lib_2.13', version: '0.9.0' - api group: 'eu.timepit', name: 'refined_2.13', version: '0.10.1' - api group: 'org.scala-lang', name: 'scala-library', version: '2.13.13' - api group: 'org.scala-lang.modules' , name: 'scala-parallel-collections_2.13', version: '1.0.4' - api group: 'com.typesafe.scala-logging', name: 'scala-logging_2.13', version: '3.9.2' - api group: 'org.scalatest', name: 'scalatest_2.13', version: '3.2.9' - api group: 'com.dimafeng', name: 'testcontainers-scala_2.13', version: '0.40.17' + api group: 'io.monix', name: 'monix_3', version: '3.4.1' + api group: 'com.lihaoyi', name: 'os-lib_3', version: '0.9.3' + api group: 'eu.timepit', name: 'refined_3', version: '0.11.1' + api group: 'org.scala-lang', name: 'scala3-library_3', version: '3.3.3' + api group: 'org.scala-lang.modules' , name: 'scala-parallel-collections_3', version: '1.0.4' + api group: 'com.typesafe.scala-logging', name: 'scala-logging_3', version: '3.9.5' + api group: 'org.scalatest', name: 'scalatest_3', version: '3.2.18' + api group: 'com.dimafeng', name: 'testcontainers-scala_3', version: '0.40.17' api group: 'org.testcontainers', name: 'testcontainers', version: "1.18.3" api group: 'eu.rekawek.toxiproxy', name: 'toxiproxy-java', version: "2.1.4" api group: 'com.unboundid', name: 'unboundid-ldapsdk', version: '6.0.11' api group: 'com.mashape.unirest', name: 'unirest-java', version: '1.4.9' - api group: 'com.lihaoyi', name: 'upickle_2.13', version: '3.1.0' + api group: 'com.lihaoyi', name: 'upickle_3', version: '3.2.0' } diff --git a/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/ElasticsearchNodeWaitingStrategy.scala b/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/ElasticsearchNodeWaitingStrategy.scala index 7266efe226..9437118f21 100644 --- a/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/ElasticsearchNodeWaitingStrategy.scala +++ b/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/ElasticsearchNodeWaitingStrategy.scala @@ -23,8 +23,6 @@ import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy import tech.beshu.ror.utils.httpclient.RestClient import tech.beshu.ror.utils.misc.{EsStartupChecker, Version} -import java.util.concurrent.TimeUnit -import scala.concurrent.duration._ import scala.util.Try class ElasticsearchNodeWaitingStrategy(esVersion: String, @@ -35,7 +33,6 @@ class ElasticsearchNodeWaitingStrategy(esVersion: String, with StrictLogging { override def waitUntilReady(): Unit = { - implicit val startupThreshold: FiniteDuration = FiniteDuration(startupTimeout.toMillis, TimeUnit.MILLISECONDS) val client = restClient.runAttempt().fold(throw _, identity) val checker = if (Version.greaterOrEqualThan(esVersion, 8, 3, 0)) { diff --git a/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/EsClusterContainer.scala b/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/EsClusterContainer.scala index 9d01ee15b8..1e018ca1ce 100644 --- a/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/EsClusterContainer.scala +++ b/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/EsClusterContainer.scala @@ -19,7 +19,6 @@ package tech.beshu.ror.utils.containers import cats.data.NonEmptyList import com.dimafeng.testcontainers.{Container, SingleContainer} import eu.timepit.refined.api.Refined -import eu.timepit.refined.auto._ import eu.timepit.refined.numeric.Positive import monix.eval.{Coeval, Task} import monix.execution.Scheduler.Implicits.global @@ -28,6 +27,8 @@ import tech.beshu.ror.utils.containers.EsClusterSettings.NodeType import tech.beshu.ror.utils.containers.images.{ReadonlyRestPlugin, ReadonlyRestWithEnabledXpackSecurityPlugin, XpackSecurityPlugin} import tech.beshu.ror.utils.elasticsearch.ClusterManager +import scala.compiletime.error + class EsClusterContainer private[containers](val esClusterSettings: EsClusterSettings, val nodeCreators: NonEmptyList[StartedClusterDependencies => EsContainer], dependencies: List[DependencyDef]) @@ -130,7 +131,7 @@ object EsClusterSettings { def create(clusterName: String, securityType: SecurityType, - numberOfInstances: Int Refined Positive = 1, + numberOfInstances: Int Refined Positive = positiveInt(1), nodeDataInitializer: ElasticsearchNodeDataInitializer = NoOpElasticsearchNodeDataInitializer, containerSpecification: ContainerSpecification = ContainerSpecification.empty, dependentServicesContainers: List[DependencyDef] = Nil, @@ -162,7 +163,11 @@ object EsClusterSettings { } final case class NodeType(securityType: SecurityType, - numberOfInstances: Int Refined Positive = 1) + numberOfInstances: Int Refined Positive = positiveInt(1)) + + inline def positiveInt(inline i: Int): Refined[Int, Positive] = { + inline if (i > 0) Refined.unsafeApply(i) else error(s"$i is not positive") + } } diff --git a/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/LdapContainer.scala b/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/LdapContainer.scala index a079896107..e7032017af 100644 --- a/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/LdapContainer.scala +++ b/tests-utils/src/main/scala/tech/beshu/ror/utils/containers/LdapContainer.scala @@ -16,6 +16,7 @@ */ package tech.beshu.ror.utils.containers +import better.files.Dispose.FlatMap.Implicits import better.files.{Disposable, Dispose, File, Resource} import com.dimafeng.testcontainers.GenericContainer import com.typesafe.scalalogging.LazyLogging @@ -26,10 +27,10 @@ import monix.execution.Scheduler.Implicits.global import org.testcontainers.containers.Network import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy import tech.beshu.ror.utils.containers.LdapContainer.{InitScriptSource, defaults} -import tech.beshu.ror.utils.misc.ScalaUtils._ +import tech.beshu.ror.utils.misc.ScalaUtils.* import java.io.{BufferedReader, InputStreamReader} -import scala.concurrent.duration._ +import scala.concurrent.duration.* import scala.language.{implicitConversions, postfixOps} class LdapContainer private[containers] (name: String, ldapInitScript: InitScriptSource) @@ -122,7 +123,8 @@ object NonStoppableLdapContainer { private class LdapWaitStrategy(name: String, ldapInitScript: InitScriptSource) extends HostPortWaitStrategy() - with LazyLogging { + with LazyLogging + with Implicits { override def waitUntilReady(): Unit = { super.waitUntilReady() diff --git a/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/AuditIndexManager.scala b/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/AuditIndexManager.scala index 980b58c7c7..da50415ef4 100644 --- a/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/AuditIndexManager.scala +++ b/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/AuditIndexManager.scala @@ -26,8 +26,8 @@ class AuditIndexManager(restClient: RestClient, indexName: String) extends BaseManager(restClient, esVersion, esNativeApi = true) { - lazy val searchManager = new SearchManager(restClient, esVersion) - lazy val indexManager = new IndexManager(restClient, esVersion) + final lazy val searchManager = new SearchManager(restClient, esVersion) + final lazy val indexManager = new IndexManager(restClient, esVersion) def getEntries: AuditEntriesResult = { val result = searchManager.eventually(searchManager.search(indexName))( diff --git a/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/RorApiManager.scala b/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/RorApiManager.scala index de5ddde613..8ea94206f9 100644 --- a/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/RorApiManager.scala +++ b/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/RorApiManager.scala @@ -32,7 +32,7 @@ class RorApiManager(client: RestClient, override val additionalHeaders: Map[String, String] = Map.empty) extends BaseManager(client, esVersion, esNativeApi = false) { - lazy val documentManager = new DocumentManager(client, esVersion) + final lazy val documentManager = new DocumentManager(client, esVersion) def fetchMetadata(preferredGroupId: Option[String] = None, correlationId: Option[String] = None): RorApiJsonResponse = { diff --git a/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/SearchManager.scala b/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/SearchManager.scala index 0f9eb6a31b..573c01b15a 100644 --- a/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/SearchManager.scala +++ b/tests-utils/src/main/scala/tech/beshu/ror/utils/elasticsearch/SearchManager.scala @@ -20,14 +20,13 @@ import org.apache.http.HttpResponse import org.apache.http.client.methods.{HttpGet, HttpPost} import org.apache.http.entity.StringEntity import tech.beshu.ror.utils.elasticsearch.BaseManager.JSON +import tech.beshu.ror.utils.elasticsearch.SearchManager.* import tech.beshu.ror.utils.httpclient.{HttpGetWithEntity, RestClient} import tech.beshu.ror.utils.misc.Version import ujson.Value -import scala.annotation.nowarn import scala.concurrent.duration.FiniteDuration import scala.util.Try -import SearchManager._ class SearchManager(client: RestClient, esVersion: String, @@ -110,7 +109,7 @@ class SearchManager(client: RestClient, request } - private def createSearchRequest(@nowarn("cat=unused") indexNames: List[String] = Nil, + private def createSearchRequest(indexNames: List[String] = Nil, customSize: Option[Int] = None, scroll: Option[FiniteDuration] = None) = { val queryParams = Map( diff --git a/tests-utils/src/main/scala/tech/beshu/ror/utils/misc/EsStartupChecker.scala b/tests-utils/src/main/scala/tech/beshu/ror/utils/misc/EsStartupChecker.scala index 513eb984a5..86fe2b3787 100644 --- a/tests-utils/src/main/scala/tech/beshu/ror/utils/misc/EsStartupChecker.scala +++ b/tests-utils/src/main/scala/tech/beshu/ror/utils/misc/EsStartupChecker.scala @@ -16,82 +16,89 @@ */ package tech.beshu.ror.utils.misc -import cats.Id -import cats.implicits._ +import cats.effect.Resource +import cats.implicits.* import com.typesafe.scalalogging.LazyLogging +import monix.eval.Task +import monix.execution.Scheduler.Implicits.global import org.apache.http.client.methods.HttpGet -import retry.RetryPolicies.{constantDelay, limitRetriesByCumulativeDelay} -import retry.{RetryDetails, RetryPolicy, retrying} import tech.beshu.ror.utils.httpclient.HttpResponseHelper.deserializeJsonBody import tech.beshu.ror.utils.httpclient.RestClient -import tech.beshu.ror.utils.misc.EsStartupChecker.Mode -import tech.beshu.ror.utils.misc.ScalaUtils._ +import tech.beshu.ror.utils.misc.EsStartupChecker.{ClusterNotReady, Mode} -import scala.annotation.nowarn -import scala.concurrent.duration._ +import scala.concurrent.duration.* import scala.language.postfixOps -import scala.util.Try class EsStartupChecker private(name: String, client: RestClient, mode: Mode) - (implicit val startupTimeout: FiniteDuration) extends LazyLogging { def waitForStart(): Boolean = { - retry { - checkClusterHealth(client).fold( - throwable => { - logger.debug(s"[$name] Cannot check ES health: ${throwable.getLocalizedMessage}") - false - }, - identity - ) - } + retryBackoff(clusterIsReady(client), maxRetries = 30, interval = 2 seconds) + .map((_: Unit) => true) + .onErrorRecover(_ => false) + .runSyncUnsafe(2 minutes) } - private def retry(checkClusterHealthAction: => Boolean) - (implicit startupThreshold: FiniteDuration) = { - val policy: RetryPolicy[Id] = limitRetriesByCumulativeDelay(startupThreshold, constantDelay(2 seconds)) - val predicate = (_: Boolean) == true - - @nowarn("cat=unused") - def onFailure(failedValue: Boolean, details: RetryDetails): Unit = { - logger.debug(s"[$name] ES not ready yet. Retrying ...") - } - - retrying(policy, predicate, onFailure) { - checkClusterHealthAction + private def retryBackoff[A](source: Task[A], + maxRetries: Int, + interval: FiniteDuration): Task[A] = { + source.onErrorHandleWith { + case ex: Exception => + if (maxRetries > 0) + retryBackoff(source, maxRetries - 1, interval).delayExecution(interval) + else + Task.raiseError(ex) } } - private def checkClusterHealth(client: RestClient) = { - val clusterHealthRequest = new HttpGet(client.from("_cluster/health")) - Try(client.execute(clusterHealthRequest)).bracket { response => - response.getStatusLine.getStatusCode match { - case 200 => - mode match { - case Mode.GreenCluster => - val healthJson = deserializeJsonBody(RestClient.bodyFrom(response)) - "green" == healthJson.get("status") - case Mode.Accessible => - true + private def clusterIsReady(client: RestClient): Task[Unit] = { + Resource + .make( + Task + .delay(client.execute(new HttpGet(client.from("_cluster/health")))) + .recoverWith { ex => + logger.error(s"[$name] ES not ready yet, healthcheck failed") + Task.raiseError(ex) } - case _ => - false + )( + response => Task.delay(response.close()) + ) + .use { response => + response.getStatusLine.getStatusCode match { + case 200 => + mode match { + case Mode.GreenCluster => + val healthJson = deserializeJsonBody(RestClient.bodyFrom(response)) + val healthStatus = healthJson.get("status") + if (healthStatus == "green") { + logger.info(s"[$name] ES is ready") + Task.unit + } else { + logger.info(s"[$name] ES not ready yet, health status is $healthStatus") + Task.raiseError(ClusterNotReady) + } + case Mode.Accessible => + logger.info(s"[$name] ES is ready") + Task.unit + } + case otherStatus => + logger.info(s"[$name] ES not ready yet, received HTTP $otherStatus") + Task.raiseError(ClusterNotReady) + } } - } } } object EsStartupChecker { - def greenEsClusterChecker(name: String, client: RestClient) - (implicit startupTimeout: FiniteDuration): EsStartupChecker = + private case object ClusterNotReady extends Exception + + def greenEsClusterChecker(name: String, client: RestClient): EsStartupChecker = new EsStartupChecker(name, client, Mode.GreenCluster) - def accessibleEsChecker(name: String, client: RestClient) - (implicit startupTimeout: FiniteDuration): EsStartupChecker = + def accessibleEsChecker(name: String, client: RestClient): EsStartupChecker = new EsStartupChecker(name, client, Mode.Accessible) private sealed trait Mode diff --git a/tests-utils/src/main/scala/tech/beshu/ror/utils/misc/JwtUtils.scala b/tests-utils/src/main/scala/tech/beshu/ror/utils/misc/JwtUtils.scala index 77bb8dcf88..31e2c9358c 100644 --- a/tests-utils/src/main/scala/tech/beshu/ror/utils/misc/JwtUtils.scala +++ b/tests-utils/src/main/scala/tech/beshu/ror/utils/misc/JwtUtils.scala @@ -23,7 +23,7 @@ import io.jsonwebtoken.security.Keys import io.jsonwebtoken.{Jwts, SignatureAlgorithm} import tech.beshu.ror.utils.misc.JwtUtils.Jwt.Secret -import scala.jdk.CollectionConverters._ +import scala.jdk.CollectionConverters.* import scala.language.implicitConversions object JwtUtils { @@ -105,4 +105,6 @@ object JwtUtils { } implicit def string2ClaimKey(value: String): ClaimKey = ClaimKey(value) + + private implicit def a2B[A, B](value: A)(implicit f: A => B): B = f(value) }