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