github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/testing/channel.go (about) 1 // Copyright 2011, 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package testing 5 6 import ( 7 "reflect" 8 "time" 9 10 gc "launchpad.net/gocheck" 11 12 jc "launchpad.net/juju-core/testing/checkers" 13 ) 14 15 // NotifyAsserterC gives helper functions for making assertions about how a 16 // channel operates (whether we get a receive event or not, whether it is 17 // closed, etc.) 18 type NotifyAsserterC struct { 19 // C is a gocheck C structure for doing assertions 20 C *gc.C 21 // Chan is the channel we want to receive on 22 Chan <-chan struct{} 23 // Precond will be called before waiting on the channel, can be nil 24 Precond func() 25 } 26 27 // AssertReceive will ensure that we get an event on the channel and the 28 // channel is not closed. 29 func (a *NotifyAsserterC) AssertReceive() { 30 if a.Precond != nil { 31 a.Precond() 32 } 33 select { 34 case _, ok := <-a.Chan: 35 a.C.Assert(ok, jc.IsTrue) 36 case <-time.After(LongWait): 37 a.C.Fatalf("timed out waiting for channel message") 38 } 39 } 40 41 // AssertOneReceive checks that we have exactly one message, and no more 42 func (a *NotifyAsserterC) AssertOneReceive() { 43 a.AssertReceive() 44 a.AssertNoReceive() 45 } 46 47 // AssertClosed ensures that we get a closed event on the channel 48 func (a *NotifyAsserterC) AssertClosed() { 49 if a.Precond != nil { 50 a.Precond() 51 } 52 select { 53 case _, ok := <-a.Chan: 54 a.C.Assert(ok, jc.IsFalse) 55 case <-time.After(LongWait): 56 a.C.Fatalf("timed out waiting for channel to close") 57 } 58 } 59 60 // Assert that we fail to receive on the channel after a short wait. 61 func (a *NotifyAsserterC) AssertNoReceive() { 62 select { 63 case <-a.Chan: 64 a.C.Fatalf("unexpected receive") 65 case <-time.After(ShortWait): 66 } 67 } 68 69 // ContentAsserterC is like NotifyAsserterC in that it checks the behavior of a 70 // channel. The difference is that we expect actual content on the channel, so 71 // callers need to put that into and out of an 'interface{}' 72 type ContentAsserterC struct { 73 // C is a gocheck C structure for doing assertions 74 C *gc.C 75 // Chan is the channel we want to receive on 76 Chan interface{} 77 // Precond will be called before waiting on the channel, can be nil 78 Precond func() 79 } 80 81 // recv waits to receive a value on the channe for the given 82 // time. It returns the value received, if any, whether it 83 // was received ok (the channel was not closed) and 84 // whether the receive timed out. 85 func (a *ContentAsserterC) recv(timeout time.Duration) (val interface{}, ok, timedOut bool) { 86 if a.Precond != nil { 87 a.Precond() 88 } 89 which, v, ok := reflect.Select([]reflect.SelectCase{{ 90 Dir: reflect.SelectRecv, 91 Chan: reflect.ValueOf(a.Chan), 92 }, { 93 Dir: reflect.SelectRecv, 94 Chan: reflect.ValueOf(time.After(timeout)), 95 }}) 96 switch which { 97 case 0: 98 a.C.Assert(ok, jc.IsTrue) 99 return v.Interface(), ok, false 100 case 1: 101 return nil, false, true 102 } 103 panic("unreachable") 104 } 105 106 // AssertReceive will ensure that we get an event on the channel and the 107 // channel is not closed. It will return the content received 108 func (a *ContentAsserterC) AssertReceive() interface{} { 109 v, ok, timedOut := a.recv(LongWait) 110 if timedOut { 111 a.C.Fatalf("timed out waiting for channel message") 112 } 113 a.C.Assert(ok, jc.IsTrue) 114 return v 115 } 116 117 // AssertOneReceive checks that we have exactly one message, and no more 118 func (a *ContentAsserterC) AssertOneReceive() interface{} { 119 res := a.AssertReceive() 120 a.AssertNoReceive() 121 return res 122 } 123 124 // AssertClosed ensures that we get a closed event on the channel 125 func (a *ContentAsserterC) AssertClosed() { 126 _, ok, timedOut := a.recv(LongWait) 127 if timedOut { 128 a.C.Fatalf("timed out waiting for channel to close") 129 } 130 a.C.Assert(ok, jc.IsFalse) 131 } 132 133 // Assert that we fail to receive on the channel after a short wait. 134 func (a *ContentAsserterC) AssertNoReceive() { 135 content, _, timedOut := a.recv(ShortWait) 136 if timedOut { 137 return 138 } 139 a.C.Fatalf("unexpected receive: %#v", content) 140 }