Merge lp:~jameinel/juju-core/only-943 into lp:~juju/juju-core/trunk
- only-943
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 949 |
Proposed branch: | lp:~jameinel/juju-core/only-943 |
Merge into: | lp:~juju/juju-core/trunk |
Diff against target: |
1612 lines (+497/-125) 50 files modified
cmd/cmd.go (+6/-1) cmd/cmd_test.go (+7/-7) cmd/filevar_test.go (+1/-1) cmd/juju/addrelation_test.go (+2/-1) cmd/juju/addunit_test.go (+2/-1) cmd/juju/bootstrap_test.go (+1/-1) cmd/juju/cmd_test.go (+2/-2) cmd/juju/config_test.go (+4/-3) cmd/juju/constraints_test.go (+2/-1) cmd/juju/deploy_test.go (+2/-1) cmd/juju/destroymachine_test.go (+2/-1) cmd/juju/destroyrelation_test.go (+2/-1) cmd/juju/destroyservice_test.go (+2/-1) cmd/juju/destroyunit_test.go (+2/-1) cmd/juju/expose_test.go (+2/-1) cmd/juju/init_test.go (+5/-5) cmd/juju/resolved_test.go (+2/-1) cmd/juju/scp_test.go (+1/-1) cmd/juju/ssh_test.go (+1/-1) cmd/juju/status_test.go (+1/-1) cmd/juju/unexpose_test.go (+2/-1) cmd/juju/upgradejuju_test.go (+2/-3) cmd/jujud/agent_test.go (+1/-1) cmd/jujud/bootstrap_test.go (+2/-2) cmd/logging_test.go (+4/-4) cmd/output_test.go (+4/-3) cmd/supercommand_test.go (+1/-1) cmd/util_test.go (+0/-5) environs/agent/agent.go (+1/-1) juju/api.go (+1/-1) juju/conn.go (+2/-2) state/api/api_test.go (+2/-2) state/api/error.go (+2/-1) state/open.go (+28/-5) state/state_test.go (+5/-5) state/unit_test.go (+1/-1) store/server.go (+67/-2) store/server_test.go (+47/-4) store/store.go (+164/-19) store/store_test.go (+60/-3) testing/cmd.go (+27/-4) worker/uniter/jujuc/config-get_test.go (+3/-3) worker/uniter/jujuc/ports_test.go (+1/-1) worker/uniter/jujuc/relation-get_test.go (+4/-3) worker/uniter/jujuc/relation-ids_test.go (+3/-2) worker/uniter/jujuc/relation-list_test.go (+3/-2) worker/uniter/jujuc/relation-set_test.go (+2/-2) worker/uniter/jujuc/server.go (+6/-1) worker/uniter/jujuc/unit-get_test.go (+3/-3) worker/uniter/jujuc/util_test.go (+0/-5) |
To merge this branch: | bzr merge lp:~jameinel/juju-core/only-943 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
The Go Language Gophers | Pending | ||
Review via email: mp+151005@code.launchpad.net |
Commit message
Description of the change
revert only r943
William merged a change which reverted trunk back to 942
because rev 943 broke the test suite.
This just re-introduces all of the merges 944-947, so that
Gustavo and Ian don't have to re-propose and get approval
for their changes again.
I've run the test suite to make sure it passes as long as
just 943 has been removed.
In the future, you can just cherrypick-out specific revisions
with (eg):
bzr merge . -r 943..942
And then run the test suite, and propose it. (Which is essentially
what this patch does, except it also reverts 948 which removed
all of those other revisions.)
John A Meinel (jameinel) wrote : | # |
Ian Booth (wallyworld) wrote : | # |
LGTM. Thanks for doing this.
William Reade (fwereade) wrote : | # |
LGTM -- thank you very much.
John A Meinel (jameinel) wrote : | # |
*** Submitted:
revert only r943
William merged a change which reverted trunk back to 942
because rev 943 broke the test suite.
This just re-introduces all of the merges 944-947, so that
Gustavo and Ian don't have to re-propose and get approval
for their changes again.
I've run the test suite to make sure it passes as long as
just 943 has been removed.
In the future, you can just cherrypick-out specific revisions
with (eg):
bzr merge . -r 943..942
And then run the test suite, and propose it. (Which is essentially
what this patch does, except it also reverts 948 which removed
all of those other revisions.)
R=wallyworld, fwereade
CC=
https:/
Preview Diff
1 | === modified file 'cmd/cmd.go' |
2 | --- cmd/cmd.go 2013-02-28 08:11:29 +0000 |
3 | +++ cmd/cmd.go 2013-02-28 12:30:29 +0000 |
4 | @@ -165,7 +165,12 @@ |
5 | if err != nil { |
6 | panic(err) |
7 | } |
8 | - return &Context{abs, os.Stdin, os.Stdout, os.Stderr} |
9 | + return &Context{ |
10 | + Dir: abs, |
11 | + Stdin: os.Stdin, |
12 | + Stdout: os.Stdout, |
13 | + Stderr: os.Stderr, |
14 | + } |
15 | } |
16 | |
17 | // CheckEmpty is a utility function that returns an error if args is not empty. |
18 | |
19 | === modified file 'cmd/cmd_test.go' |
20 | --- cmd/cmd_test.go 2013-02-28 08:11:29 +0000 |
21 | +++ cmd/cmd_test.go 2013-02-28 12:30:29 +0000 |
22 | @@ -16,7 +16,7 @@ |
23 | var _ = Suite(&CmdSuite{}) |
24 | |
25 | func (s *CmdSuite) TestContext(c *C) { |
26 | - ctx := dummyContext(c) |
27 | + ctx := testing.Context(c) |
28 | c.Assert(ctx.AbsPath("/foo/bar"), Equals, "/foo/bar") |
29 | c.Assert(ctx.AbsPath("foo/bar"), Equals, filepath.Join(ctx.Dir, "foo/bar")) |
30 | } |
31 | @@ -49,7 +49,7 @@ |
32 | |
33 | func (s *CmdSuite) TestMainInitError(c *C) { |
34 | for _, t := range initErrorTests { |
35 | - ctx := dummyContext(c) |
36 | + ctx := testing.Context(c) |
37 | result := cmd.Main(t.c, ctx, []string{"--unknown"}) |
38 | c.Assert(result, Equals, 2) |
39 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
40 | @@ -59,7 +59,7 @@ |
41 | } |
42 | |
43 | func (s *CmdSuite) TestMainRunError(c *C) { |
44 | - ctx := dummyContext(c) |
45 | + ctx := testing.Context(c) |
46 | result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "error"}) |
47 | c.Assert(result, Equals, 1) |
48 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
49 | @@ -67,7 +67,7 @@ |
50 | } |
51 | |
52 | func (s *CmdSuite) TestMainRunSilentError(c *C) { |
53 | - ctx := dummyContext(c) |
54 | + ctx := testing.Context(c) |
55 | result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "silent-error"}) |
56 | c.Assert(result, Equals, 1) |
57 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
58 | @@ -75,7 +75,7 @@ |
59 | } |
60 | |
61 | func (s *CmdSuite) TestMainSuccess(c *C) { |
62 | - ctx := dummyContext(c) |
63 | + ctx := testing.Context(c) |
64 | result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "success!"}) |
65 | c.Assert(result, Equals, 0) |
66 | c.Assert(bufferString(ctx.Stdout), Equals, "success!\n") |
67 | @@ -84,7 +84,7 @@ |
68 | |
69 | func (s *CmdSuite) TestStdin(c *C) { |
70 | const phrase = "Do you, Juju?" |
71 | - ctx := dummyContext(c) |
72 | + ctx := testing.Context(c) |
73 | ctx.Stdin = bytes.NewBuffer([]byte(phrase)) |
74 | result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "echo"}) |
75 | c.Assert(result, Equals, 0) |
76 | @@ -94,7 +94,7 @@ |
77 | |
78 | func (s *CmdSuite) TestMainHelp(c *C) { |
79 | for _, arg := range []string{"-h", "--help"} { |
80 | - ctx := dummyContext(c) |
81 | + ctx := testing.Context(c) |
82 | result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{arg}) |
83 | c.Assert(result, Equals, 0) |
84 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
85 | |
86 | === modified file 'cmd/filevar_test.go' |
87 | --- cmd/filevar_test.go 2013-02-28 08:11:29 +0000 |
88 | +++ cmd/filevar_test.go 2013-02-28 12:30:29 +0000 |
89 | @@ -17,7 +17,7 @@ |
90 | var _ = Suite(&FileVarSuite{}) |
91 | |
92 | func (s *FileVarSuite) SetUpTest(c *C) { |
93 | - s.ctx = &cmd.Context{c.MkDir(), nil, nil, nil} |
94 | + s.ctx = testing.Context(c) |
95 | s.ValidPath = s.ctx.AbsPath("valid.yaml") |
96 | s.InvalidPath = s.ctx.AbsPath("invalid.yaml") |
97 | f, err := os.Create(s.ValidPath) |
98 | |
99 | === modified file 'cmd/juju/addrelation_test.go' |
100 | --- cmd/juju/addrelation_test.go 2013-02-28 08:11:29 +0000 |
101 | +++ cmd/juju/addrelation_test.go 2013-02-28 12:30:29 +0000 |
102 | @@ -12,7 +12,8 @@ |
103 | var _ = Suite(&AddRelationSuite{}) |
104 | |
105 | func runAddRelation(c *C, args ...string) error { |
106 | - return testing.RunCommand(c, &AddRelationCommand{}, args) |
107 | + _, err := testing.RunCommand(c, &AddRelationCommand{}, args) |
108 | + return err |
109 | } |
110 | |
111 | var msWpAlreadyExists = `cannot add relation "wp:db ms:server": relation already exists` |
112 | |
113 | === modified file 'cmd/juju/addunit_test.go' |
114 | --- cmd/juju/addunit_test.go 2013-02-28 08:11:29 +0000 |
115 | +++ cmd/juju/addunit_test.go 2013-02-28 12:30:29 +0000 |
116 | @@ -13,7 +13,8 @@ |
117 | var _ = Suite(&AddUnitSuite{}) |
118 | |
119 | func runAddUnit(c *C, args ...string) error { |
120 | - return testing.RunCommand(c, &AddUnitCommand{}, args) |
121 | + _, err := testing.RunCommand(c, &AddUnitCommand{}, args) |
122 | + return err |
123 | } |
124 | |
125 | func (s *AddUnitSuite) TestAddUnit(c *C) { |
126 | |
127 | === modified file 'cmd/juju/bootstrap_test.go' |
128 | --- cmd/juju/bootstrap_test.go 2013-02-28 08:11:29 +0000 |
129 | +++ cmd/juju/bootstrap_test.go 2013-02-28 12:30:29 +0000 |
130 | @@ -91,7 +91,7 @@ |
131 | func (*BootstrapSuite) TestMissingEnvironment(c *C) { |
132 | defer makeFakeHome(c, "empty").restore() |
133 | // bootstrap without an environments.yaml |
134 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
135 | + ctx := testing.Context(c) |
136 | code := cmd.Main(&BootstrapCommand{}, ctx, nil) |
137 | c.Check(code, Equals, 1) |
138 | errStr := ctx.Stderr.(*bytes.Buffer).String() |
139 | |
140 | === modified file 'cmd/juju/cmd_test.go' |
141 | --- cmd/juju/cmd_test.go 2013-02-28 08:11:29 +0000 |
142 | +++ cmd/juju/cmd_test.go 2013-02-28 12:30:29 +0000 |
143 | @@ -198,7 +198,7 @@ |
144 | } |
145 | |
146 | // test relative --config path |
147 | - ctx := &cmd.Context{c.MkDir(), nil, nil, nil} |
148 | + ctx := coretesting.Context(c) |
149 | expected := []byte("test: data") |
150 | path := ctx.AbsPath("testconfig.yaml") |
151 | file, err := os.Create(path) |
152 | @@ -323,7 +323,7 @@ |
153 | |
154 | // test --config path |
155 | expected := []byte("this: is some test data") |
156 | - ctx := &cmd.Context{c.MkDir(), nil, nil, nil} |
157 | + ctx := coretesting.Context(c) |
158 | path := ctx.AbsPath("testconfig.yaml") |
159 | file, err := os.Create(path) |
160 | c.Assert(err, IsNil) |
161 | |
162 | === modified file 'cmd/juju/config_test.go' |
163 | --- cmd/juju/config_test.go 2013-02-28 08:11:29 +0000 |
164 | +++ cmd/juju/config_test.go 2013-02-28 12:30:29 +0000 |
165 | @@ -8,6 +8,7 @@ |
166 | "launchpad.net/goyaml" |
167 | "launchpad.net/juju-core/cmd" |
168 | "launchpad.net/juju-core/juju/testing" |
169 | + coretesting "launchpad.net/juju-core/testing" |
170 | ) |
171 | |
172 | // juju get and set tests (because one needs the other) |
173 | @@ -61,7 +62,7 @@ |
174 | _, err := s.State.AddService("dummy-service", sch) |
175 | c.Assert(err, IsNil) |
176 | for _, t := range getTests { |
177 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
178 | + ctx := coretesting.Context(c) |
179 | code := cmd.Main(&GetCommand{}, ctx, []string{t.service}) |
180 | c.Check(code, Equals, 0) |
181 | c.Assert(ctx.Stderr.(*bytes.Buffer).String(), Equals, "") |
182 | @@ -129,7 +130,7 @@ |
183 | for i, t := range setTests { |
184 | args := append([]string{"dummy-service"}, t.args...) |
185 | c.Logf("test %d. %s", i, t.about) |
186 | - ctx := &cmd.Context{dir, &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
187 | + ctx := coretesting.ContextForDir(c, dir) |
188 | code := cmd.Main(&SetCommand{}, ctx, args) |
189 | if t.err != "" { |
190 | c.Check(code, Not(Equals), 0) |
191 | @@ -144,7 +145,7 @@ |
192 | } |
193 | |
194 | func setupConfigfile(c *C, dir string) { |
195 | - ctx := &cmd.Context{dir, nil, nil, nil} |
196 | + ctx := coretesting.ContextForDir(c, dir) |
197 | path := ctx.AbsPath("testconfig.yaml") |
198 | file, err := os.Create(path) |
199 | c.Assert(err, IsNil) |
200 | |
201 | === modified file 'cmd/juju/constraints_test.go' |
202 | --- cmd/juju/constraints_test.go 2013-02-28 08:11:29 +0000 |
203 | +++ cmd/juju/constraints_test.go 2013-02-28 12:30:29 +0000 |
204 | @@ -6,6 +6,7 @@ |
205 | "launchpad.net/juju-core/cmd" |
206 | "launchpad.net/juju-core/juju/testing" |
207 | "launchpad.net/juju-core/state" |
208 | + coretesting "launchpad.net/juju-core/testing" |
209 | ) |
210 | |
211 | type ConstraintsCommandsSuite struct { |
212 | @@ -15,7 +16,7 @@ |
213 | var _ = Suite(&ConstraintsCommandsSuite{}) |
214 | |
215 | func runCmdLine(c *C, com cmd.Command, args ...string) (code int, stdout, stderr string) { |
216 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
217 | + ctx := coretesting.Context(c) |
218 | code = cmd.Main(com, ctx, args) |
219 | stdout = ctx.Stdout.(*bytes.Buffer).String() |
220 | stderr = ctx.Stderr.(*bytes.Buffer).String() |
221 | |
222 | === modified file 'cmd/juju/deploy_test.go' |
223 | --- cmd/juju/deploy_test.go 2013-02-28 08:11:29 +0000 |
224 | +++ cmd/juju/deploy_test.go 2013-02-28 12:30:29 +0000 |
225 | @@ -106,7 +106,8 @@ |
226 | var _ = Suite(&DeploySuite{}) |
227 | |
228 | func runDeploy(c *C, args ...string) error { |
229 | - return coretesting.RunCommand(c, &DeployCommand{}, args) |
230 | + _, err := coretesting.RunCommand(c, &DeployCommand{}, args) |
231 | + return err |
232 | } |
233 | |
234 | var initErrorTests = []struct { |
235 | |
236 | === modified file 'cmd/juju/destroymachine_test.go' |
237 | --- cmd/juju/destroymachine_test.go 2013-02-28 08:11:29 +0000 |
238 | +++ cmd/juju/destroymachine_test.go 2013-02-28 12:30:29 +0000 |
239 | @@ -13,7 +13,8 @@ |
240 | var _ = Suite(&DestroyMachineSuite{}) |
241 | |
242 | func runDestroyMachine(c *C, args ...string) error { |
243 | - return testing.RunCommand(c, &DestroyMachineCommand{}, args) |
244 | + _, err := testing.RunCommand(c, &DestroyMachineCommand{}, args) |
245 | + return err |
246 | } |
247 | |
248 | func (s *DestroyMachineSuite) TestDestroyMachine(c *C) { |
249 | |
250 | === modified file 'cmd/juju/destroyrelation_test.go' |
251 | --- cmd/juju/destroyrelation_test.go 2013-02-28 08:11:29 +0000 |
252 | +++ cmd/juju/destroyrelation_test.go 2013-02-28 12:30:29 +0000 |
253 | @@ -12,7 +12,8 @@ |
254 | var _ = Suite(&DestroyRelationSuite{}) |
255 | |
256 | func runDestroyRelation(c *C, args ...string) error { |
257 | - return testing.RunCommand(c, &DestroyRelationCommand{}, args) |
258 | + _, err := testing.RunCommand(c, &DestroyRelationCommand{}, args) |
259 | + return err |
260 | } |
261 | |
262 | func (s *DestroyRelationSuite) TestDestroyRelation(c *C) { |
263 | |
264 | === modified file 'cmd/juju/destroyservice_test.go' |
265 | --- cmd/juju/destroyservice_test.go 2013-02-28 08:11:29 +0000 |
266 | +++ cmd/juju/destroyservice_test.go 2013-02-28 12:30:29 +0000 |
267 | @@ -13,7 +13,8 @@ |
268 | var _ = Suite(&DestroyServiceSuite{}) |
269 | |
270 | func runDestroyService(c *C, args ...string) error { |
271 | - return testing.RunCommand(c, &DestroyServiceCommand{}, args) |
272 | + _, err := testing.RunCommand(c, &DestroyServiceCommand{}, args) |
273 | + return err |
274 | } |
275 | |
276 | func (s *DestroyServiceSuite) TestSuccess(c *C) { |
277 | |
278 | === modified file 'cmd/juju/destroyunit_test.go' |
279 | --- cmd/juju/destroyunit_test.go 2013-02-28 08:11:29 +0000 |
280 | +++ cmd/juju/destroyunit_test.go 2013-02-28 12:30:29 +0000 |
281 | @@ -14,7 +14,8 @@ |
282 | var _ = Suite(&DestroyUnitSuite{}) |
283 | |
284 | func runDestroyUnit(c *C, args ...string) error { |
285 | - return testing.RunCommand(c, &DestroyUnitCommand{}, args) |
286 | + _, err := testing.RunCommand(c, &DestroyUnitCommand{}, args) |
287 | + return err |
288 | } |
289 | |
290 | func (s *DestroyUnitSuite) TestDestroyUnit(c *C) { |
291 | |
292 | === modified file 'cmd/juju/expose_test.go' |
293 | --- cmd/juju/expose_test.go 2013-02-28 08:11:29 +0000 |
294 | +++ cmd/juju/expose_test.go 2013-02-28 12:30:29 +0000 |
295 | @@ -13,7 +13,8 @@ |
296 | var _ = Suite(&ExposeSuite{}) |
297 | |
298 | func runExpose(c *C, args ...string) error { |
299 | - return testing.RunCommand(c, &ExposeCommand{}, args) |
300 | + _, err := testing.RunCommand(c, &ExposeCommand{}, args) |
301 | + return err |
302 | } |
303 | |
304 | func (s *ExposeSuite) assertExposed(c *C, service string) { |
305 | |
306 | === modified file 'cmd/juju/init_test.go' |
307 | --- cmd/juju/init_test.go 2013-02-28 08:11:29 +0000 |
308 | +++ cmd/juju/init_test.go 2013-02-28 12:30:29 +0000 |
309 | @@ -1,12 +1,12 @@ |
310 | package main |
311 | |
312 | import ( |
313 | + "bytes" |
314 | "io/ioutil" |
315 | - |
316 | - "bytes" |
317 | . "launchpad.net/gocheck" |
318 | "launchpad.net/juju-core/cmd" |
319 | "launchpad.net/juju-core/environs" |
320 | + "launchpad.net/juju-core/testing" |
321 | "strings" |
322 | ) |
323 | |
324 | @@ -18,7 +18,7 @@ |
325 | func (*InitSuite) TestBoilerPlateEnvironment(c *C) { |
326 | defer makeFakeHome(c, "empty").restore() |
327 | // run without an environments.yaml |
328 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
329 | + ctx := testing.Context(c) |
330 | code := cmd.Main(&InitCommand{}, ctx, []string{"-w"}) |
331 | c.Check(code, Equals, 0) |
332 | outStr := ctx.Stdout.(*bytes.Buffer).String() |
333 | @@ -44,7 +44,7 @@ |
334 | _, err := environs.WriteEnvirons(environpath, env) |
335 | c.Assert(err, IsNil) |
336 | |
337 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
338 | + ctx := testing.Context(c) |
339 | code := cmd.Main(&InitCommand{}, ctx, []string{"-w"}) |
340 | c.Check(code, Equals, 0) |
341 | errOut := ctx.Stdout.(*bytes.Buffer).String() |
342 | @@ -70,7 +70,7 @@ |
343 | _, err := environs.WriteEnvirons(environpath, env) |
344 | c.Assert(err, IsNil) |
345 | |
346 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
347 | + ctx := testing.Context(c) |
348 | code := cmd.Main(&InitCommand{}, ctx, nil) |
349 | c.Check(code, Equals, 0) |
350 | errOut := ctx.Stdout.(*bytes.Buffer).String() |
351 | |
352 | === modified file 'cmd/juju/resolved_test.go' |
353 | --- cmd/juju/resolved_test.go 2013-02-28 08:11:29 +0000 |
354 | +++ cmd/juju/resolved_test.go 2013-02-28 12:30:29 +0000 |
355 | @@ -13,7 +13,8 @@ |
356 | var _ = Suite(&ResolvedSuite{}) |
357 | |
358 | func runResolved(c *C, args []string) error { |
359 | - return testing.RunCommand(c, &ResolvedCommand{}, args) |
360 | + _, err := testing.RunCommand(c, &ResolvedCommand{}, args) |
361 | + return err |
362 | } |
363 | |
364 | var resolvedTests = []struct { |
365 | |
366 | === modified file 'cmd/juju/scp_test.go' |
367 | --- cmd/juju/scp_test.go 2013-02-28 08:11:29 +0000 |
368 | +++ cmd/juju/scp_test.go 2013-02-28 12:30:29 +0000 |
369 | @@ -63,7 +63,7 @@ |
370 | |
371 | for _, t := range scpTests { |
372 | c.Logf("testing juju scp %s", t.args) |
373 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
374 | + ctx := coretesting.Context(c) |
375 | code := cmd.Main(&SCPCommand{}, ctx, t.args) |
376 | c.Check(code, Equals, 0) |
377 | c.Check(ctx.Stderr.(*bytes.Buffer).String(), Equals, "") |
378 | |
379 | === modified file 'cmd/juju/ssh_test.go' |
380 | --- cmd/juju/ssh_test.go 2013-02-28 08:11:29 +0000 |
381 | +++ cmd/juju/ssh_test.go 2013-02-28 12:30:29 +0000 |
382 | @@ -107,7 +107,7 @@ |
383 | |
384 | for _, t := range sshTests { |
385 | c.Logf("testing juju ssh %s", t.args) |
386 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
387 | + ctx := coretesting.Context(c) |
388 | code := cmd.Main(&SSHCommand{}, ctx, t.args) |
389 | c.Check(code, Equals, 0) |
390 | c.Check(ctx.Stderr.(*bytes.Buffer).String(), Equals, "") |
391 | |
392 | === modified file 'cmd/juju/status_test.go' |
393 | --- cmd/juju/status_test.go 2013-02-28 08:11:29 +0000 |
394 | +++ cmd/juju/status_test.go 2013-02-28 12:30:29 +0000 |
395 | @@ -248,7 +248,7 @@ |
396 | for _, t := range statusTests { |
397 | c.Logf("testing %s: %s", format, t.title) |
398 | t.prepare(s.State, s.Conn, c) |
399 | - ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
400 | + ctx := coretesting.Context(c) |
401 | code := cmd.Main(&StatusCommand{}, ctx, []string{"--format", format}) |
402 | c.Check(code, Equals, 0) |
403 | c.Assert(ctx.Stderr.(*bytes.Buffer).String(), Equals, "") |
404 | |
405 | === modified file 'cmd/juju/unexpose_test.go' |
406 | --- cmd/juju/unexpose_test.go 2013-02-28 08:11:29 +0000 |
407 | +++ cmd/juju/unexpose_test.go 2013-02-28 12:30:29 +0000 |
408 | @@ -13,7 +13,8 @@ |
409 | var _ = Suite(&UnexposeSuite{}) |
410 | |
411 | func runUnexpose(c *C, args ...string) error { |
412 | - return testing.RunCommand(c, &UnexposeCommand{}, args) |
413 | + _, err := testing.RunCommand(c, &UnexposeCommand{}, args) |
414 | + return err |
415 | } |
416 | |
417 | func (s *UnexposeSuite) assertExposed(c *C, service string, expected bool) { |
418 | |
419 | === modified file 'cmd/juju/upgradejuju_test.go' |
420 | --- cmd/juju/upgradejuju_test.go 2013-02-28 08:11:29 +0000 |
421 | +++ cmd/juju/upgradejuju_test.go 2013-02-28 12:30:29 +0000 |
422 | @@ -3,7 +3,6 @@ |
423 | import ( |
424 | "io/ioutil" |
425 | . "launchpad.net/gocheck" |
426 | - "launchpad.net/juju-core/cmd" |
427 | "launchpad.net/juju-core/environs" |
428 | "launchpad.net/juju-core/juju/testing" |
429 | "launchpad.net/juju-core/state" |
430 | @@ -188,7 +187,7 @@ |
431 | c.Check(err, ErrorMatches, test.expectInitErr) |
432 | continue |
433 | } |
434 | - err = com.Run(&cmd.Context{c.MkDir(), nil, ioutil.Discard, ioutil.Discard}) |
435 | + err = com.Run(coretesting.Context(c)) |
436 | if test.expectErr != "" { |
437 | c.Check(err, ErrorMatches, test.expectErr) |
438 | continue |
439 | @@ -230,7 +229,7 @@ |
440 | |
441 | func (s *UpgradeJujuSuite) TestUpgradeJujuWithRealPutTools(c *C) { |
442 | s.Reset(c) |
443 | - err := coretesting.RunCommand(c, &UpgradeJujuCommand{}, []string{"--upload-tools", "--dev"}) |
444 | + _, err := coretesting.RunCommand(c, &UpgradeJujuCommand{}, []string{"--upload-tools", "--dev"}) |
445 | c.Assert(err, IsNil) |
446 | p := environs.ToolsStoragePath(version.Current) |
447 | r, err := s.Conn.Environ.Storage().Get(p) |
448 | |
449 | === modified file 'cmd/jujud/agent_test.go' |
450 | --- cmd/jujud/agent_test.go 2013-02-28 08:11:29 +0000 |
451 | +++ cmd/jujud/agent_test.go 2013-02-28 12:30:29 +0000 |
452 | @@ -342,7 +342,7 @@ |
453 | info := s.StateInfo(c) |
454 | info.EntityName = ent.EntityName() |
455 | info.Password = "initial" |
456 | - testOpenState(c, info, state.ErrUnauthorized) |
457 | + testOpenState(c, info, state.Unauthorizedf("unauth")) |
458 | |
459 | // Read the configuration and check that we can connect with it. |
460 | c.Assert(refreshConfig(conf), IsNil) |
461 | |
462 | === modified file 'cmd/jujud/bootstrap_test.go' |
463 | --- cmd/jujud/bootstrap_test.go 2013-02-28 08:11:29 +0000 |
464 | +++ cmd/jujud/bootstrap_test.go 2013-02-28 12:30:29 +0000 |
465 | @@ -145,7 +145,7 @@ |
466 | st.Close() |
467 | } |
468 | if expectErr != nil { |
469 | - c.Assert(err, Equals, expectErr) |
470 | + c.Assert(state.IsUnauthorizedError(err), Equals, true) |
471 | } else { |
472 | c.Assert(err, IsNil) |
473 | } |
474 | @@ -177,7 +177,7 @@ |
475 | Addrs: []string{testing.MgoAddr}, |
476 | CACert: []byte(testing.CACert), |
477 | } |
478 | - testOpenState(c, info, state.ErrUnauthorized) |
479 | + testOpenState(c, info, state.Unauthorizedf("some auth problem")) |
480 | |
481 | info.EntityName, info.Password = "machine-0", "foo" |
482 | testOpenState(c, info, nil) |
483 | |
484 | === modified file 'cmd/logging_test.go' |
485 | --- cmd/logging_test.go 2013-02-28 08:11:29 +0000 |
486 | +++ cmd/logging_test.go 2013-02-28 12:30:29 +0000 |
487 | @@ -61,7 +61,7 @@ |
488 | {"foo", false, false, NotNil}, |
489 | } { |
490 | l := &cmd.Log{t.path, t.verbose, t.debug} |
491 | - ctx := dummyContext(c) |
492 | + ctx := testing.Context(c) |
493 | err := l.Start(ctx) |
494 | c.Assert(err, IsNil) |
495 | c.Assert(log.Target, t.target) |
496 | @@ -71,7 +71,7 @@ |
497 | |
498 | func (s *LogSuite) TestStderr(c *C) { |
499 | l := &cmd.Log{Verbose: true} |
500 | - ctx := dummyContext(c) |
501 | + ctx := testing.Context(c) |
502 | err := l.Start(ctx) |
503 | c.Assert(err, IsNil) |
504 | log.Printf("hello") |
505 | @@ -80,7 +80,7 @@ |
506 | |
507 | func (s *LogSuite) TestRelPathLog(c *C) { |
508 | l := &cmd.Log{Path: "foo.log"} |
509 | - ctx := dummyContext(c) |
510 | + ctx := testing.Context(c) |
511 | err := l.Start(ctx) |
512 | c.Assert(err, IsNil) |
513 | log.Printf("hello") |
514 | @@ -93,7 +93,7 @@ |
515 | func (s *LogSuite) TestAbsPathLog(c *C) { |
516 | path := filepath.Join(c.MkDir(), "foo.log") |
517 | l := &cmd.Log{Path: path} |
518 | - ctx := dummyContext(c) |
519 | + ctx := testing.Context(c) |
520 | err := l.Start(ctx) |
521 | c.Assert(err, IsNil) |
522 | log.Printf("hello") |
523 | |
524 | === modified file 'cmd/output_test.go' |
525 | --- cmd/output_test.go 2013-02-28 08:11:29 +0000 |
526 | +++ cmd/output_test.go 2013-02-28 12:30:29 +0000 |
527 | @@ -4,6 +4,7 @@ |
528 | "launchpad.net/gnuflag" |
529 | . "launchpad.net/gocheck" |
530 | "launchpad.net/juju-core/cmd" |
531 | + "launchpad.net/juju-core/testing" |
532 | ) |
533 | |
534 | // OutputCommand is a command that uses the output.go formatters. |
535 | @@ -102,7 +103,7 @@ |
536 | } |
537 | for i, t := range tests { |
538 | c.Logf(" test %d", i) |
539 | - ctx := dummyContext(c) |
540 | + ctx := testing.Context(c) |
541 | result := cmd.Main(&OutputCommand{value: t.value}, ctx, args) |
542 | c.Assert(result, Equals, 0) |
543 | c.Assert(bufferString(ctx.Stdout), Equals, t.output) |
544 | @@ -110,7 +111,7 @@ |
545 | } |
546 | } |
547 | |
548 | - ctx := dummyContext(c) |
549 | + ctx := testing.Context(c) |
550 | result := cmd.Main(&OutputCommand{}, ctx, []string{"--format", "cuneiform"}) |
551 | c.Assert(result, Equals, 2) |
552 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
553 | @@ -122,7 +123,7 @@ |
554 | // this argument format. |
555 | // LP #1059921 |
556 | func (s *CmdSuite) TestFormatAlternativeSyntax(c *C) { |
557 | - ctx := dummyContext(c) |
558 | + ctx := testing.Context(c) |
559 | result := cmd.Main(&OutputCommand{}, ctx, []string{"--format=json"}) |
560 | c.Assert(result, Equals, 0) |
561 | c.Assert(bufferString(ctx.Stdout), Equals, "null\n") |
562 | |
563 | === modified file 'cmd/supercommand_test.go' |
564 | --- cmd/supercommand_test.go 2013-02-28 08:11:29 +0000 |
565 | +++ cmd/supercommand_test.go 2013-02-28 12:30:29 +0000 |
566 | @@ -99,7 +99,7 @@ |
567 | }() |
568 | jc := &cmd.SuperCommand{Name: "jujutest", Log: &cmd.Log{}} |
569 | jc.Register(&TestCommand{Name: "blah"}) |
570 | - ctx := dummyContext(c) |
571 | + ctx := testing.Context(c) |
572 | code := cmd.Main(jc, ctx, []string{"blah", "--option", "error", "--debug"}) |
573 | c.Assert(code, Equals, 1) |
574 | c.Assert(bufferString(ctx.Stderr), Matches, `.* JUJU jujutest blah command failed: BAM! |
575 | |
576 | === modified file 'cmd/util_test.go' |
577 | --- cmd/util_test.go 2013-02-28 08:11:29 +0000 |
578 | +++ cmd/util_test.go 2013-02-28 12:30:29 +0000 |
579 | @@ -6,14 +6,9 @@ |
580 | "fmt" |
581 | "io" |
582 | "launchpad.net/gnuflag" |
583 | - . "launchpad.net/gocheck" |
584 | "launchpad.net/juju-core/cmd" |
585 | ) |
586 | |
587 | -func dummyContext(c *C) *cmd.Context { |
588 | - return &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}} |
589 | -} |
590 | - |
591 | func bufferString(stream io.Writer) string { |
592 | return stream.(*bytes.Buffer).String() |
593 | } |
594 | |
595 | === modified file 'environs/agent/agent.go' |
596 | --- environs/agent/agent.go 2013-02-28 08:11:29 +0000 |
597 | +++ environs/agent/agent.go 2013-02-28 12:30:29 +0000 |
598 | @@ -205,7 +205,7 @@ |
599 | if err == nil { |
600 | return st, "", nil |
601 | } |
602 | - if err != state.ErrUnauthorized { |
603 | + if !state.IsUnauthorizedError(err) { |
604 | return nil, "", err |
605 | } |
606 | // Access isn't authorized even though we have a password |
607 | |
608 | === modified file 'juju/api.go' |
609 | --- juju/api.go 2013-02-28 08:11:29 +0000 |
610 | +++ juju/api.go 2013-02-28 12:30:29 +0000 |
611 | @@ -29,7 +29,7 @@ |
612 | info.Password = password |
613 | |
614 | st, err := api.Open(info) |
615 | - // TODO(rog): handle ErrUnauthorized when the API handles passwords. |
616 | + // TODO(rog): handle errUnauthorized when the API handles passwords. |
617 | if err != nil { |
618 | return nil, err |
619 | } |
620 | |
621 | === modified file 'juju/conn.go' |
622 | --- juju/conn.go 2013-02-28 08:11:29 +0000 |
623 | +++ juju/conn.go 2013-02-28 12:30:29 +0000 |
624 | @@ -43,7 +43,7 @@ |
625 | } |
626 | info.Password = password |
627 | st, err := state.Open(info) |
628 | - if err == state.ErrUnauthorized { |
629 | + if state.IsUnauthorizedError(err) { |
630 | // We can't connect with the administrator password,; |
631 | // perhaps this was the first connection and the |
632 | // password has not been changed yet. |
633 | @@ -54,7 +54,7 @@ |
634 | // initialized and the initial password set. |
635 | for a := redialStrategy.Start(); a.Next(); { |
636 | st, err = state.Open(info) |
637 | - if err != state.ErrUnauthorized { |
638 | + if !state.IsUnauthorizedError(err) { |
639 | break |
640 | } |
641 | } |
642 | |
643 | === modified file 'state/api/api_test.go' |
644 | --- state/api/api_test.go 2013-02-28 08:11:29 +0000 |
645 | +++ state/api/api_test.go 2013-02-28 12:30:29 +0000 |
646 | @@ -679,7 +679,7 @@ |
647 | c.Assert(ok, Equals, true) |
648 | |
649 | // Wait long enough for the Next request to be sent |
650 | - // so it's blocking on the server side. |
651 | + // so it's blocking on the server side. |
652 | time.Sleep(50 * time.Millisecond) |
653 | c.Logf("stopping server") |
654 | err = srv.Stop() |
655 | @@ -752,7 +752,7 @@ |
656 | err: state.NotFoundf("hello"), |
657 | code: api.CodeNotFound, |
658 | }, { |
659 | - err: state.ErrUnauthorized, |
660 | + err: state.Unauthorizedf("hello"), |
661 | code: api.CodeUnauthorized, |
662 | }, { |
663 | err: state.ErrCannotEnterScopeYet, |
664 | |
665 | === modified file 'state/api/error.go' |
666 | --- state/api/error.go 2013-02-28 08:11:29 +0000 |
667 | +++ state/api/error.go 2013-02-28 12:30:29 +0000 |
668 | @@ -33,7 +33,6 @@ |
669 | ) |
670 | |
671 | var singletonErrorCodes = map[error]string{ |
672 | - state.ErrUnauthorized: CodeUnauthorized, |
673 | state.ErrCannotEnterScopeYet: CodeCannotEnterScopeYet, |
674 | state.ErrCannotEnterScope: CodeCannotEnterScope, |
675 | state.ErrExcessiveContention: CodeExcessiveContention, |
676 | @@ -62,6 +61,8 @@ |
677 | code := singletonErrorCodes[err] |
678 | switch { |
679 | case code != "": |
680 | + case state.IsUnauthorizedError(err): |
681 | + code = CodeUnauthorized |
682 | case state.IsNotFound(err): |
683 | code = CodeNotFound |
684 | case state.IsNotAssigned(err): |
685 | |
686 | === modified file 'state/open.go' |
687 | --- state/open.go 2013-02-28 08:11:29 +0000 |
688 | +++ state/open.go 2013-02-28 12:30:29 +0000 |
689 | @@ -42,7 +42,7 @@ |
690 | // Open connects to the server described by the given |
691 | // info, waits for it to be initialized, and returns a new State |
692 | // representing the environment connected to. |
693 | -// It returns ErrUnauthorized if access is unauthorized. |
694 | +// It returns unauthorizedError if access is unauthorized. |
695 | func Open(info *Info) (*State, error) { |
696 | log.Printf("state: opening state; mongo addresses: %q; entity %q", info.Addrs, info.EntityName) |
697 | if len(info.Addrs) == 0 { |
698 | @@ -89,7 +89,7 @@ |
699 | |
700 | // Initialize sets up an initial empty state and returns it. |
701 | // This needs to be performed only once for a given environment. |
702 | -// It returns ErrUnauthorized if access is unauthorized. |
703 | +// It returns unauthorizedError if access is unauthorized. |
704 | func Initialize(info *Info, cfg *config.Config) (rst *State, err error) { |
705 | st, err := Open(info) |
706 | if err != nil { |
707 | @@ -148,7 +148,30 @@ |
708 | logSizeTests = 1000000 |
709 | ) |
710 | |
711 | -var ErrUnauthorized = errors.New("unauthorized access") |
712 | +// unauthorizedError represents the error that an operation is unauthorized. |
713 | +// Use IsUnauthorized() to determine if the error was related to authorization failure. |
714 | +type unauthorizedError struct { |
715 | + msg string |
716 | + error |
717 | +} |
718 | + |
719 | +func IsUnauthorizedError(err error) bool { |
720 | + _, ok := err.(*unauthorizedError) |
721 | + return ok |
722 | +} |
723 | + |
724 | +func (e *unauthorizedError) Error() string { |
725 | + if e.error != nil { |
726 | + return fmt.Sprintf("%s: %v", e.msg, e.error.Error()) |
727 | + } |
728 | + return e.msg |
729 | +} |
730 | + |
731 | +// Unauthorizedf returns an error for which IsUnauthorizedError returns true. |
732 | +// It is mainly used for testing. |
733 | +func Unauthorizedf(format string, args ...interface{}) error { |
734 | + return &unauthorizedError{fmt.Sprintf(format, args...), nil} |
735 | +} |
736 | |
737 | func maybeUnauthorized(err error, msg string) error { |
738 | if err == nil { |
739 | @@ -157,10 +180,10 @@ |
740 | // Unauthorized access errors have no error code, |
741 | // just a simple error string. |
742 | if err.Error() == "auth fails" { |
743 | - return ErrUnauthorized |
744 | + return &unauthorizedError{msg, err} |
745 | } |
746 | if err, ok := err.(*mgo.QueryError); ok && err.Code == 10057 { |
747 | - return ErrUnauthorized |
748 | + return &unauthorizedError{msg, err} |
749 | } |
750 | return fmt.Errorf("%s: %v", msg, err) |
751 | } |
752 | |
753 | === modified file 'state/state_test.go' |
754 | --- state/state_test.go 2013-02-28 08:11:29 +0000 |
755 | +++ state/state_test.go 2013-02-28 12:30:29 +0000 |
756 | @@ -1173,11 +1173,11 @@ |
757 | info := state.TestingStateInfo() |
758 | info.EntityName, info.Password = "arble", "bar" |
759 | err := tryOpenState(info) |
760 | - c.Assert(err, Equals, state.ErrUnauthorized) |
761 | + c.Assert(state.IsUnauthorizedError(err), Equals, true) |
762 | |
763 | info.EntityName, info.Password = "arble", "" |
764 | err = tryOpenState(info) |
765 | - c.Assert(err, Equals, state.ErrUnauthorized) |
766 | + c.Assert(state.IsUnauthorizedError(err), Equals, true) |
767 | |
768 | info.EntityName, info.Password = "", "" |
769 | err = tryOpenState(info) |
770 | @@ -1253,7 +1253,7 @@ |
771 | info.EntityName = ent.EntityName() |
772 | info.Password = "bar" |
773 | err = tryOpenState(info) |
774 | - c.Assert(err, Equals, state.ErrUnauthorized) |
775 | + c.Assert(state.IsUnauthorizedError(err), Equals, true) |
776 | |
777 | // Check that we can log in with the correct password. |
778 | info.Password = "foo" |
779 | @@ -1271,7 +1271,7 @@ |
780 | // Check that we cannot log in with the old password. |
781 | info.Password = "foo" |
782 | err = tryOpenState(info) |
783 | - c.Assert(err, Equals, state.ErrUnauthorized) |
784 | + c.Assert(state.IsUnauthorizedError(err), Equals, true) |
785 | |
786 | // Check that we can log in with the correct password. |
787 | info.Password = "bar" |
788 | @@ -1299,7 +1299,7 @@ |
789 | defer s.State.SetAdminMongoPassword("") |
790 | info := state.TestingStateInfo() |
791 | err = tryOpenState(info) |
792 | - c.Assert(err, Equals, state.ErrUnauthorized) |
793 | + c.Assert(state.IsUnauthorizedError(err), Equals, true) |
794 | |
795 | info.Password = "foo" |
796 | err = tryOpenState(info) |
797 | |
798 | === modified file 'state/unit_test.go' |
799 | --- state/unit_test.go 2013-02-28 08:11:29 +0000 |
800 | +++ state/unit_test.go 2013-02-28 12:30:29 +0000 |
801 | @@ -214,7 +214,7 @@ |
802 | info.EntityName = m.EntityName() |
803 | info.Password = "foo1" |
804 | err = tryOpenState(info) |
805 | - c.Assert(err, Equals, state.ErrUnauthorized) |
806 | + c.Assert(state.IsUnauthorizedError(err), Equals, true) |
807 | |
808 | // Connect as the machine entity. |
809 | info.EntityName = m.EntityName() |
810 | |
811 | === modified file 'store/server.go' |
812 | --- store/server.go 2013-02-28 08:11:29 +0000 |
813 | +++ store/server.go 2013-02-28 12:30:29 +0000 |
814 | @@ -156,17 +156,22 @@ |
815 | return |
816 | } |
817 | key := strings.Split(base, ":") |
818 | + r.ParseForm() |
819 | + listing := r.Form.Get("list") == "1" |
820 | prefix := false |
821 | if key[len(key)-1] == "*" { |
822 | prefix = true |
823 | key = key[:len(key)-1] |
824 | - if len(key) == 0 { |
825 | + if len(key) == 0 && !listing { |
826 | // No point in counting something unknown. |
827 | w.WriteHeader(http.StatusForbidden) |
828 | return |
829 | } |
830 | } |
831 | - r.ParseForm() |
832 | + if listing && prefix { |
833 | + s.serveStatsList(w, r, key) |
834 | + return |
835 | + } |
836 | sum, err := s.store.SumCounter(key, prefix) |
837 | if err != nil { |
838 | log.Printf("store: cannot sum counter: %v", err) |
839 | @@ -174,6 +179,10 @@ |
840 | return |
841 | } |
842 | data := []byte(strconv.FormatInt(sum, 10)) |
843 | + if listing { |
844 | + // Listing a single item.. silly, but whatever. |
845 | + data = []byte(base + " " + string(data) + "\n") |
846 | + } |
847 | w.Header().Set("Content-Type", "text/plain") |
848 | w.Header().Set("Content-Length", strconv.Itoa(len(data))) |
849 | _, err = w.Write(data) |
850 | @@ -183,6 +192,62 @@ |
851 | } |
852 | } |
853 | |
854 | +func (s *Server) serveStatsList(w http.ResponseWriter, r *http.Request, prefix []string) { |
855 | + entries, err := s.store.ListCounters(prefix) |
856 | + if err != nil { |
857 | + log.Printf("store: cannot list counter: %v", err) |
858 | + w.WriteHeader(http.StatusInternalServerError) |
859 | + return |
860 | + } |
861 | + |
862 | + // First build keys and figure max key length. |
863 | + var buf []byte |
864 | + var maxKeyLength int |
865 | + type resultItem struct { |
866 | + key string |
867 | + count int64 |
868 | + } |
869 | + var result []resultItem |
870 | + for i := range entries { |
871 | + entry := &entries[i] |
872 | + for j := range entry.Key { |
873 | + buf = append(buf, entry.Key[j]...) |
874 | + buf = append(buf, ':') |
875 | + } |
876 | + if entry.Prefix { |
877 | + buf = append(buf, '*') |
878 | + } else { |
879 | + buf = buf[:len(buf)-1] |
880 | + } |
881 | + if maxKeyLength < len(buf) { |
882 | + maxKeyLength = len(buf) |
883 | + } |
884 | + result = append(result, resultItem{string(buf), entry.Count}) |
885 | + buf = buf[:0] |
886 | + } |
887 | + |
888 | + // Then join all keys and counts in a single formatted buffer. |
889 | + spaces := make([]byte, maxKeyLength+2) |
890 | + for i := range spaces { |
891 | + spaces[i] = ' ' |
892 | + } |
893 | + for i := range result { |
894 | + item := &result[i] |
895 | + buf = append(buf, item.key...) |
896 | + buf = append(buf, spaces[len(item.key):]...) |
897 | + buf = strconv.AppendInt(buf, item.count, 10) |
898 | + buf = append(buf, '\n') |
899 | + } |
900 | + |
901 | + w.Header().Set("Content-Type", "text/plain") |
902 | + w.Header().Set("Content-Length", strconv.Itoa(len(buf))) |
903 | + _, err = w.Write(buf) |
904 | + if err != nil { |
905 | + log.Printf("store: cannot write content: %v", err) |
906 | + w.WriteHeader(http.StatusInternalServerError) |
907 | + } |
908 | +} |
909 | + |
910 | func (s *Server) serveBlitzKey(w http.ResponseWriter, r *http.Request) { |
911 | w.Header().Set("Connection", "close") |
912 | w.Header().Set("Content-Type", "text/plain") |
913 | |
914 | === modified file 'store/server_test.go' |
915 | --- store/server_test.go 2013-02-28 08:11:29 +0000 |
916 | +++ store/server_test.go 2013-02-28 12:30:29 +0000 |
917 | @@ -163,7 +163,7 @@ |
918 | } |
919 | |
920 | func (s *StoreSuite) TestStatsCounter(c *C) { |
921 | - for _, key := range [][]string{{"a", "b"}, {"a", "b"}, {"a"}} { |
922 | + for _, key := range [][]string{{"a", "b"}, {"a", "b"}, {"a", "c"}, {"a"}} { |
923 | err := s.store.IncCounter(key) |
924 | c.Assert(err, IsNil) |
925 | } |
926 | @@ -171,9 +171,11 @@ |
927 | server, _ := s.prepareServer(c) |
928 | |
929 | expected := map[string]string{ |
930 | - "a:b": "2", |
931 | - "a:*": "3", |
932 | - "a": "1", |
933 | + "a:b": "2", |
934 | + "a:b:*": "0", |
935 | + "a:*": "3", |
936 | + "a": "1", |
937 | + "a:b:c": "0", |
938 | } |
939 | |
940 | for counter, n := range expected { |
941 | @@ -190,6 +192,47 @@ |
942 | } |
943 | } |
944 | |
945 | +func (s *StoreSuite) TestStatsCounterList(c *C) { |
946 | + incs := [][]string{ |
947 | + {"a"}, |
948 | + {"a", "b"}, |
949 | + {"a", "b", "c"}, |
950 | + {"a", "b", "c"}, |
951 | + {"a", "b", "d"}, |
952 | + {"a", "b", "e"}, |
953 | + {"a", "f", "g"}, |
954 | + {"a", "f", "h"}, |
955 | + {"a", "i"}, |
956 | + {"j", "k"}, |
957 | + } |
958 | + for _, key := range incs { |
959 | + err := s.store.IncCounter(key) |
960 | + c.Assert(err, IsNil) |
961 | + } |
962 | + |
963 | + server, _ := s.prepareServer(c) |
964 | + |
965 | + tests := [][]string{ |
966 | + {"a", "a 1\n"}, |
967 | + {"a:*", "a:b:* 4\na:f:* 2\na:b 1\na:i 1\n"}, |
968 | + {"a:b:*", "a:b:c 2\na:b:d 1\na:b:e 1\n"}, |
969 | + } |
970 | + |
971 | + for i := range tests { |
972 | + req, err := http.NewRequest("GET", "/stats/counter/"+tests[i][0], nil) |
973 | + c.Assert(err, IsNil) |
974 | + req.Form = url.Values{"list": []string{"1"}} |
975 | + rec := httptest.NewRecorder() |
976 | + server.ServeHTTP(rec, req) |
977 | + |
978 | + data, err := ioutil.ReadAll(rec.Body) |
979 | + c.Assert(string(data), Equals, tests[i][1]) |
980 | + |
981 | + c.Assert(rec.Header().Get("Content-Type"), Equals, "text/plain") |
982 | + c.Assert(rec.Header().Get("Content-Length"), Equals, strconv.Itoa(len(tests[i][1]))) |
983 | + } |
984 | +} |
985 | + |
986 | func (s *StoreSuite) TestBlitzKey(c *C) { |
987 | server, _ := s.prepareServer(c) |
988 | |
989 | |
990 | === modified file 'store/store.go' |
991 | --- store/store.go 2013-02-28 08:11:29 +0000 |
992 | +++ store/store.go 2013-02-28 12:30:29 +0000 |
993 | @@ -16,6 +16,7 @@ |
994 | "launchpad.net/juju-core/log" |
995 | "sort" |
996 | "strconv" |
997 | + "strings" |
998 | "sync" |
999 | "time" |
1000 | ) |
1001 | @@ -45,8 +46,10 @@ |
1002 | |
1003 | // Cache for statistics key words (two generations). |
1004 | cacheMu sync.RWMutex |
1005 | - statsTokenNew map[string]int |
1006 | - statsTokenOld map[string]int |
1007 | + statsIdNew map[string]int |
1008 | + statsIdOld map[string]int |
1009 | + statsTokenNew map[int]string |
1010 | + statsTokenOld map[int]string |
1011 | } |
1012 | |
1013 | // Open creates a new session with the store. It connects to the MongoDB |
1014 | @@ -130,10 +133,7 @@ |
1015 | err = nil |
1016 | id, found := s.statsTokenId(key[i]) |
1017 | if !found { |
1018 | - var t struct { |
1019 | - Id int "_id" |
1020 | - Token string "t" |
1021 | - } |
1022 | + var t tokenId |
1023 | err = tokens.Find(bson.D{{"t", key[i]}}).One(&t) |
1024 | if err == mgo.ErrNotFound { |
1025 | if !write { |
1026 | @@ -163,7 +163,12 @@ |
1027 | return string(skey), nil |
1028 | } |
1029 | |
1030 | -const statsTokenCacheSize = 512 |
1031 | +const statsTokenCacheSize = 1024 |
1032 | + |
1033 | +type tokenId struct { |
1034 | + Id int "_id" |
1035 | + Token string "t" |
1036 | +} |
1037 | |
1038 | // cacheStatsTokenId adds the id for token into the cache. |
1039 | // The cache has two generations so that the least frequently used |
1040 | @@ -172,25 +177,45 @@ |
1041 | s.cacheMu.Lock() |
1042 | defer s.cacheMu.Unlock() |
1043 | // Can't possibly be >, but reviews want it for defensiveness. |
1044 | - if len(s.statsTokenNew) >= statsTokenCacheSize { |
1045 | + if len(s.statsIdNew) >= statsTokenCacheSize { |
1046 | + s.statsIdOld = s.statsIdNew |
1047 | + s.statsIdNew = nil |
1048 | s.statsTokenOld = s.statsTokenNew |
1049 | s.statsTokenNew = nil |
1050 | } |
1051 | - if s.statsTokenNew == nil { |
1052 | - s.statsTokenNew = make(map[string]int, statsTokenCacheSize) |
1053 | + if s.statsIdNew == nil { |
1054 | + s.statsIdNew = make(map[string]int, statsTokenCacheSize) |
1055 | + s.statsTokenNew = make(map[int]string, statsTokenCacheSize) |
1056 | } |
1057 | - s.statsTokenNew[token] = id |
1058 | + s.statsIdNew[token] = id |
1059 | + s.statsTokenNew[id] = token |
1060 | } |
1061 | |
1062 | // statsTokenId returns the id for token from the cache, if found. |
1063 | func (s *Store) statsTokenId(token string) (id int, found bool) { |
1064 | s.cacheMu.RLock() |
1065 | - id, found = s.statsTokenNew[token] |
1066 | - if found { |
1067 | - s.cacheMu.RUnlock() |
1068 | - return |
1069 | - } |
1070 | - id, found = s.statsTokenOld[token] |
1071 | + id, found = s.statsIdNew[token] |
1072 | + if found { |
1073 | + s.cacheMu.RUnlock() |
1074 | + return |
1075 | + } |
1076 | + id, found = s.statsIdOld[token] |
1077 | + s.cacheMu.RUnlock() |
1078 | + if found { |
1079 | + s.cacheStatsTokenId(token, id) |
1080 | + } |
1081 | + return |
1082 | +} |
1083 | + |
1084 | +// statsIdToken returns the token for id from the cache, if found. |
1085 | +func (s *Store) statsIdToken(id int) (token string, found bool) { |
1086 | + s.cacheMu.RLock() |
1087 | + token, found = s.statsTokenNew[id] |
1088 | + if found { |
1089 | + s.cacheMu.RUnlock() |
1090 | + return |
1091 | + } |
1092 | + token, found = s.statsTokenOld[id] |
1093 | s.cacheMu.RUnlock() |
1094 | if found { |
1095 | s.cacheStatsTokenId(token, id) |
1096 | @@ -219,7 +244,8 @@ |
1097 | } |
1098 | |
1099 | // SumCounter returns the sum of all the counters that exactly match key, |
1100 | -// or that are prefixed by it if prefix is true. |
1101 | +// or that are prefixed by it if prefix is true. In the latter case, a key |
1102 | +// that matches the prefix exactly won't be included in the sum. |
1103 | func (s *Store) SumCounter(key []string, prefix bool) (count int64, err error) { |
1104 | session := s.session.Copy() |
1105 | defer session.Close() |
1106 | @@ -234,7 +260,7 @@ |
1107 | |
1108 | var regex string |
1109 | if prefix { |
1110 | - regex = "^" + skey |
1111 | + regex = "^" + skey + ".+" |
1112 | } else { |
1113 | regex = "^" + skey + "$" |
1114 | } |
1115 | @@ -252,6 +278,125 @@ |
1116 | return 0, err |
1117 | } |
1118 | |
1119 | +type Counter struct { |
1120 | + Key []string |
1121 | + Count int64 |
1122 | + Prefix bool |
1123 | +} |
1124 | + |
1125 | +// ListCounters returns a list of all keys directly under the provided prefix, |
1126 | +// and a prefix-aggregated view of deeper keys. |
1127 | +// |
1128 | +// For example, given the following counts: |
1129 | +// |
1130 | +// {"a", "b"}: 1, |
1131 | +// {"a", "c"}: 3 |
1132 | +// {"a", "c", "d"}: 5 |
1133 | +// {"a", "c", "e"}: 7 |
1134 | +// |
1135 | +// The following key prefixes will present the respective list results: |
1136 | +// |
1137 | +// {"a"} => {{"a", "b"}, 1, false}, {{"a", "c"}, 3, false}, {{"a", "c"}, 12, true} |
1138 | +// {"a", "c"} => {{"a", "c", "d"}, 3, false}, {"a", "c", "e"}, 5, false} |
1139 | +// |
1140 | +func (s *Store) ListCounters(keyPrefix []string) ([]Counter, error) { |
1141 | + session := s.session.Copy() |
1142 | + defer session.Close() |
1143 | + |
1144 | + tokensColl := session.StatTokens() |
1145 | + countersColl := session.StatCounters() |
1146 | + |
1147 | + skey, err := s.statsKey(session, keyPrefix, false) |
1148 | + if err == ErrNotFound { |
1149 | + return nil, nil |
1150 | + } |
1151 | + if err != nil { |
1152 | + return nil, err |
1153 | + } |
1154 | + regex := "^" + skey + ".+" |
1155 | + |
1156 | + // For a search key "a:b:" matching a key "a:b:c:d:e:", this map function emits "a:b:c:*". |
1157 | + // For a search key "a:b:" matching a key "a:b:c:", it emits "a:b:c:". |
1158 | + mapf := fmt.Sprintf(` |
1159 | + function() { |
1160 | + var k = this.k; |
1161 | + var i = k.indexOf(':', %d)+1; |
1162 | + if (k.length > i) { k = k.substr(0, i)+'*'; } |
1163 | + emit(k, this.c); |
1164 | + }`, len(skey)) |
1165 | + reducef := "function(key, values) { return Array.sum(values); }" |
1166 | + job := mgo.MapReduce{Map: mapf, Reduce: reducef} |
1167 | + |
1168 | + var result []struct { |
1169 | + Key string `bson:"_id"` |
1170 | + Value int64 |
1171 | + } |
1172 | + _, err = countersColl.Find(bson.D{{"k", bson.D{{"$regex", regex}}}}).MapReduce(&job, &result) |
1173 | + if err != nil { |
1174 | + return nil, err |
1175 | + } |
1176 | + var counters []Counter |
1177 | + for i := range result { |
1178 | + ids := strings.Split(result[i].Key, ":") |
1179 | + tokens := make([]string, 0, len(ids)) |
1180 | + for i := 0; i < len(ids)-1; i++ { |
1181 | + if ids[i] == "*" { |
1182 | + continue |
1183 | + } |
1184 | + id, err := strconv.ParseInt(ids[i], 32, 32) |
1185 | + if err != nil { |
1186 | + return nil, fmt.Errorf("store: invalid id: %q", ids[i]) |
1187 | + } |
1188 | + token, found := s.statsIdToken(int(id)) |
1189 | + if !found { |
1190 | + var t tokenId |
1191 | + err = tokensColl.FindId(id).One(&t) |
1192 | + if err == mgo.ErrNotFound { |
1193 | + return nil, fmt.Errorf("store: internal error; token id not found: %d", id) |
1194 | + } |
1195 | + s.cacheStatsTokenId(t.Token, t.Id) |
1196 | + token = t.Token |
1197 | + } |
1198 | + tokens = append(tokens, token) |
1199 | + } |
1200 | + counter := Counter{ |
1201 | + Key: tokens, |
1202 | + Count: result[i].Value, |
1203 | + Prefix: len(ids) > 0 && ids[len(ids)-1] == "*", |
1204 | + } |
1205 | + counters = append(counters, counter) |
1206 | + } |
1207 | + sort.Sort(sortableCounters(counters)) |
1208 | + return counters, nil |
1209 | +} |
1210 | + |
1211 | +type sortableCounters []Counter |
1212 | + |
1213 | +func (s sortableCounters) Len() int { return len(s) } |
1214 | +func (s sortableCounters) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
1215 | +func (s sortableCounters) Less(i, j int) bool { |
1216 | + // Larger counts first. |
1217 | + if s[i].Count != s[j].Count { |
1218 | + return s[j].Count < s[i].Count |
1219 | + } |
1220 | + // Then smaller/shorter keys first. |
1221 | + ki := s[i].Key |
1222 | + kj := s[j].Key |
1223 | + for n := range ki { |
1224 | + if n >= len(kj) { |
1225 | + return false |
1226 | + } |
1227 | + if ki[n] != kj[n] { |
1228 | + return ki[n] < kj[n] |
1229 | + } |
1230 | + } |
1231 | + if len(ki) < len(kj) { |
1232 | + return true |
1233 | + } |
1234 | + // Then full keys first. |
1235 | + return !s[i].Prefix && s[j].Prefix |
1236 | +} |
1237 | + |
1238 | // A CharmPublisher is responsible for importing a charm dir onto the store. |
1239 | type CharmPublisher struct { |
1240 | revision int |
1241 | |
1242 | === modified file 'store/store_test.go' |
1243 | --- store/store_test.go 2013-02-28 08:11:29 +0000 |
1244 | +++ store/store_test.go 2013-02-28 12:30:29 +0000 |
1245 | @@ -464,8 +464,8 @@ |
1246 | {[]string{"a", "b", "c"}, false, 10}, |
1247 | {[]string{"a", "b"}, false, 7}, |
1248 | {[]string{"a", "z", "b"}, false, 3}, |
1249 | - {[]string{"a", "b", "c"}, true, 10}, |
1250 | - {[]string{"a", "b"}, true, 17}, |
1251 | + {[]string{"a", "b", "c"}, true, 0}, |
1252 | + {[]string{"a", "b"}, true, 10}, |
1253 | {[]string{"a"}, true, 20}, |
1254 | {[]string{"b"}, true, 0}, |
1255 | } |
1256 | @@ -523,7 +523,7 @@ |
1257 | c.Assert(err, IsNil) |
1258 | c.Assert(sum, Equals, int64(0)) |
1259 | |
1260 | - const genSize = 512 |
1261 | + const genSize = 1024 |
1262 | |
1263 | // All of these will be cached, as we have two generations |
1264 | // of genSize entries each. |
1265 | @@ -597,6 +597,63 @@ |
1266 | c.Assert(sum, Equals, int64(10)) |
1267 | } |
1268 | |
1269 | +func (s *StoreSuite) TestCounterList(c *C) { |
1270 | + incs := [][]string{ |
1271 | + {"c", "b", "a"}, // Assign internal id c < id b < id a, to make sorting slightly trickier. |
1272 | + {"a"}, |
1273 | + {"a", "c"}, |
1274 | + {"a", "b"}, |
1275 | + {"a", "b", "c"}, |
1276 | + {"a", "b", "c"}, |
1277 | + {"a", "b", "e"}, |
1278 | + {"a", "b", "d"}, |
1279 | + {"a", "f", "g"}, |
1280 | + {"a", "f", "h"}, |
1281 | + {"a", "i"}, |
1282 | + {"a", "i", "j"}, |
1283 | + {"k", "l"}, |
1284 | + } |
1285 | + for _, key := range incs { |
1286 | + err := s.store.IncCounter(key) |
1287 | + c.Assert(err, IsNil) |
1288 | + } |
1289 | + |
1290 | + tests := []struct { |
1291 | + prefix []string |
1292 | + result []store.Counter |
1293 | + }{ |
1294 | + { |
1295 | + []string{"a"}, |
1296 | + []store.Counter{ |
1297 | + {[]string{"a", "b"}, 4, true}, |
1298 | + {[]string{"a", "f"}, 2, true}, |
1299 | + {[]string{"a", "b"}, 1, false}, |
1300 | + {[]string{"a", "c"}, 1, false}, |
1301 | + {[]string{"a", "i"}, 1, false}, |
1302 | + {[]string{"a", "i"}, 1, true}, |
1303 | + }, |
1304 | + }, { |
1305 | + []string{"a", "b"}, |
1306 | + []store.Counter{ |
1307 | + {[]string{"a", "b", "c"}, 2, false}, |
1308 | + {[]string{"a", "b", "d"}, 1, false}, |
1309 | + {[]string{"a", "b", "e"}, 1, false}, |
1310 | + }, |
1311 | + }, |
1312 | + } |
1313 | + |
1314 | + // Use a different store to exercise cache filling. |
1315 | + st, err := store.Open(s.Addr) |
1316 | + c.Assert(err, IsNil) |
1317 | + defer st.Close() |
1318 | + |
1319 | + for i := range tests { |
1320 | + result, err := st.ListCounters(tests[i].prefix) |
1321 | + c.Assert(err, IsNil) |
1322 | + c.Assert(result, DeepEquals, tests[i].result) |
1323 | + } |
1324 | +} |
1325 | + |
1326 | func (s *TrivialSuite) TestEventString(c *C) { |
1327 | c.Assert(store.EventPublished, Matches, "published") |
1328 | c.Assert(store.EventPublishError, Matches, "publish-error") |
1329 | |
1330 | === modified file 'testing/cmd.go' |
1331 | --- testing/cmd.go 2013-02-28 08:11:29 +0000 |
1332 | +++ testing/cmd.go 2013-02-28 12:30:29 +0000 |
1333 | @@ -27,15 +27,38 @@ |
1334 | return c.Init(f.Args()) |
1335 | } |
1336 | |
1337 | +// Context creates a simple command execution context with the current |
1338 | +// dir set to a newly created directory within the test directory. |
1339 | +func Context(c *C) *cmd.Context { |
1340 | + return &cmd.Context{ |
1341 | + Dir: c.MkDir(), |
1342 | + Stdin: &bytes.Buffer{}, |
1343 | + Stdout: &bytes.Buffer{}, |
1344 | + Stderr: &bytes.Buffer{}, |
1345 | + } |
1346 | +} |
1347 | + |
1348 | +// ContextForDir creates a simple command execution context with the current |
1349 | +// dir set to the specified directory. |
1350 | +func ContextForDir(c *C, dir string) *cmd.Context { |
1351 | + return &cmd.Context{ |
1352 | + Dir: dir, |
1353 | + Stdin: &bytes.Buffer{}, |
1354 | + Stdout: &bytes.Buffer{}, |
1355 | + Stderr: &bytes.Buffer{}, |
1356 | + } |
1357 | +} |
1358 | + |
1359 | // RunCommand will run a command with the specified args. The returned error |
1360 | // may come from either the parsing of the args, the command initialisation or |
1361 | // the actual running of the command. Access to the resulting output streams |
1362 | -// is not provided with this function. |
1363 | -func RunCommand(c *C, com cmd.Command, args []string) error { |
1364 | +// is provided through the returned context instance. |
1365 | +func RunCommand(c *C, com cmd.Command, args []string) (*cmd.Context, error) { |
1366 | if err := InitCommand(com, args); err != nil { |
1367 | - return err |
1368 | + return nil, err |
1369 | } |
1370 | - return com.Run(&cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}) |
1371 | + var context = Context(c) |
1372 | + return context, com.Run(context) |
1373 | } |
1374 | |
1375 | // TestInit checks that a command initialises correctly with the given set of |
1376 | |
1377 | === modified file 'worker/uniter/jujuc/config-get_test.go' |
1378 | --- worker/uniter/jujuc/config-get_test.go 2013-02-28 08:11:29 +0000 |
1379 | +++ worker/uniter/jujuc/config-get_test.go 2013-02-28 12:30:29 +0000 |
1380 | @@ -41,7 +41,7 @@ |
1381 | hctx := s.GetHookContext(c, -1, "") |
1382 | com, err := jujuc.NewCommand(hctx, "config-get") |
1383 | c.Assert(err, IsNil) |
1384 | - ctx := dummyContext(c) |
1385 | + ctx := testing.Context(c) |
1386 | code := cmd.Main(com, ctx, t.args) |
1387 | c.Assert(code, Equals, 0) |
1388 | c.Assert(bufferString(ctx.Stderr), Equals, "") |
1389 | @@ -53,7 +53,7 @@ |
1390 | hctx := s.GetHookContext(c, -1, "") |
1391 | com, err := jujuc.NewCommand(hctx, "config-get") |
1392 | c.Assert(err, IsNil) |
1393 | - ctx := dummyContext(c) |
1394 | + ctx := testing.Context(c) |
1395 | code := cmd.Main(com, ctx, []string{"--help"}) |
1396 | c.Assert(code, Equals, 0) |
1397 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
1398 | @@ -74,7 +74,7 @@ |
1399 | hctx := s.GetHookContext(c, -1, "") |
1400 | com, err := jujuc.NewCommand(hctx, "config-get") |
1401 | c.Assert(err, IsNil) |
1402 | - ctx := dummyContext(c) |
1403 | + ctx := testing.Context(c) |
1404 | code := cmd.Main(com, ctx, []string{"--output", "some-file", "monsters"}) |
1405 | c.Assert(code, Equals, 0) |
1406 | c.Assert(bufferString(ctx.Stderr), Equals, "") |
1407 | |
1408 | === modified file 'worker/uniter/jujuc/ports_test.go' |
1409 | --- worker/uniter/jujuc/ports_test.go 2013-02-28 08:11:29 +0000 |
1410 | +++ worker/uniter/jujuc/ports_test.go 2013-02-28 12:30:29 +0000 |
1411 | @@ -29,7 +29,7 @@ |
1412 | for _, t := range portsTests { |
1413 | com, err := jujuc.NewCommand(hctx, t.cmd[0]) |
1414 | c.Assert(err, IsNil) |
1415 | - ctx := dummyContext(c) |
1416 | + ctx := testing.Context(c) |
1417 | code := cmd.Main(com, ctx, t.cmd[1:]) |
1418 | c.Assert(code, Equals, 0) |
1419 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
1420 | |
1421 | === modified file 'worker/uniter/jujuc/relation-get_test.go' |
1422 | --- worker/uniter/jujuc/relation-get_test.go 2013-02-28 08:11:29 +0000 |
1423 | +++ worker/uniter/jujuc/relation-get_test.go 2013-02-28 12:30:29 +0000 |
1424 | @@ -5,6 +5,7 @@ |
1425 | "io/ioutil" |
1426 | . "launchpad.net/gocheck" |
1427 | "launchpad.net/juju-core/cmd" |
1428 | + "launchpad.net/juju-core/testing" |
1429 | "launchpad.net/juju-core/worker/uniter/jujuc" |
1430 | "path/filepath" |
1431 | ) |
1432 | @@ -165,7 +166,7 @@ |
1433 | hctx := s.GetHookContext(c, t.relid, t.unit) |
1434 | com, err := jujuc.NewCommand(hctx, "relation-get") |
1435 | c.Assert(err, IsNil) |
1436 | - ctx := dummyContext(c) |
1437 | + ctx := testing.Context(c) |
1438 | code := cmd.Main(com, ctx, t.args) |
1439 | c.Assert(code, Equals, t.code) |
1440 | if code == 0 { |
1441 | @@ -230,7 +231,7 @@ |
1442 | hctx := s.GetHookContext(c, t.relid, t.unit) |
1443 | com, err := jujuc.NewCommand(hctx, "relation-get") |
1444 | c.Assert(err, IsNil) |
1445 | - ctx := dummyContext(c) |
1446 | + ctx := testing.Context(c) |
1447 | code := cmd.Main(com, ctx, []string{"--help"}) |
1448 | c.Assert(code, Equals, 0) |
1449 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
1450 | @@ -247,7 +248,7 @@ |
1451 | hctx := s.GetHookContext(c, 1, "m/0") |
1452 | com, err := jujuc.NewCommand(hctx, "relation-get") |
1453 | c.Assert(err, IsNil) |
1454 | - ctx := dummyContext(c) |
1455 | + ctx := testing.Context(c) |
1456 | code := cmd.Main(com, ctx, []string{"--output", "some-file", "pew"}) |
1457 | c.Assert(code, Equals, 0) |
1458 | c.Assert(bufferString(ctx.Stderr), Equals, "") |
1459 | |
1460 | === modified file 'worker/uniter/jujuc/relation-ids_test.go' |
1461 | --- worker/uniter/jujuc/relation-ids_test.go 2013-02-28 08:11:29 +0000 |
1462 | +++ worker/uniter/jujuc/relation-ids_test.go 2013-02-28 12:30:29 +0000 |
1463 | @@ -4,6 +4,7 @@ |
1464 | "fmt" |
1465 | . "launchpad.net/gocheck" |
1466 | "launchpad.net/juju-core/cmd" |
1467 | + "launchpad.net/juju-core/testing" |
1468 | "launchpad.net/juju-core/worker/uniter/jujuc" |
1469 | ) |
1470 | |
1471 | @@ -101,7 +102,7 @@ |
1472 | hctx := s.GetHookContext(c, t.relid, "") |
1473 | com, err := jujuc.NewCommand(hctx, "relation-ids") |
1474 | c.Assert(err, IsNil) |
1475 | - ctx := dummyContext(c) |
1476 | + ctx := testing.Context(c) |
1477 | code := cmd.Main(com, ctx, t.args) |
1478 | c.Assert(code, Equals, t.code) |
1479 | if code == 0 { |
1480 | @@ -141,7 +142,7 @@ |
1481 | hctx := s.GetHookContext(c, relid, "") |
1482 | com, err := jujuc.NewCommand(hctx, "relation-ids") |
1483 | c.Assert(err, IsNil) |
1484 | - ctx := dummyContext(c) |
1485 | + ctx := testing.Context(c) |
1486 | code := cmd.Main(com, ctx, []string{"--help"}) |
1487 | c.Assert(code, Equals, 0) |
1488 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
1489 | |
1490 | === modified file 'worker/uniter/jujuc/relation-list_test.go' |
1491 | --- worker/uniter/jujuc/relation-list_test.go 2013-02-28 08:11:29 +0000 |
1492 | +++ worker/uniter/jujuc/relation-list_test.go 2013-02-28 12:30:29 +0000 |
1493 | @@ -4,6 +4,7 @@ |
1494 | "fmt" |
1495 | . "launchpad.net/gocheck" |
1496 | "launchpad.net/juju-core/cmd" |
1497 | + "launchpad.net/juju-core/testing" |
1498 | "launchpad.net/juju-core/worker/uniter/jujuc" |
1499 | ) |
1500 | |
1501 | @@ -107,7 +108,7 @@ |
1502 | setMembers(hctx.rels[1], t.members1) |
1503 | com, err := jujuc.NewCommand(hctx, "relation-list") |
1504 | c.Assert(err, IsNil) |
1505 | - ctx := dummyContext(c) |
1506 | + ctx := testing.Context(c) |
1507 | code := cmd.Main(com, ctx, t.args) |
1508 | c.Logf(bufferString(ctx.Stderr)) |
1509 | c.Assert(code, Equals, t.code) |
1510 | @@ -148,7 +149,7 @@ |
1511 | hctx := s.GetHookContext(c, relid, "") |
1512 | com, err := jujuc.NewCommand(hctx, "relation-list") |
1513 | c.Assert(err, IsNil) |
1514 | - ctx := dummyContext(c) |
1515 | + ctx := testing.Context(c) |
1516 | code := cmd.Main(com, ctx, []string{"--help"}) |
1517 | c.Assert(code, Equals, 0) |
1518 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
1519 | |
1520 | === modified file 'worker/uniter/jujuc/relation-set_test.go' |
1521 | --- worker/uniter/jujuc/relation-set_test.go 2013-02-28 08:11:29 +0000 |
1522 | +++ worker/uniter/jujuc/relation-set_test.go 2013-02-28 12:30:29 +0000 |
1523 | @@ -25,7 +25,7 @@ |
1524 | hctx := s.GetHookContext(c, t.relid, "") |
1525 | com, err := jujuc.NewCommand(hctx, "relation-set") |
1526 | c.Assert(err, IsNil) |
1527 | - ctx := dummyContext(c) |
1528 | + ctx := testing.Context(c) |
1529 | code := cmd.Main(com, ctx, []string{"--help"}) |
1530 | c.Assert(code, Equals, 0) |
1531 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
1532 | @@ -198,7 +198,7 @@ |
1533 | rset := com.(*jujuc.RelationSetCommand) |
1534 | rset.RelationId = 1 |
1535 | rset.Settings = t.change |
1536 | - ctx := dummyContext(c) |
1537 | + ctx := testing.Context(c) |
1538 | err = com.Run(ctx) |
1539 | c.Assert(err, IsNil) |
1540 | |
1541 | |
1542 | === modified file 'worker/uniter/jujuc/server.go' |
1543 | --- worker/uniter/jujuc/server.go 2013-02-28 08:11:29 +0000 |
1544 | +++ worker/uniter/jujuc/server.go 2013-02-28 12:30:29 +0000 |
1545 | @@ -91,7 +91,12 @@ |
1546 | return badReqErrorf("%s", err) |
1547 | } |
1548 | var stdin, stdout, stderr bytes.Buffer |
1549 | - ctx := &cmd.Context{req.Dir, &stdin, &stdout, &stderr} |
1550 | + ctx := &cmd.Context{ |
1551 | + Dir: req.Dir, |
1552 | + Stdin: &stdin, |
1553 | + Stdout: &stdout, |
1554 | + Stderr: &stderr, |
1555 | + } |
1556 | j.mu.Lock() |
1557 | defer j.mu.Unlock() |
1558 | log.Printf("worker/uniter/jujuc: running hook %q %q", req.CommandName, req.Args) |
1559 | |
1560 | === modified file 'worker/uniter/jujuc/unit-get_test.go' |
1561 | --- worker/uniter/jujuc/unit-get_test.go 2013-02-28 08:11:29 +0000 |
1562 | +++ worker/uniter/jujuc/unit-get_test.go 2013-02-28 12:30:29 +0000 |
1563 | @@ -37,7 +37,7 @@ |
1564 | func (s *UnitGetSuite) TestOutputFormat(c *C) { |
1565 | for _, t := range unitGetTests { |
1566 | com := s.createCommand(c) |
1567 | - ctx := dummyContext(c) |
1568 | + ctx := testing.Context(c) |
1569 | code := cmd.Main(com, ctx, t.args) |
1570 | c.Assert(code, Equals, 0) |
1571 | c.Assert(bufferString(ctx.Stderr), Equals, "") |
1572 | @@ -47,7 +47,7 @@ |
1573 | |
1574 | func (s *UnitGetSuite) TestHelp(c *C) { |
1575 | com := s.createCommand(c) |
1576 | - ctx := dummyContext(c) |
1577 | + ctx := testing.Context(c) |
1578 | code := cmd.Main(com, ctx, []string{"--help"}) |
1579 | c.Assert(code, Equals, 0) |
1580 | c.Assert(bufferString(ctx.Stdout), Equals, "") |
1581 | @@ -64,7 +64,7 @@ |
1582 | |
1583 | func (s *UnitGetSuite) TestOutputPath(c *C) { |
1584 | com := s.createCommand(c) |
1585 | - ctx := dummyContext(c) |
1586 | + ctx := testing.Context(c) |
1587 | code := cmd.Main(com, ctx, []string{"--output", "some-file", "private-address"}) |
1588 | c.Assert(code, Equals, 0) |
1589 | c.Assert(bufferString(ctx.Stderr), Equals, "") |
1590 | |
1591 | === modified file 'worker/uniter/jujuc/util_test.go' |
1592 | --- worker/uniter/jujuc/util_test.go 2013-02-28 08:11:29 +0000 |
1593 | +++ worker/uniter/jujuc/util_test.go 2013-02-28 12:30:29 +0000 |
1594 | @@ -5,7 +5,6 @@ |
1595 | "fmt" |
1596 | "io" |
1597 | . "launchpad.net/gocheck" |
1598 | - "launchpad.net/juju-core/cmd" |
1599 | "launchpad.net/juju-core/state" |
1600 | "launchpad.net/juju-core/worker/uniter/jujuc" |
1601 | "sort" |
1602 | @@ -14,10 +13,6 @@ |
1603 | |
1604 | func TestPackage(t *testing.T) { TestingT(t) } |
1605 | |
1606 | -func dummyContext(c *C) *cmd.Context { |
1607 | - return &cmd.Context{c.MkDir(), nil, &bytes.Buffer{}, &bytes.Buffer{}} |
1608 | -} |
1609 | - |
1610 | func bufferString(w io.Writer) string { |
1611 | return w.(*bytes.Buffer).String() |
1612 | } |
Reviewers: mp+151005_ code.launchpad. net,
Message:
Please take a look.
Description:
revert only r943
William merged a change which reverted trunk back to 942
because rev 943 broke the test suite.
This just re-introduces all of the merges 944-947, so that
Gustavo and Ian don't have to re-propose and get approval
for their changes again.
I've run the test suite to make sure it passes as long as
just 943 has been removed.
In the future, you can just cherrypick-out specific revisions
with (eg):
bzr merge . -r 943..942
And then run the test suite, and propose it. (Which is essentially
what this patch does, except it also reverts 948 which removed
all of those other revisions.)
https:/ /code.launchpad .net/~jameinel/ juju-core/ only-943/ +merge/ 151005
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/7424046/
Affected files: addrelation_ test.go addunit_ test.go bootstrap_ test.go cmd_test. go config_ test.go constraints_ test.go deploy_ test.go destroymachine_ test.go destroyrelation _test.go destroyservice_ test.go destroyunit_ test.go expose_ test.go init_test. go resolved_ test.go scp_test. go ssh_test. go status_ test.go unexpose_ test.go upgradejuju_ test.go agent_test. go bootstrap_ test.go d_test. go agent/agent. go api_test. go test.go uniter/ jujuc/config- get_test. go uniter/ jujuc/ports_ test.go uniter/ jujuc/relation- get_test. go uniter/ jujuc/relation- ids_test. go uniter/ jujuc/relation- list_test. go uniter/ jujuc/relation- set_test. go uniter/ jujuc/server. go uniter/ jujuc/unit- get_test. go uniter/ jujuc/util_ test.go
A [revision details]
M cmd/cmd.go
M cmd/cmd_test.go
M cmd/filevar_test.go
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/juju/
M cmd/jujud/
M cmd/jujud/
M cmd/logging_test.go
M cmd/output_test.go
M cmd/supercomman
M cmd/util_test.go
M environs/
M juju/api.go
M juju/conn.go
M state/api/
M state/api/error.go
M state/open.go
M state/state_test.go
M state/unit_test.go
M store/server.go
M store/server_
M store/store.go
M store/store_test.go
M testing/cmd.go
M worker/
M worker/
M worker/
M worker/
M worker/
M worker/
M worker/
M worker/
M worker/