Skip to content

Commit 6e0250e

Browse files
committed
add WsClientTestKit
1 parent 99d241e commit 6e0250e

File tree

7 files changed

+135
-42
lines changed

7 files changed

+135
-42
lines changed

testkit/build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ libraryDependencies ++= Seq(
1010
"com.github.kirviq" % "dumbster" % "1.7.1",
1111
"org.rapidoid" % "rapidoid-http-server" % "5.5.5",
1212
"org.scalatest" %% "scalatest" % Versions.scalatest,
13-
"com.typesafe.akka" %% "akka-stream-testkit" % Versions.akka % Test
13+
"com.typesafe.akka" %% "akka-stream-testkit" % Versions.akka
1414
)

testkit/src/main/scala/app/softnetwork/notification/scalatest/AllNotificationsApiRoutesTestKit.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ import org.scalatest.Suite
88

99
trait AllNotificationsApiRoutesTestKit[SD <: SessionData with SessionDataDecorator[SD]]
1010
extends NotificationApiRoutesTestKit[SD, Notification]
11-
with AllNotificationsTestKit { _: Suite with ApiRoutes with SessionMaterials[SD] => }
11+
with AllNotificationsTestKit {
12+
_: Suite with ApiRoutes with SessionMaterials[SD] with WsClientTestKit =>
13+
}

testkit/src/main/scala/app/softnetwork/notification/scalatest/AllNotificationsRoutesTestKit.scala

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,31 @@
11
package app.softnetwork.notification.scalatest
22

33
import akka.actor.typed.ActorSystem
4+
import akka.http.scaladsl.testkit.WSProbe
5+
import app.softnetwork.api.server.config.ServerSettings
6+
import app.softnetwork.notification.config.NotificationSettings
47
import app.softnetwork.notification.model.Notification
58
import app.softnetwork.notification.service.NotificationService
9+
import app.softnetwork.notification.spi.{WsChannels, WsSessions}
610
import app.softnetwork.session.model.{SessionData, SessionDataCompanion, SessionDataDecorator}
711
import app.softnetwork.session.service.SessionMaterials
812
import com.softwaremill.session.{RefreshTokenStorage, SessionConfig, SessionManager}
913
import org.scalatest.Suite
10-
import org.slf4j.{Logger, LoggerFactory}
1114
import org.softnetwork.session.model.Session
1215

16+
import java.net.URLEncoder
1317
import scala.concurrent.ExecutionContext
1418

