-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
dashboard/app: test coverage /file link
1. Init 1 coveragedb client per AppEngine instance. 2. Always init coverage handlers. It simplifies testing. 3. Read webGit from ctx to make it mockable. 4. Read coveragedb client from ctx to make it mockable. 5. Use int for file line number and int64 for merged coverage.
- Loading branch information
1 parent
de67257
commit a3e20fd
Showing
17 changed files
with
354 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
// Copyright 2025 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. | ||
|
||
package main | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"github.com/google/syzkaller/pkg/coveragedb" | ||
"github.com/google/syzkaller/pkg/coveragedb/mocks" | ||
"github.com/google/syzkaller/pkg/coveragedb/spannerclient" | ||
"github.com/google/syzkaller/pkg/covermerger" | ||
mergermocks "github.com/google/syzkaller/pkg/covermerger/mocks" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/mock" | ||
"google.golang.org/api/iterator" | ||
) | ||
|
||
func TestFileCoverage(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
covDB func(t *testing.T) spannerclient.SpannerClient | ||
fileProv covermerger.FileVersProvider | ||
url string | ||
wantInRes []string | ||
}{ | ||
{ | ||
name: "empty db", | ||
covDB: func(t *testing.T) spannerclient.SpannerClient { return emptyCoverageDBFixture(t, 1) }, | ||
fileProv: staticFileProvider(t), | ||
url: "/test2/graph/coverage/file?dateto=2025-01-31&period=month&commit=c0e75905caf368e19aab585d20151500e750de89&filepath=virt/kvm/kvm_main.c", | ||
wantInRes: []string{"1 line1"}, | ||
}, | ||
{ | ||
name: "regular db", | ||
covDB: func(t *testing.T) spannerclient.SpannerClient { return coverageDBFixture(t) }, | ||
fileProv: staticFileProvider(t), | ||
url: "/test2/graph/coverage/file?dateto=2025-01-31&period=month&commit=c0e75905caf368e19aab585d20151500e750de89&filepath=virt/kvm/kvm_main.c", | ||
wantInRes: []string{ | ||
"4 1 line1", | ||
"5 2 line2", | ||
"6 3 line3"}, | ||
}, | ||
{ | ||
name: "multimanager db", | ||
covDB: func(t *testing.T) spannerclient.SpannerClient { return multiManagerCovDBFixture(t) }, | ||
fileProv: staticFileProvider(t), | ||
url: "/test2/graph/coverage/file?dateto=2025-01-31&period=month&commit=c0e75905caf368e19aab585d20151500e750de89&filepath=virt/kvm/kvm_main.c&manager=special-cc-manager&unique-only=1", | ||
wantInRes: []string{ | ||
" 0 1 line1", // Covered, is not unique. | ||
" 5 2 line2", // Covered and is unique. | ||
" 3 line3", // Covered only by "*" managers. | ||
}, | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
c := NewCtx(t) | ||
defer c.Close() | ||
c.setCoverageMocks("test2", test.covDB(t), test.fileProv) | ||
fileCovPage, err := c.GET(test.url) | ||
assert.NoError(t, err) | ||
got := string(fileCovPage) | ||
for _, want := range test.wantInRes { | ||
if !strings.Contains(got, want) { | ||
t.Errorf(`"%s" wasn't found in "%s"'`, want, got) | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func staticFileProvider(t *testing.T) covermerger.FileVersProvider { | ||
m := mergermocks.NewFileVersProvider(t) | ||
m.On("GetFileVersions", mock.Anything, mock.Anything). | ||
Return(func(targetFilePath string, repoCommits ...covermerger.RepoCommit, | ||
) covermerger.FileVersions { | ||
res := covermerger.FileVersions{} | ||
for _, rc := range repoCommits { | ||
res[rc] = `line1 | ||
line2 | ||
line3` | ||
} | ||
return res | ||
}, nil) | ||
return m | ||
} | ||
|
||
func emptyCoverageDBFixture(t *testing.T, times int) spannerclient.SpannerClient { | ||
mRowIterator := mocks.NewRowIterator(t) | ||
mRowIterator.On("Stop").Return().Times(times) | ||
mRowIterator.On("Next"). | ||
Return(nil, iterator.Done).Times(times) | ||
|
||
mTran := mocks.NewReadOnlyTransaction(t) | ||
mTran.On("Query", mock.Anything, mock.Anything). | ||
Return(mRowIterator).Times(times) | ||
|
||
m := mocks.NewSpannerClient(t) | ||
m.On("Single"). | ||
Return(mTran).Times(times) | ||
return m | ||
} | ||
|
||
func coverageDBFixture(t *testing.T) spannerclient.SpannerClient { | ||
mRowIt := newRowIteratorMock(t, []*coveragedb.LinesCoverage{{ | ||
LinesInstrumented: []int64{1, 2, 3}, | ||
HitCounts: []int64{4, 5, 6}, | ||
}}) | ||
|
||
mTran := mocks.NewReadOnlyTransaction(t) | ||
mTran.On("Query", mock.Anything, mock.Anything). | ||
Return(mRowIt).Once() | ||
|
||
m := mocks.NewSpannerClient(t) | ||
m.On("Single"). | ||
Return(mTran).Once() | ||
return m | ||
} | ||
|
||
func multiManagerCovDBFixture(t *testing.T) spannerclient.SpannerClient { | ||
mReadFullCoverageTran := mocks.NewReadOnlyTransaction(t) | ||
mReadFullCoverageTran.On("Query", mock.Anything, mock.Anything). | ||
Return(newRowIteratorMock(t, []*coveragedb.LinesCoverage{{ | ||
LinesInstrumented: []int64{1, 2, 3}, | ||
HitCounts: []int64{4, 5, 6}, | ||
}})).Once() | ||
|
||
mReadPartialCoverageTran := mocks.NewReadOnlyTransaction(t) | ||
mReadPartialCoverageTran.On("Query", mock.Anything, mock.Anything). | ||
Return(newRowIteratorMock(t, []*coveragedb.LinesCoverage{{ | ||
LinesInstrumented: []int64{1, 2}, | ||
HitCounts: []int64{3, 5}, | ||
}})).Once() | ||
|
||
m := mocks.NewSpannerClient(t) | ||
// The order matters. Full coverage is fetched second. | ||
m.On("Single"). | ||
Return(mReadPartialCoverageTran).Once() | ||
m.On("Single"). | ||
Return(mReadFullCoverageTran).Once() | ||
|
||
return m | ||
} | ||
|
||
func newRowIteratorMock(t *testing.T, cov []*coveragedb.LinesCoverage, | ||
) *mocks.RowIterator { | ||
m := mocks.NewRowIterator(t) | ||
m.On("Stop").Once().Return() | ||
for _, item := range cov { | ||
mRow := mocks.NewRow(t) | ||
mRow.On("ToStruct", mock.Anything). | ||
Run(func(args mock.Arguments) { | ||
arg := args.Get(0).(*coveragedb.LinesCoverage) | ||
*arg = *item | ||
}). | ||
Return(nil).Once() | ||
|
||
m.On("Next"). | ||
Return(mRow, nil).Once() | ||
} | ||
|
||
m.On("Next"). | ||
Return(nil, iterator.Done).Once() | ||
return m | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.