package org.edx.mobile.test.http;
import com.google.gson.Gson;
import org.edx.mobile.http.OkHttpUtil;
import org.edx.mobile.model.Filter;
import org.edx.mobile.model.api.AnnouncementsModel;
import org.edx.mobile.model.api.EnrolledCoursesResponse;
import org.edx.mobile.model.api.HandoutModel;
import org.edx.mobile.model.api.ResetPasswordResponse;
import org.edx.mobile.model.api.SectionEntry;
import org.edx.mobile.model.api.SyncLastAccessedSubsectionResponse;
import org.edx.mobile.model.api.VideoResponseModel;
import org.edx.mobile.model.course.BlockPath;
import org.edx.mobile.model.course.BlockType;
import org.edx.mobile.model.course.CourseComponent;
import org.edx.mobile.model.course.DiscussionBlockModel;
import org.edx.mobile.model.course.DiscussionData;
import org.edx.mobile.model.course.HasDownloadEntry;
import org.edx.mobile.model.course.IBlock;
import org.edx.mobile.model.course.VideoBlockModel;
import org.edx.mobile.model.course.VideoData;
import org.edx.mobile.module.registration.model.RegistrationDescription;
import org.edx.mobile.test.util.MockDataUtil;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Ignore;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import retrofit2.Response;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* This class contains unit tests for API calls to server.
* <p/>
* Note: We aren't actually calling a live server for responses
* as we already have a mock server implemented.
*/
public class ApiTests extends HttpBaseTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
}
// TODO: Debug and fix test failure
@Ignore
@Test
public void testSyncLastSubsection() throws Exception {
login();
EnrolledCoursesResponse e = api.getEnrolledCourses().get(0);
Map<String, SectionEntry> map = api.getCourseHierarchy(e.getCourse().getId(), false);
Entry<String, SectionEntry> entry = map.entrySet().iterator().next();
Entry<String, ArrayList<VideoResponseModel>> subsection = entry.getValue().sections.entrySet().iterator().next();
String courseId = e.getCourse().getId();
String lastVisitedModuleId = subsection.getValue().get(0).getSection().getId();
assertNotNull(courseId);
assertNotNull(lastVisitedModuleId);
print(String.format("course= %s ; sub-section= %s", courseId, lastVisitedModuleId));
// TODO: lastVisitedModuleId must be section.id (id is now available)
SyncLastAccessedSubsectionResponse model = api.syncLastAccessedSubsection(courseId, lastVisitedModuleId);
assertNotNull(model);
print("sync returned: " + model.last_visited_module_id);
}
// TODO: Debug and fix test failure
@Ignore
@Test
public void testGetLastAccessedModule() throws Exception {
login();
EnrolledCoursesResponse e = api.getEnrolledCourses().get(0);
String courseId = e.getCourse().getId();
assertNotNull(courseId);
print(String.format("course= %s", courseId));
SyncLastAccessedSubsectionResponse model = api.getLastAccessedSubsection(courseId);
assertNotNull(model);
// print(model.json);
}
@Test
public void testResetPassword() throws Exception {
print("test: reset password");
Response<ResetPasswordResponse> response = loginService.resetPassword("user@edx.org").execute();
assertTrue(response.isSuccessful());
ResetPasswordResponse model = response.body();
assertTrue(model != null);
print(model.value);
print("test: finished: reset password");
}
// TODO: Debug and fix test failure
@Ignore
@Test
public void testHandouts() throws Exception {
login();
// get a course id for this test
List<EnrolledCoursesResponse> courses = api.getEnrolledCourses();
assertTrue("Must have enrolled to at least one course",
courses != null && courses.size() > 0);
String handoutURL = courses.get(0).getCourse().getCourse_handouts();
HandoutModel model = api.getHandout(handoutURL, false);
assertTrue(model != null);
print(model.handouts_html);
}
@Test
public void testChannelId() throws Exception {
login();
// get a course id for this test
List<EnrolledCoursesResponse> courses = api.getEnrolledCourses();
assertTrue("Must have enrolled to at least one course",
courses != null && courses.size() > 0);
String subscription_id = courses.get(0).getCourse().getSubscription_id();
//should the channelId be mandatory?
assertTrue(subscription_id != null);
}
// TODO: Debug and fix test failure
@Ignore
@Test
public void testCourseStructure() throws Exception {
login();
// get a course id for this test
List<EnrolledCoursesResponse> courses = api.getEnrolledCourses();
assertTrue("Must have enrolled to at least one course",
courses != null && courses.size() > 0);
String courseId = courses.get(0).getCourse().getId();
Map<String, SectionEntry> chapters = api.getCourseHierarchy(courseId, false);
for (Entry<String, SectionEntry> entry : chapters.entrySet()) {
print("---------------" + entry.getKey() + "---------------");
for (Entry<String, ArrayList<VideoResponseModel>> se : entry.getValue().sections.entrySet()) {
print("------------" + se.getKey() + "------------");
for (VideoResponseModel v : se.getValue()) {
print(v.getSummary().getDisplayName());
}
}
}
}
@Test
@Override
public void login() throws Exception {
super.login();
}
// TODO: Debug and fix test failure
@Ignore
@Test
public void testGetAnnouncement() throws Exception {
login();
// get a course id for this test
List<EnrolledCoursesResponse> courses = api.getEnrolledCourses();
assertTrue("Must have enrolled to at least one course",
courses != null && courses.size() > 0);
String updatesUrl = courses.get(0).getCourse().getCourse_updates();
List<AnnouncementsModel> res = api.getAnnouncement(updatesUrl, false);
assertTrue(res != null);
for (AnnouncementsModel r : res) {
print(r.getDate());
}
}
@Test
public void testReadRegistrationDescription() throws Exception {
RegistrationDescription form = api.getRegistrationDescription();
assertNotNull(form);
assertNotNull(form.getEndpoint());
assertNotNull(form.getMethod());
assertNotNull(form.getFields());
assertTrue(form.getFields().size() > 0);
// verify if enum type is parsed
assertNotNull(form.getFields().get(0).getFieldType());
}
// TODO: Debug and fix test failure
@Ignore
@Test
public void testEnrollInACourse() throws Exception {
login();
print("test: Enroll in a course");
EnrolledCoursesResponse e = api.getEnrolledCourses().get(0);
String courseId = e.getCourse().getId();
boolean success = api.enrollInACourse(courseId, true);
assertTrue(success);
print("success");
print("test: finished: reset password");
}
@Test
public void testGetCourseStructure() throws Exception {
login();
// General overall testing of CourseComponent API without recursion
EnrolledCoursesResponse e = api.getEnrolledCourses().get(0);
final String courseId = e.getCourse().getId();
final CourseComponent courseComponent = serviceManager.getCourseStructure(courseId,
OkHttpUtil.REQUEST_CACHE_TYPE.IGNORE_CACHE);
assertNotNull(courseComponent);
assertNotNull(courseComponent.getRoot());
assertEquals(courseId, courseComponent.getCourseId());
List<IBlock> children = courseComponent.getChildren();
assertNotNull(children);
List<CourseComponent> childContainers = new ArrayList<>();
List<CourseComponent> childLeafs = new ArrayList<>();
for (IBlock c : children) {
assertTrue(c instanceof CourseComponent);
final CourseComponent child = (CourseComponent) c;
assertEquals(child, courseComponent.find(new Filter<CourseComponent>() {
@Override
public boolean apply(CourseComponent component) {
return child.getId().equals(component.getId());
}
}));
List<IBlock> grandchildren = child.getChildren();
for (IBlock gc : grandchildren) {
assertTrue(gc instanceof CourseComponent);
final CourseComponent grandchild = (CourseComponent) c;
assertEquals(grandchild, courseComponent.find(new Filter<CourseComponent>() {
@Override
public boolean apply(CourseComponent component) {
return grandchild.getId().equals(component.getId());
}
}));
}
assertNull(child.find(new Filter<CourseComponent>() {
@Override
public boolean apply(CourseComponent component) {
return courseComponent.getId().equals(component.getId());
}
}));
if (child.isContainer()) {
childContainers.add(child);
} else {
childLeafs.add(child);
}
}
assertEquals(childContainers, courseComponent.getChildContainers());
assertEquals(childLeafs, courseComponent.getChildLeafs());
assertTrue(courseComponent.isLastChild());
int childrenSize = children.size();
assertTrue(childrenSize > 0);
assertTrue(((CourseComponent)
children.get(childrenSize - 1)).isLastChild());
BlockType blockType = courseComponent.getType();
assertSame(courseComponent,
courseComponent.getAncestor(Integer.MAX_VALUE));
assertSame(courseComponent,
courseComponent.getAncestor(EnumSet.of(blockType)));
List<VideoBlockModel> videos = courseComponent.getVideos();
assertNotNull(videos);
for (HasDownloadEntry video : videos) {
assertNotNull(video);
assertTrue(video instanceof CourseComponent);
CourseComponent videoComponent = (CourseComponent) video;
assertFalse(videoComponent.isContainer());
assertEquals(BlockType.VIDEO, videoComponent.getType());
}
for (BlockType type : BlockType.values()) {
EnumSet<BlockType> typeSet = EnumSet.of(type);
List<CourseComponent> typeComponents = new ArrayList<>();
courseComponent.fetchAllLeafComponents(typeComponents, typeSet);
for (CourseComponent typeComponent : typeComponents) {
assertEquals(type, typeComponent.getType());
verifyModelParsing(typeComponent);
}
if (type != blockType) {
assertNotSame(courseComponent,
courseComponent.getAncestor(EnumSet.of(type)));
}
}
BlockPath path = courseComponent.getPath();
assertNotNull(path);
assertEquals(1, path.getPath().size());
assertSame(courseComponent, path.get(0));
List<CourseComponent> leafComponents = new ArrayList<>();
courseComponent.fetchAllLeafComponents(leafComponents,
EnumSet.allOf(BlockType.class));
for (CourseComponent leafComponent : leafComponents) {
BlockPath leafPath = leafComponent.getPath();
assertNotNull(leafPath);
int pathSize = leafPath.getPath().size();
assertTrue(pathSize > 1);
CourseComponent component = leafComponent;
for (int i = pathSize - 1; i >= 0; i--) {
assertSame(component, leafPath.get(i));
component = component.getParent();
}
}
}
/**
* Verifies the parsing of course structure json to {@link CourseComponent} model class.
*
* @param component Parsed {@link CourseComponent} model.
*/
private void verifyModelParsing(CourseComponent component) throws IOException, JSONException {
JSONObject jsonObj;
jsonObj = new JSONObject(MockDataUtil.getMockResponse("get_course_structure"));
jsonObj = jsonObj.getJSONObject("blocks");
jsonObj = jsonObj.getJSONObject(component.getId());
assertNotNull(jsonObj);
// Not using the getDisplayName function below, because it returns a placeholder text
// when the display_name field's value is empty.
assertEquals(jsonObj.getString("display_name"), component.getInternalName());
assertEquals(jsonObj.getBoolean("graded"), component.isGraded());
assertEquals(jsonObj.getString("student_view_url"), component.getBlockUrl());
assertEquals(jsonObj.getBoolean("student_view_multi_device"), component.isMultiDevice());
assertEquals(jsonObj.getString("lms_web_url"), component.getWebUrl());
// Type specific validations
Gson gson = new Gson();
switch (component.getType()) {
case VIDEO: {
JSONObject dataObj = jsonObj.getJSONObject("student_view_data");
// Our current parser checks the existence of these fields to determine the type to convert into
assertTrue(dataObj.has("encoded_videos") || dataObj.has("transcripts"));
String dataRawJson = dataObj.toString();
assertTrue(component instanceof VideoBlockModel);
VideoBlockModel model = (VideoBlockModel) component;
VideoData expected = gson.fromJson(dataRawJson, VideoData.class);
assertEquals(expected, model.getData());
break;
}
case DISCUSSION: {
JSONObject dataObj = jsonObj.getJSONObject("student_view_data");
// Our current parser checks the existence of these fields to determine the type to convert into
assertTrue(dataObj.has("topic_id"));
String dataRawJson = dataObj.toString();
assertTrue(component instanceof DiscussionBlockModel);
DiscussionBlockModel model = (DiscussionBlockModel) component;
DiscussionData expected = gson.fromJson(dataRawJson, DiscussionData.class);
assertEquals(expected, model.getData());
break;
}
}
}
}