package com.pivotallabs.api;

import com.xtremelabs.robolectric.Robolectric;
import com.xtremelabs.robolectric.RobolectricTestRunner;
import com.xtremelabs.robolectric.util.HttpRequestData;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthScope;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Map;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;

@RunWith(RobolectricTestRunner.class)
public class ApiGatewayTest {
    private ApiGateway apiGateway;
    private TestApiResponseCallbacks responseCallbacks;

    @Before
    public void setUp() throws Exception {
        apiGateway = new ApiGateway();
        responseCallbacks = new TestApiResponseCallbacks();
    }

    @Test
    public void dispatch_shouldCallOntoTheSuccessWhenApiResponseIsSuccess() throws Exception {
        ApiResponse apiResponse = new ApiResponse(200, "response body");
        apiGateway.dispatch(apiResponse, responseCallbacks);

        assertThat(responseCallbacks.successResponse, sameInstance(apiResponse));
        assertThat(responseCallbacks.failureResponse, nullValue());
        assertThat(responseCallbacks.onCompleteWasCalled, equalTo(true));
    }

    @Test
    public void dispatch_shouldCallOnFailureWhenApiResponseIsFailure() throws Exception {
        ApiResponse apiResponse = new ApiResponse(500, "response body");
        apiGateway.dispatch(apiResponse, responseCallbacks);

        assertThat(responseCallbacks.failureResponse, sameInstance(apiResponse));
        assertThat(responseCallbacks.successResponse, nullValue());
        assertThat(responseCallbacks.onCompleteWasCalled, equalTo(true));
    }

    @Test
    public void shouldMakeRemoteCalls() {
        ApiRequest apiRequest = new TestApiRequest();
        apiGateway.makeRequest(apiRequest, responseCallbacks);

        Robolectric.addPendingHttpResponse(200, "response body");

        Robolectric.backgroundScheduler.runOneTask();

        HttpRequestData sentHttpRequestData = Robolectric.getSentHttpRequestData(0);
        HttpRequest sentHttpRequest = sentHttpRequestData.getHttpRequest();
        assertThat(sentHttpRequest.getRequestLine().getUri(), equalTo("www.example.com"));
        assertThat(sentHttpRequest.getRequestLine().getMethod(), equalTo(HttpGet.METHOD_NAME));

        assertThat(sentHttpRequest.getHeaders("foo")[0].getValue(), equalTo("bar"));

        CredentialsProvider credentialsProvider =
                (CredentialsProvider) sentHttpRequestData.getHttpContext().getAttribute(ClientContext.CREDS_PROVIDER);
        assertThat(credentialsProvider.getCredentials(AuthScope.ANY).getUserPrincipal().getName(), CoreMatchers.equalTo("spongebob"));
        assertThat(credentialsProvider.getCredentials(AuthScope.ANY).getPassword(), CoreMatchers.equalTo("squarepants"));
    }

    @Test
    public void shouldDispatchUponReceivingResponse() throws Exception {
        Robolectric.addPendingHttpResponse(200, "response body");

        apiGateway.makeRequest(new TestApiRequest(), responseCallbacks);
        Robolectric.backgroundScheduler.runOneTask();

        assertThat(responseCallbacks.successResponse, nullValue());

        Robolectric.uiThreadScheduler.runOneTask();

        assertThat(responseCallbacks.successResponse.getResponseBody(), equalTo("response body\n"));
    }

    private class TestApiRequest extends ApiRequest {
        @Override public String getUrlString() {
            return "www.example.com";
        }

        @Override public Map<String, String> getParameters() {
            Map<String, String> parameters = super.getParameters();
            parameters.put("baz", "bang");
            return parameters;
        }

        @Override public Map<String, String> getHeaders() {
            Map<String, String> headers = super.getHeaders();
            headers.put("foo", "bar");
            return headers;
        }

        @Override public String getPostBody() {
            return super.getPostBody();
        }

        @Override public String getUsername() {
            return "spongebob";
        }

        @Override public String getPassword() {
            return "squarepants";
        }
    }
}

@@ -123,24 +123,83 @@
 TestRunner;%0A
+import com.xtremelabs.robolectric.shadows.ShadowAsyncTask;%0A
 import com.x
@@ -2112,24 +2112,82 @@
 teCalls() %7B%0A
+        ShadowAsyncTask.getAsyncTaskScheduler().pause();%0A%0A
         ApiR
@@ -2367,38 +2367,44 @@
         
-Robolectric.background
+ShadowAsyncTask.getAsyncTask
 Schedule
@@ -2396,32 +2396,34 @@
 yncTaskScheduler
+()
 .runOneTask();%0A%0A
@@ -3365,32 +3365,142 @@
 ows Exception %7B%0A
+        ShadowAsyncTask.getAsyncTaskScheduler().pause();%0A        Robolectric.getUiThreadScheduler().pause();%0A%0A
         Robolect
@@ -3541,32 +3541,32 @@
 esponse body%22);%0A
-
 %0A        apiGate
@@ -3635,30 +3635,36 @@
     
-Robolectric.background
+ShadowAsyncTask.getAsyncTask
 Sche
@@ -3660,32 +3660,34 @@
 yncTaskScheduler
+()
 .runOneTask();%0A%0A
@@ -3775,17 +3775,20 @@
 lectric.
-u
+getU
 iThreadS
@@ -3795,16 +3795,18 @@
 cheduler
+()
 .runOneT

Bring tests into alignment with robolectric