Skip to content

Commit f3aadf6

Browse files
authored
chore: migrate acctest in its own package and split tests in their own package (#2458)
* ensure that tests are in their own package * fix tfproviderlint
1 parent d2ae788 commit f3aadf6

File tree

340 files changed

+2856
-2532
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

340 files changed

+2856
-2532
lines changed

.github/contributing/acceptance_test.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ The definition of a complete test looks like this:
9999

100100
```go
101101
func TestAccScalewayInstanceServerImport(t *testing.T) {
102-
tt := NewTestTools(t)
102+
tt := acctest.NewTestTools(t)
103103
defer tt.Cleanup()
104104
resource.ParallelTest(t, resource.TestCase{
105105
PreCheck: func() { testAccPreCheck(t) },
@@ -152,7 +152,7 @@ When executing the test, the following steps are taken for each `TestStep`:
152152
return fmt.Errorf("resource not found: %s", n)
153153
}
154154
155-
instanceAPI, zone, ID, err := instanceAPIWithZoneAndID(tt.Meta, rs.Primary.ID)
155+
instanceAPI, zone, ID, err := scaleway.InstanceAPIWithZoneAndID(tt.Meta, rs.Primary.ID)
156156
if err != nil {
157157
return err
158158
}
@@ -190,7 +190,7 @@ When executing the test, the following steps are taken for each `TestStep`:
190190
continue
191191
}
192192
193-
instanceAPI, zone, ID, err := instanceAPIWithZoneAndID(tt.Meta, rs.Primary.ID)
193+
instanceAPI, zone, ID, err := scaleway.InstanceAPIWithZoneAndID(tt.Meta, rs.Primary.ID)
194194
if err != nil {
195195
return err
196196
}

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ linters:
6262
- tagliatelle # Checks the struct tags. [fast: true, auto-fix: false]
6363
- tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 [fast: false, auto-fix: false]
6464
- testifylint # Checks usage of github.com/stretchr/testify. [fast: false, auto-fix: false]
65+
- testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false]
6566
- thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false]
6667
- tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes [fast: false, auto-fix: false]
6768
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code [fast: false, auto-fix: false]

cmd/tftemplate/datasource_test.go.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
)
99

1010
func TestAccScalewayDataSource{{.Resource}}_Basic(t *testing.T) {
11-
tt := NewTestTools(t)
11+
tt := acctest.NewTestTools(t)
1212
defer tt.Cleanup()
1313
resource.ParallelTest(t, resource.TestCase{
1414
PreCheck: func() { testAccPreCheck(t) },

cmd/tftemplate/resource_test.go.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func testSweep{{ .Resource }}(_ string) error {
4646
}
4747

4848
func TestAccScaleway{{.Resource}}_Basic(t *testing.T) {
49-
tt := NewTestTools(t)
49+
tt := acctest.NewTestTools(t)
5050
defer tt.Cleanup()
5151

5252
resource.ParallelTest(t, resource.TestCase{

internal/acctest/acctest.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package acctest
2+
3+
import (
4+
"context"
5+
"strconv"
6+
"strings"
7+
"testing"
8+
"time"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
12+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/transport"
13+
"github.com/scaleway/terraform-provider-scaleway/v2/scaleway"
14+
"github.com/stretchr/testify/require"
15+
)
16+
17+
func PreCheck(_ *testing.T) {}
18+
19+
type TestTools struct {
20+
T *testing.T
21+
Meta *meta.Meta
22+
ProviderFactories map[string]func() (*schema.Provider, error)
23+
Cleanup func()
24+
}
25+
26+
func NewTestTools(t *testing.T) *TestTools {
27+
t.Helper()
28+
ctx := context.Background()
29+
// Create a http client with recording capabilities
30+
httpClient, cleanup, err := getHTTPRecoder(t, *UpdateCassettes)
31+
require.NoError(t, err)
32+
33+
// Create meta that will be passed in the provider config
34+
m, err := meta.NewMeta(ctx, &meta.Config{
35+
ProviderSchema: nil,
36+
TerraformVersion: "terraform-tests",
37+
HTTPClient: httpClient,
38+
})
39+
require.NoError(t, err)
40+
41+
if !*UpdateCassettes {
42+
tmp := 0 * time.Second
43+
transport.DefaultWaitRetryInterval = &tmp
44+
}
45+
46+
return &TestTools{
47+
T: t,
48+
Meta: m,
49+
ProviderFactories: map[string]func() (*schema.Provider, error){
50+
"scaleway": func() (*schema.Provider, error) {
51+
return scaleway.Provider(&scaleway.ProviderConfig{Meta: m})(), nil
52+
},
53+
},
54+
Cleanup: cleanup,
55+
}
56+
}
57+
58+
// Test Generated name has format: "{prefix}-{generated_number}
59+
// example: test-acc-scaleway-project-3723338038624371236
60+
func extractTestGeneratedNamePrefix(name string) string {
61+
// {prefix}-{generated}
62+
// ^
63+
dashIndex := strings.LastIndex(name, "-")
64+
65+
generated := name[dashIndex+1:]
66+
_, generatedToIntErr := strconv.ParseInt(generated, 10, 64)
67+
68+
if dashIndex == -1 || generatedToIntErr != nil {
69+
// some are only {name}
70+
return name
71+
}
72+
73+
// {prefix}
74+
return name[:dashIndex]
75+
}
76+
77+
// Generated names have format: "tf-{prefix}-{generated1}-{generated2}"
78+
// example: tf-sg-gifted-yonath
79+
func extractGeneratedNamePrefix(name string) string {
80+
if strings.Count(name, "-") < 3 {
81+
return name
82+
}
83+
// tf-{prefix}-gifted-yonath
84+
name = strings.TrimPrefix(name, "tf-")
85+
86+
// {prefix}-gifted-yonath
87+
// ^
88+
dashIndex := strings.LastIndex(name, "-")
89+
name = name[:dashIndex]
90+
// {prefix}-gifted
91+
// ^
92+
dashIndex = strings.LastIndex(name, "-")
93+
name = name[:dashIndex]
94+
return name
95+
}
96+
97+
// compareJSONFieldsStrings compare two strings from request JSON bodies
98+
// has special case when string are terraform generated names
99+
func compareJSONFieldsStrings(expected, actual string) bool {
100+
expectedHandled := expected
101+
actualHandled := actual
102+
103+
// Remove s3 url suffix to allow comparison
104+
if strings.HasSuffix(actual, ".s3-website.fr-par.scw.cloud") {
105+
actual = strings.TrimSuffix(actual, ".s3-website.fr-par.scw.cloud")
106+
expected = strings.TrimSuffix(expected, ".s3-website.fr-par.scw.cloud")
107+
}
108+
109+
// Try to parse test generated name
110+
if strings.Contains(actual, "-") {
111+
expectedHandled = extractTestGeneratedNamePrefix(expected)
112+
actualHandled = extractTestGeneratedNamePrefix(actual)
113+
}
114+
115+
// Try provider generated name
116+
if actualHandled == actual && strings.HasPrefix(actual, "tf-") {
117+
expectedHandled = extractGeneratedNamePrefix(expected)
118+
actualHandled = extractGeneratedNamePrefix(actual)
119+
}
120+
121+
return expectedHandled == actualHandled
122+
}
123+
124+
// compareJSONBodies compare two given maps that represent json bodies
125+
// returns true if both json are equivalent
126+
func compareJSONBodies(expected, actual map[string]interface{}) bool {
127+
// Check for each key in actual requests
128+
// Compare its value to cassette content if marshal-able to string
129+
for key := range actual {
130+
expectedValue, exists := expected[key]
131+
if !exists {
132+
// Actual request may contain a field that does not exist in cassette
133+
// New fields can appear in requests with new api features
134+
// We do not want to generate new cassettes for each new features
135+
continue
136+
}
137+
if !compareJSONFields(expectedValue, actual[key]) {
138+
return false
139+
}
140+
}
141+
142+
for key := range expected {
143+
_, exists := actual[key]
144+
if !exists && expected[key] != nil {
145+
// Fails match if cassettes contains a field not in actual requests
146+
// Fields should not disappear from requests unless a sdk breaking change
147+
// We ignore if field is nil in cassette as it could be an old deprecated and unused field
148+
return false
149+
}
150+
}
151+
return true
152+
}

internal/acctest/checks.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package acctest
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
9+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
10+
)
11+
12+
// CheckResourceIDChanged checks that the ID of the resource has indeed changed, in case of ForceNew for example.
13+
// It will fail if resourceID is empty so be sure to use acctest.CheckResourceIDPersisted first in a test suite.
14+
func CheckResourceIDChanged(resourceName string, resourceID *string) resource.TestCheckFunc {
15+
return func(s *terraform.State) error {
16+
if resourceID == nil || *resourceID == "" {
17+
return errors.New("resourceID was not set")
18+
}
19+
rs, ok := s.RootModule().Resources[resourceName]
20+
if !ok {
21+
return fmt.Errorf("resource was not found: %s", resourceName)
22+
}
23+
if *resourceID == rs.Primary.ID {
24+
return errors.New("resource ID persisted when it should have changed")
25+
}
26+
*resourceID = rs.Primary.ID
27+
return nil
28+
}
29+
}
30+
31+
// CheckResourceIDPersisted checks that the ID of the resource is the same throughout tests of migration or mutation
32+
// It can be used to check that no ForceNew has been done
33+
func CheckResourceIDPersisted(resourceName string, resourceID *string) resource.TestCheckFunc {
34+
return func(s *terraform.State) error {
35+
rs, ok := s.RootModule().Resources[resourceName]
36+
if !ok {
37+
return fmt.Errorf("resource was not found: %s", resourceName)
38+
}
39+
if *resourceID != "" && *resourceID != rs.Primary.ID {
40+
return errors.New("resource ID changed when it should have persisted")
41+
}
42+
*resourceID = rs.Primary.ID
43+
return nil
44+
}
45+
}
46+
47+
// CheckResourceRawIDMatches asserts the equality of IDs from two specified attributes of two Scaleway resources.
48+
func CheckResourceRawIDMatches(res1, attr1, res2, attr2 string) resource.TestCheckFunc {
49+
return func(s *terraform.State) error {
50+
rs1, ok1 := s.RootModule().Resources[res1]
51+
if !ok1 {
52+
return fmt.Errorf("not found: %s", res1)
53+
}
54+
55+
rs2, ok2 := s.RootModule().Resources[res2]
56+
if !ok2 {
57+
return fmt.Errorf("not found: %s", res2)
58+
}
59+
60+
id1 := locality.ExpandID(rs1.Primary.Attributes[attr1])
61+
id2 := locality.ExpandID(rs2.Primary.Attributes[attr2])
62+
63+
if id1 != id2 {
64+
return fmt.Errorf("ID mismatch: %s from resource %s does not match ID %s from resource %s", id1, res1, id2, res2)
65+
}
66+
67+
return nil
68+
}
69+
}

0 commit comments

Comments
 (0)