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