Skip to content

Commit

Permalink
(test): Support integration tests for HttpElasticExecutor methods (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
dbulaja98 authored Dec 15, 2022
1 parent a64ffbc commit 610fdb0
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 18 deletions.
139 changes: 133 additions & 6 deletions modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package zio.elasticsearch

import sttp.client3.httpclient.zio.HttpClientZioBackend
import sttp.client3.{SttpBackend, basicRequest}
import sttp.model.StatusCode.{NotFound, Ok}
import zio.elasticsearch.ElasticConfig.Default
import zio.{Task, ZIO}
import zio.elasticsearch.ElasticError.DocumentRetrievingError.{DecoderError, DocumentNotFound}
import zio.test.Assertion.equalTo
import zio.test.Assertion.{equalTo, isFalse, isLeft, isRight, isTrue, isUnit}
import zio.test.TestAspect.nondeterministic
import zio.test._

Expand All @@ -17,13 +22,13 @@ object HttpExecutorSpec extends IntegrationSpec {
document <- ElasticRequest.getById[CustomerDocument](index, documentId).execute
} yield document

assertZIO(result)(Assertion.isRight(equalTo(customer)))
assertZIO(result)(isRight(equalTo(customer)))
}
},
test("return DocumentNotFound if the document does not exist") {
checkOnce(genDocumentId) { documentId =>
assertZIO(ElasticRequest.getById[CustomerDocument](index, documentId).execute)(
Assertion.isLeft(equalTo(DocumentNotFound))
isLeft(equalTo(DocumentNotFound))
)
}
},
Expand All @@ -34,9 +39,131 @@ object HttpExecutorSpec extends IntegrationSpec {
document <- ElasticRequest.getById[CustomerDocument](index, documentId).execute
} yield document

assertZIO(result)(Assertion.isLeft(equalTo(DecoderError(".address(missing)"))))
assertZIO(result)(isLeft(equalTo(DecoderError(".address(missing)"))))
}
}
) @@ nondeterministic
).provideShared(elasticsearchLayer)
),
suite("creating document")(
test("successfully create document") {
checkOnce(genCustomer) { customer =>
val result = for {
docId <- ElasticRequest.create[CustomerDocument](index, customer).execute
res <- ElasticRequest.getById[CustomerDocument](index, docId.getOrElse(DocumentId(""))).execute
} yield res

assertZIO(result)(isRight(equalTo(customer)))
}
},
test("successfully create document with ID given") {
checkOnce(genDocumentId, genCustomer) { (documentId, customer) =>
val result = for {
_ <- ElasticRequest.create[CustomerDocument](index, documentId, customer).execute
doc <- ElasticRequest.getById[CustomerDocument](index, documentId).execute
} yield doc

assertZIO(result)(isRight(equalTo(customer)))
}
},
test("fail to create document with ID given") {
checkOnce(genDocumentId, genCustomer, genCustomer) { (documentId, customer1, customer2) =>
val result = for {
_ <- ElasticRequest.upsert[CustomerDocument](index, documentId, customer1).execute
_ <- ElasticRequest.create[CustomerDocument](index, documentId, customer2).execute
doc <- ElasticRequest.getById[CustomerDocument](index, documentId).execute
} yield doc

assertZIO(result)(isRight(equalTo(customer1)))
}
}
),
suite("creating or updating document")(
test("successfully create document") {
checkOnce(genDocumentId, genCustomer) { (documentId, customer) =>
val result = for {
_ <- ElasticRequest.upsert[CustomerDocument](index, documentId, customer).execute
doc <- ElasticRequest.getById[CustomerDocument](index, documentId).execute
} yield doc

assertZIO(result)(isRight(equalTo(customer)))
}
},
test("successfully update document") {
checkOnce(genDocumentId, genCustomer, genCustomer) { (documentId, customer1, customer2) =>
val result = for {
_ <- ElasticRequest.create[CustomerDocument](index, documentId, customer1).execute
_ <- ElasticRequest.upsert[CustomerDocument](index, documentId, customer2).execute
doc <- ElasticRequest.getById[CustomerDocument](index, documentId).execute
} yield doc

assertZIO(result)(isRight(equalTo(customer2)))
}
}
),
suite("finding document")(
test("return true if the document exists") {
checkOnce(genDocumentId, genCustomer) { (documentId, customer) =>
val result = for {
_ <- ElasticRequest.upsert[CustomerDocument](index, documentId, customer).execute
exists <- ElasticRequest.exists(index, documentId).execute
} yield exists

assertZIO(result)(isTrue)
}
},
test("return false if the document does not exist") {
checkOnce(genDocumentId) { documentId =>
assertZIO(ElasticRequest.exists(index, documentId).execute)(isFalse)
}
}
),
suite("deleting document by ID")(
test("return unit if document deletion was successful") {
checkOnce(genDocumentId, genCustomer) { (documentId, customer) =>
val result = for {
_ <- ElasticRequest.upsert[CustomerDocument](index, documentId, customer).execute
res <- ElasticRequest.deleteById(index, documentId).execute
} yield res

assertZIO(result)(isRight(isUnit))
}
},
test("return DocumentNotFound if the document does not exist") {
checkOnce(genDocumentId) { documentId =>
assertZIO(ElasticRequest.deleteById(index, documentId).execute)(isLeft(equalTo(DocumentNotFound)))
}
}
),
suite("creating index")(
test("return true if creation was successful") {
checkOnce(genIndexName) { name =>
val result = for {
_ <- ElasticRequest.createIndex(name, None).execute
sttp <- ZIO.service[SttpBackend[Task, Any]]
indexExists <- basicRequest
.head(Default.uri.withPath(name.toString))
.send(sttp)
.map(_.code.equals(Ok))
} yield indexExists

assertZIO(result)(isTrue)
}
}
),
suite("delete index")(
test("return true if deletion was successful") {
checkOnce(genIndexName) { name =>
val result = for {
_ <- ElasticRequest.deleteIndex(name).execute
sttp <- ZIO.service[SttpBackend[Task, Any]]
deleted <- basicRequest
.head(Default.uri.withPath(name.toString))
.send(sttp)
.map(_.code.equals(NotFound))
} yield deleted

assertZIO(result)(isTrue)
}
}
)
).provideShared(elasticsearchLayer, HttpClientZioBackend.layer()) @@ nondeterministic
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package zio.elasticsearch

