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  }