github.com/metasources/buildx@v0.0.0-20230418141019-7aa1459cedea/test/cli/trait_assertions_test.go (about) 1 package cli 2 3 import ( 4 "encoding/json" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "regexp" 9 "strings" 10 "testing" 11 12 "github.com/acarl005/stripansi" 13 "github.com/stretchr/testify/require" 14 ) 15 16 type traitAssertion func(tb testing.TB, stdout, stderr string, rc int) 17 18 func assertFileOutput(tb testing.TB, path string, assertions ...traitAssertion) traitAssertion { 19 tb.Helper() 20 21 return func(tb testing.TB, _, stderr string, rc int) { 22 content, err := os.ReadFile(path) 23 require.NoError(tb, err) 24 contentStr := string(content) 25 26 for _, assertion := range assertions { 27 // treat the file content as stdout 28 assertion(tb, contentStr, stderr, rc) 29 } 30 } 31 } 32 33 func assertJsonReport(tb testing.TB, stdout, _ string, _ int) { 34 tb.Helper() 35 var data interface{} 36 37 if err := json.Unmarshal([]byte(stdout), &data); err != nil { 38 tb.Errorf("expected to find a JSON report, but was unmarshalable: %+v", err) 39 } 40 } 41 42 func assertTableReport(tb testing.TB, stdout, _ string, _ int) { 43 tb.Helper() 44 if !strings.Contains(stdout, "NAME") || !strings.Contains(stdout, "VERSION") || !strings.Contains(stdout, "TYPE") { 45 tb.Errorf("expected to find a table report, but did not") 46 } 47 } 48 49 //func assertScope(scope source.Scope) traitAssertion { 50 // return func(tb testing.TB, stdout, stderr string, rc int) { 51 // tb.Helper() 52 // // we can only verify source with the json report 53 // assertJsonReport(tb, stdout, stderr, rc) 54 // 55 // if !strings.Contains(stdout, fmt.Sprintf(`"scope": "%s"`, scope.String())) { 56 // tb.Errorf("JSON report did not indicate the %q scope", scope) 57 // } 58 // } 59 //} 60 61 func assertLoggingLevel(level string) traitAssertion { 62 // match examples: 63 // "[0000] INFO" 64 // "[0012] DEBUG" 65 logPattern := regexp.MustCompile(`(?m)^\[\d\d\d\d\]\s+` + strings.ToUpper(level)) 66 return func(tb testing.TB, _, stderr string, _ int) { 67 tb.Helper() 68 if !logPattern.MatchString(stripansi.Strip(stderr)) { 69 tb.Errorf("output did not indicate the %q logging level", level) 70 } 71 } 72 } 73 74 func assertNotInOutput(data string) traitAssertion { 75 return func(tb testing.TB, stdout, stderr string, _ int) { 76 tb.Helper() 77 if strings.Contains(stripansi.Strip(stderr), data) { 78 tb.Errorf("data=%q was found in stderr, but should not have been there", data) 79 } 80 if strings.Contains(stripansi.Strip(stdout), data) { 81 tb.Errorf("data=%q was found in stdout, but should not have been there", data) 82 } 83 } 84 } 85 86 func assertInOutput(data string) traitAssertion { 87 return func(tb testing.TB, stdout, stderr string, _ int) { 88 tb.Helper() 89 if !strings.Contains(stripansi.Strip(stderr), data) && !strings.Contains(stripansi.Strip(stdout), data) { 90 tb.Errorf("data=%q was NOT found in any output, but should have been there", data) 91 } 92 } 93 } 94 95 func assertStdoutLengthGreaterThan(length uint) traitAssertion { 96 return func(tb testing.TB, stdout, _ string, _ int) { 97 tb.Helper() 98 if uint(len(stdout)) < length { 99 tb.Errorf("not enough output (expected at least %d, got %d)", length, len(stdout)) 100 } 101 } 102 } 103 104 func assertPackageCount(length uint) traitAssertion { 105 return func(tb testing.TB, stdout, _ string, _ int) { 106 tb.Helper() 107 type partial struct { 108 Artifacts []interface{} `json:"artifacts"` 109 } 110 var data partial 111 112 if err := json.Unmarshal([]byte(stdout), &data); err != nil { 113 tb.Errorf("expected to find a JSON report, but was unmarshalable: %+v", err) 114 } 115 116 if uint(len(data.Artifacts)) != length { 117 tb.Errorf("expected package count of %d, but found %d", length, len(data.Artifacts)) 118 119 } 120 } 121 } 122 123 func assertFailingReturnCode(tb testing.TB, _, _ string, rc int) { 124 tb.Helper() 125 if rc == 0 { 126 tb.Errorf("expected a failure but got rc=%d", rc) 127 } 128 } 129 130 func assertSuccessfulReturnCode(tb testing.TB, _, _ string, rc int) { 131 tb.Helper() 132 if rc != 0 { 133 tb.Errorf("expected no failure but got rc=%d", rc) 134 } 135 } 136 137 func assertVerifyAttestation(coverageImage string) traitAssertion { 138 return func(tb testing.TB, stdout, _ string, _ int) { 139 tb.Helper() 140 cosignPath := filepath.Join(repoRoot(tb), ".tmp/cosign") 141 err := os.WriteFile("attestation.json", []byte(stdout), 0664) 142 if err != nil { 143 tb.Errorf("could not write attestation to disk") 144 } 145 defer os.Remove("attestation.json") 146 attachCmd := exec.Command( 147 cosignPath, 148 "attach", 149 "attestation", 150 "--attestation", 151 "attestation.json", 152 coverageImage, // TODO which remote image to use? 153 ) 154 155 stdout, stderr, _ := runCommand(attachCmd, nil) 156 if attachCmd.ProcessState.ExitCode() != 0 { 157 tb.Log("STDOUT", stdout) 158 tb.Log("STDERR", stderr) 159 tb.Fatalf("could not attach image") 160 } 161 162 verifyCmd := exec.Command( 163 cosignPath, 164 "verify-attestation", 165 coverageImage, // TODO which remote image to use? 166 ) 167 168 stdout, stderr, _ = runCommand(verifyCmd, nil) 169 if attachCmd.ProcessState.ExitCode() != 0 { 170 tb.Log("STDOUT", stdout) 171 tb.Log("STDERR", stderr) 172 tb.Fatalf("could not verify attestation") 173 } 174 } 175 } 176 177 func assertFileExists(file string) traitAssertion { 178 return func(tb testing.TB, _, _ string, _ int) { 179 tb.Helper() 180 if _, err := os.Stat(file); err != nil { 181 tb.Errorf("expected file to exist %s", file) 182 } 183 } 184 }