Merge lp:~fwereade/juju-core/errors-cleanup into lp:~juju/juju-core/trunk

Proposed by William Reade
Status: Rejected
Rejected by: William Reade
Proposed branch: lp:~fwereade/juju-core/errors-cleanup
Merge into: lp:~juju/juju-core/trunk
Diff against target: 821 lines (+214/-133)
22 files modified
charm/repo.go (+8/-15)
charm/repo_test.go (+25/-16)
cmd/juju/deploy_test.go (+1/-1)
cmd/juju/publish.go (+8/-6)
cmd/juju/upgradecharm_test.go (+7/-6)
cmd/jujud/agent_test.go (+11/-10)
cmd/jujud/bootstrap_test.go (+6/-6)
environs/dummy/storage.go (+1/-1)
environs/ec2/storage.go (+1/-1)
environs/imagemetadata/simplestreams.go (+5/-5)
environs/local/storage.go (+1/-1)
environs/maas/storage.go (+2/-2)
environs/openstack/storage.go (+1/-1)
environs/tools.go (+1/-1)
environs/tools_test.go (+4/-4)
errors/errors.go (+42/-40)
errors/errors_test.go (+74/-0)
state/apiserver/client_test.go (+1/-1)
state/apiserver/errors_test.go (+2/-2)
state/open.go (+8/-4)
state/state_test.go (+0/-7)
testing/charm.go (+5/-3)
To merge this branch: bzr merge lp:~fwereade/juju-core/errors-cleanup
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Review via email: mp+168928@code.launchpad.net

Description of the change

errors: tests, consistency

We weren't testing or making sensible use of the embedded errors in
NotFoundError and UnauthorizedError; we were doing inappropriate things
with both error types in various situations; the action of NotFoundf was
not consistent with Unauthorizedf.

These conditions no longer apply; and the various charm.Repository types in
play now produce errors.NotFoundError instead of charm.NotFoundError.

I'm also more than somewhat freaked out by the "auth fails" magic string.
Can anyone explain that?

https://codereview.appspot.com/9830049/

To post a comment you must log in.
Revision history for this message
William Reade (fwereade) wrote :

Reviewers: mp+168928_code.launchpad.net,

Message:
Please take a look.

Description:
errors: tests, consistency

We weren't testing or making sensible use of the embedded errors in
NotFoundError and UnauthorizedError; we were doing inappropriate things
with both error types in various situations; the action of NotFoundf was
not consistent with Unauthorizedf.

These conditions no longer apply; and the various charm.Repository types
in
play now produce errors.NotFoundError instead of charm.NotFoundError.

I'm also more than somewhat freaked out by the "auth fails" magic
string.
Can anyone explain that?

https://code.launchpad.net/~fwereade/juju-core/errors-cleanup/+merge/168928

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/9830049/

Affected files:
   A [revision details]
   M charm/repo.go
   M charm/repo_test.go
   M cmd/juju/deploy_test.go
   M cmd/juju/publish.go
   M cmd/juju/upgradecharm_test.go
   M cmd/jujud/agent_test.go
   M cmd/jujud/bootstrap_test.go
   M environs/dummy/storage.go
   M environs/ec2/storage.go
   M environs/imagemetadata/simplestreams.go
   M environs/local/storage.go
   M environs/maas/storage.go
   M environs/openstack/storage.go
   M environs/tools.go
   M environs/tools_test.go
   M errors/errors.go
   A errors/errors_test.go
   M state/apiserver/client_test.go
   M state/apiserver/errors_test.go
   M state/open.go
   M state/state_test.go
   M testing/charm.go

Revision history for this message
Roger Peppe (rogpeppe) wrote :

LGTM with some suggestions. i'd like to lose the stuttering and this
seems like a reasonable CL to do it in.

https://codereview.appspot.com/9830049/diff/1/charm/repo.go
File charm/repo.go (right):

