github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/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/loggo"
     9  	"github.com/juju/names/v5"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	"github.com/juju/worker/v3"
    13  	"github.com/juju/worker/v3/dependency"
    14  	dt "github.com/juju/worker/v3/dependency/testing"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/agent"
    18  	"github.com/juju/juju/api"
    19  	"github.com/juju/juju/api/base"
    20  	coretesting "github.com/juju/juju/testing"
    21  	"github.com/juju/juju/worker/apicaller"
    22  )
    23  
    24  type ManifoldSuite struct {
    25  	testing.IsolationSuite
    26  	testing.Stub
    27  
    28  	manifold       dependency.Manifold
    29  	manifoldConfig apicaller.ManifoldConfig
    30  	agent          *mockAgent
    31  	conn           *mockConn
    32  	context        dependency.Context
    33  }
    34  
    35  var _ = gc.Suite(&ManifoldSuite{})
    36  
    37  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    38  	s.IsolationSuite.SetUpTest(c)
    39  	s.Stub = testing.Stub{}
    40  	s.manifoldConfig = apicaller.ManifoldConfig{
    41  		AgentName:            "agent-name",
    42  		APIConfigWatcherName: "api-config-watcher-name",
    43  		APIOpen: func(*api.Info, api.DialOpts) (api.Connection, error) {
    44  			panic("just a fake")
    45  		},
    46  		NewConnection: func(a agent.Agent, apiOpen api.OpenFunc, logger apicaller.Logger) (api.Connection, error) {
    47  			c.Check(apiOpen, gc.NotNil) // uncomparable
    48  			c.Check(logger, gc.NotNil)  // uncomparable
    49  			s.AddCall("NewConnection", a)
    50  			if err := s.NextErr(); err != nil {
    51  				return nil, err
    52  			}
    53  			return s.conn, nil
    54  		},
    55  		Filter: func(err error) error {
    56  			panic(err)
    57  		},
    58  		Logger: loggo.GetLogger("test"),
    59  	}
    60  	s.manifold = apicaller.Manifold(s.manifoldConfig)
    61  	checkFilter := func() {
    62  		s.manifold.Filter(errors.New("arrgh"))
    63  	}
    64  	c.Check(checkFilter, gc.PanicMatches, "arrgh")
    65  
    66  	s.agent = &mockAgent{
    67  		stub:   &s.Stub,
    68  		model:  coretesting.ModelTag,
    69  		entity: names.NewMachineTag("42"),
    70  	}
    71  	s.context = dt.StubContext(nil, map[string]interface{}{
    72  		"agent-name": s.agent,
    73  	})
    74  
    75  	// Watch out for this: it uses its own Stub because Close calls
    76  	// are made from the worker's loop goroutine. You should make
    77  	// sure to stop the worker before checking the mock conn's calls.
    78  	s.conn = &mockConn{
    79  		stub:   &testing.Stub{},
    80  		broken: make(chan struct{}),
    81  	}
    82  }
    83  
    84  func (s *ManifoldSuite) TestInputsOptionalConfigPropertiesUnset(c *gc.C) {
    85  	s.manifoldConfig.APIConfigWatcherName = ""
    86  	c.Check(apicaller.Manifold(s.manifoldConfig).Inputs, jc.DeepEquals, []string{
    87  		"agent-name",
    88  	})
    89  }
    90  
    91  func (s *ManifoldSuite) TestInputs(c *gc.C) {
    92  	c.Check(s.manifold.Inputs, jc.DeepEquals, []string{
    93  		"agent-name",
    94  		"api-config-watcher-name",
    95  	})
    96  }
    97  
    98  func (s *ManifoldSuite) TestStartMissingAgent(c *gc.C) {
    99  	context := dt.StubContext(nil, map[string]interface{}{
   100  		"agent-name": dependency.ErrMissing,
   101  	})
   102  
   103  	worker, err := s.manifold.Start(context)
   104  	c.Check(worker, gc.IsNil)
   105  	c.Check(err, gc.Equals, dependency.ErrMissing)
   106  	s.CheckCalls(c, nil)
   107  }
   108  
   109  func (s *ManifoldSuite) TestStartCannotOpenAPI(c *gc.C) {
   110  	s.SetErrors(errors.New("no api for you"))
   111  
   112  	worker, err := s.manifold.Start(s.context)
   113  	c.Check(worker, gc.IsNil)
   114  	c.Check(err, gc.ErrorMatches, `\[deadbe\] "machine-42" cannot open api: no api for you`)
   115  	s.CheckCalls(c, []testing.StubCall{{
   116  		FuncName: "NewConnection",
   117  		Args:     []interface{}{s.agent},
   118  	}})
   119  }
   120  
   121  func (s *ManifoldSuite) TestStartSuccess(c *gc.C) {
   122  	worker, err := s.manifold.Start(s.context)
   123  	c.Check(err, jc.ErrorIsNil)
   124  	defer assertStop(c, worker)
   125  	s.CheckCalls(c, []testing.StubCall{{
   126  		FuncName: "NewConnection",
   127  		Args:     []interface{}{s.agent},
   128  	}})
   129  }
   130  
   131  func (s *ManifoldSuite) setupWorkerTest(c *gc.C) worker.Worker {
   132  	w, err := s.manifold.Start(s.context)
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	s.AddCleanup(func(c *gc.C) { w.Kill() })
   135  	return w
   136  }
   137  
   138  func (s *ManifoldSuite) TestKillWorkerClosesConnection(c *gc.C) {
   139  	worker := s.setupWorkerTest(c)
   140  	assertStop(c, worker)
   141  	s.conn.stub.CheckCalls(c, []testing.StubCall{{
   142  		FuncName: "Close",
   143  	}})
   144  }
   145  
   146  func (s *ManifoldSuite) TestKillWorkerReportsCloseErr(c *gc.C) {
   147  	s.conn.stub.SetErrors(errors.New("bad plumbing"))
   148  	worker := s.setupWorkerTest(c)
   149  
   150  	assertStopError(c, worker, "bad plumbing")
   151  	s.conn.stub.CheckCalls(c, []testing.StubCall{{
   152  		FuncName: "Close",
   153  	}})
   154  }
   155  
   156  func (s *ManifoldSuite) TestBrokenConnectionKillsWorkerWithCloseErr(c *gc.C) {
   157  	s.conn.stub.SetErrors(errors.New("bad plumbing"))
   158  	worker := s.setupWorkerTest(c)
   159  
   160  	close(s.conn.broken)
   161  	err := worker.Wait()
   162  	c.Check(err, gc.ErrorMatches, "bad plumbing")
   163  	s.conn.stub.CheckCalls(c, []testing.StubCall{{
   164  		FuncName: "Close",
   165  	}})
   166  }
   167  
   168  func (s *ManifoldSuite) TestBrokenConnectionKillsWorkerWithFallbackErr(c *gc.C) {
   169  	worker := s.setupWorkerTest(c)
   170  
   171  	close(s.conn.broken)
   172  	err := worker.Wait()
   173  	c.Check(err, gc.ErrorMatches, "api connection broken unexpectedly")
   174  	s.conn.stub.CheckCalls(c, []testing.StubCall{{
   175  		FuncName: "Close",
   176  	}})
   177  }
   178  
   179  func (s *ManifoldSuite) TestOutputSuccess(c *gc.C) {
   180  	worker := s.setupWorkerTest(c)
   181  
   182  	var apicaller base.APICaller
   183  	err := s.manifold.Output(worker, &apicaller)
   184  	c.Check(err, jc.ErrorIsNil)
   185  	c.Check(apicaller, gc.Equals, s.conn)
   186  
   187  	var conn api.Connection
   188  	err = s.manifold.Output(worker, &conn)
   189  	c.Check(err, jc.ErrorIsNil)
   190  	c.Check(conn, gc.Equals, s.conn)
   191  }
   192  
   193  func (s *ManifoldSuite) TestOutputBadWorker(c *gc.C) {
   194  	var apicaller base.APICaller
   195  	err := s.manifold.Output(dummyWorker{}, &apicaller)
   196  	c.Check(apicaller, gc.IsNil)
   197  	c.Check(err.Error(), gc.Equals, "in should be a *apicaller.apiConnWorker; got apicaller_test.dummyWorker")
   198  }
   199  
   200  func (s *ManifoldSuite) TestOutputBadTarget(c *gc.C) {
   201  	worker := s.setupWorkerTest(c)
   202  
   203  	var apicaller interface{}
   204  	err := s.manifold.Output(worker, &apicaller)
   205  	c.Check(apicaller, gc.IsNil)
   206  	c.Check(err.Error(), gc.Equals, "out should be *base.APICaller or *api.Connection; got *interface {}")
   207  }