Index: /trunk/src/VBox/Main/include/MediumImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MediumImpl.h	(revision 75372)
+++ /trunk/src/VBox/Main/include/MediumImpl.h	(revision 75373)
@@ -202,4 +202,9 @@
     void i_cancelMergeTo(MediumLockList *aChildrenToReparent,
                        MediumLockList *aMediumLockList);
+
+    HRESULT i_resize(LONG64 aLogicalSize,
+                     MediumLockList *aMediumLockList,
+                     ComObjPtr<Progress> *aProgress,
+                     bool aWait);
 
     HRESULT i_fixParentUuidOfChildren(MediumLockList *pChildrenToReparent);
Index: /trunk/src/VBox/Main/src-server/MediumImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MediumImpl.cpp	(revision 75372)
+++ /trunk/src/VBox/Main/src-server/MediumImpl.cpp	(revision 75373)
@@ -3379,13 +3379,12 @@
     HRESULT rc = S_OK;
     ComObjPtr<Progress> pProgress;
-    Medium::Task *pTask = NULL;
+
+    /* Build the medium lock list. */
+    MediumLockList *pMediumLockList(new MediumLockList());
 
     try
     {
-        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-        /* Build the medium lock list. */
-        MediumLockList *pMediumLockList(new MediumLockList());
-        alock.release();
+        const char *pszError = NULL;
+
         rc = i_createMediumLockList(true /* fFailIfInaccessible */ ,
                                     this /* pToLockWrite */,
@@ -3393,20 +3392,22 @@
                                     NULL,
                                     *pMediumLockList);
-        alock.acquire();
         if (FAILED(rc))
         {
+            pszError = tr("Failed to create medium lock list when resize '%s'");
+        }
+        else
+        {
+            rc = pMediumLockList->Lock();
+            if (FAILED(rc))
+                pszError = tr("Failed to lock media when compacting '%s'");
+        }
+
+
+        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+        if (FAILED(rc))
+        {
             delete pMediumLockList;
-            throw rc;
-        }
-
-        alock.release();
-        rc = pMediumLockList->Lock();
-        alock.acquire();
-        if (FAILED(rc))
-        {
-            delete pMediumLockList;
-            throw setError(rc,
-                           tr("Failed to lock media when compacting '%s'"),
-                           i_getLocationFull().c_str());
+            throw setError(rc, pszError, i_getLocationFull().c_str());
         }
 
@@ -3414,5 +3415,5 @@
         rc = pProgress->init(m->pVirtualBox,
                              static_cast <IMedium *>(this),
-                             BstrFmt(tr("Compacting medium '%s'"), m->strLocationFull.c_str()).raw(),
+                             BstrFmt(tr("Resizing medium '%s'"), m->strLocationFull.c_str()).raw(),
                              TRUE /* aCancelable */);
         if (FAILED(rc))
@@ -3421,23 +3422,14 @@
             throw rc;
         }
-
-        /* setup task object to carry out the operation asynchronously */
-        pTask = new Medium::ResizeTask(this, aLogicalSize, pProgress, pMediumLockList);
-        rc = pTask->rc();
-        AssertComRC(rc);
-        if (FAILED(rc))
-            throw rc;
     }
     catch (HRESULT aRC) { rc = aRC; }
 
     if (SUCCEEDED(rc))
-    {
-        rc = pTask->createThread();
-
-        if (SUCCEEDED(rc))
-            pProgress.queryInterfaceTo(aProgress.asOutParam());
-    }
-    else if (pTask != NULL)
-        delete pTask;
+        rc = i_resize(aLogicalSize, pMediumLockList, &pProgress, false /* aWait */);
+
+    if (SUCCEEDED(rc))
+        pProgress.queryInterfaceTo(aProgress.asOutParam());
+    else
+        delete pMediumLockList;
 
     return rc;
@@ -5530,5 +5522,14 @@
                  * media are used by a running VM.
                  */
-                bool fMergeIntoThis = cbMediumThis > cbMediumOther;
+
+                uint32_t mediumVariants =  MediumVariant_Fixed | MediumVariant_VmdkStreamOptimized;
+                uint32_t mediumCaps = MediumFormatCapabilities_CreateDynamic | MediumFormatCapabilities_File;
+
+                bool fDynamicOther =    pOther->i_getMediumFormat()->i_getCapabilities() & mediumCaps
+                                     && pOther->i_getVariant() & ~mediumVariants;
+                bool fDynamicThis =    i_getMediumFormat()->i_getCapabilities() & mediumCaps
+                                    && i_getVariant() & ~mediumVariants;
+                bool fMergeIntoThis =    (fDynamicThis && !fDynamicOther)
+                                      || (fDynamicThis == fDynamicOther && cbMediumThis > cbMediumOther);
                 fMergeForward = fMergeIntoThis != fThisParent;
             }
@@ -6004,5 +6005,9 @@
                                              i_getName().c_str(),
                                              tgtName.c_str()).raw(),
-                                     TRUE /* aCancelable */);
+                                     TRUE, /* aCancelable */
+                                     2, /* Number of opearations */
+                                     BstrFmt(tr("Resizing medium '%s' before merge"),
+                                             tgtName.c_str()).raw()
+                                     );
                 if (FAILED(rc))
                     throw rc;
@@ -6051,5 +6056,6 @@
  * @param aMediumLockList Medium locking information.
  *
- * @note Locks the media from the chain for writing.
+ * @note Locks the tree lock for writing. Locks the media from the chain
+ *       for writing.
  */
 void Medium::i_cancelMergeTo(MediumLockList *aChildrenToReparent,
@@ -6096,4 +6102,107 @@
     if (aChildrenToReparent)
         delete aChildrenToReparent;
+}
+
+/**
+ * Resizes the media.
+ *
+ * If @a aWait is @c true then this method will perform the operation on the
+ * calling thread and will not return to the caller until the operation is
+ * completed. When this method succeeds, the state of the target medium (and all
+ * involved extra media) will be restored. @a aMediumLockList will not be
+ * deleted, whether the operation is successful or not. The caller has to do
+ * this if appropriate.
+ *
+ * If @a aWait is @c false then this method will create a thread to perform the
+ * operation asynchronously and will return immediately. The thread will reset
+ * the state of the target medium (and all involved extra media) and delete
+ * @a aMediumLockList.
+ *
+ * When this method fails (regardless of the @a aWait mode), it is a caller's
+ * responsibility to undo state changes and delete @a aMediumLockList.
+ *
+ * If @a aProgress is not NULL but the object it points to is @c null then a new
+ * progress object will be created and assigned to @a *aProgress on success,
+ * otherwise the existing progress object is used. If Progress is NULL, then no
+ * progress object is created/used at all. Note that @a aProgress cannot be
+ * NULL when @a aWait is @c false (this method will assert in this case).
+ *
+ * @param aLogicalSize  New nominal capacity of the medium in bytes.
+ * @param aMediumLockList Medium locking information.
+ * @param aProgress     Where to find/store a Progress object to track operation
+ *                      completion.
+ * @param aWait         @c true if this method should block instead of creating
+ *                      an asynchronous thread.
+ *
+ * @note Locks the media from the chain for writing.
+ */
+
+HRESULT Medium::i_resize(LONG64 aLogicalSize,
+                         MediumLockList *aMediumLockList,
+                         ComObjPtr<Progress> *aProgress,
+                         bool aWait)
+{
+    AssertReturn(aMediumLockList != NULL, E_FAIL);
+    AssertReturn(aProgress != NULL || aWait == true, E_FAIL);
+
+    AutoCaller autoCaller(this);
+    AssertComRCReturnRC(autoCaller.rc());
+
+    HRESULT rc = S_OK;
+    ComObjPtr<Progress> pProgress;
+    Medium::Task *pTask = NULL;
+
+    try
+    {
+        if (aProgress != NULL)
+        {
+            /* use the existing progress object... */
+            pProgress = *aProgress;
+
+            /* ...but create a new one if it is null */
+            if (pProgress.isNull())
+            {
+                AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+                pProgress.createObject();
+                rc = pProgress->init(m->pVirtualBox,
+                                     static_cast <IMedium *>(this),
+                                     BstrFmt(tr("Resizing medium '%s'"), m->strLocationFull.c_str()).raw(),
+                                     TRUE /* aCancelable */);
+                if (FAILED(rc))
+                    throw rc;
+            }
+        }
+
+        /* setup task object to carry out the operation asynchronously */
+        pTask = new Medium::ResizeTask(this,
+                                       aLogicalSize,
+                                       pProgress,
+                                       aMediumLockList,
+                                       aWait /* fKeepMediumLockList */);
+        rc = pTask->rc();
+        AssertComRC(rc);
+        if (FAILED(rc))
+            throw rc;
+    }
+    catch (HRESULT aRC) { rc = aRC; }
+
+    if (SUCCEEDED(rc))
+    {
+        if (aWait)
+        {
+            rc = pTask->runNow();
+            delete pTask;
+        }
+        else
+            rc = pTask->createThread();
+
+        if (SUCCEEDED(rc) && aProgress != NULL)
+            *aProgress = pProgress;
+    }
+    else if (pTask != NULL)
+        delete pTask;
+
+    return rc;
 }
 
@@ -8653,4 +8762,88 @@
                                task.mParentForTarget->m->strLocationFull.c_str());
             }
+
+        // Resize target to source size, if possible. Otherwise throw an error.
+        // It's offline resizing. Online resizing will be called in the
+        // SessionMachine::onlineMergeMedium.
+
+        uint64_t sourceSize = 0;
+        Utf8Str sourceName;
+        {
+            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+            sourceSize = i_getLogicalSize();
+            sourceName = i_getName();
+        }
+        uint64_t targetSize = 0;
+        Utf8Str targetName;
+        {
+            AutoReadLock alock(pTarget COMMA_LOCKVAL_SRC_POS);
+            targetSize = pTarget->i_getLogicalSize();
+            targetName = pTarget->i_getName();
+        }
+
+        //reducing vm disks are not implemented yet
+        if (sourceSize > targetSize)
+        {
+            if (i_isMediumFormatFile())
+            {
+                // Have to make own lock list, because "resize" method resizes only last image
+                // in the lock chain. The lock chain already in the task.mpMediumLockList, so
+                // just make new lock list based on it. In fact the own lock list neither makes
+                // double locking of mediums nor unlocks them during delete, because medium
+                // already locked by task.mpMediumLockList and own list is used just to specify
+                // what "resize" method should resize.
+
+                MediumLockList* pMediumLockListForResize = new MediumLockList();
+
+                for (MediumLockList::Base::iterator it = task.mpMediumLockList->GetBegin();
+                     it != task.mpMediumLockList->GetEnd();
+                     ++it)
+                {
+                    ComObjPtr<Medium> pMedium = it->GetMedium();
+                    pMediumLockListForResize->Append(pMedium, pMedium->m->state == MediumState_LockedWrite);
+                    if (pMedium == pTarget)
+                        break;
+                }
+
+                // just to switch internal state of the lock list to avoid errors during list deletion,
+                // because all meduims in the list already locked by task.mpMediumLockList
+                HRESULT rc = pMediumLockListForResize->Lock(true /* fSkipOverLockedMedia */);
+                if (FAILED(rc))
+                {
+                    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+                    rc = setError(rc,
+                                  tr("Failed to lock the medium '%s' to resize before merge"),
+                                  targetName.c_str());
+                    delete pMediumLockListForResize;
+                    throw rc;
+                }
+
+                ComObjPtr<Progress> pProgress(task.GetProgressObject());
+                rc = pTarget->i_resize(sourceSize, pMediumLockListForResize, &pProgress, true);
+                if (FAILED(rc))
+                {
+                    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+                    rc = setError(rc,
+                                  tr("Failed to set size of '%s' to size of '%s'"),
+                                  targetName.c_str(), sourceName.c_str());
+                    delete pMediumLockListForResize;
+                    throw rc;
+                }
+                delete pMediumLockListForResize;
+            }
+            else
+            {
+                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+                HRESULT rc = setError(VBOX_E_NOT_SUPPORTED,
+                                      tr("Sizes of '%s' and '%s' are different and medium format does not support resing"),
+                                      sourceName.c_str(), targetName.c_str());
+                throw rc;
+            }
+        }
+
+        task.GetProgressObject()->SetNextOperation(BstrFmt(tr("Merging medium '%s' to '%s'"),
+                                                           i_getName().c_str(),
+                                                           targetName.c_str()).raw(),
+                                                   1);
 
         PVDISK hdd;
@@ -9786,5 +9979,10 @@
                     Assert(pMedium->m->state == MediumState_LockedWrite);
                 else
-                    Assert(pMedium->m->state == MediumState_LockedRead);
+                    Assert(pMedium->m->state == MediumState_LockedRead ||
+                           // Allow resize the target image during mergeTo in case
+                           // of direction from parent to child because all intermediate
+                           // images are marked to MediumState_Deleting and will be
+                           // destroyed after successful merge
+                           pMedium->m->state == MediumState_Deleting);
 
                 /* Open all media but last in read-only mode. Do not handle
Index: /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp	(revision 75372)
+++ /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp	(revision 75373)
@@ -2504,4 +2504,6 @@
     }
 
+    bool fDeleteOnline = mData->mMachineState == MachineState_Running || mData->mMachineState == MachineState_Paused;
+
     // count normal hard disks and add their sizes to the weight
     for (MediumAttachmentList::iterator
@@ -2527,4 +2529,7 @@
                 // normal or immutable media need attention
                 ++ulOpCount;
+                // offline merge includes medium resizing
+                if (!fDeleteOnline)
+                    ++ulOpCount;
                 ulTotalWeight += (ULONG)(pHD->i_getSize() / _1M);
             }
@@ -2542,7 +2547,4 @@
                     Bstr(tr("Setting up")).raw(),
                     1);
-
-    bool fDeleteOnline = (   (mData->mMachineState == MachineState_Running)
-                          || (mData->mMachineState == MachineState_Paused));
 
     /* create and start the task on a separate thread */
