go.temporal.io/server@v1.23.0/common/persistence/tests/task_queue_task.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package tests
    26  
    27  import (
    28  	"context"
    29  	"math/rand"
    30  	"testing"
    31  	"time"
    32  
    33  	"github.com/google/uuid"
    34  	"github.com/stretchr/testify/require"
    35  	"github.com/stretchr/testify/suite"
    36  	enumspb "go.temporal.io/api/enums/v1"
    37  	"google.golang.org/protobuf/types/known/timestamppb"
    38  
    39  	clockspb "go.temporal.io/server/api/clock/v1"
    40  	persistencespb "go.temporal.io/server/api/persistence/v1"
    41  	"go.temporal.io/server/common/debug"
    42  
    43  	"go.temporal.io/server/common/log"
    44  	p "go.temporal.io/server/common/persistence"
    45  	"go.temporal.io/server/common/persistence/serialization"
    46  	"go.temporal.io/server/common/testing/protorequire"
    47  )
    48  
    49  type (
    50  	TaskQueueTaskSuite struct {
    51  		suite.Suite
    52  		*require.Assertions
    53  
    54  		stickyTTL     time.Duration
    55  		taskTTL       time.Duration
    56  		namespaceID   string
    57  		taskQueueName string
    58  		taskQueueType enumspb.TaskQueueType
    59  
    60  		taskManager p.TaskManager
    61  		logger      log.Logger
    62  
    63  		ctx    context.Context
    64  		cancel context.CancelFunc
    65  	}
    66  )
    67  
    68  func NewTaskQueueTaskSuite(
    69  	t *testing.T,
    70  	taskManager p.TaskStore,
    71  	logger log.Logger,
    72  ) *TaskQueueTaskSuite {
    73  	return &TaskQueueTaskSuite{
    74  		Assertions: require.New(t),
    75  		taskManager: p.NewTaskManager(
    76  			taskManager,
    77  			serialization.NewSerializer(),
    78  		),
    79  		logger: logger,
    80  	}
    81  }
    82  
    83  func (s *TaskQueueTaskSuite) SetupSuite() {
    84  }
    85  
    86  func (s *TaskQueueTaskSuite) TearDownSuite() {
    87  }
    88  
    89  func (s *TaskQueueTaskSuite) SetupTest() {
    90  	s.Assertions = require.New(s.T())
    91  	s.ctx, s.cancel = context.WithTimeout(context.Background(), 30*time.Second*debug.TimeoutMultiplier)
    92  
    93  	s.stickyTTL = time.Second * 10
    94  	s.taskTTL = time.Second * 16
    95  	s.namespaceID = uuid.New().String()
    96  	s.taskQueueName = uuid.New().String()
    97  	s.taskQueueType = enumspb.TaskQueueType(rand.Int31n(
    98  		int32(len(enumspb.TaskQueueType_name)) + 1),
    99  	)
   100  }
   101  
   102  func (s *TaskQueueTaskSuite) TearDownTest() {
   103  	s.cancel()
   104  }
   105  
   106  func (s *TaskQueueTaskSuite) TestCreateGet_Conflict() {
   107  	rangeID := rand.Int63()
   108  	taskQueue := s.createTaskQueue(rangeID)
   109  
   110  	taskID := rand.Int63()
   111  	task := s.randomTask(taskID)
   112  	_, err := s.taskManager.CreateTasks(s.ctx, &p.CreateTasksRequest{
   113  		TaskQueueInfo: &p.PersistedTaskQueueInfo{
   114  			RangeID: rand.Int63(),
   115  			Data:    taskQueue,
   116  		},
   117  		Tasks: []*persistencespb.AllocatedTaskInfo{task},
   118  	})
   119  	s.IsType(&p.ConditionFailedError{}, err)
   120  
   121  	resp, err := s.taskManager.GetTasks(s.ctx, &p.GetTasksRequest{
   122  		NamespaceID:        s.namespaceID,
   123  		TaskQueue:          s.taskQueueName,
   124  		TaskType:           s.taskQueueType,
   125  		InclusiveMinTaskID: taskID,
   126  		ExclusiveMaxTaskID: taskID + 1,
   127  		PageSize:           100,
   128  		NextPageToken:      nil,
   129  	})
   130  	s.NoError(err)
   131  	protorequire.ProtoSliceEqual(s.T(), []*persistencespb.AllocatedTaskInfo{}, resp.Tasks)
   132  	s.Nil(resp.NextPageToken)
   133  }
   134  
   135  func (s *TaskQueueTaskSuite) TestCreateGet_One() {
   136  	rangeID := rand.Int63()
   137  	taskQueue := s.createTaskQueue(rangeID)
   138  
   139  	taskID := rand.Int63()
   140  	task := s.randomTask(taskID)
   141  	_, err := s.taskManager.CreateTasks(s.ctx, &p.CreateTasksRequest{
   142  		TaskQueueInfo: &p.PersistedTaskQueueInfo{
   143  			RangeID: rangeID,
   144  			Data:    taskQueue,
   145  		},
   146  		Tasks: []*persistencespb.AllocatedTaskInfo{task},
   147  	})
   148  	s.NoError(err)
   149  
   150  	resp, err := s.taskManager.GetTasks(s.ctx, &p.GetTasksRequest{
   151  		NamespaceID:        s.namespaceID,
   152  		TaskQueue:          s.taskQueueName,
   153  		TaskType:           s.taskQueueType,
   154  		InclusiveMinTaskID: taskID,
   155  		ExclusiveMaxTaskID: taskID + 1,
   156  		PageSize:           100,
   157  		NextPageToken:      nil,
   158  	})
   159  	s.NoError(err)
   160  	protorequire.ProtoSliceEqual(s.T(), []*persistencespb.AllocatedTaskInfo{task}, resp.Tasks)
   161  	s.Nil(resp.NextPageToken)
   162  }
   163  
   164  func (s *TaskQueueTaskSuite) TestCreateGet_Multiple() {
   165  	numCreateBatch := 32
   166  	createBatchSize := 32
   167  	numTasks := int64(createBatchSize * numCreateBatch)
   168  	minTaskID := rand.Int63()
   169  	maxTaskID := minTaskID + numTasks
   170  
   171  	rangeID := rand.Int63()
   172  	taskQueue := s.createTaskQueue(rangeID)
   173  
   174  	var expectedTasks []*persistencespb.AllocatedTaskInfo
   175  	for i := 0; i < numCreateBatch; i++ {
   176  		var tasks []*persistencespb.AllocatedTaskInfo
   177  		for j := 0; j < createBatchSize; j++ {
   178  			taskID := minTaskID + int64(i*numCreateBatch+j)
   179  			task := s.randomTask(taskID)
   180  			tasks = append(tasks, task)
   181  			expectedTasks = append(expectedTasks, task)
   182  		}
   183  		_, err := s.taskManager.CreateTasks(s.ctx, &p.CreateTasksRequest{
   184  			TaskQueueInfo: &p.PersistedTaskQueueInfo{
   185  				RangeID: rangeID,
   186  				Data:    taskQueue,
   187  			},
   188  			Tasks: tasks,
   189  		})
   190  		s.NoError(err)
   191  	}
   192  
   193  	var token []byte
   194  	var actualTasks []*persistencespb.AllocatedTaskInfo
   195  	for doContinue := true; doContinue; doContinue = len(token) > 0 {
   196  		resp, err := s.taskManager.GetTasks(s.ctx, &p.GetTasksRequest{
   197  			NamespaceID:        s.namespaceID,
   198  			TaskQueue:          s.taskQueueName,
   199  			TaskType:           s.taskQueueType,
   200  			InclusiveMinTaskID: minTaskID,
   201  			ExclusiveMaxTaskID: maxTaskID + 1,
   202  			PageSize:           1,
   203  			NextPageToken:      token,
   204  		})
   205  		s.NoError(err)
   206  		token = resp.NextPageToken
   207  		actualTasks = append(actualTasks, resp.Tasks...)
   208  	}
   209  	protorequire.ProtoSliceEqual(s.T(), expectedTasks, actualTasks)
   210  }
   211  
   212  func (s *TaskQueueTaskSuite) TestCreateDelete_One() {
   213  	rangeID := rand.Int63()
   214  	taskQueue := s.createTaskQueue(rangeID)
   215  
   216  	taskID := rand.Int63()
   217  	task := s.randomTask(taskID)
   218  	_, err := s.taskManager.CreateTasks(s.ctx, &p.CreateTasksRequest{
   219  		TaskQueueInfo: &p.PersistedTaskQueueInfo{
   220  			RangeID: rangeID,
   221  			Data:    taskQueue,
   222  		},
   223  		Tasks: []*persistencespb.AllocatedTaskInfo{task},
   224  	})
   225  	s.NoError(err)
   226  
   227  	err = s.taskManager.CompleteTask(s.ctx, &p.CompleteTaskRequest{
   228  		TaskQueue: &p.TaskQueueKey{
   229  			NamespaceID:   s.namespaceID,
   230  			TaskQueueName: s.taskQueueName,
   231  			TaskQueueType: s.taskQueueType,
   232  		},
   233  		TaskID: taskID,
   234  	})
   235  	s.NoError(err)
   236  
   237  	resp, err := s.taskManager.GetTasks(s.ctx, &p.GetTasksRequest{
   238  		NamespaceID:        s.namespaceID,
   239  		TaskQueue:          s.taskQueueName,
   240  		TaskType:           s.taskQueueType,
   241  		InclusiveMinTaskID: taskID,
   242  		ExclusiveMaxTaskID: taskID + 1,
   243  		PageSize:           100,
   244  		NextPageToken:      nil,
   245  	})
   246  	s.NoError(err)
   247  	protorequire.ProtoSliceEqual(s.T(), []*persistencespb.AllocatedTaskInfo{}, resp.Tasks)
   248  	s.Nil(resp.NextPageToken)
   249  }
   250  
   251  func (s *TaskQueueTaskSuite) TestCreateDelete_Multiple() {
   252  	numCreateBatch := 32
   253  	createBatchSize := 32
   254  	numTasks := int64(createBatchSize * numCreateBatch)
   255  	minTaskID := rand.Int63()
   256  	maxTaskID := minTaskID + numTasks
   257  
   258  	rangeID := rand.Int63()
   259  	taskQueue := s.createTaskQueue(rangeID)
   260  
   261  	for i := 0; i < numCreateBatch; i++ {
   262  		var tasks []*persistencespb.AllocatedTaskInfo
   263  		for j := 0; j < createBatchSize; j++ {
   264  			taskID := minTaskID + int64(i*numCreateBatch+j)
   265  			task := s.randomTask(taskID)
   266  			tasks = append(tasks, task)
   267  		}
   268  		_, err := s.taskManager.CreateTasks(s.ctx, &p.CreateTasksRequest{
   269  			TaskQueueInfo: &p.PersistedTaskQueueInfo{
   270  				RangeID: rangeID,
   271  				Data:    taskQueue,
   272  			},
   273  			Tasks: tasks,
   274  		})
   275  		s.NoError(err)
   276  	}
   277  
   278  	_, err := s.taskManager.CompleteTasksLessThan(s.ctx, &p.CompleteTasksLessThanRequest{
   279  		NamespaceID:        s.namespaceID,
   280  		TaskQueueName:      s.taskQueueName,
   281  		TaskType:           s.taskQueueType,
   282  		ExclusiveMaxTaskID: maxTaskID + 1,
   283  		Limit:              int(numTasks),
   284  	})
   285  	s.NoError(err)
   286  
   287  	resp, err := s.taskManager.GetTasks(s.ctx, &p.GetTasksRequest{
   288  		NamespaceID:        s.namespaceID,
   289  		TaskQueue:          s.taskQueueName,
   290  		TaskType:           s.taskQueueType,
   291  		InclusiveMinTaskID: minTaskID,
   292  		ExclusiveMaxTaskID: maxTaskID + 1,
   293  		PageSize:           100,
   294  		NextPageToken:      nil,
   295  	})
   296  	s.NoError(err)
   297  	protorequire.ProtoSliceEqual(s.T(), []*persistencespb.AllocatedTaskInfo{}, resp.Tasks)
   298  	s.Nil(resp.NextPageToken)
   299  }
   300  
   301  func (s *TaskQueueTaskSuite) createTaskQueue(
   302  	rangeID int64,
   303  ) *persistencespb.TaskQueueInfo {
   304  	taskQueueKind := enumspb.TaskQueueKind(rand.Int31n(
   305  		int32(len(enumspb.TaskQueueKind_name)) + 1),
   306  	)
   307  	taskQueue := s.randomTaskQueueInfo(taskQueueKind)
   308  	_, err := s.taskManager.CreateTaskQueue(s.ctx, &p.CreateTaskQueueRequest{
   309  		RangeID:       rangeID,
   310  		TaskQueueInfo: taskQueue,
   311  	})
   312  	s.NoError(err)
   313  	return taskQueue
   314  }
   315  
   316  func (s *TaskQueueTaskSuite) randomTaskQueueInfo(
   317  	taskQueueKind enumspb.TaskQueueKind,
   318  ) *persistencespb.TaskQueueInfo {
   319  	now := time.Now().UTC()
   320  	var expiryTime *timestamppb.Timestamp
   321  	if taskQueueKind == enumspb.TASK_QUEUE_KIND_STICKY {
   322  		expiryTime = timestamppb.New(now.Add(s.stickyTTL))
   323  	}
   324  
   325  	return &persistencespb.TaskQueueInfo{
   326  		NamespaceId:    s.namespaceID,
   327  		Name:           s.taskQueueName,
   328  		TaskType:       s.taskQueueType,
   329  		Kind:           taskQueueKind,
   330  		AckLevel:       rand.Int63(),
   331  		ExpiryTime:     expiryTime,
   332  		LastUpdateTime: timestamppb.New(now),
   333  	}
   334  }
   335  
   336  func (s *TaskQueueTaskSuite) randomTask(
   337  	taskID int64,
   338  ) *persistencespb.AllocatedTaskInfo {
   339  	now := time.Now().UTC()
   340  	return &persistencespb.AllocatedTaskInfo{
   341  		TaskId: taskID,
   342  		Data: &persistencespb.TaskInfo{
   343  			NamespaceId:      s.namespaceID,
   344  			WorkflowId:       uuid.New().String(),
   345  			RunId:            uuid.New().String(),
   346  			ScheduledEventId: rand.Int63(),
   347  			CreateTime:       timestamppb.New(now),
   348  			ExpiryTime:       timestamppb.New(now.Add(s.taskTTL)),
   349  			Clock: &clockspb.VectorClock{
   350  				ClusterId: rand.Int63(),
   351  				ShardId:   rand.Int31(),
   352  				Clock:     rand.Int63(),
   353  			},
   354  		},
   355  	}
   356  }