feat: 更新CC码监管方案业务版文档,新增摘要、UGC专项、直播专项、存量处置、误判申诉、水印嵌入、CC码生命周期、组织保障等章节;同步macode到cccode重命名及其他代码变更
This commit is contained in:
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/tcs-iptv/tcs/internal/chain"
|
||||
"github.com/tcs-iptv/tcs/internal/hash"
|
||||
"github.com/tcs-iptv/tcs/internal/httpx"
|
||||
"github.com/tcs-iptv/tcs/internal/macode"
|
||||
"github.com/tcs-iptv/tcs/internal/cccode"
|
||||
"github.com/tcs-iptv/tcs/internal/service"
|
||||
)
|
||||
|
||||
@@ -24,10 +24,10 @@ func testServer(t *testing.T) (*httptest.Server, *httpx.MemoryKeyStore) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
ch := chain.NewMemoryChain()
|
||||
gen := macode.NewGenerator(macode.NewMemoryStore())
|
||||
require.NoError(t, gen.RegisterSegment(macode.Segment{
|
||||
gen := cccode.NewGenerator(cccode.NewMemoryStore())
|
||||
require.NoError(t, gen.RegisterSegment(cccode.Segment{
|
||||
IndustryNode: "8531", OrgNode: "4401",
|
||||
Category: macode.CategoryMicroDrama, Start: 1, End: 9999999, SeqWidth: 7,
|
||||
Category: cccode.CategoryMicroDrama, Start: 1, End: 9999999, SeqWidth: 7,
|
||||
}))
|
||||
svc := service.New(ch, gen)
|
||||
h := NewHandler(svc)
|
||||
@@ -115,39 +115,39 @@ func TestE2E_FullLifecycle(t *testing.T) {
|
||||
"review_id": reviewID, "issuer": "北京市广播电视局",
|
||||
})
|
||||
require.Equal(t, http.StatusOK, st)
|
||||
maCode := dataOf(resp)["ma_code"].(string)
|
||||
ccCode := dataOf(resp)["ma_code"].(string)
|
||||
cert := dataOf(resp)["certificate"].(string)
|
||||
assert.True(t, macode.IsValid(maCode))
|
||||
assert.True(t, cccode.IsValid(ccCode))
|
||||
|
||||
// 4) 入媒资库
|
||||
st, _ = signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/ingest", map[string]any{
|
||||
"ma_code": maCode, "content_twin_id": ctid, "media_asset_id": "MEDIA-001", "lib_name": "广东IPTV媒资库",
|
||||
"ma_code": ccCode, "content_twin_id": ctid, "media_asset_id": "MEDIA-001", "lib_name": "广东IPTV媒资库",
|
||||
})
|
||||
require.Equal(t, http.StatusOK, st)
|
||||
|
||||
// 5) 发布
|
||||
st, _ = signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/publish", map[string]any{
|
||||
"ma_code": maCode, "certificate": cert,
|
||||
"ma_code": ccCode, "certificate": cert,
|
||||
})
|
||||
require.Equal(t, http.StatusOK, st)
|
||||
|
||||
// 6) CDN 注入(匹配)
|
||||
st, resp = signedCall(t, b, "ak-operator", "sk-operator", "POST", "/content/inject", map[string]any{
|
||||
"content_twin_id": ctid, "ma_code": maCode, "file_sha256": "fh-e2e",
|
||||
"content_twin_id": ctid, "ma_code": ccCode, "file_sha256": "fh-e2e",
|
||||
"operator_id": "CT-IPTV-GD", "cdn_endpoint": "cdn://ct-gd/vod/1",
|
||||
})
|
||||
require.Equal(t, http.StatusOK, st)
|
||||
assert.Equal(t, true, dataOf(resp)["allowed"])
|
||||
|
||||
// 7) 映射查询
|
||||
st, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "GET", "/content/mappings?ma_code="+maCode, nil)
|
||||
st, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "GET", "/content/mappings?ma_code="+ccCode, nil)
|
||||
require.Equal(t, http.StatusOK, st)
|
||||
mappings := dataOf(resp)["mappings"].([]any)
|
||||
assert.Len(t, mappings, 3) // cp + reviewer + operator
|
||||
|
||||
// 8) 监管下架
|
||||
st, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/takedown", map[string]any{
|
||||
"ma_code": maCode, "reason": "违规",
|
||||
"ma_code": ccCode, "reason": "违规",
|
||||
})
|
||||
require.Equal(t, http.StatusOK, st)
|
||||
assert.NotEmpty(t, dataOf(resp)["cdn_endpoints"])
|
||||
@@ -171,14 +171,14 @@ func TestE2E_TamperRejected(t *testing.T) {
|
||||
_, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/issue", map[string]any{
|
||||
"review_id": reviewID, "issuer": "x",
|
||||
})
|
||||
maCode := dataOf(resp)["ma_code"].(string)
|
||||
ccCode := dataOf(resp)["ma_code"].(string)
|
||||
cert := dataOf(resp)["certificate"].(string)
|
||||
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/ingest", map[string]any{"ma_code": maCode, "content_twin_id": ctid, "media_asset_id": "M", "lib_name": "L"})
|
||||
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/publish", map[string]any{"ma_code": maCode, "certificate": cert})
|
||||
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/ingest", map[string]any{"ma_code": ccCode, "content_twin_id": ctid, "media_asset_id": "M", "lib_name": "L"})
|
||||
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/publish", map[string]any{"ma_code": ccCode, "certificate": cert})
|
||||
|
||||
// 篡改文件注入 → 拒绝
|
||||
st, _ = signedCall(t, b, "ak-operator", "sk-operator", "POST", "/content/inject", map[string]any{
|
||||
"content_twin_id": ctid, "ma_code": maCode, "file_sha256": "fh-TAMPERED",
|
||||
"content_twin_id": ctid, "ma_code": ccCode, "file_sha256": "fh-TAMPERED",
|
||||
"operator_id": "OP", "cdn_endpoint": "cdn://x",
|
||||
})
|
||||
assert.Equal(t, http.StatusBadRequest, st, "篡改注入必须被拒")
|
||||
@@ -235,14 +235,14 @@ func TestE2E_PermissionMatrix(t *testing.T) {
|
||||
|
||||
// 正常签发
|
||||
_, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/issue", map[string]any{"review_id": reviewID, "issuer": "x"})
|
||||
maCode := dataOf(resp)["ma_code"].(string)
|
||||
ccCode := dataOf(resp)["ma_code"].(string)
|
||||
|
||||
// 运营商越权下架 → 403
|
||||
st, _ = signedCall(t, b, "ak-operator", "sk-operator", "POST", "/content/takedown", map[string]any{"ma_code": maCode, "reason": "越权"})
|
||||
st, _ = signedCall(t, b, "ak-operator", "sk-operator", "POST", "/content/takedown", map[string]any{"ma_code": ccCode, "reason": "越权"})
|
||||
assert.Equal(t, http.StatusForbidden, st, "运营商不得发起下架")
|
||||
|
||||
// 无效签名 → 401
|
||||
req, _ := http.NewRequest("GET", b+"/api/v1/content/mappings?ma_code="+maCode, nil)
|
||||
req, _ := http.NewRequest("GET", b+"/api/v1/content/mappings?ma_code="+ccCode, nil)
|
||||
req.Header.Set("Authorization", "TCS ak-regulator:badsig")
|
||||
r, _ := http.DefaultClient.Do(req)
|
||||
assert.Equal(t, http.StatusUnauthorized, r.StatusCode, "错误签名应 401")
|
||||
@@ -261,10 +261,10 @@ func TestE2E_TakedownLatency(t *testing.T) {
|
||||
reviewID := dataOf(resp)["review_id"].(string)
|
||||
signedCall(t, b, "ak-reviewer", "sk-reviewer", "POST", "/content/csps-result", map[string]any{"review_id": reviewID, "approved": true})
|
||||
_, resp = signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/issue", map[string]any{"review_id": reviewID, "issuer": "x"})
|
||||
maCode := dataOf(resp)["ma_code"].(string)
|
||||
ccCode := dataOf(resp)["ma_code"].(string)
|
||||
|
||||
start := time.Now()
|
||||
st, _ := signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/takedown", map[string]any{"ma_code": maCode, "reason": "违规"})
|
||||
st, _ := signedCall(t, b, "ak-regulator", "sk-regulator", "POST", "/content/takedown", map[string]any{"ma_code": ccCode, "reason": "违规"})
|
||||
elapsed := time.Since(start)
|
||||
require.Equal(t, http.StatusOK, st)
|
||||
assert.Less(t, elapsed, time.Second, "下架端到端应在秒级内(目标分钟级)")
|
||||
|
||||
Reference in New Issue
Block a user