github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/vcs/git_repo_test.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package vcs 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 "sort" 11 "testing" 12 13 "github.com/google/go-cmp/cmp" 14 "github.com/google/syzkaller/pkg/debugtracer" 15 ) 16 17 func init() { 18 // Disable sandboxing entirely because we create test repos without sandboxing. 19 os.Setenv("SYZ_DISABLE_SANDBOXING", "yes") 20 } 21 22 func TestGitRepo(t *testing.T) { 23 t.Parallel() 24 baseDir := t.TempDir() 25 repo1 := CreateTestRepo(t, baseDir, "repo1") 26 repo2 := CreateTestRepo(t, baseDir, "repo2") 27 repo := newGit(filepath.Join(baseDir, "repo"), nil, nil) 28 { 29 com, err := repo.Poll(repo1.Dir, "master") 30 if err != nil { 31 t.Fatal(err) 32 } 33 if diff := cmp.Diff(com, repo1.Commits["master"]["1"]); diff != "" { 34 t.Fatal(diff) 35 } 36 } 37 { 38 com, err := repo.CheckoutBranch(repo1.Dir, "branch1") 39 if err != nil { 40 t.Fatal(err) 41 } 42 if diff := cmp.Diff(com, repo1.Commits["branch1"]["1"]); diff != "" { 43 t.Fatal(diff) 44 } 45 } 46 { 47 want := repo1.Commits["branch1"]["0"] 48 com, err := repo.CheckoutCommit(repo1.Dir, want.Hash) 49 if err != nil { 50 t.Fatal(err) 51 } 52 if diff := cmp.Diff(com, want); diff != "" { 53 t.Fatal(diff) 54 } 55 } 56 { 57 want := repo2.Commits["branch1"]["0"] 58 com, err := repo.CheckoutCommit(repo2.Dir, want.Hash) 59 if err != nil { 60 t.Fatal(err) 61 } 62 if diff := cmp.Diff(com, want); diff != "" { 63 t.Fatal(diff) 64 } 65 } 66 { 67 want := repo2.Commits["branch1"]["1"] 68 com, err := repo.CheckoutCommit(repo2.Dir, want.Hash) 69 if err != nil { 70 t.Fatal(err) 71 } 72 if diff := cmp.Diff(com, want); diff != "" { 73 t.Fatal(diff) 74 } 75 } 76 { 77 com, err := repo.CheckoutBranch(repo2.Dir, "branch2") 78 if err != nil { 79 t.Fatal(err) 80 } 81 if diff := cmp.Diff(com, repo2.Commits["branch2"]["1"]); diff != "" { 82 t.Fatal(diff) 83 } 84 } 85 { 86 want := repo2.Commits["branch2"]["0"] 87 com, err := repo.SwitchCommit(want.Hash) 88 if err != nil { 89 t.Fatal(err) 90 } 91 if diff := cmp.Diff(com, want); diff != "" { 92 t.Fatal(diff) 93 } 94 } 95 { 96 type Test struct { 97 head *Commit 98 commit *Commit 99 contains bool 100 } 101 tests := []Test{ 102 {repo2.Commits["branch2"]["1"], repo2.Commits["branch2"]["1"], true}, 103 {repo2.Commits["branch2"]["1"], repo2.Commits["branch2"]["0"], true}, 104 {repo2.Commits["branch2"]["1"], repo2.Commits["master"]["0"], true}, 105 {repo2.Commits["branch2"]["1"], repo2.Commits["master"]["1"], false}, 106 {repo2.Commits["branch2"]["1"], repo2.Commits["branch1"]["0"], false}, 107 {repo2.Commits["branch2"]["1"], repo2.Commits["branch1"]["1"], false}, 108 {repo2.Commits["branch2"]["0"], repo2.Commits["branch2"]["0"], true}, 109 {repo2.Commits["branch2"]["0"], repo2.Commits["branch2"]["1"], false}, 110 {repo2.Commits["branch2"]["0"], repo2.Commits["master"]["0"], true}, 111 {repo2.Commits["branch2"]["0"], repo2.Commits["master"]["1"], false}, 112 } 113 for i, test := range tests { 114 if _, err := repo.SwitchCommit(test.head.Hash); err != nil { 115 t.Fatal(err) 116 } 117 if contains, err := repo.Contains(test.commit.Hash); err != nil { 118 t.Fatal(err) 119 } else if contains != test.contains { 120 t.Errorf("test %v: got %v, want %v", i, contains, test.contains) 121 } 122 } 123 } 124 } 125 126 func TestMetadata(t *testing.T) { 127 t.Parallel() 128 repoDir := t.TempDir() 129 repo := MakeTestRepo(t, repoDir) 130 prevHash := "" 131 for i, test := range metadataTests { 132 repo.CommitChange(test.description) 133 com, err := repo.repo.HeadCommit() 134 if err != nil { 135 t.Fatal(err) 136 } 137 checkCommit(t, i, test, com, false) 138 if len(com.Parents) != 1 || com.Parents[0] != prevHash { 139 t.Fatalf("bad parents: %+q, expect %q", com.Parents, prevHash) 140 } 141 prevHash = com.Hash 142 } 143 commits, err := repo.repo.ExtractFixTagsFromCommits("HEAD", extractFixTagsEmail) 144 if err != nil { 145 t.Fatal(err) 146 } 147 if len(metadataTests) != len(commits) { 148 t.Fatalf("want %v commits, got %v", len(metadataTests), len(commits)) 149 } 150 for i, test := range metadataTests { 151 checkCommit(t, i, test, commits[len(commits)-i-1], true) 152 for _, title := range []string{test.title, test.title2} { 153 if title == "" { 154 continue 155 } 156 com, err := repo.repo.GetCommitByTitle(title) 157 if err != nil { 158 t.Error(err) 159 } else if com == nil { 160 t.Errorf("no commits found by title %q", title) 161 } else if com.Title != title { 162 t.Errorf("wrong commit %q found by title %q", com.Title, title) 163 } 164 } 165 } 166 } 167 168 func checkCommit(t *testing.T, idx int, test testCommit, com *Commit, checkTags bool) { 169 if !checkTags { 170 return 171 } 172 if test.title != com.Title { 173 t.Errorf("#%v: want title %q, got %q", idx, test.title, com.Title) 174 } 175 if test.author != com.Author { 176 t.Errorf("#%v: want author %q, got %q", idx, test.author, com.Author) 177 } 178 if userName != com.AuthorName { 179 t.Errorf("#%v: want author name %q, got %q", idx, userName, com.Author) 180 } 181 if diff := cmp.Diff(test.cc, com.Recipients.GetEmails(To)); diff != "" { 182 t.Logf("%#v", com.Recipients) 183 t.Error(diff) 184 } 185 if diff := cmp.Diff(test.tags, com.Tags); checkTags && diff != "" { 186 t.Error(diff) 187 } 188 } 189 190 type testCommit struct { 191 description string 192 title string 193 title2 string 194 author string 195 cc []string 196 tags []string 197 } 198 199 // nolint: lll 200 var metadataTests = []testCommit{ 201 { 202 description: `dashboard/app: bump max repros per bug to 10 203 204 Reported-by: syzbot+8e4090902540da8c6e8f@my.mail.com 205 `, 206 title: "dashboard/app: bump max repros per bug to 10", 207 author: userEmail, 208 cc: []string{userEmail}, 209 tags: []string{"8e4090902540da8c6e8f"}, 210 }, 211 { 212 description: `executor: remove dead code 213 214 Reported-by: syzbot+8e4090902540da8c6e8f@my.mail.com 215 Reported-by: syzbot <syzbot+a640a0fc325c29c3efcb@my.mail.com> 216 `, 217 title: "executor: remove dead code", 218 author: userEmail, 219 cc: []string{userEmail}, 220 tags: []string{"8e4090902540da8c6e8f", "a640a0fc325c29c3efcb"}, 221 }, 222 { 223 description: `pkg/csource: fix string escaping bug 224 225 Reported-and-tested-by: syzbot+8e4090902540da8c6e8fa640a0fc325c29c3efcb@my.mail.com 226 Tested-by: syzbot+4234987263748623784623758235@my.mail.com 227 `, 228 title: "pkg/csource: fix string escaping bug", 229 author: userEmail, 230 cc: []string{"syzbot+4234987263748623784623758235@my.mail.com", "syzbot+8e4090902540da8c6e8fa640a0fc325c29c3efcb@my.mail.com", userEmail}, 231 tags: []string{"8e4090902540da8c6e8fa640a0fc325c29c3efcb", "4234987263748623784623758235"}, 232 }, 233 { 234 description: `When freeing a lockf struct that already is part of a linked list, make sure to update the next pointer for the preceding lock. Prevents a double free panic. 235 236 ok millert@ 237 Reported-by: syzbot+6dd701dc797b23b8c761@my.mail.com 238 `, 239 title: "When freeing a lockf struct that already is part of a linked list, make sure to update the next pointer for the preceding lock. Prevents a double free panic.", 240 author: userEmail, 241 cc: []string{userEmail}, 242 tags: []string{"6dd701dc797b23b8c761"}, 243 }, 244 { 245 description: `ipmr: properly check rhltable_init() return value 246 247 commit 8fb472c09b9d ("ipmr: improve hash scalability") 248 added a call to rhltable_init() without checking its return value. 249 250 This problem was then later copied to IPv6 and factorized in commit 251 0bbbf0e7d0e7 ("ipmr, ip6mr: Unite creation of new mr_table") 252 253 Fixes: 8fb472c09b9d ("ipmr: improve hash scalability") 254 Fixes: 0bbbf0e7d0e7 ("ipmr, ip6mr: Unite creation of new mr_table") 255 Reported-by: syzbot+6dd701dc797b23b8c761@my.mail.com 256 `, 257 title: "ipmr: properly check rhltable_init() return value", 258 title2: "net-backports: ipmr: properly check rhltable_init() return value", 259 author: userEmail, 260 cc: []string{userEmail}, 261 tags: []string{"6dd701dc797b23b8c761"}, 262 }, 263 { 264 description: `f2fs: sanity check for total valid node blocks 265 266 Reported-by: syzbot+bf9253040425feb155ad@my.mail.com 267 Reported-by: syzbot+bf9253040425feb155ad@my.mail.com 268 `, 269 title: "f2fs: sanity check for total valid node blocks", 270 author: userEmail, 271 cc: []string{userEmail}, 272 tags: []string{"bf9253040425feb155ad"}, 273 }, 274 { 275 description: `USB: fix usbmon BUG trigger 276 277 Automated tests triggered this by opening usbmon and accessing the 278 mmap while simultaneously resizing the buffers. This bug was with 279 us since 2006, because typically applications only size the buffers 280 once and thus avoid racing. Reported by Kirill A. Shutemov. 281 282 Reported-by: <syzbot+f9831b881b3e849829fc@my.mail.com> 283 Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> 284 Cc: stable <stable@vger.kernel.org> 285 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 286 `, 287 title: "USB: fix usbmon BUG trigger", 288 author: userEmail, 289 cc: []string{"gregkh@linuxfoundation.org", userEmail, "zaitcev@redhat.com"}, 290 tags: []string{"f9831b881b3e849829fc"}, 291 }, 292 { 293 description: `Do more sanity checks when accepting socket addresses in routing messages from user land. Reported-by: syzbot+638dbf7851da8e255af5@my.mail.com`, 294 title: "Do more sanity checks when accepting socket addresses in routing messages from user land. Reported-by: syzbot+638dbf7851da8e255af5@my.mail.com", 295 author: userEmail, 296 cc: []string{userEmail}, 297 tags: []string{"638dbf7851da8e255af5"}, 298 }, 299 { 300 description: `Reported-by: syzbot+3e3c7cfa8093f8de047e@my.mail.com 301 302 Comment out an assertion that's now bogus and add a comment. 303 `, 304 title: "Reported-by: syzbot+3e3c7cfa8093f8de047e@my.mail.com", 305 author: userEmail, 306 cc: []string{userEmail}, 307 tags: []string{"3e3c7cfa8093f8de047e"}, 308 }, 309 } 310 311 func TestBisect(t *testing.T) { 312 t.Parallel() 313 repoDir := t.TempDir() 314 repo := MakeTestRepo(t, repoDir) 315 var commits []string 316 for i := 0; i < 5; i++ { 317 repo.CommitChange(fmt.Sprintf("commit %v", i)) 318 com, err := repo.repo.HeadCommit() 319 if err != nil { 320 t.Fatal(err) 321 } 322 commits = append(commits, com.Hash) 323 t.Logf("%v %v", com.Hash, com.Title) 324 } 325 type predFunc func() (BisectResult, error) 326 type Test struct { 327 pred predFunc 328 result []string 329 } 330 makePred := func(res1, res2, res3 BisectResult) predFunc { 331 return func() (BisectResult, error) { 332 current, err := repo.repo.HeadCommit() 333 if err != nil { 334 t.Fatal(err) 335 } 336 switch current.Hash { 337 case commits[1]: 338 return res1, nil 339 case commits[2]: 340 return res2, nil 341 case commits[3]: 342 return res3, nil 343 default: 344 return 0, fmt.Errorf("unknown commit %v", current.Hash) 345 } 346 } 347 } 348 tests := []Test{ 349 { 350 // All are bad. 351 func() (BisectResult, error) { 352 return BisectBad, nil 353 }, 354 []string{commits[1]}, 355 }, 356 { 357 // All are good. 358 func() (BisectResult, error) { 359 return BisectGood, nil 360 }, 361 []string{commits[4]}, 362 }, 363 { 364 // All are skipped. 365 func() (BisectResult, error) { 366 return BisectSkip, nil 367 }, 368 []string{commits[1], commits[2], commits[3], commits[4]}, 369 }, 370 { 371 // Some are skipped. 372 makePred(BisectSkip, BisectSkip, BisectGood), 373 []string{commits[4]}, 374 }, 375 { 376 // Some are skipped. 377 makePred(BisectGood, BisectSkip, BisectBad), 378 []string{commits[2], commits[3]}, 379 }, 380 { 381 // Some are skipped. 382 makePred(BisectSkip, BisectSkip, BisectGood), 383 []string{commits[4]}, 384 }, 385 } 386 for i, test := range tests { 387 t.Logf("TEST %v", i) 388 result, err := repo.repo.Bisect(commits[4], commits[0], &debugtracer.TestTracer{T: t}, test.pred) 389 if err != nil { 390 t.Fatal(err) 391 } 392 var got []string 393 for _, com := range result { 394 got = append(got, com.Hash) 395 } 396 sort.Strings(got) // git result order is non-deterministic (wat) 397 sort.Strings(test.result) 398 if diff := cmp.Diff(test.result, got); diff != "" { 399 t.Logf("result: %+v", got) 400 t.Fatal(diff) 401 } 402 } 403 }