Initial commit: breakpilot-compliance - Compliance SDK Platform
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>
This commit is contained in:
940
ai-compliance-sdk/internal/ucca/license_policy_test.go
Normal file
940
ai-compliance-sdk/internal/ucca/license_policy_test.go
Normal file
@@ -0,0 +1,940 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user