feat: implement first batch im enhancements
This commit is contained in:
@@ -121,6 +121,14 @@ type testCallsStore struct {
|
||||
next string
|
||||
}
|
||||
|
||||
type testConversationsStore struct {
|
||||
topic string
|
||||
settings *types.ConversationSettings
|
||||
settingsPatch types.ConversationSettingsPatch
|
||||
draft *types.TopicDraft
|
||||
putDraftCalled bool
|
||||
}
|
||||
|
||||
type testWorkbenchStore struct {
|
||||
modules []types.WorkbenchModule
|
||||
version int
|
||||
@@ -199,6 +207,7 @@ type testGroupBusinessStore struct {
|
||||
joinRequests []types.GroupJoinRequest
|
||||
announcement *types.GroupAnnouncement
|
||||
mutes []types.GroupMute
|
||||
files []types.GroupFile
|
||||
invitations []types.GroupInvitation
|
||||
updatedSettings types.GroupSettingsPatch
|
||||
updatedMembers []types.GroupMemberPatch
|
||||
@@ -265,6 +274,19 @@ func (s *testGroupBusinessStore) CreateInvitation(_ types.TenantID, inv *types.G
|
||||
return inv, nil
|
||||
}
|
||||
|
||||
func (s *testGroupBusinessStore) AcceptInvitation(_ types.TenantID, invitationID string, uid types.Uid, _ any, now time.Time) (*types.GroupInvitation, error) {
|
||||
for i := range s.invitations {
|
||||
if s.invitations[i].InvitationID == invitationID {
|
||||
s.invitations[i].TargetUserID = uid
|
||||
s.invitations[i].Status = types.GroupInvitationStatusJoined
|
||||
s.invitations[i].Result = "joined"
|
||||
s.invitations[i].HandledAt = &now
|
||||
return &s.invitations[i], nil
|
||||
}
|
||||
}
|
||||
return &types.GroupInvitation{InvitationID: invitationID, Topic: "grp_test", TargetUserID: uid, Status: types.GroupInvitationStatusJoined, Result: "joined", ExpiresAt: now.Add(time.Hour), HandledAt: &now}, nil
|
||||
}
|
||||
|
||||
func (s *testGroupBusinessStore) CreateJoinRequest(_ types.TenantID, req *types.GroupJoinRequest) (*types.GroupJoinRequest, error) {
|
||||
now := time.Now().UTC()
|
||||
req.CreatedAt = now
|
||||
@@ -328,6 +350,33 @@ func (s *testGroupBusinessStore) DeleteMute(_ types.TenantID, _ string, _ types.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *testGroupBusinessStore) ListFiles(_ types.TenantID, _ string, _ string, _ string, _ string, _ int) ([]types.GroupFile, string, error) {
|
||||
return s.files, "", nil
|
||||
}
|
||||
|
||||
func (s *testGroupBusinessStore) CreateFile(_ types.TenantID, file *types.GroupFile) (*types.GroupFile, error) {
|
||||
if file.GroupFileID == "" {
|
||||
file.GroupFileID = "gfile_test"
|
||||
}
|
||||
now := time.Now().UTC().Round(time.Millisecond)
|
||||
file.CreatedAt = now
|
||||
file.UpdatedAt = now
|
||||
s.files = append(s.files, *file)
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func (s *testGroupBusinessStore) DeleteFile(_ types.TenantID, topic, groupFileID string, actor types.Uid, _ bool, now time.Time) (*types.GroupFile, error) {
|
||||
for i := range s.files {
|
||||
if s.files[i].Topic == topic && s.files[i].GroupFileID == groupFileID {
|
||||
s.files[i].Status = "deleted"
|
||||
s.files[i].DeletedBy = actor
|
||||
s.files[i].DeletedAt = &now
|
||||
return &s.files[i], nil
|
||||
}
|
||||
}
|
||||
return &types.GroupFile{Topic: topic, GroupFileID: groupFileID, Status: "deleted", DeletedBy: actor, DeletedAt: &now, CreatedAt: now, UpdatedAt: now}, nil
|
||||
}
|
||||
|
||||
func (s *testGroupBusinessStore) InviteMember(_ types.TenantID, topic string, inviter, target types.Uid,
|
||||
message, idempotencyKey string, _ any, now time.Time) (bool, error) {
|
||||
for _, invitation := range s.invitations {
|
||||
@@ -410,6 +459,12 @@ func (s *testOrganizationStore) ListMembers(_ types.TenantID, _ types.Uid, depar
|
||||
return s.members, "", nil
|
||||
}
|
||||
|
||||
func (s *testOrganizationStore) ListAllMembers(_ types.TenantID, _ types.Uid, departmentID, queryText, _ string, _ int) ([]types.OrganizationMember, string, error) {
|
||||
s.departmentID = departmentID
|
||||
s.query = queryText
|
||||
return s.members, "", nil
|
||||
}
|
||||
|
||||
func (s *testOrganizationStore) Search(_ types.TenantID, _ types.Uid, queryText, resultTypes, _ string, _ int) ([]types.OrganizationSearchItem, string, error) {
|
||||
s.query = queryText
|
||||
s.resultTypes = resultTypes
|
||||
@@ -560,6 +615,13 @@ func (s *testMonthlyReportsStore) Submit(_ types.TenantID, _ types.Uid, _ string
|
||||
return s.report, nil
|
||||
}
|
||||
|
||||
func (s *testMonthlyReportsStore) Reopen(_ types.TenantID, _ types.Uid, _ string, version int) (*types.MonthlyReport, error) {
|
||||
s.report.Status = types.DailyReportStatusDraft
|
||||
s.report.SubmittedAt = nil
|
||||
s.report.Version = version + 1
|
||||
return s.report, nil
|
||||
}
|
||||
|
||||
func (s *testMonthlyReportsStore) Stats(_ types.TenantID, _ types.Uid, _ string, _ string) (*types.MonthlyReportStats, error) {
|
||||
return &types.MonthlyReportStats{ExpectedCount: 4, SubmittedCount: 2, MissingCount: 2}, nil
|
||||
}
|
||||
@@ -755,6 +817,54 @@ func (s *testCallsStore) List(tenantID types.TenantID, uid types.Uid, topic, cur
|
||||
return s.items, s.next, nil
|
||||
}
|
||||
|
||||
func (s *testConversationsStore) EnsureP2P(_ types.TenantID, uid, peer types.Uid) (string, error) {
|
||||
s.topic = uid.P2PName(peer)
|
||||
return s.topic, nil
|
||||
}
|
||||
|
||||
func (s *testConversationsStore) GetSettings(_ types.TenantID, _ types.Uid, topic string) (*types.ConversationSettings, error) {
|
||||
if s.settings == nil {
|
||||
now := time.Now().UTC().Round(time.Millisecond)
|
||||
s.settings = &types.ConversationSettings{Topic: topic, Pinned: false, Muted: false, MessageRetention: "default", Version: 1, CreatedAt: now, UpdatedAt: now}
|
||||
}
|
||||
return s.settings, nil
|
||||
}
|
||||
|
||||
func (s *testConversationsStore) UpdateSettings(_ types.TenantID, _ types.Uid, topic string, patch types.ConversationSettingsPatch) (*types.ConversationSettings, error) {
|
||||
s.settingsPatch = patch
|
||||
settings, _ := s.GetSettings(0, 0, topic)
|
||||
if patch.Pinned != nil {
|
||||
settings.Pinned = *patch.Pinned
|
||||
}
|
||||
if patch.Muted != nil {
|
||||
settings.Muted = *patch.Muted
|
||||
}
|
||||
if patch.Remark != nil {
|
||||
settings.Remark = *patch.Remark
|
||||
}
|
||||
if patch.MessageRetention != nil {
|
||||
settings.MessageRetention = *patch.MessageRetention
|
||||
}
|
||||
settings.Version = patch.Version + 1
|
||||
settings.UpdatedAt = time.Now().UTC().Round(time.Millisecond)
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
func (s *testConversationsStore) GetDraft(_ types.TenantID, _ types.Uid, topic string) (*types.TopicDraft, error) {
|
||||
if s.draft == nil {
|
||||
return nil, types.ErrNotFound
|
||||
}
|
||||
s.draft.Topic = topic
|
||||
return s.draft, nil
|
||||
}
|
||||
|
||||
func (s *testConversationsStore) PutDraft(_ types.TenantID, uid types.Uid, topic, content string, entities []byte, version int) (*types.TopicDraft, error) {
|
||||
s.putDraftCalled = true
|
||||
now := time.Now().UTC().Round(time.Millisecond)
|
||||
s.draft = &types.TopicDraft{UserID: uid, Topic: topic, Content: content, EntitiesJSON: entities, Version: version + 1, CreatedAt: now, UpdatedAt: now}
|
||||
return s.draft, nil
|
||||
}
|
||||
|
||||
func (s *testFavoritesStore) Create(_ types.TenantID, item *types.FavoriteItem) (*types.FavoriteItem, error) {
|
||||
for i := range s.items {
|
||||
existing := &s.items[i]
|
||||
@@ -1614,6 +1724,34 @@ func TestServeIMRealNameSubmissionCreatesPending(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMRealNameAppealCreatesPending(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
expectIMBearer(t, ctrl, "token-1", 7, 42)
|
||||
oldSecurity := store.Security
|
||||
security := &testSecurityStore{}
|
||||
store.Security = security
|
||||
defer func() { store.Security = oldSecurity }()
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/im/security/realname/appeals",
|
||||
bytes.NewBufferString(`{"reason":"证件信息需要更正","attachments":["file1"]}`))
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
serveIMRealNameAppeals(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
if security.realNameAppeal == nil || security.realNameAppeal.Reason != "证件信息需要更正" {
|
||||
t.Fatalf("appeal was not stored: %#v", security.realNameAppeal)
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
if data["status"] != "pending" || data["appeal_id"] == "" {
|
||||
t.Fatalf("unexpected appeal response: %#v", data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMIndependentPasswordSetAndVerify(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
@@ -1889,6 +2027,32 @@ func TestServeIMOrganizationDepartmentMembers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMOrganizationMembers(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
expectIMBearer(t, ctrl, "token-1", 7, 42)
|
||||
oldOrganization := store.Organization
|
||||
org := &testOrganizationStore{members: []types.OrganizationMember{
|
||||
{DepartmentID: "dep-sales", UserID: types.ParseUserId("usrAAAAAAAAAAA"), DisplayName: "张三", Position: "销售经理", Status: "active", Contactable: true, Version: 1},
|
||||
}}
|
||||
store.Organization = org
|
||||
defer func() { store.Organization = oldOrganization }()
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/im/organization/members?department_id=dep-sales&q=%E5%BC%A0", nil)
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec := httptest.NewRecorder()
|
||||
serveIMOrganizationMembers(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
items := data["items"].([]any)
|
||||
if len(items) != 1 || org.departmentID != "dep-sales" || org.query != "张" || data["has_more"] != false {
|
||||
t.Fatalf("unexpected organization members response: %#v department=%q query=%q", data, org.departmentID, org.query)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMOrganizationSearch(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
@@ -2144,6 +2308,41 @@ func TestServeIMMonthlyReportDraftAndSubmit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMMonthlyReportReopen(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
expectIMBearer(t, ctrl, "token-1", 7, 42)
|
||||
oldMonthlyReports := store.MonthlyReports
|
||||
now := time.Now().UTC().Round(time.Millisecond)
|
||||
submittedAt := now.Add(-time.Hour)
|
||||
reports := &testMonthlyReportsStore{report: &types.MonthlyReport{
|
||||
ReportID: "mr_test",
|
||||
AuthorID: 42,
|
||||
Month: "2026-08",
|
||||
Status: types.DailyReportStatusSubmitted,
|
||||
ReadState: "unread",
|
||||
Version: 3,
|
||||
SubmittedAt: &submittedAt,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}}
|
||||
store.MonthlyReports = reports
|
||||
defer func() { store.MonthlyReports = oldMonthlyReports }()
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/im/reports/monthly/mr_test/reopen", strings.NewReader(`{"version":3}`))
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec := httptest.NewRecorder()
|
||||
serveIMMonthlyReportResource(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
if data["status"] != types.DailyReportStatusDraft || data["action"] != "edit" || reports.report.SubmittedAt != nil {
|
||||
t.Fatalf("unexpected reopen response: %#v report=%#v", data, reports.report)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMMonthlyReportStatistics(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
@@ -3001,6 +3200,93 @@ func TestServeIMGroupInvitationAddsNonMember(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMGroupInvitationAccept(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
expectIMBearer(t, ctrl, "token-1", 7, 43)
|
||||
oldGroupBusiness := store.GroupBusiness
|
||||
groupStore := &testGroupBusinessStore{invitations: []types.GroupInvitation{{
|
||||
InvitationID: "ginv_test",
|
||||
Topic: "grpAlpha",
|
||||
InviterUserID: 42,
|
||||
TargetUserID: 43,
|
||||
Status: "pending",
|
||||
ExpiresAt: time.Now().UTC().Add(time.Hour),
|
||||
}}}
|
||||
store.GroupBusiness = groupStore
|
||||
defer func() { store.GroupBusiness = oldGroupBusiness }()
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/im/group-invitations/ginv_test/accept", nil)
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec := httptest.NewRecorder()
|
||||
serveIMGroupInvitationResource(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
if data["invitation_id"] != "ginv_test" || data["status"] != types.GroupInvitationStatusJoined || data["result"] != "joined" {
|
||||
t.Fatalf("unexpected invitation accept response: %#v", data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMGroupFiles(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
expectIMBearer(t, ctrl, "token-1", 7, 42)
|
||||
oldSubs := store.Subs
|
||||
oldGroupBusiness := store.GroupBusiness
|
||||
subs := mock_store.NewMockSubsPersistenceInterface(ctrl)
|
||||
groupStore := &testGroupBusinessStore{}
|
||||
store.Subs = subs
|
||||
store.GroupBusiness = groupStore
|
||||
defer func() {
|
||||
store.Subs = oldSubs
|
||||
store.GroupBusiness = oldGroupBusiness
|
||||
}()
|
||||
subs.EXPECT().Get(types.TenantID(7), "grpAlpha", types.Uid(42), false).Return(&types.Subscription{
|
||||
TenantID: 7, User: types.Uid(42).String(), Topic: "grpAlpha", ModeWant: types.ModeCFull, ModeGiven: types.ModeCFull,
|
||||
}, nil).Times(3)
|
||||
|
||||
createReq := httptest.NewRequest(http.MethodPost, "/v1/im/groups/grpAlpha/files",
|
||||
strings.NewReader(`{"file_id":"file1","file_name":"方案.pdf","file_type":"document","file_size":123}`))
|
||||
createReq.Header.Set("Authorization", "Bearer token-1")
|
||||
createReq.Header.Set("Idempotency-Key", "gfile-1")
|
||||
createRec := httptest.NewRecorder()
|
||||
serveIMGroupResource(createRec, createReq)
|
||||
if createRec.Code != http.StatusOK {
|
||||
t.Fatalf("create status: got %d body=%s", createRec.Code, createRec.Body.String())
|
||||
}
|
||||
created := decodeIMHTTPResponse(t, createRec).Data.(map[string]any)
|
||||
if created["file_id"] != "file1" || created["file_type"] != "document" {
|
||||
t.Fatalf("unexpected create response: %#v", created)
|
||||
}
|
||||
|
||||
listReq := httptest.NewRequest(http.MethodGet, "/v1/im/groups/grpAlpha/files", nil)
|
||||
listReq.Header.Set("Authorization", "Bearer token-1")
|
||||
listRec := httptest.NewRecorder()
|
||||
serveIMGroupResource(listRec, listReq)
|
||||
if listRec.Code != http.StatusOK {
|
||||
t.Fatalf("list status: got %d body=%s", listRec.Code, listRec.Body.String())
|
||||
}
|
||||
listed := decodeIMHTTPResponse(t, listRec).Data.(map[string]any)
|
||||
if len(listed["items"].([]any)) != 1 || listed["has_more"] != false {
|
||||
t.Fatalf("unexpected list response: %#v", listed)
|
||||
}
|
||||
|
||||
deleteReq := httptest.NewRequest(http.MethodDelete, "/v1/im/groups/grpAlpha/files/gfile_test", nil)
|
||||
deleteReq.Header.Set("Authorization", "Bearer token-1")
|
||||
deleteRec := httptest.NewRecorder()
|
||||
serveIMGroupResource(deleteRec, deleteReq)
|
||||
if deleteRec.Code != http.StatusOK {
|
||||
t.Fatalf("delete status: got %d body=%s", deleteRec.Code, deleteRec.Body.String())
|
||||
}
|
||||
deleted := decodeIMHTTPResponse(t, deleteRec).Data.(map[string]any)
|
||||
if deleted["status"] != "deleted" || deleted["deleted_by"] != types.Uid(42).UserId() {
|
||||
t.Fatalf("unexpected delete response: %#v", deleted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMGroupQRCodesAndResolve(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
@@ -3950,6 +4236,104 @@ func TestServeIMConversationContext(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMP2PConversation(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
expectIMBearer(t, ctrl, "token-1", 7, 1)
|
||||
oldConversations := store.Conversations
|
||||
oldRelations := store.Relations
|
||||
peer := types.Uid(2)
|
||||
conversations := &testConversationsStore{}
|
||||
store.Conversations = conversations
|
||||
store.Relations = &testRelationsStore{}
|
||||
defer func() {
|
||||
store.Conversations = oldConversations
|
||||
store.Relations = oldRelations
|
||||
}()
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/im/conversations/p2p", strings.NewReader(`{"peer_user_id":"`+peer.UserId()+`"}`))
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec := httptest.NewRecorder()
|
||||
serveIMP2PConversation(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
if data["topic"] != types.Uid(1).P2PName(peer) || data["can_send"] != true {
|
||||
t.Fatalf("unexpected p2p response: %#v topic=%q", data, conversations.topic)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMConversationSettings(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
expectIMBearer(t, ctrl, "token-1", 7, 1)
|
||||
oldConversations := store.Conversations
|
||||
topic := types.Uid(1).P2PName(types.Uid(2))
|
||||
conversations := &testConversationsStore{}
|
||||
store.Conversations = conversations
|
||||
defer func() { store.Conversations = oldConversations }()
|
||||
|
||||
req := httptest.NewRequest(http.MethodPatch, "/v1/im/conversations/"+topic+"/settings", strings.NewReader(`{"pinned":true,"mute_notifications":true,"remark":"同事","version":1}`))
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec := httptest.NewRecorder()
|
||||
serveIMConversationContext(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
if data["pinned"] != true || data["mute_notifications"] != true || data["remark"] != "同事" || data["version"].(float64) != 2 {
|
||||
t.Fatalf("unexpected settings response: %#v", data)
|
||||
}
|
||||
if conversations.settingsPatch.Muted == nil || *conversations.settingsPatch.Muted != true {
|
||||
t.Fatalf("mute_notifications was not mapped to Muted patch: %#v", conversations.settingsPatch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMTopicDraftPutAndGet(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
expectIMBearer(t, ctrl, "token-1", 7, 1)
|
||||
oldMaxMessageSize := globals.maxMessageSize
|
||||
globals.maxMessageSize = 1024
|
||||
defer func() { globals.maxMessageSize = oldMaxMessageSize }()
|
||||
oldConversations := store.Conversations
|
||||
topic := "grpDraft"
|
||||
conversations := &testConversationsStore{}
|
||||
store.Conversations = conversations
|
||||
defer func() { store.Conversations = oldConversations }()
|
||||
|
||||
req := httptest.NewRequest(http.MethodPut, "/v1/im/topics/"+topic+"/draft", strings.NewReader(`{"content":"未发送草稿","entities":[{"type":"mention"}],"version":0}`))
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec := httptest.NewRecorder()
|
||||
serveIMTopicMessageAction(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("put status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
if !conversations.putDraftCalled {
|
||||
t.Fatal("expected draft store to be called")
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
if data["content"] != "未发送草稿" || data["version"].(float64) != 1 {
|
||||
t.Fatalf("unexpected draft put response: %#v", data)
|
||||
}
|
||||
|
||||
req = httptest.NewRequest(http.MethodGet, "/v1/im/topics/"+topic+"/draft", nil)
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec = httptest.NewRecorder()
|
||||
serveIMTopicMessageAction(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("get status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
data = decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
if data["content"] != "未发送草稿" {
|
||||
t.Fatalf("unexpected draft get response: %#v", data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMFriendRequestCreate(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
Reference in New Issue
Block a user