11// License: GPL. For details, see LICENSE file.
22package org .openstreetmap .josm .data .oauth ;
33
4+ import static org .junit .jupiter .api .Assertions .assertDoesNotThrow ;
45import static org .junit .jupiter .api .Assertions .assertEquals ;
56import static org .junit .jupiter .api .Assertions .assertNotNull ;
67import static org .junit .jupiter .api .Assertions .assertNull ;
78import static org .junit .jupiter .api .Assertions .assertTrue ;
89
910import java .io .IOException ;
11+ import java .net .URL ;
1012import java .util .HashMap ;
1113import java .util .Map ;
1214import java .util .Optional ;
1921import com .github .tomakehurst .wiremock .core .WireMockConfiguration ;
2022import com .github .tomakehurst .wiremock .extension .Parameters ;
2123import com .github .tomakehurst .wiremock .extension .ResponseTransformer ;
24+ import com .github .tomakehurst .wiremock .http .FixedDelayDistribution ;
2225import com .github .tomakehurst .wiremock .http .HttpHeader ;
2326import com .github .tomakehurst .wiremock .http .HttpHeaders ;
2427import com .github .tomakehurst .wiremock .http .QueryParameter ;
@@ -61,8 +64,14 @@ class OAuth20AuthorizationTest {
6164 private static final String CODE_CHALLENGE_METHOD_VALUE = "S256" ;
6265 private static final String CODE_CHALLENGE = "code_challenge" ;
6366
67+ private enum ConnectionProblems {
68+ NONE ,
69+ SOCKET_TIMEOUT
70+ }
71+
6472 private static class OAuthServerWireMock extends ResponseTransformer {
6573 String stateToReturn ;
74+ ConnectionProblems connectionProblems = ConnectionProblems .NONE ;
6675 @ Override
6776 public Response transform (Request request , Response response , FileSource files , Parameters parameters ) {
6877 try {
@@ -88,7 +97,15 @@ private Response tokenRequest(Request request, Response response) {
8897 || !queryParameters .containsKey ("code" ) || !queryParameters .containsKey ("code_verifier" )) {
8998 return Response .Builder .like (response ).but ().status (500 ).build ();
9099 }
91- return Response .Builder .like (response ).but ().body ("{\" token_type\" : \" bearer\" , \" access_token\" : \" test_access_token\" }" ).build ();
100+ switch (connectionProblems ) {
101+ case SOCKET_TIMEOUT :
102+ return Response .Builder .like (response ).but ().configureDelay (null , null ,
103+ 10_000 , new FixedDelayDistribution (0 )).build ();
104+ case NONE :
105+ default :
106+ return Response .Builder .like (response ).but ()
107+ .body ("{\" token_type\" : \" bearer\" , \" access_token\" : \" test_access_token\" }" ).build ();
108+ }
92109 }
93110
94111 private Response authorizationRequest (Request request , Response response ) {
@@ -135,6 +152,7 @@ void setup() {
135152 OpenBrowserMocker .getCalledURIs ().clear ();
136153 RemoteControl .stop (); // Ensure remote control is stopped
137154 oauthServer .stateToReturn = null ;
155+ oauthServer .connectionProblems = ConnectionProblems .NONE ;
138156 }
139157
140158 /**
@@ -163,17 +181,22 @@ public String getDefaultOsmApiUrl() {
163181 wireMockRuntimeInfo .getWireMock ().register (WireMock .post (WireMock .urlPathEqualTo ("/oauth2/token" )));
164182 }
165183
166- @ Test
167- void testAuthorize (WireMockRuntimeInfo wireMockRuntimeInfo ) throws IOException {
184+ private HttpClient generateClient (WireMockRuntimeInfo wireMockRuntimeInfo , AtomicReference <Optional <IOAuthToken >> consumer ) {
168185 final OAuth20Authorization authorization = new OAuth20Authorization ();
169- final AtomicReference <Optional <IOAuthToken >> consumer = new AtomicReference <>();
170186 OAuth20Parameters parameters = (OAuth20Parameters ) OAuthParameters .createDefault (OsmApi .getOsmApi ().getBaseUrl (), OAuthVersion .OAuth20 );
171187 RemoteControl .start ();
172188 authorization .authorize (new OAuth20Parameters (parameters .getClientId (), parameters .getClientSecret (),
173189 wireMockRuntimeInfo .getHttpBaseUrl () + "/oauth2" , wireMockRuntimeInfo .getHttpBaseUrl () + "/api" ,
174190 parameters .getRedirectUri ()), consumer ::set , OsmScopes .read_gpx );
175191 assertEquals (1 , OpenBrowserMocker .getCalledURIs ().size ());
176- HttpClient client = HttpClient .create (OpenBrowserMocker .getCalledURIs ().get (0 ).toURL ());
192+ final URL url = assertDoesNotThrow (() -> OpenBrowserMocker .getCalledURIs ().get (0 ).toURL ());
193+ return HttpClient .create (url );
194+ }
195+
196+ @ Test
197+ void testAuthorize (WireMockRuntimeInfo wireMockRuntimeInfo ) throws IOException {
198+ final AtomicReference <Optional <IOAuthToken >> consumer = new AtomicReference <>();
199+ final HttpClient client = generateClient (wireMockRuntimeInfo , consumer );
177200 try {
178201 HttpClient .Response response = client .connect ();
179202 assertEquals (200 , response .getResponseCode ());
@@ -190,15 +213,8 @@ void testAuthorize(WireMockRuntimeInfo wireMockRuntimeInfo) throws IOException {
190213 @ Test
191214 void testAuthorizeBadState (WireMockRuntimeInfo wireMockRuntimeInfo ) throws IOException {
192215 oauthServer .stateToReturn = "Bad_State" ;
193- final OAuth20Authorization authorization = new OAuth20Authorization ();
194216 final AtomicReference <Optional <IOAuthToken >> consumer = new AtomicReference <>();
195- OAuth20Parameters parameters = (OAuth20Parameters ) OAuthParameters .createDefault (OsmApi .getOsmApi ().getBaseUrl (), OAuthVersion .OAuth20 );
196- RemoteControl .start ();
197- authorization .authorize (new OAuth20Parameters (parameters .getClientId (), parameters .getClientSecret (),
198- wireMockRuntimeInfo .getHttpBaseUrl () + "/oauth2" , wireMockRuntimeInfo .getHttpBaseUrl () + "/api" ,
199- parameters .getRedirectUri ()), consumer ::set , OsmScopes .read_gpx );
200- assertEquals (1 , OpenBrowserMocker .getCalledURIs ().size ());
201- HttpClient client = HttpClient .create (OpenBrowserMocker .getCalledURIs ().get (0 ).toURL ());
217+ final HttpClient client = generateClient (wireMockRuntimeInfo , consumer );
202218 try {
203219 HttpClient .Response response = client .connect ();
204220 assertEquals (400 , response .getResponseCode ());
@@ -209,4 +225,25 @@ void testAuthorizeBadState(WireMockRuntimeInfo wireMockRuntimeInfo) throws IOExc
209225 }
210226 assertNull (consumer .get (), "The OAuth consumer should not be called since the state does not match" );
211227 }
228+
229+ @ Test
230+ void testSocketTimeout (WireMockRuntimeInfo wireMockRuntimeInfo ) throws Exception {
231+ // 1s before timeout
232+ Config .getPref ().putInt ("socket.timeout.connect" , 1 );
233+ Config .getPref ().putInt ("socket.timeout.read" , 1 );
234+ oauthServer .connectionProblems = ConnectionProblems .SOCKET_TIMEOUT ;
235+
236+ final AtomicReference <Optional <IOAuthToken >> consumer = new AtomicReference <>();
237+ final HttpClient client = generateClient (wireMockRuntimeInfo , consumer )
238+ .setConnectTimeout (15_000 ).setReadTimeout (30_000 );
239+ try {
240+ HttpClient .Response response = client .connect ();
241+ assertEquals (500 , response .getResponseCode ());
242+ String content = response .fetchContent ();
243+ assertTrue (content .contains ("java.net.SocketTimeoutException: Read timed out" ));
244+ } finally {
245+ client .disconnect ();
246+ }
247+ assertEquals (Optional .empty (), consumer .get ());
248+ }
212249}
0 commit comments