1519
trait AllNotificationsRoutesTestKit[SD <: SessionData with SessionDataDecorator[SD]]
1620
extends NotificationRoutesTestKit[SD, Notification]
17-
with AllNotificationsApiRoutesTestKit[SD] { self: Suite with SessionMaterials[SD] =>
21+
with AllNotificationsApiRoutesTestKit[SD]
22+
with WsClientTestKit { self: Suite with SessionMaterials[SD] =>
1823

1924
override def notificationService: ActorSystem[_] => NotificationService[SD] = sys =>
2025
new NotificationService[SD] with SessionMaterials[SD] {
2126
override implicit def system: ActorSystem[_] = sys
2227

2328
override lazy val ec: ExecutionContext = sys.executionContext
24-
lazy val log: Logger = LoggerFactory getLogger getClass.getName
2529

2630
override protected def sessionType: Session.SessionType = self.sessionType
2731

@@ -35,4 +39,71 @@ trait AllNotificationsRoutesTestKit[SD <: SessionData with SessionDataDecorator[
3539

3640
override implicit def companion: SessionDataCompanion[SD] = self.companion
3741
}
42+
43+
val wsPath = s"/${ServerSettings.RootPath}/${NotificationSettings.NotificationConfig.path}"
44+
45+
override def ws(
46+
clientId: String,
47+
sessionId: String,
48+
channel: Option[String] = None
49+
): Option[WSProbe] = {
50+
val encodedClientId = URLEncoder.encode(clientId, "UTF-8")
51+
channel match {
52+
case Some(c) => addChannel(c)
53+
case _ =>
54+
}
55+
val wsClient: WSProbe = WSProbe()
56+
withHeaders(
57+
WS(s"$wsPath/connect/$encodedClientId", wsClient.flow)
58+
) ~> routes ~> check {
59+
isWebSocketUpgrade shouldEqual true
60+
WsSessions.lookupClients(sessionId).getOrElse(Set.empty).contains(clientId) shouldEqual true
61+
channel match {
62+
case Some(c) =>
63+
WsChannels.lookupClients(c).getOrElse(Set.empty).contains(clientId) shouldEqual true
64+
case _ =>
65+
}
66+
Some(wsClient)
67+
}
68+
}
69+
70+
override def addChannel(channel: String): Unit = {
71+
withHeaders(
72+
Post(s"$wsPath/channels/${URLEncoder.encode(channel, "UTF-8")}")
73+
) ~> routes ~> check {
74+
status.isSuccess() shouldEqual true
75+
httpHeaders = extractHeaders(headers)
76+
extractSession(false) match {
77+
case None => fail()
78+
case Some(session) =>
79+
session
80+
.get("channels")
81+
.getOrElse("")
82+
.split(",")
83+
.filter(_.nonEmpty)
84+
.toSet
85+
.contains(channel) shouldEqual true
86+
}
87+
}
88+
}
89+
90+
override def removeChannel(channel: String): Unit = {
91+
withHeaders(
92+
Delete(s"$wsPath/channels/${URLEncoder.encode(channel, "UTF-8")}")
93+
) ~> routes ~> check {
94+
status.isSuccess() shouldEqual true
95+
httpHeaders = extractHeaders(headers)
96+
extractSession(false) match {
97+
case None => fail()
98+
case Some(session) =>
99+
session
100+
.get("channels")
101+
.getOrElse("")
102+
.split(",")
103+
.filter(_.nonEmpty)
104+
.toSet
105+
.contains(channel) shouldEqual false
106+
}
107+
}
108+
}
38109
}

testkit/src/main/scala/app/softnetwork/notification/scalatest/AllNotificationsTestKit.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ trait AllNotificationsTestKit
2828
extends NotificationGrpcServerTestKit[Notification]
2929
with NotificationTestKit[Notification]
3030
with ApnsToken {
31-
_: Suite =>
31+
_: Suite with WsClientTestKit =>
3232

3333
lazy val apnsPort: Int = availablePort
3434

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package app.softnetwork.notification.scalatest
2+
3+
import akka.http.scaladsl.testkit.WSProbe
4+
5+
trait WsClientTestKit {
6+
7+
def ws(clientId: String, sessionId: String, channel: Option[String] = None): Option[WSProbe] =
8+
None
9+
10+
def addChannel(channel: String): Unit = {}
11+
12+
def removeChannel(channel: String): Unit = {}
13+
}

testkit/src/test/scala/app/softnetwork/notification/handlers/AllNotificationsHandlerSpec.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ package app.softnetwork.notification.handlers
22

33
import org.scalatest.wordspec.AnyWordSpecLike
44
import app.softnetwork.notification.message._
5-
import app.softnetwork.notification.scalatest.AllNotificationsTestKit
5+
import app.softnetwork.notification.scalatest.{AllNotificationsTestKit, WsClientTestKit}
66
import org.slf4j.{Logger, LoggerFactory}
77

88
import scala.util.{Failure, Success}
99

1010
/** Created by smanciot on 14/04/2020.
1111
*/
12-
class AllNotificationsHandlerSpec extends AnyWordSpecLike with AllNotificationsTestKit {
12+
class AllNotificationsHandlerSpec
13+
extends AnyWordSpecLike
14+
with AllNotificationsTestKit
15+
with WsClientTestKit {
1316

1417
lazy val log: Logger = LoggerFactory getLogger getClass.getName
1518

testkit/src/test/scala/app/softnetwork/notification/service/NotificationServiceSpec.scala

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ package app.softnetwork.notification.service
22

33
import akka.http.scaladsl.testkit.WSProbe
44
import app.softnetwork.api.server.ApiRoutes
5-
import app.softnetwork.api.server.config.ServerSettings
6-
import app.softnetwork.notification.config.NotificationSettings
7-
import app.softnetwork.notification.scalatest.AllNotificationsApiRoutesTestKit
8-
import app.softnetwork.notification.spi.{WsChannels, WsSessions}
5+
import app.softnetwork.notification.scalatest.{AllNotificationsApiRoutesTestKit, WsClientTestKit}
96
import app.softnetwork.session.model.{SessionData, SessionDataDecorator}
107
import app.softnetwork.session.service.SessionMaterials
118
import org.scalatest.Suite
@@ -16,69 +13,76 @@ import scala.util.{Failure, Success}
1613

1714
trait NotificationServiceSpec[SD <: SessionData with SessionDataDecorator[SD]]
1815
extends AnyWordSpecLike
19-
with AllNotificationsApiRoutesTestKit[SD] { _: Suite with ApiRoutes with SessionMaterials[SD] =>
16+
with AllNotificationsApiRoutesTestKit[SD] {
17+
_: Suite with ApiRoutes with SessionMaterials[SD] with WsClientTestKit =>
2018

2119
override val refreshableSession: Boolean = false
2220

2321
lazy val log: Logger = LoggerFactory getLogger getClass.getName
2422

2523
val clientId = "client"
2624
val sessionId = "session"
27-
val wsPath = s"/${ServerSettings.RootPath}/${NotificationSettings.NotificationConfig.path}"
28-
lazy val wsClient: WSProbe = WSProbe()
25+
26+
var wsClient: Option[WSProbe] = None
2927

3028
"Notification service" should {
3129

3230
"connect to ws server without channel" in {
3331
createSession(sessionId)
34-
withHeaders(
35-
WS(s"$wsPath/connect/$clientId", wsClient.flow)
36-
) ~> routes ~> check {
37-
isWebSocketUpgrade shouldEqual true
38-
WsSessions.lookupClients(sessionId).getOrElse(Set.empty).contains(clientId) shouldEqual true
39-
wsClient.sendMessage("hello")
40-
}
32+
wsClient = ws(clientId, sessionId)
4133
}
4234

4335
"send message to client" in {
4436
val ws = generateWs(clientId)
4537
client.sendWs(ws) complete () match {
4638
case Success(result) =>
47-
assert(result.exists(r => r.recipient == clientId && r.status.isSent))
48-
wsClient.expectMessage(ws.message)
49-
case Failure(_) => fail()
50-
}
51-
wsClient.sendCompletion()
52-
client.sendWs(ws) complete () match {
53-
case Success(result) =>
54-
assert(result.exists(r => r.recipient == clientId && r.status.isRejected))
39+
wsClient match {
40+
case Some(cli) =>
41+
assert(result.exists(r => r.recipient == clientId && r.status.isSent))
42+
cli.expectMessage(ws.message)
43+
cli.sendCompletion()
44+
client.sendWs(ws) complete () match {
45+
case Success(result) =>
46+
assert(result.exists(r => r.recipient == clientId && r.status.isRejected))
47+
case Failure(_) => fail()
48+
}
49+
case None =>
50+
}
5551
case Failure(_) => fail()
5652
}
5753
}
5854

5955
val channel = "channel"
60-
lazy val wsChannel: WSProbe = WSProbe()
6156

6257
"connect to ws server with channel" in {
63-
withHeaders(
64-
WS(s"$wsPath/connect/$clientId?channel=$channel", wsChannel.flow)
65-
) ~> routes ~> check {
66-
isWebSocketUpgrade shouldEqual true
67-
WsSessions.lookupClients(sessionId).getOrElse(Set.empty).contains(clientId) shouldEqual true
68-
WsChannels.lookupClients(channel).getOrElse(Set.empty).contains(clientId) shouldEqual true
69-
wsChannel.sendMessage("hello")
70-
}
58+
wsClient = ws(clientId, sessionId, Some(channel))
7159
}
7260

7361
"send message to channel" in {
7462
val ws = generateWs(clientId, Some(channel)).withTo(Seq.empty)
7563
client.sendWs(ws) complete () match {
7664
case Success(result) =>
77-
assert(result.exists(r => r.recipient == clientId && r.status.isSent))
78-
wsChannel.expectMessage(ws.message)
65+
wsClient match {
66+
case Some(cli) =>
67+
assert(result.exists(r => r.recipient == clientId && r.status.isSent))
68+
cli.expectMessage(ws.message)
69+
case None =>
70+
}
7971
case Failure(_) => fail()
8072
}
81-
wsChannel.sendCompletion()
73+
}
74+
75+
"disconnect from channel" in {
76+
removeChannel(channel)
77+
}
78+
79+
"disconnect from ws server" in {
80+
wsClient match {
81+
case Some(cli) =>
82+
cli.sendCompletion()
83+
wsClient = None
84+
case None =>
85+
}
8286
}
8387
}
8488
}

0 commit comments

Comments
 (0)