github.com/golang/dep@v0.5.4/gps/verify/digest_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package verify 6 7 import ( 8 "bytes" 9 "io" 10 "os" 11 "path/filepath" 12 "testing" 13 ) 14 15 // crossBuffer is a test io.Reader that emits a few canned responses. 16 type crossBuffer struct { 17 readCount int 18 iterations []string 19 } 20 21 func (cb *crossBuffer) Read(buf []byte) (int, error) { 22 if cb.readCount == len(cb.iterations) { 23 return 0, io.EOF 24 } 25 cb.readCount++ 26 return copy(buf, cb.iterations[cb.readCount-1]), nil 27 } 28 29 func streamThruLineEndingReader(t *testing.T, iterations []string) []byte { 30 dst := new(bytes.Buffer) 31 n, err := io.Copy(dst, newLineEndingReader(&crossBuffer{iterations: iterations})) 32 if got, want := err, error(nil); got != want { 33 t.Errorf("(GOT): %v; (WNT): %v", got, want) 34 } 35 if got, want := n, int64(dst.Len()); got != want { 36 t.Errorf("(GOT): %v; (WNT): %v", got, want) 37 } 38 return dst.Bytes() 39 } 40 41 func TestLineEndingReader(t *testing.T) { 42 testCases := []struct { 43 input []string 44 output string 45 }{ 46 {[]string{"\r"}, "\r"}, 47 {[]string{"\r\n"}, "\n"}, 48 {[]string{"now is the time\r\n"}, "now is the time\n"}, 49 {[]string{"now is the time\r\n(trailing data)"}, "now is the time\n(trailing data)"}, 50 {[]string{"now is the time\n"}, "now is the time\n"}, 51 {[]string{"now is the time\r"}, "now is the time\r"}, // trailing CR ought to convey 52 {[]string{"\rnow is the time"}, "\rnow is the time"}, // CR not followed by LF ought to convey 53 {[]string{"\rnow is the time\r"}, "\rnow is the time\r"}, // CR not followed by LF ought to convey 54 55 // no line splits 56 {[]string{"first", "second", "third"}, "firstsecondthird"}, 57 58 // 1->2 and 2->3 both break across a CRLF 59 {[]string{"first\r", "\nsecond\r", "\nthird"}, "first\nsecond\nthird"}, 60 61 // 1->2 breaks across CRLF and 2->3 does not 62 {[]string{"first\r", "\nsecond", "third"}, "first\nsecondthird"}, 63 64 // 1->2 breaks across CRLF and 2 ends in CR but 3 does not begin LF 65 {[]string{"first\r", "\nsecond\r", "third"}, "first\nsecond\rthird"}, 66 67 // 1 ends in CR but 2 does not begin LF, and 2->3 breaks across CRLF 68 {[]string{"first\r", "second\r", "\nthird"}, "first\rsecond\nthird"}, 69 70 // 1 ends in CR but 2 does not begin LF, and 2->3 does not break across CRLF 71 {[]string{"first\r", "second\r", "\nthird"}, "first\rsecond\nthird"}, 72 73 // 1->2 and 2->3 both break across a CRLF, but 3->4 does not 74 {[]string{"first\r", "\nsecond\r", "\nthird\r", "fourth"}, "first\nsecond\nthird\rfourth"}, 75 {[]string{"first\r", "\nsecond\r", "\nthird\n", "fourth"}, "first\nsecond\nthird\nfourth"}, 76 77 {[]string{"this is the result\r\nfrom the first read\r", "\nthis is the result\r\nfrom the second read\r"}, 78 "this is the result\nfrom the first read\nthis is the result\nfrom the second read\r"}, 79 {[]string{"now is the time\r\nfor all good engineers\r\nto improve their test coverage!\r\n"}, 80 "now is the time\nfor all good engineers\nto improve their test coverage!\n"}, 81 {[]string{"now is the time\r\nfor all good engineers\r", "\nto improve their test coverage!\r\n"}, 82 "now is the time\nfor all good engineers\nto improve their test coverage!\n"}, 83 } 84 85 for _, testCase := range testCases { 86 got := streamThruLineEndingReader(t, testCase.input) 87 if want := []byte(testCase.output); !bytes.Equal(got, want) { 88 t.Errorf("Input: %#v; (GOT): %#q; (WNT): %#q", testCase.input, got, want) 89 } 90 } 91 } 92 93 //////////////////////////////////////// 94 95 func getTestdataVerifyRoot(t *testing.T) string { 96 cwd, err := os.Getwd() 97 if err != nil { 98 t.Fatal(err) 99 } 100 return filepath.Join(filepath.Dir(cwd), "_testdata/digest") 101 } 102 103 func TestDigestFromDirectoryBailsUnlessDirectory(t *testing.T) { 104 prefix := getTestdataVerifyRoot(t) 105 relativePathname := "launchpad.net/match" 106 _, err := DigestFromDirectory(filepath.Join(prefix, relativePathname)) 107 if got, want := err, error(nil); got != want { 108 t.Errorf("\n(GOT): %v; (WNT): %v", got, want) 109 } 110 } 111 112 func TestDigestFromDirectory(t *testing.T) { 113 relativePathname := "launchpad.net/match" 114 want := []byte{0x7e, 0x10, 0x6, 0x2f, 0x8, 0x3, 0x3c, 0x76, 0xae, 0xbc, 0xa4, 0xc9, 0xec, 0x73, 0x67, 0x15, 0x70, 0x2b, 0x0, 0x89, 0x27, 0xbb, 0x61, 0x9d, 0xc7, 0xc3, 0x39, 0x46, 0x3, 0x91, 0xb7, 0x3b} 115 116 // NOTE: Create the hash using both an absolute and a relative pathname to 117 // ensure hash ignores prefix. 118 119 t.Run("AbsolutePrefix", func(t *testing.T) { 120 t.Parallel() 121 prefix := getTestdataVerifyRoot(t) 122 got, err := DigestFromDirectory(filepath.Join(prefix, relativePathname)) 123 if err != nil { 124 t.Fatal(err) 125 } 126 if !bytes.Equal(got.Digest, want) { 127 t.Errorf("\n(GOT):\n\t%#v\n(WNT):\n\t%#v", got, want) 128 } 129 }) 130 131 t.Run("RelativePrefix", func(t *testing.T) { 132 t.Parallel() 133 prefix := "../_testdata/digest" 134 got, err := DigestFromDirectory(filepath.Join(prefix, relativePathname)) 135 if err != nil { 136 t.Fatal(err) 137 } 138 if !bytes.Equal(got.Digest, want) { 139 t.Errorf("\n(GOT):\n\t%#v\n(WNT):\n\t%#v", got, want) 140 } 141 }) 142 } 143 144 func TestVerifyDepTree(t *testing.T) { 145 vendorRoot := getTestdataVerifyRoot(t) 146 147 wantSums := map[string][]byte{ 148 "github.com/alice/match": {0x7e, 0x10, 0x6, 0x2f, 0x8, 0x3, 0x3c, 0x76, 0xae, 0xbc, 0xa4, 0xc9, 0xec, 0x73, 0x67, 0x15, 0x70, 0x2b, 0x0, 0x89, 0x27, 0xbb, 0x61, 0x9d, 0xc7, 0xc3, 0x39, 0x46, 0x3, 0x91, 0xb7, 0x3b}, 149 "github.com/alice/mismatch": []byte("some non-matching digest"), 150 "github.com/bob/emptyDigest": nil, // empty hash result 151 "github.com/bob/match": {0x7e, 0x10, 0x6, 0x2f, 0x8, 0x3, 0x3c, 0x76, 0xae, 0xbc, 0xa4, 0xc9, 0xec, 0x73, 0x67, 0x15, 0x70, 0x2b, 0x0, 0x89, 0x27, 0xbb, 0x61, 0x9d, 0xc7, 0xc3, 0x39, 0x46, 0x3, 0x91, 0xb7, 0x3b}, 152 "github.com/charlie/notInTree": nil, // not in tree result ought to superseede empty digest result 153 // matching result at seldom found directory level 154 "launchpad.net/match": {0x7e, 0x10, 0x6, 0x2f, 0x8, 0x3, 0x3c, 0x76, 0xae, 0xbc, 0xa4, 0xc9, 0xec, 0x73, 0x67, 0x15, 0x70, 0x2b, 0x0, 0x89, 0x27, 0xbb, 0x61, 0x9d, 0xc7, 0xc3, 0x39, 0x46, 0x3, 0x91, 0xb7, 0x3b}, 155 } 156 157 checkStatus := func(t *testing.T, status map[string]VendorStatus, key string, want VendorStatus) { 158 t.Helper() 159 got, ok := status[key] 160 if !ok { 161 t.Errorf("Want key: %q", key) 162 return 163 } 164 if got != want { 165 t.Errorf("Key: %q; (GOT): %v; (WNT): %v", key, got, want) 166 } 167 } 168 169 t.Run("normal", func(t *testing.T) { 170 t.Parallel() 171 wantDigests := make(map[string]VersionedDigest) 172 for k, v := range wantSums { 173 wantDigests[k] = VersionedDigest{ 174 HashVersion: HashVersion, 175 Digest: v, 176 } 177 } 178 179 status, err := CheckDepTree(vendorRoot, wantDigests) 180 if err != nil { 181 t.Fatal(err) 182 } 183 184 if got, want := len(status), 7; got != want { 185 t.Errorf("Unexpected result count from VerifyDepTree:\n\t(GOT): %v\n\t(WNT): %v", got, want) 186 } 187 188 checkStatus(t, status, "github.com/alice/match", NoMismatch) 189 checkStatus(t, status, "github.com/alice/mismatch", DigestMismatchInLock) 190 checkStatus(t, status, "github.com/alice/notInLock", NotInLock) 191 checkStatus(t, status, "github.com/bob/match", NoMismatch) 192 checkStatus(t, status, "github.com/bob/emptyDigest", EmptyDigestInLock) 193 checkStatus(t, status, "github.com/charlie/notInTree", NotInTree) 194 checkStatus(t, status, "launchpad.net/match", NoMismatch) 195 196 if t.Failed() { 197 for k, want := range wantSums { 198 got, err := DigestFromDirectory(filepath.Join(vendorRoot, k)) 199 if err != nil { 200 t.Error(err) 201 } 202 if !bytes.Equal(got.Digest, want) { 203 t.Errorf("Digest mismatch for %q\n(GOT):\n\t%#v\n(WNT):\n\t%#v", k, got, want) 204 } 205 } 206 } 207 208 }) 209 210 t.Run("hashv-mismatch", func(t *testing.T) { 211 t.Parallel() 212 wantDigests := make(map[string]VersionedDigest) 213 for k, v := range wantSums { 214 wantDigests[k] = VersionedDigest{ 215 HashVersion: HashVersion + 1, 216 Digest: v, 217 } 218 } 219 220 status, err := CheckDepTree(vendorRoot, wantDigests) 221 if err != nil { 222 t.Fatal(err) 223 } 224 225 if got, want := len(status), 7; got != want { 226 t.Errorf("Unexpected result count from VerifyDepTree:\n\t(GOT): %v\n\t(WNT): %v", got, want) 227 } 228 229 checkStatus(t, status, "github.com/alice/match", HashVersionMismatch) 230 checkStatus(t, status, "github.com/alice/mismatch", HashVersionMismatch) 231 checkStatus(t, status, "github.com/alice/notInLock", NotInLock) 232 checkStatus(t, status, "github.com/bob/match", HashVersionMismatch) 233 checkStatus(t, status, "github.com/bob/emptyDigest", HashVersionMismatch) 234 checkStatus(t, status, "github.com/charlie/notInTree", NotInTree) 235 checkStatus(t, status, "launchpad.net/match", HashVersionMismatch) 236 }) 237 238 t.Run("Non-existent directory", func(t *testing.T) { 239 t.Parallel() 240 wantDigests := make(map[string]VersionedDigest) 241 for k, v := range wantSums { 242 wantDigests[k] = VersionedDigest{ 243 HashVersion: HashVersion + 1, 244 Digest: v, 245 } 246 } 247 248 status, err := CheckDepTree("fooVendorRoot", wantDigests) 249 if err != nil { 250 t.Fatal(err) 251 } 252 253 if got, want := len(status), 6; got != want { 254 t.Errorf("Unexpected result count from VerifyDepTree:\n\t(GOT): %v\n\t(WNT): %v", got, want) 255 } 256 257 checkStatus(t, status, "github.com/alice/match", NotInTree) 258 checkStatus(t, status, "github.com/alice/mismatch", NotInTree) 259 checkStatus(t, status, "github.com/bob/match", NotInTree) 260 checkStatus(t, status, "github.com/bob/emptyDigest", NotInTree) 261 checkStatus(t, status, "github.com/charlie/notInTree", NotInTree) 262 checkStatus(t, status, "launchpad.net/match", NotInTree) 263 264 }) 265 } 266 267 func TestParseVersionedDigest(t *testing.T) { 268 t.Run("Parse valid VersionedDigest", func(t *testing.T) { 269 t.Parallel() 270 input := "1:60861e762bdbe39c4c7bf292c291329b731c9925388fd41125888f5c1c595feb" 271 vd, err := ParseVersionedDigest(input) 272 if err != nil { 273 t.Fatal() 274 } 275 276 expectedHash := "60861e762bdbe39c4c7bf292c291329b731c9925388fd41125888f5c1c595feb" 277 if got, want := vd.Digest, expectedHash; bytes.Equal(got, []byte(expectedHash)) { 278 t.Errorf("Unexpected result from ParseVersionedDigest:\n\t(GOT): %s\n\t(WNT): %s", got, want) 279 } 280 281 if got, want := vd.String(), input; got != want { 282 t.Errorf("Unexpected result from ParseVersionedDigest String:\n\t(GOT): %s\n\t(WNT): %s", got, want) 283 } 284 }) 285 286 t.Run("Parse VersionedDigest with invalid format", func(t *testing.T) { 287 t.Parallel() 288 input := "1abc" 289 _, err := ParseVersionedDigest(input) 290 if err == nil { 291 t.Error("expected error for invalid VersionedDigest format") 292 } 293 }) 294 295 t.Run("Parse VersionedDigest with invalid hex string", func(t *testing.T) { 296 t.Parallel() 297 input := "1:60861g762bdbe39c4c7bf292c291329b731c9925388fd41125888f5c1c595feb" 298 _, err := ParseVersionedDigest(input) 299 if err == nil { 300 t.Error("expected error VersionedDigest with invalid hex string") 301 } 302 }) 303 304 t.Run("Parse VersionedDigest with invalid hash version", func(t *testing.T) { 305 t.Parallel() 306 input := "a:60861e762bdbe39c4c7bf292c291329b731c9925388fd41125888f5c1c595feb" 307 _, err := ParseVersionedDigest(input) 308 if err == nil { 309 t.Error("expected error VersionedDigest with invalid hash version") 310 } 311 }) 312 } 313 314 func BenchmarkDigestFromDirectory(b *testing.B) { 315 b.Skip("Eliding benchmark of user's Go source directory") 316 317 prefix := filepath.Join(os.Getenv("GOPATH"), "src") 318 319 for i := 0; i < b.N; i++ { 320 _, err := DigestFromDirectory(prefix) 321 if err != nil { 322 b.Fatal(err) 323 } 324 } 325 } 326 327 func BenchmarkVerifyDepTree(b *testing.B) { 328 b.Skip("Eliding benchmark of user's Go source directory") 329 330 prefix := filepath.Join(os.Getenv("GOPATH"), "src") 331 332 for i := 0; i < b.N; i++ { 333 _, err := CheckDepTree(prefix, nil) 334 if err != nil { 335 b.Fatal(err) 336 } 337 } 338 }