@Test
public void testRun() throws Exception {

    CountingAnswer downloadCount = new CountingAnswer(null);
    when(mockTask.doInBackground()).thenCallRealMethod();
    mockTask.context = mockContext;
    mockTask.errors = new ArrayList<>();
    mockTask.done = new ArrayList<>();
    mockTask.pending = new ArrayList<>();
    mockTask.configuration = new Configuration();
    mockTask.configuration.hosts = new Configuration.Hosts();
    mockTask.configuration.hosts.items.add(new Configuration.Item());
    mockTask.configuration.hosts.items.add(new Configuration.Item());
    mockTask.configuration.hosts.items.add(new Configuration.Item());
    mockTask.configuration.hosts.items.add(new Configuration.Item());
    mockTask.configuration.hosts.items.get(0).title = "http-title";
    mockTask.configuration.hosts.items.get(0).state = Configuration.Item.STATE_DENY;
    mockTask.configuration.hosts.items.get(0).location = "http://foo";
    when(mockTask, "addError", any(Configuration.Item.class), anyString()).thenCallRealMethod();
    when(mockTask, "addDone", any(Configuration.Item.class)).thenCallRealMethod();
    RuleDatabaseItemUpdateRunnable itemUpdateRunnable = mock(RuleDatabaseItemUpdateRunnable.class);
    itemUpdateRunnable.parentTask = mockTask;
    itemUpdateRunnable.context = mockContext;
    itemUpdateRunnable.item = mockTask.configuration.hosts.items.get(0);
    when(itemUpdateRunnable, "run").thenCallRealMethod();
    when(itemUpdateRunnable, "shouldDownload").thenCallRealMethod();
    when(mockTask.getCommand(any(Configuration.Item.class))).thenReturn(itemUpdateRunnable);
    when(itemUpdateRunnable, "downloadFile", any(File.class), any(SingleWriterMultipleReaderFile.class), any(HttpURLConnection.class)).then(downloadCount);
    // Scenario 1: Validate response fails
    assertTrue(itemUpdateRunnable.shouldDownload());
    itemUpdateRunnable.run();
    assertEquals(0, downloadCount.numCalls);
    assertEquals(1, mockTask.done.size());
    // Scenario 2: Validate response succeeds
    when(itemUpdateRunnable.validateResponse(any(HttpURLConnection.class))).thenReturn(true);
    when(itemUpdateRunnable.getHttpURLConnection(any(File.class), any(SingleWriterMultipleReaderFile.class), any(URL.class))).thenCallRealMethod();
    when(itemUpdateRunnable.internalOpenHttpConnection(any(URL.class))).thenReturn(connection);
    assertTrue(itemUpdateRunnable.shouldDownload());
    itemUpdateRunnable.run();
    assertEquals(1, downloadCount.numCalls);
    assertEquals(2, mockTask.done.size());
    // Scenario 3: Download file throws an exception
    CountingAnswer downloadExceptionCount = new CountingAnswer(null) {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            super.answer(invocation);
            throw new IOException("FooBarException");
        }
    };
    when(itemUpdateRunnable, "downloadFile", any(File.class), any(SingleWriterMultipleReaderFile.class), any(HttpURLConnection.class)).then(downloadExceptionCount);
    assertTrue(itemUpdateRunnable.shouldDownload());
    itemUpdateRunnable.run();
    assertEquals(1, downloadExceptionCount.numCalls);
    assertEquals(1, mockTask.errors.size());
    assertEquals(3, mockTask.done.size());
    assertTrue("http-title in" + mockTask.errors.get(0), mockTask.errors.get(0).matches(".*http-title.*"));
}