Skip to content

Commit 869a9eb

Browse files
smattingpcapriottiMarko Dimjašević
authored
Refactor MLS test framework (#2678)
* Implement most of the new MLS test framework * Automatically keep track of clients in the group * Assert that add proposal is forwarded * Remove dead code * Keep track of clients in the test state * Port more external proposal tests to new framework * Refactor test testSenderNotInConversation - Also add a utility for creating an application message * Port welcome tests to new MLS test framework * Refactor test testSendAnotherUsersCommit * Port some commit tests to new MLS test framework * Port more commit tests * Refactor test testAppMessage * Refactor test testRemoteAppMessage * Port more commit tests * Fix bracket in testAppMessage * Finish porting commit tests * Refactor test testAppMessage2 * Port proposal tests * Refactor test testLocalToRemote * Refactor test testLocalToRemoteNonMember * Refactor test testRemoteToLocal * Refactor test testRemoteNonMemberToLocal * Refactor test testRemoteToLocalWrongConversation * Refactor test testAddUsersDirectly * Refactor test testRemoveUsersDirectly * Refactor test testProteusMessage * Refactor test testAddUsersToProteus * Generalise return type of awaitMatch and friends Fix error reporting in assertNoEvent * Port backend removal test * Port final test in API/MLS * Move MLS tests out of the Federation module * Remove old MLS test framework * Add CHANGELOG entry * Fix a test setup in runMLSTest * Update mls-test-cli Co-authored-by: Paolo Capriotti <[email protected]> Co-authored-by: Marko Dimjašević <[email protected]>
1 parent 8bf716d commit 869a9eb

File tree

11 files changed

+1722
-1904
lines changed

11 files changed

+1722
-1904
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Refactor MLS test framework

libs/tasty-cannon/src/Test/Tasty/Cannon.hs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -288,18 +288,18 @@ awaitMatch ::
288288
(HasCallStack, MonadIO m, MonadCatch m) =>
289289
Timeout ->
290290
WebSocket ->
291-
(Notification -> Assertion) ->
292-
m (Either MatchTimeout Notification)
291+
(Notification -> IO a) ->
292+
m (Either MatchTimeout a)
293293
awaitMatch t ws match = go [] []
294294
where
295295
go buf errs = do
296296
mn <- await t ws
297297
case mn of
298298
Just n ->
299299
do
300-
liftIO (match n)
300+
a <- liftIO (match n)
301301
refill buf
302-
pure (Right n)
302+
pure (Right a)
303303
`catchAll` \e -> case asyncExceptionFromException e of
304304
Just x -> throwM (x :: SomeAsyncException)
305305
Nothing ->
@@ -322,56 +322,56 @@ assertMatch ::
322322
(HasCallStack, MonadIO m, MonadCatch m) =>
323323
Timeout ->
324324
WebSocket ->
325-
(Notification -> Assertion) ->
326-
m Notification
325+
(Notification -> IO a) ->
326+
m a
327327
assertMatch t ws f = awaitMatch t ws f >>= assertSuccess
328328

329329
assertMatch_ ::
330330
(HasCallStack, MonadIO m, MonadCatch m) =>
331331
Timeout ->
332332
WebSocket ->
333-
(Notification -> Assertion) ->
333+
(Notification -> IO a) ->
334334
m ()
335335
assertMatch_ t w = void . assertMatch t w
336336

337337
awaitMatchN ::
338338
(HasCallStack, MonadIO m) =>
339339
Timeout ->
340340
[WebSocket] ->
341-
(Notification -> Assertion) ->
342-
m [Either MatchTimeout Notification]
341+
(Notification -> IO a) ->
342+
m [Either MatchTimeout a]
343343
awaitMatchN t wss f = snd <$$> awaitMatchN' t (((),) <$> wss) f
344344

345345
awaitMatchN' ::
346346
(HasCallStack, MonadIO m) =>
347347
Timeout ->
348348
[(extra, WebSocket)] ->
349-
(Notification -> Assertion) ->
350-
m [(extra, Either MatchTimeout Notification)]
349+
(Notification -> IO a) ->
350+
m [(extra, Either MatchTimeout a)]
351351
awaitMatchN' t wss f = liftIO $ mapConcurrently (\(extra, ws) -> (extra,) <$> awaitMatch t ws f) wss
352352

353353
assertMatchN ::
354354
(HasCallStack, MonadIO m, MonadThrow m) =>
355355
Timeout ->
356356
[WebSocket] ->
357-
(Notification -> Assertion) ->
358-
m [Notification]
357+
(Notification -> IO a) ->
358+
m [a]
359359
assertMatchN t wss f = awaitMatchN t wss f >>= mapM assertSuccess
360360

361361
assertMatchN_ ::
362362
(HasCallStack, MonadIO m, MonadThrow m) =>
363363
Timeout ->
364364
[WebSocket] ->
365-
(Notification -> Assertion) ->
365+
(Notification -> IO a) ->
366366
m ()
367367
assertMatchN_ t wss f = void $ assertMatchN t wss f
368368

369-
assertSuccess :: (HasCallStack, MonadIO m, MonadThrow m) => Either MatchTimeout Notification -> m Notification
369+
assertSuccess :: (HasCallStack, MonadIO m, MonadThrow m) => Either MatchTimeout a -> m a
370370
assertSuccess = either throwM pure
371371

372372
assertNoEvent :: (HasCallStack, MonadIO m, MonadCatch m) => Timeout -> [WebSocket] -> m ()
373373
assertNoEvent t ww = do
374-
results <- awaitMatchN' t (zip [(0 :: Int) ..] ww) (const $ pure ())
374+
results <- awaitMatchN' t (zip [(0 :: Int) ..] ww) pure
375375
for_ results $ \(ix, result) ->
376376
either (const $ pure ()) (liftIO . f ix) result
377377
where

libs/wire-api/src/Wire/API/MLS/Credential.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,15 @@ data ClientIdentity = ClientIdentity
139139
ciUser :: UserId,
140140
ciClient :: ClientId
141141
}
142-
deriving stock (Eq, Show, Generic)
142+
deriving stock (Eq, Ord, Show, Generic)
143143
deriving (FromJSON, ToJSON, S.ToSchema) via Schema ClientIdentity
144144

