From 597415c68826ed4e4b3d7f8ed73d3dcd011d30a1 Mon Sep 17 00:00:00 2001 From: Calvin Lee Fernandes Date: Wed, 11 Sep 2024 03:35:39 -0400 Subject: [PATCH] Implement support for ZIO HTTP 3.0.0 (#4034) --- project/Versions.scala | 6 +-- .../server/ziohttp/ZioHttpInterpreter.scala | 2 +- .../server/ziohttp/ZioHttpServerTest.scala | 39 +++++++++++-------- .../ZioHttpTestServerInterpreter.scala | 13 ++++--- .../zio/http/netty/TestChannelFactories.scala | 9 +++++ .../src/test/scala/zio/test/package.scala | 8 ++-- 6 files changed, 47 insertions(+), 30 deletions(-) create mode 100644 server/zio-http-server/src/test/scala/zio/http/netty/TestChannelFactories.scala diff --git a/project/Versions.scala b/project/Versions.scala index 0082bd575b..f1303241c8 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -35,9 +35,9 @@ object Versions { val refined = "0.11.2" val iron = "2.6.0" val enumeratum = "1.7.4" - val zio = "2.1.8" - val zioHttp = "3.0.0-RC8" - val zioInteropCats = "23.0.0.8" + val zio = "2.1.9" + val zioHttp = "3.0.0" + val zioInteropCats = "23.1.0.3" val zioInteropReactiveStreams = "2.0.2" val zioJson = "0.7.3" val playClient = "3.0.5" diff --git a/server/zio-http-server/src/main/scala/sttp/tapir/server/ziohttp/ZioHttpInterpreter.scala b/server/zio-http-server/src/main/scala/sttp/tapir/server/ziohttp/ZioHttpInterpreter.scala index b9db565d7c..d62875e736 100644 --- a/server/zio-http-server/src/main/scala/sttp/tapir/server/ziohttp/ZioHttpInterpreter.scala +++ b/server/zio-http-server/src/main/scala/sttp/tapir/server/ziohttp/ZioHttpInterpreter.scala @@ -136,7 +136,7 @@ trait ZioHttpInterpreter[R] { val pattern = sesWithPattern.head.routePattern val endpoints = sesWithPattern.sortBy(_.index).map(_.endpoint) // The pattern that we generate should be the same for all endpoints in a group - Route.handled(pattern)(Handler.fromFunctionHandler { (request: Request) => handleRequest(request, endpoints) }) + Route.handledIgnoreParams(pattern)(Handler.fromFunctionHandler { (request: Request) => handleRequest(request, endpoints) }) } Routes(Chunk.fromIterable(handlers)) diff --git a/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpServerTest.scala b/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpServerTest.scala index 9e266d72d8..6a079c2cd8 100644 --- a/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpServerTest.scala +++ b/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpServerTest.scala @@ -4,7 +4,6 @@ import cats.effect.IO import cats.effect.Resource import cats.implicits.toTraverseOps import io.netty.channel.ChannelFactory -import io.netty.channel.EventLoopGroup import io.netty.channel.ServerChannel import org.scalatest.Assertion import org.scalatest.Exceptional @@ -38,9 +37,6 @@ import zio.http.Middleware import zio.http.Path import zio.http.Request import zio.http.URL -import zio.http.netty.ChannelFactories -import zio.http.netty.ChannelType -import zio.http.netty.EventLoopGroups import zio.interop.catz._ import zio.stream import zio.stream.ZPipeline @@ -51,6 +47,10 @@ import java.time import scala.concurrent.Future import scala.concurrent.duration.DurationInt import zio.stream.ZSink +import zio.http.netty.NettyConfig +import zio.http.netty.ChannelType +import zio.http.netty.server.ServerEventLoopGroups +import _root_.zio.http.netty.TestChannelFactories class ZioHttpServerTest extends TestSuite { @@ -75,22 +75,27 @@ class ZioHttpServerTest extends TestSuite { implicit val r: Runtime[Any] = Runtime.default // creating the netty dependencies once, to speed up tests Resource - .scoped[IO, Any, ZEnvironment[EventLoopGroup with ChannelFactory[ServerChannel]]]({ - val eventConfig = ZLayer.succeed(new EventLoopGroups.Config { - def channelType = ChannelType.AUTO - val nThreads = 0 - val shutdownQuietPeriod = 0 - val shutdownTimeOut = 0 - val shutdownTimeUnit = scala.concurrent.duration.SECONDS - }) + .scoped[IO, Any, ZEnvironment[ServerEventLoopGroups with ChannelFactory[ServerChannel]]]({ + val eventConfig = ZLayer.succeed( + NettyConfig.default.bossGroup( + NettyConfig.BossGroup( + channelType = ChannelType.AUTO, + nThreads = 0, + shutdownQuietPeriodDuration = zio.Duration.fromSeconds(0), + shutdownTimeOutDuration = zio.Duration.fromSeconds(0) + ) + ) + ) val channelConfig: ZLayer[Any, Nothing, ChannelType.Config] = eventConfig - (channelConfig >>> ChannelFactories.Server.fromConfig) ++ (eventConfig >>> EventLoopGroups.live) + val channelFactory = (channelConfig >>> TestChannelFactories.config) + val groups = (eventConfig >>> ServerEventLoopGroups.live) + (groups ++ channelFactory) }.build) - .map { nettyDeps => - val eventLoopGroup = ZLayer.succeed(nettyDeps.get[EventLoopGroup]) - val channelFactory = ZLayer.succeed(nettyDeps.get[ChannelFactory[ServerChannel]]) - val interpreter = new ZioHttpTestServerInterpreter(eventLoopGroup, channelFactory) + .map { environment => + val groups = environment.get[ServerEventLoopGroups] + val factory = environment.get[ChannelFactory[ServerChannel]] + val interpreter = new ZioHttpTestServerInterpreter(groups, factory) val createServerTest = new DefaultCreateServerTest(backend, interpreter) def additionalTests(): List[Test] = List( diff --git a/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpTestServerInterpreter.scala b/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpTestServerInterpreter.scala index 146367809c..38af1fb3d5 100644 --- a/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpTestServerInterpreter.scala +++ b/server/zio-http-server/src/test/scala/sttp/tapir/server/ziohttp/ZioHttpTestServerInterpreter.scala @@ -2,7 +2,6 @@ package sttp.tapir.server.ziohttp import cats.data.NonEmptyList import cats.effect.{IO, Resource} -import io.netty.channel.{ChannelFactory, EventLoopGroup, ServerChannel} import sttp.capabilities.WebSockets import sttp.capabilities.zio.ZioStreams import sttp.tapir.server.ServerEndpoint @@ -12,10 +11,13 @@ import zio._ import zio.http._ import zio.interop.catz._ import scala.concurrent.duration.FiniteDuration +import zio.http.netty.server.ServerEventLoopGroups +import io.netty.channel.ChannelFactory +import io.netty.channel.ServerChannel class ZioHttpTestServerInterpreter( - eventLoopGroup: ZLayer[Any, Nothing, EventLoopGroup], - channelFactory: ZLayer[Any, Nothing, ChannelFactory[ServerChannel]] + groups: ServerEventLoopGroups, + factory: ChannelFactory[ServerChannel] ) extends TestServerInterpreter[Task, ZioStreams with WebSockets, ZioHttpServerOptions[Any], Routes[Any, Response]] { override def route( @@ -40,8 +42,8 @@ class ZioHttpTestServerInterpreter( } yield result.port) .provideSome[Scope]( zio.test.driver, - eventLoopGroup, - channelFactory, + ZLayer.succeed(groups), + ZLayer.succeed(factory), ZLayer.succeed( Server.Config.default .port(0) @@ -51,5 +53,4 @@ class ZioHttpTestServerInterpreter( ) Resource.scoped[IO, Any, Port](effect) } - } diff --git a/server/zio-http-server/src/test/scala/zio/http/netty/TestChannelFactories.scala b/server/zio-http-server/src/test/scala/zio/http/netty/TestChannelFactories.scala new file mode 100644 index 0000000000..9c43f15616 --- /dev/null +++ b/server/zio-http-server/src/test/scala/zio/http/netty/TestChannelFactories.scala @@ -0,0 +1,9 @@ +package zio.http.netty + +import io.netty.channel.{ChannelFactory, ServerChannel} +import zio.ZLayer + +// Note: Workaround to access package private ChannelFactories +object TestChannelFactories { + val config: ZLayer[ChannelType.Config, Nothing, ChannelFactory[ServerChannel]] = ChannelFactories.Server.fromConfig +} diff --git a/server/zio-http-server/src/test/scala/zio/test/package.scala b/server/zio-http-server/src/test/scala/zio/test/package.scala index 73930aefb0..4099ce42fc 100644 --- a/server/zio-http-server/src/test/scala/zio/test/package.scala +++ b/server/zio-http-server/src/test/scala/zio/test/package.scala @@ -1,13 +1,15 @@ package zio -import io.netty.channel.{ChannelFactory, EventLoopGroup, ServerChannel} import zio.http._ import zio.http.netty.NettyConfig import zio.http.netty.server.NettyDriver +import zio.http.netty.server.ServerEventLoopGroups +import io.netty.channel.ChannelFactory +import io.netty.channel.ServerChannel package object test { - val driver: ZLayer[EventLoopGroup & ChannelFactory[ServerChannel] & Server.Config, Nothing, Driver] = - ZLayer.makeSome[EventLoopGroup & ChannelFactory[ServerChannel] & Server.Config, Driver]( + val driver: ZLayer[ServerEventLoopGroups & ChannelFactory[ServerChannel] & Server.Config, Nothing, Driver] = + ZLayer.makeSome[ServerEventLoopGroups & ChannelFactory[ServerChannel] & Server.Config, Driver]( ZLayer.succeed(NettyConfig.default), NettyDriver.manual )