github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/fortress/util_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package fortress_test 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/worker.v1" 13 "gopkg.in/juju/worker.v1/dependency" 14 15 coretesting "github.com/juju/juju/testing" 16 "github.com/juju/juju/worker/fortress" 17 ) 18 19 // fixture holds a fortress worker and the manifold whence it sprang. 20 type fixture struct { 21 manifold dependency.Manifold 22 worker worker.Worker 23 } 24 25 // newFixture returns a new fixture with a running worker. The caller 26 // takes responsibility for stopping the worker (most easily accomplished 27 // by deferring a TearDown). 28 func newFixture(c *gc.C) *fixture { 29 manifold := fortress.Manifold() 30 worker, err := manifold.Start(nil) 31 c.Assert(err, jc.ErrorIsNil) 32 return &fixture{ 33 manifold: manifold, 34 worker: worker, 35 } 36 } 37 38 // TearDown stops the worker and checks it encountered no errors. 39 func (fix *fixture) TearDown(c *gc.C) { 40 CheckStop(c, fix.worker) 41 } 42 43 // Guard returns a fortress.Guard backed by the fixture's worker. 44 func (fix *fixture) Guard(c *gc.C) (out fortress.Guard) { 45 err := fix.manifold.Output(fix.worker, &out) 46 c.Assert(err, jc.ErrorIsNil) 47 return out 48 } 49 50 // Guest returns a fortress.Guest backed by the fixture's worker. 51 func (fix *fixture) Guest(c *gc.C) (out fortress.Guest) { 52 err := fix.manifold.Output(fix.worker, &out) 53 c.Assert(err, jc.ErrorIsNil) 54 return out 55 } 56 57 // startBlockingVisit Unlocks the fortress; starts a Visit and waits for it to 58 // be invoked; then leaves that Visit blocking, and returns a channel on which 59 // you (1) *can* send a value to unblock the visit but (2) *must* defer a close 60 // (in case your test fails before sending, in which case we still want to stop 61 // the visit). 62 func (fix *fixture) startBlockingVisit(c *gc.C) chan<- struct{} { 63 err := fix.Guard(c).Unlock() 64 c.Assert(err, jc.ErrorIsNil) 65 visitStarted := make(chan struct{}, 1) 66 defer close(visitStarted) 67 unblockVisit := make(chan struct{}, 1) 68 go func() { 69 err := fix.Guest(c).Visit(func() error { 70 visitStarted <- struct{}{} 71 <-unblockVisit 72 return nil 73 }, nil) 74 c.Check(err, jc.ErrorIsNil) 75 }() 76 select { 77 case <-visitStarted: 78 case <-time.After(coretesting.LongWait): 79 c.Fatalf("visit never started") 80 } 81 return unblockVisit 82 } 83 84 // AssertUnlocked checks that the supplied Guest can Visit its fortress. 85 func AssertUnlocked(c *gc.C, guest fortress.Guest) { 86 visited := make(chan error) 87 go func() { 88 visited <- guest.Visit(badVisit, nil) 89 }() 90 91 select { 92 case err := <-visited: 93 c.Assert(err, gc.ErrorMatches, "bad!") 94 case <-time.After(coretesting.LongWait): 95 c.Fatalf("abort never handled") 96 } 97 } 98 99 // AssertUnlocked checks that the supplied Guest's Visit calls are blocked 100 // (and can be cancelled via Abort). 101 func AssertLocked(c *gc.C, guest fortress.Guest) { 102 visited := make(chan error) 103 abort := make(chan struct{}) 104 go func() { 105 visited <- guest.Visit(badVisit, abort) 106 }() 107 108 // NOTE(fwereade): this isn't about interacting with a timer; it's about 109 // making sure other goroutines have had ample opportunity to do stuff. 110 delay := time.After(coretesting.ShortWait) 111 for { 112 select { 113 case <-delay: 114 delay = nil 115 close(abort) 116 case err := <-visited: 117 c.Assert(err, gc.Equals, fortress.ErrAborted) 118 return 119 case <-time.After(coretesting.LongWait): 120 c.Fatalf("timed out") 121 } 122 } 123 } 124 125 // CheckStop stops the worker and checks it encountered no error. 126 func CheckStop(c *gc.C, w worker.Worker) { 127 c.Check(worker.Stop(w), jc.ErrorIsNil) 128 } 129 130 // badVisit is a Vist that always fails. 131 func badVisit() error { 132 return errors.New("bad!") 133 }