github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/utils/stringforwarder/stringforwarder_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package stringforwarder_test
     5  
     6  import (
     7  	"sync"
     8  	"time"
     9  
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	coretesting "github.com/juju/juju/testing"
    14  	"github.com/juju/juju/utils/stringforwarder"
    15  )
    16  
    17  type StringForwarderSuite struct{}
    18  
    19  var _ = gc.Suite(&StringForwarderSuite{})
    20  
    21  // waitFor event to happen, or timeout and fail the test
    22  func waitFor(c *gc.C, event <-chan struct{}) {
    23  	select {
    24  	case <-event:
    25  	case <-time.After(coretesting.LongWait):
    26  		c.Fatalf("timeout waiting for event")
    27  	}
    28  }
    29  
    30  // sendEvent will send a message on a channel, or timeout if the channel is
    31  // never available and fail the test.
    32  func sendEvent(c *gc.C, event chan struct{}) {
    33  	select {
    34  	case event <- struct{}{}:
    35  	case <-time.After(coretesting.LongWait):
    36  		c.Fatalf("failed to send the event")
    37  	}
    38  }
    39  
    40  func (*StringForwarderSuite) TestReceives(c *gc.C) {
    41  	var messages []string
    42  	received := make(chan struct{}, 10)
    43  	forwarder := stringforwarder.New(func(msg string) {
    44  		messages = append(messages, msg)
    45  		received <- struct{}{}
    46  	})
    47  	forwarder.Forward("one")
    48  	waitFor(c, received)
    49  	c.Check(forwarder.Stop(), gc.Equals, uint64(0))
    50  	c.Check(messages, gc.DeepEquals, []string{"one"})
    51  }
    52  
    53  func noopCallback(string) {
    54  }
    55  
    56  func (*StringForwarderSuite) TestStopIsReentrant(c *gc.C) {
    57  	forwarder := stringforwarder.New(noopCallback)
    58  	forwarder.Stop()
    59  	forwarder.Stop()
    60  }
    61  
    62  func (*StringForwarderSuite) TestMessagesDroppedAfterStop(c *gc.C) {
    63  	var messages []string
    64  	forwarder := stringforwarder.New(func(msg string) {
    65  		messages = append(messages, msg)
    66  	})
    67  	forwarder.Stop()
    68  	forwarder.Forward("one")
    69  	forwarder.Forward("two")
    70  	forwarder.Stop()
    71  	c.Check(messages, gc.HasLen, 0)
    72  }
    73  
    74  func (*StringForwarderSuite) TestAllDroppedWithNoCallback(c *gc.C) {
    75  	forwarder := stringforwarder.New(nil)
    76  	forwarder.Forward("one")
    77  	forwarder.Forward("two")
    78  	forwarder.Forward("three")
    79  	c.Check(forwarder.Stop(), gc.Equals, uint64(3))
    80  }
    81  
    82  func (*StringForwarderSuite) TestMessagesDroppedWhenBusy(c *gc.C) {
    83  	var messages []string
    84  	received := make(chan struct{}, 10)
    85  	next := make(chan struct{})
    86  	blockingCallback := func(msg string) {
    87  		waitFor(c, next)
    88  		messages = append(messages, msg)
    89  		sendEvent(c, received)
    90  	}
    91  	forwarder := stringforwarder.New(blockingCallback)
    92  	forwarder.Forward("first")
    93  	forwarder.Forward("second")
    94  	forwarder.Forward("third")
    95  	// At this point we should have started processing "first", but the
    96  	// other two messages are dropped.
    97  	sendEvent(c, next)
    98  	waitFor(c, received)
    99  	// now we should be ready to get another message
   100  	forwarder.Forward("fourth")
   101  	forwarder.Forward("fifth")
   102  	// finish fourth
   103  	sendEvent(c, next)
   104  	waitFor(c, received)
   105  	dropCount := forwarder.Stop()
   106  	c.Check(messages, gc.DeepEquals, []string{"first", "fourth"})
   107  	c.Check(dropCount, gc.Equals, uint64(3))
   108  }
   109  
   110  func (*StringForwarderSuite) TestRace(c *gc.C) {
   111  	forwarder := stringforwarder.New(noopCallback)
   112  	stop := make(chan struct{})
   113  	wg := &sync.WaitGroup{}
   114  	f := func(wg *sync.WaitGroup) {
   115  		wg.Done()
   116  		for {
   117  			select {
   118  			case <-stop:
   119  				return
   120  			default:
   121  				forwarder.Forward("next message")
   122  			}
   123  		}
   124  	}
   125  	for i := 0; i < 4; i++ {
   126  		wg.Add(1)
   127  		go f(wg)
   128  	}
   129  	wg.Wait()
   130  	time.Sleep(10 * time.Millisecond)
   131  	close(stop)
   132  	count := forwarder.Stop()
   133  	c.Check(count, jc.GreaterThan, uint64(0))
   134  }
   135  
   136  func (*StringForwarderSuite) TestSchedulerSensitivity(c *gc.C) {
   137  	var wg sync.WaitGroup
   138  	f := func() {
   139  		defer wg.Done()
   140  		forwarder := stringforwarder.New(noopCallback)
   141  		forwarder.Forward("msg")
   142  		n := forwarder.Stop()
   143  		c.Check(n, gc.Equals, uint64(0))
   144  	}
   145  	for i := 0; i < 1000; i++ {
   146  		wg.Add(1)
   147  		go f()
   148  	}
   149  	wg.Wait()
   150  }