Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
haskell-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
160
Issues
160
List
Board
Labels
Milestones
Merge Requests
14
Merge Requests
14
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gargantext
haskell-gargantext
Commits
1217baf4
Verified
Commit
1217baf4
authored
Jan 22, 2025
by
Przemyslaw Kaminski
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[tests] notifications: test async notifications for update tree
Related to
#418
parent
874785e9
Pipeline
#7256
canceled with stages
in 3 minutes and 34 seconds
Changes
3
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
99 additions
and
47 deletions
+99
-47
Notifications.hs
test/Test/API/Notifications.hs
+96
-43
Prelude.hs
test/Test/API/Prelude.hs
+1
-2
Notifications.hs
test/Test/Core/Notifications.hs
+2
-2
No files found.
test/Test/API/Notifications.hs
View file @
1217baf4
...
@@ -11,6 +11,7 @@ Portability : POSIX
...
@@ -11,6 +11,7 @@ Portability : POSIX
{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ScopedTypeVariables #-}
...
@@ -20,28 +21,37 @@ module Test.API.Notifications (
...
@@ -20,28 +21,37 @@ module Test.API.Notifications (
import
Control.Concurrent
(
threadDelay
)
import
Control.Concurrent
(
threadDelay
)
import
Control.Concurrent.STM.TChan
import
Control.Concurrent.STM.TChan
import
Control.Concurrent.STM.TSem
(
newTSem
,
signalTSem
)
import
Control.Concurrent.STM.TSem
(
newTSem
,
signalTSem
,
TSem
)
import
Control.Lens
((
^.
))
import
Control.Lens
((
^.
))
import
Control.Monad
(
void
)
import
Control.Monad.STM
(
atomically
)
import
Control.Monad.STM
(
atomically
)
import
Data.Aeson
qualified
as
Aeson
import
Data.Aeson
qualified
as
Aeson
import
Fmt
((
+|
),
(
|+
))
import
Gargantext.API.Admin.Auth.Types
(
AuthResponse
,
authRes_token
,
authRes_tree_id
)
import
Gargantext.Core.Config
(
gc_notifications_config
)
import
Gargantext.Core.Config
(
gc_notifications_config
)
import
Gargantext.Core.Notifications.CentralExchange
qualified
as
CE
import
Gargantext.Core.Notifications.CentralExchange
qualified
as
CE
import
Gargantext.Core.Notifications.CentralExchange.Types
qualified
as
CET
import
Gargantext.Core.Notifications.CentralExchange.Types
qualified
as
CET
import
Gargantext.Core.Notifications.Dispatcher.Types
qualified
as
DT
import
Gargantext.Core.Notifications.Dispatcher.Types
qualified
as
DT
import
Gargantext.Core.Types.Individu
(
GargPassword
(
..
))
import
Gargantext.System.Logging
(
withLogger
)
import
Gargantext.System.Logging
(
withLogger
)
import
Network.WebSockets
qualified
as
WS
import
Network.WebSockets
qualified
as
WS
import
Prelude
import
Prelude
import
System.Timeout
qualified
as
Timeout
import
System.Timeout
qualified
as
Timeout
import
Test.API.Setup
(
SpecContext
(
..
),
withTestDBAndPort
)
import
Test.API.Prelude
(
newCorpusForUser
)
import
Test.API.Routes
(
mkUrl
)
import
Test.API.Setup
(
SpecContext
(
..
),
dbEnvSetup
,
withTestDBAndPort
)
import
Test.Database.Types
(
test_config
)
import
Test.Database.Types
(
test_config
)
import
Test.Hspec
import
Test.Hspec
import
Test.Hspec.Wai.Internal
(
withApplication
)
import
Test.Instances
()
import
Test.Instances
()
import
Test.Utils
(
waitForTChanValue
,
waitForTSem
)
import
Text.RawString.QQ
(
r
)
import
Test.Utils
(
protected
,
waitForTChanValue
,
waitForTSem
,
withValidLoginA
)
import
Test.Utils.Notifications
(
withAsyncWSConnection
)
import
Test.Utils.Notifications
(
withAsyncWSConnection
)
tests
::
Spec
tests
::
Spec
tests
=
sequential
$
around
All
withTestDBAndPort
$
do
tests
=
sequential
$
around
withTestDBAndPort
$
do
describe
"Notifications"
$
do
describe
"Notifications"
$
do
it
"ping WS notification works"
$
\
(
SpecContext
testEnv
port
_app
_
)
->
do
it
"ping WS notification works"
$
\
(
SpecContext
testEnv
port
_app
_
)
->
do
let
nc
=
(
test_config
testEnv
)
^.
gc_notifications_config
let
nc
=
(
test_config
testEnv
)
^.
gc_notifications_config
...
@@ -54,20 +64,8 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
...
@@ -54,20 +64,8 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
-- locking mechanisms than blindly call 'threadDelay'.
-- locking mechanisms than blindly call 'threadDelay'.
wsTSem
<-
atomically
$
newTSem
0
wsTSem
<-
atomically
$
newTSem
0
tchan
<-
newTChanIO
::
IO
(
TChan
(
Maybe
DT
.
Notification
))
tchan
<-
newTChanIO
::
IO
(
TChan
(
Maybe
DT
.
Notification
))
-- setup a websocket connection
let
wsConnect
conn
=
withLogger
()
$
\
_ioL
->
do
withAsyncWSConnection
(
"127.0.0.1"
,
port
)
(
wsConnection
topic
wsTSem
tchan
)
$
\
_a
->
do
-- logMsg ioL DEBUG $ "[wsConnect] subscribing topic: " <> show topic
WS
.
sendTextData
conn
$
Aeson
.
encode
(
DT
.
WSSubscribe
topic
)
-- inform the test process that we sent the subscription request
atomically
$
signalTSem
wsTSem
-- logMsg ioL DEBUG $ "[wsConnect] waiting for notification"
d
<-
WS
.
receiveData
conn
-- logMsg ioL DEBUG $ "[wsConnect] received " <> show d
let
dec
=
Aeson
.
decode
d
::
Maybe
DT
.
Notification
atomically
$
writeTChan
tchan
dec
withAsyncWSConnection
(
"127.0.0.1"
,
port
)
wsConnect
$
\
_a
->
do
-- wait for ws process to inform us about topic subscription
-- wait for ws process to inform us about topic subscription
waitForTSem
wsTSem
500
waitForTSem
wsTSem
500
...
@@ -133,31 +131,86 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
...
@@ -133,31 +131,86 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
-- wait for the value
-- wait for the value
waitForTChanValue
tchan
Nothing
1
_000
waitForTChanValue
tchan
Nothing
1
_000
it
"simple update tree WS notification works"
$
\
(
SpecContext
testEnv
port
_app
_
)
->
do
describe
"Update tree notifications"
$
do
let
nc
=
(
test_config
testEnv
)
^.
gc_notifications_config
it
"simple WS notification works"
$
\
(
SpecContext
testEnv
port
_app
_
)
->
do
let
nc
=
(
test_config
testEnv
)
^.
gc_notifications_config
let
topic
=
DT
.
UpdateTree
0
wsTSem
<-
atomically
$
newTSem
0
-- initially locked
tchan
<-
newTChanIO
::
IO
(
TChan
(
Maybe
DT
.
Notification
))
withAsyncWSConnection
(
"127.0.0.1"
,
port
)
(
wsConnection
topic
wsTSem
tchan
)
$
\
_a
->
do
waitForTSem
wsTSem
500
let
nodeId
=
0
CE
.
notify
nc
$
CET
.
UpdateTreeFirstLevel
nodeId
waitForTChanValue
tchan
(
Just
$
DT
.
NUpdateTree
nodeId
)
1
_000
let
topic
=
DT
.
UpdateTree
0
it
"WS notification on node creation works"
$
\
ctx
@
(
SpecContext
_testEnv
port
app
_
)
->
do
wsTSem
<-
atomically
$
newTSem
0
-- initially locked
checkNotification
ctx
$
\
authRes
->
do
tchan
<-
newTChanIO
::
IO
(
TChan
(
Maybe
DT
.
Notification
))
let
token
=
authRes
^.
authRes_token
-- setup a websocket connection
let
treeId
=
authRes
^.
authRes_tree_id
let
wsConnect
conn
=
withLogger
()
$
\
_ioL
->
do
let
query
=
[
r
|
{"pn_name": "test", "pn_typename": "NodeCorpus"}
|]
-- logMsg ioL DEBUG $ "[wsConnect] subscribing topic: " <> show topic
void
$
withApplication
app
$
do
WS
.
sendTextData
conn
$
Aeson
.
encode
(
DT
.
WSSubscribe
topic
)
protected
token
"POST"
(
mkUrl
port
$
"/node/"
+|
treeId
|+
""
)
query
-- inform the test process that we sent the subscription request
atomically
$
signalTSem
wsTSem
it
"WS notification on node deletion works"
$
\
ctx
@
(
SpecContext
testEnv
port
app
_
)
->
do
checkNotification
ctx
$
\
authRes
->
do
let
token
=
authRes
^.
authRes_token
cId
<-
newCorpusForUser
testEnv
"alice"
-- logMsg ioL DEBUG $ "[wsConnect] waiting for notification"
void
$
withApplication
app
$
do
d
<-
WS
.
receiveData
conn
protected
token
"DELETE"
(
mkUrl
port
$
"/node/"
+|
cId
|+
""
)
""
-- logMsg ioL DEBUG $ "[wsConnect] received " <> show d
let
dec
=
Aeson
.
decode
d
::
Maybe
DT
.
Notification
it
"WS notification on node rename works"
$
\
ctx
@
(
SpecContext
testEnv
port
app
_
)
->
do
atomically
$
writeTChan
tchan
dec
checkNotification
ctx
$
\
authRes
->
do
let
token
=
authRes
^.
authRes_token
withAsyncWSConnection
(
"127.0.0.1"
,
port
)
wsConnect
$
\
_a
->
do
cId
<-
newCorpusForUser
testEnv
"alice"
waitForTSem
wsTSem
500
void
$
withApplication
app
$
do
let
nodeId
=
0
let
query
=
[
r
|
{"name": "newName"}
|]
CE
.
notify
nc
$
CET
.
UpdateTreeFirstLevel
nodeId
protected
token
"PUT"
(
mkUrl
port
$
"/node/"
+|
cId
|+
"/rename"
)
query
waitForTChanValue
tchan
(
Just
$
DT
.
NUpdateTree
nodeId
)
1
_000
checkNotification
::
SpecContext
a
->
(
AuthResponse
->
IO
()
)
->
IO
()
checkNotification
ctx
@
(
SpecContext
_testEnv
port
_app
_
)
act
=
do
_
<-
dbEnvSetup
ctx
withValidLoginA
port
"alice"
(
GargPassword
"alice"
)
$
\
_clientEnv
authRes
->
do
-- Subscribe to user tree notifications
let
treeId
=
authRes
^.
authRes_tree_id
let
topic
=
DT
.
UpdateTree
treeId
wsTSem
<-
atomically
$
newTSem
0
-- initially locked
tchan
<-
newTChanIO
::
IO
(
TChan
(
Maybe
DT
.
Notification
))
withAsyncWSConnection
(
"127.0.0.1"
,
port
)
(
wsConnection
topic
wsTSem
tchan
)
$
\
_a
->
do
waitForTSem
wsTSem
500
act
authRes
waitForTChanValue
tchan
(
Just
$
DT
.
NUpdateTree
treeId
)
1
_000
wsConnection
::
DT
.
Topic
->
TSem
->
TChan
(
Maybe
DT
.
Notification
)
->
WS
.
Connection
->
IO
()
wsConnection
topic
wsTSem
tchan
conn
=
withLogger
()
$
\
_ioL
->
do
-- logMsg ioL DEBUG $ "[wsConnect] subscribing topic: " <> show topic
WS
.
sendTextData
conn
$
Aeson
.
encode
(
DT
.
WSSubscribe
topic
)
-- inform the test process that we sent the subscription request
atomically
$
signalTSem
wsTSem
-- logMsg ioL DEBUG $ "[wsConnect] waiting for notification"
d
<-
WS
.
receiveData
conn
-- logMsg ioL DEBUG $ "[wsConnect] received " <> show d
let
dec
=
Aeson
.
decode
d
::
Maybe
DT
.
Notification
atomically
$
writeTChan
tchan
dec
test/Test/API/Prelude.hs
View file @
1217baf4
...
@@ -16,8 +16,7 @@ import Data.Aeson qualified as JSON
...
@@ -16,8 +16,7 @@ import Data.Aeson qualified as JSON
import
Data.Text
qualified
as
T
import
Data.Text
qualified
as
T
import
Gargantext.API.Errors
import
Gargantext.API.Errors
import
Gargantext.Core.Types.Individu
import
Gargantext.Core.Types.Individu
import
Gargantext.Core.Types
(
NodeId
)
import
Gargantext.Core.Types
(
NodeId
,
NodeType
(
..
))
import
Gargantext.Core.Types
(
NodeType
(
..
))
import
Gargantext.Core.Worker.Env
()
-- instance HasNodeError
import
Gargantext.Core.Worker.Env
()
-- instance HasNodeError
import
Gargantext.Database.Action.User
import
Gargantext.Database.Action.User
import
Gargantext.Database.Admin.Types.Hyperdata.Corpus
import
Gargantext.Database.Admin.Types.Hyperdata.Corpus
...
...
test/Test/Core/Notifications.hs
View file @
1217baf4
...
@@ -35,5 +35,5 @@ qcTests :: TestTree
...
@@ -35,5 +35,5 @@ qcTests :: TestTree
qcTests
=
qcTests
=
testGroup
"Notifications QuickCheck tests"
$
do
testGroup
"Notifications QuickCheck tests"
$
do
[
QC
.
testProperty
"CEMessage aeson encoding"
$
\
m
->
A
.
decode
(
A
.
encode
(
m
::
CEMessage
))
==
Just
m
[
QC
.
testProperty
"CEMessage aeson encoding"
$
\
m
->
A
.
decode
(
A
.
encode
(
m
::
CEMessage
))
==
Just
m
,
QC
.
testProperty
"Topic aeson encoding"
$
\
t
->
A
.
decode
(
A
.
encode
(
t
::
Topic
))
==
Just
t
,
QC
.
testProperty
"Topic aeson encoding"
$
\
t
->
A
.
decode
(
A
.
encode
(
t
::
Topic
))
==
Just
t
,
QC
.
testProperty
"WSRequest aeson encoding"
$
\
ws
->
A
.
decode
(
A
.
encode
(
ws
::
WSRequest
))
==
Just
ws
]
,
QC
.
testProperty
"WSRequest aeson encoding"
$
\
ws
->
A
.
decode
(
A
.
encode
(
ws
::
WSRequest
))
==
Just
ws
]
Przemyslaw Kaminski
@cgenie
mentioned in commit
03b33383
·
Jan 30, 2025
mentioned in commit
03b33383
mentioned in commit 03b33383dd67c1821a4edb4628923cf7bd039d90
Toggle commit list
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment