package org.edx.mobile.test.http;
import android.text.TextUtils;
import com.google.gson.JsonObject;
import org.edx.mobile.http.HttpStatus;
import org.edx.mobile.test.BaseTestCase;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Ignore;
import java.io.IOException;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
/**
* use MockWebService for Api test
* TODO - code refactoring need for OkHttpBaseTestCase and HttpBaseTestCase
* we need to depreciate OkHttpBaseTestCase soon.
*/
@Ignore
public class OkHttpBaseTestCase extends BaseTestCase {
private static final int DELAY_MS = 2000; // Network calls will take 2 seconds.
private static final int VARIANCE_PCT = 40; // Network delay varies by ±40%.
private static final int ERROR_PCT = 3; // 3% of network calls will fail.
private static final int ERROR_DELAY_FACTOR = 3; // Network errors will be scaled by this value.
private static final Random random = new Random(); // Random instance for determining delays
private static final String API_HOST_URL = "API_HOST_URL"; // Config key for API host url
// Use a mock server to serve fixed responses
protected MockWebServer server;
/**
* Returns the base url used by the mock server
*/
private String getBaseMockUrl() {
return "http://" + server.getHostName() + ":" + server.getPort();
}
@Override
public void setUp() throws Exception {
server = new MockWebServer();
server.setDispatcher(new MockResponseDispatcher());
server.start();
super.setUp();
}
@Override
protected JsonObject generateConfigProperties() throws IOException {
// Add the mock host url in the test config properties
JsonObject properties = super.generateConfigProperties();
properties.addProperty(API_HOST_URL, getBaseMockUrl());
return properties;
}
@Override
public void tearDown() throws Exception {
super.tearDown();
server.shutdown();
}
/**
* Get the delay (in milliseconds) that should be used for delaying
* a successful network call response.
*/
private static int calculateDelayForSuccess() {
float errorPercent = VARIANCE_PCT / 100f; // e.g., 20 / 100f == 0.2f
float lowerBound = 1f - errorPercent; // 0.2f --> 0.8f
float upperBound = 1f + errorPercent; // 0.2f --> 1.2f
float bound = upperBound - lowerBound; // 1.2f - 0.8f == 0.4f
float delayPercent = (random.nextFloat() * bound) +
lowerBound; // 0.8 + (rnd * 0.4)
return (int) (DELAY_MS * delayPercent);
}
/**
* Get the delay (in milliseconds) that should be used for delaying
* a network call response.
*/
private static int calculateDelayForCall() {
// Commenting out the random failure mode delay since we want our
// tests to be reproducible
return //calculateIsFailure() ? calculateDelayForError() :
calculateDelayForSuccess();
}
/**
* Match url to a regex template while allowing extra slash and query
* strings at the end
*/
private static boolean urlMatches(String url, String template) {
if (TextUtils.isEmpty(url) || TextUtils.isEmpty(template)) {
return false;
}
String pattern = '^' + template;
if (template.charAt(template.length() - 1) != '/') {
pattern += "/?";
}
pattern += "(\\?.*)?$";
return url.matches(pattern);
}
private MockResponse generateMockResponse(RecordedRequest request) {
final String method = request.getMethod();
final String path = request.getPath();
MockResponse response = new MockResponse();
response.addHeader("Set-Cookie", "csrftoken=dummy; Max-Age=31449600; Path=/");
response.setResponseCode(HttpStatus.NOT_FOUND);
if ("POST".equals(method)) {
if (urlMatches(path, "/oauth2/access_token")) {
response.setResponseCode(HttpStatus.OK);
response.setBody("{\"access_token\": \"dummy\", \"token_type\": \"Bearer\", \"expires_in\": 2591999, \"scope\": \"\"}");
} else if (urlMatches(path, "/api/mobile/v0.5/users/staff/course_status_info/[^/]+/[^/]+/[^/]+")) {
try {
JSONObject body = new JSONObject(request.getBody().readUtf8());
String moduleId = body.getString("last_visited_module_id");
response.setResponseCode(HttpStatus.OK);
response.setBody("{\"last_visited_module_id\": \"" + moduleId + "\", \"last_visited_module_path\": [\"" + moduleId + "\"]}");
} catch (JSONException e) {
e.printStackTrace();
}
} else if (urlMatches(path, "/api/enrollment/v1/enrollment")) {
try {
JSONObject body = new JSONObject(request.getBody().readUtf8());
response.setResponseCode(HttpStatus.OK);
response.setBody("{\"created\": \"2015-04-21T18:25:55Z\", \"mode\": \"honor\", \"is_active\": true, \"course_details\": {\"course_end\": null, \"course_start\": \"2030-01-01T00:00:00Z\", \"course_modes\": [{\"slug\": \"honor\", \"name\": \"Honor Code Certificate\", \"min_price\": 0, \"suggested_prices\": [], \"currency\": \"usd\", \"expiration_datetime\": null, \"description\": null, \"sku\": null}], \"enrollment_start\": null, \"enrollment_end\": null, \"invite_only\": false, \"course_id\": \""
+ body.getJSONObject("course_details").getString("course_id") + "\"}, \"user\": \"staff\"}");
} catch (JSONException e) {
e.printStackTrace();
}
} else if (urlMatches(path, "/password_reset")) {
response.setResponseCode(HttpStatus.OK);
response.setBody("{\"value\": \"\\n<header>\\n <h2>Password reset successful</h2>\\n <hr>\\n</header>\\n\\n<div class=\\\"message\\\">\\n <p>We've e-mailed you instructions for setting your password to the e-mail address you submitted. You should be receiving it shortly.</p>\\n</div>\\n\", \"success\": true}");
}
} else if ("GET".equals(method)) {
if (urlMatches(path, "/api/mobile/v0.5/my_user_info")) {
String baseMockUrl = getBaseMockUrl();
response.setResponseCode(HttpStatus.OK);
response.setBody("{\"id\": 4, \"username\": \"staff\", \"email\": \"staff@example.com\", \"name\": \"staff\", \"course_enrollments\": \"" + baseMockUrl + "/api/mobile/v0.5/users/staff/course_enrollments/\"}");
} else if (urlMatches(path, "/api/mobile/v0.5/users/[^/]+/course_enrollments")) {
String baseMockUrl = getBaseMockUrl();
response.setResponseCode(HttpStatus.OK);
response.setBody("[{\"created\": \"2015-04-21T18:25:55Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/knockknock.org/kk001/2015_T1/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/knockknock.org/kk001/2015_T1/updates\", \"number\": \"kk001\", \"org\": \"knockknock.org\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/knockknock.org/kk001/2015_T1\", \"id\": \"knockknock.org/kk001/2015_T1\", \"latest_updates\": {\"video\": null}, \"end\": null, \"name\": \"knockknockwhoisthere\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/knockknock.org/kk001/2015_T1/handouts\", \"start\": \"2030-01-01T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_NNXG6Y3LNNXG6Y3LFZXXEZZPNNVTAMBRF4ZDAMJVL5KDC___\", \"course_image\": \"/c4x/knockknock.org/kk001/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2015-03-06T20:21:37Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/McGillX/Body101x/1T2015/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/McGillX/Body101x/1T2015/updates\", \"number\": \"Body101x\", \"org\": \"McGillX\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/McGillX/Body101x/1T2015\", \"id\": \"McGillX/Body101x/1T2015\", \"latest_updates\": {\"video\": null}, \"end\": null, \"name\": \"The Body Matters\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/McGillX/Body101x/1T2015/handouts\", \"start\": \"2030-01-01T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_JVRUO2LMNRMC6QTPMR4TCMBRPAXTCVBSGAYTK___\", \"course_image\": \"/c4x/McGillX/Body101x/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2015-03-06T20:19:18Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/SMES/PSYCH101x/1T2015/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/SMES/PSYCH101x/1T2015/updates\", \"number\": \"PSYCH101x\", \"org\": \"SMES\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/SMES/PSYCH101x/1T2015\", \"id\": \"SMES/PSYCH101x/1T2015\", \"latest_updates\": {\"video\": null}, \"end\": null, \"name\": \"Introductory Psychology\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/SMES/PSYCH101x/1T2015/handouts\", \"start\": \"2030-01-01T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_KNGUKUZPKBJVSQ2IGEYDC6BPGFKDEMBRGU______\", \"course_image\": \"/c4x/SMES/PSYCH101x/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2015-03-06T20:15:39Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/UC3Mx/IT.1.1x/1T2015/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/UC3Mx/IT.1.1x/1T2015/updates\", \"number\": \"IT.1.1x\", \"org\": \"UC3Mx\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/UC3Mx/IT.1.1x/1T2015\", \"id\": \"UC3Mx/IT.1.1x/1T2015\", \"latest_updates\": {\"video\": null}, \"end\": null, \"name\": \"Introduction to Programming with Java - Part 1\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/UC3Mx/IT.1.1x/1T2015/handouts\", \"start\": \"2030-01-01T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_KVBTGTLYF5EVILRRFYYXQLZRKQZDAMJV\", \"course_image\": \"/c4x/UC3Mx/IT.1.1x/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-12-30T17:31:59Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/apple/banana/carrot/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/apple/banana/carrot/updates\", \"number\": \"banana\", \"org\": \"apple\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/apple/banana/carrot\", \"id\": \"apple/banana/carrot\", \"latest_updates\": {\"video\": null}, \"end\": null, \"name\": \"splittest\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/apple/banana/carrot/handouts\", \"start\": \"2030-01-01T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_MFYHA3DFF5RGC3TBNZQS6Y3BOJZG65A_\", \"course_image\": \"/c4x/apple/banana/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-12-30T17:17:55Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/split/split/split/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/split/split/split/updates\", \"number\": \"split\", \"org\": \"split\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/split/split/split\", \"id\": \"split/split/split\", \"latest_updates\": {\"video\": null}, \"end\": null, \"name\": \"Split Test Module\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/split/split/split/handouts\", \"start\": \"2030-01-01T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_ONYGY2LUF5ZXA3DJOQXXG4DMNF2A____\", \"course_image\": \"/c4x/split/split/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-11-25T15:48:41Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/15.390.1x/3T2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/15.390.1x/3T2014/updates\", \"number\": \"15.390.1x\", \"org\": \"MITx\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/MITx/15.390.1x/3T2014\", \"id\": \"MITx/15.390.1x/3T2014\", \"latest_updates\": {\"video\": null}, \"end\": \"2015-03-31T00:00:00Z\", \"name\": \"Entrepreneurship 101: Who is your customer?\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/15.390.1x/3T2014/handouts\", \"start\": \"2015-01-09T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_JVEVI6BPGE2S4MZZGAXDC6BPGNKDEMBRGQ______\", \"course_image\": \"/c4x/MITx/15.390.1x/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-11-24T19:51:07Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edx/1/2/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edx/1/2/updates\", \"number\": \"1\", \"org\": \"edx\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/edx/1/2\", \"id\": \"edx/1/2\", \"latest_updates\": {\"video\": null}, \"end\": \"2015-01-12T23:00:00Z\", \"name\": \"Paradigms of Computer Programming - Abstraction and Concurrency\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edx/1/2/handouts\", \"start\": \"2014-11-16T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_MVSHQLZRF4ZA____\", \"course_image\": \"/c4x/edx/1/asset/Illu_LouvainX1_262x136.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-11-21T19:13:15Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/Lou/LVM101/2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/Lou/LVM101/2014/updates\", \"number\": \"LVM101\", \"org\": \"Lou\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/Lou/LVM101/2014\", \"id\": \"Lou/LVM101/2014\", \"latest_updates\": {\"video\": null}, \"end\": \"2015-01-12T23:00:00Z\", \"name\": \"Paradigms of Computer Programming - Abstraction and Concurrency\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/Lou/LVM101/2014/handouts\", \"start\": \"2014-11-16T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_JRXXKL2MKZGTCMBRF4ZDAMJU\", \"course_image\": \"/c4x/Lou/LVM101/asset/Illu_LouvainX1_262x136.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:37:33Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/UQx/World101x/3T2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/UQx/World101x/3T2014/updates\", \"number\": \"World101x\", \"org\": \"UQx\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/UQx/World101x/3T2014\", \"id\": \"UQx/World101x/3T2014\", \"latest_updates\": {\"video\": null}, \"end\": \"2014-10-26T23:59:00Z\", \"name\": \"Anthropology of Current World Issues\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/UQx/World101x/3T2014/handouts\", \"start\": \"2014-08-25T09:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_KVIXQL2XN5ZGYZBRGAYXQLZTKQZDAMJU\", \"course_image\": \"/c4x/UQx/World101x/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:36:17Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/LouvainX/Louv3.02x/3T2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/LouvainX/Louv3.02x/3T2014/updates\", \"number\": \"Louv3x\", \"org\": \"LouvainX\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/LouvainX/Louv3.02x/3T2014\", \"id\": \"LouvainX/Louv3.02x/3T2014\", \"latest_updates\": {\"video\": null}, \"end\": \"2014-11-15T00:00:00Z\", \"name\": \"D\\u00e9couvrir la science politique\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/LouvainX/Louv3.02x/3T2014/handouts\", \"start\": \"2014-09-25T00:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_JRXXK5TBNFXFQL2MN52XMMZOGAZHQLZTKQZDAMJU\", \"course_image\": \"/c4x/LouvainX/Louv3.02x/asset/Illu_LouvainX3-136x262.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:34:36Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/LouvainX/Louv1.1x/3T2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/LouvainX/Louv1.1x/3T2014/updates\", \"number\": \"Louv1.1x\", \"org\": \"LouvainX\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/LouvainX/Louv1.1x/3T2014\", \"id\": \"LouvainX/Louv1.1x/3T2014\", \"latest_updates\": {\"video\": null}, \"end\": \"2014-11-30T22:59:00Z\", \"name\": \"Paradigms of Computer Programming - Fundamentals\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/LouvainX/Louv1.1x/3T2014/handouts\", \"start\": \"2014-09-22T10:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_JRXXK5TBNFXFQL2MN52XMMJOGF4C6M2UGIYDCNA_\", \"course_image\": \"/c4x/LouvainX/Louv1.1x/asset/Illu_LouvainX1_262x136.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:32:34Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/6.002x_4x/3T2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/6.002x_4x/3T2014/updates\", \"number\": \"6.002x\", \"org\": \"MITx\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/MITx/6.002x_4x/3T2014\", \"id\": \"MITx/6.002x_4x/3T2014\", \"latest_updates\": {\"video\": null}, \"end\": \"2014-12-15T05:00:00Z\", \"name\": \"Circuits and Electronics\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/6.002x_4x/3T2014/handouts\", \"start\": \"2014-08-25T15:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_JVEVI6BPGYXDAMBSPBPTI6BPGNKDEMBRGQ______\", \"course_image\": \"/c4x/MITx/6.002x_4x/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:30:50Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/4.605x_2/3T2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/4.605x_2/3T2014/updates\", \"number\": \"4.605x\", \"org\": \"MITx\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/MITx/4.605x_2/3T2014\", \"id\": \"MITx/4.605x_2/3T2014\", \"latest_updates\": {\"video\": null}, \"end\": \"2014-12-11T05:00:00Z\", \"name\": \"A Global History of Architecture: Part 1\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/MITx/4.605x_2/3T2014/handouts\", \"start\": \"2014-09-23T14:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_JVEVI6BPGQXDMMBVPBPTELZTKQZDAMJU\", \"course_image\": \"/c4x/MITx/4.605x_2/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:29:39Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/HarvardX/AmPoX.1/2014_T3/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/HarvardX/AmPoX.1/2014_T3/updates\", \"number\": \"AmPoX.1\", \"org\": \"HarvardX\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/HarvardX/AmPoX.1/2014_T3\", \"id\": \"HarvardX/AmPoX.1/2014_T3\", \"latest_updates\": {\"video\": null}, \"end\": \"2014-10-17T21:00:00Z\", \"name\": \"Poetry in America: The Poetry of Early New England\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/HarvardX/AmPoX.1/2014_T3/handouts\", \"start\": \"2014-09-10T16:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_JBQXE5TBOJSFQL2BNVIG6WBOGEXTEMBRGRPVIMY_\", \"course_image\": \"/c4x/HarvardX/AmPoX.1/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:28:30Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/DelftX/ET.3034TU/3T2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/DelftX/ET.3034TU/3T2014/updates\", \"number\": \"ET.3034TU\", \"org\": \"DelftX\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/DelftX/ET.3034TU/3T2014\", \"id\": \"DelftX/ET.3034TU/3T2014\", \"latest_updates\": {\"video\": null}, \"end\": \"2014-12-06T10:00:00Z\", \"name\": \"Solar Energy\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/DelftX/ET.3034TU/3T2014/handouts\", \"start\": \"2014-09-01T09:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_IRSWYZTULAXUKVBOGMYDGNCUKUXTGVBSGAYTI___\", \"course_image\": \"/c4x/DelftX/ET.3034TU/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:18:30Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edX/DemoX.1/2014/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edX/DemoX.1/2014/updates\", \"number\": \"DemoX.1\", \"org\": \"edX\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/edX/DemoX.1/2014\", \"id\": \"edX/DemoX.1/2014\", \"latest_updates\": {\"video\": null}, \"end\": null, \"name\": \"Demo Course\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edX/DemoX.1/2014/handouts\", \"start\": \"2014-08-01T04:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_MVSFQL2EMVWW6WBOGEXTEMBRGQ______\", \"course_image\": \"/c4x/edX/DemoX.1/asset/CourseListingImage.png\"}, \"certificate\": {}}, {\"created\": \"2014-09-19T19:16:13Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/WellesleyX/SOC108x/2014_SOND/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/WellesleyX/SOC108x/2014_SOND/updates\", \"number\": \"SOC108x\", \"org\": \"WellesleyX\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/WellesleyX/SOC108x/2014_SOND\", \"id\": \"WellesleyX/SOC108x/2014_SOND\", \"latest_updates\": {\"video\": null}, \"end\": \"2014-11-10T23:30:00Z\", \"name\": \"Introduction to Global Sociology\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/WellesleyX/SOC108x/2014_SOND/handouts\", \"start\": \"2014-09-02T19:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_K5SWY3DFONWGK6KYF5JU6QZRGA4HQLZSGAYTIX2TJ5HEI___\", \"course_image\": \"/c4x/WellesleyX/SOC108x/asset/images_course_image.jpg\"}, \"certificate\": {}}, {\"created\": \"2014-08-25T16:38:08Z\", \"mode\": \"honor\", \"is_active\": true, \"course\": {\"course_about\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edX/DemoX/Demo_Course/about\", \"course_updates\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edX/DemoX/Demo_Course/updates\", \"number\": \"DemoX\", \"org\": \"edX\", \"video_outline\": \"" + baseMockUrl + "/api/mobile/v0.5/video_outlines/courses/edX/DemoX/Demo_Course\", \"id\": \"edX/DemoX/Demo_Course\", \"latest_updates\": {\"video\": null}, \"end\": null, \"name\": \"edX Demonstration Course\", \"course_handouts\": \"" + baseMockUrl + "/api/mobile/v0.5/course_info/edX/DemoX/Demo_Course/handouts\", \"start\": \"2013-02-05T05:00:00Z\", \"social_urls\": {\"facebook\": null}, \"subscription_id\": \"course_MVSFQL2EMVWW6WBPIRSW2327INXXK4TTMU______\", \"course_image\": \"/c4x/edX/DemoX/asset/images_course_image.jpg\"}, \"certificate\": {}}]");
} else if (urlMatches(path, "/api/mobile/v0.5/video_outlines/courses/[^/]+/[^/]+/[^/]+")) {
response.setResponseCode(HttpStatus.OK);
response.setBody("[]");
} else if (urlMatches(path, "/api/mobile/v0.5/course_info/[^/]+/[^/]+/[^/]+/updates")) {
response.setResponseCode(HttpStatus.OK);
response.setBody("[]");
} else if (urlMatches(path, "/api/mobile/v0.5/users/staff/course_status_info/[^/]+/[^/]+/[^/]+")) {
Matcher matcher = Pattern.compile(
"/api/mobile/v0.5/users/staff/course_status_info/([^/]+)/([^/]+)/([^/]+)", 0).matcher(path);
matcher.matches();
String moduleId = "i4x://" + matcher.group(1) + '/' + matcher.group(2) + "/course/" + matcher.group(3);
response.setResponseCode(HttpStatus.OK);
response.setBody("{\"last_visited_module_id\": \"" + moduleId + "\", \"last_visited_module_path\": [\"" + moduleId + "\"]}");
} else if (urlMatches(path, "/api/mobile/v0.5/course_info/[^/]+/[^/]+/[^/]+/handouts")) {
// TODO: Find out if this is a wrong API call or server issue
response.setResponseCode(HttpStatus.NOT_FOUND);
response.setBody("{\"detail\": \"Not found\"}");
}
}
return response;
}
/**
* Handler for requests on the mock server that will send mock responses
* according to the request urls
*/
private class MockResponseDispatcher extends Dispatcher {
@Override
public MockResponse dispatch(RecordedRequest recordedRequest)
throws InterruptedException {
Thread.sleep(calculateDelayForCall());
return generateMockResponse(recordedRequest);
}
}
}