github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/action/showoutput_test.go (about) 1 // Copyright 2014-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package action_test 5 6 import ( 7 "bytes" 8 "errors" 9 "strings" 10 "time" 11 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/cmd/juju/action" 17 "github.com/juju/juju/testing" 18 ) 19 20 type ShowOutputSuite struct { 21 BaseActionSuite 22 } 23 24 var _ = gc.Suite(&ShowOutputSuite{}) 25 26 func (s *ShowOutputSuite) SetUpTest(c *gc.C) { 27 s.BaseActionSuite.SetUpTest(c) 28 } 29 30 func (s *ShowOutputSuite) TestInit(c *gc.C) { 31 tests := []struct { 32 should string 33 args []string 34 expectError string 35 }{{ 36 should: "fail with missing arg", 37 args: []string{}, 38 expectError: "no action ID specified", 39 }, { 40 should: "fail with multiple args", 41 args: []string{"12345", "54321"}, 42 expectError: `unrecognized args: \["54321"\]`, 43 }} 44 45 for i, t := range tests { 46 for _, modelFlag := range s.modelFlags { 47 c.Logf("test %d: it should %s: juju show-action-output %s", i, 48 t.should, strings.Join(t.args, " ")) 49 cmd, _ := action.NewShowOutputCommandForTest(s.store) 50 args := append([]string{modelFlag, "admin"}, t.args...) 51 err := testing.InitCommand(cmd, args) 52 if t.expectError != "" { 53 c.Check(err, gc.ErrorMatches, t.expectError) 54 } 55 } 56 } 57 } 58 59 func (s *ShowOutputSuite) TestRun(c *gc.C) { 60 tests := []struct { 61 should string 62 withClientWait string 63 withClientQueryID string 64 withAPIDelay time.Duration 65 withAPITimeout time.Duration 66 withTags params.FindTagsResults 67 withAPIResponse []params.ActionResult 68 withAPIError string 69 expectedErr string 70 expectedOutput string 71 }{{ 72 should: "handle wait-time formatting errors", 73 withClientWait: "not-a-duration-at-all", 74 expectedErr: "time: invalid duration not-a-duration-at-all", 75 }, { 76 should: "timeout if result never comes", 77 withClientWait: "3s", 78 withAPIDelay: 6 * time.Second, 79 withAPITimeout: 10 * time.Second, 80 withClientQueryID: validActionId, 81 withTags: tagsForIdPrefix(validActionId, validActionTagString), 82 withAPIResponse: []params.ActionResult{{}}, 83 expectedOutput: ` 84 status: pending 85 timing: 86 enqueued: 2015-02-14 08:13:00 +0000 UTC 87 started: 2015-02-14 08:15:00 +0000 UTC 88 `[1:], 89 }, { 90 should: "pass api error through properly", 91 withClientQueryID: validActionId, 92 withAPITimeout: 10 * time.Second, 93 withTags: tagsForIdPrefix(validActionId, validActionTagString), 94 withAPIError: "api call error", 95 expectedErr: "api call error", 96 }, { 97 should: "fail with no tag matches", 98 withClientQueryID: validActionId, 99 withAPITimeout: 10 * time.Second, 100 withTags: tagsForIdPrefix(validActionId), 101 expectedErr: `actions for identifier "` + validActionId + `" not found`, 102 }, { 103 should: "fail with no results", 104 withClientQueryID: validActionId, 105 withAPITimeout: 10 * time.Second, 106 withTags: tagsForIdPrefix(validActionId, validActionTagString), 107 withAPIResponse: []params.ActionResult{}, 108 expectedErr: "no results for action " + validActionId, 109 }, { 110 should: "error correctly with multiple results", 111 withClientQueryID: validActionId, 112 withAPITimeout: 10 * time.Second, 113 withTags: tagsForIdPrefix(validActionId, validActionTagString), 114 withAPIResponse: []params.ActionResult{{}, {}}, 115 expectedErr: "too many results for action " + validActionId, 116 }, { 117 should: "pass through an error from the API server", 118 withClientQueryID: validActionId, 119 withAPITimeout: 10 * time.Second, 120 withTags: tagsForIdPrefix(validActionId, validActionTagString), 121 withAPIResponse: []params.ActionResult{{ 122 Error: common.ServerError(errors.New("an apiserver error")), 123 }}, 124 expectedErr: "an apiserver error", 125 }, { 126 should: "only return once status is no longer running or pending", 127 withAPIDelay: 2 * time.Second, 128 withClientWait: "6s", 129 withClientQueryID: validActionId, 130 withAPITimeout: 4 * time.Second, 131 withTags: tagsForIdPrefix(validActionId, validActionTagString), 132 withAPIResponse: []params.ActionResult{{ 133 Status: "running", 134 Output: map[string]interface{}{ 135 "foo": map[string]interface{}{ 136 "bar": "baz", 137 }, 138 }, 139 Enqueued: time.Date(2015, time.February, 14, 8, 13, 0, 0, time.UTC), 140 Started: time.Date(2015, time.February, 14, 8, 15, 0, 0, time.UTC), 141 }}, 142 expectedErr: "test timed out before wait time", 143 }, { 144 should: "pretty-print action output", 145 withClientQueryID: validActionId, 146 withAPITimeout: 10 * time.Second, 147 withTags: tagsForIdPrefix(validActionId, validActionTagString), 148 withAPIResponse: []params.ActionResult{{ 149 Status: "complete", 150 Message: "oh dear", 151 Output: map[string]interface{}{ 152 "foo": map[string]interface{}{ 153 "bar": "baz", 154 }, 155 }, 156 Enqueued: time.Date(2015, time.February, 14, 8, 13, 0, 0, time.UTC), 157 Started: time.Date(2015, time.February, 14, 8, 15, 0, 0, time.UTC), 158 Completed: time.Date(2015, time.February, 14, 8, 15, 30, 0, time.UTC), 159 }}, 160 expectedOutput: ` 161 message: oh dear 162 results: 163 foo: 164 bar: baz 165 status: complete 166 timing: 167 completed: 2015-02-14 08:15:30 +0000 UTC 168 enqueued: 2015-02-14 08:13:00 +0000 UTC 169 started: 2015-02-14 08:15:00 +0000 UTC 170 `[1:], 171 }, { 172 should: "pretty-print action output with no completed time", 173 withClientQueryID: validActionId, 174 withAPITimeout: 10 * time.Second, 175 withTags: tagsForIdPrefix(validActionId, validActionTagString), 176 withAPIResponse: []params.ActionResult{{ 177 Status: "pending", 178 Output: map[string]interface{}{ 179 "foo": map[string]interface{}{ 180 "bar": "baz", 181 }, 182 }, 183 Enqueued: time.Date(2015, time.February, 14, 8, 13, 0, 0, time.UTC), 184 Started: time.Date(2015, time.February, 14, 8, 15, 0, 0, time.UTC), 185 }}, 186 expectedOutput: ` 187 results: 188 foo: 189 bar: baz 190 status: pending 191 timing: 192 enqueued: 2015-02-14 08:13:00 +0000 UTC 193 started: 2015-02-14 08:15:00 +0000 UTC 194 `[1:], 195 }, { 196 should: "pretty-print action output with no enqueued time", 197 withClientQueryID: validActionId, 198 withAPITimeout: 10 * time.Second, 199 withTags: tagsForIdPrefix(validActionId, validActionTagString), 200 withAPIResponse: []params.ActionResult{{ 201 Status: "pending", 202 Output: map[string]interface{}{ 203 "foo": map[string]interface{}{ 204 "bar": "baz", 205 }, 206 }, 207 Completed: time.Date(2015, time.February, 14, 8, 15, 30, 0, time.UTC), 208 Started: time.Date(2015, time.February, 14, 8, 15, 0, 0, time.UTC), 209 }}, 210 expectedOutput: ` 211 results: 212 foo: 213 bar: baz 214 status: pending 215 timing: 216 completed: 2015-02-14 08:15:30 +0000 UTC 217 started: 2015-02-14 08:15:00 +0000 UTC 218 `[1:], 219 }, { 220 should: "pretty-print action output with no started time", 221 withClientQueryID: validActionId, 222 withAPITimeout: 10 * time.Second, 223 withTags: tagsForIdPrefix(validActionId, validActionTagString), 224 withAPIResponse: []params.ActionResult{{ 225 Status: "pending", 226 Output: map[string]interface{}{ 227 "foo": map[string]interface{}{ 228 "bar": "baz", 229 }, 230 }, 231 Enqueued: time.Date(2015, time.February, 14, 8, 13, 0, 0, time.UTC), 232 Completed: time.Date(2015, time.February, 14, 8, 15, 30, 0, time.UTC), 233 }}, 234 expectedOutput: ` 235 results: 236 foo: 237 bar: baz 238 status: pending 239 timing: 240 completed: 2015-02-14 08:15:30 +0000 UTC 241 enqueued: 2015-02-14 08:13:00 +0000 UTC 242 `[1:], 243 }, { 244 should: "set an appropriate timer and wait, get a result", 245 withClientQueryID: validActionId, 246 withAPITimeout: 10 * time.Second, 247 withClientWait: "4s", 248 withAPIDelay: 2 * time.Second, 249 withTags: tagsForIdPrefix(validActionId, validActionTagString), 250 withAPIResponse: []params.ActionResult{{ 251 Status: "completed", 252 Output: map[string]interface{}{ 253 "foo": map[string]interface{}{ 254 "bar": "baz", 255 }, 256 }, 257 Enqueued: time.Date(2015, time.February, 14, 8, 13, 0, 0, time.UTC), 258 Completed: time.Date(2015, time.February, 14, 8, 15, 30, 0, time.UTC), 259 }}, 260 expectedOutput: ` 261 results: 262 foo: 263 bar: baz 264 status: completed 265 timing: 266 completed: 2015-02-14 08:15:30 +0000 UTC 267 enqueued: 2015-02-14 08:13:00 +0000 UTC 268 `[1:], 269 }} 270 271 for i, t := range tests { 272 for _, modelFlag := range s.modelFlags { 273 c.Logf("test %d (model flag %v): should %s", i, modelFlag, t.should) 274 testRunHelper( 275 c, s, 276 makeFakeClient( 277 t.withAPIDelay, 278 t.withAPITimeout, 279 t.withTags, 280 t.withAPIResponse, 281 params.ActionsByNames{}, 282 t.withAPIError), 283 t.expectedErr, 284 t.expectedOutput, 285 t.withClientWait, 286 t.withClientQueryID, 287 modelFlag, 288 ) 289 } 290 } 291 } 292 293 func testRunHelper(c *gc.C, s *ShowOutputSuite, client *fakeAPIClient, expectedErr, expectedOutput, wait, query, modelFlag string) { 294 unpatch := s.BaseActionSuite.patchAPIClient(client) 295 defer unpatch() 296 args := append([]string{modelFlag, "admin"}, query) 297 if wait != "" { 298 args = append(args, "--wait", wait) 299 } 300 cmd, _ := action.NewShowOutputCommandForTest(s.store) 301 ctx, err := testing.RunCommand(c, cmd, args...) 302 if expectedErr != "" { 303 c.Check(err, gc.ErrorMatches, expectedErr) 304 } else { 305 c.Assert(err, gc.IsNil) 306 c.Check(ctx.Stdout.(*bytes.Buffer).String(), gc.Equals, expectedOutput) 307 } 308 } 309 310 func makeFakeClient( 311 delay, timeout time.Duration, 312 tags params.FindTagsResults, 313 response []params.ActionResult, 314 actionsByNames params.ActionsByNames, 315 errStr string, 316 ) *fakeAPIClient { 317 client := &fakeAPIClient{ 318 delay: time.NewTimer(delay), 319 timeout: time.NewTimer(timeout), 320 actionTagMatches: tags, 321 actionResults: response, 322 actionsByNames: actionsByNames, 323 } 324 if errStr != "" { 325 client.apiErr = errors.New(errStr) 326 } 327 return client 328 }