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