@@ -2814,6 +2816,6 @@
             // a file representation such as iSCSI.
 
-            // not going to merge a big source into a small target
-            if (pSource->i_getLogicalSize() > pTarget->i_getLogicalSize())
+            // not going to merge a big source into a small target on online merge. Otherwise it will be resized
+            if (fNeedsOnlineMerge && pSource->i_getLogicalSize() > pTarget->i_getLogicalSize())
             {
                 rc = setError(E_FAIL,
@@ -3039,5 +3041,9 @@
             }
 
-            task.m_pProgress->SetNextOperation(BstrFmt(tr("Merging differencing image '%s'"),
+            const char *pszOperationText = it->mfNeedsOnlineMerge ?
+                                             tr("Merging differencing image '%s'")
+                                           : tr("Resizing before merge differencing image '%s'");
+
+            task.m_pProgress->SetNextOperation(BstrFmt(pszOperationText,
                                                pMedium->i_getName().c_str()).raw(),
                                                ulWeight);
Index: /trunk/src/VBox/Storage/VD.cpp
===================================================================
--- /trunk/src/VBox/Storage/VD.cpp	(revision 75372)
+++ /trunk/src/VBox/Storage/VD.cpp	(revision 75373)
@@ -36,4 +36,5 @@
 #include <iprt/sg.h>
 #include <iprt/semaphore.h>
+#include <iprt/vector.h>
 
 #include "VDInternal.h"
@@ -362,4 +363,7 @@
     uint8_t          abData[1];
 } VDMETAXFER;
+
+/* vector for temporary storing image sizes */
+RTVEC_DECL(VDImgSzVec, uint64_t)
 
 /**
@@ -7046,4 +7050,5 @@
             uint64_t uOffset = 0;
             uint64_t cbRemaining = cbSize;
+
             do
             {
Index: /trunk/src/VBox/ValidationKit/tests/storage/tdStorageSnapshotMerging1.py
===================================================================
--- /trunk/src/VBox/ValidationKit/tests/storage/tdStorageSnapshotMerging1.py	(revision 75372)
+++ /trunk/src/VBox/ValidationKit/tests/storage/tdStorageSnapshotMerging1.py	(revision 75373)
@@ -28,6 +28,5 @@
 terms and conditions of either the GPL or the CDDL or both.
 """
-__version__ = "$Id$"
-
+__version__ = "$Revision$"
 
 # Standard Python imports.
@@ -35,4 +34,5 @@
 import sys;
 import uuid;
+import zlib;
 
 # Only the main script needs to modify the path.
@@ -47,4 +47,5 @@
 from testdriver import vbox;
 from testdriver import vboxcon;
+from testdriver import vboxwrappers;
 
 def _ControllerTypeToName(eControllerType):
@@ -62,9 +63,21 @@
     return sType;
 
+def crc32_of_file(filepath):
+    fileobj = open(filepath,'rb');
+    current = 0;
+    
+    while True:
+        buf = fileobj.read(1024 * 1024);
+        if not buf:
+            break
+        current = zlib.crc32(buf, current);
+        
+    fileobj.close();
+    return current % 2**32;
+
 class tdStorageSnapshot(vbox.TestDriver):                                      # pylint: disable=R0902
     """
     Storage benchmark.
     """
-
     def __init__(self):
         vbox.TestDriver.__init__(self);
@@ -73,10 +86,8 @@
         self.oGuestToGuestSess = None;
         self.oGuestToGuestTxs  = None;
-        self.asTestVMsDef      = ['tst-win7-vhd', 'tst-debian-vhd', 'tst-debian-vdi'];
-        self.asTestVMs         = self.asTestVMsDef;
-        self.asSkipVMs         = [];
         self.asStorageCtrlsDef = ['AHCI', 'IDE', 'LsiLogicSAS', 'LsiLogic', 'BusLogic'];
         self.asStorageCtrls    = self.asStorageCtrlsDef;
-        self.asDiskFormatsDef  = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW', 'iSCSI'];
+        #self.asDiskFormatsDef  = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW', 'iSCSI'];
+        self.asDiskFormatsDef  = ['VDI', 'VMDK', 'VHD'];
         self.asDiskFormats     = self.asDiskFormatsDef;
         self.sRndData          = os.urandom(100*1024*1024);
@@ -93,10 +104,4 @@
         reporter.log('  --disk-formats  <type1[:type2[:...]]>');
         reporter.log('      Default: %s' % (':'.join(self.asDiskFormats)));
-        reporter.log('  --test-vms      <vm1[:vm2[:...]]>');
-        reporter.log('      Test the specified VMs in the given order. Use this to change');
-        reporter.log('      the execution order or limit the choice of VMs');
-        reporter.log('      Default: %s  (all)' % (':'.join(self.asTestVMsDef)));
-        reporter.log('  --skip-vms      <vm1[:vm2[:...]]>');
-        reporter.log('      Skip the specified VMs when testing.');
         return rc;
 
@@ -111,80 +116,13 @@
             if iArg >= len(asArgs): raise base.InvalidOption('The "--disk-formats" takes a colon separated list of disk formats');
             self.asDiskFormats = asArgs[iArg].split(':');
-        elif asArgs[iArg] == '--test-vms':
-            iArg += 1;
-            if iArg >= len(asArgs): raise base.InvalidOption('The "--test-vms" takes colon separated list');
-            self.asTestVMs = asArgs[iArg].split(':');
-            for s in self.asTestVMs:
-                if s not in self.asTestVMsDef:
-                    raise base.InvalidOption('The "--test-vms" value "%s" is not valid; valid values are: %s' \
-                        % (s, ' '.join(self.asTestVMsDef)));
-        elif asArgs[iArg] == '--skip-vms':
-            iArg += 1;
-            if iArg >= len(asArgs): raise base.InvalidOption('The "--skip-vms" takes colon separated list');
-            self.asSkipVMs = asArgs[iArg].split(':');
-            for s in self.asSkipVMs:
-                if s not in self.asTestVMsDef:
-                    reporter.log('warning: The "--test-vms" value "%s" does not specify any of our test VMs.' % (s));
         else:
             return vbox.TestDriver.parseOption(self, asArgs, iArg);
         return iArg + 1;
 
-    def completeOptions(self):
-        # Remove skipped VMs from the test list.
-        for sVM in self.asSkipVMs:
-            try:    self.asTestVMs.remove(sVM);
-            except: pass;
-
-        return vbox.TestDriver.completeOptions(self);
-
     def getResourceSet(self):
         # Construct the resource list the first time it's queried.
         if self.asRsrcs is None:
-            self.asRsrcs = [];
-            if 'tst-win7-vhd' in self.asTestVMs:
-                self.asRsrcs.append('4.2/storage/win7.vhd');
-
-            if 'tst-debian-vhd' in self.asTestVMs:
-                self.asRsrcs.append('4.2/storage/debian.vhd');
-
-            if 'tst-debian-vdi' in self.asTestVMs:
-                self.asRsrcs.append('4.2/storage/debian.vdi');
-
+            self.asRsrcs = ['5.3/storage/mergeMedium/t-orig.vdi', '5.3/storage/mergeMedium/t-fixed.vdi', '5.3/storage/mergeMedium/t-resized.vdi'];
         return self.asRsrcs;
-
-    def actionConfig(self):
-
-        # Make sure vboxapi has been imported so we can use the constants.
-        if not self.importVBoxApi():
-            return False;
-
-        #
-        # Configure the VMs we're going to use.
-        #
-
-        # Windows VMs
-        if 'tst-win7-vhd' in self.asTestVMs:
-            oVM = self.createTestVM('tst-win7-vhd', 1, '4.2/storage/win7.vhd', sKind = 'Windows7', fIoApic = True, \
-                                    eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
-                                    eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
-            if oVM is None:
-                return False;
-
-        # Linux VMs
-        if 'tst-debian-vhd' in self.asTestVMs:
-            oVM = self.createTestVM('tst-debian-vhd', 1, '4.2/storage/debian.vhd', sKind = 'Debian_64', fIoApic = True, \
-                                    eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
-                                    eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
-            if oVM is None:
-                return False;
-
-        if 'tst-debian-vdi' in self.asTestVMs:
-            oVM = self.createTestVM('tst-debian-vdi', 1, '4.2/storage/debian.vdi', sKind = 'Debian_64', fIoApic = True, \
-                                    eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
-                                    eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
-            if oVM is None:
-                return False;
-
-        return True;
 
     def actionExecute(self):
@@ -194,23 +132,138 @@
         fRc = self.test1();
         return fRc;
-
-
+    
+    def resizeMedium(self, oMedium, cbNewSize):
+        if oMedium.deviceType is not vboxcon.DeviceType_HardDisk:
+            return False;
+        
+        if oMedium.type is not vboxcon.MediumType_Normal:
+            return False;
+        
+        #currently only VDI can be resizable. Medium variant is not checked, because testcase creates disks itself
+        oMediumFormat = oMedium.mediumFormat;
+        if oMediumFormat.id != 'VDI':
+            return False;
+        
+        cbCurrSize = oMedium.logicalSize;
+        # currently reduce is not supported
+        if cbNewSize < cbCurrSize: 
+            return False;
+        
+        try:
+            oProgressCom = oMedium.resize(cbNewSize);
+            oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oVBox.oTstDrv, 'Resize medium %s' % (oMedium.name));
+            oProgress.wait(cMsTimeout = 60 * 1000);
+            oProgress.logResult();
+        except:
+            reporter.logXcpt('IMedium::resize failed on %s' % (oMedium.name));
+            return False;
+        
+        return True;
+    
+    def getMedium(self, oVM, sController):
+        oMediumAttachments = oVM.getMediumAttachmentsOfController(sController);
+        
+        for oAttachment in oMediumAttachments:
+            oMedium = oAttachment.medium;
+            if oMedium.deviceType is not vboxcon.DeviceType_HardDisk:
+                continue;
+            if oMedium.type is not vboxcon.MediumType_Normal:
+                continue;
+            return oMedium;
+        
+        return None; 
+    
+    def getSnapshotMedium(self, oSnapshot, sController):
+        oVM = oSnapshot.machine;
+        oMedium = self.getMedium(oVM, sController);
+        
+        for oChildMedium in oMedium.children:
+            for uSnapshotId in oChildMedium.getSnapshotIds(oVM.id):
+                if uSnapshotId == oVM.id:
+                    return oChildMedium;
+                
+        return None;
+    
+    def openMedium(self, sHd, fImmutable = False):
+        """
+        Opens medium in readonly mode.
+        Returns Medium object on success and None on failure.  Error information is logged.
+        """
+        sFullName = self.oVBox.oTstDrv.getFullResourceName(sHd);
+        try:
+            oHd = self.oVBox.findHardDisk(sFullName);
+        except:
+            try:
+                if self.fpApiVer >= 4.1:
+                    oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly, False);
+                elif self.fpApiVer >= 4.0:
+                    oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly);
+                else:
+                    oHd = self.oVBox.openHardDisk(sFullName, vboxcon.AccessMode_ReadOnly, False, "", False, "");
+                    
+            except:
+                reporter.errorXcpt('failed to open hd "%s"' % (sFullName));
+                return False;
+            
+        try:
+            if fImmutable:
+                oHd.type = vboxcon.MediumType_Immutable;
+            else:
+                oHd.type = vboxcon.MediumType_Normal;
+                
+        except:
+            if fImmutable:
+                reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
+            else:
+                reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
+            
+            return None;
+        
+        return oHd;
+    
+    def cloneMedium(self, oSrcHd, oTgtHd):
+        """
+        Clones medium into target medium.
+        """
+        try:
+            oProgressCom = oSrcHd.cloneTo(oTgtHd, (vboxcon.MediumVariant_Standard, ), None);
+            oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oVBox.oTstDrv, 'clone base disk %s to %s' % (oSrcHd.name, oTgtHd.name));
+            oProgress.wait(cMsTimeout = 60 * 1000);
+            oProgress.logResult();
+        except:
+            reporter.errorXcpt('failed to clone medium %s to %s' % (oSrcHd.name, oTgtHd.name));
+            return False;
+        
+        return True;
+    
+    def deleteVM(self, oVM):
+        try:
+            oVM.unregister(vboxcon.CleanupMode_DetachAllReturnNone);
+        except:
+            reporter.logXcpt();
+            pass;
+        
+        if self.fpApiVer >= 4.0:
+            try:
+                if self.fpApiVer >= 4.3:
+                    oProgress = oVM.deleteConfig([]);
+                else:
+                    oProgress = oVM.delete(None);
+                self.waitOnProgress(oProgress);
+                
+            except:
+                reporter.logXcpt();
+                
+        else:
+            try:    oVM.deleteSettings();
+            except: reporter.logXcpt();
+            
+        return None;
+    
     #
     # Test execution helpers.
     #
 
-    def test1UploadFile(self, oSession, oTxsSession):
-        """
-        Uploads a test file to the test machine.
-        """
-        reporter.testStart('Upload file');
-
-        fRc = self.txsUploadString(oSession, oTxsSession, self.sRndData, '${SCRATCH}/' + str(uuid.uuid4()), \
-                                   cMsTimeout = 3600 * 1000);
-
-        reporter.testDone(not fRc);
-        return fRc;
-
-    def test1OneCfg(self, sVmName, eStorageController, sDiskFormat):
+    def test1OneCfg(self, eStorageController, oDskFmt):
         """
         Runs the specified VM thru test #1.
@@ -219,60 +272,117 @@
         the actual test result.
         """
-        oVM = self.getVmByName(sVmName);
-
-        # @ŧodo: Implement support for different formats.
-        _ = sDiskFormat;
-
+        
+        (asExts, aTypes) = oDskFmt.describeFileExtensions()
+        for i in range(0, len(asExts)): #pylint: disable=consider-using-enumerate
+            if aTypes[i] is vboxcon.DeviceType_HardDisk:
+                sExt = '.' + asExts[i]
+                break
+            
+        if sExt is None:
+            return False;
+        
+        oOrigBaseHd = self.openMedium('5.3/storage/mergeMedium/t-orig.vdi');
+        if oOrigBaseHd is None:
+            return False;
+        
+        #currently only VDI can be resizable. Medium variant is not checked, because testcase creates disks itself
+        fFmtDynamic = oDskFmt.id == 'VDI'; 
+        sOrigWithDiffHd = '5.3/storage/mergeMedium/t-fixed.vdi'
+        uOrigCrc = 0x7a417cbb;
+        
+        if fFmtDynamic:
+            sOrigWithDiffHd = '5.3/storage/mergeMedium/t-resized.vdi';
+            uOrigCrc = 0xa8f5daa3;
+            
+        oOrigWithDiffHd = self.openMedium(sOrigWithDiffHd);
+        if oOrigWithDiffHd is None:
+            return False;
+        
+        oVM = self.createTestVM('testvm', 1, None);
+        if oVM is None:
+            return False;
+        
+        sController = _ControllerTypeToName(eStorageController);
+        
         # Reconfigure the VM
+        oSession = self.openSession(oVM);
+        if oSession is None:
+            return False;
+        # Attach HD
+
         fRc = True;
-        oSession = self.openSession(oVM);
+        sFile = 't-base' + sExt;
+        sHddPath = os.path.join(self.oVBox.oTstDrv.sScratchPath, sFile);
+        oHd = oSession.createBaseHd(sHddPath, sFmt=oDskFmt.id, cb=oOrigBaseHd.logicalSize);
+        #if oSession.createBaseHd can't create disk because it exists, oHd will point to some stub object anyway
+        fRc = fRc and oHd is not None and oHd.logicalSize == oOrigBaseHd.logicalSize;
+        fRc = fRc and self.cloneMedium(oOrigBaseHd, oHd);
+            
+        fRc = fRc and oSession.ensureControllerAttached(sController);
+        fRc = fRc and oSession.setStorageControllerType(eStorageController, sController);
+        fRc = fRc and oSession.saveSettings();
+        fRc = fRc and oSession.attachHd(sHddPath, sController, iPort = 0, fImmutable=False, fForceResource=False)
+        
+        if fRc:
+            oSession.takeSnapshot('Base snapshot');
+            oSnapshot = oSession.findSnapshot('Base snapshot');
+            
+            if oSnapshot is not None:
+                oSnapshotMedium = self.getSnapshotMedium(oSnapshot, sController);
+                fRc = oSnapshotMedium is not None;
+                
+                if fFmtDynamic:
+                    fRc = fRc and self.resizeMedium(oSnapshotMedium, oOrigWithDiffHd.logicalSize);
+                fRc = fRc and self.cloneMedium(oOrigWithDiffHd, oSnapshotMedium);
+                fRc = fRc and oSession.deleteSnapshot(oSnapshot.id, cMsTimeout = 120 * 1000);
+                
+                if fRc:
+                    # disk for result test by checksum
+                    sResFilePath = os.path.join(self.oVBox.oTstDrv.sScratchPath, 't_res.vmdk');
+                    sResFilePathRaw = os.path.join(self.oVBox.oTstDrv.sScratchPath, 't_res-flat.vmdk');
+                    oResHd = oSession.createBaseHd(sResFilePath, sFmt='VMDK', cb=oOrigWithDiffHd.logicalSize, tMediumVariant = (vboxcon.MediumVariant_Fixed, ));
+                    fRc = oResHd is not None;
+                    fRc = fRc and self.cloneMedium(oHd, oResHd);
+                    
+                    uResCrc32 = 0;
+                    if fRc:
+                        uResCrc32 = crc32_of_file(sResFilePathRaw);
+                        if uResCrc32 == uOrigCrc:
+                            reporter.log('Snapshot merged successfully. Data of the result medium are correspond to data of the original medium');
+                            fRc = True;
+                        else:
+                            reporter.error('Snapshot merging failed. Data of the result medium not correspond to data of the original medium');
+                            fRc = False;
+                    
+                    self.oVBox.deleteHdByMedium(oResHd);
+
         if oSession is not None:
-            # Attach HD
-            fRc = oSession.ensureControllerAttached(_ControllerTypeToName(eStorageController));
-            fRc = fRc and oSession.setStorageControllerType(eStorageController, _ControllerTypeToName(eStorageController));
-            fRc = fRc and oSession.saveSettings();
-            fRc = oSession.close() and fRc and True; # pychecker hack.
-            oSession = None;
-        else:
-            fRc = False;
-
-        # Start up.
-        if fRc is True:
-            self.logVmInfo(oVM);
-            oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(sVmName, fCdWait = False, fNatForwardingForTxs = True);
-            if oSession is not None:
-                self.addTask(oTxsSession);
-
-                # Fudge factor - Allow the guest to finish starting up.
-                self.sleep(5);
-
-                # Do a snapshot first.
-                oSession.takeSnapshot('Base snapshot');
-
-                for i in range(0, 10):
-                    oSession.takeSnapshot('Snapshot ' + str(i));
-                    self.test1UploadFile(oSession, oTxsSession);
-                    msNow = base.timestampMilli();
-                    oSnapshot = oSession.findSnapshot('Snapshot ' + str(i));
-                    oSession.deleteSnapshot(oSnapshot.id, cMsTimeout = 60 * 1000);
-                    msElapsed = base.timestampMilli() - msNow;
-                    reporter.log('Deleting snapshot %d took %d ms' % (i, msElapsed));
-
-                # cleanup.
-                self.removeTask(oTxsSession);
-                self.terminateVmBySession(oSession)
-            else:
-                fRc = False;
+            if oHd is not None:
+                oSession.detachHd(sController, iPort = 0, iDevice = 0);
+                
+            oSession.saveSettings(fClose = True);
+            if oHd is not None:
+                self.oVBox.deleteHdByMedium(oHd);
+        
+        self.deleteVM(oVM);
         return fRc;
 
-    def test1OneVM(self, sVmName):
-        """
-        Runs one VM thru the various configurations.
-        """
+    def test1(self):
+        """
+        Executes test #1 thru the various configurations.
+        """
+        if not self.importVBoxApi():
+            return False;
+        
+        sVmName = 'testvm';
         reporter.testStart(sVmName);
+
+        aoDskFmts = self.oVBoxMgr.getArray(self.oVBox.systemProperties, 'mediumFormats')
+        if aoDskFmts is None or len(aoDskFmts) < 1:
+            return False;
+        
         fRc = True;
         for sStorageCtrl in self.asStorageCtrls:
             reporter.testStart(sStorageCtrl);
-
             if sStorageCtrl == 'AHCI':
                 eStorageCtrl = vboxcon.StorageControllerType_IntelAhci;
@@ -287,30 +397,20 @@
             else:
                 eStorageCtrl = None;
-
-            for sDiskFormat in self.asDiskFormats:
-                reporter.testStart('%s' % (sDiskFormat));
-                self.test1OneCfg(sVmName, eStorageCtrl, sDiskFormat);
-                reporter.testDone();
+            
+            for oDskFmt in aoDskFmts:
+                if (oDskFmt.id in self.asDiskFormats):
+                    reporter.testStart('%s' % (oDskFmt.id));
+                    fRc = self.test1OneCfg(eStorageCtrl, oDskFmt);
+                    reporter.testDone();
+                    if not fRc:
+                        break;
+        
             reporter.testDone();
+            if not fRc:
+                break;
+        
         reporter.testDone();
         return fRc;
 
-    def test1(self):
-        """
-        Executes test #1.
-        """
-
-        # Loop thru the test VMs.
-        for sVM in self.asTestVMs:
-            # run test on the VM.
-            if not self.test1OneVM(sVM):
-                fRc = False;
-            else:
-                fRc = True;
-
-        return fRc;
-
-
-
 if __name__ == '__main__':
     sys.exit(tdStorageSnapshot().main(sys.argv));
