@@ -23,29 +23,59 @@ const tmAnswers = {
2323 }
2424}
2525
26- class AgentAPI {
27- downloadSecureFile ( ) {
28- const rs = new Readable ( ) ;
29- rs . _read = ( ) => { } ;
30- rs . push ( 'data' ) ;
26+ function createMockStream ( options : {
27+ statusCode ?: number ;
28+ statusMessage ?: string ;
29+ contentType ?: string ;
30+ data ?: string ;
31+ emitError ?: Error ;
32+ } = { } ) {
33+ const {
34+ statusCode = 200 ,
35+ statusMessage = 'OK' ,
36+ contentType = 'application/octet-stream' ,
37+ data = 'data' ,
38+ emitError,
39+ } = options ;
40+
41+ const rs = new Readable ( ) ;
42+ rs . _read = ( ) => { } ;
43+ ( rs as any ) . statusCode = statusCode ;
44+ ( rs as any ) . statusMessage = statusMessage ;
45+ ( rs as any ) . headers = { 'content-type' : contentType } ;
46+
47+ if ( emitError ) {
48+ setTimeout ( ( ) => {
49+ rs . emit ( 'error' , emitError ) ;
50+ } , 10 ) ;
51+ } else {
52+ if ( data ) rs . push ( data ) ;
3153 rs . push ( null ) ;
32- return rs ;
3354 }
55+
56+ return rs ;
3457}
3558
36- class WebApi {
37- getTaskAgentApi ( ) {
38- return new Promise ( ( resolve ) => {
39- resolve ( new AgentAPI ( ) ) ;
40- } ) ;
59+ // Helper function to create a complete node API mock
60+ function createNodeApiMock ( streamOptions ?: Parameters < typeof createMockStream > [ 0 ] ) {
61+ class MockAgentAPI {
62+ downloadSecureFile ( ) {
63+ return Promise . resolve ( createMockStream ( streamOptions ) ) ;
64+ }
4165 }
42- }
4366
44- export const nodeapiMock = {
45- WebApi ,
46- getPersonalAccessTokenHandler ( ) {
47- return { } as IRequestHandler ;
67+ class MockWebApi {
68+ getTaskAgentApi ( ) {
69+ return Promise . resolve ( new MockAgentAPI ( ) ) ;
70+ }
4871 }
72+
73+ return {
74+ WebApi : MockWebApi ,
75+ getPersonalAccessTokenHandler ( ) {
76+ return { } as IRequestHandler ;
77+ }
78+ } ;
4979}
5080
5181export const fsMock = {
@@ -105,6 +135,12 @@ describe("securefiles-common package suites", function() {
105135 } ) ;
106136
107137 it ( "Check downloadSecureFile" , async ( ) => {
138+ const nodeapiMock = createNodeApiMock ( {
139+ statusCode : 200 ,
140+ statusMessage : 'OK' ,
141+ contentType : 'application/octet-stream'
142+ } ) ;
143+
108144 registerMock ( "azure-devops-node-api" , nodeapiMock ) ;
109145 registerMock ( "fs" , fsMock ) ;
110146 const secureFiles = require ( "../securefiles-common" ) ;
@@ -127,4 +163,49 @@ describe("securefiles-common package suites", function() {
127163 const pseudoResolvedPath = tlClone . resolve ( tlClone . getVariable ( "Agent.TempDirectory" ) , tlClone . getSecureFileName ( secureFileId ) ) ;
128164 strictEqual ( resolvedPath , pseudoResolvedPath , `Resolved path "${ resolvedPath } " should be equal to "${ pseudoResolvedPath } "` ) ;
129165 } ) ;
166+
167+ it ( "Should handle HTTP error responses" , async ( ) => {
168+ const errorNodeapiMock = createNodeApiMock ( {
169+ statusCode : 500 ,
170+ statusMessage : 'Internal Server Error' ,
171+ contentType : 'application/json' ,
172+ data : '' ,
173+ } ) ;
174+
175+ registerMock ( "azure-devops-node-api" , errorNodeapiMock ) ;
176+ registerMock ( "fs" , fsMock ) ;
177+ const secureFiles = require ( "../securefiles-common" ) ;
178+ const secureFileHelpers = new secureFiles . SecureFileHelpers ( ) ;
179+
180+ try {
181+ await secureFileHelpers . downloadSecureFile ( secureFileId ) ;
182+ throw new Error ( "Expected error was not thrown" ) ;
183+ } catch ( error ) {
184+ strictEqual ( error . message . includes ( "HTTP 500" ) , true , "Should contain HTTP error status" ) ;
185+ strictEqual ( error . message . includes ( "Internal Server Error" ) , true , "Should contain HTTP error message" ) ;
186+ }
187+ } ) ;
188+
189+ it ( "Should handle stream errors during download" , async ( ) => {
190+ const streamErrorNodeapiMock = createNodeApiMock ( {
191+ statusCode : 200 ,
192+ statusMessage : 'OK' ,
193+ contentType : 'application/octet-stream' ,
194+ emitError : new Error ( 'Network connection lost' )
195+ } ) ;
196+
197+ registerMock ( "azure-devops-node-api" , streamErrorNodeapiMock ) ;
198+ registerMock ( "fs" , fsMock ) ;
199+
200+ const secureFiles = require ( "../securefiles-common" ) ;
201+ const secureFileHelpers = new secureFiles . SecureFileHelpers ( ) ;
202+
203+ try {
204+ await secureFileHelpers . downloadSecureFile ( secureFileId ) ;
205+ throw new Error ( "Expected error was not thrown" ) ;
206+ } catch ( error ) {
207+ strictEqual ( error . message . includes ( "Failed to download secure file" ) , true , "Should handle stream errors" ) ;
208+ strictEqual ( error . message . includes ( "Network connection lost" ) , true , "Should include original error message" ) ;
209+ }
210+ } ) ;
130211} ) ;
0 commit comments