From d3fa113d99c96b84d0efb0414e8f4294301c890c Mon Sep 17 00:00:00 2001 From: Dmitry Karlinsky Date: Thu, 15 Jun 2023 12:43:13 +0300 Subject: [PATCH] netty-shading: adding testing step (#2253) * netty-shading: adding testing step * runs subset of tests from zio-http against locally published shaded jar * set scalas in the ci step * scalafmt * trying run step with `++$Scala213!` * trying to fix sbt command * trying to use env var (PUBLISH_SHADED) * trying to debug testing step * moving steps to postamble * attempting to appease scalafix --- .github/workflows/ci.yml | 9 +++- build.sbt | 51 ++++++++++++++++++- project/Shading.scala | 15 +++++- .../test/scala/zio/http/ClientHttpsSpec.scala | 7 +-- .../src/test/scala/zio/http/HeaderSpec.scala | 20 ++++---- .../src/test/scala/zio/http/SSLSpec.scala | 7 ++- .../src/test/scala/zio/http/ServerSpec.scala | 7 ++- .../scala/zio/http/internal/HttpGen.scala | 5 -- 8 files changed, 87 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5004d27ed..5833b6c135 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,12 @@ jobs: if: ${{ github.event_name == 'pull_request' }} run: sbt ++2.13.8 doc + - name: zio-http-shaded Tests + if: matrix.scala == '2.13.8' + env: + PUBLISH_SHADED: true + run: sbt ++${{ matrix.scala }} zioHttpShadedTests/test + - name: Compress target directories run: tar cf targets.tar zio-http-cli/target target zio-http/target zio-http-docs/target zio-http-benchmarks/target zio-http-example/target zio-http-testkit/target project/target @@ -167,10 +173,11 @@ jobs: env: PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + PUBLISH_SHADED: true CI_SONATYPE_RELEASE: ${{ secrets.CI_SONATYPE_RELEASE }} SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} PGP_SECRET: ${{ secrets.PGP_SECRET }} - run: sbt ++${{ matrix.scala }} -Dpublish.shaded=true ci-release + run: sbt ++${{ matrix.scala }} ci-release update_release_draft: name: Release Drafter diff --git a/build.sbt b/build.sbt index 71beeca1f3..d431f972e0 100644 --- a/build.sbt +++ b/build.sbt @@ -45,9 +45,10 @@ ThisBuild / githubWorkflowPublish := ), ), WorkflowStep.Sbt( - List("-Dpublish.shaded=true", "ci-release"), + List("ci-release"), name = Some("Release Shaded"), env = Map( + Shading.env.PUBLISH_SHADED -> "true", "PGP_PASSPHRASE" -> "${{ secrets.PGP_PASSPHRASE }}", "PGP_SECRET" -> "${{ secrets.PGP_SECRET }}", "SONATYPE_PASSWORD" -> "${{ secrets.SONATYPE_PASSWORD }}", @@ -78,7 +79,18 @@ ThisBuild / githubWorkflowBuildPostamble := ), ), scalas = List(Scala213), - ).steps + ).steps ++ + WorkflowJob( + id = "zio-http-shaded-tests", + name = "Test shaded version of zio-http", + steps = List( + WorkflowStep.Sbt( + name = Some("zio-http-shaded Tests"), + commands = List("zioHttpShadedTests/test"), + cond = Some(s"matrix.scala == '$Scala213'"), + env = Map(Shading.env.PUBLISH_SHADED -> "true") + )) + ).steps inThisBuild( List( @@ -126,6 +138,41 @@ lazy val zioHttp = (project in file("zio-http")) }, ) +/** + * Special subproject to sanity test the shaded version of zio-http. + * Run using `sbt -Dpublish.shaded zioHttpShadedTests/test`. + * This will trigger `publishLocal` on zio-http and then run tests using the shaded artifact as a dependency, instead of zio-http classes. + */ +lazy val zioHttpShadedTests = if(Shading.shadingEnabled) { + (project in file("zio-http-shaded-tests")) + .settings(stdSettings("zio-http-shaded-tests")) + .settings( + Compile / sources := Nil, + Test / sources := ( + baseDirectory.value / ".." / "zio-http" / "src" / "test" / "scala" ** "*.scala" --- + // Exclude tests of netty specific internal stuff + baseDirectory.value / ".." / "zio-http" / "src" / "test" / "scala" ** "netty" ** "*.scala" + ).get, + Test / scalaSource := (baseDirectory.value / ".." / "zio-http" / "src" / "test" / "scala"), + Test / resourceDirectory := (baseDirectory.value / ".." / "zio-http" / "src" / "test" / "resources"), + testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"), + libraryDependencies ++= Seq( + `zio-test-sbt`, + `zio-test`, + "dev.zio" %% "zio-http-shaded" % version.value, + ) + ) + .settings(publishSetting(false)) + .settings(Test / test := (Test / test).dependsOn(zioHttp / publishLocal).value) +} else { + (project in file(".")).settings( + Compile / sources := Nil, + Test / sources := Nil, + name := "noop", + publish / skip := true, + ) +} + lazy val zioHttpBenchmarks = (project in file("zio-http-benchmarks")) .enablePlugins(JmhPlugin) .settings(stdSettings("zio-http-benchmarks")) diff --git a/project/Shading.scala b/project/Shading.scala index af86cdcdb3..c76c6a61dc 100644 --- a/project/Shading.scala +++ b/project/Shading.scala @@ -4,6 +4,14 @@ import coursier.ShadingPlugin.autoImport._ import sbt.Plugins object Shading { + object env { + val PUBLISH_SHADED = "PUBLISH_SHADED" + } + + object sysprops { + val `publish.shaded` = "publish.shaded" + } + def shadingSettings() = if (shadingEnabled) { Seq( shadedModules ++= (netty :+ `netty-incubator`).map(_.module).toSet, @@ -12,8 +20,11 @@ object Shading { ) } else Nil - def shadingEnabled = { - sys.props.get("publish.shaded").fold(false)(_.toBoolean) + lazy val shadingEnabled = { + val enabled = sys.props.get(sysprops.`publish.shaded`).fold(false)(_.toBoolean) || + sys.env.get(env.PUBLISH_SHADED).fold(false)(_.toBoolean) + println(s"*** shading enabled: $enabled (env.PUBLISH_SHADED=${sys.env.get(env.PUBLISH_SHADED)}, sysprops.`publish.shaded`=${sys.props.get(sysprops.`publish.shaded`)})") + enabled } def plugins(): Seq[Plugins] = if(shadingEnabled) Seq(ShadingPlugin) else Nil diff --git a/zio-http/src/test/scala/zio/http/ClientHttpsSpec.scala b/zio-http/src/test/scala/zio/http/ClientHttpsSpec.scala index d0b3818b7e..ed1d17adda 100644 --- a/zio-http/src/test/scala/zio/http/ClientHttpsSpec.scala +++ b/zio-http/src/test/scala/zio/http/ClientHttpsSpec.scala @@ -16,17 +16,14 @@ package zio.http -import zio.test.Assertion.{anything, equalTo, fails, isSubtype} +import zio.test.Assertion.{anything, equalTo, fails, hasField} import zio.test.TestAspect.{ignore, timeout} import zio.test.{ZIOSpecDefault, assertZIO} import zio.{Scope, ZLayer, durationInt} -import zio.http.Status import zio.http.netty.NettyConfig import zio.http.netty.client.NettyClientDriver -import io.netty.handler.codec.DecoderException - object ClientHttpsSpec extends ZIOSpecDefault { val sslConfig = ClientSSLConfig.FromTrustStoreResource( @@ -57,7 +54,7 @@ object ClientHttpsSpec extends ZIOSpecDefault { "https://untrusted-root.badssl.com/", ) .exit - assertZIO(actual)(fails(isSubtype[DecoderException](anything))) + assertZIO(actual)(fails(hasField("class.simpleName", _.getClass.getSimpleName, equalTo("DecoderException")))) }, ).provide( ZLayer.succeed(ZClient.Config.default.ssl(sslConfig)), diff --git a/zio-http/src/test/scala/zio/http/HeaderSpec.scala b/zio-http/src/test/scala/zio/http/HeaderSpec.scala index b20cad1afb..c17879d627 100644 --- a/zio-http/src/test/scala/zio/http/HeaderSpec.scala +++ b/zio-http/src/test/scala/zio/http/HeaderSpec.scala @@ -19,8 +19,6 @@ package zio.http import zio.test.Assertion._ import zio.test.{ZIOSpecDefault, assert} -import io.netty.handler.codec.http.{HttpHeaderNames, HttpHeaderValues} - object HeaderSpec extends ZIOSpecDefault { def spec = suite("Header")( @@ -30,30 +28,30 @@ object HeaderSpec extends ZIOSpecDefault { assert(actual)(isNone) }, test("should return header from predefined headers list by String") { - val actual = predefinedHeaders.rawHeader(HttpHeaderNames.CONTENT_TYPE) - assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) + val actual = predefinedHeaders.rawHeader(Header.ContentType.name) + assert(actual)(isSome(equalTo(MediaType.application.json.fullType))) }, test("should return header from predefined headers list by String of another case") { val actual = predefinedHeaders.rawHeader("Content-Type") - assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) + assert(actual)(isSome(equalTo(MediaType.application.json.fullType))) }, test("should return header from predefined headers list by AsciiString") { - val actual = predefinedHeaders.rawHeader(HttpHeaderNames.CONTENT_TYPE) - assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) + val actual = predefinedHeaders.rawHeader(Header.ContentType.name) + assert(actual)(isSome(equalTo(MediaType.application.json.fullType))) }, test("should return header from custom headers list by String") { - val actual = customHeaders.rawHeader(HttpHeaderNames.CONTENT_TYPE) + val actual = customHeaders.rawHeader(Header.ContentType.name) assert(actual)(isSome(equalTo(customContentJsonHeader.renderedValue))) }, test("should return header from custom headers list by AsciiString") { - val actual = customHeaders.rawHeader(HttpHeaderNames.CONTENT_TYPE) + val actual = customHeaders.rawHeader(Header.ContentType.name) assert(actual)(isSome(equalTo(customContentJsonHeader.renderedValue))) }, ), suite("getHeaderValue")( test("should return header value") { - val actual = predefinedHeaders.rawHeader(HttpHeaderNames.CONTENT_TYPE) - assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) + val actual = predefinedHeaders.rawHeader(Header.ContentType.name) + assert(actual)(isSome(equalTo(MediaType.application.json.fullType))) }, ), suite("hasHeader")( diff --git a/zio-http/src/test/scala/zio/http/SSLSpec.scala b/zio-http/src/test/scala/zio/http/SSLSpec.scala index 2db65a40c4..ddd2af7ed4 100644 --- a/zio-http/src/test/scala/zio/http/SSLSpec.scala +++ b/zio-http/src/test/scala/zio/http/SSLSpec.scala @@ -24,8 +24,6 @@ import zio.{Scope, ZIO, ZLayer, durationInt} import zio.http.netty.NettyConfig import zio.http.netty.client.NettyClientDriver -import io.netty.handler.codec.DecoderException - object SSLSpec extends ZIOSpecDefault { val sslConfig = SSLConfig.fromResource("server.crt", "server.key") @@ -66,8 +64,9 @@ object SSLSpec extends ZIOSpecDefault { test("fail with DecoderException when client doesn't have the server certificate") { val actual = Client .request("https://localhost:8073/success") - .catchSome { case _: DecoderException => - ZIO.succeed("DecoderException") + .catchSome { + case e if e.getClass.getSimpleName == "DecoderException" => + ZIO.succeed("DecoderException") } assertZIO(actual)(equalTo("DecoderException")) }.provide( diff --git a/zio-http/src/test/scala/zio/http/ServerSpec.scala b/zio-http/src/test/scala/zio/http/ServerSpec.scala index 33d689a6dc..36a88913e2 100644 --- a/zio-http/src/test/scala/zio/http/ServerSpec.scala +++ b/zio-http/src/test/scala/zio/http/ServerSpec.scala @@ -26,12 +26,9 @@ import zio.{Chunk, Scope, ZIO, ZLayer, durationInt} import zio.stream.{ZPipeline, ZStream} -import zio.http.Server.{Config, RequestStreaming} import zio.http.html.{body, div, id} import zio.http.internal.{DynamicServer, HttpGen, HttpRunnableSpec} -import io.netty.handler.codec.PrematureChannelClosureException - object ServerSpec extends HttpRunnableSpec { private val nonEmptyContent = for { @@ -221,7 +218,9 @@ object ServerSpec extends HttpRunnableSpec { val app = Handler.fromZIO { ZIO.interrupt.as(Response.text("not interrupted")) }.toHttp - assertZIO(app.deploy.run().exit)(failsWithA[PrematureChannelClosureException]) + assertZIO(app.deploy.run().exit)( + fails(hasField("class.simpleName", _.getClass.getSimpleName, equalTo("PrematureChannelClosureException"))), + ) }, ) + suite("proxy") { diff --git a/zio-http/src/test/scala/zio/http/internal/HttpGen.scala b/zio-http/src/test/scala/zio/http/internal/HttpGen.scala index e07231c45f..4d01e77a2f 100644 --- a/zio-http/src/test/scala/zio/http/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zio/http/internal/HttpGen.scala @@ -27,9 +27,6 @@ import zio.http.Header._ import zio.http.Path.Segment import zio.http.URL.Location import zio.http._ -import zio.http.netty.NettyBody - -import io.netty.buffer.Unpooled object HttpGen { def anyPath: Gen[Any, Path] = for { @@ -87,7 +84,6 @@ object HttpGen { ), Body.fromString(list.mkString("")), Body.fromChunk(Chunk.fromArray(list.mkString("").getBytes())), - NettyBody.fromByteBuf(Unpooled.copiedBuffer(list.mkString(""), Charsets.Http)), Body.empty, ), ) @@ -125,7 +121,6 @@ object HttpGen { ), Body.fromString(list.mkString("")), Body.fromChunk(Chunk.fromArray(list.mkString("").getBytes())), - NettyBody.fromByteBuf(Unpooled.copiedBuffer(list.mkString(""), Charsets.Http)), ), ) } yield cnt