diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/plugins/AutoArchiverTask.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/plugins/AutoArchiverTask.java
index adf6e61213368eda572f8693a0c03e3fe3cf6a16..0fd2922fe8943fd99061478d3718122166ca5b6a 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/plugins/AutoArchiverTask.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/plugins/AutoArchiverTask.java
@@ -79,8 +79,13 @@ public class AutoArchiverTask implements IMaintenanceTask
     @Override
     public void execute()
     {
-        operationLog.info("start");
-        List<AbstractExternalData> dataSets = policy.filter(archiveCandidateDiscoverer.findDatasetsForArchiving(openBISService, criteria));
+        List<AbstractExternalData> candidates = archiveCandidateDiscoverer.findDatasetsForArchiving(openBISService, criteria);
+        if (candidates.isEmpty())
+        {
+            return;
+        }
+        operationLog.info("apply policy to " + candidates.size() + " candidates for archiving.");
+        List<AbstractExternalData> dataSets = policy.filter(candidates);
         if (dataSets.isEmpty())
         {
             operationLog.info("nothing to archive");
@@ -90,7 +95,6 @@ public class AutoArchiverTask implements IMaintenanceTask
                     + CollectionUtils.abbreviate(Code.extractCodes(dataSets), 10));
             openBISService.archiveDataSets(Code.extractCodes(dataSets), removeFromDataStore);
         }
