hmpo-model 4.0.1 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/model-error.js +51 -0
- package/lib/remote-model.js +11 -11
- package/package.json +1 -1
- package/test/lib/spec.remote-model.js +61 -13
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
class ModelError extends Error {
|
|
3
|
+
constructor(e) {
|
|
4
|
+
super(e);
|
|
5
|
+
Object.defineProperties(this, {
|
|
6
|
+
original: {
|
|
7
|
+
value: e,
|
|
8
|
+
enumerable: false,
|
|
9
|
+
writable: false,
|
|
10
|
+
configurable: true,
|
|
11
|
+
},
|
|
12
|
+
name: {
|
|
13
|
+
value: e.name,
|
|
14
|
+
enumerable: false,
|
|
15
|
+
writable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
},
|
|
18
|
+
code: {
|
|
19
|
+
value: e.code,
|
|
20
|
+
enumerable: false,
|
|
21
|
+
writable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
},
|
|
24
|
+
errno: {
|
|
25
|
+
value: e.errno,
|
|
26
|
+
enumerable: false,
|
|
27
|
+
writable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
},
|
|
30
|
+
info: {
|
|
31
|
+
get: () => this.original.info,
|
|
32
|
+
enumerable: false,
|
|
33
|
+
configurable: true
|
|
34
|
+
},
|
|
35
|
+
stack: {
|
|
36
|
+
get: () => this.original.stack,
|
|
37
|
+
enumerable: false,
|
|
38
|
+
configurable: true
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
this.code = e.code;
|
|
42
|
+
|
|
43
|
+
if (this.code === 'ETIMEDOUT') {
|
|
44
|
+
this.message = 'Connection timed out';
|
|
45
|
+
this.status = 504;
|
|
46
|
+
}
|
|
47
|
+
this.status = this.status || (e.response && e.response.statusCode) || 503;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = ModelError;
|
package/lib/remote-model.js
CHANGED
|
@@ -5,6 +5,7 @@ const LocalModel = require('./local-model');
|
|
|
5
5
|
const got = require('got');
|
|
6
6
|
const kebabCase = require('lodash.kebabcase');
|
|
7
7
|
const { URL } = require('url');
|
|
8
|
+
const ModelError = require('./model-error');
|
|
8
9
|
|
|
9
10
|
const DEFAULT_TIMEOUT = 60000;
|
|
10
11
|
|
|
@@ -174,20 +175,19 @@ class RemoteModel extends LocalModel {
|
|
|
174
175
|
};
|
|
175
176
|
|
|
176
177
|
this.got(settings)
|
|
177
|
-
.catch(err => {
|
|
178
|
-
debug('request got error', err);
|
|
179
|
-
setResponseTime();
|
|
180
|
-
if (err.code === 'ETIMEDOUT') {
|
|
181
|
-
err.message = 'Connection timed out';
|
|
182
|
-
err.status = 504;
|
|
183
|
-
}
|
|
184
|
-
err.status = err.status || (err.response && err.response.statusCode) || 503;
|
|
185
|
-
return _callback(err, null, err.status, err.response);
|
|
186
|
-
})
|
|
187
178
|
.then(response => {
|
|
188
179
|
debug('request got response', response);
|
|
189
180
|
setResponseTime();
|
|
190
181
|
this.handleResponse(response, _callback);
|
|
182
|
+
})
|
|
183
|
+
.catch(err => {
|
|
184
|
+
setResponseTime();
|
|
185
|
+
if (err.code === 'ERR_NON_2XX_3XX_RESPONSE' && err.response) {
|
|
186
|
+
return this.handleResponse(err.response, _callback);
|
|
187
|
+
}
|
|
188
|
+
err = new ModelError(err);
|
|
189
|
+
debug('request got error', err);
|
|
190
|
+
_callback(err, null, err.status);
|
|
191
191
|
});
|
|
192
192
|
}
|
|
193
193
|
|
|
@@ -199,7 +199,7 @@ class RemoteModel extends LocalModel {
|
|
|
199
199
|
} catch (err) {
|
|
200
200
|
err.status = response.statusCode;
|
|
201
201
|
err.body = response.body;
|
|
202
|
-
return callback(err, null,
|
|
202
|
+
return callback(err, null, err.status);
|
|
203
203
|
}
|
|
204
204
|
this.parseResponse(response.statusCode, data, callback);
|
|
205
205
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const Model = require('../../lib/remote-model');
|
|
4
|
+
const ModelError = require('../../lib/model-error');
|
|
4
5
|
const BaseModel = require('../../lib/local-model');
|
|
5
6
|
const logger = require('hmpo-logger');
|
|
6
7
|
|
|
@@ -649,9 +650,16 @@ describe('Remote Model', () => {
|
|
|
649
650
|
settings: settings,
|
|
650
651
|
statusCode: 418,
|
|
651
652
|
responseTime: sinon.match.number,
|
|
652
|
-
err:
|
|
653
|
+
err: sinon.match.instanceOf(ModelError),
|
|
653
654
|
data: null
|
|
654
655
|
});
|
|
656
|
+
model.logError.args[0][0].err.should.include({
|
|
657
|
+
name: 'Error',
|
|
658
|
+
message: 'Error: Lorem Ipsum',
|
|
659
|
+
status: 418,
|
|
660
|
+
info: undefined,
|
|
661
|
+
});
|
|
662
|
+
model.logError.args[0][0].err.stack.should.be.a('string');
|
|
655
663
|
});
|
|
656
664
|
|
|
657
665
|
it('should emit a fail event', () => {
|
|
@@ -659,15 +667,17 @@ describe('Remote Model', () => {
|
|
|
659
667
|
|
|
660
668
|
model.emit.should.have.been.calledWithExactly(
|
|
661
669
|
'fail',
|
|
662
|
-
sinon.match(
|
|
663
|
-
message: error.message,
|
|
664
|
-
status: 418
|
|
665
|
-
}),
|
|
670
|
+
sinon.match.instanceOf(ModelError),
|
|
666
671
|
null,
|
|
667
672
|
settings,
|
|
668
673
|
418,
|
|
669
674
|
sinon.match.number
|
|
670
675
|
);
|
|
676
|
+
model.emit.args[1][1].should.include({
|
|
677
|
+
name: 'Error',
|
|
678
|
+
message: 'Error: Lorem Ipsum',
|
|
679
|
+
status: 418,
|
|
680
|
+
});
|
|
671
681
|
});
|
|
672
682
|
|
|
673
683
|
it('should translate timeout errors with status codes', () => {
|
|
@@ -679,11 +689,14 @@ describe('Remote Model', () => {
|
|
|
679
689
|
settings: settings,
|
|
680
690
|
statusCode: 504,
|
|
681
691
|
responseTime: sinon.match.number,
|
|
682
|
-
err: sinon.match(
|
|
683
|
-
message: 'Connection timed out'
|
|
684
|
-
}),
|
|
692
|
+
err: sinon.match.instanceOf(ModelError),
|
|
685
693
|
data: null
|
|
686
694
|
});
|
|
695
|
+
model.logError.args[0][0].err.should.include({
|
|
696
|
+
name: 'Error',
|
|
697
|
+
message: 'Connection timed out',
|
|
698
|
+
status: 504
|
|
699
|
+
});
|
|
687
700
|
});
|
|
688
701
|
|
|
689
702
|
it('should translate errors without status codes', () => {
|
|
@@ -695,12 +708,14 @@ describe('Remote Model', () => {
|
|
|
695
708
|
settings: settings,
|
|
696
709
|
statusCode: 503,
|
|
697
710
|
responseTime: sinon.match.number,
|
|
698
|
-
err: sinon.match(
|
|
699
|
-
message: error.message,
|
|
700
|
-
status: 503,
|
|
701
|
-
}),
|
|
711
|
+
err: sinon.match.instanceOf(ModelError),
|
|
702
712
|
data: null
|
|
703
713
|
});
|
|
714
|
+
model.logError.args[0][0].err.should.include({
|
|
715
|
+
name: 'Error',
|
|
716
|
+
message: 'Error: Lorem Ipsum',
|
|
717
|
+
status: 503
|
|
718
|
+
});
|
|
704
719
|
});
|
|
705
720
|
|
|
706
721
|
it('should fire fail hook', () => {
|
|
@@ -713,11 +728,44 @@ describe('Remote Model', () => {
|
|
|
713
728
|
settings: settings,
|
|
714
729
|
statusCode: 418,
|
|
715
730
|
responseTime: sinon.match.number,
|
|
716
|
-
err:
|
|
731
|
+
err: sinon.match.instanceOf(ModelError),
|
|
717
732
|
data: null
|
|
718
733
|
});
|
|
719
734
|
hook.should.have.been.calledOn(model);
|
|
720
735
|
});
|
|
736
|
+
|
|
737
|
+
it('should handle response for ERR_NON_2XX_3XX_RESPONSE errors', () => {
|
|
738
|
+
error.code = 'ERR_NON_2XX_3XX_RESPONSE';
|
|
739
|
+
error.response = {
|
|
740
|
+
'body': JSON.stringify({'data': 'value'}),
|
|
741
|
+
'statusCode': 404
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
model.request(settings, cb);
|
|
745
|
+
console.log(model.logError.args[0][0]);
|
|
746
|
+
model.logError.should.have.been.calledWithExactly({
|
|
747
|
+
settings: settings,
|
|
748
|
+
statusCode: 404,
|
|
749
|
+
responseTime: sinon.match.number,
|
|
750
|
+
err: {
|
|
751
|
+
status: 404,
|
|
752
|
+
data: 'value'
|
|
753
|
+
},
|
|
754
|
+
data: { data: 'value' }
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
cb.should.have.been.calledWithExactly(
|
|
758
|
+
{
|
|
759
|
+
status: 404,
|
|
760
|
+
data: 'value'
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
data: 'value'
|
|
764
|
+
},
|
|
765
|
+
sinon.match.number
|
|
766
|
+
);
|
|
767
|
+
});
|
|
768
|
+
|
|
721
769
|
});
|
|
722
770
|
|
|
723
771
|
context('on success', () => {
|