github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/dependency/util_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package dependency_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  	"launchpad.net/tomb"
    14  
    15  	coretesting "github.com/juju/juju/testing"
    16  	"github.com/juju/juju/worker"
    17  	"github.com/juju/juju/worker/dependency"
    18  )
    19  
    20  type engineFixture struct {
    21  	testing.IsolationSuite
    22  	engine dependency.Engine
    23  }
    24  
    25  func (s *engineFixture) SetUpTest(c *gc.C) {
    26  	s.IsolationSuite.SetUpTest(c)
    27  	s.startEngine(c, nothingFatal)
    28  }
    29  
    30  func (s *engineFixture) TearDownTest(c *gc.C) {
    31  	s.stopEngine(c)
    32  	s.IsolationSuite.TearDownTest(c)
    33  }
    34  
    35  func (s *engineFixture) startEngine(c *gc.C, isFatal dependency.IsFatalFunc) {
    36  	if s.engine != nil {
    37  		c.Fatalf("original engine not stopped")
    38  	}
    39  	config := dependency.EngineConfig{
    40  		IsFatal:     isFatal,
    41  		WorstError:  func(err0, err1 error) error { return err0 },
    42  		ErrorDelay:  coretesting.ShortWait / 2,
    43  		BounceDelay: coretesting.ShortWait / 10,
    44  	}
    45  
    46  	e, err := dependency.NewEngine(config)
    47  	c.Assert(err, jc.ErrorIsNil)
    48  	s.engine = e
    49  }
    50  
    51  func (s *engineFixture) stopEngine(c *gc.C) {
    52  	if s.engine != nil {
    53  		err := worker.Stop(s.engine)
    54  		s.engine = nil
    55  		c.Check(err, jc.ErrorIsNil)
    56  	}
    57  }
    58  
    59  type manifoldHarness struct {
    60  	inputs             []string
    61  	errors             chan error
    62  	starts             chan struct{}
    63  	ignoreExternalKill bool
    64  }
    65  
    66  func newManifoldHarness(inputs ...string) *manifoldHarness {
    67  	return &manifoldHarness{
    68  		inputs:             inputs,
    69  		errors:             make(chan error, 1000),
    70  		starts:             make(chan struct{}, 1000),
    71  		ignoreExternalKill: false,
    72  	}
    73  }
    74  
    75  // newErrorIgnoringManifoldHarness starts a minimal worker that ignores
    76  // fatal errors - and will never die.
    77  // This is potentially nasty, but it's useful in tests where we want
    78  // to generate fatal errors but not race on which one the engine see first.
    79  func newErrorIgnoringManifoldHarness(inputs ...string) *manifoldHarness {
    80  	return &manifoldHarness{
    81  		inputs:             inputs,
    82  		errors:             make(chan error, 1000),
    83  		starts:             make(chan struct{}, 1000),
    84  		ignoreExternalKill: true,
    85  	}
    86  }
    87  
    88  func (ews *manifoldHarness) Manifold() dependency.Manifold {
    89  	return dependency.Manifold{
    90  		Inputs: ews.inputs,
    91  		Start:  ews.start,
    92  	}
    93  }
    94  
    95  func (ews *manifoldHarness) start(getResource dependency.GetResourceFunc) (worker.Worker, error) {
    96  	for _, resourceName := range ews.inputs {
    97  		if err := getResource(resourceName, nil); err != nil {
    98  			return nil, err
    99  		}
   100  	}
   101  	w := &minimalWorker{tomb.Tomb{}, ews.ignoreExternalKill}
   102  	go func() {
   103  		defer w.tomb.Done()
   104  		ews.starts <- struct{}{}
   105  		select {
   106  		case <-w.tombDying():
   107  		case err := <-ews.errors:
   108  			w.tomb.Kill(err)
   109  		}
   110  	}()
   111  	return w, nil
   112  }
   113  
   114  func (ews *manifoldHarness) AssertOneStart(c *gc.C) {
   115  	ews.AssertStart(c)
   116  	ews.AssertNoStart(c)
   117  }
   118  
   119  func (ews *manifoldHarness) AssertStart(c *gc.C) {
   120  	select {
   121  	case <-ews.starts:
   122  	case <-time.After(coretesting.LongWait):
   123  		c.Fatalf("never started")
   124  	}
   125  }
   126  
   127  func (ews *manifoldHarness) AssertNoStart(c *gc.C) {
   128  	select {
   129  	case <-time.After(coretesting.ShortWait):
   130  	case <-ews.starts:
   131  		c.Fatalf("started unexpectedly")
   132  	}
   133  }
   134  
   135  func (ews *manifoldHarness) InjectError(c *gc.C, err error) {
   136  	select {
   137  	case ews.errors <- err:
   138  	case <-time.After(coretesting.LongWait):
   139  		c.Fatalf("never sent")
   140  	}
   141  }
   142  
   143  func newTracedManifoldHarness(inputs ...string) *tracedManifoldHarness {
   144  	return &tracedManifoldHarness{
   145  		&manifoldHarness{
   146  			inputs:             inputs,
   147  			errors:             make(chan error, 1000),
   148  			starts:             make(chan struct{}, 1000),
   149  			ignoreExternalKill: false,
   150  		},
   151  	}
   152  }
   153  
   154  type tracedManifoldHarness struct {
   155  	*manifoldHarness
   156  }
   157  
   158  func (ews *tracedManifoldHarness) Manifold() dependency.Manifold {
   159  	return dependency.Manifold{
   160  		Inputs: ews.inputs,
   161  		Start:  ews.start,
   162  	}
   163  }
   164  
   165  func (ews *tracedManifoldHarness) start(getResource dependency.GetResourceFunc) (worker.Worker, error) {
   166  	for _, resourceName := range ews.inputs {
   167  		if err := getResource(resourceName, nil); err != nil {
   168  			return nil, errors.Trace(err)
   169  		}
   170  	}
   171  	w := &minimalWorker{tomb.Tomb{}, ews.ignoreExternalKill}
   172  	go func() {
   173  		defer w.tomb.Done()
   174  		ews.starts <- struct{}{}
   175  		select {
   176  		case <-w.tombDying():
   177  		case err := <-ews.errors:
   178  			w.tomb.Kill(err)
   179  		}
   180  	}()
   181  	return w, nil
   182  }
   183  
   184  type minimalWorker struct {
   185  	tomb               tomb.Tomb
   186  	ignoreExternalKill bool
   187  }
   188  
   189  func (w *minimalWorker) tombDying() <-chan struct{} {
   190  	if w.ignoreExternalKill {
   191  		return nil
   192  	}
   193  	return w.tomb.Dying()
   194  }
   195  
   196  func (w *minimalWorker) Kill() {
   197  	w.tomb.Kill(nil)
   198  }
   199  
   200  func (w *minimalWorker) Wait() error {
   201  	return w.tomb.Wait()
   202  }
   203  
   204  func (w *minimalWorker) Report() map[string]interface{} {
   205  	return map[string]interface{}{
   206  		"key1": "hello there",
   207  	}
   208  }
   209  
   210  func startMinimalWorker(_ dependency.GetResourceFunc) (worker.Worker, error) {
   211  	w := &minimalWorker{}
   212  	go func() {
   213  		<-w.tomb.Dying()
   214  		w.tomb.Done()
   215  	}()
   216  	return w, nil
   217  }
   218  
   219  func nothingFatal(_ error) bool {
   220  	return false
   221  }