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

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package resumer_test
     5  
     6  import (
     7  	"errors"
     8  	"time"
     9  
    10  	"github.com/juju/clock"
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  	"gopkg.in/juju/names.v2"
    15  	"gopkg.in/juju/worker.v1"
    16  	"gopkg.in/juju/worker.v1/dependency"
    17  	dt "gopkg.in/juju/worker.v1/dependency/testing"
    18  	"gopkg.in/juju/worker.v1/workertest"
    19  
    20  	"github.com/juju/juju/agent"
    21  	"github.com/juju/juju/api/base"
    22  	"github.com/juju/juju/apiserver/params"
    23  	"github.com/juju/juju/state/multiwatcher"
    24  	coretesting "github.com/juju/juju/testing"
    25  	resumer "github.com/juju/juju/worker/resumer"
    26  )
    27  
    28  type ManifoldSuite struct {
    29  	testing.IsolationSuite
    30  }
    31  
    32  var _ = gc.Suite(&ManifoldSuite{})
    33  
    34  func (*ManifoldSuite) TestInputs(c *gc.C) {
    35  	manifold := resumer.Manifold(resumer.ManifoldConfig{
    36  		AgentName:     "bill",
    37  		APICallerName: "ben",
    38  	})
    39  	expect := []string{"bill", "ben"}
    40  	c.Check(manifold.Inputs, jc.DeepEquals, expect)
    41  }
    42  
    43  func (*ManifoldSuite) TestOutput(c *gc.C) {
    44  	manifold := resumer.Manifold(resumer.ManifoldConfig{})
    45  	c.Check(manifold.Output, gc.IsNil)
    46  }
    47  
    48  func (*ManifoldSuite) TestMissingAgent(c *gc.C) {
    49  	manifold := resumer.Manifold(resumer.ManifoldConfig{
    50  		AgentName:     "agent",
    51  		APICallerName: "api-caller",
    52  	})
    53  
    54  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
    55  		"agent":      dependency.ErrMissing,
    56  		"api-caller": &fakeAPICaller{},
    57  	}))
    58  	workertest.CheckNilOrKill(c, worker)
    59  	c.Check(err, gc.Equals, dependency.ErrMissing)
    60  }
    61  
    62  func (*ManifoldSuite) TestMissingAPICaller(c *gc.C) {
    63  	manifold := resumer.Manifold(resumer.ManifoldConfig{
    64  		AgentName:     "agent",
    65  		APICallerName: "api-caller",
    66  	})
    67  
    68  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
    69  		"agent":      &fakeAgent{},
    70  		"api-caller": dependency.ErrMissing,
    71  	}))
    72  	workertest.CheckNilOrKill(c, worker)
    73  	c.Check(err, gc.Equals, dependency.ErrMissing)
    74  }
    75  
    76  func (*ManifoldSuite) TestAgentEntity_Error(c *gc.C) {
    77  	manifold := resumer.Manifold(resumer.ManifoldConfig{
    78  		AgentName:     "agent",
    79  		APICallerName: "api-caller",
    80  	})
    81  
    82  	stub := &testing.Stub{}
    83  	stub.SetErrors(errors.New("zap"))
    84  	apiCaller := &fakeAPICaller{stub: stub}
    85  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
    86  		"agent":      &fakeAgent{},
    87  		"api-caller": apiCaller,
    88  	}))
    89  	workertest.CheckNilOrKill(c, worker)
    90  	c.Check(err, gc.ErrorMatches, "zap")
    91  
    92  	stub.CheckCalls(c, []testing.StubCall{{
    93  		FuncName: "Agent.GetEntities",
    94  		Args: []interface{}{params.Entities{
    95  			Entities: []params.Entity{{
    96  				Tag: "machine-123",
    97  			}},
    98  		}},
    99  	}})
   100  }
   101  
   102  func (s *ManifoldSuite) TestAgentEntity_NoJob(c *gc.C) {
   103  	manifold := resumer.Manifold(resumer.ManifoldConfig{
   104  		AgentName:     "agent",
   105  		APICallerName: "api-caller",
   106  	})
   107  
   108  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
   109  		"agent":      &fakeAgent{},
   110  		"api-caller": &fakeAPICaller{},
   111  	}))
   112  	workertest.CheckNilOrKill(c, worker)
   113  	c.Check(err, gc.Equals, dependency.ErrMissing)
   114  }
   115  
   116  func (s *ManifoldSuite) TestAgentEntity_NotModelManager(c *gc.C) {
   117  	manifold := resumer.Manifold(resumer.ManifoldConfig{
   118  		AgentName:     "agent",
   119  		APICallerName: "api-caller",
   120  	})
   121  
   122  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
   123  		"agent":      &fakeAgent{},
   124  		"api-caller": newFakeAPICaller(multiwatcher.JobHostUnits),
   125  	}))
   126  	workertest.CheckNilOrKill(c, worker)
   127  	c.Check(err, gc.Equals, dependency.ErrMissing)
   128  }
   129  
   130  func (s *ManifoldSuite) TestNewFacade_Missing(c *gc.C) {
   131  	manifold := resumer.Manifold(resumer.ManifoldConfig{
   132  		AgentName:     "agent",
   133  		APICallerName: "api-caller",
   134  	})
   135  
   136  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
   137  		"agent":      &fakeAgent{},
   138  		"api-caller": newFakeAPICaller(multiwatcher.JobManageModel),
   139  	}))
   140  	workertest.CheckNilOrKill(c, worker)
   141  	c.Check(err, gc.Equals, dependency.ErrUninstall)
   142  }
   143  
   144  func (s *ManifoldSuite) TestNewFacade_Error(c *gc.C) {
   145  	apiCaller := newFakeAPICaller(multiwatcher.JobManageModel)
   146  	manifold := resumer.Manifold(resumer.ManifoldConfig{
   147  		AgentName:     "agent",
   148  		APICallerName: "api-caller",
   149  		NewFacade: func(actual base.APICaller) (resumer.Facade, error) {
   150  			c.Check(actual, gc.Equals, apiCaller)
   151  			return nil, errors.New("pow")
   152  		},
   153  	})
   154  
   155  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
   156  		"agent":      &fakeAgent{},
   157  		"api-caller": apiCaller,
   158  	}))
   159  	workertest.CheckNilOrKill(c, worker)
   160  	c.Check(err, gc.ErrorMatches, "pow")
   161  }
   162  
   163  func (s *ManifoldSuite) TestNewWorker_Missing(c *gc.C) {
   164  	manifold := resumer.Manifold(resumer.ManifoldConfig{
   165  		AgentName:     "agent",
   166  		APICallerName: "api-caller",
   167  		NewFacade: func(base.APICaller) (resumer.Facade, error) {
   168  			return &fakeFacade{}, nil
   169  		},
   170  	})
   171  
   172  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
   173  		"agent":      &fakeAgent{},
   174  		"api-caller": newFakeAPICaller(multiwatcher.JobManageModel),
   175  	}))
   176  	workertest.CheckNilOrKill(c, worker)
   177  	c.Check(err, gc.Equals, dependency.ErrUninstall)
   178  }
   179  
   180  func (s *ManifoldSuite) TestNewWorker_Error(c *gc.C) {
   181  	clock := &fakeClock{}
   182  	facade := &fakeFacade{}
   183  	manifold := resumer.Manifold(resumer.ManifoldConfig{
   184  		AgentName:     "agent",
   185  		APICallerName: "api-caller",
   186  		Clock:         clock,
   187  		Interval:      time.Hour,
   188  		NewFacade: func(base.APICaller) (resumer.Facade, error) {
   189  			return facade, nil
   190  		},
   191  		NewWorker: func(actual resumer.Config) (worker.Worker, error) {
   192  			c.Check(actual, jc.DeepEquals, resumer.Config{
   193  				Facade:   facade,
   194  				Clock:    clock,
   195  				Interval: time.Hour,
   196  			})
   197  			return nil, errors.New("blam")
   198  		},
   199  	})
   200  
   201  	worker, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
   202  		"agent":      &fakeAgent{},
   203  		"api-caller": newFakeAPICaller(multiwatcher.JobManageModel),
   204  	}))
   205  	workertest.CheckNilOrKill(c, worker)
   206  	c.Check(err, gc.ErrorMatches, "blam")
   207  }
   208  
   209  func (s *ManifoldSuite) TestNewWorker_Success(c *gc.C) {
   210  	expect := &fakeWorker{}
   211  	manifold := resumer.Manifold(resumer.ManifoldConfig{
   212  		AgentName:     "agent",
   213  		APICallerName: "api-caller",
   214  		NewFacade: func(base.APICaller) (resumer.Facade, error) {
   215  			return &fakeFacade{}, nil
   216  		},
   217  		NewWorker: func(actual resumer.Config) (worker.Worker, error) {
   218  			return expect, nil
   219  		},
   220  	})
   221  
   222  	actual, err := manifold.Start(dt.StubContext(nil, map[string]interface{}{
   223  		"agent":      &fakeAgent{},
   224  		"api-caller": newFakeAPICaller(multiwatcher.JobManageModel),
   225  	}))
   226  	c.Check(err, jc.ErrorIsNil)
   227  	c.Check(actual, gc.Equals, expect)
   228  }
   229  
   230  // fakeFacade should not be called.
   231  type fakeFacade struct {
   232  	resumer.Facade
   233  }
   234  
   235  // fakeClock should not be called.
   236  type fakeClock struct {
   237  	clock.Clock
   238  }
   239  
   240  // fakeWorker should not be called.
   241  type fakeWorker struct {
   242  	worker.Worker
   243  }
   244  
   245  // fakeAgent exists to expose a tag via CurrentConfig().Tag().
   246  type fakeAgent struct {
   247  	agent.Agent
   248  }
   249  
   250  // CurrentConfig returns an agent.Config with a working Tag() method.
   251  func (a *fakeAgent) CurrentConfig() agent.Config {
   252  	return &fakeConfig{}
   253  }
   254  
   255  // fakeConfig exists to expose Tag.
   256  type fakeConfig struct {
   257  	agent.Config
   258  }
   259  
   260  // Tag returns a Tag.
   261  func (c *fakeConfig) Tag() names.Tag {
   262  	return names.NewMachineTag("123")
   263  }
   264  
   265  func newFakeAPICaller(jobs ...multiwatcher.MachineJob) *fakeAPICaller {
   266  	return &fakeAPICaller{jobs: jobs}
   267  }
   268  
   269  // fakeAPICaller exists to handle the hackish checkModelManager's api
   270  // call directly, because it shouldn't happen in this context at all
   271  // and we don't want it leaking into the config.
   272  type fakeAPICaller struct {
   273  	base.APICaller
   274  	stub *testing.Stub
   275  	jobs []multiwatcher.MachineJob
   276  }
   277  
   278  // APICall is part of the base.APICaller interface.
   279  func (f *fakeAPICaller) APICall(objType string, version int, id, request string, args interface{}, response interface{}) error {
   280  	if f.stub != nil {
   281  		// We don't usually set the stub here, most of the time
   282  		// the APICall hack is just an unwanted distraction from
   283  		// the NewFacade/NewWorker bits that *should* exist long-
   284  		// term. This makes it easier to just delete the broken
   285  		// tests, and most of this type, including all of the
   286  		// methods, when we drop the job check.
   287  		f.stub.AddCall(objType+"."+request, args)
   288  		if err := f.stub.NextErr(); err != nil {
   289  			return err
   290  		}
   291  	}
   292  
   293  	if res, ok := response.(*params.AgentGetEntitiesResults); ok {
   294  		jobs := make([]multiwatcher.MachineJob, 0, len(f.jobs))
   295  		jobs = append(jobs, f.jobs...)
   296  		res.Entities = []params.AgentGetEntitiesResult{
   297  			{Jobs: jobs},
   298  		}
   299  	}
   300  	return nil
   301  }
   302  
   303  // BestFacadeVersion is part of the base.APICaller interface.
   304  func (*fakeAPICaller) BestFacadeVersion(facade string) int {
   305  	return 42
   306  }
   307  
   308  // ModelTag is part of the base.APICaller interface.
   309  func (*fakeAPICaller) ModelTag() (names.ModelTag, bool) {
   310  	return coretesting.ModelTag, true
   311  }