Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func seedUserForAliasTest(t *testing.T, repo *userRepository, email string) {
|
||||
t.Helper()
|
||||
require.NoError(t, repo.Create(context.Background(), &service.User{
|
||||
Email: email,
|
||||
Username: email,
|
||||
PasswordHash: "hash",
|
||||
Role: service.RoleUser,
|
||||
Status: service.StatusActive,
|
||||
}))
|
||||
}
|
||||
|
||||
func TestUserRepositoryExistsByEmailAlias(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
stored string
|
||||
probe string
|
||||
want bool
|
||||
}{
|
||||
{"same address", "someone@gmail.com", "someone@gmail.com", true},
|
||||
{"gmail plus alias", "someone@gmail.com", "someone+bulk294@gmail.com", true},
|
||||
{"gmail dot trick", "d.axis.2026@gmail.com", "daxis2026@gmail.com", true},
|
||||
{"gmail dot trick both sides", "d.axis.2026@gmail.com", "da.xis.2026@gmail.com", true},
|
||||
{"stored plus alias found by canonical form", "someone+tag@gmail.com", "someone@gmail.com", true},
|
||||
{"googlemail is a gmail alias", "someone@googlemail.com", "some.one@gmail.com", true},
|
||||
{"fqdn root dot on probe", "d.axis.2026@gmail.com", "da.xis.2026@gmail.com.", true},
|
||||
{"fqdn root dot on stored row", "d.axis.2026@gmail.com.", "daxis2026@gmail.com", true},
|
||||
{"legacy row with spacing and case", " D.Axis.2026@Gmail.com ", "daxis2026@gmail.com", true},
|
||||
{"non-gmail plus alias", "first.last@qq.com", "first.last+tag@qq.com", true},
|
||||
{"different gmail inbox", "someone@gmail.com", "someoneelse@gmail.com", false},
|
||||
{"non-gmail dots are significant", "first.last@qq.com", "firstlast@qq.com", false},
|
||||
{"different domain", "someone@gmail.com", "someone@qq.com", false},
|
||||
{"distinct plus-prefixed locals", "+alice@gmail.com", "+bob@gmail.com", false},
|
||||
{"underscore is not a wildcard", "user_x@qq.com", "userax@qq.com", false},
|
||||
{"percent is not a wildcard", "a%b@qq.com", "axxb@qq.com", false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
repo, _ := newUserEntRepo(t)
|
||||
seedUserForAliasTest(t, repo, tc.stored)
|
||||
|
||||
got, err := repo.ExistsByEmailAlias(context.Background(), tc.probe)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserRepositoryExistsByEmailAliasIgnoresMalformedInput(t *testing.T) {
|
||||
repo, _ := newUserEntRepo(t)
|
||||
seedUserForAliasTest(t, repo, "someone@gmail.com")
|
||||
|
||||
got, err := repo.ExistsByEmailAlias(context.Background(), "not-an-email")
|
||||
require.NoError(t, err)
|
||||
require.False(t, got)
|
||||
}
|
||||
|
||||
func TestUserRepositoryCreateWithEmailAliasGuard(t *testing.T) {
|
||||
repo, _ := newUserEntRepo(t)
|
||||
ctx := context.Background()
|
||||
seedUserForAliasTest(t, repo, "d.axis.2026@gmail.com")
|
||||
|
||||
// 注册路径:别名变体在唯一性锁内被拒绝。
|
||||
err := repo.CreateWithEmailAliasGuard(ctx, &service.User{
|
||||
Email: "da.xis.2026+free@googlemail.com",
|
||||
Username: "alias-variant",
|
||||
PasswordHash: "hash",
|
||||
Role: service.RoleUser,
|
||||
Status: service.StatusActive,
|
||||
})
|
||||
require.ErrorIs(t, err, service.ErrEmailExists)
|
||||
|
||||
// 不同收件箱仍可注册。
|
||||
require.NoError(t, repo.CreateWithEmailAliasGuard(ctx, &service.User{
|
||||
Email: "other.person@gmail.com",
|
||||
Username: "other-person",
|
||||
PasswordHash: "hash",
|
||||
Role: service.RoleUser,
|
||||
Status: service.StatusActive,
|
||||
}))
|
||||
|
||||
// 管理员建号(Create)不受别名限制。
|
||||
require.NoError(t, repo.Create(ctx, &service.User{
|
||||
Email: "daxis2026+support@gmail.com",
|
||||
Username: "admin-created",
|
||||
PasswordHash: "hash",
|
||||
Role: service.RoleUser,
|
||||
Status: service.StatusActive,
|
||||
}))
|
||||
}
|
||||
|
||||
func TestUserRepositoryCountUsersByEmailDomain(t *testing.T) {
|
||||
repo, _ := newUserEntRepo(t)
|
||||
ctx := context.Background()
|
||||
|
||||
active := &service.User{
|
||||
Email: "first@custom.example",
|
||||
Username: "first",
|
||||
PasswordHash: "hash",
|
||||
Role: service.RoleUser,
|
||||
Status: service.StatusActive,
|
||||
}
|
||||
seedUserForAliasTest(t, repo, active.Email)
|
||||
seedUserForAliasTest(t, repo, "other@sub.custom.example")
|
||||
deleted := &service.User{
|
||||
Email: "deleted@custom.example",
|
||||
Username: "deleted",
|
||||
PasswordHash: "hash",
|
||||
Role: service.RoleUser,
|
||||
Status: service.StatusActive,
|
||||
}
|
||||
require.NoError(t, repo.Create(ctx, deleted))
|
||||
require.NoError(t, repo.Delete(ctx, deleted.ID))
|
||||
|
||||
count, err := repo.CountUsersByEmailDomain(ctx, "custom.example")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, count)
|
||||
}
|
||||
|
||||
func TestUserRepositoryCreateWithEmailAliasGuardAndDomainLimit(t *testing.T) {
|
||||
repo, _ := newUserEntRepo(t)
|
||||
ctx := context.Background()
|
||||
seedUserForAliasTest(t, repo, "first@custom.example.")
|
||||
|
||||
err := repo.CreateWithEmailAliasGuardAndDomainLimit(ctx, &service.User{
|
||||
Email: "second@custom.example",
|
||||
Username: "second",
|
||||
PasswordHash: "hash",
|
||||
Role: service.RoleUser,
|
||||
Status: service.StatusActive,
|
||||
}, "custom.example")
|
||||
require.ErrorIs(t, err, service.ErrEmailDomainRegistrationLimit)
|
||||
}
|
||||
|
||||
func TestUserRepositoryCountUsersByEmailDomainEscapesLikeWildcards(t *testing.T) {
|
||||
repo, _ := newUserEntRepo(t)
|
||||
ctx := context.Background()
|
||||
seedUserForAliasTest(t, repo, "first@foo_bar.com")
|
||||
seedUserForAliasTest(t, repo, "other@fooxbar.com")
|
||||
|
||||
count, err := repo.CountUsersByEmailDomain(ctx, "foo_bar.com")
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, count)
|
||||
}
|
||||
Reference in New Issue
Block a user