-        operationLog.info("end");
     }
 
     @Override
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/plugins/AutoArchiverTaskTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/plugins/AutoArchiverTaskTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..df8079c5995b5aafae77cdf985ed8139afac9177
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/plugins/AutoArchiverTaskTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2015 ETH Zuerich, SIS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.etlserver.plugins;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.log4j.Level;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.springframework.beans.factory.BeanFactory;
+import org.testng.AssertJUnit;
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.common.logging.BufferedAppender;
+import ch.systemsx.cisd.common.properties.PropertyUtils;
+import ch.systemsx.cisd.common.test.RecordingMatcher;
+import ch.systemsx.cisd.etlserver.IArchiveCandidateDiscoverer;
+import ch.systemsx.cisd.etlserver.IAutoArchiverPolicy;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProviderTestWrapper;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ArchiverDataSetCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PhysicalDataSet;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.DataSetBuilder;
+import ch.systemsx.cisd.openbis.util.LogRecordingUtils;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class AutoArchiverTaskTest extends AssertJUnit
+{
+    public static final class MockDiscoverer implements IArchiveCandidateDiscoverer
+    {
+        private List<AbstractExternalData> dataSets;
+
+        public MockDiscoverer(Properties properties)
+        {
+            List<String> dataSetCodes = PropertyUtils.getList(properties, "data-sets");
+            dataSets = new ArrayList<AbstractExternalData>();
+            for (String dataSetCode : dataSetCodes)
+            {
+                dataSets.add(new DataSetBuilder().code(dataSetCode).getDataSet());
+            }
+        }
+
+        @Override
+        public List<AbstractExternalData> findDatasetsForArchiving(IEncapsulatedOpenBISService openbis, 
+                ArchiverDataSetCriteria criteria)
+        {
+            return dataSets;
+        }
+    }
+    
+    public static final class MockPolicy implements IAutoArchiverPolicy
+    {
+        private Set<String> dataSetToBeFiltered;
+
+        public MockPolicy(Properties properties)
+        {
+            dataSetToBeFiltered = new HashSet<String>(PropertyUtils.getList(properties, "data-sets"));
+        }
+
+        @Override
+        public List<AbstractExternalData> filter(List<AbstractExternalData> dataSets)
+        {
+            List<AbstractExternalData> result = new ArrayList<AbstractExternalData>();
+            for (AbstractExternalData dataSet : dataSets)
+            {
+                if (dataSetToBeFiltered.contains(dataSet.getCode()))
+                {
+                    result.add(dataSet);
+                }
+            }
+            return result;
+        }
+    }
+    private BufferedAppender logRecorder;
+
+    private Mockery context;
+
+    private IEncapsulatedOpenBISService service;
+
+    @BeforeMethod
+    public void setUpTestEnvironment()
+    {
+        logRecorder = LogRecordingUtils.createRecorder("%-5p %c - %m%n", Level.INFO, "OPERATION.*");
+        context = new Mockery();
+        final BeanFactory beanFactory = context.mock(BeanFactory.class);
+        ServiceProviderTestWrapper.setApplicationContext(beanFactory);
+        service = ServiceProviderTestWrapper.mock(context, IEncapsulatedOpenBISService.class);
+    }
+
+    @AfterMethod
+    public void checkMockExpectations(ITestResult result)
+    {
+        ServiceProviderTestWrapper.restoreApplicationContext();
+        String logContent = logRecorder.getLogContent();
+        System.out.println("======= Log content for " + result.getName() + "():");
+        System.out.println(logContent);
+        System.out.println("=======");
+        if (result.getStatus() == ITestResult.FAILURE)
+        {
+            fail(result.getName() + " failed. Log content:\n" + logContent);
+        }
+        logRecorder.reset();
+        // To following line of code should also be called at the end of each test method.
+        // Otherwise one does not known which test failed.
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testNoCandidates()
+    {
+        RecordingMatcher<ArchiverDataSetCriteria> criteriaRecorder = prepareListAvailableDataSets();
+
+        createAutoArchiver(new Properties()).execute();
+
+        assertLogs();
+        assertEquals(30, criteriaRecorder.recordedObject().getOlderThan());
+        assertEquals(null, criteriaRecorder.recordedObject().tryGetDataSetTypeCode());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testArchivingWithDefaultProperties()
+    {
+        PhysicalDataSet ds1 = new DataSetBuilder().code("ds1").getDataSet();
+        RecordingMatcher<ArchiverDataSetCriteria> criteriaRecorder = prepareListAvailableDataSets(ds1);
+        prepareArchiveDataSets(false, Arrays.asList("ds1"));
+        
+        createAutoArchiver(new Properties()).execute();
+        
+        assertLogs(applyLog(1), archivingLog("ds1"));
+        assertEquals(30, criteriaRecorder.recordedObject().getOlderThan());
+        assertEquals(null, criteriaRecorder.recordedObject().tryGetDataSetTypeCode());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testArchivingWithNoFilteredDataSets()
+    {
+        PhysicalDataSet ds1 = new DataSetBuilder().code("ds1").getDataSet();
+        RecordingMatcher<ArchiverDataSetCriteria> criteriaRecorder = prepareListAvailableDataSets(ds1);
+        Properties properties = new Properties();
+        properties.setProperty("policy.class", MockPolicy.class.getName());
+        
+        createAutoArchiver(properties).execute();
+        
+        assertLogs(applyLog(1), nothingLog());
+        assertEquals(30, criteriaRecorder.recordedObject().getOlderThan());
+        assertEquals(null, criteriaRecorder.recordedObject().tryGetDataSetTypeCode());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testArchivingWithFilteredDataSets()
+    {
+        PhysicalDataSet ds1 = new DataSetBuilder().code("ds1").getDataSet();
+        PhysicalDataSet ds2 = new DataSetBuilder().code("ds2").getDataSet();
+        PhysicalDataSet ds3 = new DataSetBuilder().code("ds3").getDataSet();
+        RecordingMatcher<ArchiverDataSetCriteria> criteriaRecorder = prepareListAvailableDataSets(ds1, ds2, ds3);
+        Properties properties = new Properties();
+        properties.setProperty("older-than", "10");
+        properties.setProperty("data-set-type", "MY-TYPE");
+        properties.setProperty("remove-datasets-from-store", "true");
+        properties.setProperty("policy.class", MockPolicy.class.getName());
+        properties.setProperty("policy.data-sets", "ds1, ds3");
+        prepareArchiveDataSets(true, Arrays.asList("ds1", "ds3"));
+        
+        createAutoArchiver(properties).execute();
+        
+        assertLogs(applyLog(3), archivingLog("ds1", "ds3"));
+        assertEquals(10, criteriaRecorder.recordedObject().getOlderThan());
+        assertEquals("MY-TYPE", criteriaRecorder.recordedObject().tryGetDataSetTypeCode());
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testArchivingWithCustomDiscoverer()
+    {
+        Properties properties = new Properties();
+        properties.setProperty("archive-candidate-discoverer.data-sets", "ds1, ds2");
+        properties.setProperty("archive-candidate-discoverer.class", MockDiscoverer.class.getName());
+        prepareArchiveDataSets(false, Arrays.asList("ds1", "ds2"));
+        
+        createAutoArchiver(properties).execute();
+        
+        assertLogs(applyLog(2), archivingLog("ds1", "ds2"));
+        context.assertIsSatisfied();
+    }
+    
+    private void prepareArchiveDataSets(final boolean removeFromDataStore, final List<String> dataSetCodes)
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(service).archiveDataSets(dataSetCodes, removeFromDataStore);
+                }
+            });
+    }
+
+    private RecordingMatcher<ArchiverDataSetCriteria> prepareListAvailableDataSets(final AbstractExternalData... dataSets)
+    {
+        final RecordingMatcher<ArchiverDataSetCriteria> criteriaRecorder = new RecordingMatcher<ArchiverDataSetCriteria>();
+        context.checking(new Expectations()
+            {
+                {
+                    one(service).listAvailableDataSets(with(criteriaRecorder));
+                    will(returnValue(Arrays.asList(dataSets)));
+                }
+            });
+        return criteriaRecorder;
+    }
+    
+    private String applyLog(int numberOfCandidates)
+    {
+        return "apply policy to " + numberOfCandidates + " candidates for archiving.";
+    }
+    
+    private String nothingLog()
+    {
+        return "nothing to archive";
+    }
+    
+    private String archivingLog(String...dataSetCodes)
+    {
+        return "archiving: " + Arrays.asList(dataSetCodes);
+    }
+    
+    private void assertLogs(String...expectedLogEntries)
+    {
+        assertEquals(createBasicLogExpectation(expectedLogEntries).toString().trim(), logRecorder.getLogContent());
+    }
+
+    private StringBuilder createBasicLogExpectation(String... expectedLogEntries)
+    {
+        StringBuilder builder = new StringBuilder();
+        List<String> entries = new ArrayList<String>(Arrays.asList(expectedLogEntries));
+        entries.add(0, "Plugin AutoArchiver initialized");
+        for (String logEntry : entries)
+        {
+            builder.append("INFO  OPERATION.AutoArchiverTask - ").append(logEntry).append('\n');
+        }
+        return builder;
+    }
+    
+    private AutoArchiverTask createAutoArchiver(Properties properties)
+    {
+        AutoArchiverTask autoArchiverTask = new AutoArchiverTask();
+        autoArchiverTask.setUp("AutoArchiver", properties);
+        return autoArchiverTask;
+    }
+}