go.temporal.io/server@v1.23.0/common/persistence/sql/sqlplugin/tests/history_execution.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  	"math/rand"
    29  	"testing"
    30  
    31  	"github.com/stretchr/testify/require"
    32  	"github.com/stretchr/testify/suite"
    33  
    34  	"go.temporal.io/server/common/persistence/sql/sqlplugin"
    35  	"go.temporal.io/server/common/primitives"
    36  	"go.temporal.io/server/common/shuffle"
    37  )
    38  
    39  type (
    40  	historyExecutionSuite struct {
    41  		suite.Suite
    42  		*require.Assertions
    43  
    44  		store sqlplugin.HistoryExecution
    45  	}
    46  )
    47  
    48  const (
    49  	testHistoryExecutionWorkflowID = "random workflow ID"
    50  
    51  	testHistoryExecutionEncoding      = "random encoding"
    52  	testHistoryExecutionStateEncoding = "random encoding"
    53  )
    54  
    55  var (
    56  	testHistoryExecutionData      = []byte("random history execution data")
    57  	testHistoryExecutionStateData = []byte("random history execution state data")
    58  )
    59  
    60  func NewHistoryExecutionSuite(
    61  	t *testing.T,
    62  	store sqlplugin.HistoryExecution,
    63  ) *historyExecutionSuite {
    64  	return &historyExecutionSuite{
    65  		Assertions: require.New(t),
    66  		store:      store,
    67  	}
    68  }
    69  
    70  func (s *historyExecutionSuite) SetupSuite() {
    71  
    72  }
    73  
    74  func (s *historyExecutionSuite) TearDownSuite() {
    75  
    76  }
    77  
    78  func (s *historyExecutionSuite) SetupTest() {
    79  	s.Assertions = require.New(s.T())
    80  }
    81  
    82  func (s *historyExecutionSuite) TearDownTest() {
    83  
    84  }
    85  
    86  func (s *historyExecutionSuite) TestInsert_Success() {
    87  	shardID := rand.Int31()
    88  	namespaceID := primitives.NewUUID()
    89  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
    90  	runID := primitives.NewUUID()
    91  	nextEventID := rand.Int63()
    92  	lastWriteVersion := rand.Int63()
    93  
    94  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
    95  	result, err := s.store.InsertIntoExecutions(newExecutionContext(), &execution)
    96  	s.NoError(err)
    97  	rowsAffected, err := result.RowsAffected()
    98  	s.NoError(err)
    99  	s.Equal(1, int(rowsAffected))
   100  }
   101  
   102  func (s *historyExecutionSuite) TestInsert_Fail_Duplicate() {
   103  	shardID := rand.Int31()
   104  	namespaceID := primitives.NewUUID()
   105  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   106  	runID := primitives.NewUUID()
   107  	nextEventID := rand.Int63()
   108  	lastWriteVersion := rand.Int63()
   109  
   110  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   111  	result, err := s.store.InsertIntoExecutions(newExecutionContext(), &execution)
   112  	s.NoError(err)
   113  	rowsAffected, err := result.RowsAffected()
   114  	s.NoError(err)
   115  	s.Equal(1, int(rowsAffected))
   116  
   117  	execution = s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   118  	_, err = s.store.InsertIntoExecutions(newExecutionContext(), &execution)
   119  	s.Error(err) // TODO persistence layer should do proper error translation
   120  }
   121  
   122  func (s *historyExecutionSuite) TestInsertSelect() {
   123  	shardID := rand.Int31()
   124  	namespaceID := primitives.NewUUID()
   125  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   126  	runID := primitives.NewUUID()
   127  	nextEventID := rand.Int63()
   128  	lastWriteVersion := rand.Int63()
   129  
   130  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   131  	result, err := s.store.InsertIntoExecutions(newExecutionContext(), &execution)
   132  	s.NoError(err)
   133  	rowsAffected, err := result.RowsAffected()
   134  	s.NoError(err)
   135  	s.Equal(1, int(rowsAffected))
   136  
   137  	filter := sqlplugin.ExecutionsFilter{
   138  		ShardID:     shardID,
   139  		NamespaceID: namespaceID,
   140  		WorkflowID:  workflowID,
   141  		RunID:       runID,
   142  	}
   143  	row, err := s.store.SelectFromExecutions(newExecutionContext(), filter)
   144  	s.NoError(err)
   145  	s.Equal(&execution, row)
   146  }
   147  
   148  func (s *historyExecutionSuite) TestInsertUpdate_Success() {
   149  	shardID := rand.Int31()
   150  	namespaceID := primitives.NewUUID()
   151  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   152  	runID := primitives.NewUUID()
   153  	nextEventID := rand.Int63()
   154  	lastWriteVersion := rand.Int63()
   155  
   156  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   157  	result, err := s.store.InsertIntoExecutions(newExecutionContext(), &execution)
   158  	s.NoError(err)
   159  	rowsAffected, err := result.RowsAffected()
   160  	s.NoError(err)
   161  	s.Equal(1, int(rowsAffected))
   162  
   163  	execution = s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, rand.Int63(), rand.Int63())
   164  	result, err = s.store.UpdateExecutions(newExecutionContext(), &execution)
   165  	s.NoError(err)
   166  	rowsAffected, err = result.RowsAffected()
   167  	s.NoError(err)
   168  	s.Equal(1, int(rowsAffected))
   169  }
   170  
   171  func (s *historyExecutionSuite) TestUpdate_Fail() {
   172  	shardID := rand.Int31()
   173  	namespaceID := primitives.NewUUID()
   174  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   175  	runID := primitives.NewUUID()
   176  	nextEventID := rand.Int63()
   177  	lastWriteVersion := rand.Int63()
   178  
   179  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   180  	result, err := s.store.UpdateExecutions(newExecutionContext(), &execution)
   181  	s.NoError(err)
   182  	rowsAffected, err := result.RowsAffected()
   183  	s.NoError(err)
   184  	s.Equal(0, int(rowsAffected))
   185  }
   186  
   187  func (s *historyExecutionSuite) TestInsertUpdateSelect() {
   188  	shardID := rand.Int31()
   189  	namespaceID := primitives.NewUUID()
   190  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   191  	runID := primitives.NewUUID()
   192  	nextEventID := rand.Int63()
   193  	lastWriteVersion := rand.Int63()
   194  
   195  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   196  	result, err := s.store.InsertIntoExecutions(newExecutionContext(), &execution)
   197  	s.NoError(err)
   198  	rowsAffected, err := result.RowsAffected()
   199  	s.NoError(err)
   200  	s.Equal(1, int(rowsAffected))
   201  
   202  	execution = s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, rand.Int63(), rand.Int63())
   203  	result, err = s.store.UpdateExecutions(newExecutionContext(), &execution)
   204  	s.NoError(err)
   205  	rowsAffected, err = result.RowsAffected()
   206  	s.NoError(err)
   207  	s.Equal(1, int(rowsAffected))
   208  
   209  	filter := sqlplugin.ExecutionsFilter{
   210  		ShardID:     shardID,
   211  		NamespaceID: namespaceID,
   212  		WorkflowID:  workflowID,
   213  		RunID:       runID,
   214  	}
   215  	row, err := s.store.SelectFromExecutions(newExecutionContext(), filter)
   216  	s.NoError(err)
   217  	s.Equal(&execution, row)
   218  }
   219  
   220  func (s *historyExecutionSuite) TestDeleteSelect() {
   221  	shardID := rand.Int31()
   222  	namespaceID := primitives.NewUUID()
   223  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   224  	runID := primitives.NewUUID()
   225  
   226  	filter := sqlplugin.ExecutionsFilter{
   227  		ShardID:     shardID,
   228  		NamespaceID: namespaceID,
   229  		WorkflowID:  workflowID,
   230  		RunID:       runID,
   231  	}
   232  	result, err := s.store.DeleteFromExecutions(newExecutionContext(), filter)
   233  	s.NoError(err)
   234  	rowsAffected, err := result.RowsAffected()
   235  	s.NoError(err)
   236  	s.Equal(0, int(rowsAffected))
   237  
   238  	_, err = s.store.SelectFromExecutions(newExecutionContext(), filter)
   239  	s.Error(err) // TODO persistence layer should do proper error translation
   240  }
   241  
   242  func (s *historyExecutionSuite) TestInsertDeleteSelect() {
   243  	shardID := rand.Int31()
   244  	namespaceID := primitives.NewUUID()
   245  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   246  	runID := primitives.NewUUID()
   247  	nextEventID := rand.Int63()
   248  	lastWriteVersion := rand.Int63()
   249  
   250  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   251  	result, err := s.store.InsertIntoExecutions(newExecutionContext(), &execution)
   252  	s.NoError(err)
   253  	rowsAffected, err := result.RowsAffected()
   254  	s.NoError(err)
   255  	s.Equal(1, int(rowsAffected))
   256  
   257  	filter := sqlplugin.ExecutionsFilter{
   258  		ShardID:     shardID,
   259  		NamespaceID: namespaceID,
   260  		WorkflowID:  workflowID,
   261  		RunID:       runID,
   262  	}
   263  	result, err = s.store.DeleteFromExecutions(newExecutionContext(), filter)
   264  	s.NoError(err)
   265  	rowsAffected, err = result.RowsAffected()
   266  	s.NoError(err)
   267  	s.Equal(1, int(rowsAffected))
   268  
   269  	_, err = s.store.SelectFromExecutions(newExecutionContext(), filter)
   270  	s.Error(err) // TODO persistence layer should do proper error translation
   271  }
   272  
   273  func (s *historyExecutionSuite) TestReadLock() {
   274  	shardID := rand.Int31()
   275  	namespaceID := primitives.NewUUID()
   276  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   277  	runID := primitives.NewUUID()
   278  	nextEventID := rand.Int63()
   279  	lastWriteVersion := rand.Int63()
   280  
   281  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   282  	result, err := s.store.InsertIntoExecutions(newExecutionContext(), &execution)
   283  	s.NoError(err)
   284  	rowsAffected, err := result.RowsAffected()
   285  	s.NoError(err)
   286  	s.Equal(1, int(rowsAffected))
   287  
   288  	filter := sqlplugin.ExecutionsFilter{
   289  		ShardID:     shardID,
   290  		NamespaceID: namespaceID,
   291  		WorkflowID:  workflowID,
   292  		RunID:       runID,
   293  	}
   294  	rowDBVersion, rowNextEventID, err := s.store.ReadLockExecutions(newExecutionContext(), filter)
   295  	s.NoError(err)
   296  	s.Equal(execution.DBRecordVersion, rowDBVersion)
   297  	s.Equal(execution.NextEventID, rowNextEventID)
   298  }
   299  
   300  func (s *historyExecutionSuite) TestWriteLock() {
   301  	shardID := rand.Int31()
   302  	namespaceID := primitives.NewUUID()
   303  	workflowID := shuffle.String(testHistoryExecutionWorkflowID)
   304  	runID := primitives.NewUUID()
   305  	nextEventID := rand.Int63()
   306  	lastWriteVersion := rand.Int63()
   307  
   308  	execution := s.newRandomExecutionRow(shardID, namespaceID, workflowID, runID, nextEventID, lastWriteVersion)
   309  	result, err := s.store.InsertIntoExecutions(newExecutionContext(), &execution)
   310  	s.NoError(err)
   311  	rowsAffected, err := result.RowsAffected()
   312  	s.NoError(err)
   313  	s.Equal(1, int(rowsAffected))
   314  
   315  	filter := sqlplugin.ExecutionsFilter{
   316  		ShardID:     shardID,
   317  		NamespaceID: namespaceID,
   318  		WorkflowID:  workflowID,
   319  		RunID:       runID,
   320  	}
   321  	rowDBVersion, rowNextEventID, err := s.store.WriteLockExecutions(newExecutionContext(), filter)
   322  	s.NoError(err)
   323  	s.Equal(execution.DBRecordVersion, rowDBVersion)
   324  	s.Equal(execution.NextEventID, rowNextEventID)
   325  }
   326  
   327  func (s *historyExecutionSuite) newRandomExecutionRow(
   328  	shardID int32,
   329  	namespaceID primitives.UUID,
   330  	workflowID string,
   331  	runID primitives.UUID,
   332  	nextEventID int64,
   333  	lastWriteVersion int64,
   334  ) sqlplugin.ExecutionsRow {
   335  	return sqlplugin.ExecutionsRow{
   336  		ShardID:          shardID,
   337  		NamespaceID:      namespaceID,
   338  		WorkflowID:       workflowID,
   339  		RunID:            runID,
   340  		NextEventID:      nextEventID,
   341  		LastWriteVersion: lastWriteVersion,
   342  		Data:             shuffle.Bytes(testHistoryExecutionData),
   343  		DataEncoding:     testHistoryExecutionEncoding,
   344  		State:            shuffle.Bytes(testHistoryExecutionStateData),
   345  		StateEncoding:    testHistoryExecutionStateEncoding,
   346  	}
   347  }