diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2026-02-02 08:12:51 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2026-02-02 07:25:26 +0000 |
| commit | 018ebef2bbad9aa0e117fb8e7768c481e0dd4dd4 (patch) | |
| tree | b0dba3854ec0286a41a63b30a3e2cb898f11f4ee | |
| parent | 6b8752f20c06eee857545047ab920e63322bf4c8 (diff) | |
dashboard/app: improve TestLocalUI
- allow to see UI as admin/user/none
- populate DB before opening browser
- don't log requests for favicon.ico
- fix http handler registration for the test namespace
- populate database with slightly more realistic data
| -rw-r--r-- | dashboard/app/app_test.go | 10 | ||||
| -rw-r--r-- | dashboard/app/local_ui_test.go | 49 |
2 files changed, 51 insertions, 8 deletions
diff --git a/dashboard/app/app_test.go b/dashboard/app/app_test.go index cfabcc473..53b121462 100644 --- a/dashboard/app/app_test.go +++ b/dashboard/app/app_test.go @@ -36,6 +36,16 @@ func init() { notifyAboutUnsuccessfulBisections = true ensureConfigImmutability = true initMocks() + // Insert namespaces from localUIConfig into testConfig. + // This is required b/c main.go registers HTTP handlers for all namespaces + // in the main installed config only, so if we don't do that the localUIConfig + // namespaces won't have handlers. // It's not important if there are duplicates + // b/c registration code mostly looks at namespace names. + for ns, cfg := range localUIConfig.Namespaces { + if testConfig.Namespaces[ns] == nil { + testConfig.Namespaces[ns] = cfg + } + } installConfig(testConfig) } diff --git a/dashboard/app/local_ui_test.go b/dashboard/app/local_ui_test.go index e17f46fac..610b5ff45 100644 --- a/dashboard/app/local_ui_test.go +++ b/dashboard/app/local_ui_test.go @@ -16,6 +16,7 @@ import ( "time" "github.com/google/syzkaller/dashboard/dashapi" + "github.com/google/syzkaller/pkg/aflow/ai" "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/sys/targets" "github.com/stretchr/testify/require" @@ -25,6 +26,7 @@ import ( var ( flagLocalUI = flag.Bool("local-ui", false, "start local web server in the TestLocalUI test") flagLocalUIAddr = flag.String("local-ui-addr", "127.0.0.1:0", "run the web server on this network address") + flagLocalUIUser = flag.String("local-ui-user", "admin", "authenticate requests as admin/user/none") ) // Run the test with: @@ -48,20 +50,20 @@ func TestLocalUI(t *testing.T) { c.transformContext = func(ctx context.Context) context.Context { return contextWithConfig(ctx, localUIConfig) } + populateLocalUIDB(t, c) ln, err := net.Listen("tcp4", *flagLocalUIAddr) require.NoError(t, err) url := fmt.Sprintf("http://%v", ln.Addr()) exec.Command("xdg-open", url+"/linux").Start() go func() { - populateLocalUIDB(t, c) // Let the dev_appserver print tons of unuseful garbage to the console // before we print the serving address, so it's possible to find it in all the garbage. - time.Sleep(2 * time.Second) + time.Sleep(3 * time.Second) t.Logf("serving http on %v", url) }() require.NoError(t, http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { url := r.URL.String() - if file := filepath.Join(".", url); url != "/" && osutil.IsExist(file) { + if file := filepath.Join(".", url); url != "/" && (osutil.IsExist(file) || url == "/favicon.ico") { http.ServeFile(w, r, file) return } @@ -72,7 +74,12 @@ func TestLocalUI(t *testing.T) { req.Header.Add("X-Appengine-User-IP", "127.0.0.1") req = req.WithContext(c.transformContext(req.Context())) req = registerRequest(req, c) - aetest.Login(makeUser(AuthorizedAdmin), req) + switch *flagLocalUIUser { + case "admin": + aetest.Login(makeUser(AuthorizedAdmin), req) + case "user": + aetest.Login(makeUser(AuthorizedUser), req) + } http.DefaultServeMux.ServeHTTP(w, req) }))) } @@ -87,7 +94,7 @@ var localUIConfig = &GlobalConfig{ AI: true, Key: password1, Clients: map[string]string{ - client1: password1, + localUIClient: localUIPassword, }, Repos: []KernelRepo{ { @@ -112,8 +119,18 @@ var localUIConfig = &GlobalConfig{ }, } +const ( + localUIClient = "local_ui_client" + localUIPassword = "localuipasswordlocaluipasswordlocaluipassword" +) + func populateLocalUIDB(t *testing.T, c *Ctx) { - client := c.makeClient(client1, password1, true) + client := c.makeClient(localUIClient, localUIPassword, true) + bugTitles := []string{ + "KASAN: slab-use-after-free Write in nr_neigh_put", + "KCSAN: data-race in mISDN_ioctl / mISDN_read", + "WARNING in raw_ioctl", + } for buildID := 0; buildID < 3; buildID++ { build := &dashapi.Build{ Manager: fmt.Sprintf("manager%v", buildID), @@ -131,11 +148,11 @@ func populateLocalUIDB(t *testing.T, c *Ctx) { KernelConfig: []byte(fmt.Sprintf("config%v", buildID)), } client.UploadBuild(build) - for bugID := 0; bugID < 3; bugID++ { + for bugID := 0; bugID < len(bugTitles); bugID++ { for crashID := 0; crashID < 3; crashID++ { client.ReportCrash(&dashapi.Crash{ BuildID: build.ID, - Title: fmt.Sprintf("title %v %v", bugID, crashID), + Title: bugTitles[bugID], Log: []byte(fmt.Sprintf("log %v %v", bugID, crashID)), Report: []byte(fmt.Sprintf("report %v %v", bugID, crashID)), MachineInfo: []byte(fmt.Sprintf("machine info %v %v", bugID, crashID)), @@ -147,4 +164,20 @@ func populateLocalUIDB(t *testing.T, c *Ctx) { } } } + resp, _ := client.AIJobPoll(&dashapi.AIJobPollReq{ + CodeRevision: "xxx", + Workflows: []dashapi.AIWorkflow{ + {Type: ai.WorkflowPatching, Name: string(ai.WorkflowPatching)}, + {Type: ai.WorkflowModeration, Name: string(ai.WorkflowModeration)}, + {Type: ai.WorkflowAssessmentKCSAN, Name: string(ai.WorkflowAssessmentKCSAN)}, + }, + }) + client.AIJobDone(&dashapi.AIJobDoneReq{ + ID: resp.ID, + Results: map[string]any{ + "Benign": false, + "Confident": true, + "Explanation": "ISO C says data races result in undefined program behavior.", + }, + }) } |
