Skip to content

Commit 0b2b5cd

Browse files
committed
make the "close connection on monix task *" tests generic
1 parent 48ad7b0 commit 0b2b5cd

File tree

4 files changed

+47
-107
lines changed

4 files changed

+47
-107
lines changed

rest/jetty/src/test/scala/io/udash/rest/jetty/CloseStaleJettyConnectionsOnMonixTimeout.scala

Lines changed: 0 additions & 104 deletions
This file was deleted.

rest/jetty/src/test/scala/io/udash/rest/jetty/JettyRestCallTest.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import io.udash.rest.{RestApiTestScenarios, ServletBasedRestApiTest}
66
import org.eclipse.jetty.client.HttpClient
77

88
final class JettyRestCallTest extends ServletBasedRestApiTest with RestApiTestScenarios {
9-
val client: HttpClient = new HttpClient
9+
val client: HttpClient = new HttpClient() {
10+
setMaxConnectionsPerDestination(MaxConnections)
11+
}
1012

1113
def clientHandle: HandleRequest =
1214
JettyRestClient.asHandleRequest(client, s"$baseUrl/api", maxPayloadSize)

rest/src/test/scala/io/udash/rest/RestApiTest.scala

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
package io.udash
22
package rest
33

4-
import com.avsystem.commons._
4+
import com.avsystem.commons.*
5+
import com.avsystem.commons.misc.ScalaDurationExtensions.durationIntOps
56
import io.udash.rest.raw.RawRest
67
import io.udash.rest.raw.RawRest.HandleRequest
8+
import monix.eval.Task
79
import monix.execution.Scheduler
810
import org.scalactic.source.Position
11+
import org.scalatest.concurrent.PatienceConfiguration.Timeout
912
import org.scalatest.concurrent.ScalaFutures
1013
import org.scalatest.funsuite.AnyFunSuite
1114

15+
import scala.concurrent.duration.FiniteDuration
16+
1217
abstract class RestApiTest extends AnyFunSuite with ScalaFutures {
18+
19+
protected final val MaxConnections: Int = 1 // to timeout quickly
20+
protected final val Connections: Int = 10 // > MaxConnections
21+
protected final val CallTimeout: FiniteDuration = 300.millis // << idle timeout
22+
1323
implicit def scheduler: Scheduler = Scheduler.global
1424

1525
final val serverHandle: RawRest.HandleRequest =
@@ -30,6 +40,9 @@ abstract class RestApiTest extends AnyFunSuite with ScalaFutures {
3040
case arr: Array[_] => IArraySeq.empty[AnyRef] ++ arr.iterator.map(mkDeep)
3141
case _ => value
3242
}
43+
44+
def getNeverGetCounter(): Int = RestTestApi.Impl.neverGetCounter.get()
45+
def resetNeverGetCounter(): Unit = RestTestApi.Impl.neverGetCounter.set(0)
3346
}
3447

3548
trait RestApiTestScenarios extends RestApiTest {
@@ -89,6 +102,29 @@ trait RestApiTestScenarios extends RestApiTest {
89102
test("body using third party type") {
90103
testCall(_.thirdPartyBody(HasThirdParty(ThirdParty(5))))
91104
}
105+
106+
test("close connection on monix task timeout") {
107+
resetNeverGetCounter()
108+
Task
109+
.traverse(List.range(0, Connections))(_ => Task.deferFuture(proxy.neverGet).timeout(CallTimeout).failed)
110+
.map(_ => assertResult(expected = Connections)(actual = getNeverGetCounter())) // neverGet should be called Connections times
111+
.runToFuture
112+
.futureValue(Timeout(30.seconds))
113+
}
114+
115+
test("close connection on monix task cancellation") {
116+
resetNeverGetCounter()
117+
Task
118+
.traverse(List.range(0, Connections)) { i =>
119+
val cancelable = Task.deferFuture(proxy.neverGet).runAsync(_ => ())
120+
Task.sleep(100.millis)
121+
.restartUntil(_ => getNeverGetCounter() >= i)
122+
.map(_ => cancelable.cancel())
123+
}
124+
.map(_ => assertResult(expected = Connections)(actual = getNeverGetCounter())) // neverGet should be called Connections times
125+
.runToFuture
126+
.futureValue(Timeout(30.seconds))
127+
}
92128
}
93129

94130
class DirectRestApiTest extends RestApiTestScenarios {

rest/src/test/scala/io/udash/rest/RestTestApi.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.avsystem.commons.serialization.json.JsonStringOutput
99
import io.udash.rest.openapi.adjusters.*
1010
import io.udash.rest.openapi.{Header as OASHeader, *}
1111
import io.udash.rest.raw.*
12+
import monix.execution.atomic.Atomic
1213
import monix.execution.{FutureUtils, Scheduler}
1314

1415
import scala.concurrent.Future
@@ -94,6 +95,8 @@ case class ErrorWrapper[T](error: T)
9495
object ErrorWrapper extends HasPolyGenCodec[ErrorWrapper]
9596

9697
trait RestTestApi {
98+
final val neverGetCounter = Atomic(0)
99+
97100
@GET @group("TrivialGroup") def trivialGet: Future[Unit]
98101
@GET @group("TrivialDescribedGroup") @tagDescription("something") def failingGet: Future[Unit]
99102
@GET def jsonFailingGet: Future[Unit]
@@ -181,7 +184,10 @@ object RestTestApi extends DefaultRestApiCompanion[RestTestApi] {
181184
def failingGet: Future[Unit] = Future.failed(HttpErrorException.plain(503, "nie"))
182185
def jsonFailingGet: Future[Unit] = Future.failed(HttpErrorException(503, HttpBody.json(JsonValue(JsonStringOutput.write(ErrorWrapper("nie"))))))
183186
def moreFailingGet: Future[Unit] = throw HttpErrorException.plain(503, "nie")
184-
def neverGet: Future[Unit] = Future.never
187+
def neverGet: Future[Unit] = {
188+
neverGetCounter.transform(_ + 1)
189+
Future.never
190+
}
185191
def wait(millis: Int): Future[String] = FutureUtils.delayedResult(millis.millis)(s"waited $millis ms")
186192
def getEntity(id: RestEntityId): Future[RestEntity] = Future.successful(RestEntity(id, s"${id.value}-name"))
187193
def complexGet(p1: Int, p2: String, h1: Int, h2: String, q1: Int, q2: String, q3: Opt[Int], c1: Int, c2: String): Future[RestEntity] =

0 commit comments

Comments
 (0)