github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/romulus/setplan/set_plan_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package setplan_test
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"net/url"
    10  	stdtesting "testing"
    11  
    12  	"github.com/juju/cmd/cmdtesting"
    13  	"github.com/juju/errors"
    14  	"github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	gc "gopkg.in/check.v1"
    17  	"gopkg.in/juju/charm.v6-unstable"
    18  	"gopkg.in/macaroon-bakery.v1/bakery"
    19  	"gopkg.in/macaroon-bakery.v1/bakery/checkers"
    20  	"gopkg.in/macaroon.v1"
    21  
    22  	"github.com/juju/juju/cmd/juju/romulus/setplan"
    23  	jjjtesting "github.com/juju/juju/juju/testing"
    24  	"github.com/juju/juju/state"
    25  	"github.com/juju/juju/testcharms"
    26  	jjtesting "github.com/juju/juju/testing"
    27  )
    28  
    29  func TestPackage(t *stdtesting.T) {
    30  	jjtesting.MgoTestPackage(t)
    31  }
    32  
    33  var _ = gc.Suite(&setPlanCommandSuite{})
    34  
    35  type setPlanCommandSuite struct {
    36  	jjjtesting.JujuConnSuite
    37  
    38  	mockAPI  *mockapi
    39  	charmURL string
    40  }
    41  
    42  func (s *setPlanCommandSuite) SetUpTest(c *gc.C) {
    43  	s.JujuConnSuite.SetUpTest(c)
    44  
    45  	ch := testcharms.Repo.CharmDir("dummy")
    46  	curl := charm.MustParseURL(
    47  		fmt.Sprintf("local:quantal/%s-%d", ch.Meta().Name, ch.Revision()),
    48  	)
    49  	s.charmURL = curl.String()
    50  	charmInfo := state.CharmInfo{
    51  		Charm:       ch,
    52  		ID:          curl,
    53  		StoragePath: "dummy-path",
    54  		SHA256:      "dummy-1",
    55  	}
    56  	dummyCharm, err := s.State.AddCharm(charmInfo)
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	s.AddTestingService(c, "mysql", dummyCharm)
    59  
    60  	mockAPI, err := newMockAPI()
    61  	c.Assert(err, jc.ErrorIsNil)
    62  	s.mockAPI = mockAPI
    63  
    64  	s.PatchValue(setplan.NewAuthorizationClient, setplan.APIClientFnc(s.mockAPI))
    65  }
    66  
    67  func (s setPlanCommandSuite) TestSetPlanCommand(c *gc.C) {
    68  	tests := []struct {
    69  		about       string
    70  		plan        string
    71  		application string
    72  		err         string
    73  		apiErr      error
    74  		apiCalls    []testing.StubCall
    75  	}{{
    76  		about:       "all is well",
    77  		plan:        "bob/default",
    78  		application: "mysql",
    79  		apiCalls: []testing.StubCall{{
    80  			FuncName: "Authorize",
    81  			Args: []interface{}{
    82  				s.State.ModelUUID(),
    83  				s.charmURL,
    84  				"mysql",
    85  			},
    86  		}},
    87  	}, {
    88  		about:       "invalid application name",
    89  		plan:        "bob/default",
    90  		application: "mysql-0",
    91  		err:         "invalid application name \"mysql-0\"",
    92  	}, {
    93  		about:       "unknown application",
    94  		plan:        "bob/default",
    95  		application: "wordpress",
    96  		err:         "application \"wordpress\" not found.*",
    97  	}, {
    98  		about:       "unknown application",
    99  		plan:        "bob/default",
   100  		application: "mysql",
   101  		apiErr:      errors.New("some strange error"),
   102  		err:         "some strange error",
   103  	},
   104  	}
   105  	for i, test := range tests {
   106  		c.Logf("running test %d: %v", i, test.about)
   107  		s.mockAPI.ResetCalls()
   108  		if test.apiErr != nil {
   109  			s.mockAPI.SetErrors(test.apiErr)
   110  		}
   111  		_, err := cmdtesting.RunCommand(c, setplan.NewSetPlanCommand(), test.application, test.plan)
   112  		if test.err == "" {
   113  			c.Assert(err, jc.ErrorIsNil)
   114  			c.Assert(s.mockAPI.Calls(), gc.HasLen, 1)
   115  			s.mockAPI.CheckCalls(c, test.apiCalls)
   116  
   117  			app, err := s.State.Application("mysql")
   118  			c.Assert(err, jc.ErrorIsNil)
   119  			svcMacaroon := app.MetricCredentials()
   120  			data, err := json.Marshal(macaroon.Slice{s.mockAPI.macaroon})
   121  			c.Assert(err, jc.ErrorIsNil)
   122  			c.Assert(svcMacaroon, gc.DeepEquals, data)
   123  		} else {
   124  			c.Assert(err, gc.ErrorMatches, test.err)
   125  			c.Assert(s.mockAPI.Calls(), gc.HasLen, 0)
   126  		}
   127  	}
   128  }
   129  
   130  func (s *setPlanCommandSuite) TestNoArgs(c *gc.C) {
   131  	_, err := cmdtesting.RunCommand(c, setplan.NewSetPlanCommand())
   132  	c.Assert(err, gc.ErrorMatches, "need to specify application name and plan url")
   133  }
   134  
   135  func newMockAPI() (*mockapi, error) {
   136  	kp, err := bakery.GenerateKey()
   137  	if err != nil {
   138  		return nil, errors.Trace(err)
   139  	}
   140  	svc, err := bakery.NewService(bakery.NewServiceParams{
   141  		Location: "omnibus",
   142  		Key:      kp,
   143  	})
   144  	if err != nil {
   145  		return nil, errors.Trace(err)
   146  	}
   147  	return &mockapi{
   148  		service: svc,
   149  	}, nil
   150  }
   151  
   152  type mockapi struct {
   153  	testing.Stub
   154  
   155  	service  *bakery.Service
   156  	macaroon *macaroon.Macaroon
   157  }
   158  
   159  func (m *mockapi) Authorize(modelUUID, charmURL, applicationName, plan string, visitWebPage func(*url.URL) error) (*macaroon.Macaroon, error) {
   160  	err := m.NextErr()
   161  	if err != nil {
   162  		return nil, errors.Trace(err)
   163  	}
   164  	m.AddCall("Authorize", modelUUID, charmURL, applicationName)
   165  	macaroon, err := m.service.NewMacaroon(
   166  		"",
   167  		nil,
   168  		[]checkers.Caveat{
   169  			checkers.DeclaredCaveat("environment", modelUUID),
   170  			checkers.DeclaredCaveat("charm", charmURL),
   171  			checkers.DeclaredCaveat("service", applicationName),
   172  			checkers.DeclaredCaveat("plan", plan),
   173  		},
   174  	)
   175  	if err != nil {
   176  		return nil, errors.Trace(err)
   177  	}
   178  	m.macaroon = macaroon
   179  	return m.macaroon, nil
   180  }