Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1473)

Side by Side Diff: go/src/infra/gae/libs/memlock/memlock_test.go

Issue 1159173004: Non racy tests for memlock. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « go/src/infra/gae/libs/memlock/memlock.infra_testing ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package memlock 5 package memlock
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "infra/gae/libs/wrapper" 9 "infra/gae/libs/wrapper"
10 "infra/gae/libs/wrapper/memory" 10 "infra/gae/libs/wrapper/memory"
11 "infra/libs/clock"
12 "infra/libs/clock/testclock"
13 "runtime"
11 "testing" 14 "testing"
12 "time" 15 "time"
13 16
14 . "github.com/smartystreets/goconvey/convey" 17 . "github.com/smartystreets/goconvey/convey"
15 "golang.org/x/net/context" 18 "golang.org/x/net/context"
16 19
17 "appengine/memcache" 20 "appengine/memcache"
18 ) 21 )
19 22
20 func init() { 23 func init() {
21 delay = time.Millisecond 24 delay = time.Millisecond
22 memcacheLockTime = time.Millisecond * 4 25 memcacheLockTime = time.Millisecond * 4
23 } 26 }
24 27
25 func TestSimple(t *testing.T) { 28 func TestSimple(t *testing.T) {
26 // TODO(riannucci): Mock time.After so that we don't have to delay for r eal. 29 // TODO(riannucci): Mock time.After so that we don't have to delay for r eal.
27 30
31 const key = memlockKeyPrefix + "testkey"
32
28 Convey("basic locking", t, func() { 33 Convey("basic locking", t, func() {
29 » » c := memory.Use(context.Background()) 34 » » start := time.Date(1986, time.October, 26, 1, 20, 00, 00, time.U TC)
30 » » mc := wrapper.GetMC(c).(interface { 35 » » ctx, clk := testclock.UseTime(context.Background(), start)
36 » » blocker := make(chan struct{})
37 » » clk.SetTimerCallback(func(clock.Timer) {
38 » » » clk.Add(delay)
39 » » » select {
40 » » » case blocker <- struct{}{}:
41 » » » default:
42 » » » }
43 » » })
44 » » ctx = memory.Use(ctx)
45 » » mc := wrapper.GetMC(ctx).(interface {
31 wrapper.Testable 46 wrapper.Testable
32 wrapper.MCSingleReadWriter 47 wrapper.MCSingleReadWriter
33 }) 48 })
34 49
35 Convey("fails to acquire when memcache is down", func() { 50 Convey("fails to acquire when memcache is down", func() {
36 mc.BreakFeatures(nil, "Add") 51 mc.BreakFeatures(nil, "Add")
37 » » » err := TryWithLock(c, "testkey", "id", func(check func() bool) error { 52 » » » err := TryWithLock(ctx, "testkey", "id", func(check func () bool) error {
38 // should never reach here 53 // should never reach here
39 So(false, ShouldBeTrue) 54 So(false, ShouldBeTrue)
40 return nil 55 return nil
41 }) 56 })
42 So(err, ShouldEqual, ErrFailedToLock) 57 So(err, ShouldEqual, ErrFailedToLock)
43 }) 58 })
44 59
45 Convey("returns the inner error", func() { 60 Convey("returns the inner error", func() {
46 toRet := fmt.Errorf("sup") 61 toRet := fmt.Errorf("sup")
47 » » » err := TryWithLock(c, "testkey", "id", func(check func() bool) error { 62 » » » err := TryWithLock(ctx, "testkey", "id", func(check func () bool) error {
63 » » » » return toRet
64 » » » })
65 » » » So(err, ShouldEqual, toRet)
66 » » })
67
68 » » Convey("returns the error", func() {
69 » » » toRet := fmt.Errorf("sup")
70 » » » err := TryWithLock(ctx, "testkey", "id", func(check func () bool) error {
48 return toRet 71 return toRet
49 }) 72 })
50 So(err, ShouldEqual, toRet) 73 So(err, ShouldEqual, toRet)
51 }) 74 })
52 75
53 Convey("can acquire when empty", func() { 76 Convey("can acquire when empty", func() {
54 » » » err := TryWithLock(c, "testkey", "id", func(check func() bool) error { 77 » » » err := TryWithLock(ctx, "testkey", "id", func(check func () bool) error {
55 So(check(), ShouldBeTrue) 78 So(check(), ShouldBeTrue)
56 79
80 waitFalse := func() {
81 <-blocker
82 for i := 0; i < 3; i++ {
83 if check() {
84 runtime.Gosched()
85 }
86 }
87 So(check(), ShouldBeFalse)
88 }
89
57 Convey("waiting for a while keeps refreshing the lock", func() { 90 Convey("waiting for a while keeps refreshing the lock", func() {
58 » » » » » time.Sleep(memcacheLockTime * 8) 91 » » » » » // simulate waiting for 64*delay time, a nd ensuring that checkLoop
92 » » » » » // runs that many times.
93 » » » » » for i := 0; i < 64; i++ {
94 » » » » » » <-blocker
95 » » » » » » clk.Add(delay)
96 » » » » » }
59 So(check(), ShouldBeTrue) 97 So(check(), ShouldBeTrue)
60 }) 98 })
61 99
62 Convey("but sometimes we might lose it", func() { 100 Convey("but sometimes we might lose it", func() {
63 Convey("because it was evicted", func() { 101 Convey("because it was evicted", func() {
64 » » » » » » mc.Delete(memlockKeyPrefix + "te stkey") 102 » » » » » » mc.Delete(key)
65 » » » » » » time.Sleep(memcacheLockTime) 103 » » » » » » clk.Add(memcacheLockTime)
66 » » » » » » So(check(), ShouldBeFalse) 104 » » » » » » waitFalse()
67 » » » » » })
68
69 » » » » » Convey("because it got evicted (but we r ace)", func() {
70 » » » » » » mc.Set(&memcache.Item{
71 » » » » » » » Key: memlockKeyPrefix + "testkey",
72 » » » » » » » Value: []byte(""),
73 » » » » » » })
74 }) 105 })
75 106
76 Convey("or because it was stolen", func( ) { 107 Convey("or because it was stolen", func( ) {
77 » » » » » » mc.Set(&memcache.Item{ 108 » » » » » » mc.Set(&memcache.Item{Key: key, Value: []byte("wat")})
78 » » » » » » » Key: memlockKeyPrefix + "testkey", 109 » » » » » » waitFalse()
79 » » » » » » » Value: []byte("wat"),
80 » » » » » » })
81 » » » » » » time.Sleep(memcacheLockTime)
82 » » » » » » So(check(), ShouldBeFalse)
83 }) 110 })
84 111
85 Convey("or because of service issues", f unc() { 112 Convey("or because of service issues", f unc() {
86 mc.BreakFeatures(nil, "CompareAn dSwap") 113 mc.BreakFeatures(nil, "CompareAn dSwap")
87 » » » » » » time.Sleep(memcacheLockTime) 114 » » » » » » waitFalse()
88 » » » » » » So(check(), ShouldBeFalse)
89 }) 115 })
90 }) 116 })
91 return nil 117 return nil
92 }) 118 })
93 So(err, ShouldBeNil) 119 So(err, ShouldBeNil)
94 }) 120 })
95 121
96 Convey("an empty context id is an error", func() { 122 Convey("an empty context id is an error", func() {
97 » » » So(TryWithLock(c, "testkey", "", nil), ShouldEqual, ErrE mptyClientID) 123 » » » So(TryWithLock(ctx, "testkey", "", nil), ShouldEqual, Er rEmptyClientID)
98 }) 124 })
99 }) 125 })
100 } 126 }
OLDNEW
« no previous file with comments | « go/src/infra/gae/libs/memlock/memlock.infra_testing ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698