github.com/crossplane/upjet@v1.3.0/pkg/transformers/resolver_test.go (about) 1 // SPDX-FileCopyrightText: 2024 The Crossplane Authors <https://crossplane.io> 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package transformers 6 7 import ( 8 "path/filepath" 9 "testing" 10 11 "github.com/crossplane/crossplane-runtime/pkg/test" 12 "github.com/google/go-cmp/cmp" 13 "github.com/pkg/errors" 14 "github.com/spf13/afero" 15 "golang.org/x/tools/go/packages/packagestest" 16 ) 17 18 func TestTransformPackages(t *testing.T) { 19 // args struct to define input arguments for each test case 20 type args struct { 21 apiGroupSuffix string 22 apiResolverPackage string 23 apiGroupOverrides map[string]string 24 resolverFilePattern string 25 ignorePackageLoadErrors bool 26 patterns []string 27 inputFilePath string 28 } 29 30 // want struct to define the expected outcome for each test case 31 type want struct { 32 // errFunc receives the transformed resolver file's path 33 errFunc func(string) error 34 transformedPath string 35 } 36 37 // testCase struct for defining test cases 38 type testCase struct { 39 reason string 40 args args 41 want want 42 } 43 44 cases := map[string]testCase{ 45 "SuccessfulTransformation": { 46 reason: "Transformation of the source file that has been generated by crossplane-tool's angryjet succeeds with the expected transformed file.", 47 args: args{ 48 apiGroupSuffix: "aws.upbound.io", 49 apiResolverPackage: "github.com/upbound/provider-aws/internal/apis", 50 resolverFilePattern: "zz_generated.resolvers.go", 51 inputFilePath: "testdata/apigatewayv2.resolvers.go.txt", 52 ignorePackageLoadErrors: true, 53 patterns: []string{"./testdata"}, 54 }, 55 want: want{ 56 transformedPath: "testdata/apigatewayv2.resolvers.transformed.go.txt", 57 }, 58 }, 59 "TransformationIdempotency": { 60 reason: "The applied transformation is idempotent, i.e., applying the transformer on an already transformed file does not change the transformed file.", 61 args: args{ 62 apiGroupSuffix: "aws.upbound.io", 63 apiResolverPackage: "github.com/upbound/provider-aws/internal/apis", 64 resolverFilePattern: "zz_generated.resolvers.go", 65 inputFilePath: "testdata/apigatewayv2.resolvers.transformed.go.txt", 66 ignorePackageLoadErrors: true, 67 patterns: []string{"./testdata"}, 68 }, 69 want: want{ 70 transformedPath: "testdata/apigatewayv2.resolvers.transformed.go.txt", 71 }, 72 }, 73 "TransformationFailure": { 74 reason: "The transformation source is not a valid angryjet-generated resolver file: List type is missing for a resolution source.", 75 args: args{ 76 apiGroupSuffix: "aws.upbound.io", 77 apiResolverPackage: "github.com/upbound/provider-aws/internal/apis", 78 resolverFilePattern: "zz_generated.resolvers.go", 79 inputFilePath: "testdata/missing_list_type.resolvers.go.txt", 80 ignorePackageLoadErrors: true, 81 patterns: []string{"./testdata"}, 82 }, 83 want: want{ 84 errFunc: func(transformedPath string) error { 85 return errors.Wrapf( 86 errors.Wrap( 87 errors.New(`failed to extract the GVKs for the reference targets. Group: "fake.aws.upbound.io", Version: "testdata", Kind: "Project", List Kind: ""`), 88 "failed to inspect the resolver file for transformation"), 89 "failed to transform the resolver file %s", transformedPath) 90 }, 91 }, 92 }, 93 "SuccessfulTransformationWithGroupOverrides": { 94 reason: "Transformation of the source file with a group overrides configuration succeeds with the expected transformed file.", 95 args: args{ 96 apiGroupSuffix: "aws.upbound.io", 97 apiResolverPackage: "github.com/upbound/provider-aws/internal/resolver", 98 apiGroupOverrides: map[string]string{ 99 "ec2.aws.upbound.io": "replacedec2.aws.upbound.io", 100 }, 101 resolverFilePattern: "zz_generated.resolvers.go", 102 inputFilePath: "testdata/apigatewayv2.resolvers.go.txt", 103 ignorePackageLoadErrors: true, 104 patterns: []string{"./testdata"}, 105 }, 106 want: want{ 107 transformedPath: "testdata/apigatewayv2.resolvers.withoverrides.go.txt", 108 }, 109 }, 110 } 111 112 for name, tc := range cases { 113 t.Run(name, func(t *testing.T) { 114 inputFileContents := readFile(t, afero.NewOsFs(), tc.args.inputFilePath, tc.reason) 115 exported := packagestest.Export(t, packagestest.Modules, []packagestest.Module{{ 116 Name: "fake", 117 Files: map[string]interface{}{ 118 filepath.Join("testdata", tc.args.resolverFilePattern): inputFileContents, 119 }}}) 120 defer exported.Cleanup() 121 exported.Config.Mode = defaultLoadMode 122 memFS := afero.NewMemMapFs() 123 transformedFilePath := filepath.Join(exported.Temp(), "fake", "testdata", tc.args.resolverFilePattern) 124 writeFile(t, memFS, transformedFilePath, []byte(inputFileContents), tc.reason) 125 126 r := NewResolver(memFS, tc.args.apiGroupSuffix, tc.args.apiResolverPackage, tc.args.ignorePackageLoadErrors, nil, 127 WithLoaderConfig(exported.Config), 128 WithAPIGroupOverrides(tc.args.apiGroupOverrides)) 129 err := r.TransformPackages("zz_generated.resolvers.go", tc.args.patterns...) 130 var wantErr error 131 if tc.want.errFunc != nil { 132 wantErr = tc.want.errFunc(transformedFilePath) 133 } 134 if diff := cmp.Diff(wantErr, err, test.EquateErrors()); diff != "" { 135 t.Errorf("\n%s\nResolver.TransformPackages(...): -wantErr, +gotErr:\n%s", tc.reason, diff) 136 } 137 if wantErr != nil { 138 return 139 } 140 if diff := cmp.Diff(readFile(t, afero.NewOsFs(), tc.want.transformedPath, tc.reason), 141 readFile(t, memFS, transformedFilePath, tc.reason)); diff != "" { 142 t.Errorf("\n%s\nResolver.TransformPackages(...): -want, +got:\n%s", tc.reason, diff) 143 } 144 }) 145 } 146 } 147 148 func readFile(t *testing.T, fs afero.Fs, filePath string, reason string) string { 149 buff, err := afero.ReadFile(fs, filePath) 150 if err != nil { 151 t.Fatalf("\n%s\n: Failed to write the test artifact to the path %s: %v", reason, filePath, err) 152 } 153 return string(buff) 154 } 155 156 func writeFile(t *testing.T, fs afero.Fs, filePath string, buff []byte, reason string) string { 157 err := afero.WriteFile(fs, filePath, buff, 0o600) 158 if err != nil { 159 t.Fatalf("\n%s\n: Failed to load the test artifact from the path %s: %v", reason, filePath, err) 160 } 161 return string(buff) 162 }