golang.org/x/build@v0.0.0-20240506185731-218518f32b70/internal/cloud/fake_aws_test.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package cloud 6 7 import ( 8 "context" 9 "fmt" 10 "net" 11 "testing" 12 13 "github.com/google/go-cmp/cmp" 14 "github.com/google/go-cmp/cmp/cmpopts" 15 ) 16 17 func TestFakeAWSClientInstance(t *testing.T) { 18 t.Run("invalid-params", func(t *testing.T) { 19 ctx := context.Background() 20 f := NewFakeAWSClient() 21 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 22 if gotErr != nil { 23 t.Fatalf("unable to create instance: %s", gotErr) 24 } 25 if gotInst, gotErr := f.Instance(nil, inst.ID); gotErr == nil { 26 t.Errorf("Instance(nil, %s) = %+v, nil, want error", inst.ID, gotInst) 27 } 28 if gotInst, gotErr := f.Instance(ctx, ""); gotErr == nil { 29 t.Errorf("Instance(ctx, %s) = %+v, nil, want error", "", gotInst) 30 } 31 }) 32 t.Run("existing-instance", func(t *testing.T) { 33 ctx := context.Background() 34 f := NewFakeAWSClient() 35 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 36 if gotErr != nil { 37 t.Fatalf("unable to create instance") 38 } 39 gotInst, gotErr := f.Instance(ctx, inst.ID) 40 if gotErr != nil || gotInst == nil || gotInst.ID != inst.ID { 41 t.Errorf("Instance(ctx, %s) = %v, %s, want %+v, nil", inst.ID, gotInst, gotErr, inst) 42 } 43 }) 44 t.Run("non-existing-instance", func(t *testing.T) { 45 ctx := context.Background() 46 f := NewFakeAWSClient() 47 instID := "instance-random" 48 gotInst, gotErr := f.Instance(ctx, instID) 49 if gotErr == nil || gotInst != nil { 50 t.Errorf("Instance(ctx, %s) = %v, %s, want error", instID, gotInst, gotErr) 51 } 52 }) 53 t.Run("terminated-instance", func(t *testing.T) { 54 ctx := context.Background() 55 f := NewFakeAWSClient() 56 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 57 if gotErr != nil { 58 t.Fatalf("unable to create instance") 59 } 60 if gotErr := f.DestroyInstances(ctx, inst.ID); gotErr != nil { 61 t.Fatalf("unable to destroy instance") 62 } 63 gotInst, gotErr := f.Instance(ctx, inst.ID) 64 if gotErr != nil || gotInst == nil || gotInst.ID != inst.ID { 65 t.Errorf("Instance(ctx, %s) = %v, %s, want %+v, nil", inst.ID, gotInst, gotErr, inst) 66 } 67 }) 68 } 69 70 func TestFakeAWSClientRunningInstances(t *testing.T) { 71 t.Run("invalid-params", func(t *testing.T) { 72 ctx := context.Background() 73 f := NewFakeAWSClient() 74 _, gotErr := f.CreateInstance(ctx, generateVMConfig()) 75 if gotErr != nil { 76 t.Fatalf("unable to create instance: %s", gotErr) 77 } 78 if gotInst, gotErr := f.RunningInstances(nil); gotErr == nil { 79 t.Errorf("RunningInstances(nil) = %+v, nil, want error", gotInst) 80 } 81 }) 82 t.Run("no-instances", func(t *testing.T) { 83 ctx := context.Background() 84 f := NewFakeAWSClient() 85 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 86 if gotErr != nil { 87 t.Fatalf("unable to create instance") 88 } 89 gotInsts, gotErr := f.RunningInstances(ctx) 90 if gotErr != nil { 91 t.Errorf("RunningInstances() error = %v, no error", gotErr) 92 } 93 if !cmp.Equal(gotInsts, []*Instance{inst}) { 94 t.Errorf("RunningInstances() = %+v, %s; want %+v", gotInsts, gotErr, []*Instance{inst}) 95 } 96 }) 97 t.Run("single-instance", func(t *testing.T) { 98 ctx := context.Background() 99 f := NewFakeAWSClient() 100 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 101 if gotErr != nil { 102 t.Fatalf("unable to create instance") 103 } 104 gotInsts, gotErr := f.RunningInstances(ctx) 105 if gotErr != nil { 106 t.Errorf("RunningInstances() error = %v, no error", gotErr) 107 } 108 if !cmp.Equal(gotInsts, []*Instance{inst}) { 109 t.Errorf("RunningInstances() = %+v, %s; want %+v", gotInsts, gotErr, []*Instance{inst}) 110 } 111 }) 112 t.Run("multiple-instances", func(t *testing.T) { 113 ctx := context.Background() 114 f := NewFakeAWSClient() 115 create := []*EC2VMConfiguration{ 116 generateVMConfig(), 117 generateVMConfig(), 118 generateVMConfig(), 119 } 120 insts := make([]*Instance, 0, len(create)) 121 for _, config := range create { 122 inst, gotErr := f.CreateInstance(ctx, config) 123 if gotErr != nil { 124 t.Fatalf("unable to create instance") 125 } 126 insts = append(insts, inst) 127 } 128 gotInsts, gotErr := f.RunningInstances(ctx) 129 if gotErr != nil { 130 t.Errorf("RunningInstances() error = %v, no error", gotErr) 131 } 132 opt := cmpopts.SortSlices(func(i, j *Instance) bool { return i.ID < j.ID }) 133 if !cmp.Equal(gotInsts, insts, opt) { 134 t.Errorf("RunningInstances() = %+v, %s; want %+v", gotInsts, gotErr, insts) 135 } 136 }) 137 138 t.Run("multiple-instances-with-one-termination", func(t *testing.T) { 139 ctx := context.Background() 140 f := NewFakeAWSClient() 141 create := []*EC2VMConfiguration{ 142 generateVMConfig(), 143 generateVMConfig(), 144 generateVMConfig(), 145 } 146 insts := make([]*Instance, 0, len(create)) 147 for _, config := range create { 148 inst, gotErr := f.CreateInstance(ctx, config) 149 if gotErr != nil { 150 t.Fatalf("unable to create instance") 151 } 152 insts = append(insts, inst) 153 } 154 if gotErr := f.DestroyInstances(ctx, insts[0].ID); gotErr != nil { 155 t.Fatalf("unable to destroy instance") 156 } 157 gotInsts, gotErr := f.RunningInstances(ctx) 158 if gotErr != nil { 159 t.Errorf("RunningInstances() error = %v, no error", gotErr) 160 } 161 opt := cmpopts.SortSlices(func(i, j *Instance) bool { return i.ID < j.ID }) 162 if !cmp.Equal(gotInsts, insts[1:], opt) { 163 t.Errorf("RunningInstances() = %+v, %s; want %+v", gotInsts, gotErr, insts[1:]) 164 } 165 }) 166 } 167 168 func TestFakeAWSClientInstanceTypesARM(t *testing.T) { 169 t.Run("invalid-params", func(t *testing.T) { 170 f := NewFakeAWSClient() 171 if gotITs, gotErr := f.InstanceTypesARM(nil); gotErr == nil { 172 t.Errorf("InstanceTypesARM(nil) = %+v, nil, want error", gotITs) 173 } 174 }) 175 t.Run("no-instances", func(t *testing.T) { 176 ctx := context.Background() 177 f := NewFakeAWSClient() 178 gotITs, gotErr := f.InstanceTypesARM(ctx) 179 if gotErr != nil { 180 t.Errorf("InstanceTypesARM(ctx) error = %v, no error", gotErr) 181 } 182 if !cmp.Equal(gotITs, f.instanceTypes) { 183 t.Errorf("InstanceTypesARM(ctx) = %+v, %s; want %+v", gotITs, gotErr, f.instanceTypes) 184 } 185 }) 186 } 187 188 func TestFakeAWSClientQuota(t *testing.T) { 189 t.Run("invalid-context", func(t *testing.T) { 190 f := NewFakeAWSClient() 191 gotQuota, gotErr := f.Quota(nil, QuotaServiceEC2, QuotaCodeCPUOnDemand) 192 if gotErr == nil || gotQuota != 0 { 193 t.Errorf("Quota(nil, %s, %s) = %d, %s, want error", QuotaServiceEC2, QuotaCodeCPUOnDemand, gotQuota, gotErr) 194 } 195 }) 196 t.Run("invalid-service", func(t *testing.T) { 197 f := NewFakeAWSClient() 198 gotQuota, gotErr := f.Quota(context.Background(), "", QuotaCodeCPUOnDemand) 199 if gotErr == nil || gotQuota != 0 { 200 t.Errorf("Quota(ctx, \"\", %s) = %d, %s, want error", QuotaCodeCPUOnDemand, gotQuota, gotErr) 201 } 202 }) 203 t.Run("invalid-quota-code", func(t *testing.T) { 204 f := NewFakeAWSClient() 205 gotQuota, gotErr := f.Quota(context.Background(), QuotaServiceEC2, "") 206 if gotErr == nil || gotQuota != 0 { 207 t.Errorf("Quota(ctx, %s, \"\") = %d, %s, want error", QuotaServiceEC2, gotQuota, gotErr) 208 } 209 }) 210 t.Run("valid-request", func(t *testing.T) { 211 f := NewFakeAWSClient() 212 wantQuota, ok := f.serviceQuotas[serviceQuotaKey{QuotaCodeCPUOnDemand, QuotaServiceEC2}] 213 if !ok { 214 t.Fatal("unable to retrieve quota value") 215 } 216 gotQuota, gotErr := f.Quota(context.Background(), QuotaServiceEC2, QuotaCodeCPUOnDemand) 217 if gotErr != nil || gotQuota != wantQuota { 218 t.Errorf("Quota(ctx, %s, %s) = %d, %s, want %d, nil", QuotaServiceEC2, 219 QuotaCodeCPUOnDemand, gotQuota, gotErr, wantQuota) 220 } 221 }) 222 } 223 224 func TestFakeAWSClientCreateInstance(t *testing.T) { 225 t.Run("create-instance", func(t *testing.T) { 226 ctx := context.Background() 227 f := NewFakeAWSClient() 228 ud := &EC2UserData{} 229 config := &EC2VMConfiguration{ 230 Description: "desc", 231 ImageID: "id-44", 232 Name: "name-22", 233 SSHKeyID: "key-43", 234 SecurityGroups: []string{"sg-1", "sg-2"}, 235 Tags: map[string]string{ 236 "key-1": "value-1", 237 }, 238 Type: "ami-44", 239 UserData: ud.EncodedString(), 240 Zone: "zone-14", 241 } 242 gotInst, gotErr := f.CreateInstance(ctx, config) 243 if gotErr != nil { 244 t.Fatalf("CreateInstance(ctx, %+v) = %+v, %s; want no error", config, gotInst, gotErr) 245 } 246 // generated fields 247 if gotInst.CPUCount <= 0 { 248 t.Errorf("Instance. is not set") 249 } 250 if gotInst.ID == "" { 251 t.Errorf("Instance.ID is not set") 252 } 253 if gotInst.IPAddressExternal == "" { 254 t.Errorf("Instance.IPAddressExternal is not set") 255 } 256 if gotInst.IPAddressInternal == "" { 257 t.Errorf("Instance.IPAddressInternal is not set") 258 } 259 if gotInst.State == "" { 260 t.Errorf("Instance.State is not set") 261 } 262 // config fields 263 if gotInst.Description != config.Description { 264 t.Errorf("Instance.Description = %s, want %s", gotInst.Description, config.Description) 265 } 266 if gotInst.ImageID != config.ImageID { 267 t.Errorf("Instance.ImageID = %s, want %s", gotInst.ImageID, config.ImageID) 268 } 269 if gotInst.Name != config.Name { 270 t.Errorf("Instance.Name = %s, want %s", gotInst.Name, config.Name) 271 } 272 if gotInst.SSHKeyID != config.SSHKeyID { 273 t.Errorf("Instance.SSHKeyID = %s, want %s", gotInst.SSHKeyID, config.SSHKeyID) 274 } 275 if !cmp.Equal(gotInst.SecurityGroups, config.SecurityGroups) { 276 t.Errorf("Instance.SecurityGroups = %s, want %s", gotInst.SecurityGroups, config.SecurityGroups) 277 } 278 if !cmp.Equal(gotInst.Tags, config.Tags) { 279 t.Errorf("Instance.Tags = %+v, want %+v", gotInst.Tags, config.Tags) 280 } 281 if gotInst.Type != config.Type { 282 t.Errorf("Instance.Type = %s, want %s", gotInst.Type, config.Type) 283 } 284 if gotInst.Zone != config.Zone { 285 t.Errorf("Instance.Zone = %s, want %s", gotInst.Zone, config.Zone) 286 } 287 }) 288 } 289 290 func TestFakeAWSClientDestroyInstances(t *testing.T) { 291 t.Run("invalid-params", func(t *testing.T) { 292 ctx := context.Background() 293 f := NewFakeAWSClient() 294 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 295 if gotErr != nil { 296 t.Fatalf("unable to create instance: %s", gotErr) 297 } 298 if gotErr := f.DestroyInstances(nil, inst.ID); gotErr == nil { 299 t.Errorf("DestroyInstances(nil, %s) = nil, want error", inst.ID) 300 } 301 if gotErr := f.DestroyInstances(ctx); gotErr == nil { 302 t.Error("DestroyInstances(ctx) = nil, want error") 303 } 304 }) 305 t.Run("destroy-existing-instance", func(t *testing.T) { 306 ctx := context.Background() 307 f := NewFakeAWSClient() 308 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 309 if gotErr != nil { 310 t.Fatalf("unable to create instance") 311 } 312 if gotErr = f.DestroyInstances(ctx, inst.ID); gotErr != nil { 313 t.Errorf("DestroyInstances(ctx, %s) = %s; want no error", inst.ID, gotErr) 314 } 315 }) 316 t.Run("destroy-existing-instances", func(t *testing.T) { 317 ctx := context.Background() 318 f := NewFakeAWSClient() 319 inst1, gotErr := f.CreateInstance(ctx, generateVMConfig()) 320 if gotErr != nil { 321 t.Fatalf("unable to create instance") 322 } 323 inst2, gotErr := f.CreateInstance(ctx, generateVMConfig()) 324 if gotErr != nil { 325 t.Fatalf("unable to create instance") 326 } 327 if gotErr = f.DestroyInstances(ctx, inst1.ID, inst2.ID); gotErr != nil { 328 t.Errorf("DestroyInstances(ctx, %s, %s) = %s; want no error", inst1.ID, inst2.ID, gotErr) 329 } 330 }) 331 t.Run("destroy-non-existing-instance", func(t *testing.T) { 332 ctx := context.Background() 333 f := NewFakeAWSClient() 334 instID := "instance-random" 335 if gotErr := f.DestroyInstances(ctx, instID); gotErr == nil { 336 t.Errorf("DestroyInstances(ctx, %s) = %s; want error", instID, gotErr) 337 } 338 }) 339 } 340 341 func TestFakeAWSClientWaitUntilInstanceRunning(t *testing.T) { 342 t.Run("invalid-params", func(t *testing.T) { 343 ctx := context.Background() 344 f := NewFakeAWSClient() 345 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 346 if gotErr != nil { 347 t.Fatalf("unable to create instance: %s", gotErr) 348 } 349 if gotErr := f.WaitUntilInstanceRunning(nil, inst.ID); gotErr == nil { 350 t.Errorf("WaitUntilInstanceRunning(nil, %s) = nil, want error", inst.ID) 351 } 352 if gotErr := f.WaitUntilInstanceRunning(ctx, ""); gotErr == nil { 353 t.Errorf("WaitUntilInstanceRunning(ctx, %s) = nil, want error", "") 354 } 355 }) 356 t.Run("wait-for-existing-instance", func(t *testing.T) { 357 ctx := context.Background() 358 f := NewFakeAWSClient() 359 inst, gotErr := f.CreateInstance(ctx, generateVMConfig()) 360 if gotErr != nil { 361 t.Fatalf("unable to create instance") 362 } 363 if gotErr = f.WaitUntilInstanceRunning(ctx, inst.ID); gotErr != nil { 364 t.Errorf("WaitUntilInstanceRunning(ctx, %s) = %s; want no error", inst.ID, gotErr) 365 } 366 }) 367 t.Run("wait-for-non-existing-instance", func(t *testing.T) { 368 ctx := context.Background() 369 f := NewFakeAWSClient() 370 instID := "instance-random" 371 if gotErr := f.WaitUntilInstanceRunning(ctx, instID); gotErr == nil { 372 t.Errorf("WaitUntilInstanceRunning(ctx, %s) = %s; want error", instID, gotErr) 373 } 374 }) 375 } 376 377 func TestRandIPv4(t *testing.T) { 378 got := randIPv4() 379 gotIP := net.ParseIP(got) 380 if gotIP == nil { 381 t.Errorf("randIPv4() = %v, want conforment IPv4 address", got) 382 } 383 } 384 385 func generateVMConfig() *EC2VMConfiguration { 386 return &EC2VMConfiguration{ 387 ImageID: fmt.Sprintf("ami-%s", randHex(4)), 388 SSHKeyID: fmt.Sprintf("key-%s", randHex(4)), 389 Type: fmt.Sprintf("type-%s", randHex(4)), 390 Zone: fmt.Sprintf("zone-%s", randHex(4)), 391 } 392 }