You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ra...@apache.org on 2018/03/29 18:55:46 UTC

[cloudstack] branch master updated: [CLOUDSTACK-10241] Duplicated file SRs being created in XenServer pools (#2414)

This is an automated email from the ASF dual-hosted git repository.

rafael pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new 060715e  [CLOUDSTACK-10241] Duplicated file SRs being created in XenServer pools (#2414)
060715e is described below

commit 060715e9f5f929804b7f515cfba0b4b130581876
Author: Rafael Weingärtner <ra...@gmail.com>
AuthorDate: Thu Mar 29 15:55:42 2018 -0300

    [CLOUDSTACK-10241] Duplicated file SRs being created in XenServer pools (#2414)
    
    * [CLOUDSTACK-10241] Duplicated file SRs being created in XenServer pools
    
    Due to a race condition between multiple management servers, in some rare cases, CloudStack is creating multiple file SRs to the same secondary folder. This causes a problem when introducing the SR to the XenServer pools, as “there will be VDIs with duplicated UUIDs“. The VDIs are the same, but they are seen in different SRs, and therefore cause an error.
    
    The solution to avoid race conditions between management servers is to use a deterministic srUuid for the file SR to be created (we are leaving XenServer with the burden of managing race conditions). The UUID is based on the SR file path and is generated using  UUID#nameUUIDFromBytes. Therefore, if there is an SR with the generated UUID, this means that some other management server has just created it. An exception will occur and it will contain a message saying 'Db_exn.Uniqueness_con [...]
---
 .../xenserver/resource/CitrixResourceBase.java     |   4 +-
 .../resource/Xenserver625StorageProcessor.java     | 345 ++++++++++------
 .../resource/XenServer625ResourceTest.java         |   3 +-
 .../resource/Xenserver625StorageProcessorTest.java | 459 +++++++++++++++++++++
 4 files changed, 679 insertions(+), 132 deletions(-)

diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
index 88df2ce..19670b2 100644
--- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java
@@ -198,7 +198,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
     private final static int BASE_TO_CONVERT_BYTES_INTO_KILOBYTES = 1024;
 
-    protected static final XenServerConnectionPool ConnPool = XenServerConnectionPool.getInstance();
+    private static final XenServerConnectionPool ConnPool = XenServerConnectionPool.getInstance();
     // static min values for guests on xenserver
     private static final long mem_128m = 134217728L;
 
@@ -243,7 +243,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
     protected String _guestNetworkName;
     protected int _heartbeatInterval = 60;
     protected int _heartbeatTimeout = 120;
-    protected final XsHost _host = new XsHost();
+    protected XsHost _host = new XsHost();
     protected String _instance; // instance name (default is usually "VM")
     protected boolean _isOvs = false;
     protected String _linkLocalPrivateNetworkName;
diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
index dea1752..d809560 100644
--- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java
@@ -18,6 +18,27 @@
  */
 package com.cloud.hypervisor.xenserver.resource;
 
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.cloudstack.storage.command.CopyCmdAnswer;
+import org.apache.cloudstack.storage.command.CopyCommand;
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.xmlrpc.XmlRpcException;
+
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
@@ -37,26 +58,9 @@ import com.xensource.xenapi.SR;
 import com.xensource.xenapi.Task;
 import com.xensource.xenapi.Types;
 import com.xensource.xenapi.Types.BadServerResponse;
+import com.xensource.xenapi.Types.StorageOperations;
 import com.xensource.xenapi.Types.XenAPIException;
 import com.xensource.xenapi.VDI;
-import org.apache.cloudstack.storage.command.CopyCmdAnswer;
-import org.apache.cloudstack.storage.command.CopyCommand;
-import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
-import org.apache.cloudstack.storage.to.SnapshotObjectTO;
-import org.apache.cloudstack.storage.to.TemplateObjectTO;
-import org.apache.cloudstack.storage.to.VolumeObjectTO;
-import org.apache.commons.lang.StringUtils;
-import org.apache.log4j.Logger;
-import org.apache.xmlrpc.XmlRpcException;
-
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
 
 public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
     private static final Logger s_logger = Logger.getLogger(XenServerStorageProcessor.class);
@@ -65,90 +69,181 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
         super(resource);
     }
 
-    protected boolean mountNfs(final Connection conn, final String remoteDir, String localDir) {
+    private void mountNfs(Connection conn, String remoteDir, String localDir) {
         if (localDir == null) {
             localDir = "/var/cloud_mount/" + UUID.nameUUIDFromBytes(remoteDir.getBytes());
         }
-
-        final String results = hypervisorResource.callHostPluginAsync(conn, "cloud-plugin-storage", "mountNfsSecondaryStorage", 100 * 1000, "localDir", localDir, "remoteDir",
-                remoteDir);
-
-        if (results == null || results.isEmpty()) {
+        String result = hypervisorResource.callHostPluginAsync(conn, "cloud-plugin-storage", "mountNfsSecondaryStorage", 100 * 1000, "localDir", localDir, "remoteDir", remoteDir);
+        if (StringUtils.isBlank(result)) {
             final String errMsg = "Could not mount secondary storage " + remoteDir + " on host " + localDir;
-
             s_logger.warn(errMsg);
-
             throw new CloudRuntimeException(errMsg);
         }
-
-        return true;
     }
 
-    protected boolean makeDirectory(final Connection conn, final String path) {
-        final String result = hypervisorResource.callHostPlugin(conn, "cloud-plugin-storage", "makeDirectory", "path", path);
+    protected boolean makeDirectory(Connection conn, String path) {
+        String result = hypervisorResource.callHostPlugin(conn, "cloud-plugin-storage", "makeDirectory", "path", path);
+        return StringUtils.isNotBlank(result);
+    }
 
-        if (result == null || result.isEmpty()) {
-            return false;
+    /**
+     *  Creates the file SR for the given path. If there already exist a file SR for the path, we return the existing one.
+     *  This method uses a synchronized block to guarantee that only a single file SR is created per path.
+     *  If it is not possible to retrieve one file SR or to create one, a runtime exception will be thrown.
+     */
+    protected SR createFileSR(Connection conn, String path) {
+        String srPath = StringUtils.trim(path);
+        synchronized (srPath) {
+            SR sr = retrieveAlreadyConfiguredSrWithoutException(conn, srPath);
+            if (sr == null) {
+                sr = createNewFileSr(conn, srPath);
+            }
+            if (sr == null) {
+                String hostUuid = this.hypervisorResource._host.getUuid();
+                throw new CloudRuntimeException(String.format("Could not retrieve an already used file SR for path [%s] or create a new file SR on host [%s]", srPath, hostUuid));
+            }
+            return sr;
         }
-
-        return true;
     }
 
-    protected SR createFileSR(final Connection conn, final String path) {
+    /**
+     * Creates a new file SR for the given path. If any of XenServer's checked exception occurs, we use method {@link #removeSrAndPbdIfPossible(Connection, SR, PBD)} to clean the created PBD and SR entries.
+     * To avoid race conditions between management servers, we are using a deterministic srUuid for the file SR to be created (we are leaving XenServer with the burden of managing race conditions). The UUID is based on the SR file path, and is generated using {@link UUID#nameUUIDFromBytes(byte[])}.
+     * If there is an SR with the generated UUID, this means that some other management server has just created it. An exception will occur and this exception will be an {@link InternalError}. The exception will contain {@link InternalError#message} a message saying 'Db_exn.Uniqueness_constraint_violation'.
+     * For cases where the previous described error happens, we catch the exception and use the method {@link #retrieveAlreadyConfiguredSrWithoutException(Connection, String)}.
+     */
+    protected SR createNewFileSr(Connection conn, String srPath) {
+        String hostUuid = hypervisorResource.getHost().getUuid();
+        s_logger.debug(String.format("Creating file SR for path [%s] on host [%s]", srPath, this.hypervisorResource._host.getUuid()));
         SR sr = null;
         PBD pbd = null;
-
         try {
-            final String srname = path.trim();
-            synchronized (srname.intern()) {
-                final Set<SR> srs = SR.getByNameLabel(conn, srname);
-                if (srs != null && !srs.isEmpty()) {
-                    return srs.iterator().next();
-                }
-                final Map<String, String> smConfig = new HashMap<String, String>();
-                final Host host = Host.getByUuid(conn, hypervisorResource.getHost().getUuid());
-                final String uuid = UUID.randomUUID().toString();
-                sr = SR.introduce(conn, uuid, srname, srname, "file", "file", false, smConfig);
-                final PBD.Record record = new PBD.Record();
-                record.host = host;
-                record.SR = sr;
-                smConfig.put("location", path);
-                record.deviceConfig = smConfig;
-                pbd = PBD.create(conn, record);
-                pbd.plug(conn);
-                sr.scan(conn);
-            }
+            Host host = Host.getByUuid(conn, hostUuid);
+            String srUuid = UUID.nameUUIDFromBytes(srPath.getBytes()).toString();
+
+            Map<String, String> smConfig = new HashMap<String, String>();
+            sr = SR.introduce(conn, srUuid, srPath, srPath, "file", "file", false, smConfig);
+
+            PBD.Record record = new PBD.Record();
+            record.host = host;
+            record.SR = sr;
+            smConfig.put("location", srPath);
+            record.deviceConfig = smConfig;
+            pbd = PBD.create(conn, record);
+            pbd.plug(conn);
+            sr.scan(conn);
             return sr;
-        } catch (final Exception ex) {
-            try {
-                if (pbd != null) {
-                    pbd.destroy(conn);
+        } catch (XenAPIException | XmlRpcException e) {
+            if (e instanceof Types.InternalError) {
+                String expectedDuplicatedFileSrErrorMessage = "Db_exn.Uniqueness_constraint_violation";
+
+                Types.InternalError internalErrorException = (Types.InternalError)e;
+                if (StringUtils.contains(internalErrorException.message, expectedDuplicatedFileSrErrorMessage)) {
+                    s_logger.debug(String.format(
+                            "It seems that we have hit a race condition case here while creating file SR for [%s]. Instead of creating one, we will reuse the one that already exist in the XenServer pool.",
+                            srPath));
+                    return retrieveAlreadyConfiguredSrWithoutException(conn, srPath);
                 }
-            } catch (final Exception e1) {
-                s_logger.debug("Failed to destroy PBD", ex);
             }
+            removeSrAndPbdIfPossible(conn, sr, pbd);
+            s_logger.debug(String.format("Could not create file SR [%s] on host [%s].", srPath, hostUuid), e);
+            return null;
+        }
+    }
 
-            try {
-                if (sr != null) {
-                    sr.forget(conn);
-                }
-            } catch (final Exception e2) {
-                s_logger.error("Failed to forget SR", ex);
-            }
+    /**
+     * Calls {@link #unplugPbd(Connection, PBD)} and {@link #forgetSr(Connection, SR)}, if respective objects are not null.
+     */
+    protected void removeSrAndPbdIfPossible(Connection conn, SR sr, PBD pbd) {
+        if (pbd != null) {
+            unplugPbd(conn, pbd);
+        }
+        if (sr != null) {
+            forgetSr(conn, sr);
+        }
+    }
+
+    /**
+     * This is a simple facade for {@link #retrieveAlreadyConfiguredSr(Connection, String)} method.
+     * If we catch any of the checked exception of {@link #retrieveAlreadyConfiguredSr(Connection, String)}, we re-throw as a {@link CloudRuntimeException}.
+     */
+    protected SR retrieveAlreadyConfiguredSrWithoutException(Connection conn, String srPath) {
+        try {
+            return retrieveAlreadyConfiguredSr(conn, srPath);
+        } catch (XenAPIException | XmlRpcException e) {
+            throw new CloudRuntimeException("Unexpected exception while trying to retrieve an already configured file SR for path: " + srPath);
+        }
+    }
 
-            final String msg = "createFileSR failed! due to the following: " + ex.toString();
+    /**
+     *  This method will check if there is an already configured file SR for the given path. If by any chance we find more than one SR with the same name (mount point path) we throw a runtime exception because this situation should never happen.
+     *  If we find an SR, we check if the SR is working properly (performing an {@link SR#scan(Connection)}). If everything is ok with the SR, we return it.
+     *  Otherwise, we remove the SR using {@link #forgetSr(Connection, SR)} method;
+     */
+    protected SR retrieveAlreadyConfiguredSr(Connection conn, String path) throws XenAPIException, XmlRpcException {
+        Set<SR> srs = SR.getByNameLabel(conn, path);
+        if (CollectionUtils.isEmpty(srs)) {
+            s_logger.debug("No file SR found for path: " + path);
+            return null;
+        }
+        if (srs.size() > 1) {
+            throw new CloudRuntimeException("There should be only one SR with name-label: " + path);
+        }
+        SR sr = srs.iterator().next();
+        String srUuid = sr.getUuid(conn);
+        s_logger.debug(String.format("SR [%s] was already introduced in XenServer. Checking if we can reuse it.", srUuid));
+        Map<String, StorageOperations> currentOperations = sr.getCurrentOperations(conn);
+        if (MapUtils.isEmpty(currentOperations)) {
+            s_logger.debug(String.format("There are no current operation in SR [%s]. It looks like an unusual condition. We will check if it is usable before returning it.", srUuid));
+        }
+        try {
+            sr.scan(conn);
+        } catch (XenAPIException | XmlRpcException e) {
+            s_logger.debug(String.format("Problems while checking if cached temporary SR [%s] is working properly (we executed sr-scan). We will not reuse it.", srUuid));
+            forgetSr(conn, sr);
+            return null;
+        }
+        s_logger.debug(String.format("Cached temporary SR [%s] is working properly. We will reuse it.", srUuid));
+        return sr;
+    }
 
-            s_logger.warn(msg, ex);
+    /**
+     *  Forgets the given SR. Before executing the command {@link SR#forget(Connection)}, we will unplug all of its PBDs using {@link PBD#unplug(Connection)}.
+     *  Checked exceptions are captured and re-thrown as {@link CloudRuntimeException}.
+     */
+    protected void forgetSr(Connection conn, SR sr) {
+        String srUuid = StringUtils.EMPTY;
+        try {
+            srUuid = sr.getUuid(conn);
+            Set<PBD> pbDs = sr.getPBDs(conn);
+            for (PBD pbd : pbDs) {
+                s_logger.debug(String.format("Unpluging PBD [%s] of SR [%s] as it is not working properly.", pbd.getUuid(conn), srUuid));
+                unplugPbd(conn, pbd);
+            }
+            s_logger.debug(String.format("Forgetting SR [%s] as it is not working properly.", srUuid));
+            sr.forget(conn);
+        } catch (XenAPIException | XmlRpcException e) {
+            throw new CloudRuntimeException("Exception while forgeting SR: " + srUuid, e);
+        }
+    }
 
-            throw new CloudRuntimeException(msg, ex);
+    /**
+     * Unplugs the given {@link PBD}. If checked exception happens, we re-throw as {@link CloudRuntimeException}
+     */
+    protected void unplugPbd(Connection conn, PBD pbd) {
+        String pbdUuid = StringUtils.EMPTY;
+        try {
+            pbdUuid = pbd.getUuid(conn);
+            pbd.unplug(conn);
+        } catch (XenAPIException | XmlRpcException e) {
+            throw new CloudRuntimeException(String.format("Exception while unpluging PBD [%s].", pbdUuid));
         }
     }
 
-    protected SR createFileSr(final Connection conn, final String remotePath, final String dir) {
-        final String localDir = "/var/cloud_mount/" + UUID.nameUUIDFromBytes(remotePath.getBytes());
+    protected SR createFileSr(Connection conn, String remotePath, String dir) {
+        String localDir = "/var/cloud_mount/" + UUID.nameUUIDFromBytes(remotePath.getBytes());
         mountNfs(conn, remotePath, localDir);
-        final SR sr = createFileSR(conn, localDir + "/" + dir);
-        return sr;
+        return createFileSR(conn, localDir + "/" + dir);
     }
 
     @Override
@@ -165,8 +260,8 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
 
         try {
             if (srcStore instanceof NfsTO && srcData.getObjectType() == DataObjectType.TEMPLATE) {
-                final NfsTO srcImageStore = (NfsTO) srcStore;
-                final TemplateObjectTO srcTemplate = (TemplateObjectTO) srcData;
+                final NfsTO srcImageStore = (NfsTO)srcStore;
+                final TemplateObjectTO srcTemplate = (TemplateObjectTO)srcData;
                 final String storeUrl = srcImageStore.getUrl();
                 final URI uri = new URI(storeUrl);
                 String volumePath = srcData.getPath();
@@ -188,8 +283,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
                 final Set<VDI> setVdis = srcSr.getVDIs(conn);
 
                 if (setVdis.size() != 1) {
-                    return new CopyCmdAnswer("Expected 1 VDI template, but found " + setVdis.size() + " VDI templates on: " +
-                            uri.getHost() + ":" + uri.getPath() + "/" + volumeDirectory);
+                    return new CopyCmdAnswer("Expected 1 VDI template, but found " + setVdis.size() + " VDI templates on: " + uri.getHost() + ":" + uri.getPath() + "/" + volumeDirectory);
                 }
 
                 final VDI srcVdi = setVdis.iterator().next();
@@ -202,7 +296,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
                 String chapInitiatorUsername = null;
                 String chapInitiatorSecret = null;
 
-                final PrimaryDataStoreTO destStore = (PrimaryDataStoreTO) destData.getDataStore();
+                final PrimaryDataStoreTO destStore = (PrimaryDataStoreTO)destData.getDataStore();
 
                 Map<String, String> details = destStore.getDetails();
 
@@ -317,8 +411,8 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
         return new CopyCmdAnswer("not implemented yet");
     }
 
-    protected String backupSnapshot(final Connection conn, final String primaryStorageSRUuid, final String localMountPoint, final String path,
-            final String secondaryStorageMountPath, final String snapshotUuid, String prevBackupUuid, final String prevSnapshotUuid, final Boolean isISCSI, int wait) {
+    protected String backupSnapshot(final Connection conn, final String primaryStorageSRUuid, final String localMountPoint, final String path, final String secondaryStorageMountPath,
+            final String snapshotUuid, String prevBackupUuid, final String prevSnapshotUuid, final Boolean isISCSI, int wait) {
         boolean filesrcreated = false;
         // boolean copied = false;
 
@@ -378,8 +472,8 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
 
     @Override
     protected String getVhdParent(final Connection conn, final String primaryStorageSRUuid, final String snapshotUuid, final Boolean isISCSI) {
-        final String parentUuid = hypervisorResource.callHostPlugin(conn, "cloud-plugin-storage", "getVhdParent", "primaryStorageSRUuid", primaryStorageSRUuid, "snapshotUuid",
-                snapshotUuid, "isISCSI", isISCSI.toString());
+        final String parentUuid = hypervisorResource.callHostPlugin(conn, "cloud-plugin-storage", "getVhdParent", "primaryStorageSRUuid", primaryStorageSRUuid, "snapshotUuid", snapshotUuid, "isISCSI",
+                isISCSI.toString());
 
         if (parentUuid == null || parentUuid.isEmpty() || parentUuid.equalsIgnoreCase("None")) {
             s_logger.debug("Unable to get parent of VHD " + snapshotUuid + " in SR " + primaryStorageSRUuid);
@@ -396,23 +490,23 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
         final DataTO cacheData = cmd.getCacheTO();
         final DataTO destData = cmd.getDestTO();
         final int wait = cmd.getWait();
-        final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) srcData.getDataStore();
+        final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore();
         final String primaryStorageNameLabel = primaryStore.getUuid();
         String secondaryStorageUrl = null;
         NfsTO cacheStore = null;
         String destPath = null;
         if (cacheData != null) {
-            cacheStore = (NfsTO) cacheData.getDataStore();
+            cacheStore = (NfsTO)cacheData.getDataStore();
             secondaryStorageUrl = cacheStore.getUrl();
             destPath = cacheData.getPath();
         } else {
-            cacheStore = (NfsTO) destData.getDataStore();
+            cacheStore = (NfsTO)destData.getDataStore();
             secondaryStorageUrl = cacheStore.getUrl();
             destPath = destData.getPath();
         }
 
-        final SnapshotObjectTO snapshotTO = (SnapshotObjectTO) srcData;
-        final SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO) destData;
+        final SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData;
+        final SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData;
         String snapshotUuid = snapshotTO.getPath();
 
         final String prevBackupUuid = snapshotOnImage.getParentSnapshotPath();
@@ -437,8 +531,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
                 final String chapInitiatorSecret = srcDetails.get(DiskTO.CHAP_INITIATOR_SECRET);
                 final String srType = CitrixResourceBase.SRType.LVMOISCSI.toString();
 
-                primaryStorageSR = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName,
-                        chapInitiatorUsername, chapInitiatorSecret, false, srType, true);
+                primaryStorageSR = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, false, srType, true);
 
                 final VDI srcVdi = primaryStorageSR.getVDIs(conn).iterator().next();
                 if (srcVdi == null) {
@@ -474,7 +567,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
                     mountNfs(conn, secondaryStorageMountPath, localDir);
                     final boolean result = makeDirectory(conn, localDir + "/" + folder);
                     if (!result) {
-                        details = " Filed to create folder " + folder + " in secondary storage";
+                        details = " Failed to create folder " + folder + " in secondary storage";
                         s_logger.warn(details);
                         return new CopyCmdAnswer(details);
                     }
@@ -493,7 +586,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
                     if (destStore instanceof SwiftTO) {
                         try {
                             final String container = "S-" + snapshotTO.getVolume().getVolumeId().toString();
-                            final String destSnapshotName = swiftBackupSnapshot(conn, (SwiftTO) destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, container, false, wait);
+                            final String destSnapshotName = swiftBackupSnapshot(conn, (SwiftTO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, container, false, wait);
                             final String swiftPath = container + File.separator + destSnapshotName;
                             finalPath = swiftPath;
                         } finally {
@@ -506,7 +599,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
 
                     } else if (destStore instanceof S3TO) {
                         try {
-                            finalPath = backupSnapshotToS3(conn, (S3TO) destStore, snapshotSr.getUuid(conn), folder, snapshotBackupUuid, isISCSI, wait);
+                            finalPath = backupSnapshotToS3(conn, (S3TO)destStore, snapshotSr.getUuid(conn), folder, snapshotBackupUuid, isISCSI, wait);
                             if (finalPath == null) {
                                 throw new CloudRuntimeException("S3 upload of snapshots " + snapshotBackupUuid + " failed");
                             }
@@ -543,17 +636,15 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
                 final String primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
                 if (destStore instanceof SwiftTO) {
                     final String container = "S-" + snapshotTO.getVolume().getVolumeId().toString();
-                    snapshotBackupUuid = swiftBackupSnapshot(conn, (SwiftTO) destStore, primaryStorageSRUuid, snapshotPaUuid, "S-"
-                            + snapshotTO.getVolume().getVolumeId().toString(), isISCSI, wait);
+                    snapshotBackupUuid = swiftBackupSnapshot(conn, (SwiftTO)destStore, primaryStorageSRUuid, snapshotPaUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), isISCSI, wait);
                     finalPath = container + File.separator + snapshotBackupUuid;
                 } else if (destStore instanceof S3TO) {
-                    finalPath = backupSnapshotToS3(conn, (S3TO) destStore, primaryStorageSRUuid, folder, snapshotPaUuid, isISCSI, wait);
+                    finalPath = backupSnapshotToS3(conn, (S3TO)destStore, primaryStorageSRUuid, folder, snapshotPaUuid, isISCSI, wait);
                     if (finalPath == null) {
                         throw new CloudRuntimeException("S3 upload of snapshots " + snapshotPaUuid + " failed");
                     }
                 } else {
-                    final String result = backupSnapshot(conn, primaryStorageSRUuid, localMountPoint, folder, secondaryStorageMountPath, snapshotUuid, prevBackupUuid,
-                            prevSnapshotUuid, isISCSI, wait);
+                    final String result = backupSnapshot(conn, primaryStorageSRUuid, localMountPoint, folder, secondaryStorageMountPath, snapshotUuid, prevBackupUuid, prevSnapshotUuid, isISCSI, wait);
                     final String[] tmp = result.split("#");
                     snapshotBackupUuid = tmp[0];
                     physicalSize = Long.parseLong(tmp[1]);
@@ -574,7 +665,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
                 newSnapshot.setParentSnapshotPath(prevBackupUuid);
             }
             s_logger.info("New snapshot details: " + newSnapshot.toString());
-            s_logger.info("New snapshot physical utilization: "+physicalSize);
+            s_logger.info("New snapshot physical utilization: " + physicalSize);
 
             return new CopyCmdAnswer(newSnapshot);
         } catch (final Exception e) {
@@ -592,9 +683,9 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
     @Override
     public Answer createTemplateFromVolume(final CopyCommand cmd) {
         final Connection conn = hypervisorResource.getConnection();
-        final VolumeObjectTO volume = (VolumeObjectTO) cmd.getSrcTO();
-        final TemplateObjectTO template = (TemplateObjectTO) cmd.getDestTO();
-        final NfsTO destStore = (NfsTO) cmd.getDestTO().getDataStore();
+        final VolumeObjectTO volume = (VolumeObjectTO)cmd.getSrcTO();
+        final TemplateObjectTO template = (TemplateObjectTO)cmd.getDestTO();
+        final NfsTO destStore = (NfsTO)cmd.getDestTO().getDataStore();
         final int wait = cmd.getWait();
 
         final String secondaryStoragePoolURL = destStore.getUrl();
@@ -640,8 +731,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
             final long physicalSize = tmpltVDI.getPhysicalUtilisation(conn);
             // create the template.properties file
             final String templatePath = secondaryStorageMountPath + "/" + installPath;
-            result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize,
-                    template.getId());
+            result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, template.getId());
             if (!result) {
                 throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir");
             }
@@ -691,10 +781,10 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
     public Answer createVolumeFromSnapshot(final CopyCommand cmd) {
         final Connection conn = hypervisorResource.getConnection();
         final DataTO srcData = cmd.getSrcTO();
-        final SnapshotObjectTO snapshot = (SnapshotObjectTO) srcData;
+        final SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData;
         final DataTO destData = cmd.getDestTO();
-        final PrimaryDataStoreTO pool = (PrimaryDataStoreTO) destData.getDataStore();
-        final VolumeObjectTO volume = (VolumeObjectTO) destData;
+        final PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore();
+        final VolumeObjectTO volume = (VolumeObjectTO)destData;
         final DataStoreTO imageStore = srcData.getDataStore();
 
         if (srcData.getDataStore() instanceof PrimaryDataStoreTO && destData.getDataStore() instanceof PrimaryDataStoreTO) {
@@ -705,7 +795,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
             return new CopyCmdAnswer("unsupported protocol");
         }
 
-        final NfsTO nfsImageStore = (NfsTO) imageStore;
+        final NfsTO nfsImageStore = (NfsTO)imageStore;
         final String primaryStorageNameLabel = pool.getUuid();
         final String secondaryStorageUrl = nfsImageStore.getUrl();
         final int wait = cmd.getWait();
@@ -725,7 +815,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
 
         try {
             if (pool.isManaged()) {
-                Map<String,String> destDetails = cmd.getOptions2();
+                Map<String, String> destDetails = cmd.getOptions2();
 
                 final String iScsiName = destDetails.get(DiskTO.IQN);
                 final String storageHost = destDetails.get(DiskTO.STORAGE_HOST);
@@ -733,16 +823,14 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
                 final String chapInitiatorSecret = destDetails.get(DiskTO.CHAP_INITIATOR_SECRET);
                 final String srType = CitrixResourceBase.SRType.LVMOISCSI.toString();
 
-                primaryStorageSR = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName,
-                        chapInitiatorUsername, chapInitiatorSecret, false, srType, true);
+                primaryStorageSR = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, false, srType, true);
 
             } else {
                 primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);
             }
 
             if (primaryStorageSR == null) {
-                throw new InternalErrorException("Could not create volume from snapshot because the primary Storage SR could not be created from the name label: "
-                        + primaryStorageNameLabel);
+                throw new InternalErrorException("Could not create volume from snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel);
             }
 
             final String nameLabel = "cloud-" + UUID.randomUUID().toString();
@@ -821,8 +909,8 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
     @Override
     public Answer copyVolumeFromPrimaryToSecondary(final CopyCommand cmd) {
         final Connection conn = hypervisorResource.getConnection();
-        final VolumeObjectTO srcVolume = (VolumeObjectTO) cmd.getSrcTO();
-        final VolumeObjectTO destVolume = (VolumeObjectTO) cmd.getDestTO();
+        final VolumeObjectTO srcVolume = (VolumeObjectTO)cmd.getSrcTO();
+        final VolumeObjectTO destVolume = (VolumeObjectTO)cmd.getDestTO();
         final int wait = cmd.getWait();
         final DataStoreTO destStore = destVolume.getDataStore();
 
@@ -830,7 +918,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
             SR secondaryStorage = null;
             Task task = null;
             try {
-                final NfsTO nfsStore = (NfsTO) destStore;
+                final NfsTO nfsStore = (NfsTO)destStore;
                 final URI uri = new URI(nfsStore.getUrl());
                 // Create the volume folder
                 if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath())) {
@@ -876,13 +964,13 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
         final DataTO srcData = cmd.getSrcTO();
         final DataTO destData = cmd.getDestTO();
         final int wait = cmd.getWait();
-        final VolumeObjectTO srcVolume = (VolumeObjectTO) srcData;
-        final VolumeObjectTO destVolume = (VolumeObjectTO) destData;
-        final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) destVolume.getDataStore();
+        final VolumeObjectTO srcVolume = (VolumeObjectTO)srcData;
+        final VolumeObjectTO destVolume = (VolumeObjectTO)destData;
+        final PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)destVolume.getDataStore();
         final DataStoreTO srcStore = srcVolume.getDataStore();
 
         if (srcStore instanceof NfsTO) {
-            final NfsTO nfsStore = (NfsTO) srcStore;
+            final NfsTO nfsStore = (NfsTO)srcStore;
             final String volumePath = srcVolume.getPath();
             int index = volumePath.lastIndexOf("/");
             final String volumeDirectory = volumePath.substring(0, index);
@@ -948,11 +1036,11 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
 
         final int wait = cmd.getWait();
 
-        final SnapshotObjectTO srcObj = (SnapshotObjectTO) srcData;
-        final TemplateObjectTO destObj = (TemplateObjectTO) destData;
+        final SnapshotObjectTO srcObj = (SnapshotObjectTO)srcData;
+        final TemplateObjectTO destObj = (TemplateObjectTO)destData;
 
-        final NfsTO srcStore = (NfsTO) srcObj.getDataStore();
-        final NfsTO destStore = (NfsTO) destObj.getDataStore();
+        final NfsTO srcStore = (NfsTO)srcObj.getDataStore();
+        final NfsTO destStore = (NfsTO)destObj.getDataStore();
 
         URI srcUri = null;
         URI destUri = null;
@@ -1083,8 +1171,8 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
     private Answer createTemplateFromSnapshot2(final CopyCommand cmd) {
         final Connection conn = hypervisorResource.getConnection();
 
-        final SnapshotObjectTO snapshotObjTO = (SnapshotObjectTO) cmd.getSrcTO();
-        final TemplateObjectTO templateObjTO = (TemplateObjectTO) cmd.getDestTO();
+        final SnapshotObjectTO snapshotObjTO = (SnapshotObjectTO)cmd.getSrcTO();
+        final TemplateObjectTO templateObjTO = (TemplateObjectTO)cmd.getDestTO();
 
         if (!(snapshotObjTO.getDataStore() instanceof PrimaryDataStoreTO) || !(templateObjTO.getDataStore() instanceof NfsTO)) {
             return null;
@@ -1153,8 +1241,7 @@ public class Xenserver625StorageProcessor extends XenServerStorageProcessor {
 
             templatePath = templatePath.replaceAll("//", "/");
 
-            result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, templateFilename, templateUuid, nameLabel, null, physicalSize, virtualSize,
-                    templateObjTO.getId());
+            result = hypervisorResource.postCreatePrivateTemplate(conn, templatePath, templateFilename, templateUuid, nameLabel, null, physicalSize, virtualSize, templateObjTO.getId());
 
             if (!result) {
                 throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir");
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java
index 317562c..fc14d9f 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java
@@ -19,6 +19,7 @@ import org.apache.xmlrpc.XmlRpcException;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.xensource.xenapi.Types.XenAPIException;
@@ -28,7 +29,7 @@ public class XenServer625ResourceTest extends CitrixResourceBaseTest {
     @Before
     @Override
     public void beforeTest() throws XenAPIException, XmlRpcException {
-        super.citrixResourceBase = new Xenserver625Resource();
+        super.citrixResourceBase = Mockito.spy(new Xenserver625Resource());
         super.beforeTest();
     }
 
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessorTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessorTest.java
new file mode 100644
index 0000000..0cf99b6
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessorTest.java
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 com.cloud.hypervisor.xenserver.resource;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.times;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.xmlrpc.XmlRpcException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Host;
+import com.xensource.xenapi.PBD;
+import com.xensource.xenapi.PBD.Record;
+import com.xensource.xenapi.SR;
+import com.xensource.xenapi.Types.InternalError;
+import com.xensource.xenapi.Types.XenAPIException;
+
+@RunWith(PowerMockRunner.class)
+public class Xenserver625StorageProcessorTest {
+
+    @InjectMocks
+    private Xenserver625StorageProcessor xenserver625StorageProcessor;
+
+    @Mock
+    private CitrixResourceBase citrixResourceBase;
+
+    @Mock
+    private Connection connectionMock;
+
+    private String pathMock = "pathMock";
+
+    @Before
+    public void before() {
+        xenserver625StorageProcessor = Mockito.spy(new Xenserver625StorageProcessor(citrixResourceBase));
+        citrixResourceBase._host = Mockito.mock(XsHost.class);
+        Mockito.when(citrixResourceBase.getHost()).thenReturn(citrixResourceBase._host);
+    }
+
+    @Test
+    public void makeDirectoryTestCallHostPlugingReturningEmpty() {
+        boolean makeDirectoryReturn = configureAndExecuteMakeDirectoryMethodForTest(pathMock, StringUtils.EMPTY);
+
+        assertFalse(makeDirectoryReturn);
+    }
+
+    @Test
+    public void makeDirectoryTestCallHostPlugingReturningNull() {
+        boolean makeDirectoryReturn = configureAndExecuteMakeDirectoryMethodForTest(pathMock, null);
+
+        assertFalse(makeDirectoryReturn);
+    }
+
+    @Test
+    public void makeDirectoryTestCallHostPlugingReturningSomething() {
+        boolean makeDirectoryReturn = configureAndExecuteMakeDirectoryMethodForTest(pathMock, "/fictitious/path/to/use/in/unit/test");
+
+        assertTrue(makeDirectoryReturn);
+    }
+
+    private boolean configureAndExecuteMakeDirectoryMethodForTest(String path, String returnMakeDirectory) {
+        Mockito.when(citrixResourceBase.callHostPlugin(connectionMock, "cloud-plugin-storage", "makeDirectory", "path", path)).thenReturn(returnMakeDirectory);
+        return xenserver625StorageProcessor.makeDirectory(connectionMock, path);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void createFileSRTestNoSrRetrieveNoSrCreated() {
+        Mockito.doReturn(null).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+        Mockito.doReturn(null).when(xenserver625StorageProcessor).createNewFileSr(connectionMock, pathMock);
+
+        xenserver625StorageProcessor.createFileSR(connectionMock, pathMock);
+    }
+
+    @Test
+    public void createFileSRTestSrAlreadyConfigured() {
+        SR srMockRetrievedMethod = Mockito.mock(SR.class);
+        SR srMockCreateMethod = Mockito.mock(SR.class);
+
+        Mockito.doReturn(srMockRetrievedMethod).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+        Mockito.doReturn(srMockCreateMethod).when(xenserver625StorageProcessor).createNewFileSr(connectionMock, pathMock);
+
+        SR methodCreateFileSrResult = xenserver625StorageProcessor.createFileSR(connectionMock, pathMock);
+
+        InOrder inOrder = Mockito.inOrder(xenserver625StorageProcessor);
+        inOrder.verify(xenserver625StorageProcessor, times(1)).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+        inOrder.verify(xenserver625StorageProcessor, times(0)).createNewFileSr(connectionMock, pathMock);
+
+        Assert.assertEquals(srMockRetrievedMethod, methodCreateFileSrResult);
+    }
+
+    @Test
+    public void createFileSRTestSrNotConfiguredAlreadyCreatingSr() {
+        SR srMockCreateMethod = Mockito.mock(SR.class);
+
+        Mockito.doReturn(null).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+        Mockito.doReturn(srMockCreateMethod).when(xenserver625StorageProcessor).createNewFileSr(connectionMock, pathMock);
+
+        SR methodCreateFileSrResult = xenserver625StorageProcessor.createFileSR(connectionMock, pathMock);
+
+        InOrder inOrder = Mockito.inOrder(xenserver625StorageProcessor);
+        inOrder.verify(xenserver625StorageProcessor, times(1)).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+        inOrder.verify(xenserver625StorageProcessor, times(1)).createNewFileSr(connectionMock, pathMock);
+
+        Assert.assertEquals(srMockCreateMethod, methodCreateFileSrResult);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void retrieveAlreadyConfiguredSrWithoutExceptionThrowingXenAPIException() throws XenAPIException, XmlRpcException {
+        Mockito.doThrow(XenAPIException.class).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+
+        xenserver625StorageProcessor.retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void retrieveAlreadyConfiguredSrWithoutExceptionThrowingXmlRpcException() throws XenAPIException, XmlRpcException {
+        Mockito.doThrow(XmlRpcException.class).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+
+        xenserver625StorageProcessor.retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void retrieveAlreadyConfiguredSrWithoutExceptionThrowingOtherException() throws XenAPIException, XmlRpcException {
+        Mockito.doThrow(RuntimeException.class).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+
+        xenserver625StorageProcessor.retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+    }
+
+    @Test
+    public void retrieveAlreadyConfiguredSrWithoutExceptionMethodWorking() throws XenAPIException, XmlRpcException {
+        SR srMock = Mockito.mock(SR.class);
+        Mockito.doReturn(srMock).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+
+        SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+
+        Mockito.verify(xenserver625StorageProcessor).retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+        Assert.assertEquals(srMock, sr);
+    }
+
+    @Test
+    @PrepareForTest(SR.class)
+    public void retrieveAlreadyConfiguredSrTestNoSrFound() throws XenAPIException, XmlRpcException {
+        prepareToReturnSrs(null);
+
+        SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+
+        PowerMockito.verifyStatic();
+        SR.getByNameLabel(connectionMock, pathMock);
+        Assert.assertNull(sr);
+    }
+
+    private void prepareToReturnSrs(Set<SR> srs) throws XenAPIException, XmlRpcException {
+        PowerMockito.mockStatic(SR.class);
+        PowerMockito.when(SR.getByNameLabel(connectionMock, pathMock)).thenReturn(srs);
+    }
+
+    @PrepareForTest(SR.class)
+    @Test(expected = CloudRuntimeException.class)
+    public void retrieveAlreadyConfiguredSrTestMultipleSrsFound() throws XenAPIException, XmlRpcException {
+        HashSet<SR> srs = new HashSet<>();
+        srs.add(Mockito.mock(SR.class));
+        srs.add(Mockito.mock(SR.class));
+
+        prepareToReturnSrs(srs);
+
+        xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+    }
+
+    @Test
+    @PrepareForTest(SR.class)
+    public void retrieveAlreadyConfiguredSrTestSrFailsSanityCheckWithXenAPIException() throws XenAPIException, XmlRpcException {
+        configureAndExecuteMethodRetrieveAlreadyConfiguredSrTestSrFailsSanityCheckForException(XenAPIException.class);
+    }
+
+    @Test
+    @PrepareForTest(SR.class)
+    public void retrieveAlreadyConfiguredSrTestSrFailsSanityCheckWithXmlRpcException() throws XenAPIException, XmlRpcException {
+        configureAndExecuteMethodRetrieveAlreadyConfiguredSrTestSrFailsSanityCheckForException(XmlRpcException.class);
+    }
+
+    @PrepareForTest(SR.class)
+    @Test(expected = RuntimeException.class)
+    public void retrieveAlreadyConfiguredSrTestSrFailsSanityCheckWithRuntimeException() throws XenAPIException, XmlRpcException {
+        configureAndExecuteMethodRetrieveAlreadyConfiguredSrTestSrFailsSanityCheckForException(RuntimeException.class);
+    }
+
+    private void configureAndExecuteMethodRetrieveAlreadyConfiguredSrTestSrFailsSanityCheckForException(Class<? extends Throwable> exceptionClass) throws XenAPIException, XmlRpcException {
+        SR srMock = Mockito.mock(SR.class);
+        Mockito.doThrow(exceptionClass).when(srMock).scan(connectionMock);
+
+        HashSet<SR> srs = new HashSet<>();
+        srs.add(srMock);
+
+        prepareToReturnSrs(srs);
+        Mockito.doNothing().when(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+
+        SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+
+        Assert.assertNull(sr);
+        Mockito.verify(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+    }
+
+    @Test
+    @PrepareForTest(SR.class)
+    public void methodRetrieveAlreadyConfiguredSrTestSrScanSucceeds() throws XenAPIException, XmlRpcException {
+        SR srMock = Mockito.mock(SR.class);
+        Mockito.doNothing().when(srMock).scan(connectionMock);
+
+        HashSet<SR> srs = new HashSet<>();
+        srs.add(srMock);
+
+        prepareToReturnSrs(srs);
+        Mockito.doNothing().when(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+
+        SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+
+        Assert.assertEquals(srMock, sr);
+        Mockito.verify(xenserver625StorageProcessor, times(0)).forgetSr(connectionMock, srMock);
+    }
+
+    @Test
+    public void forgetSrTest() throws XenAPIException, XmlRpcException {
+        PBD pbdMock = Mockito.mock(PBD.class);
+        Set<PBD> pbds = new HashSet<>();
+        pbds.add(pbdMock);
+
+        SR srMock = Mockito.mock(SR.class);
+        Mockito.when(srMock.getPBDs(connectionMock)).thenReturn(pbds);
+
+        Mockito.doNothing().when(xenserver625StorageProcessor).unplugPbd(connectionMock, pbdMock);
+
+        xenserver625StorageProcessor.forgetSr(connectionMock, srMock);
+        Mockito.verify(srMock).getPBDs(connectionMock);
+        Mockito.verify(xenserver625StorageProcessor, times(1)).unplugPbd(connectionMock, pbdMock);
+        Mockito.verify(srMock).forget(connectionMock);
+    }
+
+    @Test
+    public void unplugPbdTest() throws XenAPIException, XmlRpcException {
+        PBD pbdMock = Mockito.mock(PBD.class);
+
+        xenserver625StorageProcessor.unplugPbd(connectionMock, pbdMock);
+
+        Mockito.verify(pbdMock).getUuid(connectionMock);
+        Mockito.verify(pbdMock).unplug(connectionMock);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void unplugPbdTestThrowXenAPIException() throws XenAPIException, XmlRpcException {
+        prepareAndExecuteUnplugMethodForException(XenAPIException.class);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void unplugPbdTestThrowXmlRpcException() throws XenAPIException, XmlRpcException {
+        prepareAndExecuteUnplugMethodForException(XmlRpcException.class);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void unplugPbdTestThrowRuntimeException() throws XenAPIException, XmlRpcException {
+        prepareAndExecuteUnplugMethodForException(RuntimeException.class);
+    }
+
+    private void prepareAndExecuteUnplugMethodForException(Class<? extends Throwable> exceptionClass) throws XenAPIException, XmlRpcException {
+        PBD pbdMock = Mockito.mock(PBD.class);
+        Mockito.doThrow(exceptionClass).when(pbdMock).unplug(connectionMock);
+        xenserver625StorageProcessor.unplugPbd(connectionMock, pbdMock);
+    }
+
+    @Test
+    @PrepareForTest({Host.class, SR.class})
+    public void createNewFileSrTestThrowingXenAPIException() throws XenAPIException, XmlRpcException {
+        prepareAndExecuteTestcreateNewFileSrTestThrowingException(XenAPIException.class);
+    }
+
+    @Test
+    @PrepareForTest({Host.class, SR.class})
+    public void createNewFileSrTestThrowingXmlRpcException() throws XenAPIException, XmlRpcException {
+        prepareAndExecuteTestcreateNewFileSrTestThrowingException(XmlRpcException.class);
+    }
+
+    @Test(expected = RuntimeException.class)
+    @PrepareForTest({Host.class, SR.class})
+    public void createNewFileSrTestThrowingRuntimeException() throws XenAPIException, XmlRpcException {
+        prepareAndExecuteTestcreateNewFileSrTestThrowingException(RuntimeException.class);
+    }
+
+    private void prepareAndExecuteTestcreateNewFileSrTestThrowingException(Class<? extends Throwable> exceptionClass) throws XenAPIException, XmlRpcException {
+        String uuid = "hostUuid";
+        Mockito.when(citrixResourceBase._host.getUuid()).thenReturn(uuid);
+
+        String srUuid = UUID.nameUUIDFromBytes(pathMock.getBytes()).toString();
+
+        Host hostMock = Mockito.mock(Host.class);
+
+        PowerMockito.mockStatic(Host.class);
+        PowerMockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
+
+        PowerMockito.mockStatic(SR.class);
+        PowerMockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
+                Mockito.anyMapOf(String.class, String.class))).thenThrow(Mockito.mock(exceptionClass));
+
+        Mockito.doNothing().when(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
+
+        SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
+
+        assertNull(sr);
+        Mockito.verify(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
+    }
+
+    @Test
+    @PrepareForTest({Host.class, SR.class})
+    public void createNewFileSrTestThrowingDbUniqueException() throws XenAPIException, XmlRpcException {
+        String uuid = "hostUuid";
+        Mockito.when(citrixResourceBase._host.getUuid()).thenReturn(uuid);
+
+        SR srMock = Mockito.mock(SR.class);
+        Mockito.doReturn(srMock).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+        String srUuid = UUID.nameUUIDFromBytes(pathMock.getBytes()).toString();
+
+        Host hostMock = Mockito.mock(Host.class);
+
+        PowerMockito.mockStatic(Host.class);
+        PowerMockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
+
+        PowerMockito.mockStatic(SR.class);
+        InternalError dbUniquenessException = new InternalError("message: Db_exn.Uniqueness_constraint_violation(\"SR\", \"uuid\", \"fd3edbcf-f142-83d1-3fcb-029ca2446b68\")");
+
+        PowerMockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
+                Mockito.anyMapOf(String.class, String.class))).thenThrow(dbUniquenessException);
+
+        Mockito.doNothing().when(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
+
+        SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
+
+        Assert.assertEquals(srMock, sr);
+        Mockito.verify(xenserver625StorageProcessor, times(0)).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
+        Mockito.verify(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+    }
+
+    @Test
+    @PrepareForTest({Host.class, SR.class, PBD.class})
+    public void createNewFileSrTest() throws XenAPIException, XmlRpcException {
+        String uuid = "hostUuid";
+        Mockito.when(citrixResourceBase._host.getUuid()).thenReturn(uuid);
+
+        SR srMock = Mockito.mock(SR.class);
+        Mockito.doReturn(srMock).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+        String srUuid = UUID.nameUUIDFromBytes(pathMock.getBytes()).toString();
+
+        Host hostMock = Mockito.mock(Host.class);
+
+        PowerMockito.mockStatic(Host.class);
+        PowerMockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
+
+        PowerMockito.mockStatic(SR.class);
+        PowerMockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
+                Mockito.anyMapOf(String.class, String.class))).thenReturn(srMock);
+
+        PowerMockito.mockStatic(PBD.class);
+        PBD pbdMock = Mockito.mock(PBD.class);
+        PowerMockito.when(PBD.create(Mockito.eq(connectionMock), Mockito.any(Record.class))).thenReturn(pbdMock);
+
+        Mockito.doNothing().when(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
+        SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
+
+        Assert.assertEquals(srMock, sr);
+        Mockito.verify(xenserver625StorageProcessor, times(0)).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
+        Mockito.verify(xenserver625StorageProcessor, times(0)).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+
+        Mockito.verify(srMock).scan(connectionMock);
+        Mockito.verify(pbdMock).plug(connectionMock);
+
+        PowerMockito.verifyStatic();
+        SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
+                Mockito.anyMapOf(String.class, String.class));
+        PBD.create(Mockito.eq(connectionMock), Mockito.any(Record.class));
+    }
+
+    @Test
+    public void removeSrAndPbdIfPossibleBothPbdAndSrNotNull() {
+        SR srMock = Mockito.mock(SR.class);
+        Mockito.doNothing().when(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+
+        PBD pbdMock = Mockito.mock(PBD.class);
+        Mockito.doNothing().when(xenserver625StorageProcessor).unplugPbd(connectionMock, pbdMock);
+
+        xenserver625StorageProcessor.removeSrAndPbdIfPossible(connectionMock, srMock, pbdMock);
+
+        Mockito.verify(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+        Mockito.verify(xenserver625StorageProcessor).unplugPbd(connectionMock, pbdMock);
+
+    }
+
+    @Test
+    public void removeSrAndPbdIfPossiblePbdNullAndSrNotNull() {
+        SR srMock = Mockito.mock(SR.class);
+        Mockito.doNothing().when(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+
+        xenserver625StorageProcessor.removeSrAndPbdIfPossible(connectionMock, srMock, null);
+
+        Mockito.verify(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+        Mockito.verify(xenserver625StorageProcessor, times(0)).unplugPbd(Mockito.eq(connectionMock), Mockito.any(PBD.class));
+
+    }
+
+    @Test
+    public void removeSrAndPbdIfPossiblePbdNotNullButSrNull() {
+        PBD pbdMock = Mockito.mock(PBD.class);
+        Mockito.doNothing().when(xenserver625StorageProcessor).unplugPbd(connectionMock, pbdMock);
+
+        xenserver625StorageProcessor.removeSrAndPbdIfPossible(connectionMock, null, pbdMock);
+
+        Mockito.verify(xenserver625StorageProcessor, times(0)).forgetSr(Mockito.eq(connectionMock), Mockito.any(SR.class));
+        Mockito.verify(xenserver625StorageProcessor).unplugPbd(connectionMock, pbdMock);
+
+    }
+
+    @Test
+    public void removeSrAndPbdIfPossibleBothPbdAndSrNull() {
+        xenserver625StorageProcessor.removeSrAndPbdIfPossible(connectionMock, null, null);
+
+        Mockito.verify(xenserver625StorageProcessor, times(0)).forgetSr(Mockito.eq(connectionMock), Mockito.any(SR.class));
+        Mockito.verify(xenserver625StorageProcessor, times(0)).unplugPbd(Mockito.eq(connectionMock), Mockito.any(PBD.class));
+
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
rafael@apache.org.