diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/AbstractCommand.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/AbstractCommand.java
index 500910abac5f454b0d8a285ee8712e3f28206698..5a402c707955e84eb1062b73b426bef7612b26aa 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/AbstractCommand.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/AbstractCommand.java
@@ -29,6 +29,7 @@ import org.apache.commons.lang.StringUtils;
 
 import ch.systemsx.cisd.args4j.CmdLineParser;
 import ch.systemsx.cisd.args4j.ExampleMode;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.properties.ExtendedProperties;
 import ch.systemsx.cisd.common.ssl.SslCertificateHelper;
 import ch.systemsx.cisd.openbis.common.api.client.ServiceFinder;
@@ -44,7 +45,7 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationService
  */
 abstract class AbstractCommand
 {
-    private static final String BASH_COMMAND = "share-manager.sh";
+    static final String BASH_COMMAND = "share-manager.sh";
     private final String name;
     
     protected String sessionToken;
@@ -80,7 +81,7 @@ abstract class AbstractCommand
             parser.printUsage(writer, null);
             out.println("Example: " + cmdString + parser.printExample(ExampleMode.ALL) + " "
                     + getRequiredArgumentsString());
-            throw new IllegalArgumentException(writer.toString());
+            throw new UserFailureException(writer.toString());
         }
     }
     
@@ -89,26 +90,36 @@ abstract class AbstractCommand
         String username = getArguments().getUsername();
         if (StringUtils.isBlank(username))
         {
-            throw new IllegalArgumentException("Unspecified user name.");
+            throw new UserFailureException("Unspecified user name.");
         }
         String password = getArguments().getPassword();
         if (StringUtils.isBlank(password))
         {
-            throw new IllegalArgumentException("Unspecified password.");
+            throw new UserFailureException("Unspecified password.");
         }
         Properties properties = loadServiceProperties();
         String openBisServerUrl = DssPropertyParametersUtil.getOpenBisServerUrl(properties);
-        SslCertificateHelper.trustAnyCertificate(openBisServerUrl);
-        ServiceFinder serviceFinder = new ServiceFinder("openbis", IGeneralInformationService.SERVICE_URL);
-        IGeneralInformationService infoService = serviceFinder.createService(IGeneralInformationService.class,
-                openBisServerUrl);
+        IGeneralInformationService infoService = createGeneralInfoService(openBisServerUrl);
         sessionToken = infoService.tryToAuthenticateForAllServices(username, password);
         if (sessionToken == null)
         {
-            throw new IllegalArgumentException("Invalid username/password combination");
+            throw new UserFailureException("Invalid username/password combination.");
         }
         String downloadUrl = DssPropertyParametersUtil.getDownloadUrl(properties);
-        service = new DssServiceRpcGenericFactory().getService(downloadUrl);
+        service = createDssService(downloadUrl);
+    }
+
+    IDssServiceRpcGeneric createDssService(String downloadUrl)
+    {
+        return new DssServiceRpcGenericFactory().getService(downloadUrl);
+    }
+
+    IGeneralInformationService createGeneralInfoService(String openBisServerUrl)
+    {
+        SslCertificateHelper.trustAnyCertificate(openBisServerUrl);
+        ServiceFinder serviceFinder =
+                new ServiceFinder("openbis", IGeneralInformationService.SERVICE_URL);
+        return serviceFinder.createService(IGeneralInformationService.class, openBisServerUrl);
     }
 
     private Properties loadServiceProperties()
