blob: 0e94c079e95f230cb49984621f1ef18a1b4f2bce [file] [log] [blame]
package org.wordpress.android.util;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.test.InstrumentationTestCase;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.mockwebserver.Dispatcher;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.wordpress.android.TestUtils;
import org.wordpress.android.WordPress;
import org.xmlrpc.android.LoggedInputStream;
import org.xmlrpc.android.XMLRPCUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
public class HealthCheckTest extends InstrumentationTestCase {
private static final String sAssetPathBase = "health-check/";
private static final String sServerAddressMagicString = "mockserver";
private static final String sServerResponsesMagicScheme = "asset:";
private void setLocale(String language, String country) {
Locale locale = new Locale(language, country);
Locale.setDefault(locale);
Resources res = getInstrumentation().getTargetContext().getResources();
Configuration config = res.getConfiguration();
config.locale = locale;
res.updateConfiguration(config, res.getDisplayMetrics());
}
@Override
protected void setUp() {
WordPress.setupVolleyQueue();
// set the app locale to english since the tests only support English for now
setLocale("en", "US");
}
@Override
protected void tearDown() {
}
private static String stringFromAsset(Context context, String assetFilename) throws IOException {
LoggedInputStream mLoggedInputStream = new LoggedInputStream(context.getAssets().open(assetFilename));
return TestUtils.convertStreamToString(mLoggedInputStream);
}
private static JSONObject jsonFromAsset(Context context, String assetFilename) throws IOException, JSONException {
return new JSONObject(stringFromAsset(context, assetFilename));
}
public void testHealthCheckXplat() throws JSONException, IOException {
JSONArray testCases = jsonFromAsset(getInstrumentation().getContext(), sAssetPathBase +
"health-check-xplat-testcases.json").getJSONArray("testcases");
for (int i = 0; i < testCases.length(); i++) {
final JSONObject testCase = testCases.getJSONObject(i);
final String testCaseComment = testCase.getString("comment");
final JSONObject testSetup = testCase.getJSONObject("setup");
final String realm = testCase.getString("realm");
switch (realm) {
case "URL_CANONICALIZATION":
runUrlCanonicalization(testCaseComment, testSetup);
break;
case "XMLPRC_DISCOVERY":
runXmlrpcDiscovery(testCaseComment, testSetup);
break;
default:
// fail the testsuite
assertTrue("health-check realm " + realm + " is not supported!", false);
break;
}
}
}
private void runUrlCanonicalization(String testCaseComment, JSONObject testSetup) throws JSONException {
final JSONObject input = testSetup.getJSONObject("input");
final String inputUrl = input.isNull("siteUrl") ? null : input.getString("siteUrl");
final JSONObject output = testSetup.getJSONObject("output");
final String outputUrl = output.optString("siteUrl", null);
final JSONObject error = output.optJSONObject("error");
String canonicalizedUrl = null;
try {
canonicalizedUrl = XMLRPCUtils.sanitizeSiteUrl(inputUrl, true);
// if we reached this point, it means that no error occurred
assertNull(testCaseMessage("Testcase defines an error but no error occurred!", testCaseComment), error);
} catch (XMLRPCUtils.XMLRPCUtilsException hce) {
assertNotNull(testCaseMessage("Error occurred but testcase does not define an error!", testCaseComment),
error);
assertEquals(testCaseMessage("Error message does not match the defined one!", testCaseComment), error
.getString("message"), getInstrumentation().getTargetContext().getString(hce.errorMsgId));
}
assertEquals(testCaseMessage("Canonicalized URL does not match the defined one!", testCaseComment),
outputUrl, canonicalizedUrl);
}
private void runXmlrpcDiscovery(String testCaseComment, JSONObject testSetup) throws JSONException, IOException {
final MockWebServer server = new MockWebServer();
testSetup = new JSONObject(replaceServerMagicName(server, testSetup.toString()));
final JSONObject input = testSetup.getJSONObject("input");
setupMockHttpServer(server, input);
final String inputUrl = input.isNull("siteUrl") ? server.url("").toString() : input.getString("siteUrl");
final JSONObject output = testSetup.getJSONObject("output");
final String outputUrl = output.optString("xmlrpcEndpoint", null);
final JSONObject error = output.optJSONObject("error");
String xmlrpcUrl = null;
try {
xmlrpcUrl = XMLRPCUtils.verifyOrDiscoverXmlRpcUrl(inputUrl, input.optString("username", null), input
.optString("username", null));
// if we reached this point, it means that no error occurred
assertNull(testCaseMessage("Testcase defines an error but no error occurred!", testCaseComment), error);
} catch (XMLRPCUtils.XMLRPCUtilsException hce) {
assertNotNull(testCaseMessage("Error occurred but testcase does not define an error!", testCaseComment),
error);
assertEquals(testCaseMessage("Error message does not match the defined one!", testCaseComment), error
.getString("message"), getInstrumentation().getTargetContext().getString(hce.errorMsgId));
}
assertEquals(testCaseMessage("XMLRPC URL does not match the defined one!", testCaseComment), outputUrl,
xmlrpcUrl);
server.shutdown();
}
private MockWebServer setupMockHttpServer(MockWebServer server, JSONObject requestResponsesJson) throws
JSONException, IOException {
final Map<RecordedRequest, MockResponse> mockRequestResponses = new HashMap<>();
final JSONArray serverMock = requestResponsesJson.getJSONArray("serverMock");
for (int i = 0; i < serverMock.length(); i++) {
final JSONObject reqRespJson = serverMock.getJSONObject(i);
final JSONObject reqJson = reqRespJson.getJSONObject("request");
Headers reqHeaders = json2Headers(reqJson.optJSONObject("headers"));
RecordedRequest recordedRequest = new RecordedRequest(reqJson.getString("method") + " " + reqJson
.getString("path") + " HTTP/1.1", reqHeaders, null, 0, null, 0, null);
final JSONObject respJson = reqRespJson.getJSONObject("response");
Headers respHeaders = json2Headers(respJson.optJSONObject("headers"));
String body = respJson.optString("body");
if (body.startsWith(sServerResponsesMagicScheme)) {
body = stringFromAsset(getInstrumentation().getContext(), sAssetPathBase + body.substring
(sServerResponsesMagicScheme.length()));
}
body = replaceServerMagicName(server, body);
final MockResponse resp = new MockResponse()
.setResponseCode(respJson.getInt("statusCode"))
.setHeaders(respHeaders)
.setBody(body);
mockRequestResponses.put(recordedRequest, resp);
}
server.setDispatcher(new Dispatcher() {
@Override
public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
for (Map.Entry<RecordedRequest, MockResponse> reqResp : mockRequestResponses.entrySet()) {
final RecordedRequest mockRequest = reqResp.getKey();
if (mockRequest.getRequestLine().equals(request.getRequestLine())) {
return reqResp.getValue();
}
}
return new MockResponse().setResponseCode(404).setBody("");
}
});
return server;
}
private String replaceServerMagicName(MockWebServer server, String str) {
return str.replaceAll(sServerAddressMagicString, server.getHostName() + ":" + server.getPort());
}
private Headers json2Headers(JSONObject headersJson) throws JSONException {
if (headersJson != null) {
Headers.Builder headBuilder = new Headers.Builder();
Iterator<String> headerKeys = headersJson.keys();
while (headerKeys.hasNext()) {
final String headerName = headerKeys.next();
headBuilder.add(headerName, headersJson.getString(headerName));
}
return headBuilder.build();
}
return new Headers.Builder().build();
}
private String testCaseMessage(String message, String testCaseComment) {
return message + " (on testCase: '" + testCaseComment + "')";
}
}