diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/HostServices/GuestControl/testcase | |
parent | Initial commit. (diff) | |
download | virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip |
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/HostServices/GuestControl/testcase')
-rw-r--r-- | src/VBox/HostServices/GuestControl/testcase/Makefile.kmk | 46 | ||||
-rw-r--r-- | src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp | 272 |
2 files changed, 318 insertions, 0 deletions
diff --git a/src/VBox/HostServices/GuestControl/testcase/Makefile.kmk b/src/VBox/HostServices/GuestControl/testcase/Makefile.kmk new file mode 100644 index 00000000..ac513c7c --- /dev/null +++ b/src/VBox/HostServices/GuestControl/testcase/Makefile.kmk @@ -0,0 +1,46 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the Guest Control Host Service testcases. +# + +# +# Copyright (C) 2010-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBOX_ONLY_SDK) + + # Set this in LocalConfig.kmk if you are working on the guest property + # service to automatically run the testcase at build time. + # OTHERS += $(tstGuestControlSvc_0_OUTDIR)/tstGuestControlSvc.run + # + + PROGRAMS += tstGuestControlSvc + TESTING += $(tstGuestControlSvc_0_OUTDIR)/tstGuestControlSvc.run + tstGuestControlSvc_TEMPLATE = VBOXR3TSTEXE + # The second define here is to ensure that the testcase will run fast, + # without waiting for any thread synchronisation. + tstGuestControlSvc_DEFS = VBOX_WITH_HGCM VBOX_GUEST_CONTROL_TEST_NOTHREAD + tstGuestControlSvc_SOURCES = \ + ../VBoxGuestControlSvc.cpp \ + tstGuestControlSvc.cpp + tstGuestControlSvc_LIBS = $(LIB_RUNTIME) $(LIB_VMM) + +$$(tstGuestControlSvc_0_OUTDIR)/tstGuestControlSvc.run: $$(tstGuestControlSvc_1_STAGE_TARGET) + export VBOX_LOG_DEST=nofile; $(tstGuestControlSvc_1_STAGE_TARGET) quiet + $(QUIET)$(APPEND) -t "$@" "done" + +endif + +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp b/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp new file mode 100644 index 00000000..8f4dd460 --- /dev/null +++ b/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp @@ -0,0 +1,272 @@ +/* $Id: tstGuestControlSvc.cpp $ */ +/** @file + * Testcase for the guest control service. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/HostServices/GuestControlSvc.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <iprt/test.h> + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static RTTEST g_hTest = NIL_RTTEST; + +using namespace guestControl; + +extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable); + +/** Simple call handle structure for the guest call completion callback */ +struct VBOXHGCMCALLHANDLE_TYPEDEF +{ + /** Where to store the result code. */ + int32_t rc; +}; + +/** Call completion callback for guest calls. */ +static DECLCALLBACK(int) callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc) +{ + callHandle->rc = rc; + return VINF_SUCCESS; +} + +/** + * Initialise the HGCM service table as much as we need to start the + * service. + * + * @return IPRT status code. + * @param pTable the table to initialise + */ +int initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers) +{ + pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE); + pTable->u32Version = VBOX_HGCM_SVC_VERSION; + pHelpers->pfnCallComplete = callComplete; + pTable->pHelpers = pHelpers; + + return VINF_SUCCESS; +} + +typedef struct CMDHOST +{ + /** The HGCM command to execute. */ + int cmd; + /** Number of parameters. */ + int num_parms; + /** The actual parameters. */ + const PVBOXHGCMSVCPARM parms; + /** Flag indicating whether we need a connected client for this command. */ + bool fNeedsClient; + /** The desired return value from the host. */ + int rc; +} CMDHOST, *PCMDHOST; + +typedef struct CMDCLIENT +{ + /** The client's ID. */ + int client_id; + /** The HGCM command to execute. */ + int cmd; + /** Number of parameters. */ + int num_parms; + /** The actual parameters. */ + const PVBOXHGCMSVCPARM parms; + /** The desired return value from the host. */ + int rc; +} CMDCLIENT, *PCMDCLIENT; + +/** + * Tests the HOST_EXEC_CMD function. + * @returns iprt status value to indicate whether the test went as expected. + * @note prints its own diagnostic information to stdout. + */ +static int testHostCmd(const VBOXHGCMSVCFNTABLE *pTable, const PCMDHOST pCmd, uint32_t uNumTests) +{ + int rc = VINF_SUCCESS; + if (!VALID_PTR(pTable->pfnHostCall)) + { + RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Invalid pfnHostCall() pointer\n"); + rc = VERR_INVALID_POINTER; + } + if (RT_SUCCESS(rc)) + { + for (unsigned i = 0; (i < uNumTests) && RT_SUCCESS(rc); i++) + { + RTTestPrintf(g_hTest, RTTESTLVL_INFO, "Testing #%u (cmd: %d, num_parms: %d, parms: 0x%p\n", + i, pCmd[i].cmd, pCmd[i].num_parms, pCmd[i].parms); + + if (pCmd[i].fNeedsClient) + { + int client_rc = pTable->pfnConnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */, 0, false); + if (RT_FAILURE(client_rc)) + rc = client_rc; + } + + if (RT_SUCCESS(rc)) + { + int host_rc = pTable->pfnHostCall(pTable->pvService, + pCmd[i].cmd, + pCmd[i].num_parms, + pCmd[i].parms); + if (host_rc != pCmd[i].rc) + { + RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Host call test #%u returned with rc=%Rrc instead of rc=%Rrc\n", + i, host_rc, pCmd[i].rc); + rc = host_rc; + if (RT_SUCCESS(rc)) + rc = VERR_INVALID_PARAMETER; + } + + if (pCmd[i].fNeedsClient) + { + int client_rc = pTable->pfnDisconnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */); + if (RT_SUCCESS(rc)) + rc = client_rc; + } + } + } + } + return rc; +} + +static int testHost(const VBOXHGCMSVCFNTABLE *pTable) +{ + RTTestSub(g_hTest, "Testing host commands ..."); + + VBOXHGCMSVCPARM aParms[1]; + HGCMSvcSetU32(&aParms[0], 1000 /* Context ID */); + + CMDHOST aCmdHostAll[] = + { +#if 0 + /** No client connected. */ + { 1024 /* Not existing command */, 0, 0, false, VERR_NOT_FOUND }, + { -1 /* Invalid command */, 0, 0, false, VERR_NOT_FOUND }, + { HOST_CANCEL_PENDING_WAITS, 1024, 0, false, VERR_NOT_FOUND }, + { HOST_CANCEL_PENDING_WAITS, 0, &aParms[0], false, VERR_NOT_FOUND }, + + /** No client connected, valid command. */ + { HOST_CANCEL_PENDING_WAITS, 0, 0, false, VERR_NOT_FOUND }, + + /** Client connected, no parameters given. */ + { HOST_EXEC_SET_INPUT, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER }, + { 1024 /* Not existing command */, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER }, + { -1 /* Invalid command */, 0 /* No parameters given */, 0, true, VERR_INVALID_PARAMETER }, + + /** Client connected, valid parameters given. */ + { HOST_CANCEL_PENDING_WAITS, 0, 0, true, VINF_SUCCESS }, + { HOST_CANCEL_PENDING_WAITS, 1024, &aParms[0], true, VINF_SUCCESS }, + { HOST_CANCEL_PENDING_WAITS, 0, &aParms[0], true, VINF_SUCCESS}, +#endif + + /** Client connected, invalid parameters given. */ + { HOST_MSG_EXEC_CMD, 1024, 0, true, VERR_INVALID_POINTER }, + { HOST_MSG_EXEC_CMD, 1, 0, true, VERR_INVALID_POINTER }, + { HOST_MSG_EXEC_CMD, -1, 0, true, VERR_INVALID_POINTER }, + + /** Client connected, parameters given. */ + { HOST_MSG_CANCEL_PENDING_WAITS, 1, &aParms[0], true, VINF_SUCCESS }, + { HOST_MSG_EXEC_CMD, 1, &aParms[0], true, VINF_SUCCESS }, + { HOST_MSG_EXEC_SET_INPUT, 1, &aParms[0], true, VINF_SUCCESS }, + { HOST_MSG_EXEC_GET_OUTPUT, 1, &aParms[0], true, VINF_SUCCESS }, + + /** Client connected, unknown command + valid parameters given. */ + { -1, 1, &aParms[0], true, VINF_SUCCESS } + }; + + int rc = testHostCmd(pTable, &aCmdHostAll[0], RT_ELEMENTS(aCmdHostAll)); + RTTestSubDone(g_hTest); + return rc; +} + +static int testClient(const VBOXHGCMSVCFNTABLE *pTable) +{ + RTTestSub(g_hTest, "Testing client commands ..."); + + int rc = pTable->pfnConnect(pTable->pvService, 1 /* Client ID */, NULL /* pvClient */, 0, false); + if (RT_SUCCESS(rc)) + { + VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS }; + + /* No commands from host yet. */ + VBOXHGCMSVCPARM aParmsGuest[8]; + HGCMSvcSetU32(&aParmsGuest[0], 0 /* Msg type */); + HGCMSvcSetU32(&aParmsGuest[1], 0 /* Parameters */); + pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */, + GUEST_MSG_WAIT, 2, &aParmsGuest[0], 0); + RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VINF_SUCCESS, callHandle.rc); + + /* Host: Add a dummy command. */ + VBOXHGCMSVCPARM aParmsHost[8]; + HGCMSvcSetU32(&aParmsHost[0], 1000 /* Context ID */); + HGCMSvcSetStr(&aParmsHost[1], "foo.bar"); + HGCMSvcSetStr(&aParmsHost[2], "baz"); + + rc = pTable->pfnHostCall(pTable->pvService, HOST_MSG_EXEC_CMD, 3, &aParmsHost[0]); + RTTEST_CHECK_RC_RET(g_hTest, rc, VINF_SUCCESS, rc); + + /* Client: Disconnect again. */ + int rc2 = pTable->pfnDisconnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */); + if (RT_SUCCESS(rc)) + rc = rc2; + } + + RTTestSubDone(g_hTest); + return rc; +} + +/* + * Set environment variable "IPRT_TEST_MAX_LEVEL=all" to get more debug output! + */ +int main() +{ + RTEXITCODE rcExit = RTTestInitAndCreate("tstGuestControlSvc", &g_hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(g_hTest); + + /* Some host info. */ + RTTestIPrintf(RTTESTLVL_ALWAYS, "sizeof(void*)=%d\n", sizeof(void*)); + + /* Do the tests. */ + VBOXHGCMSVCFNTABLE svcTable; + VBOXHGCMSVCHELPERS svcHelpers; + RTTEST_CHECK_RC_RET(g_hTest, initTable(&svcTable, &svcHelpers), VINF_SUCCESS, 1); + + do + { + RTTESTI_CHECK_RC_BREAK(VBoxHGCMSvcLoad(&svcTable), VINF_SUCCESS); + + RTTESTI_CHECK_RC_BREAK(testHost(&svcTable), VINF_SUCCESS); + + RTTESTI_CHECK_RC_BREAK(svcTable.pfnUnload(svcTable.pvService), VINF_SUCCESS); + + RTTESTI_CHECK_RC_BREAK(VBoxHGCMSvcLoad(&svcTable), VINF_SUCCESS); + + RTTESTI_CHECK_RC_BREAK(testClient(&svcTable), VINF_SUCCESS); + + RTTESTI_CHECK_RC_BREAK(svcTable.pfnUnload(svcTable.pvService), VINF_SUCCESS); + + } while (0); + + return RTTestSummaryAndDestroy(g_hTest); +} + |