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

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package httpserverargs_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock"
    10  	"github.com/juju/clock/testclock"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    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/apiserver/apiserverhttp"
    21  	"github.com/juju/juju/apiserver/httpcontext"
    22  	"github.com/juju/juju/state"
    23  	"github.com/juju/juju/worker/httpserverargs"
    24  )
    25  
    26  type ManifoldSuite struct {
    27  	testing.IsolationSuite
    28  
    29  	config        httpserverargs.ManifoldConfig
    30  	manifold      dependency.Manifold
    31  	context       dependency.Context
    32  	clock         *testclock.Clock
    33  	state         stubStateTracker
    34  	authenticator mockLocalMacaroonAuthenticator
    35  
    36  	stub testing.Stub
    37  }
    38  
    39  var _ = gc.Suite(&ManifoldSuite{})
    40  
    41  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    42  	s.IsolationSuite.SetUpTest(c)
    43  
    44  	s.clock = testclock.NewClock(time.Time{})
    45  	s.state = stubStateTracker{}
    46  	s.stub.ResetCalls()
    47  
    48  	s.context = s.newContext(nil)
    49  	s.config = httpserverargs.ManifoldConfig{
    50  		ClockName:             "clock",
    51  		StateName:             "state",
    52  		ControllerPortName:    "controller-port",
    53  		NewStateAuthenticator: s.newStateAuthenticator,
    54  	}
    55  	s.manifold = httpserverargs.Manifold(s.config)
    56  }
    57  
    58  func (s *ManifoldSuite) newContext(overlay map[string]interface{}) dependency.Context {
    59  	resources := map[string]interface{}{
    60  		"clock":           s.clock,
    61  		"state":           &s.state,
    62  		"controller-port": nil,
    63  	}
    64  	for k, v := range overlay {
    65  		resources[k] = v
    66  	}
    67  	return dt.StubContext(nil, resources)
    68  }
    69  
    70  func (s *ManifoldSuite) newStateAuthenticator(
    71  	statePool *state.StatePool,
    72  	mux *apiserverhttp.Mux,
    73  	clock clock.Clock,
    74  	abort <-chan struct{},
    75  ) (httpcontext.LocalMacaroonAuthenticator, error) {
    76  	s.stub.MethodCall(s, "NewStateAuthenticator", statePool, mux, clock, abort)
    77  	if err := s.stub.NextErr(); err != nil {
    78  		return nil, err
    79  	}
    80  	return &s.authenticator, nil
    81  }
    82  
    83  var expectedInputs = []string{"state", "clock", "controller-port"}
    84  
    85  func (s *ManifoldSuite) TestInputs(c *gc.C) {
    86  	c.Assert(s.manifold.Inputs, jc.SameContents, expectedInputs)
    87  }
    88  
    89  func (s *ManifoldSuite) TestMissingInputs(c *gc.C) {
    90  	for _, input := range expectedInputs {
    91  		context := s.newContext(map[string]interface{}{
    92  			input: dependency.ErrMissing,
    93  		})
    94  		_, err := s.manifold.Start(context)
    95  		c.Assert(errors.Cause(err), gc.Equals, dependency.ErrMissing)
    96  	}
    97  }
    98  
    99  func (s *ManifoldSuite) TestMuxOutput(c *gc.C) {
   100  	w := s.startWorkerClean(c)
   101  	defer workertest.CleanKill(c, w)
   102  
   103  	var mux *apiserverhttp.Mux
   104  	err := s.manifold.Output(w, &mux)
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	c.Assert(mux, gc.NotNil)
   107  }
   108  
   109  func (s *ManifoldSuite) TestAuthenticatorOutput(c *gc.C) {
   110  	w := s.startWorkerClean(c)
   111  	defer workertest.CleanKill(c, w)
   112  
   113  	var auth1 httpcontext.Authenticator
   114  	var auth2 httpcontext.LocalMacaroonAuthenticator
   115  	for _, out := range []interface{}{&auth1, &auth2} {
   116  		err := s.manifold.Output(w, out)
   117  		c.Assert(err, jc.ErrorIsNil)
   118  	}
   119  	c.Assert(auth1, gc.NotNil)
   120  	c.Assert(auth1, gc.Equals, auth2)
   121  }
   122  
   123  func (s *ManifoldSuite) startWorkerClean(c *gc.C) worker.Worker {
   124  	w, err := s.manifold.Start(s.context)
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	workertest.CheckAlive(c, w)
   127  	return w
   128  }
   129  
   130  func (s *ManifoldSuite) TestStopWorkerClosesState(c *gc.C) {
   131  	w := s.startWorkerClean(c)
   132  	defer workertest.CleanKill(c, w)
   133  
   134  	s.state.CheckCallNames(c, "Use")
   135  
   136  	workertest.CleanKill(c, w)
   137  	s.state.CheckCallNames(c, "Use", "Done")
   138  }
   139  
   140  func (s *ManifoldSuite) TestStoppingWorkerClosesAuthenticator(c *gc.C) {
   141  	w := s.startWorkerClean(c)
   142  	s.stub.CheckCallNames(c, "NewStateAuthenticator")
   143  	authArgs := s.stub.Calls()[0].Args
   144  	c.Assert(authArgs, gc.HasLen, 4)
   145  	abort := authArgs[3].(<-chan struct{})
   146  
   147  	// abort should still be open at this point.
   148  	select {
   149  	case <-abort:
   150  		c.Fatalf("abort closed while worker still running")
   151  	default:
   152  	}
   153  
   154  	workertest.CleanKill(c, w)
   155  	select {
   156  	case <-abort:
   157  	default:
   158  		c.Fatalf("authenticator abort channel not closed")
   159  	}
   160  }
   161  
   162  func (s *ManifoldSuite) TestValidate(c *gc.C) {
   163  	type test struct {
   164  		f      func(*httpserverargs.ManifoldConfig)
   165  		expect string
   166  	}
   167  	tests := []test{{
   168  		func(cfg *httpserverargs.ManifoldConfig) { cfg.StateName = "" },
   169  		"empty StateName not valid",
   170  	}, {
   171  		func(cfg *httpserverargs.ManifoldConfig) { cfg.ClockName = "" },
   172  		"empty ClockName not valid",
   173  	}, {
   174  		func(cfg *httpserverargs.ManifoldConfig) { cfg.ControllerPortName = "" },
   175  		"empty ControllerPortName not valid",
   176  	}, {
   177  		func(cfg *httpserverargs.ManifoldConfig) { cfg.NewStateAuthenticator = nil },
   178  		"nil NewStateAuthenticator not valid",
   179  	}}
   180  	for i, test := range tests {
   181  		c.Logf("test #%d (%s)", i, test.expect)
   182  		config := s.config
   183  		test.f(&config)
   184  		manifold := httpserverargs.Manifold(config)
   185  		w, err := manifold.Start(s.context)
   186  		workertest.CheckNilOrKill(c, w)
   187  		c.Check(err, gc.ErrorMatches, test.expect)
   188  	}
   189  }
   190  
   191  type mockLocalMacaroonAuthenticator struct {
   192  	httpcontext.LocalMacaroonAuthenticator
   193  }
   194  
   195  type stubStateTracker struct {
   196  	testing.Stub
   197  	pool state.StatePool
   198  }
   199  
   200  func (s *stubStateTracker) Use() (*state.StatePool, error) {
   201  	s.MethodCall(s, "Use")
   202  	return &s.pool, s.NextErr()
   203  }
   204  
   205  func (s *stubStateTracker) Done() error {
   206  	s.MethodCall(s, "Done")
   207  	return s.NextErr()
   208  }
   209  
   210  func (s *stubStateTracker) Report() map[string]interface{} {
   211  	s.MethodCall(s, "Report")
   212  	return nil
   213  }