github.com/uber/kraken@v0.1.4/lib/persistedretry/writeback/store_test.go (about)

     1  // Copyright (c) 2016-2019 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package writeback
    15  
    16  import (
    17  	"sync"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/stretchr/testify/require"
    22  	"github.com/uber/kraken/lib/persistedretry"
    23  	"github.com/uber/kraken/localdb"
    24  )
    25  
    26  func checkTask(t *testing.T, expected *Task, result persistedretry.Task) {
    27  	t.Helper()
    28  
    29  	expectedCopy := *expected
    30  	resultCopy := *(result.(*Task))
    31  
    32  	require.InDelta(t, expectedCopy.CreatedAt.Unix(), resultCopy.CreatedAt.Unix(), 1)
    33  	expectedCopy.CreatedAt = time.Time{}
    34  	resultCopy.CreatedAt = time.Time{}
    35  
    36  	require.InDelta(t, expectedCopy.LastAttempt.Unix(), resultCopy.LastAttempt.Unix(), 1)
    37  	expectedCopy.LastAttempt = time.Time{}
    38  	resultCopy.LastAttempt = time.Time{}
    39  
    40  	require.Equal(t, expectedCopy, resultCopy)
    41  }
    42  
    43  func checkTasks(t *testing.T, expected []*Task, result []persistedretry.Task) {
    44  	t.Helper()
    45  
    46  	require.Equal(t, len(expected), len(result))
    47  
    48  	for i := 0; i < len(expected); i++ {
    49  		checkTask(t, expected[i], result[i])
    50  	}
    51  }
    52  
    53  func checkPending(t *testing.T, store *Store, expected ...*Task) {
    54  	t.Helper()
    55  
    56  	result, err := store.GetPending()
    57  	require.NoError(t, err)
    58  	checkTasks(t, expected, result)
    59  }
    60  
    61  func checkFailed(t *testing.T, store *Store, expected ...*Task) {
    62  	t.Helper()
    63  
    64  	result, err := store.GetFailed()
    65  	require.NoError(t, err)
    66  	checkTasks(t, expected, result)
    67  }
    68  
    69  func TestDatabaseNotLocked(t *testing.T) {
    70  	require := require.New(t)
    71  
    72  	db, cleanup := localdb.Fixture()
    73  	defer cleanup()
    74  
    75  	store := NewStore(db)
    76  
    77  	var wg sync.WaitGroup
    78  	for i := 0; i < 200; i++ {
    79  		wg.Add(1)
    80  		go func() {
    81  			defer wg.Done()
    82  			_, err := store.GetFailed()
    83  			require.NoError(err)
    84  			require.NoError(store.AddPending(TaskFixture()))
    85  		}()
    86  
    87  	}
    88  	wg.Wait()
    89  }
    90  
    91  func TestAddPending(t *testing.T) {
    92  	require := require.New(t)
    93  
    94  	db, cleanup := localdb.Fixture()
    95  	defer cleanup()
    96  
    97  	store := NewStore(db)
    98  
    99  	task := TaskFixture()
   100  
   101  	require.NoError(store.AddPending(task))
   102  
   103  	checkPending(t, store, task)
   104  }
   105  
   106  func TestAddPendingTwiceReturnsErrTaskExists(t *testing.T) {
   107  	require := require.New(t)
   108  
   109  	db, cleanup := localdb.Fixture()
   110  	defer cleanup()
   111  
   112  	store := NewStore(db)
   113  
   114  	task := TaskFixture()
   115  
   116  	require.NoError(store.AddPending(task))
   117  	require.Equal(persistedretry.ErrTaskExists, store.AddPending(task))
   118  }
   119  
   120  func TestAddFailed(t *testing.T) {
   121  	require := require.New(t)
   122  
   123  	db, cleanup := localdb.Fixture()
   124  	defer cleanup()
   125  
   126  	store := NewStore(db)
   127  
   128  	task := TaskFixture()
   129  
   130  	require.NoError(store.AddFailed(task))
   131  
   132  	checkFailed(t, store, task)
   133  }
   134  
   135  func TestAddFailedTwiceReturnsErrTaskExists(t *testing.T) {
   136  	require := require.New(t)
   137  
   138  	db, cleanup := localdb.Fixture()
   139  	defer cleanup()
   140  
   141  	store := NewStore(db)
   142  
   143  	task := TaskFixture()
   144  
   145  	require.NoError(store.AddFailed(task))
   146  	require.Equal(persistedretry.ErrTaskExists, store.AddFailed(task))
   147  }
   148  
   149  func TestStateTransitions(t *testing.T) {
   150  	require := require.New(t)
   151  
   152  	db, cleanup := localdb.Fixture()
   153  	defer cleanup()
   154  
   155  	store := NewStore(db)
   156  
   157  	task := TaskFixture()
   158  
   159  	require.NoError(store.AddPending(task))
   160  	checkPending(t, store, task)
   161  	checkFailed(t, store)
   162  
   163  	require.NoError(store.MarkFailed(task))
   164  	checkPending(t, store)
   165  	checkFailed(t, store, task)
   166  
   167  	require.NoError(store.MarkPending(task))
   168  	checkPending(t, store, task)
   169  	checkFailed(t, store)
   170  }
   171  
   172  func TestMarkTaskNotFound(t *testing.T) {
   173  	require := require.New(t)
   174  
   175  	db, cleanup := localdb.Fixture()
   176  	defer cleanup()
   177  
   178  	store := NewStore(db)
   179  
   180  	task := TaskFixture()
   181  
   182  	require.Equal(persistedretry.ErrTaskNotFound, store.MarkPending(task))
   183  	require.Equal(persistedretry.ErrTaskNotFound, store.MarkFailed(task))
   184  }
   185  
   186  func TestRemove(t *testing.T) {
   187  	require := require.New(t)
   188  
   189  	db, cleanup := localdb.Fixture()
   190  	defer cleanup()
   191  
   192  	store := NewStore(db)
   193  
   194  	task := TaskFixture()
   195  
   196  	require.NoError(store.AddPending(task))
   197  
   198  	checkPending(t, store, task)
   199  
   200  	require.NoError(store.Remove(task))
   201  
   202  	checkPending(t, store)
   203  }
   204  
   205  func TestDelay(t *testing.T) {
   206  	require := require.New(t)
   207  
   208  	db, cleanup := localdb.Fixture()
   209  	defer cleanup()
   210  
   211  	store := NewStore(db)
   212  
   213  	task1 := TaskFixture()
   214  	task1.Delay = 5 * time.Minute
   215  
   216  	task2 := TaskFixture()
   217  	task2.Delay = 0
   218  
   219  	require.NoError(store.AddPending(task1))
   220  	require.NoError(store.AddPending(task2))
   221  
   222  	pending, err := store.GetPending()
   223  	require.NoError(err)
   224  	checkTasks(t, []*Task{task1, task2}, pending)
   225  
   226  	require.False(pending[0].Ready())
   227  	require.True(pending[1].Ready())
   228  }
   229  
   230  func TestFind(t *testing.T) {
   231  	require := require.New(t)
   232  
   233  	db, cleanup := localdb.Fixture()
   234  	defer cleanup()
   235  
   236  	store := NewStore(db)
   237  
   238  	task1 := TaskFixture()
   239  	task2 := TaskFixture()
   240  
   241  	require.NoError(store.AddPending(task1))
   242  	require.NoError(store.AddPending(task2))
   243  
   244  	result, err := store.Find(NewNameQuery(task1.Name))
   245  	require.NoError(err)
   246  	checkTasks(t, []*Task{task1}, result)
   247  }
   248  
   249  func TestFindEmpty(t *testing.T) {
   250  	require := require.New(t)
   251  
   252  	db, cleanup := localdb.Fixture()
   253  	defer cleanup()
   254  
   255  	store := NewStore(db)
   256  
   257  	require.NoError(store.AddPending(TaskFixture()))
   258  
   259  	result, err := store.Find(NewNameQuery("nonexistent name"))
   260  	require.NoError(err)
   261  	require.Empty(result)
   262  }