Skip to content

Commit 9b49bd6

Browse files
authored
Merge pull request #43390 from hashicorp/td-resource-identity-generate-existing-resource-tests
Resource Identity: Generate Identity upgrade tests for existing resources
2 parents d0746da + 9f65538 commit 9b49bd6

File tree

448 files changed

+21966
-9199
lines changed

Some content is hidden

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

448 files changed

+21966
-9199
lines changed

internal/generate/common/generator.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ func (g *Generator) NewUnformattedFileDestination(filename string) Destination {
8686
}
8787
}
8888

89+
func (g *Generator) NewFileDestinationWithFormatter(filename string, formatter func([]byte) ([]byte, error)) Destination {
90+
return &fileDestination{
91+
filename: filename,
92+
baseDestination: baseDestination{
93+
formatter: formatter,
94+
},
95+
}
96+
}
97+
8998
type fileDestination struct {
9099
baseDestination
91100
append bool

internal/generate/identitytests/main.go

Lines changed: 142 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"time"
2626

2727
"github.com/dlclark/regexp2"
28+
"github.com/hashicorp/go-version"
2829
acctestgen "github.com/hashicorp/terraform-provider-aws/internal/acctest/generate"
2930
"github.com/hashicorp/terraform-provider-aws/internal/generate/common"
3031
"github.com/hashicorp/terraform-provider-aws/internal/generate/tests"
@@ -133,6 +134,7 @@ func main() {
133134
"inc": func(i int) int {
134135
return i + 1
135136
},
137+
"NewVersion": version.NewVersion,
136138
}
137139
templates, err := template.New("identitytests").Funcs(templateFuncMap).Parse(resourceTestGoTmpl)
138140
if err != nil {
@@ -147,34 +149,38 @@ func main() {
147149
g.Fatalf("generating file (%s): %s", filename, err)
148150
}
149151

150-
basicConfigTmplFile := path.Join("testdata", "tmpl", fmt.Sprintf("%s_basic.gtpl", sourceName))
152+
basicConfigTmplFile := fmt.Sprintf("%s_basic.gtpl", sourceName)
153+
basicConfigTmplPath := path.Join("testdata", "tmpl", basicConfigTmplFile)
151154
var configTmplFile string
152-
var configTmpl string
153-
if _, err := os.Stat(basicConfigTmplFile); err == nil {
155+
var configTmplPath string
156+
if _, err := os.Stat(basicConfigTmplPath); err == nil {
154157
configTmplFile = basicConfigTmplFile
158+
configTmplPath = basicConfigTmplPath
155159
} else if !errors.Is(err, os.ErrNotExist) {
156-
g.Fatalf("accessing config template %q: %w", basicConfigTmplFile, err)
160+
g.Fatalf("accessing config template %q: %w", basicConfigTmplPath, err)
157161
}
158162

159-
tagsConfigTmplFile := path.Join("testdata", "tmpl", fmt.Sprintf("%s_tags.gtpl", sourceName))
160-
if configTmplFile == "" {
161-
if _, err := os.Stat(tagsConfigTmplFile); err == nil {
163+
tagsConfigTmplFile := fmt.Sprintf("%s_tags.gtpl", sourceName)
164+
tagsConfigTmplPath := path.Join("testdata", "tmpl", tagsConfigTmplFile)
165+
if configTmplPath == "" {
166+
if _, err := os.Stat(tagsConfigTmplPath); err == nil {
162167
configTmplFile = tagsConfigTmplFile
168+
configTmplPath = tagsConfigTmplPath
163169
} else if !errors.Is(err, os.ErrNotExist) {
164-
g.Fatalf("accessing config template %q: %w", tagsConfigTmplFile, err)
170+
g.Fatalf("accessing config template %q: %w", tagsConfigTmplPath, err)
165171
}
166172
}
167173

168-
if configTmplFile == "" {
169-
g.Errorf("no config template found for %q at %q or %q", sourceName, basicConfigTmplFile, tagsConfigTmplFile)
174+
if configTmplPath == "" {
175+
g.Errorf("no config template found for %q at %q or %q", sourceName, basicConfigTmplPath, tagsConfigTmplPath)
170176
continue
171177
}
172178

173-
b, err := os.ReadFile(configTmplFile)
179+
b, err := os.ReadFile(configTmplPath)
174180
if err != nil {
175-
g.Fatalf("reading config template %q: %w", configTmplFile, err)
181+
g.Fatalf("reading config template %q: %w", configTmplPath, err)
176182
}
177-
configTmpl = string(b)
183+
configTmpl := string(b)
178184
resource.GenerateConfig = true
179185

180186
if resource.GenerateConfig {
@@ -194,7 +200,7 @@ func main() {
194200

195201
_, err = tfTemplates.New("body").Parse(configTmpl)
196202
if err != nil {
197-
g.Fatalf("parsing config template %q: %s", tagsConfigTmplFile, err)
203+
g.Fatalf("parsing config template %q: %s", configTmplPath, err)
198204
}
199205

200206
_, err = tfTemplates.New("region").Parse("")
@@ -204,11 +210,63 @@ func main() {
204210

205211
common := commonConfig{
206212
AdditionalTfVars: additionalTfVars,
213+
RequiredEnvVars: resource.RequiredEnvVars,
207214
WithRName: (resource.Generator != ""),
208215
}
209216

210217
generateTestConfig(g, testDirPath, "basic", tfTemplates, common)
211218

219+
// if resource.HasV6_0SDKv2Fix {
220+
if !resource.MutableIdentity {
221+
if resource.PreIdentityVersion.Equal(v5_100_0) {
222+
tfTemplatesV5, err := tfTemplates.Clone()
223+
if err != nil {
224+
g.Fatalf("cloning Terraform config template: %s", err)
225+
}
226+
ext := filepath.Ext(configTmplFile)
227+
name := strings.TrimSuffix(configTmplFile, ext)
228+
configTmplV5File := name + "_v5.100.0" + ext
229+
configTmplV5Path := path.Join("testdata", "tmpl", configTmplV5File)
230+
if _, err := os.Stat(configTmplV5Path); err == nil {
231+
b, err := os.ReadFile(configTmplV5Path)
232+
if err != nil {
233+
g.Fatalf("reading config template %q: %s", configTmplV5Path, err)
234+
}
235+
configTmplV5 := string(b)
236+
_, err = tfTemplatesV5.New("body").Parse(configTmplV5)
237+
if err != nil {
238+
g.Fatalf("parsing config template %q: %s", configTmplV5Path, err)
239+
}
240+
}
241+
commonV5 := common
242+
commonV5.ExternalProviders = map[string]requiredProvider{
243+
"aws": {
244+
Source: "hashicorp/aws",
245+
Version: "5.100.0",
246+
},
247+
}
248+
generateTestConfig(g, testDirPath, "basic_v5.100.0", tfTemplatesV5, commonV5)
249+
250+
commonV6 := common
251+
commonV6.ExternalProviders = map[string]requiredProvider{
252+
"aws": {
253+
Source: "hashicorp/aws",
254+
Version: "6.0.0",
255+
},
256+
}
257+
generateTestConfig(g, testDirPath, "basic_v6.0.0", tfTemplates, commonV6)
258+
} else {
259+
commonPreIdentity := common
260+
commonPreIdentity.ExternalProviders = map[string]requiredProvider{
261+
"aws": {
262+
Source: "hashicorp/aws",
263+
Version: resource.PreIdentityVersion.String(),
264+
},
265+
}
266+
generateTestConfig(g, testDirPath, fmt.Sprintf("basic_v%s", resource.PreIdentityVersion.String()), tfTemplates, commonPreIdentity)
267+
}
268+
}
269+
212270
_, err = tfTemplates.New("region").Parse("\n region = var.region\n")
213271
if err != nil {
214272
g.Fatalf("parsing config template: %s", err)
@@ -227,6 +285,10 @@ func main() {
227285
}
228286
}
229287

288+
var (
289+
v5_100_0 = version.Must(version.NewVersion("5.100.0"))
290+
)
291+
230292
type serviceRecords struct {
231293
primary data.ServiceRecord
232294
additional []data.ServiceRecord
@@ -379,6 +441,10 @@ type ResourceDatum struct {
379441
identityAttribute string
380442
IdentityDuplicateAttrs []string
381443
IDAttrFormat string
444+
HasV6_0NullValuesError bool
445+
HasV6_0RefreshError bool
446+
RequiredEnvVars []string
447+
PreIdentityVersion *version.Version
382448
}
383449

384450
func (d ResourceDatum) AdditionalTfVars() map[string]string {
@@ -475,9 +541,16 @@ type codeBlock struct {
475541
}
476542

477543
type commonConfig struct {
478-
AdditionalTfVars []string
479-
WithRName bool
480-
WithRegion bool
544+
AdditionalTfVars []string
545+
WithRName bool
546+
WithRegion bool
547+
ExternalProviders map[string]requiredProvider
548+
RequiredEnvVars []string
549+
}
550+
551+
type requiredProvider struct {
552+
Source string
553+
Version string
481554
}
482555

483556
type ConfigDatum struct {
@@ -556,6 +629,7 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) {
556629
HasExistsFunc: true,
557630
HasRegionOverrideTest: true,
558631
plannableImportAction: importActionNoop,
632+
PreIdentityVersion: version.Must(version.NewVersion("5.100.0")),
559633
}
560634
hasIdentity := false
561635
skip := false
@@ -686,6 +760,19 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) {
686760
case "NoImport":
687761
d.NoImport = true
688762

763+
// TODO: allow underscore?
764+
case "V60SDKv2Fix":
765+
d.HasV6_0NullValuesError = true
766+
767+
args := common.ParseArgs(m[3])
768+
if attr, ok := args.Keyword["v60RefreshError"]; ok {
769+
if b, err := strconv.ParseBool(attr); err != nil {
770+
v.errs = append(v.errs, fmt.Errorf("invalid v60RefreshError value (%s): %s: %w", attr, fmt.Sprintf("%s.%s", v.packageName, v.functionName), err))
771+
} else {
772+
d.HasV6_0RefreshError = b
773+
}
774+
}
775+
689776
case "Testing":
690777
args := common.ParseArgs(m[3])
691778

@@ -912,7 +999,7 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) {
912999
}
9131000
if attr, ok := args.Keyword["serializeDelay"]; ok {
9141001
if b, err := strconv.ParseBool(attr); err != nil {
915-
v.errs = append(v.errs, fmt.Errorf("invalid serializeDelay value: %q at %s. Should be duration value.", attr, fmt.Sprintf("%s.%s", v.packageName, v.functionName)))
1002+
v.errs = append(v.errs, fmt.Errorf("invalid serializeDelay value: %q at %s. Should be boolean value.", attr, fmt.Sprintf("%s.%s", v.packageName, v.functionName)))
9161003
continue
9171004
} else {
9181005
d.SerializeDelay = b
@@ -940,6 +1027,28 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) {
9401027
d.HasRegionOverrideTest = b
9411028
}
9421029
}
1030+
if attr, ok := args.Keyword["v60NullValuesError"]; ok {
1031+
if b, err := strconv.ParseBool(attr); err != nil {
1032+
v.errs = append(v.errs, fmt.Errorf("invalid v60NullValuesError value (%s): %s: %w", attr, fmt.Sprintf("%s.%s", v.packageName, v.functionName), err))
1033+
} else {
1034+
d.HasV6_0NullValuesError = b
1035+
}
1036+
}
1037+
if attr, ok := args.Keyword["v60RefreshError"]; ok {
1038+
if b, err := strconv.ParseBool(attr); err != nil {
1039+
v.errs = append(v.errs, fmt.Errorf("invalid v60RefreshError value (%s): %s: %w", attr, fmt.Sprintf("%s.%s", v.packageName, v.functionName), err))
1040+
} else {
1041+
d.HasV6_0RefreshError = b
1042+
}
1043+
}
1044+
if attr, ok := args.Keyword["preIdentityVersion"]; ok {
1045+
version, err := version.NewVersion(attr)
1046+
if err != nil {
1047+
v.errs = append(v.errs, fmt.Errorf("invalid preIdentityVersion value: %q at %s. Should be version value.", attr, fmt.Sprintf("%s.%s", v.packageName, v.functionName)))
1048+
continue
1049+
}
1050+
d.PreIdentityVersion = version
1051+
}
9431052
if attr, ok := args.Keyword["tlsKey"]; ok {
9441053
if b, err := strconv.ParseBool(attr); err != nil {
9451054
v.errs = append(v.errs, fmt.Errorf("invalid tlsKey value: %q at %s. Should be boolean value.", attr, fmt.Sprintf("%s.%s", v.packageName, v.functionName)))
@@ -951,6 +1060,10 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) {
9511060
if attr, ok := args.Keyword["tlsKeyDomain"]; ok {
9521061
tlsKeyCN = attr
9531062
}
1063+
1064+
if attr, ok := args.Keyword["requireEnvVar"]; ok {
1065+
d.RequiredEnvVars = append(d.RequiredEnvVars, attr)
1066+
}
9541067
}
9551068
}
9561069
}
@@ -1029,18 +1142,26 @@ func (v *visitor) Visit(node ast.Node) ast.Visitor {
10291142
return v
10301143
}
10311144

1032-
func generateTestConfig(g *common.Generator, dirPath, test string, tfTemplates *template.Template, common commonConfig) {
1145+
func generateTestConfig(g *common.Generator, dirPath, test string, tfTemplates *template.Template, config commonConfig) {
10331146
testName := test
10341147
dirPath = path.Join(dirPath, testName)
10351148
if err := os.MkdirAll(dirPath, 0755); err != nil {
10361149
g.Fatalf("creating test directory %q: %w", dirPath, err)
10371150
}
10381151

10391152
mainPath := path.Join(dirPath, "main_gen.tf")
1040-
tf := g.NewUnformattedFileDestination(mainPath)
1153+
var tf common.Destination
1154+
if test == "basic_v5.100.0" {
1155+
tf = g.NewFileDestinationWithFormatter(mainPath, func(b []byte) ([]byte, error) {
1156+
re := regexp.MustCompile(`(data\.aws_region\.\w+)\.region`) // nosemgrep:ci.calling-regexp.MustCompile-directly
1157+
return re.ReplaceAll(b, []byte("$1.name")), nil
1158+
})
1159+
} else {
1160+
tf = g.NewUnformattedFileDestination(mainPath)
1161+
}
10411162

10421163
configData := ConfigDatum{
1043-
commonConfig: common,
1164+
commonConfig: config,
10441165
}
10451166
if err := tf.BufferTemplateSet(tfTemplates, configData); err != nil {
10461167
g.Fatalf("error generating Terraform file %q: %s", mainPath, err)

0 commit comments

Comments
 (0)