Index: go/src/infra/gae/libs/memlock/memlock_test.go |
diff --git a/go/src/infra/gae/libs/memlock/memlock_test.go b/go/src/infra/gae/libs/memlock/memlock_test.go |
new file mode 100644 |
index 0000000000000000000000000000000000000000..891d61991afd36dd4d62a6748f75d3fa5703c05f |
--- /dev/null |
+++ b/go/src/infra/gae/libs/memlock/memlock_test.go |
@@ -0,0 +1,102 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// +build appengine |
+ |
+package memlock |
+ |
+import ( |
+ "testing" |
+ "time" |
+ |
+ "appengine/memcache" |
+ |
+ "infra/gae/libs/context/memory" |
+ |
+ . "github.com/smartystreets/goconvey/convey" |
+) |
+ |
+func init() { |
+ delay = time.Millisecond |
+ memcacheLockTime = time.Millisecond * 4 |
+} |
+ |
+func TestSimple(t *testing.T) { |
+ |
+ Convey("basic locking", t, func() { |
+ c := memory.NewBestContext() |
+ mc := c.Memcache |
+ mcImpl := mc.(*memory.MemcacheImpl) |
+ |
+ l, err := New(mc, "testkey", "") |
+ So(err, ShouldBeNil) |
+ |
+ Convey("fails to acquire when memcache is down", func() { |
+ mcImpl.SetBrokenFeatures("Add") |
+ gotIt := l.TryWithLock(func(check func() bool) { |
+ // should never reach here |
+ So(false, ShouldBeTrue) |
+ }) |
+ So(gotIt, ShouldBeFalse) |
+ }) |
+ |
+ Convey("can acquire when empty", func() { |
+ gotIt := l.TryWithLock(func(check func() bool) { |
+ So(check(), ShouldBeTrue) |
+ |
+ Convey("waiting for a while keeps refreshing the lock", func() { |
+ time.Sleep(memcacheLockTime * 8) |
+ So(check(), ShouldBeTrue) |
+ }) |
+ |
+ Convey("but sometimes we might lose it", func() { |
+ Convey("because it was evicted", func() { |
+ mc.Delete("memlock:testkey") |
+ time.Sleep(memcacheLockTime) |
+ So(check(), ShouldBeFalse) |
+ }) |
+ |
+ Convey("because it got evicted (but we race)", func() { |
+ mc.Set(&memcache.Item{ |
+ Key: "memlock:testkey", |
+ Value: []byte(""), |
+ }) |
+ }) |
+ |
+ Convey("or because it was stolen", func() { |
+ mc.Set(&memcache.Item{ |
+ Key: "memlock:testkey", |
+ Value: []byte("wat"), |
+ }) |
+ time.Sleep(memcacheLockTime) |
+ So(check(), ShouldBeFalse) |
+ }) |
+ |
+ Convey("or because of service issues", func() { |
+ mcImpl.SetBrokenFeatures("CompareAndSwap") |
+ time.Sleep(memcacheLockTime) |
+ So(check(), ShouldBeFalse) |
+ }) |
+ }) |
+ }) |
+ So(gotIt, ShouldBeTrue) |
+ |
+ Convey("but reentry is a no-no", func() { |
+ gotIt := l.TryWithLock(func(check func() bool) { |
+ So(check(), ShouldBeTrue) |
+ So(func() { |
+ l.TryWithLock(func(func() bool) {}) |
+ }, ShouldPanic) |
+ }) |
+ So(gotIt, ShouldBeTrue) |
+ }) |
+ }) |
+ |
+ Convey("an empty context id is random", func() { |
+ l2, err := New(mc, "testkey", "") |
+ So(err, ShouldBeNil) |
+ So(l2.clientID, ShouldNotResemble, l.clientID) |
+ }) |
+ }) |
+} |