Skip to content

Commit 4ea2356

Browse files
committed
Add scala 3 support
Done by using the `sbt-scala3-migrate` plugin, following https://docs.scala-lang.org/scala3/guides/migration/scala3-migrate.html Also replaced usage of scala.reflect with izumi-reflect (in `NewMockitoSugar`). Some scalatest eventually changes (`Position` removed) needed an adjustment, and `scala-collection-compat` needed manual adjustments (replacing usage of `scala.collection.JavaConverters` with `scala.jdk.CollectionConverters`). The `FastestServerLBSpec` is changed to prevent `java.lang.VerifyError: Bad type on operand stack`. Closes #105
1 parent deea22a commit 4ea2356

25 files changed

+68
-66
lines changed

build.sbt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ scmInfo := Some(ScmInfo(url("https://github.com/inoio/solrs"), "[email protected]:i
1212

1313
licenses := Seq("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.html"))
1414

15-
scalaVersion := "2.12.17"
15+
scalaVersion := "3.2.1"
1616

1717
// Remember: also update scala versions in .travis.yml!
18-
crossScalaVersions := Seq("2.12.17", "2.13.10")
18+
crossScalaVersions := Seq("2.12.17", "2.13.10", "3.2.1")
1919

2020
scalacOptions ++= Seq(
2121
"-unchecked",
@@ -56,10 +56,16 @@ libraryDependencies ++= Seq(
5656
"org.scalatestplus" %% "junit-4-13" % "3.2.14.0" % "test",
5757
"com.github.sbt" % "junit-interface" % "0.13.3" % Test,
5858
"org.hamcrest" % "hamcrest-library" % "2.2" % "test",
59+
"dev.zio" %% "izumi-reflect" % "2.2.3" % Test,
5960
"org.apache.solr" % "solr-test-framework" % solrVersion % "test" excludeAll(ExclusionRule(organization = "org.apache.logging.log4j")),
6061
"com.twitter" %% "util-core" % "22.12.0" % "optional"
6162
)
6263

64+
excludeDependencies ++= (
65+
if (scalaVersion.value.startsWith("2.12")) Seq()
66+
else Seq("org.scala-lang.modules" %% "scala-collection-compat")
67+
)
68+
6369
// Fork tests so that SolrRunner's shutdown hook kicks in
6470
Test / fork := true
6571
enablePlugins(ParadoxSitePlugin)

src/main/paradox/resources/HelloScala.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
77

88
class HelloScala extends App {
99

10-
val solr = AsyncSolrClient("http://localhost:8983/solr/collection1")
10+
val solr: AsyncSolrClient[Future] = AsyncSolrClient("http://localhost:8983/solr/collection1")
1111
val response: Future[QueryResponse] = solr.query(new SolrQuery("scala"))
1212
response.foreach {
1313
qr => println(s"found ${qr.getResults.getNumFound} docs")

src/main/paradox/resources/HelloTwitter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import com.twitter.util.Future
66

77
class HelloTwitter extends App {
88

9-
val solr = AsyncSolrClient("http://localhost:8983/solr")
9+
val solr: AsyncSolrClient[Future] = AsyncSolrClient("http://localhost:8983/solr")
1010
val response: Future[QueryResponse] = solr.query(new SolrQuery("scala"))
1111
response.onSuccess {
1212
qr => println(s"found ${qr.getResults.getNumFound} docs")

src/main/scala/io/ino/solrs/AsyncSolrClient.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import org.asynchttpclient.Response
5151
import org.slf4j.LoggerFactory
5252

5353
import scala.concurrent.duration._
54-
import scala.collection.JavaConverters._
54+
import scala.jdk.CollectionConverters._
5555
import scala.util.Failure
5656
import scala.util.Success
5757
import scala.util.control.NonFatal

src/main/scala/io/ino/solrs/JavaAsyncSolrClient.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import org.apache.solr.common.SolrDocumentList
2121
import org.apache.solr.common.SolrInputDocument
2222
import org.asynchttpclient.AsyncHttpClient
2323

24-
import scala.collection.JavaConverters._
24+
import scala.jdk.CollectionConverters._
2525
import scala.compat.java8.FunctionConverters._
2626
import scala.compat.java8.OptionConverters._
2727

src/main/scala/io/ino/solrs/LoadBalancer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ object RoundRobinLB {
102102
def apply(baseUrls: IndexedSeq[String]): RoundRobinLB = new RoundRobinLB(StaticSolrServers(baseUrls))
103103

104104
/* Java API */
105-
import scala.collection.JavaConverters._
105+
import scala.jdk.CollectionConverters._
106106
def create(baseUrls: java.lang.Iterable[String]): RoundRobinLB = apply(baseUrls.asScala.toIndexedSeq)
107107
}
108108

@@ -502,7 +502,7 @@ import java.lang.management.ManagementFactory
502502
import javax.management.ObjectName
503503
import javax.management.openmbean._
504504

505-
import scala.collection.JavaConverters._
505+
import scala.jdk.CollectionConverters._
506506

507507
/**
508508
* JMX support for FastestServerLB, implementation of FastestServerLBMBean, to be mixed into FastestServerLB.

src/main/scala/io/ino/solrs/PerformanceStats.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class PerformanceStats(val solrServer: SolrServer, initialPredictedResponseTime:
8888
// those requests will no longer be available for prediction
8989
currentRequests.values.foreach { requests =>
9090
if(requests.size() > currentRequestsSizeCheckLimit) {
91-
import scala.collection.JavaConverters._
91+
import scala.jdk.CollectionConverters._
9292
val requestsToRemove = requests.asScala.filter(_.startedAtMillis > currentRequestsRemoveThreshold)
9393
logger.warn(s"Current requests exceed limit $currentRequestsSizeCheckLimit, removing ${requestsToRemove.size} requests for cleanup.")
9494
requestsToRemove.foreach(entry => requests.remove(entry))
@@ -145,7 +145,7 @@ class PerformanceStats(val solrServer: SolrServer, initialPredictedResponseTime:
145145
def dumpStats(queryClass: QueryClass): Unit = {
146146
val sb = new StringBuilder()
147147
sb.append(s"====== stats for [${solrServer.baseUrl}][queryClass $queryClass] at ${clock.millis()} millis ======")
148-
import scala.collection.JavaConverters._
148+
import scala.jdk.CollectionConverters._
149149
currentRequests(queryClass).asScala.foreach(req => sb.append(s"\n[currentRequest] $req"))
150150
buckets.foreach { case (sec, bucket) =>
151151
bucket.averageDuration(queryClass).foreach(duration => sb.append(s"\n[bucket(sec $sec)] $duration"))

src/main/scala/io/ino/solrs/RetryPolicy.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ case class RetryServer(server: SolrServer) extends RetryDecision {
3636

3737
object RetryDecision {
3838

39-
final val Fail = StandardRetryDecision(Result.Fail)
40-
final val Retry = StandardRetryDecision(Result.Retry)
39+
final val Fail: StandardRetryDecision = StandardRetryDecision(Result.Fail)
40+
final val Retry: StandardRetryDecision = StandardRetryDecision(Result.Retry)
4141

4242
sealed trait Result
4343
object Result {

src/main/scala/io/ino/solrs/SolrServers.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import io.ino.solrs.ServerStateChangeObservable.StateChange
1111
import io.ino.solrs.future.Future
1212
import io.ino.solrs.future.FutureFactory
1313
import io.ino.solrs.future.JavaFutureFactory
14-
import io.ino.solrs.future.ScalaFutureFactory
1514
import org.apache.solr.client.solrj.SolrQuery
1615
import org.apache.solr.client.solrj.SolrRequest
1716
import org.apache.solr.client.solrj.SolrServerException
@@ -24,7 +23,6 @@ import org.asynchttpclient.AsyncHttpClient
2423
import org.asynchttpclient.Response
2524
import org.slf4j.LoggerFactory
2625

27-
import scala.collection.generic.CanBuildFrom
2826
import scala.collection.mutable
2927
import scala.util.Failure
3028
import scala.util.Success
@@ -61,7 +59,7 @@ object StaticSolrServers {
6159
new StaticSolrServers(baseUrls.map(SolrServer(_)))
6260

6361
/* Java API */
64-
import scala.collection.JavaConverters._
62+
import scala.jdk.CollectionConverters._
6563
def create(baseUrls: java.lang.Iterable[String]): StaticSolrServers =
6664
apply(baseUrls.asScala.toIndexedSeq)
6765
}
@@ -366,7 +364,7 @@ object CloudSolrServers {
366364
count: Int): Builder = {
367365
def delegate(collection: String): Seq[SolrQuery] = {
368366
val res = queriesByCollection(collection)
369-
import scala.collection.JavaConverters._
367+
import scala.jdk.CollectionConverters._
370368
res.asScala.toList
371369
}
372370
copy(warmupQueries = Some(WarmupQueries(delegate, count)))
@@ -396,7 +394,7 @@ object CloudSolrServers {
396394
servers: IndexedSeq[ShardReplica])
397395

398396
private[solrs] def getCollections(clusterState: ClusterState): Map[String, CollectionInfo] = {
399-
import scala.collection.JavaConverters._
397+
import scala.jdk.CollectionConverters._
400398

401399
clusterState.getCollectionsMap.asScala.foldLeft(
402400
Map.empty[String, CollectionInfo]
@@ -408,7 +406,7 @@ object CloudSolrServers {
408406
}
409407

410408
private def mapSliceReplicas[A](slices: util.Collection[Slice])(fun: Replica => A): Iterable[A] = {
411-
import scala.collection.JavaConverters.collectionAsScalaIterableConverter
409+
import scala.jdk.CollectionConverters._
412410
slices.asScala.flatMap(_.getReplicas.asScala.map(repl => fun(repl)))
413411
}
414412

src/test/scala/io/ino/solrs/AsyncSolrClientFunSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import org.scalatest.concurrent.Eventually.eventually
99
import org.scalatest.concurrent.PatienceConfiguration.Timeout
1010

1111
import scala.annotation.meta.field
12-
import scala.collection.JavaConverters._
12+
import scala.jdk.CollectionConverters._
1313
import scala.concurrent.duration._
1414

1515
class AsyncSolrClientFunSpec extends StandardFunSpec with RunningSolr {
1616

17-
private implicit val timeout = 1.second
17+
private implicit val timeout: FiniteDuration = 1.second
1818

1919
private lazy val solrs = AsyncSolrClient(s"http://localhost:${solrRunner.port}/solr/collection1")
2020

src/test/scala/io/ino/solrs/AsyncSolrClientIntegrationSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ import scala.xml.XML
2727

2828
class AsyncSolrClientIntegrationSpec extends StandardFunSpec with RunningSolr {
2929

30-
private implicit val patienceConfig = PatienceConfig(
30+
private implicit val patienceConfig: PatienceConfig = PatienceConfig(
3131
timeout = scaled(Span(10000, Millis)),
3232
interval = scaled(Span(20, Millis))
3333
)
3434

35-
private implicit val timeout = 1.second
35+
private implicit val timeout: FiniteDuration = 1.second
3636
private val httpClient = new DefaultAsyncHttpClient()
3737

3838
private lazy val solrUrl = s"http://localhost:${solrRunner.port}/solr/collection1"

src/test/scala/io/ino/solrs/AsyncSolrClientSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import scala.util.control.NoStackTrace
1717
class AsyncSolrClientSpec extends StandardFunSpec {
1818

1919
private val query = new SolrQuery("*:*")
20-
private implicit val timeout = 1.second
20+
private implicit val timeout: FiniteDuration = 1.second
2121

2222
describe("Solr") {
2323

src/test/scala/io/ino/solrs/CloudSolrServersSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class CloudSolrServersSpec extends AnyFunSpec with Matchers {
4444
}
4545

4646
it("should read all servers from ClusterState with multiple shards") {
47-
import scala.collection.JavaConverters._
47+
import scala.jdk.CollectionConverters._
4848

4949
val bytes = Files.readAllBytes(Paths.get(this.getClass.getResource("/cluster_status.json").toURI))
5050
val cs = ClusterState.load(1, bytes, Set("server1:8983_solr").asJava)

src/test/scala/io/ino/solrs/CloudSolrServersUninitializedIntegrationSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import scala.concurrent.duration._
1414
*/
1515
class CloudSolrServersUninitializedIntegrationSpec extends StandardFunSpec {
1616

17-
private implicit val awaitTimeout = 2 seconds
18-
private implicit val patienceConfig = PatienceConfig(timeout = scaled(Span(1000, Millis)))
17+
private implicit val awaitTimeout: FiniteDuration = 2 seconds
18+
private implicit val patienceConfig: PatienceConfig = PatienceConfig(timeout = scaled(Span(1000, Millis)))
1919

2020
private var solrRunner: SolrCloudRunner = _
2121
private def solrServerUrls = solrRunner.solrCoreUrls

src/test/scala/io/ino/solrs/FastestServerLBSpec.scala

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import org.apache.solr.common.params.ShardParams.SHARDS_PREFERENCE_REPLICA_TYPE
1919
import org.mockito.ArgumentMatchers.{eq => mockEq}
2020
import org.mockito.ArgumentMatchers._
2121
import org.mockito.Mockito._
22-
import org.scalactic.source.Position
2322
import org.scalatest.concurrent.Eventually._
24-
import org.scalatest.enablers.Retrying
2523

2624
import scala.concurrent.Future
2725
import scala.concurrent.duration._
@@ -71,13 +69,13 @@ class FastestServerLBSpec extends StandardFunSpec {
7169
override def matching(r: SolrRequest[_]): Try[IndexedSeq[SolrServer]] =
7270
Success(Vector.empty)
7371
}
74-
val cut = newDynamicLB(nonMatchingServers)
72+
val cut = newDynamicLB(nonMatchingServers, q, clock)
7573
cut.solrServer(r) shouldBe a[Failure[_]]
7674
}
7775

7876
it("should only return active solr servers") {
7977
val servers = IndexedSeq(SolrServer("host1"), SolrServer("host2"))
80-
val cut = newDynamicLB(new StaticSolrServers(servers))
78+
val cut = newDynamicLB(new StaticSolrServers(servers), q, clock)
8179

8280
cut.solrServer(r) should be(Success(SolrServer("host1")))
8381
// we must create some performance stats for host1, so that host2 will be selected
@@ -108,7 +106,7 @@ class FastestServerLBSpec extends StandardFunSpec {
108106
val cut = newDynamicLB(new StaticSolrServers(servers) {
109107
override def findLeader(servers: Iterable[SolrServer]): Option[ShardReplica] =
110108
ShardReplica.findLeader(servers)
111-
})
109+
}, q, clock)
112110

113111
val r = new UpdateRequest()
114112

@@ -141,7 +139,7 @@ class FastestServerLBSpec extends StandardFunSpec {
141139
val server2 = shardReplica("host2", replicaType = TLOG)
142140
val server3 = shardReplica("host3", replicaType = PULL)
143141
val servers = IndexedSeq(server1, server2, server3)
144-
val cut = newDynamicLB(new StaticSolrServers(servers))
142+
val cut = newDynamicLB(new StaticSolrServers(servers), this.q, clock)
145143

146144
// shards.preference=replica.location:local,replica.type:PULL,replica.type:TLOG
147145
def q(replicaTypes: Replica.Type*) =
@@ -173,7 +171,7 @@ class FastestServerLBSpec extends StandardFunSpec {
173171
}
174172

175173
it("should return the fastest server by default") {
176-
val cut = newDynamicLB(solrServers)
174+
val cut = newDynamicLB(solrServers, q, clock)
177175

178176
when(solrs.doExecute[QueryResponse](any(), any())(any())).thenReturn(delayedResponse(1))
179177
cut.test(server1)
@@ -191,7 +189,7 @@ class FastestServerLBSpec extends StandardFunSpec {
191189
* if servers are equally fast then the first one should not get all requests...
192190
*/
193191
it("should round robin equally fast servers") {
194-
val cut = newDynamicLB(solrServers)
192+
val cut = newDynamicLB(solrServers, q, clock)
195193

196194
runTests(cut,
197195
server1,
@@ -220,7 +218,7 @@ class FastestServerLBSpec extends StandardFunSpec {
220218
}
221219

222220
it("should consider the preferred server if it's one of the fastest servers") {
223-
val cut = newDynamicLB(solrServers)
221+
val cut = newDynamicLB(solrServers, q, clock)
224222
val preferred = Success(server2)
225223

226224
runTests(cut,
@@ -252,7 +250,7 @@ class FastestServerLBSpec extends StandardFunSpec {
252250
}
253251

254252
it("should return the server with a better predicted response time") {
255-
val cut = newDynamicLB(solrServers)
253+
val cut = newDynamicLB(solrServers, q, clock)
256254

257255
runTests(cut,
258256
server1,
@@ -297,7 +295,7 @@ class FastestServerLBSpec extends StandardFunSpec {
297295
*/
298296
it("should allow to quantize / consider (very) similar predicted response times to be equal") {
299297
// quantize to 5: 0 to 4 = 0, 5 to 9 = 1 etc.
300-
val cut = newDynamicLB(solrServers, mapPredictedResponseTime = t => t / 5)
298+
val cut = newDynamicLB(solrServers, q, clock, mapPredictedResponseTime = t => t / 5)
301299

302300
runTests(cut,
303301
server1,
@@ -343,7 +341,7 @@ class FastestServerLBSpec extends StandardFunSpec {
343341
}
344342

345343
it("should initially test servers to gather performance stats") {
346-
val cut = newDynamicLB(solrServers, minDelay = 10 millis)
344+
val cut = newDynamicLB(solrServers, q, clock, minDelay = 10 millis)
347345
solrServers.all.foreach(s =>
348346
verify(solrs).doExecute[QueryResponse](mockEq(s), hasQuery(q))(any()))
349347
}
@@ -451,9 +449,7 @@ class FastestServerLBSpec extends StandardFunSpec {
451449
s =>
452450
verify(spyClient, atLeastOnce()).doExecute[QueryResponse](mockEq(s),
453451
hasQuery(testQuery))(any()))
454-
}(PatienceConfig(timeout = maxDelay * 2, interval = maxDelay / 10),
455-
Retrying.retryingNatureOfT,
456-
Position.here)
452+
}
457453
}
458454
}
459455

@@ -481,6 +477,8 @@ class FastestServerLBSpec extends StandardFunSpec {
481477
}
482478

483479
private def newDynamicLB(solrServers: SolrServers,
480+
q: SolrQuery,
481+
clock: Clock,
484482
minDelay: Duration = 50 millis,
485483
mapPredictedResponseTime: Long => Long = identity): FastestServerLB = {
486484
cut = new FastestServerLB(solrServers,

src/test/scala/io/ino/solrs/Fixtures.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ object Fixtures {
1313
replicaType: Replica.Type = Replica.Type.NRT,
1414
isLeader: Boolean = false
1515
): ShardReplica = {
16-
import scala.collection.JavaConverters.mutableMapAsJavaMapConverter
16+
import scala.jdk.CollectionConverters._
1717
val leaderProps: Map[String, AnyRef] = if(isLeader) Map(ZkStateReader.LEADER_PROP -> true.toString) else Map.empty
1818
val replicaStatus = status match {
1919
case Enabled => Replica.State.ACTIVE
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
package io.ino.solrs
22

3+
import izumi.reflect.Tag
34
import org.mockito.Mockito.{mock => mockitoMock}
45

5-
import scala.reflect.runtime.universe._
6-
76
/**
87
* Improves over MockitoSugar in that it supports higher kinded types.
98
* MockitoSugar fails for them with "erroneous or inaccessible type" due to the used
109
* Manifest (see also http://stackoverflow.com/questions/26010800/why-does-getting-a-manifest-of-a-trait-with-a-higher-kinded-type-does-not-work)
1110
*/
1211
trait NewMockitoSugar {
1312

14-
def mock[T <: AnyRef](implicit tag: TypeTag[T]): T = {
15-
val m = tag.mirror
16-
mockitoMock(m.runtimeClass(tag.tpe).asInstanceOf[Class[T]])
13+
def mock[T <: AnyRef](implicit tag: Tag[T]): T = {
14+
mockitoMock(tag.closestClass.asInstanceOf[Class[T]])
1715
}
1816

1917
}

src/test/scala/io/ino/solrs/PingStatusObserverIntegrationSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class PingStatusObserverIntegrationSpec extends AnyFunSpec with BeforeAndAfterAl
2020

2121
import PingStatusObserverIntegrationSpec._
2222

23-
private implicit val awaitTimeout = 2000 millis
23+
private implicit val awaitTimeout: FiniteDuration = 2000 millis
2424
private val httpClientTimeout = 100
2525
private val httpClient = new DefaultAsyncHttpClient(new DefaultAsyncHttpClientConfig.Builder().setRequestTimeout(httpClientTimeout).build)
2626

src/test/scala/io/ino/solrs/RoundRobinLBSpec.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@ import org.apache.solr.common.cloud.Replica
99
import org.apache.solr.common.cloud.Replica.Type.NRT
1010
import org.apache.solr.common.cloud.Replica.Type.PULL
1111
import org.apache.solr.common.cloud.Replica.Type.TLOG
12-
import org.apache.solr.common.params.ShardParams
1312
import org.apache.solr.common.params.ShardParams.SHARDS_PREFERENCE
1413
import org.apache.solr.common.params.ShardParams.SHARDS_PREFERENCE_REPLICA_TYPE
1514
import org.scalatest.funspec.AnyFunSpec
1615
import org.scalatest.matchers.should.Matchers
17-
import org.scalatest.matchers.should.Matchers.convertToAnyShouldWrapper
1816

1917
import scala.util.Failure
2018
import scala.util.Success

0 commit comments

Comments
 (0)