mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-11 07:46:37 +08:00
111 lines
3.6 KiB
Go
111 lines
3.6 KiB
Go
package reader
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// 书源按用户独立:同一 URL 的两个用户各自持有副本,启停/删除/搜索互不影响。
|
|
|
|
func TestSourcesArePerUser(t *testing.T) {
|
|
srv := newCacheTestServer()
|
|
defer srv.Close()
|
|
svc, _ := newLoginTestService(t)
|
|
ctx := t.Context()
|
|
|
|
raw := cacheTestSourceJSON(srv.URL)
|
|
if _, err := svc.ImportSources(ctx, "u1", raw); err != nil {
|
|
t.Fatalf("u1 导入失败: %v", err)
|
|
}
|
|
// 第二个用户导入同一书源 URL:旧实现会撞 source_url 唯一索引(导入失败)。
|
|
if _, err := svc.ImportSources(ctx, "u2", raw); err != nil {
|
|
t.Fatalf("u2 导入同一书源失败(书源未按用户隔离): %v", err)
|
|
}
|
|
|
|
u1Sources, err := svc.ListSources(ctx, "u1")
|
|
if err != nil || len(u1Sources) != 1 {
|
|
t.Fatalf("u1 应有 1 个书源: n=%d err=%v", len(u1Sources), err)
|
|
}
|
|
u2Sources, err := svc.ListSources(ctx, "u2")
|
|
if err != nil || len(u2Sources) != 1 {
|
|
t.Fatalf("u2 应有 1 个书源: n=%d err=%v", len(u2Sources), err)
|
|
}
|
|
if u1Sources[0].ID == u2Sources[0].ID {
|
|
t.Fatal("两个用户应各持一份副本(行 ID 不同)")
|
|
}
|
|
if u1Sources[0].UserID != "u1" || u2Sources[0].UserID != "u2" {
|
|
t.Fatalf("书源归属错误: u1=%q u2=%q", u1Sources[0].UserID, u2Sources[0].UserID)
|
|
}
|
|
|
|
// 启停互不影响。
|
|
if err := svc.UpdateSourceEnabled(ctx, "u1", u1Sources[0].ID, false); err != nil {
|
|
t.Fatalf("u1 停用失败: %v", err)
|
|
}
|
|
u2After, _ := svc.ListSources(ctx, "u2")
|
|
if len(u2After) != 1 || !u2After[0].Enabled {
|
|
t.Fatal("u1 停用影响到了 u2 的书源")
|
|
}
|
|
|
|
// 删除只删自己那份。
|
|
if err := svc.DeleteSource(ctx, "u1", u1Sources[0].ID); err != nil {
|
|
t.Fatalf("u1 删除失败: %v", err)
|
|
}
|
|
if left, _ := svc.ListSources(ctx, "u1"); len(left) != 0 {
|
|
t.Fatalf("u1 应已无书源: n=%d", len(left))
|
|
}
|
|
if left, _ := svc.ListSources(ctx, "u2"); len(left) != 1 {
|
|
t.Fatalf("u2 的书源被误删: n=%d", len(left))
|
|
}
|
|
|
|
// 越权删除他人书源必须失败。
|
|
if err := svc.DeleteSource(ctx, "u1", u2Sources[0].ID); err == nil {
|
|
t.Fatal("u1 不应能删除 u2 的书源")
|
|
}
|
|
}
|
|
|
|
// 搜索只使用当前用户的书源范围。
|
|
func TestSearchUsesOwnSourcesOnly(t *testing.T) {
|
|
srv := e2eServer()
|
|
defer srv.Close()
|
|
svc, _ := newLoginTestService(t)
|
|
ctx := t.Context()
|
|
|
|
if _, err := svc.ImportSources(ctx, "u1", e2eSourceJSON(srv.URL)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// u2 没有任何书源:搜索应直接报「没有已启用的书源」,而不是用 u1 的源。
|
|
if _, _, err := svc.Search(ctx, "u2", "书", nil, 1); err == nil || !strings.Contains(err.Error(), "没有已启用的书源") {
|
|
t.Fatalf("u2 无书源时应拒绝搜索,实际 err=%v", err)
|
|
}
|
|
// u1 自己的搜索正常。
|
|
books, _, err := svc.Search(ctx, "u1", "书", nil, 1)
|
|
if err != nil {
|
|
t.Fatalf("u1 搜索失败: %v", err)
|
|
}
|
|
if len(books) == 0 {
|
|
t.Fatal("u1 应搜到结果")
|
|
}
|
|
}
|
|
|
|
// 同一书源 URL 的两个用户副本:删除再导入仍然可用(物理删除释放唯一键)。
|
|
func TestDeleteAndReimportSameSource(t *testing.T) {
|
|
srv := newCacheTestServer()
|
|
defer srv.Close()
|
|
svc, _ := newLoginTestService(t)
|
|
ctx := t.Context()
|
|
|
|
if _, err := svc.ImportSources(ctx, "u1", cacheTestSourceJSON(srv.URL)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sources, _ := svc.ListSources(ctx, "u1")
|
|
if err := svc.DeleteSource(ctx, "u1", sources[0].ID); err != nil {
|
|
t.Fatalf("删除失败: %v", err)
|
|
}
|
|
if _, err := svc.ImportSources(ctx, "u1", cacheTestSourceJSON(srv.URL)); err != nil {
|
|
t.Fatalf("删除后重新导入失败: %v", err)
|
|
}
|
|
if again, _ := svc.ListSources(ctx, "u1"); len(again) != 1 {
|
|
t.Fatalf("重新导入后应有 1 个书源: n=%d", len(again))
|
|
}
|
|
}
|