blob: 8ee39a825b5f8c46a22bcb9c5e579c2ddae0fbf1 [file] [log] [blame]
package sqlculpritstore
import (
"context"
"encoding/json"
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.skia.org/infra/go/sql/pool"
"go.skia.org/infra/perf/go/culprit"
pb "go.skia.org/infra/perf/go/culprit/proto/v1"
"go.skia.org/infra/perf/go/culprit/sqlculpritstore/schema"
"go.skia.org/infra/perf/go/sql/sqltest"
)
func setUp(t *testing.T) (culprit.Store, pool.Pool) {
db := sqltest.NewCockroachDBForTests(t, "culprits")
store, err := New(db)
require.NoError(t, err)
return store, db
}
func TestGet_HappyPath_ReturnsCulprits(t *testing.T) {
store, db := setUp(t)
ctx := context.Background()
id := uuid.NewString()
groupIssueMap := map[string]string{"a1": "b1"}
existingCommit := schema.CulpritSchema{
Id: id,
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
AnomalyGroupIDs: []string{"a1"},
IssueIds: []string{"b1"},
GroupIssueMap: groupIssueMap,
}
populateDb(t, ctx, db, existingCommit)
actual, err := store.Get(ctx, []string{id})
require.NoError(t, err)
expected := []*pb.Culprit{{
Commit: &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
},
AnomalyGroupIds: []string{"a1"},
IssueIds: []string{"b1"},
GroupIssueMap: groupIssueMap,
}}
assert.ElementsMatch(t, actual, expected)
}
func TestUpsert_MissingAnomlayGroupId_ReturnErr(t *testing.T) {
store, _ := setUp(t)
ctx := context.Background()
commit := &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
}
commits := []*pb.Commit{commit}
_, err := store.Upsert(ctx, "", commits)
assert.Error(t, err)
}
func TestUpsert_DifferentHost_ReturnErr(t *testing.T) {
store, _ := setUp(t)
ctx := context.Background()
commit1 := &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
}
commit2 := &pb.Commit{
Host: "chromium1.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "456",
}
commits := []*pb.Commit{commit1, commit2}
_, err := store.Upsert(ctx, "111", commits)
assert.Error(t, err)
}
func TestUpsert_DifferentProject_ReturnErr(t *testing.T) {
store, _ := setUp(t)
ctx := context.Background()
commit1 := &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
}
commit2 := &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium1/src",
Ref: "refs/head/main",
Revision: "456",
}
commits := []*pb.Commit{commit1, commit2}
_, err := store.Upsert(ctx, "111", commits)
assert.Error(t, err)
}
func TestUpsert_DifferentRef_ReturnErr(t *testing.T) {
store, _ := setUp(t)
ctx := context.Background()
commit1 := &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
}
commit2 := &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main1",
Revision: "456",
}
commits := []*pb.Commit{commit1, commit2}
_, err := store.Upsert(ctx, "111", commits)
assert.Error(t, err)
}
func TestUpsert_InsertNewCulprit_UpdateDbAndReturnNil(t *testing.T) {
store, db := setUp(t)
ctx := context.Background()
commit := &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
}
commits := []*pb.Commit{commit}
_, err := store.Upsert(ctx, "111", commits)
require.NoError(t, err)
expected := []schema.CulpritSchema{{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
AnomalyGroupIDs: []string{"111"},
GroupIssueMap: map[string]string(nil),
}}
actual := getCulpritsFromDb(t, ctx, db)
assert.ElementsMatch(t, actual, expected)
}
func TestUpsert_UpdateExistingCulprit_UpdateDbAndReturnNil(t *testing.T) {
store, db := setUp(t)
ctx := context.Background()
existingCommit := schema.CulpritSchema{
Id: uuid.NewString(),
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
AnomalyGroupIDs: []string{"111"},
}
populateDb(t, ctx, db, existingCommit)
commit := &pb.Commit{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
}
commits := []*pb.Commit{commit}
_, err := store.Upsert(ctx, "222", commits) // anomlay_group_id is different
require.NoError(t, err)
expected := []schema.CulpritSchema{{
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
AnomalyGroupIDs: []string{"222", "111"},
GroupIssueMap: map[string]string(nil),
}}
actual := getCulpritsFromDb(t, ctx, db)
assert.ElementsMatch(t, actual, expected)
}
func TestAddIssueId_NoIssueId_UpdateDbAndReturnNil(t *testing.T) {
store, db := setUp(t)
ctx := context.Background()
culpritID := uuid.NewString()
existingCommit := schema.CulpritSchema{
Id: culpritID,
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
AnomalyGroupIDs: []string{"111"},
GroupIssueMap: map[string]string{},
}
populateDb(t, ctx, db, existingCommit)
err := store.AddIssueId(ctx, existingCommit.Id, "bugid", "111")
require.NoError(t, err)
actual, err := store.Get(ctx, []string{culpritID})
assert.NoError(t, err)
assert.Equal(t, len(actual), 1)
assert.ElementsMatch(t, actual[0].IssueIds, []string{"bugid"})
assert.Equal(t, actual[0].GroupIssueMap["111"], "bugid")
}
func TestAddIssueId_UnexpectedGroup_ReturnErr(t *testing.T) {
store, db := setUp(t)
ctx := context.Background()
existingCommit := schema.CulpritSchema{
Id: uuid.NewString(),
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
AnomalyGroupIDs: []string{"111"},
IssueIds: []string{"bugid1"},
}
populateDb(t, ctx, db, existingCommit)
err := store.AddIssueId(ctx, existingCommit.Id, "bugid2", "222")
require.Error(t, err)
require.Contains(t, err.Error(), "not related to the culprit")
}
func TestAddIssueId_ExistingGroupAndIssue_ReturnErr(t *testing.T) {
store, db := setUp(t)
ctx := context.Background()
existingCommit := schema.CulpritSchema{
Id: uuid.NewString(),
Host: "chromium.googlesource.com",
Project: "chromium/src",
Ref: "refs/head/main",
Revision: "123",
AnomalyGroupIDs: []string{"111"},
IssueIds: []string{"bugid1"},
GroupIssueMap: map[string]string{"111": "bugid1"},
}
populateDb(t, ctx, db, existingCommit)
err := store.AddIssueId(ctx, existingCommit.Id, "bugid2", "111")
require.Error(t, err)
require.Contains(t, err.Error(), "group id 111 has related issue already")
}
func populateDb(t *testing.T, ctx context.Context, db pool.Pool, culprit schema.CulpritSchema) {
group_issue_map, _ := json.Marshal(culprit.GroupIssueMap)
const query = `INSERT INTO Culprits
(id, host, project, ref, revision, anomaly_group_ids, issue_ids, group_issue_map)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8)`
if _, err := db.Exec(ctx, query, culprit.Id, culprit.Host, culprit.Project, culprit.Ref, culprit.Revision, culprit.AnomalyGroupIDs, culprit.IssueIds, group_issue_map); err != nil {
require.NoError(t, err)
}
}
func getCulpritsFromDb(t *testing.T, ctx context.Context, db pool.Pool) []schema.CulpritSchema {
actual := []schema.CulpritSchema{}
rows, _ := db.Query(ctx, "SELECT host, project, ref, revision, anomaly_group_ids, issue_ids, group_issue_map FROM Culprits")
for rows.Next() {
var culpritInDb schema.CulpritSchema
var group_issue_map_in_jsonb []byte
if err := rows.Scan(&culpritInDb.Host, &culpritInDb.Project, &culpritInDb.Ref, &culpritInDb.Revision, &culpritInDb.AnomalyGroupIDs, &culpritInDb.IssueIds, &group_issue_map_in_jsonb); err != nil {
require.NoError(t, err)
}
var group_issue_map map[string]string
_ = json.Unmarshal(group_issue_map_in_jsonb, &group_issue_map)
culpritInDb.GroupIssueMap = group_issue_map
actual = append(actual, culpritInDb)
}
return actual
}