-
Notifications
You must be signed in to change notification settings - Fork 9.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Testing Framework] Add test file HCL configuration and parser functionality #33325
Merged
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
4e373dd
Add test structure to views package for rendering test output
liamcervante 7a8d712
Add test file HCL configuration and parser functionality
liamcervante 295ffc5
Merge branch 'main' of github.com:hashicorp/terraform into liamcervan…
liamcervante cbc5ddf
address comments
liamcervante File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,7 +32,7 @@ import ( | |
// .tf files are parsed using the HCL native syntax while .tf.json files are | ||
// parsed using the HCL JSON syntax. | ||
func (p *Parser) LoadConfigDir(path string) (*Module, hcl.Diagnostics) { | ||
primaryPaths, overridePaths, diags := p.dirFiles(path) | ||
primaryPaths, overridePaths, _, diags := p.dirFiles(path, "") | ||
if diags.HasErrors() { | ||
return nil, diags | ||
} | ||
|
@@ -50,20 +50,51 @@ func (p *Parser) LoadConfigDir(path string) (*Module, hcl.Diagnostics) { | |
return mod, diags | ||
} | ||
|
||
// LoadConfigDirWithTests matches LoadConfigDir, but the return Module also | ||
// contains any relevant .tftest files. | ||
func (p *Parser) LoadConfigDirWithTests(path string, testDirectory string) (*Module, hcl.Diagnostics) { | ||
primaryPaths, overridePaths, testPaths, diags := p.dirFiles(path, testDirectory) | ||
if diags.HasErrors() { | ||
return nil, diags | ||
} | ||
|
||
primary, fDiags := p.loadFiles(primaryPaths, false) | ||
diags = append(diags, fDiags...) | ||
override, fDiags := p.loadFiles(overridePaths, true) | ||
diags = append(diags, fDiags...) | ||
tests, fDiags := p.loadTestFiles(path, testPaths) | ||
diags = append(diags, fDiags...) | ||
|
||
mod, modDiags := NewModuleWithTests(primary, override, tests) | ||
diags = append(diags, modDiags...) | ||
|
||
mod.SourceDir = path | ||
|
||
return mod, diags | ||
} | ||
|
||
// ConfigDirFiles returns lists of the primary and override files configuration | ||
// files in the given directory. | ||
// | ||
// If the given directory does not exist or cannot be read, error diagnostics | ||
// are returned. If errors are returned, the resulting lists may be incomplete. | ||
func (p Parser) ConfigDirFiles(dir string) (primary, override []string, diags hcl.Diagnostics) { | ||
return p.dirFiles(dir) | ||
primary, override, _, diags = p.dirFiles(dir, "") | ||
return primary, override, diags | ||
} | ||
|
||
// ConfigDirFilesWithTests matches ConfigDirFiles except it also returns the | ||
// paths to any test files within the module. | ||
func (p Parser) ConfigDirFilesWithTests(dir string, testDirectory string) (primary, override, tests []string, diags hcl.Diagnostics) { | ||
return p.dirFiles(dir, testDirectory) | ||
} | ||
|
||
// IsConfigDir determines whether the given path refers to a directory that | ||
// exists and contains at least one Terraform config file (with a .tf or | ||
// .tf.json extension.) | ||
// .tf.json extension.). Note, we explicitely exclude checking for tests here | ||
// as tests must live alongside actual .tf config files. | ||
func (p *Parser) IsConfigDir(path string) bool { | ||
primaryPaths, overridePaths, _ := p.dirFiles(path) | ||
primaryPaths, overridePaths, _, _ := p.dirFiles(path, "") | ||
return (len(primaryPaths) + len(overridePaths)) > 0 | ||
} | ||
|
||
|
@@ -88,7 +119,9 @@ func (p *Parser) loadFiles(paths []string, override bool) ([]*File, hcl.Diagnost | |
return files, diags | ||
} | ||
|
||
func (p *Parser) dirFiles(dir string) (primary, override []string, diags hcl.Diagnostics) { | ||
func (p *Parser) dirFiles(dir string, testsDir string) (primary, override, tests []string, diags hcl.Diagnostics) { | ||
includeTests := len(testsDir) > 0 | ||
|
||
infos, err := p.fs.ReadDir(dir) | ||
if err != nil { | ||
diags = append(diags, &hcl.Diagnostic{ | ||
|
@@ -101,7 +134,31 @@ func (p *Parser) dirFiles(dir string) (primary, override []string, diags hcl.Dia | |
|
||
for _, info := range infos { | ||
if info.IsDir() { | ||
// We only care about files | ||
if includeTests && info.Name() == testsDir { | ||
testsDir := filepath.Join(dir, info.Name()) | ||
testInfos, err := p.fs.ReadDir(testsDir) | ||
if err != nil { | ||
diags = append(diags, &hcl.Diagnostic{ | ||
Severity: hcl.DiagError, | ||
Summary: "Failed to read module test directory", | ||
Detail: fmt.Sprintf("Module test directory %s does not exist or cannot be read.", testsDir), | ||
}) | ||
return | ||
} | ||
|
||
for _, testInfo := range testInfos { | ||
if testInfo.IsDir() || IsIgnoredFile(testInfo.Name()) { | ||
continue | ||
} | ||
|
||
if strings.HasSuffix(testInfo.Name(), ".tftest") || strings.HasSuffix(testInfo.Name(), ".tftest.json") { | ||
tests = append(tests, filepath.Join(testsDir, testInfo.Name())) | ||
} | ||
} | ||
} | ||
|
||
// We only care about the tests directory or terraform configuration | ||
// files. | ||
continue | ||
} | ||
|
||
|
@@ -111,6 +168,13 @@ func (p *Parser) dirFiles(dir string) (primary, override []string, diags hcl.Dia | |
continue | ||
} | ||
|
||
if ext == ".tftest" || ext == ".tftest.json" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we handle There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was a bug, fixed and added a test that loads .tftest.json files to verify the fix. |
||
if includeTests { | ||
tests = append(tests, filepath.Join(dir, name)) | ||
} | ||
continue | ||
} | ||
|
||
baseName := name[:len(name)-len(ext)] // strip extension | ||
isOverride := baseName == "override" || strings.HasSuffix(baseName, "_override") | ||
|
||
|
@@ -125,13 +189,41 @@ func (p *Parser) dirFiles(dir string) (primary, override []string, diags hcl.Dia | |
return | ||
} | ||
|
||
func (p *Parser) loadTestFiles(basePath string, paths []string) (map[string]*TestFile, hcl.Diagnostics) { | ||
var diags hcl.Diagnostics | ||
|
||
tfs := make(map[string]*TestFile) | ||
for _, path := range paths { | ||
tf, fDiags := p.LoadTestFile(path) | ||
diags = append(diags, fDiags...) | ||
if tf != nil { | ||
// We index test files relative to the module they are testing, so | ||
// the key is the relative path between basePath and path. | ||
relPath, err := filepath.Rel(basePath, path) | ||
if err != nil { | ||
diags = append(diags, &hcl.Diagnostic{ | ||
Severity: hcl.DiagWarning, | ||
Summary: "Failed to calculate relative path", | ||
Detail: fmt.Sprintf("Terraform could not calculate the relative path for test file %s and it has been skipped: %s", path, err), | ||
}) | ||
continue | ||
} | ||
tfs[relPath] = tf | ||
} | ||
} | ||
|
||
return tfs, diags | ||
} | ||
|
||
// fileExt returns the Terraform configuration extension of the given | ||
// path, or a blank string if it is not a recognized extension. | ||
func fileExt(path string) string { | ||
if strings.HasSuffix(path, ".tf") { | ||
return ".tf" | ||
} else if strings.HasSuffix(path, ".tf.json") { | ||
return ".tf.json" | ||
} else if strings.HasSuffix(path, ".tftest") { | ||
return ".tftest" | ||
} else { | ||
return "" | ||
} | ||
|
@@ -157,7 +249,7 @@ func IsEmptyDir(path string) (bool, error) { | |
} | ||
|
||
p := NewParser(nil) | ||
fs, os, diags := p.dirFiles(path) | ||
fs, os, _, diags := p.dirFiles(path, "") | ||
if diags.HasErrors() { | ||
return false, diags | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a while to understand what this function is doing now. While I think the previous function signature was basically self-explanatory, a function called
dirFiles
which takes two arguments isn't quite as intuitive. Perhaps a comment would help.As a starting point, here's my understanding, which might of course be wrong:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment!