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 }