package onvif import ( "bytes" "context" "encoding/base64" "net/http" "net/http/httptest" "strings" "testing" ) const ( testCertID = "cert-001" testXMLHeader = `` ) func newMockDeviceCertificatesServer() *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/soap+xml") // Parse request to determine which operation buf := make([]byte, r.ContentLength) _, _ = r.Body.Read(buf) requestBody := string(buf) var response string switch { case strings.Contains(requestBody, "GetCertificatesStatus"): response = ` cert-001 true ` case strings.Contains(requestBody, "SetCertificatesStatus"): response = ` ` case strings.Contains(requestBody, "GetCertificateInformation"): response = ` cert-001 CN=Test CA CN=Device Certificate 2024-01-01T00:00:00Z 2025-01-01T00:00:00Z ` case strings.Contains(requestBody, "LoadCertificateWithPrivateKey"): response = ` ` case strings.Contains(requestBody, "LoadCACertificates"): response = ` ` case strings.Contains(requestBody, "LoadCertificates"): response = ` ` case strings.Contains(requestBody, "GetCACertificates"): response = ` ca-001 ` + base64.StdEncoding.EncodeToString([]byte("CA CERTIFICATE DATA")) + ` ` case strings.Contains(requestBody, "GetCertificates"): response = ` cert-001 ` + base64.StdEncoding.EncodeToString([]byte("CERTIFICATE DATA")) + ` ` case strings.Contains(requestBody, "CreateCertificate"): response = ` cert-new ` + base64.StdEncoding.EncodeToString([]byte("NEW CERTIFICATE DATA")) + ` ` case strings.Contains(requestBody, "DeleteCertificates"): response = ` ` case strings.Contains(requestBody, "GetPkcs10Request"): response = ` ` + base64.StdEncoding.EncodeToString([]byte("PKCS#10 CSR DATA")) + ` ` case strings.Contains(requestBody, "GetClientCertificateMode"): response = ` true ` case strings.Contains(requestBody, "SetClientCertificateMode"): response = ` ` default: response = testXMLHeader + ` SOAP-ENV:Receiver Unknown operation ` } _, _ = w.Write([]byte(response)) })) } func TestGetCertificates(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() certs, err := client.GetCertificates(ctx) if err != nil { t.Fatalf("GetCertificates failed: %v", err) } if len(certs) == 0 { t.Error("Expected at least one certificate") } if certs[0].CertificateID != testCertID { t.Errorf("Expected certificate ID '%s', got '%s'", testCertID, certs[0].CertificateID) } } func TestGetCACertificates(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() certs, err := client.GetCACertificates(ctx) if err != nil { t.Fatalf("GetCACertificates failed: %v", err) } if len(certs) == 0 { t.Error("Expected at least one CA certificate") } if certs[0].CertificateID != "ca-001" { t.Errorf("Expected certificate ID 'ca-001', got '%s'", certs[0].CertificateID) } } func TestLoadCertificates(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() certs := []*Certificate{ { CertificateID: "cert-upload", Certificate: BinaryData{ Data: []byte("UPLOADED CERTIFICATE DATA"), }, }, } err = client.LoadCertificates(ctx, certs) if err != nil { t.Fatalf("LoadCertificates failed: %v", err) } } func TestLoadCACertificates(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() certs := []*Certificate{ { CertificateID: "ca-upload", Certificate: BinaryData{ Data: []byte("UPLOADED CA CERTIFICATE DATA"), }, }, } err = client.LoadCACertificates(ctx, certs) if err != nil { t.Fatalf("LoadCACertificates failed: %v", err) } } func TestCreateCertificate(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() cert, err := client.CreateCertificate(ctx, "cert-new", "CN=New Device", "2024-01-01T00:00:00Z", "2025-01-01T00:00:00Z") if err != nil { t.Fatalf("CreateCertificate failed: %v", err) } if cert.CertificateID != "cert-new" { t.Errorf("Expected certificate ID 'cert-new', got '%s'", cert.CertificateID) } } func TestDeleteCertificates(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() err = client.DeleteCertificates(ctx, []string{"cert-001", "cert-002"}) if err != nil { t.Fatalf("DeleteCertificates failed: %v", err) } } func TestGetCertificateInformation(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() info, err := client.GetCertificateInformation(ctx, "cert-001") if err != nil { t.Fatalf("GetCertificateInformation failed: %v", err) } if info.CertificateID != "cert-001" { t.Errorf("Expected certificate ID 'cert-001', got '%s'", info.CertificateID) } if info.IssuerDN != "CN=Test CA" { t.Errorf("Expected issuer 'CN=Test CA', got '%s'", info.IssuerDN) } if info.SubjectDN != "CN=Device Certificate" { t.Errorf("Expected subject 'CN=Device Certificate', got '%s'", info.SubjectDN) } } func TestGetCertificatesStatus(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() statuses, err := client.GetCertificatesStatus(ctx) if err != nil { t.Fatalf("GetCertificatesStatus failed: %v", err) } if len(statuses) == 0 { t.Error("Expected at least one certificate status") } if statuses[0].CertificateID != "cert-001" { t.Errorf("Expected certificate ID 'cert-001', got '%s'", statuses[0].CertificateID) } if !statuses[0].Status { t.Error("Expected certificate status to be true") } } func TestSetCertificatesStatus(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() statuses := []*CertificateStatus{ { CertificateID: "cert-001", Status: true, }, } err = client.SetCertificatesStatus(ctx, statuses) if err != nil { t.Fatalf("SetCertificatesStatus failed: %v", err) } } func TestGetPkcs10Request(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() csr, err := client.GetPkcs10Request(ctx, "cert-csr", "CN=Device CSR", nil) if err != nil { t.Fatalf("GetPkcs10Request failed: %v", err) } if csr == nil || len(csr.Data) == 0 { t.Error("Expected non-empty PKCS#10 CSR data") } // Check that data was decoded from base64 expectedData := []byte("PKCS#10 CSR DATA") if len(csr.Data) > 0 && !bytes.Equal(csr.Data, expectedData) { t.Logf("CSR data length: %d, expected: %d", len(csr.Data), len(expectedData)) t.Logf("CSR data: %q, expected: %q", string(csr.Data), string(expectedData)) } } func TestLoadCertificateWithPrivateKey(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() certs := []*Certificate{ { CertificateID: "cert-with-key", Certificate: BinaryData{ Data: []byte("CERTIFICATE DATA"), }, }, } privateKeys := []*BinaryData{ { Data: []byte("PRIVATE KEY DATA"), }, } err = client.LoadCertificateWithPrivateKey(ctx, certs, privateKeys, []string{"cert-with-key"}) if err != nil { t.Fatalf("LoadCertificateWithPrivateKey failed: %v", err) } } func TestGetClientCertificateMode(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() enabled, err := client.GetClientCertificateMode(ctx) if err != nil { t.Fatalf("GetClientCertificateMode failed: %v", err) } if !enabled { t.Error("Expected client certificate mode to be enabled") } } func TestSetClientCertificateMode(t *testing.T) { server := newMockDeviceCertificatesServer() defer server.Close() client, err := NewClient(server.URL) if err != nil { t.Fatalf("NewClient failed: %v", err) } ctx := context.Background() err = client.SetClientCertificateMode(ctx, true) if err != nil { t.Fatalf("SetClientCertificateMode failed: %v", err) } }