refactor: improve media service client methods and clean up test files

- Introduced helper methods `getMediaEndpoint` and `getMediaSoapClient` in the media client for better code reuse and clarity.
- Updated various media service methods to utilize the new helper methods, enhancing maintainability.
- Cleaned up test files by standardizing formatting and removing unnecessary blank lines for improved readability.
This commit is contained in:
0x524a
2025-12-02 01:22:06 -05:00
parent 202218e24e
commit 2ea36220f7
9 changed files with 177 additions and 176 deletions
+18 -16
View File
@@ -11,6 +11,20 @@ import (
// Media service namespace // Media service namespace
const mediaNamespace = "http://www.onvif.org/ver10/media/wsdl" const mediaNamespace = "http://www.onvif.org/ver10/media/wsdl"
// getMediaEndpoint returns the media endpoint, falling back to the default endpoint if not set.
func (c *Client) getMediaEndpoint() string {
if c.mediaEndpoint != "" {
return c.mediaEndpoint
}
return c.endpoint
}
// getMediaSoapClient creates a new SOAP client for media operations.
func (c *Client) getMediaSoapClient() *soap.Client {
username, password := c.GetCredentials()
return soap.NewClient(c.httpClient, username, password)
}
// GetProfiles retrieves all media profiles // GetProfiles retrieves all media profiles
func (c *Client) GetProfiles(ctx context.Context) ([]*Profile, error) { func (c *Client) GetProfiles(ctx context.Context) ([]*Profile, error) {
endpoint := c.mediaEndpoint endpoint := c.mediaEndpoint
@@ -2046,13 +2060,8 @@ func (c *Client) GetMetadataConfigurationOptions(ctx context.Context, configurat
} }
// GetAudioOutputConfiguration retrieves audio output configuration // GetAudioOutputConfiguration retrieves audio output configuration
//
//nolint:dupl // Similar structure to GetAudioSourceConfiguration but different types and operations
func (c *Client) GetAudioOutputConfiguration(ctx context.Context, configurationToken string) (*AudioOutputConfiguration, error) { func (c *Client) GetAudioOutputConfiguration(ctx context.Context, configurationToken string) (*AudioOutputConfiguration, error) {
endpoint := c.mediaEndpoint endpoint := c.getMediaEndpoint()
if endpoint == "" {
endpoint = c.endpoint
}
type GetAudioOutputConfiguration struct { type GetAudioOutputConfiguration struct {
XMLName xml.Name `xml:"trt:GetAudioOutputConfiguration"` XMLName xml.Name `xml:"trt:GetAudioOutputConfiguration"`
@@ -2076,9 +2085,7 @@ func (c *Client) GetAudioOutputConfiguration(ctx context.Context, configurationT
} }
var resp GetAudioOutputConfigurationResponse var resp GetAudioOutputConfigurationResponse
soapClient := c.getMediaSoapClient()
username, password := c.GetCredentials()
soapClient := soap.NewClient(c.httpClient, username, password)
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil { if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
return nil, fmt.Errorf("GetAudioOutputConfiguration failed: %w", err) return nil, fmt.Errorf("GetAudioOutputConfiguration failed: %w", err)
@@ -2703,10 +2710,7 @@ func (c *Client) GetVideoSourceConfiguration(ctx context.Context, configurationT
// GetAudioSourceConfiguration retrieves a specific audio source configuration // GetAudioSourceConfiguration retrieves a specific audio source configuration
func (c *Client) GetAudioSourceConfiguration(ctx context.Context, configurationToken string) (*AudioSourceConfiguration, error) { func (c *Client) GetAudioSourceConfiguration(ctx context.Context, configurationToken string) (*AudioSourceConfiguration, error) {
endpoint := c.mediaEndpoint endpoint := c.getMediaEndpoint()
if endpoint == "" {
endpoint = c.endpoint
}
type GetAudioSourceConfiguration struct { type GetAudioSourceConfiguration struct {
XMLName xml.Name `xml:"trt:GetAudioSourceConfiguration"` XMLName xml.Name `xml:"trt:GetAudioSourceConfiguration"`
@@ -2730,9 +2734,7 @@ func (c *Client) GetAudioSourceConfiguration(ctx context.Context, configurationT
} }
var resp GetAudioSourceConfigurationResponse var resp GetAudioSourceConfigurationResponse
soapClient := c.getMediaSoapClient()
username, password := c.GetCredentials()
soapClient := soap.NewClient(c.httpClient, username, password)
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil { if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
return nil, fmt.Errorf("GetAudioSourceConfiguration failed: %w", err) return nil, fmt.Errorf("GetAudioSourceConfiguration failed: %w", err)
+1 -2
View File
@@ -35,7 +35,7 @@ func TestGetProfiles(t *testing.T) {
})) }))
defer server.Close() defer server.Close()
client, err := NewClient(server.URL+"/onvif/media_service") client, err := NewClient(server.URL + "/onvif/media_service")
if err != nil { if err != nil {
t.Fatalf("NewClient() failed: %v", err) t.Fatalf("NewClient() failed: %v", err)
} }
@@ -1487,4 +1487,3 @@ func TestGetOSDOptions(t *testing.T) {
t.Errorf("Expected MaximumNumberOfOSDs 10, got %d", options.MaximumNumberOfOSDs) t.Errorf("Expected MaximumNumberOfOSDs 10, got %d", options.MaximumNumberOfOSDs)
} }
} }
+9 -9
View File
@@ -20,9 +20,9 @@ func TestHandleGetDeviceInformation(t *testing.T) {
} }
tests := []struct { tests := []struct {
name string name string
got string got string
want string want string
}{ }{
{"Manufacturer", deviceResp.Manufacturer, config.DeviceInfo.Manufacturer}, {"Manufacturer", deviceResp.Manufacturer, config.DeviceInfo.Manufacturer},
{"Model", deviceResp.Model, config.DeviceInfo.Model}, {"Model", deviceResp.Model, config.DeviceInfo.Model},
@@ -206,8 +206,8 @@ func TestCapabilitiesStructure(t *testing.T) {
XAddr: "http://localhost:8080/onvif/media_service", XAddr: "http://localhost:8080/onvif/media_service",
StreamingCapabilities: &StreamingCapabilities{ StreamingCapabilities: &StreamingCapabilities{
RTPMulticast: true, RTPMulticast: true,
RTP_TCP: true, RTP_TCP: true,
RTP_RTSP_TCP: true, RTP_RTSP_TCP: true,
}, },
}, },
} }
@@ -236,8 +236,8 @@ func TestMediaCapabilitiesStructure(t *testing.T) {
XAddr: "http://localhost:8080/onvif/media_service", XAddr: "http://localhost:8080/onvif/media_service",
StreamingCapabilities: &StreamingCapabilities{ StreamingCapabilities: &StreamingCapabilities{
RTPMulticast: true, RTPMulticast: true,
RTP_TCP: true, RTP_TCP: true,
RTP_RTSP_TCP: true, RTP_RTSP_TCP: true,
}, },
} }
@@ -362,8 +362,8 @@ func TestGetCapabilitiesResponse(t *testing.T) {
XAddr: "http://localhost:8080/media", XAddr: "http://localhost:8080/media",
StreamingCapabilities: &StreamingCapabilities{ StreamingCapabilities: &StreamingCapabilities{
RTPMulticast: true, RTPMulticast: true,
RTP_TCP: true, RTP_TCP: true,
RTP_RTSP_TCP: true, RTP_RTSP_TCP: true,
}, },
}, },
} }
+38 -38
View File
@@ -217,28 +217,28 @@ func TestImagingSettings(t *testing.T) {
func TestBacklightCompensation(t *testing.T) { func TestBacklightCompensation(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
comp BacklightCompensation comp BacklightCompensation
expectValid bool expectValid bool
}{ }{
{ {
name: "Backlight ON", name: "Backlight ON",
comp: BacklightCompensation{Mode: "ON", Level: 50}, comp: BacklightCompensation{Mode: "ON", Level: 50},
expectValid: true, expectValid: true,
}, },
{ {
name: "Backlight OFF", name: "Backlight OFF",
comp: BacklightCompensation{Mode: "OFF", Level: 0}, comp: BacklightCompensation{Mode: "OFF", Level: 0},
expectValid: true, expectValid: true,
}, },
{ {
name: "Invalid mode", name: "Invalid mode",
comp: BacklightCompensation{Mode: "INVALID", Level: 50}, comp: BacklightCompensation{Mode: "INVALID", Level: 50},
expectValid: false, expectValid: false,
}, },
{ {
name: "Level out of range", name: "Level out of range",
comp: BacklightCompensation{Mode: "ON", Level: 150}, comp: BacklightCompensation{Mode: "ON", Level: 150},
expectValid: false, expectValid: false,
}, },
} }
@@ -256,27 +256,27 @@ func TestBacklightCompensation(t *testing.T) {
func TestExposureSettings(t *testing.T) { func TestExposureSettings(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
exposure ExposureSettings exposure ExposureSettings
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid AUTO exposure", name: "Valid AUTO exposure",
exposure: ExposureSettings{ exposure: ExposureSettings{
Mode: "AUTO", Mode: "AUTO",
Priority: "FrameRate", Priority: "FrameRate",
MinExposure: 1, MinExposure: 1,
MaxExposure: 10000, MaxExposure: 10000,
Gain: 50, Gain: 50,
}, },
expectValid: true, expectValid: true,
}, },
{ {
name: "Valid MANUAL exposure", name: "Valid MANUAL exposure",
exposure: ExposureSettings{ exposure: ExposureSettings{
Mode: "MANUAL", Mode: "MANUAL",
ExposureTime: 100, ExposureTime: 100,
Gain: 50, Gain: 50,
}, },
expectValid: true, expectValid: true,
}, },
@@ -301,17 +301,17 @@ func TestExposureSettings(t *testing.T) {
func TestFocusSettings(t *testing.T) { func TestFocusSettings(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
focus FocusSettings focus FocusSettings
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid AUTO focus", name: "Valid AUTO focus",
focus: FocusSettings{ focus: FocusSettings{
AutoFocusMode: "AUTO", AutoFocusMode: "AUTO",
DefaultSpeed: 0.5, DefaultSpeed: 0.5,
NearLimit: 0, NearLimit: 0,
FarLimit: 1, FarLimit: 1,
}, },
expectValid: true, expectValid: true,
}, },
@@ -319,8 +319,8 @@ func TestFocusSettings(t *testing.T) {
name: "Valid MANUAL focus", name: "Valid MANUAL focus",
focus: FocusSettings{ focus: FocusSettings{
AutoFocusMode: "MANUAL", AutoFocusMode: "MANUAL",
DefaultSpeed: 0.5, DefaultSpeed: 0.5,
CurrentPos: 0.5, CurrentPos: 0.5,
}, },
expectValid: true, expectValid: true,
}, },
@@ -345,14 +345,14 @@ func TestFocusSettings(t *testing.T) {
func TestWhiteBalanceSettings(t *testing.T) { func TestWhiteBalanceSettings(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
whiteBalance WhiteBalanceSettings whiteBalance WhiteBalanceSettings
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid AUTO white balance", name: "Valid AUTO white balance",
whiteBalance: WhiteBalanceSettings{ whiteBalance: WhiteBalanceSettings{
Mode: "AUTO", Mode: "AUTO",
CrGain: 128, CrGain: 128,
CbGain: 128, CbGain: 128,
}, },
@@ -361,7 +361,7 @@ func TestWhiteBalanceSettings(t *testing.T) {
{ {
name: "Valid MANUAL white balance", name: "Valid MANUAL white balance",
whiteBalance: WhiteBalanceSettings{ whiteBalance: WhiteBalanceSettings{
Mode: "MANUAL", Mode: "MANUAL",
CrGain: 100, CrGain: 100,
CbGain: 120, CbGain: 120,
}, },
@@ -370,7 +370,7 @@ func TestWhiteBalanceSettings(t *testing.T) {
{ {
name: "Gain out of range", name: "Gain out of range",
whiteBalance: WhiteBalanceSettings{ whiteBalance: WhiteBalanceSettings{
Mode: "AUTO", Mode: "AUTO",
CrGain: 300, CrGain: 300,
CbGain: 128, CbGain: 128,
}, },
@@ -393,23 +393,23 @@ func TestWhiteBalanceSettings(t *testing.T) {
func TestWideDynamicRange(t *testing.T) { func TestWideDynamicRange(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
wdr WDRSettings wdr WDRSettings
expectValid bool expectValid bool
}{ }{
{ {
name: "WDR ON", name: "WDR ON",
wdr: WDRSettings{Mode: "ON", Level: 50}, wdr: WDRSettings{Mode: "ON", Level: 50},
expectValid: true, expectValid: true,
}, },
{ {
name: "WDR OFF", name: "WDR OFF",
wdr: WDRSettings{Mode: "OFF", Level: 0}, wdr: WDRSettings{Mode: "OFF", Level: 0},
expectValid: true, expectValid: true,
}, },
{ {
name: "Invalid mode", name: "Invalid mode",
wdr: WDRSettings{Mode: "INVALID", Level: 50}, wdr: WDRSettings{Mode: "INVALID", Level: 50},
expectValid: false, expectValid: false,
}, },
} }
@@ -509,7 +509,7 @@ func TestSetImagingSettingsEdgeCases(t *testing.T) {
} }
resp, err := server.HandleSetImagingSettings(&setReq) resp, err := server.HandleSetImagingSettings(&setReq)
if err == nil && resp != nil { if err == nil && resp != nil {
t.Logf("SetImagingSettings with nil settings succeeded") t.Logf("SetImagingSettings with nil settings succeeded")
} }
+27 -27
View File
@@ -174,9 +174,9 @@ func TestVideoEncoderConfigurationStructure(t *testing.T) {
Quality: 80, Quality: 80,
Resolution: VideoResolution{Width: 1920, Height: 1080}, Resolution: VideoResolution{Width: 1920, Height: 1080},
RateControl: &VideoRateControl{ RateControl: &VideoRateControl{
FrameRateLimit: 30, FrameRateLimit: 30,
EncodingInterval: 1, EncodingInterval: 1,
BitrateLimit: 2048, BitrateLimit: 2048,
}, },
} }
@@ -225,28 +225,28 @@ func TestGetProfilesResponseXML(t *testing.T) {
func TestIntRectangle(t *testing.T) { func TestIntRectangle(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
rect IntRectangle rect IntRectangle
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid rectangle", name: "Valid rectangle",
rect: IntRectangle{X: 0, Y: 0, Width: 100, Height: 100}, rect: IntRectangle{X: 0, Y: 0, Width: 100, Height: 100},
expectValid: true, expectValid: true,
}, },
{ {
name: "Zero width", name: "Zero width",
rect: IntRectangle{X: 0, Y: 0, Width: 0, Height: 100}, rect: IntRectangle{X: 0, Y: 0, Width: 0, Height: 100},
expectValid: false, expectValid: false,
}, },
{ {
name: "Zero height", name: "Zero height",
rect: IntRectangle{X: 0, Y: 0, Width: 100, Height: 0}, rect: IntRectangle{X: 0, Y: 0, Width: 100, Height: 0},
expectValid: false, expectValid: false,
}, },
{ {
name: "Negative dimensions", name: "Negative dimensions",
rect: IntRectangle{X: -10, Y: -10, Width: 100, Height: 100}, rect: IntRectangle{X: -10, Y: -10, Width: 100, Height: 100},
expectValid: true, // Negative coordinates may be valid expectValid: true, // Negative coordinates may be valid
}, },
} }
@@ -263,33 +263,33 @@ func TestIntRectangle(t *testing.T) {
func TestVideoResolution(t *testing.T) { func TestVideoResolution(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
resolution VideoResolution resolution VideoResolution
expectValid bool expectValid bool
}{ }{
{ {
name: "1080p", name: "1080p",
resolution: VideoResolution{Width: 1920, Height: 1080}, resolution: VideoResolution{Width: 1920, Height: 1080},
expectValid: true, expectValid: true,
}, },
{ {
name: "720p", name: "720p",
resolution: VideoResolution{Width: 1280, Height: 720}, resolution: VideoResolution{Width: 1280, Height: 720},
expectValid: true, expectValid: true,
}, },
{ {
name: "VGA", name: "VGA",
resolution: VideoResolution{Width: 640, Height: 480}, resolution: VideoResolution{Width: 640, Height: 480},
expectValid: true, expectValid: true,
}, },
{ {
name: "4K", name: "4K",
resolution: VideoResolution{Width: 3840, Height: 2160}, resolution: VideoResolution{Width: 3840, Height: 2160},
expectValid: true, expectValid: true,
}, },
{ {
name: "Zero width", name: "Zero width",
resolution: VideoResolution{Width: 0, Height: 1080}, resolution: VideoResolution{Width: 0, Height: 1080},
expectValid: false, expectValid: false,
}, },
} }
@@ -306,9 +306,9 @@ func TestVideoResolution(t *testing.T) {
func TestMulticastConfiguration(t *testing.T) { func TestMulticastConfiguration(t *testing.T) {
cfg := MulticastConfiguration{ cfg := MulticastConfiguration{
Address: IPAddress{IPv4Address: "239.255.255.250"}, Address: IPAddress{IPv4Address: "239.255.255.250"},
Port: 1900, Port: 1900,
TTL: 128, TTL: 128,
AutoStart: true, AutoStart: true,
} }
+20 -20
View File
@@ -265,28 +265,28 @@ func _DisabledTestHandleStop(t *testing.T) {
func TestPTZPosition(t *testing.T) { func TestPTZPosition(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
position PTZPosition position PTZPosition
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid center position", name: "Valid center position",
position: PTZPosition{Pan: 0, Tilt: 0, Zoom: 0}, position: PTZPosition{Pan: 0, Tilt: 0, Zoom: 0},
expectValid: true, expectValid: true,
}, },
{ {
name: "Position with pan", name: "Position with pan",
position: PTZPosition{Pan: 45, Tilt: 0, Zoom: 0}, position: PTZPosition{Pan: 45, Tilt: 0, Zoom: 0},
expectValid: true, expectValid: true,
}, },
{ {
name: "Position with zoom", name: "Position with zoom",
position: PTZPosition{Pan: 0, Tilt: 0, Zoom: 5}, position: PTZPosition{Pan: 0, Tilt: 0, Zoom: 5},
expectValid: true, expectValid: true,
}, },
{ {
name: "Full position", name: "Full position",
position: PTZPosition{Pan: 180, Tilt: 45, Zoom: 10}, position: PTZPosition{Pan: 180, Tilt: 45, Zoom: 10},
expectValid: true, expectValid: true,
}, },
} }
@@ -328,23 +328,23 @@ func TestPTZSpeed(t *testing.T) {
tilt := 0.5 tilt := 0.5
zoom := 0.5 zoom := 0.5
tests := []struct { tests := []struct {
name string name string
speed PTZVector speed PTZVector
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid speed", name: "Valid speed",
speed: PTZVector{PanTilt: &Vector2D{X: pan, Y: tilt}, Zoom: &Vector1D{X: zoom}}, speed: PTZVector{PanTilt: &Vector2D{X: pan, Y: tilt}, Zoom: &Vector1D{X: zoom}},
expectValid: true, expectValid: true,
}, },
{ {
name: "High speed", name: "High speed",
speed: PTZVector{PanTilt: &Vector2D{X: 1.0, Y: 1.0}, Zoom: &Vector1D{X: 1.0}}, speed: PTZVector{PanTilt: &Vector2D{X: 1.0, Y: 1.0}, Zoom: &Vector1D{X: 1.0}},
expectValid: true, expectValid: true,
}, },
{ {
name: "Zero speed", name: "Zero speed",
speed: PTZVector{PanTilt: &Vector2D{X: 0, Y: 0}, Zoom: &Vector1D{X: 0}}, speed: PTZVector{PanTilt: &Vector2D{X: 0, Y: 0}, Zoom: &Vector1D{X: 0}},
expectValid: true, expectValid: true,
}, },
} }
@@ -438,7 +438,7 @@ func TestPTZMovementOperations(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
resp, err := tt.handler([]byte(tt.reqXML)) resp, err := tt.handler([]byte(tt.reqXML))
// These may fail due to XML namespace issues, but we're testing the handler exists // These may fail due to XML namespace issues, but we're testing the handler exists
if resp == nil && err == nil { if resp == nil && err == nil {
t.Logf("%s: got nil response and nil error", tt.name) t.Logf("%s: got nil response and nil error", tt.name)
@@ -501,7 +501,7 @@ func TestPTZStateTransitions(t *testing.T) {
// Verify position can be updated // Verify position can be updated
ptzState.LastUpdate = time.Now() ptzState.LastUpdate = time.Now()
updatedState, _ := server.GetPTZState(profileToken) updatedState, _ := server.GetPTZState(profileToken)
if updatedState == nil { if updatedState == nil {
t.Fatal("Updated PTZ state is nil") t.Fatal("Updated PTZ state is nil")
+5 -5
View File
@@ -271,9 +271,9 @@ func TestGetImagingState(t *testing.T) {
videoSourceToken := config.Profiles[0].VideoSource.Token videoSourceToken := config.Profiles[0].VideoSource.Token
tests := []struct { tests := []struct {
name string name string
token string token string
expectOk bool expectOk bool
checkFunc func(*ImagingState) error checkFunc func(*ImagingState) error
}{ }{
{ {
@@ -436,11 +436,11 @@ func TestServerInfoMethod(t *testing.T) {
server, _ := New(config) server, _ := New(config)
info := server.ServerInfo() info := server.ServerInfo()
if info == "" { if info == "" {
t.Fatal("ServerInfo() returned empty string") t.Fatal("ServerInfo() returned empty string")
} }
// ServerInfo returns a formatted string with server information // ServerInfo returns a formatted string with server information
if !strings.Contains(info, "127.0.0.1") && !strings.Contains(info, "localhost") { if !strings.Contains(info, "127.0.0.1") && !strings.Contains(info, "localhost") {
t.Logf("ServerInfo may not contain host: %s", info) t.Logf("ServerInfo may not contain host: %s", info)
+2 -2
View File
@@ -125,8 +125,8 @@ func TestExtractAction(t *testing.T) {
handler := NewHandler("", "") handler := NewHandler("", "")
tests := []struct { tests := []struct {
name string name string
soapBody string soapBody string
expectedAction string expectedAction string
}{ }{
{ {
+57 -57
View File
@@ -10,7 +10,7 @@ func TestDefaultConfig(t *testing.T) {
config := DefaultConfig() config := DefaultConfig()
tests := []struct { tests := []struct {
name string name string
checkFunc func(*Config) error checkFunc func(*Config) error
}{ }{
{ {
@@ -131,28 +131,28 @@ func TestDefaultConfig(t *testing.T) {
func TestResolution(t *testing.T) { func TestResolution(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
resolution Resolution resolution Resolution
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid resolution 1920x1080", name: "Valid resolution 1920x1080",
resolution: Resolution{Width: 1920, Height: 1080}, resolution: Resolution{Width: 1920, Height: 1080},
expectValid: true, expectValid: true,
}, },
{ {
name: "Valid resolution 640x480", name: "Valid resolution 640x480",
resolution: Resolution{Width: 640, Height: 480}, resolution: Resolution{Width: 640, Height: 480},
expectValid: true, expectValid: true,
}, },
{ {
name: "Zero width", name: "Zero width",
resolution: Resolution{Width: 0, Height: 1080}, resolution: Resolution{Width: 0, Height: 1080},
expectValid: false, expectValid: false,
}, },
{ {
name: "Zero height", name: "Zero height",
resolution: Resolution{Width: 1920, Height: 0}, resolution: Resolution{Width: 1920, Height: 0},
expectValid: false, expectValid: false,
}, },
} }
@@ -160,7 +160,7 @@ func TestResolution(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if (tt.resolution.Width > 0 && tt.resolution.Height > 0) != tt.expectValid { if (tt.resolution.Width > 0 && tt.resolution.Height > 0) != tt.expectValid {
t.Errorf("Resolution validation failed: Width=%d, Height=%d", t.Errorf("Resolution validation failed: Width=%d, Height=%d",
tt.resolution.Width, tt.resolution.Height) tt.resolution.Width, tt.resolution.Height)
} }
}) })
@@ -219,23 +219,23 @@ func TestRange(t *testing.T) {
func TestBounds(t *testing.T) { func TestBounds(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
bounds Bounds bounds Bounds
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid bounds", name: "Valid bounds",
bounds: Bounds{X: 0, Y: 0, Width: 1920, Height: 1080}, bounds: Bounds{X: 0, Y: 0, Width: 1920, Height: 1080},
expectValid: true, expectValid: true,
}, },
{ {
name: "Zero width", name: "Zero width",
bounds: Bounds{X: 0, Y: 0, Width: 0, Height: 1080}, bounds: Bounds{X: 0, Y: 0, Width: 0, Height: 1080},
expectValid: false, expectValid: false,
}, },
{ {
name: "Negative coordinates", name: "Negative coordinates",
bounds: Bounds{X: -10, Y: -10, Width: 1920, Height: 1080}, bounds: Bounds{X: -10, Y: -10, Width: 1920, Height: 1080},
expectValid: true, // Negative coordinates may be valid in some cases expectValid: true, // Negative coordinates may be valid in some cases
}, },
} }
@@ -252,8 +252,8 @@ func TestBounds(t *testing.T) {
func TestPreset(t *testing.T) { func TestPreset(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
preset Preset preset Preset
expectValid bool expectValid bool
}{ }{
{ {
@@ -277,7 +277,7 @@ func TestPreset(t *testing.T) {
name: "Preset with empty name", name: "Preset with empty name",
preset: Preset{ preset: Preset{
Token: "preset_1", Token: "preset_1",
Name: "", Name: "",
}, },
expectValid: false, expectValid: false,
}, },
@@ -287,7 +287,7 @@ func TestPreset(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
isValid := tt.preset.Token != "" && tt.preset.Name != "" isValid := tt.preset.Token != "" && tt.preset.Name != ""
if isValid != tt.expectValid { if isValid != tt.expectValid {
t.Errorf("Preset validation failed: Token=%s, Name=%s", t.Errorf("Preset validation failed: Token=%s, Name=%s",
tt.preset.Token, tt.preset.Name) tt.preset.Token, tt.preset.Name)
} }
}) })
@@ -346,9 +346,9 @@ func TestPTZConfig(t *testing.T) {
func TestVideoEncoderConfig(t *testing.T) { func TestVideoEncoderConfig(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
encoderConfig VideoEncoderConfig encoderConfig VideoEncoderConfig
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid H264 encoder", name: "Valid H264 encoder",
@@ -406,7 +406,7 @@ func TestVideoEncoderConfig(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
isValid := tt.encoderConfig.Encoding != "" && isValid := tt.encoderConfig.Encoding != "" &&
tt.encoderConfig.Quality >= 0 && tt.encoderConfig.Quality <= 100 && tt.encoderConfig.Quality >= 0 && tt.encoderConfig.Quality <= 100 &&
tt.encoderConfig.Resolution.Width > 0 && tt.encoderConfig.Resolution.Height > 0 tt.encoderConfig.Resolution.Width > 0 && tt.encoderConfig.Resolution.Height > 0
if isValid != tt.expectValid { if isValid != tt.expectValid {
@@ -418,9 +418,9 @@ func TestVideoEncoderConfig(t *testing.T) {
func TestProfileConfig(t *testing.T) { func TestProfileConfig(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
profileConfig ProfileConfig profileConfig ProfileConfig
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid profile config", name: "Valid profile config",
@@ -475,7 +475,7 @@ func TestSnapshotConfig(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
snapshotConfig SnapshotConfig snapshotConfig SnapshotConfig
expectValid bool expectValid bool
}{ }{
{ {
name: "Valid snapshot config", name: "Valid snapshot config",
@@ -509,7 +509,7 @@ func TestSnapshotConfig(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Snapshot config is valid if it has resolution and quality when enabled // Snapshot config is valid if it has resolution and quality when enabled
isValid := !tt.snapshotConfig.Enabled || isValid := !tt.snapshotConfig.Enabled ||
(tt.snapshotConfig.Resolution.Width > 0 && tt.snapshotConfig.Resolution.Height > 0) (tt.snapshotConfig.Resolution.Width > 0 && tt.snapshotConfig.Resolution.Height > 0)
if isValid != tt.expectValid { if isValid != tt.expectValid {
t.Errorf("Snapshot validation failed: Enabled=%v, Resolution=%dx%d", t.Errorf("Snapshot validation failed: Enabled=%v, Resolution=%dx%d",
@@ -545,10 +545,10 @@ func TestServiceEndpoints(t *testing.T) {
{ {
name: "Default endpoints", name: "Default endpoints",
config: &Config{ config: &Config{
Host: "192.168.1.100", Host: "192.168.1.100",
Port: 8080, Port: 8080,
BasePath: "/onvif", BasePath: "/onvif",
SupportPTZ: true, SupportPTZ: true,
SupportEvents: true, SupportEvents: true,
}, },
host: "", host: "",
@@ -557,10 +557,10 @@ func TestServiceEndpoints(t *testing.T) {
{ {
name: "Custom host", name: "Custom host",
config: &Config{ config: &Config{
Host: "192.168.1.100", Host: "192.168.1.100",
Port: 8080, Port: 8080,
BasePath: "/onvif", BasePath: "/onvif",
SupportPTZ: false, SupportPTZ: false,
SupportEvents: false, SupportEvents: false,
}, },
host: "custom.example.com", host: "custom.example.com",
@@ -569,9 +569,9 @@ func TestServiceEndpoints(t *testing.T) {
{ {
name: "Port 80", name: "Port 80",
config: &Config{ config: &Config{
Host: "localhost", Host: "localhost",
Port: 80, Port: 80,
BasePath: "/onvif", BasePath: "/onvif",
SupportPTZ: true, SupportPTZ: true,
}, },
host: "", host: "",
@@ -602,7 +602,7 @@ func TestServiceEndpoints(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
endpoints := tt.config.ServiceEndpoints(tt.host) endpoints := tt.config.ServiceEndpoints(tt.host)
for _, svc := range tt.expectServices { for _, svc := range tt.expectServices {
if _, ok := endpoints[svc]; !ok { if _, ok := endpoints[svc]; !ok {
t.Errorf("Missing endpoint: %s", svc) t.Errorf("Missing endpoint: %s", svc)
@@ -621,15 +621,15 @@ func TestServiceEndpoints(t *testing.T) {
func TestServiceEndpointsURL(t *testing.T) { func TestServiceEndpointsURL(t *testing.T) {
config := &Config{ config := &Config{
Host: "example.com", Host: "example.com",
Port: 9000, Port: 9000,
BasePath: "/services", BasePath: "/services",
SupportPTZ: true, SupportPTZ: true,
SupportEvents: true, SupportEvents: true,
} }
endpoints := config.ServiceEndpoints("example.com") endpoints := config.ServiceEndpoints("example.com")
expectedDeviceURL := "http://example.com:9000/services/device_service" expectedDeviceURL := "http://example.com:9000/services/device_service"
if endpoints["device"] != expectedDeviceURL { if endpoints["device"] != expectedDeviceURL {
t.Errorf("Device endpoint mismatch: got %s, want %s", endpoints["device"], expectedDeviceURL) t.Errorf("Device endpoint mismatch: got %s, want %s", endpoints["device"], expectedDeviceURL)
@@ -639,27 +639,27 @@ func TestServiceEndpointsURL(t *testing.T) {
func TestToONVIFProfile(t *testing.T) { func TestToONVIFProfile(t *testing.T) {
profile := &ProfileConfig{ profile := &ProfileConfig{
Token: "profile_1", Token: "profile_1",
Name: "HD Profile", Name: "HD Profile",
VideoSource: VideoSourceConfig{ VideoSource: VideoSourceConfig{
Token: "source_1", Token: "source_1",
Framerate: 30, Framerate: 30,
Resolution: Resolution{Width: 1920, Height: 1080}, Resolution: Resolution{Width: 1920, Height: 1080},
}, },
VideoEncoder: VideoEncoderConfig{ VideoEncoder: VideoEncoderConfig{
Encoding: "H264", Encoding: "H264",
Bitrate: 4096, Bitrate: 4096,
Framerate: 30, Framerate: 30,
Resolution: Resolution{Width: 1920, Height: 1080}, Resolution: Resolution{Width: 1920, Height: 1080},
}, },
Snapshot: SnapshotConfig{ Snapshot: SnapshotConfig{
Enabled: true, Enabled: true,
Resolution: Resolution{Width: 1920, Height: 1080}, Resolution: Resolution{Width: 1920, Height: 1080},
Quality: 85.0, Quality: 85.0,
}, },
} }
onvifProfile := profile.ToONVIFProfile() onvifProfile := profile.ToONVIFProfile()
if onvifProfile.Token != "profile_1" { if onvifProfile.Token != "profile_1" {
t.Errorf("Profile token mismatch: got %s", onvifProfile.Token) t.Errorf("Profile token mismatch: got %s", onvifProfile.Token)
} }