11import { ProviderError } from "@smithy/property-provider" ;
2- import { createServer } from "http" ;
3- import nock from "nock" ;
4- import { afterEach , beforeAll , describe , expect , test as it , vi } from "vitest" ;
2+ import { afterEach , describe , expect , test as it , vi } from "vitest" ;
53
64import { httpRequest } from "./httpRequest" ;
75
6+ vi . mock ( "http" , async ( ) => {
7+ const actual : any = vi . importActual ( "http" ) ;
8+
9+ const pkg = {
10+ ...actual ,
11+ request : vi . fn ( ) ,
12+ } ;
13+ return {
14+ ...pkg ,
15+ default : pkg ,
16+ } ;
17+ } ) ;
18+
19+ import EventEmitter from "events" ;
20+ import { request } from "http" ;
21+
822describe ( "httpRequest" , ( ) => {
923 let port : number ;
1024 const hostname = "localhost" ;
1125 const path = "/" ;
1226
13- const getOpenPort = async ( candidatePort = 4321 ) : Promise < number > => {
14- try {
15- return new Promise < number > ( ( resolve , reject ) => {
16- const server = createServer ( ) ;
17- server . on ( "error" , ( ) => reject ( ) ) ;
18- server . listen ( candidatePort ) ;
19- server . close ( ( ) => resolve ( candidatePort ) ) ;
20- } ) ;
21- } catch ( e ) {
22- return await getOpenPort ( candidatePort + 1 ) ;
23- }
24- } ;
25-
26- beforeAll ( async ( ) => {
27- port = await getOpenPort ( ) ;
28- } ) ;
29-
3027 afterEach ( ( ) => {
3128 vi . clearAllMocks ( ) ;
3229 } ) ;
3330
31+ function mockResponse ( { expectedResponse, statusCode = 200 } : any ) {
32+ return vi . mocked ( request ) . mockImplementationOnce ( ( ( ) => {
33+ const request = Object . assign ( new EventEmitter ( ) , {
34+ destroy : vi . fn ( ) ,
35+ end : vi . fn ( ) ,
36+ } ) ;
37+ const response = new EventEmitter ( ) as any ;
38+ response . statusCode = statusCode ;
39+ setTimeout ( ( ) => {
40+ request . emit ( "response" , response ) ;
41+ setTimeout ( ( ) => {
42+ response . emit ( "data" , Buffer . from ( expectedResponse ) ) ;
43+ response . emit ( "end" ) ;
44+ } , 50 ) ;
45+ } , 50 ) ;
46+ return request ;
47+ } ) as any ) ;
48+ }
49+
3450 describe ( "returns response" , ( ) => {
3551 it ( "defaults to method GET" , async ( ) => {
3652 const expectedResponse = "expectedResponse" ;
37- const scope = nock ( `http://${ hostname } :${ port } ` ) . get ( path ) . reply ( 200 , expectedResponse ) ;
53+
54+ mockResponse ( { expectedResponse } ) ;
3855
3956 const response = await httpRequest ( { hostname, path, port } ) ;
4057 expect ( response . toString ( ) ) . toStrictEqual ( expectedResponse ) ;
41-
42- scope . done ( ) ;
4358 } ) ;
4459
4560 it ( "uses method passed in options" , async ( ) => {
4661 const method = "POST" ;
4762 const expectedResponse = "expectedResponse" ;
48- const scope = nock ( `http:// ${ hostname } : ${ port } ` ) . post ( path ) . reply ( 200 , expectedResponse ) ;
63+ mockResponse ( { expectedResponse } ) ;
4964
5065 const response = await httpRequest ( { hostname, path, port, method } ) ;
5166 expect ( response . toString ( ) ) . toStrictEqual ( expectedResponse ) ;
52-
53- scope . done ( ) ;
5467 } ) ;
5568
5669 it ( "works with IPv6 hostname with encapsulated brackets" , async ( ) => {
5770 const expectedResponse = "expectedResponse" ;
5871 const encapsulatedIPv6Hostname = "[::1]" ;
59- const scope = nock ( `http:// ${ encapsulatedIPv6Hostname } : ${ port } ` ) . get ( path ) . reply ( 200 , expectedResponse ) ;
72+ mockResponse ( { expectedResponse } ) ;
6073
6174 const response = await httpRequest ( { hostname : encapsulatedIPv6Hostname , path, port } ) ;
6275 expect ( response . toString ( ) ) . toStrictEqual ( expectedResponse ) ;
63-
64- scope . done ( ) ;
6576 } ) ;
6677 } ) ;
6778
6879 describe ( "throws error" , ( ) => {
6980 const errorOnStatusCode = async ( statusCode : number ) => {
7081 it ( `statusCode: ${ statusCode } ` , async ( ) => {
71- const scope = nock ( `http://${ hostname } :${ port } ` ) . get ( path ) . reply ( statusCode , "continue" ) ;
82+ mockResponse ( {
83+ statusCode,
84+ expectedResponse : "continue" ,
85+ } ) ;
7286
7387 await expect ( httpRequest ( { hostname, path, port } ) ) . rejects . toStrictEqual (
7488 Object . assign ( new ProviderError ( "Error response received from instance metadata service" ) , { statusCode } )
7589 ) ;
76-
77- scope . done ( ) ;
7890 } ) ;
7991 } ;
8092
8193 it ( "when request throws error" , async ( ) => {
82- const scope = nock ( `http://${ hostname } :${ port } ` ) . get ( path ) . replyWithError ( "error" ) ;
94+ vi . mocked ( request ) . mockImplementationOnce ( ( ( ) => {
95+ const request = Object . assign ( new EventEmitter ( ) , {
96+ destroy : vi . fn ( ) ,
97+ end : vi . fn ( ) ,
98+ } ) ;
99+ setTimeout ( ( ) => {
100+ request . emit ( "error" ) ;
101+ } , 50 ) ;
102+ return request ;
103+ } ) as any ) ;
83104
84105 await expect ( httpRequest ( { hostname, path, port } ) ) . rejects . toStrictEqual (
85106 new ProviderError ( "Unable to connect to instance metadata service" )
86107 ) ;
87-
88- scope . done ( ) ;
89108 } ) ;
90109
91110 describe ( "when request returns with statusCode < 200" , ( ) => {
@@ -99,16 +118,21 @@ describe("httpRequest", () => {
99118
100119 it ( "timeout" , async ( ) => {
101120 const timeout = 1000 ;
102- const scope = nock ( `http://${ hostname } :${ port } ` )
103- . get ( path )
104- . delay ( timeout * 2 )
105- . reply ( 200 , "expectedResponse" ) ;
121+ vi . mocked ( request ) . mockImplementationOnce ( ( ( ) => {
122+ const request = Object . assign ( new EventEmitter ( ) , {
123+ destroy : vi . fn ( ) ,
124+ end : vi . fn ( ) ,
125+ } ) ;
126+ const response = new EventEmitter ( ) as any ;
127+ response . statusCode = 200 ;
128+ setTimeout ( ( ) => {
129+ request . emit ( "timeout" ) ;
130+ } , 50 ) ;
131+ return request ;
132+ } ) as any ) ;
106133
107134 await expect ( httpRequest ( { hostname, path, port, timeout } ) ) . rejects . toStrictEqual (
108135 new ProviderError ( "TimeoutError from instance metadata service" )
109136 ) ;
110-
111- nock . abortPendingRequests ( ) ;
112- scope . done ( ) ;
113137 } ) ;
114138} ) ;
0 commit comments