Skip to content

Commit

Permalink
Acceptance tests for metal device timeouts
Browse files Browse the repository at this point in the history
  • Loading branch information
aayushrangwala committed Aug 23, 2023
1 parent c458c7b commit f3725b4
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 113 deletions.
12 changes: 9 additions & 3 deletions equinix/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import (
)

var (
testAccProviders map[string]*schema.Provider
testAccProvider *schema.Provider
testExternalProviders map[string]resource.ExternalProvider
testAccProviders map[string]*schema.Provider
testAccProviderFactories map[string]func() (*schema.Provider, error)
testAccProvider *schema.Provider
testExternalProviders map[string]resource.ExternalProvider
)

type mockedResourceDataProvider struct {
Expand Down Expand Up @@ -127,6 +128,11 @@ func init() {
testAccProviders = map[string]*schema.Provider{
"equinix": testAccProvider,
}
testAccProviderFactories = map[string]func() (*schema.Provider, error){
"equinix": func() (*schema.Provider, error) {
return testAccProvider, nil
},
}
testExternalProviders = map[string]resource.ExternalProvider{
"random": {
Source: "hashicorp/random",
Expand Down
200 changes: 104 additions & 96 deletions equinix/resource_metal_device_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package equinix

import (
"context"
"errors"
"fmt"
"log"
"net"
Expand All @@ -11,6 +12,7 @@ import (
"testing"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -338,28 +340,6 @@ func TestAccMetalDevice_update(t *testing.T) {
})
}

func TestAccMetalDevice_timeouts(t *testing.T) {
rs := acctest.RandString(10)
rInt := acctest.RandInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
Providers: testAccProviders,
CheckDestroy: testAccMetalDeviceCheckDestroyed,
Steps: []resource.TestStep{
{
Config: testAccMetalDeviceConfig_timeout(rInt, rs),
ExpectError: matchErrDeviceReadyTimeout,
},
{
Config: testAccMetalDeviceConfig_reinstall_timeout(rInt+1, rs),
ExpectError: matchErrDeviceReadyTimeout,
},
},
})
}

func TestAccMetalDevice_IPXEScriptUrl(t *testing.T) {
var device, d2 packngo.Device
rs := acctest.RandString(10)
Expand Down Expand Up @@ -579,6 +559,23 @@ func testAccMetalDeviceExists(n string, device *packngo.Device) resource.TestChe
}
}

func testAccWaitForMetalDeviceActive(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
defaultTimeout := 20 * time.Minute

rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Record ID is set")
}
rd := new(schema.ResourceData)
rd.SetId(rs.Primary.ID)
return waitForActiveDevice(context.Background(), rd, testAccProvider.Meta(), defaultTimeout)
}
}

