diff options
Diffstat (limited to 'src/VBox/Main/testcase')
30 files changed, 9937 insertions, 0 deletions
diff --git a/src/VBox/Main/testcase/Makefile.kmk b/src/VBox/Main/testcase/Makefile.kmk new file mode 100644 index 00000000..d2fb9a72 --- /dev/null +++ b/src/VBox/Main/testcase/Makefile.kmk @@ -0,0 +1,343 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the VBox API testcases. +# + +# +# Copyright (C) 2004-2022 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>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk + + +# +# Target and globals (small mess) +# +ifndef VBOX_ONLY_SDK + if defined(VBOX_WITH_TESTCASES) + PROGRAMS += \ + tstAPI \ + tstVBoxAPI \ + tstVBoxAPIPerf \ + tstVBoxMultipleVM \ + $(if $(VBOX_OSE),,tstOVF) \ + $(if $(VBOX_WITH_XPCOM),tstVBoxAPIXPCOM,tstVBoxAPIWin msiDarwinDescriptorDecoder) \ + $(if $(VBOX_WITH_RESOURCE_USAGE_API),tstCollector,) \ + $(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlContextID,) \ + $(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlParseBuffer,) \ + $(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlPaths,) \ + tstMediumLock \ + tstBstr \ + tstGuid \ + tstUnattendedScript \ + tstVBoxCrypto + PROGRAMS.linux += \ + $(if $(VBOX_WITH_USB),tstUSBProxyLinux,) + endif # !VBOX_WITH_TESTCASES +endif # !VBOX_ONLY_SDK +if defined(VBOX_ONLY_SDK) || !defined(VBOX_WITH_XPCOM) + INSTALLS += samplesMSCOM +endif +if defined(VBOX_ONLY_SDK) || defined(VBOX_WITH_XPCOM) + INSTALLS += samplesXPCOM +endif + + +# +# The samples +# +samplesMSCOM_MODE = a+r,u+w +samplesMSCOM_INST = $(INST_SDK)bindings/mscom/samples/ +samplesMSCOM_SOURCES = tstVBoxAPIWin.cpp makefile.tstVBoxAPIWin=>Makefile + +samplesXPCOM_MODE = a+r,u+w +samplesXPCOM_INST = $(INST_SDK)bindings/xpcom/samples/ +samplesXPCOM_SOURCES = tstVBoxAPIXPCOM.cpp makefile.tstVBoxAPIXPCOM=>Makefile + +# +# tstVBoxMultipleVM +# +tstVBoxMultipleVM_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstVBoxMultipleVM_SOURCES = tstVBoxMultipleVM.cpp + +# +# tstAPI +# +tstAPI_TEMPLATE = VBOXMAINCLIENTTSTEXE +#tstAPI_INST = $(INST_SDK)bindings/gluecom/samples/ +tstAPI_SOURCES = tstAPI.cpp + +# +# tstVBoxAPI +# +tstVBoxAPI_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstVBoxAPI_SOURCES = \ + tstVBoxAPI.cpp + +# +# tstVBoxAPIPerf +# +tstVBoxAPIPerf_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstVBoxAPIPerf_SOURCES = \ + tstVBoxAPIPerf.cpp + +# +# tstOVF +# +tstOVF_TEMPLATE = VBOXMAINCLIENTTSTEXE +#tstOVF_INST = $(INST_SDK)bindings/gluecom/samples/ +tstOVF_SOURCES = tstOVF.cpp + +ifndef VBOX_OSE +# +# OVF test data. +# +INSTALLS += ovf-testcases +ovf-testcases_MODE = a+r,u+w +ovf-testcases_INST = $(INST_TESTCASE)ovf-testcases/ +ovf-testcases_SOURCES = \ + ovf-dummy.vmdk \ + ovf-joomla-0.9/joomla-1.1.4-ovf.ovf=>ovf-joomla-0.9/joomla-1.1.4-ovf.ovf \ + ovf-winhost-audio-nodisks/WinXP.ovf=>ovf-winhost-audio-nodisks/WinXP.ovf \ + ovf-winxp-vbox-sharedfolders/winxp.ovf=>ovf-winxp-vbox-sharedfolders/winxp.ovf +endif + + +# +# tstVBoxAPIXPCOM +# +# We only build the testcase here to make sure it builds. +# It comes with a custom makefile which should be tested as well! +# +# Use very generic template to make the build environment similar +# to the standalone case, to detect if IPRT or glue use sneaks in. +# +tstVBoxAPIXPCOM_TEMPLATE = VBOXR3EXE +tstVBoxAPIXPCOM_INST = $(INST_TESTCASE) +tstVBoxAPIXPCOM_SOURCES = tstVBoxAPIXPCOM.cpp +tstVBoxAPIXPCOM_INCS = \ + $(VBOX_PATH_SDK)/bindings/xpcom/include \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/nsprpub \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/string \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/xpcom \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/ipcd +tstVBoxAPIXPCOM_LIBS = \ + $(LIB_XPCOM) \ + $(LIB_RUNTIME) +tstVBoxAPIXPCOM_CXXFLAGS = -fshort-wchar +ifdef VBOX_WITH_RUNPATH + tstVBoxAPIXPCOM_LDFLAGS = '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RUNPATH)' $(TEMPLATE_VBoxBldProg_LDFLAGS) +else ifdef VBOX_WITH_RELATIVE_RUNPATH + tstVBoxAPIXPCOM_LDFLAGS = '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RELATIVE_RUNPATH)/..' $(TEMPLATE_VBoxBldProg_LDFLAGS) +endif +tstVBoxAPIXPCOM_INTERMEDIATES = \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h +ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + tstVBoxAPIXPCOM_DEFS += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +endif + + +# +# tstVBoxAPIWin +# +# Use very generic template to make the build environment similar +# to the standalone case, to detect if IPRT or glue use sneaks in. +# +tstVBoxAPIWin_TEMPLATE = VBOXR3EXE +tstVBoxAPIWin_INST = $(INST_TESTCASE) +tstVBoxAPIWin_SOURCES = \ + tstVBoxAPIWin.cpp \ + $(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c +tstVBoxAPIWin_INCS = \ + $(VBOX_PATH_SDK)/bindings/mscom/include +tstVBoxAPIWin_INTERMEDIATES = \ + $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h + + +# +# msiDarwinDescriptorDecoder +# +# Use very generic template to make the build environment similar +# to the standalone case, to detect if IPRT or glue use sneaks in. +# +msiDarwinDescriptorDecoder_TEMPLATE = VBOXR3EXE +msiDarwinDescriptorDecoder_INST = $(VBOX_INST_TOOLS) +msiDarwinDescriptorDecoder_SOURCES = \ + msiDarwinDescriptorDecoder.cpp + + +# +# tstCollector +# +# Note! VBOX_MAIN_APIWRAPPER_GEN_HDRS is only defined if kmk is executed a +# parent directory. Since the rules for generating the files listed by +# the variable lives in the parent makefile, this is not a problem. +# +tstCollector_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstCollector_SOURCES = \ + tstCollector.cpp \ + ../src-server/Performance.cpp +tstCollector_INCS = \ + ../include \ + $(VBOX_MAIN_APIWRAPPER_INCS) +tstCollector_INTERMEDIATES = $(VBOX_MAIN_APIWRAPPER_GEN_HDRS) +tstCollector_DEFS = VBOX_COLLECTOR_TEST_CASE +tstCollector_LDFLAGS.darwin = -lproc +tstCollector_LDFLAGS.solaris = -lkstat -lnvpair +tstCollector_LDFLAGS.win = psapi.lib powrprof.lib + + +# +# tstGuestCtrlContextID +# +tstGuestCtrlContextID_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstGuestCtrlContextID_INTERMEDIATES = $(VBOX_MAIN_APIWRAPPER_GEN_HDRS) +tstGuestCtrlContextID_DEFS += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE +tstGuestCtrlContextID_SOURCES = \ + tstGuestCtrlContextID.cpp \ + ../src-client/GuestCtrlPrivate.cpp +tstGuestCtrlContextID_INCS = ../include \ + $(VBOX_MAIN_APIWRAPPER_INCS) + + +# +# tstGuestCtrlParseBuffer +# +tstGuestCtrlParseBuffer_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstGuestCtrlParseBuffer_INTERMEDIATES = $(VBOX_MAIN_APIWRAPPER_GEN_HDRS) +tstGuestCtrlParseBuffer_DEFS += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE +tstGuestCtrlParseBuffer_SOURCES = \ + tstGuestCtrlParseBuffer.cpp \ + ../src-client/GuestCtrlPrivate.cpp +tstGuestCtrlParseBuffer_INCS = ../include \ + $(VBOX_MAIN_APIWRAPPER_INCS) + + +# +# tstGuestCtrlPaths +# +tstGuestCtrlPaths_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstGuestCtrlPaths_INTERMEDIATES = $(VBOX_MAIN_APIWRAPPER_GEN_HDRS) +tstGuestCtrlPaths_DEFS += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE +tstGuestCtrlPaths_SOURCES = \ + tstGuestCtrlPaths.cpp \ + ../src-client/GuestCtrlPrivate.cpp +tstGuestCtrlPaths_INCS = ../include \ + $(VBOX_MAIN_APIWRAPPER_INCS) + +if 0 # Enable this if you want automatic runs after compilation. + $$(tstGuestCtrlPaths_0_OUTDIR)/tstGuestCtrlPaths.run: $$(tstGuestCtrlPaths_1_STAGE_TARGET) + export VBOX_LOG_DEST=nofile; $(tstGuestCtrlPaths_1_STAGE_TARGET) quiet + $(QUIET)$(APPEND) -t "$@" "done" + OTHERS += $(tstGuestCtrlPaths_0_OUTDIR)/tstGuestCtrlPaths.run +endif + + +# +# tstUSBProxyLinux +# +tstUSBProxyLinux_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstUSBProxyLinux_INTERMEDIATES = $(VBOX_MAIN_APIWRAPPER_GEN_HDRS) +tstUSBProxyLinux_SOURCES = \ + tstUSBProxyLinux.cpp \ + ../src-server/linux/USBGetDevices.cpp +tstUSBProxyLinux_INCS = \ + . \ + ../include \ + $(VBOX_PATH_SDK)/bindings/xpcom/include \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/nsprpub \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/xpcom \ + $(VBOX_MAIN_APIWRAPPER_INCS) +tstUSBProxyLinux_DEFS = \ + UNIT_TEST \ + VBOX_WITH_USB \ + VBOX_USB_WITH_SYSFS \ + VBOX_WITH_XPCOM +tstUSBProxyLinux_DEPS = \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h +tstUSBProxyLinux_LIBS += \ + $(PATH_OUT)/lib/USBLib.a \ + $(PATH_OUT)/lib/VBoxCOM.a + + +# +# tstMediumLock +# +tstMediumLock_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstMediumLock_SOURCES = tstMediumLock.cpp + + +# +# tstBstr +# +tstBstr_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstBstr_SOURCES = tstBstr.cpp + + +# +# tstGuid +# +tstGuid_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstGuid_SOURCES = tstGuid.cpp + + +# +# tstUnattendedScript +# +tstUnattendedScript_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstUnattendedScript_DEFS = VBOX_WITH_UNATTENDED IN_VBOXSVC IN_TST_UNATTENDED_SCRIPT +tstUnattendedScript_INTERMEDIATES = \ + $(VBOX_MAIN_APIWRAPPER_GEN_HDRS) \ + $(VBOX_XML_SCHEMADEFS_H) +tstUnattendedScript_INCS = \ + ../include \ + $(VBOX_MAIN_APIWRAPPER_INCS) \ + $(dir $(VBOX_XML_SCHEMADEFS_H)) +tstUnattendedScript_SOURCES = \ + tstUnattendedScript.cpp \ + ../src-server/UnattendedScript.cpp \ + ../src-all/TextScript.cpp \ + ../src-all/VirtualBoxBase.cpp \ + ../src-all/VirtualBoxErrorInfoImpl.cpp \ + ../src-all/AutoCaller.cpp \ + ../src-all/GlobalStatusConversion.cpp +tstUnattendedScript_LIBS = \ + $(PATH_STAGE_LIB)/VBoxAPIWrap$(VBOX_SUFF_LIB) + +INSTALLS += tstUnattendedScriptFiles +tstUnattendedScriptFiles_TEMPLATE = VBOXMAINTSTEXE +tstUnattendedScriptFiles_SOURCES = \ + tstUnattendedScript-1.template \ + tstUnattendedScript-1.expected + + +# +# tstVBoxCrypto +# +tstVBoxCrypto_TEMPLATE = VBOXMAINCLIENTTSTEXE +tstVBoxCrypto_SOURCES = tstVBoxCrypto.cpp + + + +# generate rules. +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/Main/testcase/VBoxVBTest/TestForm.frm b/src/VBox/Main/testcase/VBoxVBTest/TestForm.frm new file mode 100644 index 00000000..3ba63c8f --- /dev/null +++ b/src/VBox/Main/testcase/VBoxVBTest/TestForm.frm @@ -0,0 +1,137 @@ +VERSION 5.00 +Begin VB.Form TestForm + Caption = "VirtualBox Test" + ClientHeight = 4692 + ClientLeft = 60 + ClientTop = 348 + ClientWidth = 6972 + LinkTopic = "TestForm" + ScaleHeight = 4692 + ScaleWidth = 6972 + StartUpPosition = 3 'Windows Default + Begin VB.ListBox machineList + Height = 2352 + ItemData = "TestForm.frx":0000 + Left = 240 + List = "TestForm.frx":0007 + TabIndex = 4 + Top = 2040 + Width = 6492 + End + Begin VB.CommandButton getMachieListCmd + Caption = "Get Machine List" + Height = 372 + Left = 2640 + TabIndex = 0 + Top = 720 + Width = 1692 + End + Begin VB.Label Label3 + AutoSize = -1 'True + Caption = "Registered Machines:" + Height = 192 + Left = 240 + TabIndex = 5 + Top = 1680 + Width = 1572 + End + Begin VB.Label versionLabel + AutoSize = -1 'True + Caption = "<none>" + Height = 192 + Left = 1680 + TabIndex = 3 + Top = 1320 + Width = 528 + End + Begin VB.Label Label2 + AutoSize = -1 'True + Caption = "VirtualBox Version:" + Height = 252 + Left = 240 + TabIndex = 2 + Top = 1320 + Width = 1344 + End + Begin VB.Label Label1 + Alignment = 2 'Center + Caption = $"TestForm.frx":0013 + Height = 372 + Left = 240 + TabIndex = 1 + Top = 120 + Width = 6492 + WordWrap = -1 'True + End +End +Attribute VB_Name = "TestForm" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = True +Attribute VB_Exposed = False + +Private Declare Function SetEnvironmentVariable Lib "kernel32" _ + Alias "SetEnvironmentVariableA" (ByVal lpName As String, ByVal lpValue As String) As Long +Private Declare Function GetEnvironmentVariable Lib "kernel32" _ + Alias "GetEnvironmentVariableA" (ByVal lpName As String, ByVal lpValue As String, ByVal nSize As Long) As Long + +Private Sub Form_Load() + + ' Set where to take VirtualBox configuration from + + 'SetEnvironmentVariable "VBOX_USER_HOME", "E:\VirtualBoxHome\win" + + ' Setup debug logging (available only in debug builds) + + 'PATH_OUT_BASE = "D:/Coding/innotek/vbox/out" + + 'SetEnvironmentVariable "VBOX_LOG", "main.e.l.f + gui.e.l.f" + 'SetEnvironmentVariable "VBOX_LOG_FLAGS", "time tid thread" + 'SetEnvironmentVariable "VBOX_LOG_DEST", "dir:" + PATH_OUT_BASE + "/logs" + +End Sub + +Private Sub getMachieListCmd_Click() + + ' Clear the old list contents + + machineList.Clear + machineList.Refresh + + versionLabel.Caption = "<none>" + + ' Disable the button and the list for the duration of the call + + getMachieListCmd.Enabled = False + machineList.Enabled = False + + ' Obtain the global VirtualBox object (this will start + ' the VirtualBox server if it is not already started) + + Dim vbox As VirtualBox.VirtualBox + Set vbox = New VirtualBox.VirtualBox + + ' Get the VirtualBox server version + + versionLabel.Caption = vbox.Version + + ' Obtain a list of registered machines + + Dim machines() As VirtualBox.IMachine + machines = vbox.Machines2 + + If UBound(machines) < 0 Then + machineList.AddItem ("<none>") + Else + For i = 0 To UBound(machines) + Item = machines(i).Name + " (" + machines(i).OSTypeId() + ")" + machineList.AddItem (Item) + Next i + End If + + ' Reenable the button and the list + + getMachieListCmd.Enabled = True + machineList.Enabled = True + +End Sub diff --git a/src/VBox/Main/testcase/VBoxVBTest/TestForm.frx b/src/VBox/Main/testcase/VBoxVBTest/TestForm.frx Binary files differnew file mode 100644 index 00000000..bd27fb45 --- /dev/null +++ b/src/VBox/Main/testcase/VBoxVBTest/TestForm.frx diff --git a/src/VBox/Main/testcase/VBoxVBTest/VBoxVBTest.vbp b/src/VBox/Main/testcase/VBoxVBTest/VBoxVBTest.vbp new file mode 100644 index 00000000..cdc19c8a --- /dev/null +++ b/src/VBox/Main/testcase/VBoxVBTest/VBoxVBTest.vbp @@ -0,0 +1,34 @@ +Type=Exe +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINDOWS\system32\stdole2.tlb#OLE Automation +Reference=*\G{D7569351-1750-46F0-936E-BD127D5BC264}#1.3#0#VBoxC.dll#InnoTek VirtualBox Machine Type Library +Form=TestForm.frm +Startup="TestForm" +ExeName32="VBoxVBTest.exe" +Command32="" +Name="VBoxVBTest" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="Something" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/src/VBox/Main/testcase/makefile.tstVBoxAPIWin b/src/VBox/Main/testcase/makefile.tstVBoxAPIWin new file mode 100644 index 00000000..af8299d3 --- /dev/null +++ b/src/VBox/Main/testcase/makefile.tstVBoxAPIWin @@ -0,0 +1,100 @@ +# $Id: makefile.tstVBoxAPIWin $ +## @file +# tstVBoxAPILinux makefile +# + +# +# Copyright (C) 2006-2022 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>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# +# Several assumptions and propositions: +# - Visual Studio has already installed on machine or you already have nmake.exe, cl.exe, link.exe +# - Windows SDK has already installed on machine or you already have Uuid.Lib Ole32.Lib OleAut32.Lib OleDlg.Lib +# - VirtualBox SDK was downloaded and was placed into folder where VirtualBox had been installed. +# - nmake is a default tool that builds projects based on commands contained in this description file +# - cl is cl.exe - Windows compiler +# - link is link.exe - Windows linker +# - all needed paths have been set in working environment. It means that when you type "cl" from the console, +# Windows shall find cl.exe by using enviroment variable PATH or something similar. +# +# The best way to accomplish it is to run a script vcvars32.bat located in the Visual studio "bin" directory. +# This script installs needed paths in your working environment. +# Important!!! +# Script vcvars32.bat sets up needed paths only for local console session. +# For permanent using, needed paths must be added globally. +# +# Several possible examples of paths: +# VS_INSTALL_PATH = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\" +# VS_INCLUDE_PATH = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include" +# WIN_SDK_INCLUDE_PATH = "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include" +# WIN_SDK_LIB_PATH = "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib\x64\" +# VB_INSTALL_PATH = "C:\Program Files\Oracle\VirtualBox" +# + + +CXX = cl +LINK = link +PATH_MSCOM = ../../../bindings/mscom +INCS_MSCOM = $(PATH_MSCOM)/include +LIBS_MSCOM = $(PATH_MSCOM)/lib + +LIBS_DEPS = "Uuid.Lib" "Ole32.Lib" "OleAut32.Lib" "OleDlg.Lib" + +tstVBoxAPIWin_SOURCES = $(LIBS_MSCOM)/VirtualBox_i.c +tstVBoxAPIWin_DEPS = $(INCS_MSCOM) + +COMPILER_CMDLINE = /Zi /nologo /W3 /WX- /Od /Oy- /Gm /EHsc /RTC1 /GS /fp:precise /Gd /analyze- /errorReport:queue + +LINKER_CMDLINE = /INCREMENTAL /DEBUG /SUBSYSTEM:CONSOLE + +# default linking +tstVBoxAPIWin.exe: tstVBoxAPIWin.obj VirtualBox_i.obj + $(LINK) /out:tstVBoxAPIWin.exe $** $(LIBS_DEPS) + +# default compilation +tstVBoxAPIWin.obj: + $(CXX) /c /I$(INCS_MSCOM) tstVBoxAPIWin.cpp + +# default compilation +VirtualBox_i.obj: + $(CXX) /c /I$(INCS_MSCOM) $(tstVBoxAPIWin_SOURCES) + +# linking with defined linker's options +#tstVBoxAPIWin.exe: tstVBoxAPIWin.obj VirtualBox_i.obj +# $(LINK) $(LINKER_CMDLINE) /out:tstVBoxAPIWin.exe $** $(LIBS_DEPS) + +# compile with pre-defined compiler's options and locally defined paths +#tstVBoxAPIWin.obj: +# $(CXX) /c $(COMPILER_CMDLINE) /I$(INCS_MSCOM) /I$(WIN_SDK_INCLUDE_PATH) /I$(VS_INCLUDE_PATH) tstVBoxAPIWin.cpp + +# compile with locally defined paths +#tstVBoxAPIWin.obj: +# $(CXX) /c /I$(INCS_MSCOM) /I$(WIN_SDK_INCLUDE_PATH) /I$(VS_INCLUDE_PATH) tstVBoxAPIWin.cpp + +# compile with pre-defined compiler's options and locally defined paths +#VirtualBox_i.obj: +# $(CXX) /c $(COMPILER_CMDLINE) /I$(INCS_MSCOM) /I$(WIN_SDK_INCLUDE_PATH) /I$(VS_INCLUDE_PATH) $(tstVBoxAPIWin_SOURCES) + +# compile with locally defined paths +#VirtualBox_i.obj: +# $(CXX) /c /I$(INCS_MSCOM) /I$(WIN_SDK_INCLUDE_PATH) /I$(VS_INCLUDE_PATH) $(tstVBoxAPIWin_SOURCES) + diff --git a/src/VBox/Main/testcase/makefile.tstVBoxAPIXPCOM b/src/VBox/Main/testcase/makefile.tstVBoxAPIXPCOM new file mode 100644 index 00000000..c91f5149 --- /dev/null +++ b/src/VBox/Main/testcase/makefile.tstVBoxAPIXPCOM @@ -0,0 +1,65 @@ +# $Id: makefile.tstVBoxAPIXPCOM $ +## @file +# tstVBoxAPIXPCOM makefile +# + +# +# Copyright (C) 2006-2022 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>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +PATH_XPCOM = .. +PATH_BIN = ../../../../ + +# This setting must be the same as used when building VBoxXPCOM.so. +# If you get a lot of unresolved symbols, try commenting it out. +VBOX_WITH_XPCOM_NAMESPACE_CLEANUP=1 + +PATH_XPCOM_IDL = $(PATH_XPCOM)/idl +INCS_XPCOM = $(PATH_XPCOM)/include \ + $(PATH_XPCOM)/include/nsprpub \ + $(PATH_XPCOM)/include/string \ + $(PATH_XPCOM)/include/xpcom \ + $(PATH_XPCOM)/include/ipcd + +ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + DEFS_XPCOM += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +endif + +# Adjust this to match your platform, pick from RT_OS_LINUX, RT_OS_WINDOWS, +# RT_OS_DARWIN, RT_OS_SOLARIS... +DEFS_XPCOM += RT_OS_LINUX + + +# +# Link with the public XPCOM libraries +# +tstVBoxAPIXPCOM: tstVBoxAPIXPCOM.o + g++ -g -o $@ $^ \ + $(PATH_BIN)/VBoxXPCOM.so \ + -Wl,-rpath $(PATH_BIN)/ \ + -ldl -lpthread + +tstVBoxAPIXPCOM.o: tstVBoxAPIXPCOM.cpp + g++ -c -g -fshort-wchar $(addprefix -I, $(INCS_XPCOM)) $(addprefix -D, $(DEFS_XPCOM)) -o $@ tstVBoxAPIXPCOM.cpp + +clean: + rm -f tstVBoxAPIXPCOM tstVBoxAPIXPCOM.o + diff --git a/src/VBox/Main/testcase/msiDarwinDescriptorDecoder.cpp b/src/VBox/Main/testcase/msiDarwinDescriptorDecoder.cpp new file mode 100644 index 00000000..f81aaab6 --- /dev/null +++ b/src/VBox/Main/testcase/msiDarwinDescriptorDecoder.cpp @@ -0,0 +1,81 @@ +/* $Id: msiDarwinDescriptorDecoder.cpp $ */ +/** @file + * msiDarwinDescriptorDecoder + */ + +/* + * Copyright (C) 2016-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +#include <stdio.h> +#include <iprt/win/windows.h> /* Avoid -Wall warnings. */ + + + +typedef DWORD (WINAPI *PFNMSIDECOMPOSEDESCRIPTORW)(PCWSTR pwszDescriptor, + LPWSTR pwszProductCode /*[40]*/, + LPWSTR pwszFeatureId /*[40]*/, + LPWSTR pwszComponentCode /*[40]*/, + DWORD *poffArguments); + +int wmain(int cArgs, wchar_t **papwszArgs) +{ + HMODULE hmodMsi = LoadLibrary("msi.dll"); + PFNMSIDECOMPOSEDESCRIPTORW pfnMsiDecomposeDescriptorW; + pfnMsiDecomposeDescriptorW = (PFNMSIDECOMPOSEDESCRIPTORW)GetProcAddress(hmodMsi, "MsiDecomposeDescriptorW"); + if (!pfnMsiDecomposeDescriptorW) + { + fprintf(stderr, "Failed to load msi.dll or resolve 'MsiDecomposeDescriptorW'\n"); + return 1; + } + + int rcExit = 0; + for (int iArg = 1; iArg < cArgs; iArg++) + { + wchar_t wszProductCode[40] = { 0 }; + wchar_t wszFeatureId[40] = { 0 }; + wchar_t wszComponentCode[40] = { 0 }; + DWORD offArguments = ~(DWORD)0; + DWORD dwErr = pfnMsiDecomposeDescriptorW(papwszArgs[iArg], wszProductCode, wszFeatureId, wszComponentCode, &offArguments); + if (dwErr == 0) + { + fprintf(stderr, + "#%u: '%ls'\n" + " -> Product=%ls\n" + " -> FeatureId=%ls\n" + " -> ComponentCode=%ls\n" + " -> offArguments=%#lx (%ld)\n" + , iArg, papwszArgs[iArg], wszProductCode, wszFeatureId, wszComponentCode, offArguments, offArguments); + } + else + { + fprintf(stderr, + "#%u: '%ls'\n" + " -> error %lu (%#lx)\n" + , iArg, papwszArgs[iArg], dwErr, dwErr); + rcExit = 1; + } + } + + return rcExit; +} + diff --git a/src/VBox/Main/testcase/ovf-joomla-0.9/joomla-1.1.4-ovf.ovf b/src/VBox/Main/testcase/ovf-joomla-0.9/joomla-1.1.4-ovf.ovf new file mode 100644 index 00000000..924379a8 --- /dev/null +++ b/src/VBox/Main/testcase/ovf-joomla-0.9/joomla-1.1.4-ovf.ovf @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<ovf:Envelope xmlns:ovf="http://www.vmware.com/schema/ovf/1/envelope" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ovf:version="0.9"> +<References> +<File ovf:href="joomla-1.1.4-ovf-0.vmdk" ovf:id="file1" ovf:size="199414784"/> +<File ovf:href="joomla-1.1.4-ovf-1.vmdk" ovf:id="file2" ovf:size="393216"/> +</References> +<Section xsi:type="ovf:NetworkSection_Type"> +<Info>List of networks</Info> +<Network ovf:name="Network 1"> +<Description>The "Network 1" network</Description> +</Network> +</Section> +<Section xsi:type="ovf:DiskSection_Type"> +<Info>List of Virtual Disks</Info> +<Disk ovf:capacity="1610612736" ovf:diskId="disk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/specifications/vmdk.html#sparse" ovf:populatedSize="639434752"/> +<Disk ovf:capacity="10737418240" ovf:diskId="disk2" ovf:fileRef="file2" ovf:format="http://www.vmware.com/specifications/vmdk.html#sparse" ovf:populatedSize="7536640"/> +</Section> +<Content ovf:id="joomla-1.1.4-ovf" xsi:type="ovf:VirtualSystem_Type"> +<Info>A virtual machine</Info> +<Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type"> +<Info>An annotation</Info> +<Annotation>This is a JumpBox for joomla. For more information, please visit http://www.jumpbox.com/</Annotation> +<!-- <Annotation>This is a JumpBox for joomla. For more information, please visit http://www.jumpbox.com/</Annotation> --> +</Section> +<Section ovf:id="101" ovf:required="false" xsi:type="ovf:OperatingSystemSection_Type"> +<Info>Guest Operating System</Info> +<Description>Ubuntu</Description> +</Section> +<Section xsi:type="ovf:VirtualHardwareSection_Type"> +<Info>1 CPU, 256 memory</Info> +<System> +<vssd:VirtualSystemType>vmx-04</vssd:VirtualSystemType> +</System> +<Item> +<rasd:Caption>1 virtual CPUs</rasd:Caption> +<rasd:Description>Number of virtual CPUs</rasd:Description> +<rasd:InstanceId>1</rasd:InstanceId> +<rasd:ResourceType>3</rasd:ResourceType> +<rasd:VirtualQuantity>1</rasd:VirtualQuantity> +</Item> +<Item> +<rasd:Caption>256 MB of memory</rasd:Caption> +<rasd:Description>Memory Size</rasd:Description> +<rasd:InstanceId>2</rasd:InstanceId> +<rasd:ResourceType>4</rasd:ResourceType> +<rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits> +<rasd:VirtualQuantity>256</rasd:VirtualQuantity> +</Item> +<Item> +<rasd:Caption>Harddisk 0</rasd:Caption> +<rasd:InstanceId>9</rasd:InstanceId> +<rasd:ResourceType>17</rasd:ResourceType> +<rasd:HostResource>/disk/disk1</rasd:HostResource> +<rasd:Parent>8</rasd:Parent> +<rasd:AddressOnParent>0</rasd:AddressOnParent> +</Item> +<Item> +<rasd:Caption>Harddisk 1</rasd:Caption> +<rasd:InstanceId>10</rasd:InstanceId> +<rasd:ResourceType>17</rasd:ResourceType> +<rasd:HostResource>/disk/disk2</rasd:HostResource> +<rasd:Parent>8</rasd:Parent> +<rasd:AddressOnParent>1</rasd:AddressOnParent> +</Item> +<Item> +<rasd:Caption>SCSI Controller 0</rasd:Caption> +<rasd:InstanceId>8</rasd:InstanceId> +<rasd:ResourceType>6</rasd:ResourceType> +<rasd:ResourceSubType>lsilogic</rasd:ResourceSubType> +<rasd:BusNumber>0</rasd:BusNumber> +</Item> +<Item> +<rasd:Caption>Ethernet adapter on "Network 1"</rasd:Caption> +<rasd:InstanceId>7</rasd:InstanceId> +<rasd:ResourceType>10</rasd:ResourceType> +<rasd:ResourceSubType>PCNet32</rasd:ResourceSubType> +<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> +<rasd:Connection>Network 1</rasd:Connection> +<rasd:AddressOnParent>1</rasd:AddressOnParent> +</Item> +</Section> +</Content> +</ovf:Envelope> diff --git a/src/VBox/Main/testcase/ovf-winhost-audio-nodisks/WinXP.ovf b/src/VBox/Main/testcase/ovf-winhost-audio-nodisks/WinXP.ovf new file mode 100644 index 00000000..ea46077e --- /dev/null +++ b/src/VBox/Main/testcase/ovf-winhost-audio-nodisks/WinXP.ovf @@ -0,0 +1,267 @@ +<?xml version="1.0"?> +<Envelope ovf:version="1.0" xml:lang="en-US" xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vbox="http://www.virtualbox.org/ovf/machine"> + <References/> + <DiskSection> + <Info>List of the virtual disks used in the package</Info> + </DiskSection> + <NetworkSection> + <Info>Logical networks used in the package</Info> + <Network ovf:name="NAT"> + <Description>Logical network used by this appliance.</Description> + </Network> + </NetworkSection> + <VirtualSystem ovf:id="WinXP"> + <Info>A virtual machine</Info> + <OperatingSystemSection ovf:id="67"> + <Info>The kind of installed guest operating system</Info> + <Description>WindowsXP</Description> + </OperatingSystemSection> + <VirtualHardwareSection> + <Info>Virtual hardware requirements for a virtual machine</Info> + <System> + <vssd:ElementName>Virtual Hardware Family</vssd:ElementName> + <vssd:InstanceID>0</vssd:InstanceID> + <vssd:VirtualSystemIdentifier>WinXP</vssd:VirtualSystemIdentifier> + <vssd:VirtualSystemType>virtualbox-2.2</vssd:VirtualSystemType> + </System> + <Item> + <rasd:Caption>1 virtual CPU</rasd:Caption> + <rasd:Description>Number of virtual CPUs</rasd:Description> + <rasd:ElementName>1 virtual CPU</rasd:ElementName> + <rasd:InstanceID>1</rasd:InstanceID> + <rasd:ResourceType>3</rasd:ResourceType> + <rasd:VirtualQuantity>1</rasd:VirtualQuantity> + </Item> + <Item> + <rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits> + <rasd:Caption>512 MB of memory</rasd:Caption> + <rasd:Description>Memory Size</rasd:Description> + <rasd:ElementName>512 MB of memory</rasd:ElementName> + <rasd:InstanceID>2</rasd:InstanceID> + <rasd:ResourceType>4</rasd:ResourceType> + <rasd:VirtualQuantity>512</rasd:VirtualQuantity> + </Item> + <Item> + <rasd:Address>0</rasd:Address> + <rasd:Caption>ideController0</rasd:Caption> + <rasd:Description>IDE Controller</rasd:Description> + <rasd:ElementName>ideController0</rasd:ElementName> + <rasd:InstanceID>3</rasd:InstanceID> + <rasd:ResourceSubType>PIIX3</rasd:ResourceSubType> + <rasd:ResourceType>5</rasd:ResourceType> + </Item> + <Item> + <rasd:Address>1</rasd:Address> + <rasd:Caption>ideController1</rasd:Caption> + <rasd:Description>IDE Controller</rasd:Description> + <rasd:ElementName>ideController1</rasd:ElementName> + <rasd:InstanceID>4</rasd:InstanceID> + <rasd:ResourceSubType>PIIX3</rasd:ResourceSubType> + <rasd:ResourceType>5</rasd:ResourceType> + </Item> + <Item> + <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> + <rasd:Caption>Ethernet adapter on 'NAT'</rasd:Caption> + <rasd:Connection>NAT</rasd:Connection> + <rasd:ElementName>Ethernet adapter on 'NAT'</rasd:ElementName> + <rasd:InstanceID>5</rasd:InstanceID> + <rasd:ResourceSubType>PCNet32</rasd:ResourceSubType> + <rasd:ResourceType>10</rasd:ResourceType> + </Item> + <Item> + <rasd:Address>0</rasd:Address> + <rasd:Caption>usb</rasd:Caption> + <rasd:Description>USB Controller</rasd:Description> + <rasd:ElementName>usb</rasd:ElementName> + <rasd:InstanceID>6</rasd:InstanceID> + <rasd:ResourceType>23</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>3</rasd:AddressOnParent> + <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> + <rasd:Caption>sound</rasd:Caption> + <rasd:Description>Sound Card</rasd:Description> + <rasd:ElementName>sound</rasd:ElementName> + <rasd:InstanceID>7</rasd:InstanceID> + <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType> + <rasd:ResourceType>35</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>0</rasd:AddressOnParent> + <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> + <rasd:Caption>cdrom1</rasd:Caption> + <rasd:Description>CD-ROM Drive</rasd:Description> + <rasd:ElementName>cdrom1</rasd:ElementName> + <rasd:InstanceID>8</rasd:InstanceID> + <rasd:Parent>4</rasd:Parent> + <rasd:ResourceType>15</rasd:ResourceType> + </Item> + </VirtualHardwareSection> + <vbox:Machine ovf:required="false" version="1.10-windows" uuid="{fc4b0fa2-61a7-4974-939a-d25bdab59971}" name="WinXP" OSType="WindowsXP" lastStateChange="2010-07-20T14:23:26Z"> + <ovf:Info>Complete VirtualBox machine configuration in VirtualBox format</ovf:Info> + <ExtraData> + <ExtraDataItem name="GUI/LastCloseAction" value="powerOff"/> + <ExtraDataItem name="GUI/LastGuestSizeHint" value="640,480"/> + <ExtraDataItem name="GUI/LastNormalWindowPosition" value="520,243,640,523"/> + <ExtraDataItem name="GUI/LastScaleWindowPosition" value="520,265,640,480"/> + <ExtraDataItem name="GUI/MiniToolBarAlignment" value="bottom"/> + <ExtraDataItem name="GUI/SaveMountedAtRuntime" value="yes"/> + <ExtraDataItem name="GUI/ShowMiniToolBar" value="yes"/> + </ExtraData> + <Hardware version="2"> + <CPU count="1" hotplug="false"> + <HardwareVirtEx enabled="true" exclusive="false"/> + <HardwareVirtExNestedPaging enabled="true"/> + <HardwareVirtExVPID enabled="true"/> + <PAE enabled="false"/> + </CPU> + <Memory RAMSize="512" PageFusion="false"/> + <HID Pointing="PS2Mouse" Keyboard="PS2Keyboard"/> + <HPET enabled="false"/> + <Boot> + <Order position="1" device="HardDisk"/> + <Order position="2" device="None"/> + <Order position="3" device="None"/> + <Order position="4" device="None"/> + </Boot> + <Display VRAMSize="20" monitorCount="1" accelerate3D="false" accelerate2DVideo="false"/> + <RemoteDisplay enabled="false" port="3389" authType="Null" authTimeout="5000"> + <VideoChannel enabled="false" quality="75"/> + </RemoteDisplay> + <BIOS> + <ACPI enabled="true"/> + <IOAPIC enabled="false"/> + <Logo fadeIn="true" fadeOut="true" displayTime="0"/> + <BootMenu mode="MessageAndMenu"/> + <TimeOffset value="0"/> + <PXEDebug enabled="false"/> + </BIOS> + <USBController enabled="true" enabledEhci="true"/> + <Network> + <Adapter slot="0" enabled="true" MACAddress="080027FDEC62" cable="true" speed="0" type="Am79C973"> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </Adapter> + <Adapter slot="1" enabled="false" MACAddress="08002767B875" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="2" enabled="false" MACAddress="080027CE5CC2" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="3" enabled="false" MACAddress="0800277CCAFC" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="4" enabled="false" MACAddress="080027D1AE28" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="5" enabled="false" MACAddress="080027A2AA62" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="6" enabled="false" MACAddress="080027BFC29B" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="7" enabled="false" MACAddress="080027A2A78A" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + </Network> + <UART> + <Port slot="0" enabled="false" IOBase="0x3f8" IRQ="4" hostMode="Disconnected"/> + <Port slot="1" enabled="false" IOBase="0x3f8" IRQ="4" hostMode="Disconnected"/> + </UART> + <LPT> + <Port slot="0" enabled="false" IOBase="0x378" IRQ="4"/> + <Port slot="1" enabled="false" IOBase="0x378" IRQ="4"/> + </LPT> + <AudioAdapter controller="AC97" driver="DirectSound" enabled="true"/> + <RTC localOrUTC="local"/> + <SharedFolders/> + <Clipboard mode="Bidirectional"/> + <IO> + <IoCache enabled="true" size="5"/> + <IoBandwidth max="0"/> + </IO> + <Guest memoryBalloonSize="0"/> + <GuestProperties> + <GuestProperty name="/VirtualBox/GuestInfo/OS/Product" value="Windows XP Professional" timestamp="1279634733194581900" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/Release" value="5.1.2600" timestamp="1279634733206582500" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/Version" value="" timestamp="1279634733209582700" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/ServicePack" value="2" timestamp="1279634733215583100" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Version" value="3.1.51" timestamp="1279634733216583100" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Revision" value="60359" timestamp="1279634733217583200" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/InstallDir" value="C:/Program Files/Oracle/VirtualBox Guest Additions" timestamp="1279634733219583300" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxControl.exe" value="3.1.51r60359" timestamp="1279634733223583500" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxHook.dll" value="3.1.51r60359" timestamp="1279634733227583700" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxDisp.dll" value="3.1.51r60359" timestamp="1279634733230583900" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxMRXNP.dll" value="3.1.51r60359" timestamp="1279634733235584200" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxService.exe" value="3.1.51r60359" timestamp="1279634733236584300" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxTray.exe" value="3.1.51r60359" timestamp="1279634733243584700" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxGINA.dll" value="-" timestamp="1279634733274586400" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxCredProv.dll" value="-" timestamp="1279634733292587500" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLarrayspu.dll" value="3.1.51r60359" timestamp="1279634733294587600" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLcrutil.dll" value="3.1.51r60359" timestamp="1279634733296587700" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLerrorspu.dll" value="3.1.51r60359" timestamp="1279634733298587800" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLpackspu.dll" value="3.1.51r60359" timestamp="1279634733300587900" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLpassthroughspu.dll" value="3.1.51r60359" timestamp="1279634733303588100" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLfeedbackspu.dll" value="3.1.51r60359" timestamp="1279634733305588200" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGL.dll" value="3.1.51r60359" timestamp="1279634733310588500" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxGuest.sys" value="3.1.51r60359" timestamp="1279634733316588800" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxMouse.sys" value="3.1.51r60359" timestamp="1279634733321589100" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxSF.sys" value="3.1.51r60359" timestamp="1279634733325589400" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxVideo.sys" value="3.1.51r60359" timestamp="1279634733331589700" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/NoLoggedInUsers" value="false" timestamp="1279634743366163600" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/HostVerLastChecked" value="3.2.51" timestamp="1279634759329076700" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/LoggedInUsersList" value="Dsen" timestamp="1279634773413882300" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/LoggedInUsers" value="1" timestamp="1279634773414882300" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/Count" value="1" timestamp="1279634773416882400" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/IP" value="10.0.2.15" timestamp="1279634773417882500" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/Broadcast" value="255.255.255.255" timestamp="1279634773418882600" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/Netmask" value="255.255.255.0" timestamp="1279634773418882601" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/0/Status" value="Up" timestamp="1279634773419882600" flags=""/> + <GuestProperty name="/VirtualBox/HostInfo/GUI/LanguageID" value="C" timestamp="1279636075749371600" flags=""/> + </GuestProperties> + </Hardware> + <StorageControllers> + <StorageController name="IDE Controller" type="PIIX3" PortCount="2" useHostIOCache="true"> + <AttachedDevice passthrough="false" type="DVD" port="1" device="0"/> + </StorageController> + </StorageControllers> + </vbox:Machine> + </VirtualSystem> +</Envelope> diff --git a/src/VBox/Main/testcase/ovf-winxp-vbox-sharedfolders/winxp.ovf b/src/VBox/Main/testcase/ovf-winxp-vbox-sharedfolders/winxp.ovf new file mode 100644 index 00000000..9d6ce61c --- /dev/null +++ b/src/VBox/Main/testcase/ovf-winxp-vbox-sharedfolders/winxp.ovf @@ -0,0 +1,315 @@ +<?xml version="1.0"?> +<Envelope ovf:version="1.0" xml:lang="en-US" xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vbox="http://www.virtualbox.org/ovf/machine"> + <References> + <File ovf:href="Windows 5.1 XP 1 merged.vmdk" ovf:id="file1" ovf:size="4948965888"/> + <File ovf:href="smallvdi.vmdk" ovf:id="file2" ovf:size="1265152"/> + </References> + <DiskSection> + <Info>List of the virtual disks used in the package</Info> + <Disk ovf:capacity="10485760000" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" vbox:uuid="1fc3c37e-079b-477b-a6d7-84c0e8a717ac"/> + <Disk ovf:capacity="2147483648" ovf:diskId="vmdisk2" ovf:fileRef="file2" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" vbox:uuid="cf2b9350-4d5f-42a2-be70-b85a00c2ec9f"/> + </DiskSection> + <NetworkSection> + <Info>Logical networks used in the package</Info> + <Network ovf:name="NAT"> + <Description>Logical network used by this appliance.</Description> + </Network> + </NetworkSection> + <VirtualSystem ovf:id="Windows 5.1 XP 1"> + <Info>A virtual machine</Info> + <OperatingSystemSection ovf:id="67"> + <Info>The kind of installed guest operating system</Info> + <Description>WindowsXP</Description> + </OperatingSystemSection> + <VirtualHardwareSection> + <Info>Virtual hardware requirements for a virtual machine</Info> + <System> + <vssd:ElementName>Virtual Hardware Family</vssd:ElementName> + <vssd:InstanceID>0</vssd:InstanceID> + <vssd:VirtualSystemIdentifier>Windows 5.1 XP 1</vssd:VirtualSystemIdentifier> + <vssd:VirtualSystemType>virtualbox-2.2</vssd:VirtualSystemType> + </System> + <Item> + <rasd:Caption>1 virtual CPU</rasd:Caption> + <rasd:Description>Number of virtual CPUs</rasd:Description> + <rasd:ElementName>1 virtual CPU</rasd:ElementName> + <rasd:InstanceID>1</rasd:InstanceID> + <rasd:ResourceType>3</rasd:ResourceType> + <rasd:VirtualQuantity>1</rasd:VirtualQuantity> + </Item> + <Item> + <rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits> + <rasd:Caption>895 MB of memory</rasd:Caption> + <rasd:Description>Memory Size</rasd:Description> + <rasd:ElementName>895 MB of memory</rasd:ElementName> + <rasd:InstanceID>2</rasd:InstanceID> + <rasd:ResourceType>4</rasd:ResourceType> + <rasd:VirtualQuantity>895</rasd:VirtualQuantity> + </Item> + <Item> + <rasd:Address>0</rasd:Address> + <rasd:Caption>ideController0</rasd:Caption> + <rasd:Description>IDE Controller</rasd:Description> + <rasd:ElementName>ideController0</rasd:ElementName> + <rasd:InstanceID>3</rasd:InstanceID> + <rasd:ResourceSubType>PIIX3</rasd:ResourceSubType> + <rasd:ResourceType>5</rasd:ResourceType> + </Item> + <Item> + <rasd:Address>1</rasd:Address> + <rasd:Caption>ideController1</rasd:Caption> + <rasd:Description>IDE Controller</rasd:Description> + <rasd:ElementName>ideController1</rasd:ElementName> + <rasd:InstanceID>4</rasd:InstanceID> + <rasd:ResourceSubType>PIIX3</rasd:ResourceSubType> + <rasd:ResourceType>5</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>0</rasd:AddressOnParent> + <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> + <rasd:Caption>floppy0</rasd:Caption> + <rasd:Description>Floppy Drive</rasd:Description> + <rasd:ElementName>floppy0</rasd:ElementName> + <rasd:InstanceID>5</rasd:InstanceID> + <rasd:ResourceType>14</rasd:ResourceType> + </Item> + <Item> + <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> + <rasd:Caption>Ethernet adapter on 'NAT'</rasd:Caption> + <rasd:Connection>NAT</rasd:Connection> + <rasd:ElementName>Ethernet adapter on 'NAT'</rasd:ElementName> + <rasd:InstanceID>6</rasd:InstanceID> + <rasd:ResourceSubType>PCNet32</rasd:ResourceSubType> + <rasd:ResourceType>10</rasd:ResourceType> + </Item> + <Item> + <rasd:Address>0</rasd:Address> + <rasd:Caption>usb</rasd:Caption> + <rasd:Description>USB Controller</rasd:Description> + <rasd:ElementName>usb</rasd:ElementName> + <rasd:InstanceID>7</rasd:InstanceID> + <rasd:ResourceType>23</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>3</rasd:AddressOnParent> + <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> + <rasd:Caption>sound</rasd:Caption> + <rasd:Description>Sound Card</rasd:Description> + <rasd:ElementName>sound</rasd:ElementName> + <rasd:InstanceID>8</rasd:InstanceID> + <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType> + <rasd:ResourceType>35</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>0</rasd:AddressOnParent> + <rasd:Caption>disk1</rasd:Caption> + <rasd:Description>Disk Image</rasd:Description> + <rasd:ElementName>disk1</rasd:ElementName> + <rasd:HostResource>/disk/vmdisk1</rasd:HostResource> + <rasd:InstanceID>9</rasd:InstanceID> + <rasd:Parent>3</rasd:Parent> + <rasd:ResourceType>17</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>1</rasd:AddressOnParent> + <rasd:Caption>disk2</rasd:Caption> + <rasd:Description>Disk Image</rasd:Description> + <rasd:ElementName>disk2</rasd:ElementName> + <rasd:HostResource>/disk/vmdisk2</rasd:HostResource> + <rasd:InstanceID>10</rasd:InstanceID> + <rasd:Parent>3</rasd:Parent> + <rasd:ResourceType>17</rasd:ResourceType> + </Item> + <Item> + <rasd:AddressOnParent>0</rasd:AddressOnParent> + <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> + <rasd:Caption>cdrom1</rasd:Caption> + <rasd:Description>CD-ROM Drive</rasd:Description> + <rasd:ElementName>cdrom1</rasd:ElementName> + <rasd:InstanceID>11</rasd:InstanceID> + <rasd:Parent>4</rasd:Parent> + <rasd:ResourceType>15</rasd:ResourceType> + </Item> + </VirtualHardwareSection> + <vbox:Machine ovf:required="false" version="1.10-linux" uuid="{5f102a55-a51b-48e3-b45a-b28d33469488}" name="Windows 5.1 XP 1" OSType="WindowsXP" snapshotFolder="Snapshots" lastStateChange="2010-06-15T15:33:58Z"> + <ovf:Info>Complete VirtualBox machine configuration in VirtualBox format</ovf:Info> + <ExtraData> + <ExtraDataItem name="GUI/InfoDlgState" value="380,662,normal"/> + <ExtraDataItem name="GUI/LastCloseAction" value="save"/> + <ExtraDataItem name="GUI/LastGuestSizeHint" value="1136,933"/> + <ExtraDataItem name="GUI/LastWindowPostion" value="188,53,1136,977"/> + <ExtraDataItem name="GUI/MiniToolBarAlignment" value="bottom"/> + <ExtraDataItem name="GUI/SaveMountedAtRuntime" value="yes"/> + <ExtraDataItem name="GUI/ShowMiniToolBar" value="yes"/> + <ExtraDataItem name="VBoxInternal2/VRDPBindPort" value="3389"/> + </ExtraData> + <Hardware version="2"> + <CPU count="1" hotplug="false"> + <HardwareVirtEx enabled="true" exclusive="true"/> + <HardwareVirtExNestedPaging enabled="true"/> + <HardwareVirtExVPID enabled="false"/> + <PAE enabled="false"/> + </CPU> + <Memory RAMSize="895" PageFusion="false"/> + <HID Pointing="PS2Mouse" Keyboard="PS2Keyboard"/> + <HPET enabled="false"/> + <Boot> + <Order position="1" device="Floppy"/> + <Order position="2" device="DVD"/> + <Order position="3" device="HardDisk"/> + <Order position="4" device="None"/> + </Boot> + <Display VRAMSize="24" monitorCount="1" accelerate3D="true" accelerate2DVideo="false"/> + <RemoteDisplay enabled="true" port="3389" authType="Null" authTimeout="5000"> + <VideoChannel enabled="false" quality="75"/> + </RemoteDisplay> + <BIOS> + <ACPI enabled="true"/> + <IOAPIC enabled="false"/> + <Logo fadeIn="true" fadeOut="false" displayTime="0"/> + <BootMenu mode="MessageAndMenu"/> + <TimeOffset value="0"/> + <PXEDebug enabled="false"/> + </BIOS> + <USBController enabled="true" enabledEhci="false"> + <DeviceFilter name="SanDisk U3 Cruzer Micro [0200]" active="true" vendorId="0781" productId="5406" revision="0200" manufacturer="SanDisk" product="U3 Cruzer Micro" serialNumber="0877201B1A11B7A6" remote="no"/> + </USBController> + <Network> + <Adapter slot="0" enabled="true" MACAddress="080027F1086C" cable="true" speed="0" type="Am79C973"> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </Adapter> + <Adapter slot="1" enabled="false" MACAddress="0800273B18E3" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="2" enabled="false" MACAddress="080027C9B8C9" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="3" enabled="false" MACAddress="08002729FB57" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="4" enabled="false" MACAddress="080027C6BF50" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="5" enabled="false" MACAddress="080027DF7499" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="6" enabled="false" MACAddress="080027FB8C2B" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + <Adapter slot="7" enabled="false" MACAddress="080027614C1B" cable="true" speed="0" type="Am79C973"> + <DisabledModes> + <NAT> + <DNS pass-domain="true" use-proxy="false" use-host-resolver="false"/> + <Alias logging="false" proxy-only="false" use-same-ports="false"/> + </NAT> + </DisabledModes> + </Adapter> + </Network> + <UART> + <Port slot="0" enabled="false" IOBase="0x3f8" IRQ="4" hostMode="Disconnected"/> + <Port slot="1" enabled="false" IOBase="0x3f8" IRQ="4" hostMode="Disconnected"/> + </UART> + <LPT> + <Port slot="0" enabled="false" IOBase="0x378" IRQ="4"/> + <Port slot="1" enabled="false" IOBase="0x378" IRQ="4"/> + </LPT> + <AudioAdapter controller="AC97" driver="ALSA" enabled="true"/> + <RTC localOrUTC="local"/> + <SharedFolders> + <SharedFolder name="t" hostPath="/path/does/not/exist" writable="true"/> + </SharedFolders> + <Clipboard mode="Bidirectional"/> + <IO> + <IoCache enabled="true" size="5"/> + <IoBandwidth max="0"/> + </IO> + <Guest memoryBalloonSize="0"/> + <GuestProperties> + <GuestProperty name="/VirtualBox/HostInfo/GUI/LanguageID" value="C" timestamp="1276615475026659000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/Product" value="Windows XP Professional" timestamp="1276615535415199000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/Release" value="5.1.2600" timestamp="1276615535423377000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/Version" value="" timestamp="1276615535424390000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/ServicePack" value="3" timestamp="1276615535425834000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Version" value="3.1.7" timestamp="1276615535426567000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Revision" value="60877" timestamp="1276615535428273000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/InstallDir" value="C:/Program Files/Sun/VirtualBox Guest Additions" timestamp="1276615535428823000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxControl.exe" value="3.1.7r60877" timestamp="1276615535452159000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxHook.dll" value="3.1.7r60877" timestamp="1276615535453735000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxDisp.dll" value="3.1.7r60877" timestamp="1276615535455440000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxMRXNP.dll" value="3.1.7r60877" timestamp="1276615535456268000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxService.exe" value="3.1.7r60877" timestamp="1276615535457312000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxTray.exe" value="3.1.7r60877" timestamp="1276615535458094000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxGINA.dll" value="3.0.0r49275" timestamp="1276615535458828000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxCredProv.dll" value="-" timestamp="1276615535467867000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLarrayspu.dll" value="3.1.7r60877" timestamp="1276615535468601000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLcrutil.dll" value="3.1.7r60877" timestamp="1276615535469299000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLerrorspu.dll" value="3.1.7r60877" timestamp="1276615535469853000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLpackspu.dll" value="3.1.7r60877" timestamp="1276615535491615000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLpassthroughspu.dll" value="3.1.7r60877" timestamp="1276615535492438000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGLfeedbackspu.dll" value="3.1.7r60877" timestamp="1276615535493364000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxOGL.dll" value="3.1.7r60877" timestamp="1276615535494186000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxGuest.sys" value="3.1.7r60877" timestamp="1276615535495047000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxMouse.sys" value="3.1.7r60877" timestamp="1276615535495946000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxSF.sys" value="3.1.7r60877" timestamp="1276615535496631000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/Components/VBoxVideo.sys" value="3.1.7r60877" timestamp="1276615535497318000" flags=""/> + <GuestProperty name="/VirtualBox/GuestAdd/HostVerLastChecked" value="3.2.51" timestamp="1276615561761565000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/LoggedInUsersList" value="" timestamp="1276616026260647000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/LoggedInUsers" value="0" timestamp="1276616026262352000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/OS/NoLoggedInUsers" value="true" timestamp="1276616026262920000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/IP" value="" timestamp="1276616026263814000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/Broadcast" value="" timestamp="1276616026264275000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/0/V4/Netmask" value="" timestamp="1276616026264727000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/0/Status" value="" timestamp="1276616026265170000" flags=""/> + <GuestProperty name="/VirtualBox/GuestInfo/Net/Count" value="0" timestamp="1276616026266071000" flags=""/> + </GuestProperties> + </Hardware> + <StorageControllers> + <StorageController name="IDE Controller" type="PIIX3" PortCount="2" useHostIOCache="true"> + <AttachedDevice type="HardDisk" port="0" device="0"> + <Image uuid="{1fc3c37e-079b-477b-a6d7-84c0e8a717ac}"/> + </AttachedDevice> + <AttachedDevice type="HardDisk" port="0" device="1"> + <Image uuid="{cf2b9350-4d5f-42a2-be70-b85a00c2ec9f}"/> + </AttachedDevice> + <AttachedDevice passthrough="false" type="DVD" port="1" device="0"/> + </StorageController> + <StorageController name="Floppy Controller" type="I82078" PortCount="1" useHostIOCache="true"> + <AttachedDevice type="Floppy" port="0" device="0"/> + </StorageController> + </StorageControllers> + </vbox:Machine> + </VirtualSystem> +</Envelope> diff --git a/src/VBox/Main/testcase/tstAPI.cpp b/src/VBox/Main/testcase/tstAPI.cpp new file mode 100644 index 00000000..df0a8905 --- /dev/null +++ b/src/VBox/Main/testcase/tstAPI.cpp @@ -0,0 +1,1706 @@ +/* $Id: tstAPI.cpp $ */ +/** @file + * tstAPI - test program for our COM/XPCOM interface + */ + +/* + * Copyright (C) 2006-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <VBox/com/com.h> +#include <VBox/com/string.h> +#include <VBox/com/Guid.h> +#include <VBox/com/ErrorInfo.h> +#include <VBox/com/errorprint.h> + +#include <VBox/com/VirtualBox.h> + +using namespace com; + +#define LOG_ENABLED +#define LOG_GROUP LOG_GROUP_MAIN +#include <VBox/log.h> + +#include <iprt/initterm.h> +#include <iprt/path.h> +#include <iprt/param.h> +#include <iprt/stream.h> +#include <iprt/thread.h> + + +// forward declarations +/////////////////////////////////////////////////////////////////////////////// + +#ifdef VBOX_WITH_RESOURCE_USAGE_API +static Bstr getObjectName(ComPtr<IVirtualBox> aVirtualBox, ComPtr<IUnknown> aObject); +static void queryMetrics(ComPtr<IVirtualBox> aVirtualBox, + ComPtr<IPerformanceCollector> collector, + ComSafeArrayIn(IUnknown *, objects)); +static void listAffectedMetrics(ComPtr<IVirtualBox> aVirtualBox, + ComSafeArrayIn(IPerformanceMetric*, aMetrics)); +#endif + +// funcs +/////////////////////////////////////////////////////////////////////////////// + +HRESULT readAndChangeMachineSettings(IMachine *machine, IMachine *readonlyMachine = 0) +{ + HRESULT hrc = S_OK; + + Bstr name; + RTPrintf("Getting machine name...\n"); + CHECK_ERROR_RET(machine, COMGETTER(Name)(name.asOutParam()), hrc); + RTPrintf("Name: {%ls}\n", name.raw()); + + RTPrintf("Getting machine GUID...\n"); + Bstr guid; + CHECK_ERROR(machine, COMGETTER(Id)(guid.asOutParam())); + if (SUCCEEDED(hrc) && !guid.isEmpty()) { + RTPrintf("Guid::toString(): {%s}\n", Utf8Str(guid).c_str()); + } else { + RTPrintf("WARNING: there's no GUID!"); + } + + ULONG memorySize; + RTPrintf("Getting memory size...\n"); + CHECK_ERROR_RET(machine, COMGETTER(MemorySize)(&memorySize), hrc); + RTPrintf("Memory size: %d\n", memorySize); + + MachineState_T machineState; + RTPrintf("Getting machine state...\n"); + CHECK_ERROR_RET(machine, COMGETTER(State)(&machineState), hrc); + RTPrintf("Machine state: %d\n", machineState); + + BOOL modified; + RTPrintf("Are any settings modified?...\n"); + CHECK_ERROR(machine, COMGETTER(SettingsModified)(&modified)); + if (SUCCEEDED(hrc)) + RTPrintf("%s\n", modified ? "yes" : "no"); + + ULONG memorySizeBig = memorySize * 10; + RTPrintf("Changing memory size to %d...\n", memorySizeBig); + CHECK_ERROR(machine, COMSETTER(MemorySize)(memorySizeBig)); + + if (SUCCEEDED(hrc)) + { + RTPrintf("Are any settings modified now?...\n"); + CHECK_ERROR_RET(machine, COMGETTER(SettingsModified)(&modified), hrc); + RTPrintf("%s\n", modified ? "yes" : "no"); + ASSERT_RET(modified, 0); + + ULONG memorySizeGot; + RTPrintf("Getting memory size again...\n"); + CHECK_ERROR_RET(machine, COMGETTER(MemorySize)(&memorySizeGot), hrc); + RTPrintf("Memory size: %d\n", memorySizeGot); + ASSERT_RET(memorySizeGot == memorySizeBig, 0); + + if (readonlyMachine) + { + RTPrintf("Getting memory size of the counterpart readonly machine...\n"); + ULONG memorySizeRO; + readonlyMachine->COMGETTER(MemorySize)(&memorySizeRO); + RTPrintf("Memory size: %d\n", memorySizeRO); + ASSERT_RET(memorySizeRO != memorySizeGot, 0); + } + + RTPrintf("Discarding recent changes...\n"); + CHECK_ERROR_RET(machine, DiscardSettings(), hrc); + RTPrintf("Are any settings modified after discarding?...\n"); + CHECK_ERROR_RET(machine, COMGETTER(SettingsModified)(&modified), hrc); + RTPrintf("%s\n", modified ? "yes" : "no"); + ASSERT_RET(!modified, 0); + + RTPrintf("Getting memory size once more...\n"); + CHECK_ERROR_RET(machine, COMGETTER(MemorySize)(&memorySizeGot), hrc); + RTPrintf("Memory size: %d\n", memorySizeGot); + ASSERT_RET(memorySizeGot == memorySize, 0); + + memorySize = memorySize > 128 ? memorySize / 2 : memorySize * 2; + RTPrintf("Changing memory size to %d...\n", memorySize); + CHECK_ERROR_RET(machine, COMSETTER(MemorySize)(memorySize), hrc); + } + + Bstr desc; + RTPrintf("Getting description...\n"); + CHECK_ERROR_RET(machine, COMGETTER(Description)(desc.asOutParam()), hrc); + RTPrintf("Description is: \"%ls\"\n", desc.raw()); + + desc = L"This is an exemplary description (changed)."; + RTPrintf("Setting description to \"%ls\"...\n", desc.raw()); + CHECK_ERROR_RET(machine, COMSETTER(Description)(desc.raw()), hrc); + + RTPrintf("Saving machine settings...\n"); + CHECK_ERROR(machine, SaveSettings()); + if (SUCCEEDED(hrc)) + { + RTPrintf("Are any settings modified after saving?...\n"); + CHECK_ERROR_RET(machine, COMGETTER(SettingsModified)(&modified), hrc); + RTPrintf("%s\n", modified ? "yes" : "no"); + ASSERT_RET(!modified, 0); + + if (readonlyMachine) { + RTPrintf("Getting memory size of the counterpart readonly machine...\n"); + ULONG memorySizeRO; + readonlyMachine->COMGETTER(MemorySize)(&memorySizeRO); + RTPrintf("Memory size: %d\n", memorySizeRO); + ASSERT_RET(memorySizeRO == memorySize, 0); + } + } + + Bstr extraDataKey = L"Blafasel"; + Bstr extraData; + RTPrintf("Getting extra data key {%ls}...\n", extraDataKey.raw()); + CHECK_ERROR_RET(machine, GetExtraData(extraDataKey.raw(), extraData.asOutParam()), hrc); + if (!extraData.isEmpty()) { + RTPrintf("Extra data value: {%ls}\n", extraData.raw()); + } else { + RTPrintf("No extra data exists\n"); + } + + if (extraData.isEmpty()) + extraData = L"Das ist die Berliner Luft, Luft, Luft..."; + else + extraData.setNull(); + RTPrintf("Setting extra data key {%ls} to {%ls}...\n", + extraDataKey.raw(), extraData.raw()); + CHECK_ERROR(machine, SetExtraData(extraDataKey.raw(), extraData.raw())); + + if (SUCCEEDED(hrc)) { + RTPrintf("Getting extra data key {%ls} again...\n", extraDataKey.raw()); + CHECK_ERROR_RET(machine, GetExtraData(extraDataKey.raw(), extraData.asOutParam()), hrc); + if (!extraData.isEmpty()) { + RTPrintf("Extra data value: {%ls}\n", extraData.raw()); + } else { + RTPrintf("No extra data exists\n"); + } + } + + return hrc; +} + +// main +/////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char *argv[]) +{ + /* + * Initialize the VBox runtime without loading + * the support driver. + */ + RTR3InitExe(argc, &argv, 0); + + HRESULT hrc; + + { + char homeDir[RTPATH_MAX]; + GetVBoxUserHomeDirectory(homeDir, sizeof(homeDir)); + RTPrintf("VirtualBox Home Directory = '%s'\n", homeDir); + } + + RTPrintf("Initializing COM...\n"); + + hrc = com::Initialize(); + if (FAILED(hrc)) + { + RTPrintf("ERROR: failed to initialize COM!\n"); + return hrc; + } + + do + { + // scopes all the stuff till shutdown + //////////////////////////////////////////////////////////////////////////// + + ComPtr<IVirtualBoxClient> virtualBoxClient; + ComPtr<IVirtualBox> virtualBox; + ComPtr<ISession> session; + +#if 0 + // Utf8Str test + //////////////////////////////////////////////////////////////////////////// + + Utf8Str nullUtf8Str; + RTPrintf("nullUtf8Str='%s'\n", nullUtf8Str.raw()); + + Utf8Str simpleUtf8Str = "simpleUtf8Str"; + RTPrintf("simpleUtf8Str='%s'\n", simpleUtf8Str.raw()); + + Utf8Str utf8StrFmt = Utf8StrFmt("[0=%d]%s[1=%d]", 0, "utf8StrFmt", 1); + RTPrintf("utf8StrFmt='%s'\n", utf8StrFmt.raw()); + +#endif + + RTPrintf("Creating VirtualBox object...\n"); + hrc = virtualBoxClient.createInprocObject(CLSID_VirtualBoxClient); + if (SUCCEEDED(hrc)) + hrc = virtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam()); + if (FAILED(hrc)) + RTPrintf("ERROR: failed to create the VirtualBox object!\n"); + else + { + hrc = session.createInprocObject(CLSID_Session); + if (FAILED(hrc)) + RTPrintf("ERROR: failed to create a session object!\n"); + } + + if (FAILED(hrc)) + { + com::ErrorInfo info; + if (!info.isFullAvailable() && !info.isBasicAvailable()) + { + com::GluePrintRCMessage(hrc); + RTPrintf("Most likely, the VirtualBox COM server is not running or failed to start.\n"); + } + else + com::GluePrintErrorInfo(info); + break; + } + +#if 0 + // Testing VirtualBox::COMGETTER(ProgressOperations). + // This is designed to be tested while running + // "./VBoxManage clonehd src.vdi clone.vdi" in parallel. + // It will then display the progress every 2 seconds. + //////////////////////////////////////////////////////////////////////////// + { + RTPrintf("Testing VirtualBox::COMGETTER(ProgressOperations)...\n"); + + for (;;) { + com::SafeIfaceArray<IProgress> operations; + + CHECK_ERROR_BREAK(virtualBox, + COMGETTER(ProgressOperations)(ComSafeArrayAsOutParam(operations))); + + RTPrintf("operations: %d\n", operations.size()); + if (operations.size() == 0) + break; // No more operations left. + + for (size_t i = 0; i < operations.size(); ++i) { + PRInt32 percent; + + operations[i]->COMGETTER(Percent)(&percent); + RTPrintf("operations[%u]: %ld\n", (unsigned)i, (long)percent); + } + RTThreadSleep(2000); // msec + } + } +#endif + +#if 0 + // IUnknown identity test + //////////////////////////////////////////////////////////////////////////// + { + { + ComPtr<IVirtualBox> virtualBox2; + + RTPrintf("Creating one more VirtualBox object...\n"); + CHECK_RC(virtualBoxClient->COMGETTER(virtualBox2.asOutParam())); + if (FAILED(rc)) + { + CHECK_ERROR_NOCALL(); + break; + } + + RTPrintf("IVirtualBox(virtualBox)=%p IVirtualBox(virtualBox2)=%p\n", + (IVirtualBox *)virtualBox, (IVirtualBox *)virtualBox2); + Assert((IVirtualBox *)virtualBox == (IVirtualBox *)virtualBox2); + + ComPtr<IUnknown> unk(virtualBox); + ComPtr<IUnknown> unk2; + unk2 = virtualBox2; + + RTPrintf("IUnknown(virtualBox)=%p IUnknown(virtualBox2)=%p\n", + (IUnknown *)unk, (IUnknown *)unk2); + Assert((IUnknown *)unk == (IUnknown *)unk2); + + ComPtr<IVirtualBox> vb = unk; + ComPtr<IVirtualBox> vb2 = unk; + + RTPrintf("IVirtualBox(IUnknown(virtualBox))=%p IVirtualBox(IUnknown(virtualBox2))=%p\n", + (IVirtualBox *)vb, (IVirtualBox *)vb2); + Assert((IVirtualBox *)vb == (IVirtualBox *)vb2); + } + + { + ComPtr<IHost> host; + CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam())); + RTPrintf(" IHost(host)=%p\n", (IHost *)host); + ComPtr<IUnknown> unk = host; + RTPrintf(" IUnknown(host)=%p\n", (IUnknown *)unk); + ComPtr<IHost> host_copy = unk; + RTPrintf(" IHost(host_copy)=%p\n", (IHost *)host_copy); + ComPtr<IUnknown> unk_copy = host_copy; + RTPrintf(" IUnknown(host_copy)=%p\n", (IUnknown *)unk_copy); + Assert((IUnknown *)unk == (IUnknown *)unk_copy); + + /* query IUnknown on IUnknown */ + ComPtr<IUnknown> unk_copy_copy; + unk_copy.queryInterfaceTo(unk_copy_copy.asOutParam()); + RTPrintf(" IUnknown(unk_copy)=%p\n", (IUnknown *)unk_copy_copy); + Assert((IUnknown *)unk_copy == (IUnknown *)unk_copy_copy); + /* query IUnknown on IUnknown in the opposite direction */ + unk_copy_copy.queryInterfaceTo(unk_copy.asOutParam()); + RTPrintf(" IUnknown(unk_copy_copy)=%p\n", (IUnknown *)unk_copy); + Assert((IUnknown *)unk_copy == (IUnknown *)unk_copy_copy); + + /* query IUnknown again after releasing all previous IUnknown instances + * but keeping IHost -- it should remain the same (Identity Rule) */ + IUnknown *oldUnk = unk; + unk.setNull(); + unk_copy.setNull(); + unk_copy_copy.setNull(); + unk = host; + RTPrintf(" IUnknown(host)=%p\n", (IUnknown *)unk); + Assert(oldUnk == (IUnknown *)unk); + } + +// RTPrintf("Will be now released (press Enter)..."); +// getchar(); + } +#endif + +#if 0 + // the simplest COM API test + //////////////////////////////////////////////////////////////////////////// + { + Bstr version; + CHECK_ERROR_BREAK(virtualBox, COMGETTER(Version)(version.asOutParam())); + RTPrintf("VirtualBox version = %ls\n", version.raw()); + } +#endif + +#if 0 + // Array test + //////////////////////////////////////////////////////////////////////////// + { + RTPrintf("Calling IVirtualBox::Machines...\n"); + + com::SafeIfaceArray<IMachine> machines; + CHECK_ERROR_BREAK(virtualBox, + COMGETTER(Machines)(ComSafeArrayAsOutParam(machines))); + + RTPrintf("%u machines registered (machines.isNull()=%d).\n", + machines.size(), machines.isNull()); + + for (size_t i = 0; i < machines.size(); ++ i) + { + Bstr name; + CHECK_ERROR_BREAK(machines[i], COMGETTER(Name)(name.asOutParam())); + RTPrintf("machines[%u]='%s'\n", i, Utf8Str(name).raw()); + } + +#if 0 + { + RTPrintf("Testing [out] arrays...\n"); + com::SafeGUIDArray uuids; + CHECK_ERROR_BREAK(virtualBox, + COMGETTER(Uuids)(ComSafeArrayAsOutParam(uuids))); + + for (size_t i = 0; i < uuids.size(); ++ i) + RTPrintf("uuids[%u]=%RTuuid\n", i, &uuids[i]); + } + + { + RTPrintf("Testing [in] arrays...\n"); + com::SafeGUIDArray uuids(5); + for (size_t i = 0; i < uuids.size(); ++ i) + { + Guid id; + id.create(); + uuids[i] = id; + RTPrintf("uuids[%u]=%RTuuid\n", i, &uuids[i]); + } + + CHECK_ERROR_BREAK(virtualBox, + SetUuids(ComSafeArrayAsInParam(uuids))); + } +#endif + + } +#endif + +#if 0 + // some outdated stuff + //////////////////////////////////////////////////////////////////////////// + + RTPrintf("Getting IHost interface...\n"); + IHost *host; + rc = virtualBox->GetHost(&host); + if (SUCCEEDED(rc)) + { + IHostDVDDriveCollection *dvdColl; + rc = host->GetHostDVDDrives(&dvdColl); + if (SUCCEEDED(rc)) + { + IHostDVDDrive *dvdDrive = NULL; + dvdColl->GetNextHostDVDDrive(dvdDrive, &dvdDrive); + while (dvdDrive) + { + BSTR driveName; + char *driveNameUtf8; + dvdDrive->GetDriveName(&driveName); + RTUtf16ToUtf8((PCRTUTF16)driveName, &driveNameUtf8); + RTPrintf("Host DVD drive name: %s\n", driveNameUtf8); + RTStrFree(driveNameUtf8); + SysFreeString(driveName); + IHostDVDDrive *dvdDriveTemp = dvdDrive; + dvdColl->GetNextHostDVDDrive(dvdDriveTemp, &dvdDrive); + dvdDriveTemp->Release(); + } + dvdColl->Release(); + } else + { + RTPrintf("Could not get host DVD drive collection\n"); + } + + IHostFloppyDriveCollection *floppyColl; + rc = host->GetHostFloppyDrives(&floppyColl); + if (SUCCEEDED(rc)) + { + IHostFloppyDrive *floppyDrive = NULL; + floppyColl->GetNextHostFloppyDrive(floppyDrive, &floppyDrive); + while (floppyDrive) + { + BSTR driveName; + char *driveNameUtf8; + floppyDrive->GetDriveName(&driveName); + RTUtf16ToUtf8((PCRTUTF16)driveName, &driveNameUtf8); + RTPrintf("Host floppy drive name: %s\n", driveNameUtf8); + RTStrFree(driveNameUtf8); + SysFreeString(driveName); + IHostFloppyDrive *floppyDriveTemp = floppyDrive; + floppyColl->GetNextHostFloppyDrive(floppyDriveTemp, &floppyDrive); + floppyDriveTemp->Release(); + } + floppyColl->Release(); + } else + { + RTPrintf("Could not get host floppy drive collection\n"); + } + host->Release(); + } else + { + RTPrintf("Call failed\n"); + } + RTPrintf("\n"); +#endif + +#if 0 + // IVirtualBoxErrorInfo test + //////////////////////////////////////////////////////////////////////////// + { + // RPC calls + + // call a method that will definitely fail + Guid uuid; + ComPtr<IHardDisk> hardDisk; + rc = virtualBox->GetHardDisk(uuid, hardDisk.asOutParam()); + RTPrintf("virtualBox->GetHardDisk(null-uuid)=%08X\n", rc); + +// { +// com::ErrorInfo info(virtualBox); +// PRINT_ERROR_INFO(info); +// } + + // call a method that will definitely succeed + Bstr version; + rc = virtualBox->COMGETTER(Version)(version.asOutParam()); + RTPrintf("virtualBox->COMGETTER(Version)=%08X\n", rc); + + { + com::ErrorInfo info(virtualBox); + PRINT_ERROR_INFO(info); + } + + // Local calls + + // call a method that will definitely fail + ComPtr<IMachine> machine; + rc = session->COMGETTER(Machine)(machine.asOutParam()); + RTPrintf("session->COMGETTER(Machine)=%08X\n", rc); + +// { +// com::ErrorInfo info(virtualBox); +// PRINT_ERROR_INFO(info); +// } + + // call a method that will definitely succeed + SessionState_T state; + rc = session->COMGETTER(State)(&state); + RTPrintf("session->COMGETTER(State)=%08X\n", rc); + + { + com::ErrorInfo info(virtualBox); + PRINT_ERROR_INFO(info); + } + } +#endif + +#if 0 + // register the existing hard disk image + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IHardDisk> hd; + Bstr src = L"E:\\develop\\innotek\\images\\NewHardDisk.vdi"; + RTPrintf("Opening the existing hard disk '%ls'...\n", src.raw()); + CHECK_ERROR_BREAK(virtualBox, OpenHardDisk(src, AccessMode_ReadWrite, hd.asOutParam())); + RTPrintf("Enter to continue...\n"); + getchar(); + RTPrintf("Registering the existing hard disk '%ls'...\n", src.raw()); + CHECK_ERROR_BREAK(virtualBox, RegisterHardDisk(hd)); + RTPrintf("Enter to continue...\n"); + getchar(); + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // find and unregister the existing hard disk image + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IVirtualDiskImage> vdi; + Bstr src = L"CreatorTest.vdi"; + RTPrintf("Unregistering the hard disk '%ls'...\n", src.raw()); + CHECK_ERROR_BREAK(virtualBox, FindVirtualDiskImage(src, vdi.asOutParam())); + ComPtr<IHardDisk> hd = vdi; + Guid id; + CHECK_ERROR_BREAK(hd, COMGETTER(Id)(id.asOutParam())); + CHECK_ERROR_BREAK(virtualBox, UnregisterHardDisk(id, hd.asOutParam())); + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // clone the registered hard disk + /////////////////////////////////////////////////////////////////////////// + do + { +#if defined RT_OS_LINUX + Bstr src = L"/mnt/hugaida/common/develop/innotek/images/freedos-linux.vdi"; +#else + Bstr src = L"E:/develop/innotek/images/freedos.vdi"; +#endif + Bstr dst = L"./clone.vdi"; + RTPrintf("Cloning '%ls' to '%ls'...\n", src.raw(), dst.raw()); + ComPtr<IVirtualDiskImage> vdi; + CHECK_ERROR_BREAK(virtualBox, FindVirtualDiskImage(src, vdi.asOutParam())); + ComPtr<IHardDisk> hd = vdi; + ComPtr<IProgress> progress; + CHECK_ERROR_BREAK(hd, CloneToImage(dst, vdi.asOutParam(), progress.asOutParam())); + RTPrintf("Waiting for completion...\n"); + CHECK_ERROR_BREAK(progress, WaitForCompletion(-1)); + ProgressErrorInfo ei(progress); + if (FAILED(ei.getResultCode())) + { + PRINT_ERROR_INFO(ei); + } + else + { + vdi->COMGETTER(FilePath)(dst.asOutParam()); + RTPrintf("Actual clone path is '%ls'\n", dst.raw()); + } + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // find a registered hard disk by location and get properties + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IHardDisk> hd; + static const wchar_t *Names[] = + { +#ifndef RT_OS_LINUX + L"freedos.vdi", + L"MS-DOS.vmdk", + L"iscsi", + L"some/path/and/disk.vdi", +#else + L"xp.vdi", + L"Xp.vDI", +#endif + }; + + RTPrintf("\n"); + + for (size_t i = 0; i < RT_ELEMENTS(Names); ++ i) + { + Bstr src = Names[i]; + RTPrintf("Searching for hard disk '%ls'...\n", src.raw()); + rc = virtualBox->FindHardDisk(src, hd.asOutParam()); + if (SUCCEEDED(rc)) + { + Guid id; + Bstr location; + CHECK_ERROR_BREAK(hd, COMGETTER(Id)(id.asOutParam())); + CHECK_ERROR_BREAK(hd, COMGETTER(Location)(location.asOutParam())); + RTPrintf("Found, UUID={%RTuuid}, location='%ls'.\n", + id.raw(), location.raw()); + + com::SafeArray<BSTR> names; + com::SafeArray<BSTR> values; + + CHECK_ERROR_BREAK(hd, GetProperties(NULL, + ComSafeArrayAsOutParam(names), + ComSafeArrayAsOutParam(values))); + + RTPrintf("Properties:\n"); + for (size_t i = 0; i < names.size(); ++ i) + RTPrintf(" %ls = %ls\n", names[i], values[i]); + + if (names.size() == 0) + RTPrintf(" <none>\n"); + +#if 0 + Bstr name("TargetAddress"); + Bstr value = Utf8StrFmt("lalala (%llu)", RTTimeMilliTS()); + + RTPrintf("Settings property %ls to %ls...\n", name.raw(), value.raw()); + CHECK_ERROR(hd, SetProperty(name, value)); +#endif + } + else + { + com::ErrorInfo info(virtualBox); + PRINT_ERROR_INFO(info); + } + RTPrintf("\n"); + } + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // access the machine in read-only mode + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IMachine> machine; + Bstr name = argc > 1 ? argv[1] : "dos"; + RTPrintf("Getting a machine object named '%ls'...\n", name.raw()); + CHECK_ERROR_BREAK(virtualBox, FindMachine(name, machine.asOutParam())); + RTPrintf("Accessing the machine in read-only mode:\n"); + readAndChangeMachineSettings(machine); +#if 0 + if (argc != 2) + { + RTPrintf("Error: a string has to be supplied!\n"); + } + else + { + Bstr secureLabel = argv[1]; + machine->COMSETTER(ExtraData)(L"VBoxSDL/SecureLabel", secureLabel); + } +#endif + } + while (0); + RTPrintf("\n"); +#endif + +#if 0 + // create a new machine (w/o registering it) + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IMachine> machine; +#if defined(RT_OS_LINUX) + Bstr baseDir = L"/tmp/vbox"; +#else + Bstr baseDir = L"C:\\vbox"; +#endif + Bstr name = L"machina"; + + RTPrintf("Creating a new machine object(base dir '%ls', name '%ls')...\n", + baseDir.raw(), name.raw()); + CHECK_ERROR_BREAK(virtualBox, CreateMachine(name, L"", baseDir, L"", + false, + machine.asOutParam())); + + RTPrintf("Getting name...\n"); + CHECK_ERROR_BREAK(machine, COMGETTER(Name)(name.asOutParam())); + RTPrintf("Name: {%ls}\n", name.raw()); + + BOOL modified = FALSE; + RTPrintf("Are any settings modified?...\n"); + CHECK_ERROR_BREAK(machine, COMGETTER(SettingsModified)(&modified)); + RTPrintf("%s\n", modified ? "yes" : "no"); + + ASSERT_BREAK(modified == TRUE); + + name = L"Kakaya prekrasnaya virtual'naya mashina!"; + RTPrintf("Setting new name ({%ls})...\n", name.raw()); + CHECK_ERROR_BREAK(machine, COMSETTER(Name)(name)); + + RTPrintf("Setting memory size to 111...\n"); + CHECK_ERROR_BREAK(machine, COMSETTER(MemorySize)(111)); + + Bstr desc = L"This is an exemplary description."; + RTPrintf("Setting description to \"%ls\"...\n", desc.raw()); + CHECK_ERROR_BREAK(machine, COMSETTER(Description)(desc)); + + ComPtr<IGuestOSType> guestOSType; + Bstr type = L"os2warp45"; + CHECK_ERROR_BREAK(virtualBox, GetGuestOSType(type, guestOSType.asOutParam())); + + RTPrintf("Saving new machine settings...\n"); + CHECK_ERROR_BREAK(machine, SaveSettings()); + + RTPrintf("Accessing the newly created machine:\n"); + readAndChangeMachineSettings(machine); + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // enumerate host DVD drives + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IHost> host; + CHECK_RC_BREAK(virtualBox->COMGETTER(Host)(host.asOutParam())); + + { + ComPtr<IHostDVDDriveCollection> coll; + CHECK_RC_BREAK(host->COMGETTER(DVDDrives)(coll.asOutParam())); + ComPtr<IHostDVDDriveEnumerator> enumerator; + CHECK_RC_BREAK(coll->Enumerate(enumerator.asOutParam())); + BOOL hasmore; + while (SUCCEEDED(enumerator->HasMore(&hasmore)) && hasmore) + { + ComPtr<IHostDVDDrive> drive; + CHECK_RC_BREAK(enumerator->GetNext(drive.asOutParam())); + Bstr name; + CHECK_RC_BREAK(drive->COMGETTER(Name)(name.asOutParam())); + RTPrintf("Host DVD drive: name={%ls}\n", name.raw()); + } + CHECK_RC_BREAK(rc); + + ComPtr<IHostDVDDrive> drive; + CHECK_ERROR(enumerator, GetNext(drive.asOutParam())); + CHECK_ERROR(coll, GetItemAt(1000, drive.asOutParam())); + CHECK_ERROR(coll, FindByName(Bstr("R:"), drive.asOutParam())); + if (SUCCEEDED(rc)) + { + Bstr name; + CHECK_RC_BREAK(drive->COMGETTER(Name)(name.asOutParam())); + RTPrintf("Found by name: name={%ls}\n", name.raw()); + } + } + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // check for available hd backends + /////////////////////////////////////////////////////////////////////////// + { + RTPrintf("Supported hard disk backends: --------------------------\n"); + ComPtr<ISystemProperties> systemProperties; + CHECK_ERROR_BREAK(virtualBox, + COMGETTER(SystemProperties)(systemProperties.asOutParam())); + com::SafeIfaceArray<IHardDiskFormat> hardDiskFormats; + CHECK_ERROR_BREAK(systemProperties, + COMGETTER(HardDiskFormats)(ComSafeArrayAsOutParam(hardDiskFormats))); + + for (size_t i = 0; i < hardDiskFormats.size(); ++ i) + { + /* General information */ + Bstr id; + CHECK_ERROR_BREAK(hardDiskFormats[i], + COMGETTER(Id)(id.asOutParam())); + + Bstr description; + CHECK_ERROR_BREAK(hardDiskFormats[i], + COMGETTER(Id)(description.asOutParam())); + + ULONG caps; + CHECK_ERROR_BREAK(hardDiskFormats[i], + COMGETTER(Capabilities)(&caps)); + + RTPrintf("Backend %u: id='%ls' description='%ls' capabilities=%#06x extensions='", + i, id.raw(), description.raw(), caps); + + /* File extensions */ + com::SafeArray<BSTR> fileExtensions; + CHECK_ERROR_BREAK(hardDiskFormats[i], + COMGETTER(FileExtensions)(ComSafeArrayAsOutParam(fileExtensions))); + for (size_t a = 0; a < fileExtensions.size(); ++ a) + { + RTPrintf("%ls", Bstr(fileExtensions[a]).raw()); + if (a != fileExtensions.size()-1) + RTPrintf(","); + } + RTPrintf("'"); + + /* Configuration keys */ + com::SafeArray<BSTR> propertyNames; + com::SafeArray<BSTR> propertyDescriptions; + com::SafeArray<ULONG> propertyTypes; + com::SafeArray<ULONG> propertyFlags; + com::SafeArray<BSTR> propertyDefaults; + CHECK_ERROR_BREAK(hardDiskFormats[i], + DescribeProperties(ComSafeArrayAsOutParam(propertyNames), + ComSafeArrayAsOutParam(propertyDescriptions), + ComSafeArrayAsOutParam(propertyTypes), + ComSafeArrayAsOutParam(propertyFlags), + ComSafeArrayAsOutParam(propertyDefaults))); + + RTPrintf(" config=("); + if (propertyNames.size() > 0) + { + for (size_t a = 0; a < propertyNames.size(); ++ a) + { + RTPrintf("key='%ls' desc='%ls' type=", Bstr(propertyNames[a]).raw(), Bstr(propertyDescriptions[a]).raw()); + switch (propertyTypes[a]) + { + case DataType_Int32Type: RTPrintf("int"); break; + case DataType_Int8Type: RTPrintf("byte"); break; + case DataType_StringType: RTPrintf("string"); break; + } + RTPrintf(" flags=%#04x", propertyFlags[a]); + RTPrintf(" default='%ls'", Bstr(propertyDefaults[a]).raw()); + if (a != propertyNames.size()-1) + RTPrintf(","); + } + } + RTPrintf(")\n"); + } + RTPrintf("-------------------------------------------------------\n"); + } +#endif + +#if 0 + // enumerate hard disks & dvd images + /////////////////////////////////////////////////////////////////////////// + do + { + { + com::SafeIfaceArray<IHardDisk> disks; + CHECK_ERROR_BREAK(virtualBox, + COMGETTER(HardDisks)(ComSafeArrayAsOutParam(disks))); + + RTPrintf("%u base hard disks registered (disks.isNull()=%d).\n", + disks.size(), disks.isNull()); + + for (size_t i = 0; i < disks.size(); ++ i) + { + Bstr loc; + CHECK_ERROR_BREAK(disks[i], COMGETTER(Location)(loc.asOutParam())); + Guid id; + CHECK_ERROR_BREAK(disks[i], COMGETTER(Id)(id.asOutParam())); + MediaState_T state; + CHECK_ERROR_BREAK(disks[i], COMGETTER(State)(&state)); + Bstr format; + CHECK_ERROR_BREAK(disks[i], COMGETTER(Format)(format.asOutParam())); + + RTPrintf(" disks[%u]: '%ls'\n" + " UUID: {%RTuuid}\n" + " State: %s\n" + " Format: %ls\n", + i, loc.raw(), id.raw(), + state == MediaState_NotCreated ? "Not Created" : + state == MediaState_Created ? "Created" : + state == MediaState_Inaccessible ? "Inaccessible" : + state == MediaState_LockedRead ? "Locked Read" : + state == MediaState_LockedWrite ? "Locked Write" : + "???", + format.raw()); + + if (state == MediaState_Inaccessible) + { + Bstr error; + CHECK_ERROR_BREAK(disks[i], + COMGETTER(LastAccessError)(error.asOutParam())); + RTPrintf(" Access Error: %ls\n", error.raw()); + } + + /* get usage */ + + RTPrintf(" Used by VMs:\n"); + + com::SafeGUIDArray ids; + CHECK_ERROR_BREAK(disks[i], + COMGETTER(MachineIds)(ComSafeArrayAsOutParam(ids))); + if (ids.size() == 0) + { + RTPrintf(" <not used>\n"); + } + else + { + for (size_t j = 0; j < ids.size(); ++ j) + { + RTPrintf(" {%RTuuid}\n", &ids[j]); + } + } + } + } + { + com::SafeIfaceArray<IDVDImage> images; + CHECK_ERROR_BREAK(virtualBox, + COMGETTER(DVDImages)(ComSafeArrayAsOutParam(images))); + + RTPrintf("%u DVD images registered (images.isNull()=%d).\n", + images.size(), images.isNull()); + + for (size_t i = 0; i < images.size(); ++ i) + { + Bstr loc; + CHECK_ERROR_BREAK(images[i], COMGETTER(Location)(loc.asOutParam())); + Guid id; + CHECK_ERROR_BREAK(images[i], COMGETTER(Id)(id.asOutParam())); + MediaState_T state; + CHECK_ERROR_BREAK(images[i], COMGETTER(State)(&state)); + + RTPrintf(" images[%u]: '%ls'\n" + " UUID: {%RTuuid}\n" + " State: %s\n", + i, loc.raw(), id.raw(), + state == MediaState_NotCreated ? "Not Created" : + state == MediaState_Created ? "Created" : + state == MediaState_Inaccessible ? "Inaccessible" : + state == MediaState_LockedRead ? "Locked Read" : + state == MediaState_LockedWrite ? "Locked Write" : + "???"); + + if (state == MediaState_Inaccessible) + { + Bstr error; + CHECK_ERROR_BREAK(images[i], + COMGETTER(LastAccessError)(error.asOutParam())); + RTPrintf(" Access Error: %ls\n", error.raw()); + } + + /* get usage */ + + RTPrintf(" Used by VMs:\n"); + + com::SafeGUIDArray ids; + CHECK_ERROR_BREAK(images[i], + COMGETTER(MachineIds)(ComSafeArrayAsOutParam(ids))); + if (ids.size() == 0) + { + RTPrintf(" <not used>\n"); + } + else + { + for (size_t j = 0; j < ids.size(); ++ j) + { + RTPrintf(" {%RTuuid}\n", &ids[j]); + } + } + } + } + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // open a (direct) session + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IMachine> machine; + Bstr name = argc > 1 ? argv[1] : "dos"; + RTPrintf("Getting a machine object named '%ls'...\n", name.raw()); + CHECK_ERROR_BREAK(virtualBox, FindMachine(name, machine.asOutParam())); + Guid guid; + CHECK_RC_BREAK(machine->COMGETTER(Id)(guid.asOutParam())); + RTPrintf("Opening a session for this machine...\n"); + CHECK_RC_BREAK(virtualBox->OpenSession(session, guid)); +#if 1 + ComPtr<IMachine> sessionMachine; + RTPrintf("Getting machine session object...\n"); + CHECK_RC_BREAK(session->COMGETTER(Machine)(sessionMachine.asOutParam())); + RTPrintf("Accessing the machine within the session:\n"); + readAndChangeMachineSettings(sessionMachine, machine); +#if 0 + RTPrintf("\n"); + RTPrintf("Enabling the VRDE server (must succeed even if the VM is saved):\n"); + ComPtr<IVRDEServer> vrdeServer; + CHECK_ERROR_BREAK(sessionMachine, COMGETTER(VRDEServer)(vrdeServer.asOutParam())); + if (FAILED(vrdeServer->COMSETTER(Enabled)(TRUE))) + { + PRINT_ERROR_INFO(com::ErrorInfo(vrdeServer)); + } + else + { + BOOL enabled = FALSE; + CHECK_ERROR_BREAK(vrdeServer, COMGETTER(Enabled)(&enabled)); + RTPrintf("VRDE server is %s\n", enabled ? "enabled" : "disabled"); + } +#endif +#endif +#if 0 + ComPtr<IConsole> console; + RTPrintf("Getting the console object...\n"); + CHECK_RC_BREAK(session->COMGETTER(Console)(console.asOutParam())); + RTPrintf("Discarding the current machine state...\n"); + ComPtr<IProgress> progress; + CHECK_ERROR_BREAK(console, DiscardCurrentState(progress.asOutParam())); + RTPrintf("Waiting for completion...\n"); + CHECK_ERROR_BREAK(progress, WaitForCompletion(-1)); + ProgressErrorInfo ei(progress); + if (FAILED(ei.getResultCode())) + { + PRINT_ERROR_INFO(ei); + + ComPtr<IUnknown> initiator; + CHECK_ERROR_BREAK(progress, COMGETTER(Initiator)(initiator.asOutParam())); + + RTPrintf("initiator(unk) = %p\n", (IUnknown *)initiator); + RTPrintf("console(unk) = %p\n", (IUnknown *)ComPtr<IUnknown>((IConsole *)console)); + RTPrintf("console = %p\n", (IConsole *)console); + } +#endif + RTPrintf("Press enter to close session..."); + getchar(); + session->Close(); + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // open a remote session + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IMachine> machine; + Bstr name = L"dos"; + RTPrintf("Getting a machine object named '%ls'...\n", name.raw()); + CHECK_RC_BREAK(virtualBox->FindMachine(name, machine.asOutParam())); + Guid guid; + CHECK_RC_BREAK(machine->COMGETTER(Id)(guid.asOutParam())); + RTPrintf("Opening a remote session for this machine...\n"); + ComPtr<IProgress> progress; + CHECK_RC_BREAK(virtualBox->OpenRemoteSession(session, guid, Bstr("gui"), + NULL, progress.asOutParam())); + RTPrintf("Waiting for the session to open...\n"); + CHECK_RC_BREAK(progress->WaitForCompletion(-1)); + ComPtr<IMachine> sessionMachine; + RTPrintf("Getting machine session object...\n"); + CHECK_RC_BREAK(session->COMGETTER(Machine)(sessionMachine.asOutParam())); + ComPtr<IConsole> console; + RTPrintf("Getting console object...\n"); + CHECK_RC_BREAK(session->COMGETTER(Console)(console.asOutParam())); + RTPrintf("Press enter to pause the VM execution in the remote session..."); + getchar(); + CHECK_RC(console->Pause()); + RTPrintf("Press enter to close this session..."); + getchar(); + session->Close(); + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 0 + // open an existing remote session + /////////////////////////////////////////////////////////////////////////// + do + { + ComPtr<IMachine> machine; + Bstr name = "dos"; + RTPrintf("Getting a machine object named '%ls'...\n", name.raw()); + CHECK_RC_BREAK(virtualBox->FindMachine(name, machine.asOutParam())); + Guid guid; + CHECK_RC_BREAK(machine->COMGETTER(Id)(guid.asOutParam())); + RTPrintf("Opening an existing remote session for this machine...\n"); + CHECK_RC_BREAK(virtualBox->OpenExistingSession(session, guid)); + ComPtr<IMachine> sessionMachine; + RTPrintf("Getting machine session object...\n"); + CHECK_RC_BREAK(session->COMGETTER(Machine)(sessionMachine.asOutParam())); + +#if 0 + Bstr extraDataKey = "VBoxSDL/SecureLabel"; + Bstr extraData = "Das kommt jetzt noch viel krasser vom total konkreten API!"; + CHECK_RC(sessionMachine->SetExtraData(extraDataKey, extraData)); +#endif +#if 0 + ComPtr<IConsole> console; + RTPrintf("Getting console object...\n"); + CHECK_RC_BREAK(session->COMGETTER(Console)(console.asOutParam())); + RTPrintf("Press enter to pause the VM execution in the remote session..."); + getchar(); + CHECK_RC(console->Pause()); + RTPrintf("Press enter to close this session..."); + getchar(); +#endif + session->Close(); + } + while (FALSE); + RTPrintf("\n"); +#endif + +#if 1 + do { + // Get host + ComPtr<IHost> host; + CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam())); + + ULONG uMemSize, uMemAvail; + CHECK_ERROR_BREAK(host, COMGETTER(MemorySize)(&uMemSize)); + RTPrintf("Total memory (MB): %u\n", uMemSize); + CHECK_ERROR_BREAK(host, COMGETTER(MemoryAvailable)(&uMemAvail)); + RTPrintf("Free memory (MB): %u\n", uMemAvail); + } while (0); +#endif + +#if 0 + do { + // Get host + ComPtr<IHost> host; + CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam())); + + com::SafeIfaceArray<IHostNetworkInterface> hostNetworkInterfaces; + CHECK_ERROR_BREAK(host, + COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(hostNetworkInterfaces))); + if (hostNetworkInterfaces.size() > 0) + { + ComPtr<IHostNetworkInterface> networkInterface = hostNetworkInterfaces[0]; + Bstr interfaceName; + networkInterface->COMGETTER(Name)(interfaceName.asOutParam()); + RTPrintf("Found %d network interfaces, testing with %ls...\n", hostNetworkInterfaces.size(), interfaceName.raw()); + Bstr interfaceGuid; + networkInterface->COMGETTER(Id)(interfaceGuid.asOutParam()); + // Find the interface by its name + networkInterface.setNull(); + CHECK_ERROR_BREAK(host, + FindHostNetworkInterfaceByName(interfaceName.raw(), networkInterface.asOutParam())); + Bstr interfaceGuid2; + networkInterface->COMGETTER(Id)(interfaceGuid2.asOutParam()); + if (interfaceGuid2 != interfaceGuid) + RTPrintf("Failed to retrieve an interface by name %ls.\n", interfaceName.raw()); + // Find the interface by its guid + networkInterface.setNull(); + CHECK_ERROR_BREAK(host, + FindHostNetworkInterfaceById(interfaceGuid.raw(), networkInterface.asOutParam())); + Bstr interfaceName2; + networkInterface->COMGETTER(Name)(interfaceName2.asOutParam()); + if (interfaceName != interfaceName2) + RTPrintf("Failed to retrieve an interface by GUID %ls.\n", interfaceGuid.raw()); + } + else + { + RTPrintf("No network interfaces found!\n"); + } + } while (0); +#endif + +#if 0 + // DNS & Co. + /////////////////////////////////////////////////////////////////////////// + /* XXX: Note it's endless loop */ + do + { + ComPtr<IHost> host; + CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam())); + + { + Bstr domainName; + CHECK_ERROR_BREAK(host,COMGETTER(DomainName)(domainName.asOutParam())); + RTPrintf("Domain name: %ls\n", domainName.raw()); + } + + com::SafeArray<BSTR> strs; + CHECK_ERROR_BREAK(host, COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs))); + + unsigned int i; + for (i = 0; i < strs.size(); ++i) + RTPrintf("Name server[%d]:%s\n", i, com::Utf8Str(strs[i]).c_str()); + + RTThreadSleep(1000); + } + while (1); + RTPrintf("\n"); +#endif + + +#if 0 && defined(VBOX_WITH_RESOURCE_USAGE_API) + do { + // Get collector + ComPtr<IPerformanceCollector> collector; + CHECK_ERROR_BREAK(virtualBox, + COMGETTER(PerformanceCollector)(collector.asOutParam())); + + + // Fill base metrics array + Bstr baseMetricNames[] = { L"Net/eth0/Load" }; + com::SafeArray<BSTR> baseMetrics(1); + baseMetricNames[0].cloneTo(&baseMetrics[0]); + + // Get host + ComPtr<IHost> host; + CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam())); + + // Get host network interfaces + // com::SafeIfaceArray<IHostNetworkInterface> hostNetworkInterfaces; + // CHECK_ERROR_BREAK(host, + // COMGETTER(NetworkInterfaces)(ComSafeArrayAsOutParam(hostNetworkInterfaces))); + + // Setup base metrics + // Note that one needs to set up metrics after a session is open for a machine. + com::SafeIfaceArray<IPerformanceMetric> affectedMetrics; + com::SafeIfaceArray<IUnknown> objects(1); + host.queryInterfaceTo(&objects[0]); + CHECK_ERROR_BREAK(collector, SetupMetrics(ComSafeArrayAsInParam(baseMetrics), + ComSafeArrayAsInParam(objects), 1u, 10u, + ComSafeArrayAsOutParam(affectedMetrics))); + listAffectedMetrics(virtualBox, + ComSafeArrayAsInParam(affectedMetrics)); + affectedMetrics.setNull(); + + RTPrintf("Sleeping for 5 seconds...\n"); + RTThreadSleep(5000); // Sleep for 5 seconds + + RTPrintf("\nMetrics collected: --------------------\n"); + queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects)); + } while (false); +#endif /* VBOX_WITH_RESOURCE_USAGE_API */ +#if 0 && defined(VBOX_WITH_RESOURCE_USAGE_API) + do { + // Get collector + ComPtr<IPerformanceCollector> collector; + CHECK_ERROR_BREAK(virtualBox, + COMGETTER(PerformanceCollector)(collector.asOutParam())); + + + // Fill base metrics array + //Bstr baseMetricNames[] = { L"CPU/Load,RAM/Usage" }; + Bstr baseMetricNames[] = { L"RAM/VMM" }; + com::SafeArray<BSTR> baseMetrics(1); + baseMetricNames[0].cloneTo(&baseMetrics[0]); + + // Get host + ComPtr<IHost> host; + CHECK_ERROR_BREAK(virtualBox, COMGETTER(Host)(host.asOutParam())); + + // Get machine + ComPtr<IMachine> machine; + Bstr name = argc > 1 ? argv[1] : "dsl"; + Bstr sessionType = argc > 2 ? argv[2] : "headless"; + RTPrintf("Getting a machine object named '%ls'...\n", name.raw()); + CHECK_ERROR_BREAK(virtualBox, FindMachine(name.raw(), machine.asOutParam())); + + // Open session + ComPtr<IProgress> progress; + RTPrintf("Launching VM process...\n"); + CHECK_ERROR_BREAK(machine, LaunchVMProcess(session, sessionType.raw(), + ComSafeArrayNullInParam(), progress.asOutParam())); + RTPrintf("Waiting for the VM to power on...\n"); + CHECK_ERROR_BREAK(progress, WaitForCompletion(-1)); + + // ComPtr<IMachine> sessionMachine; + // RTPrintf("Getting machine session object...\n"); + // CHECK_ERROR_BREAK(session, COMGETTER(Machine)(sessionMachine.asOutParam())); + + // Setup base metrics + // Note that one needs to set up metrics after a session is open for a machine. + com::SafeIfaceArray<IPerformanceMetric> affectedMetrics; + com::SafeIfaceArray<IUnknown> objects(1); + host.queryInterfaceTo(&objects[0]); + //machine.queryInterfaceTo(&objects[1]); + CHECK_ERROR_BREAK(collector, SetupMetrics(ComSafeArrayAsInParam(baseMetrics), + ComSafeArrayAsInParam(objects), 1u, 10u, + ComSafeArrayAsOutParam(affectedMetrics))); + listAffectedMetrics(virtualBox, + ComSafeArrayAsInParam(affectedMetrics)); + affectedMetrics.setNull(); + + // Get console + ComPtr<IConsole> console; + RTPrintf("Getting console object...\n"); + CHECK_ERROR_BREAK(session, COMGETTER(Console)(console.asOutParam())); + + RTThreadSleep(5000); // Sleep for 5 seconds + + RTPrintf("\nMetrics collected with VM running: --------------------\n"); + queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects)); + + // Pause + //RTPrintf("Press enter to pause the VM execution in the remote session..."); + //getchar(); + CHECK_ERROR_BREAK(console, Pause()); + + RTThreadSleep(5000); // Sleep for 5 seconds + + RTPrintf("\nMetrics collected with VM paused: ---------------------\n"); + queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects)); + + RTPrintf("\nDrop collected metrics: ----------------------------------------\n"); + CHECK_ERROR_BREAK(collector, + SetupMetrics(ComSafeArrayAsInParam(baseMetrics), + ComSafeArrayAsInParam(objects), + 1u, 5u, ComSafeArrayAsOutParam(affectedMetrics))); + listAffectedMetrics(virtualBox, + ComSafeArrayAsInParam(affectedMetrics)); + affectedMetrics.setNull(); + queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects)); + + com::SafeIfaceArray<IUnknown> vmObject(1); + machine.queryInterfaceTo(&vmObject[0]); + + RTPrintf("\nDisable collection of VM metrics: ------------------------------\n"); + CHECK_ERROR_BREAK(collector, + DisableMetrics(ComSafeArrayAsInParam(baseMetrics), + ComSafeArrayAsInParam(vmObject), + ComSafeArrayAsOutParam(affectedMetrics))); + listAffectedMetrics(virtualBox, + ComSafeArrayAsInParam(affectedMetrics)); + affectedMetrics.setNull(); + RTThreadSleep(5000); // Sleep for 5 seconds + queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects)); + + RTPrintf("\nRe-enable collection of all metrics: ---------------------------\n"); + CHECK_ERROR_BREAK(collector, + EnableMetrics(ComSafeArrayAsInParam(baseMetrics), + ComSafeArrayAsInParam(objects), + ComSafeArrayAsOutParam(affectedMetrics))); + listAffectedMetrics(virtualBox, + ComSafeArrayAsInParam(affectedMetrics)); + affectedMetrics.setNull(); + RTThreadSleep(5000); // Sleep for 5 seconds + queryMetrics(virtualBox, collector, ComSafeArrayAsInParam(objects)); + + // Power off + RTPrintf("Press enter to power off VM..."); + getchar(); + CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam())); + RTPrintf("Waiting for the VM to power down...\n"); + CHECK_ERROR_BREAK(progress, WaitForCompletion(-1)); + RTPrintf("Press enter to close this session..."); + getchar(); + session->UnlockMachine(); + } while (false); +#endif /* VBOX_WITH_RESOURCE_USAGE_API */ +#if 0 + // check of OVF appliance handling + /////////////////////////////////////////////////////////////////////////// + do + { + Bstr ovf = argc > 1 ? argv[1] : "someOVF.ovf"; + RTPrintf("Try to open %ls ...\n", ovf.raw()); + + ComPtr<IAppliance> appliance; + CHECK_ERROR_BREAK(virtualBox, + CreateAppliance(appliance.asOutParam())); + CHECK_ERROR_BREAK(appliance, Read(ovf)); + Bstr path; + CHECK_ERROR_BREAK(appliance, COMGETTER(Path)(path.asOutParam())); + RTPrintf("Successfully opened %ls.\n", path.raw()); + CHECK_ERROR_BREAK(appliance, Interpret()); + RTPrintf("Successfully interpreted %ls.\n", path.raw()); + RTPrintf("Appliance:\n"); + // Fetch all disks + com::SafeArray<BSTR> retDisks; + CHECK_ERROR_BREAK(appliance, + COMGETTER(Disks)(ComSafeArrayAsOutParam(retDisks))); + if (retDisks.size() > 0) + { + RTPrintf("Disks:"); + for (unsigned i = 0; i < retDisks.size(); i++) + RTPrintf(" %ls", Bstr(retDisks[i]).raw()); + RTPrintf("\n"); + } + /* Fetch all virtual system descriptions */ + com::SafeIfaceArray<IVirtualSystemDescription> retVSD; + CHECK_ERROR_BREAK(appliance, + COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(retVSD))); + if (retVSD.size() > 0) + { + for (unsigned i = 0; i < retVSD.size(); ++i) + { + com::SafeArray<VirtualSystemDescriptionType_T> retTypes; + com::SafeArray<BSTR> retRefValues; + com::SafeArray<BSTR> retOrigValues; + com::SafeArray<BSTR> retAutoValues; + com::SafeArray<BSTR> retConfiguration; + CHECK_ERROR_BREAK(retVSD[i], + GetDescription(ComSafeArrayAsOutParam(retTypes), + ComSafeArrayAsOutParam(retRefValues), + ComSafeArrayAsOutParam(retOrigValues), + ComSafeArrayAsOutParam(retAutoValues), + ComSafeArrayAsOutParam(retConfiguration))); + + RTPrintf("VirtualSystemDescription:\n"); + for (unsigned a = 0; a < retTypes.size(); ++a) + { + RTPrintf(" %d %ls %ls %ls\n", + retTypes[a], + Bstr(retOrigValues[a]).raw(), + Bstr(retAutoValues[a]).raw(), + Bstr(retConfiguration[a]).raw()); + } + /* Show warnings from interpret */ + com::SafeArray<BSTR> retWarnings; + CHECK_ERROR_BREAK(retVSD[i], + GetWarnings(ComSafeArrayAsOutParam(retWarnings))); + if (retWarnings.size() > 0) + { + RTPrintf("The following warnings occurs on interpret:\n"); + for (unsigned r = 0; r < retWarnings.size(); ++r) + RTPrintf("%ls\n", Bstr(retWarnings[r]).raw()); + RTPrintf("\n"); + } + } + RTPrintf("\n"); + } + RTPrintf("Try to import the appliance ...\n"); + ComPtr<IProgress> progress; + CHECK_ERROR_BREAK(appliance, + ImportMachines(progress.asOutParam())); + CHECK_ERROR(progress, WaitForCompletion(-1)); + if (SUCCEEDED(rc)) + { + /* Check if the import was successfully */ + progress->COMGETTER(ResultCode)(&rc); + if (FAILED(rc)) + { + com::ProgressErrorInfo info(progress); + if (info.isBasicAvailable()) + RTPrintf("Error: failed to import appliance. Error message: %ls\n", info.getText().raw()); + else + RTPrintf("Error: failed to import appliance. No error message available!\n"); + } + else + RTPrintf("Successfully imported the appliance.\n"); + } + + } + while (FALSE); + RTPrintf("\n"); +#endif +#if 0 + // check of network bandwidth control + /////////////////////////////////////////////////////////////////////////// + do + { + Bstr name = argc > 1 ? argv[1] : "ubuntu"; + Bstr sessionType = argc > 2 ? argv[2] : "headless"; + Bstr grpName = "tstAPI"; + { + // Get machine + ComPtr<IMachine> machine; + ComPtr<IBandwidthControl> bwCtrl; + ComPtr<IBandwidthGroup> bwGroup; + ComPtr<INetworkAdapter> nic; + RTPrintf("Getting a machine object named '%ls'...\n", name.raw()); + CHECK_ERROR_BREAK(virtualBox, FindMachine(name.raw(), machine.asOutParam())); + /* open a session for the VM (new or shared) */ + CHECK_ERROR_BREAK(machine, LockMachine(session, LockType_Shared)); + SessionType_T st; + CHECK_ERROR_BREAK(session, COMGETTER(Type)(&st)); + bool fRunTime = (st == SessionType_Shared); + if (fRunTime) + { + RTPrintf("Machine %ls must not be running!\n"); + break; + } + /* get the mutable session machine */ + session->COMGETTER(Machine)(machine.asOutParam()); + CHECK_ERROR_BREAK(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam())); + + RTPrintf("Creating bandwidth group named '%ls'...\n", grpName.raw()); + CHECK_ERROR_BREAK(bwCtrl, CreateBandwidthGroup(grpName.raw(), BandwidthGroupType_Network, 123)); + + + CHECK_ERROR_BREAK(bwCtrl, GetBandwidthGroup(grpName.raw(), bwGroup.asOutParam())); + CHECK_ERROR_BREAK(machine, GetNetworkAdapter(0, nic.asOutParam())); + RTPrintf("Assigning the group to the first network adapter...\n"); + CHECK_ERROR_BREAK(nic, COMSETTER(BandwidthGroup)(bwGroup)); + CHECK_ERROR_BREAK(machine, SaveSettings()); + RTPrintf("Press enter to close this session..."); + getchar(); + session->UnlockMachine(); + } + { + // Get machine + ComPtr<IMachine> machine; + ComPtr<IBandwidthControl> bwCtrl; + ComPtr<IBandwidthGroup> bwGroup; + Bstr grpNameReadFromNic; + ComPtr<INetworkAdapter> nic; + RTPrintf("Getting a machine object named '%ls'...\n", name.raw()); + CHECK_ERROR_BREAK(virtualBox, FindMachine(name.raw(), machine.asOutParam())); + /* open a session for the VM (new or shared) */ + CHECK_ERROR_BREAK(machine, LockMachine(session, LockType_Shared)); + /* get the mutable session machine */ + session->COMGETTER(Machine)(machine.asOutParam()); + CHECK_ERROR_BREAK(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam())); + CHECK_ERROR_BREAK(machine, GetNetworkAdapter(0, nic.asOutParam())); + + RTPrintf("Reading the group back from the first network adapter...\n"); + CHECK_ERROR_BREAK(nic, COMGETTER(BandwidthGroup)(bwGroup.asOutParam())); + if (bwGroup.isNull()) + RTPrintf("Error: Bandwidth group is null at the first network adapter!\n"); + else + { + CHECK_ERROR_BREAK(bwGroup, COMGETTER(Name)(grpNameReadFromNic.asOutParam())); + if (grpName != grpNameReadFromNic) + RTPrintf("Error: Bandwidth group names do not match (%ls != %ls)!\n", grpName.raw(), grpNameReadFromNic.raw()); + else + RTPrintf("Successfully retrieved bandwidth group attribute from NIC (name=%ls)\n", grpNameReadFromNic.raw()); + ComPtr<IBandwidthGroup> bwGroupEmpty; + RTPrintf("Assigning an empty group to the first network adapter...\n"); + CHECK_ERROR_BREAK(nic, COMSETTER(BandwidthGroup)(bwGroupEmpty)); + } + RTPrintf("Removing bandwidth group named '%ls'...\n", grpName.raw()); + CHECK_ERROR_BREAK(bwCtrl, DeleteBandwidthGroup(grpName.raw())); + CHECK_ERROR_BREAK(machine, SaveSettings()); + RTPrintf("Press enter to close this session..."); + getchar(); + session->UnlockMachine(); + } + } while (FALSE); + RTPrintf("\n"); +#endif + + RTPrintf("Press enter to release Session and VirtualBox instances..."); + getchar(); + + // end "all-stuff" scope + //////////////////////////////////////////////////////////////////////////// + } + while (0); + + RTPrintf("Press enter to shutdown COM..."); + getchar(); + + com::Shutdown(); + + RTPrintf("tstAPI FINISHED.\n"); + + return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; +} + +#ifdef VBOX_WITH_RESOURCE_USAGE_API + +static void queryMetrics(ComPtr<IVirtualBox> aVirtualBox, + ComPtr<IPerformanceCollector> collector, + ComSafeArrayIn(IUnknown *, objects)) +{ + HRESULT rc; + + //Bstr metricNames[] = { L"CPU/Load/User:avg,CPU/Load/System:avg,CPU/Load/Idle:avg,RAM/Usage/Total,RAM/Usage/Used:avg" }; + Bstr metricNames[] = { L"*" }; + com::SafeArray<BSTR> metrics(1); + metricNames[0].cloneTo(&metrics[0]); + com::SafeArray<BSTR> retNames; + com::SafeIfaceArray<IUnknown> retObjects; + com::SafeArray<BSTR> retUnits; + com::SafeArray<ULONG> retScales; + com::SafeArray<ULONG> retSequenceNumbers; + com::SafeArray<ULONG> retIndices; + com::SafeArray<ULONG> retLengths; + com::SafeArray<LONG> retData; + CHECK_ERROR(collector, QueryMetricsData(ComSafeArrayAsInParam(metrics), + ComSafeArrayInArg(objects), + ComSafeArrayAsOutParam(retNames), + ComSafeArrayAsOutParam(retObjects), + ComSafeArrayAsOutParam(retUnits), + ComSafeArrayAsOutParam(retScales), + ComSafeArrayAsOutParam(retSequenceNumbers), + ComSafeArrayAsOutParam(retIndices), + ComSafeArrayAsOutParam(retLengths), + ComSafeArrayAsOutParam(retData))); + RTPrintf("Object Metric Values\n" + "---------- -------------------- --------------------------------------------\n"); + for (unsigned i = 0; i < retNames.size(); i++) + { + Bstr metricUnit(retUnits[i]); + Bstr metricName(retNames[i]); + RTPrintf("%-10ls %-20ls ", getObjectName(aVirtualBox, retObjects[i]).raw(), metricName.raw()); + const char *separator = ""; + for (unsigned j = 0; j < retLengths[i]; j++) + { + if (retScales[i] == 1) + RTPrintf("%s%d %ls", separator, retData[retIndices[i] + j], metricUnit.raw()); + else + RTPrintf("%s%d.%02d%ls", separator, retData[retIndices[i] + j] / retScales[i], + (retData[retIndices[i] + j] * 100 / retScales[i]) % 100, metricUnit.raw()); + separator = ", "; + } + RTPrintf("\n"); + } +} + +static Bstr getObjectName(ComPtr<IVirtualBox> aVirtualBox, + ComPtr<IUnknown> aObject) +{ + HRESULT rc; + + ComPtr<IHost> host = aObject; + if (!host.isNull()) + return Bstr("host"); + + ComPtr<IMachine> machine = aObject; + if (!machine.isNull()) + { + Bstr name; + CHECK_ERROR(machine, COMGETTER(Name)(name.asOutParam())); + if (SUCCEEDED(rc)) + return name; + } + return Bstr("unknown"); +} + +static void listAffectedMetrics(ComPtr<IVirtualBox> aVirtualBox, + ComSafeArrayIn(IPerformanceMetric*, aMetrics)) +{ + HRESULT rc; + com::SafeIfaceArray<IPerformanceMetric> metrics(ComSafeArrayInArg(aMetrics)); + if (metrics.size()) + { + ComPtr<IUnknown> object; + Bstr metricName; + RTPrintf("The following metrics were modified:\n\n" + "Object Metric\n" + "---------- --------------------\n"); + for (size_t i = 0; i < metrics.size(); i++) + { + CHECK_ERROR(metrics[i], COMGETTER(Object)(object.asOutParam())); + CHECK_ERROR(metrics[i], COMGETTER(MetricName)(metricName.asOutParam())); + RTPrintf("%-10ls %-20ls\n", + getObjectName(aVirtualBox, object).raw(), metricName.raw()); + } + RTPrintf("\n"); + } + else + { + RTPrintf("No metrics match the specified filter!\n"); + } +} + +#endif /* VBOX_WITH_RESOURCE_USAGE_API */ +/* vim: set shiftwidth=4 tabstop=4 expandtab: */ diff --git a/src/VBox/Main/testcase/tstBstr.cpp b/src/VBox/Main/testcase/tstBstr.cpp new file mode 100644 index 00000000..1b702758 --- /dev/null +++ b/src/VBox/Main/testcase/tstBstr.cpp @@ -0,0 +1,295 @@ +/* $Id: tstBstr.cpp $ */ +/** @file + * API Glue Testcase - Bstr. + */ + +/* + * Copyright (C) 2019-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/com/string.h> + +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/test.h> +#include <iprt/uni.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define CHECK_BSTR(a_Expr, a_bstr, a_szExpected) \ + do { \ + a_Expr; \ + size_t cchExpect = RTStrCalcUtf16Len(a_szExpected); \ + if ((a_bstr).length() != cchExpect) \ + RTTestFailed(hTest, "line %u: length() -> %zu, expected %zu (%ls vs %s)", \ + __LINE__, (a_bstr).length(), cchExpect, (a_bstr).raw(), a_szExpected); \ + else \ + { \ + int iDiff = (a_bstr).compareUtf8(a_szExpected); \ + if (iDiff) \ + RTTestFailed(hTest, "line %u: compareUtf8() -> %d: %ls vs %s", \ + __LINE__, iDiff, (a_bstr).raw(), a_szExpected); \ + } \ + } while (0) + + + +static void testBstrPrintf(RTTEST hTest) +{ + RTTestSub(hTest, "Bstr::printf"); + + com::Bstr bstr1; + CHECK_BSTR(bstr1.printf(""), bstr1, ""); + CHECK_BSTR(bstr1.printf("1234098694"), bstr1, "1234098694"); + CHECK_BSTR(bstr1.printf("%u-%u-%u-%s-%u", 42, 999, 42, "asdkfhjasldfk0", 42), + bstr1, "42-999-42-asdkfhjasldfk0-42"); + + com::Bstr bstr2; + CHECK_BSTR(bstr2.printf("%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls::%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls::%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls-%ls", + bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), + bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), + bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw(), bstr1.raw()), + bstr2, "42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42::42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42::42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42"); + CHECK_BSTR(bstr2.appendPrintf("-9999998888888777776666655554443322110!"), + bstr2, "42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42::42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42::42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-9999998888888777776666655554443322110!"); + CHECK_BSTR(bstr2.appendPrintf("!"), + bstr2, "42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42::42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42::42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-42-999-42-asdkfhjasldfk0-42-9999998888888777776666655554443322110!!"); +} + +static void testBstrAppend(RTTEST hTest) +{ + RTTestSub(hTest, "Bstr::append"); + + /* C-string source: */ + com::Bstr bstr1; + CHECK_BSTR(bstr1.append("1234"), bstr1, "1234"); + CHECK_BSTR(bstr1.append("56"), bstr1, "123456"); + CHECK_BSTR(bstr1.append("7"), bstr1, "1234567"); + CHECK_BSTR(bstr1.append("89abcdefghijklmnopqrstuvwxyz"), bstr1, "123456789abcdefghijklmnopqrstuvwxyz"); + CHECK_BSTR(bstr1.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + CHECK_BSTR(bstr1.append("123456789abcdefghijklmnopqrstuvwxyz"), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz"); + CHECK_BSTR(bstr1.append("_"), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + CHECK_BSTR(bstr1.append(""), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + + com::Bstr bstr2; + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(""), VINF_SUCCESS), bstr2, ""); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow("1234"), VINF_SUCCESS), bstr2, "1234"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow("56"), VINF_SUCCESS), bstr2, "123456"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow("7"), VINF_SUCCESS), bstr2, "1234567"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow("89abcdefghijklmnopqrstuvwxyz"), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyz"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow("123456789abcdefghijklmnopqrstuvwxyz"), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow("_"), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(""), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + + /* Bstr source: */ + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(bstr1), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr1.appendNoThrow(bstr2), VINF_SUCCESS), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + + com::Bstr const bstrWord1("word"); + CHECK_BSTR(bstr1.setNull(), bstr1, ""); + CHECK_BSTR(bstr1.append(bstr2, 5, 10), bstr1, "6789abcdef"); + CHECK_BSTR(bstr1.append(bstr2, 4096, 10), bstr1, "6789abcdef"); + CHECK_BSTR(bstr1.append(bstrWord1, 1), bstr1, "6789abcdeford"); + CHECK_BSTR(bstr1.append(bstrWord1, 1,1), bstr1, "6789abcdefordo"); + CHECK_BSTR(bstr1.append(bstrWord1, 1,2), bstr1, "6789abcdefordoor"); + CHECK_BSTR(bstr1.append(bstrWord1, 1,3), bstr1, "6789abcdefordoorord"); + CHECK_BSTR(bstr1.append(bstrWord1, 1,4), bstr1, "6789abcdefordoorordord"); + CHECK_BSTR(bstr1.append(bstrWord1, 3,1), bstr1, "6789abcdefordoorordordd"); + CHECK_BSTR(bstr1.append(bstrWord1, 3,2), bstr1, "6789abcdefordoorordorddd"); + CHECK_BSTR(bstr1.append(bstrWord1, 3), bstr1, "6789abcdefordoorordordddd"); + + com::Bstr bstr3; + CHECK_BSTR(bstr3.setNull(), bstr3, ""); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstr2, 5, 10), VINF_SUCCESS), bstr3, "6789abcdef"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstr2, 4096, 10),VINF_SUCCESS), bstr3, "6789abcdef"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 1), VINF_SUCCESS), bstr3, "6789abcdeford"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 1,1), VINF_SUCCESS), bstr3, "6789abcdefordo"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 1,2), VINF_SUCCESS), bstr3, "6789abcdefordoor"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 1,3), VINF_SUCCESS), bstr3, "6789abcdefordoorord"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 1,4), VINF_SUCCESS), bstr3, "6789abcdefordoorordord"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 3,1), VINF_SUCCESS), bstr3, "6789abcdefordoorordordd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 3,2), VINF_SUCCESS), bstr3, "6789abcdefordoorordorddd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 3), VINF_SUCCESS), bstr3, "6789abcdefordoorordordddd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord1, 3), VINF_SUCCESS), bstr3, "6789abcdefordoorordorddddd"); + com::Bstr const bstrWord2("-SEP-"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstrWord2, 0), VINF_SUCCESS), bstr3, "6789abcdefordoorordorddddd-SEP-"); + + /* CBSTR source: */ + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(bstr1.raw()), VINF_SUCCESS), bstr3, "6789abcdefordoorordorddddd-SEP-6789abcdefordoorordordddd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr1.appendNoThrow(bstr3.raw()), VINF_SUCCESS), bstr1, "6789abcdefordoorordordddd6789abcdefordoorordorddddd-SEP-6789abcdefordoorordordddd"); + + CBSTR const pwsz2 = bstr2.raw(); + CBSTR const pwszWord1 = bstrWord1.raw(); + CHECK_BSTR(bstr1.setNull(), bstr1, ""); + CHECK_BSTR(bstr1.append(pwsz2 + 5, 10), bstr1, "6789abcdef"); + CHECK_BSTR(bstr1.append(pwszWord1 + 1), bstr1, "6789abcdeford"); + CHECK_BSTR(bstr1.append(pwszWord1 + 1, 1), bstr1, "6789abcdefordo"); + CHECK_BSTR(bstr1.append(pwszWord1 + 1, 2), bstr1, "6789abcdefordoor"); + CHECK_BSTR(bstr1.append(pwszWord1 + 1, 3), bstr1, "6789abcdefordoorord"); + CHECK_BSTR(bstr1.append(pwszWord1 + 1, 4), bstr1, "6789abcdefordoorordord"); + CHECK_BSTR(bstr1.append(pwszWord1 + 3, 1), bstr1, "6789abcdefordoorordordd"); + CHECK_BSTR(bstr1.append(pwszWord1 + 3, 2), bstr1, "6789abcdefordoorordorddd"); + CHECK_BSTR(bstr1.append(pwszWord1 + 3), bstr1, "6789abcdefordoorordordddd"); + + CHECK_BSTR(bstr3.setNull(), bstr3, ""); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwsz2 + 5, 10), VINF_SUCCESS), bstr3, "6789abcdef"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 1), VINF_SUCCESS), bstr3, "6789abcdeford"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 1, 1), VINF_SUCCESS), bstr3, "6789abcdefordo"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 1, 2), VINF_SUCCESS), bstr3, "6789abcdefordoor"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 1, 3), VINF_SUCCESS), bstr3, "6789abcdefordoorord"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 1, 4), VINF_SUCCESS), bstr3, "6789abcdefordoorordord"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 3, 1), VINF_SUCCESS), bstr3, "6789abcdefordoorordordd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 3, 2), VINF_SUCCESS), bstr3, "6789abcdefordoorordorddd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 3), VINF_SUCCESS), bstr3, "6789abcdefordoorordordddd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(pwszWord1 + 3), VINF_SUCCESS), bstr3, "6789abcdefordoorordorddddd"); + + /* RTCString source: */ + bstr1.setNull(); + CHECK_BSTR(bstr1.append(RTCString("1234")), bstr1, "1234"); + CHECK_BSTR(bstr1.append(RTCString("56")), bstr1, "123456"); + CHECK_BSTR(bstr1.append(RTCString("7")), bstr1, "1234567"); + CHECK_BSTR(bstr1.append(RTCString("89abcdefghijklmnopqrstuvwxyz")), bstr1, "123456789abcdefghijklmnopqrstuvwxyz"); + CHECK_BSTR(bstr1.append(RTCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ")), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + CHECK_BSTR(bstr1.append(RTCString("123456789abcdefghijklmnopqrstuvwxyz")), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz"); + CHECK_BSTR(bstr1.append(RTCString("_")), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + CHECK_BSTR(bstr1.append(RTCString()), bstr1, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + + bstr2.setNull(); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("")), VINF_SUCCESS), bstr2, ""); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("1234")), VINF_SUCCESS), bstr2, "1234"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("56")), VINF_SUCCESS), bstr2, "123456"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("7")), VINF_SUCCESS), bstr2, "1234567"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("89abcdefghijklmnopqrstuvwxyz")), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyz"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ")), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("123456789abcdefghijklmnopqrstuvwxyz")), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("_")), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr2.appendNoThrow(RTCString("")), VINF_SUCCESS), bstr2, "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz_"); + + RTCString const strWord1 = "word"; + CHECK_BSTR(bstr1.setNull(), bstr1, ""); + CHECK_BSTR(bstr1.append(com::Utf8Str(bstr2), 5, 10), bstr1, "6789abcdef"); + CHECK_BSTR(bstr1.append(com::Utf8Str(bstr2), 4096, 10), bstr1, "6789abcdef"); + CHECK_BSTR(bstr1.append(strWord1, 1), bstr1, "6789abcdeford"); + CHECK_BSTR(bstr1.append(strWord1, 1,1), bstr1, "6789abcdefordo"); + CHECK_BSTR(bstr1.append(strWord1, 1,2), bstr1, "6789abcdefordoor"); + CHECK_BSTR(bstr1.append(strWord1, 1,3), bstr1, "6789abcdefordoorord"); + CHECK_BSTR(bstr1.append(strWord1, 1,4), bstr1, "6789abcdefordoorordord"); + CHECK_BSTR(bstr1.append(strWord1, 3,1), bstr1, "6789abcdefordoorordordd"); + CHECK_BSTR(bstr1.append(strWord1, 3,2), bstr1, "6789abcdefordoorordorddd"); + CHECK_BSTR(bstr1.append(strWord1, 3), bstr1, "6789abcdefordoorordordddd"); + + CHECK_BSTR(bstr3.setNull(), bstr3, ""); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(com::Utf8Str(bstr2), 5, 10), VINF_SUCCESS), bstr3, "6789abcdef"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(com::Utf8Str(bstr2), 4096, 10),VINF_SUCCESS), bstr3, "6789abcdef"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 1), VINF_SUCCESS), bstr3, "6789abcdeford"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 1,1), VINF_SUCCESS), bstr3, "6789abcdefordo"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 1,2), VINF_SUCCESS), bstr3, "6789abcdefordoor"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 1,3), VINF_SUCCESS), bstr3, "6789abcdefordoorord"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 1,4), VINF_SUCCESS), bstr3, "6789abcdefordoorordord"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 3,1), VINF_SUCCESS), bstr3, "6789abcdefordoorordordd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 3,2), VINF_SUCCESS), bstr3, "6789abcdefordoorordorddd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 3), VINF_SUCCESS), bstr3, "6789abcdefordoorordordddd"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow(strWord1, 3), VINF_SUCCESS), bstr3, "6789abcdefordoorordorddddd"); + + /* char: */ + CHECK_BSTR(bstr1.setNull(), bstr1, ""); + CHECK_BSTR(bstr1.append('-'), bstr1, "-"); + CHECK_BSTR(bstr1.append('a'), bstr1, "-a"); + CHECK_BSTR(bstr1.append('b'), bstr1, "-ab"); + CHECK_BSTR(bstr1.append('Z'), bstr1, "-abZ"); + CHECK_BSTR(bstr1.append('-'), bstr1, "-abZ-"); + + CHECK_BSTR(bstr3.setNull(), bstr3, ""); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow('-'), VINF_SUCCESS), bstr3, "-"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow('a'), VINF_SUCCESS), bstr3, "-a"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow('b'), VINF_SUCCESS), bstr3, "-ab"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow('Z'), VINF_SUCCESS), bstr3, "-abZ"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendNoThrow('-'), VINF_SUCCESS), bstr3, "-abZ-"); + + /* unicode codepoint: */ + CHECK_BSTR(bstr1.setNull(), bstr1, ""); + CHECK_BSTR(bstr1.appendCodePoint('-'), bstr1, "-"); + CHECK_BSTR(bstr1.appendCodePoint('a'), bstr1, "-a"); + CHECK_BSTR(bstr1.appendCodePoint('b'), bstr1, "-ab"); + CHECK_BSTR(bstr1.appendCodePoint('Z'), bstr1, "-abZ"); + CHECK_BSTR(bstr1.appendCodePoint('-'), bstr1, "-abZ-"); + CHECK_BSTR(bstr1.appendCodePoint(0x39f), bstr1, "-abZ-\xce\x9f"); + CHECK_BSTR(bstr1.appendCodePoint(0x1f50), bstr1, "-abZ-\xce\x9f\xe1\xbd\x90"); + CHECK_BSTR(bstr1.appendCodePoint(0x3c7), bstr1, "-abZ-\xce\x9f\xe1\xbd\x90\xcf\x87"); + CHECK_BSTR(bstr1.appendCodePoint(0x1f76), bstr1, "-abZ-\xce\x9f\xe1\xbd\x90\xcf\x87\xe1\xbd\xb6"); + + CHECK_BSTR(bstr3.setNull(), bstr3, ""); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow('-'), VINF_SUCCESS), bstr3, "-"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow('a'), VINF_SUCCESS), bstr3, "-a"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow('b'), VINF_SUCCESS), bstr3, "-ab"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow('Z'), VINF_SUCCESS), bstr3, "-abZ"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow('-'), VINF_SUCCESS), bstr3, "-abZ-"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow(0x39f), VINF_SUCCESS), bstr3, "-abZ-\xce\x9f"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow(0x1f50), VINF_SUCCESS), bstr3, "-abZ-\xce\x9f\xe1\xbd\x90"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow(0x3c7), VINF_SUCCESS), bstr3, "-abZ-\xce\x9f\xe1\xbd\x90\xcf\x87"); + CHECK_BSTR(RTTESTI_CHECK_RC(bstr3.appendCodePointNoThrow(0x1f76), VINF_SUCCESS), bstr3, "-abZ-\xce\x9f\xe1\xbd\x90\xcf\x87\xe1\xbd\xb6"); +} + + +static void testBstrErase(RTTEST hTest) +{ + RTTestSub(hTest, "Bstr::erase"); + + com::Bstr bstr1; + CHECK_BSTR(bstr1.erase(), bstr1, ""); + CHECK_BSTR(bstr1.erase(99), bstr1, ""); + CHECK_BSTR(bstr1.erase(99,999), bstr1, ""); + + CHECK_BSTR(bstr1 = "asdlfjhasldfjhaldfhjalhjsdf", bstr1, "asdlfjhasldfjhaldfhjalhjsdf"); + CHECK_BSTR(bstr1.erase(8, 9), bstr1, "asdlfjhafhjalhjsdf"); + CHECK_BSTR(bstr1.erase(17, 20), bstr1, "asdlfjhafhjalhjsd"); + CHECK_BSTR(bstr1.erase(16, 1), bstr1, "asdlfjhafhjalhjs"); + CHECK_BSTR(bstr1.erase(15, 0), bstr1, "asdlfjhafhjalhjs"); + CHECK_BSTR(bstr1.erase(13, 3), bstr1, "asdlfjhafhjal"); + CHECK_BSTR(bstr1.erase(3, 3), bstr1, "asdhafhjal"); + CHECK_BSTR(bstr1.erase(), bstr1, ""); +} + + +int main() +{ + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstBstr", &hTest); + if (rcExit == RTEXITCODE_SUCCESS) + { + RTTestBanner(hTest); + + testBstrPrintf(hTest); + testBstrAppend(hTest); + testBstrErase(hTest); + + rcExit = RTTestSummaryAndDestroy(hTest); + } + return rcExit; +} + diff --git a/src/VBox/Main/testcase/tstCollector.cpp b/src/VBox/Main/testcase/tstCollector.cpp new file mode 100644 index 00000000..4f42ec01 --- /dev/null +++ b/src/VBox/Main/testcase/tstCollector.cpp @@ -0,0 +1,588 @@ +/* $Id: tstCollector.cpp $ */ +/** @file + * VirtualBox Main - Performance collector classes test cases. + */ + +/* + * Copyright (C) 2008-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#ifdef RT_OS_DARWIN +# include "../src-server/darwin/PerformanceDarwin.cpp" +#endif +#ifdef RT_OS_FREEBSD +# include "../src-server/freebsd/PerformanceFreeBSD.cpp" +#endif +#ifdef RT_OS_LINUX +# include "../src-server/linux/PerformanceLinux.cpp" +#endif +#ifdef RT_OS_OS2 +# include "../src-server/os2/PerformanceOS2.cpp" +#endif +#ifdef RT_OS_SOLARIS +# include "../src-server/solaris/PerformanceSolaris.cpp" +#endif +#ifdef RT_OS_WINDOWS +# define _WIN32_DCOM +# include <iprt/win/objidl.h> +# include <iprt/win/objbase.h> +# include "../src-server/win/PerformanceWin.cpp" +#endif + +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <iprt/env.h> +#include <iprt/err.h> +#include <iprt/process.h> +#include <iprt/thread.h> +#include <iprt/time.h> + +#define RUN_TIME_MS 1000 + +#define N_CALLS(n, fn) \ + do {\ + for (int call = 0; call < n; ++call) \ + rc = collector->fn; \ + if (RT_FAILURE(rc)) \ + RTPrintf("tstCollector: "#fn" -> %Rrc\n", rc); \ + } while (0) + +#define CALLS_PER_SECOND(fn, args) \ + do { \ + nCalls = 0; \ + start = RTTimeMilliTS(); \ + do { \ + rc = collector->fn args; \ + if (RT_FAILURE(rc)) \ + break; \ + ++nCalls; \ + } while (RTTimeMilliTS() - start < RUN_TIME_MS); \ + if (RT_FAILURE(rc)) \ + RTPrintf("tstCollector: "#fn" -> %Rrc\n", rc); \ + else \ + RTPrintf("%70s -- %u calls per second\n", #fn, nCalls); \ + } while (0) + +void shutdownProcessList(std::vector<RTPROCESS> const &rProcesses) +{ + for (size_t i = 0; i < rProcesses.size(); i++) + RTProcTerminate(rProcesses[i]); +} + +void measurePerformance(pm::CollectorHAL *collector, const char *pszName, int cVMs) +{ + + const char * const args[] = { pszName, "-child", NULL }; + pm::CollectorHints hints; + std::vector<RTPROCESS> processes; + + hints.collectHostCpuLoad(); + hints.collectHostRamUsage(); + /* Start fake VMs */ + for (int i = 0; i < cVMs; ++i) + { + RTPROCESS pid; + int rc = RTProcCreate(pszName, args, RTENV_DEFAULT, 0, &pid); + if (RT_FAILURE(rc)) + { + hints.getProcesses(processes); + shutdownProcessList(processes); + + RTPrintf("tstCollector: RTProcCreate() -> %Rrc\n", rc); + return; + } + hints.collectProcessCpuLoad(pid); + hints.collectProcessRamUsage(pid); + } + + hints.getProcesses(processes); + RTThreadSleep(30000); // Let children settle for half a minute + + int rc; + ULONG tmp; + uint64_t tmp64; + uint64_t start; + unsigned int nCalls; + /* Pre-collect */ + CALLS_PER_SECOND(preCollect, (hints, 0)); + /* Host CPU load */ + CALLS_PER_SECOND(getRawHostCpuLoad, (&tmp64, &tmp64, &tmp64)); + /* Process CPU load */ + CALLS_PER_SECOND(getRawProcessCpuLoad, (processes[nCalls % cVMs], &tmp64, &tmp64, &tmp64)); + /* Host CPU speed */ + CALLS_PER_SECOND(getHostCpuMHz, (&tmp)); + /* Host RAM usage */ + CALLS_PER_SECOND(getHostMemoryUsage, (&tmp, &tmp, &tmp)); + /* Process RAM usage */ + CALLS_PER_SECOND(getProcessMemoryUsage, (processes[nCalls % cVMs], &tmp)); + + start = RTTimeNanoTS(); + + int times; + for (times = 0; times < 100; times++) + { + /* Pre-collect */ + N_CALLS(1, preCollect(hints, 0)); + /* Host CPU load */ + N_CALLS(1, getRawHostCpuLoad(&tmp64, &tmp64, &tmp64)); + /* Host CPU speed */ + N_CALLS(1, getHostCpuMHz(&tmp)); + /* Host RAM usage */ + N_CALLS(1, getHostMemoryUsage(&tmp, &tmp, &tmp)); + /* Process CPU load */ + N_CALLS(cVMs, getRawProcessCpuLoad(processes[call], &tmp64, &tmp64, &tmp64)); + /* Process RAM usage */ + N_CALLS(cVMs, getProcessMemoryUsage(processes[call], &tmp)); + } + RTPrintf("\n%d VMs -- %u%% of CPU time\n", cVMs, (unsigned)((double)(RTTimeNanoTS() - start) / 10000000.0 / times)); + + /* Shut down fake VMs */ + shutdownProcessList(processes); +} + +#ifdef RT_OS_SOLARIS +#define NETIFNAME "net0" +#else +#define NETIFNAME "eth0" +#endif +int testNetwork(pm::CollectorHAL *collector) +{ + pm::CollectorHints hints; + uint64_t hostRxStart, hostTxStart; + uint64_t hostRxStop, hostTxStop, speed = 125000000; /* Assume 1Gbit/s */ + + RTPrintf("tstCollector: TESTING - Network load, sleeping for 5 s...\n"); + + hostRxStart = hostTxStart = 0; + int rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostNetworkLoad(NETIFNAME, &hostRxStart, &hostTxStart); + if (rc == VERR_NOT_IMPLEMENTED) + RTPrintf("tstCollector: getRawHostNetworkLoad() not implemented, skipping\n"); + else + { + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc); + return 1; + } + + RTThreadSleep(5000); // Sleep for five seconds + + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + hostRxStop = hostRxStart; + hostTxStop = hostTxStart; + rc = collector->getRawHostNetworkLoad(NETIFNAME, &hostRxStop, &hostTxStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostNetworkLoad() -> %Rrc\n", rc); + return 1; + } + RTPrintf("tstCollector: host network speed = %llu bytes/sec (%llu mbit/sec)\n", + speed, speed/(1000000/8)); + RTPrintf("tstCollector: host network rx = %llu bytes/sec (%llu mbit/sec, %u.%u %%)\n", + (hostRxStop - hostRxStart)/5, (hostRxStop - hostRxStart)/(5000000/8), + (hostRxStop - hostRxStart) * 100 / (speed * 5), + (hostRxStop - hostRxStart) * 10000 / (speed * 5) % 100); + RTPrintf("tstCollector: host network tx = %llu bytes/sec (%llu mbit/sec, %u.%u %%)\n\n", + (hostTxStop - hostTxStart)/5, (hostTxStop - hostTxStart)/(5000000/8), + (hostTxStop - hostTxStart) * 100 / (speed * 5), + (hostTxStop - hostTxStart) * 10000 / (speed * 5) % 100); + } + + return 0; +} + +#define FSNAME "/" +int testFsUsage(pm::CollectorHAL *collector) +{ + RTPrintf("tstCollector: TESTING - File system usage\n"); + + ULONG total, used, available; + + int rc = collector->getHostFilesystemUsage(FSNAME, &total, &used, &available); + if (rc == VERR_NOT_IMPLEMENTED) + RTPrintf("tstCollector: getHostFilesystemUsage() not implemented, skipping\n"); + else + { + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getHostFilesystemUsage() -> %Rrc\n", rc); + return 1; + } + RTPrintf("tstCollector: host root fs total = %lu MB\n", total); + RTPrintf("tstCollector: host root fs used = %lu MB\n", used); + RTPrintf("tstCollector: host root fs available = %lu MB\n\n", available); + } + return 0; +} + +int testDisk(pm::CollectorHAL *collector) +{ + pm::CollectorHints hints; + uint64_t diskMsStart, totalMsStart; + uint64_t diskMsStop, totalMsStop; + + pm::DiskList disksUsage, disksLoad; + int rc = collector->getDiskListByFs(FSNAME, disksUsage, disksLoad); + if (rc == VERR_NOT_IMPLEMENTED) + RTPrintf("tstCollector: getDiskListByFs() not implemented, skipping\n"); + else + { + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getDiskListByFs(%s) -> %Rrc\n", FSNAME, rc); + return 1; + } + if (disksUsage.empty()) + { + RTPrintf("tstCollector: getDiskListByFs(%s) returned empty usage list\n", FSNAME); + return 0; + } + if (disksLoad.empty()) + { + RTPrintf("tstCollector: getDiskListByFs(%s) returned empty usage list\n", FSNAME); + return 0; + } + + pm::DiskList::iterator it; + for (it = disksUsage.begin(); it != disksUsage.end(); ++it) + { + uint64_t diskSize = 0; + rc = collector->getHostDiskSize(it->c_str(), &diskSize); + RTPrintf("tstCollector: TESTING - Disk size (%s) = %llu\n", it->c_str(), diskSize); + if (rc == VERR_FILE_NOT_FOUND) + RTPrintf("tstCollector: getHostDiskSize(%s) returned VERR_FILE_NOT_FOUND\n", it->c_str()); + else if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getHostDiskSize() -> %Rrc\n", rc); + return 1; + } + } + + for (it = disksLoad.begin(); it != disksLoad.end(); ++it) + { + RTPrintf("tstCollector: TESTING - Disk utilization (%s), sleeping for 5 s...\n", it->c_str()); + + hints.collectHostCpuLoad(); + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostDiskLoad(it->c_str(), &diskMsStart, &totalMsStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostDiskLoad() -> %Rrc\n", rc); + return 1; + } + + RTThreadSleep(5000); // Sleep for five seconds + + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostDiskLoad(it->c_str(), &diskMsStop, &totalMsStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostDiskLoad() -> %Rrc\n", rc); + return 1; + } + RTPrintf("tstCollector: host disk util = %llu msec (%u.%u %%), total = %llu msec\n\n", + (diskMsStop - diskMsStart), + (unsigned)((diskMsStop - diskMsStart) * 100 / (totalMsStop - totalMsStart)), + (unsigned)((diskMsStop - diskMsStart) * 10000 / (totalMsStop - totalMsStart) % 100), + totalMsStop - totalMsStart); + } + } + + return 0; +} + + + +int main(int argc, char *argv[]) +{ + bool cpuTest, ramTest, netTest, diskTest, fsTest, perfTest; + cpuTest = ramTest = netTest = diskTest = fsTest = perfTest = false; + /* + * Initialize the VBox runtime without loading + * the support driver. + */ + int rc = RTR3InitExe(argc, &argv, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: RTR3InitExe() -> %d\n", rc); + return 1; + } + if (argc > 1) + { + if (!strcmp(argv[1], "-child")) + { + /* We have spawned ourselves as a child process -- scratch the leg */ + RTThreadSleep(1000000); + return 1; + } + for (int i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-cpu")) + cpuTest = true; + else if (!strcmp(argv[i], "-ram")) + ramTest = true; + else if (!strcmp(argv[i], "-net")) + netTest = true; + else if (!strcmp(argv[i], "-disk")) + diskTest = true; + else if (!strcmp(argv[i], "-fs")) + fsTest = true; + else if (!strcmp(argv[i], "-perf")) + perfTest = true; + else + { + RTPrintf("tstCollector: Unknown option: %s\n", argv[i]); + return 2; + } + } + } + else + cpuTest = ramTest = netTest = diskTest = fsTest = perfTest = true; + +#ifdef RT_OS_WINDOWS + HRESULT hRes = CoInitialize(NULL); + /* + * Need to initialize security to access performance enumerators. + */ + hRes = CoInitializeSecurity( + NULL, + -1, + NULL, + NULL, + RPC_C_AUTHN_LEVEL_NONE, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, EOAC_NONE, 0); +#endif + + pm::CollectorHAL *collector = pm::createHAL(); + if (!collector) + { + RTPrintf("tstCollector: createMetricFactory() failed\n"); + return 1; + } + + pm::CollectorHints hints; + if (cpuTest) + { + hints.collectHostCpuLoad(); + hints.collectProcessCpuLoad(RTProcSelf()); + } + if (ramTest) + { + hints.collectHostRamUsage(); + hints.collectProcessRamUsage(RTProcSelf()); + } + + uint64_t start; + + uint64_t hostUserStart, hostKernelStart, hostIdleStart; + uint64_t hostUserStop, hostKernelStop, hostIdleStop, hostTotal; + + uint64_t processUserStart, processKernelStart, processTotalStart; + uint64_t processUserStop, processKernelStop, processTotalStop; + + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + if (cpuTest) + { + RTPrintf("tstCollector: TESTING - CPU load, sleeping for 5 s...\n"); + + rc = collector->getRawHostCpuLoad(&hostUserStart, &hostKernelStart, &hostIdleStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStart, &processKernelStart, &processTotalStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); + return 1; + } + + RTThreadSleep(5000); // Sleep for 5 seconds + + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostCpuLoad(&hostUserStop, &hostKernelStop, &hostIdleStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStop, &processKernelStop, &processTotalStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); + return 1; + } + hostTotal = hostUserStop - hostUserStart + + hostKernelStop - hostKernelStart + + hostIdleStop - hostIdleStart; + RTPrintf("tstCollector: host cpu user = %u.%u %%\n", + (unsigned)((hostUserStop - hostUserStart) * 100 / hostTotal), + (unsigned)((hostUserStop - hostUserStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: host cpu kernel = %u.%u %%\n", + (unsigned)((hostKernelStop - hostKernelStart) * 100 / hostTotal), + (unsigned)((hostKernelStop - hostKernelStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: host cpu idle = %u.%u %%\n", + (unsigned)((hostIdleStop - hostIdleStart) * 100 / hostTotal), + (unsigned)((hostIdleStop - hostIdleStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: process cpu user = %u.%u %%\n", + (unsigned)((processUserStop - processUserStart) * 100 / (processTotalStop - processTotalStart)), + (unsigned)((processUserStop - processUserStart) * 10000 / (processTotalStop - processTotalStart) % 100)); + RTPrintf("tstCollector: process cpu kernel = %u.%u %%\n\n", + (unsigned)((processKernelStop - processKernelStart) * 100 / (processTotalStop - processTotalStart)), + (unsigned)((processKernelStop - processKernelStart) * 10000 / (processTotalStop - processTotalStart) % 100)); + + RTPrintf("tstCollector: TESTING - CPU load, looping for 5 s...\n"); + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostCpuLoad(&hostUserStart, &hostKernelStart, &hostIdleStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStart, &processKernelStart, &processTotalStart); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); + return 1; + } + start = RTTimeMilliTS(); + while (RTTimeMilliTS() - start < 5000) + ; // Loop for 5 seconds + rc = collector->preCollect(hints, 0); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: preCollect() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawHostCpuLoad(&hostUserStop, &hostKernelStop, &hostIdleStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawHostCpuLoad() -> %Rrc\n", rc); + return 1; + } + rc = collector->getRawProcessCpuLoad(RTProcSelf(), &processUserStop, &processKernelStop, &processTotalStop); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getRawProcessCpuLoad() -> %Rrc\n", rc); + return 1; + } + hostTotal = hostUserStop - hostUserStart + + hostKernelStop - hostKernelStart + + hostIdleStop - hostIdleStart; + RTPrintf("tstCollector: host cpu user = %u.%u %%\n", + (unsigned)((hostUserStop - hostUserStart) * 100 / hostTotal), + (unsigned)((hostUserStop - hostUserStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: host cpu kernel = %u.%u %%\n", + (unsigned)((hostKernelStop - hostKernelStart) * 100 / hostTotal), + (unsigned)((hostKernelStop - hostKernelStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: host cpu idle = %u.%u %%\n", + (unsigned)((hostIdleStop - hostIdleStart) * 100 / hostTotal), + (unsigned)((hostIdleStop - hostIdleStart) * 10000 / hostTotal % 100)); + RTPrintf("tstCollector: process cpu user = %u.%u %%\n", + (unsigned)((processUserStop - processUserStart) * 100 / (processTotalStop - processTotalStart)), + (unsigned)((processUserStop - processUserStart) * 10000 / (processTotalStop - processTotalStart) % 100)); + RTPrintf("tstCollector: process cpu kernel = %u.%u %%\n\n", + (unsigned)((processKernelStop - processKernelStart) * 100 / (processTotalStop - processTotalStart)), + (unsigned)((processKernelStop - processKernelStart) * 10000 / (processTotalStop - processTotalStart) % 100)); + } + + if (ramTest) + { + RTPrintf("tstCollector: TESTING - Memory usage\n"); + + ULONG total, used, available, processUsed; + + rc = collector->getHostMemoryUsage(&total, &used, &available); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getHostMemoryUsage() -> %Rrc\n", rc); + return 1; + } + rc = collector->getProcessMemoryUsage(RTProcSelf(), &processUsed); + if (RT_FAILURE(rc)) + { + RTPrintf("tstCollector: getProcessMemoryUsage() -> %Rrc\n", rc); + return 1; + } + RTPrintf("tstCollector: host mem total = %lu kB\n", total); + RTPrintf("tstCollector: host mem used = %lu kB\n", used); + RTPrintf("tstCollector: host mem available = %lu kB\n", available); + RTPrintf("tstCollector: process mem used = %lu kB\n\n", processUsed); + } + + if (netTest) + rc = testNetwork(collector); + if (fsTest) + rc = testFsUsage(collector); + if (diskTest) + rc = testDisk(collector); + if (perfTest) + { + RTPrintf("tstCollector: TESTING - Performance\n\n"); + + measurePerformance(collector, argv[0], 100); + } + + delete collector; + + RTPrintf("\ntstCollector FINISHED.\n"); + + return RTEXITCODE_SUCCESS; +} + diff --git a/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp b/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp new file mode 100644 index 00000000..f53e08f7 --- /dev/null +++ b/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp @@ -0,0 +1,125 @@ +/* $Id: tstGuestCtrlContextID.cpp $ */ +/** @file + * Context ID makeup/extraction test cases. + */ + +/* + * Copyright (C) 2012-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_ENABLED +#define LOG_GROUP LOG_GROUP_MAIN +#include <VBox/log.h> + +#include "../include/GuestCtrlImplPrivate.h" + +using namespace com; + +#include <iprt/env.h> +#include <iprt/rand.h> +#include <iprt/stream.h> +#include <iprt/test.h> + +int main() +{ + RTTEST hTest; + int rc = RTTestInitAndCreate("tstGuestCtrlContextID", &hTest); + if (rc) + return rc; + RTTestBanner(hTest); + + RTTestIPrintf(RTTESTLVL_DEBUG, "Initializing COM...\n"); + HRESULT hrc = com::Initialize(); + if (FAILED(hrc)) + { + RTTestFailed(hTest, "Failed to initialize COM (%Rhrc)!\n", hrc); + return RTEXITCODE_FAILURE; + } + + /* Don't let the assertions trigger here + * -- we rely on the return values in the test(s) below. */ + RTAssertSetQuiet(true); + +#if 0 + for (int t = 0; t < 4 && !RTTestErrorCount(hTest); t++) + { + uint32_t uSession = RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_SESSIONS - 1); + uint32_t uFilter = VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSession); + RTTestIPrintf(RTTESTLVL_INFO, "Session: %RU32, Filter: %x\n", uSession, uFilter); + + uint32_t uSession2 = RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_SESSIONS - 1); + uint32_t uCID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSession2, + RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_OBJECTS - 1), + RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_CONTEXTS - 1)); + RTTestIPrintf(RTTESTLVL_INFO, "CID: %x (Session: %d), Masked: %x\n", + uCID, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uCID), uCID & uFilter); + if ((uCID & uFilter) == uCID) + { + RTTestIPrintf(RTTESTLVL_INFO, "=========== Masking works: %x vs. %x\n", + uCID & uFilter, uFilter); + } + } +#endif + + uint32_t uContextMax = UINT32_MAX; + RTTestIPrintf(RTTESTLVL_DEBUG, "Max context is: %RU32\n", uContextMax); + + /* Do 4048 tests total. */ + for (int t = 0; t < 4048 && !RTTestErrorCount(hTest); t++) + { + /* VBOX_GUESTCTRL_MAX_* includes 0 as an object, so subtract one. */ + uint32_t s = RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_SESSIONS - 1); + uint32_t p = RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_OBJECTS - 1); + uint32_t c = RTRandU32Ex(0, VBOX_GUESTCTRL_MAX_CONTEXTS - 1); + + uint64_t uContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(s, p, c); + RTTestIPrintf(RTTESTLVL_DEBUG, "ContextID (%d,%d,%d) = %RU32\n", s, p, c, uContextID); + if (s != VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID)) + { + RTTestFailed(hTest, "%d,%d,%d: Session is %d, expected %d -> %RU64\n", + s, p, c, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID), s, uContextID); + } + else if (p != VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID)) + { + RTTestFailed(hTest, "%d,%d,%d: Object is %d, expected %d -> %RU64\n", + s, p, c, VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID), p, uContextID); + } + if (c != VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)) + { + RTTestFailed(hTest, "%d,%d,%d: Count is %d, expected %d -> %RU64\n", + s, p, c, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID), c, uContextID); + } + if (uContextID > UINT32_MAX) + { + RTTestFailed(hTest, "%d,%d,%d: Value overflow; does not fit anymore: %RU64\n", + s, p, c, uContextID); + } + } + + RTTestIPrintf(RTTESTLVL_DEBUG, "Shutting down COM...\n"); + com::Shutdown(); + + /* + * Summary. + */ + return RTTestSummaryAndDestroy(hTest); +} + diff --git a/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp b/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp new file mode 100644 index 00000000..1f4a50ce --- /dev/null +++ b/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp @@ -0,0 +1,297 @@ +/* $Id: tstGuestCtrlParseBuffer.cpp $ */ +/** @file + * Output stream parsing test cases. + */ + +/* + * Copyright (C) 2011-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_MAIN +#include <VBox/err.h> +#include <VBox/log.h> + +#include "../include/GuestCtrlImplPrivate.h" + +using namespace com; + +#include <iprt/env.h> +#include <iprt/test.h> +#include <iprt/stream.h> + +#ifndef BYTE +# define BYTE uint8_t +#endif + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define STR_SIZE(a_sz) RT_STR_TUPLE(a_sz) + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef struct VBOXGUESTCTRL_BUFFER_VALUE +{ + char *pszValue; +} VBOXGUESTCTRL_BUFFER_VALUE, *PVBOXGUESTCTRL_BUFFER_VALUE; +typedef std::map< RTCString, VBOXGUESTCTRL_BUFFER_VALUE > GuestBufferMap; +typedef std::map< RTCString, VBOXGUESTCTRL_BUFFER_VALUE >::iterator GuestBufferMapIter; +typedef std::map< RTCString, VBOXGUESTCTRL_BUFFER_VALUE >::const_iterator GuestBufferMapIterConst; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +char szUnterm1[] = { 'a', 's', 'd', 'f' }; +char szUnterm2[] = { 'f', 'o', 'o', '3', '=', 'b', 'a', 'r', '3' }; + +static struct +{ + const char *pbData; + size_t cbData; + uint32_t offStart; + uint32_t offAfter; + uint32_t cMapElements; + int iResult; +} g_aTestBlocks[] = +{ + /* + * Single object parsing. + * An object is represented by one or multiple key=value pairs which are + * separated by a single "\0". If this termination is missing it will be assumed + * that we need to collect more data to do a successful parsing. + */ + /* Invalid stuff. */ + { NULL, 0, 0, 0, 0, VERR_INVALID_POINTER }, + { NULL, 512, 0, 0, 0, VERR_INVALID_POINTER }, + { "", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, + { "", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, + { "foo=bar1", 0, 0, 0, 0, VERR_INVALID_PARAMETER }, + { "foo=bar2", 0, 50, 50, 0, VERR_INVALID_PARAMETER }, + /* Empty buffers. */ + { "", 1, 0, 1, 0, VINF_SUCCESS }, + { "\0", 1, 0, 1, 0, VINF_SUCCESS }, + /* Unterminated values (missing "\0"). */ + { STR_SIZE("test1"), 0, 0, 0, VERR_MORE_DATA }, + { STR_SIZE("test2="), 0, 0, 0, VERR_MORE_DATA }, + { STR_SIZE("test3=test3"), 0, 0, 0, VERR_MORE_DATA }, + { STR_SIZE("test4=test4\0t41"), 0, sizeof("test4=test4\0") - 1, 1, VERR_MORE_DATA }, + { STR_SIZE("test5=test5\0t51=t51"), 0, sizeof("test5=test5\0") - 1, 1, VERR_MORE_DATA }, + /* Next block unterminated. */ + { STR_SIZE("t51=t51\0t52=t52\0\0t53=t53"), 0, sizeof("t51=t51\0t52=t52\0") - 1, 2, VINF_SUCCESS }, + { STR_SIZE("test6=test6\0\0t61=t61"), 0, sizeof("test6=test6\0") - 1, 1, VINF_SUCCESS }, + /* Good stuff. */ + { STR_SIZE("test61=\0test611=test611\0"), 0, sizeof("test61=\0test611=test611\0") - 1, 2, VINF_SUCCESS }, + { STR_SIZE("test7=test7\0\0"), 0, sizeof("test7=test7\0") - 1, 1, VINF_SUCCESS }, + { STR_SIZE("test8=test8\0t81=t81\0\0"), 0, sizeof("test8=test8\0t81=t81\0") - 1, 2, VINF_SUCCESS }, + /* Good stuff, but with a second block -- should be *not* taken into account since + * we're only interested in parsing/handling the first object. */ + { STR_SIZE("t9=t9\0t91=t91\0\0t92=t92\0\0"), 0, sizeof("t9=t9\0t91=t91\0") - 1, 2, VINF_SUCCESS }, + /* Nasty stuff. */ + /* iso 8859-1 encoding (?) of 'aou' all with diaeresis '=f' and 'ao' with diaeresis. */ + { STR_SIZE("\xe4\xf6\xfc=\x66\xe4\xf6\0\0"), 0, sizeof("\xe4\xf6\xfc=\x66\xe4\xf6\0") - 1, 1, VINF_SUCCESS }, + /* Like above, but after the first '\0' it adds 'ooo=aaa' all letters with diaeresis. */ + { STR_SIZE("\xe4\xf6\xfc=\x66\xe4\xf6\0\xf6\xf6\xf6=\xe4\xe4\xe4"), + 0, sizeof("\xe4\xf6\xfc=\x66\xe4\xf6\0") - 1, 1, VERR_MORE_DATA }, + /* Some "real world" examples. */ + { STR_SIZE("hdr_id=vbt_stat\0hdr_ver=1\0name=foo.txt\0\0"), 0, sizeof("hdr_id=vbt_stat\0hdr_ver=1\0name=foo.txt\0") - 1, + 3, VINF_SUCCESS } +}; + +static struct +{ + const char *pbData; + size_t cbData; + /** Number of data blocks retrieved. These are separated by "\0\0". */ + uint32_t cBlocks; + /** Overall result when done parsing. */ + int iResult; +} const g_aTestStream[] = +{ + /* No blocks. */ + { "\0\0\0\0", sizeof("\0\0\0\0"), 0, VERR_NO_DATA }, + /* Good stuff. */ + { "\0b1=b1\0\0", sizeof("\0b1=b1\0\0"), 1, VERR_NO_DATA }, + { "b1=b1\0\0", sizeof("b1=b1\0\0"), 1, VERR_NO_DATA }, + { "b1=b1\0b2=b2\0\0", sizeof("b1=b1\0b2=b2\0\0"), 1, VERR_NO_DATA }, + { "b1=b1\0b2=b2\0\0\0", sizeof("b1=b1\0b2=b2\0\0\0"), 1, VERR_NO_DATA } +}; + +int manualTest(void) +{ + int rc = VINF_SUCCESS; + static struct + { + const char *pbData; + size_t cbData; + uint32_t offStart; + uint32_t offAfter; + uint32_t cMapElements; + int iResult; + } const s_aTest[] = + { + { "test5=test5\0t51=t51", sizeof("test5=test5\0t51=t51"), 0, sizeof("test5=test5\0") - 1, 1, VERR_MORE_DATA }, + { "\0\0test5=test5\0t51=t51", sizeof("\0\0test5=test5\0t51=t51"), 0, sizeof("\0\0test5=test5\0") - 1, 1, VERR_MORE_DATA }, + }; + + for (unsigned iTest = 0; iTest < RT_ELEMENTS(s_aTest); iTest++) + { + RTTestIPrintf(RTTESTLVL_DEBUG, "Manual test #%d\n", iTest); + + GuestProcessStream stream; + rc = stream.AddData((BYTE *)s_aTest[iTest].pbData, s_aTest[iTest].cbData); + + for (;;) + { + GuestProcessStreamBlock block; + rc = stream.ParseBlock(block); + RTTestIPrintf(RTTESTLVL_DEBUG, "\tReturned with rc=%Rrc, numItems=%ld\n", + rc, block.GetCount()); + + if (block.GetCount()) + break; + } + } + + return rc; +} + +int main() +{ + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstParseBuffer", &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(hTest); + + RTTestIPrintf(RTTESTLVL_DEBUG, "Initializing COM...\n"); + HRESULT hrc = com::Initialize(); + if (FAILED(hrc)) + { + RTTestFailed(hTest, "Failed to initialize COM (%Rhrc)!\n", hrc); + return RTEXITCODE_FAILURE; + } + +#ifdef DEBUG_andy + int rc = manualTest(); + if (RT_FAILURE(rc)) + return RTEXITCODE_FAILURE; +#endif + + AssertCompile(sizeof("sizecheck") == 10); + AssertCompile(sizeof("off=rab") == 8); + AssertCompile(sizeof("off=rab\0\0") == 10); + + RTTestSub(hTest, "Lines"); + for (unsigned iTest = 0; iTest < RT_ELEMENTS(g_aTestBlocks); iTest++) + { + RTTestIPrintf(RTTESTLVL_DEBUG, "=> Test #%u\n", iTest); + + GuestProcessStream stream; + if (RT_FAILURE(g_aTestBlocks[iTest].iResult)) + RTTestDisableAssertions(hTest); + int iResult = stream.AddData((BYTE *)g_aTestBlocks[iTest].pbData, g_aTestBlocks[iTest].cbData); + if (RT_FAILURE(g_aTestBlocks[iTest].iResult)) + RTTestRestoreAssertions(hTest); + if (RT_SUCCESS(iResult)) + { + GuestProcessStreamBlock curBlock; + iResult = stream.ParseBlock(curBlock); + if (iResult != g_aTestBlocks[iTest].iResult) + RTTestFailed(hTest, "Block #%u: Returned %Rrc, expected %Rrc", iTest, iResult, g_aTestBlocks[iTest].iResult); + else if (stream.GetOffset() != g_aTestBlocks[iTest].offAfter) + RTTestFailed(hTest, "Block #%uOffset %zu wrong, expected %u\n", + iTest, stream.GetOffset(), g_aTestBlocks[iTest].offAfter); + else if (iResult == VERR_MORE_DATA) + RTTestIPrintf(RTTESTLVL_DEBUG, "\tMore data (Offset: %zu)\n", stream.GetOffset()); + + if (RT_SUCCESS(iResult) || iResult == VERR_MORE_DATA) + if (curBlock.GetCount() != g_aTestBlocks[iTest].cMapElements) + RTTestFailed(hTest, "Block #%u: Map has %u elements, expected %u\n", + iTest, curBlock.GetCount(), g_aTestBlocks[iTest].cMapElements); + + /* There is remaining data left in the buffer (which needs to be merged + * with a following buffer) -- print it. */ + size_t off = stream.GetOffset(); + size_t cbToWrite = g_aTestBlocks[iTest].cbData - off; + if (cbToWrite) + { + RTTestIPrintf(RTTESTLVL_DEBUG, "\tRemaining (%u):\n", cbToWrite); + + /* How to properly get the current RTTESTLVL (aka IPRT_TEST_MAX_LEVEL) here? + * Hack alert: Using RTEnvGet for now. */ + if (!RTStrICmp(RTEnvGet("IPRT_TEST_MAX_LEVEL"), "debug")) + RTStrmWriteEx(g_pStdOut, &g_aTestBlocks[iTest].pbData[off], cbToWrite - 1, NULL); + } + } + } + + RTTestSub(hTest, "Blocks"); + for (unsigned iTest = 0; iTest < RT_ELEMENTS(g_aTestStream); iTest++) + { + RTTestIPrintf(RTTESTLVL_DEBUG, "=> Block test #%u\n", iTest); + + GuestProcessStream stream; + int iResult = stream.AddData((BYTE*)g_aTestStream[iTest].pbData, g_aTestStream[iTest].cbData); + if (RT_SUCCESS(iResult)) + { + uint32_t cBlocks = 0; + uint8_t uSafeCouunter = 0; + do + { + GuestProcessStreamBlock curBlock; + iResult = stream.ParseBlock(curBlock); + RTTestIPrintf(RTTESTLVL_DEBUG, "Block #%u: Returned with %Rrc", iTest, iResult); + if (RT_SUCCESS(iResult)) + { + /* Only count block which have at least one pair. */ + if (curBlock.GetCount()) + cBlocks++; + } + if (uSafeCouunter++ > 32) + break; + } while (RT_SUCCESS(iResult)); + + if (iResult != g_aTestStream[iTest].iResult) + RTTestFailed(hTest, "Block #%uReturned %Rrc, expected %Rrc", iTest, iResult, g_aTestStream[iTest].iResult); + else if (cBlocks != g_aTestStream[iTest].cBlocks) + RTTestFailed(hTest, "Block #%uReturned %u blocks, expected %u", iTest, cBlocks, g_aTestStream[iTest].cBlocks); + } + else + RTTestFailed(hTest, "Block #%u: Adding data failed with %Rrc", iTest, iResult); + } + + RTTestIPrintf(RTTESTLVL_DEBUG, "Shutting down COM...\n"); + com::Shutdown(); + + /* + * Summary. + */ + return RTTestSummaryAndDestroy(hTest); +} + diff --git a/src/VBox/Main/testcase/tstGuestCtrlPaths.cpp b/src/VBox/Main/testcase/tstGuestCtrlPaths.cpp new file mode 100644 index 00000000..6cec555a --- /dev/null +++ b/src/VBox/Main/testcase/tstGuestCtrlPaths.cpp @@ -0,0 +1,167 @@ +/* $Id */ +/** @file + * Guest Control path test cases. + */ + +/* + * Copyright (C) 2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_ENABLED +#define LOG_GROUP LOG_GROUP_MAIN +#include <VBox/log.h> + +#include "../include/GuestCtrlImplPrivate.h" + +using namespace com; + +#include <iprt/assert.h> +#include <iprt/env.h> +#include <iprt/rand.h> +#include <iprt/stream.h> +#include <iprt/test.h> + + +DECLINLINE(void) tstPathBuildDestination(const Utf8Str &strSrcPath, PathStyle_T enmSrcPathStyle, + const Utf8Str &strDstPath, PathStyle_T enmDstPathStyle, + int rcExp, Utf8Str strPathExp) +{ + Utf8Str strDstPath2 = strDstPath; + int vrc = GuestPath::BuildDestinationPath(strSrcPath, enmSrcPathStyle, strDstPath2, enmDstPathStyle); + RTTESTI_CHECK_MSG_RETV(vrc == rcExp, ("Expected %Rrc, got %Rrc for '%s'\n", rcExp, vrc, strDstPath.c_str())); + RTTESTI_CHECK_MSG_RETV(strDstPath2 == strPathExp, ("Expected '%s', got '%s'\n", strPathExp.c_str(), strDstPath2.c_str())); +} + +DECLINLINE(void) tstPathTranslate(Utf8Str strPath, PathStyle_T enmSrcPathStyle, PathStyle_T enmDstPathStyle, int rcExp, Utf8Str strPathExp) +{ + Utf8Str strPath2 = strPath; + int vrc = GuestPath::Translate(strPath2, enmSrcPathStyle, enmDstPathStyle); + RTTESTI_CHECK_MSG_RETV(vrc == rcExp, ("Expected %Rrc, got %Rrc for '%s'\n", rcExp, vrc, strPath.c_str())); + RTTESTI_CHECK_MSG_RETV(strPath2 == strPathExp, ("Expected '%s', got '%s'\n", strPathExp.c_str(), strPath2.c_str())); +} + +int main() +{ + RTTEST hTest; + int vrc = RTTestInitAndCreate("tstGuestCtrlPaths", &hTest); + if (vrc) + return vrc; + RTTestBanner(hTest); + + RTTestIPrintf(RTTESTLVL_DEBUG, "Initializing COM...\n"); + HRESULT hrc = com::Initialize(); + if (FAILED(hrc)) + { + RTTestFailed(hTest, "Failed to initialize COM (%Rhrc)!\n", hrc); + return RTEXITCODE_FAILURE; + } + + /* Don't let the assertions trigger here + * -- we rely on the return values in the test(s) below. */ + RTAssertSetQuiet(true); + + /* + * Path translation testing. + */ + tstPathTranslate("", PathStyle_DOS, PathStyle_DOS, VINF_SUCCESS, ""); + + tstPathTranslate("foo", PathStyle_DOS, PathStyle_DOS, VINF_SUCCESS, "foo"); + tstPathTranslate("foo", PathStyle_UNIX, PathStyle_UNIX, VINF_SUCCESS, "foo"); + tstPathTranslate("foo", PathStyle_DOS, PathStyle_UNIX, VINF_SUCCESS, "foo"); + tstPathTranslate("foo", PathStyle_UNIX, PathStyle_UNIX, VINF_SUCCESS, "foo"); + + tstPathTranslate("foo\\bar", PathStyle_DOS, PathStyle_DOS, VINF_SUCCESS, "foo\\bar"); + tstPathTranslate("foo/bar", PathStyle_UNIX, PathStyle_UNIX, VINF_SUCCESS, "foo/bar"); + + tstPathTranslate("foo\\bar\\", PathStyle_DOS, PathStyle_DOS, VINF_SUCCESS, "foo\\bar\\"); + tstPathTranslate("foo/bar/", PathStyle_UNIX, PathStyle_UNIX, VINF_SUCCESS, "foo/bar/"); + /* Actually also allowed on Windows. */ + tstPathTranslate("foo/bar/", PathStyle_DOS, PathStyle_UNIX, VINF_SUCCESS, "foo/bar/"); + + tstPathTranslate("foo\\bar\\BAZ", PathStyle_DOS, PathStyle_DOS, VINF_SUCCESS, "foo\\bar\\BAZ"); + tstPathTranslate("foo/bar/BAZ", PathStyle_UNIX, PathStyle_UNIX, VINF_SUCCESS, "foo/bar/BAZ"); + + tstPathTranslate("foo\\bar\\dir with space\\", PathStyle_DOS, PathStyle_UNIX, VINF_SUCCESS, "foo/bar/dir with space/"); + tstPathTranslate("foo/bar/dir with space/", PathStyle_UNIX, PathStyle_UNIX, VINF_SUCCESS, "foo/bar/dir with space/"); + +#if 0 + /** Do a mapping of "\", which marks an escape sequence for paths on UNIX-y OSes to DOS-based OSes (like Windows), + * however, on DOS "\" is a path separator. See @bugref{21095} */ + tstPathTranslate("foo/bar/dir_with_escape_sequence\\ space", PathStyle_UNIX, PathStyle_UNIX, VINF_SUCCESS, "foo/bar/dir_with_escape_sequence\\ space"); + tstPathTranslate("foo/bar/dir_with_escape_sequence\\ space", PathStyle_UNIX, PathStyle_DOS, VINF_SUCCESS, "foo\\bar\\dir_with_escape_sequence space"); + tstPathTranslate("foo/bar/1_dir_with_escape_sequence/the\\ space", PathStyle_UNIX, PathStyle_DOS, VINF_SUCCESS, "foo\\bar\\1_dir_with_escape_sequence\\the space"); + tstPathTranslate("foo/bar/2_dir_with_escape_sequence/the\\ \\ space", PathStyle_UNIX, PathStyle_DOS, VINF_SUCCESS, "foo\\bar\\2_dir_with_escape_sequence\\the space"); + tstPathTranslate("foo/bar/dir_with_escape_sequence/spaces at end\\ \\ ", PathStyle_UNIX, PathStyle_DOS, VINF_SUCCESS, "foo\\bar\\dir_with_escape_sequence\\spaces at end "); +#endif + + /* Filter out double slashes (cosmetic only). */ + tstPathTranslate("\\\\", PathStyle_DOS, PathStyle_DOS, VINF_SUCCESS, "\\"); + tstPathTranslate("foo\\\\bar\\", PathStyle_DOS, PathStyle_DOS, VINF_SUCCESS, "foo\\bar\\"); + + /* Mixed slashes. */ + tstPathTranslate("\\\\foo/bar\\\\baz", PathStyle_UNIX, PathStyle_UNIX, VINF_SUCCESS, "\\\\foo/bar\\\\baz"); +#if 0 /** @todo Not clear what to expect here. */ + tstPathTranslate("with spaces\\ foo/\\ bar", PathStyle_UNIX, PathStyle_DOS, VINF_SUCCESS, "with spaces foo\\ bar"); +#endif + + /* + * Destination path building testing. + */ + bool fQuiet = RTAssertSetQuiet(true); + bool fMayPanic = RTAssertSetMayPanic(false); + tstPathBuildDestination("", PathStyle_UNIX, "", PathStyle_UNIX, VERR_PATH_ZERO_LENGTH, ""); + tstPathBuildDestination(".", PathStyle_UNIX, ".", PathStyle_UNIX, VINF_SUCCESS, "."); + tstPathBuildDestination("..", PathStyle_UNIX, "..", PathStyle_UNIX, VERR_INVALID_PARAMETER, ".."); + tstPathBuildDestination("/tmp/", PathStyle_UNIX, "/root/../foo", PathStyle_UNIX, VERR_INVALID_PARAMETER, "/root/../foo"); + /* ".." in actual file names are allowed. */ + tstPathBuildDestination("/tmp/", PathStyle_UNIX, "/root/foo..bar", PathStyle_UNIX, VINF_SUCCESS, "/root/foo..bar"); + /* Ditto for path names which consist of more than just "..". */ + tstPathBuildDestination("/tmp/", PathStyle_UNIX, "/root/foo..bar/baz", PathStyle_UNIX, VINF_SUCCESS, "/root/foo..bar/baz"); + tstPathBuildDestination("...", PathStyle_UNIX, "...", PathStyle_UNIX, VINF_SUCCESS, "..."); + tstPathBuildDestination("foo", PathStyle_UNIX, "bar", PathStyle_UNIX, VINF_SUCCESS, "bar"); + tstPathBuildDestination("foo/", PathStyle_UNIX, "bar/", PathStyle_UNIX, VINF_SUCCESS, "bar/"); + tstPathBuildDestination("foo/", PathStyle_UNIX, "bar/baz", PathStyle_UNIX, VINF_SUCCESS, "bar/baz"); + tstPathBuildDestination("foo/baz", PathStyle_UNIX, "bar/", PathStyle_UNIX, VINF_SUCCESS, "bar/baz"); + tstPathBuildDestination("foo/baz", PathStyle_UNIX, "bar\\", PathStyle_DOS, VINF_SUCCESS, "bar\\baz"); + + tstPathBuildDestination("c:\\temp\\", PathStyle_DOS, "/tmp/", PathStyle_UNIX, VINF_SUCCESS, "/tmp/"); + tstPathBuildDestination("c:\\TEMP\\", PathStyle_DOS, "/TmP/", PathStyle_UNIX, VINF_SUCCESS, "/TmP/"); + tstPathBuildDestination("c:\\temp\\foo.txt", PathStyle_DOS, "/tmp/foo.txt", PathStyle_UNIX, VINF_SUCCESS, "/tmp/foo.txt"); + tstPathBuildDestination("c:\\temp\\bar\\foo.txt", PathStyle_DOS, "/tmp/foo2.txt", PathStyle_UNIX, VINF_SUCCESS, "/tmp/foo2.txt"); + tstPathBuildDestination("c:\\temp\\bar\\foo3.txt", PathStyle_DOS, "/tmp/", PathStyle_UNIX, VINF_SUCCESS, "/tmp/foo3.txt"); + + tstPathBuildDestination("/tmp/bar/", PathStyle_UNIX, "c:\\temp\\", PathStyle_DOS, VINF_SUCCESS, "c:\\temp\\"); + tstPathBuildDestination("/tmp/BaR/", PathStyle_UNIX, "c:\\tEmP\\", PathStyle_DOS, VINF_SUCCESS, "c:\\tEmP\\"); + tstPathBuildDestination("/tmp/foo.txt", PathStyle_UNIX, "c:\\temp\\foo.txt", PathStyle_DOS, VINF_SUCCESS, "c:\\temp\\foo.txt"); + tstPathBuildDestination("/tmp/bar/foo.txt", PathStyle_UNIX, "c:\\temp\\foo2.txt", PathStyle_DOS, VINF_SUCCESS, "c:\\temp\\foo2.txt"); + tstPathBuildDestination("/tmp/bar/foo3.txt", PathStyle_UNIX, "c:\\temp\\", PathStyle_DOS, VINF_SUCCESS, "c:\\temp\\foo3.txt"); + RTAssertSetMayPanic(fMayPanic); + RTAssertSetQuiet(fQuiet); + + RTTestIPrintf(RTTESTLVL_DEBUG, "Shutting down COM...\n"); + com::Shutdown(); + + /* + * Summary. + */ + return RTTestSummaryAndDestroy(hTest); +} + diff --git a/src/VBox/Main/testcase/tstGuid.cpp b/src/VBox/Main/testcase/tstGuid.cpp new file mode 100644 index 00000000..4d662ce4 --- /dev/null +++ b/src/VBox/Main/testcase/tstGuid.cpp @@ -0,0 +1,110 @@ +/* $Id: tstGuid.cpp $ */ +/** @file + * API Glue Testcase - Guid. + */ + +/* + * Copyright (C) 2013-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/com/Guid.h> + +#include <iprt/errcore.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/test.h> +#include <iprt/uni.h> + + +static void test1(RTTEST hTest) +{ + RTTestSub(hTest, "Basics"); + +#define CHECK(expr) RTTESTI_CHECK(expr) +#define CHECK_DUMP(expr, value) \ + do { \ + if (!(expr)) \ + RTTestFailed(hTest, "%d: FAILED %s, got \"%s\"", __LINE__, #expr, value); \ + } while (0) + +#define CHECK_DUMP_I(expr) \ + do { \ + if (!(expr)) \ + RTTestFailed(hTest, "%d: FAILED %s, got \"%d\"", __LINE__, #expr, expr); \ + } while (0) +#define CHECK_EQUAL(Str, szExpect) \ + do { \ + if (!(Str).equals(szExpect)) \ + RTTestIFailed("line %u: expected \"%s\" got \"%s\"", __LINE__, szExpect, (Str).c_str()); \ + } while (0) +#define CHECK_EQUAL_I(iRes, iExpect) \ + do { \ + if (iRes != iExpect) \ + RTTestIFailed("line %u: expected \"%zd\" got \"%zd\"", __LINE__, iExpect, iRes); \ + } while (0) + + com::Guid zero; + CHECK(zero.isZero()); + + com::Guid copyZero(zero); + CHECK(copyZero.isZero()); + + com::Guid assignZero(zero); + CHECK(assignZero.isZero()); + + com::Guid random; + random.create(); + CHECK(!random.isZero()); + + com::Guid copyRandom(random); + CHECK(!copyRandom.isZero()); + + com::Guid assignRandom(random); + CHECK(!assignRandom.isZero()); + + /** @todo extend this a lot, it needs to cover many more cases */ + +#undef CHECK +#undef CHECK_DUMP +#undef CHECK_DUMP_I +#undef CHECK_EQUAL +} + + +int main() +{ + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstGuid", &hTest); + if (rcExit == RTEXITCODE_SUCCESS) + { + RTTestBanner(hTest); + + test1(hTest); + + rcExit = RTTestSummaryAndDestroy(hTest); + } + return rcExit; +} + diff --git a/src/VBox/Main/testcase/tstMediumLock.cpp b/src/VBox/Main/testcase/tstMediumLock.cpp new file mode 100644 index 00000000..57629d53 --- /dev/null +++ b/src/VBox/Main/testcase/tstMediumLock.cpp @@ -0,0 +1,309 @@ +/* $Id: tstMediumLock.cpp $ */ +/** @file + * Medium lock test cases. + */ + +/* + * Copyright (C) 2013-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_ENABLED +#define LOG_GROUP LOG_GROUP_MAIN +#include <VBox/log.h> + +#include <VBox/com/com.h> +#include <VBox/com/ptr.h> +#include <VBox/com/defs.h> +#include <VBox/com/array.h> +#include <VBox/com/string.h> +#include <VBox/com/VirtualBox.h> + +#include <iprt/assert.h> +#include <iprt/uuid.h> +#include <iprt/path.h> +#include <iprt/string.h> +#include <iprt/initterm.h> +#include <iprt/test.h> + +using namespace com; + + +#define TEST_RT_SUCCESS(x,y,z) \ + do \ + { \ + int rc = (y); \ + if (RT_FAILURE(rc)) \ + RTTestFailed((x), "%s %Rrc", (z), rc); \ + } while (0) + +#define TEST_COM_SUCCESS(x,y,z) \ + do \ + { \ + HRESULT hrc = (y); \ + if (FAILED(hrc)) \ + RTTestFailed((x), "%s %Rhrc", (z), hrc); \ + } while (0) + +#define TEST_COM_FAILURE(x,y,z) \ + do \ + { \ + HRESULT hrc = (y); \ + if (SUCCEEDED(hrc)) \ + RTTestFailed((x), "%s", (z)); \ + } while (0) + +int main(int argc, char *argv[]) +{ + /* Init the runtime without loading the support driver. */ + RTR3InitExe(argc, &argv, 0); + + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstMediumLock", &hTest); + if (rcExit) + return rcExit; + RTTestBanner(hTest); + + bool fComInit = false; + ComPtr<IVirtualBoxClient> pVirtualBoxClient; + ComPtr<IVirtualBox> pVirtualBox; + char szPathTemp[RTPATH_MAX] = ""; + ComPtr<IMedium> pMedium; + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Constructing temp image name"); + TEST_RT_SUCCESS(hTest, RTPathTemp(szPathTemp, sizeof(szPathTemp)), "temp directory"); + RTUUID uuid; + RTUuidCreate(&uuid); + char szFile[50]; + RTStrPrintf(szFile, sizeof(szFile), "%RTuuid.vdi", &uuid); + TEST_RT_SUCCESS(hTest, RTPathAppend(szPathTemp, sizeof(szPathTemp), szFile), "concatenate image name"); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Initializing COM"); + TEST_COM_SUCCESS(hTest, Initialize(), "init"); + } + + if (!RTTestSubErrorCount(hTest)) + { + fComInit = true; + + RTTestSub(hTest, "Getting VirtualBox reference"); + TEST_COM_SUCCESS(hTest, pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient), "vboxclient reference"); + TEST_COM_SUCCESS(hTest, pVirtualBoxClient->COMGETTER(VirtualBox)(pVirtualBox.asOutParam()), "vbox reference"); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Creating temp hard disk medium"); + TEST_COM_SUCCESS(hTest, pVirtualBox->CreateMedium(Bstr("VDI").raw(), Bstr(szPathTemp).raw(), AccessMode_ReadWrite, DeviceType_HardDisk, pMedium.asOutParam()), "create medium"); + if (!pMedium.isNull()) + { + ComPtr<IProgress> pProgress; + SafeArray<MediumVariant_T> variant; + variant.push_back(MediumVariant_Standard); + TEST_COM_SUCCESS(hTest, pMedium->CreateBaseStorage(_1M, ComSafeArrayAsInParam(variant), pProgress.asOutParam()), "create base storage"); + if (!pProgress.isNull()) + TEST_COM_SUCCESS(hTest, pProgress->WaitForCompletion(30000), "waiting for completion of create"); + } + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Write locks"); + ComPtr<IToken> pToken1, pToken2; + + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockWrite(pToken1.asOutParam()), "write lock"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock write state"); + if (mediumState != MediumState_LockedWrite) + RTTestFailed(hTest, "wrong lock write medium state %d", mediumState); + + TEST_COM_FAILURE(hTest, pMedium->LockWrite(pToken2.asOutParam()), "nested write lock succeeded"); + if (!pToken2.isNull()) + RTTestFailed(hTest, "pToken2 is not null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock write state"); + if (mediumState != MediumState_LockedWrite) + RTTestFailed(hTest, "wrong after nested lock write medium state %d", mediumState); + + if (!pToken1.isNull()) + TEST_COM_SUCCESS(hTest, pToken1->Abandon(), "write unlock"); + else + RTTestFailed(hTest, "pToken1 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock write state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong unlock write medium state %d", mediumState); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Read locks"); + ComPtr<IToken> pToken1, pToken2; + + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockRead(pToken1.asOutParam()), "read lock"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong lock read medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockRead(pToken2.asOutParam()), "nested read lock failed"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState); + + if (!pToken2.isNull()) + TEST_COM_SUCCESS(hTest, pToken2->Abandon(), "read nested unlock"); + else + RTTestFailed(hTest, "pToken2 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState); + + if (!pToken1.isNull()) + TEST_COM_SUCCESS(hTest, pToken1->Abandon(), "read nested unlock"); + else + RTTestFailed(hTest, "pToken1 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock read state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong unlock read medium state %d", mediumState); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Mixing write and read locks"); + ComPtr<IToken> pToken1, pToken2; + + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockWrite(pToken1.asOutParam()), "write lock"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock write state"); + if (mediumState != MediumState_LockedWrite) + RTTestFailed(hTest, "wrong lock write medium state %d", mediumState); + + TEST_COM_FAILURE(hTest, pMedium->LockRead(pToken2.asOutParam()), "write+read lock succeeded"); + if (!pToken2.isNull()) + RTTestFailed(hTest, "pToken2 is not null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock write state"); + if (mediumState != MediumState_LockedWrite) + RTTestFailed(hTest, "wrong after nested lock write medium state %d", mediumState); + + if (!pToken1.isNull()) + TEST_COM_SUCCESS(hTest, pToken1->Abandon(), "write unlock"); + else + RTTestFailed(hTest, "pToken1 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock write state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong unlock write medium state %d", mediumState); + } + + if (!RTTestSubErrorCount(hTest)) + { + RTTestSub(hTest, "Mixing read and write locks"); + ComPtr<IToken> pToken1, pToken2; + + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong medium state %d", mediumState); + + TEST_COM_SUCCESS(hTest, pMedium->LockRead(pToken1.asOutParam()), "read lock"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong lock read medium state %d", mediumState); + + TEST_COM_FAILURE(hTest, pMedium->LockWrite(pToken2.asOutParam()), "read+write lock succeeded"); + if (!pToken2.isNull()) + RTTestFailed(hTest, "pToken2 is not null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state"); + if (mediumState != MediumState_LockedRead) + RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState); + + if (!pToken1.isNull()) + TEST_COM_SUCCESS(hTest, pToken1->Abandon(), "read unlock"); + else + RTTestFailed(hTest, "pToken1 is null"); + + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock read state"); + if (mediumState != MediumState_Created) + RTTestFailed(hTest, "wrong unlock read medium state %d", mediumState); + } + + /* Cleanup, also part of the testcase */ + + if (!pMedium.isNull()) + { + RTTestSub(hTest, "Closing medium"); + MediumState_T mediumState = MediumState_NotCreated; + TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state"); + if (mediumState == MediumState_Created) + { + ComPtr<IProgress> pProgress; + TEST_COM_SUCCESS(hTest, pMedium->DeleteStorage(pProgress.asOutParam()), "deleting storage"); + if (!pProgress.isNull()) + TEST_COM_SUCCESS(hTest, pProgress->WaitForCompletion(30000), "waiting for completion of delete"); + } + TEST_COM_SUCCESS(hTest, pMedium->Close(), "closing"); + pMedium.setNull(); + } + + pVirtualBox.setNull(); + pVirtualBoxClient.setNull(); + + /* Make sure that there are no object references alive here, XPCOM does + * a very bad job at cleaning up such leftovers, spitting out warning + * messages in a debug build. */ + + if (fComInit) + { + RTTestIPrintf(RTTESTLVL_DEBUG, "Shutting down COM...\n"); + Shutdown(); + } + + /* + * Summary. + */ + return RTTestSummaryAndDestroy(hTest); +} diff --git a/src/VBox/Main/testcase/tstOVF.cpp b/src/VBox/Main/testcase/tstOVF.cpp new file mode 100644 index 00000000..90b62174 --- /dev/null +++ b/src/VBox/Main/testcase/tstOVF.cpp @@ -0,0 +1,431 @@ +/* $Id: tstOVF.cpp $ */ +/** @file + * + * tstOVF - testcases for OVF import and export + */ + +/* + * Copyright (C) 2010-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include <VBox/com/VirtualBox.h> + +#include <VBox/com/com.h> +#include <VBox/com/array.h> +#include <VBox/com/string.h> +#include <VBox/com/ErrorInfo.h> +#include <VBox/com/errorprint.h> + +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <iprt/file.h> +#include <iprt/path.h> +#include <iprt/param.h> + +#include <list> + +using namespace com; + +// main +/////////////////////////////////////////////////////////////////////////////// + +/** + * Quick hack exception structure. + * + */ +struct MyError +{ + MyError(HRESULT rc, + const char *pcsz, + IProgress *pProgress = NULL) + : m_rc(rc) + { + m_str = "ERROR: "; + m_str += pcsz; + + if (pProgress) + { + com::ProgressErrorInfo info(pProgress); + com::GluePrintErrorInfo(info); + } + else if (rc != S_OK) + { + com::ErrorInfo info; + if (!info.isFullAvailable() && !info.isBasicAvailable()) + com::GluePrintRCMessage(rc); + else + com::GluePrintErrorInfo(info); + } + } + + Utf8Str m_str; + HRESULT m_rc; +}; + +/** + * Imports the given OVF file, with all bells and whistles. + * Throws MyError on errors. + * @param pcszPrefix Descriptive short prefix string for console output. + * @param pVirtualBox VirtualBox instance. + * @param pcszOVF0 File to import. + * @param llMachinesCreated out: UUIDs of machines that were created so that caller can clean up. + */ +void importOVF(const char *pcszPrefix, + ComPtr<IVirtualBox> &pVirtualBox, + const char *pcszOVF0, + std::list<Guid> &llMachinesCreated) +{ + char szAbsOVF[RTPATH_MAX]; + RTPathExecDir(szAbsOVF, sizeof(szAbsOVF)); + RTPathAppend(szAbsOVF, sizeof(szAbsOVF), pcszOVF0); + + RTPrintf("%s: reading appliance \"%s\"...\n", pcszPrefix, szAbsOVF); + ComPtr<IAppliance> pAppl; + HRESULT rc = pVirtualBox->CreateAppliance(pAppl.asOutParam()); + if (FAILED(rc)) throw MyError(rc, "failed to create appliance\n"); + + ComPtr<IProgress> pProgress; + rc = pAppl->Read(Bstr(szAbsOVF).raw(), pProgress.asOutParam()); + if (FAILED(rc)) throw MyError(rc, "Appliance::Read() failed\n"); + rc = pProgress->WaitForCompletion(-1); + if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n"); + LONG rc2; + pProgress->COMGETTER(ResultCode)(&rc2); + if (FAILED(rc2)) throw MyError(rc2, "Appliance::Read() failed\n", pProgress); + + RTPrintf("%s: interpreting appliance \"%s\"...\n", pcszPrefix, szAbsOVF); + rc = pAppl->Interpret(); + if (FAILED(rc)) throw MyError(rc, "Appliance::Interpret() failed\n"); + + com::SafeIfaceArray<IVirtualSystemDescription> aDescriptions; + rc = pAppl->COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(aDescriptions)); + for (uint32_t u = 0; + u < aDescriptions.size(); + ++u) + { + ComPtr<IVirtualSystemDescription> pVSys = aDescriptions[u]; + + com::SafeArray<VirtualSystemDescriptionType_T> aTypes; + com::SafeArray<BSTR> aRefs; + com::SafeArray<BSTR> aOvfValues; + com::SafeArray<BSTR> aVBoxValues; + com::SafeArray<BSTR> aExtraConfigValues; + rc = pVSys->GetDescription(ComSafeArrayAsOutParam(aTypes), + ComSafeArrayAsOutParam(aRefs), + ComSafeArrayAsOutParam(aOvfValues), + ComSafeArrayAsOutParam(aVBoxValues), + ComSafeArrayAsOutParam(aExtraConfigValues)); + if (FAILED(rc)) throw MyError(rc, "VirtualSystemDescription::GetDescription() failed\n"); + + for (uint32_t u2 = 0; + u2 < aTypes.size(); + ++u2) + { + const char *pcszType; + + VirtualSystemDescriptionType_T t = aTypes[u2]; + switch (t) + { + case VirtualSystemDescriptionType_OS: + pcszType = "ostype"; + break; + + case VirtualSystemDescriptionType_Name: + pcszType = "name"; + break; + + case VirtualSystemDescriptionType_Product: + pcszType = "product"; + break; + + case VirtualSystemDescriptionType_ProductUrl: + pcszType = "producturl"; + break; + + case VirtualSystemDescriptionType_Vendor: + pcszType = "vendor"; + break; + + case VirtualSystemDescriptionType_VendorUrl: + pcszType = "vendorurl"; + break; + + case VirtualSystemDescriptionType_Version: + pcszType = "version"; + break; + + case VirtualSystemDescriptionType_Description: + pcszType = "description"; + break; + + case VirtualSystemDescriptionType_License: + pcszType = "license"; + break; + + case VirtualSystemDescriptionType_CPU: + pcszType = "cpu"; + break; + + case VirtualSystemDescriptionType_Memory: + pcszType = "memory"; + break; + + case VirtualSystemDescriptionType_HardDiskControllerIDE: + pcszType = "ide"; + break; + + case VirtualSystemDescriptionType_HardDiskControllerSATA: + pcszType = "sata"; + break; + + case VirtualSystemDescriptionType_HardDiskControllerSAS: + pcszType = "sas"; + break; + + case VirtualSystemDescriptionType_HardDiskControllerSCSI: + pcszType = "scsi"; + break; + + case VirtualSystemDescriptionType_HardDiskControllerVirtioSCSI: + pcszType = "virtio-scsi"; + break; + + case VirtualSystemDescriptionType_HardDiskImage: + pcszType = "hd"; + break; + + case VirtualSystemDescriptionType_CDROM: + pcszType = "cdrom"; + break; + + case VirtualSystemDescriptionType_Floppy: + pcszType = "floppy"; + break; + + case VirtualSystemDescriptionType_NetworkAdapter: + pcszType = "net"; + break; + + case VirtualSystemDescriptionType_USBController: + pcszType = "usb"; + break; + + case VirtualSystemDescriptionType_SoundCard: + pcszType = "sound"; + break; + + case VirtualSystemDescriptionType_SettingsFile: + pcszType = "settings"; + break; + + case VirtualSystemDescriptionType_BaseFolder: + pcszType = "basefolder"; + break; + + case VirtualSystemDescriptionType_PrimaryGroup: + pcszType = "primarygroup"; + break; + + default: + throw MyError(E_UNEXPECTED, "Invalid VirtualSystemDescriptionType (enum)\n"); + break; + } + + RTPrintf(" vsys %2u item %2u: type %2d (%s), ovf: \"%ls\", vbox: \"%ls\", extra: \"%ls\"\n", + u, u2, t, pcszType, + aOvfValues[u2], + aVBoxValues[u2], + aExtraConfigValues[u2]); + } + } + + RTPrintf("%s: importing %d machine(s)...\n", pcszPrefix, aDescriptions.size()); + SafeArray<ImportOptions_T> sfaOptions; + rc = pAppl->ImportMachines(ComSafeArrayAsInParam(sfaOptions), pProgress.asOutParam()); + if (FAILED(rc)) throw MyError(rc, "Appliance::ImportMachines() failed\n"); + rc = pProgress->WaitForCompletion(-1); + if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n"); + pProgress->COMGETTER(ResultCode)(&rc2); + if (FAILED(rc2)) throw MyError(rc2, "Appliance::ImportMachines() failed\n", pProgress); + + com::SafeArray<BSTR> aMachineUUIDs; + rc = pAppl->COMGETTER(Machines)(ComSafeArrayAsOutParam(aMachineUUIDs)); + if (FAILED(rc)) throw MyError(rc, "Appliance::GetMachines() failed\n"); + + for (size_t u = 0; + u < aMachineUUIDs.size(); + ++u) + { + RTPrintf("%s: created machine %u: %ls\n", pcszPrefix, u, aMachineUUIDs[u]); + llMachinesCreated.push_back(Guid(Bstr(aMachineUUIDs[u]))); + } + + RTPrintf("%s: success!\n", pcszPrefix); +} + +/** + * Copies ovf-testcases/ovf-dummy.vmdk to the given target and appends that + * target as a string to the given list so that the caller can delete it + * again later. + * @param llFiles2Delete List of strings to append the target file path to. + * @param pcszDest Target for dummy VMDK. + */ +void copyDummyDiskImage(const char *pcszPrefix, + std::list<Utf8Str> &llFiles2Delete, + const char *pcszDest) +{ + char szSrc[RTPATH_MAX]; + RTPathExecDir(szSrc, sizeof(szSrc)); + RTPathAppend(szSrc, sizeof(szSrc), "ovf-testcases/ovf-dummy.vmdk"); + + char szDst[RTPATH_MAX]; + RTPathExecDir(szDst, sizeof(szDst)); + RTPathAppend(szDst, sizeof(szDst), pcszDest); + RTPrintf("%s: copying ovf-dummy.vmdk to \"%s\"...\n", pcszPrefix, pcszDest); + + /* Delete the destination file if it exists or RTFileCopy will fail. */ + if (RTFileExists(szDst)) + { + RTPrintf("Deleting file %s...\n", szDst); + RTFileDelete(szDst); + } + + int vrc = RTFileCopy(szSrc, szDst); + if (RT_FAILURE(vrc)) throw MyError(0, Utf8StrFmt("Cannot copy ovf-dummy.vmdk to %s: %Rra\n", pcszDest, vrc).c_str()); + llFiles2Delete.push_back(szDst); +} + +/** + * + * @param argc + * @param argv[] + * @return + */ +int main(int argc, char *argv[]) +{ + RTR3InitExe(argc, &argv, 0); + + RTEXITCODE rcExit = RTEXITCODE_SUCCESS; + HRESULT rc = S_OK; + + std::list<Utf8Str> llFiles2Delete; + std::list<Guid> llMachinesCreated; + + ComPtr<IVirtualBoxClient> pVirtualBoxClient; + ComPtr<IVirtualBox> pVirtualBox; + + try + { + RTPrintf("Initializing COM...\n"); + rc = com::Initialize(); + if (FAILED(rc)) throw MyError(rc, "failed to initialize COM!\n"); + + ComPtr<ISession> pSession; + + RTPrintf("Creating VirtualBox object...\n"); + rc = pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient); + if (SUCCEEDED(rc)) + rc = pVirtualBoxClient->COMGETTER(VirtualBox)(pVirtualBox.asOutParam()); + if (FAILED(rc)) throw MyError(rc, "failed to create the VirtualBox object!\n"); + + rc = pSession.createInprocObject(CLSID_Session); + if (FAILED(rc)) throw MyError(rc, "failed to create a session object!\n"); + + // for each testcase, we will copy the dummy VMDK image to the subdirectory with the OVF testcase + // so that the import will find the disks it expects; this is just for testing the import since + // the imported machines will obviously not be usable. + // llFiles2Delete receives the paths of all the files that we need to clean up later. + + // testcase 1: import ovf-joomla-0.9/joomla-1.1.4-ovf.ovf + copyDummyDiskImage("joomla-0.9", llFiles2Delete, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf-0.vmdk"); + copyDummyDiskImage("joomla-0.9", llFiles2Delete, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf-1.vmdk"); + importOVF("joomla-0.9", pVirtualBox, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf.ovf", llMachinesCreated); + + // testcase 2: import ovf-winxp-vbox-sharedfolders/winxp.ovf + copyDummyDiskImage("winxp-vbox-sharedfolders", llFiles2Delete, "ovf-testcases/ovf-winxp-vbox-sharedfolders/Windows 5.1 XP 1 merged.vmdk"); + copyDummyDiskImage("winxp-vbox-sharedfolders", llFiles2Delete, "ovf-testcases/ovf-winxp-vbox-sharedfolders/smallvdi.vmdk"); + importOVF("winxp-vbox-sharedfolders", pVirtualBox, "ovf-testcases/ovf-winxp-vbox-sharedfolders/winxp.ovf", llMachinesCreated); + + // testcase 3: import ovf-winxp-vbox-sharedfolders/winxp.ovf + importOVF("winhost-audio-nodisks", pVirtualBox, "ovf-testcases/ovf-winhost-audio-nodisks/WinXP.ovf", llMachinesCreated); + + RTPrintf("Machine imports done, no errors. Cleaning up...\n"); + } + catch (MyError &e) + { + rc = e.m_rc; + RTPrintf("%s", e.m_str.c_str()); + rcExit = RTEXITCODE_FAILURE; + } + + try + { + // clean up the machines created + for (std::list<Guid>::const_iterator it = llMachinesCreated.begin(); + it != llMachinesCreated.end(); + ++it) + { + const Guid &uuid = *it; + Bstr bstrUUID(uuid.toUtf16()); + ComPtr<IMachine> pMachine; + rc = pVirtualBox->FindMachine(bstrUUID.raw(), pMachine.asOutParam()); + if (FAILED(rc)) throw MyError(rc, "VirtualBox::FindMachine() failed\n"); + + RTPrintf(" Deleting machine %ls...\n", bstrUUID.raw()); + SafeIfaceArray<IMedium> sfaMedia; + rc = pMachine->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, + ComSafeArrayAsOutParam(sfaMedia)); + if (FAILED(rc)) throw MyError(rc, "Machine::Unregister() failed\n"); + + ComPtr<IProgress> pProgress; + rc = pMachine->DeleteConfig(ComSafeArrayAsInParam(sfaMedia), pProgress.asOutParam()); + if (FAILED(rc)) throw MyError(rc, "Machine::DeleteSettings() failed\n"); + rc = pProgress->WaitForCompletion(-1); + if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n"); + } + } + catch (MyError &e) + { + rc = e.m_rc; + RTPrintf("%s", e.m_str.c_str()); + rcExit = RTEXITCODE_FAILURE; + } + + // clean up the VMDK copies that we made in copyDummyDiskImage() + for (std::list<Utf8Str>::const_iterator it = llFiles2Delete.begin(); + it != llFiles2Delete.end(); + ++it) + { + const Utf8Str &strFile = *it; + RTPrintf("Deleting file %s...\n", strFile.c_str()); + RTFileDelete(strFile.c_str()); + } + + pVirtualBox.setNull(); + pVirtualBoxClient.setNull(); + + RTPrintf("Shutting down COM...\n"); + com::Shutdown(); + RTPrintf("tstOVF all done: %s\n", rcExit ? "ERROR" : "SUCCESS"); + + return rcExit; +} + diff --git a/src/VBox/Main/testcase/tstUSBLinux.h b/src/VBox/Main/testcase/tstUSBLinux.h new file mode 100644 index 00000000..b112db96 --- /dev/null +++ b/src/VBox/Main/testcase/tstUSBLinux.h @@ -0,0 +1,79 @@ +/* $Id: tstUSBLinux.h $ */ +/** @file + * VirtualBox USB Proxy Service class, test version for Linux hosts. + */ + +/* + * Copyright (C) 2008-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#ifndef MAIN_INCLUDED_SRC_testcase_tstUSBLinux_h +#define MAIN_INCLUDED_SRC_testcase_tstUSBLinux_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +typedef int HRESULT; +enum { S_OK = 0, E_NOTIMPL = 1 }; + +#include <VBox/usb.h> +#include <VBox/usbfilter.h> + +#include <VBox/err.h> + +#ifdef VBOX_USB_WITH_SYSFS +# include <libhal.h> +#endif + +#include <stdio.h> +/** + * The Linux hosted USB Proxy Service. + */ +class USBProxyServiceLinux +{ +public: + USBProxyServiceLinux() + : mLastError(VINF_SUCCESS) + {} + + HRESULT initSysfs(void); + PUSBDEVICE getDevicesFromSysfs(void); + int getLastError(void) + { + return mLastError; + } + +private: + int start(void) { return VINF_SUCCESS; } + static void freeDevice(PUSBDEVICE) {} /* We don't care about leaks in a test. */ + int usbProbeInterfacesFromLibhal(const char *pszHalUuid, PUSBDEVICE pDev); + int mLastError; +# ifdef VBOX_USB_WITH_SYSFS + /** Our connection to DBus for getting information from hal. This will be + * NULL if the initialisation failed. */ + DBusConnection *mDBusConnection; + /** Handle to libhal. */ + LibHalContext *mLibHalContext; +# endif +}; + +#endif /* !MAIN_INCLUDED_SRC_testcase_tstUSBLinux_h */ + diff --git a/src/VBox/Main/testcase/tstUSBProxyLinux.cpp b/src/VBox/Main/testcase/tstUSBProxyLinux.cpp new file mode 100644 index 00000000..db199da3 --- /dev/null +++ b/src/VBox/Main/testcase/tstUSBProxyLinux.cpp @@ -0,0 +1,195 @@ +/* $Id: tstUSBProxyLinux.cpp $ */ +/** @file + * USBProxyBackendLinux test case. + */ + +/* + * Copyright (C) 2011-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ + +#include "USBGetDevices.h" + +#include <VBox/err.h> +#include <iprt/assert.h> +#include <iprt/env.h> +#include <iprt/string.h> +#include <iprt/test.h> + +/*** BEGIN STUBS ***/ + +static struct +{ + const char *pcszEnvUsb; + const char *pcszEnvUsbRoot; + const char *pcszDevicesRoot; + bool fDevicesAccessible; + const char *pcszUsbfsRoot; + bool fUsbfsAccessible; + int rcMethodInit; + const char *pcszDevicesRootExpected; + bool fUsingUsbfsExpected; + int rcExpected; +} s_testEnvironment[] = +{ + /* "sysfs" and valid root in the environment */ + { "sysfs", "/dev/bus/usb", "/dev/bus/usb", true, NULL, false, VINF_SUCCESS, "/dev/bus/usb", false, VINF_SUCCESS }, + /* "sysfs" and bad root in the environment */ + { "sysfs", "/dev/bus/usb", "/dev/vboxusb", false, "/proc/usb/bus", false, VINF_SUCCESS, "", true, VERR_NOT_FOUND }, + /* "sysfs" and no root in the environment */ + { "sysfs", NULL, "/dev/vboxusb", true, NULL, false, VINF_SUCCESS, "/dev/vboxusb", false, VINF_SUCCESS }, + /* "usbfs" and valid root in the environment */ + { "usbfs", "/dev/bus/usb", NULL, false, "/dev/bus/usb", true, VINF_SUCCESS, "/dev/bus/usb", true, VINF_SUCCESS }, + /* "usbfs" and bad root in the environment */ + { "usbfs", "/dev/bus/usb", "/dev/vboxusb", false, "/proc/usb/bus", false, VINF_SUCCESS, "", true, VERR_NOT_FOUND }, + /* "usbfs" and no root in the environment */ + { "usbfs", NULL, NULL, false, "/proc/bus/usb", true, VINF_SUCCESS, "/proc/bus/usb", true, VINF_SUCCESS }, + /* invalid method in the environment, sysfs available */ + { "invalid", "/dev/bus/usb", "/dev/vboxusb", true, NULL, false, VINF_SUCCESS, "/dev/vboxusb", false, VINF_SUCCESS }, + /* invalid method in the environment, usbfs available */ + { "invalid", "/dev/bus/usb", NULL, true, "/proc/bus/usb", true, VINF_SUCCESS, "/proc/bus/usb", true, VINF_SUCCESS }, + /* invalid method in the environment, sysfs inaccessible */ + { "invalid", "/dev/bus/usb", "/dev/vboxusb", false, NULL, false, VINF_SUCCESS, "", true, VERR_VUSB_USB_DEVICE_PERMISSION }, + /* invalid method in the environment, usbfs inaccessible */ + { "invalid", "/dev/bus/usb", NULL, false, "/proc/bus/usb", false, VINF_SUCCESS, "", true, VERR_VUSB_USBFS_PERMISSION }, + /* No environment, sysfs and usbfs available but without access permissions. */ + { NULL, NULL, "/dev/vboxusb", false, "/proc/bus/usb", false, VERR_NO_MEMORY, "", true, VERR_VUSB_USB_DEVICE_PERMISSION }, + /* No environment, sysfs and usbfs available, access permissions for sysfs. */ + { NULL, NULL, "/dev/vboxusb", true, "/proc/bus/usb", false, VINF_SUCCESS, "/dev/vboxusb", false, VINF_SUCCESS }, + /* No environment, sysfs and usbfs available, access permissions for usbfs. */ + { NULL, NULL, "/dev/vboxusb", false, "/proc/bus/usb", true, VINF_SUCCESS, "/proc/bus/usb", true, VINF_SUCCESS }, + /* No environment, sysfs available but without access permissions. */ + { NULL, NULL, "/dev/vboxusb", false, NULL, false, VERR_NO_MEMORY, "", true, VERR_VUSB_USB_DEVICE_PERMISSION }, + /* No environment, usbfs available but without access permissions. */ + { NULL, NULL, NULL, false, "/proc/bus/usb", false, VERR_NO_MEMORY, "", true, VERR_VUSB_USBFS_PERMISSION }, +}; + +static void testInit(RTTEST hTest) +{ + RTTestSub(hTest, "Testing USBProxyLinuxChooseMethod"); + for (unsigned i = 0; i < RT_ELEMENTS(s_testEnvironment); ++i) + { + bool fUsingUsbfs = true; + const char *pcszDevicesRoot = ""; + + TestUSBSetEnv(s_testEnvironment[i].pcszEnvUsb, + s_testEnvironment[i].pcszEnvUsbRoot); + TestUSBSetupInit(s_testEnvironment[i].pcszUsbfsRoot, + s_testEnvironment[i].fUsbfsAccessible, + s_testEnvironment[i].pcszDevicesRoot, + s_testEnvironment[i].fDevicesAccessible, + s_testEnvironment[i].rcMethodInit); + int rc = USBProxyLinuxChooseMethod(&fUsingUsbfs, &pcszDevicesRoot); + RTTESTI_CHECK_MSG(rc == s_testEnvironment[i].rcExpected, + ("rc=%Rrc (test index %i) instead of %Rrc!\n", + rc, i, s_testEnvironment[i].rcExpected)); + RTTESTI_CHECK_MSG(!RTStrCmp(pcszDevicesRoot, + s_testEnvironment[i].pcszDevicesRootExpected), + ("testGetDevicesRoot() returned %s (test index %i) instead of %s!\n", + pcszDevicesRoot, i, + s_testEnvironment[i].pcszDevicesRootExpected)); + RTTESTI_CHECK_MSG( fUsingUsbfs + == s_testEnvironment[i].fUsingUsbfsExpected, + ("testGetUsingUsbfs() returned %RTbool (test index %i) instead of %RTbool!\n", + fUsingUsbfs, i, + s_testEnvironment[i].fUsingUsbfsExpected)); + } +} + +static struct +{ + const char *pacszDeviceAddresses[16]; + const char *pacszAccessibleFiles[16]; + const char *pcszRoot; + bool fIsDeviceNodes; + bool fAvailableExpected; +} s_testCheckDeviceRoot[] = +{ + /* /dev/vboxusb accessible -> device nodes method available */ + { { NULL }, { "/dev/vboxusb" }, "/dev/vboxusb", true, true }, + /* /dev/vboxusb present but not accessible -> device nodes method not + * available */ + { { NULL }, { NULL }, "/dev/vboxusb", true, false }, + /* /proc/bus/usb available but empty -> usbfs method available (we can't + * really check in this case) */ + { { NULL }, { "/proc/bus/usb" }, "/proc/bus/usb", false, true }, + /* /proc/bus/usb not available or not accessible -> usbfs method not available */ + { { NULL }, { NULL }, "/proc/bus/usb", false, false }, + /* /proc/bus/usb available, one inaccessible device -> usbfs method not + * available */ + { { "/proc/bus/usb/001/001" }, { "/proc/bus/usb" }, "/proc/bus/usb", false, false }, + /* /proc/bus/usb available, one device of two inaccessible -> usbfs method + * not available */ + { { "/proc/bus/usb/001/001", "/proc/bus/usb/002/002" }, + { "/proc/bus/usb", "/proc/bus/usb/001/001" }, "/proc/bus/usb", false, false }, + /* /proc/bus/usb available, two accessible devices -> usbfs method + * available */ + { { "/proc/bus/usb/001/001", "/proc/bus/usb/002/002" }, + { "/proc/bus/usb", "/proc/bus/usb/001/001", "/proc/bus/usb/002/002" }, + "/proc/bus/usb", false, true } +}; + +static void testCheckDeviceRoot(RTTEST hTest) +{ + RTTestSub(hTest, "Testing the USBProxyLinuxCheckDeviceRoot API"); + for (unsigned i = 0; i < RT_ELEMENTS(s_testCheckDeviceRoot); ++i) + { + TestUSBSetAvailableUsbfsDevices(s_testCheckDeviceRoot[i] + .pacszDeviceAddresses); + TestUSBSetAccessibleFiles(s_testCheckDeviceRoot[i] + .pacszAccessibleFiles); + bool fAvailable = USBProxyLinuxCheckDeviceRoot + (s_testCheckDeviceRoot[i].pcszRoot, + s_testCheckDeviceRoot[i].fIsDeviceNodes); + RTTESTI_CHECK_MSG( fAvailable + == s_testCheckDeviceRoot[i].fAvailableExpected, + ("USBProxyLinuxCheckDeviceRoot() returned %RTbool (test index %i) instead of %RTbool!\n", + fAvailable, i, + s_testCheckDeviceRoot[i].fAvailableExpected)); + } +} + +int main(void) +{ + /* + * Init the runtime, test and say hello. + */ + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstUSBProxyLinux", &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(hTest); + + /* + * Run the tests. + */ + testInit(hTest); + testCheckDeviceRoot(hTest); + + /* + * Summary + */ + return RTTestSummaryAndDestroy(hTest); +} diff --git a/src/VBox/Main/testcase/tstUnattendedScript-1.expected b/src/VBox/Main/testcase/tstUnattendedScript-1.expected new file mode 100644 index 00000000..1457a2e7 --- /dev/null +++ b/src/VBox/Main/testcase/tstUnattendedScript-1.expected @@ -0,0 +1,384 @@ +/* + * Regular conditions. + */ +01=true +02=false +03=true +04=true +05=true +06=false +07=true +08=false +09=true + +/* + * Expression conditions. + */ +01=true +02=false +03=true +04=true +05=true +06=false +07=true +08=false +09=true + + +/* + * Regular inserts. + */ +/* variables */ +01=vboxuser +02=changeme +03=changeme +04=VBox & VBox; +05=911 +06=/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word="word" --sq-word='word' +07=/aux/install/dir +08=42 +09=x86 +10=x86 +11=i386 +12=i486 +13=i686 +14=3.4.2 +15=3 +16=cet +17=cet +18=cet +19=dk_DK +20=dk-DK +21=dk +22=DK +23=my-extra-long-name.hostname.com +24=my-extra-long-name +25=my-extra-long-n +26=hostname.com +27=http://proxy.intranet.com:443 + +/* indicators */ +01=1 +02=0 +03=1 +04=1 +05=1 +06=0 +07=1 +08=0 +09=1 + + +/* + * Expression inserts + */ +/* variables */ +01=vboxuser +02=changeme +03=changeme +04=VBox & VBox; +05=911 +06=/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word="word" --sq-word='word' +07=/aux/install/dir +08=42 +09=x86 +10=x86 +11=i386 +12=i486 +13=i686 +14=3.4.2 +15=3 +16=cet +17=cet +18=cet +19=dk_DK +20=dk-DK +21=dk +22=DK +23=my-extra-long-name.hostname.com +24=my-extra-long-name +25=my-extra-long-n +26=hostname.com +27=http://proxy.intranet.com:443 + +/* indicators */ +01=1 +02=0 +03=1 +04=1 +05=1 +06=0 +07=1 +08=0 +09=1 + + +/* + * Regular inserts with shell quoting. + */ +/* variables */ +01=vboxuser +02=changeme +03=changeme +04='VBox & VBox;' +05=911 +06='/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word="word" --sq-word='"'"'word'"'"'' +07=/aux/install/dir +08=42 +09=x86 +10=x86 +11=i386 +12=i486 +13=i686 +14=3.4.2 +15=3 +16=cet +17=cet +18=cet +19=dk_DK +20=dk-DK +21=dk +22=DK +23=my-extra-long-name.hostname.com +24=my-extra-long-name +25=my-extra-long-n +26=hostname.com +27=http://proxy.intranet.com:443 + +/* indicators */ +01=1 +02=0 +03=1 +04=1 +05=1 +06=0 +07=1 +08=0 +09=1 + + +/* + * Expression inserts with shell quoting. + */ +/* variables */ +01=vboxuser +02=changeme +03=changeme +04='VBox & VBox;' +05=911 +06='/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word="word" --sq-word='"'"'word'"'"'' +07=/aux/install/dir +08=42 +09=x86 +10=x86 +11=i386 +12=i486 +13=i686 +14=3.4.2 +15=3 +16=cet +17=cet +18=cet +19=dk_DK +20=dk-DK +21=dk +22=DK +23=my-extra-long-name.hostname.com +24=my-extra-long-name +25=my-extra-long-n +26=hostname.com +27=http://proxy.intranet.com:443 + +/* indicators */ +01=1 +02=0 +03=1 +04=1 +05=1 +06=0 +07=1 +08=0 +09=1 + + +/* + * Regular inserts escaped for use in XML element. + */ +/* variables */ +01=vboxuser +02=changeme +03=changeme +04=VBox & VBox; +05=911 +06=/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word="word" --sq-word='word' +07=/aux/install/dir +08=42 +09=x86 +10=x86 +11=i386 +12=i486 +13=i686 +14=3.4.2 +15=3 +16=cet +17=cet +18=cet +19=dk_DK +20=dk-DK +21=dk +22=DK +23=my-extra-long-name.hostname.com +24=my-extra-long-name +25=my-extra-long-n +26=hostname.com +27=http://proxy.intranet.com:443 + +/* indicators */ +01=1 +02=0 +03=1 +04=1 +05=1 +06=0 +07=1 +08=0 +09=1 + + +/* + * Expression inserts escaped for use in XML element. + */ +/* variables */ +01=vboxuser +02=changeme +03=changeme +04=VBox & VBox; +05=911 +06=/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word="word" --sq-word='word' +07=/aux/install/dir +08=42 +09=x86 +10=x86 +11=i386 +12=i486 +13=i686 +14=3.4.2 +15=3 +16=cet +17=cet +18=cet +19=dk_DK +20=dk-DK +21=dk +22=DK +23=my-extra-long-name.hostname.com +24=my-extra-long-name +25=my-extra-long-n +26=hostname.com +27=http://proxy.intranet.com:443 + +/* indicators */ +01=1 +02=0 +03=1 +04=1 +05=1 +06=0 +07=1 +08=0 +09=1 + + +/* + * Regular inserts escaped for use in double quoted attributes. + */ +/* variables */ +01=vboxuser +02=changeme +03=changeme +04=VBox & VBox; +05=911 +06=/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word="word" --sq-word='word' +07=/aux/install/dir +08=42 +09=x86 +10=x86 +11=i386 +12=i486 +13=i686 +14=3.4.2 +15=3 +16=cet +17=cet +18=cet +19=dk_DK +20=dk-DK +21=dk +22=DK +23=my-extra-long-name.hostname.com +24=my-extra-long-name +25=my-extra-long-n +26=hostname.com +27=http://proxy.intranet.com:443 + +/* indicators */ +01=1 +02=0 +03=1 +04=1 +05=1 +06=0 +07=1 +08=0 +09=1 + + +/* + * Expression inserts escaped for use in double quoted attributes. + */ +/* variables */ +01=vboxuser +02=changeme +03=changeme +04=VBox & VBox; +05=911 +06=/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word="word" --sq-word='word' +07=/aux/install/dir +08=42 +09=x86 +10=x86 +11=i386 +12=i486 +13=i686 +14=3.4.2 +15=3 +16=cet +17=cet +18=cet +19=dk_DK +20=dk-DK +21=dk +22=DK +23=my-extra-long-name.hostname.com +24=my-extra-long-name +25=my-extra-long-n +26=hostname.com +27=http://proxy.intranet.com:443 + +/* indicators */ +01=1 +02=0 +03=1 +04=1 +05=1 +06=0 +07=1 +08=0 +09=1 + + +/* + * Some typical expression conditions. + */ +01: GUEST_OS_VERSION >= 1.2.3 +02: GUEST_OS_VERSION <= 3.4.2 diff --git a/src/VBox/Main/testcase/tstUnattendedScript-1.template b/src/VBox/Main/testcase/tstUnattendedScript-1.template new file mode 100644 index 00000000..07762c7d --- /dev/null +++ b/src/VBox/Main/testcase/tstUnattendedScript-1.template @@ -0,0 +1,384 @@ +/* + * Regular conditions. + */ +01=@@VBOX_COND_IS_INSTALLING_ADDITIONS@@true@@VBOX_COND_ELSE@@ false @@VBOX_COND_END@@ +02=@@VBOX_COND_IS_USER_LOGIN_ADMINISTRATOR@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +03=@@VBOX_COND_IS_INSTALLING_TEST_EXEC_SERVICE@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +04=@@VBOX_COND_HAS_POST_INSTALL_COMMAND@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +05=@@VBOX_COND_HAS_PRODUCT_KEY@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +06=@@VBOX_COND_IS_MINIMAL_INSTALLATION@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +07=@@VBOX_COND_IS_FIRMWARE_UEFI@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +08=@@VBOX_COND_IS_RTC_USING_UTC@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +09=@@VBOX_COND_HAS_PROXY@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ + +/* + * Expression conditions. + */ +01=@@VBOX_COND[${IS_INSTALLING_ADDITIONS}]@@true@@VBOX_COND_ELSE@@ false @@VBOX_COND_END@@ +02=@@VBOX_COND[${IS_USER_LOGIN_ADMINISTRATOR}]@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +03=@@VBOX_COND[${IS_INSTALLING_TEST_EXEC_SERVICE}]@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +04=@@VBOX_COND[${HAS_POST_INSTALL_COMMAND}]@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +05=@@VBOX_COND[${HAS_PRODUCT_KEY}]@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +06=@@VBOX_COND[${IS_MINIMAL_INSTALLATION}]@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +07=@@VBOX_COND[${IS_FIRMWARE_UEFI}]@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +08=@@VBOX_COND[${IS_RTC_USING_UTC}]@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ +09=@@VBOX_COND[${HAS_PROXY}]@@true@@VBOX_COND_ELSE@@false@@VBOX_COND_END@@ + + +/* + * Regular inserts. + */ +/* variables */ +01=@@VBOX_INSERT_USER_LOGIN@@ +02=@@VBOX_INSERT_USER_PASSWORD@@ +03=@@VBOX_INSERT_ROOT_PASSWORD@@ +04=@@VBOX_INSERT_USER_FULL_NAME@@ +05=@@VBOX_INSERT_PRODUCT_KEY@@ +06=@@VBOX_INSERT_POST_INSTALL_COMMAND@@ +07=@@VBOX_INSERT_AUXILIARY_INSTALL_DIR@@ +08=@@VBOX_INSERT_IMAGE_INDEX@@ +09=@@VBOX_INSERT_OS_ARCH@@ +10=@@VBOX_INSERT_OS_ARCH2@@ +11=@@VBOX_INSERT_OS_ARCH3@@ +12=@@VBOX_INSERT_OS_ARCH4@@ +13=@@VBOX_INSERT_OS_ARCH6@@ +14=@@VBOX_INSERT_GUEST_OS_VERSION@@ +15=@@VBOX_INSERT_GUEST_OS_MAJOR_VERSION@@ +16=@@VBOX_INSERT_TIME_ZONE_UX@@ +17=@@VBOX_INSERT_TIME_ZONE_WIN_NAME@@ +18=@@VBOX_INSERT_TIME_ZONE_WIN_INDEX@@ +19=@@VBOX_INSERT_LOCALE@@ +20=@@VBOX_INSERT_DASH_LOCALE@@ +21=@@VBOX_INSERT_LANGUAGE@@ +22=@@VBOX_INSERT_COUNTRY@@ +23=@@VBOX_INSERT_HOSTNAME_FQDN@@ +24=@@VBOX_INSERT_HOSTNAME_WITHOUT_DOMAIN@@ +25=@@VBOX_INSERT_HOSTNAME_WITHOUT_DOMAIN_MAX_15@@ +26=@@VBOX_INSERT_HOSTNAME_DOMAIN@@ +27=@@VBOX_INSERT_PROXY@@ + +/* indicators */ +01=@@VBOX_INSERT_IS_INSTALLING_ADDITIONS@@ +02=@@VBOX_INSERT_IS_USER_LOGIN_ADMINISTRATOR@@ +03=@@VBOX_INSERT_IS_INSTALLING_TEST_EXEC_SERVICE@@ +04=@@VBOX_INSERT_HAS_POST_INSTALL_COMMAND@@ +05=@@VBOX_INSERT_HAS_PRODUCT_KEY@@ +06=@@VBOX_INSERT_IS_MINIMAL_INSTALLATION@@ +07=@@VBOX_INSERT_IS_FIRMWARE_UEFI@@ +08=@@VBOX_INSERT_IS_RTC_USING_UTC@@ +09=@@VBOX_INSERT_HAS_PROXY@@ + + +/* + * Expression inserts + */ +/* variables */ +01=@@VBOX_INSERT[${USER_LOGIN}]@@ +02=@@VBOX_INSERT[${USER_PASSWORD}]@@ +03=@@VBOX_INSERT[${ROOT_PASSWORD}]@@ +04=@@VBOX_INSERT[${USER_FULL_NAME}]@@ +05=@@VBOX_INSERT[${PRODUCT_KEY}]@@ +06=@@VBOX_INSERT[${POST_INSTALL_COMMAND}]@@ +07=@@VBOX_INSERT[${AUXILIARY_INSTALL_DIR}]@@ +08=@@VBOX_INSERT[${IMAGE_INDEX}]@@ +09=@@VBOX_INSERT[${OS_ARCH}]@@ +10=@@VBOX_INSERT[${OS_ARCH2}]@@ +11=@@VBOX_INSERT[${OS_ARCH3}]@@ +12=@@VBOX_INSERT[${OS_ARCH4}]@@ +13=@@VBOX_INSERT[${OS_ARCH6}]@@ +14=@@VBOX_INSERT[${GUEST_OS_VERSION}]@@ +15=@@VBOX_INSERT[${GUEST_OS_MAJOR_VERSION}]@@ +16=@@VBOX_INSERT[${TIME_ZONE_UX}]@@ +17=@@VBOX_INSERT[${TIME_ZONE_WIN_NAME}]@@ +18=@@VBOX_INSERT[${TIME_ZONE_WIN_INDEX}]@@ +19=@@VBOX_INSERT[${LOCALE}]@@ +20=@@VBOX_INSERT[${DASH_LOCALE}]@@ +21=@@VBOX_INSERT[${LANGUAGE}]@@ +22=@@VBOX_INSERT[${COUNTRY}]@@ +23=@@VBOX_INSERT[${HOSTNAME_FQDN}]@@ +24=@@VBOX_INSERT[${HOSTNAME_WITHOUT_DOMAIN}]@@ +25=@@VBOX_INSERT[${HOSTNAME_WITHOUT_DOMAIN_MAX_15}]@@ +26=@@VBOX_INSERT[${HOSTNAME_DOMAIN}]@@ +27=@@VBOX_INSERT[${PROXY}]@@ + +/* indicators */ +01=@@VBOX_INSERT[${IS_INSTALLING_ADDITIONS}]@@ +02=@@VBOX_INSERT[${IS_USER_LOGIN_ADMINISTRATOR}]@@ +03=@@VBOX_INSERT[${IS_INSTALLING_TEST_EXEC_SERVICE}]@@ +04=@@VBOX_INSERT[${HAS_POST_INSTALL_COMMAND}]@@ +05=@@VBOX_INSERT[${HAS_PRODUCT_KEY}]@@ +06=@@VBOX_INSERT[${IS_MINIMAL_INSTALLATION}]@@ +07=@@VBOX_INSERT[${IS_FIRMWARE_UEFI}]@@ +08=@@VBOX_INSERT[${IS_RTC_USING_UTC}]@@ +09=@@VBOX_INSERT[${HAS_PROXY}]@@ + + +/* + * Regular inserts with shell quoting. + */ +/* variables */ +01=@@VBOX_INSERT_USER_LOGIN_SH@@ +02=@@VBOX_INSERT_USER_PASSWORD_SH@@ +03=@@VBOX_INSERT_ROOT_PASSWORD_SH@@ +04=@@VBOX_INSERT_USER_FULL_NAME_SH@@ +05=@@VBOX_INSERT_PRODUCT_KEY_SH@@ +06=@@VBOX_INSERT_POST_INSTALL_COMMAND_SH@@ +07=@@VBOX_INSERT_AUXILIARY_INSTALL_DIR_SH@@ +08=@@VBOX_INSERT_IMAGE_INDEX_SH@@ +09=@@VBOX_INSERT_OS_ARCH_SH@@ +10=@@VBOX_INSERT_OS_ARCH2_SH@@ +11=@@VBOX_INSERT_OS_ARCH3_SH@@ +12=@@VBOX_INSERT_OS_ARCH4_SH@@ +13=@@VBOX_INSERT_OS_ARCH6_SH@@ +14=@@VBOX_INSERT_GUEST_OS_VERSION_SH@@ +15=@@VBOX_INSERT_GUEST_OS_MAJOR_VERSION_SH@@ +16=@@VBOX_INSERT_TIME_ZONE_UX_SH@@ +17=@@VBOX_INSERT_TIME_ZONE_WIN_NAME_SH@@ +18=@@VBOX_INSERT_TIME_ZONE_WIN_INDEX_SH@@ +19=@@VBOX_INSERT_LOCALE_SH@@ +20=@@VBOX_INSERT_DASH_LOCALE_SH@@ +21=@@VBOX_INSERT_LANGUAGE_SH@@ +22=@@VBOX_INSERT_COUNTRY_SH@@ +23=@@VBOX_INSERT_HOSTNAME_FQDN_SH@@ +24=@@VBOX_INSERT_HOSTNAME_WITHOUT_DOMAIN_SH@@ +25=@@VBOX_INSERT_HOSTNAME_WITHOUT_DOMAIN_MAX_15_SH@@ +26=@@VBOX_INSERT_HOSTNAME_DOMAIN_SH@@ +27=@@VBOX_INSERT_PROXY_SH@@ + +/* indicators */ +01=@@VBOX_INSERT_IS_INSTALLING_ADDITIONS_SH@@ +02=@@VBOX_INSERT_IS_USER_LOGIN_ADMINISTRATOR_SH@@ +03=@@VBOX_INSERT_IS_INSTALLING_TEST_EXEC_SERVICE_SH@@ +04=@@VBOX_INSERT_HAS_POST_INSTALL_COMMAND_SH@@ +05=@@VBOX_INSERT_HAS_PRODUCT_KEY_SH@@ +06=@@VBOX_INSERT_IS_MINIMAL_INSTALLATION_SH@@ +07=@@VBOX_INSERT_IS_FIRMWARE_UEFI_SH@@ +08=@@VBOX_INSERT_IS_RTC_USING_UTC_SH@@ +09=@@VBOX_INSERT_HAS_PROXY_SH@@ + + +/* + * Expression inserts with shell quoting. + */ +/* variables */ +01=@@VBOX_INSERT[${USER_LOGIN}]SH@@ +02=@@VBOX_INSERT[${USER_PASSWORD}]SH@@ +03=@@VBOX_INSERT[${ROOT_PASSWORD}]SH@@ +04=@@VBOX_INSERT[${USER_FULL_NAME}]SH@@ +05=@@VBOX_INSERT[${PRODUCT_KEY}]SH@@ +06=@@VBOX_INSERT[${POST_INSTALL_COMMAND}]SH@@ +07=@@VBOX_INSERT[${AUXILIARY_INSTALL_DIR}]SH@@ +08=@@VBOX_INSERT[${IMAGE_INDEX}]SH@@ +09=@@VBOX_INSERT[${OS_ARCH}]SH@@ +10=@@VBOX_INSERT[${OS_ARCH2}]SH@@ +11=@@VBOX_INSERT[${OS_ARCH3}]SH@@ +12=@@VBOX_INSERT[${OS_ARCH4}]SH@@ +13=@@VBOX_INSERT[${OS_ARCH6}]SH@@ +14=@@VBOX_INSERT[${GUEST_OS_VERSION}]SH@@ +15=@@VBOX_INSERT[${GUEST_OS_MAJOR_VERSION}]SH@@ +16=@@VBOX_INSERT[${TIME_ZONE_UX}]SH@@ +17=@@VBOX_INSERT[${TIME_ZONE_WIN_NAME}]SH@@ +18=@@VBOX_INSERT[${TIME_ZONE_WIN_INDEX}]SH@@ +19=@@VBOX_INSERT[${LOCALE}]SH@@ +20=@@VBOX_INSERT[${DASH_LOCALE}]SH@@ +21=@@VBOX_INSERT[${LANGUAGE}]SH@@ +22=@@VBOX_INSERT[${COUNTRY}]SH@@ +23=@@VBOX_INSERT[${HOSTNAME_FQDN}]SH@@ +24=@@VBOX_INSERT[${HOSTNAME_WITHOUT_DOMAIN}]SH@@ +25=@@VBOX_INSERT[${HOSTNAME_WITHOUT_DOMAIN_MAX_15}]SH@@ +26=@@VBOX_INSERT[${HOSTNAME_DOMAIN}]SH@@ +27=@@VBOX_INSERT[${PROXY}]SH@@ + +/* indicators */ +01=@@VBOX_INSERT[${IS_INSTALLING_ADDITIONS}]SH@@ +02=@@VBOX_INSERT[${IS_USER_LOGIN_ADMINISTRATOR}]SH@@ +03=@@VBOX_INSERT[${IS_INSTALLING_TEST_EXEC_SERVICE}]SH@@ +04=@@VBOX_INSERT[${HAS_POST_INSTALL_COMMAND}]SH@@ +05=@@VBOX_INSERT[${HAS_PRODUCT_KEY}]SH@@ +06=@@VBOX_INSERT[${IS_MINIMAL_INSTALLATION}]SH@@ +07=@@VBOX_INSERT[${IS_FIRMWARE_UEFI}]SH@@ +08=@@VBOX_INSERT[${IS_RTC_USING_UTC}]SH@@ +09=@@VBOX_INSERT[${HAS_PROXY}]SH@@ + + +/* + * Regular inserts escaped for use in XML element. + */ +/* variables */ +01=@@VBOX_INSERT_USER_LOGIN_ELEMENT@@ +02=@@VBOX_INSERT_USER_PASSWORD_ELEMENT@@ +03=@@VBOX_INSERT_ROOT_PASSWORD_ELEMENT@@ +04=@@VBOX_INSERT_USER_FULL_NAME_ELEMENT@@ +05=@@VBOX_INSERT_PRODUCT_KEY_ELEMENT@@ +06=@@VBOX_INSERT_POST_INSTALL_COMMAND_ELEMENT@@ +07=@@VBOX_INSERT_AUXILIARY_INSTALL_DIR_ELEMENT@@ +08=@@VBOX_INSERT_IMAGE_INDEX_ELEMENT@@ +09=@@VBOX_INSERT_OS_ARCH_ELEMENT@@ +10=@@VBOX_INSERT_OS_ARCH2_ELEMENT@@ +11=@@VBOX_INSERT_OS_ARCH3_ELEMENT@@ +12=@@VBOX_INSERT_OS_ARCH4_ELEMENT@@ +13=@@VBOX_INSERT_OS_ARCH6_ELEMENT@@ +14=@@VBOX_INSERT_GUEST_OS_VERSION_ELEMENT@@ +15=@@VBOX_INSERT_GUEST_OS_MAJOR_VERSION_ELEMENT@@ +16=@@VBOX_INSERT_TIME_ZONE_UX_ELEMENT@@ +17=@@VBOX_INSERT_TIME_ZONE_WIN_NAME_ELEMENT@@ +18=@@VBOX_INSERT_TIME_ZONE_WIN_INDEX_ELEMENT@@ +19=@@VBOX_INSERT_LOCALE_ELEMENT@@ +20=@@VBOX_INSERT_DASH_LOCALE_ELEMENT@@ +21=@@VBOX_INSERT_LANGUAGE_ELEMENT@@ +22=@@VBOX_INSERT_COUNTRY_ELEMENT@@ +23=@@VBOX_INSERT_HOSTNAME_FQDN_ELEMENT@@ +24=@@VBOX_INSERT_HOSTNAME_WITHOUT_DOMAIN_ELEMENT@@ +25=@@VBOX_INSERT_HOSTNAME_WITHOUT_DOMAIN_MAX_15_ELEMENT@@ +26=@@VBOX_INSERT_HOSTNAME_DOMAIN_ELEMENT@@ +27=@@VBOX_INSERT_PROXY_ELEMENT@@ + +/* indicators */ +01=@@VBOX_INSERT_IS_INSTALLING_ADDITIONS_ELEMENT@@ +02=@@VBOX_INSERT_IS_USER_LOGIN_ADMINISTRATOR_ELEMENT@@ +03=@@VBOX_INSERT_IS_INSTALLING_TEST_EXEC_SERVICE_ELEMENT@@ +04=@@VBOX_INSERT_HAS_POST_INSTALL_COMMAND_ELEMENT@@ +05=@@VBOX_INSERT_HAS_PRODUCT_KEY_ELEMENT@@ +06=@@VBOX_INSERT_IS_MINIMAL_INSTALLATION_ELEMENT@@ +07=@@VBOX_INSERT_IS_FIRMWARE_UEFI_ELEMENT@@ +08=@@VBOX_INSERT_IS_RTC_USING_UTC_ELEMENT@@ +09=@@VBOX_INSERT_HAS_PROXY_ELEMENT@@ + + +/* + * Expression inserts escaped for use in XML element. + */ +/* variables */ +01=@@VBOX_INSERT[${USER_LOGIN}]ELEMENT@@ +02=@@VBOX_INSERT[${USER_PASSWORD}]ELEMENT@@ +03=@@VBOX_INSERT[${ROOT_PASSWORD}]ELEMENT@@ +04=@@VBOX_INSERT[${USER_FULL_NAME}]ELEMENT@@ +05=@@VBOX_INSERT[${PRODUCT_KEY}]ELEMENT@@ +06=@@VBOX_INSERT[${POST_INSTALL_COMMAND}]ELEMENT@@ +07=@@VBOX_INSERT[${AUXILIARY_INSTALL_DIR}]ELEMENT@@ +08=@@VBOX_INSERT[${IMAGE_INDEX}]ELEMENT@@ +09=@@VBOX_INSERT[${OS_ARCH}]ELEMENT@@ +10=@@VBOX_INSERT[${OS_ARCH2}]ELEMENT@@ +11=@@VBOX_INSERT[${OS_ARCH3}]ELEMENT@@ +12=@@VBOX_INSERT[${OS_ARCH4}]ELEMENT@@ +13=@@VBOX_INSERT[${OS_ARCH6}]ELEMENT@@ +14=@@VBOX_INSERT[${GUEST_OS_VERSION}]ELEMENT@@ +15=@@VBOX_INSERT[${GUEST_OS_MAJOR_VERSION}]ELEMENT@@ +16=@@VBOX_INSERT[${TIME_ZONE_UX}]ELEMENT@@ +17=@@VBOX_INSERT[${TIME_ZONE_WIN_NAME}]ELEMENT@@ +18=@@VBOX_INSERT[${TIME_ZONE_WIN_INDEX}]ELEMENT@@ +19=@@VBOX_INSERT[${LOCALE}]ELEMENT@@ +20=@@VBOX_INSERT[${DASH_LOCALE}]ELEMENT@@ +21=@@VBOX_INSERT[${LANGUAGE}]ELEMENT@@ +22=@@VBOX_INSERT[${COUNTRY}]ELEMENT@@ +23=@@VBOX_INSERT[${HOSTNAME_FQDN}]ELEMENT@@ +24=@@VBOX_INSERT[${HOSTNAME_WITHOUT_DOMAIN}]ELEMENT@@ +25=@@VBOX_INSERT[${HOSTNAME_WITHOUT_DOMAIN_MAX_15}]ELEMENT@@ +26=@@VBOX_INSERT[${HOSTNAME_DOMAIN}]ELEMENT@@ +27=@@VBOX_INSERT[${PROXY}]ELEMENT@@ + +/* indicators */ +01=@@VBOX_INSERT[${IS_INSTALLING_ADDITIONS}]ELEMENT@@ +02=@@VBOX_INSERT[${IS_USER_LOGIN_ADMINISTRATOR}]ELEMENT@@ +03=@@VBOX_INSERT[${IS_INSTALLING_TEST_EXEC_SERVICE}]ELEMENT@@ +04=@@VBOX_INSERT[${HAS_POST_INSTALL_COMMAND}]ELEMENT@@ +05=@@VBOX_INSERT[${HAS_PRODUCT_KEY}]ELEMENT@@ +06=@@VBOX_INSERT[${IS_MINIMAL_INSTALLATION}]ELEMENT@@ +07=@@VBOX_INSERT[${IS_FIRMWARE_UEFI}]ELEMENT@@ +08=@@VBOX_INSERT[${IS_RTC_USING_UTC}]ELEMENT@@ +09=@@VBOX_INSERT[${HAS_PROXY}]ELEMENT@@ + + +/* + * Regular inserts escaped for use in double quoted attributes. + */ +/* variables */ +01=@@VBOX_INSERT_USER_LOGIN_ATTRIB_DQ@@ +02=@@VBOX_INSERT_USER_PASSWORD_ATTRIB_DQ@@ +03=@@VBOX_INSERT_ROOT_PASSWORD_ATTRIB_DQ@@ +04=@@VBOX_INSERT_USER_FULL_NAME_ATTRIB_DQ@@ +05=@@VBOX_INSERT_PRODUCT_KEY_ATTRIB_DQ@@ +06=@@VBOX_INSERT_POST_INSTALL_COMMAND_ATTRIB_DQ@@ +07=@@VBOX_INSERT_AUXILIARY_INSTALL_DIR_ATTRIB_DQ@@ +08=@@VBOX_INSERT_IMAGE_INDEX_ATTRIB_DQ@@ +09=@@VBOX_INSERT_OS_ARCH_ATTRIB_DQ@@ +10=@@VBOX_INSERT_OS_ARCH2_ATTRIB_DQ@@ +11=@@VBOX_INSERT_OS_ARCH3_ATTRIB_DQ@@ +12=@@VBOX_INSERT_OS_ARCH4_ATTRIB_DQ@@ +13=@@VBOX_INSERT_OS_ARCH6_ATTRIB_DQ@@ +14=@@VBOX_INSERT_GUEST_OS_VERSION_ATTRIB_DQ@@ +15=@@VBOX_INSERT_GUEST_OS_MAJOR_VERSION_ATTRIB_DQ@@ +16=@@VBOX_INSERT_TIME_ZONE_UX_ATTRIB_DQ@@ +17=@@VBOX_INSERT_TIME_ZONE_WIN_NAME_ATTRIB_DQ@@ +18=@@VBOX_INSERT_TIME_ZONE_WIN_INDEX_ATTRIB_DQ@@ +19=@@VBOX_INSERT_LOCALE_ATTRIB_DQ@@ +20=@@VBOX_INSERT_DASH_LOCALE_ATTRIB_DQ@@ +21=@@VBOX_INSERT_LANGUAGE_ATTRIB_DQ@@ +22=@@VBOX_INSERT_COUNTRY_ATTRIB_DQ@@ +23=@@VBOX_INSERT_HOSTNAME_FQDN_ATTRIB_DQ@@ +24=@@VBOX_INSERT_HOSTNAME_WITHOUT_DOMAIN_ATTRIB_DQ@@ +25=@@VBOX_INSERT_HOSTNAME_WITHOUT_DOMAIN_MAX_15_ATTRIB_DQ@@ +26=@@VBOX_INSERT_HOSTNAME_DOMAIN_ATTRIB_DQ@@ +27=@@VBOX_INSERT_PROXY_ATTRIB_DQ@@ + +/* indicators */ +01=@@VBOX_INSERT_IS_INSTALLING_ADDITIONS_ATTRIB_DQ@@ +02=@@VBOX_INSERT_IS_USER_LOGIN_ADMINISTRATOR_ATTRIB_DQ@@ +03=@@VBOX_INSERT_IS_INSTALLING_TEST_EXEC_SERVICE_ATTRIB_DQ@@ +04=@@VBOX_INSERT_HAS_POST_INSTALL_COMMAND_ATTRIB_DQ@@ +05=@@VBOX_INSERT_HAS_PRODUCT_KEY_ATTRIB_DQ@@ +06=@@VBOX_INSERT_IS_MINIMAL_INSTALLATION_ATTRIB_DQ@@ +07=@@VBOX_INSERT_IS_FIRMWARE_UEFI_ATTRIB_DQ@@ +08=@@VBOX_INSERT_IS_RTC_USING_UTC_ATTRIB_DQ@@ +09=@@VBOX_INSERT_HAS_PROXY_ATTRIB_DQ@@ + + +/* + * Expression inserts escaped for use in double quoted attributes. + */ +/* variables */ +01=@@VBOX_INSERT[${USER_LOGIN}]ATTRIB_DQ@@ +02=@@VBOX_INSERT[${USER_PASSWORD}]ATTRIB_DQ@@ +03=@@VBOX_INSERT[${ROOT_PASSWORD}]ATTRIB_DQ@@ +04=@@VBOX_INSERT[${USER_FULL_NAME}]ATTRIB_DQ@@ +05=@@VBOX_INSERT[${PRODUCT_KEY}]ATTRIB_DQ@@ +06=@@VBOX_INSERT[${POST_INSTALL_COMMAND}]ATTRIB_DQ@@ +07=@@VBOX_INSERT[${AUXILIARY_INSTALL_DIR}]ATTRIB_DQ@@ +08=@@VBOX_INSERT[${IMAGE_INDEX}]ATTRIB_DQ@@ +09=@@VBOX_INSERT[${OS_ARCH}]ATTRIB_DQ@@ +10=@@VBOX_INSERT[${OS_ARCH2}]ATTRIB_DQ@@ +11=@@VBOX_INSERT[${OS_ARCH3}]ATTRIB_DQ@@ +12=@@VBOX_INSERT[${OS_ARCH4}]ATTRIB_DQ@@ +13=@@VBOX_INSERT[${OS_ARCH6}]ATTRIB_DQ@@ +14=@@VBOX_INSERT[${GUEST_OS_VERSION}]ATTRIB_DQ@@ +15=@@VBOX_INSERT[${GUEST_OS_MAJOR_VERSION}]ATTRIB_DQ@@ +16=@@VBOX_INSERT[${TIME_ZONE_UX}]ATTRIB_DQ@@ +17=@@VBOX_INSERT[${TIME_ZONE_WIN_NAME}]ATTRIB_DQ@@ +18=@@VBOX_INSERT[${TIME_ZONE_WIN_INDEX}]ATTRIB_DQ@@ +19=@@VBOX_INSERT[${LOCALE}]ATTRIB_DQ@@ +20=@@VBOX_INSERT[${DASH_LOCALE}]ATTRIB_DQ@@ +21=@@VBOX_INSERT[${LANGUAGE}]ATTRIB_DQ@@ +22=@@VBOX_INSERT[${COUNTRY}]ATTRIB_DQ@@ +23=@@VBOX_INSERT[${HOSTNAME_FQDN}]ATTRIB_DQ@@ +24=@@VBOX_INSERT[${HOSTNAME_WITHOUT_DOMAIN}]ATTRIB_DQ@@ +25=@@VBOX_INSERT[${HOSTNAME_WITHOUT_DOMAIN_MAX_15}]ATTRIB_DQ@@ +26=@@VBOX_INSERT[${HOSTNAME_DOMAIN}]ATTRIB_DQ@@ +27=@@VBOX_INSERT[${PROXY}]ATTRIB_DQ@@ + +/* indicators */ +01=@@VBOX_INSERT[${IS_INSTALLING_ADDITIONS}]ATTRIB_DQ@@ +02=@@VBOX_INSERT[${IS_USER_LOGIN_ADMINISTRATOR}]ATTRIB_DQ@@ +03=@@VBOX_INSERT[${IS_INSTALLING_TEST_EXEC_SERVICE}]ATTRIB_DQ@@ +04=@@VBOX_INSERT[${HAS_POST_INSTALL_COMMAND}]ATTRIB_DQ@@ +05=@@VBOX_INSERT[${HAS_PRODUCT_KEY}]ATTRIB_DQ@@ +06=@@VBOX_INSERT[${IS_MINIMAL_INSTALLATION}]ATTRIB_DQ@@ +07=@@VBOX_INSERT[${IS_FIRMWARE_UEFI}]ATTRIB_DQ@@ +08=@@VBOX_INSERT[${IS_RTC_USING_UTC}]ATTRIB_DQ@@ +09=@@VBOX_INSERT[${HAS_PROXY}]ATTRIB_DQ@@ + + +/* + * Some typical expression conditions. + */ +01: @@VBOX_COND[${GUEST_OS_VERSION} vge 1.2.3]@@ GUEST_OS_VERSION >= 1.2.3@@VBOX_COND_ELSE@@ failed@@VBOX_COND_END@@ +02: @@VBOX_COND[${GUEST_OS_VERSION} vle 3.4.2]@@ GUEST_OS_VERSION <= 3.4.2@@VBOX_COND_ELSE@@ failed@@VBOX_COND_END@@ diff --git a/src/VBox/Main/testcase/tstUnattendedScript.cpp b/src/VBox/Main/testcase/tstUnattendedScript.cpp new file mode 100644 index 00000000..09d3f37a --- /dev/null +++ b/src/VBox/Main/testcase/tstUnattendedScript.cpp @@ -0,0 +1,731 @@ +/* $Id: tstUnattendedScript.cpp $ */ +/** @file + * tstUnattendedScript - testcases for UnattendedScript. + */ + +/* + * Copyright (C) 2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "UnattendedScript.h" + +#include <VBox/com/VirtualBox.h> +#include <VBox/com/errorprint.h> + +#include <iprt/file.h> +#include <iprt/path.h> +#include <iprt/test.h> +#include <iprt/stream.h> + +#include "VirtualBoxBase.h" +#include "UnattendedImpl.h" +#include "UnattendedScript.h" +#include "VirtualBoxImpl.h" +#include "MachineImpl.h" + +using namespace std; + + +/********************************************************************************************************************************* +* Unattended Stub Implementation * +*********************************************************************************************************************************/ +Unattended::Unattended() + : mhThreadReconfigureVM(NIL_RTNATIVETHREAD), mfRtcUseUtc(false), mfGuestOs64Bit(false) + , mpInstaller(NULL), mpTimeZoneInfo(NULL), mfIsDefaultAuxiliaryBasePath(true), mfDoneDetectIsoOS(false) +{ + mStrUser = "vboxuser"; + mStrPassword = "changeme"; + mStrFullUserName = "VBox & VBox;"; + mStrProductKey = "911"; + mStrIsoPath = "/iso/path/file.iso"; + mStrAdditionsIsoPath = "/iso/path/addition.iso"; + mfInstallGuestAdditions = true; + mfInstallTestExecService = true; + mStrValidationKitIsoPath = "/iso/path/valkit.iso"; + mStrTimeZone = "cet"; + mpTimeZoneInfo = NULL; + mStrLocale = "dk_DK"; + mStrLanguage = "dk"; + mStrCountry = "DK"; + //mPackageSelectionAdjustments = "minimal"; + mStrHostname = "my-extra-long-name.hostname.com"; + mStrAuxiliaryBasePath = "/aux/path/pfx-"; + mfIsDefaultAuxiliaryBasePath = false; + midxImage = 42; + mStrScriptTemplatePath = "/path/to/script-template.file"; + mStrPostInstallScriptTemplatePath = "/path/to/post-install-template.file"; + mStrPostInstallCommand = "/bin/post-install-command arg1 arg2 --amp=& --lt=< --gt=> --dq-word=\"word\" --sq-word='word'"; + mStrExtraInstallKernelParameters = "extra=kernel parameters quiet amp=& lt=< gt=>"; + mStrProxy = "http://proxy.intranet.com:443"; + + mfDoneDetectIsoOS = true; + mStrDetectedOSTypeId = "MyOSTypeId"; + mStrDetectedOSVersion = "3.4.2"; + mStrDetectedOSFlavor = "server"; + //mDetectedOSLanguages = "en_UK" + mStrDetectedOSHints = "nudge nudge wink wink"; +} + +Unattended::~Unattended() +{ +} + +HRESULT Unattended::FinalConstruct() +{ + return BaseFinalConstruct(); +} + +void Unattended::FinalRelease() +{ + uninit(); + BaseFinalRelease(); +} + +void Unattended::uninit() +{ +} + +HRESULT Unattended::initUnattended(VirtualBox *aParent) +{ + unconst(mParent) = aParent; + return S_OK; +} + +HRESULT Unattended::detectIsoOS() +{ + return E_NOTIMPL; +} + + +HRESULT Unattended::prepare() +{ + return E_NOTIMPL; +} + +HRESULT Unattended::constructMedia() +{ + return E_NOTIMPL; +} + +HRESULT Unattended::reconfigureVM() +{ + return E_NOTIMPL; +} + +HRESULT Unattended::done() +{ + return E_NOTIMPL; +} + +HRESULT Unattended::getIsoPath(com::Utf8Str &isoPath) +{ + RT_NOREF(isoPath); + return E_NOTIMPL; +} + +HRESULT Unattended::setIsoPath(const com::Utf8Str &isoPath) +{ + RT_NOREF(isoPath); + return E_NOTIMPL; +} + +HRESULT Unattended::getUser(com::Utf8Str &user) +{ + RT_NOREF(user); + return E_NOTIMPL; +} + + +HRESULT Unattended::setUser(const com::Utf8Str &user) +{ + RT_NOREF(user); + return E_NOTIMPL; +} + +HRESULT Unattended::getPassword(com::Utf8Str &password) +{ + RT_NOREF(password); + return E_NOTIMPL; +} + +HRESULT Unattended::setPassword(const com::Utf8Str &password) +{ + RT_NOREF(password); + return E_NOTIMPL; +} + +HRESULT Unattended::getFullUserName(com::Utf8Str &fullUserName) +{ + RT_NOREF(fullUserName); + return E_NOTIMPL; +} + +HRESULT Unattended::setFullUserName(const com::Utf8Str &fullUserName) +{ + RT_NOREF(fullUserName); + return E_NOTIMPL; +} + +HRESULT Unattended::getProductKey(com::Utf8Str &productKey) +{ + RT_NOREF(productKey); + return E_NOTIMPL; +} + +HRESULT Unattended::setProductKey(const com::Utf8Str &productKey) +{ + RT_NOREF(productKey); + return E_NOTIMPL; +} + +HRESULT Unattended::getAdditionsIsoPath(com::Utf8Str &additionsIsoPath) +{ + RT_NOREF(additionsIsoPath); + return E_NOTIMPL; +} + +HRESULT Unattended::setAdditionsIsoPath(const com::Utf8Str &additionsIsoPath) +{ + RT_NOREF(additionsIsoPath); + return E_NOTIMPL; +} + +HRESULT Unattended::getInstallGuestAdditions(BOOL *installGuestAdditions) +{ + RT_NOREF(installGuestAdditions); + return E_NOTIMPL; +} + +HRESULT Unattended::setInstallGuestAdditions(BOOL installGuestAdditions) +{ + RT_NOREF(installGuestAdditions); + return E_NOTIMPL; +} + +HRESULT Unattended::getValidationKitIsoPath(com::Utf8Str &aValidationKitIsoPath) +{ + RT_NOREF(aValidationKitIsoPath); + return E_NOTIMPL; +} + +HRESULT Unattended::setValidationKitIsoPath(const com::Utf8Str &aValidationKitIsoPath) +{ + RT_NOREF(aValidationKitIsoPath); + return E_NOTIMPL; +} + +HRESULT Unattended::getInstallTestExecService(BOOL *aInstallTestExecService) +{ + RT_NOREF(aInstallTestExecService); + return E_NOTIMPL; +} + +HRESULT Unattended::setInstallTestExecService(BOOL aInstallTestExecService) +{ + RT_NOREF(aInstallTestExecService); + return E_NOTIMPL; +} + +HRESULT Unattended::getTimeZone(com::Utf8Str &aTimeZone) +{ + RT_NOREF(aTimeZone); + return E_NOTIMPL; +} + +HRESULT Unattended::setTimeZone(const com::Utf8Str &aTimezone) +{ + RT_NOREF(aTimezone); + return E_NOTIMPL; +} + +HRESULT Unattended::getLocale(com::Utf8Str &aLocale) +{ + RT_NOREF(aLocale); + return E_NOTIMPL; +} + +HRESULT Unattended::setLocale(const com::Utf8Str &aLocale) +{ + RT_NOREF(aLocale); + return E_NOTIMPL; +} + +HRESULT Unattended::getLanguage(com::Utf8Str &aLanguage) +{ + RT_NOREF(aLanguage); + return E_NOTIMPL; +} + +HRESULT Unattended::setLanguage(const com::Utf8Str &aLanguage) +{ + RT_NOREF(aLanguage); + return E_NOTIMPL; +} + +HRESULT Unattended::getCountry(com::Utf8Str &aCountry) +{ + RT_NOREF(aCountry); + return E_NOTIMPL; +} + +HRESULT Unattended::setCountry(const com::Utf8Str &aCountry) +{ + RT_NOREF(aCountry); + return E_NOTIMPL; +} + +HRESULT Unattended::getProxy(com::Utf8Str &aProxy) +{ + RT_NOREF(aProxy); + return E_NOTIMPL; +} + +HRESULT Unattended::setProxy(const com::Utf8Str &aProxy) +{ + RT_NOREF(aProxy); + return E_NOTIMPL; +} + +HRESULT Unattended::getPackageSelectionAdjustments(com::Utf8Str &aPackageSelectionAdjustments) +{ + RT_NOREF(aPackageSelectionAdjustments); + return E_NOTIMPL; +} + +HRESULT Unattended::setPackageSelectionAdjustments(const com::Utf8Str &aPackageSelectionAdjustments) +{ + RT_NOREF(aPackageSelectionAdjustments); + return E_NOTIMPL; +} + +HRESULT Unattended::getHostname(com::Utf8Str &aHostname) +{ + RT_NOREF(aHostname); + return E_NOTIMPL; +} + +HRESULT Unattended::setHostname(const com::Utf8Str &aHostname) +{ + RT_NOREF(aHostname); + return E_NOTIMPL; +} + +HRESULT Unattended::getAuxiliaryBasePath(com::Utf8Str &aAuxiliaryBasePath) +{ + RT_NOREF(aAuxiliaryBasePath); + return E_NOTIMPL; +} + +HRESULT Unattended::setAuxiliaryBasePath(const com::Utf8Str &aAuxiliaryBasePath) +{ + RT_NOREF(aAuxiliaryBasePath); + return E_NOTIMPL; +} + +HRESULT Unattended::getImageIndex(ULONG *index) +{ + AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); + *index = midxImage; + return S_OK; +} + +HRESULT Unattended::setImageIndex(ULONG index) +{ + RT_NOREF(index); + return E_NOTIMPL; +} + +HRESULT Unattended::getMachine(ComPtr<IMachine> &aMachine) +{ + RT_NOREF(aMachine); + return E_NOTIMPL; +} + +HRESULT Unattended::setMachine(const ComPtr<IMachine> &aMachine) +{ + RT_NOREF(aMachine); + return E_NOTIMPL; +} + +HRESULT Unattended::getScriptTemplatePath(com::Utf8Str &aScriptTemplatePath) +{ + RT_NOREF(aScriptTemplatePath); + return E_NOTIMPL; +} + +HRESULT Unattended::setScriptTemplatePath(const com::Utf8Str &aScriptTemplatePath) +{ + RT_NOREF(aScriptTemplatePath); + return E_NOTIMPL; + +} + +HRESULT Unattended::getPostInstallScriptTemplatePath(com::Utf8Str &aPostInstallScriptTemplatePath) +{ + RT_NOREF(aPostInstallScriptTemplatePath); + return E_NOTIMPL; +} + +HRESULT Unattended::setPostInstallScriptTemplatePath(const com::Utf8Str &aPostInstallScriptTemplatePath) +{ + RT_NOREF(aPostInstallScriptTemplatePath); + return E_NOTIMPL; +} + +HRESULT Unattended::getPostInstallCommand(com::Utf8Str &aPostInstallCommand) +{ + RT_NOREF(aPostInstallCommand); + return E_NOTIMPL; +} + +HRESULT Unattended::setPostInstallCommand(const com::Utf8Str &aPostInstallCommand) +{ + RT_NOREF(aPostInstallCommand); + return E_NOTIMPL; +} + +HRESULT Unattended::getExtraInstallKernelParameters(com::Utf8Str &aExtraInstallKernelParameters) +{ + RT_NOREF(aExtraInstallKernelParameters); + return E_NOTIMPL; +} + +HRESULT Unattended::setExtraInstallKernelParameters(const com::Utf8Str &aExtraInstallKernelParameters) +{ + RT_NOREF(aExtraInstallKernelParameters); + return E_NOTIMPL; +} + +HRESULT Unattended::getDetectedOSTypeId(com::Utf8Str &aDetectedOSTypeId) +{ + RT_NOREF(aDetectedOSTypeId); + return E_NOTIMPL; +} + +HRESULT Unattended::getDetectedOSVersion(com::Utf8Str &aDetectedOSVersion) +{ + RT_NOREF(aDetectedOSVersion); + return E_NOTIMPL; +} + +HRESULT Unattended::getDetectedOSFlavor(com::Utf8Str &aDetectedOSFlavor) +{ + RT_NOREF(aDetectedOSFlavor); + return E_NOTIMPL; +} + +HRESULT Unattended::getDetectedOSLanguages(com::Utf8Str &aDetectedOSLanguages) +{ + RT_NOREF(aDetectedOSLanguages); + return E_NOTIMPL; +} + +HRESULT Unattended::getDetectedOSHints(com::Utf8Str &aDetectedOSHints) +{ + RT_NOREF(aDetectedOSHints); + return E_NOTIMPL; +} + +HRESULT Unattended::getDetectedImageNames(std::vector<com::Utf8Str> &aDetectedImageNames) +{ + RT_NOREF(aDetectedImageNames); + return E_NOTIMPL; +} + +HRESULT Unattended::getDetectedImageIndices(std::vector<ULONG> &aDetectedImageIndices) +{ + RT_NOREF(aDetectedImageIndices); + return E_NOTIMPL; +} + +HRESULT Unattended::getIsUnattendedInstallSupported(BOOL *aIsUnattendedInstallSupported) +{ + RT_NOREF(aIsUnattendedInstallSupported); + return E_NOTIMPL; +} + +HRESULT Unattended::getAvoidUpdatesOverNetwork(BOOL *aAvoidUpdatesOverNetwork) +{ + RT_NOREF(aAvoidUpdatesOverNetwork); + return E_NOTIMPL; +} + +HRESULT Unattended::setAvoidUpdatesOverNetwork(BOOL aAvoidUpdatesOverNetwork) +{ + RT_NOREF(aAvoidUpdatesOverNetwork); + return E_NOTIMPL; +} + + +/* + * Getters that the installer and script classes can use. + */ +Utf8Str const &Unattended::i_getIsoPath() const +{ + return mStrIsoPath; +} + +Utf8Str const &Unattended::i_getUser() const +{ + return mStrUser; +} + +Utf8Str const &Unattended::i_getPassword() const +{ + return mStrPassword; +} + +Utf8Str const &Unattended::i_getFullUserName() const +{ + return mStrFullUserName.isNotEmpty() ? mStrFullUserName : mStrUser; +} + +Utf8Str const &Unattended::i_getProductKey() const +{ + return mStrProductKey; +} + +Utf8Str const &Unattended::i_getProxy() const +{ + return mStrProxy; +} + +Utf8Str const &Unattended::i_getAdditionsIsoPath() const +{ + return mStrAdditionsIsoPath; +} + +bool Unattended::i_getInstallGuestAdditions() const +{ + return mfInstallGuestAdditions; +} + +Utf8Str const &Unattended::i_getValidationKitIsoPath() const +{ + return mStrValidationKitIsoPath; +} + +bool Unattended::i_getInstallTestExecService() const +{ + return mfInstallTestExecService; +} + +Utf8Str const &Unattended::i_getTimeZone() const +{ + return mStrTimeZone; +} + +PCRTTIMEZONEINFO Unattended::i_getTimeZoneInfo() const +{ + return mpTimeZoneInfo; +} + +Utf8Str const &Unattended::i_getLocale() const +{ + return mStrLocale; +} + +Utf8Str const &Unattended::i_getLanguage() const +{ + return mStrLanguage; +} + +Utf8Str const &Unattended::i_getCountry() const +{ + return mStrCountry; +} + +bool Unattended::i_isMinimalInstallation() const +{ + size_t i = mPackageSelectionAdjustments.size(); + while (i-- > 0) + if (mPackageSelectionAdjustments[i].equals("minimal")) + return true; + return false; +} + +Utf8Str const &Unattended::i_getHostname() const +{ + return mStrHostname; +} + +Utf8Str const &Unattended::i_getAuxiliaryBasePath() const +{ + return mStrAuxiliaryBasePath; +} + +ULONG Unattended::i_getImageIndex() const +{ + return midxImage; +} + +Utf8Str const &Unattended::i_getScriptTemplatePath() const +{ + return mStrScriptTemplatePath; +} + +Utf8Str const &Unattended::i_getPostInstallScriptTemplatePath() const +{ + return mStrPostInstallScriptTemplatePath; +} + +Utf8Str const &Unattended::i_getPostInstallCommand() const +{ + return mStrPostInstallCommand; +} + +Utf8Str const &Unattended::i_getAuxiliaryInstallDir() const +{ + static Utf8Str s_strAuxInstallDir("/aux/install/dir"); + return s_strAuxInstallDir; +} + +Utf8Str const &Unattended::i_getExtraInstallKernelParameters() const +{ + return mStrExtraInstallKernelParameters; +} + +bool Unattended::i_isRtcUsingUtc() const +{ + return mfRtcUseUtc; +} + +bool Unattended::i_isGuestOs64Bit() const +{ + return mfGuestOs64Bit; +} + +bool Unattended::i_isFirmwareEFI() const +{ + return menmFirmwareType != FirmwareType_BIOS; +} + +Utf8Str const &Unattended::i_getDetectedOSVersion() +{ + return mStrDetectedOSVersion; +} + +bool Unattended::i_getAvoidUpdatesOverNetwork() const +{ + return mfAvoidUpdatesOverNetwork; +} + + +/********************************************************************************************************************************* +* The Testcase * +*********************************************************************************************************************************/ + +static bool loadFileAsString(const char *pszFilename, Utf8Str &rstrContent) +{ + rstrContent.setNull(); + + char szPath[RTPATH_MAX]; + RTTESTI_CHECK_RC_RET(RTPathExecDir(szPath, sizeof(szPath)), VINF_SUCCESS, false); + RTTESTI_CHECK_RC_RET(RTPathAppend(szPath, sizeof(szPath), pszFilename), VINF_SUCCESS, false); + + RTFILE hFile; + RTTESTI_CHECK_RC_RET(RTFileOpen(&hFile, szPath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE), VINF_SUCCESS, false); + + uint64_t cbFile = 0; + RTTESTI_CHECK_RC_RET(RTFileQuerySize(hFile, &cbFile), VINF_SUCCESS, false); + + rstrContent.reserve((size_t)cbFile + 1); + RTTESTI_CHECK_RC_RET(RTFileRead(hFile, rstrContent.mutableRaw(), (size_t)cbFile, NULL), VINF_SUCCESS, false); + rstrContent.mutableRaw()[cbFile] = '\0'; + rstrContent.jolt(); + + RTTESTI_CHECK_RC_RET(RTFileClose(hFile), VINF_SUCCESS, false); + + return true; +} + +static void doTest1() +{ + RTTestISub("tstUnattendedScript-1.template"); + + /* Create the parent class instance: */ + ComObjPtr<Unattended> ptrParent; + HRESULT hrc = ptrParent.createObject(); + RTTESTI_CHECK_MSG_RETV(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc)); + + /* Instantiate the script editor. */ + UnattendedScriptTemplate Tmpl(ptrParent, "template.ext", "file.ext"); +#define CHECK_HRESULT(a_Expr) do { \ + HRESULT hrcThis = a_Expr; \ + if (SUCCEEDED(hrcThis)) break; \ + RTTestIFailed("line %d: %s -> %Rhrc", __LINE__, #a_Expr, hrcThis); \ + GlueHandleComError(ptrParent, NULL, hrcThis, NULL, __LINE__); \ + } while (0) + + /* Load the exercise script. */ + char szPath[RTPATH_MAX]; + RTTESTI_CHECK_RC_RETV(RTPathExecDir(szPath, sizeof(szPath)), VINF_SUCCESS); + RTTESTI_CHECK_RC_RETV(RTPathAppend(szPath, sizeof(szPath), "tstUnattendedScript-1.template"), VINF_SUCCESS); + CHECK_HRESULT(Tmpl.read(szPath)); + + /* Save the template to string. */ + Utf8Str strActual; + CHECK_HRESULT(Tmpl.saveToString(strActual)); + + /* Load the expected result. */ + Utf8Str strExpected; + RTTESTI_CHECK_RETV(loadFileAsString("tstUnattendedScript-1.expected", strExpected)); + + /* Compare the two. */ + if (strExpected != strActual) + { + RTTestIFailed("Output does not match tstUnattendedScript-1.expect!"); + RTTestIFailureDetails("------ BEGIN OUTPUT ------\n"); + RTStrmWrite(g_pStdErr, strActual.c_str(), strActual.length()); + RTTestIFailureDetails("------- END OUTPUT -------\n"); + + RTCList<RTCString, RTCString *> const lstActual = strActual.split("\n"); + RTCList<RTCString, RTCString *> const lstExpected = strExpected.split("\n"); + size_t const cLines = RT_MIN(lstActual.size(), lstExpected.size()); + for (size_t i = 0; i < cLines; i++) + if (lstActual[i] != lstExpected[i]) + { + RTTestIFailureDetails("First difference on line %u:\n%s\nexpected:\n%s\n", + i + 1, lstActual[i].c_str(), lstExpected[i].c_str()); + break; + } + } +} + +int main() +{ + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstUnattendedScript", &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + +#ifdef RT_OS_WINDOWS + /*ATL::CComModule *g_pAtlComModule = */ new(ATL::CComModule); +#endif + + doTest1(); + + return RTTestSummaryAndDestroy(hTest); +} diff --git a/src/VBox/Main/testcase/tstVBoxAPI.cpp b/src/VBox/Main/testcase/tstVBoxAPI.cpp new file mode 100644 index 00000000..c94b9eb3 --- /dev/null +++ b/src/VBox/Main/testcase/tstVBoxAPI.cpp @@ -0,0 +1,417 @@ +/* $Id: tstVBoxAPI.cpp $ */ +/** @file + * tstVBoxAPI - Checks VirtualBox API. + */ + +/* + * Copyright (C) 2006-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/com/com.h> +#include <VBox/com/string.h> +#include <VBox/com/array.h> +#include <VBox/com/Guid.h> +#include <VBox/com/ErrorInfo.h> +#include <VBox/com/errorprint.h> +#include <VBox/com/VirtualBox.h> +#include <VBox/sup.h> + +#include <iprt/test.h> +#include <iprt/time.h> + +using namespace com; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static RTTEST g_hTest; +static Bstr tstMachineName = "tstVBoxAPI test VM"; + + +/** Worker for TST_COM_EXPR(). */ +static HRESULT tstComExpr(HRESULT hrc, const char *pszOperation, int iLine) +{ + if (FAILED(hrc)) + RTTestFailed(g_hTest, "%s failed on line %u with hrc=%Rhrc", pszOperation, iLine, hrc); + return hrc; +} + +/** Macro that executes the given expression and report any failure. + * The expression must return a HRESULT. */ +#define TST_COM_EXPR(expr) tstComExpr(expr, #expr, __LINE__) + + +static BOOL tstApiIVirtualBox(IVirtualBox *pVBox) +{ + HRESULT hrc; + Bstr bstrTmp; + ULONG ulTmp; + + RTTestSub(g_hTest, "IVirtualBox::version"); + CHECK_ERROR(pVBox, COMGETTER(Version)(bstrTmp.asOutParam())); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::version"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::version failed", __LINE__); + + RTTestSub(g_hTest, "IVirtualBox::versionNormalized"); + CHECK_ERROR(pVBox, COMGETTER(VersionNormalized)(bstrTmp.asOutParam())); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::versionNormalized"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::versionNormalized failed", __LINE__); + + RTTestSub(g_hTest, "IVirtualBox::revision"); + CHECK_ERROR(pVBox, COMGETTER(Revision)(&ulTmp)); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::revision"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::revision failed", __LINE__); + + RTTestSub(g_hTest, "IVirtualBox::packageType"); + CHECK_ERROR(pVBox, COMGETTER(PackageType)(bstrTmp.asOutParam())); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::packageType"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::packageType failed", __LINE__); + + RTTestSub(g_hTest, "IVirtualBox::APIVersion"); + CHECK_ERROR(pVBox, COMGETTER(APIVersion)(bstrTmp.asOutParam())); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::APIVersion"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::APIVersion failed", __LINE__); + + RTTestSub(g_hTest, "IVirtualBox::homeFolder"); + CHECK_ERROR(pVBox, COMGETTER(HomeFolder)(bstrTmp.asOutParam())); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::homeFolder"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::homeFolder failed", __LINE__); + + RTTestSub(g_hTest, "IVirtualBox::settingsFilePath"); + CHECK_ERROR(pVBox, COMGETTER(SettingsFilePath)(bstrTmp.asOutParam())); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::settingsFilePath"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::settingsFilePath failed", __LINE__); + + com::SafeIfaceArray<IGuestOSType> guestOSTypes; + RTTestSub(g_hTest, "IVirtualBox::guestOSTypes"); + CHECK_ERROR(pVBox, COMGETTER(GuestOSTypes)(ComSafeArrayAsOutParam(guestOSTypes))); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::guestOSTypes"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::guestOSTypes failed", __LINE__); + + /** Create VM */ + RTTestSub(g_hTest, "IVirtualBox::CreateMachine"); + ComPtr<IMachine> ptrMachine; + com::SafeArray<BSTR> groups; + /** Default VM settings */ + CHECK_ERROR(pVBox, CreateMachine(NULL, /** Settings */ + tstMachineName.raw(), /** Name */ + ComSafeArrayAsInParam(groups), /** Groups */ + NULL, /** OS Type */ + NULL, /** Create flags */ + NULL, /** Cipher */ + NULL, /** Password id */ + NULL, /** Password */ + ptrMachine.asOutParam())); /** Machine */ + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::CreateMachine"); + else + { + RTTestFailed(g_hTest, "%d: IVirtualBox::CreateMachine failed", __LINE__); + return FALSE; + } + + RTTestSub(g_hTest, "IVirtualBox::RegisterMachine"); + CHECK_ERROR(pVBox, RegisterMachine(ptrMachine)); + if (SUCCEEDED(hrc)) + RTTestPassed(g_hTest, "IVirtualBox::RegisterMachine"); + else + { + RTTestFailed(g_hTest, "%d: IVirtualBox::RegisterMachine failed", __LINE__); + return FALSE; + } + + ComPtr<IHost> host; + RTTestSub(g_hTest, "IVirtualBox::host"); + CHECK_ERROR(pVBox, COMGETTER(Host)(host.asOutParam())); + if (SUCCEEDED(hrc)) + { + /** @todo Add IHost testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::host"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::host failed", __LINE__); + + ComPtr<ISystemProperties> sysprop; + RTTestSub(g_hTest, "IVirtualBox::systemProperties"); + CHECK_ERROR(pVBox, COMGETTER(SystemProperties)(sysprop.asOutParam())); + if (SUCCEEDED(hrc)) + { + /** @todo Add ISystemProperties testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::systemProperties"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::systemProperties failed", __LINE__); + + com::SafeIfaceArray<IMachine> machines; + RTTestSub(g_hTest, "IVirtualBox::machines"); + CHECK_ERROR(pVBox, COMGETTER(Machines)(ComSafeArrayAsOutParam(machines))); + if (SUCCEEDED(hrc)) + { + bool bFound = FALSE; + for (size_t i = 0; i < machines.size(); ++i) + { + if (machines[i]) + { + Bstr tmpName; + hrc = machines[i]->COMGETTER(Name)(tmpName.asOutParam()); + if (SUCCEEDED(hrc)) + { + if (tmpName == tstMachineName) + { + bFound = TRUE; + break; + } + } + } + } + + if (bFound) + RTTestPassed(g_hTest, "IVirtualBox::machines"); + else + RTTestFailed(g_hTest, "%d: IVirtualBox::machines failed. No created machine found", __LINE__); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::machines failed", __LINE__); + +#if 0 /** Not yet implemented */ + com::SafeIfaceArray<ISharedFolder> sharedFolders; + RTTestSub(g_hTest, "IVirtualBox::sharedFolders"); + CHECK_ERROR(pVBox, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(sharedFolders))); + if (SUCCEEDED(rc)) + { + /** @todo Add ISharedFolders testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::sharedFolders"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::sharedFolders failed", __LINE__); +#endif + + com::SafeIfaceArray<IMedium> hardDisks; + RTTestSub(g_hTest, "IVirtualBox::hardDisks"); + CHECK_ERROR(pVBox, COMGETTER(HardDisks)(ComSafeArrayAsOutParam(hardDisks))); + if (SUCCEEDED(hrc)) + { + /** @todo Add hardDisks testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::hardDisks"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::hardDisks failed", __LINE__); + + com::SafeIfaceArray<IMedium> DVDImages; + RTTestSub(g_hTest, "IVirtualBox::DVDImages"); + CHECK_ERROR(pVBox, COMGETTER(DVDImages)(ComSafeArrayAsOutParam(DVDImages))); + if (SUCCEEDED(hrc)) + { + /** @todo Add DVDImages testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::DVDImages"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::DVDImages failed", __LINE__); + + com::SafeIfaceArray<IMedium> floppyImages; + RTTestSub(g_hTest, "IVirtualBox::floppyImages"); + CHECK_ERROR(pVBox, COMGETTER(FloppyImages)(ComSafeArrayAsOutParam(floppyImages))); + if (SUCCEEDED(hrc)) + { + /** @todo Add floppyImages testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::floppyImages"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::floppyImages failed", __LINE__); + + com::SafeIfaceArray<IProgress> progressOperations; + RTTestSub(g_hTest, "IVirtualBox::progressOperations"); + CHECK_ERROR(pVBox, COMGETTER(ProgressOperations)(ComSafeArrayAsOutParam(progressOperations))); + if (SUCCEEDED(hrc)) + { + /** @todo Add IProgress testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::progressOperations"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::progressOperations failed", __LINE__); + + ComPtr<IPerformanceCollector> performanceCollector; + RTTestSub(g_hTest, "IVirtualBox::performanceCollector"); + CHECK_ERROR(pVBox, COMGETTER(PerformanceCollector)(performanceCollector.asOutParam())); + if (SUCCEEDED(hrc)) + { + /** @todo Add IPerformanceCollector testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::performanceCollector"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::performanceCollector failed", __LINE__); + + com::SafeIfaceArray<IDHCPServer> DHCPServers; + RTTestSub(g_hTest, "IVirtualBox::DHCPServers"); + CHECK_ERROR(pVBox, COMGETTER(DHCPServers)(ComSafeArrayAsOutParam(DHCPServers))); + if (SUCCEEDED(hrc)) + { + /** @todo Add IDHCPServers testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::DHCPServers"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::DHCPServers failed", __LINE__); + + com::SafeIfaceArray<INATNetwork> NATNetworks; + RTTestSub(g_hTest, "IVirtualBox::NATNetworks"); + CHECK_ERROR(pVBox, COMGETTER(NATNetworks)(ComSafeArrayAsOutParam(NATNetworks))); + if (SUCCEEDED(hrc)) + { + /** @todo Add INATNetworks testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::NATNetworks"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::NATNetworks failed", __LINE__); + + ComPtr<IEventSource> eventSource; + RTTestSub(g_hTest, "IVirtualBox::eventSource"); + CHECK_ERROR(pVBox, COMGETTER(EventSource)(eventSource.asOutParam())); + if (SUCCEEDED(hrc)) + { + /** @todo Add IEventSource testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::eventSource"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::eventSource failed", __LINE__); + + ComPtr<IExtPackManager> extensionPackManager; + RTTestSub(g_hTest, "IVirtualBox::extensionPackManager"); + CHECK_ERROR(pVBox, COMGETTER(ExtensionPackManager)(extensionPackManager.asOutParam())); + if (SUCCEEDED(hrc)) + { + /** @todo Add IExtPackManager testing here. */ + RTTestPassed(g_hTest, "IVirtualBox::extensionPackManager"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::extensionPackManager failed", __LINE__); + + com::SafeArray<BSTR> internalNetworks; + RTTestSub(g_hTest, "IVirtualBox::internalNetworks"); + CHECK_ERROR(pVBox, COMGETTER(InternalNetworks)(ComSafeArrayAsOutParam(internalNetworks))); + if (SUCCEEDED(hrc)) + { + RTTestPassed(g_hTest, "IVirtualBox::internalNetworks"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::internalNetworks failed", __LINE__); + + com::SafeArray<BSTR> genericNetworkDrivers; + RTTestSub(g_hTest, "IVirtualBox::genericNetworkDrivers"); + CHECK_ERROR(pVBox, COMGETTER(GenericNetworkDrivers)(ComSafeArrayAsOutParam(genericNetworkDrivers))); + if (SUCCEEDED(hrc)) + { + RTTestPassed(g_hTest, "IVirtualBox::genericNetworkDrivers"); + } + else + RTTestFailed(g_hTest, "%d: IVirtualBox::genericNetworkDrivers failed", __LINE__); + + return TRUE; +} + + +static BOOL tstApiClean(IVirtualBox *pVBox) +{ + HRESULT hrc; + + /** Delete created VM and its files */ + ComPtr<IMachine> machine; + CHECK_ERROR_RET(pVBox, FindMachine(Bstr(tstMachineName).raw(), machine.asOutParam()), FALSE); + SafeIfaceArray<IMedium> media; + CHECK_ERROR_RET(machine, Unregister(CleanupMode_DetachAllReturnHardDisksOnly, + ComSafeArrayAsOutParam(media)), FALSE); + ComPtr<IProgress> progress; + CHECK_ERROR_RET(machine, DeleteConfig(ComSafeArrayAsInParam(media), progress.asOutParam()), FALSE); + CHECK_ERROR_RET(progress, WaitForCompletion(-1), FALSE); + + return TRUE; +} + + +int main() +{ + /* + * Initialization. + */ + RTEXITCODE rcExit = RTTestInitAndCreate("tstVBoxAPI", &g_hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + SUPR3Init(NULL); /* Better time support. */ + RTTestBanner(g_hTest); + + RTTestSub(g_hTest, "Initializing COM and singletons"); + HRESULT hrc = com::Initialize(); + if (SUCCEEDED(hrc)) + { + ComPtr<IVirtualBoxClient> ptrVBoxClient; + ComPtr<IVirtualBox> ptrVBox; + hrc = TST_COM_EXPR(ptrVBoxClient.createInprocObject(CLSID_VirtualBoxClient)); + if (SUCCEEDED(hrc)) + hrc = TST_COM_EXPR(ptrVBoxClient->COMGETTER(VirtualBox)(ptrVBox.asOutParam())); + if (SUCCEEDED(hrc)) + { + ComPtr<ISession> ptrSession; + hrc = TST_COM_EXPR(ptrSession.createInprocObject(CLSID_Session)); + if (SUCCEEDED(hrc)) + { + RTTestSubDone(g_hTest); + + /* + * Call test functions. + */ + + /** Test IVirtualBox interface */ + tstApiIVirtualBox(ptrVBox); + + + /** Clean files/configs */ + tstApiClean(ptrVBox); + } + } + + ptrVBox.setNull(); + ptrVBoxClient.setNull(); + com::Shutdown(); + } + else + RTTestIFailed("com::Initialize failed with hrc=%Rhrc", hrc); + return RTTestSummaryAndDestroy(g_hTest); +} diff --git a/src/VBox/Main/testcase/tstVBoxAPIPerf.cpp b/src/VBox/Main/testcase/tstVBoxAPIPerf.cpp new file mode 100644 index 00000000..00c2a97c --- /dev/null +++ b/src/VBox/Main/testcase/tstVBoxAPIPerf.cpp @@ -0,0 +1,257 @@ +/* $Id: tstVBoxAPIPerf.cpp $ */ +/** @file + * tstVBoxAPIPerf - Checks the performance of the COM / XPOM API. + */ + +/* + * Copyright (C) 2006-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/com/com.h> +#include <VBox/com/string.h> +#include <VBox/com/array.h> +#include <VBox/com/Guid.h> +#include <VBox/com/ErrorInfo.h> +#include <VBox/com/VirtualBox.h> +#include <VBox/sup.h> + +#include <iprt/test.h> +#include <iprt/time.h> + + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static RTTEST g_hTest; + + +/** Worker fro TST_COM_EXPR(). */ +static HRESULT tstComExpr(HRESULT hrc, const char *pszOperation, int iLine) +{ + if (FAILED(hrc)) + RTTestFailed(g_hTest, "%s failed on line %u with hrc=%Rhrc", pszOperation, iLine, hrc); + return hrc; +} + +/** Macro that executes the given expression and report any failure. + * The expression must return a HRESULT. */ +#define TST_COM_EXPR(expr) tstComExpr(expr, #expr, __LINE__) + + + +static void tstApiPrf1(IVirtualBox *pVBox) +{ + RTTestSub(g_hTest, "IVirtualBox::Revision performance"); + + uint32_t const cCalls = 65536; + uint32_t cLeft = cCalls; + uint64_t uStartTS = RTTimeNanoTS(); + while (cLeft-- > 0) + { + ULONG uRev; + HRESULT hrc = pVBox->COMGETTER(Revision)(&uRev); + if (FAILED(hrc)) + { + tstComExpr(hrc, "IVirtualBox::Revision", __LINE__); + return; + } + } + uint64_t uElapsed = RTTimeNanoTS() - uStartTS; + RTTestValue(g_hTest, "IVirtualBox::Revision average", uElapsed / cCalls, RTTESTUNIT_NS_PER_CALL); + RTTestSubDone(g_hTest); +} + + +static void tstApiPrf2(IVirtualBox *pVBox) +{ + RTTestSub(g_hTest, "IVirtualBox::Version performance"); + + uint32_t const cCalls = 65536; + uint32_t cLeft = cCalls; + uint64_t uStartTS = RTTimeNanoTS(); + while (cLeft-- > 0) + { + com::Bstr bstrVersion; + HRESULT hrc = pVBox->COMGETTER(Version)(bstrVersion.asOutParam()); + if (FAILED(hrc)) + { + tstComExpr(hrc, "IVirtualBox::Version", __LINE__); + return; + } + } + uint64_t uElapsed = RTTimeNanoTS() - uStartTS; + RTTestValue(g_hTest, "IVirtualBox::Version average", uElapsed / cCalls, RTTESTUNIT_NS_PER_CALL); + RTTestSubDone(g_hTest); +} + + +static void tstApiPrf3(IVirtualBox *pVBox) +{ + RTTestSub(g_hTest, "IVirtualBox::Host performance"); + + /* The first call. */ + uint64_t uStartTS = RTTimeNanoTS(); + IHost *pHost = NULL; + HRESULT hrc = pVBox->COMGETTER(Host)(&pHost); + if (FAILED(hrc)) + { + tstComExpr(hrc, "IVirtualBox::Host", __LINE__); + return; + } + pHost->Release(); + uint64_t uElapsed = RTTimeNanoTS() - uStartTS; + RTTestValue(g_hTest, "IVirtualBox::Host first", uElapsed, RTTESTUNIT_NS); + + /* Subsequent calls. */ + uint32_t const cCalls1 = 4096; + uint32_t cLeft = cCalls1; + uStartTS = RTTimeNanoTS(); + while (cLeft-- > 0) + { + IHost *pHost2 = NULL; + hrc = pVBox->COMGETTER(Host)(&pHost2); + if (FAILED(hrc)) + { + tstComExpr(hrc, "IVirtualBox::Host", __LINE__); + return; + } + pHost2->Release(); + } + uElapsed = RTTimeNanoTS() - uStartTS; + RTTestValue(g_hTest, "IVirtualBox::Host average", uElapsed / cCalls1, RTTESTUNIT_NS_PER_CALL); + + /* Keep a reference around and see how that changes things. + Note! VBoxSVC is not creating and destroying Host(). */ + pHost = NULL; + hrc = pVBox->COMGETTER(Host)(&pHost); + + uint32_t const cCalls2 = 16384; + cLeft = cCalls2; + uStartTS = RTTimeNanoTS(); + while (cLeft-- > 0) + { + IHost *pHost2 = NULL; + hrc = pVBox->COMGETTER(Host)(&pHost2); + if (FAILED(hrc)) + { + tstComExpr(hrc, "IVirtualBox::Host", __LINE__); + pHost->Release(); + return; + } + pHost2->Release(); + } + uElapsed = RTTimeNanoTS() - uStartTS; + RTTestValue(g_hTest, "IVirtualBox::Host 2nd ref", uElapsed / cCalls2, RTTESTUNIT_NS_PER_CALL); + pHost->Release(); + + RTTestSubDone(g_hTest); +} + + +static void tstApiPrf4(IVirtualBox *pVBox) +{ + RTTestSub(g_hTest, "IHost::GetProcessorFeature performance"); + + IHost *pHost = NULL; + HRESULT hrc = pVBox->COMGETTER(Host)(&pHost); + if (FAILED(hrc)) + { + tstComExpr(hrc, "IVirtualBox::Host", __LINE__); + return; + } + + uint32_t const cCalls = 65536; + uint32_t cLeft = cCalls; + uint64_t uStartTS = RTTimeNanoTS(); + while (cLeft-- > 0) + { + BOOL fSupported; + hrc = pHost->GetProcessorFeature(ProcessorFeature_PAE, &fSupported); + if (FAILED(hrc)) + { + tstComExpr(hrc, "IHost::GetProcessorFeature", __LINE__); + pHost->Release(); + return; + } + } + uint64_t uElapsed = RTTimeNanoTS() - uStartTS; + RTTestValue(g_hTest, "IHost::GetProcessorFeature average", uElapsed / cCalls, RTTESTUNIT_NS_PER_CALL); + pHost->Release(); + RTTestSubDone(g_hTest); +} + + + +int main() +{ + /* + * Initialization. + */ + RTEXITCODE rcExit = RTTestInitAndCreate("tstVBoxAPIPerf", &g_hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + SUPR3Init(NULL); /* Better time support. */ + RTTestBanner(g_hTest); + + RTTestSub(g_hTest, "Initializing COM and singletons"); + HRESULT hrc = com::Initialize(); + if (SUCCEEDED(hrc)) + { + ComPtr<IVirtualBoxClient> ptrVBoxClient; + ComPtr<IVirtualBox> ptrVBox; + hrc = TST_COM_EXPR(ptrVBoxClient.createInprocObject(CLSID_VirtualBoxClient)); + if (SUCCEEDED(hrc)) + hrc = TST_COM_EXPR(ptrVBoxClient->COMGETTER(VirtualBox)(ptrVBox.asOutParam())); + if (SUCCEEDED(hrc)) + { + ComPtr<ISession> ptrSession; + hrc = TST_COM_EXPR(ptrSession.createInprocObject(CLSID_Session)); + if (SUCCEEDED(hrc)) + { + RTTestSubDone(g_hTest); + + /* + * Call test functions. + */ + tstApiPrf1(ptrVBox); + tstApiPrf2(ptrVBox); + tstApiPrf3(ptrVBox); + + /** @todo Find something that returns a 2nd instance of an interface and see + * how if wrapper stuff is reused in any way. */ + tstApiPrf4(ptrVBox); + } + } + + ptrVBox.setNull(); + ptrVBoxClient.setNull(); + com::Shutdown(); + } + else + RTTestIFailed("com::Initialize failed with hrc=%Rhrc", hrc); + return RTTestSummaryAndDestroy(g_hTest); +} + diff --git a/src/VBox/Main/testcase/tstVBoxAPIWin.cpp b/src/VBox/Main/testcase/tstVBoxAPIWin.cpp new file mode 100644 index 00000000..444fa4d5 --- /dev/null +++ b/src/VBox/Main/testcase/tstVBoxAPIWin.cpp @@ -0,0 +1,305 @@ +/* $Id: tstVBoxAPIWin.cpp $ */ +/** @file + * + * tstVBoxAPIWin - sample program to illustrate the VirtualBox + * COM API for machine management on Windows. + It only uses standard C/C++ and COM semantics, + * no additional VBox classes/macros/helpers. To + * make things even easier to follow, only the + * standard Win32 API has been used. Typically, + * C++ developers would make use of Microsoft's + * ATL to ease development. + */ + +/* + * Copyright (C) 2006-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * PURPOSE OF THIS SAMPLE PROGRAM + * ------------------------------ + * + * This sample program is intended to demonstrate the minimal code necessary + * to use VirtualBox COM API for learning puroses only. The program uses pure + * Win32 API and doesn't have any extra dependencies to let you better + * understand what is going on when a client talks to the VirtualBox core + * using the COM framework. + * + * However, if you want to write a real application, it is highly recommended + * to use our MS COM XPCOM Glue library and helper C++ classes. This way, you + * will get at least the following benefits: + * + * a) better portability: both the MS COM (used on Windows) and XPCOM (used + * everywhere else) VirtualBox client application from the same source code + * (including common smart C++ templates for automatic interface pointer + * reference counter and string data management); + * b) simpler XPCOM initialization and shutdown (only a single method call + * that does everything right). + * + * Currently, there is no separate sample program that uses the VirtualBox MS + * COM XPCOM Glue library. Please refer to the sources of stock VirtualBox + * applications such as the VirtualBox GUI frontend or the VBoxManage command + * line frontend. + */ + + +#include <stdio.h> +#include <iprt/win/windows.h> /* Avoid -Wall warnings. */ +#include "VirtualBox.h" + +#define SAFE_RELEASE(x) \ + if (x) { \ + x->Release(); \ + x = NULL; \ + } + +int listVMs(IVirtualBox *virtualBox) +{ + HRESULT rc; + + /* + * First we have to get a list of all registered VMs + */ + SAFEARRAY *machinesArray = NULL; + + rc = virtualBox->get_Machines(&machinesArray); + if (SUCCEEDED(rc)) + { + IMachine **machines; + rc = SafeArrayAccessData(machinesArray, (void **) &machines); + if (SUCCEEDED(rc)) + { + for (ULONG i = 0; i < machinesArray->rgsabound[0].cElements; ++i) + { + BSTR str; + + rc = machines[i]->get_Name(&str); + if (SUCCEEDED(rc)) + { + printf("Name: %S\n", str); + SysFreeString(str); + } + } + + SafeArrayUnaccessData(machinesArray); + } + + SafeArrayDestroy(machinesArray); + } + + return 0; +} + + +int testErrorInfo(IVirtualBox *virtualBox) +{ + HRESULT rc; + + /* Try to find a machine that doesn't exist */ + IMachine *machine = NULL; + BSTR machineName = SysAllocString(L"Foobar"); + + rc = virtualBox->FindMachine(machineName, &machine); + + if (FAILED(rc)) + { + IErrorInfo *errorInfo; + + rc = GetErrorInfo(0, &errorInfo); + + if (FAILED(rc)) + printf("Error getting error info! rc=%#lx\n", rc); + else + { + BSTR errorDescription = NULL; + + rc = errorInfo->GetDescription(&errorDescription); + + if (FAILED(rc) || !errorDescription) + printf("Error getting error description! rc=%#lx\n", rc); + else + { + printf("Successfully retrieved error description: %S\n", errorDescription); + + SysFreeString(errorDescription); + } + + errorInfo->Release(); + } + } + + SAFE_RELEASE(machine); + SysFreeString(machineName); + + return 0; +} + + +int testStartVM(IVirtualBox *virtualBox) +{ + HRESULT rc; + + /* Try to start a VM called "WinXP SP2". */ + IMachine *machine = NULL; + BSTR machineName = SysAllocString(L"WinXP SP2"); + + rc = virtualBox->FindMachine(machineName, &machine); + + if (FAILED(rc)) + { + IErrorInfo *errorInfo; + + rc = GetErrorInfo(0, &errorInfo); + + if (FAILED(rc)) + printf("Error getting error info! rc=%#lx\n", rc); + else + { + BSTR errorDescription = NULL; + + rc = errorInfo->GetDescription(&errorDescription); + + if (FAILED(rc) || !errorDescription) + printf("Error getting error description! rc=%#lx\n", rc); + else + { + printf("Successfully retrieved error description: %S\n", errorDescription); + + SysFreeString(errorDescription); + } + + SAFE_RELEASE(errorInfo); + } + } + else + { + ISession *session = NULL; + IConsole *console = NULL; + IProgress *progress = NULL; + BSTR sessiontype = SysAllocString(L"gui"); + BSTR guid; + + do + { + rc = machine->get_Id(&guid); /* Get the GUID of the machine. */ + if (!SUCCEEDED(rc)) + { + printf("Error retrieving machine ID! rc=%#lx\n", rc); + break; + } + + /* Create the session object. */ + rc = CoCreateInstance(CLSID_Session, /* the VirtualBox base object */ + NULL, /* no aggregation */ + CLSCTX_INPROC_SERVER, /* the object lives in the current process */ + IID_ISession, /* IID of the interface */ + (void**)&session); + if (!SUCCEEDED(rc)) + { + printf("Error creating Session instance! rc=%#lx\n", rc); + break; + } + + /* Start a VM session using the delivered VBox GUI. */ + rc = machine->LaunchVMProcess(session, sessiontype, + NULL, &progress); + if (!SUCCEEDED(rc)) + { + printf("Could not open remote session! rc=%#lx\n", rc); + break; + } + + /* Wait until VM is running. */ + printf("Starting VM, please wait ...\n"); + rc = progress->WaitForCompletion(-1); + + /* Get console object. */ + session->get_Console(&console); + + /* Bring console window to front. */ + machine->ShowConsoleWindow(0); + + printf("Press enter to power off VM and close the session...\n"); + getchar(); + + /* Power down the machine. */ + rc = console->PowerDown(&progress); + + /* Wait until VM is powered down. */ + printf("Powering off VM, please wait ...\n"); + rc = progress->WaitForCompletion(-1); + + /* Close the session. */ + rc = session->UnlockMachine(); + + } while (0); + + SAFE_RELEASE(console); + SAFE_RELEASE(progress); + SAFE_RELEASE(session); + SysFreeString(guid); + SysFreeString(sessiontype); + SAFE_RELEASE(machine); + } + + SysFreeString(machineName); + + return 0; +} + + +int main() +{ + /* Initialize the COM subsystem. */ + CoInitialize(NULL); + + /* Instantiate the VirtualBox root object. */ + IVirtualBoxClient *virtualBoxClient; + HRESULT rc = CoCreateInstance(CLSID_VirtualBoxClient, /* the VirtualBoxClient object */ + NULL, /* no aggregation */ + CLSCTX_INPROC_SERVER, /* the object lives in the current process */ + IID_IVirtualBoxClient, /* IID of the interface */ + (void**)&virtualBoxClient); + if (SUCCEEDED(rc)) + { + IVirtualBox *virtualBox; + rc = virtualBoxClient->get_VirtualBox(&virtualBox); + if (SUCCEEDED(rc)) + { + listVMs(virtualBox); + + testErrorInfo(virtualBox); + + /* Enable the following line to get a VM started. */ + //testStartVM(virtualBox); + + /* Release the VirtualBox object. */ + virtualBox->Release(); + virtualBoxClient->Release(); + } + else + printf("Error creating VirtualBox instance! rc=%#lx\n", rc); + } + + CoUninitialize(); + return 0; +} + diff --git a/src/VBox/Main/testcase/tstVBoxAPIXPCOM.cpp b/src/VBox/Main/testcase/tstVBoxAPIXPCOM.cpp new file mode 100644 index 00000000..12908a15 --- /dev/null +++ b/src/VBox/Main/testcase/tstVBoxAPIXPCOM.cpp @@ -0,0 +1,684 @@ +/* $Id: tstVBoxAPIXPCOM.cpp $ */ +/** @file + * + * tstVBoxAPIXPCOM - sample program to illustrate the VirtualBox + * XPCOM API for machine management. + * It only uses standard C/C++ and XPCOM semantics, + * no additional VBox classes/macros/helpers. + */ + +/* + * Copyright (C) 2006-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +/* + * PURPOSE OF THIS SAMPLE PROGRAM + * ------------------------------ + * + * This sample program is intended to demonstrate the minimal code necessary + * to use VirtualBox XPCOM API for learning puroses only. The program uses + * pure XPCOM and doesn't have any extra dependencies to let you better + * understand what is going on when a client talks to the VirtualBox core + * using the XPCOM framework. + * + * However, if you want to write a real application, it is highly recommended + * to use our MS COM XPCOM Glue library and helper C++ classes. This way, you + * will get at least the following benefits: + * + * a) better portability: both the MS COM (used on Windows) and XPCOM (used + * everywhere else) VirtualBox client application from the same source code + * (including common smart C++ templates for automatic interface pointer + * reference counter and string data management); + * b) simpler XPCOM initialization and shutdown (only a single method call + * that does everything right). + * + * Currently, there is no separate sample program that uses the VirtualBox MS + * COM XPCOM Glue library. Please refer to the sources of stock VirtualBox + * applications such as the VirtualBox GUI frontend or the VBoxManage command + * line frontend. + * + * + * RUNNING THIS SAMPLE PROGRAM + * --------------------------- + * + * This sample program needs to know where the VirtualBox core files reside + * and where to search for VirtualBox shared libraries. Therefore, you need to + * use the following (or similar) command to execute it: + * + * $ env VBOX_XPCOM_HOME=../../.. LD_LIBRARY_PATH=../../.. ./tstVBoxAPIXPCOM + * + * The above command assumes that VBoxRT.so, VBoxXPCOM.so and others reside in + * the directory ../../.. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <iconv.h> + +/* + * Include the XPCOM headers + */ +#include <nsMemory.h> +#include <nsString.h> +#include <nsIServiceManager.h> +#include <nsEventQueueUtils.h> + +#include <nsIExceptionService.h> + +/* + * VirtualBox XPCOM interface. This header is generated + * from IDL which in turn is generated from a custom XML format. + */ +#include "VirtualBox_XPCOM.h" + +/* + * Prototypes + */ + +char *nsIDToString(nsID *guid); +void printErrorInfo(); + + +/** + * Display all registered VMs on the screen with some information about each + * + * @param virtualBox VirtualBox instance object. + */ +void listVMs(IVirtualBox *virtualBox) +{ + nsresult rc; + + printf("----------------------------------------------------\n"); + printf("VM List:\n\n"); + + /* + * Get the list of all registered VMs + */ + IMachine **machines = NULL; + PRUint32 cMachines = 0; + + rc = virtualBox->GetMachines(&cMachines, &machines); + if (NS_SUCCEEDED(rc)) + { + /* + * Iterate through the collection + */ + for (PRUint32 i = 0; i < cMachines; ++ i) + { + IMachine *machine = machines[i]; + if (machine) + { + PRBool isAccessible = PR_FALSE; + machine->GetAccessible(&isAccessible); + + if (isAccessible) + { + nsXPIDLString machineName; + machine->GetName(getter_Copies(machineName)); + char *machineNameAscii = ToNewCString(machineName); + printf("\tName: %s\n", machineNameAscii); + free(machineNameAscii); + } + else + { + printf("\tName: <inaccessible>\n"); + } + + nsXPIDLString iid; + machine->GetId(getter_Copies(iid)); + const char *uuidString = ToNewCString(iid); + printf("\tUUID: %s\n", uuidString); + free((void*)uuidString); + + if (isAccessible) + { + nsXPIDLString configFile; + machine->GetSettingsFilePath(getter_Copies(configFile)); + char *configFileAscii = ToNewCString(configFile); + printf("\tConfig file: %s\n", configFileAscii); + free(configFileAscii); + + PRUint32 memorySize; + machine->GetMemorySize(&memorySize); + printf("\tMemory size: %uMB\n", memorySize); + + nsXPIDLString typeId; + machine->GetOSTypeId(getter_Copies(typeId)); + IGuestOSType *osType = nsnull; + virtualBox->GetGuestOSType(typeId.get(), &osType); + nsXPIDLString osName; + osType->GetDescription(getter_Copies(osName)); + char *osNameAscii = ToNewCString(osName); + printf("\tGuest OS: %s\n\n", osNameAscii); + free(osNameAscii); + osType->Release(); + } + + /* don't forget to release the objects in the array... */ + machine->Release(); + } + } + nsMemory::Free(machines); + } + printf("----------------------------------------------------\n\n"); +} + +/** + * Create a sample VM + * + * @param virtualBox VirtualBox instance object. + */ +void createVM(IVirtualBox *virtualBox) +{ + nsresult rc; + /* + * First create a unnamed new VM. It will be unconfigured and not be saved + * in the configuration until we explicitely choose to do so. + */ + nsCOMPtr<IMachine> machine; + rc = virtualBox->CreateMachine(NULL, /* settings file */ + NS_LITERAL_STRING("A brand new name").get(), + 0, nsnull, /* groups (safearray)*/ + nsnull, /* ostype */ + nsnull, /* create flags */ + nsnull, /* cipher */ + nsnull, /* password id */ + nsnull, /* password */ + getter_AddRefs(machine)); + if (NS_FAILED(rc)) + { + printf("Error: could not create machine! rc=%#x\n", rc); + return; + } + + /* + * Set some properties + */ + /* alternative to illustrate the use of string classes */ + rc = machine->SetName(NS_ConvertUTF8toUTF16("A new name").get()); + rc = machine->SetMemorySize(128); + + /* + * Now a more advanced property -- the guest OS type. This is + * an object by itself which has to be found first. Note that we + * use the ID of the guest OS type here which is an internal + * representation (you can find that by configuring the OS type of + * a machine in the GUI and then looking at the <Guest ostype=""/> + * setting in the XML file. It is also possible to get the OS type from + * its description (win2k would be "Windows 2000") by getting the + * guest OS type collection and enumerating it. + */ + nsCOMPtr<IGuestOSType> osType; + rc = virtualBox->GetGuestOSType(NS_LITERAL_STRING("Windows2000").get(), + getter_AddRefs(osType)); + if (NS_FAILED(rc)) + { + printf("Error: could not find guest OS type! rc=%#x\n", rc); + } + else + { + machine->SetOSTypeId(NS_LITERAL_STRING("Windows2000").get()); + } + + /* + * Register the VM. Note that this call also saves the VM config + * to disk. It is also possible to save the VM settings but not + * register the VM. + * + * Also note that due to current VirtualBox limitations, the machine + * must be registered *before* we can attach hard disks to it. + */ + rc = virtualBox->RegisterMachine(machine); + if (NS_FAILED(rc)) + { + printf("Error: could not register machine! rc=%#x\n", rc); + printErrorInfo(); + return; + } + + nsCOMPtr<IMachine> origMachine = machine; + + /* + * In order to manipulate the registered machine, we must open a session + * for that machine. Do it now. + */ + nsCOMPtr<ISession> session; + nsCOMPtr<IMachine> sessionMachine; + { + nsCOMPtr<nsIComponentManager> manager; + rc = NS_GetComponentManager(getter_AddRefs(manager)); + if (NS_FAILED(rc)) + { + printf("Error: could not get component manager! rc=%#x\n", rc); + return; + } + rc = manager->CreateInstanceByContractID(NS_SESSION_CONTRACTID, + nsnull, + NS_GET_IID(ISession), + getter_AddRefs(session)); + if (NS_FAILED(rc)) + { + printf("Error, could not instantiate session object! rc=%#x\n", rc); + return; + } + + rc = machine->LockMachine(session, LockType_Write); + if (NS_FAILED(rc)) + { + printf("Error, could not lock the machine for the session! rc=%#x\n", rc); + return; + } + + /* + * After the machine is registered, the initial machine object becomes + * immutable. In order to get a mutable machine object, we must query + * it from the opened session object. + */ + rc = session->GetMachine(getter_AddRefs(sessionMachine)); + if (NS_FAILED(rc)) + { + printf("Error, could not get machine session! rc=%#x\n", rc); + return; + } + } + + /* + * Create a virtual harddisk + */ + nsCOMPtr<IMedium> hardDisk = 0; + rc = virtualBox->CreateMedium(NS_LITERAL_STRING("VDI").get(), + NS_LITERAL_STRING("/tmp/TestHardDisk.vdi").get(), + AccessMode_ReadWrite, DeviceType_HardDisk, + getter_AddRefs(hardDisk)); + if (NS_FAILED(rc)) + { + printf("Failed creating a hard disk object! rc=%#x\n", rc); + } + else + { + /* + * We have only created an object so far. No on disk representation exists + * because none of its properties has been set so far. Let's continue creating + * a dynamically expanding image. + */ + nsCOMPtr<IProgress> progress; + MediumVariant_T mediumVariants[] = + { MediumVariant_Standard }; + rc = hardDisk->CreateBaseStorage(100 * 1024 * 1024, // size in bytes + sizeof(mediumVariants) / sizeof(mediumVariants[0]), mediumVariants, + getter_AddRefs(progress)); // optional progress object + if (NS_FAILED(rc)) + { + printf("Failed creating hard disk image! rc=%#x\n", rc); + } + else + { + /* + * Creating the image is done in the background because it can take quite + * some time (at least fixed size images). We have to wait for its completion. + * Here we wait forever (timeout -1) which is potentially dangerous. + */ + rc = progress->WaitForCompletion(-1); + PRInt32 resultCode; + progress->GetResultCode(&resultCode); + if (NS_FAILED(rc) || NS_FAILED(resultCode)) + { + printf("Error: could not create hard disk! rc=%#x\n", + NS_FAILED(rc) ? rc : resultCode); + } + else + { + /* + * Now that it's created, we can assign it to the VM. + */ + rc = sessionMachine->AttachDevice( + NS_LITERAL_STRING("IDE Controller").get(), // controller identifier + 0, // channel number on the controller + 0, // device number on the controller + DeviceType_HardDisk, + hardDisk); + if (NS_FAILED(rc)) + { + printf("Error: could not attach hard disk! rc=%#x\n", rc); + } + } + } + } + + /* + * It's got a hard disk but that one is new and thus not bootable. Make it + * boot from an ISO file. This requires some processing. First the ISO file + * has to be registered and then mounted to the VM's DVD drive and selected + * as the boot device. + */ + nsCOMPtr<IMedium> dvdImage; + rc = virtualBox->OpenMedium(NS_LITERAL_STRING("/home/vbox/isos/winnt4ger.iso").get(), + DeviceType_DVD, + AccessMode_ReadOnly, + false /* fForceNewUuid */, + getter_AddRefs(dvdImage)); + if (NS_FAILED(rc)) + printf("Error: could not open CD image! rc=%#x\n", rc); + else + { + /* + * Now assign it to our VM + */ + rc = sessionMachine->MountMedium( + NS_LITERAL_STRING("IDE Controller").get(), // controller identifier + 2, // channel number on the controller + 0, // device number on the controller + dvdImage, + PR_FALSE); // aForce + if (NS_FAILED(rc)) + { + printf("Error: could not mount ISO image! rc=%#x\n", rc); + } + else + { + /* + * Last step: tell the VM to boot from the CD. + */ + rc = sessionMachine->SetBootOrder(1, DeviceType::DVD); + if (NS_FAILED(rc)) + { + printf("Could not set boot device! rc=%#x\n", rc); + } + } + } + + /* + * Save all changes we've just made. + */ + rc = sessionMachine->SaveSettings(); + if (NS_FAILED(rc)) + printf("Could not save machine settings! rc=%#x\n", rc); + + /* + * It is always important to close the open session when it becomes not + * necessary any more. + */ + session->UnlockMachine(); + + IMedium **aMedia; + PRUint32 cMedia; + rc = machine->Unregister((CleanupMode_T)CleanupMode_DetachAllReturnHardDisksOnly, + &cMedia, &aMedia); + if (NS_FAILED(rc)) + printf("Unregistering the machine failed! rc=%#x\n", rc); + else + { + nsCOMPtr<IProgress> pProgress; + rc = machine->DeleteConfig(cMedia, aMedia, getter_AddRefs(pProgress)); + if (NS_FAILED(rc)) + printf("Deleting of machine failed! rc=%#x\n", rc); + else + { + rc = pProgress->WaitForCompletion(-1); + PRInt32 resultCode; + pProgress->GetResultCode(&resultCode); + if (NS_FAILED(rc) || NS_FAILED(resultCode)) + printf("Failed to delete the machine! rc=%#x\n", + NS_FAILED(rc) ? rc : resultCode); + } + + /* Release the media array: */ + for (PRUint32 i = 0; i < cMedia; i++) + if (aMedia[i]) + aMedia[i]->Release(); + nsMemory::Free(aMedia); + } +} + +// main +/////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char **argv) +{ + /* + * Check that PRUnichar is equal in size to what compiler composes L"" + * strings from; otherwise NS_LITERAL_STRING macros won't work correctly + * and we will get a meaningless SIGSEGV. This, of course, must be checked + * at compile time in xpcom/string/nsTDependentString.h, but XPCOM lacks + * compile-time assert macros and I'm not going to add them now. + */ + if (sizeof(PRUnichar) != sizeof(wchar_t)) + { + printf("Error: sizeof(PRUnichar) {%lu} != sizeof(wchar_t) {%lu}!\n" + "Probably, you forgot the -fshort-wchar compiler option.\n", + (unsigned long) sizeof(PRUnichar), + (unsigned long) sizeof(wchar_t)); + return -1; + } + +#if 1 /* Please ignore this! It is very very crude. */ +# ifdef RTPATH_APP_PRIVATE_ARCH + if (!getenv("VBOX_XPCOM_HOME")) + setenv("VBOX_XPCOM_HOME", RTPATH_APP_PRIVATE_ARCH, 1); +# else + char szTmp[8192]; + if (!getenv("VBOX_XPCOM_HOME")) + { + strcpy(szTmp, argv[0]); + *strrchr(szTmp, '/') = '\0'; + strcat(szTmp, "/.."); + fprintf(stderr, "tstVBoxAPIXPCOM: VBOX_XPCOM_HOME is not set, using '%s' instead\n", szTmp); + setenv("VBOX_XPCOM_HOME", szTmp, 1); + } +# endif +#endif + (void)argc; (void)argv; + + nsresult rc; + + /* + * This is the standard XPCOM init procedure. + * What we do is just follow the required steps to get an instance + * of our main interface, which is IVirtualBox. + * + * Note that we scope all nsCOMPtr variables in order to have all XPCOM + * objects automatically released before we call NS_ShutdownXPCOM at the + * end. This is an XPCOM requirement. + */ + { + nsCOMPtr<nsIServiceManager> serviceManager; + rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull); + if (NS_FAILED(rc)) + { + printf("Error: XPCOM could not be initialized! rc=%#x\n", rc); + return -1; + } + +#if 0 + /* + * Register our components. This step is only necessary if this executable + * implements XPCOM components itself which is not the case for this + * simple example. + */ + nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager); + if (!registrar) + { + printf("Error: could not query nsIComponentRegistrar interface!\n"); + return -1; + } + registrar->AutoRegister(nsnull); +#endif + + /* + * Make sure the main event queue is created. This event queue is + * responsible for dispatching incoming XPCOM IPC messages. The main + * thread should run this event queue's loop during lengthy non-XPCOM + * operations to ensure messages from the VirtualBox server and other + * XPCOM IPC clients are processed. This use case doesn't perform such + * operations so it doesn't run the event loop. + */ + nsCOMPtr<nsIEventQueue> eventQ; + rc = NS_GetMainEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rc)) + { + printf("Error: could not get main event queue! rc=%#x\n", rc); + return -1; + } + + /* + * Now XPCOM is ready and we can start to do real work. + * IVirtualBox is the root interface of VirtualBox and will be + * retrieved from the XPCOM component manager. We use the + * XPCOM provided smart pointer nsCOMPtr for all objects because + * that's very convenient and removes the need deal with reference + * counting and freeing. + */ + nsCOMPtr<nsIComponentManager> manager; + rc = NS_GetComponentManager(getter_AddRefs(manager)); + if (NS_FAILED(rc)) + { + printf("Error: could not get component manager! rc=%#x\n", rc); + return -1; + } + + nsCOMPtr<IVirtualBox> virtualBox; + rc = manager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID, + nsnull, + NS_GET_IID(IVirtualBox), + getter_AddRefs(virtualBox)); + if (NS_FAILED(rc)) + { + printf("Error, could not instantiate VirtualBox object! rc=%#x\n", rc); + return -1; + } + printf("VirtualBox object created\n"); + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + + listVMs(virtualBox); + + createVM(virtualBox); + + + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + + /* this is enough to free the IVirtualBox instance -- smart pointers rule! */ + virtualBox = nsnull; + + /* + * Process events that might have queued up in the XPCOM event + * queue. If we don't process them, the server might hang. + */ + eventQ->ProcessPendingEvents(); + } + + /* + * Perform the standard XPCOM shutdown procedure. + */ + NS_ShutdownXPCOM(nsnull); + printf("Done!\n"); + return 0; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////// +//// Helpers +////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Helper function to convert an nsID into a human readable string + * + * @returns result string, allocated. Has to be freed using free() + * @param guid Pointer to nsID that will be converted. + */ +char *nsIDToString(nsID *guid) +{ + char *res = (char*)malloc(39); + + if (res != NULL) + { + snprintf(res, 39, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + guid->m0, (PRUint32)guid->m1, (PRUint32)guid->m2, + (PRUint32)guid->m3[0], (PRUint32)guid->m3[1], (PRUint32)guid->m3[2], + (PRUint32)guid->m3[3], (PRUint32)guid->m3[4], (PRUint32)guid->m3[5], + (PRUint32)guid->m3[6], (PRUint32)guid->m3[7]); + } + return res; +} + +/** + * Helper function to print XPCOM exception information set on the current + * thread after a failed XPCOM method call. This function will also print + * extended VirtualBox error info if it is available. + */ +void printErrorInfo() +{ + nsresult rc; + + nsCOMPtr<nsIExceptionService> es; + es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc); + if (NS_SUCCEEDED(rc)) + { + nsCOMPtr<nsIExceptionManager> em; + rc = es->GetCurrentExceptionManager(getter_AddRefs(em)); + if (NS_SUCCEEDED(rc)) + { + nsCOMPtr<nsIException> ex; + rc = em->GetCurrentException(getter_AddRefs(ex)); + if (NS_SUCCEEDED(rc) && ex) + { + nsCOMPtr<IVirtualBoxErrorInfo> info; + info = do_QueryInterface(ex, &rc); + if (NS_SUCCEEDED(rc) && info) + { + /* got extended error info */ + printf("Extended error info (IVirtualBoxErrorInfo):\n"); + PRInt32 resultCode = NS_OK; + info->GetResultCode(&resultCode); + printf(" resultCode=%08X\n", resultCode); + nsXPIDLString component; + info->GetComponent(getter_Copies(component)); + printf(" component=%s\n", NS_ConvertUTF16toUTF8(component).get()); + nsXPIDLString text; + info->GetText(getter_Copies(text)); + printf(" text=%s\n", NS_ConvertUTF16toUTF8(text).get()); + } + else + { + /* got basic error info */ + printf("Basic error info (nsIException):\n"); + nsresult resultCode = NS_OK; + ex->GetResult(&resultCode); + printf(" resultCode=%08X\n", resultCode); + nsXPIDLCString message; + ex->GetMessage(getter_Copies(message)); + printf(" message=%s\n", message.get()); + } + + /* reset the exception to NULL to indicate we've processed it */ + em->SetCurrentException(NULL); + + rc = NS_OK; + } + } + } +} diff --git a/src/VBox/Main/testcase/tstVBoxCrypto.cpp b/src/VBox/Main/testcase/tstVBoxCrypto.cpp new file mode 100644 index 00000000..0f3fbcf6 --- /dev/null +++ b/src/VBox/Main/testcase/tstVBoxCrypto.cpp @@ -0,0 +1,431 @@ +/* $Id: tstVBoxCrypto.cpp $ */ +/** @file + * tstVBoxCrypto - Testcase for the cryptographic support module. + */ + +/* + * Copyright (C) 2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/VBoxCryptoIf.h> +#include <VBox/err.h> + +#include <iprt/file.h> +#include <iprt/test.h> +#include <iprt/ldr.h> +#include <iprt/mem.h> +#include <iprt/memsafer.h> +#include <iprt/rand.h> +#include <iprt/string.h> +#include <iprt/vfs.h> + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static RTTEST g_hTest; +static const uint8_t g_abDek[64] = { 0x42 }; +static const char g_szPassword[] = "testtesttest"; +static const char g_szPasswordWrong[] = "testtest"; + +static const char *g_aCiphers[] = +{ + "AES-XTS128-PLAIN64", + "AES-GCM128", + "AES-CTR128", + + "AES-XTS256-PLAIN64", + "AES-GCM256", + "AES-CTR256" +}; + +#define CHECK_STR(str1, str2) do { if (strcmp(str1, str2)) { RTTestIFailed("line %u: '%s' != '%s' (*)", __LINE__, str1, str2); } } while (0) +#define CHECK_BYTES(bytes1, bytes2, size) do { if (memcmp(bytes1, bytes2, size)) { RTTestIFailed("line %u: '%s' != '%s' (*)", __LINE__, #bytes1, bytes2); } } while (0) + + +/** + * Creates a new cryptographic context and returns the encoded string version on success. + * + * @returns VBox status code. + * @param pCryptoIf Pointer to the cryptographic interface. + * @param pszCipher The cipher to use. + * @param pszPassword The password to use. + * @param ppszCtx Where to store the pointer to the context on success. + */ +static int tstCryptoCtxCreate(PCVBOXCRYPTOIF pCryptoIf, const char *pszCipher, const char *pszPassword, char **ppszCtx) +{ + VBOXCRYPTOCTX hCryptoCtx; + + int rc = pCryptoIf->pfnCryptoCtxCreate(pszCipher, pszPassword, &hCryptoCtx); + if (RT_SUCCESS(rc)) + { + rc = pCryptoIf->pfnCryptoCtxSave(hCryptoCtx, ppszCtx); + int rc2 = pCryptoIf->pfnCryptoCtxDestroy(hCryptoCtx); + AssertReleaseRC(rc2); + } + + return rc; +} + + +/** + * Writes data to the given file until the given size is reached. + * + * @returns VBox status code. + * @param hVfsFile The file handle to write to. + * @param cbWrite Number of bytes to write. + */ +static int tstCryptoVfsWrite(RTVFSFILE hVfsFile, size_t cbWrite) +{ + RTTestISub("Writing to encrypted file"); + + int rc = VINF_SUCCESS; + size_t cbBufLeft = _128K; + void *pv = RTMemTmpAllocZ(cbBufLeft); + if (pv) + { + size_t cbLeft = cbWrite; + uint32_t cCounter = 0; + uint8_t *pb = (uint8_t *)pv; + + /* Fill the counter buffer. */ + uint32_t *pu32 = (uint32_t *)pv; + for (uint32_t i = 0; i < cbBufLeft / sizeof(uint32_t); i++) + *pu32++ = cCounter++; + + + for (;;) + { + size_t cbThisWrite = RTRandU64Ex(1, RT_MIN(cbBufLeft, cbLeft)); + rc = RTVfsFileWrite(hVfsFile, pb, cbThisWrite, NULL /*pcbWritten*/); + if (RT_FAILURE(rc)) + { + RTTestIFailed("Writing to file failed with %Rrc (cbLeft=%zu, cbBufLeft=%zu, cbThisWrite=%zu)", + rc, cbLeft, cbBufLeft, cbThisWrite); + break; + } + + cbLeft -= cbThisWrite; + cbBufLeft -= cbThisWrite; + pb += cbThisWrite; + + if (!cbBufLeft) + { + /* Fill the counter buffer again. */ + pu32 = (uint32_t *)pv; + pb = (uint8_t *)pv; + cbBufLeft = _128K; + for (uint32_t i = 0; i < cbBufLeft / sizeof(uint32_t); i++) + *pu32++ = cCounter++; + } + + if (!cbLeft) + break; + } + + RTMemTmpFree(pv); + } + else + { + RTTestIFailed("Allocating write buffer failed - out of memory"); + rc = VERR_NO_MEMORY; + } + + RTTestISubDone(); + return rc; +} + + +/** + * Writes data to the given file until the given size is reached. + * + * @returns VBox status code. + * @param hVfsFile The file handle to write to. + * @param cbFile Size of the file payload in bytes. + */ +static int tstCryptoVfsReadAndVerify(RTVFSFILE hVfsFile, size_t cbFile) +{ + RTTestISub("Reading from encrypted file and verifying data"); + + int rc = VINF_SUCCESS; + void *pv = RTMemTmpAllocZ(_128K); + if (pv) + { + size_t cbLeft = cbFile; + uint32_t cCounter = 0; + + for (;;) + { + /* Read the data in multiple calls. */ + size_t cbBufLeft = RT_MIN(cbLeft, _128K); + uint8_t *pb = (uint8_t *)pv; + + while (cbBufLeft) + { + size_t cbThisRead = RTRandU64Ex(1, RT_MIN(cbBufLeft, cbLeft)); + rc = RTVfsFileRead(hVfsFile, pb, cbThisRead, NULL /*pcbWritten*/); + if (RT_FAILURE(rc)) + { + RTTestIFailed("Reading from file failed with %Rrc (cbLeft=%zu, cbBufLeft=%zu, cbThisRead=%zu)", + rc, cbLeft, cbBufLeft, cbThisRead); + break; + } + + cbBufLeft -= cbThisRead; + pb += cbThisRead; + } + + if (RT_FAILURE(rc)) + break; + + /* Verify the read data. */ + size_t cbInBuffer = RT_MIN(cbLeft, _128K); + Assert(!(cbInBuffer % sizeof(uint32_t))); + uint32_t *pu32 = (uint32_t *)pv; + + for (uint32_t i = 0; i < cbInBuffer / sizeof(uint32_t); i++) + { + if (*pu32 != cCounter) + { + RTTestIFailed("Reading from file resulted in corrupted data (expected '%#x' got '%#x')", + cCounter, *pu32); + break; + } + + pu32++; + cCounter++; + } + + cbLeft -= RT_MIN(cbLeft, _128K); + if (!cbLeft) + break; + } + + RTMemTmpFree(pv); + } + else + { + RTTestIFailed("Allocating read buffer failed - out of memory"); + rc = VERR_NO_MEMORY; + } + + RTTestISubDone(); + return rc; +} + + +/** + * Testing some basics of the encrypted file VFS code. + * + * @returns nothing. + * @param pCryptoIf Pointer to the callback table. + */ +static void tstCryptoVfsBasics(PCVBOXCRYPTOIF pCryptoIf) +{ + RTTestISub("Encrypted file - Basics"); + + RTTestDisableAssertions(g_hTest); + + char *pszCtx = NULL; + int rc = tstCryptoCtxCreate(pCryptoIf, g_aCiphers[4], g_szPassword, &pszCtx); + if (RT_SUCCESS(rc)) + { + /* Create the memory file to write to. */ + RTVFSFILE hVfsFile; + rc = RTVfsMemFileCreate(NIL_RTVFSIOSTREAM, 0 /*cbEstimate*/, &hVfsFile); + if (RT_SUCCESS(rc)) + { + RTVFSFILE hVfsFileEnc; + + RTTestISub("Creating encrypted file"); + + rc = pCryptoIf->pfnCryptoFileFromVfsFile(hVfsFile, pszCtx, g_szPassword, &hVfsFileEnc); + if (RT_SUCCESS(rc)) + { + RTTestISubDone(); + + size_t cbFile = RT_ALIGN_Z(RTRandU32Ex(_1K, 10 * _1M), sizeof(uint32_t)); /* Align to full counter field size. */ + rc = tstCryptoVfsWrite(hVfsFileEnc, cbFile); + RTVfsFileRelease(hVfsFileEnc); /* Close file. */ + if (RT_SUCCESS(rc)) + { + /* Reopen for reading. */ + RTTestISub("Open encrypted file"); + + /* Reset the memory file offset. */ + RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL /*poffActual*/); + + rc = pCryptoIf->pfnCryptoFileFromVfsFile(hVfsFile, pszCtx, g_szPassword, &hVfsFileEnc); + if (RT_SUCCESS(rc)) + { + RTTestISubDone(); + + RTTestISub("Query encrypted file size"); + uint64_t cbFileRd; + rc = RTVfsFileQuerySize(hVfsFileEnc, &cbFileRd); + if (RT_SUCCESS(rc)) + { + if (cbFile != cbFileRd) + RTTestIFailed("Unexpected file size, got %#llx expected %#zx", cbFileRd, cbFile); + + RTTestISubDone(); + tstCryptoVfsReadAndVerify(hVfsFileEnc, cbFile); + } + else + RTTestIFailed("Querying encrypted file size failed %Rrc", rc); + + RTVfsFileRelease(hVfsFileEnc); /* Close file. */ + } + else + RTTestIFailed("Opening encrypted file for reading failed with %Rrc", rc); + + } + /* Error set on failure. */ + } + else + RTTestIFailed("Creating encrypted file handle failed with %Rrc", rc); + + RTVfsFileRelease(hVfsFile); + } + else + RTTestIFailed("Creating a new encrypted file failed with %Rrc", rc); + + RTMemFree(pszCtx); + } + else + RTTestIFailed("Creating a new encrypted context failed with %Rrc", rc); + + RTTestRestoreAssertions(g_hTest); + RTTestISubDone(); +} + + +/** + * Testing some basics of the crypto keystore code. + * + * @returns nothing. + * @param pCryptoIf Pointer to the callback table. + */ +static void tstCryptoKeyStoreBasics(PCVBOXCRYPTOIF pCryptoIf) +{ + RTTestISub("Crypto Keystore - Basics"); + + RTTestDisableAssertions(g_hTest); + + for (uint32_t i = 0; i < RT_ELEMENTS(g_aCiphers); i++) + { + RTTestISubF("Creating a new keystore for cipher '%s'", g_aCiphers[i]); + + char *pszKeystoreEnc = NULL; /**< The encoded keystore. */ + int rc = pCryptoIf->pfnCryptoKeyStoreCreate(g_szPassword, &g_abDek[0], sizeof(g_abDek), + g_aCiphers[i], &pszKeystoreEnc); + if (RT_SUCCESS(rc)) + { + uint8_t *pbKey = NULL; + size_t cbKey = 0; + char *pszCipher = NULL; + + RTTestSub(g_hTest, "Trying to unlock DEK with wrong password"); + rc = pCryptoIf->pfnCryptoKeyStoreGetDekFromEncoded(pszKeystoreEnc, g_szPasswordWrong, + &pbKey, &cbKey, &pszCipher); + RTTESTI_CHECK_RC(rc, VERR_VD_PASSWORD_INCORRECT); + + RTTestSub(g_hTest, "Trying to unlock DEK with correct password"); + rc = pCryptoIf->pfnCryptoKeyStoreGetDekFromEncoded(pszKeystoreEnc, g_szPassword, + &pbKey, &cbKey, &pszCipher); + RTTESTI_CHECK_RC_OK(rc); + if (RT_SUCCESS(rc)) + { + RTTESTI_CHECK(cbKey == sizeof(g_abDek)); + CHECK_STR(pszCipher, g_aCiphers[i]); + CHECK_BYTES(pbKey, &g_abDek[0], sizeof(g_abDek)); + + RTMemSaferFree(pbKey, cbKey); + } + + RTMemFree(pszKeystoreEnc); + } + else + RTTestIFailed("Creating a new keystore failed with %Rrc", rc); + } + + RTTestRestoreAssertions(g_hTest); +} + + +int main(int argc, char *argv[]) +{ + /* + * Initialization. + */ + RTEXITCODE rcExit = RTTestInitAndCreate("tstVBoxCrypto", &g_hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(g_hTest); + + RTTestSub(g_hTest, "Loading the cryptographic support module"); + const char *pszModCrypto = NULL; + if (argc == 2) + { + /* The module to load is given on the command line. */ + pszModCrypto = argv[1]; + } + else + { + /* Try find it in the extension pack. */ + /** @todo */ + RTTestSkipped(g_hTest, "Getting the module from the extension pack is not implemented yet, skipping testcase"); + } + + if (pszModCrypto) + { + RTLDRMOD hLdrModCrypto = NIL_RTLDRMOD; + int rc = RTLdrLoad(pszModCrypto, &hLdrModCrypto); + if (RT_SUCCESS(rc)) + { + PFNVBOXCRYPTOENTRY pfnCryptoEntry = NULL; + rc = RTLdrGetSymbol(hLdrModCrypto, VBOX_CRYPTO_MOD_ENTRY_POINT, (void **)&pfnCryptoEntry); + if (RT_SUCCESS(rc)) + { + PCVBOXCRYPTOIF pCryptoIf = NULL; + rc = pfnCryptoEntry(&pCryptoIf); + if (RT_SUCCESS(rc)) + { + /* Loading succeeded, now we can start real testing. */ + tstCryptoKeyStoreBasics(pCryptoIf); + tstCryptoVfsBasics(pCryptoIf); + } + else + RTTestIFailed("Calling '%s' failed with %Rrc", VBOX_CRYPTO_MOD_ENTRY_POINT, rc); + } + else + RTTestIFailed("Failed to resolve entry point '%s' with %Rrc", VBOX_CRYPTO_MOD_ENTRY_POINT, rc); + } + else + RTTestIFailed("Failed to load the crypto module '%s' with %Rrc", pszModCrypto, rc); + } + + return RTTestSummaryAndDestroy(g_hTest); +} diff --git a/src/VBox/Main/testcase/tstVBoxMultipleVM.cpp b/src/VBox/Main/testcase/tstVBoxMultipleVM.cpp new file mode 100644 index 00000000..fc12ab80 --- /dev/null +++ b/src/VBox/Main/testcase/tstVBoxMultipleVM.cpp @@ -0,0 +1,617 @@ +/** @file + * tstVBoxMultipleVM - load test for ClientWatcher. + */ + +/* + * Copyright (C) 2006-2022 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>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/com/com.h> +#include <VBox/com/string.h> +#include <VBox/com/array.h> +#include <VBox/com/Guid.h> +#include <VBox/com/ErrorInfo.h> +#include <VBox/com/errorprint.h> +#include <iprt/assert.h> +#include <iprt/errcore.h> +#include <VBox/com/VirtualBox.h> +#include <iprt/stream.h> +#include <iprt/semaphore.h> +#include <iprt/thread.h> +#include <VBox/sup.h> + +#include <vector> +#include <algorithm> + +#include <iprt/test.h> +#include <iprt/time.h> +#include <iprt/rand.h> +#include <iprt/getopt.h> + +using namespace com; + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/* Arguments of test thread */ +struct TestThreadArgs +{ + /** number of machines that should be run simultaneousely */ + uint32_t machinesPackSize; + /** percents of VM Stop operation what should be called + * without session unlocking */ + uint32_t percentsUnlok; + /** How much time in milliseconds test will be executed */ + uint64_t cMsExecutionTime; + /** How much machines create for the test */ + uint32_t numberMachines; +}; + + +/********************************************************************************************************************************* +* Global Variables & defs * +*********************************************************************************************************************************/ +static RTTEST g_hTest; +#ifdef RT_ARCH_AMD64 +typedef std::vector<Bstr> TMachinesList; +static volatile bool g_RunTest = true; +static RTSEMEVENT g_PingEevent; +static volatile uint64_t g_Counter = 0; +static TestThreadArgs g_Args; + + +/** Worker for TST_COM_EXPR(). */ +static HRESULT tstComExpr(HRESULT hrc, const char *pszOperation, int iLine) +{ + if (FAILED(hrc)) + { + RTTestFailed(g_hTest, "%s failed on line %u with hrc=%Rhrc\n", pszOperation, iLine, hrc); + } + return hrc; +} + + +#define CHECK_ERROR_L(iface, method) \ + do { \ + hrc = iface->method; \ + if (FAILED(hrc)) \ + RTPrintf("warning: %s->%s failed on line %u with hrc=%Rhrc\n", #iface, #method, __LINE__, hrc);\ + } while (0) + + +/** Macro that executes the given expression and report any failure. + * The expression must return a HRESULT. */ +#define TST_COM_EXPR(expr) tstComExpr(expr, #expr, __LINE__) + + +static int tstStartVM(IVirtualBox *pVBox, ISession *pSession, Bstr machineID, bool fSkipUnlock) +{ + HRESULT hrc; + ComPtr<IProgress> progress; + ComPtr<IMachine> machine; + Bstr machineName; + + hrc = TST_COM_EXPR(pVBox->FindMachine(machineID.raw(), machine.asOutParam())); + if(SUCCEEDED(hrc)) + hrc = TST_COM_EXPR(machine->COMGETTER(Name)(machineName.asOutParam())); + if(SUCCEEDED(hrc)) + { + hrc = machine->LaunchVMProcess(pSession, Bstr("headless").raw(), + ComSafeArrayNullInParam(), progress.asOutParam()); + } + if (SUCCEEDED(hrc) && !progress.isNull()) + { + CHECK_ERROR_L(progress, WaitForCompletion(-1)); + if (SUCCEEDED(hrc)) + { + BOOL completed = true; + CHECK_ERROR_L(progress, COMGETTER(Completed)(&completed)); + if (SUCCEEDED(hrc)) + { + Assert(completed); + LONG iRc; + CHECK_ERROR_L(progress, COMGETTER(ResultCode)(&iRc)); + if (SUCCEEDED(hrc)) + { + if (FAILED(iRc)) + { + ProgressErrorInfo info(progress); + RTPrintf("Start VM '%ls' failed. Warning: %ls.\n", machineName.raw(), info.getText().raw()); + } + else + RTPrintf("VM '%ls' started.\n", machineName.raw()); + } + } + } + if (!fSkipUnlock) + pSession->UnlockMachine(); + else + RTPrintf("Session unlock skipped.\n"); + } + return hrc; +} + + +static int tstStopVM(IVirtualBox* pVBox, ISession* pSession, Bstr machineID, bool fSkipUnlock) +{ + ComPtr<IMachine> machine; + HRESULT hrc = TST_COM_EXPR(pVBox->FindMachine(machineID.raw(), machine.asOutParam())); + if (SUCCEEDED(hrc)) + { + Bstr machineName; + hrc = TST_COM_EXPR(machine->COMGETTER(Name)(machineName.asOutParam())); + if (SUCCEEDED(hrc)) + { + MachineState_T machineState; + hrc = TST_COM_EXPR(machine->COMGETTER(State)(&machineState)); + // check that machine is in running state + if ( SUCCEEDED(hrc) + && ( machineState == MachineState_Running + || machineState == MachineState_Paused)) + { + ComPtr<IConsole> console; + ComPtr<IProgress> progress; + + hrc = TST_COM_EXPR(machine->LockMachine(pSession, LockType_Shared)); + if(SUCCEEDED(hrc)) + TST_COM_EXPR(pSession->COMGETTER(Console)(console.asOutParam())); + if(SUCCEEDED(hrc)) + hrc = console->PowerDown(progress.asOutParam()); + if (SUCCEEDED(hrc) && !progress.isNull()) + { + //RTPrintf("Stopping VM %ls...\n", machineName.raw()); + CHECK_ERROR_L(progress, WaitForCompletion(-1)); + if (SUCCEEDED(hrc)) + { + BOOL completed = true; + CHECK_ERROR_L(progress, COMGETTER(Completed)(&completed)); + if (SUCCEEDED(hrc)) + { + //ASSERT(completed); + LONG iRc; + CHECK_ERROR_L(progress, COMGETTER(ResultCode)(&iRc)); + if (SUCCEEDED(hrc)) + { + if (FAILED(iRc)) + { + ProgressErrorInfo info(progress); + RTPrintf("Stop VM %ls failed. Warning: %ls.\n", machineName.raw(), info.getText().raw()); + hrc = iRc; + } + else + { + RTPrintf("VM '%ls' stopped.\n", machineName.raw()); + } + } + } + } + if (!fSkipUnlock) + pSession->UnlockMachine(); + else + RTPrintf("Session unlock skipped.\n"); + } + } + } + } + return hrc; +} + + +/** + * Get random @a maxCount machines from list of existing VMs. + * + * @note Can return less then maxCount machines. + */ +static int tstGetMachinesList(IVirtualBox *pVBox, uint32_t maxCount, TMachinesList &listToFill) +{ + com::SafeIfaceArray<IMachine> machines; + HRESULT hrc = TST_COM_EXPR(pVBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines))); + if (SUCCEEDED(hrc)) + { + + size_t cMachines = RT_MIN(machines.size(), maxCount); + for (size_t i = 0; i < cMachines; ++i) + { + // choose random index of machine + uint32_t idx = RTRandU32Ex(0, (uint32_t)machines.size() - 1); + if (machines[idx]) + { + Bstr bstrId; + Bstr machineName; + CHECK_ERROR_L(machines[idx], COMGETTER(Id)(bstrId.asOutParam())); + if (SUCCEEDED(hrc)) + CHECK_ERROR_L(machines[idx], COMGETTER(Name)(machineName.asOutParam())); + if (SUCCEEDED(hrc)) + { + if (Utf8Str(machineName).startsWith("umtvm")) + listToFill.push_back(bstrId); + } + } + } + + // remove duplicates from the vector + std::sort(listToFill.begin(), listToFill.end()); + listToFill.erase(std::unique(listToFill.begin(), listToFill.end()), listToFill.end()); + RTPrintf("Filled pack of %d from %d machines.\n", listToFill.size(), machines.size()); + } + + return hrc; +} + + +static int tstMachinesPack(IVirtualBox *pVBox, uint32_t maxPackSize, uint32_t percentage) +{ + HRESULT hrc = S_OK; + TMachinesList machinesList; + bool alwaysUnlock = false; + uint64_t percN = 0; + + // choose and fill pack of machines for test + tstGetMachinesList(pVBox, maxPackSize, machinesList); + + RTPrintf("Start test.\n"); + // screw up counter + g_Counter = UINT64_MAX - machinesList.size() <= g_Counter ? 0 : g_Counter; + if (percentage > 0) + percN = 100 / percentage; + else + alwaysUnlock = true; + + // start all machines in pack + for (TMachinesList::iterator it = machinesList.begin(); + it != machinesList.end() && g_RunTest; + ++it) + { + ComPtr<ISession> session; + hrc = session.createInprocObject(CLSID_Session); + if (SUCCEEDED(hrc)) + { + hrc = tstStartVM(pVBox, session, *it, !(alwaysUnlock || g_Counter++ % percN)); + } + RTSemEventSignal(g_PingEevent); + RTThreadSleep(100); + } + // stop all machines in the pack + for (TMachinesList::iterator it = machinesList.begin(); + it != machinesList.end() && g_RunTest; + ++it) + { + ComPtr<ISession> session; + hrc = session.createInprocObject(CLSID_Session); + if (SUCCEEDED(hrc)) + { + // stop machines, skip session unlock of given % of machines + hrc = tstStopVM(pVBox, session, *it, !(alwaysUnlock || g_Counter++ % percN)); + } + RTSemEventSignal(g_PingEevent); + RTThreadSleep(100); + } + return hrc; +} + + +static Bstr tstMakeMachineName(int i) +{ + char szMachineName[32]; + RTStrPrintf(szMachineName, sizeof(szMachineName), "umtvm%d", i); + return Bstr(szMachineName); +} + + +static int tstCreateMachines(IVirtualBox *pVBox) +{ + HRESULT hrc = S_OK; + // create machines for the test + for (uint32_t i = 0; i < g_Args.numberMachines; i++) + { + ComPtr<IMachine> ptrMachine; + com::SafeArray<BSTR> groups; + + Bstr machineName(tstMakeMachineName(i)); + /* Default VM settings */ + CHECK_ERROR_L(pVBox, CreateMachine(NULL, /* Settings */ + machineName.raw(), /* Name */ + ComSafeArrayAsInParam(groups), /* Groups */ + NULL, /* OS Type */ + NULL, /** Cipher */ + NULL, /** Password id */ + NULL, /** Password */ + NULL, /* Create flags */ + ptrMachine.asOutParam())); + if (SUCCEEDED(hrc)) + { + CHECK_ERROR_L(pVBox, RegisterMachine(ptrMachine)); + RTPrintf("Machine '%ls' created\n", machineName.raw()); + } + + RTSemEventSignal(g_PingEevent); + RTThreadSleep(100); + } + return hrc; +} + + +static int tstClean(IVirtualBox *pVBox, IVirtualBoxClient *pClient) +{ + RT_NOREF(pClient); + HRESULT hrc = S_OK; + + // stop all machines created for the test + for (uint32_t i = 0; i < g_Args.numberMachines; i++) + { + ComPtr<IMachine> machine; + ComPtr<IProgress> progress; + ComPtr<ISession> session; + SafeIfaceArray<IMedium> media; + + Bstr machineName(tstMakeMachineName(i)); + + /* Delete created VM and its files */ + CHECK_ERROR_L(pVBox, FindMachine(machineName.raw(), machine.asOutParam())); + + // try to stop it again if it was not stopped + if (SUCCEEDED(hrc)) + { + MachineState_T machineState; + CHECK_ERROR_L(machine, COMGETTER(State)(&machineState)); + if ( SUCCEEDED(hrc) + && ( machineState == MachineState_Running + || machineState == MachineState_Paused) ) + { + hrc = session.createInprocObject(CLSID_Session); + if (SUCCEEDED(hrc)) + tstStopVM(pVBox, session, machineName, FALSE); + } + } + + if (SUCCEEDED(hrc)) + CHECK_ERROR_L(machine, Unregister(CleanupMode_DetachAllReturnHardDisksOnly, ComSafeArrayAsOutParam(media))); + if (SUCCEEDED(hrc)) + CHECK_ERROR_L(machine, DeleteConfig(ComSafeArrayAsInParam(media), progress.asOutParam())); + if (SUCCEEDED(hrc)) + CHECK_ERROR_L(progress, WaitForCompletion(-1)); + if (SUCCEEDED(hrc)) + RTPrintf("Machine '%ls' deleted.\n", machineName.raw()); + } + return hrc; +} + + +static DECLCALLBACK(int) tstThreadRun(RTTHREAD hThreadSelf, void *pvUser) +{ + RT_NOREF(hThreadSelf); + TestThreadArgs* args = (TestThreadArgs*)pvUser; + Assert(args != NULL); + uint32_t maxPackSize = args->machinesPackSize; + uint32_t percentage = args->percentsUnlok; + + HRESULT hrc = com::Initialize(); + if (SUCCEEDED(hrc)) + { + ComPtr<IVirtualBoxClient> ptrVBoxClient; + ComPtr<IVirtualBox> ptrVBox; + + hrc = TST_COM_EXPR(ptrVBoxClient.createInprocObject(CLSID_VirtualBoxClient)); + if (SUCCEEDED(hrc)) + hrc = TST_COM_EXPR(ptrVBoxClient->COMGETTER(VirtualBox)(ptrVBox.asOutParam())); + if (SUCCEEDED(hrc)) + { + RTPrintf("Creating machines...\n"); + tstCreateMachines(ptrVBox); + + while (g_RunTest) + { + hrc = tstMachinesPack(ptrVBox, maxPackSize, percentage); + } + + RTPrintf("Deleting machines...\n"); + tstClean(ptrVBox, ptrVBoxClient); + } + + g_RunTest = false; + RTSemEventSignal(g_PingEevent); + RTThreadSleep(100); + + ptrVBox = NULL; + ptrVBoxClient = NULL; + com::Shutdown(); + } + return hrc; +} + + +static int ParseArguments(int argc, char **argv, TestThreadArgs *pArgs) +{ + RTGETOPTSTATE GetState; + RTGETOPTUNION ValueUnion; + static const RTGETOPTDEF s_aOptions[] = + { + { "--packsize", 'p', RTGETOPT_REQ_UINT32 }, // number of machines to start together + { "--lock", 's', RTGETOPT_REQ_UINT32 }, // percentage of VM sessions closed without Unlok + { "--time", 't', RTGETOPT_REQ_UINT64 }, // required time of load test execution, in seconds + { "--machines" , 'u', RTGETOPT_REQ_UINT32 } + }; + int rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/); + AssertRCReturn(rc, rc); + AssertPtr(pArgs); + + while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0) + { + switch (rc) + { + case 'p': + if (ValueUnion.u32 == 0) + { + RTPrintf("--packsize should be more then zero\n"); + return VERR_INVALID_PARAMETER; + } + if (ValueUnion.u32 > 16000) + { + RTPrintf("maximum --packsize value is 16000.\n" + "That means can use no more then 16000 machines for the test.\n"); + return VERR_INVALID_PARAMETER; + } + pArgs->machinesPackSize = ValueUnion.u32; + break; + + case 's': + if (ValueUnion.u32 > 100) + { + RTPrintf("maximum --lock value is 100.\n" + "That means 100 percent of sessions should be closed without unlock.\n"); + return VERR_INVALID_PARAMETER; + } + pArgs->percentsUnlok = ValueUnion.u32; + break; + + case 't': + pArgs->cMsExecutionTime = ValueUnion.u64 * 1000; + break; + + case 'u': + if (ValueUnion.u32 > 16000) + { + RTPrintf("maximum --machines value is 16000.\n" + "That means can make no more then 16000 machines for the test.\n"); + return VERR_INVALID_PARAMETER; + } + if (ValueUnion.u32 < pArgs->machinesPackSize) + { + RTPrintf("--machines value should be larger then --packsize value.\n"); + return VERR_INVALID_PARAMETER; + } + pArgs->numberMachines = ValueUnion.u32; + break; + + default: + RTGetOptPrintError(rc, &ValueUnion); + return rc; + } + } + return rc; +} + +#endif /* RT_ARCH_AMD64 */ + + +/** + * + * Examples: + * - tstVBoxClientWatcherLoad --packsize 500 --lock 10 --time 14400 --machines 4000 + * It will create 4000 VMs with names "utmvm0"..."utmvm3999". It will start + * 500 random VMs together, stop them, without closing their session with + * probability 10%, will repeat this over 4 hours. After test it will + * delete all "utmvm..." machines. + * + * - tstVBoxClientWatcherLoad --packsize 1 --lock 30 --time 3600 --machines 1000 + * It will create 1000 VMs with names "utmvm0"..."utmvm999". It will start + * random VM - stop them, without closing their session with probability + * 30%, will repeat this over 30 minutes. After test it will delete all + * "utmvm..." machines. + */ +int main(int argc, char **argv) +{ + RT_NOREF(argc, argv); + RTEXITCODE rcExit = RTTestInitAndCreate("tstVBoxMultipleVM", &g_hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + SUPR3Init(NULL); + com::Initialize(); + RTTestBanner(g_hTest); + +#ifndef RT_ARCH_AMD64 + /* + * Linux OOM killer when running many VMs on a 32-bit host. + */ + return RTTestSkipAndDestroy(g_hTest, "The test can only run reliably on 64-bit hosts."); +#else /* RT_ARCH_AMD64 */ + + RTPrintf("Initializing ...\n"); + int rc = RTSemEventCreate(&g_PingEevent); + AssertRC(rc); + + g_Args.machinesPackSize = 100; + g_Args.percentsUnlok = 10; + g_Args.cMsExecutionTime = 3*RT_MS_1MIN; + g_Args.numberMachines = 200; + + /* + * Skip this test for the time being. Saw crashes on several test boxes but no time + * to debug. + */ + if (argc == 1) + return RTTestSkipAndDestroy(g_hTest, "Test crashes sometimes.\n"); + + rc = ParseArguments(argc, argv, &g_Args); + if (RT_FAILURE(rc)) + return RTTestSkipAndDestroy(g_hTest, "Invalid arguments.\n"); + + RTPrintf("Arguments packSize = %d, percentUnlok = %d, time = %lld.\n", + g_Args.machinesPackSize, g_Args.percentsUnlok, g_Args.cMsExecutionTime); + + RTTHREAD hThread; + rc = RTThreadCreate(&hThread, tstThreadRun, (void *)&g_Args, + 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstThreadRun"); + if (RT_SUCCESS(rc)) + { + AssertRC(rc); + + uint64_t msStart = RTTimeMilliTS(); + while (RTTimeMilliTS() - msStart < g_Args.cMsExecutionTime && g_RunTest) + { + // check that test thread didn't hang and call us periodically + // allowed 30 seconds for operation - msStart or stop VM + rc = RTSemEventWait(g_PingEevent, 3 * 60 * 1000); + if (RT_FAILURE(rc)) + { + if (rc == VERR_TIMEOUT) + { + RTTestFailed(g_hTest, "Timeout. Deadlock?\n"); + com::Shutdown(); + return RTTestSummaryAndDestroy(g_hTest); + } + AssertRC(rc); + } + } + + RTPrintf("Finishing...\n"); + + // finish test thread + g_RunTest = false; + // wait it for finish + RTThreadWait(hThread, RT_INDEFINITE_WAIT, &rc); + } + RTSemEventDestroy(g_PingEevent); + + com::Shutdown(); + if (RT_FAILURE(rc)) + RTTestFailed(g_hTest, "Test failed.\n"); + else + RTTestPassed(g_hTest, "Test finished.\n"); + return RTTestSummaryAndDestroy(g_hTest); +#endif /* RT_ARCH_AMD64 */ +} + |