From f98ac5d0854b57e742ef104c60eeb1b3e3e4c1c0 Mon Sep 17 00:00:00 2001 From: Alain Kaeslin Date: Wed, 29 Apr 2026 07:01:26 +0200 Subject: [PATCH 1/4] test: add failing assertions for SourceVolume.Name and SourceVolume.HREF VolumeStub lacks Name and HREF fields, so the integration test cannot compile when referencing these fields from VolumeSnapshot.SourceVolume. --- test/integration/volume_snapshots_integration_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/integration/volume_snapshots_integration_test.go b/test/integration/volume_snapshots_integration_test.go index 000ffc4..2b290d0 100644 --- a/test/integration/volume_snapshots_integration_test.go +++ b/test/integration/volume_snapshots_integration_test.go @@ -53,6 +53,12 @@ func TestIntegrationVolumeSnapshot_CRUD(t *testing.T) { if retrieved.SourceVolume.UUID != volume.UUID { t.Errorf("Expected retrieved snapshot SourceVolume.UUID to be %s, got %q", volume.UUID, retrieved.SourceVolume.UUID) } + if retrieved.SourceVolume.Name != volume.Name { + t.Errorf("Expected SourceVolume.Name %q, got %q", volume.Name, retrieved.SourceVolume.Name) + } + if retrieved.SourceVolume.HREF == "" { + t.Error("Expected SourceVolume.HREF to be non-empty") + } snapshots, err := client.VolumeSnapshots.List(ctx) if err != nil { From ba44487aab773755f51f12f2919f487b59cf8631 Mon Sep 17 00:00:00 2001 From: Alain Kaeslin Date: Wed, 29 Apr 2026 07:02:22 +0200 Subject: [PATCH 2/4] feat: introduce SourceVolumeStub with HREF and Name for VolumeSnapshot.SourceVolume VolumeStub was structurally wrong for the source_volume context: the API returns only href/uuid/name there, while VolumeStub carries type/device_path/size_gb. The new SourceVolumeStub matches the actual API shape. --- volume_snapshots.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/volume_snapshots.go b/volume_snapshots.go index b654588..1cea82f 100644 --- a/volume_snapshots.go +++ b/volume_snapshots.go @@ -2,16 +2,22 @@ package cloudscale const volumeSnapshotsBasePath = "v1/volume-snapshots" +type SourceVolumeStub struct { + HREF string `json:"href"` + UUID string `json:"uuid"` + Name string `json:"name"` +} + type VolumeSnapshot struct { ZonalResource TaggedResource - HREF string `json:"href,omitempty"` - UUID string `json:"uuid,omitempty"` - Name string `json:"name,omitempty"` - SizeGB int `json:"size_gb,omitempty"` - CreatedAt string `json:"created_at,omitempty"` - SourceVolume VolumeStub `json:"source_volume,omitempty"` - Status string `json:"status,omitempty"` + HREF string `json:"href,omitempty"` + UUID string `json:"uuid,omitempty"` + Name string `json:"name,omitempty"` + SizeGB int `json:"size_gb,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + SourceVolume SourceVolumeStub `json:"source_volume,omitempty"` + Status string `json:"status,omitempty"` } type VolumeSnapshotCreateRequest struct { From 61d091fb3d7db5fd9909ce8ec81ef28f91162e0b Mon Sep 17 00:00:00 2001 From: Alain Kaeslin Date: Wed, 29 Apr 2026 07:14:38 +0200 Subject: [PATCH 3/4] test: add failing assertions for VolumeStub.HREF and VolumeStub.Name VolumeStub lacks HREF and Name fields, so the integration test cannot compile when checking these fields on Server.Volumes entries. --- test/integration/servers_integration_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/integration/servers_integration_test.go b/test/integration/servers_integration_test.go index e236db0..fcbe39e 100644 --- a/test/integration/servers_integration_test.go +++ b/test/integration/servers_integration_test.go @@ -352,6 +352,15 @@ func TestIntegrationServer_MultipleVolumes(t *testing.T) { t.Errorf("Volumes response\n got=%#v\nwant=%#v", actual, expected) } + for _, volume := range server.Volumes { + if volume.HREF == "" { + t.Errorf("Expected volume HREF to be non-empty for UUID %s", volume.UUID) + } + if volume.Name == "" { + t.Errorf("Expected volume Name to be non-empty for UUID %s", volume.UUID) + } + } + // delete all volume, except the root volume for _, volume := range server.Volumes[1:] { volumeUUID := volume.UUID From 5baf3f43ce39f72dfa7ba4491a2d3e921f3ab53b Mon Sep 17 00:00:00 2001 From: Alain Kaeslin Date: Wed, 29 Apr 2026 07:15:58 +0200 Subject: [PATCH 4/4] feat: fix VolumeStub to match actual API shape Add HREF and Name, remove DevicePath which the API does not return. Update the DeepEqual assertion in TestIntegrationServer_MultipleVolumes to zero out instance-specific fields before comparing. --- servers.go | 9 +++++---- test/integration/servers_integration_test.go | 10 ++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/servers.go b/servers.go index d55c8f5..c6667fd 100644 --- a/servers.go +++ b/servers.go @@ -58,10 +58,11 @@ type ImageServerStub struct { } type VolumeStub struct { - Type string `json:"type"` - DevicePath string `json:"device_path"` - SizeGB int `json:"size_gb"` - UUID string `json:"uuid"` + HREF string `json:"href"` + UUID string `json:"uuid"` + Name string `json:"name"` + Type string `json:"type"` + SizeGB int `json:"size_gb"` } type Interface struct { diff --git a/test/integration/servers_integration_test.go b/test/integration/servers_integration_test.go index fcbe39e..4e194a3 100644 --- a/test/integration/servers_integration_test.go +++ b/test/integration/servers_integration_test.go @@ -337,16 +337,18 @@ func TestIntegrationServer_MultipleVolumes(t *testing.T) { t.Fatalf("Servers.WaitFor returned error %s\n", err) } - // Ignore UUIDs in this comparison + // Ignore instance-specific fields in this comparison actual := make([]cloudscale.VolumeStub, len(server.Volumes)) copy(actual, server.Volumes) for i := range actual { actual[i].UUID = "" + actual[i].HREF = "" + actual[i].Name = "" } expected := []cloudscale.VolumeStub{ - {Type: "ssd", DevicePath: "", SizeGB: 10, UUID: ""}, - {Type: "ssd", DevicePath: "", SizeGB: 3, UUID: ""}, - {Type: "bulk", DevicePath: "", SizeGB: 100, UUID: ""}, + {Type: "ssd", SizeGB: 10}, + {Type: "ssd", SizeGB: 3}, + {Type: "bulk", SizeGB: 100}, } if !reflect.DeepEqual(actual, expected) { t.Errorf("Volumes response\n got=%#v\nwant=%#v", actual, expected)