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