package com.mopub.nativeads;
import android.app.Activity;
import android.os.Build.VERSION_CODES;
import com.mopub.common.DownloadResponse;
import com.mopub.common.test.support.SdkTestRunner;
import com.mopub.nativeads.MoPubNativeAdPositioning.MoPubClientPositioning;
import com.mopub.nativeads.PositioningSource.PositioningListener;
import com.mopub.network.Networking;
import com.mopub.volley.Request;
import com.mopub.volley.RequestQueue;
import com.mopub.volley.VolleyError;
import org.apache.http.HttpStatus;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SdkTestRunner.class)
public class ServerPositioningSourceTest {
@Mock PositioningListener mockPositioningListener;
@Captor ArgumentCaptor<PositioningRequest> positionRequestCaptor;
@Mock DownloadResponse mockValidResponse;
@Mock DownloadResponse mockNotFoundResponse;
@Mock DownloadResponse mockInvalidJsonResponse;
@Mock DownloadResponse mockWarmingUpJsonResponse;
@Mock
RequestQueue mockRequestQueue;
@Captor ArgumentCaptor<MoPubClientPositioning> positioningCaptor;
ServerPositioningSource subject;
@Before
public void setUp() {
Activity activity = Robolectric.buildActivity(Activity.class).create().get();
subject = new ServerPositioningSource(activity);
Networking.setRequestQueueForTesting(mockRequestQueue);
when(mockValidResponse.getStatusCode()).thenReturn(HttpStatus.SC_OK);
when(mockValidResponse.getByteArray()).thenReturn("{fixed: []}".getBytes());
when(mockInvalidJsonResponse.getStatusCode()).thenReturn(HttpStatus.SC_OK);
when(mockInvalidJsonResponse.getByteArray()).thenReturn("blah blah".getBytes());
when(mockWarmingUpJsonResponse.getStatusCode()).thenReturn(HttpStatus.SC_OK);
when(mockWarmingUpJsonResponse.getByteArray()).thenReturn(
"{\"error\":\"WARMING_UP\"}".getBytes());
when(mockNotFoundResponse.getStatusCode()).thenReturn(HttpStatus.SC_NOT_FOUND);
}
@Test
public void loadPositions_shouldAddToRequestQueue() {
subject.loadPositions("test_ad_unit", mockPositioningListener);
verify(mockRequestQueue).add(any(Request.class));
}
@Test
public void loadPositionsTwice_shouldCancelPreviousRequest_shouldNotCallListener() {
subject.loadPositions("test_ad_unit", mockPositioningListener);
subject.loadPositions("test_ad_unit", mockPositioningListener);
verify(mockRequestQueue, times(2)).add(any(Request.class));
verify(mockPositioningListener, never()).onFailed();
verify(mockPositioningListener, never()).onLoad(any(MoPubClientPositioning.class));
}
@Test
public void loadPositionsTwice_afterSuccess_shouldNotCancelPreviousRequest() {
subject.loadPositions("test_ad_unit", mockPositioningListener);
verify(mockRequestQueue).add(positionRequestCaptor.capture());
reset(mockRequestQueue);
subject.loadPositions("test_ad_unit", mockPositioningListener);
verify(mockRequestQueue).add(any(Request.class));
}
@Test
public void loadPositions_thenComplete_withValidResponse_shouldCallOnLoadListener() {
subject.loadPositions("test_ad_unit", mockPositioningListener);
verify(mockRequestQueue).add(positionRequestCaptor.capture());
final PositioningRequest value = positionRequestCaptor.getValue();
final MoPubClientPositioning response = new MoPubClientPositioning().enableRepeatingPositions(3);
value.deliverResponse(response);
verify(mockPositioningListener).onLoad(eq(response));
}
@Config(reportSdk = VERSION_CODES.ICE_CREAM_SANDWICH)
@Test
public void loadPositions_thenComplete_withErrorResponse_shouldRetry() throws Exception {
subject.loadPositions("test_ad_unit", mockPositioningListener);
verify(mockRequestQueue).add(positionRequestCaptor.capture());
reset(mockRequestQueue);
// We get VolleyErrors for invalid JSON, 404s, 5xx, and {"error": "WARMING_UP"}
positionRequestCaptor.getValue().deliverError(new VolleyError("Some test error"));
Robolectric.getUiThreadScheduler().advanceToLastPostedRunnable();
verify(mockRequestQueue).add(any(Request.class));
}
@Config(reportSdk = VERSION_CODES.ICE_CREAM_SANDWICH)
@Test
public void loadPositions_withPendingRetry_shouldNotRetry() {
subject.loadPositions("test_ad_unit", mockPositioningListener);
verify(mockRequestQueue).add(positionRequestCaptor.capture());
reset(mockRequestQueue);
positionRequestCaptor.getValue().deliverError(new VolleyError("testError"));
subject.loadPositions("test_ad_unit", mockPositioningListener);
Robolectric.getUiThreadScheduler().advanceToLastPostedRunnable();
// If a retry happened, we'd have two here.
verify(mockRequestQueue).add(any(Request.class));
}
@Test
public void loadPositions_thenFailAfterMaxRetryTime_shouldCallFailureHandler() {
ServerPositioningSource.MAXIMUM_RETRY_TIME_MILLISECONDS = 999;
subject.loadPositions("test_ad_unit", mockPositioningListener);
verify(mockRequestQueue).add(positionRequestCaptor.capture());
positionRequestCaptor.getValue().deliverError(new VolleyError("test error"));
verify(mockPositioningListener).onFailed();
}
}