mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-09-05 07:02:06 +08:00
* feat: afterMsgSaveDB webhook fix(config): add default webhook event filters fix(core): handle group mentions and webhook enqueue errors Use group IDs when filtering group-message attention callbacks, and report failures when asynchronous webhook tasks cannot be queued or posted. feat(webhook): add standalone mock webhook server CLI test(webhook): add mock server and test suite for all callback commands feat(msgtransfer): trigger afterMsgSaveDB webhook when message saved to DB feat(config): add afterMsgSaveDB webhook configuration feat(callbackstruct): add CallbackAfterMsgSaveDB command and request structs * refactor(core): simplify asynchronous webhook enqueueing
210 lines
6.9 KiB
Go
210 lines
6.9 KiB
Go
// Copyright © 2023 OpenIM. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package webhook
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
|
|
sdkws "github.com/openimsdk/protocol/sdkws"
|
|
"github.com/openimsdk/protocol/wrapperspb"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func runWebhookTest(t *testing.T, srv *Server, command string, reqObj any) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
body, err := json.Marshal(reqObj)
|
|
require.NoError(t, err)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/callbackExample/"+command, bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
|
|
srv.ServeHTTP(w, req)
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
return w
|
|
}
|
|
|
|
func TestAllWebhookCallbacks_UserAndStatus(t *testing.T) {
|
|
t.Parallel()
|
|
srv := NewServer()
|
|
|
|
t.Run("UserRegister", func(t *testing.T) {
|
|
w := runWebhookTest(t, srv, cbapi.CallbackBeforeUserRegisterCommand, &cbapi.CallbackBeforeUserRegisterReq{
|
|
CallbackCommand: cbapi.CallbackCommand(cbapi.CallbackBeforeUserRegisterCommand),
|
|
Users: []*sdkws.UserInfo{{UserID: "u1", Nickname: "User1"}},
|
|
})
|
|
var resp cbapi.CallbackBeforeUserRegisterResp
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
require.Len(t, resp.Users, 1)
|
|
require.Equal(t, "User1", resp.Users[0].Nickname)
|
|
|
|
runWebhookTest(t, srv, cbapi.CallbackAfterUserRegisterCommand, &cbapi.CallbackAfterUserRegisterReq{
|
|
CallbackCommand: cbapi.CallbackCommand(cbapi.CallbackAfterUserRegisterCommand),
|
|
Users: []*sdkws.UserInfo{{UserID: "u1"}},
|
|
})
|
|
})
|
|
|
|
t.Run("UpdateUserInfo", func(t *testing.T) {
|
|
newNick := "NewNick"
|
|
w := runWebhookTest(t, srv, cbapi.CallbackBeforeUpdateUserInfoCommand, &cbapi.CallbackBeforeUpdateUserInfoReq{
|
|
CallbackCommand: cbapi.CallbackCommand(cbapi.CallbackBeforeUpdateUserInfoCommand),
|
|
UserID: "u1",
|
|
Nickname: &newNick,
|
|
})
|
|
var resp cbapi.CallbackBeforeUpdateUserInfoResp
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
require.NotNil(t, resp.Nickname)
|
|
require.Equal(t, "NewNick", *resp.Nickname)
|
|
|
|
runWebhookTest(t, srv, cbapi.CallbackAfterUpdateUserInfoCommand, &cbapi.CallbackAfterUpdateUserInfoReq{
|
|
CallbackCommand: cbapi.CallbackCommand(cbapi.CallbackAfterUpdateUserInfoCommand),
|
|
UserID: "u1",
|
|
Nickname: "NewNick",
|
|
})
|
|
})
|
|
|
|
t.Run("UpdateUserInfoEx", func(t *testing.T) {
|
|
w := runWebhookTest(t, srv, cbapi.CallbackBeforeUpdateUserInfoExCommand, &cbapi.CallbackBeforeUpdateUserInfoExReq{
|
|
CallbackCommand: cbapi.CallbackCommand(cbapi.CallbackBeforeUpdateUserInfoExCommand),
|
|
UserID: "u1",
|
|
Ex: wrapperspb.String("new-ex"),
|
|
})
|
|
var resp cbapi.CallbackBeforeUpdateUserInfoExResp
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
require.NotNil(t, resp.Ex)
|
|
require.Equal(t, "new-ex", resp.Ex.Value)
|
|
|
|
runWebhookTest(t, srv, cbapi.CallbackAfterUpdateUserInfoExCommand, &cbapi.CallbackAfterUpdateUserInfoExReq{
|
|
CallbackCommand: cbapi.CallbackCommand(cbapi.CallbackAfterUpdateUserInfoExCommand),
|
|
UserID: "u1",
|
|
Ex: wrapperspb.String("new-ex"),
|
|
})
|
|
})
|
|
|
|
t.Run("UserStatusGateway", func(t *testing.T) {
|
|
for _, cmd := range []string{
|
|
cbapi.CallbackAfterUserOnlineCommand,
|
|
cbapi.CallbackAfterUserOfflineCommand,
|
|
cbapi.CallbackAfterUserKickOffCommand,
|
|
} {
|
|
runWebhookTest(t, srv, cmd, &cbapi.CallbackUserOnlineReq{
|
|
UserStatusCallbackReq: cbapi.UserStatusCallbackReq{
|
|
UserStatusBaseCallback: cbapi.UserStatusBaseCallback{
|
|
CallbackCommand: cmd,
|
|
Platform: "iOS",
|
|
},
|
|
UserID: "u1",
|
|
},
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAllWebhookCallbacks_FriendAndGroup(t *testing.T) {
|
|
t.Parallel()
|
|
srv := NewServer()
|
|
|
|
t.Run("FriendCallbacks", func(t *testing.T) {
|
|
friendCmds := []string{
|
|
cbapi.CallbackBeforeAddFriendCommand,
|
|
cbapi.CallbackAfterAddFriendCommand,
|
|
cbapi.CallbackBeforeAddFriendAgreeCommand,
|
|
cbapi.CallbackAfterAddFriendAgreeCommand,
|
|
cbapi.CallbackAfterDeleteFriendCommand,
|
|
cbapi.CallbackBeforeImportFriendsCommand,
|
|
cbapi.CallbackAfterImportFriendsCommand,
|
|
cbapi.CallbackBeforeSetFriendRemarkCommand,
|
|
cbapi.CallbackAfterSetFriendRemarkCommand,
|
|
cbapi.CallbackBeforeAddBlackCommand,
|
|
cbapi.CallbackAfterRemoveBlackCommand,
|
|
}
|
|
for _, cmd := range friendCmds {
|
|
runWebhookTest(t, srv, cmd, &cbapi.CallbackBeforeAddFriendReq{
|
|
CallbackCommand: cbapi.CallbackCommand(cmd),
|
|
FromUserID: "u1",
|
|
ToUserID: "u2",
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("GroupCallbacks", func(t *testing.T) {
|
|
groupCmds := []string{
|
|
cbapi.CallbackBeforeCreateGroupCommand,
|
|
cbapi.CallbackAfterCreateGroupCommand,
|
|
cbapi.CallbackBeforeMembersJoinGroupCommand,
|
|
cbapi.CallbackBeforeJoinGroupCommand,
|
|
cbapi.CallbackAfterJoinGroupCommand,
|
|
cbapi.CallbackAfterQuitGroupCommand,
|
|
cbapi.CallbackAfterKickGroupCommand,
|
|
cbapi.CallbackAfterDisMissGroupCommand,
|
|
cbapi.CallbackAfterTransferGroupOwnerCommand,
|
|
cbapi.CallbackBeforeInviteJoinGroupCommand,
|
|
cbapi.CallbackBeforeSetGroupInfoCommand,
|
|
cbapi.CallbackAfterSetGroupInfoCommand,
|
|
cbapi.CallbackBeforeSetGroupInfoExCommand,
|
|
cbapi.CallbackAfterSetGroupInfoExCommand,
|
|
cbapi.CallbackBeforeSetGroupMemberInfoCommand,
|
|
cbapi.CallbackAfterSetGroupMemberInfoCommand,
|
|
}
|
|
for _, cmd := range groupCmds {
|
|
runWebhookTest(t, srv, cmd, &cbapi.CallbackQuitGroupReq{
|
|
CallbackCommand: cbapi.CallbackCommand(cmd),
|
|
GroupID: "g1",
|
|
UserID: "u1",
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAllWebhookCallbacks_MsgAndPush(t *testing.T) {
|
|
t.Parallel()
|
|
srv := NewServer()
|
|
|
|
msgCmds := []string{
|
|
cbapi.CallbackBeforeSendSingleMsgCommand,
|
|
cbapi.CallbackAfterSendSingleMsgCommand,
|
|
cbapi.CallbackBeforeSendGroupMsgCommand,
|
|
cbapi.CallbackAfterSendGroupMsgCommand,
|
|
cbapi.CallbackBeforeMsgModifyCommand,
|
|
cbapi.CallbackAfterSingleMsgReadCommand,
|
|
cbapi.CallbackAfterGroupMsgReadCommand,
|
|
cbapi.CallbackAfterMsgSaveDBCommand,
|
|
cbapi.CallbackAfterRevokeMsgCommand,
|
|
cbapi.CallbackBeforeOfflinePushCommand,
|
|
cbapi.CallbackBeforeOnlinePushCommand,
|
|
cbapi.CallbackBeforeGroupOnlinePushCommand,
|
|
}
|
|
|
|
for _, cmd := range msgCmds {
|
|
cmd := cmd
|
|
t.Run(cmd, func(t *testing.T) {
|
|
t.Parallel()
|
|
runWebhookTest(t, srv, cmd, &cbapi.CallbackAfterMsgSaveDBReq{
|
|
CommonCallbackReq: cbapi.CommonCallbackReq{
|
|
SendID: "u1",
|
|
CallbackCommand: cmd,
|
|
},
|
|
RecvID: "u2",
|
|
GroupID: "g1",
|
|
})
|
|
})
|
|
}
|
|
}
|