github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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  	// NOTE: This test is not as exhaustive as the one in state,
   661  	// because the watcher is already tested there. Here we just
   662  	// ensure we get the events when we expect them and don't get
   663  	// them when they're not expected.
   664  
   665  	statetesting.AssertStop(c, w)
   666  	wc.AssertClosed()
   667  }
   668  
   669  func (s *unitSuite) TestWatchAddressesErrors(c *gc.C) {
   670  	err := s.wordpressUnit.UnassignFromMachine()
   671  	c.Assert(err, jc.ErrorIsNil)
   672  	_, err = s.apiUnit.WatchAddresses()
   673  	c.Assert(err, jc.Satisfies, params.IsCodeNotAssigned)
   674  }
   675  
   676  func (s *unitSuite) TestAddMetrics(c *gc.C) {
   677  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   678  		func(results interface{}) error {
   679  			result := results.(*params.ErrorResults)
   680  			result.Results = make([]params.ErrorResult, 1)
   681  			return nil
   682  		},
   683  	)
   684  	metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}}
   685  	err := s.apiUnit.AddMetrics(metrics)
   686  	c.Assert(err, jc.ErrorIsNil)
   687  }
   688  
   689  func (s *unitSuite) TestAddMetricsError(c *gc.C) {
   690  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   691  		func(results interface{}) error {
   692  			result := results.(*params.ErrorResults)
   693  			result.Results = make([]params.ErrorResult, 1)
   694  			return fmt.Errorf("test error")
   695  		},
   696  	)
   697  	metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}}
   698  	err := s.apiUnit.AddMetrics(metrics)
   699  	c.Assert(err, gc.ErrorMatches, "unable to add metric: test error")
   700  }
   701  
   702  func (s *unitSuite) TestAddMetricsResultError(c *gc.C) {
   703  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   704  		func(results interface{}) error {
   705  			result := results.(*params.ErrorResults)
   706  			result.Results = make([]params.ErrorResult, 1)
   707  			result.Results[0].Error = &params.Error{
   708  				Message: "error adding metrics",
   709  				Code:    params.CodeNotAssigned,
   710  			}
   711  			return nil
   712  		},
   713  	)
   714  	metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}}
   715  	err := s.apiUnit.AddMetrics(metrics)
   716  	c.Assert(err, gc.ErrorMatches, "error adding metrics")
   717  }
   718  
   719  func (s *unitSuite) TestMeterStatus(c *gc.C) {
   720  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   721  		func(results interface{}) error {
   722  			result := results.(*params.MeterStatusResults)
   723  			result.Results = make([]params.MeterStatusResult, 1)
   724  			result.Results[0].Code = "GREEN"
   725  			result.Results[0].Info = "All ok."
   726  			return nil
   727  		},
   728  	)
   729  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   730  	c.Assert(err, jc.ErrorIsNil)
   731  	c.Assert(statusCode, gc.Equals, "GREEN")
   732  	c.Assert(statusInfo, gc.Equals, "All ok.")
   733  }
   734  
   735  func (s *unitSuite) TestMeterStatusError(c *gc.C) {
   736  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   737  		func(results interface{}) error {
   738  			result := results.(*params.MeterStatusResults)
   739  			result.Results = make([]params.MeterStatusResult, 1)
   740  			return fmt.Errorf("boo")
   741  		},
   742  	)
   743  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   744  	c.Assert(err, gc.ErrorMatches, "boo")
   745  	c.Assert(statusCode, gc.Equals, "")
   746  	c.Assert(statusInfo, gc.Equals, "")
   747  }
   748  
   749  func (s *unitSuite) TestMeterStatusResultError(c *gc.C) {
   750  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   751  		func(results interface{}) error {
   752  			result := results.(*params.MeterStatusResults)
   753  			result.Results = make([]params.MeterStatusResult, 1)
   754  			result.Results[0].Error = &params.Error{
   755  				Message: "error getting meter status",
   756  				Code:    params.CodeNotAssigned,
   757  			}
   758  			return nil
   759  		},
   760  	)
   761  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   762  	c.Assert(err, gc.ErrorMatches, "error getting meter status")
   763  	c.Assert(statusCode, gc.Equals, "")
   764  	c.Assert(statusInfo, gc.Equals, "")
   765  }
   766  
   767  func (s *unitSuite) TestWatchMeterStatus(c *gc.C) {
   768  	w, err := s.apiUnit.WatchMeterStatus()
   769  	defer statetesting.AssertStop(c, w)
   770  	wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w)
   771  
   772  	// Initial event.
   773  	wc.AssertOneChange()
   774  
   775  	err = s.wordpressUnit.SetMeterStatus("GREEN", "ok")
   776  	c.Assert(err, jc.ErrorIsNil)
   777  	err = s.wordpressUnit.SetMeterStatus("AMBER", "ok")
   778  	c.Assert(err, jc.ErrorIsNil)
   779  	wc.AssertOneChange()
   780  
   781  	// Non-change is not reported.
   782  	err = s.wordpressUnit.SetMeterStatus("AMBER", "ok")
   783  	c.Assert(err, jc.ErrorIsNil)
   784  	wc.AssertNoChange()
   785  
   786  	mm, err := s.State.MetricsManager()
   787  	c.Assert(err, jc.ErrorIsNil)
   788  	err = mm.SetLastSuccessfulSend(time.Now())
   789  	c.Assert(err, jc.ErrorIsNil)
   790  	for i := 0; i < 3; i++ {
   791  		err := mm.IncrementConsecutiveErrors()
   792  		c.Assert(err, jc.ErrorIsNil)
   793  	}
   794  	status := mm.MeterStatus()
   795  	c.Assert(status.Code, gc.Equals, state.MeterAmber) // Confirm meter status has changed
   796  	wc.AssertOneChange()
   797  
   798  	statetesting.AssertStop(c, w)
   799  	wc.AssertClosed()
   800  }
   801  
   802  func (s *unitSuite) patchNewState(
   803  	c *gc.C,
   804  	patchFunc func(_ base.APICaller, _ names.UnitTag) *uniter.State,
   805  ) {
   806  	s.uniterSuite.patchNewState(c, patchFunc)
   807  	var err error
   808  	s.apiUnit, err = s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag))
   809  	c.Assert(err, jc.ErrorIsNil)
   810  }
   811  
   812  type unitMetricBatchesSuite struct {
   813  	testing.JujuConnSuite
   814  
   815  	st      *api.State
   816  	uniter  *uniter.State
   817  	apiUnit *uniter.Unit
   818  	charm   *state.Charm
   819  }
   820  
   821  var _ = gc.Suite(&unitMetricBatchesSuite{})
   822  
   823  func (s *unitMetricBatchesSuite) SetUpTest(c *gc.C) {
   824  	s.JujuConnSuite.SetUpTest(c)
   825  
   826  	s.charm = s.Factory.MakeCharm(c, &jujufactory.CharmParams{
   827  		Name: "metered",
   828  		URL:  "cs:quantal/metered",
   829  	})
   830  	service := s.Factory.MakeService(c, &jujufactory.ServiceParams{
   831  		Charm: s.charm,
   832  	})
   833  	unit := s.Factory.MakeUnit(c, &jujufactory.UnitParams{
   834  		Service:     service,
   835  		SetCharmURL: true,
   836  	})
   837  
   838  	password, err := utils.RandomPassword()
   839  	c.Assert(err, jc.ErrorIsNil)
   840  	err = unit.SetPassword(password)
   841  	c.Assert(err, jc.ErrorIsNil)
   842  	s.st = s.OpenAPIAs(c, unit.Tag(), password)
   843  
   844  	// Create the uniter API facade.
   845  	s.uniter, err = s.st.Uniter()
   846  	c.Assert(err, jc.ErrorIsNil)
   847  	c.Assert(s.uniter, gc.NotNil)
   848  
   849  	s.apiUnit, err = s.uniter.Unit(unit.Tag().(names.UnitTag))
   850  	c.Assert(err, jc.ErrorIsNil)
   851  }
   852  
   853  func (s *unitMetricBatchesSuite) TestSendMetricBatchPatch(c *gc.C) {
   854  	metrics := []params.Metric{{"pings", "5", time.Now().UTC()}}
   855  	uuid := utils.MustNewUUID().String()
   856  	batch := params.MetricBatch{
   857  		UUID:     uuid,
   858  		CharmURL: s.charm.URL().String(),
   859  		Created:  time.Now(),
   860  		Metrics:  metrics,
   861  	}
   862  
   863  	var called bool
   864  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches",
   865  		func(response interface{}) error {
   866  			called = true
   867  			result := response.(*params.ErrorResults)
   868  			result.Results = make([]params.ErrorResult, 1)
   869  			return nil
   870  		})
   871  
   872  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
   873  	c.Assert(err, jc.ErrorIsNil)
   874  	c.Assert(results, gc.HasLen, 1)
   875  	c.Assert(results[batch.UUID], gc.IsNil)
   876  	c.Assert(called, jc.IsTrue)
   877  }
   878  
   879  func (s *unitMetricBatchesSuite) TestSendMetricBatchFail(c *gc.C) {
   880  	var called bool
   881  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches",
   882  		func(response interface{}) error {
   883  			called = true
   884  			result := response.(*params.ErrorResults)
   885  			result.Results = make([]params.ErrorResult, 1)
   886  			result.Results[0].Error = common.ServerError(common.ErrPerm)
   887  			return nil
   888  		})
   889  	metrics := []params.Metric{{"pings", "5", time.Now().UTC()}}
   890  	uuid := utils.MustNewUUID().String()
   891  	batch := params.MetricBatch{
   892  		UUID:     uuid,
   893  		CharmURL: s.charm.URL().String(),
   894  		Created:  time.Now(),
   895  		Metrics:  metrics,
   896  	}
   897  
   898  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
   899  	c.Assert(err, jc.ErrorIsNil)
   900  	c.Assert(results, gc.HasLen, 1)
   901  	c.Assert(results[batch.UUID], gc.ErrorMatches, "permission denied")
   902  	c.Assert(called, jc.IsTrue)
   903  }
   904  
   905  func (s *unitMetricBatchesSuite) TestSendMetricBatchNotImplemented(c *gc.C) {
   906  	var called bool
   907  	uniter.PatchUnitFacadeCall(s, s.apiUnit, func(request string, args, response interface{}) error {
   908  		switch request {
   909  		case "AddMetricBatches":
   910  			result := response.(*params.ErrorResults)
   911  			result.Results = make([]params.ErrorResult, 1)
   912  			return &params.Error{"not implemented", params.CodeNotImplemented}
   913  		case "AddMetrics":
   914  			called = true
   915  			result := response.(*params.ErrorResults)
   916  			result.Results = make([]params.ErrorResult, 1)
   917  			return nil
   918  		default:
   919  			panic(fmt.Errorf("unexpected request %q received", request))
   920  		}
   921  	})
   922  
   923  	metrics := []params.Metric{{"pings", "5", time.Now().UTC()}}
   924  	uuid := utils.MustNewUUID().String()
   925  	batch := params.MetricBatch{
   926  		UUID:     uuid,
   927  		CharmURL: s.charm.URL().String(),
   928  		Created:  time.Now(),
   929  		Metrics:  metrics,
   930  	}
   931  
   932  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
   933  	c.Assert(err, jc.ErrorIsNil)
   934  	c.Assert(called, jc.IsTrue)
   935  	c.Assert(results, gc.HasLen, 1)
   936  	c.Assert(results[batch.UUID], gc.IsNil)
   937  }
   938  
   939  func (s *unitMetricBatchesSuite) TestSendMetricBatch(c *gc.C) {
   940  	uuid := utils.MustNewUUID().String()
   941  	now := time.Now().Round(time.Second).UTC()
   942  	metrics := []params.Metric{{"pings", "5", now}}
   943  	batch := params.MetricBatch{
   944  		UUID:     uuid,
   945  		CharmURL: s.charm.URL().String(),
   946  		Created:  now,
   947  		Metrics:  metrics,
   948  	}
   949  
   950  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
   951  	c.Assert(err, jc.ErrorIsNil)
   952  	c.Assert(results, gc.HasLen, 1)
   953  	c.Assert(results[batch.UUID], gc.IsNil)
   954  
   955  	batches, err := s.State.MetricBatches()
   956  	c.Assert(err, gc.IsNil)
   957  	c.Assert(batches, gc.HasLen, 1)
   958  	c.Assert(batches[0].UUID(), gc.Equals, uuid)
   959  	c.Assert(batches[0].Sent(), jc.IsFalse)
   960  	c.Assert(batches[0].CharmURL(), gc.Equals, s.charm.URL().String())
   961  	c.Assert(batches[0].Metrics(), gc.HasLen, 1)
   962  	c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings")
   963  	c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings")
   964  	c.Assert(batches[0].Metrics()[0].Value, gc.Equals, "5")
   965  }