diff options
| author | Taras Madan <tarasmadan@google.com> | 2025-01-28 15:33:48 +0100 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2025-01-29 11:10:34 +0000 |
| commit | 136953f126961dd23d155ae33078a9cab1e8a2d0 (patch) | |
| tree | ce958322ec891d019a7070f2d6f3ecef21374edc /pkg/coveragedb | |
| parent | f6dd7a77e4d2c0503672d68ce9f19b42bec99299 (diff) | |
pkg/coveragedb: store information about covered file functions in db
Diffstat (limited to 'pkg/coveragedb')
| -rw-r--r-- | pkg/coveragedb/coveragedb.go | 99 | ||||
| -rw-r--r-- | pkg/coveragedb/coveragedb_mock_test.go | 24 |
2 files changed, 80 insertions, 43 deletions
diff --git a/pkg/coveragedb/coveragedb.go b/pkg/coveragedb/coveragedb.go index f2c1cdd69..5c60958fa 100644 --- a/pkg/coveragedb/coveragedb.go +++ b/pkg/coveragedb/coveragedb.go @@ -22,22 +22,6 @@ import ( "google.golang.org/api/iterator" ) -type FilesRecord struct { - Session string - FilePath string - Instrumented int64 - Covered int64 - LinesInstrumented []int64 - HitCounts []int64 - Manager string // "*" means "collected from all managers" -} - -type FileSubsystems struct { - Namespace string - FilePath string - Subsystems []string -} - type HistoryRecord struct { Session string Time time.Time @@ -49,6 +33,25 @@ type HistoryRecord struct { TotalRows int64 } +type MergedCoverageRecord struct { + Manager string + FilePath string + FileData *Coverage +} + +// FuncLines represents the 'functions' table records. +// It could be used to maps 'hitcounts' from 'files' table to the function names. +type FuncLines struct { + FilePath string + FuncName string + Lines []int64 // List of lines we know belong to this function name according to the addr2line output. +} + +type JSONLWrapper struct { + MCR *MergedCoverageRecord + FL *FuncLines +} + type Coverage struct { Instrumented int64 Covered int64 @@ -65,23 +68,27 @@ func (c *Coverage) AddLineHitCount(line int, hitCount int64) { } } -type MergedCoverageRecord struct { - Manager string - FilePath string - FileData *Coverage +type filesRecord struct { + Session string + FilePath string + Instrumented int64 + Covered int64 + LinesInstrumented []int64 + HitCounts []int64 + Manager string // "*" means "collected from all managers" } -// FuncLines represents the 'functions' table records. -// It could be used to maps 'hitcounts' from 'files' table to the function names. -type FuncLines struct { +type functionsRecord struct { + Session string FilePath string FuncName string - Lines []int64 // List of lines we know belong to this function name according to the addr2line output. + Lines []int64 } -type JSONLWrapper struct { - MCR *MergedCoverageRecord - FL *FuncLines +type fileSubsystems struct { + Namespace string + FilePath string + Subsystems []string } func SaveMergeResult(ctx context.Context, client spannerclient.SpannerClient, descr *HistoryRecord, dec *json.Decoder, @@ -94,23 +101,26 @@ func SaveMergeResult(ctx context.Context, client spannerclient.SpannerClient, de ssCache := make(map[string][]string) session := uuid.New().String() - mutations := []*spanner.Mutation{} + var mutations []*spanner.Mutation for { - var mcr MergedCoverageRecord - err := dec.Decode(&mcr) + var wr JSONLWrapper + err := dec.Decode(&wr) if err == io.EOF { break } if err != nil { return rowsCreated, fmt.Errorf("dec.Decode(MergedCoverageRecord): %w", err) } - if mcr.FileData == nil { - return rowsCreated, errors.New("field MergedCoverageRecord.FileData can't be nil") + if mcr := wr.MCR; mcr != nil { + mutations = append(mutations, fileRecordMutation(session, mcr)) + subsystems := getFileSubsystems(mcr.FilePath, ssMatcher, ssCache) + mutations = append(mutations, fileSubsystemsMutation(descr.Namespace, mcr.FilePath, subsystems)) + } else if fl := wr.FL; fl != nil { + mutations = append(mutations, fileFunctionsMutation(session, fl)) + } else { + return rowsCreated, errors.New("JSONLWrapper can't be empty") } - mutations = append(mutations, fileRecordMutation(session, &mcr)) - subsystems := fileSubsystems(mcr.FilePath, ssMatcher, ssCache) - mutations = append(mutations, fileSubsystemsMutation(descr.Namespace, mcr.FilePath, subsystems)) // There is a limit on the number of mutations per transaction (80k) imposed by the DB. // This includes both explicit mutations of the fields (6 fields * 1k records = 6k mutations) // and implicit index mutations. @@ -203,8 +213,21 @@ func historyMutation(session string, template *HistoryRecord) *spanner.Mutation return historyInsert } +func fileFunctionsMutation(session string, fl *FuncLines) *spanner.Mutation { + insert, err := spanner.InsertOrUpdateStruct("functions", &functionsRecord{ + Session: session, + FilePath: fl.FilePath, + FuncName: fl.FuncName, + Lines: fl.Lines, + }) + if err != nil { + panic(fmt.Sprintf("failed to fileFunctionsMutation: %v", err)) + } + return insert +} + func fileRecordMutation(session string, mcr *MergedCoverageRecord) *spanner.Mutation { - insert, err := spanner.InsertOrUpdateStruct("files", &FilesRecord{ + insert, err := spanner.InsertOrUpdateStruct("files", &filesRecord{ Session: session, FilePath: mcr.FilePath, Instrumented: mcr.FileData.Instrumented, @@ -220,7 +243,7 @@ func fileRecordMutation(session string, mcr *MergedCoverageRecord) *spanner.Muta } func fileSubsystemsMutation(ns, filePath string, subsystems []string) *spanner.Mutation { - insert, err := spanner.InsertOrUpdateStruct("file_subsystems", &FileSubsystems{ + insert, err := spanner.InsertOrUpdateStruct("file_subsystems", &fileSubsystems{ Namespace: ns, FilePath: filePath, Subsystems: subsystems, @@ -231,7 +254,7 @@ func fileSubsystemsMutation(ns, filePath string, subsystems []string) *spanner.M return insert } -func fileSubsystems(filePath string, ssMatcher *subsystem.PathMatcher, ssCache map[string][]string) []string { +func getFileSubsystems(filePath string, ssMatcher *subsystem.PathMatcher, ssCache map[string][]string) []string { sss, cached := ssCache[filePath] if !cached { for _, match := range ssMatcher.Match(filePath) { diff --git a/pkg/coveragedb/coveragedb_mock_test.go b/pkg/coveragedb/coveragedb_mock_test.go index b0ffb7815..dac6fe777 100644 --- a/pkg/coveragedb/coveragedb_mock_test.go +++ b/pkg/coveragedb/coveragedb_mock_test.go @@ -45,9 +45,10 @@ func TestSaveMergeResult(t *testing.T) { jsonl: strings.NewReader(`{a}`), wantErr: true, }, + // nolint: dupl { - name: "1 record, Ok", - jsonl: strings.NewReader(`{"FileData":{}}`), + name: "1 MCR record, Ok", + jsonl: strings.NewReader(`{"MCR":{"FileData":{}}}`), descr: &HistoryRecord{}, wantRows: 3, // 1 in files, 1 in file_subsystems and 1 in merge_history mockTune: func(t *testing.T, m *mocks.SpannerClient) { @@ -57,10 +58,23 @@ func TestSaveMergeResult(t *testing.T) { Once() }, }, + // nolint: dupl + { + name: "1 FC record, Ok", + jsonl: strings.NewReader(`{"FL":{}}`), + descr: &HistoryRecord{}, + wantRows: 2, // 1 in functions and 1 in merge_history + mockTune: func(t *testing.T, m *mocks.SpannerClient) { + m. + On("Apply", mock.Anything, mock.Anything). + Return(time.Now(), nil). + Once() + }, + }, { name: "2 records, Ok", - jsonl: strings.NewReader(` {"FileData":{}} - {"FileData":{}}`), + jsonl: strings.NewReader(` {"MCR":{"FileData":{}}} + {"MCR":{"FileData":{}}}`), descr: &HistoryRecord{}, wantRows: 5, mockTune: func(t *testing.T, m *mocks.SpannerClient) { @@ -77,7 +91,7 @@ func TestSaveMergeResult(t *testing.T) { }, { name: "2k records, Ok", - jsonl: strings.NewReader(strings.Repeat("{\"FileData\":{}}\n", 2000)), + jsonl: strings.NewReader(strings.Repeat("{\"MCR\":{\"FileData\":{}}}\n", 2000)), descr: &HistoryRecord{}, wantRows: 4001, mockTune: func(t *testing.T, m *mocks.SpannerClient) { |
