144 lines
5.7 KiB
Go
144 lines
5.7 KiB
Go
package support
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.118im.com/im_team/olons_server/internal/config"
|
|
"git.118im.com/im_team/olons_server/internal/imclient"
|
|
"git.118im.com/im_team/olons_server/internal/store"
|
|
)
|
|
|
|
type repositoryStub struct {
|
|
agent *store.CustomerService
|
|
identity *store.MemberIMIdentity
|
|
}
|
|
|
|
func (r *repositoryStub) CustomerServiceByID(context.Context, int64, int64) (*store.CustomerService, error) {
|
|
return r.agent, nil
|
|
}
|
|
func (r *repositoryStub) MemberIMIdentity(context.Context, int64, int64) (*store.MemberIMIdentity, error) {
|
|
return r.identity, nil
|
|
}
|
|
func (r *repositoryStub) MemberIMProfile(context.Context, int64, int64) (*store.MemberIMProfile, error) {
|
|
return nil, store.ErrResourceNotFound
|
|
}
|
|
func (r *repositoryStub) SaveMemberIMIdentity(context.Context, *store.MemberIMIdentity) (*store.MemberIMIdentity, error) {
|
|
return r.identity, nil
|
|
}
|
|
|
|
type imStub struct {
|
|
friendRequests int
|
|
loginAttempts int
|
|
resetPasswords int
|
|
loginError error
|
|
}
|
|
|
|
func (i *imStub) Ready() bool { return true }
|
|
func (i *imStub) Config() config.IMConfig {
|
|
return config.IMConfig{TenantCode: "allrich", HTTPAPIURL: "https://api.118im.com/v1/im",
|
|
WebSocketURL: "wss://api.118im.com/v0/channels", FileURL: "https://api.118im.com/v0/file", APIKey: "key"}
|
|
}
|
|
func (i *imStub) CreateUser(context.Context, string, string, string) (*imclient.CreatedUser, error) {
|
|
return nil, nil
|
|
}
|
|
func (i *imStub) FindUserByUsername(context.Context, string) (*imclient.CreatedUser, error) {
|
|
return nil, nil
|
|
}
|
|
func (i *imStub) LoginBasic(context.Context, string, string, string, string) (*imclient.Session, error) {
|
|
i.loginAttempts++
|
|
if i.loginError != nil {
|
|
err := i.loginError
|
|
i.loginError = nil
|
|
return nil, err
|
|
}
|
|
return &imclient.Session{UserID: "usr_member", Token: "token", ExpiresAt: time.Now().Add(time.Hour)}, nil
|
|
}
|
|
func (i *imStub) ResetPassword(context.Context, string, string) error {
|
|
i.resetPasswords++
|
|
return nil
|
|
}
|
|
func (i *imStub) UserProfile(context.Context, string, string) (*imclient.UserProfile, error) {
|
|
return &imclient.UserProfile{UserID: "usr_agent", Relationship: "none"}, nil
|
|
}
|
|
func (i *imStub) CreateFriendRequest(context.Context, string, string, string) (*imclient.FriendRequest, error) {
|
|
i.friendRequests++
|
|
return &imclient.FriendRequest{RequestID: "frq_1", Status: "accepted"}, nil
|
|
}
|
|
func (i *imStub) EnsureP2P(context.Context, string, string, string) (*imclient.Conversation, error) {
|
|
return &imclient.Conversation{Topic: "p2p-topic", Relationship: "friend", CanSend: true}, nil
|
|
}
|
|
|
|
func TestOpenSessionAutoAcceptsAndReturnsTopic(t *testing.T) {
|
|
repository := &repositoryStub{
|
|
agent: &store.CustomerService{ID: 3, Name: "客服01", IMTenantCode: "allrich", IMUserID: "usr_agent", OnlineStatus: 1},
|
|
identity: &store.MemberIMIdentity{TenantID: 0, MemberID: 9, IMTenantCode: "allrich", IMUserID: "usr_member", IMUsername: "member01"},
|
|
}
|
|
im := &imStub{}
|
|
service := New(repository, im, config.AuthConfig{FinanceMasterKey: strings.Repeat("k", 32)})
|
|
repository.identity.IMPasswordCipher, _ = service.encryptCredential("password")
|
|
session, err := service.OpenSession(context.Background(), 0, 9, 3, SessionRequest{DeviceID: "web-1", Platform: "web"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if session.Topic != "p2p-topic" || session.CurrentUserID != "usr_member" || session.Agent.IMUserID != "usr_agent" {
|
|
t.Fatalf("unexpected session: %+v", session)
|
|
}
|
|
if im.friendRequests != 1 {
|
|
t.Fatalf("friend requests = %d, want 1", im.friendRequests)
|
|
}
|
|
}
|
|
|
|
func TestOpenSessionReturnsSameOriginEndpoints(t *testing.T) {
|
|
repository := &repositoryStub{
|
|
agent: &store.CustomerService{ID: 3, Name: "客服01", IMTenantCode: "allrich", IMUserID: "usr_agent", OnlineStatus: 1},
|
|
identity: &store.MemberIMIdentity{TenantID: 0, MemberID: 9, IMTenantCode: "allrich", IMUserID: "usr_member", IMUsername: "member01"},
|
|
}
|
|
im := &imStub{}
|
|
service := New(repository, im, config.AuthConfig{FinanceMasterKey: strings.Repeat("k", 32)})
|
|
repository.identity.IMPasswordCipher, _ = service.encryptCredential("password")
|
|
|
|
session, err := service.OpenSession(context.Background(), 0, 9, 3, SessionRequest{DeviceID: "web-1", Platform: "web"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if session.APIBaseURL != "/v1/im" || session.WebSocketURL != "/v0/channels" || session.FileURL != "/v0/file" {
|
|
t.Fatalf("browser endpoints must be same-origin paths: %+v", session)
|
|
}
|
|
}
|
|
|
|
func TestOpenSessionRepairsDriftedIMCredential(t *testing.T) {
|
|
repository := &repositoryStub{
|
|
agent: &store.CustomerService{ID: 3, Name: "客服01", IMTenantCode: "allrich", IMUserID: "usr_agent", OnlineStatus: 1},
|
|
identity: &store.MemberIMIdentity{TenantID: 0, MemberID: 9, IMTenantCode: "allrich", IMUserID: "usr_member", IMUsername: "member01"},
|
|
}
|
|
im := &imStub{loginError: &imclient.Error{Status: 401, Reason: "authentication failed"}}
|
|
service := New(repository, im, config.AuthConfig{FinanceMasterKey: strings.Repeat("k", 32)})
|
|
repository.identity.IMPasswordCipher, _ = service.encryptCredential("stale-password")
|
|
|
|
session, err := service.OpenSession(context.Background(), 0, 9, 3, SessionRequest{DeviceID: "web-1", Platform: "web"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if session.Topic != "p2p-topic" {
|
|
t.Fatalf("unexpected session: %+v", session)
|
|
}
|
|
if im.loginAttempts != 2 || im.resetPasswords != 1 {
|
|
t.Fatalf("login attempts=%d reset passwords=%d, want 2 and 1", im.loginAttempts, im.resetPasswords)
|
|
}
|
|
}
|
|
|
|
func TestMemberIMUsernameMatchesIMConstraint(t *testing.T) {
|
|
username := memberIMUsername(0, 9223372036854775807, "allrich")
|
|
if len(username) != 10 {
|
|
t.Fatalf("username length = %d, want 10: %s", len(username), username)
|
|
}
|
|
for _, ch := range username {
|
|
if (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') {
|
|
t.Fatalf("invalid username %q", username)
|
|
}
|
|
}
|
|
}
|