| OLD | NEW |
| 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 "runtime" | |
| 10 "testing" | 9 "testing" |
| 11 "time" | 10 "time" |
| 12 | 11 |
| 13 "infra/gae/libs/gae" | 12 "infra/gae/libs/gae" |
| 14 "infra/gae/libs/gae/filters/featureBreaker" | 13 "infra/gae/libs/gae/filters/featureBreaker" |
| 15 "infra/gae/libs/gae/memory" | 14 "infra/gae/libs/gae/memory" |
| 16 | 15 |
| 17 "github.com/luci/luci-go/common/clock" | 16 "github.com/luci/luci-go/common/clock" |
| 18 "github.com/luci/luci-go/common/clock/testclock" | 17 "github.com/luci/luci-go/common/clock/testclock" |
| 19 . "github.com/smartystreets/goconvey/convey" | 18 . "github.com/smartystreets/goconvey/convey" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 39 select { | 38 select { |
| 40 case blocker <- struct{}{}: | 39 case blocker <- struct{}{}: |
| 41 default: | 40 default: |
| 42 } | 41 } |
| 43 }) | 42 }) |
| 44 ctx, fb := featureBreaker.FilterMC(memory.Use(ctx), nil) | 43 ctx, fb := featureBreaker.FilterMC(memory.Use(ctx), nil) |
| 45 mc := gae.GetMC(ctx) | 44 mc := gae.GetMC(ctx) |
| 46 | 45 |
| 47 Convey("fails to acquire when memcache is down", func() { | 46 Convey("fails to acquire when memcache is down", func() { |
| 48 fb.BreakFeatures(nil, "Add") | 47 fb.BreakFeatures(nil, "Add") |
| 49 » » » err := TryWithLock(ctx, "testkey", "id", func(check func
() bool) error { | 48 » » » err := TryWithLock(ctx, "testkey", "id", func(context.Co
ntext) error { |
| 50 // should never reach here | 49 // should never reach here |
| 51 So(false, ShouldBeTrue) | 50 So(false, ShouldBeTrue) |
| 52 return nil | 51 return nil |
| 53 }) | 52 }) |
| 54 So(err, ShouldEqual, ErrFailedToLock) | 53 So(err, ShouldEqual, ErrFailedToLock) |
| 55 }) | 54 }) |
| 56 | 55 |
| 57 Convey("returns the inner error", func() { | 56 Convey("returns the inner error", func() { |
| 58 toRet := fmt.Errorf("sup") | 57 toRet := fmt.Errorf("sup") |
| 59 » » » err := TryWithLock(ctx, "testkey", "id", func(check func
() bool) error { | 58 » » » err := TryWithLock(ctx, "testkey", "id", func(context.Co
ntext) error { |
| 60 return toRet | 59 return toRet |
| 61 }) | 60 }) |
| 62 So(err, ShouldEqual, toRet) | 61 So(err, ShouldEqual, toRet) |
| 63 }) | 62 }) |
| 64 | 63 |
| 65 Convey("returns the error", func() { | 64 Convey("returns the error", func() { |
| 66 toRet := fmt.Errorf("sup") | 65 toRet := fmt.Errorf("sup") |
| 67 » » » err := TryWithLock(ctx, "testkey", "id", func(check func
() bool) error { | 66 » » » err := TryWithLock(ctx, "testkey", "id", func(context.Co
ntext) error { |
| 68 return toRet | 67 return toRet |
| 69 }) | 68 }) |
| 70 So(err, ShouldEqual, toRet) | 69 So(err, ShouldEqual, toRet) |
| 71 }) | 70 }) |
| 72 | 71 |
| 73 Convey("can acquire when empty", func() { | 72 Convey("can acquire when empty", func() { |
| 74 » » » err := TryWithLock(ctx, "testkey", "id", func(check func
() bool) error { | 73 » » » err := TryWithLock(ctx, "testkey", "id", func(ctx contex
t.Context) error { |
| 75 » » » » So(check(), ShouldBeTrue) | 74 » » » » isDone := func() bool { |
| 75 » » » » » select { |
| 76 » » » » » case <-ctx.Done(): |
| 77 » » » » » » return true |
| 78 » » » » » default: |
| 79 » » » » » » return false |
| 80 » » » » » } |
| 81 » » » » } |
| 82 |
| 83 » » » » So(isDone(), ShouldBeFalse) |
| 76 | 84 |
| 77 waitFalse := func() { | 85 waitFalse := func() { |
| 78 » » » » » <-blocker | 86 » » » » loop: |
| 79 » » » » » for i := 0; i < 3; i++ { | 87 » » » » » for { |
| 80 » » » » » » if check() { | 88 » » » » » » select { |
| 81 » » » » » » » runtime.Gosched() | 89 » » » » » » case <-blocker: |
| 90 » » » » » » » continue |
| 91 » » » » » » case <-ctx.Done(): |
| 92 » » » » » » » break loop |
| 82 } | 93 } |
| 83 } | 94 } |
| 84 » » » » » So(check(), ShouldBeFalse) | 95 » » » » » So(isDone(), ShouldBeTrue) |
| 85 } | 96 } |
| 86 | 97 |
| 87 Convey("waiting for a while keeps refreshing the
lock", func() { | 98 Convey("waiting for a while keeps refreshing the
lock", func() { |
| 88 // simulate waiting for 64*delay time, a
nd ensuring that checkLoop | 99 // simulate waiting for 64*delay time, a
nd ensuring that checkLoop |
| 89 // runs that many times. | 100 // runs that many times. |
| 90 for i := 0; i < 64; i++ { | 101 for i := 0; i < 64; i++ { |
| 91 <-blocker | 102 <-blocker |
| 92 clk.Add(delay) | 103 clk.Add(delay) |
| 93 } | 104 } |
| 94 » » » » » So(check(), ShouldBeTrue) | 105 » » » » » So(isDone(), ShouldBeFalse) |
| 95 }) | 106 }) |
| 96 | 107 |
| 97 Convey("but sometimes we might lose it", func()
{ | 108 Convey("but sometimes we might lose it", func()
{ |
| 98 Convey("because it was evicted", func()
{ | 109 Convey("because it was evicted", func()
{ |
| 99 mc.Delete(key) | 110 mc.Delete(key) |
| 100 clk.Add(memcacheLockTime) | 111 clk.Add(memcacheLockTime) |
| 101 waitFalse() | 112 waitFalse() |
| 102 }) | 113 }) |
| 103 | 114 |
| 104 Convey("or because it was stolen", func(
) { | 115 Convey("or because it was stolen", func(
) { |
| 105 mc.Set(mc.NewItem(key).SetValue(
[]byte("wat"))) | 116 mc.Set(mc.NewItem(key).SetValue(
[]byte("wat"))) |
| 106 waitFalse() | 117 waitFalse() |
| 107 }) | 118 }) |
| 108 | 119 |
| 109 Convey("or because of service issues", f
unc() { | 120 Convey("or because of service issues", f
unc() { |
| 110 fb.BreakFeatures(nil, "CompareAn
dSwap") | 121 fb.BreakFeatures(nil, "CompareAn
dSwap") |
| 111 waitFalse() | 122 waitFalse() |
| 112 }) | 123 }) |
| 113 }) | 124 }) |
| 114 return nil | 125 return nil |
| 115 }) | 126 }) |
| 116 So(err, ShouldBeNil) | 127 So(err, ShouldBeNil) |
| 117 }) | 128 }) |
| 118 | 129 |
| 119 Convey("an empty context id is an error", func() { | 130 Convey("an empty context id is an error", func() { |
| 120 So(TryWithLock(ctx, "testkey", "", nil), ShouldEqual, Er
rEmptyClientID) | 131 So(TryWithLock(ctx, "testkey", "", nil), ShouldEqual, Er
rEmptyClientID) |
| 121 }) | 132 }) |
| 122 }) | 133 }) |
| 123 } | 134 } |
| OLD | NEW |