package com.b2msolutions.reyna.services;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.b2msolutions.reyna.*;
import com.b2msolutions.reyna.Dispatcher.Result;
import com.b2msolutions.reyna.system.Message;
import com.b2msolutions.reyna.system.PeriodicBackoutCheck;
import com.b2msolutions.reyna.system.Preferences;
import com.b2msolutions.reyna.system.Thread;
import com.b2msolutions.reyna.messageProvider.BatchProvider;
import com.b2msolutions.reyna.messageProvider.IMessageProvider;
import com.b2msolutions.reyna.messageProvider.MessageProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowConnectivityManager;
import java.io.IOException;
import java.net.URISyntaxException;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.*;
import static org.robolectric.Shadows.shadowOf;
import static test.Assert.assertServiceStarted;
@Config(sdk = 18)
@RunWith(RobolectricTestRunner.class)
public class ForwardServiceTest {
private ForwardService forwardService;
@Mock Dispatcher dispatcher;
@Mock
Repository repository;
@Mock Thread thread;
@Mock
NetworkInfo networkInfo;
@Mock
PeriodicBackoutCheck periodicBackoutCheck;
private Context context;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.context = RuntimeEnvironment.application.getApplicationContext();
this.forwardService = Robolectric.setupService(ForwardService.class);
this.forwardService.dispatcher = dispatcher;
this.forwardService.repository = repository;
this.forwardService.thread = thread;
this.forwardService.periodicBackoutCheck = this.periodicBackoutCheck;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
ShadowConnectivityManager shadowConnectivityManager = shadowOf(connectivityManager);
shadowConnectivityManager.setActiveNetworkInfo(networkInfo);
when(networkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
when(networkInfo.isConnectedOrConnecting()).thenReturn(true);
doReturn(true).when(this.periodicBackoutCheck).timeElapsed("ForwardService_Backout_Temporary_Error", 300000);
}
@Test
public void sleepTimeoutShouldBeCorrect() {
assertEquals(1000, ForwardService.SLEEP_MILLISECONDS);
}
@Test
public void temporaryErrorTimeoutShouldBeCorrect() {
assertEquals(300000, ForwardService.TEMPORARY_ERROR_MILLISECONDS);
}
@Test
public void testConstruction() {
this.forwardService = new ForwardService();
assertNotNull(this.forwardService);
assertNotNull(this.forwardService.periodicBackoutCheck);
assertNotNull(this.forwardService.repository);
}
@Test
public void whenBatchModeEnabledMessageProviderShouldBeBatchProvider() {
new Preferences(this.forwardService).saveBatchUpload(true);
IMessageProvider messageProvider = this.forwardService.getMessageProvider();
assertNotNull(messageProvider);
assertEquals(BatchProvider.class, messageProvider.getClass());
}
@Test
public void whenBatchModeDisabledMessageProviderShouldBeMessageProvider() {
new Preferences(this.forwardService).saveBatchUpload(false);
IMessageProvider messageProvider = this.forwardService.getMessageProvider();
assertNotNull(messageProvider);
assertEquals(MessageProvider.class, messageProvider.getClass());
}
@Test
public void whenNotNullIntentShouldNotThrow() {
this.forwardService.onHandleIntent(null);
}
@Test
public void whenThereAreNoMessagesShouldNotThrow() {
this.forwardService.onHandleIntent(null);
}
@Test
public void whenThereAreNoMessagesShouldNotSleep() throws InterruptedException {
this.forwardService.onHandleIntent(new Intent());
verify(this.thread, never()).sleep(anyLong());
}
@Test
public void whenMoveNextThrowsShouldNotThrow() throws URISyntaxException {
when(this.repository.getNext()).thenThrow(new URISyntaxException("", ""));
this.forwardService.onHandleIntent(new Intent());
}
@Test
public void whenSingleMessageAndDispatchReturnsOKShouldDeleteMessage() throws URISyntaxException, InterruptedException {
Message message = mock(Message.class);
when(this.repository.getNext()).thenReturn(message).thenReturn(null);
when(this.dispatcher.sendMessage(this.forwardService, message)).thenReturn(Result.OK);
this.forwardService.onHandleIntent(new Intent());
InOrder inorder = inOrder(this.thread, this.dispatcher, this.repository);
inorder.verify(this.thread).sleep(ForwardService.SLEEP_MILLISECONDS);
inorder.verify(this.dispatcher).sendMessage(this.forwardService, message);
inorder.verify(this.repository).delete(message);
verify(this.periodicBackoutCheck, never()).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenCallingOnHandleIntentAndMessageProviderThrowsShouldNotThrow() throws URISyntaxException, InterruptedException {
doThrow(IOException.class).when(this.repository).getNext();
this.forwardService.onHandleIntent(new Intent());
verify(this.repository).close();
}
@Test
public void whenTwoMessagesAndDispatchReturnsOKShouldDeleteMessages() throws URISyntaxException, InterruptedException {
Message message1 = mock(Message.class);
Message message2 = mock(Message.class);
when(this.repository.getNext())
.thenReturn(message1)
.thenReturn(message2)
.thenReturn(null);
when(this.dispatcher.sendMessage(this.forwardService, message1)).thenReturn(Result.OK);
when(this.dispatcher.sendMessage(this.forwardService, message2)).thenReturn(Result.OK);
this.forwardService.onHandleIntent(new Intent());
InOrder inorder = inOrder(this.thread, this.dispatcher, this.repository);
inorder.verify(this.thread).sleep(ForwardService.SLEEP_MILLISECONDS);
inorder.verify(this.dispatcher).sendMessage(this.forwardService, message1);
inorder.verify(this.repository).delete(message1);
inorder.verify(this.thread).sleep(ForwardService.SLEEP_MILLISECONDS);
inorder.verify(this.dispatcher).sendMessage(this.forwardService, message2);
inorder.verify(this.repository).delete(message2);
verify(this.periodicBackoutCheck, never()).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenSingleMessageAndDispatchReturnsTemporaryErrorShouldNotDeleteMessage() throws URISyntaxException, InterruptedException {
Message message = mock(Message.class);
when(this.repository.getNext()).thenReturn(message).thenReturn(null);
when(this.dispatcher.sendMessage(this.forwardService, message)).thenReturn(Result.TEMPORARY_ERROR);
this.forwardService.onHandleIntent(new Intent());
verify(this.dispatcher).sendMessage(this.forwardService, message);
verify(this.repository, never()).delete(message);
verify(this.repository, never()).deleteMessagesFrom(anyLong());
verify(this.periodicBackoutCheck).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenSingleMessageAndDispatchReturnsBlackoutShouldNotDeleteMessage() throws URISyntaxException, InterruptedException {
Message message = mock(Message.class);
when(this.repository.getNext()).thenReturn(message).thenReturn(null);
when(this.dispatcher.sendMessage(this.forwardService, message)).thenReturn(Result.BLACKOUT);
this.forwardService.onHandleIntent(new Intent());
verify(this.dispatcher).sendMessage(this.forwardService, message);
verify(this.repository, never()).delete(message);
verify(this.repository, never()).deleteMessagesFrom(anyLong());
verify(this.periodicBackoutCheck, never()).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenSingleMessageAndDispatchReturnsNotConnectedShouldNotDeleteMessage() throws URISyntaxException, InterruptedException {
Message message = mock(Message.class);
when(this.repository.getNext()).thenReturn(message).thenReturn(null);
when(this.dispatcher.sendMessage(this.forwardService, message)).thenReturn(Result.NOTCONNECTED);
this.forwardService.onHandleIntent(new Intent());
verify(this.dispatcher).sendMessage(this.forwardService, message);
verify(this.repository, never()).delete(message);
verify(this.repository, never()).deleteMessagesFrom(anyLong());
verify(this.periodicBackoutCheck, never()).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenTwoMessagesAndFirstDispatchReturnsTemporaryErrorShouldNotDeleteMessages() throws URISyntaxException, InterruptedException {
Message message1 = mock(Message.class);
Message message2 = mock(Message.class);
when(this.repository.getNext())
.thenReturn(message1)
.thenReturn(message2)
.thenReturn(null);
when(this.dispatcher.sendMessage(this.forwardService, message1)).thenReturn(Result.TEMPORARY_ERROR);
this.forwardService.onHandleIntent(new Intent());
InOrder inorder = inOrder(this.dispatcher, this.repository);
inorder.verify(this.dispatcher).sendMessage(this.forwardService, message1);
inorder.verify(this.repository, never()).delete(message1);
inorder.verify(this.dispatcher, never()).sendMessage(this.forwardService, message2);
inorder.verify(this.repository, never()).delete(message2);
inorder.verify(this.repository, never()).deleteMessagesFrom(anyLong());
verify(this.periodicBackoutCheck).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenTwoMessagesAndFirstDispatchReturnsBlackoutShouldNotDeleteMessages() throws URISyntaxException, InterruptedException {
Message message1 = mock(Message.class);
Message message2 = mock(Message.class);
when(this.repository.getNext())
.thenReturn(message1)
.thenReturn(message2)
.thenReturn(null);
when(this.dispatcher.sendMessage(this.forwardService, message1)).thenReturn(Result.BLACKOUT);
this.forwardService.onHandleIntent(new Intent());
InOrder inorder = inOrder(this.dispatcher, this.repository);
inorder.verify(this.dispatcher).sendMessage(this.forwardService, message1);
inorder.verify(this.repository, never()).delete(message1);
inorder.verify(this.dispatcher, never()).sendMessage(this.forwardService, message2);
inorder.verify(this.repository, never()).delete(message2);
inorder.verify(this.repository, never()).deleteMessagesFrom(anyLong());
verify(this.periodicBackoutCheck, never()).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenTwoMessagesAndFirstDispatchReturnsPermanentErrorShouldDeleteMessages() throws URISyntaxException, InterruptedException {
Message message1 = mock(Message.class);
Message message2 = mock(Message.class);
when(this.repository.getNext())
.thenReturn(message1)
.thenReturn(message2)
.thenReturn(null);
when(this.dispatcher.sendMessage(this.forwardService, message1)).thenReturn(Result.PERMANENT_ERROR);
when(this.dispatcher.sendMessage(this.forwardService, message2)).thenReturn(Result.OK);
this.forwardService.onHandleIntent(new Intent());
InOrder inorder = inOrder(this.dispatcher, this.repository);
inorder.verify(this.dispatcher).sendMessage(this.forwardService, message1);
inorder.verify(this.repository).delete(message1);
inorder.verify(this.dispatcher).sendMessage(this.forwardService, message2);
inorder.verify(this.repository).delete(message2);
verify(this.periodicBackoutCheck, never()).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenSendMessageShouldCheckForCanSendFirstNotGetNextMessageWhenCannotSend() throws URISyntaxException, InterruptedException {
when(this.networkInfo.isConnectedOrConnecting()).thenReturn(false);
this.forwardService.onHandleIntent(new Intent());
verify(this.repository, never()).getNext();
}
@Test
public void whenCallingStartShouldStartService() {
ForwardService.start(this.context);
assertServiceStarted(ForwardService.class);
}
@Test
public void whenMessageProviderCannotSendShouldDoNothing() throws URISyntaxException, InterruptedException {
PeriodicBackoutCheck periodicBackoutCheck1 = new PeriodicBackoutCheck(this.context);
periodicBackoutCheck1.record("BatchProvider");
new Preferences(this.context).saveBatchUpload(true);
this.forwardService.onHandleIntent(new Intent());
verify(this.repository, never()).getNext();
verify(this.repository, never()).delete(any(Message.class));
verify(this.repository).close();
verify(this.periodicBackoutCheck, never()).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenPreviousMessagesFailedWithTemporaryErrorShouldNotTryToSendAnyMessageWithinFiveMinutes() throws URISyntaxException, InterruptedException {
doReturn(false).when(this.periodicBackoutCheck).timeElapsed("ForwardService_Backout_Temporary_Error", 300000);
this.forwardService.onHandleIntent(new Intent());
verify(this.repository, never()).getNext();
verify(this.repository, never()).delete(any(Message.class));
verify(this.repository).close();
verify(this.periodicBackoutCheck, never()).record("ForwardService_Backout_Temporary_Error");
}
@Test
public void whenCallingStartShouldAcquirePowerLock() {
ForwardService.start(RuntimeEnvironment.application.getApplicationContext());
Intent intent = assertServiceStarted(ForwardService.class);
int lockId = intent.getIntExtra("android.support.content.wakelockid", -1);
assertTrue(lockId != -1);
}
}