diff --git a/jvm/src/test/scala/cs214/webapp/AppSuite.scala b/jvm/src/test/scala/cs214/webapp/AppSuite.scala index 9549259215fa9ba7355b87df2ccf53b253a0438b..c0d3c8c569b34a1fe1d2df3bd208a6c2a70d7436 100644 --- a/jvm/src/test/scala/cs214/webapp/AppSuite.scala +++ b/jvm/src/test/scala/cs214/webapp/AppSuite.scala @@ -169,3 +169,48 @@ class WebSocketSuite extends PingPongSuite: ws.sendText(app.wire.eventFormat.encode("b").toString) val r0b = decodeActions(ws.receiveText()) assertEquals(r0b, Seq(Action.Render("b"))) + + test("ws: Webserver survives many connections to a single app"): + withServer: server ?=> + def userId(n: Int) = f"p$n" + def withJavaWss[Lst <: JWebSocket.Listener] + (instanceId: String, nUsers: Int, listener: String => Lst) + (body: Seq[(JWebSocket, Lst)] => Unit) = + def loop(i: Int, wss: Seq[(JWebSocket, Lst)]): Unit = + if i >= nUsers then + body(wss) + wss.foreach: (ws, lst) => + ws.sendClose(1000, "bye") + ws.abort() + else + val uId = userId(i) + val lst = listener(uId) + val ws = withJavaWs(instanceId, uId, lst)(ws => ws) + loop(i + 1, (ws, lst) +: wss) + loop(0, Seq()) + + val nUsers = 1000 + val inst = createInstance((0 to nUsers).map(userId)) + + class QueuedListener extends JWebSocket.Listener: + var partials: String = "" + val queue = java.util.concurrent.LinkedTransferQueue[String]() + + def receiveText() = + queue.take() + + override def onText(webSocket: JWebSocket, data: CharSequence, last: Boolean) + : java.util.concurrent.CompletionStage[?] = + webSocket.synchronized: + partials += data.toString + if last then + queue.add(partials) + partials = "" + super.onText(webSocket, data, last) + + withJavaWss(inst.instanceId, nUsers, _ => QueuedListener()): wss => + wss.head._1.sendText(app.wire.eventFormat.encode("a").toString, true) + val rng = scala.util.Random(12) + rng.shuffle(wss).foreach: (ws, lst) => + assertEquals(decodeActions(lst.receiveText()), Seq(Action.Render("hello"))) + assertEquals(decodeActions(lst.receiveText()), Seq(Action.Render("a")))