1
// Copyright 2012, 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
10
"github.com/juju/errors"
11
"github.com/juju/names"
12
jc "github.com/juju/testing/checkers"
14
gc "gopkg.in/check.v1"
15
"gopkg.in/macaroon.v1"
17
"github.com/juju/juju/apiserver/common"
18
"github.com/juju/juju/apiserver/params"
19
"github.com/juju/juju/core/leadership"
20
"github.com/juju/juju/core/lease"
21
"github.com/juju/juju/resource/api"
22
"github.com/juju/juju/state"
23
"github.com/juju/juju/testing"
26
type errorsSuite struct {
30
var _ = gc.Suite(&errorsSuite{})
32
var errorTransformTests = []struct {
36
helperFunc func(error) bool
38
err: errors.NotFoundf("hello"),
39
code: params.CodeNotFound,
40
status: http.StatusNotFound,
41
helperFunc: params.IsCodeNotFound,
43
err: errors.Unauthorizedf("hello"),
44
code: params.CodeUnauthorized,
45
status: http.StatusUnauthorized,
46
helperFunc: params.IsCodeUnauthorized,
48
err: state.ErrCannotEnterScopeYet,
49
code: params.CodeCannotEnterScopeYet,
50
status: http.StatusInternalServerError,
51
helperFunc: params.IsCodeCannotEnterScopeYet,
53
err: state.ErrCannotEnterScope,
54
code: params.CodeCannotEnterScope,
55
status: http.StatusInternalServerError,
56
helperFunc: params.IsCodeCannotEnterScope,
59
code: params.CodeDead,
60
status: http.StatusInternalServerError,
61
helperFunc: params.IsCodeDead,
63
err: txn.ErrExcessiveContention,
64
code: params.CodeExcessiveContention,
65
status: http.StatusInternalServerError,
66
helperFunc: params.IsCodeExcessiveContention,
68
err: state.ErrUnitHasSubordinates,
69
code: params.CodeUnitHasSubordinates,
70
status: http.StatusInternalServerError,
71
helperFunc: params.IsCodeUnitHasSubordinates,
74
code: params.CodeNotFound,
75
status: http.StatusNotFound,
76
helperFunc: params.IsCodeNotFound,
78
err: common.NoAddressSetError(names.NewUnitTag("mysql/0"), "public"),
79
code: params.CodeNoAddressSet,
80
status: http.StatusInternalServerError,
81
helperFunc: params.IsCodeNoAddressSet,
83
err: common.ErrBadCreds,
84
code: params.CodeUnauthorized,
85
status: http.StatusUnauthorized,
86
helperFunc: params.IsCodeUnauthorized,
89
code: params.CodeUnauthorized,
90
status: http.StatusUnauthorized,
91
helperFunc: params.IsCodeUnauthorized,
93
err: common.ErrNotLoggedIn,
94
code: params.CodeUnauthorized,
95
status: http.StatusUnauthorized,
96
helperFunc: params.IsCodeUnauthorized,
98
err: errors.NotProvisionedf("machine 0"),
99
code: params.CodeNotProvisioned,
100
status: http.StatusInternalServerError,
101
helperFunc: params.IsCodeNotProvisioned,
103
err: errors.AlreadyExistsf("blah"),
104
code: params.CodeAlreadyExists,
105
status: http.StatusInternalServerError,
106
helperFunc: params.IsCodeAlreadyExists,
108
err: common.ErrUnknownWatcher,
109
code: params.CodeNotFound,
110
status: http.StatusNotFound,
111
helperFunc: params.IsCodeNotFound,
113
err: errors.NotAssignedf("unit mysql/0"),
114
code: params.CodeNotAssigned,
115
status: http.StatusInternalServerError,
116
helperFunc: params.IsCodeNotAssigned,
118
err: common.ErrStoppedWatcher,
119
code: params.CodeStopped,
120
status: http.StatusInternalServerError,
121
helperFunc: params.IsCodeStopped,
123
err: &state.HasAssignedUnitsError{"42", []string{"a"}},
124
code: params.CodeHasAssignedUnits,
125
status: http.StatusInternalServerError,
126
helperFunc: params.IsCodeHasAssignedUnits,
128
err: common.ErrTryAgain,
129
code: params.CodeTryAgain,
130
status: http.StatusInternalServerError,
131
helperFunc: params.IsCodeTryAgain,
133
err: leadership.ErrClaimDenied,
134
code: params.CodeLeadershipClaimDenied,
135
status: http.StatusInternalServerError,
136
helperFunc: params.IsCodeLeadershipClaimDenied,
138
err: lease.ErrClaimDenied,
139
code: params.CodeLeaseClaimDenied,
140
status: http.StatusInternalServerError,
141
helperFunc: params.IsCodeLeaseClaimDenied,
143
err: common.OperationBlockedError("test"),
144
code: params.CodeOperationBlocked,
145
status: http.StatusBadRequest,
146
helperFunc: params.IsCodeOperationBlocked,
148
err: errors.NotSupportedf("needed feature"),
149
code: params.CodeNotSupported,
150
status: http.StatusInternalServerError,
151
helperFunc: params.IsCodeNotSupported,
153
err: errors.BadRequestf("something"),
154
code: params.CodeBadRequest,
155
status: http.StatusBadRequest,
156
helperFunc: params.IsBadRequest,
158
err: errors.MethodNotAllowedf("something"),
159
code: params.CodeMethodNotAllowed,
160
status: http.StatusMethodNotAllowed,
161
helperFunc: params.IsMethodNotAllowed,
163
err: stderrors.New("an error"),
164
status: http.StatusInternalServerError,
167
err: &common.DischargeRequiredError{
168
Cause: errors.New("something"),
169
Macaroon: sampleMacaroon,
171
status: http.StatusUnauthorized,
172
code: params.CodeDischargeRequired,
173
helperFunc: func(err error) bool {
174
err1, ok := err.(*params.Error)
175
if !ok || err1.Info == nil || err1.Info.Macaroon != sampleMacaroon {
181
err: unhashableError{"foo"},
182
status: http.StatusInternalServerError,
185
err: common.UnknownModelError("dead-beef-123456"),
186
code: params.CodeNotFound,
187
status: http.StatusNotFound,
188
helperFunc: params.IsCodeNotFound,
192
status: http.StatusOK,
195
var sampleMacaroon = func() *macaroon.Macaroon {
196
m, err := macaroon.New([]byte("key"), "id", "loc")
203
type unhashableError []string
205
func (err unhashableError) Error() string {
209
func (s *errorsSuite) TestErrorTransform(c *gc.C) {
210
for i, t := range errorTransformTests {
211
c.Logf("running test %d: %T{%q}", i, t.err, t.err)
212
err1, status := common.ServerErrorAndStatus(t.err)
214
// Sanity check that ServerError returns the same thing.
215
err2 := common.ServerError(t.err)
216
c.Assert(err2, gc.DeepEquals, err1)
217
c.Assert(status, gc.Equals, t.status)
220
c.Assert(err1, gc.IsNil)
221
c.Assert(status, gc.Equals, http.StatusOK)
224
c.Assert(err1.Message, gc.Equals, t.err.Error())
225
c.Assert(err1.Code, gc.Equals, t.code)
226
if t.helperFunc != nil {
227
c.Assert(err1, jc.Satisfies, t.helperFunc)
230
// TODO(ericsnow) Remove this switch once the other error types are supported.
232
case params.CodeHasAssignedUnits,
233
params.CodeNoAddressSet,
234
params.CodeUpgradeInProgress,
235
params.CodeMachineHasAttachedStorage,
236
params.CodeDischargeRequired:
238
case params.CodeNotFound:
239
if common.IsUnknownModelError(t.err) {
242
case params.CodeOperationBlocked:
243
// ServerError doesn't actually have a case for this code.
247
c.Logf(" checking restore (%#v)", err1)
248
restored := api.RestoreError(err1)
250
c.Check(restored, jc.ErrorIsNil)
251
} else if t.code == "" {
252
c.Check(restored.Error(), gc.Equals, t.err.Error())
254
// TODO(ericsnow) Use a stricter DeepEquals check.
255
c.Check(errors.Cause(restored), gc.FitsTypeOf, t.err)
256
c.Check(restored.Error(), gc.Equals, t.err.Error())