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

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apicaller_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names"
     9  	"github.com/juju/testing"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/agent"
    14  	"github.com/juju/juju/api"
    15  	"github.com/juju/juju/api/base"
    16  	coretesting "github.com/juju/juju/testing"
    17  	"github.com/juju/juju/worker"
    18  	"github.com/juju/juju/worker/apicaller"
    19  	"github.com/juju/juju/worker/dependency"
    20  	dt "github.com/juju/juju/worker/dependency/testing"
    21  )
    22  
    23  type ManifoldSuite struct {
    24  	testing.IsolationSuite
    25  	testing.Stub
    26  	manifold    dependency.Manifold
    27  	agent       *mockAgent
    28  	gate        *mockGate
    29  	conn        *mockConn
    30  	getResource dependency.GetResourceFunc
    31  }
    32  
    33  var _ = gc.Suite(&ManifoldSuite{})
    34  
    35  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    36  	s.IsolationSuite.SetUpTest(c)
    37  	s.Stub = testing.Stub{}
    38  	s.manifold = apicaller.Manifold(apicaller.ManifoldConfig{
    39  		AgentName:       "agent-name",
    40  		APIInfoGateName: "api-info-gate-name",
    41  	})
    42  
    43  	s.agent = &mockAgent{
    44  		stub: &s.Stub,
    45  		env:  coretesting.EnvironmentTag,
    46  	}
    47  	s.gate = &mockGate{
    48  		stub: &s.Stub,
    49  	}
    50  	s.getResource = dt.StubGetResource(dt.StubResources{
    51  		"agent-name":         dt.StubResource{Output: s.agent},
    52  		"api-info-gate-name": dt.StubResource{Output: s.gate},
    53  	})
    54  
    55  	// Watch out for this: it uses its own Stub because Close calls are made from
    56  	// the worker's loop goroutine. You should make sure to stop the worker before
    57  	// checking the mock conn's calls (unless you know the connection will outlive
    58  	// the test -- see setupMutatorTest).
    59  	s.conn = &mockConn{
    60  		stub:   &testing.Stub{},
    61  		broken: make(chan struct{}),
    62  	}
    63  	s.PatchValue(apicaller.OpenConnection, func(a agent.Agent) (api.Connection, error) {
    64  		s.AddCall("openConnection", a)
    65  		if err := s.NextErr(); err != nil {
    66  			return nil, err
    67  		}
    68  		return s.conn, nil
    69  	})
    70  }
    71  
    72  func (s *ManifoldSuite) TestInputs(c *gc.C) {
    73  	c.Check(s.manifold.Inputs, jc.DeepEquals, []string{"agent-name", "api-info-gate-name"})
    74  }
    75  
    76  func (s *ManifoldSuite) TestStartMissingAgent(c *gc.C) {
    77  	getResource := dt.StubGetResource(dt.StubResources{
    78  		"agent-name":         dt.StubResource{Error: dependency.ErrMissing},
    79  		"api-info-gate-name": dt.StubResource{Output: s.gate},
    80  	})
    81  
    82  	worker, err := s.manifold.Start(getResource)
    83  	c.Check(worker, gc.IsNil)
    84  	c.Check(err, gc.Equals, dependency.ErrMissing)
    85  	s.CheckCalls(c, nil)
    86  }
    87  
    88  func (s *ManifoldSuite) TestStartMissingGate(c *gc.C) {
    89  	getResource := dt.StubGetResource(dt.StubResources{
    90  		"agent-name":         dt.StubResource{Output: s.agent},
    91  		"api-info-gate-name": dt.StubResource{Error: dependency.ErrMissing},
    92  	})
    93  
    94  	worker, err := s.manifold.Start(getResource)
    95  	c.Check(worker, gc.IsNil)
    96  	c.Check(err, gc.Equals, dependency.ErrMissing)
    97  	s.CheckCalls(c, nil)
    98  }
    99  
   100  func (s *ManifoldSuite) TestStartCannotOpenAPI(c *gc.C) {
   101  	s.SetErrors(errors.New("no api for you"))
   102  
   103  	worker, err := s.manifold.Start(s.getResource)
   104  	c.Check(worker, gc.IsNil)
   105  	c.Check(err, gc.ErrorMatches, "cannot open api: no api for you")
   106  	s.CheckCalls(c, []testing.StubCall{{
   107  		FuncName: "openConnection",
   108  		Args:     []interface{}{s.agent},
   109  	}})
   110  }
   111  
   112  func (s *ManifoldSuite) TestStartSuccessWithEnvironnmentIdSet(c *gc.C) {
   113  	worker, err := s.manifold.Start(s.getResource)
   114  	c.Check(err, jc.ErrorIsNil)
   115  	defer assertStop(c, worker)
   116  	s.CheckCalls(c, []testing.StubCall{{
   117  		FuncName: "openConnection",
   118  		Args:     []interface{}{s.agent},
   119  	}, {
   120  		FuncName: "Unlock",
   121  	}})
   122  }
   123  
   124  func (s *ManifoldSuite) setupMutatorTest(c *gc.C) agent.ConfigMutator {
   125  	s.agent.env = names.EnvironTag{}
   126  	s.conn.stub = &s.Stub // will be unsafe if worker stopped before test finished
   127  	s.SetErrors(
   128  		nil, //                                               openConnection,
   129  		errors.New("nonfatal: always logged and ignored"), // ChangeConfig
   130  	)
   131  
   132  	worker, err := s.manifold.Start(s.getResource)
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	s.AddCleanup(func(c *gc.C) { assertStop(c, worker) })
   135  
   136  	s.CheckCallNames(c, "openConnection", "ChangeConfig", "Unlock")
   137  	changeArgs := s.Calls()[1].Args
   138  	c.Assert(changeArgs, gc.HasLen, 1)
   139  	s.ResetCalls()
   140  	return changeArgs[0].(agent.ConfigMutator)
   141  }
   142  
   143  func (s *ManifoldSuite) TestStartSuccessWithEnvironnmentIdNotSet(c *gc.C) {
   144  	mutator := s.setupMutatorTest(c)
   145  	mockSetter := &mockSetter{stub: &s.Stub}
   146  
   147  	err := mutator(mockSetter)
   148  	c.Check(err, jc.ErrorIsNil)
   149  	s.CheckCalls(c, []testing.StubCall{{
   150  		FuncName: "EnvironTag",
   151  	}, {
   152  		FuncName: "Migrate",
   153  		Args: []interface{}{agent.MigrateParams{
   154  			Environment: coretesting.EnvironmentTag,
   155  		}},
   156  	}})
   157  }
   158  
   159  func (s *ManifoldSuite) TestStartSuccessWithEnvironnmentIdNotSetBadAPIState(c *gc.C) {
   160  	mutator := s.setupMutatorTest(c)
   161  	s.SetErrors(errors.New("no tag for you"))
   162  
   163  	err := mutator(nil)
   164  	c.Check(err, gc.ErrorMatches, "no environment uuid set on api: no tag for you")
   165  	s.CheckCalls(c, []testing.StubCall{{
   166  		FuncName: "EnvironTag",
   167  	}})
   168  }
   169  
   170  func (s *ManifoldSuite) TestStartSuccessWithEnvironnmentIdNotSetMigrateFailure(c *gc.C) {
   171  	mutator := s.setupMutatorTest(c)
   172  	mockSetter := &mockSetter{stub: &s.Stub}
   173  	s.SetErrors(nil, errors.New("migrate failure"))
   174  
   175  	err := mutator(mockSetter)
   176  	c.Check(err, gc.ErrorMatches, "migrate failure")
   177  	s.CheckCalls(c, []testing.StubCall{{
   178  		FuncName: "EnvironTag",
   179  	}, {
   180  		FuncName: "Migrate",
   181  		Args: []interface{}{agent.MigrateParams{
   182  			Environment: coretesting.EnvironmentTag,
   183  		}},
   184  	}})
   185  }
   186  
   187  func (s *ManifoldSuite) setupWorkerTest(c *gc.C) worker.Worker {
   188  	w, err := s.manifold.Start(s.getResource)
   189  	c.Assert(err, jc.ErrorIsNil)
   190  	s.AddCleanup(func(c *gc.C) { w.Kill() })
   191  	return w
   192  }
   193  
   194  func (s *ManifoldSuite) TestKillWorkerClosesConnection(c *gc.C) {
   195  	worker := s.setupWorkerTest(c)
   196  	assertStop(c, worker)
   197  	s.conn.stub.CheckCalls(c, []testing.StubCall{{
   198  		FuncName: "Close",
   199  	}})
   200  }
   201  
   202  func (s *ManifoldSuite) TestKillWorkerReportsCloseErr(c *gc.C) {
   203  	s.conn.stub.SetErrors(errors.New("bad plumbing"))
   204  	worker := s.setupWorkerTest(c)
   205  
   206  	assertStopError(c, worker, "bad plumbing")
   207  	s.conn.stub.CheckCalls(c, []testing.StubCall{{
   208  		FuncName: "Close",
   209  	}})
   210  }
   211  
   212  func (s *ManifoldSuite) TestBrokenConnectionKillsWorkerWithCloseErr(c *gc.C) {
   213  	s.conn.stub.SetErrors(errors.New("bad plumbing"))
   214  	worker := s.setupWorkerTest(c)
   215  
   216  	close(s.conn.broken)
   217  	err := worker.Wait()
   218  	c.Check(err, gc.ErrorMatches, "bad plumbing")
   219  	s.conn.stub.CheckCalls(c, []testing.StubCall{{
   220  		FuncName: "Close",
   221  	}})
   222  }
   223  
   224  func (s *ManifoldSuite) TestBrokenConnectionKillsWorkerWithFallbackErr(c *gc.C) {
   225  	worker := s.setupWorkerTest(c)
   226  
   227  	close(s.conn.broken)
   228  	err := worker.Wait()
   229  	c.Check(err, gc.ErrorMatches, "api connection broken unexpectedly")
   230  	s.conn.stub.CheckCalls(c, []testing.StubCall{{
   231  		FuncName: "Close",
   232  	}})
   233  }
   234  
   235  func (s *ManifoldSuite) TestOutputSuccess(c *gc.C) {
   236  	worker := s.setupWorkerTest(c)
   237  
   238  	var apicaller base.APICaller
   239  	err := s.manifold.Output(worker, &apicaller)
   240  	c.Check(err, jc.ErrorIsNil)
   241  	c.Check(apicaller, gc.Equals, s.conn)
   242  }
   243  
   244  func (s *ManifoldSuite) TestOutputBadWorker(c *gc.C) {
   245  	var apicaller base.APICaller
   246  	err := s.manifold.Output(dummyWorker{}, &apicaller)
   247  	c.Check(apicaller, gc.IsNil)
   248  	c.Check(err.Error(), gc.Equals, "expected *apicaller.apiConnWorker->*base.APICaller; got apicaller_test.dummyWorker->*base.APICaller")
   249  }
   250  
   251  func (s *ManifoldSuite) TestOutputBadTarget(c *gc.C) {
   252  	worker := s.setupWorkerTest(c)
   253  
   254  	var apicaller interface{}
   255  	err := s.manifold.Output(worker, &apicaller)
   256  	c.Check(apicaller, gc.IsNil)
   257  	c.Check(err.Error(), gc.Equals, "expected *apicaller.apiConnWorker->*base.APICaller; got *apicaller.apiConnWorker->*interface {}")
   258  }