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