aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2026-02-02 08:12:51 +0100
committerDmitry Vyukov <dvyukov@google.com>2026-02-02 07:25:26 +0000
commit018ebef2bbad9aa0e117fb8e7768c481e0dd4dd4 (patch)
treeb0dba3854ec0286a41a63b30a3e2cb898f11f4ee
parent6b8752f20c06eee857545047ab920e63322bf4c8 (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.go10
-rw-r--r--dashboard/app/local_ui_test.go49
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.",
+ },
+ })
}