| // Copyright 2017 syzkaller project authors. All rights reserved. |
| // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. |
| |
| // +build aetest |
| |
| package dash |
| |
| import ( |
| "fmt" |
| "strings" |
| "testing" |
| "time" |
| |
| "github.com/google/syzkaller/dashboard/dashapi" |
| ) |
| |
| func init() { |
| initMocks() |
| installConfig(testConfig) |
| } |
| |
| // Config used in tests. |
| var testConfig = &GlobalConfig{ |
| AccessLevel: AccessPublic, |
| AuthDomain: "@syzkaller.com", |
| Clients: map[string]string{ |
| "reporting": "reportingkeyreportingkeyreportingkey", |
| }, |
| EmailBlacklist: []string{ |
| "\"Bar\" <BlackListed@Domain.com>", |
| }, |
| Namespaces: map[string]*Config{ |
| "test1": { |
| AccessLevel: AccessAdmin, |
| Key: "test1keytest1keytest1key", |
| Clients: map[string]string{ |
| client1: key1, |
| }, |
| Reporting: []Reporting{ |
| { |
| Name: "reporting1", |
| DailyLimit: 3, |
| Config: &TestConfig{ |
| Index: 1, |
| }, |
| Filter: func(bug *Bug) FilterResult { |
| if strings.HasPrefix(bug.Title, "skip without repro") && |
| bug.ReproLevel != dashapi.ReproLevelNone { |
| return FilterSkip |
| } |
| return FilterReport |
| }, |
| }, |
| { |
| Name: "reporting2", |
| DailyLimit: 3, |
| Config: &TestConfig{ |
| Index: 2, |
| }, |
| }, |
| }, |
| }, |
| "test2": { |
| AccessLevel: AccessAdmin, |
| Key: "test2keytest2keytest2key", |
| Clients: map[string]string{ |
| client2: key2, |
| }, |
| Managers: map[string]ConfigManager{ |
| "restricted-manager": { |
| RestrictedTestingRepo: "git://restricted.git/restricted.git", |
| RestrictedTestingReason: "you should test only on restricted.git", |
| }, |
| }, |
| Reporting: []Reporting{ |
| { |
| Name: "reporting1", |
| DailyLimit: 5, |
| Config: &EmailConfig{ |
| Email: "test@syzkaller.com", |
| Moderation: true, |
| }, |
| }, |
| { |
| Name: "reporting2", |
| DailyLimit: 3, |
| Config: &EmailConfig{ |
| Email: "bugs@syzkaller.com", |
| DefaultMaintainers: []string{"default@maintainers.com"}, |
| MailMaintainers: true, |
| }, |
| }, |
| }, |
| }, |
| // Namespaces for access level testing. |
| "access-admin": { |
| AccessLevel: AccessAdmin, |
| Key: "adminkeyadminkeyadminkey", |
| Clients: map[string]string{ |
| clientAdmin: keyAdmin, |
| }, |
| Reporting: []Reporting{ |
| { |
| Name: "access-admin-reporting1", |
| Config: &TestConfig{Index: 1}, |
| }, |
| { |
| Name: "access-admin-reporting2", |
| Config: &TestConfig{Index: 2}, |
| }, |
| }, |
| }, |
| "access-user": { |
| AccessLevel: AccessUser, |
| Key: "userkeyuserkeyuserkey", |
| Clients: map[string]string{ |
| clientUser: keyUser, |
| }, |
| Reporting: []Reporting{ |
| { |
| AccessLevel: AccessAdmin, |
| Name: "access-admin-reporting1", |
| Config: &TestConfig{Index: 1}, |
| }, |
| { |
| Name: "access-user-reporting2", |
| Config: &TestConfig{Index: 2}, |
| }, |
| }, |
| }, |
| "access-public": { |
| AccessLevel: AccessPublic, |
| Key: "publickeypublickeypublickey", |
| Clients: map[string]string{ |
| clientPublic: keyPublic, |
| }, |
| Reporting: []Reporting{ |
| { |
| AccessLevel: AccessUser, |
| Name: "access-user-reporting1", |
| Config: &TestConfig{Index: 1}, |
| }, |
| { |
| Name: "access-public-reporting2", |
| Config: &TestConfig{Index: 2}, |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| const ( |
| client1 = "client1" |
| client2 = "client2" |
| key1 = "client1keyclient1keyclient1key" |
| key2 = "client2keyclient2keyclient2key" |
| clientAdmin = "client-admin" |
| keyAdmin = "clientadminkeyclientadminkey" |
| clientUser = "client-user" |
| keyUser = "clientuserkeyclientuserkey" |
| clientPublic = "client-public" |
| keyPublic = "clientpublickeyclientpublickey" |
| ) |
| |
| type TestConfig struct { |
| Index int |
| } |
| |
| func (cfg *TestConfig) Type() string { |
| return "test" |
| } |
| |
| func (cfg *TestConfig) NeedMaintainers() bool { |
| return false |
| } |
| |
| func (cfg *TestConfig) Validate() error { |
| return nil |
| } |
| |
| func testBuild(id int) *dashapi.Build { |
| return &dashapi.Build{ |
| Manager: fmt.Sprintf("manager%v", id), |
| ID: fmt.Sprintf("build%v", id), |
| SyzkallerCommit: fmt.Sprintf("syzkaller_commit%v", id), |
| CompilerID: fmt.Sprintf("compiler%v", id), |
| KernelRepo: fmt.Sprintf("repo%v", id), |
| KernelBranch: fmt.Sprintf("branch%v", id), |
| KernelCommit: strings.Repeat(fmt.Sprint(id), 40)[:40], |
| KernelCommitTitle: fmt.Sprintf("kernel_commit_title%v", id), |
| KernelCommitDate: buildCommitDate, |
| KernelConfig: []byte(fmt.Sprintf("config%v", id)), |
| } |
| } |
| |
| var buildCommitDate = time.Date(1, 2, 3, 4, 5, 6, 0, time.UTC) |
| |
| func testCrash(build *dashapi.Build, id int) *dashapi.Crash { |
| return &dashapi.Crash{ |
| BuildID: build.ID, |
| Title: fmt.Sprintf("title%v", id), |
| Log: []byte(fmt.Sprintf("log%v", id)), |
| Report: []byte(fmt.Sprintf("report%v", id)), |
| } |
| } |
| |
| func testCrashWithRepro(build *dashapi.Build, id int) *dashapi.Crash { |
| crash := testCrash(build, id) |
| crash.ReproOpts = []byte(fmt.Sprintf("repro opts %v", id)) |
| crash.ReproSyz = []byte(fmt.Sprintf("syncfs(%v)", id)) |
| crash.ReproC = []byte(fmt.Sprintf("int main() { return %v; }", id)) |
| return crash |
| } |
| |
| func testCrashID(crash *dashapi.Crash) *dashapi.CrashID { |
| return &dashapi.CrashID{ |
| BuildID: crash.BuildID, |
| Title: crash.Title, |
| } |
| } |
| |
| func TestApp(t *testing.T) { |
| c := NewCtx(t) |
| defer c.Close() |
| |
| c.expectOK(c.GET("/")) |
| |
| apiClient1 := c.makeClient(client1, key1, false) |
| apiClient2 := c.makeClient(client2, key2, false) |
| c.expectFail("unknown api method", apiClient1.Query("unsupported_method", nil, nil)) |
| c.client.LogError("name", "msg %s", "arg") |
| |
| build := testBuild(1) |
| c.client.UploadBuild(build) |
| // Uploading the same build must be OK. |
| c.client.UploadBuild(build) |
| |
| // Some bad combinations of client/key. |
| c.expectFail("unauthorized", c.makeClient(client1, "", false).Query("upload_build", build, nil)) |
| c.expectFail("unauthorized", c.makeClient("unknown", key1, false).Query("upload_build", build, nil)) |
| c.expectFail("unauthorized", c.makeClient(client1, key2, false).Query("upload_build", build, nil)) |
| |
| crash1 := testCrash(build, 1) |
| c.client.ReportCrash(crash1) |
| |
| // Test that namespace isolation works. |
| c.expectFail("unknown build", apiClient2.Query("report_crash", crash1, nil)) |
| |
| crash2 := testCrashWithRepro(build, 2) |
| c.client.ReportCrash(crash2) |
| |
| // Provoke purgeOldCrashes. |
| for i := 0; i < 30; i++ { |
| crash := testCrash(build, 3) |
| crash.Log = []byte(fmt.Sprintf("log%v", i)) |
| crash.Report = []byte(fmt.Sprintf("report%v", i)) |
| c.client.ReportCrash(crash) |
| } |
| |
| cid := &dashapi.CrashID{ |
| BuildID: "build1", |
| Title: "title1", |
| } |
| c.client.ReportFailedRepro(cid) |
| |
| c.client.ReportingPollBugs("test") |
| |
| c.client.ReportingUpdate(&dashapi.BugUpdate{ |
| ID: "id", |
| Status: dashapi.BugStatusOpen, |
| ReproLevel: dashapi.ReproLevelC, |
| }) |
| } |