github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/e2e/porch_test.go (about) 1 // Copyright 2022 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build porch 16 17 package e2e 18 19 import ( 20 "bytes" 21 "errors" 22 "io/fs" 23 "os" 24 "os/exec" 25 "path/filepath" 26 "strings" 27 "testing" 28 "time" 29 30 "github.com/GoogleContainerTools/kpt/pkg/test/porch" 31 "github.com/google/go-cmp/cmp" 32 "sigs.k8s.io/kustomize/kyaml/yaml" 33 ) 34 35 const ( 36 updateGoldenFiles = "UPDATE_GOLDEN_FILES" 37 testGitNamespace = "test-git-namespace" 38 ) 39 40 func TestPorch(t *testing.T) { 41 abs, err := filepath.Abs(filepath.Join(".", "testdata", "porch")) 42 if err != nil { 43 t.Fatalf("Failed to get absolute path to testdata directory: %v", err) 44 } 45 runTests(t, abs) 46 } 47 48 func runTests(t *testing.T, path string) { 49 gitServerURL := startGitServer(t, path) 50 testCases := scanTestCases(t, path) 51 52 for _, tc := range testCases { 53 t.Run(tc.TestCase, func(t *testing.T) { 54 if tc.Skip != "" { 55 t.Skipf("Skipping test: %s", tc.Skip) 56 } 57 repoURL := gitServerURL + "/" + strings.ReplaceAll(tc.TestCase, "/", "-") 58 runTestCase(t, repoURL, tc) 59 }) 60 } 61 } 62 63 func runTestCase(t *testing.T, repoURL string, tc porch.TestCaseConfig) { 64 porch.KubectlCreateNamespace(t, tc.TestCase) 65 t.Cleanup(func() { 66 porch.KubectlDeleteNamespace(t, tc.TestCase) 67 }) 68 69 if tc.Repository != "" { 70 porch.RegisterRepository(t, repoURL, tc.TestCase, tc.Repository) 71 } 72 73 for i := range tc.Commands { 74 time.Sleep(5 * time.Second) 75 command := &tc.Commands[i] 76 cmd := exec.Command("kpt", command.Args...) 77 78 var stdout, stderr bytes.Buffer 79 if command.Stdin != "" { 80 cmd.Stdin = strings.NewReader(command.Stdin) 81 } 82 cmd.Stdout = &stdout 83 cmd.Stderr = &stderr 84 85 t.Logf("running command %v", strings.Join(cmd.Args, " ")) 86 err := cmd.Run() 87 88 if command.Yaml { 89 reorderYamlStdout(t, &stdout) 90 } 91 92 if os.Getenv(updateGoldenFiles) != "" { 93 updateCommand(command, err, stdout.String(), stderr.String()) 94 } 95 96 if got, want := exitCode(err), command.ExitCode; got != want { 97 t.Errorf("unexpected exit code from 'kpt %s'; got %d, want %d", strings.Join(command.Args, " "), got, want) 98 } 99 if got, want := stdout.String(), command.Stdout; got != want { 100 t.Errorf("unexpected stdout content from 'kpt %s'; (-want, +got) %s", strings.Join(command.Args, " "), cmp.Diff(want, got)) 101 } 102 if got, want := stderr.String(), command.Stderr; got != want { 103 t.Errorf("unexpected stderr content from 'kpt %s'; (-want, +got) %s", strings.Join(command.Args, " "), cmp.Diff(want, got)) 104 } 105 } 106 107 if os.Getenv(updateGoldenFiles) != "" { 108 porch.WriteTestCaseConfig(t, &tc) 109 } 110 } 111 112 func reorderYamlStdout(t *testing.T, buf *bytes.Buffer) { 113 var data interface{} 114 if err := yaml.Unmarshal(buf.Bytes(), &data); err != nil { 115 // not yaml. 116 return 117 } 118 119 var stable bytes.Buffer 120 encoder := yaml.NewEncoder(&stable) 121 encoder.SetIndent(2) 122 if err := encoder.Encode(data); err != nil { 123 t.Fatalf("Failed to re-encode yaml output: %v", err) 124 } 125 buf.Reset() 126 if _, err := buf.Write(stable.Bytes()); err != nil { 127 t.Fatalf("Failed to update reordered yaml output: %v", err) 128 } 129 } 130 131 func startGitServer(t *testing.T, path string) string { 132 gitServerURL := "http://git-server." + testGitNamespace + ".svc.cluster.local:8080" 133 134 gitServerImage := porch.GetGitServerImageName(t) 135 t.Logf("Git Image: %s", gitServerImage) 136 137 configFile := filepath.Join(path, "git-server.yaml") 138 configBytes, err := os.ReadFile(configFile) 139 if err != nil { 140 t.Fatalf("Failed to read git server config file %q: %v", configFile, err) 141 } 142 config := string(configBytes) 143 config = strings.ReplaceAll(config, "GIT_SERVER_IMAGE", gitServerImage) 144 145 t.Cleanup(func() { 146 porch.KubectlDeleteNamespace(t, testGitNamespace) 147 }) 148 149 porch.KubectlApply(t, config) 150 porch.KubectlWaitForDeployment(t, testGitNamespace, "git-server") 151 porch.KubectlWaitForService(t, testGitNamespace, "git-server") 152 porch.KubectlWaitForGitDNS(t, gitServerURL) 153 154 return gitServerURL 155 } 156 157 func scanTestCases(t *testing.T, root string) []porch.TestCaseConfig { 158 testCases := []porch.TestCaseConfig{} 159 160 if err := filepath.Walk(root, func(path string, info fs.FileInfo, err error) error { 161 if err != nil { 162 return err 163 } 164 if !info.IsDir() { 165 return nil 166 } 167 if path == root { 168 return nil 169 } 170 171 tc := porch.ReadTestCaseConfig(t, info.Name(), path) 172 testCases = append(testCases, tc) 173 174 return nil 175 }); err != nil { 176 t.Fatalf("Failed to scan test cases: %v", err) 177 } 178 179 return testCases 180 } 181 182 func updateCommand(command *porch.Command, exit error, stdout, stderr string) { 183 command.ExitCode = exitCode(exit) 184 command.Stdout = stdout 185 command.Stderr = stderr 186 } 187 188 func exitCode(exit error) int { 189 var ee *exec.ExitError 190 if errors.As(exit, &ee) { 191 return ee.ExitCode() 192 } 193 return 0 194 }