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:
selfrelease
2026-06-14 16:50:31 +08:00
commit a329d4906b
103 changed files with 20052 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
package hash
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func writeTempFile(t *testing.T, data []byte) string {
t.Helper()
dir := t.TempDir()
p := filepath.Join(dir, "master.bin")
require.NoError(t, os.WriteFile(p, data, 0o644))
return p
}
func TestSHA256Hex_Deterministic(t *testing.T) {
a := SHA256Hex([]byte("hello"))
b := SHA256Hex([]byte("hello"))
assert.Equal(t, a, b)
// 已知向量
assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", a)
}
func TestFileSHA256_MatchesBytes(t *testing.T) {
data := []byte("the quick brown fox")
p := writeTempFile(t, data)
got, err := FileSHA256(p)
require.NoError(t, err)
assert.Equal(t, SHA256Hex(data), got)
}
func TestSegmentHashes_SmallSegments(t *testing.T) {
// 25 字节,分段 10 → 3 段(10/10/5
data := []byte("0123456789ABCDEFGHIJ12345")
p := writeTempFile(t, data)
segs, err := SegmentHashes(p, 10)
require.NoError(t, err)
require.Len(t, segs, 3)
assert.Equal(t, SHA256Hex(data[0:10]), segs[0])
assert.Equal(t, SHA256Hex(data[10:20]), segs[1])
assert.Equal(t, SHA256Hex(data[20:25]), segs[2])
}
func TestMerkleTree_RootStableAndChangesOnEdit(t *testing.T) {
leaves := []string{
SHA256Hex([]byte("ep1")),
SHA256Hex([]byte("ep2")),
SHA256Hex([]byte("ep3")),
SHA256Hex([]byte("ep4")),
}
root1 := BuildMerkleTree(leaves).Root()
root2 := BuildMerkleTree(leaves).Root()
assert.Equal(t, root1, root2, "同样叶子根应一致")
assert.NotEmpty(t, root1)
// 改第3集 → 根变化
edited := append([]string(nil), leaves...)
edited[2] = SHA256Hex([]byte("ep3-tampered"))
root3 := BuildMerkleTree(edited).Root()
assert.NotEqual(t, root1, root3, "篡改任一集,根必变")
}
func TestMerkleTree_OddLeaves(t *testing.T) {
leaves := []string{
SHA256Hex([]byte("a")),
SHA256Hex([]byte("b")),
SHA256Hex([]byte("c")),
}
mt := BuildMerkleTree(leaves)
assert.NotEmpty(t, mt.Root())
}
func TestLocateChangedLeaves(t *testing.T) {
old := []string{"h1", "h2", "h3", "h4"}
neu := []string{"h1", "x2", "h3", "x4"}
changed := LocateChangedLeaves(old, neu)
assert.Equal(t, []int{1, 3}, changed, "应定位到第2集和第4集被改")
}
func TestComputeFile_FullPackage(t *testing.T) {
data := make([]byte, 25*1024) // 25KB
for i := range data {
data[i] = byte(i % 251)
}
p := writeTempFile(t, data)
pkg, err := ComputeFile(p, Options{SegmentSize: 10 * 1024})
require.NoError(t, err)
require.NoError(t, pkg.Validate())
assert.Equal(t, int64(25*1024), pkg.FileSize)
assert.Len(t, pkg.SegmentHashes, 3)
assert.NotEmpty(t, pkg.MerkleRoot)
assert.Equal(t, SHA256Hex(data), pkg.FileSHA256)
}
func TestComputeFile_EmptyFileRejected(t *testing.T) {
p := writeTempFile(t, []byte{})
_, err := ComputeFile(p, Options{})
assert.ErrorIs(t, err, ErrEmptyInput)
}
func TestComputeFile_MissingFile(t *testing.T) {
_, err := ComputeFile("/no/such/file.bin", Options{})
assert.Error(t, err)
}
func TestHashPackage_ValidateMissingFields(t *testing.T) {
assert.Error(t, (&HashPackage{MerkleRoot: "x"}).Validate()) // 缺 file_sha256
assert.Error(t, (&HashPackage{FileSHA256: "x"}).Validate()) // 缺 merkle_root
assert.NoError(t, (&HashPackage{FileSHA256: "a", MerkleRoot: "b"}).Validate())
}
func TestPerceptualHash_IdenticalAndDifferent(t *testing.T) {
// 全黑与全白图,aHash/dHash 应可区分
black := make([][]uint8, 16)
white := make([][]uint8, 16)
grad := make([][]uint8, 16)
for y := 0; y < 16; y++ {
black[y] = make([]uint8, 16)
white[y] = make([]uint8, 16)
grad[y] = make([]uint8, 16)
for x := 0; x < 16; x++ {
white[y][x] = 255
grad[y][x] = uint8(x * 16) // 水平渐变
}
}
imgBlack := newGrayTestImage(black)
imgWhite := newGrayTestImage(white)
imgGrad := newGrayTestImage(grad)
// 同一图的哈希稳定
assert.Equal(t, AHash(imgGrad), AHash(imgGrad))
assert.Equal(t, DHash(imgGrad), DHash(imgGrad))
// 渐变图的 dHash 应与纯色不同
assert.NotEqual(t, DHash(imgGrad), DHash(imgBlack))
// 汉明距离:渐变 vs 纯白 应 > 0
d, err := HammingDistance(DHash(imgGrad), DHash(imgWhite))
require.NoError(t, err)
assert.Greater(t, d, 0)
}
func TestHammingDistance_LengthMismatch(t *testing.T) {
_, err := HammingDistance("ffff", "ffffffff")
assert.Error(t, err)
}