import sttp.client3.httpclient.zio.HttpClientZioBackend
import zio.ZLayer
import zio.prelude.Newtype.unsafeWrap
import zio.test.CheckVariants.CheckN
import zio.test.{Gen, ZIOSpecDefault, checkN}

Expand All @@ -11,6 +12,9 @@ trait IntegrationSpec extends ZIOSpecDefault {

val index: IndexName = IndexName("users")

def genIndexName: Gen[Any, IndexName] =
Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(IndexName)(name.toLowerCase))

def genDocumentId: Gen[Any, DocumentId] = Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_))

def genCustomer: Gen[Any, CustomerDocument] = for {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package zio.elasticsearch

final case class ElasticConfig(host: String, port: Int)
import sttp.model.Uri

final case class ElasticConfig(host: String, port: Int) {
lazy val uri: Uri = Uri(host, port)
}

object ElasticConfig {
lazy val Default: ElasticConfig = ElasticConfig("localhost", 9200)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import sttp.client3.ziojson._
import sttp.client3.{Identity, RequestT, Response, ResponseException, SttpBackend, UriContext, basicRequest => request}
import sttp.model.MediaType.ApplicationJson
import sttp.model.StatusCode.Ok
import sttp.model.Uri
import zio.Task
import zio.ZIO.logDebug
import zio.elasticsearch.ElasticRequest._
Expand All @@ -14,8 +13,6 @@ private[elasticsearch] final class HttpElasticExecutor private (config: ElasticC

import HttpElasticExecutor._

private val basePath = Uri(config.host, config.port)

override def execute[A](request: ElasticRequest[A]): Task[A] =
request match {
case r: Create => executeCreate(r)
Expand All @@ -29,7 +26,7 @@ private[elasticsearch] final class HttpElasticExecutor private (config: ElasticC
}

private def executeGetById(r: GetById): Task[Option[Document]] = {
val uri = uri"$basePath/${r.index}/$Doc/${r.id}".withParam("routing", r.routing.map(Routing.unwrap))
val uri = uri"${config.uri}/${r.index}/$Doc/${r.id}".withParam("routing", r.routing.map(Routing.unwrap))

sendRequestWithCustomResponse[ElasticGetResponse](
request
Expand All @@ -41,9 +38,9 @@ private[elasticsearch] final class HttpElasticExecutor private (config: ElasticC
private def executeCreate(r: Create): Task[Option[DocumentId]] = {
val uri = r.id match {
case Some(documentId) =>
uri"$basePath/${r.index}/$Create/$documentId".withParam("routing", r.routing.map(Routing.unwrap))
uri"${config.uri}/${r.index}/$Create/$documentId".withParam("routing", r.routing.map(Routing.unwrap))
case None =>
uri"$basePath/${r.index}/$Doc".withParam("routing", r.routing.map(Routing.unwrap))
uri"${config.uri}/${r.index}/$Doc".withParam("routing", r.routing.map(Routing.unwrap))
}

sendRequestWithCustomResponse[ElasticCreateResponse](
Expand All @@ -58,28 +55,28 @@ private[elasticsearch] final class HttpElasticExecutor private (config: ElasticC
private def executeCreateIndex(createIndex: CreateIndex): Task[Unit] =
sendRequest(
request
.put(uri"$basePath/${createIndex.name}")
.put(uri"${config.uri}/${createIndex.name}")
.contentType(ApplicationJson)
.body(createIndex.definition.getOrElse(""))
).unit

private def executeCreateOrUpdate(r: CreateOrUpdate): Task[Unit] = {
val uri = uri"$basePath/${r.index}/$Doc/${r.id}".withParam("routing", r.routing.map(Routing.unwrap))
val uri = uri"${config.uri}/${r.index}/$Doc/${r.id}".withParam("routing", r.routing.map(Routing.unwrap))

sendRequest(request.put(uri).contentType(ApplicationJson).body(r.document.json)).unit
}

private def executeExists(r: Exists): Task[Boolean] = {
val uri = uri"$basePath/${r.index}/$Doc/${r.id}".withParam("routing", r.routing.map(Routing.unwrap))
val uri = uri"${config.uri}/${r.index}/$Doc/${r.id}".withParam("routing", r.routing.map(Routing.unwrap))

sendRequest(request.head(uri)).map(_.code.equals(Ok))
}

private def executeDeleteIndex(r: DeleteIndex): Task[Unit] =
sendRequest(request.delete(uri"$basePath/${r.name}")).unit
sendRequest(request.delete(uri"${config.uri}/${r.name}")).unit

private def executeDeleteById(r: DeleteById): Task[Option[Unit]] = {
val uri = uri"$basePath/${r.index}/$Doc/${r.id}".withParam("routing", r.routing.map(Routing.unwrap))
val uri = uri"${config.uri}/${r.index}/$Doc/${r.id}".withParam("routing", r.routing.map(Routing.unwrap))

sendRequestWithCustomResponse(
request
Expand Down

0 comments on commit 610fdb0

Please sign in to comment.