OLD | NEW |
1 // Copyright 2014 Canonical Ltd. | 1 // Copyright 2014 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package state_test | 4 package state_test |
5 | 5 |
6 import ( | 6 import ( |
| 7 "github.com/juju/loggo" |
7 jc "github.com/juju/testing/checkers" | 8 jc "github.com/juju/testing/checkers" |
8 gc "launchpad.net/gocheck" | 9 gc "launchpad.net/gocheck" |
9 | 10 |
10 "launchpad.net/juju-core/state" | 11 "launchpad.net/juju-core/state" |
11 ) | 12 ) |
12 | 13 |
13 type ActionSuite struct { | 14 type ActionSuite struct { |
14 ConnSuite | 15 ConnSuite |
15 charm *state.Charm | 16 charm *state.Charm |
16 service *state.Service | 17 service *state.Service |
17 unit *state.Unit | 18 unit *state.Unit |
18 } | 19 } |
19 | 20 |
20 var _ = gc.Suite(&ActionSuite{}) | 21 var _ = gc.Suite(&ActionSuite{}) |
21 | 22 |
22 func (s *ActionSuite) SetUpTest(c *gc.C) { | 23 func (s *ActionSuite) SetUpTest(c *gc.C) { |
23 s.ConnSuite.SetUpTest(c) | 24 s.ConnSuite.SetUpTest(c) |
24 s.charm = s.AddTestingCharm(c, "wordpress") | 25 s.charm = s.AddTestingCharm(c, "wordpress") |
25 var err error | 26 var err error |
26 s.service = s.AddTestingService(c, "wordpress", s.charm) | 27 s.service = s.AddTestingService(c, "wordpress", s.charm) |
27 c.Assert(err, gc.IsNil) | 28 c.Assert(err, gc.IsNil) |
28 s.unit, err = s.service.AddUnit() | 29 s.unit, err = s.service.AddUnit() |
29 c.Assert(err, gc.IsNil) | 30 c.Assert(err, gc.IsNil) |
30 c.Assert(s.unit.Series(), gc.Equals, "quantal") | 31 c.Assert(s.unit.Series(), gc.Equals, "quantal") |
31 } | 32 } |
32 | 33 |
33 func (s *ActionSuite) TestAddAction(c *gc.C) { | 34 func (s *ActionSuite) TestAddAction(c *gc.C) { |
34 » actionName := "fakeaction" | 35 » name := "fakeaction" |
35 » actionParams := map[string]interface{}{"outfile": "outfile.tar.bz2"} | 36 » params := map[string]interface{}{"outfile": "outfile.tar.bz2"} |
36 | 37 |
37 // verify can add an Action | 38 // verify can add an Action |
38 » actionId, err := s.unit.AddAction(actionName, actionParams) | 39 » id, err := s.unit.AddAction(name, params) |
39 c.Assert(err, gc.IsNil) | 40 c.Assert(err, gc.IsNil) |
40 » assertSaneActionId(c, actionId, s.unit.Name()) | 41 » assertSaneActionId(c, id, s.unit.Name()) |
41 | 42 |
42 // verify we can get it back out by Id | 43 // verify we can get it back out by Id |
43 » action, err := s.State.Action(actionId) | 44 » action, err := s.State.Action(id) |
44 c.Assert(err, gc.IsNil) | 45 c.Assert(err, gc.IsNil) |
45 c.Assert(action, gc.NotNil) | 46 c.Assert(action, gc.NotNil) |
46 » c.Assert(action.Id(), gc.Equals, actionId) | 47 » c.Assert(action.Id(), gc.Equals, id) |
47 | 48 |
48 // verify we get out what we put in | 49 // verify we get out what we put in |
49 » c.Assert(action.Name(), gc.Equals, actionName) | 50 » c.Assert(action.Name(), gc.Equals, name) |
50 » c.Assert(action.Payload(), jc.DeepEquals, actionParams) | 51 » c.Assert(action.Payload(), jc.DeepEquals, params) |
| 52 } |
| 53 |
| 54 func (s *ActionSuite) TestAddActionAcceptsDuplicateNames(c *gc.C) { |
| 55 » name := "fakeaction" |
| 56 » params_1 := map[string]interface{}{"outfile": "outfile.tar.bz2"} |
| 57 » params_2 := map[string]interface{}{"infile": "infile.zip"} |
| 58 |
| 59 » // verify can add two actions with same name |
| 60 » id_1, err := s.unit.AddAction(name, params_1) |
| 61 » c.Assert(err, gc.IsNil) |
| 62 » assertSaneActionId(c, id_1, s.unit.Name()) |
| 63 |
| 64 » id_2, err := s.unit.AddAction(name, params_2) |
| 65 » c.Assert(err, gc.IsNil) |
| 66 » assertSaneActionId(c, id_2, s.unit.Name()) |
| 67 |
| 68 » c.Assert(id_1, gc.Not(gc.Equals), id_2) |
| 69 |
| 70 » // verify both actually got added |
| 71 » actions, err := s.State.UnitActions(s.unit.Name()) |
| 72 » c.Assert(err, gc.IsNil) |
| 73 » c.Assert(len(actions), gc.Equals, 2) |
| 74 |
| 75 » // verify we can Fail one, retrieve the other, and they're not mixed up |
| 76 » action_1, err := s.State.Action(id_1) |
| 77 » c.Assert(err, gc.IsNil) |
| 78 » err = action_1.Fail("") |
| 79 » c.Assert(err, gc.IsNil) |
| 80 |
| 81 » action_2, err := s.State.Action(id_2) |
| 82 » c.Assert(err, gc.IsNil) |
| 83 » c.Assert(action_2.Payload(), gc.DeepEquals, params_2) |
| 84 |
| 85 » // verify only one left, and it's the expected one |
| 86 » actions, err = s.State.UnitActions(s.unit.Name()) |
| 87 » c.Assert(err, gc.IsNil) |
| 88 » c.Assert(len(actions), gc.Equals, 1) |
| 89 » c.Assert(actions[0].Id(), gc.Equals, id_2) |
51 } | 90 } |
52 | 91 |
53 func (s *ActionSuite) TestAddActionLifecycle(c *gc.C) { | 92 func (s *ActionSuite) TestAddActionLifecycle(c *gc.C) { |
54 unit, err := s.State.Unit(s.unit.Name()) | 93 unit, err := s.State.Unit(s.unit.Name()) |
55 c.Assert(err, gc.IsNil) | 94 c.Assert(err, gc.IsNil) |
56 preventUnitDestroyRemove(c, unit) | 95 preventUnitDestroyRemove(c, unit) |
57 | 96 |
58 // make unit state Dying | 97 // make unit state Dying |
59 err = unit.Destroy() | 98 err = unit.Destroy() |
60 c.Assert(err, gc.IsNil) | 99 c.Assert(err, gc.IsNil) |
61 | 100 |
62 // can add action to a dying unit | 101 // can add action to a dying unit |
63 » actionId, err := unit.AddAction("fakeaction1", map[string]interface{}{}) | 102 » id, err := unit.AddAction("fakeaction1", map[string]interface{}{}) |
64 c.Assert(err, gc.IsNil) | 103 c.Assert(err, gc.IsNil) |
65 » assertSaneActionId(c, actionId, s.unit.Name()) | 104 » assertSaneActionId(c, id, s.unit.Name()) |
66 | 105 |
67 // make sure unit is dead | 106 // make sure unit is dead |
68 err = unit.EnsureDead() | 107 err = unit.EnsureDead() |
69 c.Assert(err, gc.IsNil) | 108 c.Assert(err, gc.IsNil) |
70 | 109 |
71 // cannot add action to a dead unit | 110 // cannot add action to a dead unit |
72 _, err = unit.AddAction("fakeaction2", map[string]interface{}{}) | 111 _, err = unit.AddAction("fakeaction2", map[string]interface{}{}) |
73 c.Assert(err, gc.ErrorMatches, "unit .* is dead") | 112 c.Assert(err, gc.ErrorMatches, "unit .* is dead") |
74 } | 113 } |
75 | 114 |
76 func (s *ActionSuite) TestAddActionFailsOnDeadUnitInTransaction(c *gc.C) { | 115 func (s *ActionSuite) TestAddActionFailsOnDeadUnitInTransaction(c *gc.C) { |
77 unit, err := s.State.Unit(s.unit.Name()) | 116 unit, err := s.State.Unit(s.unit.Name()) |
78 c.Assert(err, gc.IsNil) | 117 c.Assert(err, gc.IsNil) |
79 preventUnitDestroyRemove(c, unit) | 118 preventUnitDestroyRemove(c, unit) |
80 | 119 |
81 killUnit := state.TransactionHook{ | 120 killUnit := state.TransactionHook{ |
82 Before: func() { | 121 Before: func() { |
83 c.Assert(unit.Destroy(), gc.IsNil) | 122 c.Assert(unit.Destroy(), gc.IsNil) |
84 c.Assert(unit.EnsureDead(), gc.IsNil) | 123 c.Assert(unit.EnsureDead(), gc.IsNil) |
85 }, | 124 }, |
86 } | 125 } |
87 defer state.SetTransactionHooks(c, s.State, killUnit).Check() | 126 defer state.SetTransactionHooks(c, s.State, killUnit).Check() |
88 | 127 |
89 _, err = unit.AddAction("fakeaction", map[string]interface{}{}) | 128 _, err = unit.AddAction("fakeaction", map[string]interface{}{}) |
90 c.Assert(err, gc.ErrorMatches, "unit .* is dead") | 129 c.Assert(err, gc.ErrorMatches, "unit .* is dead") |
91 } | 130 } |
92 | 131 |
93 // assertSaneActionId verifies that the actionId is of the expected | 132 func (s *ActionSuite) TestFail(c *gc.C) { |
| 133 » // TODO(jcw4): when action results are implemented we should be |
| 134 » // checking for a Fail result after calling Fail(), rather than |
| 135 » // sniffing the logs |
| 136 » defer loggo.ResetWriters() |
| 137 » logger := loggo.GetLogger("test") |
| 138 » logger.SetLogLevel(loggo.DEBUG) |
| 139 » tw := &loggo.TestWriter{} |
| 140 » c.Assert(loggo.RegisterWriter("actions-tester", tw, loggo.DEBUG), gc.IsN
il) |
| 141 |
| 142 » // get unit, add an action, retrieve that action |
| 143 » unit, err := s.State.Unit(s.unit.Name()) |
| 144 » c.Assert(err, gc.IsNil) |
| 145 » preventUnitDestroyRemove(c, unit) |
| 146 |
| 147 » id, err := unit.AddAction("action1", nil) |
| 148 » c.Assert(err, gc.IsNil) |
| 149 |
| 150 » action, err := s.State.Action(id) |
| 151 » c.Assert(err, gc.IsNil) |
| 152 |
| 153 » // fail the action, and verify that it succeeds (right now, just by |
| 154 » // sniffing the logs) |
| 155 » reason := "test fail reason" |
| 156 » err = action.Fail(reason) |
| 157 » c.Assert(err, gc.IsNil) |
| 158 » // TODO(jcw4): replace with action results check when they're implemente
d |
| 159 » c.Assert(tw.Log, jc.LogMatches, jc.SimpleMessages{{loggo.WARNING, reason
}}) |
| 160 |
| 161 » // validate that a failed action is no longer returned by UnitActions. |
| 162 » actions, err := s.State.UnitActions(unit.Name()) |
| 163 » c.Assert(err, gc.IsNil) |
| 164 » c.Assert(len(actions), gc.Equals, 0) |
| 165 } |
| 166 |
| 167 // assertSaneActionId verifies that the id is of the expected |
94 // form (unit id prefix + sequence) | 168 // form (unit id prefix + sequence) |
95 // This is a temporary assertion, we shouldn't be leaking the actual | 169 // This is a temporary assertion, we shouldn't be leaking the actual |
96 // mongo _id | 170 // mongo _id |
97 func assertSaneActionId(c *gc.C, actionId, unitName string) { | 171 func assertSaneActionId(c *gc.C, id, unitName string) { |
98 » c.Assert(actionId, gc.Matches, "^u#"+unitName+"#\\d+") | 172 » c.Assert(id, gc.Matches, "^u#"+unitName+"#a#\\d+") |
99 } | 173 } |
OLD | NEW |