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  }