Example #1
0
func (s *RootKeyStorageSuite) TestRootKey(c *gc.C) {
	now := epoch
	s.PatchValue(mgostorage.TimeNow, func() time.Time {
		return now
	})

	store := mgostorage.NewRootKeys(10).NewStorage(s.coll(), mgostorage.Policy{
		GenerateInterval: 2 * time.Minute,
		ExpiryDuration:   5 * time.Minute,
	})
	key, id, err := store.RootKey()
	c.Assert(err, gc.IsNil)
	c.Assert(key, gc.HasLen, 24)
	c.Assert(id, gc.Matches, "[0-9a-f]{32}")

	// If we get a key within the generate interval, we should
	// get the same one.
	now = epoch.Add(time.Minute)
	key1, id1, err := store.RootKey()
	c.Assert(err, gc.IsNil)
	c.Assert(key1, gc.DeepEquals, key)
	c.Assert(id1, gc.Equals, id)

	// A different storage instance should get the same root key.
	store1 := mgostorage.NewRootKeys(10).NewStorage(s.coll(), mgostorage.Policy{
		GenerateInterval: 2 * time.Minute,
		ExpiryDuration:   5 * time.Minute,
	})
	key1, id1, err = store1.RootKey()
	c.Assert(err, gc.IsNil)
	c.Assert(key1, gc.DeepEquals, key)
	c.Assert(id1, gc.Equals, id)

	// After the generation interval has passed, we should generate a new key.
	now = epoch.Add(2*time.Minute + time.Second)
	key1, id1, err = store.RootKey()
	c.Assert(err, gc.IsNil)
	c.Assert(key, gc.HasLen, 24)
	c.Assert(id, gc.Matches, "[0-9a-f]{32}")
	c.Assert(key1, gc.Not(gc.DeepEquals), key)
	c.Assert(id1, gc.Not(gc.Equals), id)

	// The other store should pick it up too.
	key2, id2, err := store1.RootKey()
	c.Assert(err, gc.IsNil)
	c.Assert(key2, gc.DeepEquals, key1)
	c.Assert(id2, gc.Equals, id1)
}
Example #2
0
func (s *RootKeyStorageSuite) TestPreferredRootKeyFromCache(c *gc.C) {
	var now time.Time
	s.PatchValue(mgostorage.TimeNow, func() time.Time {
		return now
	})
	for i, test := range preferredRootKeyTests {
		c.Logf("%d: %v", i, test.about)
		for _, key := range test.keys {
			err := s.coll().Insert(key)
			c.Assert(err, gc.IsNil)
		}
		store := mgostorage.NewRootKeys(10).NewStorage(s.coll(), test.policy)
		// Ensure that all the keys are in cache by getting all of them.
		for _, key := range test.keys {
			got, err := store.Get(key.Id)
			c.Assert(err, gc.IsNil)
			c.Assert(got, jc.DeepEquals, key.RootKey)
		}
		// Remove all the keys from the collection so that
		// we know we must be acquiring them from the cache.
		_, err := s.coll().RemoveAll(nil)
		c.Assert(err, gc.IsNil)

		// Test that RootKey returns the expected key.
		now = test.now
		_, id, err := store.RootKey()
		c.Assert(err, gc.IsNil)
		c.Assert(id, gc.Equals, test.expectId)
	}
}
Example #3
0
func (s *RootKeyStorageSuite) TestRootKeyUsesKeysValidWithPolicy(c *gc.C) {
	// We re-use the TestIsValidWithPolicy tests so that we
	// know that the mongo logic uses the same behaviour.
	var now time.Time
	s.PatchValue(mgostorage.TimeNow, func() time.Time {
		return now
	})
	for i, test := range isValidWithPolicyTests {
		c.Logf("test %d: %v", i, test.about)
		if test.key.RootKey == nil {
			// We don't store empty root keys in the database.
			c.Logf("skipping test with empty root key")
			continue
		}
		// Prime the collection with the root key document.
		_, err := s.coll().RemoveAll(nil)
		c.Assert(err, gc.IsNil)
		err = s.coll().Insert(test.key)
		c.Assert(err, gc.IsNil)

		store := mgostorage.NewRootKeys(10).NewStorage(s.coll(), test.policy)
		now = test.now
		key, id, err := store.RootKey()
		c.Assert(err, gc.IsNil)
		if test.expect {
			c.Assert(id, gc.Equals, "id")
			c.Assert(string(key), gc.Equals, "key")
		} else {
			// If it didn't match then RootKey will have
			// generated a new key.
			c.Assert(key, gc.HasLen, 24)
			c.Assert(id, gc.Matches, "[0-9a-f]{32}")
		}
	}
}
Example #4
0
func (s *RootKeyStorageSuite) TestPreferredRootKeyFromDatabase(c *gc.C) {
	var now time.Time
	s.PatchValue(mgostorage.TimeNow, func() time.Time {
		return now
	})
	for i, test := range preferredRootKeyTests {
		c.Logf("%d: %v", i, test.about)
		_, err := s.coll().RemoveAll(nil)
		c.Assert(err, gc.IsNil)
		for _, key := range test.keys {
			err := s.coll().Insert(key)
			c.Assert(err, gc.IsNil)
		}
		store := mgostorage.NewRootKeys(10).NewStorage(s.coll(), test.policy)
		now = test.now
		_, id, err := store.RootKey()
		c.Assert(err, gc.IsNil)
		c.Assert(id, gc.Equals, test.expectId)
	}
}
Example #5
0
func (s *RootKeyStorageSuite) TestEnsureIndex(c *gc.C) {
	keys := mgostorage.NewRootKeys(5)
	err := keys.EnsureIndex(s.coll())
	c.Assert(err, gc.IsNil)

	// This code can take up to 60s to run; there's no way
	// to force it to run more quickly, but it provides reassurance
	// that the code actually works.
	// Reenable the rest of this test if concerned about index behaviour.

	c.SucceedNow()

	_, id1, err := keys.NewStorage(s.coll(), mgostorage.Policy{
		ExpiryDuration: 100 * time.Millisecond,
	}).RootKey()
	c.Assert(err, gc.IsNil)

	_, id2, err := keys.NewStorage(s.coll(), mgostorage.Policy{
		ExpiryDuration: time.Hour,
	}).RootKey()
	c.Assert(err, gc.IsNil)
	c.Assert(id2, gc.Not(gc.Equals), id1)

	// Sanity check that the keys are in the collection.
	n, err := s.coll().Find(nil).Count()
	c.Assert(err, gc.IsNil)
	c.Assert(n, gc.Equals, 2)
	for i := 0; i < 100; i++ {
		n, err := s.coll().Find(nil).Count()
		c.Assert(err, gc.IsNil)
		switch n {
		case 1:
			c.SucceedNow()
		case 2:
			time.Sleep(time.Second)
		default:
			c.Fatalf("unexpected key count %v", n)
		}
	}
	c.Fatalf("key was never removed from database")
}
Example #6
0
func (s *RootKeyStorageSuite) TestGetExpiredItemFromCache(c *gc.C) {
	now := epoch
	s.PatchValue(mgostorage.TimeNow, func() time.Time {
		return now
	})
	store := mgostorage.NewRootKeys(10).NewStorage(s.coll(), mgostorage.Policy{
		ExpiryDuration: 5 * time.Minute,
	})
	_, id, err := store.RootKey()
	c.Assert(err, gc.IsNil)

	s.PatchValue(mgostorage.MgoCollectionFindId, func(*mgo.Collection, interface{}) *mgo.Query {
		c.Errorf("FindId unexpectedly called")
		return nil
	})

	now = epoch.Add(15 * time.Minute)

	_, err = store.Get(id)
	c.Assert(err, gc.Equals, bakery.ErrNotFound)
}
Example #7
0
func (s *RootKeyStorageSuite) TestGetCachesMisses(c *gc.C) {
	store := mgostorage.NewRootKeys(5).NewStorage(s.coll(), mgostorage.Policy{
		GenerateInterval: 1 * time.Minute,
		ExpiryDuration:   30 * time.Minute,
	})
	var fetched []string
	s.PatchValue(mgostorage.MgoCollectionFindId, func(coll *mgo.Collection, id interface{}) *mgo.Query {
		fetched = append(fetched, id.(string))
		return coll.FindId(id)
	})
	key, err := store.Get("foo")
	c.Assert(err, gc.Equals, bakery.ErrNotFound)
	c.Assert(key, gc.IsNil)
	c.Assert(fetched, jc.DeepEquals, []string{"foo"})
	fetched = nil

	key, err = store.Get("foo")
	c.Assert(err, gc.Equals, bakery.ErrNotFound)
	c.Assert(key, gc.IsNil)
	c.Assert(fetched, gc.IsNil)
}
Example #8
0
func (s *RootKeyStorageSuite) TestRootKeyDefaultGenerateInterval(c *gc.C) {
	now := epoch
	s.PatchValue(mgostorage.TimeNow, func() time.Time {
		return now
	})
	store := mgostorage.NewRootKeys(10).NewStorage(s.coll(), mgostorage.Policy{
		ExpiryDuration: 5 * time.Minute,
	})
	key, id, err := store.RootKey()
	c.Assert(err, gc.IsNil)

	now = epoch.Add(5 * time.Minute)
	key1, id1, err := store.RootKey()
	c.Assert(err, gc.IsNil)
	c.Assert(key1, jc.DeepEquals, key)
	c.Assert(id1, gc.Equals, id)

	now = epoch.Add(5*time.Minute + time.Millisecond)
	key1, id1, err = store.RootKey()
	c.Assert(err, gc.IsNil)
	c.Assert(key1, gc.Not(gc.DeepEquals), key)
	c.Assert(id1, gc.Not(gc.Equals), id)
}
Example #9
0
func (s *RootKeyStorageSuite) TestGet(c *gc.C) {
	now := epoch
	s.PatchValue(mgostorage.TimeNow, func() time.Time {
		return now
	})

	store := mgostorage.NewRootKeys(5).NewStorage(s.coll(), mgostorage.Policy{
		GenerateInterval: 1 * time.Minute,
		ExpiryDuration:   30 * time.Minute,
	})
	type idKey struct {
		id  string
		key []byte
	}
	var keys []idKey
	keyIds := make(map[string]bool)
	for i := 0; i < 20; i++ {
		key, id, err := store.RootKey()
		c.Assert(err, gc.IsNil)
		c.Assert(keyIds[id], gc.Equals, false)
		keys = append(keys, idKey{id, key})
		now = now.Add(time.Minute + time.Second)
	}
	for i, k := range keys {
		key, err := store.Get(k.id)
		c.Assert(err, gc.IsNil, gc.Commentf("key %d (%s)", i, k.id))
		c.Assert(key, gc.DeepEquals, k.key, gc.Commentf("key %d (%s)", i, k.id))
	}
	// Check that the keys are cached.
	//
	// Since the cache size is 5, the most recent 5 items will be in
	// the primary cache; the 5 items before that will be in the old
	// cache and nothing else will be cached.
	//
	// The first time we fetch an item from the old cache, a new
	// primary cache will be allocated, all existing items in the
	// old cache except that item will be evicted, and all items in
	// the current primary cache moved to the old cache.
	//
	// The upshot of that is that all but the first 6 calls to Get
	// should result in a database fetch.

	var fetched []string
	s.PatchValue(mgostorage.MgoCollectionFindId, func(coll *mgo.Collection, id interface{}) *mgo.Query {
		fetched = append(fetched, id.(string))
		return coll.FindId(id)
	})
	c.Logf("testing cache")

	for i := len(keys) - 1; i >= 0; i-- {
		k := keys[i]
		key, err := store.Get(k.id)
		c.Assert(err, gc.IsNil)
		c.Assert(err, gc.IsNil, gc.Commentf("key %d (%s)", i, k.id))
		c.Assert(key, gc.DeepEquals, k.key, gc.Commentf("key %d (%s)", i, k.id))
	}
	c.Assert(len(fetched), gc.Equals, len(keys)-6)
	for i, id := range fetched {
		c.Assert(id, gc.Equals, keys[len(keys)-6-i-1].id)
	}
}