1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | 'use strict'
|
33 |
|
34 | const Test = require('tape')
|
35 | const Boom = require('@hapi/boom')
|
36 | const Factory = require('../src/factory')
|
37 | const Enums = require('../src/enums')
|
38 | const Handler = require('../src/handler')
|
39 | const Proxyquire = require('proxyquire')
|
40 | const Sinon = require('sinon')
|
41 |
|
42 | Test('Handler should', handlerTest => {
|
43 | handlerTest.test('handle non error responses', async function (test) {
|
44 | const response = {}
|
45 | test.ok(Handler.onPreResponse({ response: response }, { continue: true }))
|
46 | test.end()
|
47 | })
|
48 |
|
49 | handlerTest.test('handle FSPIOPError responses', async function (test) {
|
50 | const fspiopError = Factory.createFSPIOPError(Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, 'Internal Error')
|
51 | const response = fspiopError
|
52 | test.ok(Handler.onPreResponse({ response: response }, { continue: true }))
|
53 | test.equal(response.output.statusCode, 500)
|
54 | test.equal(response.output.payload.errorInformation.errorCode, '2001')
|
55 | test.equal(response.output.payload.errorInformation.errorDescription, 'Internal server error - Internal Error')
|
56 | test.end()
|
57 | })
|
58 |
|
59 | handlerTest.test('handle FSPIOPError with undefined httpStatusCode', async function (test) {
|
60 | const fspiopError = Factory.createFSPIOPError(Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, 'Internal Error without httpStatusCode')
|
61 | delete fspiopError.httpStatusCode
|
62 | const response = fspiopError
|
63 | test.ok(Handler.onPreResponse({ response: response }, { continue: true }))
|
64 | test.equal(response.output.statusCode, 500)
|
65 | test.equal(response.output.payload.errorInformation.errorCode, '2001')
|
66 | test.equal(response.output.payload.errorInformation.errorDescription, 'Internal server error - Internal Error without httpStatusCode')
|
67 | test.end()
|
68 | })
|
69 |
|
70 | handlerTest.test('handle generic Error responses', async function (test) {
|
71 | const error = new Error('Test Error')
|
72 | const response = error
|
73 | test.ok(Handler.onPreResponse({ response: response }, { continue: true }))
|
74 | test.equal(response.output.statusCode, 500)
|
75 | test.equal(response.output.payload.errorInformation.errorCode, '2001')
|
76 | test.equal(response.output.payload.errorInformation.errorDescription, 'Internal server error - Test Error')
|
77 | test.end()
|
78 | })
|
79 |
|
80 | handlerTest.test('handle Boom errors', async function (test) {
|
81 | const response = {
|
82 | isBoom: true,
|
83 | output:
|
84 | {
|
85 | payload:
|
86 | {
|
87 | error: 'BadRequest'
|
88 | }
|
89 | }
|
90 | }
|
91 | Handler.onPreResponse({ response: response, headers: { 'fspiop-source': 'dfsp1' } }, {})
|
92 | test.equal(response.output.payload.errorInformation.errorCode, '2001')
|
93 | test.end()
|
94 | })
|
95 |
|
96 | handlerTest.test('handle Boom generated errors', async function (test) {
|
97 | const response = Boom.badRequest('some bad parameters')
|
98 |
|
99 | Handler.onPreResponse({ response }, {})
|
100 | test.equal(response.output.statusCode, 400)
|
101 | test.equal(response.output.payload.errorInformation.errorCode, '3000')
|
102 | test.equal(response.output.payload.errorInformation.errorDescription, 'Generic client error - some bad parameters')
|
103 | test.end()
|
104 | })
|
105 |
|
106 | handlerTest.test('handle a Boom 404 error', async function (test) {
|
107 | const response = {
|
108 | isBoom: true,
|
109 | output:
|
110 | {
|
111 | statusCode: 404,
|
112 | payload:
|
113 | {
|
114 | error: 'BadRequest'
|
115 | },
|
116 | headers: {
|
117 | Allow: 'get'
|
118 | }
|
119 | },
|
120 | message: 'Not Found'
|
121 | }
|
122 |
|
123 | const request = {
|
124 | path: '/noMatchingUrl/1357902468/vlkdfnvfdvnkj/vcjknsdjcnsj',
|
125 | server: {},
|
126 | response: response
|
127 | }
|
128 |
|
129 | request.server.table = function () {
|
130 | return [{ method: 'get', path: '/XXXX' }]
|
131 | }
|
132 |
|
133 | request.server.match = function (server, path) {
|
134 | return null
|
135 | }
|
136 |
|
137 | const reply = {
|
138 | continue: 123
|
139 | }
|
140 |
|
141 | Handler.onPreResponse(request, reply)
|
142 | test.equal(response.output.statusCode, 404)
|
143 | test.equal(response.output.payload.errorInformation.errorCode, '3002')
|
144 | test.equal(response.output.payload.errorInformation.errorDescription, 'Unknown URI - Not Found')
|
145 | test.end()
|
146 | })
|
147 |
|
148 | handlerTest.test('handle a Boom 405 error', async function (test) {
|
149 | const response = {
|
150 | message: '',
|
151 | output: {
|
152 | statusCode: 404,
|
153 | headers: {
|
154 | Allow: 'get'
|
155 | }
|
156 | }
|
157 | }
|
158 |
|
159 | const request = {
|
160 | path: '/authorizations/1357902468',
|
161 | server: {}
|
162 | }
|
163 |
|
164 | request.server.table = function () {
|
165 | return [{ method: 'get', path: '/authorizations/{ID}' }]
|
166 | }
|
167 |
|
168 | request.server.match = function (server, path) {
|
169 | return {}
|
170 | }
|
171 |
|
172 | const handlerResult = Handler.createFSPIOPErrorFromErrorResponse(request, response)
|
173 | test.equal(handlerResult.apiErrorCode.code, '3000')
|
174 | test.equal(handlerResult.apiErrorCode.message, 'Generic client error - Method Not Allowed')
|
175 | test.equal(handlerResult.apiErrorCode.httpStatusCode, 405)
|
176 |
|
177 | let matches = [{ method: 'get' }]
|
178 |
|
179 | let allowedHeaderValues = Handler.getAllowHeaders(matches)
|
180 | test.equal(allowedHeaderValues, 'get')
|
181 |
|
182 | request.server.table = function () {
|
183 | return [{ method: 'get', path: '/authorizations/{ID}' },
|
184 | { method: 'put', path: '/authorizations/{ID}' },
|
185 | { method: 'post', path: '/authorizationsXX/{ID}' }]
|
186 | }
|
187 |
|
188 | matches = [{ method: 'get' }, { method: 'put' }]
|
189 |
|
190 | allowedHeaderValues = Handler.getAllowHeaders(matches)
|
191 | test.equal(allowedHeaderValues, 'get,put')
|
192 | test.end()
|
193 | })
|
194 |
|
195 | handlerTest.test('handle a Boom 415 error', async function (test) {
|
196 | const response = Boom.forbidden()
|
197 | response.output.statusCode = 415
|
198 |
|
199 | response.reformat()
|
200 |
|
201 | Handler.onPreResponse({ response }, {})
|
202 | test.equal(response.output.statusCode, 400)
|
203 | test.equal(response.output.payload.errorInformation.errorCode, '3101')
|
204 | test.equal(response.output.payload.errorInformation.errorDescription, 'Malformed syntax - Forbidden')
|
205 | test.end()
|
206 | })
|
207 |
|
208 | handlerTest.test('handle a Boom Generic server error', async function (test) {
|
209 | const sandbox = Sinon.createSandbox()
|
210 | const FactoryStub = {
|
211 | createFSPIOPError: sandbox.stub().returns(Factory.createFSPIOPErrorFromErrorCode('2000'))
|
212 | }
|
213 | const Handler = Proxyquire('../src/handler', {
|
214 | './factory': FactoryStub
|
215 | })
|
216 |
|
217 | const response = Boom.forbidden()
|
218 | response.output.statusCode = null
|
219 | response.reformat()
|
220 |
|
221 | Handler.onPreResponse({ response }, {})
|
222 | test.equal(response.output.statusCode, 500)
|
223 | test.equal(response.output.payload.errorInformation.errorCode, '2000')
|
224 | test.equal(response.output.payload.errorInformation.errorDescription, 'Generic server error')
|
225 | test.end()
|
226 | })
|
227 |
|
228 | handlerTest.test('handle JOI validation errors', async function (test) {
|
229 | const response = {
|
230 | isBoom: true,
|
231 | isJoi: true,
|
232 | details: [{
|
233 | message: 'Regular expression failed validation',
|
234 | type: 'string.regex.base',
|
235 | context: {
|
236 | label: 'Regular expression failed'
|
237 | }
|
238 | }]
|
239 | }
|
240 | Handler.onPreResponse({ response: response }, {})
|
241 | test.equal(response.output.payload.errorInformation.errorDescription, 'Malformed syntax - Regular expression failed validation')
|
242 | test.equal(response.output.payload.errorInformation.errorCode, '3101')
|
243 | test.end()
|
244 | })
|
245 |
|
246 | handlerTest.test('handle incoming valid mojaloop specification error code', async function (test) {
|
247 | const payload =
|
248 | {
|
249 | errorInformation:
|
250 | {
|
251 | errorCode: '5105',
|
252 | errorDescription: 'Payee transaction limit reached',
|
253 | extensionList:
|
254 | {
|
255 | extension:
|
256 | [{
|
257 | key: 'errorDetail',
|
258 | value: 'This is an abort extension'
|
259 | }]
|
260 | }
|
261 | }
|
262 | }
|
263 | test.equal(Handler.validateIncomingErrorCode({ payload: payload }, { continue: payload }), payload)
|
264 | test.end()
|
265 | })
|
266 |
|
267 | handlerTest.test('handle incoming valid mojaloop specification error code, with a specific error above 39 which can be used for scheme-specific errors', async function (test) {
|
268 | const payload =
|
269 | {
|
270 | errorInformation:
|
271 | {
|
272 | errorCode: '5199',
|
273 | errorDescription: 'Payee transaction limit reached',
|
274 | extensionList:
|
275 | {
|
276 | extension:
|
277 | [{
|
278 | key: 'errorDetail',
|
279 | value: 'This is an abort extension'
|
280 | }]
|
281 | }
|
282 | }
|
283 | }
|
284 | test.equal(Handler.validateIncomingErrorCode({ payload: payload }, { continue: payload }), payload)
|
285 | test.end()
|
286 | })
|
287 |
|
288 | handlerTest.test('handle incoming mojaloop specification error code with invalid category', async function (test) {
|
289 | const payload =
|
290 | {
|
291 | errorInformation:
|
292 | {
|
293 | errorCode: '15105',
|
294 | errorDescription: 'Payee transaction limit reached',
|
295 | extensionList:
|
296 | {
|
297 | extension:
|
298 | [{
|
299 | key: 'errorDetail',
|
300 | value: 'This is an abort extension'
|
301 | }]
|
302 | }
|
303 | }
|
304 | }
|
305 |
|
306 | const takeoverMessage =
|
307 | {
|
308 | errorInformation: {
|
309 | errorCode: '3100',
|
310 | errorDescription: 'Generic validation error - The incoming error code: 15105 is not a valid mojaloop specification error code'
|
311 | }
|
312 | }
|
313 |
|
314 | const h = {
|
315 | response: () => {
|
316 | return {
|
317 | code: () => {
|
318 | return {
|
319 | takeover: () => { return takeoverMessage }
|
320 | }
|
321 | }
|
322 | }
|
323 | }
|
324 | }
|
325 |
|
326 | test.equal(Handler.validateIncomingErrorCode({ payload: payload }, h), takeoverMessage)
|
327 | test.end()
|
328 | })
|
329 | handlerTest.end()
|
330 | })
|