Files
MAcode/tcs-iptv/internal/service/episode_test.go
T
selfrelease a329d4906b 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 监管大屏(角色工作台/全流程演示/监管片库)
- 一剧一码+集级哈希, 集级下架/恢复, 全栈测试通过
2026-06-14 16:50:31 +08:00

128 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}