aboutsummaryrefslogtreecommitdiff
path: root/core/src/test/java/com/android/volley/toolbox/BasicAsyncNetworkTest.java
diff options
context:
space:
mode:
authorAnonymous <no-reply@google.com>2021-07-09 17:40:10 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-07-09 17:40:10 +0000
commitfd5d34f4fc6ffdf0b9c31381ffee78cf73f007d3 (patch)
treecf5d56ccdb862fd9676c855f919408ef940bc019 /core/src/test/java/com/android/volley/toolbox/BasicAsyncNetworkTest.java
parent904ab87ee280c7545a908a8ea10a833385a7cf3f (diff)
parentba6983e134f8f64ced7921f506862a7fcee59d19 (diff)
downloadvolley-android-13.0.0_r35.tar.gz
Import of Volley from GitHub to AOSP. am: 212e7004ac am: f77c53c3a3 am: f33c2e45dc am: ba6983e134t_frc_odp_330442040t_frc_odp_330442000t_frc_con_330443020t_frc_cbr_330443000t_frc_ase_330444010t_frc_art_330443060t_frc_adb_330444000frc_340821000frc_340819280frc_340819220frc_340819190frc_340819030frc_340819020frc_340819010frc_340818170frc_340818110android-vts-14.0_r4android-vts-14.0_r3android-vts-14.0_r2android-vts-14.0_r1android-u-beta-1-gplandroid-security-14.0.0_r9android-security-14.0.0_r8android-security-14.0.0_r7android-security-14.0.0_r6android-security-14.0.0_r5android-security-14.0.0_r4android-security-14.0.0_r3android-security-14.0.0_r2android-security-14.0.0_r1android-platform-14.0.0_r8android-platform-14.0.0_r7android-platform-14.0.0_r6android-platform-14.0.0_r5android-platform-14.0.0_r4android-platform-14.0.0_r3android-platform-14.0.0_r2android-platform-14.0.0_r1android-cts-14.0_r4android-cts-14.0_r3android-cts-14.0_r2android-cts-14.0_r1android-14.0.0_r9android-14.0.0_r8android-14.0.0_r7android-14.0.0_r6android-14.0.0_r51android-14.0.0_r50android-14.0.0_r5android-14.0.0_r45android-14.0.0_r44android-14.0.0_r43android-14.0.0_r42android-14.0.0_r41android-14.0.0_r40android-14.0.0_r4android-14.0.0_r39android-14.0.0_r38android-14.0.0_r37android-14.0.0_r36android-14.0.0_r35android-14.0.0_r34android-14.0.0_r33android-14.0.0_r32android-14.0.0_r31android-14.0.0_r30android-14.0.0_r3android-14.0.0_r29android-14.0.0_r28android-14.0.0_r27android-14.0.0_r26android-14.0.0_r25android-14.0.0_r24android-14.0.0_r23android-14.0.0_r22android-14.0.0_r21android-14.0.0_r20android-14.0.0_r2android-14.0.0_r19android-14.0.0_r18android-14.0.0_r17android-14.0.0_r16android-14.0.0_r15android-14.0.0_r14android-14.0.0_r13android-14.0.0_r12android-14.0.0_r11android-14.0.0_r10android-14.0.0_r1android-13.0.0_r83android-13.0.0_r82android-13.0.0_r81android-13.0.0_r80android-13.0.0_r79android-13.0.0_r78android-13.0.0_r77android-13.0.0_r76android-13.0.0_r75android-13.0.0_r74android-13.0.0_r73android-13.0.0_r72android-13.0.0_r71android-13.0.0_r70android-13.0.0_r69android-13.0.0_r68android-13.0.0_r67android-13.0.0_r66android-13.0.0_r65android-13.0.0_r64android-13.0.0_r63android-13.0.0_r62android-13.0.0_r61android-13.0.0_r60android-13.0.0_r59android-13.0.0_r58android-13.0.0_r57android-13.0.0_r56android-13.0.0_r55android-13.0.0_r54android-13.0.0_r53android-13.0.0_r52android-13.0.0_r51android-13.0.0_r50android-13.0.0_r49android-13.0.0_r48android-13.0.0_r47android-13.0.0_r46android-13.0.0_r45android-13.0.0_r44android-13.0.0_r43android-13.0.0_r42android-13.0.0_r41android-13.0.0_r40android-13.0.0_r39android-13.0.0_r38android-13.0.0_r37android-13.0.0_r36android-13.0.0_r35android-13.0.0_r34android-13.0.0_r33android-13.0.0_r32android-13.0.0_r30android-13.0.0_r29android-13.0.0_r28android-13.0.0_r27android-13.0.0_r24android-13.0.0_r23android-13.0.0_r22android-13.0.0_r21android-13.0.0_r20android-13.0.0_r19android-13.0.0_r18android-13.0.0_r17android-13.0.0_r16aml_uwb_341710010aml_uwb_341513070aml_uwb_341511050aml_uwb_341310300aml_uwb_341310030aml_uwb_341111010aml_uwb_341011000aml_uwb_331910010aml_uwb_331820070aml_uwb_331613010aml_uwb_331611010aml_uwb_331410010aml_uwb_331310030aml_uwb_331115000aml_uwb_331015040aml_uwb_330810010aml_tz5_341510070aml_tz5_341510050aml_tz5_341510010aml_tz4_332714070aml_tz4_332714050aml_tz4_332714010aml_tz4_331910000aml_tz4_331314030aml_tz4_331314020aml_tz4_331314010aml_tz4_331012050aml_tz4_331012040aml_tz4_331012000aml_rkp_341510000aml_rkp_341311000aml_rkp_341114000aml_rkp_341015010aml_rkp_341012000aml_odp_341717000aml_odp_341610000aml_hef_341717050aml_hef_341613000aml_hef_341512030aml_hef_341415040aml_hef_341311010aml_hef_341114030aml_go_wif_330911000aml_go_uwb_330912000aml_go_tz4_330912000aml_go_tet_330914010aml_go_swc_330913000aml_go_sta_330911000aml_go_sdk_330810000aml_go_sch_330911000aml_go_res_330912000aml_go_per_330912000aml_go_odp_330913000aml_go_odp_330912000aml_go_neu_330912000aml_go_net_330913000aml_go_mpr_330912000aml_go_ase_330913000aml_go_ads_330915100aml_go_ads_330915000aml_go_ads_330913000aml_go_adb_330913000aml_cfg_341510000aml_ase_341510000aml_ase_341410000aml_ase_341310010aml_ase_341113000aml_ase_340913000aml_ase_331311020aml_ase_331112000aml_ase_331011020aml_ads_341720000aml_ads_341615050aml_ads_341517040aml_ads_341413000aml_ads_341316030aml_ads_341131050aml_ads_341027030aml_ads_340915050aml_ads_331920180aml_ads_331814200aml_ads_331710270aml_ads_331611190aml_ads_331511020aml_ads_331418080aml_ads_331131000main-16k-with-phonesmain-16kandroid14-tests-releaseandroid14-security-releaseandroid14-s2-releaseandroid14-s1-releaseandroid14-releaseandroid14-qpr3-releaseandroid14-qpr2-s5-releaseandroid14-qpr2-s4-releaseandroid14-qpr2-s3-releaseandroid14-qpr2-s2-releaseandroid14-qpr2-s1-releaseandroid14-qpr2-releaseandroid14-qpr1-s2-releaseandroid14-qpr1-releaseandroid14-platform-releaseandroid14-mainline-uwb-releaseandroid14-mainline-healthfitness-releaseandroid14-mainline-appsearch-releaseandroid14-mainline-adservices-releaseandroid14-gsiandroid14-devandroid14-d2-s5-releaseandroid14-d2-s4-releaseandroid14-d2-s3-releaseandroid14-d2-s2-releaseandroid14-d2-s1-releaseandroid14-d2-releaseandroid14-d1-s7-releaseandroid14-d1-s6-releaseandroid14-d1-s5-releaseandroid14-d1-s4-releaseandroid14-d1-s3-releaseandroid14-d1-s2-releaseandroid14-d1-s1-releaseandroid14-d1-releaseandroid13-qpr3-s9-releaseandroid13-qpr3-s8-releaseandroid13-qpr3-s7-releaseandroid13-qpr3-s6-releaseandroid13-qpr3-s5-releaseandroid13-qpr3-s4-releaseandroid13-qpr3-s3-releaseandroid13-qpr3-s2-releaseandroid13-qpr3-s14-releaseandroid13-qpr3-s13-releaseandroid13-qpr3-s12-releaseandroid13-qpr3-s11-releaseandroid13-qpr3-s10-releaseandroid13-qpr3-s1-releaseandroid13-qpr3-releaseandroid13-qpr3-c-s8-releaseandroid13-qpr3-c-s7-releaseandroid13-qpr3-c-s6-releaseandroid13-qpr3-c-s5-releaseandroid13-qpr3-c-s4-releaseandroid13-qpr3-c-s3-releaseandroid13-qpr3-c-s2-releaseandroid13-qpr3-c-s12-releaseandroid13-qpr3-c-s11-releaseandroid13-qpr3-c-s10-releaseandroid13-qpr3-c-s1-releaseandroid13-qpr2-s9-releaseandroid13-qpr2-s8-releaseandroid13-qpr2-s7-releaseandroid13-qpr2-s6-releaseandroid13-qpr2-s5-releaseandroid13-qpr2-s3-releaseandroid13-qpr2-s2-releaseandroid13-qpr2-s12-releaseandroid13-qpr2-s11-releaseandroid13-qpr2-s10-releaseandroid13-qpr2-s1-releaseandroid13-qpr2-releaseandroid13-qpr2-b-s1-releaseandroid13-qpr1-s8-releaseandroid13-qpr1-s7-releaseandroid13-qpr1-s6-releaseandroid13-qpr1-s5-releaseandroid13-qpr1-s4-releaseandroid13-qpr1-s3-releaseandroid13-qpr1-s2-releaseandroid13-qpr1-s1-releaseandroid13-qpr1-releaseandroid13-mainline-uwb-releaseandroid13-mainline-tzdata4-releaseandroid13-mainline-go-wifi-releaseandroid13-mainline-go-uwb-releaseandroid13-mainline-go-tzdata4-releaseandroid13-mainline-go-tethering-releaseandroid13-mainline-go-sdkext-releaseandroid13-mainline-go-scheduling-releaseandroid13-mainline-go-resolv-releaseandroid13-mainline-go-permission-releaseandroid13-mainline-go-os-statsd-releaseandroid13-mainline-go-odp-releaseandroid13-mainline-go-neuralnetworks-releaseandroid13-mainline-go-networking-releaseandroid13-mainline-go-mediaprovider-releaseandroid13-mainline-go-media-swcodec-releaseandroid13-mainline-go-appsearch-releaseandroid13-mainline-go-adservices-releaseandroid13-mainline-go-adbd-releaseandroid13-mainline-appsearch-releaseandroid13-mainline-adservices-releaseandroid13-frc-odp-releaseandroid13-frc-conscrypt-releaseandroid13-frc-cellbroadcast-releaseandroid13-frc-art-releaseandroid13-frc-adbd-releaseandroid13-devandroid13-d4-s2-releaseandroid13-d4-s1-releaseandroid13-d4-releaseandroid13-d3-s1-releaseandroid13-d2-releaseaml_tz5_341510010aml_tz4_332714010
Original change: https://android-review.googlesource.com/c/platform/external/volley/+/1758419 Change-Id: I7191d1e2ebb6c416909593386dbbd3481241bf8c
Diffstat (limited to 'core/src/test/java/com/android/volley/toolbox/BasicAsyncNetworkTest.java')
-rw-r--r--core/src/test/java/com/android/volley/toolbox/BasicAsyncNetworkTest.java508
1 files changed, 508 insertions, 0 deletions
diff --git a/core/src/test/java/com/android/volley/toolbox/BasicAsyncNetworkTest.java b/core/src/test/java/com/android/volley/toolbox/BasicAsyncNetworkTest.java
new file mode 100644
index 0000000..91d4062
--- /dev/null
+++ b/core/src/test/java/com/android/volley/toolbox/BasicAsyncNetworkTest.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.volley.toolbox;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.android.volley.AsyncNetwork;
+import com.android.volley.AuthFailureError;
+import com.android.volley.Cache.Entry;
+import com.android.volley.Header;
+import com.android.volley.NetworkResponse;
+import com.android.volley.NoConnectionError;
+import com.android.volley.Request;
+import com.android.volley.Response;
+import com.android.volley.RetryPolicy;
+import com.android.volley.ServerError;
+import com.android.volley.TimeoutError;
+import com.android.volley.VolleyError;
+import com.android.volley.mock.MockAsyncStack;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class BasicAsyncNetworkTest {
+
+ @Mock private RetryPolicy mMockRetryPolicy;
+ @Mock private AsyncNetwork.OnRequestComplete mockCallback;
+ private ExecutorService executor = MoreExecutors.newDirectExecutorService();
+
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ }
+
+ @Test
+ public void headersAndPostParams() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse =
+ new HttpResponse(
+ 200,
+ Collections.<Header>emptyList(),
+ "foobar".getBytes(StandardCharsets.UTF_8));
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ Entry entry = new Entry();
+ entry.etag = "foobar";
+ entry.lastModified = 1503102002000L;
+ request.setCacheEntry(entry);
+ perform(request, httpNetwork).get();
+ assertEquals("foo", mockAsyncStack.getLastHeaders().get("requestheader"));
+ assertEquals("foobar", mockAsyncStack.getLastHeaders().get("If-None-Match"));
+ assertEquals(
+ "Sat, 19 Aug 2017 00:20:02 GMT",
+ mockAsyncStack.getLastHeaders().get("If-Modified-Since"));
+ assertEquals(
+ "requestpost=foo&",
+ new String(mockAsyncStack.getLastPostBody(), StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void headersAndPostParamsStream() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ ByteArrayInputStream stream = new ByteArrayInputStream("foobar".getBytes("UTF-8"));
+ HttpResponse fakeResponse =
+ new HttpResponse(200, Collections.<Header>emptyList(), 6, stream);
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ Entry entry = new Entry();
+ entry.etag = "foobar";
+ entry.lastModified = 1503102002000L;
+ request.setCacheEntry(entry);
+ perform(request, httpNetwork).get();
+ assertEquals("foo", mockAsyncStack.getLastHeaders().get("requestheader"));
+ assertEquals("foobar", mockAsyncStack.getLastHeaders().get("If-None-Match"));
+ assertEquals(
+ "Sat, 19 Aug 2017 00:20:02 GMT",
+ mockAsyncStack.getLastHeaders().get("If-Modified-Since"));
+ assertEquals(
+ "requestpost=foo&",
+ new String(mockAsyncStack.getLastPostBody(), StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void notModified() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ List<Header> headers = new ArrayList<>();
+ headers.add(new Header("ServerKeyA", "ServerValueA"));
+ headers.add(new Header("ServerKeyB", "ServerValueB"));
+ headers.add(new Header("SharedKey", "ServerValueShared"));
+ headers.add(new Header("sharedcaseinsensitivekey", "ServerValueShared1"));
+ headers.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2"));
+ HttpResponse fakeResponse = new HttpResponse(HttpURLConnection.HTTP_NOT_MODIFIED, headers);
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ Entry entry = new Entry();
+ entry.allResponseHeaders = new ArrayList<>();
+ entry.allResponseHeaders.add(new Header("CachedKeyA", "CachedValueA"));
+ entry.allResponseHeaders.add(new Header("CachedKeyB", "CachedValueB"));
+ entry.allResponseHeaders.add(new Header("SharedKey", "CachedValueShared"));
+ entry.allResponseHeaders.add(new Header("SHAREDCASEINSENSITIVEKEY", "CachedValueShared1"));
+ entry.allResponseHeaders.add(new Header("shAREDcaSEinSENSITIVEkeY", "CachedValueShared2"));
+ request.setCacheEntry(entry);
+ httpNetwork.performRequest(request, mockCallback);
+ NetworkResponse response = perform(request, httpNetwork).get();
+ List<Header> expectedHeaders = new ArrayList<>();
+ // Should have all server headers + cache headers that didn't show up in server response.
+ expectedHeaders.add(new Header("ServerKeyA", "ServerValueA"));
+ expectedHeaders.add(new Header("ServerKeyB", "ServerValueB"));
+ expectedHeaders.add(new Header("SharedKey", "ServerValueShared"));
+ expectedHeaders.add(new Header("sharedcaseinsensitivekey", "ServerValueShared1"));
+ expectedHeaders.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2"));
+ expectedHeaders.add(new Header("CachedKeyA", "CachedValueA"));
+ expectedHeaders.add(new Header("CachedKeyB", "CachedValueB"));
+ assertThat(expectedHeaders, containsInAnyOrder(response.allHeaders.toArray(new Header[0])));
+ }
+
+ @Test
+ public void notModified_legacyCache() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ List<Header> headers = new ArrayList<>();
+ headers.add(new Header("ServerKeyA", "ServerValueA"));
+ headers.add(new Header("ServerKeyB", "ServerValueB"));
+ headers.add(new Header("SharedKey", "ServerValueShared"));
+ headers.add(new Header("sharedcaseinsensitivekey", "ServerValueShared1"));
+ headers.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2"));
+ HttpResponse fakeResponse = new HttpResponse(HttpURLConnection.HTTP_NOT_MODIFIED, headers);
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ Entry entry = new Entry();
+ entry.responseHeaders = new HashMap<>();
+ entry.responseHeaders.put("CachedKeyA", "CachedValueA");
+ entry.responseHeaders.put("CachedKeyB", "CachedValueB");
+ entry.responseHeaders.put("SharedKey", "CachedValueShared");
+ entry.responseHeaders.put("SHAREDCASEINSENSITIVEKEY", "CachedValueShared1");
+ entry.responseHeaders.put("shAREDcaSEinSENSITIVEkeY", "CachedValueShared2");
+ request.setCacheEntry(entry);
+ NetworkResponse response = perform(request, httpNetwork).get();
+ List<Header> expectedHeaders = new ArrayList<>();
+ // Should have all server headers + cache headers that didn't show up in server response.
+ expectedHeaders.add(new Header("ServerKeyA", "ServerValueA"));
+ expectedHeaders.add(new Header("ServerKeyB", "ServerValueB"));
+ expectedHeaders.add(new Header("SharedKey", "ServerValueShared"));
+ expectedHeaders.add(new Header("sharedcaseinsensitivekey", "ServerValueShared1"));
+ expectedHeaders.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2"));
+ expectedHeaders.add(new Header("CachedKeyA", "CachedValueA"));
+ expectedHeaders.add(new Header("CachedKeyB", "CachedValueB"));
+ assertThat(expectedHeaders, containsInAnyOrder(response.allHeaders.toArray(new Header[0])));
+ }
+
+ @Test
+ public void socketTimeout() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ mockAsyncStack.setExceptionToThrow(new SocketTimeoutException());
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should retry socket timeouts
+ verify(mMockRetryPolicy).retry(any(TimeoutError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+
+ @Test
+ public void noConnectionDefault() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ mockAsyncStack.setExceptionToThrow(new IOException());
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should not retry when there is no connection
+ verify(mMockRetryPolicy, never()).retry(any(VolleyError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+
+ @Test
+ public void noConnectionRetry() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ mockAsyncStack.setExceptionToThrow(new IOException());
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ request.setShouldRetryConnectionErrors(true);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should retry when there is no connection
+ verify(mMockRetryPolicy).retry(any(NoConnectionError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+
+ @Test
+ public void noConnectionNoRetry() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ mockAsyncStack.setExceptionToThrow(new IOException());
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ request.setShouldRetryConnectionErrors(false);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should not retry when there is no connection
+ verify(mMockRetryPolicy, never()).retry(any(VolleyError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+
+ @Test
+ public void unauthorized() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse = new HttpResponse(401, Collections.<Header>emptyList());
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should retry in case it's an auth failure.
+ verify(mMockRetryPolicy).retry(any(AuthFailureError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void malformedUrlRequest() throws VolleyError, ExecutionException, InterruptedException {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ mockAsyncStack.setExceptionToThrow(new MalformedURLException());
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ perform(request, httpNetwork).get();
+ }
+
+ @Test
+ public void forbidden() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse = new HttpResponse(403, Collections.<Header>emptyList());
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should retry in case it's an auth failure.
+ verify(mMockRetryPolicy).retry(any(AuthFailureError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+
+ @Test
+ public void redirect() throws Exception {
+ for (int i = 300; i <= 399; i++) {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse = new HttpResponse(i, Collections.<Header>emptyList());
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ if (i != 304) {
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ } else {
+ verify(mockCallback, never()).onError(any(VolleyError.class));
+ verify(mockCallback, times(1)).onSuccess(any(NetworkResponse.class));
+ }
+ // should not retry 300 responses.
+ verify(mMockRetryPolicy, never()).retry(any(VolleyError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+ }
+
+ @Test
+ public void otherClientError() throws Exception {
+ for (int i = 400; i <= 499; i++) {
+ if (i == 401 || i == 403) {
+ // covered above.
+ continue;
+ }
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse = new HttpResponse(i, Collections.<Header>emptyList());
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should not retry other 400 errors.
+ verify(mMockRetryPolicy, never()).retry(any(VolleyError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+ }
+
+ @Test
+ public void serverError_enableRetries() throws Exception {
+ for (int i = 500; i <= 599; i++) {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse = new HttpResponse(i, Collections.<Header>emptyList());
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork =
+ new BasicAsyncNetwork.Builder(mockAsyncStack)
+ .setPool(new ByteArrayPool(4096))
+ .build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ request.setShouldRetryServerErrors(true);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should retry all 500 errors
+ verify(mMockRetryPolicy).retry(any(ServerError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+ }
+
+ @Test
+ public void serverError_disableRetries() throws Exception {
+ for (int i = 500; i <= 599; i++) {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse = new HttpResponse(i, Collections.<Header>emptyList());
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ request.setRetryPolicy(mMockRetryPolicy);
+ doThrow(new VolleyError()).when(mMockRetryPolicy).retry(any(VolleyError.class));
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onError(any(VolleyError.class));
+ verify(mockCallback, never()).onSuccess(any(NetworkResponse.class));
+ // should not retry any 500 error w/ HTTP 500 retries turned off (the default).
+ verify(mMockRetryPolicy, never()).retry(any(VolleyError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+ }
+
+ @Test
+ public void notModifiedShortCircuit() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ List<Header> headers = new ArrayList<>();
+ headers.add(new Header("ServerKeyA", "ServerValueA"));
+ headers.add(new Header("ServerKeyB", "ServerValueB"));
+ headers.add(new Header("SharedKey", "ServerValueShared"));
+ headers.add(new Header("sharedcaseinsensitivekey", "ServerValueShared1"));
+ headers.add(new Header("SharedCaseInsensitiveKey", "ServerValueShared2"));
+ HttpResponse fakeResponse = new HttpResponse(HttpURLConnection.HTTP_NOT_MODIFIED, headers);
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onSuccess(any(NetworkResponse.class));
+ verify(mockCallback, never()).onError(any(VolleyError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+
+ @Test
+ public void performRequestSuccess() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse =
+ new HttpResponse(
+ 200,
+ Collections.<Header>emptyList(),
+ "foobar".getBytes(StandardCharsets.UTF_8));
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ httpNetwork.setBlockingExecutor(executor);
+ Request<String> request = buildRequest();
+ Entry entry = new Entry();
+ entry.etag = "foobar";
+ entry.lastModified = 1503102002000L;
+ request.setCacheEntry(entry);
+ httpNetwork.performRequest(request, mockCallback);
+ verify(mockCallback, times(1)).onSuccess(any(NetworkResponse.class));
+ verify(mockCallback, never()).onError(any(VolleyError.class));
+ reset(mMockRetryPolicy, mockCallback);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void performRequestNeverSetExecutorTest() throws Exception {
+ MockAsyncStack mockAsyncStack = new MockAsyncStack();
+ HttpResponse fakeResponse = new HttpResponse(200, Collections.<Header>emptyList());
+ mockAsyncStack.setResponseToReturn(fakeResponse);
+ BasicAsyncNetwork httpNetwork = new BasicAsyncNetwork.Builder(mockAsyncStack).build();
+ Request<String> request = buildRequest();
+ perform(request, httpNetwork).get();
+ }
+
+ /** Helper functions */
+ private CompletableFuture<NetworkResponse> perform(Request<?> request, AsyncNetwork network)
+ throws VolleyError {
+ final CompletableFuture<NetworkResponse> future = new CompletableFuture<>();
+ network.performRequest(
+ request,
+ new AsyncNetwork.OnRequestComplete() {
+ @Override
+ public void onSuccess(NetworkResponse networkResponse) {
+ future.complete(networkResponse);
+ }
+
+ @Override
+ public void onError(VolleyError volleyError) {
+ future.complete(null);
+ }
+ });
+ return future;
+ }
+
+ private static Request<String> buildRequest() {
+ return new Request<String>(Request.Method.GET, "http://foo", null) {
+
+ @Override
+ protected Response<String> parseNetworkResponse(NetworkResponse response) {
+ return null;
+ }
+
+ @Override
+ protected void deliverResponse(String response) {}
+
+ @Override
+ public Map<String, String> getHeaders() {
+ Map<String, String> result = new HashMap<String, String>();
+ result.put("requestheader", "foo");
+ return result;
+ }
+
+ @Override
+ public Map<String, String> getParams() {
+ Map<String, String> result = new HashMap<String, String>();
+ result.put("requestpost", "foo");
+ return result;
+ }
+ };
+ }
+}