@@ -412,4 +412,110 @@ public Object answer(org.mockito.invocation.InvocationOnMock invocation) throws
412412 assertEquals (400 , ex .getCode ());
413413 assertEquals ("bad request" , ex .getReason ());
414414 }
415+
416+ /**
417+ * Test that execute() with ResponseHandler parameter applies authentication tokens.
418+ * This verifies the fix for the critical bug where this method was bypassing authentication.
419+ */
420+ @ SuppressWarnings ("unchecked" )
421+ @ Test
422+ public void execute_withResponseHandler_appliesAuthentication () throws Exception {
423+ // Prepare mock response
424+ when (httpClient .execute (eq (host ), any (ClassicHttpRequest .class ), (HttpContext ) isNull (), any (HttpClientResponseHandler .class )))
425+ .thenAnswer (new Answer <Object >() {
426+ @ Override
427+ public Object answer (org .mockito .invocation .InvocationOnMock invocation ) throws Throwable {
428+ HttpClientResponseHandler <?> handler = invocation .getArgument (3 );
429+ return handler .handleResponse (okResponse );
430+ }
431+ });
432+
433+ when (sstStrategy .obtainSst (httpClient , host )).thenReturn (SST );
434+
435+ // Set up authentication state by pre-populating TT token
436+ Field ttField = GoodDataHttpClient .class .getDeclaredField ("tt" );
437+ ttField .setAccessible (true );
438+ ttField .set (goodDataHttpClient , TT );
439+
440+ Field sstField = GoodDataHttpClient .class .getDeclaredField ("sst" );
441+ sstField .setAccessible (true );
442+ sstField .set (goodDataHttpClient , SST );
443+
444+ // Create test request
445+ HttpGet request = new HttpGet ("/gdc/account/profile/current" );
446+
447+ // Execute with ResponseHandler
448+ String result = goodDataHttpClient .execute (host , request , null , response -> {
449+ // Verify the response handler receives the response
450+ assertEquals (200 , response .getCode ());
451+ return "success" ;
452+ });
453+
454+ // Verify result
455+ assertEquals ("success" , result );
456+
457+ // Verify that X-GDC-AuthTT header was added to the request
458+ // This verifies authentication was applied before sending the request
459+ Header [] headers = request .getHeaders ("X-GDC-AuthTT" );
460+ assertEquals (1 , headers .length , "X-GDC-AuthTT header should be present" );
461+ assertEquals (TT , headers [0 ].getValue (), "X-GDC-AuthTT header should contain the token" );
462+ }
463+
464+ /**
465+ * Test that execute() with ResponseHandler handles 401 responses by refreshing tokens.
466+ */
467+ @ SuppressWarnings ("unchecked" )
468+ @ Test
469+ public void execute_withResponseHandler_handles401WithTokenRefresh () throws Exception {
470+ // Prepare mock sequence: first 401, then success after token refresh
471+ when (httpClient .execute (eq (host ), any (ClassicHttpRequest .class ), (HttpContext ) isNull (), any (HttpClientResponseHandler .class )))
472+ .thenAnswer (new Answer <Object >() {
473+ private int count = 0 ;
474+ @ Override
475+ public Object answer (org .mockito .invocation .InvocationOnMock invocation ) throws Throwable {
476+ HttpClientResponseHandler <?> handler = invocation .getArgument (3 );
477+ count ++;
478+ if (count == 1 ) {
479+ // First call returns 401
480+ return handler .handleResponse (ttChallengeResponse );
481+ } else if (count == 2 ) {
482+ // Token refresh call
483+ return handler .handleResponse (ttRefreshedResponse );
484+ } else {
485+ // Retry returns 200
486+ return handler .handleResponse (okResponse );
487+ }
488+ }
489+ });
490+
491+ when (sstStrategy .obtainSst (httpClient , host )).thenReturn (SST );
492+
493+ // Create test request
494+ HttpGet request = new HttpGet ("/gdc/account/profile/current" );
495+
496+ // Execute with ResponseHandler (should handle 401 and retry)
497+ String result = goodDataHttpClient .execute (host , request , null , response -> {
498+ assertEquals (200 , response .getCode (), "Should eventually receive 200 after token refresh" );
499+ return "success_after_refresh" ;
500+ });
501+
502+ // Verify result
503+ assertEquals ("success_after_refresh" , result );
504+ }
505+
506+ /**
507+ * Test that execute() with null ResponseHandler throws IllegalArgumentException.
508+ */
509+ @ Test
510+ public void execute_withNullResponseHandler_throwsException () throws Exception {
511+ HttpGet request = new HttpGet ("/gdc/account/profile/current" );
512+
513+ // Execute with null ResponseHandler should throw
514+ IllegalArgumentException ex = assertThrows (
515+ IllegalArgumentException .class ,
516+ () -> goodDataHttpClient .execute (host , request , null , null )
517+ );
518+
519+ assertTrue (ex .getMessage ().contains ("Response handler cannot be null" ));
520+ }
415521}
0 commit comments