package main import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "time" "github.com/golang/mock/gomock" "github.com/tinode/chat/server/store" "github.com/tinode/chat/server/store/mock_store" "github.com/tinode/chat/server/store/types" ) type internalAdminQueryNotFound struct{} func (internalAdminQueryNotFound) Query(types.TenantID, string, string, []any, int, int) (*types.InternalAdminQueryResult, error) { return nil, types.ErrNotFound } func TestClaimInternalNonceRejectsReplay(t *testing.T) { oldConfig := internalAPI.config internalAPI = internalAPIRuntime{config: oldConfig} defer func() { internalAPI = internalAPIRuntime{config: oldConfig} }() expiresAt := time.Now().Add(time.Minute) if !claimInternalNonce("manager-test", "single-use-nonce", "request-claim", expiresAt) { t.Fatal("first nonce claim was rejected") } if claimInternalNonce("manager-test", "single-use-nonce", "request-claim", expiresAt) { t.Fatal("replayed nonce was accepted") } } func (internalAdminQueryNotFound) QueryOne(types.TenantID, string, []any) (map[string]any, error) { return nil, types.ErrNotFound } func TestServeInternalFriendDirectAddCreatesRelationshipWithoutRequest(t *testing.T) { oldRelations := store.Relations relations := &testRelationsStore{} store.Relations = relations t.Cleanup(func() { store.Relations = oldRelations }) req := httptest.NewRequest(http.MethodPost, "/internal/admin-query/tenants/default/friends/direct", strings.NewReader(`{"user_id":"usrAQAAAAAAAAA","peer_user_id":"usrAgAAAAAAAAA"}`)) wrt := httptest.NewRecorder() serveInternalFriendDirectAdd(wrt, req, types.TenantID(1)) if wrt.Code != http.StatusOK { t.Fatalf("status: got %d, want %d; body=%s", wrt.Code, http.StatusOK, wrt.Body.String()) } if !relations.directAdded || relations.created != nil { t.Fatalf("direct_added=%v friend_request=%v, want direct add and no request", relations.directAdded, relations.created) } var payload struct { Data struct { Relationship string `json:"relationship"` } `json:"data"` } if err := json.Unmarshal(wrt.Body.Bytes(), &payload); err != nil { t.Fatal(err) } if payload.Data.Relationship != types.RelationshipFriend { t.Fatalf("relationship = %q, want %q", payload.Data.Relationship, types.RelationshipFriend) } } func TestServeInternalUserQueryMissingUserReturnsNotFound(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() oldQueries := store.InternalAdminQueries oldUsers := store.Users defer func() { store.InternalAdminQueries = oldQueries store.Users = oldUsers }() store.InternalAdminQueries = internalAdminQueryNotFound{} users := mock_store.NewMockUsersPersistenceInterface(ctrl) users.EXPECT().Get(types.TenantID(1), gomock.Any()).Return(nil, nil) store.Users = users req := httptest.NewRequest(http.MethodGet, "/internal/admin-query/tenants/default/users/1566402774239809500", nil) wrt := httptest.NewRecorder() serveInternalUserQuery(wrt, req, types.TenantID(1), "1566402774239809500") if wrt.Code != http.StatusNotFound { t.Fatalf("unexpected status: got %d, want %d; body=%s", wrt.Code, http.StatusNotFound, wrt.Body.String()) } var resp imHTTPResponse if err := json.Unmarshal(wrt.Body.Bytes(), &resp); err != nil { t.Fatalf("failed to decode response: %v", err) } if resp.Code != 30004 { t.Fatalf("unexpected response code: got %d, want 30004", resp.Code) } }