Files
im_server/server/moderation/moderation_test.go
T

76 lines
3.8 KiB
Go

package moderation
import (
"context"
"sort"
"strings"
"testing"
"time"
"github.com/tinode/chat/server/store"
"github.com/tinode/chat/server/store/types"
)
type testConfig struct {
policy *types.ModerationPolicy
words *types.SensitiveWordSet
}
func (c testConfig) Provider() (*types.ModerationProviderConfig, error) {
return &types.ModerationProviderConfig{}, nil
}
func (c testConfig) Policy(string) (*types.ModerationPolicy, error) { return c.policy, nil }
func (c testConfig) Words(string) (*types.SensitiveWordSet, error) { return c.words, nil }
func (c testConfig) SecurityPolicy(string) (*types.SecurityPolicy, error) { return nil, nil }
type testAudit struct{}
func (testAudit) RecordLogin(types.TenantID, *types.LoginAuditEvent) error { return nil }
func (testAudit) RecordLoginFailure(types.TenantID, *types.LoginFailureEvent) error { return nil }
func (testAudit) CloseLogin(types.TenantID, string, time.Time) error { return nil }
func (testAudit) ApplyMessageAction(types.TenantID, *types.MessageAdminAction) error { return nil }
func (testAudit) RecordContentModeration(types.TenantID, *types.ContentModerationLog) error {
return nil
}
func TestExtractText(t *testing.T) {
content := map[string]any{"txt": "正文", "ent": []any{map[string]any{"data": map[string]any{"title": "查看详情", "url": "https://example.com"}}}, "meta": "ignore"}
gotParts := strings.Split(ExtractText(content), "\n")
sort.Strings(gotParts)
wantParts := []string{"https://example.com", "查看详情", "正文"}
sort.Strings(wantParts)
if strings.Join(gotParts, "\n") != strings.Join(wantParts, "\n") {
got := ExtractText(content)
t.Fatalf("ExtractText()=%q", got)
}
}
func TestReviewLocalBlock(t *testing.T) {
oldConfig, oldAudit := store.ModerationConfig, store.SecurityAudit
defer func() { store.ModerationConfig, store.SecurityAudit = oldConfig, oldAudit }()
store.ModerationConfig = testConfig{policy: &types.ModerationPolicy{Enabled: true, LocalWordsEnabled: true, Scenes: map[string]bool{ScenePrivateMessage: true}, RiskActions: map[string]string{"high": ActionBlock}}, words: &types.SensitiveWordSet{Items: []*types.SensitiveWordRule{{Word: "违规词", MatchType: "contains", Scenes: []string{ScenePrivateMessage}, Action: ActionBlock, RiskLevel: "high"}}}}
store.SecurityAudit = testAudit{}
result, err := Review(context.Background(), Request{TenantID: 1, TenantCode: "default", Scene: ScenePrivateMessage, Text: "包含违规词的消息"})
if err != ErrRejected || result.Action != ActionBlock || result.Provider != "local" {
t.Fatalf("result=%+v err=%v", result, err)
}
}
func TestReviewOtherTenantUsesOwnPolicy(t *testing.T) {
oldConfig, oldAudit := store.ModerationConfig, store.SecurityAudit
defer func() { store.ModerationConfig, store.SecurityAudit = oldConfig, oldAudit }()
store.ModerationConfig = testConfig{policy: &types.ModerationPolicy{Enabled: true, LocalWordsEnabled: true, Scenes: map[string]bool{ScenePrivateMessage: true}, RiskActions: map[string]string{"high": ActionBlock}}, words: &types.SensitiveWordSet{Items: []*types.SensitiveWordRule{{Word: "违规词", MatchType: "contains", Scenes: []string{ScenePrivateMessage}, Action: ActionBlock, RiskLevel: "high"}}}}
store.SecurityAudit = testAudit{}
result, err := Review(context.Background(), Request{TenantID: 2, TenantCode: "team", Scene: ScenePrivateMessage, Text: "违规词"})
if err != ErrRejected || result.Action != ActionBlock {
t.Fatalf("result=%+v err=%v", result, err)
}
}
func TestMatchLocalWordsPinyin(t *testing.T) {
result := matchLocalWords("这里包含敏感内容", SceneGroupMessage, &types.SensitiveWordSet{Items: []*types.SensitiveWordRule{{Word: "mingan", MatchType: "pinyin", Scenes: []string{SceneGroupMessage}, RiskLevel: "medium"}}})
if result == nil || result.RiskLevel != "medium" {
t.Fatalf("result=%+v", result)
}
}