Skip to content

Commit

Permalink
(test): Implement Test Executor (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
dbulaja98 authored Jan 9, 2023
1 parent 4f6315a commit e66626a
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package zio.elasticsearch

import sttp.client3.SttpBackend
import zio.{Task, ZIO, ZLayer}
import zio.stm.TMap
import zio.{Task, ULayer, ZIO, ZLayer}

trait ElasticExecutor {
def execute[A](request: ElasticRequest[A, _]): Task[A]
Expand All @@ -18,4 +19,7 @@ object ElasticExecutor {

lazy val local: ZLayer[SttpBackend[Task, Any], Throwable, ElasticExecutor] =
ZLayer.succeed(ElasticConfig.Default) >>> live

lazy val test: ULayer[TestExecutor] =
ZLayer(TMap.empty[IndexName, TMap[DocumentId, Document]].map(TestExecutor).commit)
}
129 changes: 129 additions & 0 deletions modules/library/src/main/scala/zio/elasticsearch/TestExecutor.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package zio.elasticsearch

import zio.Random.nextUUID
import zio.elasticsearch.CreationOutcome.{AlreadyExists, Created}
import zio.elasticsearch.DeletionOutcome.{Deleted, NotFound}
import zio.elasticsearch.ElasticRequest._
import zio.json.ast.Json
import zio.stm.{STM, TMap, ZSTM}
import zio.{Task, ZIO}

private[elasticsearch] final case class TestExecutor private (data: TMap[IndexName, TMap[DocumentId, Document]])
extends ElasticExecutor {
self =>

override def execute[A](request: ElasticRequest[A, _]): Task[A] =
request match {
case CreateRequest(index, document, _, _) =>
fakeCreate(index, document)
case CreateWithIdRequest(index, id, document, _, _) =>
fakeCreateWithId(index, id, document)
case CreateIndexRequest(name, _) =>
fakeCreateIndex(name)
case CreateOrUpdateRequest(index, id, document, _, _) =>
fakeCreateOrUpdate(index, id, document)
case DeleteByIdRequest(index, id, _, _) =>
fakeDeleteById(index, id)
case DeleteIndexRequest(name) =>
fakeDeleteIndex(name)
case ExistsRequest(index, id, _) =>
fakeExists(index, id)
case GetByIdRequest(index, id, _) =>
fakeGetById(index, id)
case GetByQueryRequest(index, _, _) =>
fakeGetByQuery(index)
case map @ Map(_, _) =>
execute(map.request).flatMap(a => ZIO.fromEither(map.mapper(a)))
}

private def fakeCreate(index: IndexName, document: Document): Task[DocumentId] =
(for {
documents <- getDocumentsFromIndex(index)
documentId = DocumentId(nextUUID.toString)
_ <- documents.put(documentId, document)
} yield documentId).commit

private def fakeCreateWithId(index: IndexName, documentId: DocumentId, document: Document): Task[CreationOutcome] =
(for {
documents <- getDocumentsFromIndex(index)
alreadyExists <- documents.contains(documentId)
_ <- documents.putIfAbsent(documentId, document)
} yield if (alreadyExists) AlreadyExists else Created).commit

private def fakeCreateIndex(index: IndexName): Task[CreationOutcome] =
(for {
alreadyExists <- self.data.contains(index)
emptyDocuments <- TMap.empty[DocumentId, Document]
_ <- self.data.putIfAbsent(index, emptyDocuments)
} yield if (alreadyExists) AlreadyExists else Created).commit

private def fakeCreateOrUpdate(index: IndexName, documentId: DocumentId, document: Document): Task[Unit] =
(for {
documents <- getDocumentsFromIndex(index)
_ <- documents.put(documentId, document)
} yield ()).commit

private def fakeDeleteById(index: IndexName, documentId: DocumentId): Task[DeletionOutcome] =
(for {
documents <- getDocumentsFromIndex(index)
notExists <- documents.contains(documentId)
_ <- documents.delete(documentId)
} yield if (notExists) NotFound else Deleted).commit

private def fakeDeleteIndex(index: IndexName): Task[DeletionOutcome] =
(for {
notExists <- self.data.contains(index)
_ <- self.data.delete(index)
} yield if (notExists) NotFound else Deleted).commit

private def fakeExists(index: IndexName, documentId: DocumentId): Task[Boolean] =
(for {
documents <- getDocumentsFromIndex(index)
exists <- documents.contains(documentId)
} yield exists).commit

private def fakeGetById(index: IndexName, documentId: DocumentId): Task[Option[Document]] =
(for {
documents <- getDocumentsFromIndex(index)
maybeDocument <- documents.get(documentId)
} yield maybeDocument).commit

private def fakeGetByQuery(index: IndexName): Task[ElasticQueryResponse] = {
def createElasticQueryResponse(
index: IndexName,
documents: TMap[DocumentId, Document]
): ZSTM[Any, Nothing, ElasticQueryResponse] = {
val shards = Shards(total = 1, successful = 1, skipped = 0, failed = 0)

for {
items <-
documents.toList.map(
_.map { case (id, document) =>
Item(
index = index.toString,
`type` = "type",
id = id.toString,
score = 1,
source = Json.Str(document.json)
)
}
)
hitsSize <- documents.size
hits = Hits(total = Total(value = hitsSize, relation = ""), maxScore = 1, hits = items)
} yield ElasticQueryResponse(took = 1, timedOut = false, shards = shards, hits = hits)
}

(for {
documents <- getDocumentsFromIndex(index)
response <- createElasticQueryResponse(index, documents)
} yield response).commit
}

private def getDocumentsFromIndex(index: IndexName): ZSTM[Any, ElasticException, TMap[DocumentId, Document]] =
for {
maybeDocuments <- self.data.get(index)
documents <- maybeDocuments.fold[STM[ElasticException, TMap[DocumentId, Document]]](
STM.fail[ElasticException](new ElasticException(s"Index $index does not exists!"))
)(STM.succeed(_))
} yield documents
}

0 comments on commit e66626a

Please sign in to comment.