VirtualBox

source: vbox/trunk/src/VBox/HostServices/GuestControl/testcase/tstGuestControlSvc.cpp@ 37636

Last change on this file since 37636 was 36873, checked in by vboxsync, 13 years ago

HostServices/GuestCtrl: Rewritten testcase, now builds by default.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* $Id: tstGuestControlSvc.cpp 36873 2011-04-28 08:55:09Z vboxsync $ */
2/** @file
3 *
4 * Testcase for the guest control service.
5 */
6
7/*
8 * Copyright (C) 2011 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <VBox/HostServices/GuestControlSvc.h>
23#include <iprt/initterm.h>
24#include <iprt/stream.h>
25#include <iprt/test.h>
26
27#include "../gctrl.h"
28
29/*******************************************************************************
30* Global Variables *
31*******************************************************************************/
32static RTTEST g_hTest = NIL_RTTEST;
33
34using namespace guestControl;
35
36extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable);
37
38/** Simple call handle structure for the guest call completion callback */
39struct VBOXHGCMCALLHANDLE_TYPEDEF
40{
41 /** Where to store the result code. */
42 int32_t rc;
43};
44
45/** Call completion callback for guest calls. */
46static void callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
47{
48 callHandle->rc = rc;
49}
50
51/**
52 * Initialise the HGCM service table as much as we need to start the
53 * service.
54 *
55 * @return IPRT status.
56 * @param pTable the table to initialise
57 */
58int initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers)
59{
60 pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE);
61 pTable->u32Version = VBOX_HGCM_SVC_VERSION;
62 pHelpers->pfnCallComplete = callComplete;
63 pTable->pHelpers = pHelpers;
64
65 return VINF_SUCCESS;
66}
67
68typedef struct CMDHOST
69{
70 /** The HGCM command to execute. */
71 int cmd;
72 /** Number of parameters. */
73 int num_parms;
74 /** The actual parameters. */
75 const PVBOXHGCMSVCPARM parms;
76 /** Flag indicating whether we need a connected client for this command. */
77 bool fNeedsClient;
78 /** The desired return value from the host. */
79 int rc;
80} CMDHOST, *PCMDHOST;
81
82typedef struct CMDCLIENT
83{
84 /** The client's ID. */
85 int client_id;
86 /** The HGCM command to execute. */
87 int cmd;
88 /** Number of parameters. */
89 int num_parms;
90 /** The actual parameters. */
91 const PVBOXHGCMSVCPARM parms;
92 /** The desired return value from the host. */
93 int rc;
94} CMDCLIENT, *PCMDCLIENT;
95
96/**
97 * Tests the HOST_EXEC_CMD function.
98 * @returns iprt status value to indicate whether the test went as expected.
99 * @note prints its own diagnostic information to stdout.
100 */
101static int testHostCmd(const VBOXHGCMSVCFNTABLE *pTable, const PCMDHOST pCmd, uint32_t uNumTests)
102{
103 int rc = VINF_SUCCESS;
104 if (!VALID_PTR(pTable->pfnHostCall))
105 {
106 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Invalid pfnHostCall() pointer\n");
107 rc = VERR_INVALID_POINTER;
108 }
109 if (RT_SUCCESS(rc))
110 {
111 for (unsigned i = 0; (i < uNumTests) && RT_SUCCESS(rc); i++)
112 {
113 RTTestPrintf(g_hTest, RTTESTLVL_INFO, "Testing #%u (cmd: %d, num_parms: %d, parms: 0x%p\n",
114 i, pCmd[i].cmd, pCmd[i].num_parms, pCmd[i].parms);
115
116 if (pCmd[i].fNeedsClient)
117 {
118 int client_rc = pTable->pfnConnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */);
119 if (RT_FAILURE(client_rc))
120 rc = client_rc;
121 }
122
123 if (RT_SUCCESS(rc))
124 {
125 int host_rc = pTable->pfnHostCall(pTable->pvService,
126 pCmd[i].cmd,
127 pCmd[i].num_parms,
128 pCmd[i].parms);
129 if (host_rc != pCmd[i].rc)
130 {
131 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Host call test #%u returned with rc=%Rrc instead of rc=%Rrc\n",
132 i, host_rc, pCmd[i].rc);
133 rc = host_rc;
134 if (RT_SUCCESS(rc))
135 rc = VERR_INVALID_PARAMETER;
136 }
137
138 if (pCmd[i].fNeedsClient)
139 {
140 int client_rc = pTable->pfnDisconnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */);
141 if (RT_SUCCESS(rc))
142 rc = client_rc;
143 }
144 }
145 }
146 }
147 return rc;
148}
149
150static int testHost(const VBOXHGCMSVCFNTABLE *pTable)
151{
152 RTTestSub(g_hTest, "Testing host commands ...");
153
154 static VBOXHGCMSVCPARM s_aParms[1];
155 s_aParms[0].setUInt32(1000 /* Context ID */);
156
157 static CMDHOST s_aCmdHostAll[] =
158 {
159 /** No client connected, invalid command. */
160 { 1024 /* Not existing command */, 0, 0, false, VERR_NOT_SUPPORTED },
161 { -1 /* Invalid command */, 0, 0, false, VERR_NOT_SUPPORTED },
162 { HOST_CANCEL_PENDING_WAITS, 1024, 0, false, VERR_NOT_FOUND },
163 { HOST_CANCEL_PENDING_WAITS, 0, &s_aParms[0], false, VERR_NOT_FOUND },
164
165 /** No client connected, valid command. */
166 { HOST_CANCEL_PENDING_WAITS, 0, 0, false, VERR_NOT_FOUND },
167
168 /** Client connected. */
169 { 1024 /* Not existing command */, 0, 0, true, VERR_NOT_SUPPORTED },
170 { -1 /* Invalid command */, 0, 0, true, VERR_NOT_SUPPORTED },
171
172 /** Client connected, valid parameters given. */
173 { HOST_CANCEL_PENDING_WAITS, 0, 0, true, VINF_SUCCESS },
174 { HOST_CANCEL_PENDING_WAITS, 1024, &s_aParms[0], true, VINF_SUCCESS },
175 { HOST_CANCEL_PENDING_WAITS, 0, &s_aParms[0], true, VINF_SUCCESS},
176
177 /** Client connected, invalid parameters given. */
178 { HOST_CANCEL_PENDING_WAITS, 1024, 0, true, VERR_INVALID_POINTER },
179 { HOST_CANCEL_PENDING_WAITS, 1, 0, true, VERR_INVALID_POINTER },
180 { HOST_CANCEL_PENDING_WAITS, -1, 0, true, VERR_INVALID_POINTER },
181
182 /** Client connected, parameters given. */
183 { HOST_CANCEL_PENDING_WAITS, 1, &s_aParms[0], true, VINF_SUCCESS },
184 { HOST_EXEC_CMD, 1, &s_aParms[0], true, VINF_SUCCESS },
185 { HOST_EXEC_SET_INPUT, 1, &s_aParms[0], true, VINF_SUCCESS },
186 { HOST_EXEC_GET_OUTPUT, 1, &s_aParms[0], true, VINF_SUCCESS }
187 };
188
189 int rc = testHostCmd(pTable, &s_aCmdHostAll[0], RT_ELEMENTS(s_aCmdHostAll));
190 RTTestSubDone(g_hTest);
191 return rc;
192}
193
194static int testClient(const VBOXHGCMSVCFNTABLE *pTable)
195{
196 RTTestSub(g_hTest, "Testing client commands ...");
197
198 int rc = pTable->pfnConnect(pTable->pvService, 1 /* Client ID */, NULL /* pvClient */);
199 if (RT_SUCCESS(rc))
200 {
201 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
202
203 /* No commands from host yet. */
204 static VBOXHGCMSVCPARM s_aParmsGuest[8];
205 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
206 GUEST_GET_HOST_MSG, 2, &s_aParmsGuest[0]);
207 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VINF_SUCCESS, callHandle.rc);
208
209 /* Host: Add a dummy command. */
210 static VBOXHGCMSVCPARM s_aParmsHost[8];
211 s_aParmsHost[0].setUInt32(1000 /* Context ID */);
212 s_aParmsHost[1].setString("foo.bar");
213
214 rc = pTable->pfnHostCall(pTable->pvService, HOST_EXEC_CMD, 2, &s_aParmsHost[0]);
215 RTTEST_CHECK_RC_RET(g_hTest, rc, VINF_SUCCESS, rc);
216
217 /* Client: Get host command with a invalid parameter count specified. */
218 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
219 GUEST_GET_HOST_MSG, 1024, &s_aParmsGuest[0]);
220 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_INVALID_PARAMETER, callHandle.rc);
221 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
222 GUEST_GET_HOST_MSG, -1, &s_aParmsGuest[0]);
223 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_INVALID_PARAMETER, callHandle.rc);
224 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
225 GUEST_GET_HOST_MSG, -1, NULL);
226 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_INVALID_PARAMETER, callHandle.rc);
227 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
228 GUEST_GET_HOST_MSG, 16, NULL);
229 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_INVALID_PARAMETER, callHandle.rc);
230
231 /* Client: Get host command with a too small HGCM array. */
232 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
233 GUEST_GET_HOST_MSG, 0, &s_aParmsGuest[0]);
234 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_TOO_MUCH_DATA, callHandle.rc);
235 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
236 GUEST_GET_HOST_MSG, 1, &s_aParmsGuest[0]);
237 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_TOO_MUCH_DATA, callHandle.rc);
238
239 /* Client: Get host command without an allocated buffer. */
240 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
241 GUEST_GET_HOST_MSG, 2, &s_aParmsGuest[0]);
242 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VERR_BUFFER_OVERFLOW, callHandle.rc);
243
244 /* Client: Get host command, this time with a valid buffer. */
245 char szBuf[16];
246 s_aParmsGuest[1].setPointer(szBuf, sizeof(szBuf));
247 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
248 GUEST_GET_HOST_MSG, 2, &s_aParmsGuest[0]);
249 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VINF_SUCCESS, callHandle.rc);
250
251 /* Client: Now make sure there's no host message left anymore. */
252 pTable->pfnCall(pTable->pvService, &callHandle, 1 /* Client ID */, NULL /* pvClient */,
253 GUEST_GET_HOST_MSG, 2, &s_aParmsGuest[0]);
254 RTTEST_CHECK_RC_RET(g_hTest, callHandle.rc, VINF_SUCCESS, callHandle.rc);
255
256 /* Client: Disconnect again. */
257 int rc2 = pTable->pfnDisconnect(pTable->pvService, 1000 /* Client ID */, NULL /* pvClient */);
258 if (RT_SUCCESS(rc))
259 rc = rc2;
260 }
261
262 RTTestSubDone(g_hTest);
263 return rc;
264}
265
266/*
267 * Set environment variable "IPRT_TEST_MAX_LEVEL=all" to get more debug output!
268 */
269int main(int argc, char **argv)
270{
271 RTEXITCODE rcExit = RTTestInitAndCreate("tstGuestControlSvc", &g_hTest);
272 if (rcExit != RTEXITCODE_SUCCESS)
273 return rcExit;
274 RTTestBanner(g_hTest);
275
276 /* Some host info. */
277 RTTestIPrintf(RTTESTLVL_ALWAYS, "sizeof(void*)=%d\n", sizeof(void*));
278
279 /* Do the tests. */
280 VBOXHGCMSVCFNTABLE svcTable;
281 VBOXHGCMSVCHELPERS svcHelpers;
282 RTTEST_CHECK_RC_RET(g_hTest, initTable(&svcTable, &svcHelpers), VINF_SUCCESS, 1);
283
284 do
285 {
286 RTTESTI_CHECK_RC_BREAK(VBoxHGCMSvcLoad(&svcTable), VINF_SUCCESS);
287
288 RTTESTI_CHECK_RC_BREAK(testHost(&svcTable), VINF_SUCCESS);
289
290 RTTESTI_CHECK_RC_BREAK(svcTable.pfnUnload(svcTable.pvService), VINF_SUCCESS);
291
292 RTTESTI_CHECK_RC_BREAK(VBoxHGCMSvcLoad(&svcTable), VINF_SUCCESS);
293
294 RTTESTI_CHECK_RC_BREAK(testClient(&svcTable), VINF_SUCCESS);
295
296 RTTESTI_CHECK_RC_BREAK(svcTable.pfnUnload(svcTable.pvService), VINF_SUCCESS);
297
298 } while (0);
299
300 return RTTestSummaryAndDestroy(g_hTest);
301}
302
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette