Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement integration tests #223

Merged
merged 3 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ lazy val app = (project in file("modules/app"))
cirisCore,
cirisHtt4s,
log4Cats,
logback
logback,
weaver,
testContainers,
),
Compile / run / fork := true
)
Expand Down
33 changes: 33 additions & 0 deletions modules/app/src/test/scala/Clients.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package lila.search
package app
package test

import cats.effect.{ IO, Resource }
import lila.search.spec.{ HealthService, SearchService }
import org.http4s.Uri
import org.http4s.ember.client.EmberClientBuilder
import smithy4s.http4s.*

object Clients:

def health(uri: Uri): Resource[IO, HealthService[IO]] =
EmberClientBuilder
.default[IO]
.build
.flatMap: client =>
SimpleRestJsonBuilder
.apply(HealthService)
.client(client)
.uri(uri)
.resource

def search(uri: Uri): Resource[IO, SearchService[IO]] =
EmberClientBuilder
.default[IO]
.build
.flatMap: client =>
SimpleRestJsonBuilder
.apply(SearchService)
.client(client)
.uri(uri)
.resource
34 changes: 34 additions & 0 deletions modules/app/src/test/scala/ElasticSearchContainer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package lila.search
package app
package test

import cats.effect.{ IO, Resource }
import com.dimafeng.testcontainers.GenericContainer
import org.testcontainers.containers.wait.strategy.Wait

object ElasticSearchContainer:

private val PORT = 9200
private val container =
val env = Map(
"discovery.type" -> "single-node",
"http.cors.allow-origin" -> "/.*/",
"http.cors.enabled" -> "true",
"xpack.security.enabled" -> "false"
)
val start = IO(
GenericContainer(
"elasticsearch:7.10.1",
exposedPorts = Seq(PORT),
waitStrategy = Wait.forListeningPort(),
env = env
)
)
.flatTap(cont => IO(cont.start()))
Resource.make(start)(cont => IO(cont.stop()))

def parseConfig(container: GenericContainer): ElasticConfig =
ElasticConfig(s"http://${container.host}:${container.mappedPort(PORT)}")

def start: Resource[IO, ElasticConfig] =
container.map(parseConfig)
155 changes: 155 additions & 0 deletions modules/app/src/test/scala/IntegrationSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package lila.search
package app
package test

import cats.effect.{ IO, Resource }
import cats.syntax.all.*
import com.comcast.ip4s.*
import lila.search.spec.*
import org.http4s.Uri
import org.typelevel.log4cats.Logger
import org.typelevel.log4cats.noop.NoOpLogger
import smithy4s.Timestamp
import weaver.*

object IntegrationSuite extends IOSuite:

given Logger[IO] = NoOpLogger[IO]

private val uri = Uri.unsafeFromString("http://localhost:9999")

override type Res = AppResources
// start our server
override def sharedResource: Resource[IO, Res] =
for
elastic <- ElasticSearchContainer.start
config = testAppConfig(elastic)
res <- AppResources.instance(config)
_ <- SearchApp(res, config).run()
yield res

def testAppConfig(elastic: ElasticConfig) = AppConfig(
server =
HttpServerConfig(ip"0.0.0.0", port"9999", apiLogger = false, shutdownTimeout = 30, enableDocs = false),
elastic = elastic
)

test("health check should return healthy"):
Clients
.health(uri)
.use:
_.healthCheck()
.map(expect.same(_, HealthCheckOutput(ElasticStatus.green)))

test("forum"): _ =>
Clients
.search(uri)
.use: service =>
for
_ <- service.mapping(Index.Forum)
_ <- service
.store(
"forum_id",
Source.forum(
ForumSource(
body = "a forum post",
topic = "chess",
topicId = "chess",
troll = false,
date = Timestamp(2021, 1, 1, 0, 0, 0),
author = "nt9".some
)
)
)
_ <- service.refresh(Index.Forum)
x <- service.search(Query.forum("chess", false), 0, 12)
y <- service.search(Query.forum("nt9", false), 0, 12)
yield expect(x.hitIds.size == 1 && x == y)

