blob: 54f19142541382c2eaf32fa5aea14780d6524567 [file] [log] [blame]
package memory
import (
"fmt"
"testing"
"time"
assert "github.com/stretchr/testify/require"
"go.skia.org/infra/go/deepequal"
"go.skia.org/infra/go/testutils"
"go.skia.org/infra/task_scheduler/go/db"
"go.skia.org/infra/task_scheduler/go/db/modified"
"go.skia.org/infra/task_scheduler/go/types"
)
// TestCommentBox checks that CommentBox correctly implements CommentDB.
func TestCommentBox(t *testing.T) {
testutils.SmallTest(t)
db.TestCommentDB(t, &CommentBox{ModifiedComments: &modified.ModifiedCommentsImpl{}})
}
// TestCommentBoxWithPersistence checks that NewCommentBoxWithPersistence can be
// initialized with a persisted map and will correctly write changes to the
// provided writer.
func TestCommentBoxWithPersistence(t *testing.T) {
testutils.SmallTest(t)
expected := map[string]*types.RepoComments{}
callCount := 0
testWriter := func(actual map[string]*types.RepoComments) error {
callCount++
deepequal.AssertDeepEqual(t, expected, actual)
return nil
}
d := NewCommentBoxWithPersistence(nil, nil, testWriter)
now := time.Now()
assert.Equal(t, 0, callCount)
// Add some comments.
tc1 := types.MakeTaskComment(1, 1, 1, 1, now)
r1 := tc1.Repo
expected[r1] = &types.RepoComments{
Repo: r1,
TaskComments: map[string]map[string][]*types.TaskComment{"c1": {"n1": {tc1}}},
TaskSpecComments: map[string][]*types.TaskSpecComment{},
CommitComments: map[string][]*types.CommitComment{},
}
assert.NoError(t, d.PutTaskComment(tc1))
tc2 := types.MakeTaskComment(2, 1, 1, 1, now.Add(2*time.Second))
expected[r1].TaskComments["c1"]["n1"] = []*types.TaskComment{tc1, tc2}
assert.NoError(t, d.PutTaskComment(tc2))
tc3 := types.MakeTaskComment(3, 1, 1, 1, now.Add(time.Second))
expected[r1].TaskComments["c1"]["n1"] = []*types.TaskComment{tc1, tc3, tc2}
assert.NoError(t, d.PutTaskComment(tc3))
tc4 := types.MakeTaskComment(4, 1, 1, 2, now)
expected[r1].TaskComments["c2"] = map[string][]*types.TaskComment{"n1": {tc4}}
assert.NoError(t, d.PutTaskComment(tc4))
tc5 := types.MakeTaskComment(5, 1, 2, 2, now)
expected[r1].TaskComments["c2"]["n2"] = []*types.TaskComment{tc5}
assert.NoError(t, d.PutTaskComment(tc5))
tc6 := types.MakeTaskComment(6, 2, 3, 3, now)
r2 := tc6.Repo
expected[r2] = &types.RepoComments{
Repo: r2,
TaskComments: map[string]map[string][]*types.TaskComment{"c3": {"n3": {tc6.Copy()}}},
TaskSpecComments: map[string][]*types.TaskSpecComment{},
CommitComments: map[string][]*types.CommitComment{},
}
assert.NoError(t, d.PutTaskComment(tc6))
tc6copy := tc6.Copy() // Adding identical comment should be ignored.
assert.NoError(t, d.PutTaskComment(tc6copy))
tc6.Message = "modifying after Put shouldn't affect stored comment"
assert.True(t, callCount >= 6)
sc1 := types.MakeTaskSpecComment(1, 1, 1, now)
expected[r1].TaskSpecComments["n1"] = []*types.TaskSpecComment{sc1}
assert.NoError(t, d.PutTaskSpecComment(sc1))
cc1 := types.MakeCommitComment(1, 1, 1, now)
expected[r1].CommitComments["c1"] = []*types.CommitComment{cc1}
assert.NoError(t, d.PutCommitComment(cc1))
assert.True(t, callCount >= 8)
callCount = 0
// Check that if there's an error adding, testWriter is not called.
tc1different := tc1.Copy()
tc1different.Message = "not the same"
assert.True(t, db.IsAlreadyExists(d.PutTaskComment(tc1different)))
sc1different := sc1.Copy()
sc1different.Message = "not the same"
assert.True(t, db.IsAlreadyExists(d.PutTaskSpecComment(sc1different)))
cc1different := cc1.Copy()
cc1different.Message = "not the same"
assert.True(t, db.IsAlreadyExists(d.PutCommitComment(cc1different)))
assert.Equal(t, 0, callCount)
// Reload DB from persistent.
init := map[string]*types.RepoComments{
r1: expected[r1].Copy(),
r2: expected[r2].Copy(),
}
d = NewCommentBoxWithPersistence(nil, init, testWriter)
{
actual, err := d.GetCommentsForRepos([]string{"r0", r1, r2}, now.Add(-10000*time.Hour))
assert.NoError(t, err)
expectedSlice := []*types.RepoComments{
{Repo: "r0"},
expected[r1],
expected[r2],
}
deepequal.AssertDeepEqual(t, expectedSlice, actual)
}
assert.Equal(t, 0, callCount)
// Delete some comments.
expected[r1].TaskComments["c1"]["n1"] = []*types.TaskComment{tc1, tc2}
assert.NoError(t, d.DeleteTaskComment(tc3))
expected[r1].TaskSpecComments = map[string][]*types.TaskSpecComment{}
assert.NoError(t, d.DeleteTaskSpecComment(sc1))
expected[r1].CommitComments = map[string][]*types.CommitComment{}
assert.NoError(t, d.DeleteCommitComment(cc1))
assert.Equal(t, 3, callCount)
// Delete of nonexistent task should succeed.
assert.NoError(t, d.DeleteTaskComment(types.MakeTaskComment(99, 1, 1, 1, now.Add(99*time.Second))))
assert.NoError(t, d.DeleteTaskComment(types.MakeTaskComment(99, 1, 1, 99, now)))
assert.NoError(t, d.DeleteTaskComment(types.MakeTaskComment(99, 1, 99, 1, now)))
assert.NoError(t, d.DeleteTaskComment(types.MakeTaskComment(99, 99, 1, 1, now)))
assert.NoError(t, d.DeleteTaskSpecComment(types.MakeTaskSpecComment(99, 1, 1, now.Add(99*time.Second))))
assert.NoError(t, d.DeleteTaskSpecComment(types.MakeTaskSpecComment(99, 1, 99, now)))
assert.NoError(t, d.DeleteTaskSpecComment(types.MakeTaskSpecComment(99, 99, 1, now)))
assert.NoError(t, d.DeleteCommitComment(types.MakeCommitComment(99, 1, 1, now.Add(99*time.Second))))
assert.NoError(t, d.DeleteCommitComment(types.MakeCommitComment(99, 1, 99, now)))
assert.NoError(t, d.DeleteCommitComment(types.MakeCommitComment(99, 99, 1, now)))
{
actual, err := d.GetCommentsForRepos([]string{"r0", r1, r2}, now.Add(-10000*time.Hour))
assert.NoError(t, err)
expectedSlice := []*types.RepoComments{
{Repo: "r0"},
expected[r1],
expected[r2],
}
deepequal.AssertDeepEqual(t, expectedSlice, actual)
}
// Reload DB from persistent again.
init = map[string]*types.RepoComments{
r1: expected[r1].Copy(),
r2: expected[r2].Copy(),
}
d = NewCommentBoxWithPersistence(nil, init, testWriter)
{
actual, err := d.GetCommentsForRepos([]string{"r0", r1, r2}, now.Add(-10000*time.Hour))
assert.NoError(t, err)
expectedSlice := []*types.RepoComments{
{Repo: "r0"},
expected[r1],
expected[r2],
}
deepequal.AssertDeepEqual(t, expectedSlice, actual)
}
}
// TestCommentBoxWithPersistenceError verifies that when the writer passed to
// NewCommentBoxWithPersistence returns an error, the modification does not take
// effect.
func TestCommentBoxWithPersistenceError(t *testing.T) {
testutils.SmallTest(t)
callCount := 0
var injectedError error = nil
testWriter := func(actual map[string]*types.RepoComments) error {
callCount++
return injectedError
}
d := NewCommentBoxWithPersistence(nil, nil, testWriter)
now := time.Now()
// Add some comments.
tc1 := types.MakeTaskComment(1, 1, 1, 1, now)
tc2 := types.MakeTaskComment(2, 1, 1, 1, now.Add(2*time.Second))
tc3 := types.MakeTaskComment(3, 1, 1, 1, now.Add(time.Second))
tc4 := types.MakeTaskComment(4, 1, 1, 2, now)
tc5 := types.MakeTaskComment(5, 1, 2, 2, now)
tc6 := types.MakeTaskComment(6, 2, 3, 3, now)
for _, c := range []*types.TaskComment{tc1, tc2, tc3, tc4, tc5, tc6} {
assert.NoError(t, d.PutTaskComment(c))
}
r1 := tc1.Repo
r2 := tc6.Repo
sc1 := types.MakeTaskSpecComment(1, 1, 1, now)
assert.NoError(t, d.PutTaskSpecComment(sc1))
cc1 := types.MakeCommitComment(1, 1, 1, now)
assert.NoError(t, d.PutCommitComment(cc1))
expected := []*types.RepoComments{
{
Repo: r1,
TaskComments: map[string]map[string][]*types.TaskComment{
"c1": {
"n1": {tc1, tc3, tc2},
},
"c2": {
"n1": {tc4},
"n2": {tc5},
},
},
TaskSpecComments: map[string][]*types.TaskSpecComment{
"n1": {sc1},
},
CommitComments: map[string][]*types.CommitComment{
"c1": {cc1},
},
},
{
Repo: r2,
TaskComments: map[string]map[string][]*types.TaskComment{
"c3": {
"n3": {tc6},
},
},
TaskSpecComments: map[string][]*types.TaskSpecComment{},
CommitComments: map[string][]*types.CommitComment{},
},
}
{
actual, err := d.GetCommentsForRepos([]string{r1, r2}, now.Add(-10000*time.Hour))
assert.NoError(t, err)
deepequal.AssertDeepEqual(t, expected, actual)
}
callCount = 0
injectedError = fmt.Errorf("No comments from the peanut gallery.")
assert.Error(t, d.PutTaskComment(types.MakeTaskComment(99, 1, 1, 1, now.Add(99*time.Second))))
assert.Error(t, d.PutTaskComment(types.MakeTaskComment(99, 1, 1, 99, now)))
assert.Error(t, d.PutTaskComment(types.MakeTaskComment(99, 1, 99, 1, now)))
assert.Error(t, d.PutTaskComment(types.MakeTaskComment(99, 99, 1, 1, now)))
assert.Error(t, d.PutTaskSpecComment(types.MakeTaskSpecComment(99, 1, 1, now.Add(99*time.Second))))
assert.Error(t, d.PutTaskSpecComment(types.MakeTaskSpecComment(99, 1, 99, now)))
assert.Error(t, d.PutTaskSpecComment(types.MakeTaskSpecComment(99, 99, 1, now)))
assert.Error(t, d.PutCommitComment(types.MakeCommitComment(99, 1, 1, now.Add(99*time.Second))))
assert.Error(t, d.PutCommitComment(types.MakeCommitComment(99, 1, 99, now)))
assert.Error(t, d.PutCommitComment(types.MakeCommitComment(99, 99, 1, now)))
assert.Equal(t, 10, callCount)
// Assert nothing has changed.
{
actual, err := d.GetCommentsForRepos([]string{r1, r2}, now.Add(-10000*time.Hour))
assert.NoError(t, err)
deepequal.AssertDeepEqual(t, expected, actual)
}
assert.Error(t, d.DeleteTaskComment(tc1))
assert.Error(t, d.DeleteTaskSpecComment(sc1))
assert.Error(t, d.DeleteCommitComment(cc1))
// Assert nothing has changed.
{
actual, err := d.GetCommentsForRepos([]string{r1, r2}, now.Add(-10000*time.Hour))
assert.NoError(t, err)
deepequal.AssertDeepEqual(t, expected, actual)
}
}