Files
tasks/service/matching/backlog_manager_test.go
Alex ShtinandGitHub 8e8f1b0f7c Remove license header from every file (#7689)
## What changed?
<!-- Describe what has changed in this PR -->
Remove license header from every file. Because it is really hard to
follow in this PR here is the summary:
1. License header is removed from all `.go` and `.proto` files
:fireworks::fireworks:🎆.
2. `LICENSE` file in the root directory has only Temporal and Uber
copyrights.
3. 5 other `LICENSE` files added to the packages which have copyrights
different from Temporal and Uber: Datadog, Xargin, "Mat Ryer, Tyler
Bunnell and contributors".
4. `license_file` flag is removed from all code generation tools.
5. `copyright_file` flag is removed from `go:generate mockgen`
directive.
6. All copyright related targets are removed from `Makefile`.
7. Updated Temporal copyright year to 2025 everywhere.

## Why?
<!-- Tell your future self why have you made these changes -->
I double checked with legal department that it is not needed to have
license header in every file. One file per repo is enough. I put all
copyrights to the root `LICENSE` file and removed header from all other
files. Also updated tools and `Makefile`.
2025-05-01 18:50:21 -07:00

306 lines
9.2 KiB
Go

package matching
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/suite"
enumspb "go.temporal.io/api/enums/v1"
persistencespb "go.temporal.io/server/api/persistence/v1"
"go.temporal.io/server/common/dynamicconfig"
"go.temporal.io/server/common/metrics"
"go.temporal.io/server/common/primitives/timestamp"
"go.temporal.io/server/common/testing/testlogger"
"go.temporal.io/server/common/tqid"
"go.uber.org/mock/gomock"
)
type BacklogManagerTestSuite struct {
suite.Suite
newMatcher bool
logger *testlogger.TestLogger
blm backlogManager
controller *gomock.Controller
cancelCtx context.CancelFunc
taskMgr *testTaskManager
ptqMgr *MockphysicalTaskQueueManager
}
func TestBacklogManagerTestSuite(t *testing.T) {
t.Parallel()
suite.Run(t, &BacklogManagerTestSuite{newMatcher: false})
}
func TestBacklogManagerWithNewMatcherTestSuite(t *testing.T) {
t.Parallel()
suite.Run(t, &BacklogManagerTestSuite{newMatcher: true})
}
func (s *BacklogManagerTestSuite) SetupTest() {
s.controller = gomock.NewController(s.T())
s.logger = testlogger.NewTestLogger(s.T(), testlogger.FailOnAnyUnexpectedError)
s.taskMgr = newTestTaskManager(s.logger)
cfg := NewConfig(dynamicconfig.NewNoopCollection())
f, _ := tqid.NewTaskQueueFamily("", "test-queue")
prtn := f.TaskQueue(enumspb.TASK_QUEUE_TYPE_WORKFLOW).NormalPartition(0)
queue := UnversionedQueueKey(prtn)
tlCfg := newTaskQueueConfig(prtn.TaskQueue(), cfg, "test-namespace")
s.ptqMgr = NewMockphysicalTaskQueueManager(s.controller)
s.ptqMgr.EXPECT().QueueKey().Return(queue).AnyTimes()
s.ptqMgr.EXPECT().ProcessSpooledTask(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
var ctx context.Context
ctx, s.cancelCtx = context.WithCancel(context.Background())
s.T().Cleanup(s.cancelCtx)
if s.newMatcher {
s.blm = newPriBacklogManager(
ctx,
s.ptqMgr,
tlCfg,
s.taskMgr,
s.logger,
s.logger,
nil,
metrics.NoopMetricsHandler,
)
} else {
s.blm = newBacklogManager(
ctx,
s.ptqMgr,
tlCfg,
s.taskMgr,
s.logger,
s.logger,
nil,
metrics.NoopMetricsHandler,
)
}
}
func (s *BacklogManagerTestSuite) TestReadLevelForAllExpiredTasksInBatch() {
if s.newMatcher {
s.T().Skip("not compatible with new backlog manager")
}
blm := s.blm.(*backlogManagerImpl)
s.NoError(blm.taskWriter.initReadWriteState())
s.Equal(int64(1), blm.getDB().rangeID)
s.Equal(int64(0), blm.taskAckManager.getAckLevel())
s.Equal(int64(0), blm.taskAckManager.getReadLevel())
// Add all expired tasks
tasks := []*persistencespb.AllocatedTaskInfo{
{
Data: &persistencespb.TaskInfo{
ExpiryTime: timestamp.TimeNowPtrUtcAddSeconds(-60),
CreateTime: timestamp.TimeNowPtrUtcAddSeconds(-60 * 60),
},
TaskId: 11,
},
{
Data: &persistencespb.TaskInfo{
ExpiryTime: timestamp.TimeNowPtrUtcAddSeconds(-60),
CreateTime: timestamp.TimeNowPtrUtcAddSeconds(-60 * 60),
},
TaskId: 12,
},
}
s.NoError(blm.taskReader.addTasksToBuffer(context.TODO(), tasks))
s.Equal(int64(0), blm.taskAckManager.getAckLevel())
s.Equal(int64(12), blm.taskAckManager.getReadLevel())
// Now add a mix of valid and expired tasks
s.NoError(blm.taskReader.addTasksToBuffer(context.TODO(), []*persistencespb.AllocatedTaskInfo{
{
Data: &persistencespb.TaskInfo{
ExpiryTime: timestamp.TimeNowPtrUtcAddSeconds(-60),
CreateTime: timestamp.TimeNowPtrUtcAddSeconds(-60 * 60),
},
TaskId: 13,
},
{
Data: &persistencespb.TaskInfo{
ExpiryTime: timestamp.TimeNowPtrUtcAddSeconds(-60),
CreateTime: timestamp.TimeNowPtrUtcAddSeconds(-60 * 60),
},
TaskId: 14,
},
}))
s.Equal(int64(0), blm.taskAckManager.getAckLevel())
s.Equal(int64(14), blm.taskAckManager.getReadLevel())
}
func (s *BacklogManagerTestSuite) TestTaskWriterShutdown() {
s.blm.Start()
defer s.blm.Stop()
s.NoError(s.blm.WaitUntilInitialized(context.Background()))
s.ptqMgr.EXPECT().AddSpooledTask(gomock.Any()).MaxTimes(1)
err := s.blm.SpoolTask(&persistencespb.TaskInfo{})
s.NoError(err)
s.cancelCtx()
s.ptqMgr.EXPECT().UnloadFromPartitionManager(unloadCauseConflict).Times(1)
err = s.blm.SpoolTask(&persistencespb.TaskInfo{})
s.Error(err)
}
func (s *BacklogManagerTestSuite) TestReadBatchDone() {
if s.newMatcher {
s.T().Skip("not compatible with new backlog manager")
}
blm := s.blm.(*backlogManagerImpl)
const rangeSize = 10
const maxReadLevel = int64(120)
blm.config.RangeSize = rangeSize
blm.Start()
defer blm.Stop()
s.NoError(blm.WaitUntilInitialized(context.Background()))
blm.taskAckManager.setReadLevel(0)
blm.getDB().setMaxReadLevelForTesting(subqueueZero, maxReadLevel)
batch, err := blm.taskReader.getTaskBatch(context.Background())
s.NoError(err)
s.Empty(batch.tasks)
s.Equal(int64(rangeSize*10), batch.readLevel)
s.False(batch.isReadBatchDone)
s.NoError(err)
blm.taskAckManager.setReadLevel(batch.readLevel)
batch, err = blm.taskReader.getTaskBatch(context.Background())
s.NoError(err)
s.Empty(batch.tasks)
s.Equal(maxReadLevel, batch.readLevel)
s.True(batch.isReadBatchDone)
s.NoError(err)
}
func (s *BacklogManagerTestSuite) TestApproximateBacklogCount_IncrementedByAppendTask() {
if s.newMatcher {
s.T().Skip("not compatible with new backlog manager")
}
blm := s.blm.(*backlogManagerImpl)
// Add tasks on the taskWriters channel
blm.taskWriter.appendCh <- &writeTaskRequest{
taskInfo: &persistencespb.TaskInfo{
ExpiryTime: timestamp.TimeNowPtrUtcAddSeconds(3000),
CreateTime: timestamp.TimeNowPtrUtc(),
},
responseCh: make(chan<- error),
}
s.Equal(int64(0), blm.TotalApproximateBacklogCount())
blm.taskWriter.Start()
// Adding tasks to the buffer will increase the in-memory counter by 1
// and this will be written to persistence
s.Eventually(func() bool {
return blm.TotalApproximateBacklogCount() == int64(1)
}, time.Second*30, time.Millisecond)
}
func (s *BacklogManagerTestSuite) TestApproximateBacklogCount_DecrementedByCompleteTask() {
if s.newMatcher {
s.T().Skip("not compatible with new backlog manager")
}
blm := s.blm.(*backlogManagerImpl)
_, err := blm.getDB().RenewLease(blm.tqCtx)
s.NoError(err)
blm.taskAckManager.addTask(int64(1))
blm.taskAckManager.addTask(int64(2))
blm.taskAckManager.addTask(int64(3))
// Manually update the backlog size since adding tasks to the outstanding map does not increment the counter
blm.getDB().updateBacklogStats(3, time.Time{})
s.Equal(int64(3), blm.TotalApproximateBacklogCount(), "1 task in the backlog")
s.Equal(int64(-1), blm.taskAckManager.getAckLevel(), "should only move ack level on completion")
s.Equal(int64(3), blm.taskAckManager.getReadLevel(), "read level should be 1 since a task has been added")
// Complete tasks
ackLevel, numAcked := blm.taskAckManager.completeTask(2)
s.Equal(int64(-1), ackLevel, "should not move the ack level")
s.Equal(int64(0), numAcked, "should not decrease the backlog counter as ack level has not gone up")
ackLevel, numAcked = blm.taskAckManager.completeTask(3)
s.Equal(int64(-1), ackLevel, "should not move the ack level")
s.Equal(int64(0), numAcked, "should not decrease the backlog counter as ack level has not gone up")
ackLevel, numAcked = blm.taskAckManager.completeTask(1)
s.Equal(int64(3), ackLevel, "should move the ack level")
s.Equal(int64(3), numAcked, "should decrease the backlog counter to 0 as no more tasks in the backlog")
}
func (s *BacklogManagerTestSuite) TestApproximateBacklogCount_IncrementedBySpoolTask() {
s.blm.Start()
defer s.blm.Stop()
taskCount := 10
s.ptqMgr.EXPECT().AddSpooledTask(gomock.Any()).Return(nil).AnyTimes()
for i := 0; i < taskCount; i++ {
s.NoError(s.blm.SpoolTask(&persistencespb.TaskInfo{
ExpiryTime: timestamp.TimeNowPtrUtcAddSeconds(3000),
CreateTime: timestamp.TimeNowPtrUtc(),
}))
}
s.Equal(int64(taskCount), s.blm.TotalApproximateBacklogCount(),
"backlog count should match the number of tasks")
}
func (s *BacklogManagerTestSuite) TestApproximateBacklogCount_IncrementedBySpoolTask_ServiceError() {
s.logger.Expect(testlogger.Error, "Persistent store operation failure")
s.taskMgr.dbServiceError = true
s.blm.Start()
defer s.blm.Stop()
taskCount := 10
s.ptqMgr.EXPECT().AddSpooledTask(gomock.Any()).Return(nil).AnyTimes()
for i := 0; i < taskCount; i++ {
s.Error(s.blm.SpoolTask(&persistencespb.TaskInfo{
ExpiryTime: timestamp.TimeNowPtrUtcAddSeconds(3000),
CreateTime: timestamp.TimeNowPtrUtc(),
}))
}
s.Equal(int64(taskCount), s.blm.TotalApproximateBacklogCount(),
"backlog count should match the number of tasks despite the errors")
}
func (s *BacklogManagerTestSuite) TestApproximateBacklogCount_NotIncrementedBySpoolTask_CondFailedError() {
s.logger.Expect(testlogger.Error, "Persistent store operation failure")
s.taskMgr.dbCondFailedErr = true
s.blm.Start()
defer s.blm.Stop()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
s.ptqMgr.EXPECT().AddSpooledTask(gomock.Any()).Return(nil).AnyTimes()
s.ptqMgr.EXPECT().UnloadFromPartitionManager(unloadCauseConflict).
Do(func(_ any) { cancel() }).
AnyTimes()
s.Error(s.blm.SpoolTask(&persistencespb.TaskInfo{
ExpiryTime: timestamp.TimeNowPtrUtcAddSeconds(3000),
CreateTime: timestamp.TimeNowPtrUtc(),
}))
<-ctx.Done()
s.Equal(int64(0), s.blm.TotalApproximateBacklogCount(),
"backlog count should not be incremented")
}