@@ -136,7 +136,6 @@ describe("BinaryManager", () => {
136
136
expect ( mockLogger . warn ) . toHaveBeenCalledWith (
137
137
expect . stringContaining ( "Unable to get version" ) ,
138
138
) ;
139
-
140
139
// Should attempt to download now
141
140
expect ( mockAxios . get ) . toHaveBeenCalled ( ) ;
142
141
expect ( mockLogger . info ) . toHaveBeenCalledWith (
@@ -150,6 +149,9 @@ describe("BinaryManager", () => {
150
149
const result = await manager . fetchBinary ( mockApi , "test" ) ;
151
150
expect ( result ) . toBe ( BINARY_PATH ) ;
152
151
expect ( mockAxios . get ) . toHaveBeenCalled ( ) ;
152
+ expect ( mockLogger . info ) . toHaveBeenCalledWith (
153
+ "No existing binary found, starting download" ,
154
+ ) ;
153
155
expect ( mockLogger . info ) . toHaveBeenCalledWith (
154
156
"Downloaded binary version is" ,
155
157
TEST_VERSION ,
@@ -221,21 +223,8 @@ describe("BinaryManager", () => {
221
223
} ) ;
222
224
223
225
it ( "backs up existing binary before replacement" , async ( ) => {
224
- // Setup existing old binary
225
- vi . mocked ( cli . stat ) . mockReset ( ) ;
226
- vi . mocked ( cli . stat )
227
- . mockResolvedValueOnce ( { size : 1024 } as fs . Stats ) // Existing binary
228
- . mockResolvedValueOnce ( { size : 5242880 } as fs . Stats ) ; // After download
229
- vi . mocked ( cli . version ) . mockReset ( ) ;
230
- vi . mocked ( cli . version )
231
- . mockResolvedValueOnce ( "1.0.0" ) // Old version
232
- . mockResolvedValueOnce ( TEST_VERSION ) ; // New version after download
233
-
234
- // Setup download
235
- const stream = createMockStream ( ) ;
236
- const writeStream = createMockWriteStream ( ) ;
237
- withHttpResponse ( 200 , { "content-length" : "1024" } , stream ) ;
238
- vi . mocked ( fs . createWriteStream ) . mockReturnValue ( writeStream ) ;
226
+ withExistingBinary ( "1.0.0" ) ;
227
+ withSuccessfulDownload ( ) ;
239
228
240
229
await manager . fetchBinary ( mockApi , "test" ) ;
241
230
expect ( fse . rename ) . toHaveBeenCalledWith (
@@ -260,6 +249,9 @@ describe("BinaryManager", () => {
260
249
withHttpResponse ( 304 ) ;
261
250
const result = await manager . fetchBinary ( mockApi , "test" ) ;
262
251
expect ( result ) . toBe ( BINARY_PATH ) ;
252
+ expect ( mockLogger . info ) . toHaveBeenCalledWith (
253
+ "Using existing binary since server returned a 304" ,
254
+ ) ;
263
255
} ) ;
264
256
265
257
it ( "handles 404 platform not supported" , async ( ) => {
@@ -268,14 +260,28 @@ describe("BinaryManager", () => {
268
260
await expect ( manager . fetchBinary ( mockApi , "test" ) ) . rejects . toThrow (
269
261
"Platform not supported" ,
270
262
) ;
271
- expect ( vscode . env . openExternal ) . toHaveBeenCalled ( ) ;
263
+ expect ( vscode . env . openExternal ) . toHaveBeenCalledWith (
264
+ expect . objectContaining ( {
265
+ path : expect . stringContaining (
266
+ "github.com/coder/vscode-coder/issues/new?" ,
267
+ ) ,
268
+ } ) ,
269
+ ) ;
272
270
} ) ;
273
271
274
272
it ( "handles server errors" , async ( ) => {
275
273
withHttpResponse ( 500 ) ;
274
+ mockUI . setResponse ( "Open an Issue" ) ;
276
275
await expect ( manager . fetchBinary ( mockApi , "test" ) ) . rejects . toThrow (
277
276
"Failed to download binary" ,
278
277
) ;
278
+ expect ( vscode . env . openExternal ) . toHaveBeenCalledWith (
279
+ expect . objectContaining ( {
280
+ path : expect . stringContaining (
281
+ "github.com/coder/vscode-coder/issues/new?" ,
282
+ ) ,
283
+ } ) ,
284
+ ) ;
279
285
} ) ;
280
286
} ) ;
281
287
@@ -336,35 +342,46 @@ describe("BinaryManager", () => {
336
342
337
343
describe ( "Signature Verification" , ( ) => {
338
344
it ( "verifies valid signatures" , async ( ) => {
339
- withSuccessfulDownloadAndSignature ( ) ;
340
- vi . mocked ( pgp . verifySignature ) . mockResolvedValueOnce ( ) ;
345
+ withSuccessfulDownload ( ) ;
346
+ withSignatureResponses ( [ 200 ] ) ;
341
347
const result = await manager . fetchBinary ( mockApi , "test" ) ;
342
348
expect ( result ) . toBe ( BINARY_PATH ) ;
343
349
expect ( pgp . verifySignature ) . toHaveBeenCalled ( ) ;
344
350
} ) ;
345
351
346
352
it ( "tries fallback signature on 404" , async ( ) => {
347
- withBinaryDownload ( ) ;
353
+ withSuccessfulDownload ( ) ;
348
354
withSignatureResponses ( [ 404 , 200 ] ) ;
349
- vi . mocked ( pgp . verifySignature ) . mockResolvedValueOnce ( ) ;
350
355
mockUI . setResponse ( "Download signature" ) ;
351
356
const result = await manager . fetchBinary ( mockApi , "test" ) ;
352
357
expect ( result ) . toBe ( BINARY_PATH ) ;
358
+ expect ( vscode . window . showWarningMessage ) . toHaveBeenCalledWith (
359
+ "Signature not found" ,
360
+ expect . any ( Object ) ,
361
+ expect . any ( String ) ,
362
+ expect . any ( String ) ,
363
+ ) ;
364
+ // First download and when verfiying twice (404 then 200)
353
365
expect ( mockAxios . get ) . toHaveBeenCalledTimes ( 3 ) ;
354
366
} ) ;
355
367
356
368
it ( "allows running despite invalid signature" , async ( ) => {
357
- withSuccessfulDownloadAndSignature ( ) ;
369
+ withSuccessfulDownload ( ) ;
370
+ withSignatureResponses ( [ 200 ] ) ;
358
371
vi . mocked ( pgp . verifySignature ) . mockRejectedValueOnce (
359
372
createVerificationError ( "Invalid signature" ) ,
360
373
) ;
361
374
mockUI . setResponse ( "Run anyway" ) ;
362
375
const result = await manager . fetchBinary ( mockApi , "test" ) ;
363
376
expect ( result ) . toBe ( BINARY_PATH ) ;
377
+ expect ( mockLogger . info ) . toHaveBeenCalledWith (
378
+ "Binary will be ran anyway at user request" ,
379
+ ) ;
364
380
} ) ;
365
381
366
382
it ( "aborts on signature rejection" , async ( ) => {
367
- withSuccessfulDownloadAndSignature ( ) ;
383
+ withSuccessfulDownload ( ) ;
384
+ withSignatureResponses ( [ 200 ] ) ;
368
385
vi . mocked ( pgp . verifySignature ) . mockRejectedValueOnce (
369
386
createVerificationError ( "Invalid signature" ) ,
370
387
) ;
@@ -380,19 +397,25 @@ describe("BinaryManager", () => {
380
397
const result = await manager . fetchBinary ( mockApi , "test" ) ;
381
398
expect ( result ) . toBe ( BINARY_PATH ) ;
382
399
expect ( pgp . verifySignature ) . not . toHaveBeenCalled ( ) ;
400
+ expect ( mockLogger . info ) . toHaveBeenCalledWith (
401
+ "Skipping binary signature verification due to settings" ,
402
+ ) ;
383
403
} ) ;
384
404
385
405
it ( "allows skipping verification on 404" , async ( ) => {
386
- withBinaryDownload ( ) ;
406
+ withSuccessfulDownload ( ) ;
387
407
withHttpResponse ( 404 ) ;
388
408
mockUI . setResponse ( "Run without verification" ) ;
389
409
const result = await manager . fetchBinary ( mockApi , "test" ) ;
390
410
expect ( result ) . toBe ( BINARY_PATH ) ;
391
411
expect ( pgp . verifySignature ) . not . toHaveBeenCalled ( ) ;
412
+ expect ( mockLogger . info ) . toHaveBeenCalledWith (
413
+ expect . stringMatching ( / S i g n a t u r e d o w n l o a d f r o m ( .+ ) d e c l i n e d / ) ,
414
+ ) ;
392
415
} ) ;
393
416
394
417
it ( "handles signature download failure" , async ( ) => {
395
- withBinaryDownload ( ) ;
418
+ withSuccessfulDownload ( ) ;
396
419
withHttpResponse ( 500 ) ;
397
420
mockUI . setResponse ( "Run without verification" ) ;
398
421
const result = await manager . fetchBinary ( mockApi , "test" ) ;
@@ -406,7 +429,7 @@ describe("BinaryManager", () => {
406
429
} ) ;
407
430
408
431
it ( "aborts when user declines missing signature" , async ( ) => {
409
- withBinaryDownload ( ) ;
432
+ withSuccessfulDownload ( ) ;
410
433
withHttpResponse ( 404 ) ;
411
434
mockUI . setResponse ( undefined ) ; // User cancels
412
435
await expect ( manager . fetchBinary ( mockApi , "test" ) ) . rejects . toThrow (
@@ -482,11 +505,12 @@ describe("BinaryManager", () => {
482
505
vi . mocked ( cli . stat ) . mockReset ( ) ;
483
506
vi . mocked ( cli . stat ) . mockResolvedValueOnce ( { size : 1024 } as fs . Stats ) ; // Existing binary exists
484
507
vi . mocked ( cli . version ) . mockReset ( ) ;
485
- vi . mocked ( cli . version )
486
- . mockRejectedValueOnce ( new Error ( "corrupted" ) ) // Existing binary is corrupted
487
- . mockResolvedValueOnce ( TEST_VERSION ) ; // New download works
508
+ vi . mocked ( cli . version ) . mockRejectedValueOnce ( new Error ( "corrupted" ) ) ; // Existing binary is corrupted
488
509
}
489
510
511
+ /**
512
+ * Shouldn't reset mocks since this method is combined with other mocks.
513
+ */
490
514
function withSuccessfulDownload ( opts ?: {
491
515
headers ?: Record < string , unknown > ;
492
516
} ) {
@@ -506,25 +530,6 @@ describe("BinaryManager", () => {
506
530
vi . mocked ( cli . version ) . mockResolvedValueOnce ( TEST_VERSION ) ;
507
531
}
508
532
509
- function withBinaryDownload ( ) {
510
- const stream = createMockStream ( ) ;
511
- const writeStream = createMockWriteStream ( ) ;
512
- withHttpResponse ( 200 , { "content-length" : "1024" } , stream ) ;
513
- vi . mocked ( fs . createWriteStream ) . mockReturnValue ( writeStream ) ;
514
- // Override to ensure no existing binary initially
515
- vi . mocked ( cli . stat ) . mockReset ( ) ;
516
- vi . mocked ( cli . stat )
517
- . mockResolvedValueOnce ( undefined ) // No existing binary
518
- . mockResolvedValueOnce ( { size : 5242880 } as fs . Stats ) ; // After download
519
- vi . mocked ( cli . version ) . mockReset ( ) ;
520
- vi . mocked ( cli . version ) . mockResolvedValueOnce ( TEST_VERSION ) ;
521
- }
522
-
523
- function withSuccessfulDownloadAndSignature ( ) {
524
- withBinaryDownload ( ) ;
525
- withHttpResponse ( 200 , { "content-length" : "256" } , createMockStream ( ) ) ;
526
- }
527
-
528
533
function withSignatureResponses ( statuses : number [ ] ) {
529
534
statuses . forEach ( ( status ) => {
530
535
if ( status === 200 ) {
0 commit comments