我正在尝试为 MockWS 和 Caffeine 的使用编写一个测试。不知何故,从 MockWS 返回的值无法被驱逐。当 executorContext 不同时我遇到过这个问题,但是即使我尝试通过使用 materializer 的 executorContext 来克服这个问题,它仍然无法驱逐 ws 的返回值。你对此有什么想法吗?
插件:
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.7")
依赖项:
"com.github.blemale" %% "scaffeine" % "5.1.0",
"de.leanovate.play-mockws" %% "play-mockws" % "2.8.1" % Test
FakeTicker.scala
import com.github.benmanes.caffeine.cache.Ticker
import java.util.concurrent.atomic.AtomicLong
import scala.concurrent.duration.Duration
class FakeTicker extends Ticker {
private val nanos = new AtomicLong()
private val autoIncrementStepNanos = new AtomicLong()
override def read(): Long =
nanos.getAndAdd(autoIncrementStepNanos.get())
def advance(duration: Duration): FakeTicker = {
advance(duration.toNanos)
this
}
def advance(nanoseconds: Long): FakeTicker = {
nanos.addAndGet(nanoseconds)
this
}
def setAutoIncrement(duration: Duration): Unit = {
this.autoIncrementStepNanos.set(duration.toNanos)
}
}
(更新:25/08/2021)测试用例:
import com.github.blemale.scaffeine.{ AsyncLoadingCache, Scaffeine }
import mockws.{ MockWS, Route }
import org.scalatest.freespec.AnyFreeSpec
import play.api.mvc.Results.Ok
import play.api.test.Helpers.await
import java.util.concurrent.TimeUnit
import java.util.stream.Collectors.toList
import scala.compat.java8.DurationConverters.DurationOps
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.{ Random, Try }
import scala.jdk.CollectionConverters._
class CacheSpec extends AnyFreeSpec {
import mockws.MockWSHelpers._
implicit val ec = materializer.executionContext
val fakeTicker = new FakeTicker
case class Expired(ttl: Long, data: String)
val cache: AsyncLoadingCache[String, Expired] = Scaffeine()
.executor(ec)
.ticker(fakeTicker)
.refreshAfterWrite(1.hour)
.expireAfter(
create = (_: String, response: Expired) => response.ttl.milliseconds,
update = (_: String, response: Expired, _: FiniteDuration) => response.ttl.milliseconds,
read = (_: String, _: Expired, duration: FiniteDuration) => duration
)
.buildAsyncFuture[String, Expired](load(_))
val ws: MockWS = MockWS {
Route {
case ("POST", "/test") =>
Action {
Ok(Random.nextString(10))
}
}
}
def load(s: String): Future[Expired] = {
//Does not work:
ws.url("/test").post("test").map { result => Expired(600000, result.body) }
//Works:
//Future(Expired(600000, Random.nextString(10)))
}
"get" - {
"should pass" in {
val first = await(cache.get("test"), 1, TimeUnit.MINUTES)
println(first)
fakeTicker.advance(2.hours)
println(
Try(
"Expires after: " +
cache.underlying
.synchronous()
.policy
.expireVariably()
.stream()
.map(_.getExpiresAfter("test"))
.map(_.get().toScala)
.collect(toList())
.asScala
).getOrElse("<no element exists>")
)
val second = await(cache.get("test"), 1, TimeUnit.MINUTES)
assert(first != second)
}
}
}
输出(fakeTicker 不影响 ws 的结果驱逐):
...
Expired(600000,疕䚢篱ⳁ먚婄燂慽˥ᆯ)
Expires after: Buffer(600 seconds)
[info] - should pass *** FAILED ***
[info] Expired(600000,疕䚢篱ⳁ먚婄燂慽˥ᆯ) equaled Expired(600000,疕䚢篱ⳁ먚婄燂慽˥ᆯ) (CacheSpec.scala:73)
...
示例代码仓库:https ://github.com/veysiertekin/mockws-caffeine-test