Skip to content

Commit fe8fafb

Browse files
committed
test: extend cloud, config, and image package test coverage
- cloud: Add CloudsYamlPaths tests, invalid/empty YAML, precedence verification (8 new tests covering path resolution, invalid YAML, detailed clouds.yaml parsing) - config: Add edge case tests for empty/malformed files, partial configs, SaveTo directory creation, keybinding merging, round-trip verification (10 new tests covering validation, merge behavior, partial config handling) - image: Add ProgressReader tests (concurrent access, large data, empty reader) and imageFromGophercloud conversion tests (empty, queued, visibility modes) (12 new tests) Total: 30 new tests, all passing. Test file count: 22 → 23. Packages tested expanded from 15 → 16 (added internal/image).
1 parent 49ba645 commit fe8fafb

File tree

3 files changed

+636
-0
lines changed

3 files changed

+636
-0
lines changed

src/internal/cloud/clouds_test.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cloud
33
import (
44
"os"
55
"path/filepath"
6+
"strings"
67
"testing"
78
)
89

@@ -79,3 +80,186 @@ func TestListCloudNames_NoFile(t *testing.T) {
7980
t.Error("expected error when no clouds.yaml exists")
8081
}
8182
}
83+
84+
func TestCloudsYamlPaths_Order(t *testing.T) {
85+
t.Setenv("OS_CLIENT_CONFIG_FILE", "/custom/path/clouds.yaml")
86+
paths := CloudsYamlPaths()
87+
88+
// First path should always be relative clouds.yaml
89+
if paths[0] != "clouds.yaml" {
90+
t.Errorf("first path should be 'clouds.yaml', got %s", paths[0])
91+
}
92+
93+
// Second path should be OS_CLIENT_CONFIG_FILE (when set)
94+
if paths[1] != "/custom/path/clouds.yaml" {
95+
t.Errorf("second path should be OS_CLIENT_CONFIG_FILE, got %s", paths[1])
96+
}
97+
98+
// Last path should be the system-wide path
99+
if paths[len(paths)-1] != "/etc/openstack/clouds.yaml" {
100+
t.Errorf("last path should be /etc/openstack/clouds.yaml, got %s", paths[len(paths)-1])
101+
}
102+
}
103+
104+
func TestCloudsYamlPaths_WithoutEnv(t *testing.T) {
105+
// Ensure OS_CLIENT_CONFIG_FILE is not set
106+
t.Setenv("OS_CLIENT_CONFIG_FILE", "")
107+
paths := CloudsYamlPaths()
108+
109+
// Should have 3 paths: relative, home, system
110+
if len(paths) != 3 {
111+
t.Errorf("expected 3 paths without env, got %d: %v", len(paths), paths)
112+
}
113+
114+
if paths[0] != "clouds.yaml" {
115+
t.Errorf("first path should be 'clouds.yaml', got %s", paths[0])
116+
}
117+
}
118+
119+
func TestCloudsYamlPaths_WithEnv(t *testing.T) {
120+
t.Setenv("OS_CLIENT_CONFIG_FILE", "/my/custom/clouds.yaml")
121+
paths := CloudsYamlPaths()
122+
123+
// Should have 4 paths: relative, env, home, system
124+
if len(paths) != 4 {
125+
t.Errorf("expected 4 paths with env, got %d: %v", len(paths), paths)
126+
}
127+
128+
if paths[1] != "/my/custom/clouds.yaml" {
129+
t.Errorf("second path should be env path, got %s", paths[1])
130+
}
131+
}
132+
133+
func TestListCloudNames_InvalidYAML(t *testing.T) {
134+
dir := t.TempDir()
135+
content := `clouds:
136+
bad:
137+
[invalid yaml {{{
138+
`
139+
path := filepath.Join(dir, "clouds.yaml")
140+
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
141+
t.Fatal(err)
142+
}
143+
144+
t.Setenv("OS_CLIENT_CONFIG_FILE", path)
145+
146+
_, err := ListCloudNames()
147+
if err == nil {
148+
t.Error("expected error for invalid YAML")
149+
}
150+
if !strings.Contains(err.Error(), "parsing") {
151+
t.Errorf("error should mention parsing, got: %v", err)
152+
}
153+
}
154+
155+
func TestListCloudNames_NoCloudsKey(t *testing.T) {
156+
dir := t.TempDir()
157+
content := `not_clouds:
158+
foo: bar
159+
`
160+
path := filepath.Join(dir, "clouds.yaml")
161+
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
162+
t.Fatal(err)
163+
}
164+
165+
t.Setenv("OS_CLIENT_CONFIG_FILE", path)
166+
167+
names, err := ListCloudNames()
168+
if err != nil {
169+
t.Fatalf("unexpected error: %v", err)
170+
}
171+
// Missing 'clouds' key means empty map, so 0 names
172+
if len(names) != 0 {
173+
t.Errorf("expected 0 clouds when 'clouds' key is missing, got %d", len(names))
174+
}
175+
}
176+
177+
func TestListCloudNames_EmptyFile(t *testing.T) {
178+
dir := t.TempDir()
179+
path := filepath.Join(dir, "clouds.yaml")
180+
if err := os.WriteFile(path, []byte(""), 0644); err != nil {
181+
t.Fatal(err)
182+
}
183+
184+
t.Setenv("OS_CLIENT_CONFIG_FILE", path)
185+
186+
names, err := ListCloudNames()
187+
if err != nil {
188+
t.Fatalf("unexpected error: %v", err)
189+
}
190+
if len(names) != 0 {
191+
t.Errorf("expected 0 clouds for empty file, got %d", len(names))
192+
}
193+
}
194+
195+
func TestListCloudNames_Precedence(t *testing.T) {
196+
// When OS_CLIENT_CONFIG_FILE points to a valid file, it should be found
197+
// before the home path
198+
dir := t.TempDir()
199+
content := `clouds:
200+
env_cloud:
201+
auth:
202+
auth_url: https://env.example.com:5000
203+
`
204+
path := filepath.Join(dir, "clouds.yaml")
205+
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
206+
t.Fatal(err)
207+
}
208+
209+
t.Setenv("OS_CLIENT_CONFIG_FILE", path)
210+
t.Setenv("HOME", dir) // ensure home path doesn't interfere
211+
212+
names, err := ListCloudNames()
213+
if err != nil {
214+
t.Fatalf("unexpected error: %v", err)
215+
}
216+
217+
if len(names) != 1 || names[0] != "env_cloud" {
218+
t.Errorf("expected [env_cloud], got %v", names)
219+
}
220+
}
221+
222+
func TestListCloudNames_DetailedCloudsYaml(t *testing.T) {
223+
dir := t.TempDir()
224+
content := `clouds:
225+
production:
226+
auth:
227+
auth_url: https://keystone.prod.example.com:5000
228+
username: admin
229+
password: secret
230+
project_name: ops
231+
user_domain_name: Default
232+
project_domain_name: Default
233+
region_name: RegionOne
234+
interface: public
235+
development:
236+
auth:
237+
auth_url: https://keystone.dev.example.com:5000/v3
238+
username: developer
239+
project_name: dev-team
240+
region_name: RegionOne
241+
identity_api_version: "3"
242+
`
243+
path := filepath.Join(dir, "clouds.yaml")
244+
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
245+
t.Fatal(err)
246+
}
247+
248+
t.Setenv("OS_CLIENT_CONFIG_FILE", path)
249+
250+
names, err := ListCloudNames()
251+
if err != nil {
252+
t.Fatalf("unexpected error: %v", err)
253+
}
254+
255+
if len(names) != 2 {
256+
t.Fatalf("expected 2 clouds, got %d", len(names))
257+
}
258+
259+
expected := []string{"development", "production"}
260+
for i, name := range names {
261+
if name != expected[i] {
262+
t.Errorf("expected %s at index %d, got %s", expected[i], i, name)
263+
}
264+
}
265+
}

0 commit comments

Comments
 (0)