Example #1
0
func (*suite) TestEvictOld(c *gc.C) {
	// Test that evict removes entries even when they're
	// in the old map.

	now := time.Now()
	p := cache.New(time.Minute)

	// Populate the cache with an initial entry.
	v, err := cache.GetAtTime(p, "a", fetchValue("a"), now)
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "a")
	c.Assert(p.Len(), gc.Equals, 1)

	v, err = cache.GetAtTime(p, "b", fetchValue("b"), now.Add(time.Minute/2))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "b")
	c.Assert(p.Len(), gc.Equals, 2)

	// Fetch an item after the expiry time,
	// causing current entries to be moved to old.
	v, err = cache.GetAtTime(p, "a", fetchValue("a1"), now.Add(time.Minute+1))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "a1")
	c.Assert(p.Len(), gc.Equals, 2)
	c.Assert(cache.OldLen(p), gc.Equals, 1)

	p.Evict("b")
	v, err = cache.GetAtTime(p, "b", fetchValue("b1"), now.Add(time.Minute+2))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "b1")
}
Example #2
0
// TestRefreshedEntry tests the code path where a value is moved
// from the old map to new.
func (*suite) TestRefreshedEntry(c *gc.C) {
	now := time.Now()
	p := cache.New(time.Minute)

	// Populate the cache with an initial entry.
	v, err := cache.GetAtTime(p, "a", fetchValue("a"), now)
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "a")
	c.Assert(p.Len(), gc.Equals, 1)

	// Fetch another item very close to the expiry time.
	v, err = cache.GetAtTime(p, "b", fetchValue("b"), now.Add(time.Minute-1))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "b")
	c.Assert(p.Len(), gc.Equals, 2)

	// Fetch it again just after the expiry time,
	// which should move it into the new map.
	v, err = cache.GetAtTime(p, "b", fetchError(errUnexpectedFetch), now.Add(time.Minute+1))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "b")
	c.Assert(p.Len(), gc.Equals, 2)

	// Fetch another item, causing "a" to be removed from the cache
	// and keeping "b" in there.
	v, err = cache.GetAtTime(p, "c", fetchValue("c"), now.Add(time.Minute*2+2))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "c")
	c.Assert(p.Len(), gc.Equals, 2)
}
Example #3
0
func (*suite) TestEntriesRemovedWhenNotRetrieved(c *gc.C) {
	now := time.Now()
	p := cache.New(time.Minute)

	// Populate the cache with an initial entry.
	v, err := cache.GetAtTime(p, "a", fetchValue("a"), now)
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "a")
	c.Assert(p.Len(), gc.Equals, 1)

	// Fetch another item after the expiry time,
	// causing current entries to be moved to old.
	v, err = cache.GetAtTime(p, "b", fetchValue("b"), now.Add(time.Minute+1))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "b")
	c.Assert(p.Len(), gc.Equals, 2)
	c.Assert(cache.OldLen(p), gc.Equals, 1)

	// Fetch the other item after another expiry time
	// causing the old entries to be discarded because
	// nothing has fetched them.
	v, err = cache.GetAtTime(p, "b", fetchValue("b"), now.Add(time.Minute*2+2))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, "b")
	c.Assert(p.Len(), gc.Equals, 1)
}
Example #4
0
func (*suite) TestEntryExpiresAfterMaxEntryAge(c *gc.C) {
	now := time.Now()
	p := cache.New(time.Minute)
	v, err := cache.GetAtTime(p, "a", fetchValue(2), now)
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 2)

	// Entry is definitely not expired before half the entry expiry time.
	v, err = cache.GetAtTime(p, "a", fetchError(errUnexpectedFetch), now.Add(time.Minute/2-1))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 2)

	// Entry is definitely expired after the entry expiry time
	v, err = cache.GetAtTime(p, "a", fetchValue(3), now.Add(time.Minute+1))
	c.Assert(v, gc.Equals, 3)
}
Example #5
0
func (*suite) TestRefreshSpread(c *gc.C) {
	now := time.Now()
	p := cache.New(time.Minute)
	// Get all values to start with.
	const N = 100
	for i := 0; i < N; i++ {
		v, err := cache.GetAtTime(p, fmt.Sprint(i), fetchValue(i), now)
		c.Assert(err, gc.IsNil)
		c.Assert(v, gc.Equals, i)
	}
	counts := make([]int, time.Minute/time.Millisecond/10+1)

	// Continually get values over the course of the
	// expiry time; the fetches should be spread out.
	slot := 0
	for t := now.Add(0); t.Before(now.Add(time.Minute + 1)); t = t.Add(time.Millisecond * 10) {
		for i := 0; i < N; i++ {
			cache.GetAtTime(p, fmt.Sprint(i), func() (interface{}, error) {
				counts[slot]++
				return i, nil
			}, t)
		}
		slot++
	}

	// There should be no fetches in the first half of the cycle.
	for i := 0; i < len(counts)/2; i++ {
		c.Assert(counts[i], gc.Equals, 0, gc.Commentf("slot %d", i))
	}

	max := 0
	total := 0
	for _, count := range counts {
		if count > max {
			max = count
		}
		total += count
	}
	if max > 10 {
		c.Errorf("requests grouped too closely (max %d)", max)
	}
	c.Assert(total, gc.Equals, N)
}