github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/googlecompute/config_test.go (about) 1 package googlecompute 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "strings" 7 "testing" 8 ) 9 10 func TestConfigPrepare(t *testing.T) { 11 cases := []struct { 12 Key string 13 Value interface{} 14 Err bool 15 }{ 16 { 17 "unknown_key", 18 "bad", 19 true, 20 }, 21 22 { 23 "private_key_file", 24 "/tmp/i/should/not/exist", 25 true, 26 }, 27 28 { 29 "project_id", 30 nil, 31 true, 32 }, 33 { 34 "project_id", 35 "foo", 36 false, 37 }, 38 39 { 40 "source_image", 41 nil, 42 true, 43 }, 44 { 45 "source_image", 46 "foo", 47 false, 48 }, 49 50 { 51 "source_image_family", 52 nil, 53 false, 54 }, 55 { 56 "source_image_family", 57 "foo", 58 false, 59 }, 60 61 { 62 "zone", 63 nil, 64 true, 65 }, 66 { 67 "zone", 68 "foo", 69 false, 70 }, 71 72 { 73 "ssh_timeout", 74 "SO BAD", 75 true, 76 }, 77 { 78 "ssh_timeout", 79 "5s", 80 false, 81 }, 82 83 { 84 "state_timeout", 85 "SO BAD", 86 true, 87 }, 88 { 89 "state_timeout", 90 "5s", 91 false, 92 }, 93 { 94 "use_internal_ip", 95 nil, 96 false, 97 }, 98 { 99 "use_internal_ip", 100 false, 101 false, 102 }, 103 { 104 "use_internal_ip", 105 "SO VERY BAD", 106 true, 107 }, 108 { 109 "on_host_maintenance", 110 nil, 111 false, 112 }, 113 { 114 "on_host_maintenance", 115 "TERMINATE", 116 false, 117 }, 118 { 119 "on_host_maintenance", 120 "SO VERY BAD", 121 true, 122 }, 123 { 124 "preemptible", 125 nil, 126 false, 127 }, 128 { 129 "preemptible", 130 false, 131 false, 132 }, 133 { 134 "preemptible", 135 "SO VERY BAD", 136 true, 137 }, 138 { 139 "image_family", 140 nil, 141 false, 142 }, 143 { 144 "image_family", 145 "", 146 false, 147 }, 148 { 149 "image_family", 150 "foo-bar", 151 false, 152 }, 153 { 154 "image_family", 155 "foo bar", 156 true, 157 }, 158 { 159 "scopes", 160 []string{}, 161 false, 162 }, 163 { 164 "scopes", 165 []string{"https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/compute", "https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/sqlservice.admin"}, 166 false, 167 }, 168 { 169 "scopes", 170 []string{"https://www.googleapis.com/auth/cloud-platform"}, 171 false, 172 }, 173 } 174 175 for _, tc := range cases { 176 raw := testConfig(t) 177 178 if tc.Value == nil { 179 delete(raw, tc.Key) 180 } else { 181 raw[tc.Key] = tc.Value 182 } 183 184 _, warns, errs := NewConfig(raw) 185 186 if tc.Err { 187 testConfigErr(t, warns, errs, tc.Key) 188 } else { 189 testConfigOk(t, warns, errs) 190 } 191 } 192 } 193 194 func TestConfigPrepareAccelerator(t *testing.T) { 195 cases := []struct { 196 Keys []string 197 Values []interface{} 198 Err bool 199 }{ 200 { 201 []string{"accelerator_count", "on_host_maintenance", "accelerator_type"}, 202 []interface{}{1, "MIGRATE", "something_valid"}, 203 true, 204 }, 205 { 206 []string{"accelerator_count", "on_host_maintenance", "accelerator_type"}, 207 []interface{}{1, "TERMINATE", "something_valid"}, 208 false, 209 }, 210 { 211 []string{"accelerator_count", "on_host_maintenance", "accelerator_type"}, 212 []interface{}{1, "TERMINATE", nil}, 213 true, 214 }, 215 { 216 []string{"accelerator_count", "on_host_maintenance", "accelerator_type"}, 217 []interface{}{1, "TERMINATE", ""}, 218 true, 219 }, 220 { 221 []string{"accelerator_count", "on_host_maintenance", "accelerator_type"}, 222 []interface{}{1, "TERMINATE", "something_valid"}, 223 false, 224 }, 225 } 226 227 for _, tc := range cases { 228 raw := testConfig(t) 229 230 errStr := "" 231 for k := range tc.Keys { 232 233 // Create the string for error reporting 234 // convert value to string if it can be converted 235 errStr += fmt.Sprintf("%s:%v, ", tc.Keys[k], tc.Values[k]) 236 if tc.Values[k] == nil { 237 delete(raw, tc.Keys[k]) 238 } else { 239 raw[tc.Keys[k]] = tc.Values[k] 240 } 241 } 242 243 _, warns, errs := NewConfig(raw) 244 245 if tc.Err { 246 testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", ")) 247 } else { 248 testConfigOk(t, warns, errs) 249 } 250 } 251 } 252 253 func TestConfigDefaults(t *testing.T) { 254 cases := []struct { 255 Read func(c *Config) interface{} 256 Value interface{} 257 }{ 258 { 259 func(c *Config) interface{} { return c.Comm.Type }, 260 "ssh", 261 }, 262 263 { 264 func(c *Config) interface{} { return c.Comm.SSHPort }, 265 22, 266 }, 267 } 268 269 for _, tc := range cases { 270 raw := testConfig(t) 271 272 c, warns, errs := NewConfig(raw) 273 testConfigOk(t, warns, errs) 274 275 actual := tc.Read(c) 276 if actual != tc.Value { 277 t.Fatalf("bad: %#v", actual) 278 } 279 } 280 } 281 282 func TestImageName(t *testing.T) { 283 c, _, _ := NewConfig(testConfig(t)) 284 if !strings.HasPrefix(c.ImageName, "packer-") { 285 t.Fatalf("ImageName should have 'packer-' prefix, found %s", c.ImageName) 286 } 287 if strings.Contains(c.ImageName, "{{timestamp}}") { 288 t.Errorf("ImageName should be interpolated; found %s", c.ImageName) 289 } 290 } 291 292 func TestRegion(t *testing.T) { 293 c, _, _ := NewConfig(testConfig(t)) 294 if c.Region != "us-east1" { 295 t.Fatalf("Region should be 'us-east1' given Zone of 'us-east1-a', but is %s", c.Region) 296 } 297 } 298 299 // Helper stuff below 300 301 func testConfig(t *testing.T) map[string]interface{} { 302 return map[string]interface{}{ 303 "account_file": testAccountFile(t), 304 "project_id": "hashicorp", 305 "source_image": "foo", 306 "ssh_username": "root", 307 "image_family": "bar", 308 "image_labels": map[string]string{ 309 "label-1": "value-1", 310 "label-2": "value-2", 311 }, 312 "zone": "us-east1-a", 313 } 314 } 315 316 func testConfigStruct(t *testing.T) *Config { 317 c, warns, errs := NewConfig(testConfig(t)) 318 if len(warns) > 0 { 319 t.Fatalf("bad: %#v", len(warns)) 320 } 321 if errs != nil { 322 t.Fatalf("bad: %#v", errs) 323 } 324 325 return c 326 } 327 328 func testConfigErr(t *testing.T, warns []string, err error, extra string) { 329 if len(warns) > 0 { 330 t.Fatalf("bad: %#v", warns) 331 } 332 if err == nil { 333 t.Fatalf("should error: %s", extra) 334 } 335 } 336 337 func testConfigOk(t *testing.T, warns []string, err error) { 338 if len(warns) > 0 { 339 t.Fatalf("bad: %#v", warns) 340 } 341 if err != nil { 342 t.Fatalf("bad: %s", err) 343 } 344 } 345 346 func testAccountFile(t *testing.T) string { 347 tf, err := ioutil.TempFile("", "packer") 348 if err != nil { 349 t.Fatalf("err: %s", err) 350 } 351 defer tf.Close() 352 353 if _, err := tf.Write([]byte(testAccountContent)); err != nil { 354 t.Fatalf("err: %s", err) 355 } 356 357 return tf.Name() 358 } 359 360 // This is just some dummy data that doesn't actually work (it was revoked 361 // a long time ago). 362 const testAccountContent = `{}`