a329d4906b
- 方案文档: AVCC 体系建设、IPTV TCS 需求(0-req)/PRD(1-prd)/任务(2-task)/二三四期任务 - tcs-iptv: Go 后端(哈希SDK/MA码生成/可信数据空间mock/业务编排/HTTP API+HMAC鉴权) - web-console: React+AntD 监管大屏(角色工作台/全流程演示/监管片库) - 一剧一码+集级哈希, 集级下架/恢复, 全栈测试通过
130 lines
3.0 KiB
Go
130 lines
3.0 KiB
Go
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
|
|
}
|
|
}
|