Skip to content
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

Manage tfv test source code in magic-modules #5599

Merged
merged 4 commits into from
Jan 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 34 additions & 10 deletions mmv1/provider/terraform_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ def retrieve_list_of_manually_defined_tests_from_file(file)
def retrieve_list_of_manually_defined_tests
m1 =
retrieve_list_of_manually_defined_tests_from_file(
'third_party/validator/tests/manifest/cli_test.go.erb'
'third_party/validator/tests/source/cli_test.go.erb'
)
m2 =
retrieve_list_of_manually_defined_tests_from_file(
'third_party/validator/tests/manifest/read_test.go.erb'
'third_party/validator/tests/source/read_test.go.erb'
)
m1 | m2 # union of manually defined tests
end
Expand Down Expand Up @@ -106,6 +106,20 @@ def retrieve_full_manifest_of_non_defined_tests
non_defined_tests
end

def retrieve_test_source_files(path, suffix)
files = Dir[path + '**' + suffix]
files = files.map { |file| file.split(path)[-1] }
files.sort
end

def retrieve_test_source_code_with_location(suffix)
path = 'third_party/validator/tests/source/'
files = retrieve_test_source_files(path, suffix)
files.map do |file|
['test/' + file, path + file]
end
end

def compile_common_files(output_folder, products, _common_compile_file)
Google::LOGGER.info 'Compiling common files.'
file_template = ProviderFileTemplate.new(
Expand All @@ -116,6 +130,17 @@ def compile_common_files(output_folder, products, _common_compile_file)
)

@non_defined_tests = retrieve_full_manifest_of_non_defined_tests

test_source = retrieve_test_source_code_with_location('[b]').map do |location|
[location[0].sub('go.erb', 'go'), location[1]]
end

compile_file_list(
output_folder,
test_source,
file_template
)

compile_file_list(output_folder, [
['converters/google/resources/compute_operation.go',
'third_party/terraform/utils/compute_operation.go.erb'],
Expand All @@ -140,11 +165,7 @@ def compile_common_files(output_folder, products, _common_compile_file)
['converters/google/resources/metadata.go',
'third_party/terraform/utils/metadata.go.erb'],
['converters/google/resources/compute_instance.go',
'third_party/validator/compute_instance.go.erb'],
['test/cli_test.go',
'third_party/validator/tests/manifest/cli_test.go.erb'],
['test/read_test.go',
'third_party/validator/tests/manifest/read_test.go.erb']
'third_party/validator/compute_instance.go.erb']
],
file_template)
end
Expand All @@ -158,6 +179,11 @@ def copy_common_files(output_folder, generate_code, _generate_docs)
retrieve_full_list_of_test_files_with_location
)

copy_file_list(
output_folder,
retrieve_test_source_code_with_location('[^b]')
)

copy_file_list(output_folder, [
['converters/google/resources/constants.go',
'third_party/validator/constants.go'],
Expand Down Expand Up @@ -284,9 +310,7 @@ def copy_common_files(output_folder, generate_code, _generate_docs)
['converters/google/resources/spanner_instance_iam.go',
'third_party/validator/spanner_instance_iam.go'],
['converters/google/resources/storage_bucket_iam.go',
'third_party/validator/storage_bucket_iam.go'],
['test/utils.go',
'third_party/validator/tests/utils.go']
'third_party/validator/storage_bucket_iam.go']
])
end

Expand Down
172 changes: 172 additions & 0 deletions mmv1/third_party/validator/tests/source/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package test

import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"text/template"
"time"

"github.com/GoogleCloudPlatform/terraform-validator/converters/google"
)

const (
samplePolicyPath = "../testdata/sample_policies"
defaultAncestry = "organization/12345/folder/67890"
defaultOrganization = "12345"
defaultFolder = "67890"
defaultProject = "foobar"
defaultProviderVersion = "4.4.0"
)

var (
data *testData
tfvBinary string
tmpDir = os.TempDir()
)

// testData represents the full dataset that is used for templating terraform
// configs. It contains Google API resources that are expected to be returned
// after converting the terraform plan.
type testData struct {
// is not nil - Terraform 12 version used
TFVersion string
// provider "google"
Provider map[string]string
Project map[string]string
Time map[string]string
OrgID string
FolderID string
Ancestry string
}

