summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/tests/api
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/ValidationKit/tests/api
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/ValidationKit/tests/api')
-rw-r--r--src/VBox/ValidationKit/tests/api/Makefile.kmk72
-rw-r--r--src/VBox/ValidationKit/tests/api/__init__.py39
-rwxr-xr-xsrc/VBox/ValidationKit/tests/api/tdApi1.py99
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t1.ovabin0 -> 9216 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t2-ovftool-4.1.0.ovabin0 -> 77312 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t2.ovabin0 -> 77312 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t3-ovftool-4.1.0.ovabin0 -> 9728 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t3.ovabin0 -> 9728 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t4-ovftool-4.1.0.ovabin0 -> 116224 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t4.ovabin0 -> 116224 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t4.pem74
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t5-ovftool-4.1.0.ovabin0 -> 112640 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t5.ovabin0 -> 112640 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t6-ovftool-4.1.0.ovabin0 -> 218624 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t6.ovabin0 -> 218624 bytes
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t6.pem134
-rw-r--r--src/VBox/ValidationKit/tests/api/tdAppliance1-t7-bad-instance.ovabin0 -> 78336 bytes
-rwxr-xr-xsrc/VBox/ValidationKit/tests/api/tdAppliance1.py217
-rwxr-xr-xsrc/VBox/ValidationKit/tests/api/tdCloneMedium1.py243
-rwxr-xr-xsrc/VBox/ValidationKit/tests/api/tdCreateVMWithDefaults1.py203
-rwxr-xr-xsrc/VBox/ValidationKit/tests/api/tdMoveMedium1.py217
-rwxr-xr-xsrc/VBox/ValidationKit/tests/api/tdMoveVm1.py768
-rwxr-xr-xsrc/VBox/ValidationKit/tests/api/tdPython1.py220
-rwxr-xr-xsrc/VBox/ValidationKit/tests/api/tdTreeDepth1.py249
24 files changed, 2535 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/tests/api/Makefile.kmk b/src/VBox/ValidationKit/tests/api/Makefile.kmk
new file mode 100644
index 00000000..2598e51a
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/Makefile.kmk
@@ -0,0 +1,72 @@
+# $Id: Makefile.kmk $
+## @file
+# VirtualBox Validation Kit - API Tests.
+#
+
+#
+# Copyright (C) 2006-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+
+INSTALLS += ValidationKitTestsApi
+ValidationKitTestsApi_TEMPLATE = VBoxValidationKitR3
+ValidationKitTestsApi_INST = $(INST_VALIDATIONKIT)tests/api/
+ValidationKitTestsApi_EXEC_SOURCES := \
+ $(PATH_SUB_CURRENT)/tdApi1.py \
+ $(PATH_SUB_CURRENT)/tdAppliance1.py \
+ $(PATH_SUB_CURRENT)/tdCloneMedium1.py \
+ $(PATH_SUB_CURRENT)/tdCreateVMWithDefaults1.py \
+ $(PATH_SUB_CURRENT)/tdMoveMedium1.py \
+ $(PATH_SUB_CURRENT)/tdMoveVm1.py \
+ $(PATH_SUB_CURRENT)/tdPython1.py \
+ $(PATH_SUB_CURRENT)/tdTreeDepth1.py
+
+ifndef VBOX_OSE
+ ValidationKitTestsApi_EXEC_SOURCES += \
+ $(PATH_SUB_CURRENT)/tdCloud1.py \
+ $(PATH_SUB_CURRENT)/tdOciConnection1.py \
+ $(PATH_SUB_CURRENT)/tdOciExport1.py \
+ $(PATH_SUB_CURRENT)/tdOciImage1.py \
+ $(PATH_SUB_CURRENT)/tdOciImport1.py \
+ $(PATH_SUB_CURRENT)/tdOciInstance1.py \
+ $(PATH_SUB_CURRENT)/tdOciProfile1.py
+endif
+ValidationKitTestsApi_SOURCES := \
+ $(wildcard \
+ $(PATH_SUB_CURRENT)/*.ova \
+ )
+
+VBOX_VALIDATIONKIT_PYTHON_SOURCES += $(ValidationKitTestsApi_EXEC_SOURCES)
+
+$(evalcall def_vbox_validationkit_process_python_sources)
+include $(FILE_KBUILD_SUB_FOOTER)
diff --git a/src/VBox/ValidationKit/tests/api/__init__.py b/src/VBox/ValidationKit/tests/api/__init__.py
new file mode 100644
index 00000000..db7ec260
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/__init__.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# $Id: __init__.py $
+
+"""
+Just to make python 2.x happy.
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2012-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 155244 $"
diff --git a/src/VBox/ValidationKit/tests/api/tdApi1.py b/src/VBox/ValidationKit/tests/api/tdApi1.py
new file mode 100755
index 00000000..2aae19c8
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdApi1.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# $Id: tdApi1.py $
+
+"""
+VirtualBox Validation Kit - API Test wrapper #1 combining all API sub-tests
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2010-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 155244 $"
+
+
+# Standard Python imports.
+import os
+import sys
+
+# Only the main script needs to modify the path.
+try: __file__
+except: __file__ = sys.argv[0]
+g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.append(g_ksValidationKitDir)
+
+# Validation Kit imports.
+from testdriver import vbox
+
+
+class tdApi1(vbox.TestDriver):
+ """
+ API Test wrapper #1.
+ """
+
+ def __init__(self, aoSubTestDriverClasses = None):
+ vbox.TestDriver.__init__(self)
+ for oSubTestDriverClass in aoSubTestDriverClasses:
+ self.addSubTestDriver(oSubTestDriverClass(self));
+
+ #
+ # Overridden methods.
+ #
+
+ def actionConfig(self):
+ """
+ Import the API.
+ """
+ if not self.importVBoxApi():
+ return False
+ return True
+
+ def actionExecute(self):
+ """
+ Execute the testcase, i.e. all sub-tests.
+ """
+ fRc = True;
+ for oSubTstDrv in self.aoSubTstDrvs:
+ if oSubTstDrv.fEnabled:
+ fRc = oSubTstDrv.testIt() and fRc;
+ return fRc;
+
+
+if __name__ == '__main__':
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+ from tdPython1 import SubTstDrvPython1; # pylint: disable=relative-import
+ from tdAppliance1 import SubTstDrvAppliance1; # pylint: disable=relative-import
+ from tdMoveMedium1 import SubTstDrvMoveMedium1; # pylint: disable=relative-import
+ from tdTreeDepth1 import SubTstDrvTreeDepth1; # pylint: disable=relative-import
+ from tdMoveVm1 import SubTstDrvMoveVm1; # pylint: disable=relative-import
+ from tdCloneMedium1 import SubTstDrvCloneMedium1;# pylint: disable=relative-import
+ sys.exit(tdApi1([SubTstDrvPython1, SubTstDrvAppliance1, SubTstDrvMoveMedium1,
+ SubTstDrvTreeDepth1, SubTstDrvMoveVm1, SubTstDrvCloneMedium1]).main(sys.argv))
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t1.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t1.ova
new file mode 100644
index 00000000..aba10dbb
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t1.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t2-ovftool-4.1.0.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t2-ovftool-4.1.0.ova
new file mode 100644
index 00000000..19c2c4b9
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t2-ovftool-4.1.0.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t2.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t2.ova
new file mode 100644
index 00000000..66a173aa
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t2.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t3-ovftool-4.1.0.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t3-ovftool-4.1.0.ova
new file mode 100644
index 00000000..8027ce64
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t3-ovftool-4.1.0.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t3.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t3.ova
new file mode 100644
index 00000000..7fbf44ee
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t3.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t4-ovftool-4.1.0.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t4-ovftool-4.1.0.ova
new file mode 100644
index 00000000..2434f37e
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t4-ovftool-4.1.0.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t4.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t4.ova
new file mode 100644
index 00000000..a6549b15
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t4.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t4.pem b/src/VBox/ValidationKit/tests/api/tdAppliance1-t4.pem
new file mode 100644
index 00000000..c155d659
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t4.pem
@@ -0,0 +1,74 @@
+-----BEGIN PRIVATE KEY-----
+MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALRXOpwrjjFzFZtb
+aTtB+3kNrgrqYkye6CqvrOODZwXsljr/pduYj6bYh5OdznAFqgeeCpkqEf/2p5mD
+XlqE4cDoL2opLk7LrdmVDqX9rUkGcGf6hwTp1EAllESBIUt6LdSbL7Y5goYq1E++
+/fKSYRIniCbWp9ahTLH8hjDcw48tAgMBAAECgYAiNl4vHHA4X13dAEWBcW4UtAyt
+k3Ocl5Tx7Cv/aYFU9WI2xSMg+ttdyrxFu+1bASgVk9zs27dYeOGo1OxEfesZzQkT
+mbzvYCdYk9wAWKXQwpp78HZyEsKVipIxO+riH9ph7SFQBzB5NoADPoqwahOmeQQW
+sE3oTJRa9O+JR3muXQJBAOOt4dj+1Rwmdy83j9uOLLfO75l2pJd/hq5gN7+eNFks
+R68cbhFGkrOU13dVLquyqxAoaKc2PgZS+RfGRrohjm8CQQDKxeuqYXyrYBU4jNAS
+TgcR4lbb8HiC1AyQrdiJVtH4qLpqk92M7muHXZQGOXRizHQMrRDY+PcgLoFAnRzJ
+j0ojAkEA3rqL5ivlbtRyY86G/NHpDSdzXT2jZlFq/8tAvkOWEmYu+i9lvaC8gtFo
+t2Stc2olzni5aFq38pfY9lkRd6S8IQJBAJe3LJPnqwrish4Epa38eae07P5U1yY0
+GE6r9EcWEbZ2MDyL9Al9XjEDIDzkAiPmC7JsTx24cda/VPAOXbqlnncCQQCCevzg
+rrnTz0/3iLWkxowiKCE1EvbVALDxPwHi0zvjXbGZs8BodLxeChpJzFImbxRVAIrp
+WvZOuLqhAKjL7OOT
+-----END PRIVATE KEY-----
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 14180722474914962380 (0xc4cc0bf54fb45bcc)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=DE, ST=Example, L=For Instance, O=Beispiel GmbH, CN=beispiel.example.org
+ Validity
+ Not Before: Feb 1 01:45:27 2016 GMT
+ Not After : Jan 24 01:45:27 2046 GMT
+ Subject: C=DE, ST=Example, L=For Instance, O=Beispiel GmbH, CN=beispiel.example.org
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:b4:57:3a:9c:2b:8e:31:73:15:9b:5b:69:3b:41:
+ fb:79:0d:ae:0a:ea:62:4c:9e:e8:2a:af:ac:e3:83:
+ 67:05:ec:96:3a:ff:a5:db:98:8f:a6:d8:87:93:9d:
+ ce:70:05:aa:07:9e:0a:99:2a:11:ff:f6:a7:99:83:
+ 5e:5a:84:e1:c0:e8:2f:6a:29:2e:4e:cb:ad:d9:95:
+ 0e:a5:fd:ad:49:06:70:67:fa:87:04:e9:d4:40:25:
+ 94:44:81:21:4b:7a:2d:d4:9b:2f:b6:39:82:86:2a:
+ d4:4f:be:fd:f2:92:61:12:27:88:26:d6:a7:d6:a1:
+ 4c:b1:fc:86:30:dc:c3:8f:2d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 02:0A:B0:BC:21:63:C1:50:16:1E:8D:B7:F4:B0:1C:48:D8:E1:0A:2A
+ X509v3 Authority Key Identifier:
+ keyid:02:0A:B0:BC:21:63:C1:50:16:1E:8D:B7:F4:B0:1C:48:D8:E1:0A:2A
+
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha256WithRSAEncryption
+ 13:f1:33:5f:c7:d9:6c:20:a4:eb:f2:e5:e2:b5:e0:e8:b6:9c:
+ c7:62:4a:39:53:83:11:98:cf:11:3d:58:09:d8:38:78:71:16:
+ d4:24:cc:c8:2e:5a:2b:d3:94:6a:dc:ae:62:e7:81:6a:5f:04:
+ 84:ba:55:8c:dc:6b:ff:aa:78:4f:37:8e:fd:ba:b5:d1:27:83:
+ 47:29:30:92:63:85:53:f0:b1:b9:f4:c7:a8:b1:48:44:4e:30:
+ 6f:50:d3:35:14:87:59:d0:f8:ed:da:07:60:6c:de:6d:53:53:
+ 3d:d7:03:97:1f:6b:13:ce:92:49:20:57:4f:b0:87:30:76:66:
+ d3:43
+-----BEGIN CERTIFICATE-----
+MIICqDCCAhGgAwIBAgIJAMTMC/VPtFvMMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV
+BAYTAkRFMRAwDgYDVQQIDAdFeGFtcGxlMRUwEwYDVQQHDAxGb3IgSW5zdGFuY2Ux
+FjAUBgNVBAoMDUJlaXNwaWVsIEdtYkgxHTAbBgNVBAMMFGJlaXNwaWVsLmV4YW1w
+bGUub3JnMB4XDTE2MDIwMTAxNDUyN1oXDTQ2MDEyNDAxNDUyN1owbTELMAkGA1UE
+BhMCREUxEDAOBgNVBAgMB0V4YW1wbGUxFTATBgNVBAcMDEZvciBJbnN0YW5jZTEW
+MBQGA1UECgwNQmVpc3BpZWwgR21iSDEdMBsGA1UEAwwUYmVpc3BpZWwuZXhhbXBs
+ZS5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALRXOpwrjjFzFZtbaTtB
++3kNrgrqYkye6CqvrOODZwXsljr/pduYj6bYh5OdznAFqgeeCpkqEf/2p5mDXlqE
+4cDoL2opLk7LrdmVDqX9rUkGcGf6hwTp1EAllESBIUt6LdSbL7Y5goYq1E++/fKS
+YRIniCbWp9ahTLH8hjDcw48tAgMBAAGjUDBOMB0GA1UdDgQWBBQCCrC8IWPBUBYe
+jbf0sBxI2OEKKjAfBgNVHSMEGDAWgBQCCrC8IWPBUBYejbf0sBxI2OEKKjAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBABPxM1/H2WwgpOvy5eK14Oi2nMdi
+SjlTgxGYzxE9WAnYOHhxFtQkzMguWivTlGrcrmLngWpfBIS6VYzca/+qeE83jv26
+tdEng0cpMJJjhVPwsbn0x6ixSEROMG9Q0zUUh1nQ+O3aB2Bs3m1TUz3XA5cfaxPO
+kkkgV0+whzB2ZtND
+-----END CERTIFICATE-----
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t5-ovftool-4.1.0.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t5-ovftool-4.1.0.ova
new file mode 100644
index 00000000..6a21a19b
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t5-ovftool-4.1.0.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t5.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t5.ova
new file mode 100644
index 00000000..8e6e2e2e
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t5.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t6-ovftool-4.1.0.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t6-ovftool-4.1.0.ova
new file mode 100644
index 00000000..d5a92eb2
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t6-ovftool-4.1.0.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t6.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t6.ova
new file mode 100644
index 00000000..6480e6d5
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t6.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t6.pem b/src/VBox/ValidationKit/tests/api/tdAppliance1-t6.pem
new file mode 100644
index 00000000..1b682b0d
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t6.pem
@@ -0,0 +1,134 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEAzYlueHZlbSqlLrVAnCyQx9xgnO7jSjK6wXqlbxkl0QZLyDnh
+vNowZYnu7YZI3V+RuVzYbczlEr1qZpUeO8NF04mK1kFPJRinRiuiOtih+WwvDQd7
+7RZJhjoAcfEeogt1OzOZg8QKF1AMGlUgk5zWma4VIS75ZM6G1b77qS3rge6L9NwZ
+gthyQ1PvddYue4MNEpK+2ekZZq/GGZvd+yNP0Wq7kzcmydCgCF9EdLCZwt4BHmOS
+ZM6BUxKv+PINZgO7Wp2tBBGigg9Mf/NXofjMHp7RI16xa2W9Q/Ct2A6rb5SAB10U
+ddrtxiI+F+Jv7lNkHOCLbju7cEs+Y6XIbt1l7aVqBFpgo6cwFZ7DdLPHZkgb50hx
+dnNdwncOR1syspTF544hbmkcb/8+weq+qgsD/57b/ZGrwb8ruByDz0LZiXzxxBRe
+w9OhHZGFnuC0D1ciIvpifKe4R/kLcEgVW7yYp4W1BAZgiBJPgXArJTlUBrxamzsQ
+m6N7GxlP+vTCny7IJsQ1KWu5BqkPv0T1+zD5vUT9/lAa+XBdDHhYVm0adr4dXIef
+6ws+0zbpz8DyaD/Bg9KvRKdnziVc+pKwkWOVrFvZ6NvBex0i8Bgh4FrpkdjmrZMZ
+uuCdex0CEayuYexgUqyMg9m0GwGqVNG6mVB4cCOg0rayaqEKrbtUSxNaD/MCAwEA
+AQKCAgAnjPGQBqBf0Fv2z/P92WmGu/ZvXFyqU3aycmpRJZKsVTzR66lvkMDNWSx7
+0mJFDvXYqHAROOM/pulJkho+P8Y4/XeU4P5c0hCmJRFTp4oLl/C53h3PsoE1bgXV
+5yMQ5YmKedRpkZirgcDCdG0PWpfE/MWeHA7rgf5aNSTyGh7+YqvV02CpWAMsx4MF
+ttA8/ivOziQhhIRZySsilGazw8jBMHulyXASV63jzok6txzvbY7jjR+HfGFQXgE0
+s0c2wTMVLdA0Pzx5MH51BJtxVJHato7h8n/LfclcwHyDXddJYlb8k8GzKAynGsG+
+ENmfD7btA5xw+teHtULtI+KcysepCeVXW7Fr7PFJe1XOx1c24WrFpjeGdnG3PdqA
+Y9YbjMCD/GpCUICla3N6iRDG3imY+DUWcExVjUo6TUbQ4ofQT4WF7+2Yzg6MRqYu
+41jgF+voCXS4BH8e+ngEjd8VLHma7FPuWujodCERsvxZ7aLXBcZCH1Lje9Y8a79x
+RGX83pVHTWFRyo4wKBpRUz+hwH7MjYdfE2Q+Zl153pXw3au9jX8PUMhx9swWPGRw
+CvLPwtTwrezzdFeXg4wfJwWnvqhKIViery4z3rdjh5Zke/9+7gXmFbZ8w+QUkXXq
+cnBEJySTvpI4B9abpcEI4OO84L/A6ENDO10W4ZGfm5aD2m0vIQKCAQEA6nZAmsSr
+T1CcgrWNcY6civ8o5cMF8fM9ib5QvibRlJN9dpcZPr6+Pp2UPCkjVowk/FybP1Kw
+sqA0aXOL3VR03YpLrqdUDpe9YiFCa3ttDX0pTOdU9QW2RbOrNQVurKhzNETd37cJ
+0RYBOHJY/RxA0F8l16wSr1jTO/SRbWkFJYZS/OaH1B6gCxz6H1IgfKJddrvFZsd8
+6PnLtqsPnsXuxugqHu3ENddRqiiSNyGnqpGu0jQpPBrQEQQN5o8/X9rfNfAobChH
+Nii0va7MHudwaTTo2ytUzEV+v0kueMNU9YXgJgxzSzf1/VQC+HoNI4Vbs9XCbOWV
+z2FVBwXM+0cIMQKCAQEA4Gr1pQAymJq/9p2fiWSR8TVdrYCwvAnBu8QSqSzweNZC
+SRt7Nkhhljm7M2DuUOioMaFAT9CnyD2nJyKSAqqOngb0vo7C53UzgFu+QFMtUx/Z
+t/C96WcLYrErXfnB/sTq0Gp4tpoo1S3FZecabhlZyv1O08WXiNCcEX1VMQz2+iF9
++n2PjFuEomeWHxBWCwfB9/S0pKVHP/7833sQ8Dfsm2EwtPy3v58ln3UguaUDIe5V
+r0TmKr8kDrYgbw1ZpBOd9Wbbvj3vIN34OPoSIrcar67DCp7qYq77LYAhngfdQGed
+MUMsbU1dODWf0kwP7mncTr3mPByQUHa3ImjvJPv1YwKCAQBYa04Dz8U2/RR46pSz
+zW9Vr9Ixi7GTRALiDkaO3z7MRC7daTAZDH/cRzre0TjFa8aK8TWO1NVUF7yMRAnr
+5uzHm17dN7coZasC9b4BoKNIofnQSbEtUgEiGhanwSuyqzf+7zWpJ3LpSd4d9ml+
+0ofSzP8NbZQCUoIeqyWo2CEbvKNRQnLY2M/MQRpGc4dS2TxcCYXxM6v0hDeB5NLY
+MpbQpj80OMB0+YWPoQs7BVMgrR37obYnN4ld0WSYnU7uDDF/OtlTqIDqeMFogyHx
+SaCH3G8wMBAjlNWut59x5WAF033re2iDZlA7P9J6+DQ6QBGMKUHQJWiws2kIY/Sg
+knIRAoIBAQCzlkR/Rxo2LthhZR/PFfEIQrl1Z9+GipRDSxPX2AOT33nqARjnhqK5
+UfexlOcBTj2SgcTyWjp6LoQ9+Bc6FPzODyj5+UqVaJ/PHxuvZCCIPZu/6+I+Dlz5
+HGhk6sJIu5JhOGLjVZhJiDhIZNkstBK8M1tKcvvh23aZNF/hQcu+vOCQfLxMCMyq
+HhTvROZmK04Yu/V3MGBFISuBN32FjmtEqFEO9JGiwZuc8GFAzoEkPRLKkGtUV+Nl
+9m8cD2XlvGESib5djjh3Z8oE5nFu4HJ1lne0XxmX4QlWDwxX51kx+fi7/FJoIZnw
+qlD8PCwfkQ1g4eyFvCHskiPZYHnHce2bAoIBACW40wFIPiDRhjNywEi4miN6P+Xs
+rlM9csmxw2GG6Z4c8H/Z4SNBRQmnj/F6PHsar6SGy9WlR9mNeR2XBn4Pyf/cNjTQ
+bKzV5wPRm6P81SQjhIz4Mxdx1S30AeF1LdagWFiq0on7oRTH2SeKQspdpNeiTDbC
+sBw4SVDKmGZYGZcuT3BdvvZFEW4qncSYuUM7l9bTmsbzid/v8zn/XDQrpdPYnptD
+ljJETKQzlyrJLtTbyFlo3Osf1N4408u3rqhpw2SgKdyMiHndhxkF869Vycll+VMz
+SzPU0wI62BIPWHDBJLnxGBTa+4kUSxP+oDvCfVYCmDcfDRew3MWCK9emJnU=
+-----END RSA PRIVATE KEY-----
+Certificate:
+ Data:
+ Version: 1 (0x0)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha512WithRSAEncryption
+ Issuer: C=DE, ST=Example, L=For Instance, O=Beispiel GmbH, CN=beispiel.example.org
+ Validity
+ Not Before: Feb 15 14:27:56 2016 GMT
+ Not After : Feb 2 14:27:56 2066 GMT
+ Subject: C=DE, ST=Instance-Example, L=Examplecity, O=For Instance GmbH, OU=The Example Unit, CN=subcert.example.org/emailAddress=subcert@example.org
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (4096 bit)
+ Modulus:
+ 00:cd:89:6e:78:76:65:6d:2a:a5:2e:b5:40:9c:2c:
+ 90:c7:dc:60:9c:ee:e3:4a:32:ba:c1:7a:a5:6f:19:
+ 25:d1:06:4b:c8:39:e1:bc:da:30:65:89:ee:ed:86:
+ 48:dd:5f:91:b9:5c:d8:6d:cc:e5:12:bd:6a:66:95:
+ 1e:3b:c3:45:d3:89:8a:d6:41:4f:25:18:a7:46:2b:
+ a2:3a:d8:a1:f9:6c:2f:0d:07:7b:ed:16:49:86:3a:
+ 00:71:f1:1e:a2:0b:75:3b:33:99:83:c4:0a:17:50:
+ 0c:1a:55:20:93:9c:d6:99:ae:15:21:2e:f9:64:ce:
+ 86:d5:be:fb:a9:2d:eb:81:ee:8b:f4:dc:19:82:d8:
+ 72:43:53:ef:75:d6:2e:7b:83:0d:12:92:be:d9:e9:
+ 19:66:af:c6:19:9b:dd:fb:23:4f:d1:6a:bb:93:37:
+ 26:c9:d0:a0:08:5f:44:74:b0:99:c2:de:01:1e:63:
+ 92:64:ce:81:53:12:af:f8:f2:0d:66:03:bb:5a:9d:
+ ad:04:11:a2:82:0f:4c:7f:f3:57:a1:f8:cc:1e:9e:
+ d1:23:5e:b1:6b:65:bd:43:f0:ad:d8:0e:ab:6f:94:
+ 80:07:5d:14:75:da:ed:c6:22:3e:17:e2:6f:ee:53:
+ 64:1c:e0:8b:6e:3b:bb:70:4b:3e:63:a5:c8:6e:dd:
+ 65:ed:a5:6a:04:5a:60:a3:a7:30:15:9e:c3:74:b3:
+ c7:66:48:1b:e7:48:71:76:73:5d:c2:77:0e:47:5b:
+ 32:b2:94:c5:e7:8e:21:6e:69:1c:6f:ff:3e:c1:ea:
+ be:aa:0b:03:ff:9e:db:fd:91:ab:c1:bf:2b:b8:1c:
+ 83:cf:42:d9:89:7c:f1:c4:14:5e:c3:d3:a1:1d:91:
+ 85:9e:e0:b4:0f:57:22:22:fa:62:7c:a7:b8:47:f9:
+ 0b:70:48:15:5b:bc:98:a7:85:b5:04:06:60:88:12:
+ 4f:81:70:2b:25:39:54:06:bc:5a:9b:3b:10:9b:a3:
+ 7b:1b:19:4f:fa:f4:c2:9f:2e:c8:26:c4:35:29:6b:
+ b9:06:a9:0f:bf:44:f5:fb:30:f9:bd:44:fd:fe:50:
+ 1a:f9:70:5d:0c:78:58:56:6d:1a:76:be:1d:5c:87:
+ 9f:eb:0b:3e:d3:36:e9:cf:c0:f2:68:3f:c1:83:d2:
+ af:44:a7:67:ce:25:5c:fa:92:b0:91:63:95:ac:5b:
+ d9:e8:db:c1:7b:1d:22:f0:18:21:e0:5a:e9:91:d8:
+ e6:ad:93:19:ba:e0:9d:7b:1d:02:11:ac:ae:61:ec:
+ 60:52:ac:8c:83:d9:b4:1b:01:aa:54:d1:ba:99:50:
+ 78:70:23:a0:d2:b6:b2:6a:a1:0a:ad:bb:54:4b:13:
+ 5a:0f:f3
+ Exponent: 65537 (0x10001)
+ Signature Algorithm: sha512WithRSAEncryption
+ 2d:1c:49:41:1a:4f:dc:d8:5c:b1:fa:ca:53:38:86:26:6e:56:
+ a5:6d:2e:1d:0d:74:64:0e:89:c3:3a:c7:1d:01:6e:d1:93:b2:
+ c9:37:01:6a:ae:31:42:96:05:d7:df:fd:01:f8:bc:f3:f3:4c:
+ cd:75:ae:16:00:61:78:f2:67:c5:b1:76:76:16:39:ba:d2:6b:
+ 09:ad:99:2b:22:ce:56:89:4d:08:ca:8c:76:4c:50:6b:83:c9:
+ 46:9b:f5:9f:2d:e2:7f:e5:72:aa:76:56:c4:67:83:45:26:b7:
+ e2:ae:f7:1e:61:c9:aa:2e:8d:b8:59:42:84:37:25:c8:16:92:
+ d6:d5
+-----BEGIN CERTIFICATE-----
+MIIEGjCCA4MCAQEwDQYJKoZIhvcNAQENBQAwbTELMAkGA1UEBhMCREUxEDAOBgNV
+BAgMB0V4YW1wbGUxFTATBgNVBAcMDEZvciBJbnN0YW5jZTEWMBQGA1UECgwNQmVp
+c3BpZWwgR21iSDEdMBsGA1UEAwwUYmVpc3BpZWwuZXhhbXBsZS5vcmcwIBcNMTYw
+MjE1MTQyNzU2WhgPMjA2NjAyMDIxNDI3NTZaMIG3MQswCQYDVQQGEwJERTEZMBcG
+A1UECAwQSW5zdGFuY2UtRXhhbXBsZTEUMBIGA1UEBwwLRXhhbXBsZWNpdHkxGjAY
+BgNVBAoMEUZvciBJbnN0YW5jZSBHbWJIMRkwFwYDVQQLDBBUaGUgRXhhbXBsZSBV
+bml0MRwwGgYDVQQDDBNzdWJjZXJ0LmV4YW1wbGUub3JnMSIwIAYJKoZIhvcNAQkB
+FhNzdWJjZXJ0QGV4YW1wbGUub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAzYlueHZlbSqlLrVAnCyQx9xgnO7jSjK6wXqlbxkl0QZLyDnhvNowZYnu
+7YZI3V+RuVzYbczlEr1qZpUeO8NF04mK1kFPJRinRiuiOtih+WwvDQd77RZJhjoA
+cfEeogt1OzOZg8QKF1AMGlUgk5zWma4VIS75ZM6G1b77qS3rge6L9NwZgthyQ1Pv
+ddYue4MNEpK+2ekZZq/GGZvd+yNP0Wq7kzcmydCgCF9EdLCZwt4BHmOSZM6BUxKv
++PINZgO7Wp2tBBGigg9Mf/NXofjMHp7RI16xa2W9Q/Ct2A6rb5SAB10UddrtxiI+
+F+Jv7lNkHOCLbju7cEs+Y6XIbt1l7aVqBFpgo6cwFZ7DdLPHZkgb50hxdnNdwncO
+R1syspTF544hbmkcb/8+weq+qgsD/57b/ZGrwb8ruByDz0LZiXzxxBRew9OhHZGF
+nuC0D1ciIvpifKe4R/kLcEgVW7yYp4W1BAZgiBJPgXArJTlUBrxamzsQm6N7GxlP
++vTCny7IJsQ1KWu5BqkPv0T1+zD5vUT9/lAa+XBdDHhYVm0adr4dXIef6ws+0zbp
+z8DyaD/Bg9KvRKdnziVc+pKwkWOVrFvZ6NvBex0i8Bgh4FrpkdjmrZMZuuCdex0C
+EayuYexgUqyMg9m0GwGqVNG6mVB4cCOg0rayaqEKrbtUSxNaD/MCAwEAATANBgkq
+hkiG9w0BAQ0FAAOBgQAtHElBGk/c2Fyx+spTOIYmblalbS4dDXRkDonDOscdAW7R
+k7LJNwFqrjFClgXX3/0B+Lzz80zNda4WAGF48mfFsXZ2Fjm60msJrZkrIs5WiU0I
+yox2TFBrg8lGm/WfLeJ/5XKqdlbEZ4NFJrfirvceYcmqLo24WUKENyXIFpLW1Q==
+-----END CERTIFICATE-----
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1-t7-bad-instance.ova b/src/VBox/ValidationKit/tests/api/tdAppliance1-t7-bad-instance.ova
new file mode 100644
index 00000000..48e49059
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1-t7-bad-instance.ova
Binary files differ
diff --git a/src/VBox/ValidationKit/tests/api/tdAppliance1.py b/src/VBox/ValidationKit/tests/api/tdAppliance1.py
new file mode 100755
index 00000000..a92d8b42
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdAppliance1.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# $Id: tdAppliance1.py $
+
+"""
+VirtualBox Validation Kit - IAppliance Test #1
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2010-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 155244 $"
+
+
+# Standard Python imports.
+import os
+import sys
+import tarfile
+
+# Only the main script needs to modify the path.
+try: __file__
+except: __file__ = sys.argv[0]
+g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.append(g_ksValidationKitDir)
+
+# Validation Kit imports.
+from testdriver import base;
+from testdriver import reporter;
+from testdriver import vboxwrappers;
+
+
+class SubTstDrvAppliance1(base.SubTestDriverBase):
+ """
+ Sub-test driver for IAppliance Test #1.
+ """
+
+ def __init__(self, oTstDrv):
+ base.SubTestDriverBase.__init__(self, oTstDrv, 'appliance', 'Applicance');
+
+ def testIt(self):
+ """
+ Execute the sub-testcase.
+ """
+ fRc = True;
+
+ # Import a set of simple OVAs.
+ # Note! Manifests generated by ovftool 4.0.0 does not include the ovf, while the ones b 4.1.0 does.
+ for sOva in (
+ # t1 is a plain VM without any disks, ovftool 4.0 export from fusion
+ 'tdAppliance1-t1.ova',
+ # t2 is a plain VM with one disk. Both 4.0 and 4.1.0 exports.
+ 'tdAppliance1-t2.ova',
+ 'tdAppliance1-t2-ovftool-4.1.0.ova',
+ # t3 is a VM with one gzipped disk and selecting SHA256 on the ovftool cmdline (--compress=9 --shaAlgorithm=sha256).
+ 'tdAppliance1-t3.ova',
+ 'tdAppliance1-t3-ovftool-4.1.0.ova',
+ # t4 is a VM with with two gzipped disk, SHA256 and a (self) signed manifest (--privateKey=./tdAppliance1-t4.pem).
+ 'tdAppliance1-t4.ova',
+ 'tdAppliance1-t4-ovftool-4.1.0.ova',
+ # t5 is a VM with with one gzipped disk, SHA1 and a manifest signed by a valid (2016) DigiCert code signing cert.
+ 'tdAppliance1-t5.ova',
+ 'tdAppliance1-t5-ovftool-4.1.0.ova',
+ # t6 is a VM with with one gzipped disk, SHA1 and a manifest signed by a certificate issued by the t4 certificate,
+ # thus it should be impossible to establish a trusted path to a root CA.
+ 'tdAppliance1-t6.ova',
+ 'tdAppliance1-t6-ovftool-4.1.0.ova',
+ # t7 is based on tdAppliance1-t2-ovftool-4.1.0.ova and has modified to have an invalid InstanceID as well as an
+ # extra readme file. It was tarred up using bsdtar 2.4.12 on windows, so it uses a slightly different tar format and
+ # have different file attributes.
+ 'tdAppliance1-t7-bad-instance.ova',
+ ):
+ reporter.testStart(sOva);
+ try:
+ fRc = self.testImportOva(os.path.join(g_ksValidationKitDir, 'tests', 'api', sOva)) and fRc;
+ fRc = self.testImportOvaAsOvf(os.path.join(g_ksValidationKitDir, 'tests', 'api', sOva)) and fRc;
+ except:
+ reporter.errorXcpt();
+ fRc = False;
+ fRc = reporter.testDone() and fRc;
+
+ ## @todo more stuff
+ return fRc;
+
+ #
+ # Test execution helpers.
+ #
+
+ def testImportOva(self, sOva):
+ """ xxx """
+ oVirtualBox = self.oTstDrv.oVBoxMgr.getVirtualBox();
+
+ #
+ # Import it as OVA.
+ #
+ try:
+ oAppliance = oVirtualBox.createAppliance();
+ except:
+ return reporter.errorXcpt('IVirtualBox::createAppliance failed');
+
+ try:
+ oProgress = vboxwrappers.ProgressWrapper(oAppliance.read(sOva), self.oTstDrv.oVBoxMgr, self.oTstDrv,
+ 'read "%s"' % (sOva,));
+ except:
+ return reporter.errorXcpt('IAppliance::read("%s") failed' % (sOva,));
+ oProgress.wait();
+ if oProgress.logResult() is False:
+ return False;
+
+ try:
+ oAppliance.interpret();
+ except:
+ return reporter.errorXcpt('IAppliance::interpret() failed on "%s"' % (sOva,));
+
+ #
+ try:
+ oProgress = vboxwrappers.ProgressWrapper(oAppliance.importMachines([]),
+ self.oTstDrv.oVBoxMgr, self.oTstDrv, 'importMachines "%s"' % (sOva,));
+ except:
+ return reporter.errorXcpt('IAppliance::importMachines failed on "%s"' % (sOva,));
+ oProgress.wait();
+ if oProgress.logResult() is False:
+ return False;
+
+ #
+ # Export the
+ #
+ ## @todo do more with this OVA. Like untaring it and loading it as an OVF. Export it and import it again.
+
+ return True;
+
+ def testImportOvaAsOvf(self, sOva):
+ """
+ Unpacks the OVA into a subdirectory in the scratch area and imports it as an OVF.
+ """
+ oVirtualBox = self.oTstDrv.oVBoxMgr.getVirtualBox();
+
+ sTmpDir = os.path.join(self.oTstDrv.sScratchPath, os.path.split(sOva)[1] + '-ovf');
+ sOvf = os.path.join(sTmpDir, os.path.splitext(os.path.split(sOva)[1])[0] + '.ovf');
+
+ #
+ # Unpack
+ #
+ try:
+ os.mkdir(sTmpDir, 0o755);
+ oTarFile = tarfile.open(sOva, 'r:*'); # No 'with' support in 2.6. pylint: disable=consider-using-with
+ oTarFile.extractall(sTmpDir);
+ oTarFile.close();
+ except:
+ return reporter.errorXcpt('Unpacking "%s" to "%s" for OVF style importing failed' % (sOvf, sTmpDir,));
+
+ #
+ # Import.
+ #
+ try:
+ oAppliance2 = oVirtualBox.createAppliance();
+ except:
+ return reporter.errorXcpt('IVirtualBox::createAppliance failed (#2)');
+
+ try:
+ oProgress = vboxwrappers.ProgressWrapper(oAppliance2.read(sOvf), self.oTstDrv.oVBoxMgr, self.oTstDrv,
+ 'read "%s"' % (sOvf,));
+ except:
+ return reporter.errorXcpt('IAppliance::read("%s") failed' % (sOvf,));
+ oProgress.wait();
+ if oProgress.logResult() is False:
+ return False;
+
+ try:
+ oAppliance2.interpret();
+ except:
+ return reporter.errorXcpt('IAppliance::interpret() failed on "%s"' % (sOvf,));
+
+ try:
+ oProgress = vboxwrappers.ProgressWrapper(oAppliance2.importMachines([]),
+ self.oTstDrv.oVBoxMgr, self.oTstDrv, 'importMachines "%s"' % (sOvf,));
+ except:
+ return reporter.errorXcpt('IAppliance::importMachines failed on "%s"' % (sOvf,));
+ oProgress.wait();
+ if oProgress.logResult() is False:
+ return False;
+
+ return True;
+
+
+if __name__ == '__main__':
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+ from tests.api.tdApi1 import tdApi1;
+ sys.exit(tdApi1([SubTstDrvAppliance1]).main(sys.argv));
+
diff --git a/src/VBox/ValidationKit/tests/api/tdCloneMedium1.py b/src/VBox/ValidationKit/tests/api/tdCloneMedium1.py
new file mode 100755
index 00000000..056fb2eb
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdCloneMedium1.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# $Id: tdCloneMedium1.py $
+
+"""
+VirtualBox Validation Kit - Clone Medium Test #1
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2010-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 155244 $"
+
+
+# Standard Python imports.
+import os
+import sys
+
+# Only the main script needs to modify the path.
+try: __file__
+except: __file__ = sys.argv[0]
+g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.append(g_ksValidationKitDir)
+
+# Validation Kit imports.
+from testdriver import base
+from testdriver import reporter
+from testdriver import vboxcon
+from testdriver import vboxwrappers
+
+
+class SubTstDrvCloneMedium1(base.SubTestDriverBase):
+ """
+ Sub-test driver for Clone Medium Test #1.
+ """
+
+ def __init__(self, oTstDrv):
+ base.SubTestDriverBase.__init__(self, oTstDrv, 'clone-medium', 'Move Medium');
+
+ def testIt(self):
+ """
+ Execute the sub-testcase.
+ """
+
+ return self.testAll()
+
+ #
+ # Test execution helpers.
+ #
+
+ def createTestMedium(self, oVM, sPathSuffix, sFmt = 'VDI', cbSize = 1024*1024, data = None):
+ assert oVM is not None
+
+ oSession = self.oTstDrv.openSession(oVM)
+
+ if oSession is None:
+ return False
+
+ #
+ # Create Medium Object
+ #
+
+ sBaseHdd1Path = os.path.join(self.oTstDrv.sScratchPath, sPathSuffix)
+ sBaseHdd1Fmt = sFmt
+ cbBaseHdd1Size = cbSize
+
+ try:
+ oBaseHdd1 = oSession.createBaseHd(sBaseHdd1Path, sBaseHdd1Fmt, cbBaseHdd1Size)
+ except:
+ return reporter.errorXcpt('createBaseHd failed')
+
+ oMediumIOBaseHdd1 = oBaseHdd1.openForIO(True, "")
+
+ if data:
+ cbWritten = oMediumIOBaseHdd1.write(0, data)
+
+ if cbWritten != 1:
+ return reporter.error("Failed writing to test hdd.")
+
+ oMediumIOBaseHdd1.close()
+
+ return oBaseHdd1
+
+ def cloneMedium(self, oSrcHd, oTgtHd):
+ """
+ Clones medium into target medium.
+ """
+ try:
+ oProgressCom = oSrcHd.cloneTo(oTgtHd, (vboxcon.MediumVariant_Standard, ), None);
+ except:
+ reporter.errorXcpt('failed to clone medium %s to %s' % (oSrcHd.name, oTgtHd.name));
+ return False;
+ oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oTstDrv.oVBoxMgr, self.oTstDrv,
+ 'clone base disk %s to %s' % (oSrcHd.name, oTgtHd.name));
+ oProgress.wait(cMsTimeout = 15*60*1000); # 15 min
+ oProgress.logResult();
+ return True;
+
+ def resizeAndCloneMedium(self, oSrcHd, oTgtHd, cbTgtSize):
+ """
+ Clones medium into target medium.
+ """
+
+ try:
+ oProgressCom = oSrcHd.resizeAndCloneTo(oTgtHd, cbTgtSize, (vboxcon.MediumVariant_Standard, ), None);
+ except:
+ reporter.errorXcpt('failed to resize and clone medium %s to %s and to size %d' \
+ % (oSrcHd.name, oTgtHd.name, cbTgtSize));
+ return False;
+ oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oTstDrv.oVBoxMgr, self.oTstDrv,
+ 'resize and clone base disk %s to %s and to size %d' \
+ % (oSrcHd.name, oTgtHd.name, cbTgtSize));
+ oProgress.wait(cMsTimeout = 15*60*1000); # 15 min
+ oProgress.logResult();
+ return True;
+
+ def deleteVM(self, oVM):
+ try:
+ oVM.unregister(vboxcon.CleanupMode_DetachAllReturnNone);
+ except:
+ reporter.logXcpt();
+
+ try:
+ oProgressCom = oVM.deleteConfig([]);
+ except:
+ reporter.logXcpt();
+ else:
+ oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oTstDrv.oVBoxMgr, self.oTstDrv,
+ 'Delete VM %s' % (oVM.name));
+ oProgress.wait(cMsTimeout = 15*60*1000); # 15 min
+ oProgress.logResult();
+
+ return None;
+
+ #
+ # Tests
+ #
+
+ def testCloneOnly(self):
+ """
+ Tests cloning mediums only. No resize.
+ """
+
+ reporter.testStart("testCloneOnly")
+
+ oVM = self.oTstDrv.createTestVM('test-medium-clone-only', 1, None, 4)
+
+ hd1 = self.createTestMedium(oVM, "hd1-cloneonly", data=[0xdeadbeef])
+ hd2 = self.createTestMedium(oVM, "hd2-cloneonly")
+
+ if not self.cloneMedium(hd1, hd2):
+ return False
+
+ oMediumIOhd1 = hd1.openForIO(True, "")
+ dataHd1 = oMediumIOhd1.read(0, 4)
+ oMediumIOhd1.close()
+
+ oMediumIOhd2 = hd2.openForIO(True, "")
+ dataHd2 = oMediumIOhd2.read(0, 4)
+ oMediumIOhd2.close()
+
+ if dataHd1 != dataHd2:
+ reporter.testFailure("Data read is unexpected.")
+
+ self.deleteVM(oVM)
+
+ reporter.testDone()
+ return True
+
+ def testResizeAndClone(self):
+ """
+ Tests resizing and cloning mediums only.
+ """
+
+ reporter.testStart("testResizeAndClone")
+
+ oVM = self.oTstDrv.createTestVM('test-medium-clone-only', 1, None, 4)
+
+ hd1 = self.createTestMedium(oVM, "hd1-resizeandclone", data=[0xdeadbeef])
+ hd2 = self.createTestMedium(oVM, "hd2-resizeandclone")
+
+ if not (hasattr(hd1, "resizeAndCloneTo") and callable(getattr(hd1, "resizeAndCloneTo"))):
+ self.deleteVM(oVM)
+ reporter.testDone()
+ return True
+
+ if not self.resizeAndCloneMedium(hd1, hd2, 1024*1024*2):
+ return False
+
+ oMediumIOhd1 = hd1.openForIO(True, "")
+ dataHd1 = oMediumIOhd1.read(0, 4)
+ oMediumIOhd1.close()
+
+ oMediumIOhd2 = hd2.openForIO(True, "")
+ dataHd2 = oMediumIOhd2.read(0, 4)
+ oMediumIOhd2.close()
+
+ if dataHd1 != dataHd2:
+ reporter.testFailure("Data read is unexpected.")
+
+ if hd2.logicalSize not in (hd1.logicalSize, 1024*1024*2):
+ reporter.testFailure("Target medium did not resize.")
+
+ self.deleteVM(oVM)
+
+ reporter.testDone()
+ return True
+
+ def testAll(self):
+ return self.testCloneOnly() & self.testResizeAndClone()
+
+if __name__ == '__main__':
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+ from tdApi1 import tdApi1; # pylint: disable=relative-import
+ sys.exit(tdApi1([SubTstDrvCloneMedium1]).main(sys.argv))
diff --git a/src/VBox/ValidationKit/tests/api/tdCreateVMWithDefaults1.py b/src/VBox/ValidationKit/tests/api/tdCreateVMWithDefaults1.py
new file mode 100755
index 00000000..21892abb
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdCreateVMWithDefaults1.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# $Id: tdCreateVMWithDefaults1.py $
+
+"""
+VirtualBox Validation Kit - Create VM with IMachine::applyDefaults() Test
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2010-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 155244 $"
+
+
+# Standard Python imports.
+import os
+import sys
+
+# Only the main script needs to modify the path.
+try: __file__
+except: __file__ = sys.argv[0]
+g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.append(g_ksValidationKitDir)
+
+# Validation Kit imports.
+from testdriver import base
+from testdriver import reporter;
+from testdriver import vboxcon;
+
+
+class SubTstDrvCreateVMWithDefaults1(base.SubTestDriverBase):
+ """
+ Sub-test driver for VM Move Test #1.
+ """
+
+ def __init__(self, oTstDrv):
+ base.SubTestDriverBase.__init__(self, oTstDrv, 'create-vm-with-defaults', 'Create VMs with defaults');
+
+ def testIt(self):
+ """
+ Execute the sub-testcase.
+ """
+ reporter.log('ValidationKit folder is "%s"' % (g_ksValidationKitDir,))
+ reporter.testStart(self.sTestName);
+ fRc = self.testCreateVMWithDefaults();
+ reporter.testDone();
+ return fRc;
+
+
+ def createVMWithDefaults(self, sGuestType):
+ sName = 'testvm_%s' % (sGuestType)
+ # create VM manually, because the self.createTestVM() makes registration inside
+ # the method, but IMachine::applyDefault() must be called before machine is registered
+ try:
+ if self.oTstDrv.fpApiVer >= 4.2: # Introduces grouping (third parameter, empty for now).
+ oVM = self.oTstDrv.oVBox.createMachine("", sName, [],
+ self.oTstDrv.tryFindGuestOsId(sGuestType),
+ "")
+ elif self.oTstDrv.fpApiVer >= 4.0:
+ oVM = self.oTstDrv.oVBox.createMachine("", sName,
+ self.oTstDrv.tryFindGuestOsId(sGuestType),
+ "", False)
+ elif self.oTstDrv.fpApiVer >= 3.2:
+ oVM = self.oTstDrv.oVBox.createMachine(sName,
+ self.oTstDrv.tryFindGuestOsId(sGuestType),
+ "", "", False)
+ else:
+ oVM = self.oTstDrv.oVBox.createMachine(sName,
+ self.oTstDrv.tryFindGuestOsId(sGuestType),
+ "", "")
+ try:
+ oVM.saveSettings()
+ except:
+ reporter.logXcpt()
+ if self.oTstDrv.fpApiVer >= 4.0:
+ try:
+ if self.oTstDrv.fpApiVer >= 4.3:
+ oProgress = oVM.deleteConfig([])
+ else:
+ oProgress = oVM.delete(None);
+ self.oTstDrv.waitOnProgress(oProgress)
+ except:
+ reporter.logXcpt()
+ else:
+ try: oVM.deleteSettings()
+ except: reporter.logXcpt()
+ raise
+ except:
+ reporter.errorXcpt('failed to create vm "%s"' % (sName))
+ return None
+
+ if oVM is None:
+ return False
+
+ # apply settings
+ fRc = True
+ try:
+ if self.oTstDrv.fpApiVer >= 6.1:
+ oVM.applyDefaults('')
+ oVM.saveSettings();
+ self.oTstDrv.oVBox.registerMachine(oVM)
+ except:
+ reporter.logXcpt()
+ fRc = False
+
+ # Some errors from applyDefaults can be observed only after further settings saving.
+ # Change and save the size of the VM RAM as simple setting change.
+ oSession = self.oTstDrv.openSession(oVM)
+ if oSession is None:
+ fRc = False
+
+ if fRc:
+ try:
+ oSession.memorySize = 4096
+ oSession.saveSettings(True)
+ except:
+ reporter.logXcpt()
+ fRc = False
+
+ # delete VM
+ try:
+ oVM.unregister(vboxcon.CleanupMode_DetachAllReturnNone)
+ except:
+ reporter.logXcpt()
+
+ if self.oTstDrv.fpApiVer >= 4.0:
+ try:
+ if self.oTstDrv.fpApiVer >= 4.3:
+ oProgress = oVM.deleteConfig([])
+ else:
+ oProgress = oVM.delete(None)
+ self.oTstDrv.waitOnProgress(oProgress)
+
+ except:
+ reporter.logXcpt()
+
+ else:
+ try: oVM.deleteSettings()
+ except: reporter.logXcpt()
+
+ return fRc
+
+ def testCreateVMWithDefaults(self):
+ """
+ Test create VM with defaults.
+ """
+ if not self.oTstDrv.importVBoxApi():
+ return reporter.error('importVBoxApi');
+
+ # Get the guest OS types.
+ try:
+ aoGuestTypes = self.oTstDrv.oVBoxMgr.getArray(self.oTstDrv.oVBox, 'guestOSTypes')
+ if aoGuestTypes is None or not aoGuestTypes:
+ return reporter.error('No guest OS types');
+ except:
+ return reporter.errorXcpt();
+
+ # Create VMs with defaults for each of the guest types.
+ fRc = True
+ for oGuestType in aoGuestTypes:
+ try:
+ sGuestType = oGuestType.id;
+ except:
+ fRc = reporter.errorXcpt();
+ else:
+ reporter.testStart(sGuestType);
+ fRc = self.createVMWithDefaults(sGuestType) and fRc;
+ reporter.testDone();
+ return fRc
+
+if __name__ == '__main__':
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+ from tdApi1 import tdApi1; # pylint: disable=relative-import
+ sys.exit(tdApi1([SubTstDrvCreateVMWithDefaults1]).main(sys.argv))
+
diff --git a/src/VBox/ValidationKit/tests/api/tdMoveMedium1.py b/src/VBox/ValidationKit/tests/api/tdMoveMedium1.py
new file mode 100755
index 00000000..ca3f3891
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdMoveMedium1.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# $Id: tdMoveMedium1.py $
+
+"""
+VirtualBox Validation Kit - Medium Move Test #1
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2010-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 155244 $"
+
+
+# Standard Python imports.
+import os
+import sys
+
+# Only the main script needs to modify the path.
+try: __file__
+except: __file__ = sys.argv[0]
+g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.append(g_ksValidationKitDir)
+
+# Validation Kit imports.
+from testdriver import base
+from testdriver import reporter
+from testdriver import vboxcon
+from testdriver import vboxwrappers
+
+
+class SubTstDrvMoveMedium1(base.SubTestDriverBase):
+ """
+ Sub-test driver for Medium Move Test #1.
+ """
+
+ def __init__(self, oTstDrv):
+ base.SubTestDriverBase.__init__(self, oTstDrv, 'move-medium', 'Move Medium');
+
+ def testIt(self):
+ """
+ Execute the sub-testcase.
+ """
+ return self.testMediumMove()
+
+ #
+ # Test execution helpers.
+ #
+
+ def moveTo(self, sLocation, aoMediumAttachments):
+ for oAttachment in aoMediumAttachments:
+ try:
+ oMedium = oAttachment.medium
+ reporter.log('Move medium "%s" to "%s"' % (oMedium.name, sLocation,))
+ except:
+ reporter.errorXcpt('failed to get the medium from the IMediumAttachment "%s"' % (oAttachment))
+
+ if self.oTstDrv.fpApiVer >= 5.3 and self.oTstDrv.uRevision > 124748:
+ try:
+ oProgress = vboxwrappers.ProgressWrapper(oMedium.moveTo(sLocation), self.oTstDrv.oVBoxMgr, self.oTstDrv,
+ 'move "%s"' % (oMedium.name,));
+ except:
+ return reporter.errorXcpt('Medium::moveTo("%s") for medium "%s" failed' % (sLocation, oMedium.name,));
+ else:
+ try:
+ oProgress = vboxwrappers.ProgressWrapper(oMedium.setLocation(sLocation), self.oTstDrv.oVBoxMgr, self.oTstDrv,
+ 'move "%s"' % (oMedium.name,));
+ except:
+ return reporter.errorXcpt('Medium::setLocation("%s") for medium "%s" failed' % (sLocation, oMedium.name,));
+
+
+ oProgress.wait()
+ if oProgress.logResult() is False:
+ return False
+ return True
+
+ def checkLocation(self, sLocation, aoMediumAttachments, asFiles):
+ fRc = True
+ for oAttachment in aoMediumAttachments:
+ sFilePath = os.path.join(sLocation, asFiles[oAttachment.port])
+ sActualFilePath = oAttachment.medium.location
+ if os.path.abspath(sFilePath) != os.path.abspath(sActualFilePath):
+ reporter.log('medium location expected to be "%s" but is "%s"' % (sFilePath, sActualFilePath))
+ fRc = False;
+ if not os.path.exists(sFilePath):
+ reporter.log('medium file does not exist at "%s"' % (sFilePath,))
+ fRc = False;
+ return fRc
+
+ def testMediumMove(self):
+ """
+ Test medium moving.
+ """
+ reporter.testStart('medium moving')
+
+ try: ## @todo r=bird: Bad 'ing style.
+ oVM = self.oTstDrv.createTestVM('test-medium-move', 1, None, 4)
+ assert oVM is not None
+
+ # create hard disk images, one for each file-based backend, using the first applicable extension
+ fRc = True
+ oSession = self.oTstDrv.openSession(oVM)
+ aoDskFmts = self.oTstDrv.oVBoxMgr.getArray(self.oTstDrv.oVBox.systemProperties, 'mediumFormats')
+ asFiles = []
+ for oDskFmt in aoDskFmts:
+ aoDskFmtCaps = self.oTstDrv.oVBoxMgr.getArray(oDskFmt, 'capabilities')
+ if vboxcon.MediumFormatCapabilities_File not in aoDskFmtCaps \
+ or vboxcon.MediumFormatCapabilities_CreateDynamic not in aoDskFmtCaps:
+ continue
+ (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:
+ fRc = False
+ break
+ sFile = 'Test' + str(len(asFiles)) + sExt
+ sHddPath = os.path.join(self.oTstDrv.sScratchPath, sFile)
+ oHd = oSession.createBaseHd(sHddPath, sFmt=oDskFmt.id, cb=1024*1024)
+ if oHd is None:
+ fRc = False
+ break
+
+ # attach HDD, IDE controller exists by default, but we use SATA just in case
+ sController='SATA Controller'
+ fRc = fRc and oSession.attachHd(sHddPath, sController, iPort = len(asFiles),
+ fImmutable=False, fForceResource=False)
+ if fRc:
+ asFiles.append(sFile)
+
+ fRc = fRc and oSession.saveSettings()
+
+ #create temporary subdirectory in the current working directory
+ sOrigLoc = self.oTstDrv.sScratchPath
+ sNewLoc = os.path.join(sOrigLoc, 'newLocation')
+ os.mkdir(sNewLoc, 0o775)
+
+ aoMediumAttachments = oVM.getMediumAttachmentsOfController(sController)
+ #case 1. Only path without file name, with trailing separator
+ fRc = self.moveTo(sNewLoc + os.sep, aoMediumAttachments) and fRc
+ fRc = self.checkLocation(sNewLoc, aoMediumAttachments, asFiles) and fRc
+
+ #case 2. Only path without file name, without trailing separator
+ fRc = self.moveTo(sOrigLoc, aoMediumAttachments) and fRc
+ fRc = self.checkLocation(sOrigLoc, aoMediumAttachments, asFiles) and fRc
+
+ #case 3. Path with file name
+ #The case supposes that user has passed a destination path with a file name but hasn't added an extension/suffix
+ #to this destination file. User supposes that the extension would be added automatically and to be the same as
+ #for the original file. Difficult case, apparently this case should follow mv(1) logic
+ #and the file name is processed as folder name (aka mv(1) logic).
+ #Be discussed.
+ fRc = self.moveTo(os.path.join(sNewLoc, 'newName'), aoMediumAttachments) and fRc
+ asNewFiles = ['newName' + os.path.splitext(s)[1] for s in asFiles]
+ fRc = self.checkLocation(os.path.join(sNewLoc, 'newName'), aoMediumAttachments, asFiles) and fRc
+
+ #after the case the destination path must be corrected
+ sNewLoc = os.path.join(sNewLoc, 'newName')
+
+ #case 4. Only file name
+ fRc = self.moveTo('onlyMediumName', aoMediumAttachments) and fRc
+ asNewFiles = ['onlyMediumName' + os.path.splitext(s)[1] for s in asFiles]
+ if self.oTstDrv.fpApiVer >= 5.3:
+ fRc = self.checkLocation(sNewLoc, aoMediumAttachments, asNewFiles) and fRc
+ else:
+ fRc = self.checkLocation(sNewLoc, aoMediumAttachments,
+ [s.replace('.hdd', '.parallels') for s in asNewFiles]) and fRc
+
+ #case 5. Move all files from a snapshot
+ fRc = fRc and oSession.takeSnapshot('Snapshot1')
+ if fRc:
+ aoMediumAttachments = oVM.getMediumAttachmentsOfController(sController)
+ asSnapFiles = [os.path.basename(o.medium.name) for o in aoMediumAttachments]
+ fRc = self.moveTo(sOrigLoc, aoMediumAttachments) and fRc
+ fRc = self.checkLocation(sOrigLoc, aoMediumAttachments, asSnapFiles) and fRc
+
+ fRc = oSession.close() and fRc
+ except:
+ reporter.errorXcpt()
+
+ return reporter.testDone()[1] == 0
+
+
+if __name__ == '__main__':
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+ from tdApi1 import tdApi1; # pylint: disable=relative-import
+ sys.exit(tdApi1([SubTstDrvMoveMedium1]).main(sys.argv))
+
diff --git a/src/VBox/ValidationKit/tests/api/tdMoveVm1.py b/src/VBox/ValidationKit/tests/api/tdMoveVm1.py
new file mode 100755
index 00000000..3bf058d5
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdMoveVm1.py
@@ -0,0 +1,768 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# "$Id: tdMoveVm1.py $"
+
+"""
+VirtualBox Validation Kit - VM Move Test #1
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2010-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 155244 $"
+
+# Standard Python imports.
+import os
+import sys
+import shutil
+from collections import defaultdict
+
+# Only the main script needs to modify the path.
+try: __file__
+except: __file__ = sys.argv[0]
+g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.append(g_ksValidationKitDir)
+
+# Validation Kit imports.
+from testdriver import base
+from testdriver import reporter
+from testdriver import vboxcon
+from testdriver import vboxwrappers
+from tdMoveMedium1 import SubTstDrvMoveMedium1; # pylint: disable=relative-import
+
+
+# @todo r=aeichner: The whole path handling/checking needs fixing to also work on Windows
+# The current quick workaround is to spill os.path.normcase() all over the place when
+# constructing paths. I'll leave the real fix to the original author...
+class SubTstDrvMoveVm1(base.SubTestDriverBase):
+ """
+ Sub-test driver for VM Move Test #1.
+ """
+
+ def __init__(self, oTstDrv):
+ base.SubTestDriverBase.__init__(self, oTstDrv, 'move-vm', 'Move VM');
+
+ # Note! Hardcoded indexing in test code further down.
+ self.asRsrcs = [
+ os.path.join('5.3','isos','tdMoveVM1.iso'),
+ os.path.join('5.3','floppy','tdMoveVM1.img')
+ ];
+
+ self.asImagesNames = []
+ self.dsKeys = {
+ 'StandardImage': 'SATA Controller',
+ 'ISOImage': 'IDE Controller',
+ 'FloppyImage': 'Floppy Controller',
+ 'SettingsFile': 'Settings File',
+ 'LogFile': 'Log File',
+ 'SavedStateFile': 'Saved State File',
+ 'SnapshotFile': 'Snapshot File'
+ };
+
+ def testIt(self):
+ """
+ Execute the sub-testcase.
+ """
+ reporter.testStart(self.sTestName);
+ reporter.log('ValidationKit folder is "%s"' % (g_ksValidationKitDir,))
+ fRc = self.testVMMove();
+ return reporter.testDone(fRc is None)[1] == 0;
+
+ #
+ # Test execution helpers.
+ #
+
+ def createTestMachine(self):
+ """
+ Document me here, not with hashes above.
+ """
+ oVM = self.oTstDrv.createTestVM('test-vm-move', 1, None, 4)
+ if oVM is None:
+ return None
+
+ # create hard disk images, one for each file-based backend, using the first applicable extension
+ fRc = True
+ oSession = self.oTstDrv.openSession(oVM)
+ aoDskFmts = self.oTstDrv.oVBoxMgr.getArray(self.oTstDrv.oVBox.systemProperties, 'mediumFormats')
+
+ for oDskFmt in aoDskFmts:
+ aoDskFmtCaps = self.oTstDrv.oVBoxMgr.getArray(oDskFmt, 'capabilities')
+ if vboxcon.MediumFormatCapabilities_File not in aoDskFmtCaps \
+ or vboxcon.MediumFormatCapabilities_CreateDynamic not in aoDskFmtCaps:
+ continue
+ (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:
+ fRc = False
+ break
+ sFile = 'test-vm-move' + str(len(self.asImagesNames)) + sExt
+ sHddPath = os.path.join(self.oTstDrv.sScratchPath, sFile)
+ oHd = oSession.createBaseHd(sHddPath, sFmt=oDskFmt.id, cb=1024*1024)
+ if oHd is None:
+ fRc = False
+ break
+
+ # attach HDD, IDE controller exists by default, but we use SATA just in case
+ sController = self.dsKeys['StandardImage']
+ fRc = fRc and oSession.attachHd(sHddPath, sController, iPort = len(self.asImagesNames),
+ fImmutable=False, fForceResource=False)
+ if fRc:
+ self.asImagesNames.append(sFile)
+
+ fRc = fRc and oSession.saveSettings()
+ fRc = oSession.close() and fRc
+
+ if fRc is False:
+ oVM = None
+
+ return oVM
+
+ def moveVMToLocation(self, sLocation, oVM):
+ """
+ Document me here, not with hashes above.
+ """
+ fRc = True
+ try:
+
+ ## @todo r=bird: Too much unncessary crap inside try clause. Only oVM.moveTo needs to be here.
+ ## Though, you could make an argument for oVM.name too, perhaps.
+
+ # move machine
+ reporter.log('Moving machine "%s" to the "%s"' % (oVM.name, sLocation))
+ sType = 'basic'
+ oProgress = vboxwrappers.ProgressWrapper(oVM.moveTo(sLocation, sType), self.oTstDrv.oVBoxMgr, self.oTstDrv,
+ 'moving machine "%s"' % (oVM.name,))
+
+ except:
+ return reporter.errorXcpt('Machine::moveTo("%s") for machine "%s" failed' % (sLocation, oVM.name,))
+
+ oProgress.wait()
+ if oProgress.logResult() is False:
+ fRc = False
+ reporter.log('Progress object returned False')
+ else:
+ fRc = True
+
+ return fRc
+
+ def checkLocation(self, oMachine, dsReferenceFiles):
+ """
+ Document me.
+
+ Prerequisites:
+ 1. All standard images are attached to SATA controller
+ 2. All ISO images are attached to IDE controller
+ 3. All floppy images are attached to Floppy controller
+ 4. The type defaultdict from collection is used here (some sort of multimap data structure)
+ 5. The dsReferenceFiles parameter here is the structure defaultdict(set):
+ [
+ ('StandardImage': ['somedisk.vdi', 'somedisk.vmdk',...]),
+ ('ISOImage': ['somedisk_1.iso','somedisk_2.iso',...]),
+ ('FloppyImage': ['somedisk_1.img','somedisk_2.img',...]),
+ ('SnapshotFile': ['snapshot file 1','snapshot file 2', ...]),
+ ('SettingsFile', ['setting file',...]),
+ ('SavedStateFile': ['state file 1','state file 2',...]),
+ ('LogFile': ['log file 1','log file 2',...]),
+ ]
+ """
+
+ fRc = True
+
+ for sKey, sValue in self.dsKeys.items():
+ aActuals = set()
+ aReferences = set()
+
+ # Check standard images locations, ISO files locations, floppy images locations, snapshots files locations
+ if sKey in ('StandardImage', 'ISOImage', 'FloppyImage',):
+ aReferences = dsReferenceFiles[sKey]
+ if aReferences:
+ aoMediumAttachments = oMachine.getMediumAttachmentsOfController(sValue) ##@todo r=bird: API call, try-except!
+ for oAttachment in aoMediumAttachments:
+ aActuals.add(os.path.normcase(oAttachment.medium.location))
+
+ elif sKey == 'SnapshotFile':
+ aReferences = dsReferenceFiles[sKey]
+ if aReferences:
+ aActuals = self.__getSnapshotsFiles(oMachine)
+
+ # Check setting file location
+ elif sKey == 'SettingsFile':
+ aReferences = dsReferenceFiles[sKey]
+ if aReferences:
+ aActuals.add(os.path.normcase(oMachine.settingsFilePath))
+
+ # Check saved state files location
+ elif sKey == 'SavedStateFile':
+ aReferences = dsReferenceFiles[sKey]
+ if aReferences:
+ aActuals = self.__getStatesFiles(oMachine)
+
+ # Check log files location
+ elif sKey == 'LogFile':
+ aReferences = dsReferenceFiles[sKey]
+ if aReferences:
+ aActuals = self.__getLogFiles(oMachine)
+
+ if aActuals:
+ reporter.log('Check %s' % (sKey))
+ intersection = aReferences.intersection(aActuals)
+ for eachItem in intersection:
+ reporter.log('Item location "%s" is correct' % (eachItem))
+
+ difference = aReferences.difference(aActuals)
+ for eachItem in difference:
+ reporter.log('Item location "%s" isn\'t correct' % (eachItem))
+
+ reporter.log('####### Reference locations: #######')
+ for eachItem in aActuals:
+ reporter.log(' "%s"' % (eachItem))
+
+ if len(intersection) != len(aActuals):
+ reporter.log('Not all items in the right location. Check it.')
+ fRc = False
+
+ return fRc
+
+ def checkAPIVersion(self):
+ return self.oTstDrv.fpApiVer >= 5.3;
+
+ @staticmethod
+ def __safeListDir(sDir):
+ """ Wrapper around os.listdir that returns empty array instead of exceptions. """
+ try:
+ return os.listdir(sDir);
+ except:
+ return [];
+
+ def __getStatesFiles(self, oMachine, fPrint = False):
+ asStateFilesList = set()
+ sFolder = oMachine.snapshotFolder;
+ for sFile in self.__safeListDir(sFolder):
+ if sFile.endswith(".sav"):
+ sFullPath = os.path.normcase(os.path.join(sFolder, sFile));
+ asStateFilesList.add(sFullPath)
+ if fPrint is True:
+ reporter.log("State file is %s" % (sFullPath))
+ return asStateFilesList
+
+ def __getSnapshotsFiles(self, oMachine, fPrint = False):
+ asSnapshotsFilesList = set()
+ sFolder = oMachine.snapshotFolder
+ for sFile in self.__safeListDir(sFolder):
+ if sFile.endswith(".sav") is False:
+ sFullPath = os.path.normcase(os.path.join(sFolder, sFile));
+ asSnapshotsFilesList.add(sFullPath)
+ if fPrint is True:
+ reporter.log("Snapshot file is %s" % (sFullPath))
+ return asSnapshotsFilesList
+
+ def __getLogFiles(self, oMachine, fPrint = False):
+ asLogFilesList = set()
+ sFolder = oMachine.logFolder
+ for sFile in self.__safeListDir(sFolder):
+ if sFile.endswith(".log"):
+ sFullPath = os.path.normcase(os.path.join(sFolder, sFile));
+ asLogFilesList.add(sFullPath)
+ if fPrint is True:
+ reporter.log("Log file is %s" % (sFullPath))
+ return asLogFilesList
+
+
+ def __testScenario_2(self, oSession, oMachine, sNewLoc, sOldLoc):
+ """
+ All disks attached to VM are located inside the VM's folder.
+ There are no any snapshots and logs.
+ """
+
+ sController = self.dsKeys['StandardImage']
+ aoMediumAttachments = oMachine.getMediumAttachmentsOfController(sController)
+ oSubTstDrvMoveMedium1Instance = SubTstDrvMoveMedium1(self.oTstDrv)
+ oSubTstDrvMoveMedium1Instance.moveTo(sOldLoc, aoMediumAttachments)
+
+ del oSubTstDrvMoveMedium1Instance
+
+ dsReferenceFiles = defaultdict(set)
+
+ for s in self.asImagesNames:
+ reporter.log('"%s"' % (s,))
+ dsReferenceFiles['StandardImage'].add(os.path.normcase(sNewLoc + os.sep + oMachine.name + os.sep + s))
+
+ sSettingFile = os.path.join(sNewLoc, os.path.join(oMachine.name, oMachine.name + '.vbox'))
+ dsReferenceFiles['SettingsFile'].add(os.path.normcase(sSettingFile))
+
+ fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine)
+
+ if fRc is True:
+ fRc = self.checkLocation(oSession.o.machine, dsReferenceFiles)
+ if fRc is False:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 2nd scenario: Check locations failed... !!!!!!!!!!!!!!!!!!')
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 2nd scenario: Move VM failed... !!!!!!!!!!!!!!!!!!')
+
+ fRes = oSession.saveSettings()
+ if fRes is False:
+ reporter.log('2nd scenario: Couldn\'t save machine settings')
+
+ return fRc
+
+ def __testScenario_3(self, oSession, oMachine, sNewLoc):
+ """
+ There are snapshots
+ """
+
+ # At moment, it's used only one snapshot due to the difficulty to get
+ # all attachments of the machine (i.e. not only attached at moment)
+ cSnap = 1
+
+ for counter in range(1,cSnap+1):
+ strSnapshot = 'Snapshot' + str(counter)
+ fRc = oSession.takeSnapshot(strSnapshot)
+ if fRc is False:
+ reporter.testFailure('3rd scenario: Can\'t take snapshot "%s"' % (strSnapshot,))
+
+ dsReferenceFiles = defaultdict(set)
+
+ sController = self.dsKeys['StandardImage']
+ aoMediumAttachments = oMachine.getMediumAttachmentsOfController(sController)
+ if fRc is True:
+ for oAttachment in aoMediumAttachments:
+ sRes = oAttachment.medium.location.rpartition(os.sep)
+ dsReferenceFiles['SnapshotFile'].add(os.path.normcase(sNewLoc + os.sep + oMachine.name + os.sep +
+ 'Snapshots' + os.sep + sRes[2]))
+
+ sSettingFile = os.path.join(sNewLoc, os.path.join(oMachine.name, oMachine.name + '.vbox'))
+ dsReferenceFiles['SettingsFile'].add(os.path.normcase(sSettingFile))
+
+ fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine)
+
+ if fRc is True:
+ fRc = self.checkLocation(oSession.o.machine, dsReferenceFiles)
+ if fRc is False:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 3rd scenario: Check locations failed... !!!!!!!!!!!!!!!!!!')
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 3rd scenario: Move VM failed... !!!!!!!!!!!!!!!!!!')
+
+ fRes = oSession.saveSettings()
+ if fRes is False:
+ reporter.log('3rd scenario: Couldn\'t save machine settings')
+
+ return fRc
+
+ def __testScenario_4(self, oMachine, sNewLoc):
+ """
+ There are one or more save state files in the snapshots folder
+ and some files in the logs folder.
+ Here we run VM, next stop it in the "save" state.
+ And next move VM
+ """
+
+ # Run VM and get new Session object.
+ oSession = self.oTstDrv.startVm(oMachine);
+ if not oSession:
+ return False;
+
+ # Some time interval should be here for not closing VM just after start.
+ self.oTstDrv.waitForTasks(1000);
+
+ if oMachine.state != self.oTstDrv.oVBoxMgr.constants.MachineState_Running:
+ reporter.log("Machine '%s' is not Running" % (oMachine.name))
+ fRc = False
+
+ # Call Session::saveState(), already closes session unless it failed.
+ fRc = oSession.saveState()
+ if fRc is True:
+ reporter.log("Machine is in saved state")
+
+ fRc = self.oTstDrv.terminateVmBySession(oSession)
+
+ if fRc is True:
+ # Create a new Session object for moving VM.
+ oSession = self.oTstDrv.openSession(oMachine)
+
+ # Always clear before each scenario.
+ dsReferenceFiles = defaultdict(set)
+
+ asLogs = self.__getLogFiles(oMachine)
+ for sFile in asLogs:
+ sRes = sFile.rpartition(os.sep)
+ dsReferenceFiles['LogFile'].add(os.path.normcase(sNewLoc + os.sep + oMachine.name + os.sep +
+ 'Logs' + os.sep + sRes[2]))
+
+ asStates = self.__getStatesFiles(oMachine)
+ for sFile in asStates:
+ sRes = sFile.rpartition(os.sep)
+ dsReferenceFiles['SavedStateFile'].add(os.path.normcase(sNewLoc + os.sep + oMachine.name + os.sep +
+ 'Snapshots' + os.sep + sRes[2]))
+
+ fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine)
+
+ if fRc is True:
+ fRc = self.checkLocation(oSession.o.machine, dsReferenceFiles)
+ if fRc is False:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 4th scenario: Check locations failed... !!!!!!!!!!!!!!!!!!')
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 4th scenario: Move VM failed... !!!!!!!!!!!!!!!!!!')
+
+ # cleaning up: get rid of saved state
+ fRes = oSession.discardSavedState(True)
+ if fRes is False:
+ reporter.log('4th scenario: Failed to discard the saved state of machine')
+
+ fRes = oSession.close()
+ if fRes is False:
+ reporter.log('4th scenario: Couldn\'t close machine session')
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 4th scenario: Terminate machine by session failed... !!!!!!!!!!!!!!!!!!')
+
+ return fRc
+
+ def __testScenario_5(self, oMachine, sNewLoc, sOldLoc):
+ """
+ There is an ISO image (.iso) attached to the VM.
+ Prerequisites - there is IDE Controller and there are no any images attached to it.
+ """
+
+ fRc = True
+ sISOImageName = 'tdMoveVM1.iso'
+
+ # Always clear before each scenario.
+ dsReferenceFiles = defaultdict(set)
+
+ # Create a new Session object.
+ oSession = self.oTstDrv.openSession(oMachine)
+
+ sISOLoc = self.asRsrcs[0] # '5.3/isos/tdMoveVM1.iso'
+ reporter.log("sHost is '%s', sResourcePath is '%s'" % (self.oTstDrv.sHost, self.oTstDrv.sResourcePath))
+ sISOLoc = self.oTstDrv.getFullResourceName(sISOLoc)
+ reporter.log("sISOLoc is '%s'" % (sISOLoc,))
+
+ if not os.path.exists(sISOLoc):
+ reporter.log('ISO file does not exist at "%s"' % (sISOLoc,))
+ fRc = False
+
+ # Copy ISO image from the common resource folder into machine folder.
+ shutil.copy(sISOLoc, sOldLoc)
+
+ # Attach ISO image to the IDE controller.
+ if fRc is True:
+ # Set actual ISO location.
+ sISOLoc = sOldLoc + os.sep + sISOImageName
+ reporter.log("sISOLoc is '%s'" % (sISOLoc,))
+ if not os.path.exists(sISOLoc):
+ reporter.log('ISO file does not exist at "%s"' % (sISOLoc,))
+ fRc = False
+
+ sController=self.dsKeys['ISOImage']
+ aoMediumAttachments = oMachine.getMediumAttachmentsOfController(sController)
+ iPort = len(aoMediumAttachments)
+ fRc = oSession.attachDvd(sISOLoc, sController, iPort, iDevice = 0)
+ dsReferenceFiles['ISOImage'].add(os.path.normcase(os.path.join(os.path.join(sNewLoc, oMachine.name), sISOImageName)))
+
+ if fRc is True:
+ fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine)
+ if fRc is True:
+ fRc = self.checkLocation(oSession.o.machine, dsReferenceFiles)
+ if fRc is False:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 5th scenario: Check locations failed... !!!!!!!!!!!!!!!!!!')
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 5th scenario: Move VM failed... !!!!!!!!!!!!!!!!!!')
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 5th scenario: Attach ISO image failed... !!!!!!!!!!!!!!!!!!')
+
+ # Detach ISO image.
+ fRes = oSession.detachHd(sController, iPort, 0)
+ if fRes is False:
+ reporter.log('5th scenario: Couldn\'t detach image from the controller %s '
+ 'port %s device %s' % (sController, iPort, 0))
+
+ fRes = oSession.saveSettings()
+ if fRes is False:
+ reporter.log('5th scenario: Couldn\'t save machine settings')
+
+ fRes = oSession.close()
+ if fRes is False:
+ reporter.log('5th scenario: Couldn\'t close machine session')
+
+ return fRc
+
+ def __testScenario_6(self, oMachine, sNewLoc, sOldLoc):
+ """
+ There is a floppy image (.img) attached to the VM.
+ Prerequisites - there is Floppy Controller and there are no any images attached to it.
+ """
+
+ fRc = True
+
+ # Always clear before each scenario.
+ dsReferenceFiles = defaultdict(set)
+
+ # Create a new Session object.
+ oSession = self.oTstDrv.openSession(oMachine)
+
+ sFloppyLoc = self.asRsrcs[1] # '5.3/floppy/tdMoveVM1.img'
+ sFloppyLoc = self.oTstDrv.getFullResourceName(sFloppyLoc)
+
+ if not os.path.exists(sFloppyLoc):
+ reporter.log('Floppy disk does not exist at "%s"' % (sFloppyLoc,))
+ fRc = False
+
+ # Copy floppy image from the common resource folder into machine folder.
+ shutil.copy(sFloppyLoc, sOldLoc)
+
+ # Attach floppy image.
+ if fRc is True:
+ # Set actual floppy location.
+ sFloppyImageName = 'tdMoveVM1.img'
+ sFloppyLoc = sOldLoc + os.sep + sFloppyImageName
+ sController=self.dsKeys['FloppyImage']
+ fRc = fRc and oSession.attachFloppy(sFloppyLoc, sController, 0, 0)
+ dsReferenceFiles['FloppyImage'].add(os.path.normcase(os.path.join(os.path.join(sNewLoc, oMachine.name),
+ sFloppyImageName)))
+
+ if fRc is True:
+ fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine)
+ if fRc is True:
+ fRc = self.checkLocation(oSession.o.machine, dsReferenceFiles)
+ if fRc is False:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 6th scenario: Check locations failed... !!!!!!!!!!!!!!!!!!')
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 6th scenario: Move VM failed... !!!!!!!!!!!!!!!!!!')
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 6th scenario: Attach floppy image failed... !!!!!!!!!!!!!!!!!!')
+
+ # Detach floppy image.
+ fRes = oSession.detachHd(sController, 0, 0)
+ if fRes is False:
+ reporter.log('6th scenario: Couldn\'t detach image from the controller %s port %s device %s' % (sController, 0, 0))
+
+ fRes = oSession.saveSettings()
+ if fRes is False:
+ reporter.testFailure('6th scenario: Couldn\'t save machine settings')
+
+ fRes = oSession.close()
+ if fRes is False:
+ reporter.log('6th scenario: Couldn\'t close machine session')
+ return fRc
+
+
+ def testVMMove(self):
+ """
+ Test machine moving.
+ """
+ if not self.oTstDrv.importVBoxApi():
+ return False
+
+ fSupported = self.checkAPIVersion()
+ reporter.log('ValidationKit folder is "%s"' % (g_ksValidationKitDir,))
+
+ if fSupported is False:
+ reporter.log('API version %s is too old. Just skip this test.' % (self.oTstDrv.fpApiVer))
+ return None;
+ reporter.log('API version is "%s".' % (self.oTstDrv.fpApiVer))
+
+ # Scenarios
+ # 1. All disks attached to VM are located outside the VM's folder.
+ # There are no any snapshots and logs.
+ # In this case only VM setting file should be moved (.vbox file)
+ #
+ # 2. All disks attached to VM are located inside the VM's folder.
+ # There are no any snapshots and logs.
+ #
+ # 3. There are snapshots.
+ #
+ # 4. There are one or more save state files in the snapshots folder
+ # and some files in the logs folder.
+ #
+ # 5. There is an ISO image (.iso) attached to the VM.
+ #
+ # 6. There is a floppy image (.img) attached to the VM.
+ #
+ # 7. There are shareable disk and immutable disk attached to the VM.
+
+ try: ## @todo r=bird: Would be nice to use sub-tests here for each scenario, however
+ ## this try/catch as well as lots of return points makes that very hard.
+ ## Big try/catch stuff like this should be avoided.
+ # Create test machine.
+ oMachine = self.createTestMachine()
+ if oMachine is None:
+ reporter.error('Failed to create test machine')
+
+ # Create temporary subdirectory in the current working directory.
+ sOrigLoc = self.oTstDrv.sScratchPath
+ sBaseLoc = os.path.join(sOrigLoc, 'moveFolder')
+ os.mkdir(sBaseLoc, 0o775)
+
+ # lock machine
+ # get session machine
+ oSession = self.oTstDrv.openSession(oMachine)
+ fRc = True
+
+ sNewLoc = sBaseLoc + os.sep
+
+ dsReferenceFiles = defaultdict(set)
+
+ #
+ # 1. case:
+ #
+ # All disks attached to VM are located outside the VM's folder.
+ # There are no any snapshots and logs.
+ # In this case only VM setting file should be moved (.vbox file)
+ #
+ reporter.log("Scenario #1:");
+ for s in self.asImagesNames:
+ reporter.log('"%s"' % (s,))
+ dsReferenceFiles['StandardImage'].add(os.path.normcase(os.path.join(sOrigLoc, s)))
+
+ sSettingFile = os.path.normcase(os.path.join(sNewLoc, os.path.join(oMachine.name, oMachine.name + '.vbox')))
+ dsReferenceFiles['SettingsFile'].add(sSettingFile)
+
+ fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine)
+
+ if fRc is True:
+ fRc = self.checkLocation(oSession.o.machine, dsReferenceFiles)
+ if fRc is False:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 1st scenario: Check locations failed... !!!!!!!!!!!!!!!!!!')
+ return False;
+ else:
+ reporter.testFailure('!!!!!!!!!!!!!!!!!! 1st scenario: Move VM failed... !!!!!!!!!!!!!!!!!!')
+ return False;
+
+ fRc = oSession.saveSettings()
+ if fRc is False:
+ reporter.testFailure('1st scenario: Couldn\'t save machine settings')
+
+ #
+ # 2. case:
+ #
+ # All disks attached to VM are located inside the VM's folder.
+ # There are no any snapshots and logs.
+ #
+ reporter.log("Scenario #2:");
+ sOldLoc = sNewLoc + oMachine.name + os.sep
+ sNewLoc = os.path.join(sOrigLoc, 'moveFolder_2nd_scenario')
+ os.mkdir(sNewLoc, 0o775)
+
+ fRc = self.__testScenario_2(oSession, oMachine, sNewLoc, sOldLoc)
+ if fRc is False:
+ return False;
+
+ #
+ # 3. case:
+ #
+ # There are snapshots.
+ #
+ reporter.log("Scenario #3:");
+ sOldLoc = sNewLoc + oMachine.name + os.sep
+ sNewLoc = os.path.join(sOrigLoc, 'moveFolder_3rd_scenario')
+ os.mkdir(sNewLoc, 0o775)
+
+ fRc = self.__testScenario_3(oSession, oMachine, sNewLoc)
+ if fRc is False:
+ return False;
+
+ #
+ # 4. case:
+ #
+ # There are one or more save state files in the snapshots folder
+ # and some files in the logs folder.
+ # Here we run VM, next stop it in the "save" state.
+ # And next move VM
+ #
+ reporter.log("Scenario #4:");
+ sOldLoc = sNewLoc + oMachine.name + os.sep
+ sNewLoc = os.path.join(sOrigLoc, 'moveFolder_4th_scenario')
+ os.mkdir(sNewLoc, 0o775)
+
+ # Close Session object because after starting VM we get new instance of session
+ fRc = oSession.close() and fRc
+ if fRc is False:
+ reporter.log('Couldn\'t close machine session')
+
+ del oSession
+
+ fRc = self.__testScenario_4(oMachine, sNewLoc)
+ if fRc is False:
+ return False;
+
+ #
+ # 5. case:
+ #
+ # There is an ISO image (.iso) attached to the VM.
+ # Prerequisites - there is IDE Controller and there are no any images attached to it.
+ #
+ reporter.log("Scenario #5:");
+ sOldLoc = sNewLoc + os.sep + oMachine.name
+ sNewLoc = os.path.join(sOrigLoc, 'moveFolder_5th_scenario')
+ os.mkdir(sNewLoc, 0o775)
+ fRc = self.__testScenario_5(oMachine, sNewLoc, sOldLoc)
+ if fRc is False:
+ return False;
+
+ #
+ # 6. case:
+ #
+ # There is a floppy image (.img) attached to the VM.
+ # Prerequisites - there is Floppy Controller and there are no any images attached to it.
+ #
+ reporter.log("Scenario #6:");
+ sOldLoc = sNewLoc + os.sep + oMachine.name
+ sNewLoc = os.path.join(sOrigLoc, 'moveFolder_6th_scenario')
+ os.mkdir(sNewLoc, 0o775)
+ fRc = self.__testScenario_6(oMachine, sNewLoc, sOldLoc)
+ if fRc is False:
+ return False;
+
+# #
+# # 7. case:
+# #
+# # There are shareable disk and immutable disk attached to the VM.
+# #
+# reporter.log("Scenario #7:");
+# fRc = fRc and oSession.saveSettings()
+# if fRc is False:
+# reporter.log('Couldn\'t save machine settings')
+#
+
+ assert fRc is True
+ except:
+ reporter.errorXcpt()
+
+ return fRc;
+
+
+if __name__ == '__main__':
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+ from tdApi1 import tdApi1; # pylint: disable=relative-import
+ sys.exit(tdApi1([SubTstDrvMoveVm1]).main(sys.argv))
+
diff --git a/src/VBox/ValidationKit/tests/api/tdPython1.py b/src/VBox/ValidationKit/tests/api/tdPython1.py
new file mode 100755
index 00000000..dd9dffc7
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdPython1.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# $Id: tdPython1.py $
+
+"""
+VirtualBox Validation Kit - Python Bindings Test #1
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2010-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 155244 $"
+
+
+# Standard Python imports.
+import os
+import sys
+import time
+import threading
+
+# Only the main script needs to modify the path.
+try: __file__
+except: __file__ = sys.argv[0];
+g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
+sys.path.append(g_ksValidationKitDir);
+
+# Validation Kit imports.
+from testdriver import base;
+from testdriver import reporter;
+
+
+class SubTstDrvPython1(base.SubTestDriverBase):
+ """
+ Sub-test driver for Python Bindings Test #1.
+ """
+
+ def __init__(self, oTstDrv):
+ base.SubTestDriverBase.__init__(self, oTstDrv, 'python-binding', 'Python bindings');
+
+ def testIt(self):
+ """
+ Execute the sub-testcase.
+ """
+ return self.testEventQueueWaiting() \
+ and self.testEventQueueInterrupt();
+
+ #
+ # Test execution helpers.
+ #
+
+ def testEventQueueWaitingThreadProc(self):
+ """ Thread procedure for checking that waitForEvents fails when not called by the main thread. """
+ try:
+ rc2 = self.oTstDrv.oVBoxMgr.waitForEvents(0);
+ except:
+ return True;
+ reporter.error('waitForEvents() returned "%s" when called on a worker thread, expected exception.' % (rc2,));
+ return False;
+
+ def testEventQueueWaiting(self):
+ """
+ Test event queue waiting.
+ """
+ reporter.testStart('waitForEvents');
+
+ # Check return values and such.
+ for cMsTimeout in (0, 1, 2, 3, 256, 1000, 0):
+ iLoop = 0;
+ while True:
+ try:
+ rc = self.oTstDrv.oVBoxMgr.waitForEvents(cMsTimeout);
+ except:
+ reporter.errorXcpt();
+ break;
+ if not isinstance(rc, int):
+ reporter.error('waitForEvents returns non-integer type');
+ break;
+ if rc == 1:
+ break;
+ if rc != 0:
+ reporter.error('waitForEvents returns "%s", expected 0 or 1' % (rc,));
+ break;
+ iLoop += 1;
+ if iLoop > 10240:
+ reporter.error('waitForEvents returns 0 (success) %u times. '
+ 'Expected 1 (timeout/interrupt) after a call or two.'
+ % (iLoop,));
+ break;
+ if reporter.testErrorCount() != 0:
+ break;
+
+ # Check that we get an exception when trying to call the method from
+ # a different thread.
+ reporter.log('If running a debug build, you will see an ignored assertion now. Please ignore it.')
+ sVBoxAssertSaved = os.environ.get('VBOX_ASSERT', 'breakpoint');
+ os.environ['VBOX_ASSERT'] = 'ignore';
+ oThread = threading.Thread(target=self.testEventQueueWaitingThreadProc);
+ oThread.start();
+ oThread.join();
+ os.environ['VBOX_ASSERT'] = sVBoxAssertSaved;
+
+ return reporter.testDone()[1] == 0;
+
+ def interruptWaitEventsThreadProc(self):
+ """ Thread procedure that's used for waking up the main thread. """
+ time.sleep(2);
+ try:
+ rc2 = self.oTstDrv.oVBoxMgr.interruptWaitEvents();
+ except:
+ reporter.errorXcpt();
+ else:
+ if rc2 is True:
+ return True;
+ reporter.error('interruptWaitEvents returned "%s" when called from other thread, expected True' % (rc2,));
+ return False;
+
+ def testEventQueueInterrupt(self):
+ """
+ Test interrupting an event queue wait.
+ """
+ reporter.testStart('interruptWait');
+
+ # interrupt ourselves first and check the return value.
+ for i in range(0, 10):
+ try:
+ rc = self.oTstDrv.oVBoxMgr.interruptWaitEvents();
+ except:
+ reporter.errorXcpt();
+ break;
+ if rc is not True:
+ reporter.error('interruptWaitEvents returned "%s" expected True' % (rc,));
+ break
+
+ if reporter.testErrorCount() == 0:
+ #
+ # Interrupt a waitForEvents call.
+ #
+ # This test ASSUMES that no other events are posted to the thread's
+ # event queue once we've drained it. Also ASSUMES the box is
+ # relatively fast and not too busy because we're timing sensitive.
+ #
+ for i in range(0, 4):
+ # Try quiesce the event queue.
+ for _ in range(1, 100):
+ self.oTstDrv.oVBoxMgr.waitForEvents(0);
+
+ # Create a thread that will interrupt us in 2 seconds.
+ try:
+ oThread = threading.Thread(target=self.interruptWaitEventsThreadProc);
+ oThread.setDaemon(False); # pylint: disable=deprecated-method
+ except:
+ reporter.errorXcpt();
+ break;
+
+ cMsTimeout = 20000;
+ if i == 2:
+ cMsTimeout = -1;
+ elif i == 3:
+ cMsTimeout = -999999;
+
+ # Do the wait.
+ oThread.start();
+ msNow = base.timestampMilli();
+ try:
+ rc = self.oTstDrv.oVBoxMgr.waitForEvents(cMsTimeout);
+ except:
+ reporter.errorXcpt();
+ else:
+ msElapsed = base.timestampMilli() - msNow;
+
+ # Check the return code and elapsed time.
+ if not isinstance(rc, int):
+ reporter.error('waitForEvents returns non-integer type after %u ms, expected 1' % (msElapsed,));
+ elif rc != 1:
+ reporter.error('waitForEvents returned "%s" after %u ms, expected 1' % (rc, msElapsed));
+ if msElapsed > 15000:
+ reporter.error('waitForEvents after %u ms, expected just above 2-3 seconds' % (msElapsed,));
+ elif msElapsed < 100:
+ reporter.error('waitForEvents after %u ms, expected more than 100 ms.' % (msElapsed,));
+
+ oThread.join();
+ oThread = None;
+ if reporter.testErrorCount() != 0:
+ break;
+ reporter.log('Iteration %u was successful...' % (i + 1,));
+ return reporter.testDone()[1] == 0;
+
+
+if __name__ == '__main__':
+ from tests.api.tdApi1 import tdApi1;
+ sys.exit(tdApi1([SubTstDrvPython1]).main(sys.argv));
+
diff --git a/src/VBox/ValidationKit/tests/api/tdTreeDepth1.py b/src/VBox/ValidationKit/tests/api/tdTreeDepth1.py
new file mode 100755
index 00000000..e69a7d17
--- /dev/null
+++ b/src/VBox/ValidationKit/tests/api/tdTreeDepth1.py
@@ -0,0 +1,249 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# $Id: tdTreeDepth1.py $
+
+"""
+VirtualBox Validation Kit - Medium and Snapshot Tree Depth Test #1
+"""
+
+__copyright__ = \
+"""
+Copyright (C) 2010-2023 Oracle and/or its affiliates.
+
+This file is part of VirtualBox base platform packages, as
+available from https://www.virtualbox.org.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation, in version 3 of the
+License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see <https://www.gnu.org/licenses>.
+
+The contents of this file may alternatively be used under the terms
+of the Common Development and Distribution License Version 1.0
+(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+in the VirtualBox distribution, in which case the provisions of the
+CDDL are applicable instead of those of the GPL.
+
+You may elect to license modified versions of this file under the
+terms and conditions of either the GPL or the CDDL or both.
+
+SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+"""
+__version__ = "$Revision: 156148 $"
+
+
+# Standard Python imports.
+import os
+import sys
+import random
+
+# Only the main script needs to modify the path.
+try: __file__
+except: __file__ = sys.argv[0]
+g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.append(g_ksValidationKitDir)
+
+# Validation Kit imports.
+from testdriver import base
+from testdriver import reporter
+from testdriver import vboxcon
+
+
+class SubTstDrvTreeDepth1(base.SubTestDriverBase):
+ """
+ Sub-test driver for Medium and Snapshot Tree Depth Test #1.
+ """
+
+ def __init__(self, oTstDrv):
+ base.SubTestDriverBase.__init__(self, oTstDrv, 'tree-depth', 'Media and Snapshot tree depths');
+
+ def testIt(self):
+ """
+ Execute the sub-testcase.
+ """
+ return self.testMediumTreeDepth() \
+ and self.testSnapshotTreeDepth()
+
+ #
+ # Test execution helpers.
+ #
+
+ def testMediumTreeDepth(self):
+ """
+ Test medium tree depth.
+ """
+ reporter.testStart('mediumTreeDepth')
+
+ try:
+ oVBox = self.oTstDrv.oVBoxMgr.getVirtualBox()
+ oVM = self.oTstDrv.createTestVM('test-medium', 1, None, 4)
+ assert oVM is not None
+
+ # create chain with up to 64 disk images (medium tree depth limit)
+ fRc = True
+ oSession = self.oTstDrv.openSession(oVM)
+ cImages = random.randrange(1, 64);
+ reporter.log('Creating chain with %d disk images' % (cImages))
+ for i in range(1, cImages + 1):
+ sHddPath = os.path.join(self.oTstDrv.sScratchPath, 'Test' + str(i) + '.vdi')
+ if i == 1:
+ oHd = oSession.createBaseHd(sHddPath, cb=1024*1024)
+ else:
+ oHd = oSession.createDiffHd(oHd, sHddPath)
+ if oHd is None:
+ fRc = False
+ break
+
+ # modify the VM config, attach HDD
+ fRc = fRc and oSession.attachHd(sHddPath, sController='SATA Controller', fImmutable=False, fForceResource=False)
+ fRc = fRc and oSession.saveSettings()
+ fRc = oSession.close() and fRc
+ ## @todo r=klaus: count known hard disk images, should be cImages
+
+ # unregister, making sure the images are closed
+ sSettingsFile = oVM.settingsFilePath
+ fDetachAll = random.choice([False, True])
+ if fDetachAll:
+ reporter.log('unregistering VM, DetachAll style')
+ else:
+ reporter.log('unregistering VM, UnregisterOnly style')
+ self.oTstDrv.forgetTestMachine(oVM)
+ if fDetachAll:
+ aoHDs = oVM.unregister(vboxcon.CleanupMode_DetachAllReturnHardDisksOnly)
+ for oHD in aoHDs:
+ oHD.close()
+ aoHDs = None
+ else:
+ oVM.unregister(vboxcon.CleanupMode_UnregisterOnly)
+ oVM = None
+
+ # If there is no base image (expected) then there are no leftover
+ # child images either. Can be changed later once the todos above
+ # and below are resolved.
+ cBaseImages = len(self.oTstDrv.oVBoxMgr.getArray(oVBox, 'hardDisks'))
+ reporter.log('API reports %i base images' % (cBaseImages))
+ fRc = fRc and cBaseImages == 0
+ if cBaseImages != 0:
+ reporter.error('Got %d initial base images, expected %d' % (cBaseImages, 0));
+
+ # re-register to test loading of settings
+ reporter.log('opening VM %s, testing config reading' % (sSettingsFile))
+ if self.oTstDrv.fpApiVer >= 7.0:
+ # Needs a password parameter since 7.0.
+ oVM = oVBox.openMachine(sSettingsFile, "")
+ else:
+ oVM = oVBox.openMachine(sSettingsFile)
+ oVBox.registerMachine(oVM);
+ ## @todo r=klaus: count known hard disk images, should be cImages
+
+ reporter.log('unregistering VM')
+ oVM.unregister(vboxcon.CleanupMode_UnregisterOnly)
+ oVM = None
+
+ cBaseImages = len(self.oTstDrv.oVBoxMgr.getArray(oVBox, 'hardDisks'))
+ reporter.log('API reports %i base images' % (cBaseImages))
+ fRc = fRc and cBaseImages == 0
+ if cBaseImages != 0:
+ reporter.error('Got %d base images after unregistering, expected %d' % (cBaseImages, 0));
+
+ except:
+ reporter.errorXcpt()
+
+ return reporter.testDone()[1] == 0
+
+ def testSnapshotTreeDepth(self):
+ """
+ Test snapshot tree depth.
+ """
+ reporter.testStart('snapshotTreeDepth')
+
+ try:
+ oVBox = self.oTstDrv.oVBoxMgr.getVirtualBox()
+ oVM = self.oTstDrv.createTestVM('test-snap', 1, None, 4)
+ assert oVM is not None
+
+ # modify the VM config, create and attach empty HDD
+ oSession = self.oTstDrv.openSession(oVM)
+ sHddPath = os.path.join(self.oTstDrv.sScratchPath, 'TestSnapEmpty.vdi')
+ fRc = True
+ fRc = fRc and oSession.createAndAttachHd(sHddPath, cb=1024*1024, sController='SATA Controller', fImmutable=False)
+ fRc = fRc and oSession.saveSettings()
+
+ # take up to 200 snapshots (250 is the snapshot tree depth limit (settings.h:SETTINGS_SNAPSHOT_DEPTH_MAX))
+ cSnapshots = random.randrange(1, 200);
+ reporter.log('Taking %d snapshots' % (cSnapshots))
+ for i in range(1, cSnapshots + 1):
+ fRc = fRc and oSession.takeSnapshot('Snapshot ' + str(i))
+ fRc = oSession.close() and fRc
+ oSession = None
+ reporter.log('API reports %i snapshots' % (oVM.snapshotCount))
+ fRc = fRc and oVM.snapshotCount == cSnapshots
+ if oVM.snapshotCount != cSnapshots:
+ reporter.error('Got %d initial snapshots, expected %d' % (oVM.snapshotCount, cSnapshots));
+
+ # unregister, making sure the images are closed
+ sSettingsFile = oVM.settingsFilePath
+ fDetachAll = random.choice([False, True])
+ if fDetachAll:
+ reporter.log('unregistering VM, DetachAll style')
+ else:
+ reporter.log('unregistering VM, UnregisterOnly style')
+ self.oTstDrv.forgetTestMachine(oVM)
+ if fDetachAll:
+ aoHDs = oVM.unregister(vboxcon.CleanupMode_DetachAllReturnHardDisksOnly)
+ for oHD in aoHDs:
+ oHD.close()
+ aoHDs = None
+ else:
+ oVM.unregister(vboxcon.CleanupMode_UnregisterOnly)
+ oVM = None
+
+ # If there is no base image (expected) then there are no leftover
+ # child images either. Can be changed later once the todos above
+ # and below are resolved.
+ cBaseImages = len(self.oTstDrv.oVBoxMgr.getArray(oVBox, 'hardDisks'))
+ reporter.log('API reports %i base images' % (cBaseImages))
+ fRc = fRc and cBaseImages == 0
+ if cBaseImages != 0:
+ reporter.error('Got %d initial base images, expected %d' % (cBaseImages, 0));
+
+ # re-register to test loading of settings
+ reporter.log('opening VM %s, testing config reading' % (sSettingsFile))
+ if self.oTstDrv.fpApiVer >= 7.0:
+ # Needs a password parameter since 7.0.
+ oVM = oVBox.openMachine(sSettingsFile, "")
+ else:
+ oVM = oVBox.openMachine(sSettingsFile)
+ oVBox.registerMachine(oVM);
+ reporter.log('API reports %i snapshots' % (oVM.snapshotCount))
+ fRc = fRc and oVM.snapshotCount == cSnapshots
+ if oVM.snapshotCount != cSnapshots:
+ reporter.error('Got %d snapshots after re-registering, expected %d' % (oVM.snapshotCount, cSnapshots));
+
+ reporter.log('unregistering VM')
+ oVM.unregister(vboxcon.CleanupMode_UnregisterOnly)
+ oVM = None
+
+ cBaseImages = len(self.oTstDrv.oVBoxMgr.getArray(oVBox, 'hardDisks'))
+ reporter.log('API reports %i base images' % (cBaseImages))
+ fRc = fRc and cBaseImages == 0
+ if cBaseImages != 0:
+ reporter.error('Got %d base images after unregistering, expected %d' % (cBaseImages, 0));
+ except:
+ reporter.errorXcpt()
+
+ return reporter.testDone()[1] == 0
+
+
+if __name__ == '__main__':
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+ from tdApi1 import tdApi1; # pylint: disable=relative-import
+ sys.exit(tdApi1([SubTstDrvTreeDepth1]).main(sys.argv))