github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/runner/context/flush_test.go (about)

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package context_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	"github.com/juju/utils"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/network"
    15  	"github.com/juju/juju/worker/metrics/spool"
    16  	"github.com/juju/juju/worker/uniter/runner/context"
    17  	runnertesting "github.com/juju/juju/worker/uniter/runner/testing"
    18  )
    19  
    20  type FlushContextSuite struct {
    21  	HookContextSuite
    22  	stub testing.Stub
    23  }
    24  
    25  var _ = gc.Suite(&FlushContextSuite{})
    26  
    27  func (s *FlushContextSuite) SetUpTest(c *gc.C) {
    28  	s.HookContextSuite.SetUpTest(c)
    29  	s.stub.ResetCalls()
    30  }
    31  
    32  func (s *FlushContextSuite) TestRunHookRelationFlushingError(c *gc.C) {
    33  	ctx := s.context(c)
    34  
    35  	// Mess with multiple relation settings.
    36  	relCtx0, err := ctx.Relation(0)
    37  	c.Assert(err, jc.ErrorIsNil)
    38  	node0, err := relCtx0.Settings()
    39  	c.Assert(err, jc.ErrorIsNil)
    40  	node0.Set("foo", "1")
    41  	relCtx1, err := ctx.Relation(1)
    42  	c.Assert(err, jc.ErrorIsNil)
    43  	node1, err := relCtx1.Settings()
    44  	c.Assert(err, jc.ErrorIsNil)
    45  	node1.Set("bar", "2")
    46  
    47  	// Flush the context with a failure.
    48  	err = ctx.Flush("some badge", errors.New("blam pow"))
    49  	c.Assert(err, gc.ErrorMatches, "blam pow")
    50  
    51  	// Check that the changes have not been written to state.
    52  	settings0, err := s.relunits[0].ReadSettings("u/0")
    53  	c.Assert(err, jc.ErrorIsNil)
    54  	c.Assert(settings0, gc.DeepEquals, map[string]interface{}{"relation-name": "db0"})
    55  	settings1, err := s.relunits[1].ReadSettings("u/0")
    56  	c.Assert(err, jc.ErrorIsNil)
    57  	c.Assert(settings1, gc.DeepEquals, map[string]interface{}{"relation-name": "db1"})
    58  }
    59  
    60  func (s *FlushContextSuite) TestRunHookRelationFlushingSuccess(c *gc.C) {
    61  	ctx := s.context(c)
    62  
    63  	// Mess with multiple relation settings.
    64  	relCtx0, err := ctx.Relation(0)
    65  	c.Assert(err, jc.ErrorIsNil)
    66  	node0, err := relCtx0.Settings()
    67  	c.Assert(err, jc.ErrorIsNil)
    68  	node0.Set("baz", "3")
    69  	relCtx1, err := ctx.Relation(1)
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	node1, err := relCtx1.Settings()
    72  	c.Assert(err, jc.ErrorIsNil)
    73  	node1.Set("qux", "4")
    74  
    75  	// Flush the context with a success.
    76  	err = ctx.Flush("some badge", nil)
    77  	c.Assert(err, jc.ErrorIsNil)
    78  
    79  	// Check that the changes have been written to state.
    80  	settings0, err := s.relunits[0].ReadSettings("u/0")
    81  	c.Assert(err, jc.ErrorIsNil)
    82  	c.Assert(settings0, gc.DeepEquals, map[string]interface{}{
    83  		"relation-name": "db0",
    84  		"baz":           "3",
    85  	})
    86  	settings1, err := s.relunits[1].ReadSettings("u/0")
    87  	c.Assert(err, jc.ErrorIsNil)
    88  	c.Assert(settings1, gc.DeepEquals, map[string]interface{}{
    89  		"relation-name": "db1",
    90  		"qux":           "4",
    91  	})
    92  }
    93  
    94  func (s *FlushContextSuite) TestRunHookOpensAndClosesPendingPorts(c *gc.C) {
    95  	// Initially, no port ranges are open on the unit or its machine.
    96  	unitRanges, err := s.unit.OpenedPorts()
    97  	c.Assert(err, jc.ErrorIsNil)
    98  	c.Assert(unitRanges, gc.HasLen, 0)
    99  	machinePorts, err := s.machine.AllPorts()
   100  	c.Assert(err, jc.ErrorIsNil)
   101  	c.Assert(machinePorts, gc.HasLen, 0)
   102  
   103  	// Add another unit on the same machine.
   104  	otherUnit, err := s.service.AddUnit()
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	err = otherUnit.AssignToMachine(s.machine)
   107  	c.Assert(err, jc.ErrorIsNil)
   108  
   109  	// Open some ports on both units.
   110  	err = s.unit.OpenPorts("tcp", 100, 200)
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	err = otherUnit.OpenPorts("udp", 200, 300)
   113  	c.Assert(err, jc.ErrorIsNil)
   114  
   115  	unitRanges, err = s.unit.OpenedPorts()
   116  	c.Assert(err, jc.ErrorIsNil)
   117  	c.Assert(unitRanges, jc.DeepEquals, []network.PortRange{
   118  		{100, 200, "tcp"},
   119  	})
   120  
   121  	ctx := s.context(c)
   122  
   123  	// Try opening some ports via the context.
   124  	err = ctx.OpenPorts("tcp", 100, 200)
   125  	c.Assert(err, jc.ErrorIsNil) // duplicates are ignored
   126  	err = ctx.OpenPorts("udp", 200, 300)
   127  	c.Assert(err, gc.ErrorMatches, `cannot open 200-300/udp \(unit "u/0"\): conflicts with existing 200-300/udp \(unit "u/1"\)`)
   128  	err = ctx.OpenPorts("udp", 100, 200)
   129  	c.Assert(err, gc.ErrorMatches, `cannot open 100-200/udp \(unit "u/0"\): conflicts with existing 200-300/udp \(unit "u/1"\)`)
   130  	err = ctx.OpenPorts("udp", 10, 20)
   131  	c.Assert(err, jc.ErrorIsNil)
   132  	err = ctx.OpenPorts("tcp", 50, 100)
   133  	c.Assert(err, gc.ErrorMatches, `cannot open 50-100/tcp \(unit "u/0"\): conflicts with existing 100-200/tcp \(unit "u/0"\)`)
   134  	err = ctx.OpenPorts("tcp", 50, 80)
   135  	c.Assert(err, jc.ErrorIsNil)
   136  	err = ctx.OpenPorts("tcp", 40, 90)
   137  	c.Assert(err, gc.ErrorMatches, `cannot open 40-90/tcp \(unit "u/0"\): conflicts with 50-80/tcp requested earlier`)
   138  
   139  	// Now try closing some ports as well.
   140  	err = ctx.ClosePorts("udp", 8080, 8088)
   141  	c.Assert(err, jc.ErrorIsNil) // not existing -> ignored
   142  	err = ctx.ClosePorts("tcp", 100, 200)
   143  	c.Assert(err, jc.ErrorIsNil)
   144  	err = ctx.ClosePorts("tcp", 100, 200)
   145  	c.Assert(err, jc.ErrorIsNil) // duplicates are ignored
   146  	err = ctx.ClosePorts("udp", 200, 300)
   147  	c.Assert(err, gc.ErrorMatches, `cannot close 200-300/udp \(opened by "u/1"\) from "u/0"`)
   148  	err = ctx.ClosePorts("tcp", 50, 80)
   149  	c.Assert(err, jc.ErrorIsNil) // still pending -> no longer pending
   150  
   151  	// Ensure the ports are not actually changed on the unit yet.
   152  	unitRanges, err = s.unit.OpenedPorts()
   153  	c.Assert(err, jc.ErrorIsNil)
   154  	c.Assert(unitRanges, jc.DeepEquals, []network.PortRange{
   155  		{100, 200, "tcp"},
   156  	})
   157  
   158  	// Flush the context with a success.
   159  	err = ctx.Flush("some badge", nil)
   160  	c.Assert(err, jc.ErrorIsNil)
   161  
   162  	// Verify the unit ranges are now open.
   163  	expectUnitRanges := []network.PortRange{
   164  		{FromPort: 10, ToPort: 20, Protocol: "udp"},
   165  	}
   166  	unitRanges, err = s.unit.OpenedPorts()
   167  	c.Assert(err, jc.ErrorIsNil)
   168  	c.Assert(unitRanges, jc.DeepEquals, expectUnitRanges)
   169  }
   170  
   171  func (s *FlushContextSuite) TestRunHookAddStorageOnFailure(c *gc.C) {
   172  	ctx := s.context(c)
   173  	c.Assert(ctx.UnitName(), gc.Equals, "u/0")
   174  
   175  	size := uint64(1)
   176  	ctx.AddUnitStorage(
   177  		map[string]params.StorageConstraints{
   178  			"allecto": params.StorageConstraints{Size: &size},
   179  		})
   180  
   181  	// Flush the context with an error.
   182  	msg := "test fail run hook"
   183  	err := ctx.Flush("test fail run hook", errors.New(msg))
   184  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   185  
   186  	all, err := s.State.AllStorageInstances()
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	c.Assert(all, gc.HasLen, 0)
   189  }
   190  
   191  func (s *FlushContextSuite) TestRunHookAddUnitStorageOnSuccess(c *gc.C) {
   192  	ctx := s.context(c)
   193  	c.Assert(ctx.UnitName(), gc.Equals, "u/0")
   194  
   195  	size := uint64(1)
   196  	ctx.AddUnitStorage(
   197  		map[string]params.StorageConstraints{
   198  			"allecto": params.StorageConstraints{Size: &size},
   199  		})
   200  
   201  	// Flush the context with a success.
   202  	err := ctx.Flush("success", nil)
   203  	c.Assert(errors.Cause(err), gc.ErrorMatches, `.*storage "allecto" not found.*`)
   204  
   205  	all, err := s.State.AllStorageInstances()
   206  	c.Assert(err, jc.ErrorIsNil)
   207  	c.Assert(all, gc.HasLen, 0)
   208  }
   209  
   210  func (s *HookContextSuite) context(c *gc.C) *context.HookContext {
   211  	uuid, err := utils.NewUUID()
   212  	c.Assert(err, jc.ErrorIsNil)
   213  	return s.getHookContext(c, uuid.String(), -1, "", noProxies)
   214  }
   215  
   216  func (s *FlushContextSuite) TestBuiltinMetricNotGeneratedIfNotDefined(c *gc.C) {
   217  	uuid := utils.MustNewUUID()
   218  	paths := runnertesting.NewRealPaths(c)
   219  	ctx := s.getMeteredHookContext(c, uuid.String(), -1, "", noProxies, true, s.metricsDefinition("pings"), paths)
   220  	reader, err := spool.NewJSONMetricReader(
   221  		paths.GetMetricsSpoolDir(),
   222  	)
   223  
   224  	err = ctx.Flush("some badge", nil)
   225  	c.Assert(err, jc.ErrorIsNil)
   226  	batches, err := reader.Read()
   227  	c.Assert(err, jc.ErrorIsNil)
   228  	c.Assert(batches, gc.HasLen, 0)
   229  }