// init initializes the variables used for testing. As tests rely on
// environment variables, the parsing of those are only done once.
func init() {
// don't raise errors in glog

cwd, err := os.Getwd()
if err != nil {
log.Fatalf("cannot get current directory: %v", err)
}
tfvBinary = filepath.Join(cwd, "..", "bin", "terraform-validator")
project, ok := os.LookupEnv("TEST_PROJECT")
if !ok {
log.Printf("Missing required env var TEST_PROJECT. Default (%s) will be used.", defaultProject)
project = defaultProject
}
org, ok := os.LookupEnv("TEST_ORG_ID")
if !ok {
log.Printf("Missing required env var TEST_ORG_ID. Default (%s) will be used.", defaultOrganization)
org = defaultOrganization
}
folder, ok := os.LookupEnv("TEST_FOLDER_ID")
if !ok {
log.Printf("Missing required env var TEST_FOLDER_ID. Default (%s) will be used.", defaultFolder)
folder = defaultFolder
}
credentials, ok := os.LookupEnv("TEST_CREDENTIALS")
if ok {
// Make credentials path relative to repo root rather than
// test/ dir if it is a relative path.
if !filepath.IsAbs(credentials) {
credentials = filepath.Join(cwd, "..", credentials)
}
} else {
log.Printf("missing env var TEST_CREDENTIALS, will try to use Application Default Credentials")
}
ancestry, ok := os.LookupEnv("TEST_ANCESTRY")
if !ok {
log.Printf("Missing required env var TEST_ANCESTRY. Default (%s) will be used.", defaultAncestry)
ancestry = defaultAncestry
}
providerVersion := defaultProviderVersion
//As time is not information in terraform resource data, time is fixed for testing purposes
fixedTime := time.Date(2021, time.April, 14, 15, 16, 17, 0, time.UTC)
data = &testData{
TFVersion: "0.12",
Provider: map[string]string{
"version": providerVersion,
"project": project,
"credentials": credentials,
},
Time: map[string]string{
"RFC3339Nano": fixedTime.Format(time.RFC3339Nano),
},
Project: map[string]string{
"Name": "My Project Name",
"ProjectId": "my-project-id",
"BillingAccountName": "012345-567890-ABCDEF",
"Number": "1234567890",
},
OrgID: org,
FolderID: folder,
Ancestry: ancestry,
}
}

func generateTestFiles(t *testing.T, sourceDir string, targetDir string, selector string) {
funcMap := template.FuncMap{
"pastLastSlash": func(s string) string {
split := strings.Split(s, "/")
return split[len(split)-1]
},
}
tmpls, err := template.New("").Funcs(funcMap).
ParseGlob(filepath.Join(sourceDir, selector))
if err != nil {
t.Fatalf("generateTestFiles: %v", err)
}
for _, tmpl := range tmpls.Templates() {
if tmpl.Name() == "" {
continue // Skip base template.
}
path := filepath.Join(targetDir, tmpl.Name())
f, err := os.Create(path)
if err != nil {
t.Fatalf("creating terraform file %v: %v", path, err)
}
if err := tmpl.Execute(f, data); err != nil {
t.Fatalf("templating terraform file %v: %v", path, err)
}
if err := f.Close(); err != nil {
t.Fatalf("closing file %v: %v", path, err)
}
t.Logf("Successfully created file %v", path)
}
}

func normalizeAssets(t *testing.T, assets []google.Asset, offline bool) []google.Asset {
t.Helper()
ret := make([]google.Asset, len(assets))
re := regexp.MustCompile(`/placeholder-[^/]+`)
for i := range assets {
// Get conformity by converting to/from json.
bytes, err := json.Marshal(assets[i])
if err != nil {
t.Fatalf("marshaling: %v", err)
}

var asset google.Asset
err = json.Unmarshal(bytes, &asset)
if err != nil {
t.Fatalf("marshaling: %v", err)
}
if !offline {
// remove the ancestry as the value of that is dependent on project,
// and is not important for the test.
asset.Ancestry = ""
}
// Replace placeholder in names. This allows us to compare generated placeholders
// (for example due to "unknown after apply") with the values in the expected
// output files.
asset.Name = re.ReplaceAllString(asset.Name, fmt.Sprintf("/placeholder-foobar"))
ret[i] = asset
}
return ret
}
Loading