init: AIGC-Hub/AVCC 方案文档 + TCS-IPTV 内容可信锁定系统 MVP
- 方案文档: AVCC 体系建设、IPTV TCS 需求(0-req)/PRD(1-prd)/任务(2-task)/二三四期任务 - tcs-iptv: Go 后端(哈希SDK/MA码生成/可信数据空间mock/业务编排/HTTP API+HMAC鉴权) - web-console: React+AntD 监管大屏(角色工作台/全流程演示/监管片库) - 一剧一码+集级哈希, 集级下架/恢复, 全栈测试通过
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
package macode
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// 集成测试:需本地 PostgreSQL。通过 TCS_TEST_PG_DSN 提供连接串;未提供则跳过。
|
||||
func openTestDB(t *testing.T) *sql.DB {
|
||||
t.Helper()
|
||||
dsn := os.Getenv("TCS_TEST_PG_DSN")
|
||||
if dsn == "" {
|
||||
dsn = "postgres://postgres@localhost:5432/tcs_iptv?sslmode=disable"
|
||||
}
|
||||
db, err := sql.Open("postgres", dsn)
|
||||
if err != nil {
|
||||
t.Skipf("跳过 PG 集成测试:%v", err)
|
||||
}
|
||||
if err := db.Ping(); err != nil {
|
||||
t.Skipf("跳过 PG 集成测试(无法连接):%v", err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func cleanupKey(t *testing.T, db *sql.DB, key string) {
|
||||
t.Helper()
|
||||
_, _ = db.Exec("DELETE FROM macode_cursor WHERE segment_key = $1", key)
|
||||
}
|
||||
|
||||
func TestPostgresStore_Sequential(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
defer db.Close()
|
||||
store := NewPostgresStore(db)
|
||||
key := "test:seq:WD"
|
||||
cleanupKey(t, db, key)
|
||||
defer cleanupKey(t, db, key)
|
||||
|
||||
for want := uint64(1); want <= 5; want++ {
|
||||
got, err := store.Next(key, 1, 100)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostgresStore_Exhausted(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
defer db.Close()
|
||||
store := NewPostgresStore(db)
|
||||
key := "test:exhaust:DY"
|
||||
cleanupKey(t, db, key)
|
||||
defer cleanupKey(t, db, key)
|
||||
|
||||
_, err := store.Next(key, 1, 2)
|
||||
require.NoError(t, err)
|
||||
_, err = store.Next(key, 1, 2)
|
||||
require.NoError(t, err)
|
||||
_, err = store.Next(key, 1, 2)
|
||||
assert.ErrorIs(t, err, ErrSegmentExhausted)
|
||||
}
|
||||
|
||||
func TestPostgresStore_ConcurrentNoDuplicate(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
defer db.Close()
|
||||
store := NewPostgresStore(db)
|
||||
key := "test:concurrent:WJ"
|
||||
cleanupKey(t, db, key)
|
||||
defer cleanupKey(t, db, key)
|
||||
|
||||
const n = 200
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
seen := make(map[uint64]bool)
|
||||
dup := 0
|
||||
errs := 0
|
||||
for i := 0; i < n; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
v, err := store.Next(key, 1, 1000)
|
||||
if err != nil {
|
||||
mu.Lock()
|
||||
errs++
|
||||
mu.Unlock()
|
||||
return
|
||||
}
|
||||
mu.Lock()
|
||||
if seen[v] {
|
||||
dup++
|
||||
}
|
||||
seen[v] = true
|
||||
mu.Unlock()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
assert.Equal(t, 0, errs, "并发分配不应报错")
|
||||
assert.Equal(t, 0, dup, "并发分配不得重号")
|
||||
assert.Len(t, seen, n)
|
||||
}
|
||||
|
||||
// TestPostgresStore_WithGenerator 验证 PG 存储与生成器联动产出唯一 MA 码。
|
||||
func TestPostgresStore_WithGenerator(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
defer db.Close()
|
||||
key := fmt.Sprintf("%s:%s:%s", "8531", "4401", CategoryAnimation)
|
||||
cleanupKey(t, db, key)
|
||||
defer cleanupKey(t, db, key)
|
||||
|
||||
g := NewGenerator(NewPostgresStore(db))
|
||||
require.NoError(t, g.RegisterSegment(Segment{
|
||||
IndustryNode: "8531", OrgNode: "4401",
|
||||
Category: CategoryAnimation, Start: 1, End: 1000, SeqWidth: 7,
|
||||
}))
|
||||
|
||||
seen := map[string]bool{}
|
||||
for i := 0; i < 10; i++ {
|
||||
issued, err := g.Allocate(CategoryAnimation)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, seen[issued.MACode])
|
||||
assert.True(t, IsValid(issued.MACode))
|
||||
seen[issued.MACode] = true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user