Merge lp:~jameinel/juju-core/only-943 into lp:~juju/juju-core/trunk

Proposed by John A Meinel
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
Reviewer Review Type Date Requested Status
The Go Language Gophers Pending
Review via email: mp+151005@code.launchpad.net

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.)

https://codereview.appspot.com/7424046/

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

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:
   A [revision details]
   M cmd/cmd.go
   M cmd/cmd_test.go
   M cmd/filevar_test.go
   M cmd/juju/addrelation_test.go
   M cmd/juju/addunit_test.go
   M cmd/juju/bootstrap_test.go
   M cmd/juju/cmd_test.go
   M cmd/juju/config_test.go
   M cmd/juju/constraints_test.go
   M cmd/juju/deploy_test.go
   M cmd/juju/destroymachine_test.go
   M cmd/juju/destroyrelation_test.go
   M cmd/juju/destroyservice_test.go
   M cmd/juju/destroyunit_test.go
   M cmd/juju/expose_test.go
   M cmd/juju/init_test.go
   M cmd/juju/resolved_test.go
   M cmd/juju/scp_test.go
   M cmd/juju/ssh_test.go
   M cmd/juju/status_test.go
   M cmd/juju/unexpose_test.go
   M cmd/juju/upgradejuju_test.go
   M cmd/jujud/agent_test.go
   M cmd/jujud/bootstrap_test.go
   M cmd/logging_test.go
   M cmd/output_test.go
   M cmd/supercommand_test.go
   M cmd/util_test.go
   M environs/agent/agent.go
   M juju/api.go
   M juju/conn.go
   M state/api/api_test.go
   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_test.go
   M store/store.go
   M store/store_test.go
   M testing/cmd.go
   M worker/uniter/jujuc/config-get_test.go
   M worker/uniter/jujuc/ports_test.go
   M worker/uniter/jujuc/relation-get_test.go
   M worker/uniter/jujuc/relation-ids_test.go
   M worker/uniter/jujuc/relation-list_test.go
   M worker/uniter/jujuc/relation-set_test.go
   M worker/uniter/jujuc/server.go
   M worker/uniter/jujuc/unit-get_test.go
   M worker/uniter/jujuc/util_test.go

Revision history for this message
Ian Booth (wallyworld) wrote :

LGTM. Thanks for doing this.

https://codereview.appspot.com/7424046/

Revision history for this message
William Reade (fwereade) wrote :

LGTM -- thank you very much.

https://codereview.appspot.com/7424046/

Revision history for this message
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://codereview.appspot.com/7424046

