Skip to content

Commit 203d336

Browse files
committed
Improve coverage for testing package
1 parent b5075f2 commit 203d336

File tree

2 files changed

+93
-102
lines changed

2 files changed

+93
-102
lines changed

qa/testing.go

Lines changed: 61 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"encoding/json"
77
"errors"
88
"fmt"
9-
"io/ioutil"
109
"log"
1110
"math/rand"
1211
"net/http"
@@ -92,6 +91,57 @@ type ResourceFixture struct {
9291
New bool
9392
}
9493

94+
// wrapper type for calling resource methords
95+
type resourceCRUD func(context.Context, *schema.ResourceData, interface{}) diag.Diagnostics
96+
97+
func (cb resourceCRUD) before(before func(d *schema.ResourceData)) resourceCRUD {
98+
return func(ctx context.Context, d *schema.ResourceData, i interface{}) diag.Diagnostics {
99+
before(d)
100+
return cb(ctx, d, i)
101+
}
102+
}
103+
104+
func (cb resourceCRUD) withId(id string) resourceCRUD {
105+
return cb.before(func(d *schema.ResourceData) {
106+
d.SetId(id)
107+
})
108+
}
109+
110+
func (f ResourceFixture) prepareExecution() (resourceCRUD, error) {
111+
switch {
112+
case f.Create:
113+
if f.ID != "" {
114+
return nil, fmt.Errorf("ID is not available for Create")
115+
}
116+
return resourceCRUD(f.Resource.CreateContext), nil
117+
case f.Read:
118+
if f.ID == "" {
119+
return nil, fmt.Errorf("ID must be set for Read")
120+
}
121+
preRead := f.State
122+
f.State = nil
123+
return resourceCRUD(f.Resource.ReadContext).before(func(d *schema.ResourceData) {
124+
if f.New {
125+
d.MarkNewResource()
126+
}
127+
for k, v := range preRead {
128+
d.Set(k, v)
129+
}
130+
}).withId(f.ID), nil
131+
case f.Update:
132+
if f.ID == "" {
133+
return nil, fmt.Errorf("ID must be set for Update")
134+
}
135+
return resourceCRUD(f.Resource.UpdateContext).withId(f.ID), nil
136+
case f.Delete:
137+
if f.ID == "" {
138+
return nil, fmt.Errorf("ID must be set for Delete")
139+
}
140+
return resourceCRUD(f.Resource.DeleteContext).withId(f.ID), nil
141+
}
142+
return nil, fmt.Errorf("no `Create|Read|Update|Delete: true` specificed")
143+
}
144+
95145
// Apply runs tests from fixture
96146
func (f ResourceFixture) Apply(t *testing.T) (*schema.ResourceData, error) {
97147
client, server, err := HttpFixtureClient(t, f.Fixtures)
@@ -122,70 +172,11 @@ func (f ResourceFixture) Apply(t *testing.T) (*schema.ResourceData, error) {
122172
}
123173
f.State = fixHCL(out).(map[string]interface{})
124174
}
125-
var whatever func(d *schema.ResourceData, c interface{}) error
126-
pick := func(
127-
a func(*schema.ResourceData, interface{}) error,
128-
b func(context.Context, *schema.ResourceData, interface{}) diag.Diagnostics,
129-
d *schema.ResourceData, m interface{}) error {
130-
if b != nil {
131-
ctx := context.Background()
132-
diags := b(ctx, d, m)
133-
if diags != nil {
134-
return fmt.Errorf(diagsToString(diags))
135-
}
136-
return nil
137-
}
138-
return a(d, m)
139-
}
140175
resourceConfig := terraform.NewResourceConfigRaw(f.State)
141-
switch {
142-
case f.Create:
143-
// nolint should be a bigger context-aware refactor
144-
whatever = func(d *schema.ResourceData, m interface{}) error {
145-
//lint:ignore SA1019 TODO - remove later
146-
return pick(f.Resource.Create, f.Resource.CreateContext, d, m)
147-
}
148-
if f.ID != "" {
149-
return nil, errors.New("ID is not available for Create")
150-
}
151-
case f.Read:
152-
if f.ID == "" {
153-
return nil, errors.New("ID must be set for Read")
154-
}
155-
preRead := f.State
156-
f.State = nil
157-
whatever = func(d *schema.ResourceData, m interface{}) error {
158-
d.SetId(f.ID)
159-
if f.New {
160-
d.MarkNewResource()
161-
}
162-
for k, v := range preRead {
163-
err = d.Set(k, v)
164-
assert.NoError(t, err)
165-
}
166-
return pick(f.Resource.Read, f.Resource.ReadContext, d, m)
167-
}
168-
case f.Update:
169-
if f.ID == "" {
170-
return nil, errors.New("ID must be set for Update")
171-
}
172-
if f.Resource.UpdateContext == nil && f.Resource.Update == nil {
173-
return nil, errors.New("resource does not support Update")
174-
}
175-
whatever = func(d *schema.ResourceData, m interface{}) error {
176-
d.SetId(f.ID)
177-
return pick(f.Resource.Update, f.Resource.UpdateContext, d, m)
178-
}
179-
case f.Delete:
180-
if f.ID == "" {
181-
return nil, errors.New("ID must be set for Delete")
182-
}
183-
whatever = func(d *schema.ResourceData, m interface{}) error {
184-
d.SetId(f.ID)
185-
return pick(f.Resource.Delete, f.Resource.DeleteContext, d, m)
186-
}
176+
execute, err := f.prepareExecution()
177+
if err != nil {
178+
return nil, err
187179
}
188-
189180
if f.State != nil {
190181
diags := f.Resource.Validate(resourceConfig)
191182
if diags.HasError() {
@@ -217,9 +208,12 @@ func (f ResourceFixture) Apply(t *testing.T) (*schema.ResourceData, error) {
217208
if err != nil {
218209
return nil, err
219210
}
220-
err = whatever(resourceData, client)
221-
if err != nil {
222-
return resourceData, err
211+
if execute != nil {
212+
// this is a bit strange, but we'll fix it later
213+
diags := execute(ctx, resourceData, client)
214+
if diags != nil {
215+
return resourceData, fmt.Errorf(diagsToString(diags))
216+
}
223217
}
224218
if resourceData.Id() == "" && !f.Removed {
225219
return resourceData, fmt.Errorf("resource is not expected to be removed")
@@ -542,7 +536,7 @@ func FirstKeyValue(t *testing.T, str, key string) string {
542536
r := regexp.MustCompile(key + `\s+=\s+"([^"]*)"`)
543537
match := r.FindStringSubmatch(str)
544538
if len(match) != 2 {
545-
t.Fatalf("Cannot fin d %s in given string", key)
539+
t.Fatalf("Cannot find %s in given string", key)
546540
}
547541
return match[1]
548542
}
@@ -552,23 +546,6 @@ func AssertErrorStartsWith(t *testing.T, err error, message string) bool {
552546
return err != nil && assert.True(t, strings.HasPrefix(err.Error(), message), err.Error())
553547
}
554548

555-
// TestCreateTempFile ...
556-
func TestCreateTempFile(t *testing.T, data string) string {
557-
tmpFile, err := ioutil.TempFile("", "tf-test-create-dbfs-file")
558-
if err != nil {
559-
t.Fatal(err)
560-
}
561-
filename := tmpFile.Name()
562-
563-
err = ioutil.WriteFile(filename, []byte(data), 0644)
564-
if err != nil {
565-
os.Remove(filename)
566-
t.Fatal(err)
567-
}
568-
569-
return filename
570-
}
571-
572549
// GetEnvOrSkipTest proceeds with test only with that env variable
573550
func GetEnvOrSkipTest(t *testing.T, name string) string {
574551
value := os.Getenv(name)

qa/testing_test.go

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import (
1313
"github.com/stretchr/testify/assert"
1414
)
1515

16+
func TestRandomEmail(t *testing.T) {
17+
email := RandomEmail()
18+
assert.NotEmpty(t, email)
19+
}
20+
1621
func TestRandomLongName(t *testing.T) {
1722
n := RandomLongName()
1823
assert.Equal(t, 37, len(n))
@@ -100,10 +105,10 @@ var noopResource = &schema.Resource{
100105
Required: true,
101106
},
102107
},
103-
Read: schema.Noop,
104-
Create: schema.Noop,
105-
Update: schema.Noop,
106-
Delete: schema.Noop,
108+
ReadContext: schema.NoopContext,
109+
CreateContext: schema.NoopContext,
110+
UpdateContext: schema.NoopContext,
111+
DeleteContext: schema.NoopContext,
107112
}
108113

109114
var noopContextResource = &schema.Resource{
@@ -129,12 +134,17 @@ var noopContextResource = &schema.Resource{
129134
}
130135

131136
func TestResourceFixture_ID(t *testing.T) {
137+
_, err := ResourceFixture{}.prepareExecution()
138+
assert.EqualError(t, err, "no `Create|Read|Update|Delete: true` specificed")
139+
132140
f := ResourceFixture{
133141
Resource: noopResource,
134142
Read: true,
143+
AzureSPN: true,
144+
Gcp: true,
135145
HCL: `dummy = true`,
136146
}
137-
_, err := f.Apply(t)
147+
_, err = f.Apply(t)
138148
assert.EqualError(t, err, "ID must be set for Read")
139149

140150
f.Read = false
@@ -159,10 +169,11 @@ func TestResourceFixture_ID(t *testing.T) {
159169
f.Removed = true
160170
_, err = f.Apply(t)
161171
assert.NoError(t, err)
172+
f.ApplyNoError(t)
162173
}
163174

164175
func TestResourceFixture_Apply(t *testing.T) {
165-
d, err := ResourceFixture{
176+
ResourceFixture{
166177
CommandMock: func(commandStr string) common.CommandResults {
167178
return common.CommandResults{
168179
ResultType: "text",
@@ -175,9 +186,7 @@ func TestResourceFixture_Apply(t *testing.T) {
175186
New: true,
176187
Read: true,
177188
HCL: `dummy = true`,
178-
}.Apply(t)
179-
assert.NoError(t, err)
180-
assert.Equal(t, true, d.Get("dummy"))
189+
}.ApplyNoError(t)
181190
}
182191

183192
func TestResourceFixture_ApplyDelete(t *testing.T) {
@@ -218,7 +227,7 @@ func TestResourceFixture_InstanceState(t *testing.T) {
218227
}
219228

220229
func TestResourceFixture_Apply_Fail(t *testing.T) {
221-
_, err := ResourceFixture{
230+
ResourceFixture{
222231
CommandMock: func(commandStr string) common.CommandResults {
223232
return common.CommandResults{
224233
ResultType: "text",
@@ -231,13 +240,7 @@ func TestResourceFixture_Apply_Fail(t *testing.T) {
231240
"dummy": true,
232241
"check": false,
233242
},
234-
}.Apply(t)
235-
assert.EqualError(t, err, "invalid config supplied. [check] Invalid or unknown key")
236-
}
237-
238-
func TestTestCreateTempFile(t *testing.T) {
239-
a := TestCreateTempFile(t, "abc")
240-
assert.FileExists(t, a)
243+
}.ExpectError(t, "invalid config supplied. [check] Invalid or unknown key")
241244
}
242245

243246
func TestUnionFixturesLists(t *testing.T) {
@@ -264,6 +267,10 @@ func TestGetEnvOrSkipTest(t *testing.T) {
264267
assert.NotEmpty(t, u)
265268
}
266269

270+
func TestGetEnvOrSkipTest_Skip(t *testing.T) {
271+
GetEnvOrSkipTest(t, "")
272+
}
273+
267274
func TestDiagsToString(t *testing.T) {
268275
var d diag.Diagnostics
269276
assert.Empty(t, diagsToString(d))
@@ -308,5 +315,12 @@ func TestResourceCornerCases(t *testing.T) {
308315
Required: true,
309316
},
310317
},
311-
}.ToResource(), CornerCaseID("x"))
318+
}.ToResource(),
319+
CornerCaseID("x"),
320+
CornerCaseExpectError("I'm a teapot"),
321+
CornerCaseSkipCRUD("head"))
322+
}
323+
324+
func TestAssertErrorStartsWith(t *testing.T) {
325+
AssertErrorStartsWith(t, fmt.Errorf("abc"), "a")
312326
}

0 commit comments

Comments
 (0)