| 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 + "')"; |
| } |
| } |