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  }