Services: Admin-Compliance, Backend-Compliance, AI-Compliance-SDK, Consent-SDK, Developer-Portal, PCA-Platform, DSMS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
941 lines
24 KiB
Go
941 lines
24 KiB
Go
package ucca
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// =============================================================================
|
|
// License Policy Engine Tests
|
|
// =============================================================================
|
|
|
|
func TestNewLicensePolicyEngine(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
if engine == nil {
|
|
t.Fatal("Expected non-nil engine")
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Basic Evaluation Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_NoLicensedContent(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: false,
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.EffectiveMode != "UNRESTRICTED" {
|
|
t.Errorf("Expected UNRESTRICTED mode for no licensed content, got %s", result.EffectiveMode)
|
|
}
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for no licensed content")
|
|
}
|
|
|
|
if !result.OutputRestrictions.AllowQuotes {
|
|
t.Error("Expected AllowQuotes=true for no licensed content")
|
|
}
|
|
|
|
if !result.OutputRestrictions.AllowCopy {
|
|
t.Error("Expected AllowCopy=true for no licensed content")
|
|
}
|
|
|
|
if !result.OutputRestrictions.AllowExport {
|
|
t.Error("Expected AllowExport=true for no licensed content")
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Operation Mode Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_LinkOnlyMode(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "VDI",
|
|
LicenseType: "SINGLE_WORKSTATION",
|
|
AIUsePermitted: "UNKNOWN",
|
|
OperationMode: "LINK_ONLY",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.EffectiveMode != "LINK_ONLY" {
|
|
t.Errorf("Expected LINK_ONLY mode, got %s", result.EffectiveMode)
|
|
}
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for LINK_ONLY mode")
|
|
}
|
|
|
|
if result.RiskScore != 0 {
|
|
t.Errorf("Expected risk score 0 for LINK_ONLY, got %d", result.RiskScore)
|
|
}
|
|
|
|
if result.OutputRestrictions.AllowQuotes {
|
|
t.Error("Expected AllowQuotes=false for LINK_ONLY")
|
|
}
|
|
|
|
if result.OutputRestrictions.AllowCopy {
|
|
t.Error("Expected AllowCopy=false for LINK_ONLY")
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_NotesOnlyMode(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "ISO",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "NOTES_ONLY",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.EffectiveMode != "NOTES_ONLY" {
|
|
t.Errorf("Expected NOTES_ONLY mode, got %s", result.EffectiveMode)
|
|
}
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for NOTES_ONLY mode")
|
|
}
|
|
|
|
if result.RiskScore != 10 {
|
|
t.Errorf("Expected risk score 10 for NOTES_ONLY, got %d", result.RiskScore)
|
|
}
|
|
|
|
// Notes can be copied (they are customer's own)
|
|
if !result.OutputRestrictions.AllowCopy {
|
|
t.Error("Expected AllowCopy=true for NOTES_ONLY")
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_NotesOnlyMode_UnknownLicense(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "VDE",
|
|
LicenseType: "UNKNOWN",
|
|
AIUsePermitted: "UNKNOWN",
|
|
OperationMode: "NOTES_ONLY",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
// Should have escalation level E2
|
|
if result.EscalationLevel != "E2" {
|
|
t.Errorf("Expected escalation level E2 for unknown license, got %s", result.EscalationLevel)
|
|
}
|
|
|
|
// Should have GAP_LICENSE_UNKNOWN gap
|
|
hasGap := false
|
|
for _, gap := range result.Gaps {
|
|
if gap.ID == "GAP_LICENSE_UNKNOWN" {
|
|
hasGap = true
|
|
break
|
|
}
|
|
}
|
|
if !hasGap {
|
|
t.Error("Expected GAP_LICENSE_UNKNOWN gap for unknown license")
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_ExcerptOnlyMode_WithAIPermission(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "ISO",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "YES",
|
|
OperationMode: "EXCERPT_ONLY",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.EffectiveMode != "EXCERPT_ONLY" {
|
|
t.Errorf("Expected EXCERPT_ONLY mode, got %s", result.EffectiveMode)
|
|
}
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for EXCERPT_ONLY with AI permission")
|
|
}
|
|
|
|
// Short quotes should be allowed
|
|
if !result.OutputRestrictions.AllowQuotes {
|
|
t.Error("Expected AllowQuotes=true for EXCERPT_ONLY with AI permission")
|
|
}
|
|
|
|
// But limited to 150 chars
|
|
if result.OutputRestrictions.MaxQuoteLength != 150 {
|
|
t.Errorf("Expected MaxQuoteLength=150, got %d", result.OutputRestrictions.MaxQuoteLength)
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_ExcerptOnlyMode_WithoutAIPermission(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "ISO",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "EXCERPT_ONLY",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
// Should be downgraded to NOTES_ONLY
|
|
if result.EffectiveMode != "NOTES_ONLY" {
|
|
t.Errorf("Expected NOTES_ONLY mode (downgraded), got %s", result.EffectiveMode)
|
|
}
|
|
|
|
// Should have GAP_AI_USE_NOT_PERMITTED
|
|
hasGap := false
|
|
for _, gap := range result.Gaps {
|
|
if gap.ID == "GAP_AI_USE_NOT_PERMITTED" {
|
|
hasGap = true
|
|
break
|
|
}
|
|
}
|
|
if !hasGap {
|
|
t.Error("Expected GAP_AI_USE_NOT_PERMITTED gap")
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_FulltextRAGMode_Allowed(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "VDI",
|
|
LicenseType: "AI_LICENSE",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: true,
|
|
OperationMode: "FULLTEXT_RAG",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.EffectiveMode != "FULLTEXT_RAG" {
|
|
t.Errorf("Expected FULLTEXT_RAG mode, got %s", result.EffectiveMode)
|
|
}
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for FULLTEXT_RAG with proof")
|
|
}
|
|
|
|
if result.StopLine != nil {
|
|
t.Error("Expected no stop line for allowed FULLTEXT_RAG")
|
|
}
|
|
|
|
// Quotes allowed but limited
|
|
if !result.OutputRestrictions.AllowQuotes {
|
|
t.Error("Expected AllowQuotes=true for FULLTEXT_RAG")
|
|
}
|
|
|
|
if result.OutputRestrictions.MaxQuoteLength != 500 {
|
|
t.Errorf("Expected MaxQuoteLength=500, got %d", result.OutputRestrictions.MaxQuoteLength)
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_FulltextRAGMode_Blocked_NoProof(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "VDI",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: false, // No proof!
|
|
OperationMode: "FULLTEXT_RAG",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
// Should be blocked and downgraded to LINK_ONLY
|
|
if result.Allowed {
|
|
t.Error("Expected allowed=false for FULLTEXT_RAG without proof")
|
|
}
|
|
|
|
if result.EffectiveMode != "LINK_ONLY" {
|
|
t.Errorf("Expected LINK_ONLY mode (downgraded), got %s", result.EffectiveMode)
|
|
}
|
|
|
|
// Should have stop line
|
|
if result.StopLine == nil {
|
|
t.Fatal("Expected stop line for blocked FULLTEXT_RAG")
|
|
}
|
|
|
|
if result.StopLine.ID != "STOP_FULLTEXT_WITHOUT_PROOF" {
|
|
t.Errorf("Expected stop line STOP_FULLTEXT_WITHOUT_PROOF, got %s", result.StopLine.ID)
|
|
}
|
|
|
|
// Should have GAP_FULLTEXT_WITHOUT_PROOF
|
|
hasGap := false
|
|
for _, gap := range result.Gaps {
|
|
if gap.ID == "GAP_FULLTEXT_WITHOUT_PROOF" {
|
|
hasGap = true
|
|
if gap.Severity != "BLOCK" {
|
|
t.Error("Expected gap severity BLOCK")
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if !hasGap {
|
|
t.Error("Expected GAP_FULLTEXT_WITHOUT_PROOF gap")
|
|
}
|
|
|
|
if result.EscalationLevel != "E3" {
|
|
t.Errorf("Expected escalation level E3, got %s", result.EscalationLevel)
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_TrainingMode_Blocked(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "DIN_MEDIA",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "NO",
|
|
ProofUploaded: false,
|
|
OperationMode: "TRAINING",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.Allowed {
|
|
t.Error("Expected allowed=false for TRAINING without AI license")
|
|
}
|
|
|
|
if result.EffectiveMode != "LINK_ONLY" {
|
|
t.Errorf("Expected LINK_ONLY mode (downgraded), got %s", result.EffectiveMode)
|
|
}
|
|
|
|
// Should have stop line
|
|
if result.StopLine == nil {
|
|
t.Fatal("Expected stop line for blocked TRAINING")
|
|
}
|
|
|
|
if result.EscalationLevel != "E3" {
|
|
t.Errorf("Expected escalation level E3, got %s", result.EscalationLevel)
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_TrainingMode_Allowed(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "VDI",
|
|
LicenseType: "AI_LICENSE",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: true,
|
|
OperationMode: "TRAINING",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.EffectiveMode != "TRAINING" {
|
|
t.Errorf("Expected TRAINING mode, got %s", result.EffectiveMode)
|
|
}
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for TRAINING with AI_LICENSE")
|
|
}
|
|
|
|
// Still requires E3 review
|
|
if result.EscalationLevel != "E3" {
|
|
t.Errorf("Expected escalation level E3 even for allowed training, got %s", result.EscalationLevel)
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Publisher-Specific Tests (DIN Media)
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_DINMedia_FulltextBlocked(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "DIN_MEDIA",
|
|
LicenseType: "SINGLE_WORKSTATION",
|
|
AIUsePermitted: "NO",
|
|
ProofUploaded: false,
|
|
OperationMode: "FULLTEXT_RAG",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.Allowed {
|
|
t.Error("Expected allowed=false for DIN_MEDIA FULLTEXT_RAG without AI permission")
|
|
}
|
|
|
|
// Should have DIN-specific stop line
|
|
if result.StopLine == nil {
|
|
t.Fatal("Expected stop line for DIN_MEDIA")
|
|
}
|
|
|
|
if result.StopLine.ID != "STOP_DIN_FULLTEXT_AI_NOT_ALLOWED" {
|
|
t.Errorf("Expected stop line STOP_DIN_FULLTEXT_AI_NOT_ALLOWED, got %s", result.StopLine.ID)
|
|
}
|
|
|
|
// Should have CTRL-NO-CRAWLING-DIN control
|
|
hasControl := false
|
|
for _, ctrl := range result.RequiredControls {
|
|
if ctrl.ID == "CTRL-NO-CRAWLING-DIN" {
|
|
hasControl = true
|
|
break
|
|
}
|
|
}
|
|
if !hasControl {
|
|
t.Error("Expected CTRL-NO-CRAWLING-DIN control for DIN_MEDIA")
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_DINMedia_LinkOnlyAllowed(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "DIN_MEDIA",
|
|
LicenseType: "SINGLE_WORKSTATION",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "LINK_ONLY",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for DIN_MEDIA LINK_ONLY")
|
|
}
|
|
|
|
if result.EffectiveMode != "LINK_ONLY" {
|
|
t.Errorf("Expected LINK_ONLY mode, got %s", result.EffectiveMode)
|
|
}
|
|
|
|
// Should have no stop line for LINK_ONLY
|
|
if result.StopLine != nil {
|
|
t.Error("Expected no stop line for DIN_MEDIA LINK_ONLY")
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_DINMedia_NotesOnlyAllowed(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "DIN_MEDIA",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "NOTES_ONLY",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for DIN_MEDIA NOTES_ONLY")
|
|
}
|
|
|
|
if result.EffectiveMode != "NOTES_ONLY" {
|
|
t.Errorf("Expected NOTES_ONLY mode, got %s", result.EffectiveMode)
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Distribution Scope Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_DistributionScopeMismatch(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "ISO",
|
|
LicenseType: "SINGLE_WORKSTATION",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "LINK_ONLY",
|
|
DistributionScope: "COMPANY_INTERNAL",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
// Should have GAP_DISTRIBUTION_SCOPE_MISMATCH
|
|
hasGap := false
|
|
for _, gap := range result.Gaps {
|
|
if gap.ID == "GAP_DISTRIBUTION_SCOPE_MISMATCH" {
|
|
hasGap = true
|
|
break
|
|
}
|
|
}
|
|
if !hasGap {
|
|
t.Error("Expected GAP_DISTRIBUTION_SCOPE_MISMATCH for single workstation with company distribution")
|
|
}
|
|
|
|
if result.EscalationLevel != "E3" {
|
|
t.Errorf("Expected escalation level E3, got %s", result.EscalationLevel)
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_NetworkLicenseExternalDistribution(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "VDI",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: true,
|
|
OperationMode: "NOTES_ONLY",
|
|
DistributionScope: "EXTERNAL_CUSTOMERS",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
// Should have GAP_DISTRIBUTION_SCOPE_EXTERNAL
|
|
hasGap := false
|
|
for _, gap := range result.Gaps {
|
|
if gap.ID == "GAP_DISTRIBUTION_SCOPE_EXTERNAL" {
|
|
hasGap = true
|
|
break
|
|
}
|
|
}
|
|
if !hasGap {
|
|
t.Error("Expected GAP_DISTRIBUTION_SCOPE_EXTERNAL for network license with external distribution")
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Helper Function Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_CanIngestFulltext(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
tests := []struct {
|
|
name string
|
|
facts *LicensedContentFacts
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "No licensed content",
|
|
facts: &LicensedContentFacts{
|
|
Present: false,
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "LINK_ONLY mode",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "LINK_ONLY",
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "NOTES_ONLY mode",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "NOTES_ONLY",
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "FULLTEXT_RAG with proof",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "FULLTEXT_RAG",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: true,
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "FULLTEXT_RAG without proof",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "FULLTEXT_RAG",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: false,
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "TRAINING with AI_LICENSE",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "TRAINING",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: true,
|
|
LicenseType: "AI_LICENSE",
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "TRAINING without AI_LICENSE",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "TRAINING",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: true,
|
|
LicenseType: "NETWORK_INTRANET",
|
|
},
|
|
expected: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := engine.CanIngestFulltext(tt.facts)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected %v, got %v", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_CanIngestNotes(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
tests := []struct {
|
|
name string
|
|
facts *LicensedContentFacts
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "No licensed content",
|
|
facts: &LicensedContentFacts{
|
|
Present: false,
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "LINK_ONLY mode",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "LINK_ONLY",
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "NOTES_ONLY mode",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "NOTES_ONLY",
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "EXCERPT_ONLY mode",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "EXCERPT_ONLY",
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "FULLTEXT_RAG mode",
|
|
facts: &LicensedContentFacts{
|
|
Present: true,
|
|
OperationMode: "FULLTEXT_RAG",
|
|
},
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := engine.CanIngestNotes(tt.facts)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected %v, got %v", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_GetEffectiveMode(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
// Test downgrade scenario
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "DIN_MEDIA",
|
|
LicenseType: "SINGLE_WORKSTATION",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "FULLTEXT_RAG",
|
|
}
|
|
|
|
effectiveMode := engine.GetEffectiveMode(facts)
|
|
|
|
if effectiveMode != "LINK_ONLY" {
|
|
t.Errorf("Expected effective mode LINK_ONLY (downgraded), got %s", effectiveMode)
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_DecideIngest(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "VDI",
|
|
LicenseType: "AI_LICENSE",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: true,
|
|
OperationMode: "FULLTEXT_RAG",
|
|
}
|
|
|
|
decision := engine.DecideIngest(facts)
|
|
|
|
if !decision.AllowMetadata {
|
|
t.Error("Expected AllowMetadata=true")
|
|
}
|
|
|
|
if !decision.AllowNotes {
|
|
t.Error("Expected AllowNotes=true")
|
|
}
|
|
|
|
if !decision.AllowFulltext {
|
|
t.Error("Expected AllowFulltext=true for FULLTEXT_RAG with proof")
|
|
}
|
|
|
|
if decision.EffectiveMode != "FULLTEXT_RAG" {
|
|
t.Errorf("Expected EffectiveMode=FULLTEXT_RAG, got %s", decision.EffectiveMode)
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Audit Entry Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_FormatAuditEntry(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "DIN_MEDIA",
|
|
LicenseType: "SINGLE_WORKSTATION",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "FULLTEXT_RAG",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
entry := engine.FormatAuditEntry("tenant-123", "doc-456", facts, result)
|
|
|
|
if entry.TenantID != "tenant-123" {
|
|
t.Errorf("Expected TenantID=tenant-123, got %s", entry.TenantID)
|
|
}
|
|
|
|
if entry.DocumentID != "doc-456" {
|
|
t.Errorf("Expected DocumentID=doc-456, got %s", entry.DocumentID)
|
|
}
|
|
|
|
if entry.Decision != "DENY" {
|
|
t.Errorf("Expected Decision=DENY, got %s", entry.Decision)
|
|
}
|
|
|
|
if entry.StopLineID == "" {
|
|
t.Error("Expected StopLineID to be set for denied request")
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_FormatAuditEntry_Downgrade(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "ISO",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "EXCERPT_ONLY",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
entry := engine.FormatAuditEntry("tenant-123", "doc-456", facts, result)
|
|
|
|
if entry.Decision != "DOWNGRADE" {
|
|
t.Errorf("Expected Decision=DOWNGRADE, got %s", entry.Decision)
|
|
}
|
|
|
|
if entry.EffectiveMode != "NOTES_ONLY" {
|
|
t.Errorf("Expected EffectiveMode=NOTES_ONLY, got %s", entry.EffectiveMode)
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Human Readable Summary Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_FormatHumanReadableSummary(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "DIN_MEDIA",
|
|
LicenseType: "SINGLE_WORKSTATION",
|
|
AIUsePermitted: "NO",
|
|
OperationMode: "FULLTEXT_RAG",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
summary := engine.FormatHumanReadableSummary(result)
|
|
|
|
// Should contain key elements
|
|
if !stringContains(summary, "BLOCKIERT") {
|
|
t.Error("Summary should contain 'BLOCKIERT'")
|
|
}
|
|
|
|
if !stringContains(summary, "LINK_ONLY") {
|
|
t.Error("Summary should contain 'LINK_ONLY'")
|
|
}
|
|
|
|
if !stringContains(summary, "STOP-LINE") {
|
|
t.Error("Summary should contain '!!! STOP-LINE !!!'")
|
|
}
|
|
|
|
if !stringContains(summary, "DIN Media") {
|
|
t.Error("Summary should mention DIN Media")
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Determinism Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_Determinism(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "DIN_MEDIA",
|
|
LicenseType: "NETWORK_INTRANET",
|
|
AIUsePermitted: "NO",
|
|
ProofUploaded: false,
|
|
OperationMode: "FULLTEXT_RAG",
|
|
DistributionScope: "COMPANY_INTERNAL",
|
|
}
|
|
|
|
// Run evaluation 10 times and ensure identical results
|
|
firstResult := engine.Evaluate(facts)
|
|
|
|
for i := 0; i < 10; i++ {
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.Allowed != firstResult.Allowed {
|
|
t.Errorf("Run %d: Allowed mismatch: %v vs %v", i, result.Allowed, firstResult.Allowed)
|
|
}
|
|
if result.EffectiveMode != firstResult.EffectiveMode {
|
|
t.Errorf("Run %d: EffectiveMode mismatch: %s vs %s", i, result.EffectiveMode, firstResult.EffectiveMode)
|
|
}
|
|
if result.RiskScore != firstResult.RiskScore {
|
|
t.Errorf("Run %d: RiskScore mismatch: %d vs %d", i, result.RiskScore, firstResult.RiskScore)
|
|
}
|
|
if len(result.Gaps) != len(firstResult.Gaps) {
|
|
t.Errorf("Run %d: Gaps count mismatch: %d vs %d", i, len(result.Gaps), len(firstResult.Gaps))
|
|
}
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Edge Case Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_UnknownOperationMode(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "ISO",
|
|
OperationMode: "INVALID_MODE",
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
// Should default to LINK_ONLY
|
|
if result.EffectiveMode != "LINK_ONLY" {
|
|
t.Errorf("Expected default to LINK_ONLY for unknown mode, got %s", result.EffectiveMode)
|
|
}
|
|
|
|
if !result.Allowed {
|
|
t.Error("Expected allowed=true for fallback to LINK_ONLY")
|
|
}
|
|
}
|
|
|
|
func TestLicensePolicyEngine_EmptyFacts(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
facts := &LicensedContentFacts{}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
// Empty facts = no licensed content
|
|
if result.EffectiveMode != "UNRESTRICTED" {
|
|
t.Errorf("Expected UNRESTRICTED for empty facts, got %s", result.EffectiveMode)
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Risk Score Tests
|
|
// =============================================================================
|
|
|
|
func TestLicensePolicyEngine_RiskScores(t *testing.T) {
|
|
engine := NewLicensePolicyEngine()
|
|
|
|
tests := []struct {
|
|
name string
|
|
mode string
|
|
expectedMin int
|
|
expectedMax int
|
|
}{
|
|
{"LINK_ONLY", "LINK_ONLY", 0, 0},
|
|
{"NOTES_ONLY", "NOTES_ONLY", 10, 30},
|
|
{"EXCERPT_ONLY", "EXCERPT_ONLY", 30, 50},
|
|
{"FULLTEXT_RAG", "FULLTEXT_RAG", 60, 90},
|
|
{"TRAINING", "TRAINING", 80, 100},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
facts := &LicensedContentFacts{
|
|
Present: true,
|
|
Publisher: "VDI",
|
|
LicenseType: "AI_LICENSE",
|
|
AIUsePermitted: "YES",
|
|
ProofUploaded: true,
|
|
OperationMode: tt.mode,
|
|
}
|
|
|
|
result := engine.Evaluate(facts)
|
|
|
|
if result.RiskScore < tt.expectedMin || result.RiskScore > tt.expectedMax {
|
|
t.Errorf("Expected risk score in range [%d, %d], got %d",
|
|
tt.expectedMin, tt.expectedMax, result.RiskScore)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Helper function
|
|
func stringContains(s, substr string) bool {
|
|
return len(s) >= len(substr) && (s == substr || len(s) > 0 && stringContainsHelper(s, substr))
|
|
}
|
|
|
|
func stringContainsHelper(s, substr string) bool {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|