Skip to content

Commit ba04167

Browse files
authored
internal/testing: Initial testsdk and testprovider packages (#166)
Reference: #151 Creates an internal terraform-plugin-go based SDK and declarative provider for unit testing for within this Go module. The new `helper/resource` tests should be equivalent to the existing terraform-plugin-sdk based `TestTest_TestStep_ExternalProviders_To_ProviderFactories` and `TestTest_TestStep_ProviderFactories_To_ExternalProviders` tests.
1 parent 12db397 commit ba04167

File tree

19 files changed

+1471
-0
lines changed

19 files changed

+1471
-0
lines changed

helper/resource/teststep_providers_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@ import (
1717
"github.com/hashicorp/go-cty/cty"
1818
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
1919
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
20+
"github.com/hashicorp/terraform-plugin-go/tftypes"
2021

2122
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
2223
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
2324
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2425

2526
"github.com/hashicorp/terraform-plugin-testing/internal/plugintest"
27+
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testprovider"
28+
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/providerserver"
29+
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource"
2630
"github.com/hashicorp/terraform-plugin-testing/terraform"
2731
)
2832

@@ -1142,6 +1146,53 @@ func TestTest_TestStep_ExternalProvidersAndProviderFactories_NonHashiCorpNamespa
11421146
})
11431147
}
11441148

1149+
func TestTest_TestStep_ExternalProviders_To_ProtoV6ProviderFactories(t *testing.T) {
1150+
t.Parallel()
1151+
1152+
Test(t, TestCase{
1153+
Steps: []TestStep{
1154+
{
1155+
Config: `resource "null_resource" "test" {}`,
1156+
ExternalProviders: map[string]ExternalProvider{
1157+
"null": {
1158+
Source: "registry.terraform.io/hashicorp/null",
1159+
VersionConstraint: "3.1.1",
1160+
},
1161+
},
1162+
},
1163+
{
1164+
Config: `resource "null_resource" "test" {}`,
1165+
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
1166+
"null": providerserver.NewProviderServer(testprovider.Provider{
1167+
Resources: map[string]testprovider.Resource{
1168+
"null_resource": {
1169+
SchemaResponse: &resource.SchemaResponse{
1170+
Schema: &tfprotov6.Schema{
1171+
Block: &tfprotov6.SchemaBlock{
1172+
Attributes: []*tfprotov6.SchemaAttribute{
1173+
{
1174+
Name: "id",
1175+
Type: tftypes.String,
1176+
Computed: true,
1177+
},
1178+
{
1179+
Name: "triggers",
1180+
Type: tftypes.Map{ElementType: tftypes.String},
1181+
Optional: true,
1182+
},
1183+
},
1184+
},
1185+
},
1186+
},
1187+
},
1188+
},
1189+
}),
1190+
},
1191+
},
1192+
},
1193+
})
1194+
}
1195+
11451196
func TestTest_TestStep_ExternalProviders_To_ProviderFactories(t *testing.T) {
11461197
t.Parallel()
11471198

@@ -1406,6 +1457,66 @@ func TestTest_TestStep_ProtoV6ProviderFactories_Error(t *testing.T) {
14061457
})
14071458
}
14081459

