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