diff --git a/internal/api/client.go b/internal/api/client.go index 36797e6..71bb708 100644 --- a/internal/api/client.go +++ b/internal/api/client.go @@ -33,11 +33,6 @@ type Client interface { // uploaded to the server. Failure to block will result in flakey tests as other users may not // encrypt for this Client due to not detecting keys for the Client. Login(t ct.TestLike, opts ClientCreationOpts) error - // MustStartSyncing to begin syncing from sync v2 / sliding sync. - // Tests should call stopSyncing() at the end of the test. - // MUST BLOCK until the initial sync is complete. - // Fails the test if there was a problem syncing. - MustStartSyncing(t ct.TestLike) (stopSyncing func()) // StartSyncing to begin syncing from sync v2 / sliding sync. // Tests should call stopSyncing() at the end of the test. // MUST BLOCK until the initial sync is complete. @@ -96,9 +91,31 @@ type Client interface { Opts() ClientCreationOpts } -type Notification struct { - Event - HasMentions *bool +// TestClient is a Client with extra helper functions added to make writing tests easier. +// Client implementations are not expected to implement these helper functions, and are +// instead composed together by the test rig itself. See TestClientImpl. +type TestClient interface { + Client + MustStartSyncing(t ct.TestLike) (stopSyncing func()) +} + +func NewTestClient(c Client) TestClient { + return &testClientImpl{ + Client: c, + } +} + +type testClientImpl struct { + Client +} + +func (c *testClientImpl) MustStartSyncing(t ct.TestLike) (stopSyncing func()) { + t.Helper() + stopSyncing, err := c.StartSyncing(t) + if err != nil { + ct.Fatalf(t, "MustStartSyncing: %s", err) + } + return stopSyncing } type LoggedClient struct { @@ -136,14 +153,6 @@ func (c *LoggedClient) MustGetEvent(t ct.TestLike, roomID, eventID string) Event return c.Client.MustGetEvent(t, roomID, eventID) } -func (c *LoggedClient) MustStartSyncing(t ct.TestLike) (stopSyncing func()) { - t.Helper() - c.Logf(t, "%s MustStartSyncing starting to sync", c.logPrefix()) - stopSyncing = c.Client.MustStartSyncing(t) - c.Logf(t, "%s MustStartSyncing now syncing", c.logPrefix()) - return -} - func (c *LoggedClient) StartSyncing(t ct.TestLike) (stopSyncing func(), err error) { t.Helper() c.Logf(t, "%s StartSyncing starting to sync", c.logPrefix()) @@ -216,6 +225,11 @@ func (c *LoggedClient) logPrefix() string { return fmt.Sprintf("[%s](%s)", c.UserID(), c.Type()) } +type Notification struct { + Event + HasMentions *bool +} + // ClientCreationOpts are options to use when creating crypto clients. // // This contains a mixture of generic options which can be used across any client, and specific diff --git a/internal/api/js/js.go b/internal/api/js/js.go index 5ae0294..b421d68 100644 --- a/internal/api/js/js.go +++ b/internal/api/js/js.go @@ -549,13 +549,6 @@ func (c *JSClient) MustGetEvent(t ct.TestLike, roomID, eventID string) api.Event return ev } -func (c *JSClient) MustStartSyncing(t ct.TestLike) (stopSyncing func()) { - t.Helper() - stopSyncing, err := c.StartSyncing(t) - must.NotError(t, "StartSyncing", err) - return stopSyncing -} - // StartSyncing to begin syncing from sync v2 / sliding sync. // Tests should call stopSyncing() at the end of the test. func (c *JSClient) StartSyncing(t ct.TestLike) (stopSyncing func(), err error) { diff --git a/internal/api/rust/rust.go b/internal/api/rust/rust.go index 44db503..bd3cf1f 100644 --- a/internal/api/rust/rust.go +++ b/internal/api/rust/rust.go @@ -323,13 +323,6 @@ func (c *RustClient) MustGetEvent(t ct.TestLike, roomID, eventID string) api.Eve return *ev } -func (c *RustClient) MustStartSyncing(t ct.TestLike) (stopSyncing func()) { - t.Helper() - stopSyncing, err := c.StartSyncing(t) - must.NotError(t, "StartSyncing", err) - return stopSyncing -} - // StartSyncing to begin syncing from sync v2 / sliding sync. // Tests should call stopSyncing() at the end of the test. func (c *RustClient) StartSyncing(t ct.TestLike) (stopSyncing func(), err error) { diff --git a/internal/cc/test_context.go b/internal/cc/test_context.go index 169b356..8711215 100644 --- a/internal/cc/test_context.go +++ b/internal/cc/test_context.go @@ -70,9 +70,9 @@ func (c *TestContext) RegisterNewUser(t *testing.T, clientType api.ClientType, l // // The callback function is invoked after this, and cleanup functions are called on your behalf when the // callback function ends. -func (c *TestContext) WithClientSyncing(t *testing.T, req *ClientCreationRequest, callback func(cli api.Client)) { +func (c *TestContext) WithClientSyncing(t *testing.T, req *ClientCreationRequest, callback func(cli api.TestClient)) { t.Helper() - c.WithClientsSyncing(t, []*ClientCreationRequest{req}, func(clients []api.Client) { + c.WithClientsSyncing(t, []*ClientCreationRequest{req}, func(clients []api.TestClient) { callback(clients[0]) }) } @@ -87,9 +87,9 @@ func (c *TestContext) WithClientSyncing(t *testing.T, req *ClientCreationRequest // // The callback function is invoked after this, and cleanup functions are called on your behalf when the // callback function ends. -func (c *TestContext) WithClientsSyncing(t *testing.T, reqs []*ClientCreationRequest, callback func(clients []api.Client)) { +func (c *TestContext) WithClientsSyncing(t *testing.T, reqs []*ClientCreationRequest, callback func(clients []api.TestClient)) { t.Helper() - cryptoClients := make([]api.Client, len(reqs)) + cryptoClients := make([]api.TestClient, len(reqs)) // Login all clients BEFORE starting any of their sync loops. // We do this because Login will send device list updates and cause clients to upload OTKs/device keys. // We want to make sure ALL these keys are on the server before any test client syncs otherwise it @@ -107,18 +107,18 @@ func (c *TestContext) WithClientsSyncing(t *testing.T, reqs []*ClientCreationReq } // mustCreateMultiprocessClient creates a new RPC process and instructs it to create a client given by the client creation options. -func (c *TestContext) mustCreateMultiprocessClient(t *testing.T, req *ClientCreationRequest) api.Client { +func (c *TestContext) mustCreateMultiprocessClient(t *testing.T, req *ClientCreationRequest) api.TestClient { t.Helper() if c.RPCBinaryPath == "" { t.Skipf("RPC binary path not provided, skipping multiprocess test. To run this test, set COMPLEMENT_CRYPTO_RPC_BINARY") - return nil + return api.NewTestClient(nil) } ctxPrefix := fmt.Sprintf("%d", c.RPCInstance.Add(1)) remoteBindings, err := rpc.NewLanguageBindings(c.RPCBinaryPath, req.User.ClientType.Lang, ctxPrefix) if err != nil { t.Fatalf("Failed to create new RPC language bindings: %s", err) } - return remoteBindings.MustCreateClient(t, req.Opts) + return api.NewTestClient(remoteBindings.MustCreateClient(t, req.Opts)) } // WithAliceSyncing is a helper function which creates a rust/js client and automatically logs in Alice and starts @@ -126,7 +126,7 @@ func (c *TestContext) mustCreateMultiprocessClient(t *testing.T, req *ClientCrea // // The callback function is invoked after this, and cleanup functions are called on your behalf when the // callback function ends. -func (c *TestContext) WithAliceSyncing(t *testing.T, callback func(alice api.Client)) { +func (c *TestContext) WithAliceSyncing(t *testing.T, callback func(alice api.TestClient)) { t.Helper() must.NotEqual(t, c.Alice, nil, "No Alice defined. Call CreateTestContext() with at least 1 api.ClientType.") c.WithClientSyncing(t, &ClientCreationRequest{ @@ -139,7 +139,7 @@ func (c *TestContext) WithAliceSyncing(t *testing.T, callback func(alice api.Cli // // The callback function is invoked after this, and cleanup functions are called on your behalf when the // callback function ends. -func (c *TestContext) WithAliceAndBobSyncing(t *testing.T, callback func(alice, bob api.Client)) { +func (c *TestContext) WithAliceAndBobSyncing(t *testing.T, callback func(alice, bob api.TestClient)) { t.Helper() must.NotEqual(t, c.Bob, nil, "No Bob defined. Call CreateTestContext() with at least 2 api.ClientTypes.") c.WithClientsSyncing(t, []*ClientCreationRequest{ @@ -149,7 +149,7 @@ func (c *TestContext) WithAliceAndBobSyncing(t *testing.T, callback func(alice, { User: c.Bob, }, - }, func(clients []api.Client) { + }, func(clients []api.TestClient) { callback(clients[0], clients[1]) }) } @@ -159,7 +159,7 @@ func (c *TestContext) WithAliceAndBobSyncing(t *testing.T, callback func(alice, // // The callback function is invoked after this, and cleanup functions are called on your behalf when the // callback function ends. -func (c *TestContext) WithAliceBobAndCharlieSyncing(t *testing.T, callback func(alice, bob, charlie api.Client)) { +func (c *TestContext) WithAliceBobAndCharlieSyncing(t *testing.T, callback func(alice, bob, charlie api.TestClient)) { t.Helper() must.NotEqual(t, c.Charlie, nil, "No Charlie defined. Call CreateTestContext() with at least 3 api.ClientTypes.") c.WithClientsSyncing(t, []*ClientCreationRequest{ @@ -172,7 +172,7 @@ func (c *TestContext) WithAliceBobAndCharlieSyncing(t *testing.T, callback func( { User: c.Charlie, }, - }, func(clients []api.Client) { + }, func(clients []api.TestClient) { callback(clients[0], clients[1], clients[2]) }) } @@ -288,7 +288,7 @@ func (c *TestContext) MustRegisterNewDevice(t *testing.T, user *User, newDeviceI } // MustLoginClient is the same as MustCreateClient but also logs in the client. -func (c *TestContext) MustLoginClient(t *testing.T, req *ClientCreationRequest) api.Client { +func (c *TestContext) MustLoginClient(t *testing.T, req *ClientCreationRequest) api.TestClient { t.Helper() client := c.MustCreateClient(t, req) must.NotError(t, "failed to login client", client.Login(t, client.Opts())) @@ -297,7 +297,7 @@ func (c *TestContext) MustLoginClient(t *testing.T, req *ClientCreationRequest) // MustCreateClient creates an api.Client from an existing Complement client and the specified client type. Additional options // can be set to configure the client beyond that of the Complement client e.g to add persistent storage. -func (c *TestContext) MustCreateClient(t *testing.T, req *ClientCreationRequest) api.Client { +func (c *TestContext) MustCreateClient(t *testing.T, req *ClientCreationRequest) api.TestClient { t.Helper() if req.User == nil { ct.Fatalf(t, "MustCreateClient: ClientCreationRequest missing 'user', register one with RegisterNewUser or use an existing one.") @@ -318,11 +318,11 @@ func (c *TestContext) MustCreateClient(t *testing.T, req *ClientCreationRequest) // mustCreateClient creates an api.Client with the specified language/server, else fails the test. // // Options can be provided to configure clients, such as enabling persistent storage. -func mustCreateClient(t *testing.T, clientType api.ClientType, cfg api.ClientCreationOpts) api.Client { +func mustCreateClient(t *testing.T, clientType api.ClientType, cfg api.ClientCreationOpts) api.TestClient { bindings := langs.GetLanguageBindings(clientType.Lang) if bindings == nil { t.Fatalf("unknown language: %s", clientType.Lang) } c := bindings.MustCreateClient(t, cfg) - return c + return api.NewTestClient(c) } diff --git a/internal/deploy/rpc/client.go b/internal/deploy/rpc/client.go index 2f07061..02ab2fa 100644 --- a/internal/deploy/rpc/client.go +++ b/internal/deploy/rpc/client.go @@ -218,24 +218,6 @@ func (c *RPCClient) Login(t ct.TestLike, opts api.ClientCreationOpts) error { return err } -// MustStartSyncing to begin syncing from sync v2 / sliding sync. -// Tests should call stopSyncing() at the end of the test. -// MUST BLOCK until the initial sync is complete. -// Fails the test if there was a problem syncing. -func (c *RPCClient) MustStartSyncing(t ct.TestLike) (stopSyncing func()) { - var void int - err := c.client.Call("Server.MustStartSyncing", t.Name(), &void) - if err != nil { - t.Fatalf("RPCClient.MustStartSyncing: %s", err) - } - return func() { - err := c.client.Call("Server.StopSyncing", t.Name(), &void) - if err != nil { - t.Fatalf("RPCClient.StopSyncing: %s", err) - } - } -} - // StartSyncing to begin syncing from sync v2 / sliding sync. // Tests should call stopSyncing() at the end of the test. // MUST BLOCK until the initial sync is complete. diff --git a/internal/deploy/rpc/server.go b/internal/deploy/rpc/server.go index 1c83d14..0e363d3 100644 --- a/internal/deploy/rpc/server.go +++ b/internal/deploy/rpc/server.go @@ -111,12 +111,6 @@ func (s *Server) Login(opts api.ClientCreationOpts, void *int) error { return s.activeClient.Login(&api.MockT{}, opts) } -func (s *Server) MustStartSyncing(testName string, void *int) error { - defer s.keepAlive() - s.stopSyncing = s.activeClient.MustStartSyncing(&api.MockT{TestName: testName}) - return nil -} - func (s *Server) StartSyncing(testName string, void *int) error { defer s.keepAlive() stopSyncing, err := s.activeClient.StartSyncing(&api.MockT{TestName: testName}) diff --git a/internal/tests/client_test.go b/internal/tests/client_test.go index 72502d9..c000301 100644 --- a/internal/tests/client_test.go +++ b/internal/tests/client_test.go @@ -29,7 +29,7 @@ var ( ssDeployment *deploy.SlidingSyncDeployment // aka functions which make clients, and we don't care about the language. // Tests just loop through this array for each client impl. - clientFactories []func(t *testing.T, cfg api.ClientCreationOpts) api.Client + clientFactories []func(t *testing.T, cfg api.ClientCreationOpts) api.TestClient ) func Deploy(t *testing.T) *deploy.SlidingSyncDeployment { @@ -47,30 +47,30 @@ func Deploy(t *testing.T) *deploy.SlidingSyncDeployment { } func TestMain(m *testing.M) { - rustClientCreator := func(t *testing.T, cfg api.ClientCreationOpts) api.Client { + rustClientCreator := func(t *testing.T, cfg api.ClientCreationOpts) api.TestClient { client, err := rust.NewRustClient(t, cfg) if err != nil { t.Fatalf("NewRustClient: %s", err) } - return client + return api.NewTestClient(client) } - jsClientCreator := func(t *testing.T, cfg api.ClientCreationOpts) api.Client { + jsClientCreator := func(t *testing.T, cfg api.ClientCreationOpts) api.TestClient { client, err := js.NewJSClient(t, cfg) if err != nil { t.Fatalf("NewJSClient: %s", err) } - return client + return api.NewTestClient(client) } clientFactories = append(clientFactories, rustClientCreator, jsClientCreator) rpcBinary := os.Getenv("COMPLEMENT_CRYPTO_RPC_BINARY") if rpcBinary != "" { - clientFactories = append(clientFactories, func(t *testing.T, cfg api.ClientCreationOpts) api.Client { + clientFactories = append(clientFactories, func(t *testing.T, cfg api.ClientCreationOpts) api.TestClient { remoteBindings, err := rpc.NewLanguageBindings(rpcBinary, api.ClientTypeRust, "") if err != nil { log.Fatal(err) } - return remoteBindings.MustCreateClient(t, cfg) + return api.NewTestClient(remoteBindings.MustCreateClient(t, cfg)) }) } rust.SetupLogs("rust_sdk_logs") @@ -104,7 +104,7 @@ func TestReceiveTimeline(t *testing.T) { } // test that if we start syncing with a room full of events, we see those events. - ForEachClient(t, "existing_events", deployment, func(t *testing.T, client api.Client, csapi *client.CSAPI) { + ForEachClient(t, "existing_events", deployment, func(t *testing.T, client api.TestClient, csapi *client.CSAPI) { must.NotError(t, "Failed to login", client.Login(t, client.Opts())) roomID, eventIDs := createAndSendEvents(t, csapi) time.Sleep(time.Second) // give time for everything to settle server-side e.g sliding sync proxy @@ -132,7 +132,7 @@ func TestReceiveTimeline(t *testing.T) { }) // test that if we are already syncing and then see a room live stream full of events, we see those events. - ForEachClient(t, "live_events", deployment, func(t *testing.T, client api.Client, csapi *client.CSAPI) { + ForEachClient(t, "live_events", deployment, func(t *testing.T, client api.TestClient, csapi *client.CSAPI) { must.NotError(t, "Failed to login", client.Login(t, client.Opts())) stopSyncing := client.MustStartSyncing(t) defer stopSyncing() @@ -171,7 +171,7 @@ func TestReceiveTimeline(t *testing.T) { func TestCanWaitUntilEventInRoomBeforeRoomIsKnown(t *testing.T) { deployment := Deploy(t) - ForEachClient(t, "", deployment, func(t *testing.T, client api.Client, csapi *client.CSAPI) { + ForEachClient(t, "", deployment, func(t *testing.T, client api.TestClient, csapi *client.CSAPI) { roomID := csapi.MustCreateRoom(t, map[string]interface{}{}) eventID := csapi.SendEventSynced(t, roomID, b.Event{ Type: "m.room.message", @@ -196,7 +196,7 @@ func TestCanWaitUntilEventInRoomBeforeRoomIsKnown(t *testing.T) { func TestSendingEvents(t *testing.T) { deployment := Deploy(t) - ForEachClient(t, "", deployment, func(t *testing.T, client api.Client, csapi *client.CSAPI) { + ForEachClient(t, "", deployment, func(t *testing.T, client api.TestClient, csapi *client.CSAPI) { must.NotError(t, "Failed to login", client.Login(t, client.Opts())) roomID := csapi.MustCreateRoom(t, map[string]interface{}{}) stopSyncing := client.MustStartSyncing(t) @@ -217,7 +217,7 @@ func TestSendingEvents(t *testing.T) { } // run a subtest for each client factory -func ForEachClient(t *testing.T, name string, deployment *deploy.SlidingSyncDeployment, fn func(t *testing.T, client api.Client, csapi *client.CSAPI)) { +func ForEachClient(t *testing.T, name string, deployment *deploy.SlidingSyncDeployment, fn func(t *testing.T, client api.TestClient, csapi *client.CSAPI)) { for _, createClient := range clientFactories { csapiAlice := deployment.Register(t, "hs1", helpers.RegistrationOpts{ LocalpartSuffix: "client", diff --git a/tests/delayed_requests_test.go b/tests/delayed_requests_test.go index 4ff5f26..4720084 100644 --- a/tests/delayed_requests_test.go +++ b/tests/delayed_requests_test.go @@ -33,7 +33,7 @@ func TestDelayedInviteResponse(t *testing.T) { Instance().ForEachClientType(t, func(t *testing.T, clientType api.ClientType) { tc := Instance().CreateTestContext(t, clientType, clientType) roomID := tc.CreateNewEncryptedRoom(t, tc.Alice) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // we send a message first so clients which lazily call /members can do so now. // if we don't do this, the client won't rely on /sync for the member list so won't fail. alice.SendMessage(t, roomID, "dummy message to make /members call") diff --git a/tests/device_keys_test.go b/tests/device_keys_test.go index b18ad08..9ada72a 100644 --- a/tests/device_keys_test.go +++ b/tests/device_keys_test.go @@ -41,7 +41,7 @@ func TestFailedDeviceKeyDownloadRetries(t *testing.T) { roomID := tc.CreateNewEncryptedRoom(t, tc.Alice, cc.EncRoomOptions.Invite([]string{tc.Bob.UserID})) tc.Bob.MustJoinRoom(t, roomID, []string{"hs1"}) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // When Alice sends a message alice.SendMessage(t, roomID, "checking whether we can send a message") diff --git a/tests/federation_connectivity_test.go b/tests/federation_connectivity_test.go index 4b6b624..e72958e 100644 --- a/tests/federation_connectivity_test.go +++ b/tests/federation_connectivity_test.go @@ -32,7 +32,7 @@ func TestNewUserCannotGetKeysForOfflineServer(t *testing.T) { t.Logf("%s joining room %s", tc.Bob.UserID, roomID) tc.Bob.MustJoinRoom(t, roomID, []string{"hs1"}) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // let clients sync device keys time.Sleep(time.Second) @@ -50,7 +50,7 @@ func TestNewUserCannotGetKeysForOfflineServer(t *testing.T) { tc.Alice.MustInviteRoom(t, roomID, tc.Charlie.UserID) tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Charlie, - }, func(charlie api.Client) { + }, func(charlie api.TestClient) { tc.Charlie.MustJoinRoom(t, roomID, []string{"hs1"}) // let charlie sync device keys... and fail to get bob's keys! @@ -116,7 +116,7 @@ func TestExistingSessionCannotGetKeysForOfflineServer(t *testing.T) { tc.Bob.MustJoinRoom(t, roomIDab, []string{"hs1"}) tc.Bob.MustJoinRoom(t, roomIDbc, []string{"hs1"}) - tc.WithAliceBobAndCharlieSyncing(t, func(alice, bob, charlie api.Client) { + tc.WithAliceBobAndCharlieSyncing(t, func(alice, bob, charlie api.TestClient) { // let clients sync device keys time.Sleep(time.Second) diff --git a/tests/key_backup_test.go b/tests/key_backup_test.go index d267f3c..62c9c43 100644 --- a/tests/key_backup_test.go +++ b/tests/key_backup_test.go @@ -36,7 +36,7 @@ func TestCanBackupKeys(t *testing.T) { // SDK testing below // ----------------- - tc.WithAliceSyncing(t, func(backupCreator api.Client) { + tc.WithAliceSyncing(t, func(backupCreator api.TestClient) { body := "An encrypted message" waiter := backupCreator.WaitUntilEventInRoom(t, roomID, api.CheckEventHasBody(body)) evID := backupCreator.SendMessage(t, roomID, body) @@ -98,7 +98,7 @@ func TestBackupWrongRecoveryKeyFails(t *testing.T) { // SDK testing below // ----------------- - tc.WithAliceSyncing(t, func(backupCreator api.Client) { + tc.WithAliceSyncing(t, func(backupCreator api.TestClient) { body := "An encrypted message" waiter := backupCreator.WaitUntilEventInRoom(t, roomID, api.CheckEventHasBody(body)) evID := backupCreator.SendMessage(t, roomID, body) diff --git a/tests/membership_acls_test.go b/tests/membership_acls_test.go index 42a1cb9..a7dd54c 100644 --- a/tests/membership_acls_test.go +++ b/tests/membership_acls_test.go @@ -35,7 +35,7 @@ func TestAliceBobEncryptionWorks(t *testing.T) { // SDK testing below // ----------------- - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { wantMsgBody := "Hello world" // Check the room is in fact encrypted @@ -75,7 +75,7 @@ func TestCanDecryptMessagesAfterInviteButBeforeJoin(t *testing.T) { // SDK testing below // ----------------- - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { wantMsgBody := "Message sent when bob is invited not joined" // Check the room is in fact encrypted @@ -122,7 +122,7 @@ func TestBobCanSeeButNotDecryptHistoryInPublicRoom(t *testing.T) { // SDK testing below // ----------------- - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // Alice sends a message which Bob should not be able to decrypt beforeJoinBody := "Before Bob joins" waiter := alice.WaitUntilEventInRoom(t, roomID, api.CheckEventHasBody(beforeJoinBody)) @@ -163,7 +163,7 @@ func TestOnRejoinBobCanSeeButNotDecryptHistoryInPublicRoom(t *testing.T) { // SDK testing below // ----------------- - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // Alice sends a message which Bob should be able to decrypt. bothJoinedBody := "Alice and Bob in a room" waiter := bob.WaitUntilEventInRoom(t, roomID, api.CheckEventHasBody(bothJoinedBody)) @@ -222,7 +222,7 @@ func TestOnNewDeviceBobCanSeeButNotDecryptHistoryInPublicRoom(t *testing.T) { // SDK testing below // ----------------- - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // Alice sends a message which Bob should be able to decrypt. onlyFirstDeviceBody := "Alice and Bob in a room" waiter := bob.WaitUntilEventInRoom(t, roomID, api.CheckEventHasBody(onlyFirstDeviceBody)) @@ -234,7 +234,7 @@ func TestOnNewDeviceBobCanSeeButNotDecryptHistoryInPublicRoom(t *testing.T) { csapiBob2 := tc.MustRegisterNewDevice(t, tc.Bob, "NEW_DEVICE") tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: csapiBob2, - }, func(bob2 api.Client) { + }, func(bob2 api.TestClient) { time.Sleep(time.Second) // let device keys propagate to alice bob2.MustBackpaginate(t, roomID, 5) // ensure the older event is there time.Sleep(time.Second) @@ -265,7 +265,7 @@ func TestOnNewDeviceBobCanSeeButNotDecryptHistoryInPublicRoom(t *testing.T) { // now bob logs in again tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: csapiBob2, - }, func(bob2 api.Client) { + }, func(bob2 api.TestClient) { time.Sleep(time.Second) // let device keys propagate to alice undecryptableEvent := bob2.MustGetEvent(t, roomID, evID) must.Equal(t, undecryptableEvent.FailedToDecrypt, true, "bob's new device was able to decrypt a message sent after he had logged out") @@ -282,7 +282,7 @@ func TestChangingDeviceAfterInviteReEncrypts(t *testing.T) { // shared history visibility roomID := tc.CreateNewEncryptedRoom(t, tc.Alice, cc.EncRoomOptions.PresetPublicChat()) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // Alice invites Bob and then she sends an event tc.Alice.MustInviteRoom(t, roomID, tc.Bob.UserID) time.Sleep(time.Second) // let device keys propagate @@ -293,7 +293,7 @@ func TestChangingDeviceAfterInviteReEncrypts(t *testing.T) { csapiBob2 := tc.MustRegisterNewDevice(t, tc.Bob, "NEW_DEVICE") tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: csapiBob2, - }, func(bob2 api.Client) { + }, func(bob2 api.TestClient) { time.Sleep(time.Second) // let device keys propagate tc.Bob.MustJoinRoom(t, roomID, []string{clientTypeA.HS}) diff --git a/tests/one_time_keys_test.go b/tests/one_time_keys_test.go index 6e5605a..6bac656 100644 --- a/tests/one_time_keys_test.go +++ b/tests/one_time_keys_test.go @@ -95,7 +95,7 @@ func TestFallbackKeyIsUsedIfOneTimeKeysRunOut(t *testing.T) { // ================= // Upload OTKs and a fallback - tc.WithAliceBobAndCharlieSyncing(t, func(alice, bob, charlie api.Client) { + tc.WithAliceBobAndCharlieSyncing(t, func(alice, bob, charlie api.TestClient) { // we need to send _something_ to cause /sync v2 to return a long poll response, as fallback // keys don't wake up /sync v2. If we don't do this, rust SDK fails to realise it needs to upload a fallback // key because SS doesn't tell it, because Synapse doesn't tell SS that the fallback key was used. @@ -169,7 +169,7 @@ func TestFailedOneTimeKeyUploadRetries(t *testing.T) { }, RequestCallback: callback.SendError(2, http.StatusGatewayTimeout), }, func() { - tc.WithAliceSyncing(t, func(alice api.Client) { + tc.WithAliceSyncing(t, func(alice api.TestClient) { tc.Bob.MustDo(t, "POST", []string{ "_matrix", "client", "v3", "keys", "claim", }, client.WithJSONBody(t, map[string]any{ @@ -208,7 +208,7 @@ func TestFailedKeysClaimRetries(t *testing.T) { Instance().ForEachClientType(t, func(t *testing.T, clientType api.ClientType) { tc := Instance().CreateTestContext(t, clientType, clientType) // both clients start syncing to upload OTKs - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { var stopPoking atomic.Bool waiter := helpers.NewWaiter() // make a room which will link the 2 users together when diff --git a/tests/room_keys_test.go b/tests/room_keys_test.go index c7284b2..baa5f80 100644 --- a/tests/room_keys_test.go +++ b/tests/room_keys_test.go @@ -57,7 +57,7 @@ func TestRoomKeyIsCycledOnDeviceLogout(t *testing.T) { User: csapiAlice2, }) defer alice2.Close(t) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { alice2StopSyncing := alice2.MustStartSyncing(t) alice.WaitUntilEventInRoom(t, roomID, api.CheckEventHasMembership(tc.Bob.UserID, "join")).Waitf(t, 5*time.Second, "alice did not see own join") // check the room works @@ -117,7 +117,7 @@ func TestRoomKeyIsCycledAfterEnoughMessages(t *testing.T) { ) tc.Bob.MustJoinRoom(t, roomID, []string{clientTypeA.HS}) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // And some messages were sent, but not enough to trigger resending for i := 0; i < 4; i++ { wantMsgBody := fmt.Sprintf("Before we hit the threshold %d", i) @@ -191,7 +191,7 @@ func TestRoomKeyIsCycledAfterEnoughTime(t *testing.T) { ) tc.Bob.MustJoinRoom(t, roomID, []string{clientTypeA.HS}) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // Before we start, ensure some keys have already been sent, so we // don't get a false positive. wantMsgBody := "Before we start" @@ -226,7 +226,7 @@ func TestRoomKeyIsCycledOnMemberLeaving(t *testing.T) { Instance().ClientTypeMatrix(t, func(t *testing.T, clientTypeA, clientTypeB api.ClientType) { tc := Instance().CreateTestContext(t, clientTypeA, clientTypeB, clientTypeB) // Alice, Bob and Charlie are in a room. - tc.WithAliceBobAndCharlieSyncing(t, func(alice, bob, charlie api.Client) { + tc.WithAliceBobAndCharlieSyncing(t, func(alice, bob, charlie api.TestClient) { // do setup code after all clients are syncing to ensure that if Alice asks for Charlie's keys on receipt of the // join event, then Charlie has already uploaded keys. roomID := tc.CreateNewEncryptedRoom( @@ -281,7 +281,7 @@ func TestRoomKeyIsNotCycled(t *testing.T) { tc.Bob.MustJoinRoom(t, roomID, []string{clientTypeA.HS}) // Alice, Bob are in a room. - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // check the room works wantMsgBody := "Test Message" waiter := bob.WaitUntilEventInRoom(t, roomID, api.CheckEventHasBody(wantMsgBody)) @@ -407,7 +407,7 @@ func testRoomKeyIsNotCycledOnClientRestartRust(t *testing.T, clientType api.Clie tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Bob, - }, func(bob api.Client) { + }, func(bob api.TestClient) { wantMsgBody := "test from another process" // send a message as Alice in a different process tc.WithClientSyncing(t, &cc.ClientCreationRequest{ @@ -416,7 +416,7 @@ func testRoomKeyIsNotCycledOnClientRestartRust(t *testing.T, clientType api.Clie PersistentStorage: true, }, Multiprocess: true, - }, func(remoteAlice api.Client) { + }, func(remoteAlice api.TestClient) { eventID := remoteAlice.SendMessage(t, roomID, wantMsgBody) waiter := remoteAlice.WaitUntilEventInRoom(t, roomID, api.CheckEventHasEventID(eventID)) waiter.Waitf(t, 5*time.Second, "client did not see event %s", eventID) @@ -480,7 +480,7 @@ func testRoomKeyIsNotCycledOnClientRestartJS(t *testing.T, clientType api.Client // no alice.close here as we'll close it in the test mid-way tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Bob, - }, func(bob api.Client) { + }, func(bob api.TestClient) { // check the room works wantMsgBody := "Test Message" waiter := bob.WaitUntilEventInRoom(t, roomID, api.CheckEventHasBody(wantMsgBody)) @@ -496,7 +496,7 @@ func testRoomKeyIsNotCycledOnClientRestartJS(t *testing.T, clientType api.Client tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Alice, Opts: alice.Opts(), - }, func(alice api.Client) { + }, func(alice api.TestClient) { // now send another message from Alice, who should NOT send another new room key wantMsgBody = "Another Test Message" waiter = bob.WaitUntilEventInRoom(t, roomID, api.CheckEventHasBody(wantMsgBody)) diff --git a/tests/rust/notification_test.go b/tests/rust/notification_test.go index f791322..47bf815 100644 --- a/tests/rust/notification_test.go +++ b/tests/rust/notification_test.go @@ -118,7 +118,7 @@ func TestNSEReceiveForNonPreKeyMessage(t *testing.T) { // Bob sends a message to alice tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Bob, - }, func(bob api.Client) { + }, func(bob api.TestClient) { // let bob realise alice exists and claims keys time.Sleep(time.Second) // Send a message as Bob, this will contain ensure an Olm session is set up already before we do NSE work @@ -175,7 +175,7 @@ func TestMultiprocessNSE(t *testing.T) { // Bob sends a message to alice tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Bob, - }, func(bob api.Client) { + }, func(bob api.TestClient) { // let bob realise alice exists and claims keys time.Sleep(time.Second) for i := 0; i < numPreBackgroundMsgs; i++ { @@ -336,7 +336,7 @@ func TestMultiprocessNSEBackupKeyMacError(t *testing.T) { // Bob sends a message to alice tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Bob, - }, func(bob api.Client) { + }, func(bob api.TestClient) { // let bob realise alice exists and claims keys time.Sleep(time.Second) @@ -452,7 +452,7 @@ func TestMultiprocessNSEOlmSessionWedge(t *testing.T) { // Bob sends a message to alice tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Bob, - }, func(bob api.Client) { + }, func(bob api.TestClient) { // let bob realise alice exists and claims keys time.Sleep(time.Second) msg := "pre message" @@ -599,7 +599,7 @@ func TestNotificationClientDupeOTKUpload(t *testing.T) { // The main app will see this in /sync and then try to upload another OTK, which we will tarpit. tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Bob, - }, func(bob api.Client) { + }, func(bob api.TestClient) { eventID := bob.SendMessage(t, roomID, "Hello world!") // create a NotificationClient in the same process to fetch this "push notification". // It might make the NotificationClient upload a OTK as it would have seen 1 has been used. @@ -648,7 +648,7 @@ func TestMultiprocessInitialE2EESyncDoesntDropDeviceListUpdates(t *testing.T) { // Bob sends a message to Alice tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Alice, - }, func(alice api.Client) { + }, func(alice api.TestClient) { // ensure bob has queried keys from alice by sending a message. msg := "pre message" bob.SendMessage(t, roomID, msg) @@ -700,7 +700,7 @@ func TestMultiprocessInitialE2EESyncDoesntDropDeviceListUpdates(t *testing.T) { csapiAlice2 := tc.MustRegisterNewDevice(t, tc.Alice, "NEW_DEVICE") tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: csapiAlice2, - }, func(alice2 api.Client) { + }, func(alice2 api.TestClient) { // wait for device keys to sync up time.Sleep(time.Second) // alice[1] sends a message, this is unimportant other than to grab the event ID for the push process @@ -750,7 +750,7 @@ func bobSendsMessage(t *testing.T, tc *cc.TestContext, roomID, text string, msgs pushNotifEventID := "" tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: tc.Bob, - }, func(bob api.Client) { + }, func(bob api.TestClient) { for i := 0; i < msgsBefore; i++ { bob.SendMessage(t, roomID, fmt.Sprintf("msg before %d", i)) } diff --git a/tests/to_device_test.go b/tests/to_device_test.go index 102b6d3..56a852d 100644 --- a/tests/to_device_test.go +++ b/tests/to_device_test.go @@ -22,7 +22,7 @@ func TestClientRetriesSendToDevice(t *testing.T) { tc := Instance().CreateTestContext(t, clientTypeA, clientTypeB) roomID := tc.CreateNewEncryptedRoom(t, tc.Alice, cc.EncRoomOptions.PresetPublicChat()) tc.Bob.MustJoinRoom(t, roomID, []string{clientTypeA.HS}) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { // lets device keys be exchanged time.Sleep(time.Second) @@ -85,7 +85,7 @@ func TestUnprocessedToDeviceMessagesArentLostOnRestart(t *testing.T) { PersistentStorage: true, }, }) - tc.WithAliceSyncing(t, func(alice api.Client) { + tc.WithAliceSyncing(t, func(alice api.TestClient) { // we will close this in the test, no defer bobStopSyncing := bob.MustStartSyncing(t) // check the room works @@ -178,7 +178,7 @@ func testUnprocessedToDeviceMessagesArentLostOnRestartRust(t *testing.T, tc *cc. Opts: api.ClientCreationOpts{ PersistentStorage: true, }, - }, func(bob api.Client) { + }, func(bob api.TestClient) { // we can't rely on MustStartSyncing returning to know that the room key has been received, as // in rust we just wait for RoomListLoadingStateLoaded which is a separate connection to the // encryption loop. @@ -242,7 +242,7 @@ func testUnprocessedToDeviceMessagesArentLostOnRestartJS(t *testing.T, tc *cc.Te Opts: api.ClientCreationOpts{ PersistentStorage: true, }, - }, func(bob api.Client) { + }, func(bob api.TestClient) { // include a grace period like rust, no specific reason beyond consistency. time.Sleep(time.Second) ev := bob.MustGetEvent(t, roomID, eventID) @@ -282,7 +282,7 @@ func TestToDeviceMessagesAreBatched(t *testing.T) { clientUnderTest.Close(t) } waiter := helpers.NewWaiter() - tc.WithAliceSyncing(t, func(alice api.Client) { + tc.WithAliceSyncing(t, func(alice api.TestClient) { // intercept /sendToDevice and check we are sending 100 messages per request tc.Deployment.MITM().Configure(t).WithIntercept(mitm.InterceptOpts{ Filter: mitm.FilterParams{ @@ -345,7 +345,7 @@ func TestToDeviceMessagesArentLostWhenKeysQueryFails(t *testing.T) { // get a normal E2EE room set up roomID := tc.CreateNewEncryptedRoom(t, tc.Alice, cc.EncRoomOptions.Invite([]string{tc.Bob.UserID})) tc.Bob.MustJoinRoom(t, roomID, []string{clientType.HS}) - tc.WithAliceAndBobSyncing(t, func(alice, bob api.Client) { + tc.WithAliceAndBobSyncing(t, func(alice, bob api.TestClient) { msg := "hello world" msg2 := "new device message from alice" alice.SendMessage(t, roomID, msg) @@ -370,7 +370,7 @@ func TestToDeviceMessagesArentLostWhenKeysQueryFails(t *testing.T) { csapiAlice2 := tc.MustRegisterNewDevice(t, tc.Alice, "OTHER_DEVICE") tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: csapiAlice2, - }, func(alice2 api.Client) { + }, func(alice2 api.TestClient) { // we don't know how long it will take for the device list update to be processed, so wait 1s time.Sleep(time.Second) @@ -429,7 +429,7 @@ func TestToDeviceMessagesAreProcessedInOrder(t *testing.T) { ID string Body string }{} - tc.WithAliceSyncing(t, func(alice api.Client) { + tc.WithAliceSyncing(t, func(alice api.TestClient) { callbackFn := func(cd callback.Data) *callback.Response { // try v2 sync then SS toDeviceEvents := gjson.ParseBytes(cd.ResponseBody).Get("to_device.events").Array() @@ -469,7 +469,7 @@ func TestToDeviceMessagesAreProcessedInOrder(t *testing.T) { creationReqs[i].User.MustJoinRoom(t, roomID, []string{clientType.HS}) } // send 30 messages as each user (interleaved) - tc.WithClientsSyncing(t, creationReqs, func(clients []api.Client) { + tc.WithClientsSyncing(t, creationReqs, func(clients []api.TestClient) { for i := 0; i < numMsgsPerClient; i++ { for _, c := range clients { body := fmt.Sprintf("Message %d", i+1) diff --git a/tests/verification_test.go b/tests/verification_test.go index d437795..e1d6f74 100644 --- a/tests/verification_test.go +++ b/tests/verification_test.go @@ -67,13 +67,13 @@ func TestVerificationSAS(t *testing.T) { ClientType: verifieeClientType, } - tc.WithAliceSyncing(t, func(verifier api.Client) { + tc.WithAliceSyncing(t, func(verifier api.TestClient) { tc.WithClientSyncing(t, &cc.ClientCreationRequest{ User: verifieeUser, Opts: api.ClientCreationOpts{ DeviceID: "OTHER_DEVICE", }, - }, func(verifiee api.Client) { + }, func(verifiee api.TestClient) { status := &verificationStatus{ mu: &sync.Mutex{}, }