test("team"): _ =>
Clients
.search(uri)
.use: service =>
for
_ <- service.mapping(Index.Team)
_ <- service
.store(
"team_id",
Source.team(
TeamSource(
name = "team name",
description = "team description",
100
)
)
)
_ <- service.refresh(Index.Team)
x <- service.search(Query.team("team name"), 0, 12)
y <- service.search(Query.team("team description"), 0, 12)
yield expect(x.hitIds.size == 1 && x == y)

test("study"): _ =>
Clients
.search(uri)
.use: service =>
for
_ <- service.mapping(Index.Study)
_ <- service
.store(
"study_id",
Source.study(
StudySource(
name = "study name",
owner = "study owner",
members = List("member1", "member2"),
chapterNames = "chapter names",
chapterTexts = "chapter texts",
likes = 100,
public = true,
topics = List("topic1", "topic2")
)
)
)
_ <- service.refresh(Index.Study)
x <- service.search(Query.study("study name"), 0, 12)
y <- service.search(Query.study("study description"), 0, 12)
z <- service.search(Query.study("topic1"), 0, 12)
yield expect(x.hitIds.size == 1 && x == y && z == x)

// test game
test("game"): _ =>
Clients
.search(uri)
.use: service =>
for
_ <- service.mapping(Index.Game)
_ <- service
.store(
"game_id",
Source.game(
GameSource(
status = 1,
turns = 100,
rated = true,
perf = 1,
winnerColor = 1,
date = SearchDateTime.fromString("1999-10-20 12:20:20").toOption.get,
analysed = false,
uids = List("uid1", "uid2").some,
winner = "uid1".some,
loser = "uid2".some,
averageRating = 150.some,
ai = none,
duration = 100.some,
clockInit = 100.some,
clockInc = 100.some,
whiteUser = "white".some,
blackUser = "black".some
)
)
)
_ <- service.refresh(Index.Game)
x <- service.search(Query.game(List(1)), 0, 12)
y <- service.search(Query.game(loser = "uid2".some), 0, 12)
z <- service.search(Query.game(), 0, 12)
yield expect(x.hitIds.size == 1 && x == y && z == x)
8 changes: 2 additions & 6 deletions modules/core/src/main/scala/ESClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,7 @@ object ESClient:
dropIndex(index) >> client
.execute {
createIndex(index.name)
.mapping(
properties(fields).source(false) // all false
)
.mapping(properties(fields).source(false)) // all false
.shards(5)
.replicas(0)
.refreshInterval(Which.refreshInterval(index))
Expand All @@ -110,6 +108,4 @@ object ESClient:
.flatMap(unitOrFail)

private def dropIndex(index: Index) =
client
.execute(deleteIndex(index.name))
.flatMap(unitOrFail)
client.execute(deleteIndex(index.name))
4 changes: 2 additions & 2 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object Dependencies {
}

def http4s(artifact: String) = "org.http4s" %% s"http4s-$artifact" % V.http4s
def smithy4s(artifact: String): ModuleID = "com.disneystreaming.smithy4s" %% s"smithy4s-$artifact" % smithy4sVersion
def smithy4s(artifact: String) = "com.disneystreaming.smithy4s" %% s"smithy4s-$artifact" % smithy4sVersion

val catsCore = "org.typelevel" %% "cats-core" % "2.12.0"
val catsEffect = "org.typelevel" %% "cats-effect" % V.catsEffect
Expand Down Expand Up @@ -45,7 +45,7 @@ object Dependencies {

val ducktape = "io.github.arainko" %% "ducktape" % "0.2.2"

val testContainers = "com.dimafeng" %% "testcontainers-scala-postgresql" % "0.41.3" % Test
val testContainers = "com.dimafeng" %% "testcontainers-scala-core" % "0.41.3" % Test
val weaver = "com.disneystreaming" %% "weaver-cats" % "0.8.4" % Test
val weaverScalaCheck = "com.disneystreaming" %% "weaver-scalacheck" % "0.8.4" % Test
val catsEffectTestKit = "org.typelevel" %% "cats-effect-testkit" % V.catsEffect % Test
Expand Down
Loading