ExecutionDelegator { void executeJob(JobInvocation jobInvocation) { if (jobInvocation == null) { return; } if (!constraintChecker.areConstraintsSatisfied(jobInvocation)) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Not executing job because constraints still unmet. Job: " + jobInvocation); } jobFinishedCallback.onJobFinished(jobInvocation, JobService.RESULT_FAIL_RETRY); return; } if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Proceeding to execute job because constraints met. Job: " + jobInvocation); } synchronized (serviceConnections) { JobServiceConnection jobServiceConnection = serviceConnections.get(jobInvocation.getService()); if (jobServiceConnection != null) { jobServiceConnection.startJob(jobInvocation); return; } jobServiceConnection = new JobServiceConnection(execCallback, context); serviceConnections.put(jobInvocation.getService(), jobServiceConnection); jobServiceConnection.startJob(jobInvocation); boolean successfullyBound = tryBindingToJobService(jobInvocation, jobServiceConnection); if (successfullyBound) { } else { Log.e(TAG, "Unable to bind to " + jobInvocation.getService()); jobServiceConnection.unbind(); } } } ExecutionDelegator(
      Context context,
      JobFinishedCallback jobFinishedCallback,
      ConstraintChecker constraintChecker);   }
@Test public void executeJob_alreadyRunning_doesNotBindSecondTime() { JobInvocation jobInvocation = new JobInvocation.Builder() .setTag("tag") .setService("service") .setTrigger(Trigger.NOW) .build(); when(mockContext.bindService( any(Intent.class), any(ServiceConnection.class), eq(BIND_AUTO_CREATE))) .thenReturn(true); executionDelegator.executeJob(jobInvocation); verify(mockContext) .bindService(intentCaptor.capture(), connCaptor.capture(), eq(BIND_AUTO_CREATE)); connCaptor.getValue().onServiceConnected(null, noopBinder); assertFalse(connCaptor.getValue().wasUnbound()); assertTrue(connCaptor.getValue().isConnected()); reset(mockContext); executionDelegator.executeJob(jobInvocation); assertFalse(connCaptor.getValue().wasUnbound()); verify(mockContext, never()).unbindService(connCaptor.getValue()); verify(mockContext, never()) .bindService(any(Intent.class), any(ServiceConnection.class), eq(BIND_AUTO_CREATE)); }
@Test public void executeJob_startedButNotConnected_doNotStartAgain() { JobInvocation jobInvocation = new JobInvocation.Builder() .setTag("tag") .setService("service") .setTrigger(Trigger.NOW) .build(); when(mockContext.bindService( any(Intent.class), any(ServiceConnection.class), eq(BIND_AUTO_CREATE))) .thenReturn(true); executionDelegator.executeJob(jobInvocation); verify(mockContext) .bindService(intentCaptor.capture(), connCaptor.capture(), eq(BIND_AUTO_CREATE)); reset(mockContext); executionDelegator.executeJob(jobInvocation); verify(mockContext, never()) .bindService(any(Intent.class), any(JobServiceConnection.class), eq(BIND_AUTO_CREATE)); }
@Test public void executeJob_wasStartedButDisconnected_startAgain() { JobInvocation jobInvocation = new JobInvocation.Builder() .setTag("tag") .setService("service") .setTrigger(Trigger.NOW) .build(); when(mockContext.bindService( any(Intent.class), any(ServiceConnection.class), eq(BIND_AUTO_CREATE))) .thenReturn(true); executionDelegator.executeJob(jobInvocation); verify(mockContext) .bindService(intentCaptor.capture(), connCaptor.capture(), eq(BIND_AUTO_CREATE)); JobServiceConnection jobServiceConnection = connCaptor.getValue(); jobServiceConnection.onServiceConnected(null, noopBinder); jobServiceConnection.unbind(); verify(mockContext).unbindService(jobServiceConnection); reset(mockContext); executionDelegator.executeJob(jobInvocation); verify(mockContext) .bindService(any(Intent.class), any(JobServiceConnection.class), eq(BIND_AUTO_CREATE)); }
@Test public void testExecuteJob_handlesNull() { executionDelegator.executeJob(null); verifyZeroInteractions(mockContext); }
@Test public void testHandleMessage_doesntCrashOnBadJobData() { JobInvocation j = new JobInvocation.Builder() .setService(TestJobService.class.getName()) .setTag("tag") .setTrigger(Trigger.NOW) .build(); executionDelegator.executeJob(j); verify(mockContext).bindService(intentCaptor.capture(), connCaptor.capture(), anyInt()); Intent executeReq = intentCaptor.getValue(); assertEquals(JobService.ACTION_EXECUTE, executeReq.getAction()); }
@Test public void failedToBind_unbind() throws Exception { JobInvocation job = new JobInvocation.Builder() .setTag("TAG") .setTrigger(getContentUriTrigger()) .setService(TestJobService.class.getName()) .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) .build(); when(mockContext.bindService( any(Intent.class), any(ServiceConnection.class), eq(BIND_AUTO_CREATE))) .thenReturn(false); executionDelegator.executeJob(job); verify(mockContext) .bindService(intentCaptor.capture(), connCaptor.capture(), eq(BIND_AUTO_CREATE)); verify(mockContext).unbindService(connCaptor.getValue()); assertEquals(JobService.RESULT_FAIL_RETRY, receiver.lastResult); }
@Test public void securityException_unbinds() throws Exception { JobInvocation job = new JobInvocation.Builder() .setTag("TAG") .setTrigger(getContentUriTrigger()) .setService(TestJobService.class.getName()) .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) .build(); when(mockContext.bindService( any(Intent.class), any(ServiceConnection.class), eq(BIND_AUTO_CREATE))) .thenThrow(new SecurityException("should have gracefully handled this security exception")); executionDelegator.executeJob(job); verify(mockContext).bindService(any(Intent.class), connCaptor.capture(), eq(BIND_AUTO_CREATE)); verify(mockContext).unbindService(connCaptor.getValue()); assertEquals(JobService.RESULT_FAIL_RETRY, receiver.lastResult); }