https://codereview.appspot.com/9830049/diff/1/charm/repo.go#newcode288
charm/repo.go:288: return errors.RawNotFoundf("charm %q not found in
repository %q", curl, repoPath)
NotFoundf("charm %q in repository %q", curl, repoPath) ?

https://codereview.appspot.com/9830049/diff/1/environs/openstack/storage.go
File environs/openstack/storage.go (right):

https://codereview.appspot.com/9830049/diff/1/environs/openstack/storage.go#newcode11
environs/openstack/storage.go:11: coreerrors
"launchpad.net/juju-core/errors"
looks like this can lose the import alias.

https://codereview.appspot.com/9830049/diff/1/environs/tools_test.go
File environs/tools_test.go (right):

https://codereview.appspot.com/9830049/diff/1/environs/tools_test.go#newcode171
environs/tools_test.go:171: c.Check(err, DeepEquals,
&errors.NotFoundError{test.err.Error()})
in other tests we do check IsNotFound and the error message rather than
using DeepEquals. would that be better here too?
alternatively we could change those other tests to use this idiom,
which seems fine too.

https://codereview.appspot.com/9830049/diff/1/errors/errors.go
File errors/errors.go (right):

https://codereview.appspot.com/9830049/diff/1/errors/errors.go#newcode11
errors/errors.go:11: type NotFoundError struct {
s/NotFoundError/NotFound/ ?
(as discussed)

and ditto for Unauthorized and the Is* functions.

https://codereview.appspot.com/9830049/diff/1/state/apiserver/errors_test.go
File state/apiserver/errors_test.go (right):

https://codereview.appspot.com/9830049/diff/1/state/apiserver/errors_test.go#newcode26
state/apiserver/errors_test.go:26: err: errors.RawNotFoundf("hello"),
no real need to use Raw here, is there?

https://codereview.appspot.com/9830049/diff/1/state/open.go
File state/open.go (right):

https://codereview.appspot.com/9830049/diff/1/state/open.go#newcode188
state/open.go:188: // error value produced my mongo, or mgo, or
something? And what about
s/my mongo/by mongo/

yes, i seem to remember that in some cases, mongo
does not produce an error code when access is unauthorised.
i believe gustavo filed an issue for that, but
i don't recall where or when.

about the "need to login" error, i don't *think*
we need to check that here, as it should happen only
when setting passwords AFAICS (that error is also checked in
SetAdminMongoPassword BTW), but it's also a similar issue
re: lack of mongo error code.

https://codereview.appspot.com/9830049/diff/1/testing/charm.go
File testing/charm.go (right):

https://codereview.appspot.com/9830049/diff/1/testing/charm.go#newcode174
testing/charm.go:174: return nil, errors.RawNotFoundf("charm %q not
found in mock store", charmURL)
NotFoundf("charm %q in mock store", charmURL)
(and below)?

https://codereview.appspot.com/9830049/

Revision history for this message
Tim Penhey (thumper) wrote :

https://codereview.appspot.com/9830049/diff/1/charm/repo.go
File charm/repo.go (right):

https://codereview.appspot.com/9830049/diff/1/charm/repo.go#newcode288
charm/repo.go:288: return errors.RawNotFoundf("charm %q not found in
repository %q", curl, repoPath)
On 2013/06/12 13:51:05, rog wrote:
> NotFoundf("charm %q in repository %q", curl, repoPath) ?

What is the difference between NotFoundf and RawNotFoundf?

https://codereview.appspot.com/9830049/diff/1/charm/repo_test.go
File charm/repo_test.go (right):

https://codereview.appspot.com/9830049/diff/1/charm/repo_test.go#newcode188
charm/repo_test.go:188: c.Assert(errors.IsNotFoundError(err), Equals,
true)
Nice. Although how about a matcher?

   c.Assert(err, IsNotFoundError)
or
   c.Assert(err, errors.IsNotFound)

https://codereview.appspot.com/9830049/diff/1/environs/imagemetadata/simplestreams.go
File environs/imagemetadata/simplestreams.go (right):

https://codereview.appspot.com/9830049/diff/1/environs/imagemetadata/simplestreams.go#newcode248
environs/imagemetadata/simplestreams.go:248: return nil, dataURL,
errors.RawNotFoundf("invalid URL %q", dataURL)
Is there a good reason why we have two functions? RawNotFoundf and
NotFoundf? Why have two same but different functions/types?

https://codereview.appspot.com/9830049/diff/1/errors/errors.go
File errors/errors.go (right):

https://codereview.appspot.com/9830049/diff/1/errors/errors.go#newcode11
errors/errors.go:11: type NotFoundError struct {
On 2013/06/12 13:51:05, rog wrote:
> s/NotFoundError/NotFound/ ?
> (as discussed)

> and ditto for Unauthorized and the Is* functions.

+1 as almost always namespaced in the caller code with the package.
   errors.IsNotFound
seems nicer to me than
   errors.IsNotFoundError

Hopefully the package name makes it obvious.

(Message brought to you by the department of redundancy department)

https://codereview.appspot.com/9830049/diff/1/errors/errors.go#newcode35
errors/errors.go:35: // "foo bar".
The name of the method and be behaviour seem to be at odds to me.

https://codereview.appspot.com/9830049/

Revision history for this message
Tim Penhey (thumper) wrote :

On 2013/06/18 23:33:17, thumper wrote:
> https://codereview.appspot.com/9830049/diff/1/charm/repo.go
> File charm/repo.go (right):

> https://codereview.appspot.com/9830049/diff/1/charm/repo.go#newcode288
> charm/repo.go:288: return errors.RawNotFoundf("charm %q not found in
repository
> %q", curl, repoPath)
> On 2013/06/12 13:51:05, rog wrote:
> > NotFoundf("charm %q in repository %q", curl, repoPath) ?

> What is the difference between NotFoundf and RawNotFoundf?

> https://codereview.appspot.com/9830049/diff/1/charm/repo_test.go
> File charm/repo_test.go (right):

https://codereview.appspot.com/9830049/diff/1/charm/repo_test.go#newcode188
> charm/repo_test.go:188: c.Assert(errors.IsNotFoundError(err), Equals,
true)
> Nice. Although how about a matcher?

> c.Assert(err, IsNotFoundError)
> or
> c.Assert(err, errors.IsNotFound)

https://codereview.appspot.com/9830049/diff/1/environs/imagemetadata/simplestreams.go
> File environs/imagemetadata/simplestreams.go (right):

https://codereview.appspot.com/9830049/diff/1/environs/imagemetadata/simplestreams.go#newcode248
> environs/imagemetadata/simplestreams.go:248: return nil, dataURL,
> errors.RawNotFoundf("invalid URL %q", dataURL)
> Is there a good reason why we have two functions? RawNotFoundf and
NotFoundf?
> Why have two same but different functions/types?

> https://codereview.appspot.com/9830049/diff/1/errors/errors.go
> File errors/errors.go (right):

https://codereview.appspot.com/9830049/diff/1/errors/errors.go#newcode11
> errors/errors.go:11: type NotFoundError struct {
> On 2013/06/12 13:51:05, rog wrote:
> > s/NotFoundError/NotFound/ ?
> > (as discussed)
> >
> > and ditto for Unauthorized and the Is* functions.

> +1 as almost always namespaced in the caller code with the package.
> errors.IsNotFound
> seems nicer to me than
> errors.IsNotFoundError

> Hopefully the package name makes it obvious.

> (Message brought to you by the department of redundancy department)

https://codereview.appspot.com/9830049/diff/1/errors/errors.go#newcode35
> errors/errors.go:35: // "foo bar".
> The name of the method and be behaviour seem to be at odds to me.

LGTM - it is better than what was there before, lets not depend on
perfection

https://codereview.appspot.com/9830049/

Revision history for this message
Tim Penhey (thumper) :
review: Approve
Revision history for this message
John A Meinel (jameinel) wrote :

Note this is still targeted at the old trunk.

Unmerged revisions

1268. By William Reade

mock charm store now uses errors.NotFoundError

1267. By William Reade

merge parent

1266. By William Reade

make errors somewhat consistent

1265. By William Reade

merge parent

1264. By William Reade

trivial error message fix (but notice how little it's tested for...)

1263. By William Reade

rewrite charm.Config for clarity, adding currently-unused ParseSettingsYAML method and new Settings type

1262. By Ian Booth

Move assignment policy to global env config

Previoysly, each provider defined it's own AssignmentPolicy,
which was hard coded to AssignNew. Now, it's been made an
env setting with default AssignNew. With containers, it will be
possible to add a unit to an existing machine (if not dirty) so
this work is a step in that direction.

R=jameinel, fwereade
CC=
https://codereview.appspot.com/9824043

1261. By Ian Booth

Add dirty flag to machine state

When choosing an unused machine to assign a unit to, a check was being made
to see if there were any principal units for the machine. If machines had units
assigned and then unassigned, the machine would appear clean since number of
principal unit goes to 0 but the machine should still be considered dirty.

The machine state has a "clean" flag (boolean). Machines are created with the
clean flag set to true. It is set false when a machine has a unit assigned,
and not reset when units are unassigned. The assign to unused machine logic
is updated to look at the clean flag.

R=fwereade, thumper
CC=
https://codereview.appspot.com/9820043

1260. By Tim Penhey

First part of the provisioner refactoring.

This branch breaks up the current provisioner and defines some interfaces that
we'll be using for containers.

The broker interface is what we have starting, stopping instances, and listing
instances and related machines.

An environment broker is written that defers the actual calls to the environ.

The provisioner now creates a provisioning task for the environment provider
using a machine watcher and the environment broker. The common provisioning
methods are now in provisioner_task.go.

I refactored some of the methods as we were duplicating a lot of calls, like
get all instances, and then getting instances for individual ids. Also,
looking up specific machines, and also getting all machines. Now we just do
the "all" gets, and keep a map around for the duration of the checks.

R=wallyworld, mue, fwereade, rog
CC=
https://codereview.appspot.com/9937046

1259. By Frank Mueller

state: added CleanupWatcher

The CleanupWatcher signals the demand for the running of
state.Cleanup(). It is the first in a row of CLs to add
an according worker.

R=fwereade, dimitern
CC=
https://codereview.appspot.com/10078043

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charm/repo.go'
--- charm/repo.go 2013-06-10 20:50:42 +0000
+++ charm/repo.go 2013-06-12 12:32:25 +0000
@@ -10,12 +10,14 @@
10 "fmt"10 "fmt"
11 "io"11 "io"
12 "io/ioutil"12 "io/ioutil"
13 "launchpad.net/juju-core/log"
14 "net/http"13 "net/http"
15 "net/url"14 "net/url"
16 "os"15 "os"
17 "path/filepath"16 "path/filepath"
18 "strings"17 "strings"
18
19 "launchpad.net/juju-core/errors"
20 "launchpad.net/juju-core/log"
19)21)
2022
21// CacheDir stores the charm cache directory path.23// CacheDir stores the charm cache directory path.
@@ -46,15 +48,6 @@
46 Latest(curl *URL) (int, error)48 Latest(curl *URL) (int, error)
47}49}
4850
49// NotFoundError represents an error indicating that the requested data wasn't found.
50type NotFoundError struct {
51 msg string
52}
53
54func (e *NotFoundError) Error() string {
55 return e.msg
56}
57
58// CharmStore is a Repository that provides access to the public juju charm store.51// CharmStore is a Repository that provides access to the public juju charm store.
59type CharmStore struct {52type CharmStore struct {
60 BaseURL string53 BaseURL string
@@ -83,7 +76,7 @@
83 return nil, fmt.Errorf("charm: charm store returned response without charm %q", key)76 return nil, fmt.Errorf("charm: charm store returned response without charm %q", key)
84 }77 }
85 if len(info.Errors) == 1 && info.Errors[0] == "entry not found" {78 if len(info.Errors) == 1 && info.Errors[0] == "entry not found" {
86 return nil, &NotFoundError{fmt.Sprintf("charm not found: %s", curl)}79 return nil, errors.NotFoundf("charm %q", curl)
87 }80 }
88 return info, nil81 return info, nil
89}82}
@@ -116,9 +109,9 @@
116 }109 }
117 if len(event.Errors) == 1 && event.Errors[0] == "entry not found" {110 if len(event.Errors) == 1 && event.Errors[0] == "entry not found" {
118 if digest == "" {111 if digest == "" {
119 return nil, &NotFoundError{fmt.Sprintf("charm event not found for %q", curl)}112 return nil, errors.NotFoundf("charm event for %q", curl)
120 } else {113 } else {
121 return nil, &NotFoundError{fmt.Sprintf("charm event not found for %q with digest %q", curl, digest)}114 return nil, errors.NotFoundf("charm event for %q with digest %q", curl, digest)
122 }115 }
123 }116 }
124 return event, nil117 return event, nil
@@ -288,11 +281,11 @@
288}281}
289282
290func repoNotFound(path string) error {283func repoNotFound(path string) error {
291 return &NotFoundError{fmt.Sprintf("no repository found at %q", path)}284 return errors.NotFoundf("repository %q", path)
292}285}
293286
294func charmNotFound(curl *URL, repoPath string) error {287func charmNotFound(curl *URL, repoPath string) error {
295 return &NotFoundError{fmt.Sprintf("charm not found in %q: %s", repoPath, curl)}288 return errors.RawNotFoundf("charm %q not found in repository %q", curl, repoPath)
296}289}
297290
298func mightBeCharm(info os.FileInfo) bool {291func mightBeCharm(info os.FileInfo) bool {
299292
=== modified file 'charm/repo_test.go'
--- charm/repo_test.go 2013-06-11 23:32:05 +0000
+++ charm/repo_test.go 2013-06-12 12:32:25 +0000
@@ -9,15 +9,17 @@
9 "encoding/json"9 "encoding/json"
10 "fmt"10 "fmt"
11 "io/ioutil"11 "io/ioutil"
12 . "launchpad.net/gocheck"
13 "launchpad.net/juju-core/charm"
14 "launchpad.net/juju-core/testing"
15 "net"12 "net"
16 "net/http"13 "net/http"
17 "os"14 "os"
18 "path/filepath"15 "path/filepath"
19 "strconv"16 "strconv"
20 "strings"17 "strings"
18
19 . "launchpad.net/gocheck"
20 "launchpad.net/juju-core/charm"
21 "launchpad.net/juju-core/errors"
22 "launchpad.net/juju-core/testing"
21)23)
2224
23type MockStore struct {25type MockStore struct {
@@ -180,11 +182,13 @@
180182
181func (s *StoreSuite) TestMissing(c *C) {183func (s *StoreSuite) TestMissing(c *C) {
182 charmURL := charm.MustParseURL("cs:series/missing")184 charmURL := charm.MustParseURL("cs:series/missing")
183 expect := `charm not found: cs:series/missing`185 expect := `charm "cs:series/missing" not found`
184 _, err := s.store.Latest(charmURL)186 _, err := s.store.Latest(charmURL)
185 c.Assert(err, ErrorMatches, expect)187 c.Assert(err, ErrorMatches, expect)
188 c.Assert(errors.IsNotFoundError(err), Equals, true)
186 _, err = s.store.Get(charmURL)189 _, err = s.store.Get(charmURL)
187 c.Assert(err, ErrorMatches, expect)190 c.Assert(err, ErrorMatches, expect)
191 c.Assert(errors.IsNotFoundError(err), Equals, true)
188}192}
189193
190func (s *StoreSuite) TestError(c *C) {194func (s *StoreSuite) TestError(c *C) {
@@ -280,7 +284,8 @@
280func (s *StoreSuite) TestInfoNotFound(c *C) {284func (s *StoreSuite) TestInfoNotFound(c *C) {
281 charmURL := charm.MustParseURL("cs:series/missing")285 charmURL := charm.MustParseURL("cs:series/missing")
282 info, err := s.store.Info(charmURL)286 info, err := s.store.Info(charmURL)
283 c.Assert(err, ErrorMatches, `charm not found: cs:series/missing`)287 c.Assert(err, ErrorMatches, `charm "cs:series/missing" not found`)
288 c.Assert(errors.IsNotFoundError(err), Equals, true)
284 c.Assert(info, IsNil)289 c.Assert(info, IsNil)
285}290}
286291
@@ -319,14 +324,16 @@
319func (s *StoreSuite) TestEventNotFound(c *C) {324func (s *StoreSuite) TestEventNotFound(c *C) {
320 charmURL := charm.MustParseURL("cs:series/missing")325 charmURL := charm.MustParseURL("cs:series/missing")
321 event, err := s.store.Event(charmURL, "")326 event, err := s.store.Event(charmURL, "")
322 c.Assert(err, ErrorMatches, `charm event not found for "cs:series/missing"`)327 c.Assert(err, ErrorMatches, `charm event for "cs:series/missing" not found`)
328 c.Assert(errors.IsNotFoundError(err), Equals, true)
323 c.Assert(event, IsNil)329 c.Assert(event, IsNil)
324}330}
325331
326func (s *StoreSuite) TestEventNotFoundDigest(c *C) {332func (s *StoreSuite) TestEventNotFoundDigest(c *C) {
327 charmURL := charm.MustParseURL("cs:series/good")333 charmURL := charm.MustParseURL("cs:series/good")
328 event, err := s.store.Event(charmURL, "missing-digest")334 event, err := s.store.Event(charmURL, "missing-digest")
329 c.Assert(err, ErrorMatches, `charm event not found for "cs:series/good" with digest "missing-digest"`)335 c.Assert(err, ErrorMatches, `charm event for "cs:series/good" with digest "missing-digest" not found`)
336 c.Assert(errors.IsNotFoundError(err), Equals, true)
330 c.Assert(event, IsNil)337 c.Assert(event, IsNil)
331}338}
332339
@@ -414,7 +421,7 @@
414}421}
415422
416func (s *LocalRepoSuite) checkNotFoundErr(c *C, err error, charmURL *charm.URL) {423func (s *LocalRepoSuite) checkNotFoundErr(c *C, err error, charmURL *charm.URL) {
417 expect := `charm not found in "` + s.repo.Path + `": ` + charmURL.String()424 expect := fmt.Sprintf("charm %q not found in repository %q", charmURL, s.repo.Path)
418 c.Check(err, ErrorMatches, expect)425 c.Check(err, ErrorMatches, expect)
419}426}
420427
@@ -432,16 +439,18 @@
432}439}
433440
434func (s *LocalRepoSuite) TestMissingRepo(c *C) {441func (s *LocalRepoSuite) TestMissingRepo(c *C) {
442 curl := charm.MustParseURL("local:series/zebra")
443 expect := fmt.Sprintf("repository %q not found", s.repo.Path)
444 checkNotFound := func() {
445 _, err := s.repo.Latest(curl)
446 c.Check(err, ErrorMatches, expect)
447 _, err = s.repo.Get(curl)
448 c.Check(err, ErrorMatches, expect)
449 }
435 c.Assert(os.RemoveAll(s.repo.Path), IsNil)450 c.Assert(os.RemoveAll(s.repo.Path), IsNil)
436 _, err := s.repo.Latest(charm.MustParseURL("local:series/zebra"))451 checkNotFound()
437 c.Assert(err, ErrorMatches, `no repository found at ".*"`)
438 _, err = s.repo.Get(charm.MustParseURL("local:series/zebra"))
439 c.Assert(err, ErrorMatches, `no repository found at ".*"`)
440 c.Assert(ioutil.WriteFile(s.repo.Path, nil, 0666), IsNil)452 c.Assert(ioutil.WriteFile(s.repo.Path, nil, 0666), IsNil)
441 _, err = s.repo.Latest(charm.MustParseURL("local:series/zebra"))453 checkNotFound()
442 c.Assert(err, ErrorMatches, `no repository found at ".*"`)
443 _, err = s.repo.Get(charm.MustParseURL("local:series/zebra"))
444 c.Assert(err, ErrorMatches, `no repository found at ".*"`)
445}454}
446455
447func (s *LocalRepoSuite) TestMultipleVersions(c *C) {456func (s *LocalRepoSuite) TestMultipleVersions(c *C) {
448457
=== modified file 'cmd/juju/deploy_test.go'
--- cmd/juju/deploy_test.go 2013-06-12 11:25:32 +0000
+++ cmd/juju/deploy_test.go 2013-06-12 12:32:25 +0000
@@ -62,7 +62,7 @@
6262
63func (s *DeploySuite) TestNoCharm(c *C) {63func (s *DeploySuite) TestNoCharm(c *C) {
64 err := runDeploy(c, "local:unknown-123")64 err := runDeploy(c, "local:unknown-123")
65 c.Assert(err, ErrorMatches, `cannot get charm: charm not found in ".*": local:precise/unknown-123`)65 c.Assert(err, ErrorMatches, `cannot get charm: charm "local:precise/unknown-123" not found in repository ".*"`)
66}66}
6767
68func (s *DeploySuite) TestCharmDir(c *C) {68func (s *DeploySuite) TestCharmDir(c *C) {
6969
=== modified file 'cmd/juju/publish.go'
--- cmd/juju/publish.go 2013-05-02 15:55:42 +0000
+++ cmd/juju/publish.go 2013-06-12 12:32:25 +0000
@@ -5,14 +5,16 @@
55
6import (6import (
7 "fmt"7 "fmt"
8 "os"
9 "strings"
10 "time"
11
8 "launchpad.net/gnuflag"12 "launchpad.net/gnuflag"
9 "launchpad.net/juju-core/bzr"13 "launchpad.net/juju-core/bzr"
10 "launchpad.net/juju-core/charm"14 "launchpad.net/juju-core/charm"
11 "launchpad.net/juju-core/cmd"15 "launchpad.net/juju-core/cmd"
16 "launchpad.net/juju-core/errors"
12 "launchpad.net/juju-core/log"17 "launchpad.net/juju-core/log"
13 "os"
14 "strings"
15 "time"
16)18)
1719
18type PublishCommand struct {20type PublishCommand struct {
@@ -131,9 +133,9 @@
131 }133 }
132134
133 oldEvent, err := charm.Store.Event(curl, localDigest)135 oldEvent, err := charm.Store.Event(curl, localDigest)
134 if _, ok := err.(*charm.NotFoundError); ok {136 if errors.IsNotFoundError(err) {
135 oldEvent, err = charm.Store.Event(curl, "")137 oldEvent, err = charm.Store.Event(curl, "")
136 if _, ok := err.(*charm.NotFoundError); ok {138 if errors.IsNotFoundError(err) {
137 log.Infof("charm %s is not yet in the store", curl)139 log.Infof("charm %s is not yet in the store", curl)
138 err = nil140 err = nil
139 }141 }
@@ -156,7 +158,7 @@
156 for {158 for {
157 time.Sleep(c.pollDelay)159 time.Sleep(c.pollDelay)
158 newEvent, err := charm.Store.Event(curl, "")160 newEvent, err := charm.Store.Event(curl, "")
159 if _, ok := err.(*charm.NotFoundError); ok {161 if errors.IsNotFoundError(err) {
160 continue162 continue
161 }163 }
162 if err != nil {164 if err != nil {
163165
=== modified file 'cmd/juju/upgradecharm_test.go'
--- cmd/juju/upgradecharm_test.go 2013-06-10 20:50:42 +0000
+++ cmd/juju/upgradecharm_test.go 2013-06-12 12:32:25 +0000
@@ -41,12 +41,12 @@
41 c.Assert(err, IsNil)41 c.Assert(err, IsNil)
4242
43 err = runUpgradeCharm(c, "riak", "--repository=blah")43 err = runUpgradeCharm(c, "riak", "--repository=blah")
44 c.Assert(err, ErrorMatches, `no repository found at ".*blah"`)44 c.Assert(err, ErrorMatches, `repository ".*blah" not found`)
45 // Reset JUJU_REPOSITORY explicitly, because repoSuite.SetUpTest45 // Reset JUJU_REPOSITORY explicitly, because repoSuite.SetUpTest
46 // overwrites it (TearDownTest will revert it again).46 // overwrites it (TearDownTest will revert it again).
47 os.Setenv("JUJU_REPOSITORY", "")47 os.Setenv("JUJU_REPOSITORY", "")
48 err = runUpgradeCharm(c, "riak", "--repository=")48 err = runUpgradeCharm(c, "riak", "--repository=")
49 c.Assert(err, ErrorMatches, `charm not found in ".*": local:precise/riak`)49 c.Assert(err, ErrorMatches, `charm "local:precise/riak" not found in repository ".*"`)
50}50}
5151
52func (s *UpgradeCharmErrorsSuite) TestInvalidService(c *C) {52func (s *UpgradeCharmErrorsSuite) TestInvalidService(c *C) {
@@ -70,11 +70,12 @@
7070
71func (s *UpgradeCharmErrorsSuite) TestInvalidSwitchURL(c *C) {71func (s *UpgradeCharmErrorsSuite) TestInvalidSwitchURL(c *C) {
72 s.deployService(c)72 s.deployService(c)
73 err := runUpgradeCharm(c, "riak", "--switch=blah")73 err := runUpgradeCharm(c, "riak", "--switch=local:blah")
74 c.Assert(err, ErrorMatches, "charm not found: cs:precise/blah")74 c.Assert(err, ErrorMatches, `charm "local:precise/blah" not found in repository ".*"`)
75 err = runUpgradeCharm(c, "riak", "--switch=cs:missing/one")75 err = runUpgradeCharm(c, "riak", "--switch=local:missing/one")
76 c.Assert(err, ErrorMatches, "charm not found: cs:missing/one")76 c.Assert(err, ErrorMatches, `charm "local:missing/one" not found in repository ".*"`)
77 // TODO(dimitern): add tests with incompatible charms77 // TODO(dimitern): add tests with incompatible charms
78 // TODO(fwereade): hook up forthcoming testing.MockCharmStore for cs: tests
78}79}
7980
80func (s *UpgradeCharmErrorsSuite) TestSwitchAndRevisionFails(c *C) {81func (s *UpgradeCharmErrorsSuite) TestSwitchAndRevisionFails(c *C) {
8182
=== modified file 'cmd/jujud/agent_test.go'
--- cmd/jujud/agent_test.go 2013-05-31 08:33:34 +0000
+++ cmd/jujud/agent_test.go 2013-06-12 12:32:25 +0000
@@ -6,21 +6,22 @@
6import (6import (
7 "bytes"7 "bytes"
8 "fmt"8 "fmt"
9 "net/http"
10 "os"
11 "path/filepath"
12 "time"
13
9 . "launchpad.net/gocheck"14 . "launchpad.net/gocheck"
10 "launchpad.net/juju-core/cmd"15 "launchpad.net/juju-core/cmd"
11 "launchpad.net/juju-core/environs/agent"16 "launchpad.net/juju-core/environs/agent"
12 "launchpad.net/juju-core/environs/tools"17 "launchpad.net/juju-core/environs/tools"
13 "launchpad.net/juju-core/errors"
14 "launchpad.net/juju-core/juju/testing"
15 "launchpad.net/juju-core/state"18 "launchpad.net/juju-core/state"
16 coretesting "launchpad.net/juju-core/testing"
17 "launchpad.net/juju-core/version"19 "launchpad.net/juju-core/version"
18 "launchpad.net/juju-core/worker"20 "launchpad.net/juju-core/worker"
19 "launchpad.net/tomb"21 "launchpad.net/tomb"
20 "net/http"22
21 "os"23 "launchpad.net/juju-core/juju/testing"
22 "path/filepath"24 coretesting "launchpad.net/juju-core/testing"
23 "time"
24)25)
2526
26var _ = Suite(&toolSuite{})27var _ = Suite(&toolSuite{})
@@ -348,13 +349,13 @@
348 info := s.StateInfo(c)349 info := s.StateInfo(c)
349 info.Tag = ent.Tag()350 info.Tag = ent.Tag()
350 info.Password = "initial"351 info.Password = "initial"
351 testOpenState(c, info, errors.Unauthorizedf("unauth"))352 assertOpenState(c, info, false)
352353
353 // Read the configuration and check that we can connect with it.354 // Read the configuration and check that we can connect with it.
354 c.Assert(refreshConfig(conf), IsNil)355 c.Assert(refreshConfig(conf), IsNil)
355 newPassword := conf.StateInfo.Password356 newPassword := conf.StateInfo.Password
356357
357 testOpenState(c, conf.StateInfo, nil)358 assertOpenState(c, conf.StateInfo, true)
358359
359 // Check that it starts again ok360 // Check that it starts again ok
360 err = runStop(newAgent())361 err = runStop(newAgent())
@@ -376,7 +377,7 @@
376 c.Assert(conf.StateInfo.Password, Not(Equals), newPassword)377 c.Assert(conf.StateInfo.Password, Not(Equals), newPassword)
377378
378 info.Password = conf.StateInfo.Password379 info.Password = conf.StateInfo.Password
379 testOpenState(c, info, nil)380 assertOpenState(c, info, true)
380}381}
381382
382func (s *agentSuite) testUpgrade(c *C, agent runner, currentTools *state.Tools) {383func (s *agentSuite) testUpgrade(c *C, agent runner, currentTools *state.Tools) {
383384
=== modified file 'cmd/jujud/bootstrap_test.go'
--- cmd/jujud/bootstrap_test.go 2013-05-30 00:47:30 +0000
+++ cmd/jujud/bootstrap_test.go 2013-06-12 12:32:25 +0000
@@ -134,15 +134,15 @@
134 })134 })
135}135}
136136
137func testOpenState(c *C, info *state.Info, expectErr error) {137func assertOpenState(c *C, info *state.Info, expectSuccess bool) {
138 st, err := state.Open(info, state.DefaultDialOpts())138 st, err := state.Open(info, state.DefaultDialOpts())
139 if st != nil {139 if st != nil {
140 st.Close()140 st.Close()
141 }141 }
142 if expectErr != nil {142 if expectSuccess {
143 c.Assert(err, IsNil)
144 } else {
143 c.Assert(errors.IsUnauthorizedError(err), Equals, true)145 c.Assert(errors.IsUnauthorizedError(err), Equals, true)
144 } else {
145 c.Assert(err, IsNil)
146 }146 }
147}147}
148148
@@ -162,10 +162,10 @@
162 Addrs: []string{testing.MgoAddr},162 Addrs: []string{testing.MgoAddr},
163 CACert: []byte(testing.CACert),163 CACert: []byte(testing.CACert),
164 }164 }
165 testOpenState(c, info, errors.Unauthorizedf("some auth problem"))165 assertOpenState(c, info, false)
166166
167 info.Tag, info.Password = "machine-0", "foo"167 info.Tag, info.Password = "machine-0", "foo"
168 testOpenState(c, info, nil)168 assertOpenState(c, info, true)
169169
170 info.Tag = ""170 info.Tag = ""
171 st, err := state.Open(info, state.DefaultDialOpts())171 st, err := state.Open(info, state.DefaultDialOpts())
172172
=== modified file 'environs/dummy/storage.go'
--- environs/dummy/storage.go 2013-05-30 00:47:30 +0000
+++ environs/dummy/storage.go 2013-06-12 12:32:25 +0000
@@ -82,7 +82,7 @@
82 }82 }
83 data, ok := s.files[path]83 data, ok := s.files[path]
84 if !ok {84 if !ok {
85 return nil, errors.NotFoundf("file %q not found", path)85 return nil, errors.NotFoundf("file %q", path)
86 }86 }
87 return data, nil87 return data, nil
88}88}
8989
=== modified file 'environs/ec2/storage.go'
--- environs/ec2/storage.go 2013-05-30 00:47:30 +0000
+++ environs/ec2/storage.go 2013-06-12 12:32:25 +0000
@@ -160,7 +160,7 @@
160160
161func maybeNotFound(err error) error {161func maybeNotFound(err error) error {
162 if err != nil && s3ErrorStatusCode(err) == 404 {162 if err != nil && s3ErrorStatusCode(err) == 404 {
163 return &errors.NotFoundError{err, ""}163 return errors.RawNotFoundf("%v", err)
164 }164 }
165 return err165 return err
166}166}
167167
=== modified file 'environs/imagemetadata/simplestreams.go'
--- environs/imagemetadata/simplestreams.go 2013-05-30 05:39:33 +0000
+++ environs/imagemetadata/simplestreams.go 2013-06-12 12:32:25 +0000
@@ -245,14 +245,14 @@
245 dataURL += path245 dataURL += path
246 resp, err := http.Get(dataURL)246 resp, err := http.Get(dataURL)
247 if err != nil {247 if err != nil {
248 return nil, dataURL, errors.NotFoundf("invalid URL %q", dataURL)248 return nil, dataURL, errors.RawNotFoundf("invalid URL %q", dataURL)
249 }249 }
250 defer resp.Body.Close()250 defer resp.Body.Close()
251 if resp.StatusCode == http.StatusNotFound {251 if resp.StatusCode == http.StatusNotFound {
252 return nil, dataURL, errors.NotFoundf("cannot find URL %q", dataURL)252 return nil, dataURL, errors.NotFoundf("URL %q", dataURL)
253 }253 }
254 if resp.StatusCode == http.StatusUnauthorized {254 if resp.StatusCode == http.StatusUnauthorized {
255 return nil, dataURL, errors.Unauthorizedf("unauthorised access to URL %q", dataURL)255 return nil, dataURL, errors.Unauthorizedf("access to URL %q", dataURL)
256 }256 }
257 if resp.StatusCode != http.StatusOK {257 if resp.StatusCode != http.StatusOK {
258 return nil, dataURL, fmt.Errorf("cannot access URL %q, %q", dataURL, resp.Status)258 return nil, dataURL, fmt.Errorf("cannot access URL %q, %q", dataURL, resp.Status)
@@ -322,9 +322,9 @@
322 }322 }
323 }323 }
324 if !containsImageIds {324 if !containsImageIds {
325 return "", errors.NotFoundf("index file missing %q data", imageIds)325 return "", errors.RawNotFoundf("index file missing %q data", imageIds)
326 }326 }
327 return "", errors.NotFoundf("index file missing data for cloud %v and product name(s) %q", ic.CloudSpec, prodIds)327 return "", errors.RawNotFoundf("index file missing data for cloud %v and product name(s) %q", ic.CloudSpec, prodIds)
328}328}
329329
330// utility function to see if element exists in values slice.330// utility function to see if element exists in values slice.
331331
=== modified file 'environs/local/storage.go'
--- environs/local/storage.go 2013-05-30 00:47:30 +0000
+++ environs/local/storage.go 2013-06-12 12:32:25 +0000
@@ -42,7 +42,7 @@
42 return nil, err42 return nil, err
43 }43 }
44 if resp.StatusCode != 200 {44 if resp.StatusCode != 200 {
45 return nil, errors.NotFoundf("file %q not found", name)45 return nil, errors.NotFoundf("file %q", name)
46 }46 }
47 return resp.Body, nil47 return resp.Body, nil
48}48}
4949
=== modified file 'environs/maas/storage.go'
--- environs/maas/storage.go 2013-05-30 00:47:30 +0000
+++ environs/maas/storage.go 2013-06-12 12:32:25 +0000
@@ -77,9 +77,9 @@
77 noObj := gomaasapi.MAASObject{}77 noObj := gomaasapi.MAASObject{}
78 serverErr, ok := err.(gomaasapi.ServerError)78 serverErr, ok := err.(gomaasapi.ServerError)
79 if ok && serverErr.StatusCode == 404 {79 if ok && serverErr.StatusCode == 404 {
80 return noObj, errors.NotFoundf("file '%s' not found", name)80 return noObj, errors.NotFoundf("file %q", name)
81 }81 }
82 msg := fmt.Errorf("could not access file '%s': %v", name, err)82 msg := fmt.Errorf("could not access file %q: %v", name, err)
83 return noObj, msg83 return noObj, msg
84 }84 }
85 return obj, nil85 return obj, nil
8686
=== modified file 'environs/openstack/storage.go'
--- environs/openstack/storage.go 2013-05-31 01:02:53 +0000
+++ environs/openstack/storage.go 2013-06-12 12:32:25 +0000
@@ -160,7 +160,7 @@
160// container not being found.160// container not being found.
161func maybeNotFound(err error) (error, bool) {161func maybeNotFound(err error) (error, bool) {
162 if err != nil && gooseerrors.IsNotFound(err) {162 if err != nil && gooseerrors.IsNotFound(err) {
163 return &coreerrors.NotFoundError{err, ""}, true163 return coreerrors.RawNotFoundf("%v", err), true
164 }164 }
165 return err, false165 return err, false
166}166}
167167
=== modified file 'environs/tools.go'
--- environs/tools.go 2013-05-30 00:47:30 +0000
+++ environs/tools.go 2013-06-12 12:32:25 +0000
@@ -147,6 +147,6 @@
147147
148func convertToolsError(err *error) {148func convertToolsError(err *error) {
149 if isToolsError(*err) {149 if isToolsError(*err) {
150 *err = &errors.NotFoundError{*err, ""}150 *err = errors.RawNotFoundf("%v", *err)
151 }151 }
152}152}
153153
=== modified file 'environs/tools_test.go'
--- environs/tools_test.go 2013-05-30 00:47:30 +0000
+++ environs/tools_test.go 2013-06-12 12:32:25 +0000
@@ -168,7 +168,7 @@
168 if len(actual) > 0 {168 if len(actual) > 0 {
169 c.Logf(actual.String())169 c.Logf(actual.String())
170 }170 }
171 c.Check(err, DeepEquals, &errors.NotFoundError{test.err, ""})171 c.Check(err, DeepEquals, &errors.NotFoundError{test.err.Error()})
172 continue172 continue
173 }173 }
174 source := private174 source := private
@@ -389,7 +389,7 @@
389 if len(actual) > 0 {389 if len(actual) > 0 {
390 c.Logf(actual.String())390 c.Logf(actual.String())
391 }391 }
392 c.Check(err, DeepEquals, &errors.NotFoundError{test.err, ""})392 c.Check(err, DeepEquals, &errors.NotFoundError{test.err.Error()})
393 continue393 continue
394 }394 }
395 expect := map[version.Binary]string{}395 expect := map[version.Binary]string{}
@@ -484,7 +484,7 @@
484 if len(actual) > 0 {484 if len(actual) > 0 {
485 c.Logf(actual.String())485 c.Logf(actual.String())
486 }486 }
487 c.Check(err, DeepEquals, &errors.NotFoundError{test.err, ""})487 c.Check(err, DeepEquals, &errors.NotFoundError{test.err.Error()})
488 continue488 continue
489 }489 }
490 expect := map[version.Binary]string{}490 expect := map[version.Binary]string{}
@@ -548,7 +548,7 @@
548 }548 }
549 c.Check(actual.URL, DeepEquals, source[actual.Binary])549 c.Check(actual.URL, DeepEquals, source[actual.Binary])
550 } else {550 } else {
551 c.Check(err, DeepEquals, &errors.NotFoundError{test.err, ""})551 c.Check(err, DeepEquals, &errors.NotFoundError{test.err.Error()})
552 }552 }
553 }553 }
554}554}
555555
=== modified file 'errors/errors.go'
--- errors/errors.go 2013-05-30 00:47:30 +0000
+++ errors/errors.go 2013-06-12 12:32:25 +0000
@@ -7,60 +7,62 @@
7 "fmt"7 "fmt"
8)8)
99
10// NotFoundError records an error when something has not been found.10// NotFoundError indicates that something has not been found.
11type NotFoundError struct {11type NotFoundError struct {
12 // error is the underlying error.
13 error
14 Msg string12 Msg string
15}13}
1614
17// IsNotFoundError returns true if err is a NotFoundError.15func (e *NotFoundError) Error() string {
16 if e.Msg == "" {
17 return "<something> not found"
18 }
19 return e.Msg
20}
21
22// IsNotFoundError returns true if err is a *NotFoundError.
18func IsNotFoundError(err error) bool {23func IsNotFoundError(err error) bool {
19 if _, ok := err.(*NotFoundError); ok {24 _, ok := err.(*NotFoundError)
20 return true25 return ok
21 }26}
22 return false27
23}28// NotFoundf("foo %s", "bar") returns a *NotFoundError with the message
2429// "foo bar not found".
25func (e *NotFoundError) Error() string {
26 if e.Msg != "" || e.error == nil {
27 if e.error != nil {
28 return fmt.Sprintf("%s: %v", e.Msg, e.error.Error())
29 }
30 return e.Msg
31 }
32 return e.error.Error()
33}
34
35// NotFoundf returns a error for which IsNotFound returns
36// true. The message for the error is made up from the given
37// arguments formatted as with fmt.Sprintf, with the
38// string " not found" appended.
39func NotFoundf(format string, args ...interface{}) error {30func NotFoundf(format string, args ...interface{}) error {
40 return &NotFoundError{nil, fmt.Sprintf(format+" not found", args...)}31 return RawNotFoundf(format+" not found", args...)
41}32}
4233
43// UnauthorizedError represents the error that an operation is unauthorized.34// RawNotFoundf("foo %s", "bar") returns a *NotFoundError with the message
44// Use IsUnauthorized() to determine if the error was related to authorization failure.35// "foo bar".
36func RawNotFoundf(format string, args ...interface{}) error {
37 return &NotFoundError{fmt.Sprintf(format, args...)}
38}
39
40// UnauthorizedError indicates that some operation is unauthorized.
45type UnauthorizedError struct {41type UnauthorizedError struct {
46 error
47 Msg string42 Msg string
48}43}
4944
45func (e *UnauthorizedError) Error() string {
46 if e.Msg == "" {
47 return "unauthorized <something>"
48 }
49 return e.Msg
50}
51
52// IsUnauthorizedError returns true if err is a *UnauthorizedError.
50func IsUnauthorizedError(err error) bool {53func IsUnauthorizedError(err error) bool {
51 _, ok := err.(*UnauthorizedError)54 _, ok := err.(*UnauthorizedError)
52 return ok55 return ok
53}56}
5457
55func (e *UnauthorizedError) Error() string {58// Unauthorizedf("foo %s", "bar") returns a *UnauthorizedError with the
56 if e.error != nil {59// message "unauthorized foo bar".
57 return fmt.Sprintf("%s: %v", e.Msg, e.error.Error())
58 }
59 return e.Msg
60}
61
62// Unauthorizedf returns an error for which IsUnauthorizedError returns true.
63// It is mainly used for testing.
64func Unauthorizedf(format string, args ...interface{}) error {60func Unauthorizedf(format string, args ...interface{}) error {
65 return &UnauthorizedError{nil, fmt.Sprintf(format, args...)}61 return RawUnauthorizedf("unauthorized "+format, args...)
62}
63
64// RawUnauthorizedf("foo %s", "bar") returns a *UnauthorizedError with the
65// message "foo bar".
66func RawUnauthorizedf(format string, args ...interface{}) error {
67 return &UnauthorizedError{fmt.Sprintf(format, args...)}
66}68}
6769
=== added file 'errors/errors_test.go'
--- errors/errors_test.go 1970-01-01 00:00:00 +0000
+++ errors/errors_test.go 2013-06-12 12:32:25 +0000
@@ -0,0 +1,74 @@
1// Copyright 2011, 2012, 2013 Canonical Ltd.
2// Licensed under the AGPLv3, see LICENCE file for details.
3
4package errors_test
5
6import (
7 "fmt"
8 "testing"
9
10 . "launchpad.net/gocheck"
11 "launchpad.net/juju-core/errors"
12)
13
14func TestPackage(t *testing.T) {
15 TestingT(t)
16}
17
18type NotFoundSuite struct{}
19
20var _ = Suite(&NotFoundSuite{})
21
22func (s *NotFoundSuite) TestNotFound(c *C) {
23 emptyErr := &errors.NotFoundError{}
24 c.Check(emptyErr, ErrorMatches, `<something> not found`)
25 c.Check(errors.IsNotFoundError(emptyErr), Equals, true)
26
27 rawErr := &errors.NotFoundError{"widget cannot be located"}
28 c.Check(rawErr, ErrorMatches, `widget cannot be located`)
29 c.Check(errors.IsNotFoundError(rawErr), Equals, true)
30
31 badErr := fmt.Errorf("thingy not found")
32 c.Check(errors.IsNotFoundError(badErr), Equals, false)
33
34 c.Check(errors.IsNotFoundError(nil), Equals, false)
35}
36
37func (s *NotFoundSuite) TestNotFoundf(c *C) {
38 err := errors.NotFoundf("plop %q", "wibble")
39 c.Check(err, ErrorMatches, `plop "wibble" not found`)
40 c.Check(errors.IsNotFoundError(err), Equals, true)
41
42 err = errors.RawNotFoundf("plop %q", "wibble")
43 c.Check(err, ErrorMatches, `plop "wibble"`)
44 c.Check(errors.IsNotFoundError(err), Equals, true)
45}
46
47type UnauthorizedSuite struct{}
48
49var _ = Suite(&UnauthorizedSuite{})
50
51func (s *UnauthorizedSuite) TestUnauthorized(c *C) {
52 emptyErr := &errors.UnauthorizedError{}
53 c.Check(emptyErr, ErrorMatches, `unauthorized <something>`)
54 c.Check(errors.IsUnauthorizedError(emptyErr), Equals, true)
55
56 rawErr := &errors.UnauthorizedError{"whatchamadoodle access is forbidden"}
57 c.Check(rawErr, ErrorMatches, `whatchamadoodle access is forbidden`)
58 c.Check(errors.IsUnauthorizedError(rawErr), Equals, true)
59
60 badErr := fmt.Errorf("unauthorized thingy")
61 c.Check(errors.IsUnauthorizedError(badErr), Equals, false)
62
63 c.Check(errors.IsUnauthorizedError(nil), Equals, false)
64}
65
66func (s *UnauthorizedSuite) TestUnauthorizedf(c *C) {
67 err := errors.Unauthorizedf("plop %q", "wibble")
68 c.Check(err, ErrorMatches, `unauthorized plop "wibble"`)
69 c.Check(errors.IsUnauthorizedError(err), Equals, true)
70
71 err = errors.RawUnauthorizedf("plop %q", "wibble")
72 c.Check(err, ErrorMatches, `plop "wibble"`)
73 c.Check(errors.IsUnauthorizedError(err), Equals, true)
74}
075
=== modified file 'state/apiserver/client_test.go'
--- state/apiserver/client_test.go 2013-06-12 11:25:32 +0000
+++ state/apiserver/client_test.go 2013-06-12 12:32:25 +0000
@@ -309,7 +309,7 @@
309 "wordpress": `charm URL has invalid schema: "wordpress"`,309 "wordpress": `charm URL has invalid schema: "wordpress"`,
310 "cs:wordpress": `charm URL without series: "cs:wordpress"`,310 "cs:wordpress": `charm URL without series: "cs:wordpress"`,
311 "cs:precise/wordpress": "charm url must include revision",311 "cs:precise/wordpress": "charm url must include revision",
312 "cs:precise/wordpress-999999": `cannot get charm: charm not found in mock store: cs:precise/wordpress-999999`,312 "cs:precise/wordpress-999999": `cannot get charm: charm "cs:precise/wordpress-999999" not found in mock store`,
313 "local:precise/wordpress-999999": `charm url has unsupported schema "local"`,313 "local:precise/wordpress-999999": `charm url has unsupported schema "local"`,
314 } {314 } {
315 c.Logf("test %s", url)315 c.Logf("test %s", url)
316316
=== modified file 'state/apiserver/errors_test.go'
--- state/apiserver/errors_test.go 2013-06-06 17:09:49 +0000
+++ state/apiserver/errors_test.go 2013-06-12 12:32:25 +0000
@@ -23,10 +23,10 @@
23 err error23 err error
24 code string24 code string
25}{{25}{{
26 err: errors.NotFoundf("hello"),26 err: errors.RawNotFoundf("hello"),
27 code: api.CodeNotFound,27 code: api.CodeNotFound,
28}, {28}, {
29 err: errors.Unauthorizedf("hello"),29 err: errors.RawUnauthorizedf("hello"),
30 code: api.CodeUnauthorized,30 code: api.CodeUnauthorized,
31}, {31}, {
32 err: state.ErrCannotEnterScopeYet,32 err: state.ErrCannotEnterScopeYet,
3333
=== modified file 'state/open.go'
--- state/open.go 2013-06-10 11:16:30 +0000
+++ state/open.go 2013-06-12 12:32:25 +0000
@@ -178,19 +178,23 @@
178 logSizeTests = 1000000178 logSizeTests = 1000000
179)179)
180180
181func maybeUnauthorized(err error, msg string) error {181func maybeUnauthorized(err error, message string) error {
182 if err == nil {182 if err == nil {
183 return nil183 return nil
184 }184 }
185 // Unauthorized access errors have no error code,185 // Unauthorized access errors have no error code,
186 // just a simple error string.186 // just a simple error string.
187 // TODO(fwereade): does this comment imply that "auth fails" is a magic
188 // error value produced my mongo, or mgo, or something? And what about
189 // the magic "need to login" that's checked in testing/mgo.go? Should
190 // we be checking for that as well?
187 if err.Error() == "auth fails" {191 if err.Error() == "auth fails" {
188 return &errors.UnauthorizedError{err, msg}192 return errors.RawUnauthorizedf(message)
189 }193 }
190 if err, ok := err.(*mgo.QueryError); ok && err.Code == 10057 {194 if err, ok := err.(*mgo.QueryError); ok && err.Code == 10057 {
191 return &errors.UnauthorizedError{err, msg}195 return errors.RawUnauthorizedf(message)
192 }196 }
193 return fmt.Errorf("%s: %v", msg, err)197 return fmt.Errorf("%s: %v", message, err)
194}198}
195199
196func newState(session *mgo.Session, info *Info) (*State, error) {200func newState(session *mgo.Session, info *Info) (*State, error) {
197201
=== modified file 'state/state_test.go'
--- state/state_test.go 2013-06-11 20:56:00 +0000
+++ state/state_test.go 2013-06-12 12:32:25 +0000
@@ -79,13 +79,6 @@
79 c.Assert(apiAddrs, DeepEquals, expectedAddrs)79 c.Assert(apiAddrs, DeepEquals, expectedAddrs)
80}80}
8181
82func (s *StateSuite) TestIsNotFound(c *C) {
83 err1 := fmt.Errorf("unrelated error")
84 err2 := errors.NotFoundf("foo")
85 c.Assert(errors.IsNotFoundError(err1), Equals, false)
86 c.Assert(errors.IsNotFoundError(err2), Equals, true)
87}
88
89func (s *StateSuite) TestAddCharm(c *C) {82func (s *StateSuite) TestAddCharm(c *C) {
90 // Check that adding charms from scratch works correctly.83 // Check that adding charms from scratch works correctly.
91 ch := testing.Charms.Dir("dummy")84 ch := testing.Charms.Dir("dummy")
9285
=== modified file 'testing/charm.go'
--- testing/charm.go 2013-06-12 11:25:32 +0000
+++ testing/charm.go 2013-06-12 12:32:25 +0000
@@ -6,10 +6,12 @@
6import (6import (
7 "fmt"7 "fmt"
8 "go/build"8 "go/build"
9 "launchpad.net/juju-core/charm"
10 "os"9 "os"
11 "os/exec"10 "os/exec"
12 "path/filepath"11 "path/filepath"
12
13 "launchpad.net/juju-core/charm"
14 "launchpad.net/juju-core/errors"
13)15)
1416
15func init() {17func init() {
@@ -169,7 +171,7 @@
169 base, rev := s.interpret(charmURL)171 base, rev := s.interpret(charmURL)
170 charm, found := s.charms[base][rev]172 charm, found := s.charms[base][rev]
171 if !found {173 if !found {
172 return nil, fmt.Errorf("charm not found in mock store: %s", charmURL)174 return nil, errors.RawNotFoundf("charm %q not found in mock store", charmURL)
173 }175 }
174 return charm, nil176 return charm, nil
175}177}
@@ -179,7 +181,7 @@
179 charmURL = charmURL.WithRevision(-1)181 charmURL = charmURL.WithRevision(-1)
180 base, rev := s.interpret(charmURL)182 base, rev := s.interpret(charmURL)
181 if _, found := s.charms[base][rev]; !found {183 if _, found := s.charms[base][rev]; !found {
182 return 0, fmt.Errorf("charm not found in mock store: %s", charmURL)184 return 0, errors.RawNotFoundf("charm %q not found in mock store", charmURL)
183 }185 }
184 return rev, nil186 return rev, nil
185}187}

Subscribers

People subscribed via source and target branches