a329d4906b
- 方案文档: AVCC 体系建设、IPTV TCS 需求(0-req)/PRD(1-prd)/任务(2-task)/二三四期任务 - tcs-iptv: Go 后端(哈希SDK/MA码生成/可信数据空间mock/业务编排/HTTP API+HMAC鉴权) - web-console: React+AntD 监管大屏(角色工作台/全流程演示/监管片库) - 一剧一码+集级哈希, 集级下架/恢复, 全栈测试通过
138 lines
4.8 KiB
Go
138 lines
4.8 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/hash"
|
||
)
|
||
|
||
// issueOne 完成一次"送审→CSPS审核→发码签发",返回 maCode、ctid、证书。
|
||
func issueOne(t *testing.T, s *Service) (string, string, string) {
|
||
t.Helper()
|
||
sub, err := s.SubmitForReview(sampleSub())
|
||
require.NoError(t, err)
|
||
require.NoError(t, s.ReviewCSPS(sub.ReviewID, true, "reviewer-1")) // 审核在前
|
||
issued, err := s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "北京市广播电视局")
|
||
require.NoError(t, err)
|
||
return issued.MACode, issued.ContentTwinID, issued.Certificate
|
||
}
|
||
|
||
func TestCSPSAndTranscode(t *testing.T) {
|
||
s := newService(t)
|
||
maCode, ctid, _ := issueOne(t, s)
|
||
|
||
_, err := s.BindTranscoded(chain.RoleReviewer, ctid, "filehash-abc",
|
||
"transcoded-h265-4k", "H.265", "3840x2160", "v1.0-4k")
|
||
require.NoError(t, err)
|
||
|
||
// 转码版也能验真通过
|
||
res, err := s.Verify(maCode, "transcoded-h265-4k")
|
||
require.NoError(t, err)
|
||
assert.True(t, res.Match)
|
||
}
|
||
|
||
func TestCSPSRejected(t *testing.T) {
|
||
s := newService(t)
|
||
sub, err := s.SubmitForReview(sampleSub())
|
||
require.NoError(t, err)
|
||
// CSPS 审核驳回 → 不得发码
|
||
require.NoError(t, s.ReviewCSPS(sub.ReviewID, false, "reviewer-1"))
|
||
_, err = s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "issuer")
|
||
assert.ErrorIs(t, err, ErrNotApproved)
|
||
}
|
||
|
||
func TestIssueRequiresCSPSApproval(t *testing.T) {
|
||
s := newService(t)
|
||
sub, err := s.SubmitForReview(sampleSub())
|
||
require.NoError(t, err)
|
||
// 未经 CSPS 审核直接发码 → 拒绝
|
||
_, err = s.ApproveAndIssue(chain.RoleRegulator, sub.ReviewID, "issuer")
|
||
assert.ErrorIs(t, err, ErrNotApproved)
|
||
}
|
||
|
||
func TestIngestAndPublish(t *testing.T) {
|
||
s := newService(t)
|
||
maCode, ctid, cert := issueOne(t, s)
|
||
|
||
require.NoError(t, s.IngestToLibrary(chain.RoleReviewer, maCode, ctid, "MEDIA-001", "广东IPTV媒资库"))
|
||
|
||
// 无证书发布被拒
|
||
err := s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: ""})
|
||
assert.ErrorIs(t, err, ErrNoCertificate)
|
||
|
||
// 携带证书发布成功
|
||
require.NoError(t, s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: cert}))
|
||
}
|
||
|
||
func TestInjectToCDN_MatchAndMismatch(t *testing.T) {
|
||
s := newService(t)
|
||
maCode, ctid, cert := issueOne(t, s)
|
||
require.NoError(t, s.IngestToLibrary(chain.RoleReviewer, maCode, ctid, "MEDIA-001", "媒资库"))
|
||
require.NoError(t, s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: cert}))
|
||
|
||
// 哈希匹配 → 允许注入
|
||
res, err := s.InjectToCDN(chain.RoleOperator, ctid, maCode, "filehash-abc",
|
||
"CT-IPTV-GD", "cdn://ct-gd/iptv/vod/008923")
|
||
require.NoError(t, err)
|
||
assert.True(t, res.Allowed)
|
||
assert.NotEmpty(t, res.DistributionID)
|
||
|
||
// 哈希不匹配 → 拒绝注入
|
||
res, err = s.InjectToCDN(chain.RoleOperator, ctid, maCode, "tampered-hash",
|
||
"CT-IPTV-GD", "cdn://x")
|
||
assert.ErrorIs(t, err, ErrHashMismatch)
|
||
assert.False(t, res.Allowed)
|
||
}
|
||
|
||
func TestInjectToCDN_RevokedBlocked(t *testing.T) {
|
||
s := newService(t)
|
||
maCode, ctid, cert := issueOne(t, s)
|
||
require.NoError(t, s.IngestToLibrary(chain.RoleReviewer, maCode, ctid, "MEDIA-001", "媒资库"))
|
||
require.NoError(t, s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: cert}))
|
||
|
||
// 下架后不得注入
|
||
_, err := s.Takedown(chain.RoleRegulator, maCode, "违规")
|
||
require.NoError(t, err)
|
||
_, err = s.InjectToCDN(chain.RoleOperator, ctid, maCode, "filehash-abc", "OP", "cdn://x")
|
||
assert.ErrorIs(t, err, ErrNotApproved)
|
||
}
|
||
|
||
func TestTakedown_ResolvesMappings(t *testing.T) {
|
||
s := newService(t)
|
||
maCode, ctid, cert := issueOne(t, s)
|
||
require.NoError(t, s.IngestToLibrary(chain.RoleReviewer, maCode, ctid, "MEDIA-001", "媒资库"))
|
||
require.NoError(t, s.PublishToOperator(PublishRequest{MACode: maCode, Certificate: cert}))
|
||
_, _ = s.InjectToCDN(chain.RoleOperator, ctid, maCode, "filehash-abc", "CT-IPTV-GD", "cdn://ct-gd/vod/1")
|
||
|
||
// 非监管主体不得下架
|
||
_, err := s.Takedown(chain.RoleOperator, maCode, "越权")
|
||
assert.ErrorIs(t, err, chain.ErrPermissionDenied)
|
||
|
||
// 监管下架,解析出 CDN 端点
|
||
res, err := s.Takedown(chain.RoleRegulator, maCode, "违规")
|
||
require.NoError(t, err)
|
||
assert.Contains(t, res.CDNEndpoints, "cdn://ct-gd/vod/1")
|
||
}
|
||
|
||
func TestReportVersionChange_LocatesEpisode(t *testing.T) {
|
||
s := newService(t)
|
||
_, ctid, _ := issueOne(t, s)
|
||
|
||
old := []string{
|
||
hash.SHA256Hex([]byte("ep1")),
|
||
hash.SHA256Hex([]byte("ep2")),
|
||
hash.SHA256Hex([]byte("ep3")),
|
||
}
|
||
neu := []string{
|
||
hash.SHA256Hex([]byte("ep1")),
|
||
hash.SHA256Hex([]byte("ep2-tampered")),
|
||
hash.SHA256Hex([]byte("ep3")),
|
||
}
|
||
episodes, err := s.ReportVersionChange(ctid, "第2集被替换", "root-old", "root-new", old, neu)
|
||
require.NoError(t, err)
|
||
assert.Equal(t, []int{2}, episodes, "应定位到第2集(1-based)")
|
||
}
|