package governance import ( "context" "strings" "testing" "time" ) func TestNewClientRequiresAddress(t *testing.T) { _, err := NewClient(Config{}) if err == nil { t.Fatal("expected error for empty governance address") } } func TestNewClientAcceptsValidConfig(t *testing.T) { c, err := NewClient(Config{GovernanceAddr: "localhost:50051"}) if err != nil { t.Fatalf("unexpected error: %v", err) } if c == nil { t.Fatal("client should not be nil") } } // S-19: mTLS config tests func TestNewClientRequiresTLSWhenFlagged(t *testing.T) { _, err := NewClient(Config{ GovernanceAddr: "localhost:50051", TLSRequired: true, }) if err == nil { t.Fatal("expected error when TLS required but paths missing") } if !strings.Contains(err.Error(), "TLS is required") { t.Errorf("expected TLS error, got: %v", err) } } func TestNewClientAcceptsNoTLSWhenNotRequired(t *testing.T) { c, err := NewClient(Config{ GovernanceAddr: "localhost:50051", TLSRequired: false, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if c == nil { t.Fatal("client should not be nil") } } func TestNewClientAcceptsTLSConfig(t *testing.T) { c, err := NewClient(Config{ GovernanceAddr: "localhost:50051", TLSRequired: true, TLSCertPath: "/path/to/cert.pem", TLSKeyPath: "/path/to/key.pem", TLSCAPath: "/path/to/ca.pem", }) if err != nil { t.Fatalf("unexpected error: %v", err) } if c == nil { t.Fatal("client should not be nil") } } // S-10: RedeemResult.IsExpired tests func TestRedeemResultIsExpired(t *testing.T) { r := &RedeemResult{ ExpiresAt: time.Now().Add(-1 * time.Minute), } if !r.IsExpired() { t.Error("expected expired for past time") } } func TestRedeemResultNotExpired(t *testing.T) { r := &RedeemResult{ ExpiresAt: time.Now().Add(1 * time.Hour), } if r.IsExpired() { t.Error("expected not expired for future time") } } func TestRedeemResultZeroTimeNotExpired(t *testing.T) { r := &RedeemResult{} if r.IsExpired() { t.Error("expected not expired for zero time") } } // S-03: NotarizeCredentialEvent tests func TestNotarizeCredentialEventRequiresFingerprint(t *testing.T) { c, _ := NewClient(Config{GovernanceAddr: "localhost:50051"}) err := c.NotarizeCredentialEvent(context.Background(), CredentialEvent{ EventType: "issue", IntentID: "abc123", }) if err == nil { t.Fatal("expected error for missing fingerprint") } if !strings.Contains(err.Error(), "credential_fingerprint") { t.Errorf("expected fingerprint error, got: %v", err) } } func TestNotarizeCredentialEventRequiresIntentID(t *testing.T) { c, _ := NewClient(Config{GovernanceAddr: "localhost:50051"}) err := c.NotarizeCredentialEvent(context.Background(), CredentialEvent{ EventType: "issue", CredentialFingerprint: "abcdef0123456789", }) if err == nil { t.Fatal("expected error for missing intent_id") } if !strings.Contains(err.Error(), "intent_id") { t.Errorf("expected intent_id error, got: %v", err) } } func TestNotarizeCredentialEventRequiresEventType(t *testing.T) { c, _ := NewClient(Config{GovernanceAddr: "localhost:50051"}) err := c.NotarizeCredentialEvent(context.Background(), CredentialEvent{ IntentID: "abc123", CredentialFingerprint: "abcdef0123456789", }) if err == nil { t.Fatal("expected error for missing event_type") } if !strings.Contains(err.Error(), "event_type") { t.Errorf("expected event_type error, got: %v", err) } } // S-03: VerifyCredentialGovernance tests func TestVerifyCredentialGovernanceNoIntent(t *testing.T) { c, _ := NewClient(Config{GovernanceAddr: "localhost:50051"}) result, err := c.VerifyCredentialGovernance(context.Background(), CredentialVerification{}) if err != nil { t.Fatalf("unexpected error: %v", err) } if result.Governed { t.Error("expected Governed=false for empty intent") } } func TestVerifyCredentialGovernanceRequiresPublicKey(t *testing.T) { c, _ := NewClient(Config{GovernanceAddr: "localhost:50051"}) _, err := c.VerifyCredentialGovernance(context.Background(), CredentialVerification{ IntentID: "abc123", }) if err == nil { t.Fatal("expected error for missing public key") } if !strings.Contains(err.Error(), "certificate public key") { t.Errorf("expected public key error, got: %v", err) } }