package syncapi import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "time" keyapi "github.com/matrix-org/dendrite/keyserver/api" "github.com/matrix-org/dendrite/roomserver/api" rsapi "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/dendrite/test" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/nats-io/nats.go" ) type syncRoomserverAPI struct { rsapi.SyncRoomserverAPI rooms []*test.Room } func (s *syncRoomserverAPI) QueryLatestEventsAndState(ctx context.Context, req *rsapi.QueryLatestEventsAndStateRequest, res *rsapi.QueryLatestEventsAndStateResponse) error { var room *test.Room for _, r := range s.rooms { if r.ID == req.RoomID { room = r break } } if room == nil { res.RoomExists = false return nil } res.RoomVersion = room.Version return nil // TODO: return state } type syncUserAPI struct { userapi.SyncUserAPI accounts []userapi.Device } func (s *syncUserAPI) QueryAccessToken(ctx context.Context, req *userapi.QueryAccessTokenRequest, res *userapi.QueryAccessTokenResponse) error { for _, acc := range s.accounts { if acc.AccessToken == req.AccessToken { res.Device = &acc return nil } } res.Err = "unknown user" return nil } func (s *syncUserAPI) PerformLastSeenUpdate(ctx context.Context, req *userapi.PerformLastSeenUpdateRequest, res *userapi.PerformLastSeenUpdateResponse) error { return nil } type syncKeyAPI struct { keyapi.KeyInternalAPI } func TestSyncAPI(t *testing.T) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { testSync(t, dbType) }) } func testSync(t *testing.T, dbType test.DBType) { user := test.NewUser() room := test.NewRoom(t, user) alice := userapi.Device{ ID: "ALICEID", UserID: user.ID, AccessToken: "ALICE_BEARER_TOKEN", DisplayName: "Alice", AccountType: userapi.AccountTypeUser, } base, close := test.CreateBaseDendrite(t, dbType) defer close() jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) var msgs []*nats.Msg for _, ev := range room.Events() { var addsStateIDs []string if ev.StateKey() != nil { addsStateIDs = append(addsStateIDs, ev.EventID()) } msgs = append(msgs, test.NewOutputEventMsg(t, base, room.ID, api.OutputEvent{ Type: rsapi.OutputTypeNewRoomEvent, NewRoomEvent: &rsapi.OutputNewRoomEvent{ Event: ev, AddsStateEventIDs: addsStateIDs, }, })) } AddPublicRoutes(base, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{rooms: []*test.Room{room}}, &syncKeyAPI{}) test.MustPublishMsgs(t, jsctx, msgs...) testCases := []struct { name string req *http.Request wantCode int wantJoinedRooms []string }{ { name: "missing access token", req: test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{ "timeout": "0", })), wantCode: 401, }, { name: "unknown access token", req: test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{ "access_token": "foo", "timeout": "0", })), wantCode: 401, }, { name: "valid access token", req: test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{ "access_token": alice.AccessToken, "timeout": "0", })), wantCode: 200, wantJoinedRooms: []string{room.ID}, }, } // TODO: find a better way time.Sleep(500 * time.Millisecond) for _, tc := range testCases { w := httptest.NewRecorder() base.PublicClientAPIMux.ServeHTTP(w, tc.req) if w.Code != tc.wantCode { t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode) } if tc.wantJoinedRooms != nil { var res types.Response if err := json.NewDecoder(w.Body).Decode(&res); err != nil { t.Fatalf("%s: failed to decode response body: %s", tc.name, err) } if len(res.Rooms.Join) != len(tc.wantJoinedRooms) { t.Errorf("%s: got %v joined rooms, want %v.\nResponse: %+v", tc.name, len(res.Rooms.Join), len(tc.wantJoinedRooms), res) } t.Logf("res: %+v", res.Rooms.Join[room.ID]) gotEventIDs := make([]string, len(res.Rooms.Join[room.ID].Timeline.Events)) for i, ev := range res.Rooms.Join[room.ID].Timeline.Events { gotEventIDs[i] = ev.EventID } test.AssertEventIDsEqual(t, gotEventIDs, room.Events()) } } }