Files
MAcode/tcs-iptv/internal/chain/memory_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

150 lines
4.6 KiB
Go

package chain
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tcs-iptv/tcs/internal/model"
)
func newIssued(t *testing.T) *MemoryChain {
t.Helper()
c := NewMemoryChain()
_, err := c.IssueMA(RoleRegulator, IssueRequest{
MACode: "(京)网微剧审字(2025)第123号",
ContentTwinID: "ctid-001",
MerkleRoot: "merkle-root-1",
FileHash: "filehash-1",
Content: model.Content{Title: "示例剧集", EpisodeCount: 24},
})
require.NoError(t, err)
return c
}
func TestIssueMA_OnlyRegulator(t *testing.T) {
c := NewMemoryChain()
_, err := c.IssueMA(RoleCP, IssueRequest{MACode: "MA-1", ContentTwinID: "ct-1", FileHash: "h1"})
assert.ErrorIs(t, err, ErrPermissionDenied)
_, err = c.IssueMA(RoleReviewer, IssueRequest{MACode: "MA-1", ContentTwinID: "ct-1", FileHash: "h1"})
assert.ErrorIs(t, err, ErrPermissionDenied)
_, err = c.IssueMA(RoleRegulator, IssueRequest{MACode: "MA-1", ContentTwinID: "ct-1", FileHash: "h1"})
assert.NoError(t, err)
}
func TestIssueMA_NoReissue(t *testing.T) {
c := newIssued(t)
// 同 MA 码重复签发被拒(1:1 不可解绑/不可覆盖)
_, err := c.IssueMA(RoleRegulator, IssueRequest{
MACode: "(京)网微剧审字(2025)第123号", ContentTwinID: "ctid-001", FileHash: "other",
})
assert.ErrorIs(t, err, ErrMAAlreadyIssued)
}
func TestIssueMA_DuplicateHashRejected(t *testing.T) {
c := newIssued(t)
// 换壳重发:不同 MA 码但相同内容哈希 → 拒绝
_, err := c.IssueMA(RoleRegulator, IssueRequest{
MACode: "(沪)网微剧审字(2025)第999号", ContentTwinID: "ctid-002", FileHash: "filehash-1",
})
assert.ErrorIs(t, err, ErrHashExists)
}
func TestVerifyHash_MatchAndMismatch(t *testing.T) {
c := newIssued(t)
res, err := c.VerifyHash("(京)网微剧审字(2025)第123号", "filehash-1")
require.NoError(t, err)
assert.True(t, res.Match)
assert.True(t, res.Valid)
res, err = c.VerifyHash("(京)网微剧审字(2025)第123号", "tampered-hash")
require.NoError(t, err)
assert.False(t, res.Match)
assert.Equal(t, "filehash-1", res.BoundHash)
}
func TestVerifyHash_UnknownMA(t *testing.T) {
c := NewMemoryChain()
_, err := c.VerifyHash("no-such-ma", "h")
assert.ErrorIs(t, err, ErrMANotIssued)
}
func TestRegisterMapping_RequiresIssuedMA(t *testing.T) {
c := NewMemoryChain()
// CTID 未签发 → 拒绝
_, err := c.RegisterMapping(RoleOperator, model.Mapping{
ContentTwinID: "ctid-x", Party: model.PartyOperator, PartyID: "OP-1",
})
assert.ErrorIs(t, err, ErrMANotIssued)
c = newIssued(t)
_, err = c.RegisterMapping(RoleOperator, model.Mapping{
ContentTwinID: "ctid-001", Party: model.PartyOperator,
PartyID: "CT-IPTV-008923", CDNEndpoint: "cdn://ct-gd/iptv/vod/008923",
})
assert.NoError(t, err)
res, err := c.QueryMappings("(京)网微剧审字(2025)第123号")
require.NoError(t, err)
assert.Len(t, res.Mappings, 1)
assert.Equal(t, []string{"cdn://ct-gd/iptv/vod/008923"}, res.CDNEndpoints)
}
func TestTranscodedBinding_ParentChild(t *testing.T) {
c := newIssued(t)
_, err := c.RegisterHashBinding(RoleReviewer, model.HashBinding{
ContentTwinID: "ctid-001",
HashType: model.HashTranscoded,
HashValue: "transcoded-h265-4k",
ParentHash: "filehash-1",
Version: "v1.0-h265",
})
require.NoError(t, err)
// 转码版哈希也能验真通过
res, err := c.VerifyHash("(京)网微剧审字(2025)第123号", "transcoded-h265-4k")
require.NoError(t, err)
assert.True(t, res.Match)
}
func TestRevoke_OnlyRegulator(t *testing.T) {
c := newIssued(t)
_, _ = c.RegisterMapping(RoleOperator, model.Mapping{
ContentTwinID: "ctid-001", Party: model.PartyOperator,
PartyID: "OP-1", CDNEndpoint: "cdn://x/y/z",
})
_, err := c.Revoke(RoleOperator, "(京)网微剧审字(2025)第123号", "试图越权")
assert.ErrorIs(t, err, ErrPermissionDenied)
res, err := c.Revoke(RoleRegulator, "(京)网微剧审字(2025)第123号", "违规")
require.NoError(t, err)
assert.Contains(t, res.CDNEndpoints, "cdn://x/y/z")
ct, _ := c.QueryContent("(京)网微剧审字(2025)第123号")
assert.Equal(t, model.StatusRevoked, ct.Status)
}
func TestRecordVersionChange(t *testing.T) {
c := newIssued(t)
_, err := c.RecordVersionChange(model.VersionChange{
ContentTwinID: "ctid-001", Version: "v2.0",
ChangeReason: "片尾字幕修正", PrevHash: "filehash-1", NewHash: "filehash-2",
ReauditRequired: true, AffectedEpisode: 24,
})
assert.NoError(t, err)
}
func TestHashExists(t *testing.T) {
c := newIssued(t)
ma, ok := c.HashExists("filehash-1")
assert.True(t, ok)
assert.Equal(t, "(京)网微剧审字(2025)第123号", ma)
_, ok = c.HashExists("unknown")
assert.False(t, ok)
}