1460+
func TestTest_TestStep_ProtoV6ProviderFactories_To_ExternalProviders(t *testing.T) {
1461+
t.Parallel()
1462+
1463+
Test(t, TestCase{
1464+
Steps: []TestStep{
1465+
{
1466+
Config: `resource "null_resource" "test" {}`,
1467+
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
1468+
"null": providerserver.NewProviderServer(testprovider.Provider{
1469+
Resources: map[string]testprovider.Resource{
1470+
"null_resource": {
1471+
CreateResponse: &resource.CreateResponse{
1472+
NewState: tftypes.NewValue(
1473+
tftypes.Object{
1474+
AttributeTypes: map[string]tftypes.Type{
1475+
"id": tftypes.String,
1476+
"triggers": tftypes.Map{ElementType: tftypes.String},
1477+
},
1478+
},
1479+
map[string]tftypes.Value{
1480+
"id": tftypes.NewValue(tftypes.String, "test"),
1481+
"triggers": tftypes.NewValue(tftypes.Map{ElementType: tftypes.String}, nil),
1482+
},
1483+
),
1484+
},
1485+
SchemaResponse: &resource.SchemaResponse{
1486+
Schema: &tfprotov6.Schema{
1487+
Block: &tfprotov6.SchemaBlock{
1488+
Attributes: []*tfprotov6.SchemaAttribute{
1489+
{
1490+
Name: "id",
1491+
Type: tftypes.String,
1492+
Computed: true,
1493+
},
1494+
{
1495+
Name: "triggers",
1496+
Type: tftypes.Map{ElementType: tftypes.String},
1497+
Optional: true,
1498+
},
1499+
},
1500+
},
1501+
},
1502+
},
1503+
},
1504+
},
1505+
}),
1506+
},
1507+
},
1508+
{
1509+
Config: `resource "null_resource" "test" {}`,
1510+
ExternalProviders: map[string]ExternalProvider{
1511+
"null": {
1512+
Source: "registry.terraform.io/hashicorp/null",
1513+
},
1514+
},
1515+
},
1516+
},
1517+
})
1518+
}
1519+
14091520
func TestTest_TestStep_ProviderFactories(t *testing.T) {
14101521
t.Parallel()
14111522

internal/testing/doc.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
// Package testing contains functionality and helpers for unit testing within
5+
// this Go module.
6+
package testing
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package testprovider
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/datasource"
10+
)
11+
12+
var _ datasource.DataSource = DataSource{}
13+
14+
type DataSource struct {
15+
ReadResponse *datasource.ReadResponse
16+
SchemaResponse *datasource.SchemaResponse
17+
ValidateConfigResponse *datasource.ValidateConfigResponse
18+
}
19+
20+
func (d DataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
21+
if d.ReadResponse != nil {
22+
resp.Diagnostics = d.ReadResponse.Diagnostics
23+
resp.State = d.ReadResponse.State
24+
}
25+
}
26+
27+
func (d DataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
28+
if d.SchemaResponse != nil {
29+
resp.Diagnostics = d.SchemaResponse.Diagnostics
30+
resp.Schema = d.SchemaResponse.Schema
31+
}
32+
}
33+
34+
func (d DataSource) ValidateConfig(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) {
35+
if d.ValidateConfigResponse != nil {
36+
resp.Diagnostics = d.ValidateConfigResponse.Diagnostics
37+
}
38+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
// Package testprovider is a declarative provider for implementing unit testing
5+
// within this Go module.
6+
package testprovider
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package testprovider
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
10+
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/datasource"
11+
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/provider"
12+
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource"
13+
)
14+
15+
var _ provider.Provider = Provider{}
16+
17+
// Provider is a declarative provider implementation for unit testing in this
18+
// Go module.
19+
type Provider struct {
20+
ConfigureResponse *provider.ConfigureResponse
21+
DataSources map[string]DataSource
22+
Resources map[string]Resource
23+
SchemaResponse *provider.SchemaResponse
24+
StopResponse *provider.StopResponse
25+
ValidateConfigResponse *provider.ValidateConfigResponse
26+
}
27+
28+
func (p Provider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
29+
if p.ConfigureResponse != nil {
30+
resp.Diagnostics = p.ConfigureResponse.Diagnostics
31+
}
32+
}
33+
34+
func (p Provider) DataSourcesMap() map[string]datasource.DataSource {
35+
datasources := make(map[string]datasource.DataSource, len(p.DataSources))
36+
37+
for typeName, d := range p.DataSources {
38+
datasources[typeName] = d
39+
}
40+
41+
return datasources
42+
}
43+
44+
func (p Provider) ResourcesMap() map[string]resource.Resource {
45+
resources := make(map[string]resource.Resource, len(p.Resources))
46+
47+
for typeName, d := range p.Resources {
48+
resources[typeName] = d
49+
}
50+
51+
return resources
52+
}
53+
54+
func (p Provider) Stop(ctx context.Context, req provider.StopRequest, resp *provider.StopResponse) {
55+
if p.StopResponse != nil {
56+
resp.Error = p.StopResponse.Error
57+
}
58+
}
59+
60+
func (p Provider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
61+
if p.SchemaResponse != nil {
62+
resp.Diagnostics = p.SchemaResponse.Diagnostics
63+
resp.Schema = p.SchemaResponse.Schema
64+
}
65+
66+
resp.Schema = &tfprotov6.Schema{
67+
Block: &tfprotov6.SchemaBlock{},
68+
}
69+
}
70+
71+
func (p Provider) ValidateConfig(ctx context.Context, req provider.ValidateConfigRequest, resp *provider.ValidateConfigResponse) {
72+
if p.ValidateConfigResponse != nil {
73+
resp.Diagnostics = p.ValidateConfigResponse.Diagnostics
74+
}
75+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package testprovider
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource"
10+
)
11+
12+
var _ resource.Resource = Resource{}
13+
14+
type Resource struct {
15+
CreateResponse *resource.CreateResponse
16+
DeleteResponse *resource.DeleteResponse
17+
ImportStateResponse *resource.ImportStateResponse
18+
19+
// Planning happens multiple ways during a single TestStep, so statically
20+
// defining only the response is very problematic.
21+
PlanChangeFunc func(context.Context, resource.PlanChangeRequest, *resource.PlanChangeResponse)
22+
23+
ReadResponse *resource.ReadResponse
24+
SchemaResponse *resource.SchemaResponse
25+
UpdateResponse *resource.UpdateResponse
26+
UpgradeStateResponse *resource.UpgradeStateResponse
27+
ValidateConfigResponse *resource.ValidateConfigResponse
28+
}
29+
30+
func (r Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
31+
if r.CreateResponse != nil {
32+
resp.Diagnostics = r.CreateResponse.Diagnostics
33+
resp.NewState = r.CreateResponse.NewState
34+
}
35+
}
36+
37+
func (r Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
38+
if r.DeleteResponse != nil {
39+
resp.Diagnostics = r.DeleteResponse.Diagnostics
40+
}
41+
}
42+
43+
func (r Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
44+
if r.ImportStateResponse != nil {
45+
resp.Diagnostics = r.ImportStateResponse.Diagnostics
46+
resp.State = r.ImportStateResponse.State
47+
}
48+
}
49+
50+
func (r Resource) PlanChange(ctx context.Context, req resource.PlanChangeRequest, resp *resource.PlanChangeResponse) {
51+
if r.PlanChangeFunc != nil {
52+
r.PlanChangeFunc(ctx, req, resp)
53+
}
54+
}
55+
56+
func (r Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
57+
if r.ReadResponse != nil {
58+
resp.Diagnostics = r.ReadResponse.Diagnostics
59+
resp.NewState = r.ReadResponse.NewState
60+
}
61+
}
62+
63+
func (r Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
64+
if r.SchemaResponse != nil {
65+
resp.Diagnostics = r.SchemaResponse.Diagnostics
66+
resp.Schema = r.SchemaResponse.Schema
67+
}
68+
}
69+
70+
func (r Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
71+
if r.UpdateResponse != nil {
72+
resp.Diagnostics = r.UpdateResponse.Diagnostics
73+
resp.NewState = r.UpdateResponse.NewState
74+
}
75+
}
76+
77+
func (r Resource) UpgradeState(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
78+
if r.UpgradeStateResponse != nil {
79+
resp.Diagnostics = r.UpgradeStateResponse.Diagnostics
80+
resp.UpgradedState = r.UpgradeStateResponse.UpgradedState
81+
}
82+
}
83+
84+
func (r Resource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
85+
if r.ValidateConfigResponse != nil {
86+
resp.Diagnostics = r.ValidateConfigResponse.Diagnostics
87+
}
88+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package datasource
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
10+
"github.com/hashicorp/terraform-plugin-go/tftypes"
11+
)
12+
13+
type DataSource interface {
14+
Read(context.Context, ReadRequest, *ReadResponse)
15+
Schema(context.Context, SchemaRequest, *SchemaResponse)
16+
ValidateConfig(context.Context, ValidateConfigRequest, *ValidateConfigResponse)
17+
}
18+
19+
type ReadRequest struct {
20+
Config tftypes.Value
21+
}
22+
23+
type ReadResponse struct {
24+
Diagnostics []*tfprotov6.Diagnostic
25+
State tftypes.Value
26+
}
27+
28+
type SchemaRequest struct{}
29+
30+
type SchemaResponse struct {
31+
Diagnostics []*tfprotov6.Diagnostic
32+
Schema *tfprotov6.Schema
33+
}
34+
35+
type ValidateConfigRequest struct {
36+
Config tftypes.Value
37+
}
38+
39+
type ValidateConfigResponse struct {
40+
Diagnostics []*tfprotov6.Diagnostic
41+
}

0 commit comments

Comments
 (0)