From e3a6795b3d1bb46a0e0693ffb7fe5be2430b30db Mon Sep 17 00:00:00 2001 From: Ivar Ness Date: Thu, 5 Sep 2024 11:56:08 +0200 Subject: [PATCH 1/3] Added test for validation of graphql schema --- .../test-compile/build.sbt | 3 +- .../src/test/resources/postservice.graphql | 54 +++++++++++++++++++ .../src/test/scala/ValidateGraphQlSpec.scala | 24 +++++++++ .../compiletime-codegen/test-compile/test | 2 + 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/resources/postservice.graphql create mode 100644 codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/scala/ValidateGraphQlSpec.scala diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt index 0c11a36917..431895e826 100644 --- a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt @@ -38,6 +38,7 @@ lazy val sttp = Seq( "com.softwaremill.sttp.client3" %% "zio" % "3.9.8" ) +lazy val zioTest = Seq("dev.zio" %% "zio-test" % "2.1.9" % Test) // ### App Modules ### /** @@ -103,7 +104,7 @@ lazy val posts = ) ) ) - .settings(libraryDependencies ++= calibanLib) + .settings(libraryDependencies ++= calibanLib ++ zioTest) lazy val potatoes = project diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/resources/postservice.graphql b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/resources/postservice.graphql new file mode 100644 index 0000000000..71122441c4 --- /dev/null +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/resources/postservice.graphql @@ -0,0 +1,54 @@ +schema { + query: Query + mutation: Mutation + subscription: Subscription +} +scalar Unit + +input AuthorNameInput { + name: String! +} + +input PostContentInput { + content: String! +} + +input PostTitleInput { + title: String! +} + +type AuthorName { + name: String! +} + +type Mutation { + createPost(authorName: AuthorNameInput!, title: PostTitleInput!, content: PostContentInput!): Post + deletePost(id: ID!): Unit +} + +type Post { + id: PostId! + author: AuthorName! + title: PostTitle! + content: PostContent! +} + +type PostContent { + content: String! +} + +type PostId { + id: ID! +} + +type PostTitle { + title: String! +} + +type Query { + postById(id: ID!): Post +} + +type Subscription { + allPostsByAuthor(name: String!): Post +} \ No newline at end of file diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/scala/ValidateGraphQlSpec.scala b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/scala/ValidateGraphQlSpec.scala new file mode 100644 index 0000000000..4d688e3337 --- /dev/null +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/scala/ValidateGraphQlSpec.scala @@ -0,0 +1,24 @@ +import poc.caliban.posts.GraphQLApi + +import scala.io.Source +import java.io.File +import java.nio.file.{Files, Paths} +import zio.test.Assertion._ +import zio.test._ + +class ValidateGraphQlSpec extends ZIOSpecDefault { + + override def spec = + suite("Validate Postservice")( + test("Render postservice as earlier") { + val filename = "postservice.graphql" + val expectedGraphQL: String = Source.fromResource(filename).getLines().mkString("\n") + val gqlApi = GraphQLApi.api + val renderContent: String = s"${gqlApi.render}" + + //Files.writeString(Paths.get(File(s"/tmp/$filename").toURI), renderContent) + + assertTrue(expectedGraphQL == renderContent) + } + ) +} \ No newline at end of file diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/test b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/test index e063c05659..1ad20505c5 100644 --- a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/test +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/test @@ -201,3 +201,5 @@ $ exists modules/potatoes-clients/src/main/scala/poc/caliban/client/generated/po -$ newer modules/posts/target/ctCalibanServer/touch modules/posts/target/ctCalibanServer/touch_old # TODO: This should be newer, sadly I don't find how to make it work. -$ newer modules/posts-clients/target/scala-2.12/src_managed/main/poc/caliban/client/generated/posts/CalibanClient.scala modules/posts-clients/tmp/CalibanClient.scala.old + +> reload; test \ No newline at end of file From 06e65de3e2519d3453b50cbe32b686521a46cc74 Mon Sep 17 00:00:00 2001 From: Ivar Ness Date: Mon, 9 Sep 2024 12:26:43 +0200 Subject: [PATCH 2/3] Added snapshotTest for reuse --- build.sbt | 46 ++++++++--- .../test-compile/README.md | 13 ++- .../test-compile/build.sbt | 16 ++-- .../src/test/scala/ValidateGraphQlSpec.scala | 16 ++-- .../test-compile/project/Version.scala | 8 ++ .../scala/caliban/tools/SnapshotTest.scala | 81 +++++++++++-------- 6 files changed, 121 insertions(+), 59 deletions(-) create mode 100644 codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/project/Version.scala diff --git a/build.sbt b/build.sbt index 1486e01f98..f1c0326296 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,8 @@ import com.typesafe.tools.mima.core.* import org.scalajs.linker.interface.ModuleSplitStyle import sbtcrossproject.CrossPlugin.autoImport.{ crossProject, CrossType } +import sbt.* +import Keys.* val scala212 = "2.12.20" val scala213 = "2.13.15" @@ -215,7 +217,24 @@ lazy val tools = project "dev.zio" %% "zio-test" % zioVersion % Test, "dev.zio" %% "zio-test-sbt" % zioVersion % Test, "dev.zio" %% "zio-json" % zioJsonVersion % Test - ) + ), + Test / publishArtifact := true, + + // Include test artifact for publishLocal + publishLocalConfiguration := { + val config = publishLocalConfiguration.value + val testArtifacts = (Test / packagedArtifacts).value + config.withArtifacts(config.artifacts ++ testArtifacts).withOverwrite(true) + }, + // Exclude test artifact from publish + publishConfiguration := { + val config = publishConfiguration.value + config + .withArtifacts(config.artifacts.filterNot { case (artifact, _) => + artifact.configurations.exists(_.name == "test") + }) + .withOverwrite(true) + } ) .dependsOn(core, clientJVM, quickAdapter % Test) @@ -266,18 +285,25 @@ lazy val codegenSbt = project .settings( scriptedLaunchOpts := { scriptedLaunchOpts.value ++ - Seq("-Xmx1024M", "-Xss4M", "-Dplugin.version=" + version.value) + Seq( + "-Xmx1024M", + "-Xss4M", + "-Dplugin.version=" + version.value, + s"-Dproject.dir=${baseDirectory.value.getAbsolutePath}" + ) }, scriptedBufferLog := false, - scriptedDependencies := { - (macros / publishLocal).value - (core / publishLocal).value - (clientJVM / publishLocal).value - (tools / publishLocal).value - publishLocal.value - } + scriptedDependencies := scriptedDependencies + .dependsOn( + macros / publishLocal, + core / publishLocal, + clientJVM / publishLocal, + tools / publishLocal, + publishLocal + ) + .value ) - .dependsOn(tools) + .dependsOn(tools % "compile->compile;test->test") lazy val catsInterop = project .in(file("interop/cats")) diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/README.md b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/README.md index a800a35731..7105d0528b 100644 --- a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/README.md +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/README.md @@ -1,3 +1,14 @@ # Test doc -This test project has been copied from: https://github.com/guizmaii/poc_compile_time_caliban_client_generation \ No newline at end of file +This test project has been copied from: +https://github.com/guizmaii/poc_compile_time_caliban_client_generation + +### Running locally +You can run these tests using following sbt commandos: + +```sbt +project codegenSbt +++2.12.20 +update +scripted compiletime-codegen/test-compile +``` diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt index 431895e826..74aaa6acd1 100644 --- a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt @@ -26,19 +26,20 @@ ThisBuild / crossScalaVersions := allScala // ### Dependencies ### -lazy val calibanLib: Seq[ModuleID] = - sys.props.get("plugin.version") match { - case Some(x) => Seq("com.github.ghostdogpr" %% "caliban" % x) - case _ => sys.error("""|The system property 'plugin.version' is not defined. - |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) - } +lazy val calibanLib = Seq( + "com.github.ghostdogpr" %% "caliban" % Version.pluginVersion, + "com.github.ghostdogpr" %% "caliban-tools" % Version.pluginVersion % "compile->compile;test->test" +) lazy val sttp = Seq( "com.softwaremill.sttp.client3" %% "core" % "3.9.8", "com.softwaremill.sttp.client3" %% "zio" % "3.9.8" ) -lazy val zioTest = Seq("dev.zio" %% "zio-test" % "2.1.9" % Test) +lazy val zioTest = Seq( + "dev.zio" %% "zio-test" % "2.1.9" % Test, + "dev.zio" %% "zio-test-sbt" % "2.1.9" % Test +) // ### App Modules ### /** @@ -106,6 +107,7 @@ lazy val posts = ) .settings(libraryDependencies ++= calibanLib ++ zioTest) + lazy val potatoes = project .in(file("modules/potatoes")) diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/scala/ValidateGraphQlSpec.scala b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/scala/ValidateGraphQlSpec.scala index 4d688e3337..c6bc4f8492 100644 --- a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/scala/ValidateGraphQlSpec.scala +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/scala/ValidateGraphQlSpec.scala @@ -1,24 +1,24 @@ import poc.caliban.posts.GraphQLApi import scala.io.Source -import java.io.File -import java.nio.file.{Files, Paths} import zio.test.Assertion._ import zio.test._ +import caliban.tools._ +import java.nio.file.Path -class ValidateGraphQlSpec extends ZIOSpecDefault { +object ValidateGraphQlSpec extends SnapshotTest { + override val testName: String = "ValidateGraphQlSpec" + + val graphqlFile= "src/sbt-test/compiletime-codegen/test-compile/modules/posts/src/test/resources/postservice.graphql" + val projectDir = sys.props.get("project.dir").getOrElse("") override def spec = suite("Validate Postservice")( test("Render postservice as earlier") { - val filename = "postservice.graphql" - val expectedGraphQL: String = Source.fromResource(filename).getLines().mkString("\n") val gqlApi = GraphQLApi.api val renderContent: String = s"${gqlApi.render}" - //Files.writeString(Paths.get(File(s"/tmp/$filename").toURI), renderContent) - - assertTrue(expectedGraphQL == renderContent) + writeAndCompare(Path.of(projectDir).resolve(graphqlFile), renderContent, "Render postservice") } ) } \ No newline at end of file diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/project/Version.scala b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/project/Version.scala new file mode 100644 index 0000000000..d2c7cd4b18 --- /dev/null +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/project/Version.scala @@ -0,0 +1,8 @@ +object Version { + def pluginVersion: String = + sys.props.get("plugin.version") match { + case Some(x) => x + case _ => sys.error("""|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) + } +} diff --git a/tools/src/test/scala/caliban/tools/SnapshotTest.scala b/tools/src/test/scala/caliban/tools/SnapshotTest.scala index aa88ed8b64..99d9745706 100644 --- a/tools/src/test/scala/caliban/tools/SnapshotTest.scala +++ b/tools/src/test/scala/caliban/tools/SnapshotTest.scala @@ -2,7 +2,9 @@ package caliban.tools import caliban.tools.SnapshotTest.GitLock import zio.internal.stacktracer.SourceLocation -import zio.test.{ assert, assertTrue, Assertion, Spec, TestResult, ZIOSpecDefault } +import zio.prelude._ +import zio.test.Assertion.equalTo +import zio.test.{ assert, assertNever, assertTrue, Assertion, Spec, TestResult, ZIOSpecDefault } import zio.{ Task, Trace } import java.nio.file.{ Files, Path } @@ -16,51 +18,64 @@ trait SnapshotTest extends ZIOSpecDefault { )(str: Task[String])(implicit sourceLocation: SourceLocation, trace: Trace): Spec[Any, Throwable] = { val label = label0.replace('/', '_').replace("'", "") zio.test.test[Task[TestResult]](label) { - str.map { str => - val isCi = SnapshotTest.isCi + str.map { content => val path = SnapshotTest.projectRoot.resolve(s"tools/src/test/resources/snapshots/$testName/${label + ".scala"}") + writeAndCompare(path, content, label) + } + } + } - def write(): TestResult = { - Files.createDirectories(path.getParent) - Files.writeString(path, str) - import scala.sys.process._ - // at least don't take the git lock multiple times from same process. this can still fail if concurrent processes try to take it. - GitLock.synchronized { - // allow failing external command, but complain to stderr - try s"git add '$path'".! - catch { - case th: Throwable => - System.err.println(s"Could not add snapshot file '$path' to git: ${th.getMessage}") - } - } - assert(())(Assertion.anything) - } + private def write(path: Path, str: String): TestResult = { + Files.createDirectories(path.getParent) + Files.writeString(path, str) + import scala.sys.process._ - Try(Files.readString(path)) match { - case Success(existing) if isCi => - assertTrue(str == existing).label( - s"generated result for test '$label' did not match snapshot contents in file '$path. Rerun with environment `CI` not set to 'true' to update and then check in the file" - ) - case Success(_) => - write() - case Failure(_) if isCi => - assertTrue(false).label( - s"Could not read snapshot file '$path'. Rerun with environment `CI` not set to 'true' to create and then check in the file" - ) - case Failure(_) => - write() + var exitCode = 0 + // at least don't take the git lock multiple times from same process. this can still fail if concurrent processes try to take it. + GitLock.synchronized { + // allow failing external command, but complain to stderr + exitCode = + try + s"git add '$path'".! + catch { + case th: Throwable => + System.err.println(s"Could not add snapshot file '$path' to git: ${th.getMessage}") + -1 } - } + } + + if (exitCode == 0) { + assert(())(Assertion.anything) + } else { + assertNever(s"Failed to add file '$path' to git. Exit code: $exitCode") } } + def writeAndCompare(path: Path, content: String, label: String): TestResult = + Try(Files.readString(path)) match { + case Success(existing) if SnapshotTest.isCi => + assertTrue(content == existing).label( + s"generated result for test '$label' did not match snapshot contents in file '$path. Rerun with environment `CI` not set to 'true' to update and then check in the file" + ) + case Success(existing) if existing.equals(content) => + assert(())(Assertion.anything) + case Success(_) => + write(path, content) + case Failure(_) if SnapshotTest.isCi => + assertTrue(false).label( + s"Could not read snapshot file '$path'. Rerun with environment `CI` not set to 'true' to create and then check in the file" + ) + case Failure(_) => + write(path, content) + } + } object SnapshotTest { val `.git`: Path = Path.of(".git") val cwd: Path = Path.of(sys.props("user.dir")) - val projectRoot: Path = { + lazy val projectRoot: Path = { def lookUpwards(p: Path): Option[Path] = if (Files.list(p).anyMatch(p => p.getFileName == `.git`)) Some(p) else Option(p.getParent).flatMap(lookUpwards) From d4abf0a797a38f31ddaaea60568f36d1186bec33 Mon Sep 17 00:00:00 2001 From: Ivar Ness Date: Sun, 29 Sep 2024 13:39:41 +0200 Subject: [PATCH 3/3] Fixed formatting and updated README.md --- .../src/sbt-test/compiletime-codegen/test-compile/README.md | 2 +- .../src/sbt-test/compiletime-codegen/test-compile/build.sbt | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/README.md b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/README.md index 7105d0528b..b1629c1e88 100644 --- a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/README.md +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/README.md @@ -8,7 +8,7 @@ You can run these tests using following sbt commandos: ```sbt project codegenSbt -++2.12.20 +++2.12 update scripted compiletime-codegen/test-compile ``` diff --git a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt index 74aaa6acd1..6223f3d0ee 100644 --- a/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt +++ b/codegen-sbt/src/sbt-test/compiletime-codegen/test-compile/build.sbt @@ -27,7 +27,7 @@ ThisBuild / crossScalaVersions := allScala // ### Dependencies ### lazy val calibanLib = Seq( - "com.github.ghostdogpr" %% "caliban" % Version.pluginVersion, + "com.github.ghostdogpr" %% "caliban" % Version.pluginVersion, "com.github.ghostdogpr" %% "caliban-tools" % Version.pluginVersion % "compile->compile;test->test" ) @@ -37,7 +37,7 @@ lazy val sttp = Seq( ) lazy val zioTest = Seq( - "dev.zio" %% "zio-test" % "2.1.9" % Test, + "dev.zio" %% "zio-test" % "2.1.9" % Test, "dev.zio" %% "zio-test-sbt" % "2.1.9" % Test ) // ### App Modules ### @@ -107,7 +107,6 @@ lazy val posts = ) .settings(libraryDependencies ++= calibanLib ++ zioTest) - lazy val potatoes = project .in(file("modules/potatoes"))