github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/utils/cache/cache_test.go (about)

     1  // +build !windows
     2  
     3  package cache
     4  
     5  import (
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/rs/xid"
    10  	. "github.com/smartystreets/goconvey/convey"
    11  )
    12  
    13  func TestConstructorNewCache(t *testing.T) {
    14  
    15  	//	t.Parallel()
    16  
    17  	Convey("Given I call the method NewCache, I should a new cache", t, func() {
    18  
    19  		c := &Cache{
    20  			name: "cache",
    21  		}
    22  
    23  		So(NewCache("cache"), ShouldHaveSameTypeAs, c)
    24  	})
    25  }
    26  
    27  func TestElements(t *testing.T) {
    28  
    29  	//	t.Parallel()
    30  
    31  	c := NewCache("cache")
    32  	id := xid.New()
    33  	fakeid := xid.New()
    34  	newid := xid.New()
    35  	value := "element"
    36  	secondValue := "element2"
    37  	thirdValue := "element3"
    38  
    39  	Convey("Given that I want to test elemenets, I must initialize a cache", t, func() {
    40  
    41  		// Test Write
    42  		Convey("Given that I add a new element in the cache, it should not have errors", func() {
    43  			err := c.Add(id, value)
    44  			So(err, ShouldBeNil)
    45  		})
    46  
    47  		Convey("Given that I add the same element for a second time, I should get an error", func() {
    48  			err := c.Add(id, value)
    49  			So(err, ShouldNotBeNil)
    50  		})
    51  
    52  		// Test Read
    53  		Convey("Given that I have an element in the cache, I should be able to read it", func() {
    54  			newvalue, err := c.Get(id)
    55  			So(value, ShouldEqual, newvalue)
    56  			So(err, ShouldBeNil)
    57  		})
    58  
    59  		Convey("Given that I try to read an element that is not there, I should get an error", func() {
    60  			_, err := c.Get(fakeid)
    61  			So(err, ShouldNotBeNil)
    62  		})
    63  
    64  		// Test Update
    65  		Convey("Given that I want to update the element, I should be able to do it", func() {
    66  
    67  			err := c.Update(id, secondValue)
    68  			So(err, ShouldBeNil)
    69  			newvalue, err := c.Get(id)
    70  			So(newvalue, ShouldEqual, secondValue)
    71  			So(err, ShouldBeNil)
    72  		})
    73  
    74  		Convey("Given that I try to update an element that doesn't exist, I should get an error ", func() {
    75  			nextid := xid.New()
    76  			err := c.Update(nextid, value)
    77  			So(err, ShouldNotBeNil)
    78  		})
    79  
    80  		Convey("Given that I try to add or update an element in the cache, I should not get an error", func() {
    81  
    82  			ok := c.AddOrUpdate(newid, secondValue)
    83  			newvalue, err := c.Get(newid)
    84  			So(newvalue, ShouldEqual, secondValue)
    85  			So(err, ShouldBeNil)
    86  			So(ok, ShouldBeFalse)
    87  		})
    88  
    89  		Convey("Given that I try to update an element in the cache, I should not get an error", func() {
    90  
    91  			ok := c.AddOrUpdate(newid, thirdValue)
    92  			newvalue, err := c.Get(newid)
    93  			So(newvalue, ShouldEqual, thirdValue)
    94  			So(err, ShouldBeNil)
    95  			So(ok, ShouldBeTrue)
    96  		})
    97  
    98  		Convey("Given that I have an element in the cache, I should be able to delete it", func() {
    99  			err := c.Remove(id)
   100  			So(err, ShouldBeNil)
   101  		})
   102  
   103  		Convey("Given that I try to delete the same element twice, I should not be able to do it", func() {
   104  			err := c.Remove(id)
   105  			So(err, ShouldNotBeNil)
   106  		})
   107  	})
   108  }
   109  
   110  func Test_CacheTimer(t *testing.T) {
   111  
   112  	//t.Parallel()
   113  
   114  	Convey("Given a new cache with an expiration timer ", t, func() {
   115  		c := NewCacheWithExpiration("cache", 3*time.Second)
   116  
   117  		Convey("When I create an item that has to exist for a second", func() {
   118  			err := c.Add("key", "value")
   119  			So(err, ShouldBeNil)
   120  
   121  			Convey("Then I should be able to get back the item", func() {
   122  				val, err := c.Get("key")
   123  				So(err, ShouldBeNil)
   124  				So(val.(string), ShouldResemble, "value")
   125  
   126  				Convey("When I wait for 1 second and update the time", func() {
   127  					<-time.After(1 * time.Second)
   128  
   129  					c.AddOrUpdate("key", "value2")
   130  
   131  					Convey("I should be able to read the second item", func() {
   132  						val, err := c.Get("key")
   133  						So(err, ShouldBeNil)
   134  						So(val.(string), ShouldResemble, "value2")
   135  
   136  						Convey("But when I wait for a another second, the items should still exist", func() {
   137  							<-time.After(1 * time.Second)
   138  							val, err := c.Get("key")
   139  							So(err, ShouldBeNil)
   140  							So(val.(string), ShouldResemble, "value2")
   141  
   142  							Convey("But if I wait for two seconds after the update, the item must not exixt", func() {
   143  								<-time.After(4 * time.Second)
   144  								_, err := c.Get("key")
   145  								So(err, ShouldNotBeNil)
   146  							})
   147  						})
   148  					})
   149  
   150  				})
   151  
   152  			})
   153  		})
   154  	})
   155  }
   156  
   157  func add(a, b interface{}) interface{} {
   158  	return a.(int) + b.(int)
   159  }
   160  
   161  func TestLockedModify(t *testing.T) {
   162  
   163  	//t.Parallel()
   164  
   165  	Convey("Given a new cache", t, func() {
   166  		c := NewCache("cache")
   167  
   168  		Convey("Given an element that is an integer", func() {
   169  			err := c.Add("key", 1)
   170  			So(err, ShouldBeNil)
   171  			Convey("Given an an incremental add function", func() {
   172  				value, err := c.LockedModify("key", add, 1)
   173  				So(err, ShouldBeNil)
   174  				So(value, ShouldNotBeNil)
   175  				Convey("I should get the right value  ", func() {
   176  					val, err := c.Get("key")
   177  					So(err, ShouldBeNil)
   178  					So(val.(int), ShouldEqual, 2)
   179  				})
   180  			})
   181  		})
   182  	})
   183  }
   184  
   185  func TestTimerExpirationWithUpdate(t *testing.T) {
   186  
   187  	//t.Parallel()
   188  
   189  	Convey("Given that I instantiate 1 objects with 2 second timers", t, func() {
   190  		i := 1
   191  		c := NewCacheWithExpiration("cache", 2*time.Second)
   192  		err := c.Add(i, i)
   193  		So(err, ShouldBeNil)
   194  		Convey("When I check the cache size After 1 seconds, the size should be 1", func() {
   195  			<-time.After(1 * time.Second)
   196  			// So(c.SizeOf(), ShouldEqual, 1)
   197  			Convey("When I update the object and check again after another 1 seconds, the size should be 1", func() {
   198  				err := c.Update(1, 1)
   199  				So(err, ShouldBeNil)
   200  				<-time.After(1 * time.Second)
   201  				// So(c.SizeOf(), ShouldEqual, 1) // @TODO: fix me it should be 1
   202  				Convey("When I check the cache size After another 2 seconds, the size should be 0", func() {
   203  					<-time.After(2 * time.Second)
   204  					So(c.SizeOf(), ShouldBeZeroValue)
   205  				})
   206  			})
   207  		})
   208  	})
   209  }
   210  
   211  func TestGetReset(t *testing.T) {
   212  
   213  	//t.Parallel()
   214  
   215  	Convey("Given that I instantiate 1 object with a 2 second timer", t, func() {
   216  		c := NewCacheWithExpiration("cache", 2*time.Second)
   217  		err := c.Add("test", "test")
   218  		So(err, ShouldBeNil)
   219  		Convey("When I check the cache after 1 second, the element should be there", func() {
   220  			<-time.After(1 * time.Second)
   221  			d, err := c.Get("test")
   222  			So(err, ShouldBeNil)
   223  			So(d.(string), ShouldResemble, "test")
   224  
   225  			Convey("When I retrieve the data with get reset", func() {
   226  
   227  				val, err := c.GetReset("test", 0)
   228  				So(err, ShouldBeNil)
   229  				So(val.(string), ShouldResemble, "test")
   230  
   231  				Convey("If I wait 1100, the data should still be there ", func() {
   232  					<-time.After(1100 * time.Millisecond)
   233  					d, err := c.Get("test")
   234  					So(err, ShouldBeNil)
   235  					So(d.(string), ShouldResemble, "test")
   236  
   237  					Convey("If I wait for another second, the data should be gone", func() {
   238  						<-time.After(1200 * time.Millisecond)
   239  						val, err := c.Get("test")
   240  						So(err, ShouldNotBeNil)
   241  						So(val, ShouldBeNil)
   242  					})
   243  				})
   244  			})
   245  		})
   246  	})
   247  }
   248  
   249  func TestSetTimeOut(t *testing.T) {
   250  
   251  	//t.Parallel()
   252  
   253  	Convey("Given that I instantiate 1 object with a 2 second timer", t, func() {
   254  		c := NewCacheWithExpiration("cache", 2*time.Second)
   255  		err := c.Add("test", "test")
   256  		So(err, ShouldBeNil)
   257  		Convey("When I check the cache after 1 second, the element should be there", func() {
   258  			<-time.After(1 * time.Second)
   259  			d, err := c.Get("test")
   260  			So(err, ShouldBeNil)
   261  			err = c.SetTimeOut("test", 2*time.Second)
   262  			So(err, ShouldBeNil)
   263  			So(d.(string), ShouldResemble, "test")
   264  
   265  			Convey("When I reset the timer to two more seconds", func() {
   266  
   267  				err := c.SetTimeOut("test", 2*time.Second)
   268  				So(err, ShouldBeNil)
   269  
   270  				Convey("If I wait 1100, the data should still be there ", func() {
   271  					<-time.After(1500 * time.Millisecond)
   272  					d, err := c.Get("test")
   273  					So(err, ShouldBeNil)
   274  					So(d.(string), ShouldResemble, "test")
   275  
   276  					Convey("If I wait for another second, the data should be gone", func() {
   277  						<-time.After(1200 * time.Millisecond)
   278  						val, err := c.Get("test")
   279  						So(err, ShouldNotBeNil)
   280  						So(val, ShouldBeNil)
   281  					})
   282  				})
   283  			})
   284  		})
   285  	})
   286  }
   287  
   288  func TestCacheWithExpirationNotifier(t *testing.T) {
   289  
   290  	//t.Parallel()
   291  
   292  	finished := make(chan bool)
   293  
   294  	Convey("Given a cache with an expiration notitifier ", t, func() {
   295  		c := NewCacheWithExpirationNotifier("cache", 2*time.Second, func(id interface{}, item interface{}) {
   296  			if id.(string) == "test" && item.(string) == "test" {
   297  				finished <- true
   298  			} else {
   299  				finished <- false
   300  			}
   301  		})
   302  
   303  		Convey("When I add an element", func() {
   304  			oldtime := time.Now()
   305  			err := c.Add("test", "test")
   306  			So(err, ShouldBeNil)
   307  			Convey("I should receive a notification", func() {
   308  				r := <-finished
   309  				Duration := time.Since(oldtime)
   310  				So(r, ShouldBeTrue)
   311  				So(Duration.Seconds(), ShouldBeGreaterThanOrEqualTo, 2.0)
   312  			})
   313  		})
   314  	})
   315  }
   316  
   317  // func TestThousandsOfTimers(t *testing.T) {
   318  
   319  // 	//t.Parallel()
   320  
   321  // 	Convey("Given that I instantiate 10K objects with 2 second timers", t, func() {
   322  // 		c := NewCacheWithExpiration("cache", 2*time.Second)
   323  // 		for i := 0; i < 1000; i++ {
   324  // 			err := c.Add(i, i)
   325  // 			So(err, ShouldBeNil)
   326  // 		}
   327  // 		Convey("After I wait for 1 second and add 10K more objects with 2 second timers", func() {
   328  // 			<-time.After(1 * time.Second)
   329  // 			for i := 20000; i < 30000; i++ {
   330  // 				err := c.Add(i, i)
   331  // 				So(err, ShouldBeNil)
   332  // 			}
   333  // 			//TODO: This test is failing if we wait 3 seconds
   334  // 			Convey("After I wait for another 4 seconds", func() {
   335  // 				<-time.After(5 * time.Second)
   336  // 				Convey("I should have no objects in the cache", func() {
   337  // 					So(c.SizeOf(), ShouldEqual, 0)
   338  // 				})
   339  // 			})
   340  // 		})
   341  // 	})
   342  // }
   343  
   344  func TestRemoveWithDelay(t *testing.T) {
   345  	Convey("Given an initial cache that is non empty", t, func() {
   346  		c := NewCache("cache")
   347  		c.Add("info1", "info1") // nolint
   348  		c.Add("info2", "info2") // nolint
   349  		c.Add("info3", "info3") // nolint
   350  		c.Add("info4", "info4") // nolint
   351  
   352  		Convey("When I remove an valid entry with a duration of -1", func() {
   353  			err := c.RemoveWithDelay("info1", -1)
   354  			Convey("It should remove the entry right away", func() {
   355  				So(err, ShouldBeNil)
   356  				So(c.SizeOf(), ShouldEqual, 3)
   357  				_, err := c.Get("info1")
   358  				So(err, ShouldNotBeNil)
   359  			})
   360  		})
   361  
   362  		Convey("When I remove an valid entry with a duration of 2 seconds", func() {
   363  			err := c.RemoveWithDelay("info2", 2*time.Second)
   364  			Convey("It should remove the entry right away", func() {
   365  				So(err, ShouldBeNil)
   366  				So(c.SizeOf(), ShouldEqual, 4)
   367  				<-time.After(3 * time.Second)
   368  				So(c.SizeOf(), ShouldEqual, 3)
   369  				_, err := c.Get("info2")
   370  				So(err, ShouldNotBeNil)
   371  			})
   372  		})
   373  
   374  		Convey("When I remove an unknown entry with a duration of 2 seconds", func() {
   375  			err := c.RemoveWithDelay("unknown", 2*time.Second)
   376  			Convey("It should return an error", func() {
   377  				So(err, ShouldNotBeNil)
   378  			})
   379  		})
   380  
   381  	})
   382  }