From e1333cec627f690e0bd799ee44b28514aa6dec0b Mon Sep 17 00:00:00 2001 From: "Xinwei Xiong(cubxxw)" <3293172751nss@gmail.com> Date: Fri, 10 Nov 2023 18:35:01 +0800 Subject: [PATCH] feat: openim test Signed-off-by: Xinwei Xiong(cubxxw) <3293172751nss@gmail.com> --- test/e2e/api/token/token.go | 138 ++++++++++++++++++ test/e2e/api/user/curd.go | 44 ++++++ test/e2e/api/user/user.go | 101 +++++++++++++ test/e2e/framework/config/config.go | 21 +++ test/e2e/framework/config/config_test.go | 75 ++++++++++ .../framework/ginkgowrapper/ginkgowrapper.go | 1 + .../ginkgowrapper/ginkgowrapper_test.go | 1 + 7 files changed, 381 insertions(+) create mode 100644 test/e2e/api/token/token.go create mode 100644 test/e2e/api/user/curd.go create mode 100644 test/e2e/api/user/user.go create mode 100644 test/e2e/framework/config/config.go create mode 100644 test/e2e/framework/config/config_test.go create mode 100644 test/e2e/framework/ginkgowrapper/ginkgowrapper.go create mode 100644 test/e2e/framework/ginkgowrapper/ginkgowrapper_test.go diff --git a/test/e2e/api/token/token.go b/test/e2e/api/token/token.go new file mode 100644 index 000000000..679c0bbda --- /dev/null +++ b/test/e2e/api/token/token.go @@ -0,0 +1,138 @@ +package token + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "net/http" +) + +// API endpoints and other constants +const ( + APIHost = "http://127.0.0.1:10002" + UserTokenURL = APIHost + "/auth/user_token" + UserRegisterURL = APIHost + "/user/user_register" + SecretKey = "openIM123" + OperationID = "1646445464564" +) + +// UserTokenRequest represents a request to get a user token +type UserTokenRequest struct { + Secret string `json:"secret"` + PlatformID int `json:"platformID"` + UserID string `json:"userID"` +} + +// UserTokenResponse represents a response containing a user token +type UserTokenResponse struct { + Token string `json:"token"` + ErrCode int `json:"errCode"` +} + +// User represents user data for registration +type User struct { + UserID string `json:"userID"` + Nickname string `json:"nickname"` + FaceURL string `json:"faceURL"` +} + +// UserRegisterRequest represents a request to register a user +type UserRegisterRequest struct { + Secret string `json:"secret"` + Users []User `json:"users"` +} + +func main() { + // Example usage of functions + token, err := GetUserToken("openIM123456") + if err != nil { + log.Fatalf("Error getting user token: %v", err) + } + fmt.Println("Token:", token) + + err = RegisterUser(token, "testUserID", "TestNickname", "https://example.com/image.jpg") + if err != nil { + log.Fatalf("Error registering user: %v", err) + } +} + +// GetUserToken requests a user token from the API +func GetUserToken(userID string) (string, error) { + reqBody := UserTokenRequest{ + Secret: SecretKey, + PlatformID: 1, + UserID: userID, + } + reqBytes, err := json.Marshal(reqBody) + if err != nil { + return "", err + } + + resp, err := http.Post(UserTokenURL, "application/json", bytes.NewBuffer(reqBytes)) + if err != nil { + return "", err + } + defer resp.Body.Close() + + var tokenResp UserTokenResponse + if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { + return "", err + } + + if tokenResp.ErrCode != 0 { + return "", fmt.Errorf("error in token response: %v", tokenResp.ErrCode) + } + + return tokenResp.Token, nil +} + +// RegisterUser registers a new user using the API +func RegisterUser(token, userID, nickname, faceURL string) error { + user := User{ + UserID: userID, + Nickname: nickname, + FaceURL: faceURL, + } + reqBody := UserRegisterRequest{ + Secret: SecretKey, + Users: []User{user}, + } + reqBytes, err := json.Marshal(reqBody) + if err != nil { + return err + } + + client := &http.Client{} + req, err := http.NewRequest("POST", UserRegisterURL, bytes.NewBuffer(reqBytes)) + if err != nil { + return err + } + + req.Header.Add("Content-Type", "application/json") + req.Header.Add("operationID", OperationID) + req.Header.Add("token", token) + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + var respData map[string]interface{} + if err := json.Unmarshal(respBody, &respData); err != nil { + return err + } + + if errCode, ok := respData["errCode"].(float64); ok && errCode != 0 { + return fmt.Errorf("error in user registration response: %v", respData) + } + + return nil +} diff --git a/test/e2e/api/user/curd.go b/test/e2e/api/user/curd.go new file mode 100644 index 000000000..cdff1ea1e --- /dev/null +++ b/test/e2e/api/user/curd.go @@ -0,0 +1,44 @@ +package user + +import ( + gettoken "github.com/openimsdk/open-im-server/v3/test/e2e/api/token" +) + +// UserInfoRequest represents a request to get or update user information +type UserInfoRequest struct { + UserIDs []string `json:"userIDs,omitempty"` + UserInfo *gettoken.User `json:"userInfo,omitempty"` +} + +// GetUsersOnlineStatusRequest represents a request to get users' online status +type GetUsersOnlineStatusRequest struct { + UserIDs []string `json:"userIDs"` +} + +// GetUsersInfo retrieves detailed information for a list of user IDs +func GetUsersInfo(token string, userIDs []string) error { + requestBody := UserInfoRequest{ + UserIDs: userIDs, + } + return sendPostRequestWithToken("http://your-api-host:port/user/get_users_info", token, requestBody) +} + +// UpdateUserInfo updates the information for a user +func UpdateUserInfo(token, userID, nickname, faceURL string) error { + requestBody := UserInfoRequest{ + UserInfo: &gettoken.User{ + UserID: userID, + Nickname: nickname, + FaceURL: faceURL, + }, + } + return sendPostRequestWithToken("http://your-api-host:port/user/update_user_info", token, requestBody) +} + +// GetUsersOnlineStatus retrieves the online status for a list of user IDs +func GetUsersOnlineStatus(token string, userIDs []string) error { + requestBody := GetUsersOnlineStatusRequest{ + UserIDs: userIDs, + } + return sendPostRequestWithToken("http://your-api-host:port/user/get_users_online_status", token, requestBody) +} \ No newline at end of file diff --git a/test/e2e/api/user/user.go b/test/e2e/api/user/user.go new file mode 100644 index 000000000..63c6659a0 --- /dev/null +++ b/test/e2e/api/user/user.go @@ -0,0 +1,101 @@ +package user + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + gettoken "github.com/openimsdk/open-im-server/v3/test/e2e/api/token" +) + +// ForceLogoutRequest represents a request to force a user logout +type ForceLogoutRequest struct { + PlatformID int `json:"platformID"` + UserID string `json:"userID"` +} + +// CheckUserAccountRequest represents a request to check a user account +type CheckUserAccountRequest struct { + CheckUserIDs []string `json:"checkUserIDs"` +} + +// GetUsersRequest represents a request to get a list of users +type GetUsersRequest struct { + Pagination Pagination `json:"pagination"` +} + +// Pagination specifies the page number and number of items per page +type Pagination struct { + PageNumber int `json:"pageNumber"` + ShowNumber int `json:"showNumber"` +} + +// ForceLogout forces a user to log out +func ForceLogout(token, userID string, platformID int) error { + requestBody := ForceLogoutRequest{ + PlatformID: platformID, + UserID: userID, + } + return sendPostRequestWithToken("http://your-api-host:port/auth/force_logout", token, requestBody) +} + +// CheckUserAccount checks if the user accounts exist +func CheckUserAccount(token string, userIDs []string) error { + requestBody := CheckUserAccountRequest{ + CheckUserIDs: userIDs, + } + return sendPostRequestWithToken("http://your-api-host:port/user/account_check", token, requestBody) +} + +// GetUsers retrieves a list of users with pagination +func GetUsers(token string, pageNumber, showNumber int) error { + requestBody := GetUsersRequest{ + Pagination: Pagination{ + PageNumber: pageNumber, + ShowNumber: showNumber, + }, + } + return sendPostRequestWithToken("http://your-api-host:port/user/get_users", token, requestBody) +} + +// sendPostRequestWithToken sends a POST request with a token in the header +func sendPostRequestWithToken(url, token string, body interface{}) error { + reqBytes, err := json.Marshal(body) + if err != nil { + return err + } + + client := &http.Client{} + req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqBytes)) + if err != nil { + return err + } + + req.Header.Add("Content-Type", "application/json") + req.Header.Add("operationID", gettoken.OperationID) + req.Header.Add("token", token) + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + var respData map[string]interface{} + if err := json.Unmarshal(respBody, &respData); err != nil { + return err + } + + if errCode, ok := respData["errCode"].(float64); ok && errCode != 0 { + return fmt.Errorf("error in response: %v", respData) + } + + return nil +} diff --git a/test/e2e/framework/config/config.go b/test/e2e/framework/config/config.go new file mode 100644 index 000000000..dcf87cecf --- /dev/null +++ b/test/e2e/framework/config/config.go @@ -0,0 +1,21 @@ +package config + +import "flag" + +// Flags is the flag set that AddOptions adds to. Test authors should +// also use it instead of directly adding to the global command line. +var Flags = flag.NewFlagSet("", flag.ContinueOnError) + +// CopyFlags ensures that all flags that are defined in the source flag +// set appear in the target flag set as if they had been defined there +// directly. From the flag package it inherits the behavior that there +// is a panic if the target already contains a flag from the source. +func CopyFlags(source *flag.FlagSet, target *flag.FlagSet) { + source.VisitAll(func(flag *flag.Flag) { + // We don't need to copy flag.DefValue. The original + // default (from, say, flag.String) was stored in + // the value and gets extracted by Var for the help + // message. + target.Var(flag.Value, flag.Name, flag.Usage) + }) +} diff --git a/test/e2e/framework/config/config_test.go b/test/e2e/framework/config/config_test.go new file mode 100644 index 000000000..c411df31e --- /dev/null +++ b/test/e2e/framework/config/config_test.go @@ -0,0 +1,75 @@ +package config + +import ( + "flag" + "reflect" + "testing" +) + +func TestCopyFlags(t *testing.T) { + type args struct { + source *flag.FlagSet + target *flag.FlagSet + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Copy empty source to empty target", + args: args{ + source: flag.NewFlagSet("source", flag.ContinueOnError), + target: flag.NewFlagSet("target", flag.ContinueOnError), + }, + wantErr: false, + }, + { + name: "Copy non-empty source to empty target", + args: args{ + source: func() *flag.FlagSet { + fs := flag.NewFlagSet("source", flag.ContinueOnError) + fs.String("test-flag", "default", "test usage") + return fs + }(), + target: flag.NewFlagSet("target", flag.ContinueOnError), + }, + wantErr: false, + }, + { + name: "Copy source to target with existing flag", + args: args{ + source: func() *flag.FlagSet { + fs := flag.NewFlagSet("source", flag.ContinueOnError) + fs.String("test-flag", "default", "test usage") + return fs + }(), + target: func() *flag.FlagSet { + fs := flag.NewFlagSet("target", flag.ContinueOnError) + fs.String("test-flag", "default", "test usage") + return fs + }(), + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + defer func() { + if r := recover(); (r != nil) != tt.wantErr { + t.Errorf("CopyFlags() panic = %v, wantErr %v", r, tt.wantErr) + } + }() + CopyFlags(tt.args.source, tt.args.target) + + // 验证复制的标记 + if !tt.wantErr { + tt.args.source.VisitAll(func(f *flag.Flag) { + if gotFlag := tt.args.target.Lookup(f.Name); gotFlag == nil || !reflect.DeepEqual(gotFlag, f) { + t.Errorf("CopyFlags() failed to copy flag %s", f.Name) + } + }) + } + }) + } +} diff --git a/test/e2e/framework/ginkgowrapper/ginkgowrapper.go b/test/e2e/framework/ginkgowrapper/ginkgowrapper.go new file mode 100644 index 000000000..16779440b --- /dev/null +++ b/test/e2e/framework/ginkgowrapper/ginkgowrapper.go @@ -0,0 +1 @@ +package ginkgowrapper diff --git a/test/e2e/framework/ginkgowrapper/ginkgowrapper_test.go b/test/e2e/framework/ginkgowrapper/ginkgowrapper_test.go new file mode 100644 index 000000000..16779440b --- /dev/null +++ b/test/e2e/framework/ginkgowrapper/ginkgowrapper_test.go @@ -0,0 +1 @@ +package ginkgowrapper