145145
cidQualifiedClient :: ClientIdentity -> Qualified (UserId, ClientId)
146146
cidQualifiedClient cid = Qualified (ciUser cid, ciClient cid) (ciDomain cid)
147147

148+
cidQualifiedUser :: ClientIdentity -> Qualified UserId
149+
cidQualifiedUser = fmap fst . cidQualifiedClient
150+
148151
instance ToSchema ClientIdentity where
149152
schema =
150153
object "ClientIdentity" $

nix/pkgs/mls_test_cli/default.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ rustPlatform.buildRustPackage rec {
1515
src = fetchFromGitHub {
1616
owner = "wireapp";
1717
repo = "mls-test-cli";
18-
sha256 = "sha256-nBtXkxGstSqBEhzjcRd0RG2hv0WFgTqy1z29W2sf27U=";
19-
rev = "560186482d201fe0f6194d620dba2b623fdd7f6f";
18+
sha256 = "sha256-Gw1+b7kslc/KcB+pEqP1FuE6tAPqKtB6hlkLcXMuCcM=";
19+
rev = "f44dec2705e1833b654cb6f02271e11a6c2fdeb0";
2020
};
2121
doCheck = false;
2222
cargoSha256 = "sha256-3zUGEowQREPKsfpH2y9C7BeeTTF3zat4Qfpw74fOCHQ=";

services/brig/test/integration/Util.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ getPhoneLoginCode brig p = do
317317
let lbs = fromMaybe "" $ responseBody r
318318
pure (LoginCode <$> (lbs ^? key "code" . _String))
319319

320-
assertUpdateNotification :: WS.WebSocket -> UserId -> UserUpdate -> IO Notification
320+
assertUpdateNotification :: WS.WebSocket -> UserId -> UserUpdate -> IO ()
321321
assertUpdateNotification ws uid upd = WS.assertMatch (5 # Second) ws $ \n -> do
322322
let j = Object $ List1.head (ntfPayload n)
323323
j ^? key "type" . _String @?= Just "user.update"

services/galley/galley.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ executable galley-integration
442442
, currency-codes
443443
, data-default
444444
, data-timeout
445+
, directory
445446
, errors
446447
, exceptions
447448
, extended
@@ -451,6 +452,7 @@ executable galley-integration
451452
, galley
452453
, galley-types
453454
, gundeck-types
455+
, hex
454456
, HsOpenSSL
455457
, HsOpenSSL-x509-system
456458
, hspec
@@ -500,6 +502,7 @@ executable galley-integration
500502
, transformers
501503
, types-common
502504
, types-common-journal
505+
, unix
503506
, unliftio
504507
, unordered-containers
505508
, uri-bytestring

services/galley/test/integration/API/Federation.hs

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@
1919

2020
module API.Federation where
2121

22-
import API.MLS.Util
2322
import API.Util
2423
import Bilge hiding (head)
2524
import Bilge.Assert
2625
import Control.Lens hiding ((#))
2726
import Data.Aeson (ToJSON (..))
2827
import qualified Data.Aeson as A
2928
import Data.ByteString.Conversion (toByteString')
30-
import Data.Default
3129
import Data.Domain
3230
import Data.Id (ConvId, Id (..), UserId, newClientId, randomId)
3331
import Data.Json.Util hiding ((#))
@@ -90,9 +88,7 @@ tests s =
9088
test s "POST /federation/on-message-sent : Receive a message from another backend" onMessageSent,
9189
test s "POST /federation/send-message : Post a message sent from another backend" sendMessage,
9290
test s "POST /federation/on-user-deleted-conversations : Remove deleted remote user from local conversations" onUserDeleted,
93-
test s "POST /federation/update-conversation : Update local conversation by a remote admin " updateConversationByRemoteAdmin,
94-
test s "POST /federation/mls-welcome : Post an MLS welcome message received from another backend" sendMLSWelcome,
95-
test s "POST /federation/mls-welcome : Post an MLS welcome message (key package ref not found)" sendMLSWelcomeKeyPackageNotFound
91+
test s "POST /federation/update-conversation : Update local conversation by a remote admin " updateConversationByRemoteAdmin
9692
]
9793

9894
getConversationsAllFound :: TestM ()
@@ -1134,55 +1130,6 @@ updateConversationByRemoteAdmin = do
11341130
let convUpdate :: ConversationUpdate = fromRight (error $ "Could not parse ConversationUpdate from " <> show (frBody rpc)) $ A.eitherDecode (frBody rpc)
11351131
pure (rpc, convUpdate)
11361132

1137-
sendMLSWelcome :: TestM ()
1138-
sendMLSWelcome = do
1139-
let aliceDomain = Domain "a.far-away.example.com"
1140-
-- Alice is from the originating domain and Bob is local, i.e., on the receiving domain
1141-
MessagingSetup {..} <- aliceInvitesBob (1, LocalUser) def {creatorOrigin = RemoteUser aliceDomain}
1142-
let bob = head users
1143-
1144-
fedGalleyClient <- view tsFedGalleyClient
1145-
cannon <- view tsCannon
1146-
1147-
WS.bracketR cannon (qUnqualified (pUserId bob)) $ \wsB -> do
1148-
-- send welcome message
1149-
void $
1150-
runFedClient @"mls-welcome" fedGalleyClient aliceDomain $
1151-
MLSWelcomeRequest
1152-
(Base64ByteString welcome)
1153-
1154-
-- check that the corresponding event is received
1155-
liftIO $ do
1156-
WS.assertMatch_ (5 # WS.Second) wsB $
1157-
wsAssertMLSWelcome (pUserId bob) welcome
1158-
1159-
sendMLSWelcomeKeyPackageNotFound :: TestM ()
1160-
sendMLSWelcomeKeyPackageNotFound = do
1161-
let aliceDomain = Domain "a.far-away.example.com"
1162-
-- Alice is from the originating domain and Bob is local, i.e., on the receiving domain
1163-
MessagingSetup {..} <-
1164-
aliceInvitesBob
1165-
(1, LocalUser)
1166-
def
1167-
{ creatorOrigin = RemoteUser aliceDomain,
1168-
createClients = DontCreateClients -- no key package upload will happen
1169-
}
1170-
let bob = head users
1171-
1172-
fedGalleyClient <- view tsFedGalleyClient
1173-
cannon <- view tsCannon
1174-
1175-
WS.bracketR cannon (qUnqualified (pUserId bob)) $ \wsB -> do
1176-
-- send welcome message
1177-
void $
1178-
runFedClient @"mls-welcome" fedGalleyClient aliceDomain $
1179-
MLSWelcomeRequest
1180-
(Base64ByteString welcome)
1181-
1182-
liftIO $ do
1183-
-- check that no event is received
1184-
WS.assertNoEvent (1 # Second) [wsB]
1185-
11861133
getConvAction :: Sing tag -> SomeConversationAction -> Maybe (ConversationAction tag)
11871134
getConvAction tquery (SomeConversationAction tag action) =
11881135
case (tag, tquery) of

0 commit comments

Comments
 (0)