@@ -124,13 +135,13 @@ abstract class AbstractCommand
             return ExtendedProperties.createWith(properties);
         } catch (FileNotFoundException ex)
         {
-            throw new IllegalArgumentException("DSS service.properties file not found: "
+            throw new UserFailureException("DSS service.properties file not found: "
                     + servicPropertiesFile.getAbsolutePath()
                     + (arguments.isServicePropertiesPathSpecified() ? ""
                             : "\nUse option -sp to specify it."));
         } catch (IOException ex)
         {
-            throw new IllegalArgumentException("Error while loading '"
+            throw new UserFailureException("Error while loading '"
                     + servicPropertiesFile.getAbsolutePath() + "': " + ex, ex);
         } finally
         {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/ListSharesCommand.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/ListSharesCommand.java
index 86d9b16932a01d5381df6bd65f45f532c549a2c3..9234a17b74b5b1bd16639127e58ba9b7e1dfca75 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/ListSharesCommand.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/ListSharesCommand.java
@@ -63,7 +63,9 @@ public class ListSharesCommand extends AbstractCommand
         System.out.println(shares.size() + " shares:");
         for (ShareInfo shareInfo : shares)
         {
-            System.out.println(shareInfo.getShareId() + ": " + DirectoryRendererUtil.renderFileSize(shareInfo.getFreeSpace()) + " bytes free.");
+            System.out.println(shareInfo.getShareId() + ": "
+                    + DirectoryRendererUtil.renderFileSize(shareInfo.getFreeSpace())
+                    + " bytes free.");
         }
     }
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/ShareManagerApplication.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/ShareManagerApplication.java
index d40180fa3d3a640ed2f22c441d5d5e9608e74959..67897e919ec413db755ed3829558e261e4f69412 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/ShareManagerApplication.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/client/admin/ShareManagerApplication.java
@@ -19,6 +19,10 @@ package ch.systemsx.cisd.openbis.dss.client.admin;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.log4j.helpers.LogLog;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
 /**
  * 
  *
@@ -37,11 +41,11 @@ public class ShareManagerApplication
         }
     }
     
-    void parseAndRun(String[] args)
+    void parseAndRun(String... args)
     {
         if (args.length == 0)
         {
-            throw new IllegalArgumentException("No command specified. Allowed commands are "
+            throw new UserFailureException("No command specified. Allowed commands are "
                     + commandMap.keySet() + ".");
         }
         String commandName = args[0];
@@ -49,7 +53,7 @@ public class ShareManagerApplication
                 commandMap.get(commandName);
         if (command == null)
         {
-            throw new IllegalArgumentException("Unknown command '" + commandName
+            throw new UserFailureException("Unknown command '" + commandName
                     + "'. Allowed commands are " + commandMap.keySet() + ".");
         }
         String[] reducedArgs = new String[args.length - 1];
@@ -61,12 +65,13 @@ public class ShareManagerApplication
     
     public static void main(String[] args)
     {
+        LogLog.setQuietMode(true);
         ShareManagerApplication application =
                 new ShareManagerApplication(new ListSharesCommand(), new MoveDataSetCommand());
         try
         {
             application.parseAndRun(args);
-        } catch (IllegalArgumentException ex)
+        } catch (UserFailureException ex)
         {
             System.err.println(ex.getMessage());
             System.exit(1);
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java
index 686994bf0a4f40a4418736bc42c4b5fa5a8cd7ca..323ce039f1e89cdafd5bad3c7bd8c4fb507fb088 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGeneric.java
@@ -34,6 +34,7 @@ import org.apache.log4j.Logger;
 
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.common.filesystem.IFreeSpaceProvider;
 import ch.systemsx.cisd.common.filesystem.SimpleFreeSpaceProvider;
@@ -453,29 +454,29 @@ public class DssServiceRpcGeneric extends AbstractDssServiceRpc<IDssServiceRpcGe
         ExternalData dataSet = getOpenBISService().tryGetDataSet(dataSetCode);
         if (dataSet == null)
         {
-            throw new IllegalArgumentException("Unknown data set: " + dataSetCode);
+            throw new UserFailureException("Unknown data set: " + dataSetCode);
         }
         if (dataSet.isContainer())
         {
-            throw new IllegalArgumentException("Container data set: " + dataSetCode);
+            throw new UserFailureException("Container data set: " + dataSetCode);
         }
         DataSet realDataSet = dataSet.tryGetAsDataSet();
         String dataSetLocation = realDataSet.getDataSetLocation();
         if (realDataSet.getShareId().equals(shareId))
         {
-            throw new IllegalArgumentException("Data set " + dataSetCode + " is already in share "
+            throw new UserFailureException("Data set " + dataSetCode + " is already in share "
                     + shareId + ".");
         }
         File share = new File(getStoreDirectory(), getShareIdManager().getShareId(dataSetCode));
         File newShare = new File(getStoreDirectory(), shareId);
         if (newShare.exists() == false)
         {
-            throw new IllegalArgumentException("Share does not exists: "
+            throw new UserFailureException("Share does not exists: "
                     + newShare.getAbsolutePath());
         }
         if (newShare.isDirectory() == false)
         {
-            throw new IllegalArgumentException("Share is not a directory: "
+            throw new UserFailureException("Share is not a directory: "
                     + newShare.getAbsolutePath());
         }
         getDataSetMover().moveDataSetToAnotherShare(new File(share, dataSetLocation), newShare,
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/postregistration/EagerShufflingTaskTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/postregistration/EagerShufflingTaskTest.java
index b678a980837ada7f40d4fa1c5e2e21bc4c4f716c..9a0805fe93ed335c28973e18a22d09ab61bd4010 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/postregistration/EagerShufflingTaskTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/postregistration/EagerShufflingTaskTest.java
@@ -17,11 +17,8 @@
 package ch.systemsx.cisd.etlserver.postregistration;
 
 import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Properties;
 
 import org.apache.commons.io.FileUtils;
@@ -37,8 +34,6 @@ import ch.rinn.restrictions.Friend;
 import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
 import ch.systemsx.cisd.common.filesystem.FileUtilities;
-import ch.systemsx.cisd.common.filesystem.HostAwareFile;
-import ch.systemsx.cisd.common.filesystem.IFreeSpaceProvider;
 import ch.systemsx.cisd.common.logging.BufferedAppender;
 import ch.systemsx.cisd.common.logging.ISimpleLogger;
 import ch.systemsx.cisd.common.logging.LogLevel;
@@ -48,6 +43,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.IChecksumProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IConfigProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IShareIdManager;
+import ch.systemsx.cisd.openbis.dss.generic.shared.utils.MockFreeSpaceProvider;
 import ch.systemsx.cisd.openbis.generic.shared.Constants;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SimpleDataSetInformationDTO;
 
@@ -57,27 +53,6 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SimpleDataSetInformationDTO;
 @Friend(toClasses = EagerShufflingTask.class)
 public class EagerShufflingTaskTest extends AbstractFileSystemTestCase
 {
-    private static final class MockFreeSpaceProvider implements IFreeSpaceProvider
-    {
-        private final List<String> shares = new ArrayList<String>();
-
-        private Integer[] freeSpaceValues;
-
-        private int index;
-
-        void setFreeSpaceValues(Integer... freeSpaceValues)
-        {
-            this.freeSpaceValues = freeSpaceValues;
-        }
-
-        @Override
-        public long freeSpaceKb(HostAwareFile path) throws IOException
-        {
-            shares.add(path.getLocalFile().getName());
-            return freeSpaceValues[index++ % freeSpaceValues.length];
-        }
-    }
-
     private static final String SHARDING = "sharding/";
 
     private static final String DATA_STORE_SERVER_CODE = "DSS";
@@ -178,7 +153,7 @@ public class EagerShufflingTaskTest extends AbstractFileSystemTestCase
 
         assertEquals("Data set ds-1 successfully moved from share 1 to 4.",
                 infoMessageMatcher.recordedObject());
-        assertEquals("[1, 2, 3, 4, 4, 4]", freeSpaceProvider.shares.toString());
+        assertEquals("[1, 2, 3, 4, 4, 4]", freeSpaceProvider.getShares().toString());
         context.assertIsSatisfied();
     }
 
@@ -205,7 +180,7 @@ public class EagerShufflingTaskTest extends AbstractFileSystemTestCase
 
         assertEquals("Data set ds-1 successfully moved from share 1 to 2.",
                 infoMessageMatcher.recordedObject());
-        assertEquals("[1, 2, 3, 4, 2, 2]", freeSpaceProvider.shares.toString());
+        assertEquals("[1, 2, 3, 4, 2, 2]", freeSpaceProvider.getShares().toString());
         context.assertIsSatisfied();
     }
 
@@ -225,7 +200,7 @@ public class EagerShufflingTaskTest extends AbstractFileSystemTestCase
 
         assertEquals("No share found for shuffling data set ds-1.",
                 logMessageMatcher.recordedObject());
-        assertEquals("[1, 2, 3, 4, 1, 2, 3, 4]", freeSpaceProvider.shares.toString());
+        assertEquals("[1, 2, 3, 4, 1, 2, 3, 4]", freeSpaceProvider.getShares().toString());
         context.assertIsSatisfied();
     }
 
@@ -260,7 +235,7 @@ public class EagerShufflingTaskTest extends AbstractFileSystemTestCase
                 "After moving data set ds-1 to share 2 that share has only 900.00 KB free space. "
                         + "It might be necessary to add a new share.",
                 notificationRecorder.recordedObject());
-        assertEquals("[1, 2, 3, 4, 2, 2]", freeSpaceProvider.shares.toString());
+        assertEquals("[1, 2, 3, 4, 2, 2]", freeSpaceProvider.getShares().toString());
         context.assertIsSatisfied();
     }
 
@@ -293,7 +268,7 @@ public class EagerShufflingTaskTest extends AbstractFileSystemTestCase
 
         assertEquals("No share found for shuffling data set ds-1.",
                 notificationRecorder.recordedObject());
-        assertEquals("[1, 2, 3, 4, 1, 2, 3, 4]", freeSpaceProvider.shares.toString());
+        assertEquals("[1, 2, 3, 4, 1, 2, 3, 4]", freeSpaceProvider.getShares().toString());
         context.assertIsSatisfied();
     }
 
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/admin/ShareManagerApplicationTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/admin/ShareManagerApplicationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a46f7e9f98ba95428fab80e2e6200fd89c229598
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/client/admin/ShareManagerApplicationTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2013 ETH Zuerich, CISD
+ *
+ * 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.openbis.dss.client.admin;
+
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.testng.AssertJUnit;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.IDssServiceRpcGeneric;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationService;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ShareManagerApplicationTest extends AssertJUnit
+{
+    private static final String SEESION_TOKEN = "seesiontoken";
+
+    private static final class MockCommand extends AbstractCommand
+    {
+        private final CommonArguments arguments = new CommonArguments()
+            {
+                @Override
+                protected boolean allAdditionalMandatoryArgumentsPresent()
+                {
+                    return arguments.size() == 1;
+                }
+            };
+
+        private final IGeneralInformationService service;
+
+        private final IDssServiceRpcGeneric dssService;
+
+        private String recordedDownloadUrl;
+
+        private String recordedOpenBisServerUrl;
+
+        private boolean executed;
+
+        MockCommand(IGeneralInformationService service, IDssServiceRpcGeneric dssService)
+        {
+            super("mock");
+            this.service = service;
+            this.dssService = dssService;
+        }
+
+        @Override
+        protected CommonArguments getArguments()
+        {
+            return arguments;
+        }
+
+        @Override
+        protected String getRequiredArgumentsString()
+        {
+            return "<arg>";
+        }
+
+        @Override
+        IDssServiceRpcGeneric createDssService(String downloadUrl)
+        {
+            this.recordedDownloadUrl = downloadUrl;
+            return dssService;
+        }
+
+        @Override
+        IGeneralInformationService createGeneralInfoService(String openBisServerUrl)
+        {
+            recordedOpenBisServerUrl = openBisServerUrl;
+            return service;
+        }
+        
+        @Override
+        void execute()
+        {
+            executed = true;
+        }
+        
+    }
+    
+    private Mockery context;
+    private IDssServiceRpcGeneric dssService;
+    private IGeneralInformationService service;
+    private ShareManagerApplication shareManagerApplication;
+    private MockCommand mockCommand;
+
+    @BeforeMethod
+    public void setUp()
+    {
+        context = new Mockery();
+        dssService = context.mock(IDssServiceRpcGeneric.class);
+        service = context.mock(IGeneralInformationService.class);
+        mockCommand = new MockCommand(service, dssService);
+        shareManagerApplication = new ShareManagerApplication(mockCommand);
+    }
+
+    @AfterMethod
+    public void tearDown()
+    {
+        context.assertIsSatisfied();
+    }
+    @Test(expectedExceptionsMessageRegExp = "No command specified. Allowed commands are \\[mock\\]\\.", expectedExceptions = UserFailureException.class)
+    public void testParseAndRunMissingCommand()
+    {
+        shareManagerApplication.parseAndRun();
+        
+        context.assertIsSatisfied();
+    }
+
+    @Test(expectedExceptionsMessageRegExp = "Unknown command 'hello'. Allowed commands are \\[mock\\]\\.", expectedExceptions = UserFailureException.class)
+    public void testParseAndRunUnknowngCommand()
+    {
+        shareManagerApplication.parseAndRun("hello");
+        
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testMissingMandatoryArgument()
+    {
+        try
+        {
+            shareManagerApplication.parseAndRun("mock", "-u", "user", "-p", "pswd");
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            assertEquals(
+                    "Usage: "
+                            + AbstractCommand.BASH_COMMAND
+                            + " mock [options] <arg>\n"
+                            + " [-p,--password] VAL            : User login password\n"
+                            + " [-sp,--service-properties] VAL : Path to DSS service.properties (default:\n"
+                            + "                                  etc/service.properties)\n"
+                            + " [-u,--username] VAL            : User login name\n" + "Example: "
+                            + AbstractCommand.BASH_COMMAND + " mock -p VAL -sp VAL -u VAL <arg>\n",
+                    ex.getMessage());
+        }
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testParseAndRunLoginFailed()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(service).tryToAuthenticateForAllServices("user", "pswd");
+                    will(returnValue(null));
+                }
+            });
+        
+        try
+        {
+            shareManagerApplication.parseAndRun("mock", "-u", "user", "-p", "pswd", "a");
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            assertEquals("Invalid username/password combination.", ex.getMessage());
+        }
+        
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testParseAndRun()
+    {
+        context.checking(new Expectations()
+        {
+            {
+                one(service).tryToAuthenticateForAllServices("user", "pswd");
+                will(returnValue(SEESION_TOKEN));
+            }
+        });
+        
+        shareManagerApplication.parseAndRun("mock", "-u", "user", "-p", "pswd", "a");
+        
+        assertEquals(true, mockCommand.executed);
+        assertEquals("http://localhost:8888", mockCommand.recordedOpenBisServerUrl);
+        assertEquals("http://localhost:8889", mockCommand.recordedDownloadUrl);
+        context.assertIsSatisfied();
+    }
+    
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGenericTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGenericTest.java
index e30b6122e4b9f588f287edb32751df39b3bd7e9e..74a2d50e13f5d5fb65bb39a2831193e07bc82f7a 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGenericTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/api/v1/DssServiceRpcGenericTest.java
@@ -19,17 +19,20 @@ package ch.systemsx.cisd.openbis.dss.generic.server.api.v1;
 import java.io.File;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 
+import org.apache.commons.io.FileUtils;
 import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.springframework.aop.framework.ProxyFactoryBean;
 import org.springframework.beans.factory.support.StaticListableBeanFactory;
-import org.testng.AssertJUnit;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.common.filesystem.IFreeSpaceProvider;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.common.io.IOUtilities;
 import ch.systemsx.cisd.common.server.ISessionTokenProvider;
 import ch.systemsx.cisd.common.test.RecordingMatcher;
@@ -45,14 +48,17 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProviderTestWrapper;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.DssSessionAuthorizationHolder;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.IDssServiceRpcGeneric;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.ShareInfo;
+import ch.systemsx.cisd.openbis.dss.generic.shared.utils.MockFreeSpaceProvider;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ContainerDataSet;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSet;
 import ch.systemsx.cisd.openbis.plugin.query.shared.api.v1.IQueryApiServer;
 
 /**
  * @author Franz-Josef Elmer
  */
-public class DssServiceRpcGenericTest extends AssertJUnit
+public class DssServiceRpcGenericTest extends AbstractFileSystemTestCase
 {
-
     private static final String SESSION_TOKEN = "SESSION";
 
     private IEncapsulatedOpenBISService service;
@@ -63,8 +69,8 @@ public class DssServiceRpcGenericTest extends AssertJUnit
 
     private IShareIdManager shareIdManager;
 
-    private IFreeSpaceProvider freeSpaceProvider;
-    
+    private MockFreeSpaceProvider freeSpaceProvider;
+
     private IPluginTaskInfoProvider infoProvider;
 
     private IQueryApiServer apiService;
@@ -73,6 +79,12 @@ public class DssServiceRpcGenericTest extends AssertJUnit
 
     private IHierarchicalContent content;
 
+    private File share1;
+
+    private File share2;
+
+    private File storeDir;
+
     @BeforeMethod
     public void beforeMethod()
     {
@@ -82,7 +94,7 @@ public class DssServiceRpcGenericTest extends AssertJUnit
         context = new Mockery();
         service = context.mock(IEncapsulatedOpenBISService.class);
         apiService = context.mock(IQueryApiServer.class);
-        freeSpaceProvider = context.mock(IFreeSpaceProvider.class);
+        freeSpaceProvider = new MockFreeSpaceProvider();
         shareIdManager = context.mock(IShareIdManager.class);
         infoProvider = context.mock(IPluginTaskInfoProvider.class);
         context.checking(new Expectations()
@@ -101,6 +113,12 @@ public class DssServiceRpcGenericTest extends AssertJUnit
         DssServiceRpcGeneric nakedDssService =
                 new DssServiceRpcGeneric(service, apiService, infoProvider, freeSpaceProvider,
                         shareIdManager, contentProvider);
+        storeDir = new File(workingDirectory, "store");
+        share1 = new File(storeDir, "1");
+        share1.mkdirs();
+        share2 = new File(storeDir, "2");
+        share2.mkdirs();
+        nakedDssService.setStoreDirectory(storeDir);
         proxyFactoryBean.setTarget(nakedDssService);
         proxyFactoryBean.addAdvisor(new DssServiceRpcAuthorizationAdvisor(shareIdManager));
         dssService = (IDssServiceRpcGeneric) proxyFactoryBean.getObject();
@@ -175,7 +193,7 @@ public class DssServiceRpcGenericTest extends AssertJUnit
                     IHierarchicalContentNode mainNode = createNodeMock("mainNode");
                     one(content).getNode(path);
                     will(returnValue(mainNode));
-                    
+
                     IHierarchicalContentNode childNode1 = createNodeMock("childNode1");
                     IHierarchicalContentNode childNode1Child1 = createNodeMock("childNode1Child1");
                     IHierarchicalContentNode childNode1Child2 = createNodeMock("childNode1Child2");
@@ -244,6 +262,165 @@ public class DssServiceRpcGenericTest extends AssertJUnit
         context.assertIsSatisfied();
     }
 
+    @Test
+    public void testListAllShares()
+    {
+        prepareCheckInstanceAdminAuthorization();
+        freeSpaceProvider.setFreeSpaceValues(4711, 42);
+        
+        List<ShareInfo> shares = dssService.listAllShares(SESSION_TOKEN);
+        
+        assertEquals("1", shares.get(0).getShareId());
+        assertEquals(4711 * FileUtils.ONE_KB, shares.get(0).getFreeSpace());
+        assertEquals("2", shares.get(1).getShareId());
+        assertEquals(42 * FileUtils.ONE_KB, shares.get(1).getFreeSpace());
+        assertEquals(2, shares.size());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testShuffleDataSet()
+    {
+        File dataSetDir = new File(share1, "uuid/a/b/c/ds1");
+        dataSetDir.mkdirs();
+        FileUtilities.writeToFile(new File(dataSetDir, "hello.txt"), "hello world");
+        prepareCheckInstanceAdminAuthorization();
+        prepareLockDataSet("ds1");
+        context.checking(new Expectations()
+            {
+                {
+                    atLeast(1).of(service).tryGetDataSet("ds1");
+                    DataSet dataSet = new DataSet();
+                    dataSet.setCode("ds1");
+                    dataSet.setShareId("1");
+                    dataSet.setLocation("uuid/a/b/c/ds1");
+                    will(returnValue(dataSet));
+                    
+                    one(shareIdManager).getShareId("ds1");
+                    will(returnValue("1"));
+                    
+                    one(shareIdManager).lock("ds1");
+                    one(shareIdManager).releaseLock("ds1");
+                    
+                    one(service).updateShareIdAndSize("ds1", "2", 11);
+                    one(shareIdManager).setShareId("ds1", "2");
+                    one(shareIdManager).await("ds1");
+                }
+            });
+        freeSpaceProvider.setFreeSpaceValues(4711, 42);
+        
+        dssService.shuffleDataSet(SESSION_TOKEN, "ds1", "2");
+        
+        assertEquals("hello world",
+                FileUtilities.loadToString(new File(share2, "uuid/a/b/c/ds1/hello.txt")).trim());
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testShuffleUnknownDataSet()
+    {
+        prepareCheckInstanceAdminAuthorization();
+        prepareLockDataSet("ds1");
+        context.checking(new Expectations()
+            {
+                {
+                    atLeast(1).of(service).tryGetDataSet("ds1");
+                }
+            });
+        
+        try
+        {
+            dssService.shuffleDataSet(SESSION_TOKEN, "ds1", "2");
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            assertEquals("Unknown data set: ds1", ex.getMessage());
+        }
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testShuffleContainerDataSet()
+    {
+        prepareCheckInstanceAdminAuthorization();
+        prepareLockDataSet("ds1");
+        context.checking(new Expectations()
+            {
+                {
+                    atLeast(1).of(service).tryGetDataSet("ds1");
+                    will(returnValue(new ContainerDataSet()));
+                }
+            });
+        
+        try
+        {
+            dssService.shuffleDataSet(SESSION_TOKEN, "ds1", "2");
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            assertEquals("Container data set: ds1", ex.getMessage());
+        }
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testShuffleDataSetToSameShare()
+    {
+        prepareCheckInstanceAdminAuthorization();
+        prepareLockDataSet("ds1");
+        context.checking(new Expectations()
+            {
+                {
+                    atLeast(1).of(service).tryGetDataSet("ds1");
+                    DataSet dataSet = new DataSet();
+                    dataSet.setCode("ds1");
+                    dataSet.setShareId("1");
+                    will(returnValue(dataSet));
+                }
+            });
+
+        try
+        {
+            dssService.shuffleDataSet(SESSION_TOKEN, "ds1", "1");
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            assertEquals("Data set ds1 is already in share 1.", ex.getMessage());
+        }
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testShuffleDataSetToUnknownShare()
+    {
+        prepareCheckInstanceAdminAuthorization();
+        prepareLockDataSet("ds1");
+        context.checking(new Expectations()
+            {
+                {
+                    atLeast(1).of(service).tryGetDataSet("ds1");
+                    DataSet dataSet = new DataSet();
+                    dataSet.setCode("ds1");
+                    dataSet.setShareId("1");
+                    will(returnValue(dataSet));
+
+                    one(shareIdManager).getShareId("ds1");
+                    will(returnValue("1"));
+                }
+            });
+
+        try
+        {
+            dssService.shuffleDataSet(SESSION_TOKEN, "ds1", "3");
+            fail("UserFailureException expected");
+        } catch (UserFailureException ex)
+        {
+            assertEquals("Share does not exists: " + storeDir.getAbsolutePath() + "/3",
+                    ex.getMessage());
+        }
+        context.assertIsSatisfied();
+    }
+    
     private static String fileInfoString(String startPath, String pathInListing, long length,
             Integer checksum)
     {
@@ -265,7 +442,19 @@ public class DssServiceRpcGenericTest extends AssertJUnit
             {
                 {
                     one(shareIdManager).lock(Arrays.asList(dataSetCode));
-                    one(shareIdManager).releaseLocks();
+                    allowing(shareIdManager).releaseLocks();
+                }
+            });
+    }
+
+    private void prepareCheckInstanceAdminAuthorization()
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(service).checkInstanceAdminAuthorization(SESSION_TOKEN);
+                    one(service).checkSession(SESSION_TOKEN);
+                    allowing(shareIdManager).releaseLocks();
                 }
             });
     }
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/MockFreeSpaceProvider.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/MockFreeSpaceProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..1bd5ecc107f2da29932ed3a40365bbee7e0cf26e
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/MockFreeSpaceProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2013 ETH Zuerich, CISD
+ *
+ * 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.openbis.dss.generic.shared.utils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.systemsx.cisd.common.filesystem.HostAwareFile;
+import ch.systemsx.cisd.common.filesystem.IFreeSpaceProvider;
+
+public class MockFreeSpaceProvider implements IFreeSpaceProvider
+{
+    final List<String> shares = new ArrayList<String>();
+
+    private Integer[] freeSpaceValues;
+
+    private int index;
+
+    public void setFreeSpaceValues(Integer... freeSpaceValues)
+    {
+        this.freeSpaceValues = freeSpaceValues;
+    }
+    
+    public List<String> getShares()
+    {
+        return shares;
+    }
+
+    @Override
+    public long freeSpaceKb(HostAwareFile path) throws IOException
+    {
+        shares.add(path.getLocalFile().getName());
+        return freeSpaceValues[index++ % freeSpaceValues.length];
+    }
+}
\ No newline at end of file