@@ -13,14 +13,20 @@ jest.mock('@sentry/core', () => {
13
13
} ;
14
14
} ) ;
15
15
16
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
17
+ const httpProxyAgent = require ( 'https-proxy-agent' ) ;
18
+ jest . mock ( 'https-proxy-agent' , ( ) => {
19
+ return jest . fn ( ) . mockImplementation ( ( ) => new http . Agent ( { keepAlive : false , maxSockets : 30 , timeout : 2000 } ) ) ;
20
+ } ) ;
21
+
16
22
const SUCCESS = 200 ;
17
23
const RATE_LIMIT = 429 ;
18
24
const INVALID = 400 ;
19
25
const FAILED = 500 ;
20
26
21
27
interface TestServerOptions {
22
28
statusCode : number ;
23
- responseHeaders : Record < string , string | string [ ] | undefined > ;
29
+ responseHeaders ? : Record < string , string | string [ ] | undefined > ;
24
30
}
25
31
26
32
let testServer : http . Server | undefined ;
@@ -44,14 +50,14 @@ function setupTestServer(
44
50
res . end ( ) ;
45
51
} ) ;
46
52
47
- testServer . listen ( 12345 ) ;
53
+ testServer . listen ( 8099 ) ;
48
54
49
55
return new Promise ( resolve => {
50
56
testServer ?. on ( 'listening' , resolve ) ;
51
57
} ) ;
52
58
}
53
59
54
- const testServerUrl = 'http://localhost:12345 ' ;
60
+ const TEST_SERVER_URL = 'http://localhost:8099 ' ;
55
61
56
62
const EVENT_ENVELOPE = createEnvelope < EventEnvelope > ( { event_id : 'aa3ff046696b4bc6b609ce6d28fde9e2' , sent_at : '123' } , [
57
63
[ { type : 'event' } , { event_id : 'aa3ff046696b4bc6b609ce6d28fde9e2' } ] as EventItem ,
@@ -70,26 +76,26 @@ describe('makeNewHttpTransport()', () => {
70
76
71
77
describe ( '.send()' , ( ) => {
72
78
it ( 'should correctly return successful server response' , async ( ) => {
73
- await setupTestServer ( { statusCode : SUCCESS , responseHeaders : { } } ) ;
79
+ await setupTestServer ( { statusCode : SUCCESS } ) ;
74
80
75
- const transport = makeNewHttpTransport ( { url : testServerUrl } ) ;
81
+ const transport = makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
76
82
const transportResponse = await transport . send ( EVENT_ENVELOPE ) ;
77
83
78
84
expect ( transportResponse ) . toEqual ( expect . objectContaining ( { status : 'success' } ) ) ;
79
85
} ) ;
80
86
81
87
it ( 'should correctly send envelope to server' , async ( ) => {
82
- await setupTestServer ( { statusCode : SUCCESS , responseHeaders : { } } , ( req , body ) => {
88
+ await setupTestServer ( { statusCode : SUCCESS } , ( req , body ) => {
83
89
expect ( req . method ) . toBe ( 'POST' ) ;
84
90
expect ( body ) . toBe ( SERIALIZED_EVENT_ENVELOPE ) ;
85
91
} ) ;
86
92
87
- const transport = makeNewHttpTransport ( { url : testServerUrl } ) ;
93
+ const transport = makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
88
94
await transport . send ( EVENT_ENVELOPE ) ;
89
95
} ) ;
90
96
91
97
it ( 'should correctly send user-provided headers to server' , async ( ) => {
92
- await setupTestServer ( { statusCode : SUCCESS , responseHeaders : { } } , req => {
98
+ await setupTestServer ( { statusCode : SUCCESS } , req => {
93
99
expect ( req . headers ) . toEqual (
94
100
expect . objectContaining ( {
95
101
// node http module lower-cases incoming headers
@@ -100,7 +106,7 @@ describe('makeNewHttpTransport()', () => {
100
106
} ) ;
101
107
102
108
const transport = makeNewHttpTransport ( {
103
- url : testServerUrl ,
109
+ url : TEST_SERVER_URL ,
104
110
headers : {
105
111
'X-Some-Custom-Header-1' : 'value1' ,
106
112
'X-Some-Custom-Header-2' : 'value2' ,
@@ -115,9 +121,9 @@ describe('makeNewHttpTransport()', () => {
115
121
[ INVALID , 'invalid' ] ,
116
122
[ FAILED , 'failed' ] ,
117
123
] ) ( 'should correctly reject bad server response (status %i)' , async ( serverStatusCode , expectedStatus ) => {
118
- await setupTestServer ( { statusCode : serverStatusCode , responseHeaders : { } } ) ;
124
+ await setupTestServer ( { statusCode : serverStatusCode } ) ;
119
125
120
- const transport = makeNewHttpTransport ( { url : testServerUrl } ) ;
126
+ const transport = makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
121
127
await expect ( transport . send ( EVENT_ENVELOPE ) ) . rejects . toEqual ( expect . objectContaining ( { status : expectedStatus } ) ) ;
122
128
} ) ;
123
129
@@ -130,7 +136,7 @@ describe('makeNewHttpTransport()', () => {
130
136
} ,
131
137
} ) ;
132
138
133
- const transport = makeNewHttpTransport ( { url : testServerUrl } ) ;
139
+ const transport = makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
134
140
const transportResponse = await transport . send ( EVENT_ENVELOPE ) ;
135
141
136
142
expect ( transportResponse ) . toEqual ( expect . objectContaining ( { status : 'success' } ) ) ;
@@ -145,13 +151,88 @@ describe('makeNewHttpTransport()', () => {
145
151
} ,
146
152
} ) ;
147
153
148
- const transport = makeNewHttpTransport ( { url : testServerUrl } ) ;
154
+ const transport = makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
149
155
const transportResponse = await transport . send ( EVENT_ENVELOPE ) ;
150
156
151
157
expect ( transportResponse ) . toEqual ( expect . objectContaining ( { status : 'success' } ) ) ;
152
158
} ) ;
153
159
} ) ;
154
160
161
+ describe ( 'proxy' , ( ) => {
162
+ it ( 'can be configured through option' , ( ) => {
163
+ makeNewHttpTransport ( {
164
+ url :
'http://[email protected] :8989/mysubpath/50622' ,
165
+ proxy : 'http://example.com' ,
166
+ } ) ;
167
+
168
+ expect ( httpProxyAgent ) . toHaveBeenCalledTimes ( 1 ) ;
169
+ expect ( httpProxyAgent ) . toHaveBeenCalledWith ( 'http://example.com' ) ;
170
+ } ) ;
171
+
172
+ it ( 'can be configured through env variables option' , ( ) => {
173
+ process . env . http_proxy = 'http://example.com' ;
174
+ makeNewHttpTransport ( {
175
+ url :
'http://[email protected] :8989/mysubpath/50622' ,
176
+ } ) ;
177
+
178
+ expect ( httpProxyAgent ) . toHaveBeenCalledTimes ( 1 ) ;
179
+ expect ( httpProxyAgent ) . toHaveBeenCalledWith ( 'http://example.com' ) ;
180
+ delete process . env . http_proxy ;
181
+ } ) ;
182
+
183
+ it ( 'client options have priority over env variables' , ( ) => {
184
+ process . env . http_proxy = 'http://foo.com' ;
185
+ makeNewHttpTransport ( {
186
+ url :
'http://[email protected] :8989/mysubpath/50622' ,
187
+ proxy : 'http://bar.com' ,
188
+ } ) ;
189
+
190
+ expect ( httpProxyAgent ) . toHaveBeenCalledTimes ( 1 ) ;
191
+ expect ( httpProxyAgent ) . toHaveBeenCalledWith ( 'http://bar.com' ) ;
192
+ delete process . env . http_proxy ;
193
+ } ) ;
194
+
195
+ it ( 'no_proxy allows for skipping specific hosts' , ( ) => {
196
+ process . env . no_proxy = 'sentry.io' ;
197
+ makeNewHttpTransport ( {
198
+ url :
'http://[email protected] :8989/mysubpath/50622' ,
199
+ proxy : 'http://example.com' ,
200
+ } ) ;
201
+
202
+ expect ( httpProxyAgent ) . not . toHaveBeenCalled ( ) ;
203
+
204
+ delete process . env . no_proxy ;
205
+ } ) ;
206
+
207
+ it ( 'no_proxy works with a port' , ( ) => {
208
+ process . env . http_proxy = 'http://example.com:8080' ;
209
+ process . env . no_proxy = 'sentry.io:8989' ;
210
+
211
+ makeNewHttpTransport ( {
212
+ url :
'http://[email protected] :8989/mysubpath/50622' ,
213
+ } ) ;
214
+
215
+ expect ( httpProxyAgent ) . not . toHaveBeenCalled ( ) ;
216
+
217
+ delete process . env . no_proxy ;
218
+ delete process . env . http_proxy ;
219
+ } ) ;
220
+
221
+ it ( 'no_proxy works with multiple comma-separated hosts' , ( ) => {
222
+ process . env . http_proxy = 'http://example.com:8080' ;
223
+ process . env . no_proxy = 'example.com,sentry.io,wat.com:1337' ;
224
+
225
+ makeNewHttpTransport ( {
226
+ url :
'http://[email protected] :8989/mysubpath/50622' ,
227
+ } ) ;
228
+
229
+ expect ( httpProxyAgent ) . not . toHaveBeenCalled ( ) ;
230
+
231
+ delete process . env . no_proxy ;
232
+ delete process . env . http_proxy ;
233
+ } ) ;
234
+ } ) ;
235
+
155
236
it ( 'should register TransportRequestExecutor that returns the correct object from server response (rate limit)' , async ( ) => {
156
237
await setupTestServer ( {
157
238
statusCode : RATE_LIMIT ,
@@ -161,7 +242,7 @@ describe('makeNewHttpTransport()', () => {
161
242
} ,
162
243
} ) ;
163
244
164
- makeNewHttpTransport ( { url : testServerUrl } ) ;
245
+ makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
165
246
const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
166
247
167
248
const executorResult = registeredRequestExecutor ( {
@@ -180,13 +261,12 @@ describe('makeNewHttpTransport()', () => {
180
261
) ;
181
262
} ) ;
182
263
183
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (success )' , async ( ) => {
264
+ it ( 'should register TransportRequestExecutor that returns the correct object from server response (OK )' , async ( ) => {
184
265
await setupTestServer ( {
185
266
statusCode : SUCCESS ,
186
- responseHeaders : { } ,
187
267
} ) ;
188
268
189
- makeNewHttpTransport ( { url : testServerUrl } ) ;
269
+ makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
190
270
const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
191
271
192
272
const executorResult = registeredRequestExecutor ( {
@@ -205,7 +285,7 @@ describe('makeNewHttpTransport()', () => {
205
285
) ;
206
286
} ) ;
207
287
208
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (success but rate-limit)' , async ( ) => {
288
+ it ( 'should register TransportRequestExecutor that returns the correct object from server response (OK with rate-limit headers )' , async ( ) => {
209
289
await setupTestServer ( {
210
290
statusCode : SUCCESS ,
211
291
responseHeaders : {
@@ -214,7 +294,7 @@ describe('makeNewHttpTransport()', () => {
214
294
} ,
215
295
} ) ;
216
296
217
- makeNewHttpTransport ( { url : testServerUrl } ) ;
297
+ makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
218
298
const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
219
299
220
300
const executorResult = registeredRequestExecutor ( {
@@ -232,4 +312,32 @@ describe('makeNewHttpTransport()', () => {
232
312
} ) ,
233
313
) ;
234
314
} ) ;
315
+
316
+ it ( 'should register TransportRequestExecutor that returns the correct object from server response (NOK with rate-limit headers)' , async ( ) => {
317
+ await setupTestServer ( {
318
+ statusCode : RATE_LIMIT ,
319
+ responseHeaders : {
320
+ 'Retry-After' : '2700' ,
321
+ 'X-Sentry-Rate-Limits' : '60::organization, 2700::organization' ,
322
+ } ,
323
+ } ) ;
324
+
325
+ makeNewHttpTransport ( { url : TEST_SERVER_URL } ) ;
326
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
327
+
328
+ const executorResult = registeredRequestExecutor ( {
329
+ body : serializeEnvelope ( EVENT_ENVELOPE ) ,
330
+ category : 'error' ,
331
+ } ) ;
332
+
333
+ await expect ( executorResult ) . resolves . toEqual (
334
+ expect . objectContaining ( {
335
+ headers : {
336
+ 'retry-after' : '2700' ,
337
+ 'x-sentry-rate-limits' : '60::organization, 2700::organization' ,
338
+ } ,
339
+ statusCode : RATE_LIMIT ,
340
+ } ) ,
341
+ ) ;
342
+ } ) ;
235
343
} ) ;
0 commit comments