package onvif
import (
"context"
"encoding/xml"
"net/http"
"net/http/httptest"
"testing"
)
func TestGetDeviceInformation(t *testing.T) {
tests := []struct {
name string
handler http.HandlerFunc
wantErr bool
}{
{
name: "successful device information retrieval",
handler: func(w http.ResponseWriter, r *http.Request) {
response := `
Test Manufacturer
Test Model
1.0.0
12345
HW-001
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
},
wantErr: false,
},
{
name: "SOAP fault response",
handler: func(w http.ResponseWriter, r *http.Request) {
response := `
s:Receiver
Internal error
`
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(response))
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server := httptest.NewServer(tt.handler)
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
deviceInfo, err := client.GetDeviceInformation(context.Background())
if (err != nil) != tt.wantErr {
t.Errorf("GetDeviceInformation() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && deviceInfo == nil {
t.Error("Expected device information, got nil")
}
if !tt.wantErr && deviceInfo != nil {
if deviceInfo.Manufacturer != "Test Manufacturer" {
t.Errorf("Expected manufacturer 'Test Manufacturer', got '%s'", deviceInfo.Manufacturer)
}
}
})
}
}
func TestGetCapabilities(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
http://example.com/onvif/device_service
http://example.com/onvif/media_service
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
capabilities, err := client.GetCapabilities(context.Background())
if err != nil {
t.Fatalf("GetCapabilities() error = %v", err)
}
if capabilities == nil {
t.Fatal("Expected capabilities, got nil")
}
if capabilities.Device == nil || capabilities.Device.XAddr == "" {
t.Error("Expected Device capabilities with XAddr")
}
}
func TestGetHostname(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
false
test-camera
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
hostname, err := client.GetHostname(context.Background())
if err != nil {
t.Fatalf("GetHostname() error = %v", err)
}
if hostname == nil {
t.Fatal("Expected hostname information, got nil")
}
if hostname.Name != "test-camera" {
t.Errorf("Expected hostname 'test-camera', got '%s'", hostname.Name)
}
}
func TestSetHostname(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify the request body contains the new hostname
var envelope struct {
Body struct {
SetHostname struct {
XMLName xml.Name `xml:"SetHostname"`
Name string `xml:"Name"`
} `xml:"SetHostname"`
} `xml:"Body"`
}
if err := xml.NewDecoder(r.Body).Decode(&envelope); err != nil {
t.Errorf("Failed to decode request: %v", err)
}
if envelope.Body.SetHostname.Name != "new-hostname" {
t.Errorf("Expected hostname 'new-hostname', got '%s'", envelope.Body.SetHostname.Name)
}
response := `
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
err = client.SetHostname(context.Background(), "new-hostname")
if err != nil {
t.Fatalf("SetHostname() error = %v", err)
}
}
func TestGetDNS(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
true
example.com
IPv4
8.8.8.8
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
dns, err := client.GetDNS(context.Background())
if err != nil {
t.Fatalf("GetDNS() error = %v", err)
}
if dns == nil {
t.Fatal("Expected DNS information, got nil")
}
if !dns.FromDHCP {
t.Error("Expected DNS from DHCP")
}
}
func TestGetUsers(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
admin
Administrator
user
User
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
users, err := client.GetUsers(context.Background())
if err != nil {
t.Fatalf("GetUsers() error = %v", err)
}
if len(users) != 2 {
t.Errorf("Expected 2 users, got %d", len(users))
}
if users[0].Username != "admin" {
t.Errorf("Expected first user to be 'admin', got '%s'", users[0].Username)
}
}
func TestCreateUsers(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
users := []*User{
{
Username: "newuser",
Password: "password123",
UserLevel: "User",
},
}
err = client.CreateUsers(context.Background(), users)
if err != nil {
t.Fatalf("CreateUsers() error = %v", err)
}
}
func TestDeleteUsers(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
err = client.DeleteUsers(context.Background(), []string{"testuser"})
if err != nil {
t.Fatalf("DeleteUsers() error = %v", err)
}
}
func TestGetNetworkInterfaces(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
true
eth0
00:11:22:33:44:55
1500
true
false
192.168.1.100
24
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
interfaces, err := client.GetNetworkInterfaces(context.Background())
if err != nil {
t.Fatalf("GetNetworkInterfaces() error = %v", err)
}
if len(interfaces) != 1 {
t.Errorf("Expected 1 interface, got %d", len(interfaces))
}
if interfaces[0].Info.Name != "eth0" {
t.Errorf("Expected interface name 'eth0', got '%s'", interfaces[0].Info.Name)
}
}
func TestGetServices(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
http://www.onvif.org/ver10/device/wsdl
http://192.168.1.100/onvif/device_service
2
6
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
services, err := client.GetServices(context.Background(), true)
if err != nil {
t.Fatalf("GetServices() error = %v", err)
}
if len(services) != 1 {
t.Errorf("Expected 1 service, got %d", len(services))
}
if services[0].Namespace != "http://www.onvif.org/ver10/device/wsdl" {
t.Errorf("Expected device namespace, got %s", services[0].Namespace)
}
}
func TestGetServiceCapabilities(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
caps, err := client.GetServiceCapabilities(context.Background())
if err != nil {
t.Fatalf("GetServiceCapabilities() error = %v", err)
}
if caps.Network == nil || !caps.Network.IPFilter {
t.Error("Expected Network.IPFilter to be true")
}
}
func TestGetDiscoveryMode(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
Discoverable
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
mode, err := client.GetDiscoveryMode(context.Background())
if err != nil {
t.Fatalf("GetDiscoveryMode() error = %v", err)
}
if mode != DiscoveryModeDiscoverable {
t.Errorf("Expected Discoverable mode, got %s", mode)
}
}
func TestSetDiscoveryMode(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
err = client.SetDiscoveryMode(context.Background(), DiscoveryModeDiscoverable)
if err != nil {
t.Fatalf("SetDiscoveryMode() error = %v", err)
}
}
func TestGetEndpointReference(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
urn:uuid:12345678-1234-1234-1234-123456789abc
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
guid, err := client.GetEndpointReference(context.Background())
if err != nil {
t.Fatalf("GetEndpointReference() error = %v", err)
}
expected := "urn:uuid:12345678-1234-1234-1234-123456789abc"
if guid != expected {
t.Errorf("Expected GUID %s, got %s", expected, guid)
}
}
func TestGetNetworkProtocols(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
HTTP
true
80
RTSP
true
554
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
protocols, err := client.GetNetworkProtocols(context.Background())
if err != nil {
t.Fatalf("GetNetworkProtocols() error = %v", err)
}
if len(protocols) != 2 {
t.Fatalf("Expected 2 protocols, got %d", len(protocols))
}
if protocols[0].Name != NetworkProtocolHTTP {
t.Errorf("Expected HTTP protocol, got %s", protocols[0].Name)
}
}
func TestSetNetworkProtocols(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
protocols := []*NetworkProtocol{
{Name: NetworkProtocolHTTP, Enabled: true, Port: []int{8080}},
}
err = client.SetNetworkProtocols(context.Background(), protocols)
if err != nil {
t.Fatalf("SetNetworkProtocols() error = %v", err)
}
}
func TestGetNetworkDefaultGateway(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
192.168.1.1
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
gateway, err := client.GetNetworkDefaultGateway(context.Background())
if err != nil {
t.Fatalf("GetNetworkDefaultGateway() error = %v", err)
}
if len(gateway.IPv4Address) != 1 || gateway.IPv4Address[0] != "192.168.1.1" {
t.Errorf("Expected gateway 192.168.1.1, got %v", gateway.IPv4Address)
}
}
func TestSetNetworkDefaultGateway(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, err := NewClient(server.URL)
if err != nil {
t.Fatalf("Failed to create client: %v", err)
}
gateway := &NetworkGateway{
IPv4Address: []string{"192.168.1.1"},
}
err = client.SetNetworkDefaultGateway(context.Background(), gateway)
if err != nil {
t.Fatalf("SetNetworkDefaultGateway() error = %v", err)
}
}
func BenchmarkDeviceGetDeviceInformation(b *testing.B) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := `
Test
Model
1.0
123
HW1
`
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(response))
}))
defer server.Close()
client, _ := NewClient(server.URL)
ctx := context.Background()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = client.GetDeviceInformation(ctx)
}
}