github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/fortress/util_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package fortress_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  	"gopkg.in/juju/worker.v1"
    13  	"gopkg.in/juju/worker.v1/dependency"
    14  
    15  	coretesting "github.com/juju/juju/testing"
    16  	"github.com/juju/juju/worker/fortress"
    17  )
    18  
    19  // fixture holds a fortress worker and the manifold whence it sprang.
    20  type fixture struct {
    21  	manifold dependency.Manifold
    22  	worker   worker.Worker
    23  }
    24  
    25  // newFixture returns a new fixture with a running worker. The caller
    26  // takes responsibility for stopping the worker (most easily accomplished
    27  // by deferring a TearDown).
    28  func newFixture(c *gc.C) *fixture {
    29  	manifold := fortress.Manifold()
    30  	worker, err := manifold.Start(nil)
    31  	c.Assert(err, jc.ErrorIsNil)
    32  	return &fixture{
    33  		manifold: manifold,
    34  		worker:   worker,
    35  	}
    36  }
    37  
    38  // TearDown stops the worker and checks it encountered no errors.
    39  func (fix *fixture) TearDown(c *gc.C) {
    40  	CheckStop(c, fix.worker)
    41  }
    42  
    43  // Guard returns a fortress.Guard backed by the fixture's worker.
    44  func (fix *fixture) Guard(c *gc.C) (out fortress.Guard) {
    45  	err := fix.manifold.Output(fix.worker, &out)
    46  	c.Assert(err, jc.ErrorIsNil)
    47  	return out
    48  }
    49  
    50  // Guest returns a fortress.Guest backed by the fixture's worker.
    51  func (fix *fixture) Guest(c *gc.C) (out fortress.Guest) {
    52  	err := fix.manifold.Output(fix.worker, &out)
    53  	c.Assert(err, jc.ErrorIsNil)
    54  	return out
    55  }
    56  
    57  // startBlockingVisit Unlocks the fortress; starts a Visit and waits for it to
    58  // be invoked; then leaves that Visit blocking, and returns a channel on which
    59  // you (1) *can* send a value to unblock the visit but (2) *must* defer a close
    60  // (in case your test fails before sending, in which case we still want to stop
    61  // the visit).
    62  func (fix *fixture) startBlockingVisit(c *gc.C) chan<- struct{} {
    63  	err := fix.Guard(c).Unlock()
    64  	c.Assert(err, jc.ErrorIsNil)
    65  	visitStarted := make(chan struct{}, 1)
    66  	defer close(visitStarted)
    67  	unblockVisit := make(chan struct{}, 1)
    68  	go func() {
    69  		err := fix.Guest(c).Visit(func() error {
    70  			visitStarted <- struct{}{}
    71  			<-unblockVisit
    72  			return nil
    73  		}, nil)
    74  		c.Check(err, jc.ErrorIsNil)
    75  	}()
    76  	select {
    77  	case <-visitStarted:
    78  	case <-time.After(coretesting.LongWait):
    79  		c.Fatalf("visit never started")
    80  	}
    81  	return unblockVisit
    82  }
    83  
    84  // AssertUnlocked checks that the supplied Guest can Visit its fortress.
    85  func AssertUnlocked(c *gc.C, guest fortress.Guest) {
    86  	visited := make(chan error)
    87  	go func() {
    88  		visited <- guest.Visit(badVisit, nil)
    89  	}()
    90  
    91  	select {
    92  	case err := <-visited:
    93  		c.Assert(err, gc.ErrorMatches, "bad!")
    94  	case <-time.After(coretesting.LongWait):
    95  		c.Fatalf("abort never handled")
    96  	}
    97  }
    98  
    99  // AssertUnlocked checks that the supplied Guest's Visit calls are blocked
   100  // (and can be cancelled via Abort).
   101  func AssertLocked(c *gc.C, guest fortress.Guest) {
   102  	visited := make(chan error)
   103  	abort := make(chan struct{})
   104  	go func() {
   105  		visited <- guest.Visit(badVisit, abort)
   106  	}()
   107  
   108  	// NOTE(fwereade): this isn't about interacting with a timer; it's about
   109  	// making sure other goroutines have had ample opportunity to do stuff.
   110  	delay := time.After(coretesting.ShortWait)
   111  	for {
   112  		select {
   113  		case <-delay:
   114  			delay = nil
   115  			close(abort)
   116  		case err := <-visited:
   117  			c.Assert(err, gc.Equals, fortress.ErrAborted)
   118  			return
   119  		case <-time.After(coretesting.LongWait):
   120  			c.Fatalf("timed out")
   121  		}
   122  	}
   123  }
   124  
   125  // CheckStop stops the worker and checks it encountered no error.
   126  func CheckStop(c *gc.C, w worker.Worker) {
   127  	c.Check(worker.Stop(w), jc.ErrorIsNil)
   128  }
   129  
   130  // badVisit is a Vist that always fails.
   131  func badVisit() error {
   132  	return errors.New("bad!")
   133  }