~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/resource/api/errors_test.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012, 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package api_test
 
5
 
 
6
import (
 
7
        stderrors "errors"
 
8
        "net/http"
 
9
 
 
10
        "github.com/juju/errors"
 
11
        "github.com/juju/names"
 
12
        jc "github.com/juju/testing/checkers"
 
13
        "github.com/juju/txn"
 
14
        gc "gopkg.in/check.v1"
 
15
        "gopkg.in/macaroon.v1"
 
16
 
 
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"
 
24
)
 
25
 
 
26
type errorsSuite struct {
 
27
        testing.BaseSuite
 
28
}
 
29
 
 
30
var _ = gc.Suite(&errorsSuite{})
 
31
 
 
32
var errorTransformTests = []struct {
 
33
        err        error
 
34
        code       string
 
35
        status     int
 
36
        helperFunc func(error) bool
 
37
}{{
 
38
        err:        errors.NotFoundf("hello"),
 
39
        code:       params.CodeNotFound,
 
40
        status:     http.StatusNotFound,
 
41
        helperFunc: params.IsCodeNotFound,
 
42
}, {
 
43
        err:        errors.Unauthorizedf("hello"),
 
44
        code:       params.CodeUnauthorized,
 
45
        status:     http.StatusUnauthorized,
 
46
        helperFunc: params.IsCodeUnauthorized,
 
47
}, {
 
48
        err:        state.ErrCannotEnterScopeYet,
 
49
        code:       params.CodeCannotEnterScopeYet,
 
50
        status:     http.StatusInternalServerError,
 
51
        helperFunc: params.IsCodeCannotEnterScopeYet,
 
52
}, {
 
53
        err:        state.ErrCannotEnterScope,
 
54
        code:       params.CodeCannotEnterScope,
 
55
        status:     http.StatusInternalServerError,
 
56
        helperFunc: params.IsCodeCannotEnterScope,
 
57
}, {
 
58
        err:        state.ErrDead,
 
59
        code:       params.CodeDead,
 
60
        status:     http.StatusInternalServerError,
 
61
        helperFunc: params.IsCodeDead,
 
62
}, {
 
63
        err:        txn.ErrExcessiveContention,
 
64
        code:       params.CodeExcessiveContention,
 
65
        status:     http.StatusInternalServerError,
 
66
        helperFunc: params.IsCodeExcessiveContention,
 
67
}, {
 
68
        err:        state.ErrUnitHasSubordinates,
 
69
        code:       params.CodeUnitHasSubordinates,
 
70
        status:     http.StatusInternalServerError,
 
71
        helperFunc: params.IsCodeUnitHasSubordinates,
 
72
}, {
 
73
        err:        common.ErrBadId,
 
74
        code:       params.CodeNotFound,
 
75
        status:     http.StatusNotFound,
 
76
        helperFunc: params.IsCodeNotFound,
 
77
}, {
 
78
        err:        common.NoAddressSetError(names.NewUnitTag("mysql/0"), "public"),
 
79
        code:       params.CodeNoAddressSet,
 
80
        status:     http.StatusInternalServerError,
 
81
        helperFunc: params.IsCodeNoAddressSet,
 
82
}, {
 
83
        err:        common.ErrBadCreds,
 
84
        code:       params.CodeUnauthorized,
 
85
        status:     http.StatusUnauthorized,
 
86
        helperFunc: params.IsCodeUnauthorized,
 
87
}, {
 
88
        err:        common.ErrPerm,
 
89
        code:       params.CodeUnauthorized,
 
90
        status:     http.StatusUnauthorized,
 
91
        helperFunc: params.IsCodeUnauthorized,
 
92
}, {
 
93
        err:        common.ErrNotLoggedIn,
 
94
        code:       params.CodeUnauthorized,
 
95
        status:     http.StatusUnauthorized,
 
96
        helperFunc: params.IsCodeUnauthorized,
 
97
}, {
 
98
        err:        errors.NotProvisionedf("machine 0"),
 
99
        code:       params.CodeNotProvisioned,
 
100
        status:     http.StatusInternalServerError,
 
101
        helperFunc: params.IsCodeNotProvisioned,
 
102
}, {
 
103
        err:        errors.AlreadyExistsf("blah"),
 
104
        code:       params.CodeAlreadyExists,
 
105
        status:     http.StatusInternalServerError,
 
106
        helperFunc: params.IsCodeAlreadyExists,
 
107
}, {
 
108
        err:        common.ErrUnknownWatcher,
 
109
        code:       params.CodeNotFound,
 
110
        status:     http.StatusNotFound,
 
111
        helperFunc: params.IsCodeNotFound,
 
112
}, {
 
113
        err:        errors.NotAssignedf("unit mysql/0"),
 
114
        code:       params.CodeNotAssigned,
 
115
        status:     http.StatusInternalServerError,
 
116
        helperFunc: params.IsCodeNotAssigned,
 
117
}, {
 
118
        err:        common.ErrStoppedWatcher,
 
119
        code:       params.CodeStopped,
 
120
        status:     http.StatusInternalServerError,
 
121
        helperFunc: params.IsCodeStopped,
 
122
}, {
 
123
        err:        &state.HasAssignedUnitsError{"42", []string{"a"}},
 
124
        code:       params.CodeHasAssignedUnits,
 
125
        status:     http.StatusInternalServerError,
 
126
        helperFunc: params.IsCodeHasAssignedUnits,
 
127
}, {
 
128
        err:        common.ErrTryAgain,
 
129
        code:       params.CodeTryAgain,
 
130
        status:     http.StatusInternalServerError,
 
131
        helperFunc: params.IsCodeTryAgain,
 
132
}, {
 
133
        err:        leadership.ErrClaimDenied,
 
134
        code:       params.CodeLeadershipClaimDenied,
 
135
        status:     http.StatusInternalServerError,
 
136
        helperFunc: params.IsCodeLeadershipClaimDenied,
 
137
}, {
 
138
        err:        lease.ErrClaimDenied,
 
139
        code:       params.CodeLeaseClaimDenied,
 
140
        status:     http.StatusInternalServerError,
 
141
        helperFunc: params.IsCodeLeaseClaimDenied,
 
142
}, {
 
143
        err:        common.OperationBlockedError("test"),
 
144
        code:       params.CodeOperationBlocked,
 
145
        status:     http.StatusBadRequest,
 
146
        helperFunc: params.IsCodeOperationBlocked,
 
147
}, {
 
148
        err:        errors.NotSupportedf("needed feature"),
 
149
        code:       params.CodeNotSupported,
 
150
        status:     http.StatusInternalServerError,
 
151
        helperFunc: params.IsCodeNotSupported,
 
152
}, {
 
153
        err:        errors.BadRequestf("something"),
 
154
        code:       params.CodeBadRequest,
 
155
        status:     http.StatusBadRequest,
 
156
        helperFunc: params.IsBadRequest,
 
157
}, {
 
158
        err:        errors.MethodNotAllowedf("something"),
 
159
        code:       params.CodeMethodNotAllowed,
 
160
        status:     http.StatusMethodNotAllowed,
 
161
        helperFunc: params.IsMethodNotAllowed,
 
162
}, {
 
163
        err:    stderrors.New("an error"),
 
164
        status: http.StatusInternalServerError,
 
165
        code:   "",
 
166
}, {
 
167
        err: &common.DischargeRequiredError{
 
168
                Cause:    errors.New("something"),
 
169
                Macaroon: sampleMacaroon,
 
170
        },
 
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 {
 
176
                        return false
 
177
                }
 
178
                return true
 
179
        },
 
180
}, {
 
181
        err:    unhashableError{"foo"},
 
182
        status: http.StatusInternalServerError,
 
183
        code:   "",
 
184
}, {
 
185
        err:        common.UnknownModelError("dead-beef-123456"),
 
186
        code:       params.CodeNotFound,
 
187
        status:     http.StatusNotFound,
 
188
        helperFunc: params.IsCodeNotFound,
 
189
}, {
 
190
        err:    nil,
 
191
        code:   "",
 
192
        status: http.StatusOK,
 
193
}}
 
