github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/hook/sender_test.go (about)

     1  // Copyright 2012-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package hook_test
     5  
     6  import (
     7  	"time"
     8  
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  	"gopkg.in/juju/charm.v6-unstable/hooks"
    12  
    13  	statetesting "github.com/juju/juju/state/testing"
    14  	coretesting "github.com/juju/juju/testing"
    15  	"github.com/juju/juju/worker/uniter/hook"
    16  	"github.com/juju/juju/worker/uniter/hook/hooktesting"
    17  )
    18  
    19  type HookSenderSuite struct{}
    20  
    21  var _ = gc.Suite(&HookSenderSuite{})
    22  
    23  func assertNext(c *gc.C, out chan hook.Info, expect hook.Info) {
    24  	select {
    25  	case <-time.After(coretesting.LongWait):
    26  		c.Fatalf("timed out waiting for %#v", expect)
    27  	case actual, ok := <-out:
    28  		c.Assert(ok, jc.IsTrue)
    29  		c.Assert(actual, gc.Equals, expect)
    30  	}
    31  }
    32  
    33  func assertEmpty(c *gc.C, out chan hook.Info) {
    34  	select {
    35  	case <-time.After(coretesting.ShortWait):
    36  	case actual, ok := <-out:
    37  		c.Fatalf("got unexpected %#v %#v", actual, ok)
    38  	}
    39  }
    40  
    41  func (s *HookSenderSuite) TestSendsHooks(c *gc.C) {
    42  	expect := hooktesting.HookList(hooks.Install, hooks.ConfigChanged, hooks.Start)
    43  	source := hook.NewListSource(expect)
    44  	out := make(chan hook.Info)
    45  	sender := hook.NewSender(out, source)
    46  	defer statetesting.AssertStop(c, sender)
    47  
    48  	for i := range expect {
    49  		assertNext(c, out, expect[i])
    50  	}
    51  	assertEmpty(c, out)
    52  	statetesting.AssertStop(c, sender)
    53  	c.Assert(source.Empty(), jc.IsTrue)
    54  }
    55  
    56  func (s *HookSenderSuite) TestStopsHooks(c *gc.C) {
    57  	expect := hooktesting.HookList(hooks.Install, hooks.ConfigChanged, hooks.Start)
    58  	source := hook.NewListSource(expect)
    59  	out := make(chan hook.Info)
    60  	sender := hook.NewSender(out, source)
    61  	defer statetesting.AssertStop(c, sender)
    62  
    63  	assertNext(c, out, expect[0])
    64  	assertNext(c, out, expect[1])
    65  	statetesting.AssertStop(c, sender)
    66  	assertEmpty(c, out)
    67  	c.Assert(source.Next(), gc.Equals, expect[2])
    68  }
    69  
    70  func (s *HookSenderSuite) TestHandlesUpdatesFullQueue(c *gc.C) {
    71  	source := hooktesting.NewFullUnbufferedSource()
    72  	defer statetesting.AssertStop(c, source)
    73  
    74  	out := make(chan hook.Info)
    75  	sender := hook.NewSender(out, source)
    76  	defer statetesting.AssertStop(c, sender)
    77  
    78  	// Check we're being sent hooks but not updates.
    79  	assertActive := func() {
    80  		assertNext(c, out, hook.Info{Kind: hooks.Install})
    81  		select {
    82  		case update, ok := <-source.UpdatesC:
    83  			c.Fatalf("got unexpected update: %#v %#v", update, ok)
    84  		case <-time.After(coretesting.ShortWait):
    85  		}
    86  	}
    87  	assertActive()
    88  
    89  	// Send an event on the Changes() chan.
    90  	select {
    91  	case source.ChangesC <- source.NewChange("sent"):
    92  	case <-time.After(coretesting.LongWait):
    93  		c.Fatalf("could not send change")
    94  	}
    95  
    96  	// Now that a change has been delivered, nothing should be sent on the out
    97  	// chan, or read from the changes chan, until the Update method has completed.
    98  	select {
    99  	case source.ChangesC <- source.NewChange("notSent"):
   100  		c.Fatalf("sent extra change while updating queue")
   101  	case hi, ok := <-out:
   102  		c.Fatalf("got unexpected hook while updating queue: %#v %#v", hi, ok)
   103  	case got, ok := <-source.UpdatesC:
   104  		c.Assert(ok, jc.IsTrue)
   105  		c.Assert(got, gc.Equals, "sent")
   106  	case <-time.After(coretesting.LongWait):
   107  		c.Fatalf("timed out")
   108  	}
   109  
   110  	// Check we're still being sent hooks and not updates.
   111  	assertActive()
   112  }
   113  
   114  func (s *HookSenderSuite) TestHandlesUpdatesFullQueueSpam(c *gc.C) {
   115  	source := hooktesting.NewFullBufferedSource()
   116  	defer statetesting.AssertStop(c, source)
   117  
   118  	out := make(chan hook.Info)
   119  	sender := hook.NewSender(out, source)
   120  	defer statetesting.AssertStop(c, sender)
   121  
   122  	// Spam all channels continuously for a bit.
   123  	timeout := time.After(coretesting.LongWait)
   124  	hookCount := 0
   125  	changeCount := 0
   126  	updateCount := 0
   127  	for i := 0; i < 100; i++ {
   128  		select {
   129  		case hi, ok := <-out:
   130  			c.Assert(ok, jc.IsTrue)
   131  			c.Assert(hi, gc.DeepEquals, hook.Info{Kind: hooks.Install})
   132  			hookCount++
   133  		case source.ChangesC <- source.NewChange("sent"):
   134  			changeCount++
   135  		case update, ok := <-source.UpdatesC:
   136  			c.Assert(ok, jc.IsTrue)
   137  			c.Assert(update, gc.Equals, "sent")
   138  			updateCount++
   139  		case <-timeout:
   140  			c.Fatalf("not enough things happened in time")
   141  		}
   142  	}
   143  
   144  	// Once we've finished sending, exhaust the updates...
   145  	for i := updateCount; i < changeCount && updateCount < changeCount; i++ {
   146  		select {
   147  		case update, ok := <-source.UpdatesC:
   148  			c.Assert(ok, jc.IsTrue)
   149  			c.Assert(update, gc.Equals, "sent")
   150  			updateCount++
   151  		case <-timeout:
   152  			c.Fatalf("expected %d updates, got %d", changeCount, updateCount)
   153  		}
   154  	}
   155  
   156  	// ...and check sane end state to validate the foregoing.
   157  	c.Check(hookCount, gc.Not(gc.Equals), 0)
   158  	c.Check(changeCount, gc.Not(gc.Equals), 0)
   159  }
   160  
   161  func (s *HookSenderSuite) TestHandlesUpdatesEmptyQueue(c *gc.C) {
   162  	source := hooktesting.NewEmptySource()
   163  	defer statetesting.AssertStop(c, source)
   164  
   165  	out := make(chan hook.Info)
   166  	sender := hook.NewSender(out, source)
   167  	defer statetesting.AssertStop(c, sender)
   168  
   169  	// Check no hooks are sent and no updates delivered.
   170  	assertIdle := func() {
   171  		select {
   172  		case hi, ok := <-out:
   173  			c.Fatalf("got unexpected hook: %#v %#v", hi, ok)
   174  		case update, ok := <-source.UpdatesC:
   175  			c.Fatalf("got unexpected update: %#v %#v", update, ok)
   176  		case <-time.After(coretesting.ShortWait):
   177  		}
   178  	}
   179  	assertIdle()
   180  
   181  	// Send an event on the Changes() chan.
   182  	timeout := time.After(coretesting.LongWait)
   183  	select {
   184  	case source.ChangesC <- source.NewChange("sent"):
   185  	case <-timeout:
   186  		c.Fatalf("timed out")
   187  	}
   188  
   189  	// Now that a change has been delivered, nothing should be sent on the out
   190  	// chan, or read from the changes chan, until the Update method has completed.
   191  	select {
   192  	case source.ChangesC <- source.NewChange("notSent"):
   193  		c.Fatalf("sent extra update while updating queue")
   194  	case hi, ok := <-out:
   195  		c.Fatalf("got unexpected hook while updating queue: %#v %#v", hi, ok)
   196  	case got, ok := <-source.UpdatesC:
   197  		c.Assert(ok, jc.IsTrue)
   198  		c.Assert(got, gc.Equals, "sent")
   199  	case <-timeout:
   200  		c.Fatalf("timed out")
   201  	}
   202  
   203  	// Now the change has been delivered, nothing should be happening.
   204  	assertIdle()
   205  }
   206  
   207  func (s *HookSenderSuite) TestHandlesUpdatesEmptyQueueSpam(c *gc.C) {
   208  	source := hooktesting.NewEmptySource()
   209  	defer statetesting.AssertStop(c, source)
   210  
   211  	out := make(chan hook.Info)
   212  	sender := hook.NewSender(out, source)
   213  	defer statetesting.AssertStop(c, sender)
   214  
   215  	// Spam all channels continuously for a bit.
   216  	timeout := time.After(coretesting.LongWait)
   217  	changeCount := 0
   218  	updateCount := 0
   219  	for i := 0; i < 100; i++ {
   220  		select {
   221  		case hi, ok := <-out:
   222  			c.Fatalf("got unexpected hook: %#v %#v", hi, ok)
   223  		case source.ChangesC <- source.NewChange("sent"):
   224  			changeCount++
   225  		case update, ok := <-source.UpdatesC:
   226  			c.Assert(ok, jc.IsTrue)
   227  			c.Assert(update, gc.Equals, "sent")
   228  			updateCount++
   229  		case <-timeout:
   230  			c.Fatalf("not enough things happened in time")
   231  		}
   232  	}
   233  
   234  	// Check sane end state.
   235  	c.Check(changeCount, gc.Equals, 50)
   236  	c.Check(updateCount, gc.Equals, 50)
   237  }