/* * Catroid: An on-device visual programming system for Android devices * Copyright (C) 2010-2016 The Catrobat Team * (<http://developer.catrobat.org/credits>) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * An additional term exception under section 7 of the GNU Affero * General Public License, version 3, is available at * http://developer.catrobat.org/license_additional_term * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.catrobat.catroid.test.scratchconverter.protocol; import android.net.Uri; import android.test.AndroidTestCase; import com.google.android.gms.common.images.WebImage; import org.catrobat.catroid.common.Constants; import org.catrobat.catroid.scratchconverter.Client; import org.catrobat.catroid.scratchconverter.protocol.BaseMessageHandler; import org.catrobat.catroid.scratchconverter.protocol.Job; import org.catrobat.catroid.scratchconverter.protocol.JobHandler; import org.catrobat.catroid.scratchconverter.protocol.JsonKeys; import org.catrobat.catroid.scratchconverter.protocol.JsonKeys.JsonDataKeys; import org.catrobat.catroid.scratchconverter.protocol.WebSocketMessageListener; import org.catrobat.catroid.scratchconverter.protocol.message.Message.CategoryType; import org.catrobat.catroid.scratchconverter.protocol.message.base.BaseMessage; import org.catrobat.catroid.scratchconverter.protocol.message.base.ClientIDMessage; import org.catrobat.catroid.scratchconverter.protocol.message.base.ErrorMessage; import org.catrobat.catroid.scratchconverter.protocol.message.base.InfoMessage; import org.catrobat.catroid.scratchconverter.protocol.message.job.JobAlreadyRunningMessage; import org.catrobat.catroid.scratchconverter.protocol.message.job.JobFailedMessage; import org.catrobat.catroid.scratchconverter.protocol.message.job.JobFinishedMessage; import org.catrobat.catroid.scratchconverter.protocol.message.job.JobMessage; import org.catrobat.catroid.scratchconverter.protocol.message.job.JobOutputMessage; import org.catrobat.catroid.scratchconverter.protocol.message.job.JobProgressMessage; import org.catrobat.catroid.scratchconverter.protocol.message.job.JobReadyMessage; import org.catrobat.catroid.scratchconverter.protocol.message.job.JobRunningMessage; import org.catrobat.catroid.test.utils.Reflection; import org.json.JSONObject; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.TimeZone; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; public class WebSocketMessageListenerTest extends AndroidTestCase { private static final long VALID_CLIENT_ID = 1; private static final long JOB_ID_OF_JOB_HANDLER = 1; private static final long JOB_ID_OF_UNSCHEDULED_JOB_THAT_HAS_NO_JOB_HANDLER = 2; private WebSocketMessageListener webSocketMessageListener; private BaseMessageHandler baseMessageHandlerMock; private JobHandler jobHandlerMock; @Override protected void setUp() throws Exception { super.setUp(); System.setProperty("dexmaker.dexcache", getContext().getCacheDir().getPath()); baseMessageHandlerMock = Mockito.mock(BaseMessageHandler.class); webSocketMessageListener = new WebSocketMessageListener(); webSocketMessageListener.setBaseMessageHandler(baseMessageHandlerMock); jobHandlerMock = Mockito.mock(JobHandler.class); // add job handler to map Map<Long, JobHandler> jobHandlers = (Map<Long, JobHandler>) Reflection.getPrivateField( WebSocketMessageListener.class, webSocketMessageListener, "jobHandlers"); jobHandlers.put(JOB_ID_OF_JOB_HANDLER, jobHandlerMock); } //------------------------------------------------------------------------------------------------------------------ // WebSocket.StringCallback interface tests //------------------------------------------------------------------------------------------------------------------ public void testReceivingInvalidStringMessageShouldRaiseNoException() { webSocketMessageListener.onStringAvailable(null); webSocketMessageListener.onStringAvailable(""); } public void testReceivingClientIDMessage() { final long expectedClientID = VALID_CLIENT_ID; doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("BaseMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance ClientIDMessage", invocation.getArguments()[0] instanceof ClientIDMessage); ClientIDMessage clientIDMessage = (ClientIDMessage) invocation.getArguments()[0]; assertEquals("Wrong client ID extracted", expectedClientID, clientIDMessage.getClientID()); return null; } }).when(baseMessageHandlerMock).onBaseMessage(any(BaseMessage.class)); final String jsonMessage = createJsonBaseMessage(BaseMessage.Type.CLIENT_ID, new HashMap<String, Object>() { { put(JsonDataKeys.CLIENT_ID.toString(), expectedClientID); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(baseMessageHandlerMock, times(1)).onBaseMessage(any(BaseMessage.class)); verifyNoMoreInteractions(baseMessageHandlerMock); } public void testReceivingErrorMessage() { final String expectedErrorMessage = "Error message successfully extracted"; doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("BaseMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance ErrorMessage", invocation.getArguments()[0] instanceof ErrorMessage); ErrorMessage errorMessage = (ErrorMessage) invocation.getArguments()[0]; assertEquals("Wrong error message extracted", expectedErrorMessage, errorMessage.getMessage()); return null; } }).when(baseMessageHandlerMock).onBaseMessage(any(BaseMessage.class)); final String jsonMessage = createJsonBaseMessage(BaseMessage.Type.ERROR, new HashMap<String, Object>() { { put(JsonDataKeys.MSG.toString(), expectedErrorMessage); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(baseMessageHandlerMock, times(1)).onBaseMessage(any(BaseMessage.class)); verifyNoMoreInteractions(baseMessageHandlerMock); } public void testReceivingInfoMessage() { final float expectedCatrobatLanguageVersion = Constants.CURRENT_CATROBAT_LANGUAGE_VERSION; final String expectedProgramImageURL = "https://cdn2.scratch.mit.edu/get_image/project/11656680_480x360.png"; final WebImage expectedProgramImage = new WebImage(Uri.parse(expectedProgramImageURL)); final Job expectedFirstJob = new Job(1, "Program 1", expectedProgramImage); expectedFirstJob.setState(Job.State.FINISHED); expectedFirstJob.setProgress((short) 10); expectedFirstJob.setDownloadURL("http://scratch2.catrob.at/download?job_id=1&client_id=1&fname=Program%201"); final Job expectedSecondJob = new Job(2, "Program 2", null); expectedSecondJob.setState(Job.State.FINISHED); expectedSecondJob.setProgress((short) 20); expectedSecondJob.setDownloadURL("http://scratch2.catrob.at/download?job_id=2&client_id=1&fname=Program%202"); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("BaseMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance InfoMessage", invocation.getArguments()[0] instanceof InfoMessage); InfoMessage infoMessage = (InfoMessage) invocation.getArguments()[0]; assertEquals("Wrong catrobat language version extracted", expectedCatrobatLanguageVersion, infoMessage.getCatrobatLanguageVersion()); Job[] jobs = infoMessage.getJobList(); assertTrue("Wrong number of jobs extracted", jobs.length == 2); // first job assertEquals("Wrong state extracted of first job", expectedFirstJob.getState(), jobs[0].getState()); assertEquals("Wrong ID extracted of first job", expectedFirstJob.getJobID(), jobs[0].getJobID()); assertEquals("Wrong title extracted of first job", expectedFirstJob.getTitle(), jobs[0].getTitle()); assertEquals("Wrong image extracted of first job", expectedFirstJob.getImage().getUrl(), jobs[0].getImage().getUrl()); assertEquals("Wrong progress value extracted of first job", expectedFirstJob.getProgress(), jobs[0].getProgress()); assertEquals("Wrong downloadURL extracted of first job", expectedFirstJob.getDownloadURL(), jobs[0].getDownloadURL()); // second job assertEquals("Wrong state extracted of second job", expectedSecondJob.getState(), jobs[1].getState()); assertEquals("Wrong ID extracted of second job", expectedSecondJob.getJobID(), jobs[1].getJobID()); assertEquals("Wrong title extracted of second job", expectedSecondJob.getTitle(), jobs[1].getTitle()); assertNull("Wrong image extracted of second job", jobs[1].getImage()); assertEquals("Wrong progress value extracted of second job", expectedSecondJob.getProgress(), jobs[1].getProgress()); assertEquals("Wrong progress value extracted of second job", expectedSecondJob.getProgress(), jobs[1].getProgress()); assertEquals("Wrong downloadURL extracted of second job", expectedSecondJob.getDownloadURL(), jobs[1].getDownloadURL()); return null; } }).when(baseMessageHandlerMock).onBaseMessage(any(InfoMessage.class)); final String jsonMessage = createJsonBaseMessage(BaseMessage.Type.INFO, new HashMap<String, Object>() { { put(JsonDataKeys.CATROBAT_LANGUAGE_VERSION.toString(), expectedCatrobatLanguageVersion); put(JsonDataKeys.JOBS_INFO.toString(), new ArrayList<HashMap<String, Object>>() { { add(jobToJson(expectedFirstJob)); add(jobToJson(expectedSecondJob)); } }); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(baseMessageHandlerMock, times(1)).onBaseMessage(any(BaseMessage.class)); verifyNoMoreInteractions(baseMessageHandlerMock); } public void testReceivingJobAlreadyRunningMessage() { final String expectedJobTitle = "My program"; final String expectedJobImageURL = "https://cdn2.scratch.mit.edu/get_image/project/11656680_480x360.png"; doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance JobAlreadyRunningMessage", invocation.getArguments()[0] instanceof JobAlreadyRunningMessage); JobAlreadyRunningMessage alreadyRunningMessage; alreadyRunningMessage = (JobAlreadyRunningMessage) invocation.getArguments()[0]; assertEquals("Wrong job ID extracted", JOB_ID_OF_JOB_HANDLER, alreadyRunningMessage.getJobID()); assertEquals("Wrong job title extracted", expectedJobTitle, alreadyRunningMessage.getJobTitle()); assertEquals("Wrong job image URL extracted", expectedJobImageURL, alreadyRunningMessage.getJobImageURL()); return null; } }).when(jobHandlerMock).onJobMessage(any(JobMessage.class)); final String jsonMessage = createJsonJobMessage(JobMessage.Type.JOB_ALREADY_RUNNING, new HashMap<String, Object>() { { put(JsonDataKeys.JOB_ID.toString(), JOB_ID_OF_JOB_HANDLER); put(JsonDataKeys.JOB_TITLE.toString(), expectedJobTitle); put(JsonDataKeys.JOB_IMAGE_URL.toString(), expectedJobImageURL); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(jobHandlerMock, times(1)).onJobMessage(any(JobMessage.class)); verifyNoMoreInteractions(jobHandlerMock); } public void testReceivingJobFailedMessage() { final String expectedJobFailedMessage = "Failed to convert the program!"; doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance JobFailedMessage", invocation.getArguments()[0] instanceof JobFailedMessage); JobFailedMessage failedMessage = (JobFailedMessage) invocation.getArguments()[0]; assertEquals("Wrong job ID extracted", JOB_ID_OF_JOB_HANDLER, failedMessage.getJobID()); assertEquals("Wrong job failed message extracted", expectedJobFailedMessage, failedMessage.getMessage()); return null; } }).when(jobHandlerMock).onJobMessage(any(JobMessage.class)); final String jsonMessage = createJsonJobMessage(JobMessage.Type.JOB_FAILED, new HashMap<String, Object>() { { put(JsonDataKeys.JOB_ID.toString(), JOB_ID_OF_JOB_HANDLER); put(JsonDataKeys.MSG.toString(), expectedJobFailedMessage); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(jobHandlerMock, times(1)).onJobMessage(any(JobMessage.class)); verifyNoMoreInteractions(jobHandlerMock); } public void testReceivingJobFinishedMessage() { final String expectedDownloadURL = "http://scratch2.catrob.at/download?job_id=1&client_id=1&fname=My%20program"; final String expectedCachedUTCDateString = "2016-08-02 17:30:01"; doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance JobFinishedMessage", invocation.getArguments()[0] instanceof JobFinishedMessage); JobFinishedMessage finishedMessage = (JobFinishedMessage) invocation.getArguments()[0]; assertEquals("Wrong job ID extracted", JOB_ID_OF_JOB_HANDLER, finishedMessage.getJobID()); assertEquals("Wrong job download URL extracted", expectedDownloadURL, finishedMessage.getDownloadURL()); final Date cachedUTCDate = finishedMessage.getCachedDate(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); assertEquals("Wrong job cached date extracted", expectedCachedUTCDateString, dateFormat.format(cachedUTCDate)); return null; } }).when(jobHandlerMock).onJobMessage(any(JobMessage.class)); final String jsonMessage = createJsonJobMessage(JobMessage.Type.JOB_FINISHED, new HashMap<String, Object>() { { put(JsonDataKeys.JOB_ID.toString(), JOB_ID_OF_JOB_HANDLER); put(JsonDataKeys.URL.toString(), expectedDownloadURL); put(JsonDataKeys.CACHED_UTC_DATE.toString(), expectedCachedUTCDateString); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(jobHandlerMock, times(1)).onJobMessage(any(JobMessage.class)); verifyNoMoreInteractions(jobHandlerMock); } public void testReceivingJobOutputMessage() { final String[] expectedLines = new String[] { "line1", "line2" }; doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance JobOutputMessage", invocation.getArguments()[0] instanceof JobOutputMessage); JobOutputMessage outputMessage = (JobOutputMessage) invocation.getArguments()[0]; assertEquals("Wrong job ID extracted", JOB_ID_OF_JOB_HANDLER, outputMessage.getJobID()); final String[] lines = outputMessage.getLines(); assertEquals("Wrong number of lines extracted", 2, lines.length); assertEquals("Wrong first output line extracted", expectedLines[0], lines[0]); assertEquals("Wrong second output line extracted", expectedLines[1], lines[1]); return null; } }).when(jobHandlerMock).onJobMessage(any(JobMessage.class)); final String jsonMessage = createJsonJobMessage(JobMessage.Type.JOB_OUTPUT, new HashMap<String, Object>() { { put(JsonDataKeys.JOB_ID.toString(), JOB_ID_OF_JOB_HANDLER); put(JsonDataKeys.LINES.toString(), expectedLines); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(jobHandlerMock, times(1)).onJobMessage(any(JobMessage.class)); verifyNoMoreInteractions(jobHandlerMock); } public void testReceivingJobProgressMessage() { final short expectedProgress = 21; doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance JobProgressMessage", invocation.getArguments()[0] instanceof JobProgressMessage); JobProgressMessage progressMessage = (JobProgressMessage) invocation.getArguments()[0]; assertEquals("Wrong job ID extracted", JOB_ID_OF_JOB_HANDLER, progressMessage.getJobID()); assertEquals("Wrong job progress value extracted", expectedProgress, progressMessage.getProgress()); return null; } }).when(jobHandlerMock).onJobMessage(any(JobMessage.class)); final String jsonMessage = createJsonJobMessage(JobMessage.Type.JOB_PROGRESS, new HashMap<String, Object>() { { put(JsonDataKeys.JOB_ID.toString(), JOB_ID_OF_JOB_HANDLER); put(JsonDataKeys.PROGRESS.toString(), expectedProgress); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(jobHandlerMock, times(1)).onJobMessage(any(JobMessage.class)); verifyNoMoreInteractions(jobHandlerMock); } public void testReceivingJobReadyMessage() { doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance JobReadyMessage", invocation.getArguments()[0] instanceof JobReadyMessage); JobReadyMessage readyMessage = (JobReadyMessage) invocation.getArguments()[0]; assertEquals("Wrong job ID extracted", JOB_ID_OF_JOB_HANDLER, readyMessage.getJobID()); return null; } }).when(jobHandlerMock).onJobMessage(any(JobMessage.class)); final String jsonMessage = createJsonJobMessage(JobMessage.Type.JOB_READY, new HashMap<String, Object>() { { put(JsonDataKeys.JOB_ID.toString(), JOB_ID_OF_JOB_HANDLER); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(jobHandlerMock, times(1)).onJobMessage(any(JobMessage.class)); verifyNoMoreInteractions(jobHandlerMock); } public void testReceivingJobRunningMessage() { final String expectedJobTitle = "My program"; final String expectedJobImageURL = "https://cdn2.scratch.mit.edu/get_image/project/11656680_480x360.png"; doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertTrue("First argument must be of instance JobRunningMessage", invocation.getArguments()[0] instanceof JobRunningMessage); JobRunningMessage runningMessage = (JobRunningMessage) invocation.getArguments()[0]; assertEquals("Wrong job ID extracted", JOB_ID_OF_JOB_HANDLER, runningMessage.getJobID()); assertEquals("Wrong job title extracted", expectedJobTitle, runningMessage.getJobTitle()); assertEquals("Wrong job image URL extracted", expectedJobImageURL, runningMessage.getJobImageURL()); return null; } }).when(jobHandlerMock).onJobMessage(any(JobMessage.class)); final String jsonMessage = createJsonJobMessage(JobMessage.Type.JOB_RUNNING, new HashMap<String, Object>() { { put(JsonDataKeys.JOB_ID.toString(), JOB_ID_OF_JOB_HANDLER); put(JsonDataKeys.JOB_TITLE.toString(), expectedJobTitle); put(JsonDataKeys.JOB_IMAGE_URL.toString(), expectedJobImageURL); } }); webSocketMessageListener.onStringAvailable(jsonMessage); verify(jobHandlerMock, times(1)).onJobMessage(any(JobMessage.class)); verifyNoMoreInteractions(jobHandlerMock); } //------------------------------------------------------------------------------------------------------------------ // MessageListener interface tests //------------------------------------------------------------------------------------------------------------------ public void testScheduleJobNotInProgress() { final String expectedJobTitle = "My program"; final String expectedJobImageURL = "https://cdn2.scratch.mit.edu/get_image/project/11656680_480x360.png"; final WebImage expectedJobImage = new WebImage(Uri.parse(expectedJobImageURL)); final Job expectedJob = new Job(JOB_ID_OF_JOB_HANDLER, expectedJobTitle, expectedJobImage); final boolean expectedForceValue = false; final Client.ConvertCallback convertCallbackMock = Mockito.mock(Client.ConvertCallback.class); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertEquals("First argument must be convertCallbackMock", convertCallbackMock, invocation.getArguments()[0]); return null; } }).when(jobHandlerMock).setCallback(any(Client.ConvertCallback.class)); when(jobHandlerMock.isInProgress()).thenReturn(false); assertTrue("Job was not scheduled", webSocketMessageListener.scheduleJob(expectedJob, expectedForceValue, convertCallbackMock)); verify(jobHandlerMock, times(1)).setCallback(any(Client.ConvertCallback.class)); verify(jobHandlerMock, times(1)).onJobScheduled(); verify(jobHandlerMock, times(1)).isInProgress(); verifyNoMoreInteractions(jobHandlerMock); } public void testReschedulingAlreadyRunningJobWithDisabledForceFlagShouldFail() { final String expectedJobTitle = "My program"; final String expectedJobImageURL = "https://cdn2.scratch.mit.edu/get_image/project/11656680_480x360.png"; final WebImage expectedJobImage = new WebImage(Uri.parse(expectedJobImageURL)); final Job expectedJob = new Job(JOB_ID_OF_JOB_HANDLER, expectedJobTitle, expectedJobImage); final boolean expectedForceValue = false; final Client.ConvertCallback convertCallbackMock = Mockito.mock(Client.ConvertCallback.class); when(jobHandlerMock.isInProgress()).thenReturn(true); assertFalse("Already running job should not be rescheduled when force parameter set to false", webSocketMessageListener.scheduleJob(expectedJob, expectedForceValue, convertCallbackMock)); verify(jobHandlerMock, times(1)).isInProgress(); verifyNoMoreInteractions(jobHandlerMock); } public void testReschedulingAlreadyRunningJobWithEnabledForceFlagShouldWork() { final String expectedJobTitle = "My program"; final String expectedJobImageURL = "https://cdn2.scratch.mit.edu/get_image/project/11656680_480x360.png"; final WebImage expectedJobImage = new WebImage(Uri.parse(expectedJobImageURL)); final Job expectedJob = new Job(JOB_ID_OF_JOB_HANDLER, expectedJobTitle, expectedJobImage); final boolean expectedForceValue = true; final Client.ConvertCallback convertCallbackMock = Mockito.mock(Client.ConvertCallback.class); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertEquals("First argument must be convertCallbackMock", convertCallbackMock, invocation.getArguments()[0]); return null; } }).when(jobHandlerMock).setCallback(any(Client.ConvertCallback.class)); assertTrue("Already running Job has not been rescheduled despite of enabled force flag", webSocketMessageListener.scheduleJob(expectedJob, expectedForceValue, convertCallbackMock)); verify(jobHandlerMock, times(1)).setCallback(any(Client.ConvertCallback.class)); verify(jobHandlerMock, times(1)).onJobScheduled(); verifyNoMoreInteractions(jobHandlerMock); } public void testRestoreJobStatus() { final String expectedJobTitle = "My program"; final String expectedJobImageURL = "https://cdn2.scratch.mit.edu/get_image/project/11656680_480x360.png"; final WebImage expectedJobImage = new WebImage(Uri.parse(expectedJobImageURL)); final Job expectedJob = new Job(JOB_ID_OF_JOB_HANDLER, expectedJobTitle, expectedJobImage); final Client.ConvertCallback convertCallbackMock = Mockito.mock(Client.ConvertCallback.class); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { assertNotNull("JobMessage must not be null", invocation.getArguments()[0]); assertEquals("First argument must be convertCallbackMock", convertCallbackMock, invocation.getArguments()[0]); return null; } }).when(jobHandlerMock).setCallback(any(Client.ConvertCallback.class)); Client.DownloadCallback callback = webSocketMessageListener.restoreJobIfRunning(expectedJob, convertCallbackMock); assertNull("Already running Job has not been rescheduled despite of enabled force flag", callback); verify(jobHandlerMock, times(1)).setCallback(any(Client.ConvertCallback.class)); verifyNoMoreInteractions(jobHandlerMock); } public void testIsJobInProgressOfRunningJobShouldReturnTrue() { when(jobHandlerMock.isInProgress()).thenReturn(true); assertTrue("isJobInProgress() call must return true", webSocketMessageListener.isJobInProgress(JOB_ID_OF_JOB_HANDLER)); verify(jobHandlerMock, times(1)).isInProgress(); verifyNoMoreInteractions(jobHandlerMock); } public void testIsJobInProgressOfUnscheduledJobShouldReturnFalse() { assertFalse("isJobInProgress() call must return false", webSocketMessageListener.isJobInProgress(JOB_ID_OF_UNSCHEDULED_JOB_THAT_HAS_NO_JOB_HANDLER)); verifyZeroInteractions(jobHandlerMock); } public void testOnUserCanceledConversionEventOfRunningJobShouldForwardCallToCorrespondingJobHandler() { webSocketMessageListener.onUserCanceledConversion(JOB_ID_OF_JOB_HANDLER); verify(jobHandlerMock, times(1)).onUserCanceledConversion(); verifyNoMoreInteractions(jobHandlerMock); } public void testOnUserCanceledConversionEventOfUnscheduledJobShouldNotForwardCallToCorrespondingJobHandler() { webSocketMessageListener.onUserCanceledConversion(JOB_ID_OF_UNSCHEDULED_JOB_THAT_HAS_NO_JOB_HANDLER); verifyZeroInteractions(jobHandlerMock); } public void testGetNumberOfJobsInProgressWhenThereExistsOnlyOneRunningJobShouldReturnOne() { when(jobHandlerMock.isInProgress()).thenReturn(true); assertEquals("isJobInProgress() call must return true", webSocketMessageListener.getNumberOfJobsInProgress(), 1); verify(jobHandlerMock, times(1)).isInProgress(); verifyNoMoreInteractions(jobHandlerMock); } public void testGetNumberOfJobsInProgressWhenThereExistsOnlyOneButNotRunningJobShouldReturnZero() { when(jobHandlerMock.isInProgress()).thenReturn(false); assertEquals("isJobInProgress() call must return true", webSocketMessageListener.getNumberOfJobsInProgress(), 0); verify(jobHandlerMock, times(1)).isInProgress(); verifyNoMoreInteractions(jobHandlerMock); } //------------------------------------------------------------------------------------------------------------------ // helpers for tests //------------------------------------------------------------------------------------------------------------------ private String createJsonBaseMessage(final BaseMessage.Type type, final Map<String, Object> data) { final Map<String, Object> payloadMap = new HashMap<>(); payloadMap.put(JsonKeys.CATEGORY.toString(), CategoryType.BASE.getCategoryID()); payloadMap.put(JsonKeys.TYPE.toString(), type.getTypeID()); payloadMap.put(JsonKeys.DATA.toString(), data); final JSONObject jsonObject = new JSONObject(payloadMap); final String jsonMessage = jsonObject.toString(); assertNotNull("Cannot serialize given data to JSON! Returned null", jsonMessage); assertTrue("Cannot serialize given data to JSON! Returned empty JSON string", jsonMessage.length() > 0); return jsonMessage; } private String createJsonJobMessage(final JobMessage.Type type, final Map<String, Object> data) { final Map<String, Object> payloadMap = new HashMap<>(); payloadMap.put(JsonKeys.CATEGORY.toString(), CategoryType.JOB.getCategoryID()); payloadMap.put(JsonKeys.TYPE.toString(), type.getTypeID()); payloadMap.put(JsonKeys.DATA.toString(), data); final JSONObject jsonObject = new JSONObject(payloadMap); final String jsonMessage = jsonObject.toString(); assertNotNull("Cannot serialize given data to JSON! Returned null", jsonMessage); assertTrue("Cannot serialize given data to JSON! Returned empty JSON string", jsonMessage.length() > 0); return jsonMessage; } private HashMap<String, Object> jobToJson(final Job job) { return new HashMap<String, Object>() { { put(JsonKeys.JsonJobDataKeys.STATE.toString(), job.getState().getStateID()); put(JsonKeys.JsonJobDataKeys.JOB_ID.toString(), job.getJobID()); put(JsonKeys.JsonJobDataKeys.TITLE.toString(), job.getTitle()); if (job.getImage() != null) { put(JsonKeys.JsonJobDataKeys.IMAGE_URL.toString(), job.getImage().getUrl().toString()); } else { put(JsonKeys.JsonJobDataKeys.IMAGE_URL.toString(), null); } put(JsonKeys.JsonJobDataKeys.PROGRESS.toString(), job.getProgress()); put(JsonKeys.JsonJobDataKeys.DOWNLOAD_URL.toString(), job.getDownloadURL()); } }; } }