From 06e79121a89ab697a3f15e6a0b269d6ec9635b78 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 11:29:17 +0100 Subject: [PATCH 01/28] Set up integration test configuration in build.sbt --- build.sbt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index d36f40cfe..99cd97cfb 100644 --- a/build.sbt +++ b/build.sbt @@ -29,14 +29,19 @@ lazy val library = .in(file("modules/library")) .settings(stdSettings("zio-elasticsearch")) .settings(scalacOptions += "-language:higherKinds") + .configs(IntegrationTest) .settings( + Defaults.itSettings, libraryDependencies ++= List( "dev.zio" %% "zio-json" % "0.3.0", "dev.zio" %% "zio-schema" % "0.3.1", "dev.zio" %% "zio-schema-json" % "0.3.1", + "dev.zio" %% "zio-test" % "2.0.4" % IntegrationTest, + "dev.zio" %% "zio-test-sbt" % "2.0.4" % IntegrationTest, "com.softwaremill.sttp.client3" %% "zio" % "3.8.3", "com.softwaremill.sttp.client3" %% "zio-json" % "3.8.3" - ) + ), + testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")) ) lazy val example = From 44535e9e4540d42a12765eaa6e5f2565ca655da0 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 11:32:21 +0100 Subject: [PATCH 02/28] Set up a Docker test container --- modules/library/src/it/resources/docker-compose.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 modules/library/src/it/resources/docker-compose.yml diff --git a/modules/library/src/it/resources/docker-compose.yml b/modules/library/src/it/resources/docker-compose.yml new file mode 100644 index 000000000..d6796a14b --- /dev/null +++ b/modules/library/src/it/resources/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.8' + +services: + elasticsearch: + image: elasticsearch:7.17.6 + container_name: zio-elasticsearch-test + ports: + - "9200:9200" + environment: + discovery.type: "single-node" + xpack.security.enabled: "false" + ES_JAVA_OPTS: "-Xms512m -Xmx512m" From 1968fbcd36db3ab62f9e40caab9430c609085a74 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 11:32:38 +0100 Subject: [PATCH 03/28] Add LiveSpec --- .../src/it/scala/zio/elasticsearch/LiveSpec.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala diff --git a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala new file mode 100644 index 000000000..67af5d387 --- /dev/null +++ b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala @@ -0,0 +1,15 @@ +package zio.elasticsearch + +import sttp.client3.httpclient.zio.HttpClientZioBackend +import zio.test._ + +object LiveSpec extends ZIOSpecDefault { + + private val elasticsearchLayer = HttpClientZioBackend.layer() >>> ElasticExecutor.local + + override def spec: Spec[TestEnvironment, Any] = + suite("live test")() + .provideSomeLayerShared[TestEnvironment]( + elasticsearchLayer + ) +} From c337e96ba66bbd3eb4d8c5de3ba4d013bb063ea2 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 12:13:57 +0100 Subject: [PATCH 04/28] Add integration tests to CI workflow --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index acb68f5f8..7b30ec87e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,10 @@ jobs: uses: coursier/cache-action@v6 - name: Run tests run: ./sbt ++${{ matrix.scala }}! test + - name: Run test container + run: docker-compose modules/library/src/it/resources up -d + - name: Run integration tests + run: ./sbt ++${{ matrix.scala }}! it:test website: runs-on: ubuntu-20.04 From 50b74328327deae9898e2121e6fe9f2b4c7ead3f Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Fri, 2 Dec 2022 13:58:26 +0100 Subject: [PATCH 05/28] Add tests for getting by id --- .../it/scala/zio/elasticsearch/LiveSpec.scala | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala index 67af5d387..be9e93467 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala @@ -1,14 +1,54 @@ package zio.elasticsearch import sttp.client3.httpclient.zio.HttpClientZioBackend +import zio.elasticsearch.ElasticError.DocumentRetrievingError.{DecoderError, DocumentNotFound} +import zio.schema.{DeriveSchema, Schema} import zio.test._ object LiveSpec extends ZIOSpecDefault { private val elasticsearchLayer = HttpClientZioBackend.layer() >>> ElasticExecutor.local + final case class TestDocument1(id: String, name: String, count: Int) + final case class TestDocument2(desc: String) + + implicit val schema1: Schema[TestDocument1] = DeriveSchema.gen[TestDocument1] + implicit val schema2: Schema[TestDocument2] = DeriveSchema.gen[TestDocument2] + + private val docIndex = IndexName("indexname") + private val docId = DocumentId("documentId1") + private val docId2 = DocumentId("documentId2") + + private val document = TestDocument1("123", "Doc123", 1) + override def spec: Spec[TestEnvironment, Any] = - suite("live test")() + suite("live test")( + suite("get document by id")( + test("unsuccessfully get document by id if it does not exists") { + val doc = for { + doc <- ElasticRequest.getById[TestDocument1](docIndex, docId2).routing("10").execute + } yield doc + + assertZIO(doc)(Assertion.equalTo(Left(DocumentNotFound))) + }, + test("unsuccessfully get document by id if decoder error happens") { + val doc = for { + _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing("10").execute + doc <- ElasticRequest.getById[TestDocument2](docIndex, docId).routing("10").execute + } yield doc + + assertZIO(doc)(Assertion.equalTo(Left(DecoderError(".desc(missing)")))) + }, + test("successfully get document by id") { + val doc = for { + _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing("10").execute + doc <- ElasticRequest.getById[TestDocument1](docIndex, docId).routing("10").execute + } yield doc + + assertZIO(doc)(Assertion.equalTo(Right(document))) + } + ) + ) .provideSomeLayerShared[TestEnvironment]( elasticsearchLayer ) From 9965bf10ed124d626452f8d207c0aee946b4780b Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 11:29:17 +0100 Subject: [PATCH 06/28] Set up integration test configuration in build.sbt --- build.sbt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 1d1f35712..ff73868fb 100644 --- a/build.sbt +++ b/build.sbt @@ -29,7 +29,9 @@ lazy val library = .in(file("modules/library")) .settings(stdSettings("zio-elasticsearch")) .settings(scalacOptions += "-language:higherKinds") + .configs(IntegrationTest) .settings( + Defaults.itSettings, libraryDependencies ++= List( "com.softwaremill.sttp.client3" %% "zio" % "3.8.3", "com.softwaremill.sttp.client3" %% "zio-json" % "3.8.3", @@ -37,8 +39,11 @@ lazy val library = "dev.zio" %% "zio-prelude" % "1.0.0-RC16", "dev.zio" %% "zio-schema" % "0.3.1", "dev.zio" %% "zio-schema-json" % "0.3.1", - "org.apache.commons" % "commons-lang3" % "3.12.0" - ) + "org.apache.commons" % "commons-lang3" % "3.12.0", + "dev.zio" %% "zio-test" % "2.0.4" % IntegrationTest, + "dev.zio" %% "zio-test-sbt" % "2.0.4" % IntegrationTest + ), + testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")) ) lazy val example = From 8f32f0ec138f617b96b92da18bb016d3b4edfeb3 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 11:32:21 +0100 Subject: [PATCH 07/28] Set up a Docker test container --- modules/library/src/it/resources/docker-compose.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 modules/library/src/it/resources/docker-compose.yml diff --git a/modules/library/src/it/resources/docker-compose.yml b/modules/library/src/it/resources/docker-compose.yml new file mode 100644 index 000000000..d6796a14b --- /dev/null +++ b/modules/library/src/it/resources/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.8' + +services: + elasticsearch: + image: elasticsearch:7.17.6 + container_name: zio-elasticsearch-test + ports: + - "9200:9200" + environment: + discovery.type: "single-node" + xpack.security.enabled: "false" + ES_JAVA_OPTS: "-Xms512m -Xmx512m" From 51b8d8523d0f9381f6ecab2952be18ce89dae4de Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 11:32:38 +0100 Subject: [PATCH 08/28] Add LiveSpec --- .../src/it/scala/zio/elasticsearch/LiveSpec.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala diff --git a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala new file mode 100644 index 000000000..67af5d387 --- /dev/null +++ b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala @@ -0,0 +1,15 @@ +package zio.elasticsearch + +import sttp.client3.httpclient.zio.HttpClientZioBackend +import zio.test._ + +object LiveSpec extends ZIOSpecDefault { + + private val elasticsearchLayer = HttpClientZioBackend.layer() >>> ElasticExecutor.local + + override def spec: Spec[TestEnvironment, Any] = + suite("live test")() + .provideSomeLayerShared[TestEnvironment]( + elasticsearchLayer + ) +} From 78e8ddcf17f15f1155262cfec35550217e51cfd3 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 12:13:57 +0100 Subject: [PATCH 09/28] Add integration tests to CI workflow --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index acb68f5f8..7b30ec87e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,10 @@ jobs: uses: coursier/cache-action@v6 - name: Run tests run: ./sbt ++${{ matrix.scala }}! test + - name: Run test container + run: docker-compose modules/library/src/it/resources up -d + - name: Run integration tests + run: ./sbt ++${{ matrix.scala }}! it:test website: runs-on: ubuntu-20.04 From 8af319cdf02203e6a647005f47100dcdc6a0e40c Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Fri, 2 Dec 2022 13:58:26 +0100 Subject: [PATCH 10/28] Add tests for getting by id --- .../it/scala/zio/elasticsearch/LiveSpec.scala | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala index 67af5d387..be9e93467 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala @@ -1,14 +1,54 @@ package zio.elasticsearch import sttp.client3.httpclient.zio.HttpClientZioBackend +import zio.elasticsearch.ElasticError.DocumentRetrievingError.{DecoderError, DocumentNotFound} +import zio.schema.{DeriveSchema, Schema} import zio.test._ object LiveSpec extends ZIOSpecDefault { private val elasticsearchLayer = HttpClientZioBackend.layer() >>> ElasticExecutor.local + final case class TestDocument1(id: String, name: String, count: Int) + final case class TestDocument2(desc: String) + + implicit val schema1: Schema[TestDocument1] = DeriveSchema.gen[TestDocument1] + implicit val schema2: Schema[TestDocument2] = DeriveSchema.gen[TestDocument2] + + private val docIndex = IndexName("indexname") + private val docId = DocumentId("documentId1") + private val docId2 = DocumentId("documentId2") + + private val document = TestDocument1("123", "Doc123", 1) + override def spec: Spec[TestEnvironment, Any] = - suite("live test")() + suite("live test")( + suite("get document by id")( + test("unsuccessfully get document by id if it does not exists") { + val doc = for { + doc <- ElasticRequest.getById[TestDocument1](docIndex, docId2).routing("10").execute + } yield doc + + assertZIO(doc)(Assertion.equalTo(Left(DocumentNotFound))) + }, + test("unsuccessfully get document by id if decoder error happens") { + val doc = for { + _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing("10").execute + doc <- ElasticRequest.getById[TestDocument2](docIndex, docId).routing("10").execute + } yield doc + + assertZIO(doc)(Assertion.equalTo(Left(DecoderError(".desc(missing)")))) + }, + test("successfully get document by id") { + val doc = for { + _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing("10").execute + doc <- ElasticRequest.getById[TestDocument1](docIndex, docId).routing("10").execute + } yield doc + + assertZIO(doc)(Assertion.equalTo(Right(document))) + } + ) + ) .provideSomeLayerShared[TestEnvironment]( elasticsearchLayer ) From 42469c9102b30b3c049a5b3799bf3b86f476c376 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 14:30:41 +0100 Subject: [PATCH 11/28] Generate document ID for every test --- .../it/scala/zio/elasticsearch/LiveSpec.scala | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala index be9e93467..7b501711a 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala @@ -4,6 +4,8 @@ import sttp.client3.httpclient.zio.HttpClientZioBackend import zio.elasticsearch.ElasticError.DocumentRetrievingError.{DecoderError, DocumentNotFound} import zio.schema.{DeriveSchema, Schema} import zio.test._ +import zio._ +import java.util.UUID object LiveSpec extends ZIOSpecDefault { @@ -16,33 +18,37 @@ object LiveSpec extends ZIOSpecDefault { implicit val schema2: Schema[TestDocument2] = DeriveSchema.gen[TestDocument2] private val docIndex = IndexName("indexname") - private val docId = DocumentId("documentId1") - private val docId2 = DocumentId("documentId2") private val document = TestDocument1("123", "Doc123", 1) + private val uuid: UIO[DocumentId] = ZIO.succeed(DocumentId(UUID.randomUUID().toString)) + override def spec: Spec[TestEnvironment, Any] = suite("live test")( suite("get document by id")( test("unsuccessfully get document by id if it does not exists") { val doc = for { - doc <- ElasticRequest.getById[TestDocument1](docIndex, docId2).routing("10").execute + docId <- uuid + doc <- ElasticRequest.getById[TestDocument1](docIndex, docId).routing("10").execute } yield doc assertZIO(doc)(Assertion.equalTo(Left(DocumentNotFound))) }, test("unsuccessfully get document by id if decoder error happens") { val doc = for { - _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing("10").execute - doc <- ElasticRequest.getById[TestDocument2](docIndex, docId).routing("10").execute + docId <- uuid + _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing("10").execute + doc <- ElasticRequest.getById[TestDocument2](docIndex, docId).routing("10").execute } yield doc assertZIO(doc)(Assertion.equalTo(Left(DecoderError(".desc(missing)")))) }, test("successfully get document by id") { val doc = for { - _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing("10").execute - doc <- ElasticRequest.getById[TestDocument1](docIndex, docId).routing("10").execute + docId <- uuid + _ <- Console.printLine(docId) + _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing("10").execute + doc <- ElasticRequest.getById[TestDocument1](docIndex, docId).routing("10").execute } yield doc assertZIO(doc)(Assertion.equalTo(Right(document))) From 408858f11f49774ba75e3f79fefc9dfcd3f2b2c7 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Fri, 2 Dec 2022 14:34:03 +0100 Subject: [PATCH 12/28] Correctly specify location in docker compose --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b30ec87e..caa7fb14f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,7 +53,7 @@ jobs: - name: Run tests run: ./sbt ++${{ matrix.scala }}! test - name: Run test container - run: docker-compose modules/library/src/it/resources up -d + run: docker-compose -f modules/library/src/it/resources/docker-compose.yml up -d - name: Run integration tests run: ./sbt ++${{ matrix.scala }}! it:test From f92913c860718be7c461a87df9f42986a3a9bbd7 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Fri, 2 Dec 2022 15:31:26 +0100 Subject: [PATCH 13/28] Transfer docker-compose.yml to root --- .github/workflows/ci.yml | 2 +- modules/library/{src/it/resources => }/docker-compose.yml | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename modules/library/{src/it/resources => }/docker-compose.yml (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index caa7fb14f..a7b05dcba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,7 +53,7 @@ jobs: - name: Run tests run: ./sbt ++${{ matrix.scala }}! test - name: Run test container - run: docker-compose -f modules/library/src/it/resources/docker-compose.yml up -d + run: docker-compose -f modules/library/docker-compose.yml up -d - name: Run integration tests run: ./sbt ++${{ matrix.scala }}! it:test diff --git a/modules/library/src/it/resources/docker-compose.yml b/modules/library/docker-compose.yml similarity index 100% rename from modules/library/src/it/resources/docker-compose.yml rename to modules/library/docker-compose.yml From e07128656a9bfbb02452bfc1ac75a1314a688c1b Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 12:09:31 +0100 Subject: [PATCH 14/28] Fix code remarks --- .github/workflows/ci.yml | 4 +- .../docker-compose.yml => docker-compose.yml | 4 -- .../zio/elasticsearch/HttpExecutorSpec.scala | 50 +++++++++++++++ .../it/scala/zio/elasticsearch/LiveSpec.scala | 61 ------------------- .../zio/elasticsearch/UserDocument.scala | 12 ++++ .../scala/zio/elasticsearch/package.scala | 2 +- 6 files changed, 66 insertions(+), 67 deletions(-) rename modules/library/docker-compose.yml => docker-compose.yml (53%) create mode 100644 modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala delete mode 100644 modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala create mode 100644 modules/library/src/it/scala/zio/elasticsearch/UserDocument.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7b05dcba..a7d2454b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,9 +53,11 @@ jobs: - name: Run tests run: ./sbt ++${{ matrix.scala }}! test - name: Run test container - run: docker-compose -f modules/library/docker-compose.yml up -d + run: docker-compose -f docker-compose.yml up -d - name: Run integration tests run: ./sbt ++${{ matrix.scala }}! it:test + with: + website: runs-on: ubuntu-20.04 diff --git a/modules/library/docker-compose.yml b/docker-compose.yml similarity index 53% rename from modules/library/docker-compose.yml rename to docker-compose.yml index d6796a14b..1722efda6 100644 --- a/modules/library/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,3 @@ services: container_name: zio-elasticsearch-test ports: - "9200:9200" - environment: - discovery.type: "single-node" - xpack.security.enabled: "false" - ES_JAVA_OPTS: "-Xms512m -Xmx512m" diff --git a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala new file mode 100644 index 000000000..204743360 --- /dev/null +++ b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -0,0 +1,50 @@ +package zio.elasticsearch + +import sttp.client3.httpclient.zio.HttpClientZioBackend +import zio.elasticsearch.ElasticError.DocumentRetrievingError.{DecoderError, DocumentNotFound} +import zio.elasticsearch.UserDocument.{schema1, schema2} +import zio.test.Assertion.equalTo +import zio.test._ + +object HttpExecutorSpec extends ZIOSpecDefault { + + private val elasticsearchLayer = HttpClientZioBackend.layer() >>> ElasticExecutor.local + + private val docIndex = IndexName("indexname") + private val document = UserDocument1("123", "Doc123", 1) + + override def spec: Spec[TestEnvironment, Any] = + suite("Http executor test")( + suite("get document by id")( + test("unsuccessfully get document by id if it does not exists") { + val doc = for { + docId <- Gen.stringBounded(10, 39)(Gen.alphaNumericChar).map(DocumentId(_)).runHead + doc <- ElasticRequest.getById[UserDocument1](docIndex, docId.get).execute + } yield doc + + assertZIO(doc)(Assertion.isLeft(equalTo(DocumentNotFound))) + }, + test("unsuccessfully get document by id if decoder error happens") { + val doc = for { + docId <- Gen.stringBounded(10, 38)(Gen.alphaNumericChar).map(DocumentId(_)).runHead + _ <- ElasticRequest.upsert[UserDocument1](docIndex, docId.get, document).execute + doc <- ElasticRequest.getById[UserDocument2](docIndex, docId.get).execute + } yield doc + // TODO Is it enough just to have docId.get? + assertZIO(doc)(Assertion.isLeft(equalTo(DecoderError(".desc(missing)")))) + }, + test("successfully get document by id") { + val doc = for { + docId <- Gen.stringBounded(10, 37)(Gen.alphaNumericChar).map(DocumentId(_)).runHead + _ <- ElasticRequest.upsert[UserDocument1](docIndex, docId.get, document).execute + doc <- ElasticRequest.getById[UserDocument1](docIndex, docId.get).execute + } yield doc + () + assertZIO(doc)(Assertion.isRight(equalTo(document))) + } + ) + ) + .provideShared( + elasticsearchLayer + ) +} diff --git a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala deleted file mode 100644 index 0ce330ca9..000000000 --- a/modules/library/src/it/scala/zio/elasticsearch/LiveSpec.scala +++ /dev/null @@ -1,61 +0,0 @@ -package zio.elasticsearch - -import sttp.client3.httpclient.zio.HttpClientZioBackend -import zio.elasticsearch.ElasticError.DocumentRetrievingError.{DecoderError, DocumentNotFound} -import zio.schema.{DeriveSchema, Schema} -import zio.test._ -import zio._ -import java.util.UUID - -object LiveSpec extends ZIOSpecDefault { - - private val elasticsearchLayer = HttpClientZioBackend.layer() >>> ElasticExecutor.local - - final case class TestDocument1(id: String, name: String, count: Int) - final case class TestDocument2(desc: String) - - implicit val schema1: Schema[TestDocument1] = DeriveSchema.gen[TestDocument1] - implicit val schema2: Schema[TestDocument2] = DeriveSchema.gen[TestDocument2] - - private val docIndex = IndexName("indexname") - - private val document = TestDocument1("123", "Doc123", 1) - - private val uuid: UIO[DocumentId] = ZIO.succeed(DocumentId(UUID.randomUUID().toString)) - - override def spec: Spec[TestEnvironment, Any] = - suite("live test")( - suite("get document by id")( - test("unsuccessfully get document by id if it does not exists") { - val doc = for { - docId <- uuid - doc <- ElasticRequest.getById[TestDocument1](docIndex, docId).routing(Routing("10")).execute - } yield doc - - assertZIO(doc)(Assertion.equalTo(Left(DocumentNotFound))) - }, - test("unsuccessfully get document by id if decoder error happens") { - val doc = for { - docId <- uuid - _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing(Routing("10")).execute - doc <- ElasticRequest.getById[TestDocument2](docIndex, docId).routing(Routing("10")).execute - } yield doc - - assertZIO(doc)(Assertion.equalTo(Left(DecoderError(".desc(missing)")))) - }, - test("successfully get document by id") { - val doc = for { - docId <- uuid - _ <- Console.printLine(docId) - _ <- ElasticRequest.upsert[TestDocument1](docIndex, docId, document).routing(Routing("10")).execute - doc <- ElasticRequest.getById[TestDocument1](docIndex, docId).routing(Routing("10")).execute - } yield doc - - assertZIO(doc)(Assertion.equalTo(Right(document))) - } - ) - ) - .provideSomeLayerShared[TestEnvironment]( - elasticsearchLayer - ) -} diff --git a/modules/library/src/it/scala/zio/elasticsearch/UserDocument.scala b/modules/library/src/it/scala/zio/elasticsearch/UserDocument.scala new file mode 100644 index 000000000..c5810e07d --- /dev/null +++ b/modules/library/src/it/scala/zio/elasticsearch/UserDocument.scala @@ -0,0 +1,12 @@ +package zio.elasticsearch + +import zio.schema.{DeriveSchema, Schema} + +final case class UserDocument1(id: String, name: String, count: Int) + +final case class UserDocument2(desc: String) + +object UserDocument { + implicit val schema1: Schema[UserDocument1] = DeriveSchema.gen[UserDocument1] + implicit val schema2: Schema[UserDocument2] = DeriveSchema.gen[UserDocument2] +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index 8eb771391..808776255 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -19,7 +19,7 @@ package object elasticsearch { if ( name.toLowerCase != name || startsWithAny(name, "+", "-", "_") || - containsAny(name, '\\', '/', '*', '?', '"', '/', '<', '>', '|', ' ', ',', '#', ':') || + containsAny(name, "\\", "/", "*", "?", "\"", "/", "<", ">", "|", " ", ",", "#", ":") || equalsAny(name, ".", "..") || name.getBytes().length > 255 ) From e4c032d455e7da4afa166588504ac81ebf40e33e Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 12:15:14 +0100 Subject: [PATCH 15/28] Fix ci.yml --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7d2454b5..9f75dd234 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,8 +56,6 @@ jobs: run: docker-compose -f docker-compose.yml up -d - name: Run integration tests run: ./sbt ++${{ matrix.scala }}! it:test - with: - website: runs-on: ubuntu-20.04 From 10de58553634f0dbf9bddf386ef9bb841fa38a86 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 12:29:03 +0100 Subject: [PATCH 16/28] Fix IndexName validation --- .../library/src/main/scala/zio/elasticsearch/package.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index 808776255..7fb5bc5f0 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -19,7 +19,12 @@ package object elasticsearch { if ( name.toLowerCase != name || startsWithAny(name, "+", "-", "_") || - containsAny(name, "\\", "/", "*", "?", "\"", "/", "<", ">", "|", " ", ",", "#", ":") || + contains(name, "\\") || contains(name, "/") || + contains(name, "*") || contains(name, "?") || + contains(name, "\"") || contains(name, "<") || + contains(name, ">") || contains(name, "|") || + contains(name, " ") || contains(name, ",") || + contains(name, "#") || contains(name, ":") || equalsAny(name, ".", "..") || name.getBytes().length > 255 ) From 89605ebf027c7d8880e7bc6133a4ac8fd2111191 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 13:51:49 +0100 Subject: [PATCH 17/28] Fix IndexName validation --- .../src/main/scala/zio/elasticsearch/package.scala | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index 7fb5bc5f0..e5446d9f3 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -1,7 +1,8 @@ package zio +import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils._ -import zio.prelude.Assertion._ +import zio.prelude.Assertion.isEmptyString import zio.prelude.AssertionError.failure import zio.prelude.Newtype @@ -19,12 +20,7 @@ package object elasticsearch { if ( name.toLowerCase != name || startsWithAny(name, "+", "-", "_") || - contains(name, "\\") || contains(name, "/") || - contains(name, "*") || contains(name, "?") || - contains(name, "\"") || contains(name, "<") || - contains(name, ">") || contains(name, "|") || - contains(name, " ") || contains(name, ",") || - contains(name, "#") || contains(name, ":") || + !containsNoneOf(name, List("*", "?", "\"", "<", ">", "|", " ", ",", "#", ":")) || equalsAny(name, ".", "..") || name.getBytes().length > 255 ) @@ -47,4 +43,7 @@ package object elasticsearch { } type IndexName = IndexName.Type + def containsNoneOf(name: String, params: List[String]): Boolean = + params.forall(p => !StringUtils.contains(name, p)) + } From cbcf97908355dcb7f8bd0057606ab179b12b6d3d Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 14:34:14 +0100 Subject: [PATCH 18/28] Fix IndexName validation --- .../src/main/scala/zio/elasticsearch/package.scala | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index e5446d9f3..217c9c905 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -1,6 +1,5 @@ package zio -import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils._ import zio.prelude.Assertion.isEmptyString import zio.prelude.AssertionError.failure @@ -20,7 +19,7 @@ package object elasticsearch { if ( name.toLowerCase != name || startsWithAny(name, "+", "-", "_") || - !containsNoneOf(name, List("*", "?", "\"", "<", ">", "|", " ", ",", "#", ":")) || + !reg(name) || equalsAny(name, ".", "..") || name.getBytes().length > 255 ) @@ -43,7 +42,6 @@ package object elasticsearch { } type IndexName = IndexName.Type - def containsNoneOf(name: String, params: List[String]): Boolean = - params.forall(p => !StringUtils.contains(name, p)) - + def reg(name: String) = + name.matches("[^*?\"<>| ,#:].*$") } From 044ec5b931f748c322ede9f99379902558d403ae Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 14:42:31 +0100 Subject: [PATCH 19/28] Revert changes on IndexName validation --- .../src/main/scala/zio/elasticsearch/package.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index 217c9c905..bea118d68 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -1,5 +1,6 @@ package zio +import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils._ import zio.prelude.Assertion.isEmptyString import zio.prelude.AssertionError.failure @@ -19,7 +20,7 @@ package object elasticsearch { if ( name.toLowerCase != name || startsWithAny(name, "+", "-", "_") || - !reg(name) || + containsAny(name, List("*", "?", "\"", "<", ">", "|", " ", ",", "#", ":")) || equalsAny(name, ".", "..") || name.getBytes().length > 255 ) @@ -42,6 +43,7 @@ package object elasticsearch { } type IndexName = IndexName.Type - def reg(name: String) = - name.matches("[^*?\"<>| ,#:].*$") + def containsAny(name: String, params: List[String]): Boolean = + params.exists(p => StringUtils.contains(name, p)) + } From 110a38bbe0a9eb6e26c16b7904d0734b94d03c01 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 14:51:11 +0100 Subject: [PATCH 20/28] Add environment to es in docker-compose.yml --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 1722efda6..d6796a14b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,3 +6,7 @@ services: container_name: zio-elasticsearch-test ports: - "9200:9200" + environment: + discovery.type: "single-node" + xpack.security.enabled: "false" + ES_JAVA_OPTS: "-Xms512m -Xmx512m" From 4e62eb67f2ca007be1891a394cc028d44736e76a Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 15:47:32 +0100 Subject: [PATCH 21/28] Fix code remarks --- .../zio/elasticsearch/HttpExecutorSpec.scala | 35 ++++++++----------- .../zio/elasticsearch/UserDocument.scala | 13 ++++--- .../scala/zio/elasticsearch/package.scala | 5 +-- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala index 204743360..c02f796e7 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -2,7 +2,6 @@ package zio.elasticsearch import sttp.client3.httpclient.zio.HttpClientZioBackend import zio.elasticsearch.ElasticError.DocumentRetrievingError.{DecoderError, DocumentNotFound} -import zio.elasticsearch.UserDocument.{schema1, schema2} import zio.test.Assertion.equalTo import zio.test._ @@ -10,41 +9,37 @@ object HttpExecutorSpec extends ZIOSpecDefault { private val elasticsearchLayer = HttpClientZioBackend.layer() >>> ElasticExecutor.local - private val docIndex = IndexName("indexname") - private val document = UserDocument1("123", "Doc123", 1) + private val docIndex = IndexName("users") + private val document = CustomerDocument("123", "Doc123", "address 1", BigDecimal(100)) override def spec: Spec[TestEnvironment, Any] = - suite("Http executor test")( - suite("get document by id")( - test("unsuccessfully get document by id if it does not exists") { + suite("HTTP Executor")( + suite("get document by ID")( + test("unsuccessfully get document by ID if it does not exists") { val doc = for { docId <- Gen.stringBounded(10, 39)(Gen.alphaNumericChar).map(DocumentId(_)).runHead - doc <- ElasticRequest.getById[UserDocument1](docIndex, docId.get).execute + doc <- ElasticRequest.getById[CustomerDocument](docIndex, docId.get).execute } yield doc assertZIO(doc)(Assertion.isLeft(equalTo(DocumentNotFound))) }, - test("unsuccessfully get document by id if decoder error happens") { + test("unsuccessfully get document by ID if decoder error happens") { val doc = for { docId <- Gen.stringBounded(10, 38)(Gen.alphaNumericChar).map(DocumentId(_)).runHead - _ <- ElasticRequest.upsert[UserDocument1](docIndex, docId.get, document).execute - doc <- ElasticRequest.getById[UserDocument2](docIndex, docId.get).execute + _ <- ElasticRequest.upsert[CustomerDocument](docIndex, docId.get, document).execute + doc <- ElasticRequest.getById[EmployeeDocument](docIndex, docId.get).execute } yield doc - // TODO Is it enough just to have docId.get? - assertZIO(doc)(Assertion.isLeft(equalTo(DecoderError(".desc(missing)")))) + + assertZIO(doc)(Assertion.isLeft(equalTo(DecoderError(".degree(missing)")))) }, - test("successfully get document by id") { + test("successfully get document by ID") { val doc = for { docId <- Gen.stringBounded(10, 37)(Gen.alphaNumericChar).map(DocumentId(_)).runHead - _ <- ElasticRequest.upsert[UserDocument1](docIndex, docId.get, document).execute - doc <- ElasticRequest.getById[UserDocument1](docIndex, docId.get).execute + _ <- ElasticRequest.upsert[CustomerDocument](docIndex, docId.get, document).execute + doc <- ElasticRequest.getById[CustomerDocument](docIndex, docId.get).execute } yield doc - () assertZIO(doc)(Assertion.isRight(equalTo(document))) } ) - ) - .provideShared( - elasticsearchLayer - ) + ).provideShared(elasticsearchLayer) } diff --git a/modules/library/src/it/scala/zio/elasticsearch/UserDocument.scala b/modules/library/src/it/scala/zio/elasticsearch/UserDocument.scala index c5810e07d..3dbd69478 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/UserDocument.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/UserDocument.scala @@ -2,11 +2,14 @@ package zio.elasticsearch import zio.schema.{DeriveSchema, Schema} -final case class UserDocument1(id: String, name: String, count: Int) +final case class CustomerDocument(id: String, name: String, address: String, balance: BigDecimal) -final case class UserDocument2(desc: String) +final case class EmployeeDocument(id: String, name: String, degree: String) -object UserDocument { - implicit val schema1: Schema[UserDocument1] = DeriveSchema.gen[UserDocument1] - implicit val schema2: Schema[UserDocument2] = DeriveSchema.gen[UserDocument2] +object CustomerDocument { + implicit val schema: Schema[CustomerDocument] = DeriveSchema.gen[CustomerDocument] +} + +object EmployeeDocument { + implicit val schema: Schema[EmployeeDocument] = DeriveSchema.gen[EmployeeDocument] } diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index bea118d68..cda9101e4 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -20,7 +20,7 @@ package object elasticsearch { if ( name.toLowerCase != name || startsWithAny(name, "+", "-", "_") || - containsAny(name, List("*", "?", "\"", "<", ">", "|", " ", ",", "#", ":")) || + List("*", "?", "\"", "<", ">", "|", " ", ",", "#", ":").exists(p => StringUtils.contains(name, p)) || equalsAny(name, ".", "..") || name.getBytes().length > 255 ) @@ -43,7 +43,4 @@ package object elasticsearch { } type IndexName = IndexName.Type - def containsAny(name: String, params: List[String]): Boolean = - params.exists(p => StringUtils.contains(name, p)) - } From ebe10bc7c135e8f6c097fb940de9ff5a816b94c3 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 15:56:14 +0100 Subject: [PATCH 22/28] Fix IndexName validation --- .../library/src/main/scala/zio/elasticsearch/package.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index cda9101e4..9ef364494 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -16,11 +16,15 @@ package object elasticsearch { type DocumentId = DocumentId.Type object IndexName extends Newtype[String] { + + private def containsAny(name: String, params: List[String]): Boolean = + params.exists(p => StringUtils.contains(name, p)) + override def assertion = assertCustom { (name: String) => // scalafix:ok if ( name.toLowerCase != name || startsWithAny(name, "+", "-", "_") || - List("*", "?", "\"", "<", ">", "|", " ", ",", "#", ":").exists(p => StringUtils.contains(name, p)) || + containsAny(name, List("*", "?", "\"", "<", ">", "|", " ", ",", "#", ":")) || equalsAny(name, ".", "..") || name.getBytes().length > 255 ) From 89e794f718e30b40532de881947e2798d9733adf Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 5 Dec 2022 16:00:54 +0100 Subject: [PATCH 23/28] Fix IndexName validation --- .../library/src/main/scala/zio/elasticsearch/package.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index 9ef364494..bea118d68 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -16,10 +16,6 @@ package object elasticsearch { type DocumentId = DocumentId.Type object IndexName extends Newtype[String] { - - private def containsAny(name: String, params: List[String]): Boolean = - params.exists(p => StringUtils.contains(name, p)) - override def assertion = assertCustom { (name: String) => // scalafix:ok if ( name.toLowerCase != name || @@ -47,4 +43,7 @@ package object elasticsearch { } type IndexName = IndexName.Type + def containsAny(name: String, params: List[String]): Boolean = + params.exists(p => StringUtils.contains(name, p)) + } From 75fcedd8aa24013e5ae549680cad1d716eab5c85 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 6 Dec 2022 13:28:15 +0100 Subject: [PATCH 24/28] Refactor tests --- .../zio/elasticsearch/HttpExecutorSpec.scala | 53 +++++++++---------- .../zio/elasticsearch/IntegrationSpec.scala | 37 +++++++++++++ 2 files changed, 63 insertions(+), 27 deletions(-) create mode 100644 modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala diff --git a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala index c02f796e7..9e58340ae 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -1,45 +1,44 @@ package zio.elasticsearch -import sttp.client3.httpclient.zio.HttpClientZioBackend import zio.elasticsearch.ElasticError.DocumentRetrievingError.{DecoderError, DocumentNotFound} import zio.test.Assertion.equalTo +import zio.test.TestAspect.nondeterministic import zio.test._ -object HttpExecutorSpec extends ZIOSpecDefault { - - private val elasticsearchLayer = HttpClientZioBackend.layer() >>> ElasticExecutor.local - - private val docIndex = IndexName("users") - private val document = CustomerDocument("123", "Doc123", "address 1", BigDecimal(100)) +object HttpExecutorSpec extends ZIOSpecDefault with IntegrationSpec { override def spec: Spec[TestEnvironment, Any] = suite("HTTP Executor")( suite("get document by ID")( + test("successfully get document by ID") { + generateCustomerDocument.flatMap { expectedDoc => + val returnedDocument = for { + docId <- generateId + _ <- ElasticRequest.upsert[CustomerDocument](docIndex, docId, expectedDoc).execute + returnedDoc <- ElasticRequest.getById[CustomerDocument](docIndex, docId).execute + } yield returnedDoc + + assertZIO(returnedDocument)(Assertion.isRight(equalTo(expectedDoc))) + } + }, test("unsuccessfully get document by ID if it does not exists") { - val doc = for { - docId <- Gen.stringBounded(10, 39)(Gen.alphaNumericChar).map(DocumentId(_)).runHead - doc <- ElasticRequest.getById[CustomerDocument](docIndex, docId.get).execute - } yield doc + val returnedDocument = for { + docId <- generateId + returnedDoc <- ElasticRequest.getById[CustomerDocument](docIndex, docId).execute + } yield returnedDoc - assertZIO(doc)(Assertion.isLeft(equalTo(DocumentNotFound))) + assertZIO(returnedDocument)(Assertion.isLeft(equalTo(DocumentNotFound))) }, test("unsuccessfully get document by ID if decoder error happens") { - val doc = for { - docId <- Gen.stringBounded(10, 38)(Gen.alphaNumericChar).map(DocumentId(_)).runHead - _ <- ElasticRequest.upsert[CustomerDocument](docIndex, docId.get, document).execute - doc <- ElasticRequest.getById[EmployeeDocument](docIndex, docId.get).execute - } yield doc + val returnedDocument = for { + docId <- generateId + newDoc <- generateEmployeeDocument + _ <- ElasticRequest.upsert[EmployeeDocument](docIndex, docId, newDoc).execute + returnedDoc <- ElasticRequest.getById[CustomerDocument](docIndex, docId).execute + } yield returnedDoc - assertZIO(doc)(Assertion.isLeft(equalTo(DecoderError(".degree(missing)")))) - }, - test("successfully get document by ID") { - val doc = for { - docId <- Gen.stringBounded(10, 37)(Gen.alphaNumericChar).map(DocumentId(_)).runHead - _ <- ElasticRequest.upsert[CustomerDocument](docIndex, docId.get, document).execute - doc <- ElasticRequest.getById[CustomerDocument](docIndex, docId.get).execute - } yield doc - assertZIO(doc)(Assertion.isRight(equalTo(document))) + assertZIO(returnedDocument)(Assertion.isLeft(equalTo(DecoderError(".address(missing)")))) } - ) + ) @@ nondeterministic ).provideShared(elasticsearchLayer) } diff --git a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala new file mode 100644 index 000000000..9cd896311 --- /dev/null +++ b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala @@ -0,0 +1,37 @@ +package zio.elasticsearch + +import sttp.client3.httpclient.zio.HttpClientZioBackend +import zio.{ZIO, ZLayer} +import zio.test.Gen + +trait IntegrationSpec { + private[elasticsearch] val elasticsearchLayer: ZLayer[Any, Throwable, ElasticExecutor] = + HttpClientZioBackend.layer() >>> ElasticExecutor.local + + private[elasticsearch] val docIndex: IndexName = IndexName("users") + + private[elasticsearch] def generateId: ZIO[Any, Nothing, DocumentId] = + Gen.stringBounded(10, 40)(Gen.alphaNumericChar).runHead.map(maybeId => DocumentId(maybeId.getOrElse("DocumentId"))) + + private[elasticsearch] def generateCustomerDocument: ZIO[Any, Nothing, CustomerDocument] = for { + id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead + name <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead + address <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead + balance <- Gen.bigDecimal(100, 10000).runHead + } yield CustomerDocument( + id = id.getOrElse("123"), + name = name.getOrElse("CustomerDocument"), + address = address.getOrElse("address 1"), + balance = balance.getOrElse(BigDecimal(100)) + ) + + private[elasticsearch] def generateEmployeeDocument: ZIO[Any, Nothing, EmployeeDocument] = for { + id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead + name <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead + degree <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead + } yield EmployeeDocument( + id = id.getOrElse("123"), + name = name.getOrElse("EmployeeDocument"), + degree = degree.getOrElse("degree") + ) +} From 90f32972ee03be34ec34d105b01afa45a6b2913a Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 6 Dec 2022 15:06:12 +0100 Subject: [PATCH 25/28] Fix code remarks --- .../src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala | 4 ++-- .../src/it/scala/zio/elasticsearch/IntegrationSpec.scala | 4 ++-- .../library/src/main/scala/zio/elasticsearch/package.scala | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala index 9e58340ae..c7d06a6cd 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -11,7 +11,7 @@ object HttpExecutorSpec extends ZIOSpecDefault with IntegrationSpec { suite("HTTP Executor")( suite("get document by ID")( test("successfully get document by ID") { - generateCustomerDocument.flatMap { expectedDoc => + generateCustomer.flatMap { expectedDoc => val returnedDocument = for { docId <- generateId _ <- ElasticRequest.upsert[CustomerDocument](docIndex, docId, expectedDoc).execute @@ -32,7 +32,7 @@ object HttpExecutorSpec extends ZIOSpecDefault with IntegrationSpec { test("unsuccessfully get document by ID if decoder error happens") { val returnedDocument = for { docId <- generateId - newDoc <- generateEmployeeDocument + newDoc <- generateEmployee _ <- ElasticRequest.upsert[EmployeeDocument](docIndex, docId, newDoc).execute returnedDoc <- ElasticRequest.getById[CustomerDocument](docIndex, docId).execute } yield returnedDoc diff --git a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala index 9cd896311..a9cce61c2 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala @@ -13,7 +13,7 @@ trait IntegrationSpec { private[elasticsearch] def generateId: ZIO[Any, Nothing, DocumentId] = Gen.stringBounded(10, 40)(Gen.alphaNumericChar).runHead.map(maybeId => DocumentId(maybeId.getOrElse("DocumentId"))) - private[elasticsearch] def generateCustomerDocument: ZIO[Any, Nothing, CustomerDocument] = for { + private[elasticsearch] def generateCustomer: ZIO[Any, Nothing, CustomerDocument] = for { id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead name <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead address <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead @@ -25,7 +25,7 @@ trait IntegrationSpec { balance = balance.getOrElse(BigDecimal(100)) ) - private[elasticsearch] def generateEmployeeDocument: ZIO[Any, Nothing, EmployeeDocument] = for { + private[elasticsearch] def generateEmployee: ZIO[Any, Nothing, EmployeeDocument] = for { id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead name <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead degree <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index bea118d68..5687e07a3 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -44,6 +44,6 @@ package object elasticsearch { type IndexName = IndexName.Type def containsAny(name: String, params: List[String]): Boolean = - params.exists(p => StringUtils.contains(name, p)) + params.exists(StringUtils.contains(name, _)) } From 5174e25346b354df83247cca08ef653e1ff57bea Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 6 Dec 2022 16:49:35 +0100 Subject: [PATCH 26/28] Refactor tests --- .../zio/elasticsearch/HttpExecutorSpec.scala | 38 ++++++++-------- .../zio/elasticsearch/IntegrationSpec.scala | 45 ++++++++++--------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala index c7d06a6cd..bbb8a9c60 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -5,39 +5,37 @@ import zio.test.Assertion.equalTo import zio.test.TestAspect.nondeterministic import zio.test._ -object HttpExecutorSpec extends ZIOSpecDefault with IntegrationSpec { +object HttpExecutorSpec extends IntegrationSpec { override def spec: Spec[TestEnvironment, Any] = suite("HTTP Executor")( suite("get document by ID")( test("successfully get document by ID") { - generateCustomer.flatMap { expectedDoc => + checkOnes(genDocId, genCustomer) { (documentId, customerDocument) => val returnedDocument = for { - docId <- generateId - _ <- ElasticRequest.upsert[CustomerDocument](docIndex, docId, expectedDoc).execute - returnedDoc <- ElasticRequest.getById[CustomerDocument](docIndex, docId).execute - } yield returnedDoc + _ <- ElasticRequest.upsert[CustomerDocument](docIndex, documentId, customerDocument).execute + returnedDocument <- ElasticRequest.getById[CustomerDocument](docIndex, documentId).execute + } yield returnedDocument - assertZIO(returnedDocument)(Assertion.isRight(equalTo(expectedDoc))) + assertZIO(returnedDocument)(Assertion.isRight(equalTo(customerDocument))) } }, test("unsuccessfully get document by ID if it does not exists") { - val returnedDocument = for { - docId <- generateId - returnedDoc <- ElasticRequest.getById[CustomerDocument](docIndex, docId).execute - } yield returnedDoc - - assertZIO(returnedDocument)(Assertion.isLeft(equalTo(DocumentNotFound))) + checkOnes(genDocId) { documentId => + assertZIO(ElasticRequest.getById[CustomerDocument](docIndex, documentId).execute)( + Assertion.isLeft(equalTo(DocumentNotFound)) + ) + } }, test("unsuccessfully get document by ID if decoder error happens") { - val returnedDocument = for { - docId <- generateId - newDoc <- generateEmployee - _ <- ElasticRequest.upsert[EmployeeDocument](docIndex, docId, newDoc).execute - returnedDoc <- ElasticRequest.getById[CustomerDocument](docIndex, docId).execute - } yield returnedDoc + checkOnes(genDocId, genEmployee) { (documentId, employeeDocument) => + val returnedDocument = for { + _ <- ElasticRequest.upsert[EmployeeDocument](docIndex, documentId, employeeDocument).execute + returnedDocument <- ElasticRequest.getById[CustomerDocument](docIndex, documentId).execute + } yield returnedDocument - assertZIO(returnedDocument)(Assertion.isLeft(equalTo(DecoderError(".address(missing)")))) + assertZIO(returnedDocument)(Assertion.isLeft(equalTo(DecoderError(".address(missing)")))) + } } ) @@ nondeterministic ).provideShared(elasticsearchLayer) diff --git a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala index a9cce61c2..7a57034c5 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala @@ -1,37 +1,40 @@ package zio.elasticsearch import sttp.client3.httpclient.zio.HttpClientZioBackend -import zio.{ZIO, ZLayer} -import zio.test.Gen +import zio.ZLayer +import zio.test.CheckVariants.CheckN +import zio.test.{Gen, ZIOSpecDefault, checkN} -trait IntegrationSpec { +trait IntegrationSpec extends ZIOSpecDefault { private[elasticsearch] val elasticsearchLayer: ZLayer[Any, Throwable, ElasticExecutor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local private[elasticsearch] val docIndex: IndexName = IndexName("users") - private[elasticsearch] def generateId: ZIO[Any, Nothing, DocumentId] = - Gen.stringBounded(10, 40)(Gen.alphaNumericChar).runHead.map(maybeId => DocumentId(maybeId.getOrElse("DocumentId"))) + private[elasticsearch] def genDocId: Gen[Any, DocumentId] = + Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) - private[elasticsearch] def generateCustomer: ZIO[Any, Nothing, CustomerDocument] = for { - id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead - name <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead - address <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead - balance <- Gen.bigDecimal(100, 10000).runHead + private[elasticsearch] def genCustomer: Gen[Any, CustomerDocument] = for { + id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar) + name <- Gen.stringBounded(5, 10)(Gen.alphaChar) + address <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar) + balance <- Gen.bigDecimal(100, 10000) } yield CustomerDocument( - id = id.getOrElse("123"), - name = name.getOrElse("CustomerDocument"), - address = address.getOrElse("address 1"), - balance = balance.getOrElse(BigDecimal(100)) + id = id, + name = name, + address = address, + balance = balance ) - private[elasticsearch] def generateEmployee: ZIO[Any, Nothing, EmployeeDocument] = for { - id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar).runHead - name <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead - degree <- Gen.stringBounded(5, 10)(Gen.alphaChar).runHead + private[elasticsearch] def genEmployee: Gen[Any, EmployeeDocument] = for { + id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar) + name <- Gen.stringBounded(5, 10)(Gen.alphaChar) + degree <- Gen.stringBounded(5, 10)(Gen.alphaChar) } yield EmployeeDocument( - id = id.getOrElse("123"), - name = name.getOrElse("EmployeeDocument"), - degree = degree.getOrElse("degree") + id = id, + name = name, + degree = degree ) + + private[elasticsearch] def checkOnes: CheckN = checkN(1) } From cdb6b3f95c10f688dbd100aa0b00d6b679cb00e3 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Wed, 7 Dec 2022 09:28:41 +0100 Subject: [PATCH 27/28] Fix code remarks --- .../zio/elasticsearch/HttpExecutorSpec.scala | 36 +++++++++---------- .../zio/elasticsearch/IntegrationSpec.scala | 24 ++++--------- 2 files changed, 25 insertions(+), 35 deletions(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala index bbb8a9c60..c26ea94d9 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -9,32 +9,32 @@ object HttpExecutorSpec extends IntegrationSpec { override def spec: Spec[TestEnvironment, Any] = suite("HTTP Executor")( - suite("get document by ID")( - test("successfully get document by ID") { - checkOnes(genDocId, genCustomer) { (documentId, customerDocument) => - val returnedDocument = for { - _ <- ElasticRequest.upsert[CustomerDocument](docIndex, documentId, customerDocument).execute - returnedDocument <- ElasticRequest.getById[CustomerDocument](docIndex, documentId).execute - } yield returnedDocument + suite("retrieving document by ID")( + test("successfully return document") { + checkOnce(genDocumentId, genCustomer) { (documentId, customer) => + val result = for { + _ <- ElasticRequest.upsert[CustomerDocument](index, documentId, customer).execute + document <- ElasticRequest.getById[CustomerDocument](index, documentId).execute + } yield document - assertZIO(returnedDocument)(Assertion.isRight(equalTo(customerDocument))) + assertZIO(result)(Assertion.isRight(equalTo(customer))) } }, - test("unsuccessfully get document by ID if it does not exists") { - checkOnes(genDocId) { documentId => - assertZIO(ElasticRequest.getById[CustomerDocument](docIndex, documentId).execute)( + test("return DocumentNotFound if the document does not exist") { + checkOnce(genDocumentId) { documentId => + assertZIO(ElasticRequest.getById[CustomerDocument](index, documentId).execute)( Assertion.isLeft(equalTo(DocumentNotFound)) ) } }, - test("unsuccessfully get document by ID if decoder error happens") { - checkOnes(genDocId, genEmployee) { (documentId, employeeDocument) => - val returnedDocument = for { - _ <- ElasticRequest.upsert[EmployeeDocument](docIndex, documentId, employeeDocument).execute - returnedDocument <- ElasticRequest.getById[CustomerDocument](docIndex, documentId).execute - } yield returnedDocument + test("fail with decoding error") { + checkOnce(genDocumentId, genEmployee) { (documentId, employee) => + val result = for { + _ <- ElasticRequest.upsert[EmployeeDocument](index, documentId, employee).execute + document <- ElasticRequest.getById[CustomerDocument](index, documentId).execute + } yield document - assertZIO(returnedDocument)(Assertion.isLeft(equalTo(DecoderError(".address(missing)")))) + assertZIO(result)(Assertion.isLeft(equalTo(DecoderError(".address(missing)")))) } } ) @@ nondeterministic diff --git a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala index 7a57034c5..c5d598a80 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala @@ -9,32 +9,22 @@ trait IntegrationSpec extends ZIOSpecDefault { private[elasticsearch] val elasticsearchLayer: ZLayer[Any, Throwable, ElasticExecutor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local - private[elasticsearch] val docIndex: IndexName = IndexName("users") + val index: IndexName = IndexName("users") - private[elasticsearch] def genDocId: Gen[Any, DocumentId] = - Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) + def genDocumentId: Gen[Any, DocumentId] = Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) - private[elasticsearch] def genCustomer: Gen[Any, CustomerDocument] = for { + def genCustomer: Gen[Any, CustomerDocument] = for { id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar) name <- Gen.stringBounded(5, 10)(Gen.alphaChar) address <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar) balance <- Gen.bigDecimal(100, 10000) - } yield CustomerDocument( - id = id, - name = name, - address = address, - balance = balance - ) + } yield CustomerDocument(id = id, name = name, address = address, balance = balance) - private[elasticsearch] def genEmployee: Gen[Any, EmployeeDocument] = for { + def genEmployee: Gen[Any, EmployeeDocument] = for { id <- Gen.stringBounded(5, 10)(Gen.alphaNumericChar) name <- Gen.stringBounded(5, 10)(Gen.alphaChar) degree <- Gen.stringBounded(5, 10)(Gen.alphaChar) - } yield EmployeeDocument( - id = id, - name = name, - degree = degree - ) + } yield EmployeeDocument(id = id, name = name, degree = degree) - private[elasticsearch] def checkOnes: CheckN = checkN(1) + def checkOnce: CheckN = checkN(1) } From 56df2f358aa7284f17675da78a88cc459bf6eb48 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Wed, 7 Dec 2022 10:10:58 +0100 Subject: [PATCH 28/28] Refactor IntegrationSpec --- .../src/it/scala/zio/elasticsearch/IntegrationSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala index c5d598a80..1a19661a9 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/IntegrationSpec.scala @@ -6,7 +6,7 @@ import zio.test.CheckVariants.CheckN import zio.test.{Gen, ZIOSpecDefault, checkN} trait IntegrationSpec extends ZIOSpecDefault { - private[elasticsearch] val elasticsearchLayer: ZLayer[Any, Throwable, ElasticExecutor] = + val elasticsearchLayer: ZLayer[Any, Throwable, ElasticExecutor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local val index: IndexName = IndexName("users")