22// Node module: @loopback /http-server
33// This file is licensed under the MIT License.
44// License text available at https://opensource.org/licenses/MIT
5- import { HttpServer } from '../../' ;
5+ import { HttpServer , HttpOptions , HttpServerOptions } from '../../' ;
66import { supertest , expect } from '@loopback/testlab' ;
77import * as makeRequest from 'request-promise-native' ;
88import { ServerRequest , ServerResponse , get , IncomingMessage } from 'http' ;
9+ import * as https from 'https' ;
10+ import * as path from 'path' ;
11+ import * as fs from 'fs' ;
12+ import * as url from 'url' ;
913
1014describe ( 'HttpServer (integration)' , ( ) => {
1115 let server : HttpServer | undefined ;
1216
1317 afterEach ( stopServer ) ;
1418
15- process . env . TRAVIS
16- ? // tslint:disable-next-line:no-unused-expression
17- it . skip
18- : it ( 'formats IPv6 url correctly' , async ( ) => {
19- server = new HttpServer ( dummyRequestHandler , { host : '::1' } ) ;
20- await server . start ( ) ;
21- expect ( server . address ! . family ) . to . equal ( 'IPv6' ) ;
22- const response = await getAsync ( server . url ) ;
23- expect ( response . statusCode ) . to . equal ( 200 ) ;
24- } ) ;
19+ itSkippedOnTravis ( 'formats IPv6 url correctly' , async ( ) => {
20+ server = new HttpServer ( dummyRequestHandler , {
21+ host : '::1' ,
22+ } as HttpOptions ) ;
23+ await server . start ( ) ;
24+ expect ( server . address ! . family ) . to . equal ( 'IPv6' ) ;
25+ const response = await getAsync ( server . url ) ;
26+ expect ( response . statusCode ) . to . equal ( 200 ) ;
27+ } ) ;
2528
2629 it ( 'starts server' , async ( ) => {
27- server = new HttpServer ( dummyRequestHandler ) ;
30+ const serverOptions = givenServerOptions ( ) ;
31+ server = new HttpServer ( dummyRequestHandler , serverOptions ) ;
2832 await server . start ( ) ;
29- supertest ( server . url )
33+ await supertest ( server . url )
3034 . get ( '/' )
3135 . expect ( 200 ) ;
3236 } ) ;
3337
3438 it ( 'stops server' , async ( ) => {
35- // Explicitly setting host to IPv4 address so test runs on Travis
36- server = new HttpServer ( dummyRequestHandler , { host : '127.0.0.1' } ) ;
39+ const serverOptions = givenServerOptions ( ) ;
40+ server = new HttpServer ( dummyRequestHandler , serverOptions ) ;
3741 await server . start ( ) ;
3842 await server . stop ( ) ;
3943 await expect (
@@ -122,7 +126,7 @@ describe('HttpServer (integration)', () => {
122126 expect ( server . address ) . to . be . undefined ( ) ;
123127 } ) ;
124128
125- it ( 'exports started ' , async ( ) => {
129+ it ( 'exports listening ' , async ( ) => {
126130 server = new HttpServer ( dummyRequestHandler ) ;
127131 await server . start ( ) ;
128132 expect ( server . listening ) . to . be . true ( ) ;
@@ -134,8 +138,38 @@ describe('HttpServer (integration)', () => {
134138 server = new HttpServer ( dummyRequestHandler ) ;
135139 await server . start ( ) ;
136140 const port = server . port ;
137- const anotherServer = new HttpServer ( dummyRequestHandler , { port : port } ) ;
138- expect ( anotherServer . start ( ) ) . to . be . rejectedWith ( / E A D D R I N U S E / ) ;
141+ const anotherServer = new HttpServer ( dummyRequestHandler , {
142+ port : port ,
143+ } ) ;
144+ await expect ( anotherServer . start ( ) ) . to . be . rejectedWith ( / E A D D R I N U S E / ) ;
145+ } ) ;
146+
147+ it ( 'supports HTTPS protocol with key and certificate files' , async ( ) => {
148+ const serverOptions = givenServerOptions ( ) ;
149+ const httpsServer : HttpServer = givenHttpsServer ( serverOptions ) ;
150+ await httpsServer . start ( ) ;
151+ const response = await httpsGetAsync ( httpsServer . url ) ;
152+ expect ( response . statusCode ) . to . equal ( 200 ) ;
153+ } ) ;
154+
155+ it ( 'supports HTTPS protocol with a pfx file' , async ( ) => {
156+ const options = { usePfx : true } ;
157+ const serverOptions = givenServerOptions ( ) ;
158+ Object . assign ( serverOptions , options ) ;
159+ const httpsServer : HttpServer = givenHttpsServer ( serverOptions ) ;
160+ await httpsServer . start ( ) ;
161+ const response = await httpsGetAsync ( httpsServer . url ) ;
162+ expect ( response . statusCode ) . to . equal ( 200 ) ;
163+ } ) ;
164+
165+ itSkippedOnTravis ( 'handles IPv6 loopback address in HTTPS' , async ( ) => {
166+ const httpsServer : HttpServer = givenHttpsServer ( {
167+ host : '::1' ,
168+ } ) ;
169+ await httpsServer . start ( ) ;
170+ expect ( httpsServer . address ! . family ) . to . equal ( 'IPv6' ) ;
171+ const response = await httpsGetAsync ( httpsServer . url ) ;
172+ expect ( response . statusCode ) . to . equal ( 200 ) ;
139173 } ) ;
140174
141175 function dummyRequestHandler ( req : ServerRequest , res : ServerResponse ) : void {
@@ -147,9 +181,67 @@ describe('HttpServer (integration)', () => {
147181 await server . stop ( ) ;
148182 }
149183
150- function getAsync ( url : string ) : Promise < IncomingMessage > {
184+ function getAsync ( urlString : string ) : Promise < IncomingMessage > {
185+ return new Promise ( ( resolve , reject ) => {
186+ get ( urlString , resolve ) . on ( 'error' , reject ) ;
187+ } ) ;
188+ }
189+
190+ function givenHttpsServer ( {
191+ usePfx,
192+ host,
193+ } : {
194+ usePfx ?: boolean ;
195+ host ?: string ;
196+ } ) : HttpServer {
197+ const options : HttpServerOptions = { protocol : 'https' , host} ;
198+ if ( usePfx ) {
199+ const pfxPath = path . join ( __dirname , 'pfx.pfx' ) ;
200+ options . pfx = fs . readFileSync ( pfxPath ) ;
201+ options . passphrase = 'loopback4' ;
202+ } else {
203+ const keyPath = path . join ( __dirname , 'key.pem' ) ;
204+ const certPath = path . join ( __dirname , 'cert.pem' ) ;
205+ options . key = fs . readFileSync ( keyPath ) ;
206+ options . cert = fs . readFileSync ( certPath ) ;
207+ }
208+ return new HttpServer ( dummyRequestHandler , options ) ;
209+ }
210+
211+ function httpsGetAsync ( urlString : string ) : Promise < IncomingMessage > {
212+ const agent = new https . Agent ( {
213+ rejectUnauthorized : false ,
214+ } ) ;
215+
216+ const urlOptions = url . parse ( urlString ) ;
217+ const options = { agent, ...urlOptions } ;
218+
151219 return new Promise ( ( resolve , reject ) => {
152- get ( url , resolve ) . on ( 'error' , reject ) ;
220+ https . get ( options , resolve ) . on ( 'error' , reject ) ;
153221 } ) ;
154222 }
223+
224+ function givenServerOptions (
225+ options : Partial < HttpServerOptions > = { } ,
226+ ) : HttpServerOptions {
227+ const defaults = process . env . TRAVIS ? { host : '127.0.0.1' } : { } ;
228+ return Object . assign ( defaults , options ) ;
229+ }
230+
231+ // tslint:disable-next-line:no-any
232+ type TestCallbackRetval = void | PromiseLike < any > ;
233+
234+ function itSkippedOnTravis (
235+ expectation : string ,
236+ callback ?: (
237+ this : Mocha . ITestCallbackContext ,
238+ done : MochaDone ,
239+ ) => TestCallbackRetval ,
240+ ) : void {
241+ if ( process . env . TRAVIS ) {
242+ it . skip ( `[SKIPPED ON TRAVIS] ${ expectation } ` , callback ) ;
243+ } else {
244+ it ( expectation , callback ) ;
245+ }
246+ }
155247} ) ;
0 commit comments