https://codereview.appspot.com/7424046/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'cmd/cmd.go'
--- cmd/cmd.go 2013-02-28 08:11:29 +0000
+++ cmd/cmd.go 2013-02-28 12:30:29 +0000
@@ -165,7 +165,12 @@
165 if err != nil {165 if err != nil {
166 panic(err)166 panic(err)
167 }167 }
168 return &Context{abs, os.Stdin, os.Stdout, os.Stderr}168 return &Context{
169 Dir: abs,
170 Stdin: os.Stdin,
171 Stdout: os.Stdout,
172 Stderr: os.Stderr,
173 }
169}174}
170175
171// CheckEmpty is a utility function that returns an error if args is not empty.176// CheckEmpty is a utility function that returns an error if args is not empty.
172177
=== modified file 'cmd/cmd_test.go'
--- cmd/cmd_test.go 2013-02-28 08:11:29 +0000
+++ cmd/cmd_test.go 2013-02-28 12:30:29 +0000
@@ -16,7 +16,7 @@
16var _ = Suite(&CmdSuite{})16var _ = Suite(&CmdSuite{})
1717
18func (s *CmdSuite) TestContext(c *C) {18func (s *CmdSuite) TestContext(c *C) {
19 ctx := dummyContext(c)19 ctx := testing.Context(c)
20 c.Assert(ctx.AbsPath("/foo/bar"), Equals, "/foo/bar")20 c.Assert(ctx.AbsPath("/foo/bar"), Equals, "/foo/bar")
21 c.Assert(ctx.AbsPath("foo/bar"), Equals, filepath.Join(ctx.Dir, "foo/bar"))21 c.Assert(ctx.AbsPath("foo/bar"), Equals, filepath.Join(ctx.Dir, "foo/bar"))
22}22}
@@ -49,7 +49,7 @@
4949
50func (s *CmdSuite) TestMainInitError(c *C) {50func (s *CmdSuite) TestMainInitError(c *C) {
51 for _, t := range initErrorTests {51 for _, t := range initErrorTests {
52 ctx := dummyContext(c)52 ctx := testing.Context(c)
53 result := cmd.Main(t.c, ctx, []string{"--unknown"})53 result := cmd.Main(t.c, ctx, []string{"--unknown"})
54 c.Assert(result, Equals, 2)54 c.Assert(result, Equals, 2)
55 c.Assert(bufferString(ctx.Stdout), Equals, "")55 c.Assert(bufferString(ctx.Stdout), Equals, "")
@@ -59,7 +59,7 @@
59}59}
6060
61func (s *CmdSuite) TestMainRunError(c *C) {61func (s *CmdSuite) TestMainRunError(c *C) {
62 ctx := dummyContext(c)62 ctx := testing.Context(c)
63 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "error"})63 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "error"})
64 c.Assert(result, Equals, 1)64 c.Assert(result, Equals, 1)
65 c.Assert(bufferString(ctx.Stdout), Equals, "")65 c.Assert(bufferString(ctx.Stdout), Equals, "")
@@ -67,7 +67,7 @@
67}67}
6868
69func (s *CmdSuite) TestMainRunSilentError(c *C) {69func (s *CmdSuite) TestMainRunSilentError(c *C) {
70 ctx := dummyContext(c)70 ctx := testing.Context(c)
71 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "silent-error"})71 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "silent-error"})
72 c.Assert(result, Equals, 1)72 c.Assert(result, Equals, 1)
73 c.Assert(bufferString(ctx.Stdout), Equals, "")73 c.Assert(bufferString(ctx.Stdout), Equals, "")
@@ -75,7 +75,7 @@
75}75}
7676
77func (s *CmdSuite) TestMainSuccess(c *C) {77func (s *CmdSuite) TestMainSuccess(c *C) {
78 ctx := dummyContext(c)78 ctx := testing.Context(c)
79 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "success!"})79 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "success!"})
80 c.Assert(result, Equals, 0)80 c.Assert(result, Equals, 0)
81 c.Assert(bufferString(ctx.Stdout), Equals, "success!\n")81 c.Assert(bufferString(ctx.Stdout), Equals, "success!\n")
@@ -84,7 +84,7 @@
8484
85func (s *CmdSuite) TestStdin(c *C) {85func (s *CmdSuite) TestStdin(c *C) {
86 const phrase = "Do you, Juju?"86 const phrase = "Do you, Juju?"
87 ctx := dummyContext(c)87 ctx := testing.Context(c)
88 ctx.Stdin = bytes.NewBuffer([]byte(phrase))88 ctx.Stdin = bytes.NewBuffer([]byte(phrase))
89 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "echo"})89 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{"--option", "echo"})
90 c.Assert(result, Equals, 0)90 c.Assert(result, Equals, 0)
@@ -94,7 +94,7 @@
9494
95func (s *CmdSuite) TestMainHelp(c *C) {95func (s *CmdSuite) TestMainHelp(c *C) {
96 for _, arg := range []string{"-h", "--help"} {96 for _, arg := range []string{"-h", "--help"} {
97 ctx := dummyContext(c)97 ctx := testing.Context(c)
98 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{arg})98 result := cmd.Main(&TestCommand{Name: "verb"}, ctx, []string{arg})
99 c.Assert(result, Equals, 0)99 c.Assert(result, Equals, 0)
100 c.Assert(bufferString(ctx.Stdout), Equals, "")100 c.Assert(bufferString(ctx.Stdout), Equals, "")
101101
=== modified file 'cmd/filevar_test.go'
--- cmd/filevar_test.go 2013-02-28 08:11:29 +0000
+++ cmd/filevar_test.go 2013-02-28 12:30:29 +0000
@@ -17,7 +17,7 @@
17var _ = Suite(&FileVarSuite{})17var _ = Suite(&FileVarSuite{})
1818
19func (s *FileVarSuite) SetUpTest(c *C) {19func (s *FileVarSuite) SetUpTest(c *C) {
20 s.ctx = &cmd.Context{c.MkDir(), nil, nil, nil}20 s.ctx = testing.Context(c)
21 s.ValidPath = s.ctx.AbsPath("valid.yaml")21 s.ValidPath = s.ctx.AbsPath("valid.yaml")
22 s.InvalidPath = s.ctx.AbsPath("invalid.yaml")22 s.InvalidPath = s.ctx.AbsPath("invalid.yaml")
23 f, err := os.Create(s.ValidPath)23 f, err := os.Create(s.ValidPath)
2424
=== modified file 'cmd/juju/addrelation_test.go'
--- cmd/juju/addrelation_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/addrelation_test.go 2013-02-28 12:30:29 +0000
@@ -12,7 +12,8 @@
12var _ = Suite(&AddRelationSuite{})12var _ = Suite(&AddRelationSuite{})
1313
14func runAddRelation(c *C, args ...string) error {14func runAddRelation(c *C, args ...string) error {
15 return testing.RunCommand(c, &AddRelationCommand{}, args)15 _, err := testing.RunCommand(c, &AddRelationCommand{}, args)
16 return err
16}17}
1718
18var msWpAlreadyExists = `cannot add relation "wp:db ms:server": relation already exists`19var msWpAlreadyExists = `cannot add relation "wp:db ms:server": relation already exists`
1920
=== modified file 'cmd/juju/addunit_test.go'
--- cmd/juju/addunit_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/addunit_test.go 2013-02-28 12:30:29 +0000
@@ -13,7 +13,8 @@
13var _ = Suite(&AddUnitSuite{})13var _ = Suite(&AddUnitSuite{})
1414
15func runAddUnit(c *C, args ...string) error {15func runAddUnit(c *C, args ...string) error {
16 return testing.RunCommand(c, &AddUnitCommand{}, args)16 _, err := testing.RunCommand(c, &AddUnitCommand{}, args)
17 return err
17}18}
1819
19func (s *AddUnitSuite) TestAddUnit(c *C) {20func (s *AddUnitSuite) TestAddUnit(c *C) {
2021
=== modified file 'cmd/juju/bootstrap_test.go'
--- cmd/juju/bootstrap_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/bootstrap_test.go 2013-02-28 12:30:29 +0000
@@ -91,7 +91,7 @@
91func (*BootstrapSuite) TestMissingEnvironment(c *C) {91func (*BootstrapSuite) TestMissingEnvironment(c *C) {
92 defer makeFakeHome(c, "empty").restore()92 defer makeFakeHome(c, "empty").restore()
93 // bootstrap without an environments.yaml93 // bootstrap without an environments.yaml
94 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}94 ctx := testing.Context(c)
95 code := cmd.Main(&BootstrapCommand{}, ctx, nil)95 code := cmd.Main(&BootstrapCommand{}, ctx, nil)
96 c.Check(code, Equals, 1)96 c.Check(code, Equals, 1)
97 errStr := ctx.Stderr.(*bytes.Buffer).String()97 errStr := ctx.Stderr.(*bytes.Buffer).String()
9898
=== modified file 'cmd/juju/cmd_test.go'
--- cmd/juju/cmd_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/cmd_test.go 2013-02-28 12:30:29 +0000
@@ -198,7 +198,7 @@
198 }198 }
199199
200 // test relative --config path200 // test relative --config path
201 ctx := &cmd.Context{c.MkDir(), nil, nil, nil}201 ctx := coretesting.Context(c)
202 expected := []byte("test: data")202 expected := []byte("test: data")
203 path := ctx.AbsPath("testconfig.yaml")203 path := ctx.AbsPath("testconfig.yaml")
204 file, err := os.Create(path)204 file, err := os.Create(path)
@@ -323,7 +323,7 @@
323323
324 // test --config path324 // test --config path
325 expected := []byte("this: is some test data")325 expected := []byte("this: is some test data")
326 ctx := &cmd.Context{c.MkDir(), nil, nil, nil}326 ctx := coretesting.Context(c)
327 path := ctx.AbsPath("testconfig.yaml")327 path := ctx.AbsPath("testconfig.yaml")
328 file, err := os.Create(path)328 file, err := os.Create(path)
329 c.Assert(err, IsNil)329 c.Assert(err, IsNil)
330330
=== modified file 'cmd/juju/config_test.go'
--- cmd/juju/config_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/config_test.go 2013-02-28 12:30:29 +0000
@@ -8,6 +8,7 @@
8 "launchpad.net/goyaml"8 "launchpad.net/goyaml"
9 "launchpad.net/juju-core/cmd"9 "launchpad.net/juju-core/cmd"
10 "launchpad.net/juju-core/juju/testing"10 "launchpad.net/juju-core/juju/testing"
11 coretesting "launchpad.net/juju-core/testing"
11)12)
1213
13// juju get and set tests (because one needs the other)14// juju get and set tests (because one needs the other)
@@ -61,7 +62,7 @@
61 _, err := s.State.AddService("dummy-service", sch)62 _, err := s.State.AddService("dummy-service", sch)
62 c.Assert(err, IsNil)63 c.Assert(err, IsNil)
63 for _, t := range getTests {64 for _, t := range getTests {
64 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}65 ctx := coretesting.Context(c)
65 code := cmd.Main(&GetCommand{}, ctx, []string{t.service})66 code := cmd.Main(&GetCommand{}, ctx, []string{t.service})
66 c.Check(code, Equals, 0)67 c.Check(code, Equals, 0)
67 c.Assert(ctx.Stderr.(*bytes.Buffer).String(), Equals, "")68 c.Assert(ctx.Stderr.(*bytes.Buffer).String(), Equals, "")
@@ -129,7 +130,7 @@
129 for i, t := range setTests {130 for i, t := range setTests {
130 args := append([]string{"dummy-service"}, t.args...)131 args := append([]string{"dummy-service"}, t.args...)
131 c.Logf("test %d. %s", i, t.about)132 c.Logf("test %d. %s", i, t.about)
132 ctx := &cmd.Context{dir, &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}133 ctx := coretesting.ContextForDir(c, dir)
133 code := cmd.Main(&SetCommand{}, ctx, args)134 code := cmd.Main(&SetCommand{}, ctx, args)
134 if t.err != "" {135 if t.err != "" {
135 c.Check(code, Not(Equals), 0)136 c.Check(code, Not(Equals), 0)
@@ -144,7 +145,7 @@
144}145}
145146
146func setupConfigfile(c *C, dir string) {147func setupConfigfile(c *C, dir string) {
147 ctx := &cmd.Context{dir, nil, nil, nil}148 ctx := coretesting.ContextForDir(c, dir)
148 path := ctx.AbsPath("testconfig.yaml")149 path := ctx.AbsPath("testconfig.yaml")
149 file, err := os.Create(path)150 file, err := os.Create(path)
150 c.Assert(err, IsNil)151 c.Assert(err, IsNil)
151152
=== modified file 'cmd/juju/constraints_test.go'
--- cmd/juju/constraints_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/constraints_test.go 2013-02-28 12:30:29 +0000
@@ -6,6 +6,7 @@
6 "launchpad.net/juju-core/cmd"6 "launchpad.net/juju-core/cmd"
7 "launchpad.net/juju-core/juju/testing"7 "launchpad.net/juju-core/juju/testing"
8 "launchpad.net/juju-core/state"8 "launchpad.net/juju-core/state"
9 coretesting "launchpad.net/juju-core/testing"
9)10)
1011
11type ConstraintsCommandsSuite struct {12type ConstraintsCommandsSuite struct {
@@ -15,7 +16,7 @@
15var _ = Suite(&ConstraintsCommandsSuite{})16var _ = Suite(&ConstraintsCommandsSuite{})
1617
17func runCmdLine(c *C, com cmd.Command, args ...string) (code int, stdout, stderr string) {18func runCmdLine(c *C, com cmd.Command, args ...string) (code int, stdout, stderr string) {
18 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}19 ctx := coretesting.Context(c)
19 code = cmd.Main(com, ctx, args)20 code = cmd.Main(com, ctx, args)
20 stdout = ctx.Stdout.(*bytes.Buffer).String()21 stdout = ctx.Stdout.(*bytes.Buffer).String()
21 stderr = ctx.Stderr.(*bytes.Buffer).String()22 stderr = ctx.Stderr.(*bytes.Buffer).String()
2223
=== modified file 'cmd/juju/deploy_test.go'
--- cmd/juju/deploy_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/deploy_test.go 2013-02-28 12:30:29 +0000
@@ -106,7 +106,8 @@
106var _ = Suite(&DeploySuite{})106var _ = Suite(&DeploySuite{})
107107
108func runDeploy(c *C, args ...string) error {108func runDeploy(c *C, args ...string) error {
109 return coretesting.RunCommand(c, &DeployCommand{}, args)109 _, err := coretesting.RunCommand(c, &DeployCommand{}, args)
110 return err
110}111}
111112
112var initErrorTests = []struct {113var initErrorTests = []struct {
113114
=== modified file 'cmd/juju/destroymachine_test.go'
--- cmd/juju/destroymachine_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/destroymachine_test.go 2013-02-28 12:30:29 +0000
@@ -13,7 +13,8 @@
13var _ = Suite(&DestroyMachineSuite{})13var _ = Suite(&DestroyMachineSuite{})
1414
15func runDestroyMachine(c *C, args ...string) error {15func runDestroyMachine(c *C, args ...string) error {
16 return testing.RunCommand(c, &DestroyMachineCommand{}, args)16 _, err := testing.RunCommand(c, &DestroyMachineCommand{}, args)
17 return err
17}18}
1819
19func (s *DestroyMachineSuite) TestDestroyMachine(c *C) {20func (s *DestroyMachineSuite) TestDestroyMachine(c *C) {
2021
=== modified file 'cmd/juju/destroyrelation_test.go'
--- cmd/juju/destroyrelation_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/destroyrelation_test.go 2013-02-28 12:30:29 +0000
@@ -12,7 +12,8 @@
12var _ = Suite(&DestroyRelationSuite{})12var _ = Suite(&DestroyRelationSuite{})
1313
14func runDestroyRelation(c *C, args ...string) error {14func runDestroyRelation(c *C, args ...string) error {
15 return testing.RunCommand(c, &DestroyRelationCommand{}, args)15 _, err := testing.RunCommand(c, &DestroyRelationCommand{}, args)
16 return err
16}17}
1718
18func (s *DestroyRelationSuite) TestDestroyRelation(c *C) {19func (s *DestroyRelationSuite) TestDestroyRelation(c *C) {
1920
=== modified file 'cmd/juju/destroyservice_test.go'
--- cmd/juju/destroyservice_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/destroyservice_test.go 2013-02-28 12:30:29 +0000
@@ -13,7 +13,8 @@
13var _ = Suite(&DestroyServiceSuite{})13var _ = Suite(&DestroyServiceSuite{})
1414
15func runDestroyService(c *C, args ...string) error {15func runDestroyService(c *C, args ...string) error {
16 return testing.RunCommand(c, &DestroyServiceCommand{}, args)16 _, err := testing.RunCommand(c, &DestroyServiceCommand{}, args)
17 return err
17}18}
1819
19func (s *DestroyServiceSuite) TestSuccess(c *C) {20func (s *DestroyServiceSuite) TestSuccess(c *C) {
2021
=== modified file 'cmd/juju/destroyunit_test.go'
--- cmd/juju/destroyunit_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/destroyunit_test.go 2013-02-28 12:30:29 +0000
@@ -14,7 +14,8 @@
14var _ = Suite(&DestroyUnitSuite{})14var _ = Suite(&DestroyUnitSuite{})
1515
16func runDestroyUnit(c *C, args ...string) error {16func runDestroyUnit(c *C, args ...string) error {
17 return testing.RunCommand(c, &DestroyUnitCommand{}, args)17 _, err := testing.RunCommand(c, &DestroyUnitCommand{}, args)
18 return err
18}19}
1920
20func (s *DestroyUnitSuite) TestDestroyUnit(c *C) {21func (s *DestroyUnitSuite) TestDestroyUnit(c *C) {
2122
=== modified file 'cmd/juju/expose_test.go'
--- cmd/juju/expose_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/expose_test.go 2013-02-28 12:30:29 +0000
@@ -13,7 +13,8 @@
13var _ = Suite(&ExposeSuite{})13var _ = Suite(&ExposeSuite{})
1414
15func runExpose(c *C, args ...string) error {15func runExpose(c *C, args ...string) error {
16 return testing.RunCommand(c, &ExposeCommand{}, args)16 _, err := testing.RunCommand(c, &ExposeCommand{}, args)
17 return err
17}18}
1819
19func (s *ExposeSuite) assertExposed(c *C, service string) {20func (s *ExposeSuite) assertExposed(c *C, service string) {
2021
=== modified file 'cmd/juju/init_test.go'
--- cmd/juju/init_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/init_test.go 2013-02-28 12:30:29 +0000
@@ -1,12 +1,12 @@
1package main1package main
22
3import (3import (
4 "bytes"
4 "io/ioutil"5 "io/ioutil"
5
6 "bytes"
7 . "launchpad.net/gocheck"6 . "launchpad.net/gocheck"
8 "launchpad.net/juju-core/cmd"7 "launchpad.net/juju-core/cmd"
9 "launchpad.net/juju-core/environs"8 "launchpad.net/juju-core/environs"
9 "launchpad.net/juju-core/testing"
10 "strings"10 "strings"
11)11)
1212
@@ -18,7 +18,7 @@
18func (*InitSuite) TestBoilerPlateEnvironment(c *C) {18func (*InitSuite) TestBoilerPlateEnvironment(c *C) {
19 defer makeFakeHome(c, "empty").restore()19 defer makeFakeHome(c, "empty").restore()
20 // run without an environments.yaml20 // run without an environments.yaml
21 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}21 ctx := testing.Context(c)
22 code := cmd.Main(&InitCommand{}, ctx, []string{"-w"})22 code := cmd.Main(&InitCommand{}, ctx, []string{"-w"})
23 c.Check(code, Equals, 0)23 c.Check(code, Equals, 0)
24 outStr := ctx.Stdout.(*bytes.Buffer).String()24 outStr := ctx.Stdout.(*bytes.Buffer).String()
@@ -44,7 +44,7 @@
44 _, err := environs.WriteEnvirons(environpath, env)44 _, err := environs.WriteEnvirons(environpath, env)
45 c.Assert(err, IsNil)45 c.Assert(err, IsNil)
4646
47 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}47 ctx := testing.Context(c)
48 code := cmd.Main(&InitCommand{}, ctx, []string{"-w"})48 code := cmd.Main(&InitCommand{}, ctx, []string{"-w"})
49 c.Check(code, Equals, 0)49 c.Check(code, Equals, 0)
50 errOut := ctx.Stdout.(*bytes.Buffer).String()50 errOut := ctx.Stdout.(*bytes.Buffer).String()
@@ -70,7 +70,7 @@
70 _, err := environs.WriteEnvirons(environpath, env)70 _, err := environs.WriteEnvirons(environpath, env)
71 c.Assert(err, IsNil)71 c.Assert(err, IsNil)
7272
73 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}73 ctx := testing.Context(c)
74 code := cmd.Main(&InitCommand{}, ctx, nil)74 code := cmd.Main(&InitCommand{}, ctx, nil)
75 c.Check(code, Equals, 0)75 c.Check(code, Equals, 0)
76 errOut := ctx.Stdout.(*bytes.Buffer).String()76 errOut := ctx.Stdout.(*bytes.Buffer).String()
7777
=== modified file 'cmd/juju/resolved_test.go'
--- cmd/juju/resolved_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/resolved_test.go 2013-02-28 12:30:29 +0000
@@ -13,7 +13,8 @@
13var _ = Suite(&ResolvedSuite{})13var _ = Suite(&ResolvedSuite{})
1414
15func runResolved(c *C, args []string) error {15func runResolved(c *C, args []string) error {
16 return testing.RunCommand(c, &ResolvedCommand{}, args)16 _, err := testing.RunCommand(c, &ResolvedCommand{}, args)
17 return err
17}18}
1819
19var resolvedTests = []struct {20var resolvedTests = []struct {
2021
=== modified file 'cmd/juju/scp_test.go'
--- cmd/juju/scp_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/scp_test.go 2013-02-28 12:30:29 +0000
@@ -63,7 +63,7 @@
6363
64 for _, t := range scpTests {64 for _, t := range scpTests {
65 c.Logf("testing juju scp %s", t.args)65 c.Logf("testing juju scp %s", t.args)
66 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}66 ctx := coretesting.Context(c)
67 code := cmd.Main(&SCPCommand{}, ctx, t.args)67 code := cmd.Main(&SCPCommand{}, ctx, t.args)
68 c.Check(code, Equals, 0)68 c.Check(code, Equals, 0)
69 c.Check(ctx.Stderr.(*bytes.Buffer).String(), Equals, "")69 c.Check(ctx.Stderr.(*bytes.Buffer).String(), Equals, "")
7070
=== modified file 'cmd/juju/ssh_test.go'
--- cmd/juju/ssh_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/ssh_test.go 2013-02-28 12:30:29 +0000
@@ -107,7 +107,7 @@
107107
108 for _, t := range sshTests {108 for _, t := range sshTests {
109 c.Logf("testing juju ssh %s", t.args)109 c.Logf("testing juju ssh %s", t.args)
110 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}110 ctx := coretesting.Context(c)
111 code := cmd.Main(&SSHCommand{}, ctx, t.args)111 code := cmd.Main(&SSHCommand{}, ctx, t.args)
112 c.Check(code, Equals, 0)112 c.Check(code, Equals, 0)
113 c.Check(ctx.Stderr.(*bytes.Buffer).String(), Equals, "")113 c.Check(ctx.Stderr.(*bytes.Buffer).String(), Equals, "")
114114
=== modified file 'cmd/juju/status_test.go'
--- cmd/juju/status_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/status_test.go 2013-02-28 12:30:29 +0000
@@ -248,7 +248,7 @@
248 for _, t := range statusTests {248 for _, t := range statusTests {
249 c.Logf("testing %s: %s", format, t.title)249 c.Logf("testing %s: %s", format, t.title)
250 t.prepare(s.State, s.Conn, c)250 t.prepare(s.State, s.Conn, c)
251 ctx := &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}251 ctx := coretesting.Context(c)
252 code := cmd.Main(&StatusCommand{}, ctx, []string{"--format", format})252 code := cmd.Main(&StatusCommand{}, ctx, []string{"--format", format})
253 c.Check(code, Equals, 0)253 c.Check(code, Equals, 0)
254 c.Assert(ctx.Stderr.(*bytes.Buffer).String(), Equals, "")254 c.Assert(ctx.Stderr.(*bytes.Buffer).String(), Equals, "")
255255
=== modified file 'cmd/juju/unexpose_test.go'
--- cmd/juju/unexpose_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/unexpose_test.go 2013-02-28 12:30:29 +0000
@@ -13,7 +13,8 @@
13var _ = Suite(&UnexposeSuite{})13var _ = Suite(&UnexposeSuite{})
1414
15func runUnexpose(c *C, args ...string) error {15func runUnexpose(c *C, args ...string) error {
16 return testing.RunCommand(c, &UnexposeCommand{}, args)16 _, err := testing.RunCommand(c, &UnexposeCommand{}, args)
17 return err
17}18}
1819
19func (s *UnexposeSuite) assertExposed(c *C, service string, expected bool) {20func (s *UnexposeSuite) assertExposed(c *C, service string, expected bool) {
2021
=== modified file 'cmd/juju/upgradejuju_test.go'
--- cmd/juju/upgradejuju_test.go 2013-02-28 08:11:29 +0000
+++ cmd/juju/upgradejuju_test.go 2013-02-28 12:30:29 +0000
@@ -3,7 +3,6 @@
3import (3import (
4 "io/ioutil"4 "io/ioutil"
5 . "launchpad.net/gocheck"5 . "launchpad.net/gocheck"
6 "launchpad.net/juju-core/cmd"
7 "launchpad.net/juju-core/environs"6 "launchpad.net/juju-core/environs"
8 "launchpad.net/juju-core/juju/testing"7 "launchpad.net/juju-core/juju/testing"
9 "launchpad.net/juju-core/state"8 "launchpad.net/juju-core/state"
@@ -188,7 +187,7 @@
188 c.Check(err, ErrorMatches, test.expectInitErr)187 c.Check(err, ErrorMatches, test.expectInitErr)
189 continue188 continue
190 }189 }
191 err = com.Run(&cmd.Context{c.MkDir(), nil, ioutil.Discard, ioutil.Discard})190 err = com.Run(coretesting.Context(c))
192 if test.expectErr != "" {191 if test.expectErr != "" {
193 c.Check(err, ErrorMatches, test.expectErr)192 c.Check(err, ErrorMatches, test.expectErr)
194 continue193 continue
@@ -230,7 +229,7 @@
230229
231func (s *UpgradeJujuSuite) TestUpgradeJujuWithRealPutTools(c *C) {230func (s *UpgradeJujuSuite) TestUpgradeJujuWithRealPutTools(c *C) {
232 s.Reset(c)231 s.Reset(c)
233 err := coretesting.RunCommand(c, &UpgradeJujuCommand{}, []string{"--upload-tools", "--dev"})232 _, err := coretesting.RunCommand(c, &UpgradeJujuCommand{}, []string{"--upload-tools", "--dev"})
234 c.Assert(err, IsNil)233 c.Assert(err, IsNil)
235 p := environs.ToolsStoragePath(version.Current)234 p := environs.ToolsStoragePath(version.Current)
236 r, err := s.Conn.Environ.Storage().Get(p)235 r, err := s.Conn.Environ.Storage().Get(p)
237236
=== modified file 'cmd/jujud/agent_test.go'
--- cmd/jujud/agent_test.go 2013-02-28 08:11:29 +0000
+++ cmd/jujud/agent_test.go 2013-02-28 12:30:29 +0000
@@ -342,7 +342,7 @@
342 info := s.StateInfo(c)342 info := s.StateInfo(c)
343 info.EntityName = ent.EntityName()343 info.EntityName = ent.EntityName()
344 info.Password = "initial"344 info.Password = "initial"
345 testOpenState(c, info, state.ErrUnauthorized)345 testOpenState(c, info, state.Unauthorizedf("unauth"))
346346
347 // Read the configuration and check that we can connect with it.347 // Read the configuration and check that we can connect with it.
348 c.Assert(refreshConfig(conf), IsNil)348 c.Assert(refreshConfig(conf), IsNil)
349349
=== modified file 'cmd/jujud/bootstrap_test.go'
--- cmd/jujud/bootstrap_test.go 2013-02-28 08:11:29 +0000
+++ cmd/jujud/bootstrap_test.go 2013-02-28 12:30:29 +0000
@@ -145,7 +145,7 @@
145 st.Close()145 st.Close()
146 }146 }
147 if expectErr != nil {147 if expectErr != nil {
148 c.Assert(err, Equals, expectErr)148 c.Assert(state.IsUnauthorizedError(err), Equals, true)
149 } else {149 } else {
150 c.Assert(err, IsNil)150 c.Assert(err, IsNil)
151 }151 }
@@ -177,7 +177,7 @@
177 Addrs: []string{testing.MgoAddr},177 Addrs: []string{testing.MgoAddr},
178 CACert: []byte(testing.CACert),178 CACert: []byte(testing.CACert),
179 }179 }
180 testOpenState(c, info, state.ErrUnauthorized)180 testOpenState(c, info, state.Unauthorizedf("some auth problem"))
181181
182 info.EntityName, info.Password = "machine-0", "foo"182 info.EntityName, info.Password = "machine-0", "foo"
183 testOpenState(c, info, nil)183 testOpenState(c, info, nil)
184184
=== modified file 'cmd/logging_test.go'
--- cmd/logging_test.go 2013-02-28 08:11:29 +0000
+++ cmd/logging_test.go 2013-02-28 12:30:29 +0000
@@ -61,7 +61,7 @@
61 {"foo", false, false, NotNil},61 {"foo", false, false, NotNil},
62 } {62 } {
63 l := &cmd.Log{t.path, t.verbose, t.debug}63 l := &cmd.Log{t.path, t.verbose, t.debug}
64 ctx := dummyContext(c)64 ctx := testing.Context(c)
65 err := l.Start(ctx)65 err := l.Start(ctx)
66 c.Assert(err, IsNil)66 c.Assert(err, IsNil)
67 c.Assert(log.Target, t.target)67 c.Assert(log.Target, t.target)
@@ -71,7 +71,7 @@
7171
72func (s *LogSuite) TestStderr(c *C) {72func (s *LogSuite) TestStderr(c *C) {
73 l := &cmd.Log{Verbose: true}73 l := &cmd.Log{Verbose: true}
74 ctx := dummyContext(c)74 ctx := testing.Context(c)
75 err := l.Start(ctx)75 err := l.Start(ctx)
76 c.Assert(err, IsNil)76 c.Assert(err, IsNil)
77 log.Printf("hello")77 log.Printf("hello")
@@ -80,7 +80,7 @@
8080
81func (s *LogSuite) TestRelPathLog(c *C) {81func (s *LogSuite) TestRelPathLog(c *C) {
82 l := &cmd.Log{Path: "foo.log"}82 l := &cmd.Log{Path: "foo.log"}
83 ctx := dummyContext(c)83 ctx := testing.Context(c)
84 err := l.Start(ctx)84 err := l.Start(ctx)
85 c.Assert(err, IsNil)85 c.Assert(err, IsNil)
86 log.Printf("hello")86 log.Printf("hello")
@@ -93,7 +93,7 @@
93func (s *LogSuite) TestAbsPathLog(c *C) {93func (s *LogSuite) TestAbsPathLog(c *C) {
94 path := filepath.Join(c.MkDir(), "foo.log")94 path := filepath.Join(c.MkDir(), "foo.log")
95 l := &cmd.Log{Path: path}95 l := &cmd.Log{Path: path}
96 ctx := dummyContext(c)96 ctx := testing.Context(c)
97 err := l.Start(ctx)97 err := l.Start(ctx)
98 c.Assert(err, IsNil)98 c.Assert(err, IsNil)
99 log.Printf("hello")99 log.Printf("hello")
100100
=== modified file 'cmd/output_test.go'
--- cmd/output_test.go 2013-02-28 08:11:29 +0000
+++ cmd/output_test.go 2013-02-28 12:30:29 +0000
@@ -4,6 +4,7 @@
4 "launchpad.net/gnuflag"4 "launchpad.net/gnuflag"
5 . "launchpad.net/gocheck"5 . "launchpad.net/gocheck"
6 "launchpad.net/juju-core/cmd"6 "launchpad.net/juju-core/cmd"
7 "launchpad.net/juju-core/testing"
7)8)
89
9// OutputCommand is a command that uses the output.go formatters.10// OutputCommand is a command that uses the output.go formatters.
@@ -102,7 +103,7 @@
102 }103 }
103 for i, t := range tests {104 for i, t := range tests {
104 c.Logf(" test %d", i)105 c.Logf(" test %d", i)
105 ctx := dummyContext(c)106 ctx := testing.Context(c)
106 result := cmd.Main(&OutputCommand{value: t.value}, ctx, args)107 result := cmd.Main(&OutputCommand{value: t.value}, ctx, args)
107 c.Assert(result, Equals, 0)108 c.Assert(result, Equals, 0)
108 c.Assert(bufferString(ctx.Stdout), Equals, t.output)109 c.Assert(bufferString(ctx.Stdout), Equals, t.output)
@@ -110,7 +111,7 @@
110 }111 }
111 }112 }
112113
113 ctx := dummyContext(c)114 ctx := testing.Context(c)
114 result := cmd.Main(&OutputCommand{}, ctx, []string{"--format", "cuneiform"})115 result := cmd.Main(&OutputCommand{}, ctx, []string{"--format", "cuneiform"})
115 c.Assert(result, Equals, 2)116 c.Assert(result, Equals, 2)
116 c.Assert(bufferString(ctx.Stdout), Equals, "")117 c.Assert(bufferString(ctx.Stdout), Equals, "")
@@ -122,7 +123,7 @@
122// this argument format.123// this argument format.
123// LP #1059921124// LP #1059921
124func (s *CmdSuite) TestFormatAlternativeSyntax(c *C) {125func (s *CmdSuite) TestFormatAlternativeSyntax(c *C) {
125 ctx := dummyContext(c)126 ctx := testing.Context(c)
126 result := cmd.Main(&OutputCommand{}, ctx, []string{"--format=json"})127 result := cmd.Main(&OutputCommand{}, ctx, []string{"--format=json"})
127 c.Assert(result, Equals, 0)128 c.Assert(result, Equals, 0)
128 c.Assert(bufferString(ctx.Stdout), Equals, "null\n")129 c.Assert(bufferString(ctx.Stdout), Equals, "null\n")
129130
=== modified file 'cmd/supercommand_test.go'
--- cmd/supercommand_test.go 2013-02-28 08:11:29 +0000
+++ cmd/supercommand_test.go 2013-02-28 12:30:29 +0000
@@ -99,7 +99,7 @@
99 }()99 }()
100 jc := &cmd.SuperCommand{Name: "jujutest", Log: &cmd.Log{}}100 jc := &cmd.SuperCommand{Name: "jujutest", Log: &cmd.Log{}}
101 jc.Register(&TestCommand{Name: "blah"})101 jc.Register(&TestCommand{Name: "blah"})
102 ctx := dummyContext(c)102 ctx := testing.Context(c)
103 code := cmd.Main(jc, ctx, []string{"blah", "--option", "error", "--debug"})103 code := cmd.Main(jc, ctx, []string{"blah", "--option", "error", "--debug"})
104 c.Assert(code, Equals, 1)104 c.Assert(code, Equals, 1)
105 c.Assert(bufferString(ctx.Stderr), Matches, `.* JUJU jujutest blah command failed: BAM!105 c.Assert(bufferString(ctx.Stderr), Matches, `.* JUJU jujutest blah command failed: BAM!
106106
=== modified file 'cmd/util_test.go'
--- cmd/util_test.go 2013-02-28 08:11:29 +0000
+++ cmd/util_test.go 2013-02-28 12:30:29 +0000
@@ -6,14 +6,9 @@
6 "fmt"6 "fmt"
7 "io"7 "io"
8 "launchpad.net/gnuflag"8 "launchpad.net/gnuflag"
9 . "launchpad.net/gocheck"
10 "launchpad.net/juju-core/cmd"9 "launchpad.net/juju-core/cmd"
11)10)
1211
13func dummyContext(c *C) *cmd.Context {
14 return &cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}}
15}
16
17func bufferString(stream io.Writer) string {12func bufferString(stream io.Writer) string {
18 return stream.(*bytes.Buffer).String()13 return stream.(*bytes.Buffer).String()
19}14}
2015
=== modified file 'environs/agent/agent.go'
--- environs/agent/agent.go 2013-02-28 08:11:29 +0000
+++ environs/agent/agent.go 2013-02-28 12:30:29 +0000
@@ -205,7 +205,7 @@
205 if err == nil {205 if err == nil {
206 return st, "", nil206 return st, "", nil
207 }207 }
208 if err != state.ErrUnauthorized {208 if !state.IsUnauthorizedError(err) {
209 return nil, "", err209 return nil, "", err
210 }210 }
211 // Access isn't authorized even though we have a password211 // Access isn't authorized even though we have a password
212212
=== modified file 'juju/api.go'
--- juju/api.go 2013-02-28 08:11:29 +0000
+++ juju/api.go 2013-02-28 12:30:29 +0000
@@ -29,7 +29,7 @@
29 info.Password = password29 info.Password = password
3030
31 st, err := api.Open(info)31 st, err := api.Open(info)
32 // TODO(rog): handle ErrUnauthorized when the API handles passwords.32 // TODO(rog): handle errUnauthorized when the API handles passwords.
33 if err != nil {33 if err != nil {
34 return nil, err34 return nil, err
35 }35 }
3636
=== modified file 'juju/conn.go'
--- juju/conn.go 2013-02-28 08:11:29 +0000
+++ juju/conn.go 2013-02-28 12:30:29 +0000
@@ -43,7 +43,7 @@
43 }43 }
44 info.Password = password44 info.Password = password
45 st, err := state.Open(info)45 st, err := state.Open(info)
46 if err == state.ErrUnauthorized {46 if state.IsUnauthorizedError(err) {
47 // We can't connect with the administrator password,;47 // We can't connect with the administrator password,;
48 // perhaps this was the first connection and the48 // perhaps this was the first connection and the
49 // password has not been changed yet.49 // password has not been changed yet.
@@ -54,7 +54,7 @@
54 // initialized and the initial password set.54 // initialized and the initial password set.
55 for a := redialStrategy.Start(); a.Next(); {55 for a := redialStrategy.Start(); a.Next(); {
56 st, err = state.Open(info)56 st, err = state.Open(info)
57 if err != state.ErrUnauthorized {57 if !state.IsUnauthorizedError(err) {
58 break58 break
59 }59 }
60 }60 }
6161
=== modified file 'state/api/api_test.go'
--- state/api/api_test.go 2013-02-28 08:11:29 +0000
+++ state/api/api_test.go 2013-02-28 12:30:29 +0000
@@ -679,7 +679,7 @@
679 c.Assert(ok, Equals, true)679 c.Assert(ok, Equals, true)
680680
681 // Wait long enough for the Next request to be sent681 // Wait long enough for the Next request to be sent
682 // so it's blocking on the server side. 682 // so it's blocking on the server side.
683 time.Sleep(50 * time.Millisecond)683 time.Sleep(50 * time.Millisecond)
684 c.Logf("stopping server")684 c.Logf("stopping server")
685 err = srv.Stop()685 err = srv.Stop()
@@ -752,7 +752,7 @@
752 err: state.NotFoundf("hello"),752 err: state.NotFoundf("hello"),
753 code: api.CodeNotFound,753 code: api.CodeNotFound,
754}, {754}, {
755 err: state.ErrUnauthorized,755 err: state.Unauthorizedf("hello"),
756 code: api.CodeUnauthorized,756 code: api.CodeUnauthorized,
757}, {757}, {
758 err: state.ErrCannotEnterScopeYet,758 err: state.ErrCannotEnterScopeYet,
759759
=== modified file 'state/api/error.go'
--- state/api/error.go 2013-02-28 08:11:29 +0000
+++ state/api/error.go 2013-02-28 12:30:29 +0000
@@ -33,7 +33,6 @@
33)33)
3434
35var singletonErrorCodes = map[error]string{35var singletonErrorCodes = map[error]string{
36 state.ErrUnauthorized: CodeUnauthorized,
37 state.ErrCannotEnterScopeYet: CodeCannotEnterScopeYet,36 state.ErrCannotEnterScopeYet: CodeCannotEnterScopeYet,
38 state.ErrCannotEnterScope: CodeCannotEnterScope,37 state.ErrCannotEnterScope: CodeCannotEnterScope,
39 state.ErrExcessiveContention: CodeExcessiveContention,38 state.ErrExcessiveContention: CodeExcessiveContention,
@@ -62,6 +61,8 @@
62 code := singletonErrorCodes[err]61 code := singletonErrorCodes[err]
63 switch {62 switch {
64 case code != "":63 case code != "":
64 case state.IsUnauthorizedError(err):
65 code = CodeUnauthorized
65 case state.IsNotFound(err):66 case state.IsNotFound(err):
66 code = CodeNotFound67 code = CodeNotFound
67 case state.IsNotAssigned(err):68 case state.IsNotAssigned(err):
6869
=== modified file 'state/open.go'
--- state/open.go 2013-02-28 08:11:29 +0000
+++ state/open.go 2013-02-28 12:30:29 +0000
@@ -42,7 +42,7 @@
42// Open connects to the server described by the given42// Open connects to the server described by the given
43// info, waits for it to be initialized, and returns a new State43// info, waits for it to be initialized, and returns a new State
44// representing the environment connected to.44// representing the environment connected to.
45// It returns ErrUnauthorized if access is unauthorized.45// It returns unauthorizedError if access is unauthorized.
46func Open(info *Info) (*State, error) {46func Open(info *Info) (*State, error) {
47 log.Printf("state: opening state; mongo addresses: %q; entity %q", info.Addrs, info.EntityName)47 log.Printf("state: opening state; mongo addresses: %q; entity %q", info.Addrs, info.EntityName)
48 if len(info.Addrs) == 0 {48 if len(info.Addrs) == 0 {
@@ -89,7 +89,7 @@
8989
90// Initialize sets up an initial empty state and returns it.90// Initialize sets up an initial empty state and returns it.
91// This needs to be performed only once for a given environment.91// This needs to be performed only once for a given environment.
92// It returns ErrUnauthorized if access is unauthorized.92// It returns unauthorizedError if access is unauthorized.
93func Initialize(info *Info, cfg *config.Config) (rst *State, err error) {93func Initialize(info *Info, cfg *config.Config) (rst *State, err error) {
94 st, err := Open(info)94 st, err := Open(info)
95 if err != nil {95 if err != nil {
@@ -148,7 +148,30 @@
148 logSizeTests = 1000000148 logSizeTests = 1000000
149)149)
150150
151var ErrUnauthorized = errors.New("unauthorized access")151// unauthorizedError represents the error that an operation is unauthorized.
152// Use IsUnauthorized() to determine if the error was related to authorization failure.
153type unauthorizedError struct {
154 msg string
155 error
156}
157
158func IsUnauthorizedError(err error) bool {
159 _, ok := err.(*unauthorizedError)
160 return ok
161}
162
163func (e *unauthorizedError) Error() string {
164 if e.error != nil {
165 return fmt.Sprintf("%s: %v", e.msg, e.error.Error())
166 }
167 return e.msg
168}
169
170// Unauthorizedf returns an error for which IsUnauthorizedError returns true.
171// It is mainly used for testing.
172func Unauthorizedf(format string, args ...interface{}) error {
173 return &unauthorizedError{fmt.Sprintf(format, args...), nil}
174}
152175
153func maybeUnauthorized(err error, msg string) error {176func maybeUnauthorized(err error, msg string) error {
154 if err == nil {177 if err == nil {
@@ -157,10 +180,10 @@
157 // Unauthorized access errors have no error code,180 // Unauthorized access errors have no error code,
158 // just a simple error string.181 // just a simple error string.
159 if err.Error() == "auth fails" {182 if err.Error() == "auth fails" {
160 return ErrUnauthorized183 return &unauthorizedError{msg, err}
161 }184 }
162 if err, ok := err.(*mgo.QueryError); ok && err.Code == 10057 {185 if err, ok := err.(*mgo.QueryError); ok && err.Code == 10057 {
163 return ErrUnauthorized186 return &unauthorizedError{msg, err}
164 }187 }
165 return fmt.Errorf("%s: %v", msg, err)188 return fmt.Errorf("%s: %v", msg, err)
166}189}
167190
=== modified file 'state/state_test.go'
--- state/state_test.go 2013-02-28 08:11:29 +0000
+++ state/state_test.go 2013-02-28 12:30:29 +0000
@@ -1173,11 +1173,11 @@
1173 info := state.TestingStateInfo()1173 info := state.TestingStateInfo()
1174 info.EntityName, info.Password = "arble", "bar"1174 info.EntityName, info.Password = "arble", "bar"
1175 err := tryOpenState(info)1175 err := tryOpenState(info)
1176 c.Assert(err, Equals, state.ErrUnauthorized)1176 c.Assert(state.IsUnauthorizedError(err), Equals, true)
11771177
1178 info.EntityName, info.Password = "arble", ""1178 info.EntityName, info.Password = "arble", ""
1179 err = tryOpenState(info)1179 err = tryOpenState(info)
1180 c.Assert(err, Equals, state.ErrUnauthorized)1180 c.Assert(state.IsUnauthorizedError(err), Equals, true)
11811181
1182 info.EntityName, info.Password = "", ""1182 info.EntityName, info.Password = "", ""
1183 err = tryOpenState(info)1183 err = tryOpenState(info)
@@ -1253,7 +1253,7 @@
1253 info.EntityName = ent.EntityName()1253 info.EntityName = ent.EntityName()
1254 info.Password = "bar"1254 info.Password = "bar"
1255 err = tryOpenState(info)1255 err = tryOpenState(info)
1256 c.Assert(err, Equals, state.ErrUnauthorized)1256 c.Assert(state.IsUnauthorizedError(err), Equals, true)
12571257
1258 // Check that we can log in with the correct password.1258 // Check that we can log in with the correct password.
1259 info.Password = "foo"1259 info.Password = "foo"
@@ -1271,7 +1271,7 @@
1271 // Check that we cannot log in with the old password.1271 // Check that we cannot log in with the old password.
1272 info.Password = "foo"1272 info.Password = "foo"
1273 err = tryOpenState(info)1273 err = tryOpenState(info)
1274 c.Assert(err, Equals, state.ErrUnauthorized)1274 c.Assert(state.IsUnauthorizedError(err), Equals, true)
12751275
1276 // Check that we can log in with the correct password.1276 // Check that we can log in with the correct password.
1277 info.Password = "bar"1277 info.Password = "bar"
@@ -1299,7 +1299,7 @@
1299 defer s.State.SetAdminMongoPassword("")1299 defer s.State.SetAdminMongoPassword("")
1300 info := state.TestingStateInfo()1300 info := state.TestingStateInfo()
1301 err = tryOpenState(info)1301 err = tryOpenState(info)
1302 c.Assert(err, Equals, state.ErrUnauthorized)1302 c.Assert(state.IsUnauthorizedError(err), Equals, true)
13031303
1304 info.Password = "foo"1304 info.Password = "foo"
1305 err = tryOpenState(info)1305 err = tryOpenState(info)
13061306
=== modified file 'state/unit_test.go'
--- state/unit_test.go 2013-02-28 08:11:29 +0000
+++ state/unit_test.go 2013-02-28 12:30:29 +0000
@@ -214,7 +214,7 @@
214 info.EntityName = m.EntityName()214 info.EntityName = m.EntityName()
215 info.Password = "foo1"215 info.Password = "foo1"
216 err = tryOpenState(info)216 err = tryOpenState(info)
217 c.Assert(err, Equals, state.ErrUnauthorized)217 c.Assert(state.IsUnauthorizedError(err), Equals, true)
218218
219 // Connect as the machine entity.219 // Connect as the machine entity.
220 info.EntityName = m.EntityName()220 info.EntityName = m.EntityName()
221221
=== modified file 'store/server.go'
--- store/server.go 2013-02-28 08:11:29 +0000
+++ store/server.go 2013-02-28 12:30:29 +0000
@@ -156,17 +156,22 @@
156 return156 return
157 }157 }
158 key := strings.Split(base, ":")158 key := strings.Split(base, ":")
159 r.ParseForm()
160 listing := r.Form.Get("list") == "1"
159 prefix := false161 prefix := false
160 if key[len(key)-1] == "*" {162 if key[len(key)-1] == "*" {
161 prefix = true163 prefix = true
162 key = key[:len(key)-1]164 key = key[:len(key)-1]
163 if len(key) == 0 {165 if len(key) == 0 && !listing {
164 // No point in counting something unknown.166 // No point in counting something unknown.
165 w.WriteHeader(http.StatusForbidden)167 w.WriteHeader(http.StatusForbidden)
166 return168 return
167 }169 }
168 }170 }
169 r.ParseForm()171 if listing && prefix {
172 s.serveStatsList(w, r, key)
173 return
174 }
170 sum, err := s.store.SumCounter(key, prefix)175 sum, err := s.store.SumCounter(key, prefix)
171 if err != nil {176 if err != nil {
172 log.Printf("store: cannot sum counter: %v", err)177 log.Printf("store: cannot sum counter: %v", err)
@@ -174,6 +179,10 @@
174 return179 return
175 }180 }
176 data := []byte(strconv.FormatInt(sum, 10))181 data := []byte(strconv.FormatInt(sum, 10))
182 if listing {
183 // Listing a single item.. silly, but whatever.
184 data = []byte(base + " " + string(data) + "\n")
185 }
177 w.Header().Set("Content-Type", "text/plain")186 w.Header().Set("Content-Type", "text/plain")
178 w.Header().Set("Content-Length", strconv.Itoa(len(data)))187 w.Header().Set("Content-Length", strconv.Itoa(len(data)))
179 _, err = w.Write(data)188 _, err = w.Write(data)
@@ -183,6 +192,62 @@
183 }192 }
184}193}
185194
195func (s *Server) serveStatsList(w http.ResponseWriter, r *http.Request, prefix []string) {
196 entries, err := s.store.ListCounters(prefix)
197 if err != nil {
198 log.Printf("store: cannot list counter: %v", err)
199 w.WriteHeader(http.StatusInternalServerError)
200 return
201 }
202
203 // First build keys and figure max key length.
204 var buf []byte
205 var maxKeyLength int
206 type resultItem struct {
207 key string
208 count int64
209 }
210 var result []resultItem
211 for i := range entries {
212 entry := &entries[i]
213 for j := range entry.Key {
214 buf = append(buf, entry.Key[j]...)
215 buf = append(buf, ':')
216 }
217 if entry.Prefix {
218 buf = append(buf, '*')
219 } else {
220 buf = buf[:len(buf)-1]
221 }
222 if maxKeyLength < len(buf) {
223 maxKeyLength = len(buf)
224 }
225 result = append(result, resultItem{string(buf), entry.Count})
226 buf = buf[:0]
227 }
228
229 // Then join all keys and counts in a single formatted buffer.
230 spaces := make([]byte, maxKeyLength+2)
231 for i := range spaces {
232 spaces[i] = ' '
233 }
234 for i := range result {
235 item := &result[i]
236 buf = append(buf, item.key...)
237 buf = append(buf, spaces[len(item.key):]...)
238 buf = strconv.AppendInt(buf, item.count, 10)
239 buf = append(buf, '\n')
240 }
241
242 w.Header().Set("Content-Type", "text/plain")
243 w.Header().Set("Content-Length", strconv.Itoa(len(buf)))
244 _, err = w.Write(buf)
245 if err != nil {
246 log.Printf("store: cannot write content: %v", err)
247 w.WriteHeader(http.StatusInternalServerError)
248 }
249}
250
186func (s *Server) serveBlitzKey(w http.ResponseWriter, r *http.Request) {251func (s *Server) serveBlitzKey(w http.ResponseWriter, r *http.Request) {
187 w.Header().Set("Connection", "close")252 w.Header().Set("Connection", "close")
188 w.Header().Set("Content-Type", "text/plain")253 w.Header().Set("Content-Type", "text/plain")
189254
=== modified file 'store/server_test.go'
--- store/server_test.go 2013-02-28 08:11:29 +0000
+++ store/server_test.go 2013-02-28 12:30:29 +0000
@@ -163,7 +163,7 @@
163}163}
164164
165func (s *StoreSuite) TestStatsCounter(c *C) {165func (s *StoreSuite) TestStatsCounter(c *C) {
166 for _, key := range [][]string{{"a", "b"}, {"a", "b"}, {"a"}} {166 for _, key := range [][]string{{"a", "b"}, {"a", "b"}, {"a", "c"}, {"a"}} {
167 err := s.store.IncCounter(key)167 err := s.store.IncCounter(key)
168 c.Assert(err, IsNil)168 c.Assert(err, IsNil)
169 }169 }
@@ -171,9 +171,11 @@
171 server, _ := s.prepareServer(c)171 server, _ := s.prepareServer(c)
172172
173 expected := map[string]string{173 expected := map[string]string{
174 "a:b": "2",174 "a:b": "2",
175 "a:*": "3",175 "a:b:*": "0",
176 "a": "1",176 "a:*": "3",
177 "a": "1",
178 "a:b:c": "0",
177 }179 }
178180
179 for counter, n := range expected {181 for counter, n := range expected {
@@ -190,6 +192,47 @@
190 }192 }
191}193}
192194
195func (s *StoreSuite) TestStatsCounterList(c *C) {
196 incs := [][]string{
197 {"a"},
198 {"a", "b"},
199 {"a", "b", "c"},
200 {"a", "b", "c"},
201 {"a", "b", "d"},
202 {"a", "b", "e"},
203 {"a", "f", "g"},
204 {"a", "f", "h"},
205 {"a", "i"},
206 {"j", "k"},
207 }
208 for _, key := range incs {
209 err := s.store.IncCounter(key)
210 c.Assert(err, IsNil)
211 }
212
213 server, _ := s.prepareServer(c)
214
215 tests := [][]string{
216 {"a", "a 1\n"},
217 {"a:*", "a:b:* 4\na:f:* 2\na:b 1\na:i 1\n"},
218 {"a:b:*", "a:b:c 2\na:b:d 1\na:b:e 1\n"},
219 }
220
221 for i := range tests {
222 req, err := http.NewRequest("GET", "/stats/counter/"+tests[i][0], nil)
223 c.Assert(err, IsNil)
224 req.Form = url.Values{"list": []string{"1"}}
225 rec := httptest.NewRecorder()
226 server.ServeHTTP(rec, req)
227
228 data, err := ioutil.ReadAll(rec.Body)
229 c.Assert(string(data), Equals, tests[i][1])
230
231 c.Assert(rec.Header().Get("Content-Type"), Equals, "text/plain")
232 c.Assert(rec.Header().Get("Content-Length"), Equals, strconv.Itoa(len(tests[i][1])))
233 }
234}
235
193func (s *StoreSuite) TestBlitzKey(c *C) {236func (s *StoreSuite) TestBlitzKey(c *C) {
194 server, _ := s.prepareServer(c)237 server, _ := s.prepareServer(c)
195238
196239
=== modified file 'store/store.go'
--- store/store.go 2013-02-28 08:11:29 +0000
+++ store/store.go 2013-02-28 12:30:29 +0000
@@ -16,6 +16,7 @@
16 "launchpad.net/juju-core/log"16 "launchpad.net/juju-core/log"
17 "sort"17 "sort"
18 "strconv"18 "strconv"
19 "strings"
19 "sync"20 "sync"
20 "time"21 "time"
21)22)
@@ -45,8 +46,10 @@
4546
46 // Cache for statistics key words (two generations).47 // Cache for statistics key words (two generations).
47 cacheMu sync.RWMutex48 cacheMu sync.RWMutex
48 statsTokenNew map[string]int49 statsIdNew map[string]int
49 statsTokenOld map[string]int50 statsIdOld map[string]int
51 statsTokenNew map[int]string
52 statsTokenOld map[int]string
50}53}
5154
52// Open creates a new session with the store. It connects to the MongoDB55// Open creates a new session with the store. It connects to the MongoDB
@@ -130,10 +133,7 @@
130 err = nil133 err = nil
131 id, found := s.statsTokenId(key[i])134 id, found := s.statsTokenId(key[i])
132 if !found {135 if !found {
133 var t struct {136 var t tokenId
134 Id int "_id"
135 Token string "t"
136 }
137 err = tokens.Find(bson.D{{"t", key[i]}}).One(&t)137 err = tokens.Find(bson.D{{"t", key[i]}}).One(&t)
138 if err == mgo.ErrNotFound {138 if err == mgo.ErrNotFound {
139 if !write {139 if !write {
@@ -163,7 +163,12 @@
163 return string(skey), nil163 return string(skey), nil
164}164}
165165
166const statsTokenCacheSize = 512166const statsTokenCacheSize = 1024
167
168type tokenId struct {
169 Id int "_id"
170 Token string "t"
171}
167172
168// cacheStatsTokenId adds the id for token into the cache.173// cacheStatsTokenId adds the id for token into the cache.
169// The cache has two generations so that the least frequently used174// The cache has two generations so that the least frequently used
@@ -172,25 +177,45 @@
172 s.cacheMu.Lock()177 s.cacheMu.Lock()
173 defer s.cacheMu.Unlock()178 defer s.cacheMu.Unlock()
174 // Can't possibly be >, but reviews want it for defensiveness.179 // Can't possibly be >, but reviews want it for defensiveness.
175 if len(s.statsTokenNew) >= statsTokenCacheSize {180 if len(s.statsIdNew) >= statsTokenCacheSize {
181 s.statsIdOld = s.statsIdNew
182 s.statsIdNew = nil
176 s.statsTokenOld = s.statsTokenNew183 s.statsTokenOld = s.statsTokenNew
177 s.statsTokenNew = nil184 s.statsTokenNew = nil
178 }185 }
179 if s.statsTokenNew == nil {186 if s.statsIdNew == nil {
180 s.statsTokenNew = make(map[string]int, statsTokenCacheSize)187 s.statsIdNew = make(map[string]int, statsTokenCacheSize)
188 s.statsTokenNew = make(map[int]string, statsTokenCacheSize)
181 }189 }
182 s.statsTokenNew[token] = id190 s.statsIdNew[token] = id
191 s.statsTokenNew[id] = token
183}192}
184193
185// statsTokenId returns the id for token from the cache, if found.194// statsTokenId returns the id for token from the cache, if found.
186func (s *Store) statsTokenId(token string) (id int, found bool) {195func (s *Store) statsTokenId(token string) (id int, found bool) {
187 s.cacheMu.RLock()196 s.cacheMu.RLock()
188 id, found = s.statsTokenNew[token]197 id, found = s.statsIdNew[token]
189 if found {198 if found {
190 s.cacheMu.RUnlock()199 s.cacheMu.RUnlock()
191 return200 return
192 }201 }
193 id, found = s.statsTokenOld[token]202 id, found = s.statsIdOld[token]
203 s.cacheMu.RUnlock()
204 if found {
205 s.cacheStatsTokenId(token, id)
206 }
207 return
208}
209
210// statsIdToken returns the token for id from the cache, if found.
211func (s *Store) statsIdToken(id int) (token string, found bool) {
212 s.cacheMu.RLock()
213 token, found = s.statsTokenNew[id]
214 if found {
215 s.cacheMu.RUnlock()
216 return
217 }
218 token, found = s.statsTokenOld[id]
194 s.cacheMu.RUnlock()219 s.cacheMu.RUnlock()
195 if found {220 if found {
196 s.cacheStatsTokenId(token, id)221 s.cacheStatsTokenId(token, id)
@@ -219,7 +244,8 @@
219}244}
220245
221// SumCounter returns the sum of all the counters that exactly match key,246// SumCounter returns the sum of all the counters that exactly match key,
222// or that are prefixed by it if prefix is true.247// or that are prefixed by it if prefix is true. In the latter case, a key
248// that matches the prefix exactly won't be included in the sum.
223func (s *Store) SumCounter(key []string, prefix bool) (count int64, err error) {249func (s *Store) SumCounter(key []string, prefix bool) (count int64, err error) {
224 session := s.session.Copy()250 session := s.session.Copy()
225 defer session.Close()251 defer session.Close()
@@ -234,7 +260,7 @@
234260
235 var regex string261 var regex string
236 if prefix {262 if prefix {
237 regex = "^" + skey263 regex = "^" + skey + ".+"
238 } else {264 } else {
239 regex = "^" + skey + "$"265 regex = "^" + skey + "$"
240 }266 }
@@ -252,6 +278,125 @@
252 return 0, err278 return 0, err
253}279}
254280
281type Counter struct {
282 Key []string
283 Count int64
284 Prefix bool
285}
286
287// ListCounters returns a list of all keys directly under the provided prefix,
288// and a prefix-aggregated view of deeper keys.
289//
290// For example, given the following counts:
291//
292// {"a", "b"}: 1,
293// {"a", "c"}: 3
294// {"a", "c", "d"}: 5
295// {"a", "c", "e"}: 7
296//
297// The following key prefixes will present the respective list results:
298//
299// {"a"} => {{"a", "b"}, 1, false}, {{"a", "c"}, 3, false}, {{"a", "c"}, 12, true}
300// {"a", "c"} => {{"a", "c", "d"}, 3, false}, {"a", "c", "e"}, 5, false}
301//
302func (s *Store) ListCounters(keyPrefix []string) ([]Counter, error) {
303 session := s.session.Copy()
304 defer session.Close()
305
306 tokensColl := session.StatTokens()
307 countersColl := session.StatCounters()
308
309 skey, err := s.statsKey(session, keyPrefix, false)
310 if err == ErrNotFound {
311 return nil, nil
312 }
313 if err != nil {
314 return nil, err
315 }
316 regex := "^" + skey + ".+"
317
318 // For a search key "a:b:" matching a key "a:b:c:d:e:", this map function emits "a:b:c:*".
319 // For a search key "a:b:" matching a key "a:b:c:", it emits "a:b:c:".
320 mapf := fmt.Sprintf(`
321 function() {
322 var k = this.k;
323 var i = k.indexOf(':', %d)+1;
324 if (k.length > i) { k = k.substr(0, i)+'*'; }
325 emit(k, this.c);
326 }`, len(skey))
327 reducef := "function(key, values) { return Array.sum(values); }"
328 job := mgo.MapReduce{Map: mapf, Reduce: reducef}
329
330 var result []struct {
331 Key string `bson:"_id"`
332 Value int64
333 }
334 _, err = countersColl.Find(bson.D{{"k", bson.D{{"$regex", regex}}}}).MapReduce(&job, &result)
335 if err != nil {
336 return nil, err
337 }
338 var counters []Counter
339 for i := range result {
340 ids := strings.Split(result[i].Key, ":")
341 tokens := make([]string, 0, len(ids))
342 for i := 0; i < len(ids)-1; i++ {
343 if ids[i] == "*" {
344 continue
345 }
346 id, err := strconv.ParseInt(ids[i], 32, 32)
347 if err != nil {
348 return nil, fmt.Errorf("store: invalid id: %q", ids[i])
349 }
350 token, found := s.statsIdToken(int(id))
351 if !found {
352 var t tokenId
353 err = tokensColl.FindId(id).One(&t)
354 if err == mgo.ErrNotFound {
355 return nil, fmt.Errorf("store: internal error; token id not found: %d", id)
356 }
357 s.cacheStatsTokenId(t.Token, t.Id)
358 token = t.Token
359 }
360 tokens = append(tokens, token)
361 }
362 counter := Counter{
363 Key: tokens,
364 Count: result[i].Value,
365 Prefix: len(ids) > 0 && ids[len(ids)-1] == "*",
366 }
367 counters = append(counters, counter)
368 }
369 sort.Sort(sortableCounters(counters))
370 return counters, nil
371}
372
373type sortableCounters []Counter
374
375func (s sortableCounters) Len() int { return len(s) }
376func (s sortableCounters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
377func (s sortableCounters) Less(i, j int) bool {
378 // Larger counts first.
379 if s[i].Count != s[j].Count {
380 return s[j].Count < s[i].Count
381 }
382 // Then smaller/shorter keys first.
383 ki := s[i].Key
384 kj := s[j].Key
385 for n := range ki {
386 if n >= len(kj) {
387 return false
388 }
389 if ki[n] != kj[n] {
390 return ki[n] < kj[n]
391 }
392 }
393 if len(ki) < len(kj) {
394 return true
395 }
396 // Then full keys first.
397 return !s[i].Prefix && s[j].Prefix
398}
399
255// A CharmPublisher is responsible for importing a charm dir onto the store.400// A CharmPublisher is responsible for importing a charm dir onto the store.
256type CharmPublisher struct {401type CharmPublisher struct {
257 revision int402 revision int
258403
=== modified file 'store/store_test.go'
--- store/store_test.go 2013-02-28 08:11:29 +0000
+++ store/store_test.go 2013-02-28 12:30:29 +0000
@@ -464,8 +464,8 @@
464 {[]string{"a", "b", "c"}, false, 10},464 {[]string{"a", "b", "c"}, false, 10},
465 {[]string{"a", "b"}, false, 7},465 {[]string{"a", "b"}, false, 7},
466 {[]string{"a", "z", "b"}, false, 3},466 {[]string{"a", "z", "b"}, false, 3},
467 {[]string{"a", "b", "c"}, true, 10},467 {[]string{"a", "b", "c"}, true, 0},
468 {[]string{"a", "b"}, true, 17},468 {[]string{"a", "b"}, true, 10},
469 {[]string{"a"}, true, 20},469 {[]string{"a"}, true, 20},
470 {[]string{"b"}, true, 0},470 {[]string{"b"}, true, 0},
471 }471 }
@@ -523,7 +523,7 @@
523 c.Assert(err, IsNil)523 c.Assert(err, IsNil)
524 c.Assert(sum, Equals, int64(0))524 c.Assert(sum, Equals, int64(0))
525525
526 const genSize = 512526 const genSize = 1024
527527
528 // All of these will be cached, as we have two generations528 // All of these will be cached, as we have two generations
529 // of genSize entries each.529 // of genSize entries each.
@@ -597,6 +597,63 @@
597 c.Assert(sum, Equals, int64(10))597 c.Assert(sum, Equals, int64(10))
598}598}
599599
600func (s *StoreSuite) TestCounterList(c *C) {
601 incs := [][]string{
602 {"c", "b", "a"}, // Assign internal id c < id b < id a, to make sorting slightly trickier.
603 {"a"},
604 {"a", "c"},
605 {"a", "b"},
606 {"a", "b", "c"},
607 {"a", "b", "c"},
608 {"a", "b", "e"},
609 {"a", "b", "d"},
610 {"a", "f", "g"},
611 {"a", "f", "h"},
612 {"a", "i"},
613 {"a", "i", "j"},
614 {"k", "l"},
615 }
616 for _, key := range incs {
617 err := s.store.IncCounter(key)
618 c.Assert(err, IsNil)
619 }
620
621 tests := []struct {
622 prefix []string
623 result []store.Counter
624 }{
625 {
626 []string{"a"},
627 []store.Counter{
628 {[]string{"a", "b"}, 4, true},
629 {[]string{"a", "f"}, 2, true},
630 {[]string{"a", "b"}, 1, false},
631 {[]string{"a", "c"}, 1, false},
632 {[]string{"a", "i"}, 1, false},
633 {[]string{"a", "i"}, 1, true},
634 },
635 }, {
636 []string{"a", "b"},
637 []store.Counter{
638 {[]string{"a", "b", "c"}, 2, false},
639 {[]string{"a", "b", "d"}, 1, false},
640 {[]string{"a", "b", "e"}, 1, false},
641 },
642 },
643 }
644
645 // Use a different store to exercise cache filling.
646 st, err := store.Open(s.Addr)
647 c.Assert(err, IsNil)
648 defer st.Close()
649
650 for i := range tests {
651 result, err := st.ListCounters(tests[i].prefix)
652 c.Assert(err, IsNil)
653 c.Assert(result, DeepEquals, tests[i].result)
654 }
655}
656
600func (s *TrivialSuite) TestEventString(c *C) {657func (s *TrivialSuite) TestEventString(c *C) {
601 c.Assert(store.EventPublished, Matches, "published")658 c.Assert(store.EventPublished, Matches, "published")
602 c.Assert(store.EventPublishError, Matches, "publish-error")659 c.Assert(store.EventPublishError, Matches, "publish-error")
603660
=== modified file 'testing/cmd.go'
--- testing/cmd.go 2013-02-28 08:11:29 +0000
+++ testing/cmd.go 2013-02-28 12:30:29 +0000
@@ -27,15 +27,38 @@
27 return c.Init(f.Args())27 return c.Init(f.Args())
28}28}
2929
30// Context creates a simple command execution context with the current
31// dir set to a newly created directory within the test directory.
32func Context(c *C) *cmd.Context {
33 return &cmd.Context{
34 Dir: c.MkDir(),
35 Stdin: &bytes.Buffer{},
36 Stdout: &bytes.Buffer{},
37 Stderr: &bytes.Buffer{},
38 }
39}
40
41// ContextForDir creates a simple command execution context with the current
42// dir set to the specified directory.
43func ContextForDir(c *C, dir string) *cmd.Context {
44 return &cmd.Context{
45 Dir: dir,
46 Stdin: &bytes.Buffer{},
47 Stdout: &bytes.Buffer{},
48 Stderr: &bytes.Buffer{},
49 }
50}
51
30// RunCommand will run a command with the specified args. The returned error52// RunCommand will run a command with the specified args. The returned error
31// may come from either the parsing of the args, the command initialisation or53// may come from either the parsing of the args, the command initialisation or
32// the actual running of the command. Access to the resulting output streams54// the actual running of the command. Access to the resulting output streams
33// is not provided with this function.55// is provided through the returned context instance.
34func RunCommand(c *C, com cmd.Command, args []string) error {56func RunCommand(c *C, com cmd.Command, args []string) (*cmd.Context, error) {
35 if err := InitCommand(com, args); err != nil {57 if err := InitCommand(com, args); err != nil {
36 return err58 return nil, err
37 }59 }
38 return com.Run(&cmd.Context{c.MkDir(), &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}})60 var context = Context(c)
61 return context, com.Run(context)
39}62}
4063
41// TestInit checks that a command initialises correctly with the given set of64// TestInit checks that a command initialises correctly with the given set of
4265
=== modified file 'worker/uniter/jujuc/config-get_test.go'
--- worker/uniter/jujuc/config-get_test.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/config-get_test.go 2013-02-28 12:30:29 +0000
@@ -41,7 +41,7 @@
41 hctx := s.GetHookContext(c, -1, "")41 hctx := s.GetHookContext(c, -1, "")
42 com, err := jujuc.NewCommand(hctx, "config-get")42 com, err := jujuc.NewCommand(hctx, "config-get")
43 c.Assert(err, IsNil)43 c.Assert(err, IsNil)
44 ctx := dummyContext(c)44 ctx := testing.Context(c)
45 code := cmd.Main(com, ctx, t.args)45 code := cmd.Main(com, ctx, t.args)
46 c.Assert(code, Equals, 0)46 c.Assert(code, Equals, 0)
47 c.Assert(bufferString(ctx.Stderr), Equals, "")47 c.Assert(bufferString(ctx.Stderr), Equals, "")
@@ -53,7 +53,7 @@
53 hctx := s.GetHookContext(c, -1, "")53 hctx := s.GetHookContext(c, -1, "")
54 com, err := jujuc.NewCommand(hctx, "config-get")54 com, err := jujuc.NewCommand(hctx, "config-get")
55 c.Assert(err, IsNil)55 c.Assert(err, IsNil)
56 ctx := dummyContext(c)56 ctx := testing.Context(c)
57 code := cmd.Main(com, ctx, []string{"--help"})57 code := cmd.Main(com, ctx, []string{"--help"})
58 c.Assert(code, Equals, 0)58 c.Assert(code, Equals, 0)
59 c.Assert(bufferString(ctx.Stdout), Equals, "")59 c.Assert(bufferString(ctx.Stdout), Equals, "")
@@ -74,7 +74,7 @@
74 hctx := s.GetHookContext(c, -1, "")74 hctx := s.GetHookContext(c, -1, "")
75 com, err := jujuc.NewCommand(hctx, "config-get")75 com, err := jujuc.NewCommand(hctx, "config-get")
76 c.Assert(err, IsNil)76 c.Assert(err, IsNil)
77 ctx := dummyContext(c)77 ctx := testing.Context(c)
78 code := cmd.Main(com, ctx, []string{"--output", "some-file", "monsters"})78 code := cmd.Main(com, ctx, []string{"--output", "some-file", "monsters"})
79 c.Assert(code, Equals, 0)79 c.Assert(code, Equals, 0)
80 c.Assert(bufferString(ctx.Stderr), Equals, "")80 c.Assert(bufferString(ctx.Stderr), Equals, "")
8181
=== modified file 'worker/uniter/jujuc/ports_test.go'
--- worker/uniter/jujuc/ports_test.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/ports_test.go 2013-02-28 12:30:29 +0000
@@ -29,7 +29,7 @@
29 for _, t := range portsTests {29 for _, t := range portsTests {
30 com, err := jujuc.NewCommand(hctx, t.cmd[0])30 com, err := jujuc.NewCommand(hctx, t.cmd[0])
31 c.Assert(err, IsNil)31 c.Assert(err, IsNil)
32 ctx := dummyContext(c)32 ctx := testing.Context(c)
33 code := cmd.Main(com, ctx, t.cmd[1:])33 code := cmd.Main(com, ctx, t.cmd[1:])
34 c.Assert(code, Equals, 0)34 c.Assert(code, Equals, 0)
35 c.Assert(bufferString(ctx.Stdout), Equals, "")35 c.Assert(bufferString(ctx.Stdout), Equals, "")
3636
=== modified file 'worker/uniter/jujuc/relation-get_test.go'
--- worker/uniter/jujuc/relation-get_test.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/relation-get_test.go 2013-02-28 12:30:29 +0000
@@ -5,6 +5,7 @@
5 "io/ioutil"5 "io/ioutil"
6 . "launchpad.net/gocheck"6 . "launchpad.net/gocheck"
7 "launchpad.net/juju-core/cmd"7 "launchpad.net/juju-core/cmd"
8 "launchpad.net/juju-core/testing"
8 "launchpad.net/juju-core/worker/uniter/jujuc"9 "launchpad.net/juju-core/worker/uniter/jujuc"
9 "path/filepath"10 "path/filepath"
10)11)
@@ -165,7 +166,7 @@
165 hctx := s.GetHookContext(c, t.relid, t.unit)166 hctx := s.GetHookContext(c, t.relid, t.unit)
166 com, err := jujuc.NewCommand(hctx, "relation-get")167 com, err := jujuc.NewCommand(hctx, "relation-get")
167 c.Assert(err, IsNil)168 c.Assert(err, IsNil)
168 ctx := dummyContext(c)169 ctx := testing.Context(c)
169 code := cmd.Main(com, ctx, t.args)170 code := cmd.Main(com, ctx, t.args)
170 c.Assert(code, Equals, t.code)171 c.Assert(code, Equals, t.code)
171 if code == 0 {172 if code == 0 {
@@ -230,7 +231,7 @@
230 hctx := s.GetHookContext(c, t.relid, t.unit)231 hctx := s.GetHookContext(c, t.relid, t.unit)
231 com, err := jujuc.NewCommand(hctx, "relation-get")232 com, err := jujuc.NewCommand(hctx, "relation-get")
232 c.Assert(err, IsNil)233 c.Assert(err, IsNil)
233 ctx := dummyContext(c)234 ctx := testing.Context(c)
234 code := cmd.Main(com, ctx, []string{"--help"})235 code := cmd.Main(com, ctx, []string{"--help"})
235 c.Assert(code, Equals, 0)236 c.Assert(code, Equals, 0)
236 c.Assert(bufferString(ctx.Stdout), Equals, "")237 c.Assert(bufferString(ctx.Stdout), Equals, "")
@@ -247,7 +248,7 @@
247 hctx := s.GetHookContext(c, 1, "m/0")248 hctx := s.GetHookContext(c, 1, "m/0")
248 com, err := jujuc.NewCommand(hctx, "relation-get")249 com, err := jujuc.NewCommand(hctx, "relation-get")
249 c.Assert(err, IsNil)250 c.Assert(err, IsNil)
250 ctx := dummyContext(c)251 ctx := testing.Context(c)
251 code := cmd.Main(com, ctx, []string{"--output", "some-file", "pew"})252 code := cmd.Main(com, ctx, []string{"--output", "some-file", "pew"})
252 c.Assert(code, Equals, 0)253 c.Assert(code, Equals, 0)
253 c.Assert(bufferString(ctx.Stderr), Equals, "")254 c.Assert(bufferString(ctx.Stderr), Equals, "")
254255
=== modified file 'worker/uniter/jujuc/relation-ids_test.go'
--- worker/uniter/jujuc/relation-ids_test.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/relation-ids_test.go 2013-02-28 12:30:29 +0000
@@ -4,6 +4,7 @@
4 "fmt"4 "fmt"
5 . "launchpad.net/gocheck"5 . "launchpad.net/gocheck"
6 "launchpad.net/juju-core/cmd"6 "launchpad.net/juju-core/cmd"
7 "launchpad.net/juju-core/testing"
7 "launchpad.net/juju-core/worker/uniter/jujuc"8 "launchpad.net/juju-core/worker/uniter/jujuc"
8)9)
910
@@ -101,7 +102,7 @@
101 hctx := s.GetHookContext(c, t.relid, "")102 hctx := s.GetHookContext(c, t.relid, "")
102 com, err := jujuc.NewCommand(hctx, "relation-ids")103 com, err := jujuc.NewCommand(hctx, "relation-ids")
103 c.Assert(err, IsNil)104 c.Assert(err, IsNil)
104 ctx := dummyContext(c)105 ctx := testing.Context(c)
105 code := cmd.Main(com, ctx, t.args)106 code := cmd.Main(com, ctx, t.args)
106 c.Assert(code, Equals, t.code)107 c.Assert(code, Equals, t.code)
107 if code == 0 {108 if code == 0 {
@@ -141,7 +142,7 @@
141 hctx := s.GetHookContext(c, relid, "")142 hctx := s.GetHookContext(c, relid, "")
142 com, err := jujuc.NewCommand(hctx, "relation-ids")143 com, err := jujuc.NewCommand(hctx, "relation-ids")
143 c.Assert(err, IsNil)144 c.Assert(err, IsNil)
144 ctx := dummyContext(c)145 ctx := testing.Context(c)
145 code := cmd.Main(com, ctx, []string{"--help"})146 code := cmd.Main(com, ctx, []string{"--help"})
146 c.Assert(code, Equals, 0)147 c.Assert(code, Equals, 0)
147 c.Assert(bufferString(ctx.Stdout), Equals, "")148 c.Assert(bufferString(ctx.Stdout), Equals, "")
148149
=== modified file 'worker/uniter/jujuc/relation-list_test.go'
--- worker/uniter/jujuc/relation-list_test.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/relation-list_test.go 2013-02-28 12:30:29 +0000
@@ -4,6 +4,7 @@
4 "fmt"4 "fmt"
5 . "launchpad.net/gocheck"5 . "launchpad.net/gocheck"
6 "launchpad.net/juju-core/cmd"6 "launchpad.net/juju-core/cmd"
7 "launchpad.net/juju-core/testing"
7 "launchpad.net/juju-core/worker/uniter/jujuc"8 "launchpad.net/juju-core/worker/uniter/jujuc"
8)9)
910
@@ -107,7 +108,7 @@
107 setMembers(hctx.rels[1], t.members1)108 setMembers(hctx.rels[1], t.members1)
108 com, err := jujuc.NewCommand(hctx, "relation-list")109 com, err := jujuc.NewCommand(hctx, "relation-list")
109 c.Assert(err, IsNil)110 c.Assert(err, IsNil)
110 ctx := dummyContext(c)111 ctx := testing.Context(c)
111 code := cmd.Main(com, ctx, t.args)112 code := cmd.Main(com, ctx, t.args)
112 c.Logf(bufferString(ctx.Stderr))113 c.Logf(bufferString(ctx.Stderr))
113 c.Assert(code, Equals, t.code)114 c.Assert(code, Equals, t.code)
@@ -148,7 +149,7 @@
148 hctx := s.GetHookContext(c, relid, "")149 hctx := s.GetHookContext(c, relid, "")
149 com, err := jujuc.NewCommand(hctx, "relation-list")150 com, err := jujuc.NewCommand(hctx, "relation-list")
150 c.Assert(err, IsNil)151 c.Assert(err, IsNil)
151 ctx := dummyContext(c)152 ctx := testing.Context(c)
152 code := cmd.Main(com, ctx, []string{"--help"})153 code := cmd.Main(com, ctx, []string{"--help"})
153 c.Assert(code, Equals, 0)154 c.Assert(code, Equals, 0)
154 c.Assert(bufferString(ctx.Stdout), Equals, "")155 c.Assert(bufferString(ctx.Stdout), Equals, "")
155156
=== modified file 'worker/uniter/jujuc/relation-set_test.go'
--- worker/uniter/jujuc/relation-set_test.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/relation-set_test.go 2013-02-28 12:30:29 +0000
@@ -25,7 +25,7 @@
25 hctx := s.GetHookContext(c, t.relid, "")25 hctx := s.GetHookContext(c, t.relid, "")
26 com, err := jujuc.NewCommand(hctx, "relation-set")26 com, err := jujuc.NewCommand(hctx, "relation-set")
27 c.Assert(err, IsNil)27 c.Assert(err, IsNil)
28 ctx := dummyContext(c)28 ctx := testing.Context(c)
29 code := cmd.Main(com, ctx, []string{"--help"})29 code := cmd.Main(com, ctx, []string{"--help"})
30 c.Assert(code, Equals, 0)30 c.Assert(code, Equals, 0)
31 c.Assert(bufferString(ctx.Stdout), Equals, "")31 c.Assert(bufferString(ctx.Stdout), Equals, "")
@@ -198,7 +198,7 @@
198 rset := com.(*jujuc.RelationSetCommand)198 rset := com.(*jujuc.RelationSetCommand)
199 rset.RelationId = 1199 rset.RelationId = 1
200 rset.Settings = t.change200 rset.Settings = t.change
201 ctx := dummyContext(c)201 ctx := testing.Context(c)
202 err = com.Run(ctx)202 err = com.Run(ctx)
203 c.Assert(err, IsNil)203 c.Assert(err, IsNil)
204204
205205
=== modified file 'worker/uniter/jujuc/server.go'
--- worker/uniter/jujuc/server.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/server.go 2013-02-28 12:30:29 +0000
@@ -91,7 +91,12 @@
91 return badReqErrorf("%s", err)91 return badReqErrorf("%s", err)
92 }92 }
93 var stdin, stdout, stderr bytes.Buffer93 var stdin, stdout, stderr bytes.Buffer
94 ctx := &cmd.Context{req.Dir, &stdin, &stdout, &stderr}94 ctx := &cmd.Context{
95 Dir: req.Dir,
96 Stdin: &stdin,
97 Stdout: &stdout,
98 Stderr: &stderr,
99 }
95 j.mu.Lock()100 j.mu.Lock()
96 defer j.mu.Unlock()101 defer j.mu.Unlock()
97 log.Printf("worker/uniter/jujuc: running hook %q %q", req.CommandName, req.Args)102 log.Printf("worker/uniter/jujuc: running hook %q %q", req.CommandName, req.Args)
98103
=== modified file 'worker/uniter/jujuc/unit-get_test.go'
--- worker/uniter/jujuc/unit-get_test.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/unit-get_test.go 2013-02-28 12:30:29 +0000
@@ -37,7 +37,7 @@
37func (s *UnitGetSuite) TestOutputFormat(c *C) {37func (s *UnitGetSuite) TestOutputFormat(c *C) {
38 for _, t := range unitGetTests {38 for _, t := range unitGetTests {
39 com := s.createCommand(c)39 com := s.createCommand(c)
40 ctx := dummyContext(c)40 ctx := testing.Context(c)
41 code := cmd.Main(com, ctx, t.args)41 code := cmd.Main(com, ctx, t.args)
42 c.Assert(code, Equals, 0)42 c.Assert(code, Equals, 0)
43 c.Assert(bufferString(ctx.Stderr), Equals, "")43 c.Assert(bufferString(ctx.Stderr), Equals, "")
@@ -47,7 +47,7 @@
4747
48func (s *UnitGetSuite) TestHelp(c *C) {48func (s *UnitGetSuite) TestHelp(c *C) {
49 com := s.createCommand(c)49 com := s.createCommand(c)
50 ctx := dummyContext(c)50 ctx := testing.Context(c)
51 code := cmd.Main(com, ctx, []string{"--help"})51 code := cmd.Main(com, ctx, []string{"--help"})
52 c.Assert(code, Equals, 0)52 c.Assert(code, Equals, 0)
53 c.Assert(bufferString(ctx.Stdout), Equals, "")53 c.Assert(bufferString(ctx.Stdout), Equals, "")
@@ -64,7 +64,7 @@
6464
65func (s *UnitGetSuite) TestOutputPath(c *C) {65func (s *UnitGetSuite) TestOutputPath(c *C) {
66 com := s.createCommand(c)66 com := s.createCommand(c)
67 ctx := dummyContext(c)67 ctx := testing.Context(c)
68 code := cmd.Main(com, ctx, []string{"--output", "some-file", "private-address"})68 code := cmd.Main(com, ctx, []string{"--output", "some-file", "private-address"})
69 c.Assert(code, Equals, 0)69 c.Assert(code, Equals, 0)
70 c.Assert(bufferString(ctx.Stderr), Equals, "")70 c.Assert(bufferString(ctx.Stderr), Equals, "")
7171
=== modified file 'worker/uniter/jujuc/util_test.go'
--- worker/uniter/jujuc/util_test.go 2013-02-28 08:11:29 +0000
+++ worker/uniter/jujuc/util_test.go 2013-02-28 12:30:29 +0000
@@ -5,7 +5,6 @@
5 "fmt"5 "fmt"
6 "io"6 "io"
7 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
8 "launchpad.net/juju-core/cmd"
9 "launchpad.net/juju-core/state"8 "launchpad.net/juju-core/state"
10 "launchpad.net/juju-core/worker/uniter/jujuc"9 "launchpad.net/juju-core/worker/uniter/jujuc"
11 "sort"10 "sort"
@@ -14,10 +13,6 @@
1413
15func TestPackage(t *testing.T) { TestingT(t) }14func TestPackage(t *testing.T) { TestingT(t) }
1615
17func dummyContext(c *C) *cmd.Context {
18 return &cmd.Context{c.MkDir(), nil, &bytes.Buffer{}, &bytes.Buffer{}}
19}
20
21func bufferString(w io.Writer) string {16func bufferString(w io.Writer) string {
22 return w.(*bytes.Buffer).String()17 return w.(*bytes.Buffer).String()
23}18}

Subscribers

People subscribed via source and target branches