github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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  }