github.com/mailgun/holster/v4@v4.20.0/collections/ttlmap_test.go (about) 1 /* 2 Copyright 2017 Mailgun Technologies Inc 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 package collections 17 18 import ( 19 "testing" 20 21 "github.com/mailgun/holster/v4/clock" 22 "github.com/stretchr/testify/suite" 23 ) 24 25 type TTLMapSuite struct { 26 suite.Suite 27 } 28 29 func TestTTLMapSuite(t *testing.T) { 30 suite.Run(t, new(TTLMapSuite)) 31 } 32 33 func (s *TTLMapSuite) SetupTest() { 34 clock.Freeze(clock.Date(2012, 3, 4, 5, 6, 7, 0, clock.UTC)) 35 } 36 37 func (s *TTLMapSuite) TearDownSuite() { 38 clock.Unfreeze() 39 } 40 41 func (s *TTLMapSuite) TestSetWrong() { 42 m := NewTTLMap(1) 43 44 err := m.Set("a", 1, -1) 45 s.Require().EqualError(err, "ttlSeconds should be >= 0, got -1") 46 47 err = m.Set("a", 1, 0) 48 s.Require().EqualError(err, "ttlSeconds should be >= 0, got 0") 49 50 _, err = m.Increment("a", 1, 0) 51 s.Require().EqualError(err, "ttlSeconds should be >= 0, got 0") 52 53 _, err = m.Increment("a", 1, -1) 54 s.Require().EqualError(err, "ttlSeconds should be >= 0, got -1") 55 } 56 57 func (s *TTLMapSuite) TestRemoveExpiredEmpty() { 58 m := NewTTLMap(1) 59 m.RemoveExpired(100) 60 } 61 62 func (s *TTLMapSuite) TestRemoveLastUsedEmpty() { 63 m := NewTTLMap(1) 64 m.RemoveLastUsed(100) 65 } 66 67 func (s *TTLMapSuite) TestGetSetExpire() { 68 m := NewTTLMap(1) 69 70 err := m.Set("a", 1, 1) 71 s.Require().Equal(nil, err) 72 73 valI, exists := m.Get("a") 74 s.Require().Equal(true, exists) 75 s.Require().Equal(1, valI) 76 77 clock.Advance(1 * clock.Second) 78 79 _, exists = m.Get("a") 80 s.Require().Equal(false, exists) 81 } 82 83 func (s *TTLMapSuite) TestSetOverwrite() { 84 m := NewTTLMap(1) 85 86 err := m.Set("o", 1, 1) 87 s.Require().Equal(nil, err) 88 89 valI, exists := m.Get("o") 90 s.Require().Equal(true, exists) 91 s.Require().Equal(1, valI) 92 93 err = m.Set("o", 2, 1) 94 s.Require().Equal(nil, err) 95 96 valI, exists = m.Get("o") 97 s.Require().Equal(true, exists) 98 s.Require().Equal(2, valI) 99 } 100 101 func (s *TTLMapSuite) TestRemoveExpiredEdgeCase() { 102 m := NewTTLMap(1) 103 104 err := m.Set("a", 1, 1) 105 s.Require().Equal(nil, err) 106 107 clock.Advance(1 * clock.Second) 108 109 err = m.Set("b", 2, 1) 110 s.Require().Equal(nil, err) 111 112 _, exists := m.Get("a") 113 s.Require().Equal(false, exists) 114 115 valI, exists := m.Get("b") 116 s.Require().Equal(true, exists) 117 s.Require().Equal(2, valI) 118 119 s.Require().Equal(1, m.Len()) 120 } 121 122 func (s *TTLMapSuite) TestRemoveOutOfCapacity() { 123 m := NewTTLMap(2) 124 125 err := m.Set("a", 1, 5) 126 s.Require().Equal(nil, err) 127 128 clock.Advance(1 * clock.Second) 129 130 err = m.Set("b", 2, 6) 131 s.Require().Equal(nil, err) 132 133 err = m.Set("c", 3, 10) 134 s.Require().Equal(nil, err) 135 136 _, exists := m.Get("a") 137 s.Require().Equal(false, exists) 138 139 valI, exists := m.Get("b") 140 s.Require().Equal(true, exists) 141 s.Require().Equal(2, valI) 142 143 valI, exists = m.Get("c") 144 s.Require().Equal(true, exists) 145 s.Require().Equal(3, valI) 146 147 s.Require().Equal(2, m.Len()) 148 } 149 150 func (s *TTLMapSuite) TestGetNotExists() { 151 m := NewTTLMap(1) 152 _, exists := m.Get("a") 153 s.Require().Equal(false, exists) 154 } 155 156 func (s *TTLMapSuite) TestGetIntNotExists() { 157 m := NewTTLMap(1) 158 _, exists, err := m.GetInt("a") 159 s.Require().Equal(nil, err) 160 s.Require().Equal(false, exists) 161 } 162 163 func (s *TTLMapSuite) TestGetInvalidType() { 164 m := NewTTLMap(1) 165 err := m.Set("a", "banana", 5) 166 s.Require().NoError(err) 167 168 _, _, err = m.GetInt("a") 169 s.Require().EqualError(err, "Expected existing value to be integer, got string") 170 171 _, err = m.Increment("a", 4, 1) 172 s.Require().EqualError(err, "Expected existing value to be integer, got string") 173 } 174 175 func (s *TTLMapSuite) TestIncrementGetExpire() { 176 m := NewTTLMap(1) 177 178 _, err := m.Increment("a", 5, 1) 179 s.Require().NoError(err) 180 val, exists, err := m.GetInt("a") 181 182 s.Require().Equal(nil, err) 183 s.Require().Equal(true, exists) 184 s.Require().Equal(5, val) 185 186 clock.Advance(1 * clock.Second) 187 188 _, err = m.Increment("a", 4, 1) 189 s.Require().NoError(err) 190 val, exists, err = m.GetInt("a") 191 192 s.Require().Equal(nil, err) 193 s.Require().Equal(true, exists) 194 s.Require().Equal(4, val) 195 } 196 197 func (s *TTLMapSuite) TestIncrementOverwrite() { 198 m := NewTTLMap(1) 199 200 _, err := m.Increment("a", 5, 1) 201 s.Require().NoError(err) 202 val, exists, err := m.GetInt("a") 203 204 s.Require().Equal(nil, err) 205 s.Require().Equal(true, exists) 206 s.Require().Equal(5, val) 207 208 _, err = m.Increment("a", 4, 1) 209 s.Require().NoError(err) 210 val, exists, err = m.GetInt("a") 211 212 s.Require().Equal(nil, err) 213 s.Require().Equal(true, exists) 214 s.Require().Equal(9, val) 215 } 216 217 func (s *TTLMapSuite) TestIncrementOutOfCapacity() { 218 m := NewTTLMap(1) 219 220 _, err := m.Increment("a", 5, 1) 221 s.Require().NoError(err) 222 val, exists, err := m.GetInt("a") 223 224 s.Require().Equal(nil, err) 225 s.Require().Equal(true, exists) 226 s.Require().Equal(5, val) 227 228 _, err = m.Increment("b", 4, 1) 229 s.Require().NoError(err) 230 val, exists, err = m.GetInt("b") 231 232 s.Require().Equal(nil, err) 233 s.Require().Equal(true, exists) 234 s.Require().Equal(4, val) 235 236 _, exists, err = m.GetInt("a") 237 238 s.Require().Equal(nil, err) 239 s.Require().Equal(false, exists) 240 } 241 242 func (s *TTLMapSuite) TestIncrementRemovesExpired() { 243 m := NewTTLMap(2) 244 245 _, err := m.Increment("a", 1, 1) 246 s.Require().NoError(err) 247 _, err = m.Increment("b", 2, 2) 248 s.Require().NoError(err) 249 250 clock.Advance(1 * clock.Second) 251 _, err = m.Increment("c", 3, 3) 252 s.Require().NoError(err) 253 254 _, exists, err := m.GetInt("a") 255 256 s.Require().Equal(nil, err) 257 s.Require().Equal(false, exists) 258 259 val, exists, err := m.GetInt("b") 260 s.Require().Equal(nil, err) 261 s.Require().Equal(true, exists) 262 s.Require().Equal(2, val) 263 264 val, exists, err = m.GetInt("c") 265 s.Require().Equal(nil, err) 266 s.Require().Equal(true, exists) 267 s.Require().Equal(3, val) 268 } 269 270 func (s *TTLMapSuite) TestIncrementRemovesLastUsed() { 271 m := NewTTLMap(2) 272 273 _, err := m.Increment("a", 1, 10) 274 s.Require().NoError(err) 275 _, err = m.Increment("b", 2, 11) 276 s.Require().NoError(err) 277 _, err = m.Increment("c", 3, 12) 278 s.Require().NoError(err) 279 280 _, exists, err := m.GetInt("a") 281 282 s.Require().Equal(nil, err) 283 s.Require().Equal(false, exists) 284 285 val, exists, err := m.GetInt("b") 286 s.Require().Equal(nil, err) 287 s.Require().Equal(true, exists) 288 289 s.Require().Equal(2, val) 290 291 val, exists, err = m.GetInt("c") 292 s.Require().Equal(nil, err) 293 s.Require().Equal(true, exists) 294 s.Require().Equal(3, val) 295 } 296 297 func (s *TTLMapSuite) TestIncrementUpdatesTtl() { 298 m := NewTTLMap(1) 299 300 _, err := m.Increment("a", 1, 1) 301 s.Require().NoError(err) 302 _, err = m.Increment("a", 1, 10) 303 s.Require().NoError(err) 304 305 clock.Advance(1 * clock.Second) 306 307 val, exists, err := m.GetInt("a") 308 s.Require().Equal(nil, err) 309 s.Require().Equal(true, exists) 310 s.Require().Equal(2, val) 311 } 312 313 func (s *TTLMapSuite) TestUpdate() { 314 m := NewTTLMap(1) 315 316 _, err := m.Increment("a", 1, 1) 317 s.Require().NoError(err) 318 _, err = m.Increment("a", 1, 10) 319 s.Require().NoError(err) 320 321 clock.Advance(1 * clock.Second) 322 323 val, exists, err := m.GetInt("a") 324 s.Require().Equal(nil, err) 325 s.Require().Equal(true, exists) 326 s.Require().Equal(2, val) 327 } 328 329 func (s *TTLMapSuite) TestCallOnExpire() { 330 var called bool 331 var key string 332 var val interface{} 333 m := NewTTLMap(1) 334 m.OnExpire = func(k string, el interface{}) { 335 called = true 336 key = k 337 val = el 338 } 339 340 err := m.Set("a", 1, 1) 341 s.Require().Equal(nil, err) 342 343 valI, exists := m.Get("a") 344 s.Require().Equal(true, exists) 345 s.Require().Equal(1, valI) 346 347 clock.Advance(1 * clock.Second) 348 349 _, exists = m.Get("a") 350 s.Require().Equal(false, exists) 351 s.Require().Equal(true, called) 352 s.Require().Equal("a", key) 353 s.Require().Equal(1, val) 354 }