/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.android.sync.net.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.json.simple.JSONObject;
import org.junit.Test;
import org.mozilla.android.sync.test.helpers.BaseTestStorageRequestDelegate;
import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
import org.mozilla.android.sync.test.helpers.MockServer;
import org.mozilla.gecko.sync.net.BaseResource;
import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
import org.mozilla.gecko.sync.net.SyncStorageResponse;
import org.simpleframework.http.Request;
import org.simpleframework.http.Response;
public class TestSyncStorageRequest {
private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
private static final String LOCAL_META_URL = TEST_SERVER + "/1.1/c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd/storage/meta/global";
private static final String LOCAL_BAD_REQUEST_URL = TEST_SERVER + "/1.1/c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd/storage/bad";
private static final String EXPECTED_ERROR_CODE = "12";
private static final String EXPECTED_RETRY_AFTER_ERROR_MESSAGE = "{error:'informative error message'}";
// Corresponds to rnewman+testandroid@mozilla.com.
private static final String USER_PASS = "c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd:password";
private HTTPServerTestHelper data = new HTTPServerTestHelper();
public class TestSyncStorageRequestDelegate extends
BaseTestStorageRequestDelegate {
@Override
public void handleRequestSuccess(SyncStorageResponse res) {
assertTrue(res.wasSuccessful());
assertTrue(res.httpResponse().containsHeader("X-Weave-Timestamp"));
// Make sure we consume the rest of the body, so we can reuse the
// connection. Even test code has to be correct in this regard!
try {
System.out.println("Success body: " + res.body());
} catch (Exception e) {
e.printStackTrace();
}
BaseResource.consumeEntity(res);
data.stopHTTPServer();
}
}
public class TestBadSyncStorageRequestDelegate extends
BaseTestStorageRequestDelegate {
@Override
public void handleRequestFailure(SyncStorageResponse res) {
assertTrue(!res.wasSuccessful());
assertTrue(res.httpResponse().containsHeader("X-Weave-Timestamp"));
try {
String responseMessage = res.getErrorMessage();
String expectedMessage = SyncStorageResponse.SERVER_ERROR_MESSAGES.get(EXPECTED_ERROR_CODE);
assertEquals(expectedMessage, responseMessage);
} catch (Exception e) {
fail("Got exception fetching error message.");
}
BaseResource.consumeEntity(res);
data.stopHTTPServer();
}
}
@Test
public void testSyncStorageRequest() throws URISyntaxException, IOException {
BaseResource.rewriteLocalhost = false;
data.startHTTPServer();
SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_META_URL));
TestSyncStorageRequestDelegate delegate = new TestSyncStorageRequestDelegate();
delegate._credentials = USER_PASS;
r.delegate = delegate;
r.get();
// Server is stopped in the callback.
}
public class ErrorMockServer extends MockServer {
@Override
public void handle(Request request, Response response) {
super.handle(request, response, 400, EXPECTED_ERROR_CODE);
}
}
@Test
public void testErrorResponse() throws URISyntaxException {
BaseResource.rewriteLocalhost = false;
data.startHTTPServer(new ErrorMockServer());
SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_BAD_REQUEST_URL));
TestBadSyncStorageRequestDelegate delegate = new TestBadSyncStorageRequestDelegate();
delegate._credentials = USER_PASS;
r.delegate = delegate;
r.post(new JSONObject());
// Server is stopped in the callback.
}
// Test that the Retry-After header is correctly parsed and that handleRequestFailure
// is being called.
public class TestRetryAfterSyncStorageRequestDelegate extends
BaseTestStorageRequestDelegate {
@Override
public void handleRequestFailure(SyncStorageResponse res) {
assertTrue(!res.wasSuccessful());
assertTrue(res.httpResponse().containsHeader("Retry-After"));
assertEquals(res.retryAfterInSeconds(), 3001);
try {
String responseMessage = res.getErrorMessage();
String expectedMessage = EXPECTED_RETRY_AFTER_ERROR_MESSAGE;
assertEquals(expectedMessage, responseMessage);
} catch (Exception e) {
fail("Got exception fetching error message.");
}
BaseResource.consumeEntity(res);
data.stopHTTPServer();
}
}
public class RetryAfterMockServer extends MockServer {
@Override
public void handle(Request request, Response response) {
String errorBody = EXPECTED_RETRY_AFTER_ERROR_MESSAGE;
response.set("Retry-After", "3001");
super.handle(request, response, 503, errorBody);
}
}
@Test
public void testRetryAfterResponse() throws URISyntaxException {
BaseResource.rewriteLocalhost = false;
data.startHTTPServer(new RetryAfterMockServer());
SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_BAD_REQUEST_URL)); // URL not used -- we 503 every response
TestRetryAfterSyncStorageRequestDelegate delegate = new TestRetryAfterSyncStorageRequestDelegate();
r.delegate = delegate;
r.post(new JSONObject());
// Server is stopped in the callback.
}
// Test that the X-Weave-Backoff header is correctly parsed and that handleRequestSuccess
// is still being called.
public class TestWeaveBackoffSyncStorageRequestDelegate extends
TestSyncStorageRequestDelegate {
@Override
public void handleRequestSuccess(SyncStorageResponse res) {
assertTrue(res.httpResponse().containsHeader("X-Weave-Backoff"));
assertEquals(res.weaveBackoffInSeconds(), 1801);
super.handleRequestSuccess(res);
}
}
public class WeaveBackoffMockServer extends MockServer {
@Override
public void handle(Request request, Response response) {
response.set("X-Weave-Backoff", "1801");
super.handle(request, response);
}
}
@Test
public void testWeaveBackoffResponse() throws URISyntaxException {
BaseResource.rewriteLocalhost = false;
data.startHTTPServer(new WeaveBackoffMockServer());
SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_META_URL)); // URL re-used -- we need any successful response
TestWeaveBackoffSyncStorageRequestDelegate delegate = new TestWeaveBackoffSyncStorageRequestDelegate();
delegate._credentials = USER_PASS;
r.delegate = delegate;
r.post(new JSONObject());
// Server is stopped in the callback.
}
// Test that the X-Weave-{Quota-Remaining, Alert, Records} headers are correctly parsed and
// that handleRequestSuccess is still being called.
public class TestHeadersSyncStorageRequestDelegate extends
TestSyncStorageRequestDelegate {
@Override
public void handleRequestSuccess(SyncStorageResponse res) {
assertTrue(res.httpResponse().containsHeader("X-Weave-Quota-Remaining"));
assertTrue(res.httpResponse().containsHeader("X-Weave-Alert"));
assertTrue(res.httpResponse().containsHeader("X-Weave-Records"));
assertEquals(65536, res.weaveQuotaRemaining());
assertEquals("First weave alert string", res.weaveAlert());
assertEquals(50, res.weaveRecords());
super.handleRequestSuccess(res);
}
}
public class HeadersMockServer extends MockServer {
@Override
public void handle(Request request, Response response) {
response.set("X-Weave-Quota-Remaining", "65536");
response.set("X-Weave-Alert", "First weave alert string");
response.add("X-Weave-Alert", "Second weave alert string");
response.set("X-Weave-Records", "50");
super.handle(request, response);
}
}
@Test
public void testHeadersResponse() throws URISyntaxException {
BaseResource.rewriteLocalhost = false;
data.startHTTPServer(new HeadersMockServer());
SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_META_URL)); // URL re-used -- we need any successful response
TestHeadersSyncStorageRequestDelegate delegate = new TestHeadersSyncStorageRequestDelegate();
delegate._credentials = USER_PASS;
r.delegate = delegate;
r.post(new JSONObject());
// Server is stopped in the callback.
}
public class DeleteMockServer extends MockServer {
@Override
public void handle(Request request, Response response) {
assertTrue(request.contains("x-confirm-delete"));
assertEquals("1", request.getValue("x-confirm-delete"));
super.handle(request, response);
}
}
@Test
public void testDelete() throws URISyntaxException {
BaseResource.rewriteLocalhost = false;
data.startHTTPServer(new DeleteMockServer());
SyncStorageRecordRequest r = new SyncStorageRecordRequest(new URI(LOCAL_META_URL)); // URL re-used -- we need any successful response
TestSyncStorageRequestDelegate delegate = new TestSyncStorageRequestDelegate();
delegate._credentials = USER_PASS;
r.delegate = delegate;
r.delete();
// Server is stopped in the callback.
}
}