44/* eslint-disable func-names */
55
66var restifyClients = require ( 'restify-clients' ) ;
7+ var errors = require ( 'restify-errors' ) ;
8+ var sinon = require ( 'sinon' ) ;
79
810var restify = require ( '../lib' ) ;
11+ var jsonFormatter = require ( '../lib/formatters/json' ) ;
912
1013if ( require . cache [ __dirname + '/lib/helper.js' ] ) {
1114 delete require . cache [ __dirname + '/lib/helper.js' ] ;
@@ -36,6 +39,9 @@ before(function(callback) {
3639 // this is a bad formatter, on purpose.
3740 return x . toString ( ) ; // eslint-disable-line no-undef
3841 } ,
42+ 'text/syncerror_expected' : function ( req , res , body ) {
43+ throw new errors . InternalServerError ( 'Errors happen' ) ;
44+ } ,
3945 'application/foo; q=0.9' : function ( req , res , body ) {
4046 return 'foo!' ;
4147 } ,
@@ -108,7 +114,7 @@ test('GH-845: sync formatter', function(t) {
108114} ) ;
109115
110116test ( 'GH-845: sync formatter should blow up' , function ( t ) {
111- SERVER . on ( 'uncaughtException' , function ( req , res , route , err ) {
117+ SERVER . once ( 'uncaughtException' , function ( req , res , route , err ) {
112118 t . ok ( err ) ;
113119 t . equal ( err . name , 'ReferenceError' ) ;
114120 t . equal ( err . message , 'x is not defined' ) ;
@@ -130,6 +136,29 @@ test('GH-845: sync formatter should blow up', function(t) {
130136 ) ;
131137} ) ;
132138
139+ test ( 'sync formatter should handle expected errors gracefully' , function ( t ) {
140+ SERVER . once ( 'uncaughtException' , function ( req , res , route , err ) {
141+ throw new Error ( 'Should not reach' ) ;
142+ } ) ;
143+
144+ CLIENT . get (
145+ {
146+ path : '/sync' ,
147+ headers : {
148+ accept : 'text/syncerror_expected'
149+ }
150+ } ,
151+ function ( err , req , res , data ) {
152+ t . ok ( err ) ;
153+ t . ok ( req ) ;
154+ t . ok ( res ) ;
155+ t . equal ( res . statusCode , 500 ) ;
156+ SERVER . removeAllListeners ( 'uncaughtException' ) ;
157+ t . end ( ) ;
158+ }
159+ ) ;
160+ } ) ;
161+
133162test ( 'q-val priority' , function ( t ) {
134163 var opts = {
135164 path : '/sync' ,
@@ -228,3 +257,43 @@ test('default jsonp formatter should escape line and paragraph separators', func
228257 t . end ( ) ;
229258 } ) ;
230259} ) ;
260+
261+ // eslint-disable-next-line
262+ test ( 'default json formatter should wrap & throw InternalServer error on unserializable bodies' , function ( t ) {
263+ t . expect ( 2 ) ;
264+
265+ sinon . spy ( JSON , 'stringify' ) ;
266+
267+ SERVER . once ( 'uncaughtException' , function ( req , res , route , err ) {
268+ console . log ( err . stack ) ; // For convenience
269+ throw new Error ( 'Should not reach' ) ;
270+ } ) ;
271+
272+ var opts = {
273+ path : '/badJSON' ,
274+ name : 'badJSON'
275+ } ;
276+
277+ SERVER . get ( opts , function ( req , res , next ) {
278+ var body = { } ;
279+ // Add unserializable circular reference
280+ body . body = body ;
281+
282+ try {
283+ jsonFormatter ( req , res , body ) ;
284+ throw new Error ( 'Should not reach' ) ;
285+ } catch ( e ) {
286+ t . ok ( e instanceof errors . InternalServerError ) ;
287+ t . ok ( JSON . stringify . threw ( e . cause ( ) ) ) ;
288+ }
289+
290+ res . send ( ) ;
291+ } ) ;
292+
293+ CLIENT . get ( '/badJSON' , function ( err , req , res , data ) {
294+ SERVER . rm ( 'badJSON' ) ;
295+ SERVER . removeAllListeners ( 'uncaughtException' ) ;
296+ JSON . stringify . restore ( ) ;
297+ t . end ( ) ;
298+ } ) ;
299+ } ) ;
0 commit comments