github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-cluster/pkg/controller/testutil.go (about) 1 // Copyright 2025 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 controller 5 6 import ( 7 "context" 8 "fmt" 9 "net/http/httptest" 10 "testing" 11 "time" 12 13 "github.com/google/syzkaller/syz-cluster/pkg/api" 14 "github.com/google/syzkaller/syz-cluster/pkg/app" 15 "github.com/google/syzkaller/syz-cluster/pkg/db" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 type EntityIDs struct { 20 SeriesID string 21 SessionID string 22 } 23 24 // UploadTestSeries returns a (series ID, session ID) tuple. 25 func UploadTestSeries(t *testing.T, ctx context.Context, 26 client *api.Client, series *api.Series) EntityIDs { 27 retSeries, err := client.UploadSeries(ctx, series) 28 assert.NoError(t, err) 29 retSession, err := client.UploadSession(ctx, &api.NewSession{ 30 ExtID: series.ExtID, 31 }) 32 assert.NoError(t, err) 33 return EntityIDs{ 34 SeriesID: retSeries.ID, 35 SessionID: retSession.ID, 36 } 37 } 38 39 func UploadTestBuild(t *testing.T, ctx context.Context, client *api.Client, 40 build *api.Build) *api.UploadBuildResp { 41 ret, err := client.UploadBuild(ctx, &api.UploadBuildReq{ 42 Build: *build, 43 Log: []byte("build log"), 44 Config: []byte("build config"), 45 }) 46 assert.NoError(t, err) 47 assert.NotEmpty(t, ret.ID) 48 return ret 49 } 50 51 func TestServer(t *testing.T, env *app.AppEnvironment) *api.Client { 52 apiServer := NewAPIServer(env) 53 server := httptest.NewServer(apiServer.Mux()) 54 t.Cleanup(server.Close) 55 return api.NewClient(server.URL) 56 } 57 58 func DummySeries() *api.Series { 59 return &api.Series{ 60 ExtID: "ext-id", 61 Title: "test series name", 62 Link: "http://link/to/series", 63 Cc: []string{"first@user.com", "second@user.com"}, 64 Patches: []api.SeriesPatch{ 65 { 66 Seq: 1, 67 Title: "first patch title", 68 Body: []byte("first content"), 69 }, 70 }, 71 } 72 } 73 74 func DummyBuild() *api.Build { 75 return &api.Build{ 76 Arch: "amd64", 77 TreeName: "mainline", 78 TreeURL: "https://git/repo", 79 ConfigName: "config", 80 CommitHash: "abcd", 81 Compiler: "compiler", 82 } 83 } 84 85 func DummyFindings() []*api.NewFinding { 86 var findings []*api.NewFinding 87 for i := 0; i < 2; i++ { 88 findings = append(findings, &api.NewFinding{ 89 Title: fmt.Sprintf("finding %d", i), 90 TestName: "test", 91 Report: []byte(fmt.Sprintf("report %d", i)), 92 Log: []byte(fmt.Sprintf("log %d", i)), 93 SyzRepro: []byte(fmt.Sprintf("log %d", i)), 94 CRepro: []byte(fmt.Sprintf("log %d", i)), 95 }) 96 } 97 return findings 98 } 99 100 type SeriesWithFindingIDs struct { 101 EntityIDs 102 BaseBuildID string 103 PatchedBuildID string 104 } 105 106 func FakeSeriesWithFindings(t *testing.T, ctx context.Context, env *app.AppEnvironment, 107 client *api.Client, series *api.Series) SeriesWithFindingIDs { 108 ids := UploadTestSeries(t, ctx, client, series) 109 baseBuild := UploadTestBuild(t, ctx, client, DummyBuild()) 110 patchedBuild := UploadTestBuild(t, ctx, client, DummyBuild()) 111 err := client.UploadTestResult(ctx, &api.TestResult{ 112 SessionID: ids.SessionID, 113 BaseBuildID: baseBuild.ID, 114 PatchedBuildID: patchedBuild.ID, 115 TestName: "test", 116 Result: api.TestRunning, 117 }) 118 assert.NoError(t, err) 119 120 findings := DummyFindings() 121 for _, finding := range findings { 122 finding.SessionID = ids.SessionID 123 err = client.UploadFinding(ctx, finding) 124 assert.NoError(t, err) 125 } 126 MarkSessionFinished(t, env, ids.SessionID) 127 return SeriesWithFindingIDs{ 128 EntityIDs: ids, 129 BaseBuildID: baseBuild.ID, 130 PatchedBuildID: patchedBuild.ID, 131 } 132 } 133 134 func MarkSessionFinished(t *testing.T, env *app.AppEnvironment, sessionID string) { 135 repo := db.NewSessionRepository(env.Spanner) 136 err := repo.Update(context.Background(), sessionID, func(session *db.Session) error { 137 session.SetFinishedAt(time.Now()) 138 return nil 139 }) 140 assert.NoError(t, err) 141 }