194
 
 
195
var sampleMacaroon = func() *macaroon.Macaroon {
 
196
        m, err := macaroon.New([]byte("key"), "id", "loc")
 
197
        if err != nil {
 
198
                panic(err)
 
199
        }
 
200
        return m
 
201
}()
 
202
 
 
203
type unhashableError []string
 
204
 
 
205
func (err unhashableError) Error() string {
 
206
        return err[0]
 
207
}
 
208
 
 
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)
 
213
 
 
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)
 
218
 
 
219
                if t.err == nil {
 
220
                        c.Assert(err1, gc.IsNil)
 
221
                        c.Assert(status, gc.Equals, http.StatusOK)
 
222
                        continue
 
223
                }
 
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)
 
228
                }
 
229
 
 
230
                // TODO(ericsnow) Remove this switch once the other error types are supported.
 
231
                switch t.code {
 
232
                case params.CodeHasAssignedUnits,
 
233
                        params.CodeNoAddressSet,
 
234
                        params.CodeUpgradeInProgress,
 
235
                        params.CodeMachineHasAttachedStorage,
 
236
                        params.CodeDischargeRequired:
 
237
                        continue
 
238
                case params.CodeNotFound:
 
239
                        if common.IsUnknownModelError(t.err) {
 
240
                                continue
 
241
                        }
 
242
                case params.CodeOperationBlocked:
 
243
                        // ServerError doesn't actually have a case for this code.
 
244
                        continue
 
245
                }
 
246
 
 
247
                c.Logf("  checking restore (%#v)", err1)
 
248
                restored := api.RestoreError(err1)
 
249
                if t.err == nil {
 
250
                        c.Check(restored, jc.ErrorIsNil)
 
251
                } else if t.code == "" {
 
252
                        c.Check(restored.Error(), gc.Equals, t.err.Error())
 
253
                } else {
 
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())
 
257
                }
 
258
        }
 
259
}