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 }