github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/api/uniter/unit_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter_test
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils"
    14  	gc "gopkg.in/check.v1"
    15  	"gopkg.in/juju/charm.v5"
    16  
    17  	"github.com/juju/juju/api"
    18  	"github.com/juju/juju/api/base"
    19  	"github.com/juju/juju/api/uniter"
    20  	"github.com/juju/juju/apiserver/common"
    21  	"github.com/juju/juju/apiserver/params"
    22  	"github.com/juju/juju/juju/testing"
    23  	"github.com/juju/juju/network"
    24  	"github.com/juju/juju/state"
    25  	statetesting "github.com/juju/juju/state/testing"
    26  	jujufactory "github.com/juju/juju/testing/factory"
    27  )
    28  
    29  type unitSuite struct {
    30  	uniterSuite
    31  
    32  	apiUnit *uniter.Unit
    33  }
    34  
    35  var _ = gc.Suite(&unitSuite{})
    36  
    37  func (s *unitSuite) SetUpTest(c *gc.C) {
    38  	s.uniterSuite.SetUpTest(c)
    39  
    40  	var err error
    41  	s.apiUnit, err = s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag))
    42  	c.Assert(err, jc.ErrorIsNil)
    43  }
    44  
    45  func (s *unitSuite) TestRequestReboot(c *gc.C) {
    46  	err := s.apiUnit.RequestReboot()
    47  	c.Assert(err, jc.ErrorIsNil)
    48  	rFlag, err := s.wordpressMachine.GetRebootFlag()
    49  	c.Assert(err, jc.ErrorIsNil)
    50  	c.Assert(rFlag, jc.IsTrue)
    51  }
    52  
    53  func (s *unitSuite) TestUnitAndUnitTag(c *gc.C) {
    54  	apiUnitFoo, err := s.uniter.Unit(names.NewUnitTag("foo/42"))
    55  	c.Assert(err, gc.ErrorMatches, "permission denied")
    56  	c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized)
    57  	c.Assert(apiUnitFoo, gc.IsNil)
    58  
    59  	c.Assert(s.apiUnit.Tag(), gc.Equals, s.wordpressUnit.Tag().(names.UnitTag))
    60  }
    61  
    62  func (s *unitSuite) TestSetAgentStatus(c *gc.C) {
    63  	statusInfo, err := s.wordpressUnit.AgentStatus()
    64  	c.Assert(err, jc.ErrorIsNil)
    65  	c.Assert(statusInfo.Status, gc.Equals, state.StatusAllocating)
    66  	c.Assert(statusInfo.Message, gc.Equals, "")
    67  	c.Assert(statusInfo.Data, gc.HasLen, 0)
    68  
    69  	unitStatusInfo, err := s.wordpressUnit.Status()
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	c.Assert(unitStatusInfo.Status, gc.Equals, state.StatusUnknown)
    72  	c.Assert(unitStatusInfo.Message, gc.Equals, "Waiting for agent initialization to finish")
    73  	c.Assert(unitStatusInfo.Data, gc.HasLen, 0)
    74  
    75  	err = s.apiUnit.SetAgentStatus(params.StatusIdle, "blah", nil)
    76  	c.Assert(err, jc.ErrorIsNil)
    77  
    78  	statusInfo, err = s.wordpressUnit.AgentStatus()
    79  	c.Assert(err, jc.ErrorIsNil)
    80  	c.Assert(statusInfo.Status, gc.Equals, state.StatusIdle)
    81  	c.Assert(statusInfo.Message, gc.Equals, "blah")
    82  	c.Assert(statusInfo.Data, gc.HasLen, 0)
    83  	c.Assert(statusInfo.Since, gc.NotNil)
    84  
    85  	// Ensure that unit has not changed.
    86  	unitStatusInfo, err = s.wordpressUnit.Status()
    87  	c.Assert(err, jc.ErrorIsNil)
    88  	c.Assert(unitStatusInfo.Status, gc.Equals, state.StatusUnknown)
    89  	c.Assert(unitStatusInfo.Message, gc.Equals, "Waiting for agent initialization to finish")
    90  	c.Assert(unitStatusInfo.Data, gc.HasLen, 0)
    91  }
    92  
    93  func (s *unitSuite) TestSetUnitStatus(c *gc.C) {
    94  	statusInfo, err := s.wordpressUnit.Status()
    95  	c.Assert(err, jc.ErrorIsNil)
    96  	c.Assert(statusInfo.Status, gc.Equals, state.StatusUnknown)
    97  	c.Assert(statusInfo.Message, gc.Equals, "Waiting for agent initialization to finish")
    98  	c.Assert(statusInfo.Data, gc.HasLen, 0)
    99  
   100  	agentStatusInfo, err := s.wordpressUnit.AgentStatus()
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	c.Assert(agentStatusInfo.Status, gc.Equals, state.StatusAllocating)
   103  	c.Assert(agentStatusInfo.Message, gc.Equals, "")
   104  	c.Assert(agentStatusInfo.Data, gc.HasLen, 0)
   105  
   106  	err = s.apiUnit.SetUnitStatus(params.StatusActive, "blah", nil)
   107  	c.Assert(err, jc.ErrorIsNil)
   108  
   109  	statusInfo, err = s.wordpressUnit.Status()
   110  	c.Assert(err, jc.ErrorIsNil)
   111  	c.Assert(statusInfo.Status, gc.Equals, state.StatusActive)
   112  	c.Assert(statusInfo.Message, gc.Equals, "blah")
   113  	c.Assert(statusInfo.Data, gc.HasLen, 0)
   114  	c.Assert(statusInfo.Since, gc.NotNil)
   115  
   116  	// Ensure unit's agent has not changed.
   117  	agentStatusInfo, err = s.wordpressUnit.AgentStatus()
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	c.Assert(agentStatusInfo.Status, gc.Equals, state.StatusAllocating)
   120  	c.Assert(agentStatusInfo.Message, gc.Equals, "")
   121  	c.Assert(agentStatusInfo.Data, gc.HasLen, 0)
   122  }
   123  
   124  func (s *unitSuite) TestSetUnitStatusOldServer(c *gc.C) {
   125  	s.patchNewState(c, uniter.NewStateV1)
   126  
   127  	err := s.apiUnit.SetUnitStatus(params.StatusActive, "blah", nil)
   128  	c.Assert(err, jc.Satisfies, errors.IsNotImplemented)
   129  	c.Assert(err.Error(), gc.Equals, "SetUnitStatus not implemented")
   130  }
   131  
   132  func (s *unitSuite) TestSetAgentStatusOldServer(c *gc.C) {
   133  	s.patchNewState(c, uniter.NewStateV1)
   134  
   135  	statusInfo, err := s.wordpressUnit.Status()
   136  	c.Assert(err, jc.ErrorIsNil)
   137  	c.Assert(statusInfo.Status, gc.Equals, state.StatusUnknown)
   138  	c.Assert(statusInfo.Message, gc.Equals, "Waiting for agent initialization to finish")
   139  	c.Assert(statusInfo.Data, gc.HasLen, 0)
   140  
   141  	err = s.apiUnit.SetAgentStatus(params.StatusIdle, "blah", nil)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  
   144  	statusInfo, err = s.wordpressUnit.AgentStatus()
   145  	c.Assert(err, jc.ErrorIsNil)
   146  	c.Assert(statusInfo.Status, gc.Equals, state.StatusIdle)
   147  	c.Assert(statusInfo.Message, gc.Equals, "blah")
   148  	c.Assert(statusInfo.Data, gc.HasLen, 0)
   149  }
   150  
   151  func (s *unitSuite) TestUnitStatus(c *gc.C) {
   152  	err := s.wordpressUnit.SetStatus(state.StatusMaintenance, "blah", nil)
   153  	c.Assert(err, jc.ErrorIsNil)
   154  
   155  	result, err := s.apiUnit.UnitStatus()
   156  	c.Assert(err, jc.ErrorIsNil)
   157  	c.Assert(result.Since, gc.NotNil)
   158  	result.Since = nil
   159  	c.Assert(result, gc.DeepEquals, params.StatusResult{
   160  		Status: params.StatusMaintenance,
   161  		Info:   "blah",
   162  		Data:   map[string]interface{}{},
   163  	})
   164  }
   165  
   166  func (s *unitSuite) TestEnsureDead(c *gc.C) {
   167  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   168  
   169  	err := s.apiUnit.EnsureDead()
   170  	c.Assert(err, jc.ErrorIsNil)
   171  
   172  	err = s.wordpressUnit.Refresh()
   173  	c.Assert(err, jc.ErrorIsNil)
   174  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead)
   175  
   176  	err = s.apiUnit.EnsureDead()
   177  	c.Assert(err, jc.ErrorIsNil)
   178  	err = s.wordpressUnit.Refresh()
   179  	c.Assert(err, jc.ErrorIsNil)
   180  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead)
   181  
   182  	err = s.wordpressUnit.Remove()
   183  	c.Assert(err, jc.ErrorIsNil)
   184  	err = s.wordpressUnit.Refresh()
   185  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   186  
   187  	err = s.apiUnit.EnsureDead()
   188  	c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" not found`)
   189  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   190  }
   191  
   192  func (s *unitSuite) TestDestroy(c *gc.C) {
   193  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   194  
   195  	err := s.apiUnit.Destroy()
   196  	c.Assert(err, jc.ErrorIsNil)
   197  
   198  	err = s.wordpressUnit.Refresh()
   199  	c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" not found`)
   200  }
   201  
   202  func (s *unitSuite) TestDestroyAllSubordinates(c *gc.C) {
   203  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   204  
   205  	// Call without subordinates - no change.
   206  	err := s.apiUnit.DestroyAllSubordinates()
   207  	c.Assert(err, jc.ErrorIsNil)
   208  
   209  	// Add a couple of subordinates and try again.
   210  	_, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   211  	_, _, monitoringSub := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit)
   212  	c.Assert(loggingSub.Life(), gc.Equals, state.Alive)
   213  	c.Assert(monitoringSub.Life(), gc.Equals, state.Alive)
   214  
   215  	err = s.apiUnit.DestroyAllSubordinates()
   216  	c.Assert(err, jc.ErrorIsNil)
   217  
   218  	// Verify they got destroyed.
   219  	err = loggingSub.Refresh()
   220  	c.Assert(err, jc.ErrorIsNil)
   221  	c.Assert(loggingSub.Life(), gc.Equals, state.Dying)
   222  	err = monitoringSub.Refresh()
   223  	c.Assert(err, jc.ErrorIsNil)
   224  	c.Assert(monitoringSub.Life(), gc.Equals, state.Dying)
   225  }
   226  
   227  func (s *unitSuite) TestRefresh(c *gc.C) {
   228  	c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive)
   229  
   230  	err := s.apiUnit.EnsureDead()
   231  	c.Assert(err, jc.ErrorIsNil)
   232  	c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive)
   233  
   234  	err = s.apiUnit.Refresh()
   235  	c.Assert(err, jc.ErrorIsNil)
   236  	c.Assert(s.apiUnit.Life(), gc.Equals, params.Dead)
   237  }
   238  
   239  func (s *unitSuite) TestWatch(c *gc.C) {
   240  	c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive)
   241  
   242  	w, err := s.apiUnit.Watch()
   243  	c.Assert(err, jc.ErrorIsNil)
   244  	defer statetesting.AssertStop(c, w)
   245  	wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w)
   246  
   247  	// Initial event.
   248  	wc.AssertOneChange()
   249  
   250  	// Change something other than the lifecycle and make sure it's
   251  	// not detected.
   252  	err = s.apiUnit.SetAgentStatus(params.StatusIdle, "not really", nil)
   253  	c.Assert(err, jc.ErrorIsNil)
   254  	wc.AssertNoChange()
   255  
   256  	// Make the unit dead and check it's detected.
   257  	err = s.apiUnit.EnsureDead()
   258  	c.Assert(err, jc.ErrorIsNil)
   259  	wc.AssertOneChange()
   260  
   261  	statetesting.AssertStop(c, w)
   262  	wc.AssertClosed()
   263  }
   264  
   265  func (s *unitSuite) TestResolve(c *gc.C) {
   266  	err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks)
   267  	c.Assert(err, jc.ErrorIsNil)
   268  
   269  	mode, err := s.apiUnit.Resolved()
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	c.Assert(mode, gc.Equals, params.ResolvedRetryHooks)
   272  
   273  	err = s.apiUnit.ClearResolved()
   274  	c.Assert(err, jc.ErrorIsNil)
   275  
   276  	mode, err = s.apiUnit.Resolved()
   277  	c.Assert(err, jc.ErrorIsNil)
   278  	c.Assert(mode, gc.Equals, params.ResolvedNone)
   279  }
   280  
   281  func (s *unitSuite) TestAssignedMachineV0NotImplemented(c *gc.C) {
   282  	s.patchNewState(c, uniter.NewStateV0)
   283  
   284  	_, err := s.apiUnit.AssignedMachine()
   285  	c.Assert(err, jc.Satisfies, errors.IsNotImplemented)
   286  	c.Assert(err.Error(), gc.Equals, "unit.AssignedMachine() (need V1+) not implemented")
   287  }
   288  
   289  func (s *unitSuite) TestAssignedMachineV1(c *gc.C) {
   290  	s.patchNewState(c, uniter.NewStateV1)
   291  
   292  	machineTag, err := s.apiUnit.AssignedMachine()
   293  	c.Assert(err, jc.ErrorIsNil)
   294  	c.Assert(machineTag, gc.Equals, s.wordpressMachine.Tag())
   295  }
   296  
   297  func (s *unitSuite) TestIsPrincipal(c *gc.C) {
   298  	ok, err := s.apiUnit.IsPrincipal()
   299  	c.Assert(err, jc.ErrorIsNil)
   300  	c.Assert(ok, jc.IsTrue)
   301  }
   302  
   303  func (s *unitSuite) TestHasSubordinates(c *gc.C) {
   304  	found, err := s.apiUnit.HasSubordinates()
   305  	c.Assert(err, jc.ErrorIsNil)
   306  	c.Assert(found, jc.IsFalse)
   307  
   308  	// Add a couple of subordinates and try again.
   309  	s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   310  	s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit)
   311  
   312  	found, err = s.apiUnit.HasSubordinates()
   313  	c.Assert(err, jc.ErrorIsNil)
   314  	c.Assert(found, jc.IsTrue)
   315  }
   316  
   317  func (s *unitSuite) TestPublicAddress(c *gc.C) {
   318  	address, err := s.apiUnit.PublicAddress()
   319  	c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no public address set`)
   320  
   321  	err = s.wordpressMachine.SetProviderAddresses(
   322  		network.NewScopedAddress("1.2.3.4", network.ScopePublic),
   323  	)
   324  	c.Assert(err, jc.ErrorIsNil)
   325  
   326  	address, err = s.apiUnit.PublicAddress()
   327  	c.Assert(err, jc.ErrorIsNil)
   328  	c.Assert(address, gc.Equals, "1.2.3.4")
   329  }
   330  
   331  func (s *unitSuite) TestPrivateAddress(c *gc.C) {
   332  	address, err := s.apiUnit.PrivateAddress()
   333  	c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no private address set`)
   334  
   335  	err = s.wordpressMachine.SetProviderAddresses(
   336  		network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal),
   337  	)
   338  	c.Assert(err, jc.ErrorIsNil)
   339  
   340  	address, err = s.apiUnit.PrivateAddress()
   341  	c.Assert(err, jc.ErrorIsNil)
   342  	c.Assert(address, gc.Equals, "1.2.3.4")
   343  }
   344  
   345  func (s *unitSuite) TestAvailabilityZone(c *gc.C) {
   346  	uniter.PatchUnitResponse(s, s.apiUnit, "AvailabilityZone",
   347  		func(result interface{}) error {
   348  			if results, ok := result.(*params.StringResults); ok {
   349  				results.Results = []params.StringResult{{
   350  					Result: "a-zone",
   351  				}}
   352  			}
   353  			return nil
   354  		},
   355  	)
   356  
   357  	zone, err := s.apiUnit.AvailabilityZone()
   358  	c.Assert(err, jc.ErrorIsNil)
   359  
   360  	c.Check(zone, gc.Equals, "a-zone")
   361  }
   362  
   363  func (s *unitSuite) TestOpenClosePortRanges(c *gc.C) {
   364  	ports, err := s.wordpressUnit.OpenedPorts()
   365  	c.Assert(err, jc.ErrorIsNil)
   366  	c.Assert(ports, gc.HasLen, 0)
   367  
   368  	err = s.apiUnit.OpenPorts("tcp", 1234, 1400)
   369  	c.Assert(err, jc.ErrorIsNil)
   370  	err = s.apiUnit.OpenPorts("udp", 4321, 5000)
   371  	c.Assert(err, jc.ErrorIsNil)
   372  
   373  	ports, err = s.wordpressUnit.OpenedPorts()
   374  	c.Assert(err, jc.ErrorIsNil)
   375  	// OpenedPorts returns a sorted slice.
   376  	c.Assert(ports, gc.DeepEquals, []network.PortRange{
   377  		{Protocol: "tcp", FromPort: 1234, ToPort: 1400},
   378  		{Protocol: "udp", FromPort: 4321, ToPort: 5000},
   379  	})
   380  
   381  	err = s.apiUnit.ClosePorts("udp", 4321, 5000)
   382  	c.Assert(err, jc.ErrorIsNil)
   383  
   384  	ports, err = s.wordpressUnit.OpenedPorts()
   385  	c.Assert(err, jc.ErrorIsNil)
   386  	// OpenedPorts returns a sorted slice.
   387  	c.Assert(ports, gc.DeepEquals, []network.PortRange{
   388  		{Protocol: "tcp", FromPort: 1234, ToPort: 1400},
   389  	})
   390  
   391  	err = s.apiUnit.ClosePorts("tcp", 1234, 1400)
   392  	c.Assert(err, jc.ErrorIsNil)
   393  
   394  	ports, err = s.wordpressUnit.OpenedPorts()
   395  	c.Assert(err, jc.ErrorIsNil)
   396  	c.Assert(ports, gc.HasLen, 0)
   397  }
   398  
   399  func (s *unitSuite) TestOpenClosePort(c *gc.C) {
   400  	ports, err := s.wordpressUnit.OpenedPorts()
   401  	c.Assert(err, jc.ErrorIsNil)
   402  	c.Assert(ports, gc.HasLen, 0)
   403  
   404  	err = s.apiUnit.OpenPort("tcp", 1234)
   405  	c.Assert(err, jc.ErrorIsNil)
   406  	err = s.apiUnit.OpenPort("tcp", 4321)
   407  	c.Assert(err, jc.ErrorIsNil)
   408  
   409  	ports, err = s.wordpressUnit.OpenedPorts()
   410  	c.Assert(err, jc.ErrorIsNil)
   411  	// OpenedPorts returns a sorted slice.
   412  	c.Assert(ports, gc.DeepEquals, []network.PortRange{
   413  		{Protocol: "tcp", FromPort: 1234, ToPort: 1234},
   414  		{Protocol: "tcp", FromPort: 4321, ToPort: 4321},
   415  	})
   416  
   417  	err = s.apiUnit.ClosePort("tcp", 4321)
   418  	c.Assert(err, jc.ErrorIsNil)
   419  
   420  	ports, err = s.wordpressUnit.OpenedPorts()
   421  	c.Assert(err, jc.ErrorIsNil)
   422  	// OpenedPorts returns a sorted slice.
   423  	c.Assert(ports, gc.DeepEquals, []network.PortRange{
   424  		{Protocol: "tcp", FromPort: 1234, ToPort: 1234},
   425  	})
   426  
   427  	err = s.apiUnit.ClosePort("tcp", 1234)
   428  	c.Assert(err, jc.ErrorIsNil)
   429  
   430  	ports, err = s.wordpressUnit.OpenedPorts()
   431  	c.Assert(err, jc.ErrorIsNil)
   432  	c.Assert(ports, gc.HasLen, 0)
   433  }
   434  
   435  func (s *unitSuite) TestGetSetCharmURL(c *gc.C) {
   436  	// No charm URL set yet.
   437  	curl, ok := s.wordpressUnit.CharmURL()
   438  	c.Assert(curl, gc.IsNil)
   439  	c.Assert(ok, jc.IsFalse)
   440  
   441  	// Now check the same through the API.
   442  	_, err := s.apiUnit.CharmURL()
   443  	c.Assert(err, gc.Equals, uniter.ErrNoCharmURLSet)
   444  
   445  	err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL())
   446  	c.Assert(err, jc.ErrorIsNil)
   447  
   448  	curl, err = s.apiUnit.CharmURL()
   449  	c.Assert(err, jc.ErrorIsNil)
   450  	c.Assert(curl, gc.NotNil)
   451  	c.Assert(curl.String(), gc.Equals, s.wordpressCharm.String())
   452  }
   453  
   454  func (s *unitSuite) TestConfigSettings(c *gc.C) {
   455  	// Make sure ConfigSettings returns an error when
   456  	// no charm URL is set, as its state counterpart does.
   457  	settings, err := s.apiUnit.ConfigSettings()
   458  	c.Assert(err, gc.ErrorMatches, "unit charm not set")
   459  
   460  	// Now set the charm and try again.
   461  	err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL())
   462  	c.Assert(err, jc.ErrorIsNil)
   463  
   464  	settings, err = s.apiUnit.ConfigSettings()
   465  	c.Assert(err, jc.ErrorIsNil)
   466  	c.Assert(settings, gc.DeepEquals, charm.Settings{
   467  		"blog-title": "My Title",
   468  	})
   469  
   470  	// Update the config and check we get the changes on the next call.
   471  	err = s.wordpressService.UpdateConfigSettings(charm.Settings{
   472  		"blog-title": "superhero paparazzi",
   473  	})
   474  	c.Assert(err, jc.ErrorIsNil)
   475  
   476  	settings, err = s.apiUnit.ConfigSettings()
   477  	c.Assert(err, jc.ErrorIsNil)
   478  	c.Assert(settings, gc.DeepEquals, charm.Settings{
   479  		"blog-title": "superhero paparazzi",
   480  	})
   481  }
   482  
   483  func (s *unitSuite) TestWatchConfigSettings(c *gc.C) {
   484  	// Make sure WatchConfigSettings returns an error when
   485  	// no charm URL is set, as its state counterpart does.
   486  	w, err := s.apiUnit.WatchConfigSettings()
   487  	c.Assert(err, gc.ErrorMatches, "unit charm not set")
   488  
   489  	// Now set the charm and try again.
   490  	err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL())
   491  	c.Assert(err, jc.ErrorIsNil)
   492  
   493  	w, err = s.apiUnit.WatchConfigSettings()
   494  	defer statetesting.AssertStop(c, w)
   495  	wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w)
   496  
   497  	// Initial event.
   498  	wc.AssertOneChange()
   499  
   500  	// Update config a couple of times, check a single event.
   501  	err = s.wordpressService.UpdateConfigSettings(charm.Settings{
   502  		"blog-title": "superhero paparazzi",
   503  	})
   504  	c.Assert(err, jc.ErrorIsNil)
   505  	err = s.wordpressService.UpdateConfigSettings(charm.Settings{
   506  		"blog-title": "sauceror central",
   507  	})
   508  	c.Assert(err, jc.ErrorIsNil)
   509  	wc.AssertOneChange()
   510  
   511  	// Non-change is not reported.
   512  	err = s.wordpressService.UpdateConfigSettings(charm.Settings{
   513  		"blog-title": "sauceror central",
   514  	})
   515  	c.Assert(err, jc.ErrorIsNil)
   516  	wc.AssertNoChange()
   517  
   518  	// NOTE: This test is not as exhaustive as the one in state,
   519  	// because the watcher is already tested there. Here we just
   520  	// ensure we get the events when we expect them and don't get
   521  	// them when they're not expected.
   522  
   523  	statetesting.AssertStop(c, w)
   524  	wc.AssertClosed()
   525  }
   526  
   527  func (s *unitSuite) TestWatchActionNotifications(c *gc.C) {
   528  	w, err := s.apiUnit.WatchActionNotifications()
   529  	c.Assert(err, jc.ErrorIsNil)
   530  
   531  	defer statetesting.AssertStop(c, w)
   532  	wc := statetesting.NewStringsWatcherC(c, s.BackingState, w)
   533  
   534  	// Initial event.
   535  	wc.AssertChange()
   536  
   537  	// Add a couple of actions and make sure the changes are detected.
   538  	action, err := s.wordpressUnit.AddAction("fakeaction", map[string]interface{}{
   539  		"outfile": "foo.txt",
   540  	})
   541  	c.Assert(err, jc.ErrorIsNil)
   542  	wc.AssertChange(action.Id())
   543  
   544  	action, err = s.wordpressUnit.AddAction("fakeaction", map[string]interface{}{
   545  		"outfile": "foo.bz2",
   546  		"compression": map[string]interface{}{
   547  			"kind":    "bzip",
   548  			"quality": float64(5.0),
   549  		},
   550  	})
   551  	c.Assert(err, jc.ErrorIsNil)
   552  	wc.AssertChange(action.Id())
   553  
   554  	statetesting.AssertStop(c, w)
   555  	wc.AssertClosed()
   556  }
   557  
   558  func (s *unitSuite) TestWatchActionNotificationsError(c *gc.C) {
   559  	uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications",
   560  		func(result interface{}) error {
   561  			return fmt.Errorf("Test error")
   562  		},
   563  	)
   564  
   565  	_, err := s.apiUnit.WatchActionNotifications()
   566  	c.Assert(err.Error(), gc.Equals, "Test error")
   567  }
   568  
   569  func (s *unitSuite) TestWatchActionNotificationsErrorResults(c *gc.C) {
   570  	uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications",
   571  		func(results interface{}) error {
   572  			if results, ok := results.(*params.StringsWatchResults); ok {
   573  				results.Results = make([]params.StringsWatchResult, 1)
   574  				results.Results[0] = params.StringsWatchResult{
   575  					Error: &params.Error{
   576  						Message: "An error in the watch result.",
   577  						Code:    params.CodeNotAssigned,
   578  					},
   579  				}
   580  			}
   581  			return nil
   582  		},
   583  	)
   584  
   585  	_, err := s.apiUnit.WatchActionNotifications()
   586  	c.Assert(err.Error(), gc.Equals, "An error in the watch result.")
   587  }
   588  
   589  func (s *unitSuite) TestWatchActionNotificationsNoResults(c *gc.C) {
   590  	uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications",
   591  		func(results interface{}) error {
   592  			return nil
   593  		},
   594  	)
   595  
   596  	_, err := s.apiUnit.WatchActionNotifications()
   597  	c.Assert(err.Error(), gc.Equals, "expected 1 result, got 0")
   598  }
   599  
   600  func (s *unitSuite) TestWatchActionNotificationsMoreResults(c *gc.C) {
   601  	uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications",
   602  		func(results interface{}) error {
   603  			if results, ok := results.(*params.StringsWatchResults); ok {
   604  				results.Results = make([]params.StringsWatchResult, 2)
   605  			}
   606  			return nil
   607  		},
   608  	)
   609  
   610  	_, err := s.apiUnit.WatchActionNotifications()
   611  	c.Assert(err.Error(), gc.Equals, "expected 1 result, got 2")
   612  }
   613  
   614  func (s *unitSuite) TestServiceNameAndTag(c *gc.C) {
   615  	c.Assert(s.apiUnit.ServiceName(), gc.Equals, s.wordpressService.Name())
   616  	c.Assert(s.apiUnit.ServiceTag(), gc.Equals, s.wordpressService.Tag())
   617  }
   618  
   619  func (s *unitSuite) TestJoinedRelations(c *gc.C) {
   620  	joinedRelations, err := s.apiUnit.JoinedRelations()
   621  	c.Assert(err, jc.ErrorIsNil)
   622  	c.Assert(joinedRelations, gc.HasLen, 0)
   623  
   624  	rel1, _, _ := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit)
   625  	joinedRelations, err = s.apiUnit.JoinedRelations()
   626  	c.Assert(err, jc.ErrorIsNil)
   627  	c.Assert(joinedRelations, gc.DeepEquals, []names.RelationTag{
   628  		rel1.Tag().(names.RelationTag),
   629  	})
   630  
   631  	rel2, _, _ := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   632  	joinedRelations, err = s.apiUnit.JoinedRelations()
   633  	c.Assert(err, jc.ErrorIsNil)
   634  	c.Assert(joinedRelations, jc.SameContents, []names.RelationTag{
   635  		rel1.Tag().(names.RelationTag),
   636  		rel2.Tag().(names.RelationTag),
   637  	})
   638  }
   639  
   640  func (s *unitSuite) TestWatchAddresses(c *gc.C) {
   641  	w, err := s.apiUnit.WatchAddresses()
   642  	defer statetesting.AssertStop(c, w)
   643  	wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w)
   644  
   645  	// Initial event.
   646  	wc.AssertOneChange()
   647  
   648  	// Update config a couple of times, check a single event.
   649  	err = s.wordpressMachine.SetProviderAddresses(network.NewAddress("0.1.2.3"))
   650  	c.Assert(err, jc.ErrorIsNil)
   651  	err = s.wordpressMachine.SetProviderAddresses(network.NewAddress("0.1.2.4"))
   652  	c.Assert(err, jc.ErrorIsNil)
   653  	wc.AssertOneChange()
   654  
   655  	// Non-change is not reported.
   656  	err = s.wordpressMachine.SetProviderAddresses(network.NewAddress("0.1.2.4"))
   657  	c.Assert(err, jc.ErrorIsNil)
   658  	wc.AssertNoChange()
   659  
   660  	// Change is reported for machine addresses.
   661  	err = s.wordpressMachine.SetMachineAddresses(network.NewAddress("0.1.2.5"))
   662  	c.Assert(err, jc.ErrorIsNil)
   663  	wc.AssertOneChange()
   664  
   665  	// Set machine addresses to empty is reported.
   666  	err = s.wordpressMachine.SetMachineAddresses()
   667  	c.Assert(err, jc.ErrorIsNil)
   668  	wc.AssertOneChange()
   669  
   670  	// NOTE: This test is not as exhaustive as the one in state,
   671  	// because the watcher is already tested there. Here we just
   672  	// ensure we get the events when we expect them and don't get
   673  	// them when they're not expected.
   674  
   675  	statetesting.AssertStop(c, w)
   676  	wc.AssertClosed()
   677  }
   678  
   679  func (s *unitSuite) TestWatchAddressesErrors(c *gc.C) {
   680  	err := s.wordpressUnit.UnassignFromMachine()
   681  	c.Assert(err, jc.ErrorIsNil)
   682  	_, err = s.apiUnit.WatchAddresses()
   683  	c.Assert(err, jc.Satisfies, params.IsCodeNotAssigned)
   684  }
   685  
   686  func (s *unitSuite) TestAddMetrics(c *gc.C) {
   687  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   688  		func(results interface{}) error {
   689  			result := results.(*params.ErrorResults)
   690  			result.Results = make([]params.ErrorResult, 1)
   691  			return nil
   692  		},
   693  	)
   694  	metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}}
   695  	err := s.apiUnit.AddMetrics(metrics)
   696  	c.Assert(err, jc.ErrorIsNil)
   697  }
   698  
   699  func (s *unitSuite) TestAddMetricsError(c *gc.C) {
   700  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   701  		func(results interface{}) error {
   702  			result := results.(*params.ErrorResults)
   703  			result.Results = make([]params.ErrorResult, 1)
   704  			return fmt.Errorf("test error")
   705  		},
   706  	)
   707  	metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}}
   708  	err := s.apiUnit.AddMetrics(metrics)
   709  	c.Assert(err, gc.ErrorMatches, "unable to add metric: test error")
   710  }
   711  
   712  func (s *unitSuite) TestAddMetricsResultError(c *gc.C) {
   713  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   714  		func(results interface{}) error {
   715  			result := results.(*params.ErrorResults)
   716  			result.Results = make([]params.ErrorResult, 1)
   717  			result.Results[0].Error = &params.Error{
   718  				Message: "error adding metrics",
   719  				Code:    params.CodeNotAssigned,
   720  			}
   721  			return nil
   722  		},
   723  	)
   724  	metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}}
   725  	err := s.apiUnit.AddMetrics(metrics)
   726  	c.Assert(err, gc.ErrorMatches, "error adding metrics")
   727  }
   728  
   729  func (s *unitSuite) TestMeterStatus(c *gc.C) {
   730  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   731  		func(results interface{}) error {
   732  			result := results.(*params.MeterStatusResults)
   733  			result.Results = make([]params.MeterStatusResult, 1)
   734  			result.Results[0].Code = "GREEN"
   735  			result.Results[0].Info = "All ok."
   736  			return nil
   737  		},
   738  	)
   739  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   740  	c.Assert(err, jc.ErrorIsNil)
   741  	c.Assert(statusCode, gc.Equals, "GREEN")
   742  	c.Assert(statusInfo, gc.Equals, "All ok.")
   743  }
   744  
   745  func (s *unitSuite) TestMeterStatusError(c *gc.C) {
   746  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   747  		func(results interface{}) error {
   748  			result := results.(*params.MeterStatusResults)
   749  			result.Results = make([]params.MeterStatusResult, 1)
   750  			return fmt.Errorf("boo")
   751  		},
   752  	)
   753  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   754  	c.Assert(err, gc.ErrorMatches, "boo")
   755  	c.Assert(statusCode, gc.Equals, "")
   756  	c.Assert(statusInfo, gc.Equals, "")
   757  }
   758  
   759  func (s *unitSuite) TestMeterStatusResultError(c *gc.C) {
   760  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   761  		func(results interface{}) error {
   762  			result := results.(*params.MeterStatusResults)
   763  			result.Results = make([]params.MeterStatusResult, 1)
   764  			result.Results[0].Error = &params.Error{
   765  				Message: "error getting meter status",
   766  				Code:    params.CodeNotAssigned,
   767  			}
   768  			return nil
   769  		},
   770  	)
   771  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   772  	c.Assert(err, gc.ErrorMatches, "error getting meter status")
   773  	c.Assert(statusCode, gc.Equals, "")
   774  	c.Assert(statusInfo, gc.Equals, "")
   775  }
   776  
   777  func (s *unitSuite) TestWatchMeterStatus(c *gc.C) {
   778  	w, err := s.apiUnit.WatchMeterStatus()
   779  	defer statetesting.AssertStop(c, w)
   780  	wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w)
   781  
   782  	// Initial event.
   783  	wc.AssertOneChange()
   784  
   785  	err = s.wordpressUnit.SetMeterStatus("GREEN", "ok")
   786  	c.Assert(err, jc.ErrorIsNil)
   787  	err = s.wordpressUnit.SetMeterStatus("AMBER", "ok")
   788  	c.Assert(err, jc.ErrorIsNil)
   789  	wc.AssertOneChange()
   790  
   791  	// Non-change is not reported.
   792  	err = s.wordpressUnit.SetMeterStatus("AMBER", "ok")
   793  	c.Assert(err, jc.ErrorIsNil)
   794  	wc.AssertNoChange()
   795  
   796  	mm, err := s.State.MetricsManager()
   797  	c.Assert(err, jc.ErrorIsNil)
   798  	err = mm.SetLastSuccessfulSend(time.Now())
   799  	c.Assert(err, jc.ErrorIsNil)
   800  	for i := 0; i < 3; i++ {
   801  		err := mm.IncrementConsecutiveErrors()
   802  		c.Assert(err, jc.ErrorIsNil)
   803  	}
   804  	status := mm.MeterStatus()
   805  	c.Assert(status.Code, gc.Equals, state.MeterAmber) // Confirm meter status has changed
   806  	wc.AssertOneChange()
   807  
   808  	statetesting.AssertStop(c, w)
   809  	wc.AssertClosed()
   810  }
   811  
   812  func (s *unitSuite) patchNewState(
   813  	c *gc.C,
   814  	patchFunc func(_ base.APICaller, _ names.UnitTag) *uniter.State,
   815  ) {
   816  	s.uniterSuite.patchNewState(c, patchFunc)
   817  	var err error
   818  	s.apiUnit, err = s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag))
   819  	c.Assert(err, jc.ErrorIsNil)
   820  }
   821  
   822  type unitMetricBatchesSuite struct {
   823  	testing.JujuConnSuite
   824  
   825  	st      api.Connection
   826  	uniter  *uniter.State
   827  	apiUnit *uniter.Unit
   828  	charm   *state.Charm
   829  }
   830  
   831  var _ = gc.Suite(&unitMetricBatchesSuite{})
   832  
   833  func (s *unitMetricBatchesSuite) SetUpTest(c *gc.C) {
   834  	s.JujuConnSuite.SetUpTest(c)
   835  
   836  	s.charm = s.Factory.MakeCharm(c, &jujufactory.CharmParams{
   837  		Name: "metered",
   838  		URL:  "cs:quantal/metered",
   839  	})
   840  	service := s.Factory.MakeService(c, &jujufactory.ServiceParams{
   841  		Charm: s.charm,
   842  	})
   843  	unit := s.Factory.MakeUnit(c, &jujufactory.UnitParams{
   844  		Service:     service,
   845  		SetCharmURL: true,
   846  	})
   847  
   848  	password, err := utils.RandomPassword()
   849  	c.Assert(err, jc.ErrorIsNil)
   850  	err = unit.SetPassword(password)
   851  	c.Assert(err, jc.ErrorIsNil)
   852  	s.st = s.OpenAPIAs(c, unit.Tag(), password)
   853  
   854  	// Create the uniter API facade.
   855  	s.uniter, err = s.st.Uniter()
   856  	c.Assert(err, jc.ErrorIsNil)
   857  	c.Assert(s.uniter, gc.NotNil)
   858  
   859  	s.apiUnit, err = s.uniter.Unit(unit.Tag().(names.UnitTag))
   860  	c.Assert(err, jc.ErrorIsNil)
   861  }
   862  
   863  func (s *unitMetricBatchesSuite) TestSendMetricBatchPatch(c *gc.C) {
   864  	metrics := []params.Metric{{"pings", "5", time.Now().UTC()}}
   865  	uuid := utils.MustNewUUID().String()
   866  	batch := params.MetricBatch{
   867  		UUID:     uuid,
   868  		CharmURL: s.charm.URL().String(),
   869  		Created:  time.Now(),
   870  		Metrics:  metrics,
   871  	}
   872  
   873  	var called bool
   874  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches",
   875  		func(response interface{}) error {
   876  			called = true
   877  			result := response.(*params.ErrorResults)
   878  			result.Results = make([]params.ErrorResult, 1)
   879  			return nil
   880  		})
   881  
   882  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
   883  	c.Assert(err, jc.ErrorIsNil)
   884  	c.Assert(results, gc.HasLen, 1)
   885  	c.Assert(results[batch.UUID], gc.IsNil)
   886  	c.Assert(called, jc.IsTrue)
   887  }
   888  
   889  func (s *unitMetricBatchesSuite) TestSendMetricBatchFail(c *gc.C) {
   890  	var called bool
   891  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches",
   892  		func(response interface{}) error {
   893  			called = true
   894  			result := response.(*params.ErrorResults)
   895  			result.Results = make([]params.ErrorResult, 1)
   896  			result.Results[0].Error = common.ServerError(common.ErrPerm)
   897  			return nil
   898  		})
   899  	metrics := []params.Metric{{"pings", "5", time.Now().UTC()}}
   900  	uuid := utils.MustNewUUID().String()
   901  	batch := params.MetricBatch{
   902  		UUID:     uuid,
   903  		CharmURL: s.charm.URL().String(),
   904  		Created:  time.Now(),
   905  		Metrics:  metrics,
   906  	}
   907  
   908  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
   909  	c.Assert(err, jc.ErrorIsNil)
   910  	c.Assert(results, gc.HasLen, 1)
   911  	c.Assert(results[batch.UUID], gc.ErrorMatches, "permission denied")
   912  	c.Assert(called, jc.IsTrue)
   913  }
   914  
   915  func (s *unitMetricBatchesSuite) TestSendMetricBatchNotImplemented(c *gc.C) {
   916  	var called bool
   917  	uniter.PatchUnitFacadeCall(s, s.apiUnit, func(request string, args, response interface{}) error {
   918  		switch request {
   919  		case "AddMetricBatches":
   920  			result := response.(*params.ErrorResults)
   921  			result.Results = make([]params.ErrorResult, 1)
   922  			return &params.Error{"not implemented", params.CodeNotImplemented}
   923  		case "AddMetrics":
   924  			called = true
   925  			result := response.(*params.ErrorResults)
   926  			result.Results = make([]params.ErrorResult, 1)
   927  			return nil
   928  		default:
   929  			panic(fmt.Errorf("unexpected request %q received", request))
   930  		}
   931  	})
   932  
   933  	metrics := []params.Metric{{"pings", "5", time.Now().UTC()}}
   934  	uuid := utils.MustNewUUID().String()
   935  	batch := params.MetricBatch{
   936  		UUID:     uuid,
   937  		CharmURL: s.charm.URL().String(),
   938  		Created:  time.Now(),
   939  		Metrics:  metrics,
   940  	}
   941  
   942  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
   943  	c.Assert(err, jc.ErrorIsNil)
   944  	c.Assert(called, jc.IsTrue)
   945  	c.Assert(results, gc.HasLen, 1)
   946  	c.Assert(results[batch.UUID], gc.IsNil)
   947  }
   948  
   949  func (s *unitMetricBatchesSuite) TestSendMetricBatch(c *gc.C) {
   950  	uuid := utils.MustNewUUID().String()
   951  	now := time.Now().Round(time.Second).UTC()
   952  	metrics := []params.Metric{{"pings", "5", now}}
   953  	batch := params.MetricBatch{
   954  		UUID:     uuid,
   955  		CharmURL: s.charm.URL().String(),
   956  		Created:  now,
   957  		Metrics:  metrics,
   958  	}
   959  
   960  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
   961  	c.Assert(err, jc.ErrorIsNil)
   962  	c.Assert(results, gc.HasLen, 1)
   963  	c.Assert(results[batch.UUID], gc.IsNil)
   964  
   965  	batches, err := s.State.MetricBatches()
   966  	c.Assert(err, gc.IsNil)
   967  	c.Assert(batches, gc.HasLen, 1)
   968  	c.Assert(batches[0].UUID(), gc.Equals, uuid)
   969  	c.Assert(batches[0].Sent(), jc.IsFalse)
   970  	c.Assert(batches[0].CharmURL(), gc.Equals, s.charm.URL().String())
   971  	c.Assert(batches[0].Metrics(), gc.HasLen, 1)
   972  	c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings")
   973  	c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings")
   974  	c.Assert(batches[0].Metrics()[0].Value, gc.Equals, "5")
   975  }