github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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/schema"
    12  	coretesting "github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	"github.com/juju/utils"
    15  	gc "gopkg.in/check.v1"
    16  	"gopkg.in/juju/charm.v6"
    17  	"gopkg.in/juju/environschema.v1"
    18  	"gopkg.in/juju/names.v2"
    19  
    20  	"github.com/juju/juju/api"
    21  	"github.com/juju/juju/api/base/testing"
    22  	"github.com/juju/juju/api/uniter"
    23  	"github.com/juju/juju/apiserver/common"
    24  	"github.com/juju/juju/apiserver/params"
    25  	"github.com/juju/juju/core/application"
    26  	"github.com/juju/juju/core/model"
    27  	corenetwork "github.com/juju/juju/core/network"
    28  	"github.com/juju/juju/core/status"
    29  	"github.com/juju/juju/core/watcher/watchertest"
    30  	jujutesting "github.com/juju/juju/juju/testing"
    31  	"github.com/juju/juju/network"
    32  	"github.com/juju/juju/state"
    33  	jujufactory "github.com/juju/juju/testing/factory"
    34  )
    35  
    36  type unitSuite struct {
    37  	uniterSuite
    38  
    39  	apiUnit *uniter.Unit
    40  }
    41  
    42  var _ = gc.Suite(&unitSuite{})
    43  
    44  func (s *unitSuite) SetUpTest(c *gc.C) {
    45  	s.uniterSuite.SetUpTest(c)
    46  
    47  	var err error
    48  	s.apiUnit, err = s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag))
    49  	c.Assert(err, jc.ErrorIsNil)
    50  }
    51  
    52  func (s *unitSuite) TestRequestReboot(c *gc.C) {
    53  	err := s.apiUnit.RequestReboot()
    54  	c.Assert(err, jc.ErrorIsNil)
    55  	rFlag, err := s.wordpressMachine.GetRebootFlag()
    56  	c.Assert(err, jc.ErrorIsNil)
    57  	c.Assert(rFlag, jc.IsTrue)
    58  }
    59  
    60  func (s *unitSuite) TestUnitAndUnitTag(c *gc.C) {
    61  	apiUnitFoo, err := s.uniter.Unit(names.NewUnitTag("foo/42"))
    62  	c.Assert(err, gc.ErrorMatches, "permission denied")
    63  	c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized)
    64  	c.Assert(apiUnitFoo, gc.IsNil)
    65  
    66  	c.Assert(s.apiUnit.Tag(), gc.Equals, s.wordpressUnit.Tag().(names.UnitTag))
    67  }
    68  
    69  func (s *unitSuite) TestSetAgentStatus(c *gc.C) {
    70  	statusInfo, err := s.wordpressUnit.AgentStatus()
    71  	c.Assert(err, jc.ErrorIsNil)
    72  	c.Assert(statusInfo.Status, gc.Equals, status.Allocating)
    73  	c.Assert(statusInfo.Message, gc.Equals, "")
    74  	c.Assert(statusInfo.Data, gc.HasLen, 0)
    75  
    76  	unitStatusInfo, err := s.wordpressUnit.Status()
    77  	c.Assert(err, jc.ErrorIsNil)
    78  	c.Assert(unitStatusInfo.Status, gc.Equals, status.Waiting)
    79  	c.Assert(unitStatusInfo.Message, gc.Equals, "waiting for machine")
    80  	c.Assert(unitStatusInfo.Data, gc.HasLen, 0)
    81  
    82  	err = s.apiUnit.SetAgentStatus(status.Idle, "blah", nil)
    83  	c.Assert(err, jc.ErrorIsNil)
    84  
    85  	statusInfo, err = s.wordpressUnit.AgentStatus()
    86  	c.Assert(err, jc.ErrorIsNil)
    87  	c.Assert(statusInfo.Status, gc.Equals, status.Idle)
    88  	c.Assert(statusInfo.Message, gc.Equals, "blah")
    89  	c.Assert(statusInfo.Data, gc.HasLen, 0)
    90  	c.Assert(statusInfo.Since, gc.NotNil)
    91  
    92  	// Ensure that unit has not changed.
    93  	unitStatusInfo, err = s.wordpressUnit.Status()
    94  	c.Assert(err, jc.ErrorIsNil)
    95  	c.Assert(unitStatusInfo.Status, gc.Equals, status.Waiting)
    96  	c.Assert(unitStatusInfo.Message, gc.Equals, "waiting for machine")
    97  	c.Assert(unitStatusInfo.Data, gc.HasLen, 0)
    98  }
    99  
   100  func (s *unitSuite) TestSetUnitStatus(c *gc.C) {
   101  	statusInfo, err := s.wordpressUnit.Status()
   102  	c.Assert(err, jc.ErrorIsNil)
   103  	c.Assert(statusInfo.Status, gc.Equals, status.Waiting)
   104  	c.Assert(statusInfo.Message, gc.Equals, "waiting for machine")
   105  	c.Assert(statusInfo.Data, gc.HasLen, 0)
   106  
   107  	agentStatusInfo, err := s.wordpressUnit.AgentStatus()
   108  	c.Assert(err, jc.ErrorIsNil)
   109  	c.Assert(agentStatusInfo.Status, gc.Equals, status.Allocating)
   110  	c.Assert(agentStatusInfo.Message, gc.Equals, "")
   111  	c.Assert(agentStatusInfo.Data, gc.HasLen, 0)
   112  
   113  	err = s.apiUnit.SetUnitStatus(status.Active, "blah", nil)
   114  	c.Assert(err, jc.ErrorIsNil)
   115  
   116  	statusInfo, err = s.wordpressUnit.Status()
   117  	c.Assert(err, jc.ErrorIsNil)
   118  	c.Assert(statusInfo.Status, gc.Equals, status.Active)
   119  	c.Assert(statusInfo.Message, gc.Equals, "blah")
   120  	c.Assert(statusInfo.Data, gc.HasLen, 0)
   121  	c.Assert(statusInfo.Since, gc.NotNil)
   122  
   123  	// Ensure unit's agent has not changed.
   124  	agentStatusInfo, err = s.wordpressUnit.AgentStatus()
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	c.Assert(agentStatusInfo.Status, gc.Equals, status.Allocating)
   127  	c.Assert(agentStatusInfo.Message, gc.Equals, "")
   128  	c.Assert(agentStatusInfo.Data, gc.HasLen, 0)
   129  }
   130  
   131  func (s *unitSuite) TestUnitStatus(c *gc.C) {
   132  	now := time.Now()
   133  	sInfo := status.StatusInfo{
   134  		Status:  status.Maintenance,
   135  		Message: "blah",
   136  		Since:   &now,
   137  	}
   138  	err := s.wordpressUnit.SetStatus(sInfo)
   139  	c.Assert(err, jc.ErrorIsNil)
   140  
   141  	result, err := s.apiUnit.UnitStatus()
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	c.Assert(result.Since, gc.NotNil)
   144  	result.Since = nil
   145  	c.Assert(result, gc.DeepEquals, params.StatusResult{
   146  		Status: status.Maintenance.String(),
   147  		Info:   "blah",
   148  		Data:   map[string]interface{}{},
   149  	})
   150  }
   151  
   152  func (s *unitSuite) TestEnsureDead(c *gc.C) {
   153  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   154  
   155  	err := s.apiUnit.EnsureDead()
   156  	c.Assert(err, jc.ErrorIsNil)
   157  
   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.apiUnit.EnsureDead()
   163  	c.Assert(err, jc.ErrorIsNil)
   164  	err = s.wordpressUnit.Refresh()
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead)
   167  
   168  	err = s.wordpressUnit.Remove()
   169  	c.Assert(err, jc.ErrorIsNil)
   170  	err = s.wordpressUnit.Refresh()
   171  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   172  
   173  	err = s.apiUnit.EnsureDead()
   174  	c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" not found`)
   175  	c.Assert(err, jc.Satisfies, params.IsCodeNotFound)
   176  }
   177  
   178  func (s *unitSuite) TestDestroy(c *gc.C) {
   179  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   180  
   181  	err := s.apiUnit.Destroy()
   182  	c.Assert(err, jc.ErrorIsNil)
   183  
   184  	err = s.wordpressUnit.Refresh()
   185  	c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" not found`)
   186  }
   187  
   188  func (s *unitSuite) TestDestroyAllSubordinates(c *gc.C) {
   189  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   190  
   191  	// Call without subordinates - no change.
   192  	err := s.apiUnit.DestroyAllSubordinates()
   193  	c.Assert(err, jc.ErrorIsNil)
   194  
   195  	// Add a couple of subordinates and try again.
   196  	_, _, loggingSub := s.addRelatedApplication(c, "wordpress", "logging", s.wordpressUnit)
   197  	_, _, monitoringSub := s.addRelatedApplication(c, "wordpress", "monitoring", s.wordpressUnit)
   198  	c.Assert(loggingSub.Life(), gc.Equals, state.Alive)
   199  	c.Assert(monitoringSub.Life(), gc.Equals, state.Alive)
   200  
   201  	err = s.apiUnit.DestroyAllSubordinates()
   202  	c.Assert(err, jc.ErrorIsNil)
   203  
   204  	// Verify they got destroyed.
   205  	err = loggingSub.Refresh()
   206  	c.Assert(err, jc.ErrorIsNil)
   207  	c.Assert(loggingSub.Life(), gc.Equals, state.Dying)
   208  	err = monitoringSub.Refresh()
   209  	c.Assert(err, jc.ErrorIsNil)
   210  	c.Assert(monitoringSub.Life(), gc.Equals, state.Dying)
   211  }
   212  
   213  func (s *unitSuite) TestRefreshLife(c *gc.C) {
   214  	c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive)
   215  
   216  	err := s.apiUnit.EnsureDead()
   217  	c.Assert(err, jc.ErrorIsNil)
   218  	c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive)
   219  
   220  	err = s.apiUnit.Refresh()
   221  	c.Assert(err, jc.ErrorIsNil)
   222  	c.Assert(s.apiUnit.Life(), gc.Equals, params.Dead)
   223  }
   224  
   225  func (s *unitSuite) TestRefreshResolve(c *gc.C) {
   226  	err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks)
   227  	c.Assert(err, jc.ErrorIsNil)
   228  
   229  	err = s.apiUnit.Refresh()
   230  	c.Assert(err, jc.ErrorIsNil)
   231  	mode := s.apiUnit.Resolved()
   232  	c.Assert(mode, gc.Equals, params.ResolvedRetryHooks)
   233  
   234  	err = s.apiUnit.ClearResolved()
   235  	c.Assert(err, jc.ErrorIsNil)
   236  	mode = s.apiUnit.Resolved()
   237  	c.Assert(mode, gc.Equals, params.ResolvedRetryHooks)
   238  
   239  	err = s.apiUnit.Refresh()
   240  	c.Assert(err, jc.ErrorIsNil)
   241  	mode = s.apiUnit.Resolved()
   242  	c.Assert(mode, gc.Equals, params.ResolvedNone)
   243  }
   244  
   245  func (s *unitSuite) TestWatch(c *gc.C) {
   246  	c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive)
   247  
   248  	w, err := s.apiUnit.Watch()
   249  	c.Assert(err, jc.ErrorIsNil)
   250  	wc := watchertest.NewNotifyWatcherC(c, w, s.BackingState.StartSync)
   251  	defer wc.AssertStops()
   252  
   253  	// Initial event.
   254  	wc.AssertOneChange()
   255  
   256  	// Change something other than the lifecycle and make sure it's
   257  	// not detected.
   258  	err = s.apiUnit.SetAgentStatus(status.Idle, "not really", nil)
   259  	c.Assert(err, jc.ErrorIsNil)
   260  	wc.AssertNoChange()
   261  
   262  	// Make the unit dead and check it's detected.
   263  	err = s.apiUnit.EnsureDead()
   264  	c.Assert(err, jc.ErrorIsNil)
   265  	wc.AssertOneChange()
   266  }
   267  
   268  func (s *unitSuite) TestWatchRelations(c *gc.C) {
   269  	w, err := s.apiUnit.WatchRelations()
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync)
   272  	defer wc.AssertStops()
   273  
   274  	// Initial event.
   275  	wc.AssertChange()
   276  	wc.AssertNoChange()
   277  
   278  	// Change something other than the lifecycle and make sure it's
   279  	// not detected.
   280  	err = s.wordpressApplication.SetExposed()
   281  	c.Assert(err, jc.ErrorIsNil)
   282  	wc.AssertNoChange()
   283  
   284  	// Add another application and relate it to wordpress,
   285  	// check it's detected.
   286  	s.addMachineAppCharmAndUnit(c, "mysql")
   287  	rel := s.addRelation(c, "wordpress", "mysql")
   288  	wc.AssertChange(rel.String())
   289  
   290  	// Destroy the relation and check it's detected.
   291  	err = rel.Destroy()
   292  	c.Assert(err, jc.ErrorIsNil)
   293  	wc.AssertChange(rel.String())
   294  	wc.AssertNoChange()
   295  }
   296  
   297  func (s *unitSuite) TestSubordinateWatchRelations(c *gc.C) {
   298  	// A subordinate unit deployed with this wordpress unit shouldn't
   299  	// be notified about changes to logging mysql.
   300  	loggingRel, _, loggingUnit := s.addRelatedApplication(c, "wordpress", "logging", s.wordpressUnit)
   301  	password, err := utils.RandomPassword()
   302  	c.Assert(err, jc.ErrorIsNil)
   303  	err = loggingUnit.SetPassword(password)
   304  	c.Assert(err, jc.ErrorIsNil)
   305  
   306  	// Add another principal app that we can relate logging to.
   307  	s.addMachineAppCharmAndUnit(c, "mysql")
   308  
   309  	api := s.OpenAPIAs(c, loggingUnit.Tag(), password)
   310  	uniter, err := api.Uniter()
   311  	c.Assert(err, jc.ErrorIsNil)
   312  	apiUnit, err := uniter.Unit(loggingUnit.Tag().(names.UnitTag))
   313  	c.Assert(err, jc.ErrorIsNil)
   314  
   315  	w, err := apiUnit.WatchRelations()
   316  	c.Assert(err, jc.ErrorIsNil)
   317  
   318  	wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync)
   319  	defer wc.AssertStops()
   320  
   321  	wc.AssertChange(loggingRel.Tag().Id())
   322  	wc.AssertNoChange()
   323  
   324  	// Adding a subordinate relation to another application doesn't notify this unit.
   325  	s.addRelation(c, "mysql", "logging")
   326  	wc.AssertNoChange()
   327  
   328  	// Destroying a relevant relation does notify it.
   329  	err = loggingRel.Destroy()
   330  	c.Assert(err, jc.ErrorIsNil)
   331  
   332  	wc.AssertChange(loggingRel.Tag().Id())
   333  	wc.AssertNoChange()
   334  }
   335  
   336  func (s *unitSuite) TestAssignedMachine(c *gc.C) {
   337  	machineTag, err := s.apiUnit.AssignedMachine()
   338  	c.Assert(err, jc.ErrorIsNil)
   339  	c.Assert(machineTag, gc.Equals, s.wordpressMachine.Tag())
   340  }
   341  
   342  func (s *unitSuite) TestPrincipalName(c *gc.C) {
   343  	unitName, ok, err := s.apiUnit.PrincipalName()
   344  	c.Assert(err, jc.ErrorIsNil)
   345  	c.Assert(ok, jc.IsFalse)
   346  	c.Assert(unitName, gc.Equals, "")
   347  }
   348  
   349  func (s *unitSuite) TestHasSubordinates(c *gc.C) {
   350  	found, err := s.apiUnit.HasSubordinates()
   351  	c.Assert(err, jc.ErrorIsNil)
   352  	c.Assert(found, jc.IsFalse)
   353  
   354  	// Add a couple of subordinates and try again.
   355  	s.addRelatedApplication(c, "wordpress", "logging", s.wordpressUnit)
   356  	s.addRelatedApplication(c, "wordpress", "monitoring", s.wordpressUnit)
   357  
   358  	found, err = s.apiUnit.HasSubordinates()
   359  	c.Assert(err, jc.ErrorIsNil)
   360  	c.Assert(found, jc.IsTrue)
   361  }
   362  
   363  func (s *unitSuite) TestPublicAddress(c *gc.C) {
   364  	address, err := s.apiUnit.PublicAddress()
   365  	c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no public address set`)
   366  
   367  	err = s.wordpressMachine.SetProviderAddresses(
   368  		network.NewScopedAddress("1.2.3.4", network.ScopePublic),
   369  	)
   370  	c.Assert(err, jc.ErrorIsNil)
   371  
   372  	address, err = s.apiUnit.PublicAddress()
   373  	c.Assert(err, jc.ErrorIsNil)
   374  	c.Assert(address, gc.Equals, "1.2.3.4")
   375  }
   376  
   377  func (s *unitSuite) TestPrivateAddress(c *gc.C) {
   378  	address, err := s.apiUnit.PrivateAddress()
   379  	c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no private address set`)
   380  
   381  	err = s.wordpressMachine.SetProviderAddresses(
   382  		network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal),
   383  	)
   384  	c.Assert(err, jc.ErrorIsNil)
   385  
   386  	address, err = s.apiUnit.PrivateAddress()
   387  	c.Assert(err, jc.ErrorIsNil)
   388  	c.Assert(address, gc.Equals, "1.2.3.4")
   389  }
   390  
   391  func (s *unitSuite) TestAvailabilityZone(c *gc.C) {
   392  	uniter.PatchUnitResponse(s, s.apiUnit, "AvailabilityZone",
   393  		func(result interface{}) error {
   394  			if results, ok := result.(*params.StringResults); ok {
   395  				results.Results = []params.StringResult{{
   396  					Result: "a-zone",
   397  				}}
   398  			}
   399  			return nil
   400  		},
   401  	)
   402  
   403  	zone, err := s.apiUnit.AvailabilityZone()
   404  	c.Assert(err, jc.ErrorIsNil)
   405  
   406  	c.Check(zone, gc.Equals, "a-zone")
   407  }
   408  
   409  func (s *unitSuite) TestOpenClosePortRanges(c *gc.C) {
   410  	ports, err := s.wordpressUnit.OpenedPorts()
   411  	c.Assert(err, jc.ErrorIsNil)
   412  	c.Assert(ports, gc.HasLen, 0)
   413  
   414  	err = s.apiUnit.OpenPorts("tcp", 1234, 1400)
   415  	c.Assert(err, jc.ErrorIsNil)
   416  	err = s.apiUnit.OpenPorts("udp", 4321, 5000)
   417  	c.Assert(err, jc.ErrorIsNil)
   418  
   419  	ports, err = s.wordpressUnit.OpenedPorts()
   420  	c.Assert(err, jc.ErrorIsNil)
   421  	// OpenedPorts returns a sorted slice.
   422  	c.Assert(ports, gc.DeepEquals, []corenetwork.PortRange{
   423  		{Protocol: "tcp", FromPort: 1234, ToPort: 1400},
   424  		{Protocol: "udp", FromPort: 4321, ToPort: 5000},
   425  	})
   426  
   427  	err = s.apiUnit.ClosePorts("udp", 4321, 5000)
   428  	c.Assert(err, jc.ErrorIsNil)
   429  
   430  	ports, err = s.wordpressUnit.OpenedPorts()
   431  	c.Assert(err, jc.ErrorIsNil)
   432  	// OpenedPorts returns a sorted slice.
   433  	c.Assert(ports, gc.DeepEquals, []corenetwork.PortRange{
   434  		{Protocol: "tcp", FromPort: 1234, ToPort: 1400},
   435  	})
   436  
   437  	err = s.apiUnit.ClosePorts("tcp", 1234, 1400)
   438  	c.Assert(err, jc.ErrorIsNil)
   439  
   440  	ports, err = s.wordpressUnit.OpenedPorts()
   441  	c.Assert(err, jc.ErrorIsNil)
   442  	c.Assert(ports, gc.HasLen, 0)
   443  }
   444  
   445  func (s *unitSuite) TestGetSetCharmURL(c *gc.C) {
   446  	// No charm URL set yet.
   447  	curl, ok := s.wordpressUnit.CharmURL()
   448  	c.Assert(curl, gc.IsNil)
   449  	c.Assert(ok, jc.IsFalse)
   450  
   451  	// Now check the same through the API.
   452  	_, err := s.apiUnit.CharmURL()
   453  	c.Assert(err, gc.Equals, uniter.ErrNoCharmURLSet)
   454  
   455  	err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL())
   456  	c.Assert(err, jc.ErrorIsNil)
   457  
   458  	curl, err = s.apiUnit.CharmURL()
   459  	c.Assert(err, jc.ErrorIsNil)
   460  	c.Assert(curl, gc.NotNil)
   461  	c.Assert(curl.String(), gc.Equals, s.wordpressCharm.String())
   462  }
   463  
   464  func (s *unitSuite) TestNetworkInfo(c *gc.C) {
   465  	var called int
   466  	relId := 2
   467  	apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
   468  		called++
   469  		if called == 1 {
   470  			*(result.(*params.UnitRefreshResults)) = params.UnitRefreshResults{
   471  				Results: []params.UnitRefreshResult{{Life: params.Alive, Resolved: params.ResolvedNone}}}
   472  			return nil
   473  		}
   474  		c.Check(objType, gc.Equals, "Uniter")
   475  		c.Check(version, gc.Equals, expectedVersion)
   476  		c.Check(id, gc.Equals, "")
   477  		c.Check(request, gc.Equals, "NetworkInfo")
   478  		c.Check(arg, gc.DeepEquals, params.NetworkInfoParams{
   479  			Unit:       "unit-mysql-0",
   480  			Bindings:   []string{"server"},
   481  			RelationId: &relId,
   482  		})
   483  		c.Assert(result, gc.FitsTypeOf, &params.NetworkInfoResults{})
   484  		*(result.(*params.NetworkInfoResults)) = params.NetworkInfoResults{
   485  			Results: map[string]params.NetworkInfoResult{
   486  				"db": {
   487  					Error: &params.Error{Message: "FAIL"},
   488  				}},
   489  		}
   490  		return nil
   491  	})
   492  
   493  	ut := names.NewUnitTag("mysql/0")
   494  	st := uniter.NewState(apiCaller, ut)
   495  	unit, err := st.Unit(ut)
   496  	c.Assert(err, jc.ErrorIsNil)
   497  	result, err := unit.NetworkInfo([]string{"server"}, &relId)
   498  	c.Assert(err, jc.ErrorIsNil)
   499  	c.Assert(result["db"].Error, gc.ErrorMatches, "FAIL")
   500  	c.Assert(called, gc.Equals, 2)
   501  }
   502  
   503  func (s *unitSuite) TestConfigSettings(c *gc.C) {
   504  	// Make sure ConfigSettings returns an error when
   505  	// no charm URL is set, as its state counterpart does.
   506  	settings, err := s.apiUnit.ConfigSettings()
   507  	c.Assert(err, gc.ErrorMatches, "unit charm not set")
   508  
   509  	// Now set the charm and try again.
   510  	err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL())
   511  	c.Assert(err, jc.ErrorIsNil)
   512  
   513  	settings, err = s.apiUnit.ConfigSettings()
   514  	c.Assert(err, jc.ErrorIsNil)
   515  	c.Assert(settings, gc.DeepEquals, charm.Settings{
   516  		"blog-title": "My Title",
   517  	})
   518  
   519  	// Update the config and check we get the changes on the next call.
   520  	err = s.wordpressApplication.UpdateCharmConfig(charm.Settings{
   521  		"blog-title": "superhero paparazzi",
   522  	})
   523  	c.Assert(err, jc.ErrorIsNil)
   524  
   525  	settings, err = s.apiUnit.ConfigSettings()
   526  	c.Assert(err, jc.ErrorIsNil)
   527  	c.Assert(settings, gc.DeepEquals, charm.Settings{
   528  		"blog-title": "superhero paparazzi",
   529  	})
   530  }
   531  func (s *unitSuite) TestWatchConfigSettingsHash(c *gc.C) {
   532  	// Make sure WatchConfigSettingsHash returns an error when
   533  	// no charm URL is set, as its state counterpart does.
   534  	w, err := s.apiUnit.WatchConfigSettingsHash()
   535  	c.Assert(err, gc.ErrorMatches, "unit charm not set")
   536  
   537  	// Now set the charm and try again.
   538  	err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL())
   539  	c.Assert(err, jc.ErrorIsNil)
   540  
   541  	w, err = s.apiUnit.WatchConfigSettingsHash()
   542  	wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync)
   543  	defer wc.AssertStops()
   544  
   545  	// Initial event - this is the sha-256 hash of an empty bson.D.
   546  	wc.AssertChange("e8d7e8dfff0eed1e77b15638581672f7b25ecc1163cc5fd5a52d29d51d096c00")
   547  
   548  	err = s.wordpressApplication.UpdateCharmConfig(charm.Settings{
   549  		"blog-title": "sauceror central",
   550  	})
   551  	c.Assert(err, jc.ErrorIsNil)
   552  	wc.AssertChange("7ed6151e9c3d5144faf0946d20c283c466b4885dded6a6122ff3fdac7ee2334f")
   553  
   554  	// Non-change is not reported.
   555  	err = s.wordpressApplication.UpdateCharmConfig(charm.Settings{
   556  		"blog-title": "sauceror central",
   557  	})
   558  	c.Assert(err, jc.ErrorIsNil)
   559  	wc.AssertNoChange()
   560  }
   561  
   562  func (s *unitSuite) TestWatchTrustConfigSettingsHash(c *gc.C) {
   563  	watcher, err := s.apiUnit.WatchTrustConfigSettingsHash()
   564  	c.Assert(err, jc.ErrorIsNil)
   565  
   566  	stringsWatcher := watchertest.NewStringsWatcherC(c, watcher, s.BackingState.StartSync)
   567  	defer stringsWatcher.AssertStops()
   568  
   569  	// Initial event - this is the hash of the settings key
   570  	// a#wordpress#application + an empty bson.D.
   571  	stringsWatcher.AssertChange("92652ce7679e295c6567a3891c562dcab727c71543f8c1c3a38c3626ce064019")
   572  
   573  	// Update application config and see if it is reported
   574  	trustFieldKey := "trust"
   575  	s.wordpressApplication.UpdateApplicationConfig(application.ConfigAttributes{
   576  		trustFieldKey: true,
   577  	},
   578  		[]string{},
   579  		environschema.Fields{trustFieldKey: {
   580  			Description: "Does this application have access to trusted credentials",
   581  			Type:        environschema.Tbool,
   582  			Group:       environschema.JujuGroup,
   583  		}},
   584  		schema.Defaults{
   585  			trustFieldKey: false,
   586  		},
   587  	)
   588  	stringsWatcher.AssertChange("2f1368bde39be8106dcdca15e35cc3b5f7db5b8e429806369f621a47fb938519")
   589  }
   590  
   591  func (s *unitSuite) TestWatchActionNotifications(c *gc.C) {
   592  	w, err := s.apiUnit.WatchActionNotifications()
   593  	c.Assert(err, jc.ErrorIsNil)
   594  	wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync)
   595  	defer wc.AssertStops()
   596  
   597  	// Initial event.
   598  	wc.AssertChange()
   599  
   600  	// Add a couple of actions and make sure the changes are detected.
   601  	action, err := s.wordpressUnit.AddAction("fakeaction", map[string]interface{}{
   602  		"outfile": "foo.txt",
   603  	})
   604  	c.Assert(err, jc.ErrorIsNil)
   605  	wc.AssertChange(action.Id())
   606  
   607  	action, err = s.wordpressUnit.AddAction("fakeaction", map[string]interface{}{
   608  		"outfile": "foo.bz2",
   609  		"compression": map[string]interface{}{
   610  			"kind":    "bzip",
   611  			"quality": float64(5.0),
   612  		},
   613  	})
   614  	c.Assert(err, jc.ErrorIsNil)
   615  	wc.AssertChange(action.Id())
   616  }
   617  
   618  func (s *unitSuite) TestWatchActionNotificationsError(c *gc.C) {
   619  	uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications",
   620  		func(result interface{}) error {
   621  			return fmt.Errorf("Test error")
   622  		},
   623  	)
   624  
   625  	_, err := s.apiUnit.WatchActionNotifications()
   626  	c.Assert(err.Error(), gc.Equals, "Test error")
   627  }
   628  
   629  func (s *unitSuite) TestWatchActionNotificationsErrorResults(c *gc.C) {
   630  	uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications",
   631  		func(results interface{}) error {
   632  			if results, ok := results.(*params.StringsWatchResults); ok {
   633  				results.Results = make([]params.StringsWatchResult, 1)
   634  				results.Results[0] = params.StringsWatchResult{
   635  					Error: &params.Error{
   636  						Message: "An error in the watch result.",
   637  						Code:    params.CodeNotAssigned,
   638  					},
   639  				}
   640  			}
   641  			return nil
   642  		},
   643  	)
   644  
   645  	_, err := s.apiUnit.WatchActionNotifications()
   646  	c.Assert(err.Error(), gc.Equals, "An error in the watch result.")
   647  }
   648  
   649  func (s *unitSuite) TestWatchActionNotificationsNoResults(c *gc.C) {
   650  	uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications",
   651  		func(results interface{}) error {
   652  			return nil
   653  		},
   654  	)
   655  
   656  	_, err := s.apiUnit.WatchActionNotifications()
   657  	c.Assert(err.Error(), gc.Equals, "expected 1 result, got 0")
   658  }
   659  
   660  func (s *unitSuite) TestWatchActionNotificationsMoreResults(c *gc.C) {
   661  	uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications",
   662  		func(results interface{}) error {
   663  			if results, ok := results.(*params.StringsWatchResults); ok {
   664  				results.Results = make([]params.StringsWatchResult, 2)
   665  			}
   666  			return nil
   667  		},
   668  	)
   669  
   670  	_, err := s.apiUnit.WatchActionNotifications()
   671  	c.Assert(err.Error(), gc.Equals, "expected 1 result, got 2")
   672  }
   673  
   674  func (s *unitSuite) TestWatchUpgradeSeriesNotifications(c *gc.C) {
   675  	watcher, err := s.apiUnit.WatchUpgradeSeriesNotifications()
   676  	c.Assert(err, jc.ErrorIsNil)
   677  
   678  	notifyWatcher := watchertest.NewNotifyWatcherC(c, watcher, s.BackingState.StartSync)
   679  	defer notifyWatcher.AssertStops()
   680  
   681  	notifyWatcher.AssertOneChange()
   682  
   683  	s.CreateUpgradeSeriesLock(c)
   684  
   685  	// Expect a notification that the document was created (i.e. a lock was placed)
   686  	notifyWatcher.AssertOneChange()
   687  
   688  	err = s.wordpressMachine.RemoveUpgradeSeriesLock()
   689  	c.Assert(err, jc.ErrorIsNil)
   690  
   691  	// A notification that the document was removed (i.e. the lock was released)
   692  	notifyWatcher.AssertOneChange()
   693  }
   694  
   695  func (s *unitSuite) TestUpgradeSeriesStatusIsInitializedToUnitStarted(c *gc.C) {
   696  	// First we create the prepare lock
   697  	s.CreateUpgradeSeriesLock(c)
   698  
   699  	// Then we check to see the status of our upgrade. We note that creating
   700  	// the lock essentially kicks off an upgrade from the perspective of
   701  	// assigned units.
   702  	status, err := s.apiUnit.UpgradeSeriesStatus()
   703  	c.Assert(err, jc.ErrorIsNil)
   704  	c.Assert(status, gc.Equals, model.UpgradeSeriesPrepareStarted)
   705  }
   706  
   707  func (s *unitSuite) TestSetUpgradeSeriesStatusFailsIfNoLockExists(c *gc.C) {
   708  	arbitraryStatus := model.UpgradeSeriesNotStarted
   709  	arbitraryReason := ""
   710  
   711  	err := s.apiUnit.SetUpgradeSeriesStatus(arbitraryStatus, arbitraryReason)
   712  	c.Assert(err, gc.ErrorMatches, "upgrade lock for machine \"[0-9]*\" not found")
   713  }
   714  
   715  func (s *unitSuite) TestSetUpgradeSeriesStatusUpdatesStatus(c *gc.C) {
   716  	arbitraryNonDefaultStatus := model.UpgradeSeriesPrepareRunning
   717  	arbitraryReason := ""
   718  
   719  	// First we create the prepare lock or the required state will not exists
   720  	s.CreateUpgradeSeriesLock(c)
   721  
   722  	// Change the state to something other than the default remote state of UpgradeSeriesPrepareStarted
   723  	err := s.apiUnit.SetUpgradeSeriesStatus(arbitraryNonDefaultStatus, arbitraryReason)
   724  	c.Assert(err, jc.ErrorIsNil)
   725  
   726  	// Check to see that the upgrade status has been set appropriately
   727  	status, err := s.apiUnit.UpgradeSeriesStatus()
   728  	c.Assert(err, jc.ErrorIsNil)
   729  	c.Assert(status, gc.Equals, arbitraryNonDefaultStatus)
   730  }
   731  
   732  func (s *unitSuite) TestSetUpgradeSeriesStatusShouldOnlySetSpecifiedUnit(c *gc.C) {
   733  	// add another unit
   734  	unit2, err := s.wordpressApplication.AddUnit(state.AddUnitParams{})
   735  	c.Assert(err, jc.ErrorIsNil)
   736  
   737  	err = unit2.AssignToMachine(s.wordpressMachine)
   738  	c.Assert(err, jc.ErrorIsNil)
   739  
   740  	// Creating a lock for the machine transitions all units to started state
   741  	s.CreateUpgradeSeriesLock(c, unit2.Name())
   742  
   743  	// Complete one unit
   744  	err = unit2.SetUpgradeSeriesStatus(model.UpgradeSeriesPrepareCompleted, "")
   745  	c.Assert(err, jc.ErrorIsNil)
   746  
   747  	// The other unit should still be in the started state
   748  	status, err := s.wordpressUnit.UpgradeSeriesStatus()
   749  	c.Assert(err, jc.ErrorIsNil)
   750  	c.Assert(status, gc.Equals, model.UpgradeSeriesPrepareStarted)
   751  }
   752  
   753  func (s *unitSuite) CreateUpgradeSeriesLock(c *gc.C, additionalUnits ...string) {
   754  	unitNames := additionalUnits
   755  	unitNames = append(unitNames, s.wordpressUnit.Name())
   756  	series := "trust"
   757  
   758  	err := s.wordpressMachine.CreateUpgradeSeriesLock(unitNames, series)
   759  	c.Assert(err, jc.ErrorIsNil)
   760  }
   761  
   762  func (s *unitSuite) TestApplicationNameAndTag(c *gc.C) {
   763  	c.Assert(s.apiUnit.ApplicationName(), gc.Equals, s.wordpressApplication.Name())
   764  	c.Assert(s.apiUnit.ApplicationTag(), gc.Equals, s.wordpressApplication.Tag())
   765  }
   766  
   767  func (s *unitSuite) TestRelationSuspended(c *gc.C) {
   768  	relationStatus, err := s.apiUnit.RelationsStatus()
   769  	c.Assert(err, jc.ErrorIsNil)
   770  	c.Assert(relationStatus, gc.HasLen, 0)
   771  
   772  	rel1, _, _ := s.addRelatedApplication(c, "wordpress", "monitoring", s.wordpressUnit)
   773  	relationStatus, err = s.apiUnit.RelationsStatus()
   774  	c.Assert(err, jc.ErrorIsNil)
   775  	c.Assert(relationStatus, gc.DeepEquals, []uniter.RelationStatus{{
   776  		Tag:       rel1.Tag().(names.RelationTag),
   777  		InScope:   true,
   778  		Suspended: false,
   779  	}})
   780  
   781  	rel2 := s.addRelationSuspended(c, "wordpress", "logging", s.wordpressUnit)
   782  	relationStatus, err = s.apiUnit.RelationsStatus()
   783  	c.Assert(err, jc.ErrorIsNil)
   784  	c.Assert(relationStatus, jc.SameContents, []uniter.RelationStatus{{
   785  		Tag:       rel1.Tag().(names.RelationTag),
   786  		InScope:   true,
   787  		Suspended: false,
   788  	}, {
   789  		Tag:       rel2.Tag().(names.RelationTag),
   790  		InScope:   false,
   791  		Suspended: true,
   792  	}})
   793  }
   794  
   795  func (s *unitSuite) TestWatchAddressesHash(c *gc.C) {
   796  	w, err := s.apiUnit.WatchAddressesHash()
   797  	c.Assert(err, jc.ErrorIsNil)
   798  	wc := watchertest.NewStringsWatcherC(c, w, s.BackingState.StartSync)
   799  	defer wc.AssertStops()
   800  
   801  	// Initial event.
   802  	wc.AssertChange("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
   803  
   804  	// Update config get an event.
   805  	err = s.wordpressMachine.SetProviderAddresses(network.NewAddress("0.1.2.4"))
   806  	c.Assert(err, jc.ErrorIsNil)
   807  	wc.AssertChange("e8686213014563c18d8b3838ac3ac247dc2c7ceb0000cb01c19aa401ffc76e80")
   808  
   809  	// Non-change is not reported.
   810  	err = s.wordpressMachine.SetProviderAddresses(network.NewAddress("0.1.2.4"))
   811  	c.Assert(err, jc.ErrorIsNil)
   812  	wc.AssertNoChange()
   813  
   814  	// Change is reported for machine addresses.
   815  	err = s.wordpressMachine.SetMachineAddresses(network.NewAddress("0.1.2.5"))
   816  	c.Assert(err, jc.ErrorIsNil)
   817  	wc.AssertChange("ad269642567ef00c2c9c6ff84e9c04ecf3aa3342c1b4d98d76142471781c4495")
   818  
   819  	// Set machine addresses to empty is reported.
   820  	err = s.wordpressMachine.SetMachineAddresses()
   821  	c.Assert(err, jc.ErrorIsNil)
   822  	wc.AssertChange("e8686213014563c18d8b3838ac3ac247dc2c7ceb0000cb01c19aa401ffc76e80")
   823  }
   824  
   825  func (s *unitSuite) TestWatchAddressesHashErrors(c *gc.C) {
   826  	err := s.wordpressUnit.UnassignFromMachine()
   827  	c.Assert(err, jc.ErrorIsNil)
   828  	_, err = s.apiUnit.WatchAddressesHash()
   829  	c.Assert(err, jc.Satisfies, params.IsCodeNotAssigned)
   830  }
   831  
   832  func (s *unitSuite) TestAddMetrics(c *gc.C) {
   833  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   834  		func(results interface{}) error {
   835  			result := results.(*params.ErrorResults)
   836  			result.Results = make([]params.ErrorResult, 1)
   837  			return nil
   838  		},
   839  	)
   840  	metrics := []params.Metric{{
   841  		Key: "A", Value: "23", Time: time.Now(),
   842  	}, {
   843  		Key: "B", Value: "27.0", Time: time.Now(), Labels: map[string]string{"foo": "bar"},
   844  	}}
   845  	err := s.apiUnit.AddMetrics(metrics)
   846  	c.Assert(err, jc.ErrorIsNil)
   847  }
   848  
   849  func (s *unitSuite) TestAddMetricsError(c *gc.C) {
   850  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   851  		func(results interface{}) error {
   852  			result := results.(*params.ErrorResults)
   853  			result.Results = make([]params.ErrorResult, 1)
   854  			return fmt.Errorf("test error")
   855  		},
   856  	)
   857  	metrics := []params.Metric{{
   858  		Key: "A", Value: "23", Time: time.Now(),
   859  	}, {
   860  		Key: "B", Value: "27.0", Time: time.Now(), Labels: map[string]string{"foo": "bar"},
   861  	}}
   862  	err := s.apiUnit.AddMetrics(metrics)
   863  	c.Assert(err, gc.ErrorMatches, "unable to add metric: test error")
   864  }
   865  
   866  func (s *unitSuite) TestAddMetricsResultError(c *gc.C) {
   867  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics",
   868  		func(results interface{}) error {
   869  			result := results.(*params.ErrorResults)
   870  			result.Results = make([]params.ErrorResult, 1)
   871  			result.Results[0].Error = &params.Error{
   872  				Message: "error adding metrics",
   873  				Code:    params.CodeNotAssigned,
   874  			}
   875  			return nil
   876  		},
   877  	)
   878  	metrics := []params.Metric{{
   879  		Key: "A", Value: "23", Time: time.Now(),
   880  	}, {
   881  		Key: "B", Value: "27.0", Time: time.Now(), Labels: map[string]string{"foo": "bar"},
   882  	}}
   883  	err := s.apiUnit.AddMetrics(metrics)
   884  	c.Assert(err, gc.ErrorMatches, "error adding metrics")
   885  }
   886  
   887  func (s *unitSuite) TestMeterStatus(c *gc.C) {
   888  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   889  		func(results interface{}) error {
   890  			result := results.(*params.MeterStatusResults)
   891  			result.Results = make([]params.MeterStatusResult, 1)
   892  			result.Results[0].Code = "GREEN"
   893  			result.Results[0].Info = "All ok."
   894  			return nil
   895  		},
   896  	)
   897  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   898  	c.Assert(err, jc.ErrorIsNil)
   899  	c.Assert(statusCode, gc.Equals, "GREEN")
   900  	c.Assert(statusInfo, gc.Equals, "All ok.")
   901  }
   902  
   903  func (s *unitSuite) TestMeterStatusError(c *gc.C) {
   904  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   905  		func(results interface{}) error {
   906  			result := results.(*params.MeterStatusResults)
   907  			result.Results = make([]params.MeterStatusResult, 1)
   908  			return fmt.Errorf("boo")
   909  		},
   910  	)
   911  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   912  	c.Assert(err, gc.ErrorMatches, "boo")
   913  	c.Assert(statusCode, gc.Equals, "")
   914  	c.Assert(statusInfo, gc.Equals, "")
   915  }
   916  
   917  func (s *unitSuite) TestMeterStatusResultError(c *gc.C) {
   918  	uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus",
   919  		func(results interface{}) error {
   920  			result := results.(*params.MeterStatusResults)
   921  			result.Results = make([]params.MeterStatusResult, 1)
   922  			result.Results[0].Error = &params.Error{
   923  				Message: "error getting meter status",
   924  				Code:    params.CodeNotAssigned,
   925  			}
   926  			return nil
   927  		},
   928  	)
   929  	statusCode, statusInfo, err := s.apiUnit.MeterStatus()
   930  	c.Assert(err, gc.ErrorMatches, "error getting meter status")
   931  	c.Assert(statusCode, gc.Equals, "")
   932  	c.Assert(statusInfo, gc.Equals, "")
   933  }
   934  
   935  func (s *unitSuite) TestUpgradeSeriesStatusMultipleReturnsError(c *gc.C) {
   936  	facadeCaller := testing.StubFacadeCaller{Stub: &coretesting.Stub{}}
   937  	facadeCaller.FacadeCallFn = func(name string, args, response interface{}) error {
   938  		*(response.(*params.UpgradeSeriesStatusResults)) = params.UpgradeSeriesStatusResults{
   939  			Results: []params.UpgradeSeriesStatusResult{
   940  				{Status: "prepare started"},
   941  				{Status: "completed"},
   942  			},
   943  		}
   944  		return nil
   945  	}
   946  	uniter.PatchUnitUpgradeSeriesFacade(s.apiUnit, &facadeCaller)
   947  
   948  	_, err := s.apiUnit.UpgradeSeriesStatus()
   949  	c.Assert(err, gc.ErrorMatches, "expected 1 result, got 2")
   950  }
   951  
   952  func (s *unitSuite) TestUpgradeSeriesStatusSingleResult(c *gc.C) {
   953  	facadeCaller := testing.StubFacadeCaller{Stub: &coretesting.Stub{}}
   954  	facadeCaller.FacadeCallFn = func(name string, args, response interface{}) error {
   955  		*(response.(*params.UpgradeSeriesStatusResults)) = params.UpgradeSeriesStatusResults{
   956  			Results: []params.UpgradeSeriesStatusResult{{Status: "completed"}},
   957  		}
   958  		return nil
   959  	}
   960  	uniter.PatchUnitUpgradeSeriesFacade(s.apiUnit, &facadeCaller)
   961  
   962  	sts, err := s.apiUnit.UpgradeSeriesStatus()
   963  	c.Assert(err, jc.ErrorIsNil)
   964  	c.Check(sts, gc.Equals, model.UpgradeSeriesCompleted)
   965  }
   966  
   967  type unitMetricBatchesSuite struct {
   968  	jujutesting.JujuConnSuite
   969  
   970  	st      api.Connection
   971  	uniter  *uniter.State
   972  	apiUnit *uniter.Unit
   973  	charm   *state.Charm
   974  }
   975  
   976  var _ = gc.Suite(&unitMetricBatchesSuite{})
   977  
   978  func (s *unitMetricBatchesSuite) SetUpTest(c *gc.C) {
   979  	s.JujuConnSuite.SetUpTest(c)
   980  
   981  	s.charm = s.Factory.MakeCharm(c, &jujufactory.CharmParams{
   982  		Name: "metered",
   983  		URL:  "cs:quantal/metered",
   984  	})
   985  	application := s.Factory.MakeApplication(c, &jujufactory.ApplicationParams{
   986  		Charm: s.charm,
   987  	})
   988  	unit := s.Factory.MakeUnit(c, &jujufactory.UnitParams{
   989  		Application: application,
   990  		SetCharmURL: true,
   991  	})
   992  
   993  	password, err := utils.RandomPassword()
   994  	c.Assert(err, jc.ErrorIsNil)
   995  	err = unit.SetPassword(password)
   996  	c.Assert(err, jc.ErrorIsNil)
   997  	s.st = s.OpenAPIAs(c, unit.Tag(), password)
   998  
   999  	// Create the uniter API facade.
  1000  	s.uniter, err = s.st.Uniter()
  1001  	c.Assert(err, jc.ErrorIsNil)
  1002  	c.Assert(s.uniter, gc.NotNil)
  1003  
  1004  	s.apiUnit, err = s.uniter.Unit(unit.Tag().(names.UnitTag))
  1005  	c.Assert(err, jc.ErrorIsNil)
  1006  }
  1007  
  1008  func (s *unitMetricBatchesSuite) TestSendMetricBatchPatch(c *gc.C) {
  1009  	metrics := []params.Metric{{
  1010  		Key: "pings", Value: "5", Time: time.Now().UTC(),
  1011  	}, {
  1012  		Key: "pongs", Value: "6", Time: time.Now().UTC(), Labels: map[string]string{"foo": "bar"},
  1013  	}}
  1014  	uuid := utils.MustNewUUID().String()
  1015  	batch := params.MetricBatch{
  1016  		UUID:     uuid,
  1017  		CharmURL: s.charm.URL().String(),
  1018  		Created:  time.Now(),
  1019  		Metrics:  metrics,
  1020  	}
  1021  
  1022  	var called bool
  1023  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches",
  1024  		func(response interface{}) error {
  1025  			called = true
  1026  			result := response.(*params.ErrorResults)
  1027  			result.Results = make([]params.ErrorResult, 1)
  1028  			return nil
  1029  		})
  1030  
  1031  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
  1032  	c.Assert(err, jc.ErrorIsNil)
  1033  	c.Assert(results, gc.HasLen, 1)
  1034  	c.Assert(results[batch.UUID], gc.IsNil)
  1035  	c.Assert(called, jc.IsTrue)
  1036  }
  1037  
  1038  func (s *unitMetricBatchesSuite) TestSendMetricBatchFail(c *gc.C) {
  1039  	var called bool
  1040  	uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches",
  1041  		func(response interface{}) error {
  1042  			called = true
  1043  			result := response.(*params.ErrorResults)
  1044  			result.Results = make([]params.ErrorResult, 1)
  1045  			result.Results[0].Error = common.ServerError(common.ErrPerm)
  1046  			return nil
  1047  		})
  1048  	metrics := []params.Metric{{
  1049  		Key: "pings", Value: "5", Time: time.Now().UTC(),
  1050  	}, {
  1051  		Key: "pongs", Value: "6", Time: time.Now().UTC(), Labels: map[string]string{"foo": "bar"},
  1052  	}}
  1053  	uuid := utils.MustNewUUID().String()
  1054  	batch := params.MetricBatch{
  1055  		UUID:     uuid,
  1056  		CharmURL: s.charm.URL().String(),
  1057  		Created:  time.Now(),
  1058  		Metrics:  metrics,
  1059  	}
  1060  
  1061  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
  1062  	c.Assert(err, jc.ErrorIsNil)
  1063  	c.Assert(results, gc.HasLen, 1)
  1064  	c.Assert(results[batch.UUID], gc.ErrorMatches, "permission denied")
  1065  	c.Assert(called, jc.IsTrue)
  1066  }
  1067  
  1068  func (s *unitMetricBatchesSuite) TestSendMetricBatch(c *gc.C) {
  1069  	uuid := utils.MustNewUUID().String()
  1070  	now := time.Now().Round(time.Second).UTC()
  1071  	metrics := []params.Metric{{
  1072  		Key: "pings", Value: "5", Time: now,
  1073  	}, {
  1074  		Key: "pongs", Value: "6", Time: time.Now().UTC(), Labels: map[string]string{"foo": "bar"},
  1075  	}}
  1076  	batch := params.MetricBatch{
  1077  		UUID:     uuid,
  1078  		CharmURL: s.charm.URL().String(),
  1079  		Created:  now,
  1080  		Metrics:  metrics,
  1081  	}
  1082  
  1083  	results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch})
  1084  	c.Assert(err, jc.ErrorIsNil)
  1085  	c.Assert(results, gc.HasLen, 1)
  1086  	c.Assert(results[batch.UUID], gc.IsNil)
  1087  
  1088  	batches, err := s.State.AllMetricBatches()
  1089  	c.Assert(err, gc.IsNil)
  1090  	c.Assert(batches, gc.HasLen, 1)
  1091  	c.Assert(batches[0].UUID(), gc.Equals, uuid)
  1092  	c.Assert(batches[0].Sent(), jc.IsFalse)
  1093  	c.Assert(batches[0].CharmURL(), gc.Equals, s.charm.URL().String())
  1094  	c.Assert(batches[0].Metrics(), gc.HasLen, 2)
  1095  	c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings")
  1096  	c.Assert(batches[0].Metrics()[0].Value, gc.Equals, "5")
  1097  	c.Assert(batches[0].Metrics()[0].Labels, gc.HasLen, 0)
  1098  	c.Assert(batches[0].Metrics()[1].Key, gc.Equals, "pongs")
  1099  	c.Assert(batches[0].Metrics()[1].Value, gc.Equals, "6")
  1100  	c.Assert(batches[0].Metrics()[1].Labels, gc.DeepEquals, map[string]string{"foo": "bar"})
  1101  }