package com.rapidftr.service;
import android.content.SharedPreferences;
import com.rapidftr.CustomTestRunner;
import com.rapidftr.RapidFtrApplication;
import com.rapidftr.model.Enquiry;
import com.rapidftr.model.History;
import com.rapidftr.model.User;
import com.rapidftr.repository.EnquiryRepository;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHttpResponse;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.robolectric.Robolectric;
import javax.xml.ws.http.HTTPException;
import java.io.SyncFailedException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.rapidftr.RapidFtrApplication.SERVER_URL_PREF;
import static com.rapidftr.RapidFtrApplication.SHARED_PREFERENCES_FILE;
import static com.rapidftr.RapidFtrApplication.getApplicationInstance;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.robolectric.Robolectric.application;
import static org.robolectric.Robolectric.getFakeHttpLayer;
@RunWith(CustomTestRunner.class)
public class EnquirySyncServiceTest {
private EntityHttpDao<Enquiry> enquiryHttpDao;
@Mock
private EnquiryRepository enquiryRepository;
@Mock
private SharedPreferences sharedPreferences;
private RapidFtrApplication application;
private User user;
@Before
public void setUp() {
initMocks(this);
application = (RapidFtrApplication) Robolectric.getShadowApplication().getApplicationContext();
user = new User("userName", "password", true, "http://1.2.3.4");
application.setCurrentUser(user);
enquiryHttpDao = EntityHttpDaoFactory.createEnquiryHttpDao(application,
"http://whatever",
EnquiryHttpDao.ENQUIRIES_API_PATH,
EnquirySyncService.ENQUIRIES_API_PARAMETER);
}
@Test
public void getRecordShouldRetrieveARecordOverHttp() throws Exception {
String resourceUrl = "http://whatever/api/enquiries/dfb2031ebfb468f5200edc";
String response = "{\"_id\" : \"couch_id\", \"child_name\":\"subhas\",\"unique_identifier\":\"78223s4h1e468f5200edc\"}";
getFakeHttpLayer().addHttpResponseRule("http://whatever/api/enquiries/dfb2031ebfb468f5200edc/", response);
EnquirySyncService enquirySyncService = new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository);
Enquiry expectedEnquiry = new Enquiry(response, "createdBy");
final Enquiry downloadedEnquiry = enquirySyncService.getRecord(resourceUrl);
assertThat(downloadedEnquiry.getUniqueId(), is(expectedEnquiry.getUniqueId()));
}
@Test
public void getIdsToDownloadShouldRetrieveUrlsFromApiSinceLastUpdate() throws Exception {
String response = "[{\"location\":\"http://blah.com/123\"},{\"location\":\"http://blah.com/234\"}]";
getFakeHttpLayer().addHttpResponseRule("http://whatever/api/enquiries?updated_after=1970-01-01%2000%3A00%3A00UTC", response);
List<String> enquiryIds = new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository).getIdsToDownload();
assertThat(enquiryIds.get(0), is("http://blah.com/123"));
assertThat(enquiryIds.get(1), is("http://blah.com/234"));
}
@Test
public void shouldUseLastEnquirySyncTimestampToRetreiveIds() throws Exception {
String response = "[{\"location\":\"http://whatever/api/children/5-1ed26a0e5072830a9064361a570684f6\"},{\"location\":\"http://whatever/api/children/4-b011946150a16b0d2c6271aed05e2abe\"}]";
long time = 1412330399491l;
getApplicationInstance().getSharedPreferences().edit().putLong(RapidFtrApplication.LAST_ENQUIRY_SYNC, time).commit();
getFakeHttpLayer().addHttpResponseRule("http://whatever/api/enquiries?updated_after=2014-10-03%2009%3A59%3A59UTC", response);
new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository).getIdsToDownload();
}
@Test
public void shouldNotSendUnnecessaryParamsDuringSync() throws Exception {
String response = "{\"_id\" : \"couch_id\", \"photo_keys\":[], \"audio_attachments\":\"[]\",\"unique_identifier\":\"78223s4h1e468f5200edc\"}";
Enquiry record = new Enquiry(response);
Enquiry recordSpy = spy(record);
getFakeHttpLayer().setDefaultHttpResponse(200, response);
EnquirySyncService enquirySyncService = new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository);
enquirySyncService.sync(recordSpy, user);
verify(recordSpy).remove("photo_keys");
verify(recordSpy).remove("audio_attachments");
verify(recordSpy).remove("synced");
}
@Test
public void shouldUpdateEnquiryWhenItIsNotNew() throws Exception {
String response = "{\"_id\" : \"couch_id\", \"child_name\":\"subhas\",\"unique_identifier\":\"78223s4h1e468f5200edc\"}";
Enquiry enquiry = spy(new Enquiry(response, "createdBy"));
enquiry.put(Enquiry.FIELD_INTERNAL_ID, "id");
doReturn(false).when(enquiry).isNew();
BasicHttpResponse httpResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
httpResponse.setEntity(new StringEntity(response, ContentType.APPLICATION_JSON));
getFakeHttpLayer().addHttpResponseRule("PUT", "http://whatever/api/enquiries/id", httpResponse);
Enquiry returnedEnquiry = new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository).sync(enquiry, user);
verify(enquiryRepository).createOrUpdateWithoutHistory(returnedEnquiry);
}
@Test
public void shouldRemoveHistoriesAfterSuccessfulSync() throws Exception {
String response = "{\"_id\" : \"couch_id\", \"child_name\":\"subhas\",\"unique_identifier\":\"78223s4h1e468f5200edc\"}";
Enquiry enquirySpy = spy(new Enquiry(response, "createdBy"));
enquirySpy.put(Enquiry.FIELD_INTERNAL_ID, "id");
doReturn(false).when(enquirySpy).isNew();
enquiryHttpDao = mock(EntityHttpDao.class);
doReturn(enquirySpy).when(enquiryHttpDao).update(any(Enquiry.class), any(String.class), any(Map.class));
new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository).sync(enquirySpy, user);
verify(enquirySpy).remove(History.HISTORIES);
}
@Test(expected = SyncFailedException.class)
public void shouldNotRemoveHistoriesAfterFailedSync() throws Exception {
String response = "{\"_id\" : \"couch_id\", \"child_name\":\"subhas\",\"unique_identifier\":\"78223s4h1e468f5200edc\"}";
Enquiry enquirySpy = spy(new Enquiry(response, "createdBy"));
doReturn(false).when(enquirySpy).isNew();
enquiryHttpDao = mock(EntityHttpDao.class);
doThrow(new HTTPException(404)).when(enquiryHttpDao).update(any(Enquiry.class), any(String.class), any(Map.class));
new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository).sync(enquirySpy, user);
verify(enquirySpy, never()).remove(History.HISTORIES);
}
@Test
public void shouldCreateEnquiryWhenItIsNew() throws Exception {
String response = "{\"_id\" : \"couch_id\", \"child_name\":\"subhas\",\"unique_identifier\":\"78223s4h1e468f5200edc\"}";
Enquiry enquiry = spy(new Enquiry(response, "createdBy"));
doReturn(true).when(enquiry).isNew();
BasicHttpResponse httpResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
httpResponse.setEntity(new StringEntity(response, ContentType.APPLICATION_JSON));
getFakeHttpLayer().addHttpResponseRule("POST", "http://whatever/api/enquiries", httpResponse);
Enquiry returnedEnquiry = new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository).sync(enquiry, user);
verify(enquiryRepository).createOrUpdateWithoutHistory(returnedEnquiry);
}
@Test
public void shouldUpdateEnquiryAttributesAfterSync() throws Exception {
String response = "{\"_id\" : \"couch_id\", \"child_name\":\"subhas\",\"unique_identifier\":\"78223s4h1e468f5200edc\", \"last_updated_at\":\"2014-04-12\"}";
Enquiry enquiry = spy(new Enquiry(response, "createdBy"));
enquiry.put(Enquiry.FIELD_INTERNAL_ID, "id");
doReturn(false).when(enquiry).isNew();
BasicHttpResponse httpResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
httpResponse.setEntity(new StringEntity(response, ContentType.APPLICATION_JSON));
getFakeHttpLayer().addHttpResponseRule("PUT", "http://whatever/api/enquiries/id", httpResponse);
Enquiry returnedEnquiry = new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository).sync(enquiry, user);
verify(enquiryRepository).createOrUpdateWithoutHistory(returnedEnquiry);
assertNotNull(returnedEnquiry.getLastUpdatedAt());
assertThat(returnedEnquiry.isSynced(), CoreMatchers.is(true));
}
@Test(expected = SyncFailedException.class)
public void shouldHandleSyncFailuresAndReturnEnquiry() throws Exception {
String response = "{\"_id\" : \"couch_id\", \"child_name\":\"subhas\",\"unique_identifier\":\"78223s4h1e468f5200edc\"}";
Enquiry enquiry = spy(new Enquiry(response, "createdBy"));
doReturn(true).when(enquiry).isNew();
BasicHttpResponse httpResponse = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_INTERNAL_SERVER_ERROR, "ERROR");
httpResponse.setEntity(new StringEntity(response, ContentType.APPLICATION_JSON));
getFakeHttpLayer().addHttpResponseRule("POST", "http://whatever/api/enquiries/", httpResponse);
new EnquirySyncService(mockContext(), enquiryHttpDao, enquiryRepository).sync(enquiry, user);
assertFalse(enquiry.isSynced());
assertNull(enquiry.getLastUpdatedAt());
}
private RapidFtrApplication mockContext() {
RapidFtrApplication context = RapidFtrApplication.getApplicationInstance();
context.getSharedPreferences().edit().putString(SERVER_URL_PREF, "whatever").commit();
return context;
}
}