Exemplo n.º 1
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)
}
Exemplo n.º 2
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")
}
Exemplo n.º 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)
}
Exemplo n.º 4
0
func (*suite) TestFetchError(c *gc.C) {
	p := cache.New(time.Hour)
	expectErr := errgo.New("hello")
	v, err := p.Get("a", fetchError(expectErr))
	c.Assert(err, gc.ErrorMatches, "hello")
	c.Assert(errgo.Cause(err), gc.Equals, expectErr)
	c.Assert(v, gc.Equals, nil)
}
Exemplo n.º 5
0
func (*suite) TestFetchOnlyOnce(c *gc.C) {
	p := cache.New(time.Hour)
	v, err := p.Get("a", fetchValue(2))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 2)

	v, err = p.Get("a", fetchError(errUnexpectedFetch))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 2)
}
Exemplo n.º 6
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)
}
Exemplo n.º 7
0
func (*suite) TestEvict(c *gc.C) {
	p := cache.New(time.Hour)
	v, err := p.Get("a", fetchValue(2))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 2)

	v, err = p.Get("a", fetchValue(4))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 2)

	p.Evict("a")
	v, err = p.Get("a", fetchValue(3))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 3)

	v, err = p.Get("a", fetchValue(4))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 3)
}
Exemplo n.º 8
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)
}
Exemplo n.º 9
0
// TestConcurrentFetch checks that the cache is safe
// to use concurrently. It is designed to fail when
// tested with the race detector enabled.
func (*suite) TestConcurrentFetch(c *gc.C) {
	p := cache.New(time.Minute)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		v, err := p.Get("a", fetchValue("a"))
		c.Check(err, gc.IsNil)
		c.Check(v, gc.Equals, "a")
	}()
	wg.Add(1)
	go func() {
		defer wg.Done()
		v, err := p.Get("b", fetchValue("b"))
		c.Check(err, gc.IsNil)
		c.Check(v, gc.Equals, "b")
	}()
	wg.Wait()
}
Exemplo n.º 10
0
func (*suite) TestSimpleGet(c *gc.C) {
	p := cache.New(time.Hour)
	v, err := p.Get("a", fetchValue(2))
	c.Assert(err, gc.IsNil)
	c.Assert(v, gc.Equals, 2)
}