func testAccMetalSameDevice(t *testing.T, before, after *packngo.Device) resource.TestCheckFunc {
return func(s *terraform.State) error {
if before.ID != after.ID {
Expand Down Expand Up @@ -720,38 +717,6 @@ resource "equinix_metal_device" "test" {
`, confAccMetalDevice_base(preferable_plans, preferable_metros, preferable_os), projSuffix, rInt, rInt, testDeviceTerminationTime())
}

func testAccMetalDeviceConfig_reinstall_timeout(rInt int, projSuffix string) string {
return fmt.Sprintf(`
%s
resource "equinix_metal_project" "test" {
name = "tfacc-device-%s"
}
resource "equinix_metal_device" "test" {
hostname = "tfacc-test-device-%d"
plan = local.plan
metro = local.metro
operating_system = local.os
billing_cycle = "hourly"
project_id = "${equinix_metal_project.test.id}"
tags = ["%d"]
user_data = "#!/usr/bin/env sh\necho Reinstall\n"
termination_time = "%s"
reinstall {
enabled = true
deprovision_fast = true
}
timeouts {
create = "10s"
update = "10s"
}
}
`, confAccMetalDevice_base(preferable_plans, preferable_metros, preferable_os), projSuffix, rInt, rInt, testDeviceTerminationTime())
}

func testAccMetalDeviceConfig_allowAttributeChanges(rInt int, projSuffix string, userdata string, customdata string, attributeName string) string {
return fmt.Sprintf(`
%s
Expand Down Expand Up @@ -803,30 +768,6 @@ resource "equinix_metal_device" "test" {
`, confAccMetalDevice_base(preferable_plans, preferable_metros, preferable_os), projSuffix, rInt, rInt, rInt, testDeviceTerminationTime())
}

func testAccMetalDeviceConfig_varname_pxe(rInt int, projSuffix string) string {
return fmt.Sprintf(`
%s
resource "equinix_metal_project" "test" {
name = "tfacc-device-%s"
}
resource "equinix_metal_device" "test" {
hostname = "tfacc-test-device-%d"
description = "test-desc-%d"
plan = local.plan
metro = local.metro
operating_system = local.os
billing_cycle = "hourly"
project_id = "${equinix_metal_project.test.id}"
tags = ["%d"]
always_pxe = true
ipxe_script_url = "http://matchbox.foo.wtf:8080/boot.ipxe"
termination_time = "%s"
}
`, confAccMetalDevice_base(preferable_plans, preferable_metros, preferable_os), projSuffix, rInt, rInt, rInt, testDeviceTerminationTime())
}

func testAccMetalDeviceConfig_metro(projSuffix string) string {
return fmt.Sprintf(`
%s
Expand Down Expand Up @@ -994,53 +935,54 @@ resource "equinix_metal_device" "test_ipxe_missing" {
always_pxe = true
}`

func testAccMetalDeviceConfig_timeout(rInt int, projSuffix string) string {
func testAccMetalDeviceConfig_timeout(projSuffix string) string {
return fmt.Sprintf(`
%s
resource "equinix_metal_project" "test" {
name = "tfacc-device-%s"
name = "tfacc-device-%s"
}
resource "equinix_metal_device" "test" {
hostname = "tfacc-test-device-%d"
plan = local.plan
metro = local.metro
operating_system = local.os
billing_cycle = "hourly"
hostname = "tfacc-test-device"
description = "test-desc"
plan = "c3.small.x86"
metro = "DA"
operating_system = "ubuntu_20_04"
project_id = "${equinix_metal_project.test.id}"
tags = ["%d"]
user_data = "#!/usr/bin/env sh\necho Reinstall\n"
termination_time = "%s"
timeouts {
create = "10s"
update = "10s"
}
}`, confAccMetalDevice_base(preferable_plans, preferable_metros, preferable_os), projSuffix, rInt, rInt, testDeviceTerminationTime())
}
`, projSuffix, testDeviceTerminationTime())
}

type mockDeviceService struct {
GetFn func(deviceID string, opts *packngo.GetOptions) (*packngo.Device, *packngo.Response, error)
GetFn func(deviceID string, opts *packngo.GetOptions) (*packngo.Device, *packngo.Response, error)
CreateFn func(device *packngo.DeviceCreateRequest) (*packngo.Device, *packngo.Response, error)
UpdateFn func(string, *packngo.DeviceUpdateRequest) (*packngo.Device, *packngo.Response, error)
DeleteFn func(string, bool) (*packngo.Response, error)
}

func (m *mockDeviceService) Get(deviceID string, opts *packngo.GetOptions) (*packngo.Device, *packngo.Response, error) {
return m.GetFn(deviceID, opts)
}

func (m *mockDeviceService) Create(device *packngo.DeviceCreateRequest) (*packngo.Device, *packngo.Response, error) {
return nil, nil, mockFuncNotImplemented("Create")
return m.CreateFn(device)
}

func (m *mockDeviceService) Delete(string, bool) (*packngo.Response, error) {
return nil, mockFuncNotImplemented("Delete")
func (m *mockDeviceService) Delete(deviceId string, forceDetachVolume bool) (*packngo.Response, error) {
return m.DeleteFn(deviceId, forceDetachVolume)
}

func (m *mockDeviceService) List(string, *packngo.ListOptions) ([]packngo.Device, *packngo.Response, error) {
return nil, nil, mockFuncNotImplemented("List")
}

func (m *mockDeviceService) Update(string, *packngo.DeviceUpdateRequest) (*packngo.Device, *packngo.Response, error) {
return nil, nil, mockFuncNotImplemented("Update")
func (m *mockDeviceService) Update(deviceId string, updateReq *packngo.DeviceUpdateRequest) (*packngo.Device, *packngo.Response, error) {
return m.UpdateFn(deviceId, updateReq)
}

func (m *mockDeviceService) Reboot(string) (*packngo.Response, error) {
Expand Down Expand Up @@ -1208,3 +1150,69 @@ func TestAccMetalDevice_readErrorHandling(t *testing.T) {
})
}
}

func TestAccMetalDevice_timeouts(t *testing.T) {
d1 := &packngo.Device{
State: "active",
}
projSuffix := acctest.RandString(10)

mockMetalDeviceService := &mockDeviceService{
CreateFn: func(device *packngo.DeviceCreateRequest) (*packngo.Device, *packngo.Response, error) {
return d1, &packngo.Response{Response: &http.Response{Status: matchErrDeviceReadyTimeout.String(), StatusCode: 500}},
errors.New(matchErrDeviceReadyTimeout.String())
},
GetFn: func(deviceID string, opts *packngo.GetOptions) (*packngo.Device, *packngo.Response, error) {
return d1, &packngo.Response{Response: &http.Response{Status: "Success", StatusCode: 200}}, nil
},
}
mockMetalProjectService := &mockProjectService{
GetFn: func(projectID string, opts *packngo.GetOptions) (*packngo.Project, *packngo.Response, error) {
project := &packngo.Project{ID: "test"}
httpResp := &http.Response{Status: "Success", StatusCode: 200}
return project, &packngo.Response{Response: httpResp}, nil
},
CreateFn: func(pcr *packngo.ProjectCreateRequest) (*packngo.Project, *packngo.Response, error) {
project := &packngo.Project{ID: "test"}
httpResp := &http.Response{Status: "Success", StatusCode: 200}
return project, &packngo.Response{Response: httpResp}, nil
},
DeleteFn: func(projectID string) (*packngo.Response, error) {
httpResp := &http.Response{Status: "Success", StatusCode: 200}
return &packngo.Response{Response: httpResp}, nil
},
}
mockBgpsvc := &mockBgpConfigService{
GetFn: func(projectID string, getOpt *packngo.GetOptions) (*packngo.BGPConfig, *packngo.Response, error) {
return nil, nil, nil
},
}

mockEquinix := Provider()
mockEquinix.ConfigureContextFunc = func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
config := Config{
metal: &packngo.Client{
Devices: mockMetalDeviceService,
Projects: mockMetalProjectService,
BGPConfig: mockBgpsvc,
},
}
return &config, nil
}

mockProviders := map[string]func() (*schema.Provider, error){
"equinix": func() (*schema.Provider, error) {
return mockEquinix, nil
},
}
resource.ParallelTest(t, resource.TestCase{
ProviderFactories: mockProviders,
ExternalProviders: testExternalProviders,
Steps: []resource.TestStep{
{
Config: testAccMetalDeviceConfig_timeout(projSuffix),
ExpectError: matchErrDeviceReadyTimeout,
},
},
})
}
15 changes: 15 additions & 0 deletions equinix/resource_network_bgp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package equinix

import (
"context"
"github.com/packethost/packngo"
"testing"
"time"

Expand Down Expand Up @@ -100,6 +101,20 @@ func (r *mockedBGPUpdateRequest) Execute() error {
return nil
}

var _ packngo.BGPConfigService = &mockBgpConfigService{}

type mockBgpConfigService struct {
GetFn func(projectID string, getOpt *packngo.GetOptions) (*packngo.BGPConfig, *packngo.Response, error)
CreateFn func(projectID string, request packngo.CreateBGPConfigRequest) (*packngo.Response, error)
}

func (s *mockBgpConfigService) Get(projectID string, getOpt *packngo.GetOptions) (*packngo.BGPConfig, *packngo.Response, error) {
return s.GetFn(projectID, getOpt)
}
func (s *mockBgpConfigService) Create(projectID string, request packngo.CreateBGPConfigRequest) (*packngo.Response, error) {
return s.CreateFn(projectID, request)
}

func TestNetworkBGP_createUpdateRequest(t *testing.T) {
// given
req := &mockedBGPUpdateRequest{data: make(map[string]interface{})}
Expand Down
11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ require (
github.com/equinix/oauth2-go v1.0.0
github.com/equinix/rest-go v1.3.0
github.com/gruntwork-io/terratest v0.43.0
github.com/hashicorp/errwrap v1.1.0
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.4
github.com/hashicorp/terraform-plugin-docs v0.14.1
github.com/hashicorp/terraform-plugin-sdk/v2 v2.26.1
github.com/onsi/gomega v1.27.10
github.com/packethost/packngo v0.30.0
github.com/stretchr/testify v1.8.4
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
Expand Down Expand Up @@ -46,6 +46,7 @@ require (
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.1 // indirect
Expand Down Expand Up @@ -92,11 +93,11 @@ require (
github.com/vmihailenco/tagparser v0.1.1 // indirect
github.com/zclconf/go-cty v1.13.1 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.103.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
Loading

0 comments on commit f3725b4

Please sign in to comment.