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,127 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tcs-iptv/tcs/internal/chain"
|
||||
"github.com/tcs-iptv/tcs/internal/macode"
|
||||
"github.com/tcs-iptv/tcs/internal/model"
|
||||
)
|
||||
|
||||
// 24 集微短剧:一剧一 MA 码,每集独立哈希,可按集验真。
|
||||
func TestEpisodeLevel_OneSeriesOneCodeMultiEpisodeHash(t *testing.T) {
|
||||
s := newService(t)
|
||||
|
||||
eps := make([]model.EpisodeHash, 0, 24)
|
||||
for i := 1; i <= 24; i++ {
|
||||
eps = append(eps, model.EpisodeHash{
|
||||
Episode: i,
|
||||
FileSHA256: "ep-hash-" + string(rune('a'+i)),
|
||||
MerkleRoot: "ep-mr-" + string(rune('a'+i)),
|
||||
Duration: 180,
|
||||
})
|
||||
}
|
||||
sub := Submission{
|
||||
Title: "长安少年行", EpisodeCount: 24, Category: macode.CategoryMicroDrama,
|
||||
FileHash: "series-root-hash", MerkleRoot: "series-merkle-root",
|
||||
Episodes: eps,
|
||||
CPMediaID: "XAQJSL-2026-001", CPName: "西安曲江丝路文化传播有限公司",
|
||||
}
|
||||
r, err := s.SubmitForReview(sub)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.ReviewCSPS(r.ReviewID, true, "rv-1"))
|
||||
issued, err := s.ApproveAndIssue(chain.RoleRegulator, r.ReviewID, "陕西IPTV运营公司")
|
||||
require.NoError(t, err)
|
||||
|
||||
// 一剧一码
|
||||
assert.True(t, macode.IsValid(issued.MACode))
|
||||
|
||||
// 24 集哈希全部绑定在同一 MA 码下
|
||||
list, err := s.ListEpisodes(issued.MACode)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, list, 24)
|
||||
|
||||
// 按集验真:第 7 集正确哈希匹配
|
||||
res, err := s.VerifyEpisode(issued.MACode, 7, "ep-hash-"+string(rune('a'+7)))
|
||||
require.NoError(t, err)
|
||||
assert.True(t, res.Match)
|
||||
|
||||
// 第 7 集错误哈希 → 不匹配(疑似该集被替换)
|
||||
_, err = s.VerifyEpisode(issued.MACode, 7, "tampered-ep7")
|
||||
assert.ErrorIs(t, err, ErrHashMismatch)
|
||||
}
|
||||
|
||||
// 集级下架:只下架第3集,整剧其他集不受影响。
|
||||
func TestEpisodeTakedown(t *testing.T) {
|
||||
s := newService(t)
|
||||
|
||||
eps := []model.EpisodeHash{
|
||||
{Episode: 1, FileSHA256: "h1"}, {Episode: 2, FileSHA256: "h2"},
|
||||
{Episode: 3, FileSHA256: "h3"}, {Episode: 4, FileSHA256: "h4"},
|
||||
}
|
||||
sub := Submission{
|
||||
Title: "多集剧", EpisodeCount: 4, Category: macode.CategoryMicroDrama,
|
||||
FileHash: "series-h", MerkleRoot: "series-mr", Episodes: eps,
|
||||
}
|
||||
r, err := s.SubmitForReview(sub)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.ReviewCSPS(r.ReviewID, true, "rv-1"))
|
||||
issued, err := s.ApproveAndIssue(chain.RoleRegulator, r.ReviewID, "陕西IPTV运营公司")
|
||||
require.NoError(t, err)
|
||||
|
||||
// 运营商无权集级下架
|
||||
err = s.TakedownEpisode(chain.RoleOperator, issued.MACode, 3, "第3集违规")
|
||||
assert.ErrorIs(t, err, chain.ErrPermissionDenied)
|
||||
|
||||
// 监管下架第3集
|
||||
require.NoError(t, s.TakedownEpisode(chain.RoleRegulator, issued.MACode, 3, "第3集违规"))
|
||||
|
||||
list, err := s.ListEpisodes(issued.MACode)
|
||||
require.NoError(t, err)
|
||||
for _, b := range list {
|
||||
if b.Episode == 3 {
|
||||
assert.True(t, b.Revoked, "第3集应已下架")
|
||||
} else {
|
||||
assert.False(t, b.Revoked, "第%d集不应受影响", b.Episode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 集级子标识:MA码#E07 解析与生成。
|
||||
func TestEpisodeSubID(t *testing.T) {
|
||||
ma := "MA.156.8531.6101/WD/20260000001"
|
||||
sub := macode.EpisodeSubID(ma, 7)
|
||||
assert.Equal(t, "MA.156.8531.6101/WD/20260000001#E07", sub)
|
||||
|
||||
parsedMA, ep := macode.ParseEpisodeSubID(sub)
|
||||
assert.Equal(t, ma, parsedMA)
|
||||
assert.Equal(t, 7, ep)
|
||||
|
||||
// 无后缀 → 整剧(episode 0)
|
||||
parsedMA2, ep2 := macode.ParseEpisodeSubID(ma)
|
||||
assert.Equal(t, ma, parsedMA2)
|
||||
assert.Equal(t, 0, ep2)
|
||||
}
|
||||
|
||||
// 单体内容(电影,无分集):episodes 为空也能正常签发与整剧验真。
|
||||
func TestSingleContent_NoEpisodes(t *testing.T) {
|
||||
s := newService(t)
|
||||
sub := sampleSub()
|
||||
sub.Episodes = nil
|
||||
r, err := s.SubmitForReview(sub)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.ReviewCSPS(r.ReviewID, true, "rv-1"))
|
||||
issued, err := s.ApproveAndIssue(chain.RoleRegulator, r.ReviewID, "陕西IPTV运营公司")
|
||||
require.NoError(t, err)
|
||||
|
||||
list, err := s.ListEpisodes(issued.MACode)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, list, "单体内容无集级绑定")
|
||||
|
||||
// 整剧验真仍可用
|
||||
res, err := s.Verify(issued.MACode, sub.FileHash)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, res.Match)
|
||||
}
|
||||
Reference in New Issue
Block a user