VirtualBox

source: vbox/trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp@ 49950

Last change on this file since 49950 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 42.7 KB
Line 
1/* $Id: tstGuestPropSvc.cpp 44529 2013-02-04 15:54:15Z vboxsync $ */
2/** @file
3 *
4 * Testcase for the guest property service.
5 */
6
7/*
8 * Copyright (C) 2008-2012 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/GuestPropertySvc.h>
23#include <iprt/test.h>
24#include <iprt/time.h>
25
26
27/*******************************************************************************
28* Global Variables *
29*******************************************************************************/
30static RTTEST g_hTest = NIL_RTTEST;
31
32using namespace guestProp;
33
34extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable);
35
36/** Simple call handle structure for the guest call completion callback */
37struct VBOXHGCMCALLHANDLE_TYPEDEF
38{
39 /** Where to store the result code */
40 int32_t rc;
41};
42
43/** Call completion callback for guest calls. */
44static void callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
45{
46 callHandle->rc = rc;
47}
48
49/**
50 * Initialise the HGCM service table as much as we need to start the
51 * service
52 * @param pTable the table to initialise
53 */
54void initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers)
55{
56 pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE);
57 pTable->u32Version = VBOX_HGCM_SVC_VERSION;
58 pHelpers->pfnCallComplete = callComplete;
59 pTable->pHelpers = pHelpers;
60}
61
62/**
63 * A list of valid flag strings for testConvertFlags. The flag conversion
64 * functions should accept these and convert them from string to a flag type
65 * and back without errors.
66 */
67struct flagStrings
68{
69 /** Flag string in a format the functions should recognise */
70 const char *pcszIn;
71 /** How the functions should output the string again */
72 const char *pcszOut;
73}
74g_aValidFlagStrings[] =
75{
76 /* pcszIn, pcszOut */
77 { " ", "" },
78 { "transient, ", "TRANSIENT" },
79 { " rdOnLyHOST, transIENT , READONLY ", "TRANSIENT, READONLY" },
80 { " rdonlyguest", "RDONLYGUEST" },
81 { "rdonlyhost ", "RDONLYHOST" },
82 { "transient, transreset, rdonlyhost", "TRANSIENT, RDONLYHOST, TRANSRESET" },
83 { "transient, transreset, rdonlyguest", "TRANSIENT, RDONLYGUEST, TRANSRESET" }, /* max length */
84 { "rdonlyguest, rdonlyhost", "READONLY" },
85 { "transient, transreset, ", "TRANSIENT, TRANSRESET" }, /* Don't combine them ... */
86 { "transreset, ", "TRANSIENT, TRANSRESET" }, /* ... instead expand transreset for old adds. */
87};
88
89/**
90 * A list of invalid flag strings for testConvertFlags. The flag conversion
91 * functions should reject these.
92 */
93const char *g_apszInvalidFlagStrings[] =
94{
95 "RDONLYHOST,,",
96 " TRANSIENT READONLY"
97};
98
99/**
100 * Test the flag conversion functions.
101 * @returns iprt status value to indicate whether the test went as expected.
102 * @note prints its own diagnostic information to stdout.
103 */
104static void testConvertFlags(void)
105{
106 int rc = VINF_SUCCESS;
107 char *pszFlagBuffer = (char *)RTTestGuardedAllocTail(g_hTest, MAX_FLAGS_LEN);
108
109 RTTestISub("Conversion of valid flags strings");
110 for (unsigned i = 0; i < RT_ELEMENTS(g_aValidFlagStrings) && RT_SUCCESS(rc); ++i)
111 {
112 uint32_t fFlags;
113 rc = validateFlags(g_aValidFlagStrings[i].pcszIn, &fFlags);
114 if (RT_FAILURE(rc))
115 RTTestIFailed("Failed to validate flag string '%s'", g_aValidFlagStrings[i].pcszIn);
116 if (RT_SUCCESS(rc))
117 {
118 rc = writeFlags(fFlags, pszFlagBuffer);
119 if (RT_FAILURE(rc))
120 RTTestIFailed("Failed to convert flag string '%s' back to a string.",
121 g_aValidFlagStrings[i].pcszIn);
122 }
123 if (RT_SUCCESS(rc) && (strlen(pszFlagBuffer) > MAX_FLAGS_LEN - 1))
124 {
125 RTTestIFailed("String '%s' converts back to a flag string which is too long.\n",
126 g_aValidFlagStrings[i].pcszIn);
127 rc = VERR_TOO_MUCH_DATA;
128 }
129 if (RT_SUCCESS(rc) && (strcmp(pszFlagBuffer, g_aValidFlagStrings[i].pcszOut) != 0))
130 {
131 RTTestIFailed("String '%s' converts back to '%s' instead of to '%s'\n",
132 g_aValidFlagStrings[i].pcszIn, pszFlagBuffer,
133 g_aValidFlagStrings[i].pcszOut);
134 rc = VERR_PARSE_ERROR;
135 }
136 }
137 if (RT_SUCCESS(rc))
138 {
139 RTTestISub("Rejection of invalid flags strings");
140 for (unsigned i = 0; i < RT_ELEMENTS(g_apszInvalidFlagStrings) && RT_SUCCESS(rc); ++i)
141 {
142 uint32_t fFlags;
143 /* This is required to fail. */
144 if (RT_SUCCESS(validateFlags(g_apszInvalidFlagStrings[i], &fFlags)))
145 {
146 RTTestIFailed("String '%s' was incorrectly accepted as a valid flag string.\n",
147 g_apszInvalidFlagStrings[i]);
148 rc = VERR_PARSE_ERROR;
149 }
150 }
151 }
152 if (RT_SUCCESS(rc))
153 {
154 uint32_t u32BadFlags = ALLFLAGS << 1;
155 RTTestISub("Rejection of an invalid flags field");
156 /* This is required to fail. */
157 if (RT_SUCCESS(writeFlags(u32BadFlags, pszFlagBuffer)))
158 {
159 RTTestIFailed("Flags 0x%x were incorrectly written out as '%.*s'\n",
160 u32BadFlags, MAX_FLAGS_LEN, pszFlagBuffer);
161 rc = VERR_PARSE_ERROR;
162 }
163 }
164
165 RTTestGuardedFree(g_hTest, pszFlagBuffer);
166}
167
168/**
169 * List of property names for testSetPropsHost.
170 */
171const char *g_apcszNameBlock[] =
172{
173 "test/name/",
174 "test name",
175 "TEST NAME",
176 "/test/name",
177 NULL
178};
179
180/**
181 * List of property values for testSetPropsHost.
182 */
183const char *g_apcszValueBlock[] =
184{
185 "test/value/",
186 "test value",
187 "TEST VALUE",
188 "/test/value",
189 NULL
190};
191
192/**
193 * List of property timestamps for testSetPropsHost.
194 */
195uint64_t g_au64TimestampBlock[] =
196{
197 0, 999, 999999, UINT64_C(999999999999), 0
198};
199
200/**
201 * List of property flags for testSetPropsHost.
202 */
203const char *g_apcszFlagsBlock[] =
204{
205 "",
206 "readonly, transient",
207 "RDONLYHOST",
208 "RdOnlyGuest",
209 NULL
210};
211
212/**
213 * Test the SET_PROPS_HOST function.
214 * @returns iprt status value to indicate whether the test went as expected.
215 * @note prints its own diagnostic information to stdout.
216 */
217static void testSetPropsHost(VBOXHGCMSVCFNTABLE *ptable)
218{
219 RTTestISub("SET_PROPS_HOST");
220 RTTESTI_CHECK_RETV(RT_VALID_PTR(ptable->pfnHostCall));
221
222 VBOXHGCMSVCPARM aParms[4];
223 aParms[0].setPointer((void *)g_apcszNameBlock, 0);
224 aParms[1].setPointer((void *)g_apcszValueBlock, 0);
225 aParms[2].setPointer((void *)g_au64TimestampBlock, 0);
226 aParms[3].setPointer((void *)g_apcszFlagsBlock, 0);
227 RTTESTI_CHECK_RC(ptable->pfnHostCall(ptable->pvService, SET_PROPS_HOST, 4, &aParms[0]), VINF_SUCCESS);
228}
229
230/** Result strings for zeroth enumeration test */
231static const char *g_apchEnumResult0[] =
232{
233 "test/name/\0test/value/\0""0\0",
234 "test name\0test value\0""999\0TRANSIENT, READONLY",
235 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST",
236 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST",
237 NULL
238};
239
240/** Result string sizes for zeroth enumeration test */
241static const uint32_t g_acbEnumResult0[] =
242{
243 sizeof("test/name/\0test/value/\0""0\0"),
244 sizeof("test name\0test value\0""999\0TRANSIENT, READONLY"),
245 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"),
246 sizeof("/test/name\0/test/value\0""999999999999\0RDONLYGUEST"),
247 0
248};
249
250/**
251 * The size of the buffer returned by the zeroth enumeration test -
252 * the - 1 at the end is because of the hidden zero terminator
253 */
254static const uint32_t g_cbEnumBuffer0 =
255 sizeof("test/name/\0test/value/\0""0\0\0"
256 "test name\0test value\0""999\0TRANSIENT, READONLY\0"
257 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"
258 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1;
259
260/** Result strings for first and second enumeration test */
261static const char *g_apchEnumResult1[] =
262{
263 "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST",
264 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST",
265 NULL
266};
267
268/** Result string sizes for first and second enumeration test */
269static const uint32_t g_acbEnumResult1[] =
270{
271 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"),
272 sizeof("/test/name\0/test/value\0""999999999999\0RDONLYGUEST"),
273 0
274};
275
276/**
277 * The size of the buffer returned by the first enumeration test -
278 * the - 1 at the end is because of the hidden zero terminator
279 */
280static const uint32_t g_cbEnumBuffer1 =
281 sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"
282 "/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1;
283
284static const struct enumStringStruct
285{
286 /** The enumeration pattern to test */
287 const char *pszPatterns;
288 /** The size of the pattern string */
289 const uint32_t cchPatterns;
290 /** The expected enumeration output strings */
291 const char **papchResult;
292 /** The size of the output strings */
293 const uint32_t *pacchResult;
294 /** The size of the buffer needed for the enumeration */
295 const uint32_t cbBuffer;
296} g_aEnumStrings[] =
297{
298 {
299 "", sizeof(""),
300 g_apchEnumResult0,
301 g_acbEnumResult0,
302 g_cbEnumBuffer0
303 },
304 {
305 "/*\0?E*", sizeof("/*\0?E*"),
306 g_apchEnumResult1,
307 g_acbEnumResult1,
308 g_cbEnumBuffer1
309 },
310 {
311 "/*|?E*", sizeof("/*|?E*"),
312 g_apchEnumResult1,
313 g_acbEnumResult1,
314 g_cbEnumBuffer1
315 }
316};
317
318/**
319 * Test the ENUM_PROPS_HOST function.
320 * @returns iprt status value to indicate whether the test went as expected.
321 * @note prints its own diagnostic information to stdout.
322 */
323static void testEnumPropsHost(VBOXHGCMSVCFNTABLE *ptable)
324{
325 RTTestISub("ENUM_PROPS_HOST");
326 RTTESTI_CHECK_RETV(RT_VALID_PTR(ptable->pfnHostCall));
327
328 for (unsigned i = 0; i < RT_ELEMENTS(g_aEnumStrings); ++i)
329 {
330 VBOXHGCMSVCPARM aParms[3];
331 char abBuffer[2048];
332 RTTESTI_CHECK_RETV(g_aEnumStrings[i].cbBuffer < sizeof(abBuffer));
333
334 /* Check that we get buffer overflow with a too small buffer. */
335 aParms[0].setPointer((void *)g_aEnumStrings[i].pszPatterns, g_aEnumStrings[i].cchPatterns);
336 aParms[1].setPointer((void *)abBuffer, g_aEnumStrings[i].cbBuffer - 1);
337 memset(abBuffer, 0x55, sizeof(abBuffer));
338 int rc2 = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 3, aParms);
339 if (rc2 == VERR_BUFFER_OVERFLOW)
340 {
341 uint32_t cbNeeded;
342 RTTESTI_CHECK_RC(rc2 = aParms[2].getUInt32(&cbNeeded), VINF_SUCCESS);
343 if (RT_SUCCESS(rc2))
344 RTTESTI_CHECK_MSG(cbNeeded == g_aEnumStrings[i].cbBuffer,
345 ("expected %u, got %u, pattern %d\n", g_aEnumStrings[i].cbBuffer, cbNeeded, i));
346 }
347 else
348 RTTestIFailed("ENUM_PROPS_HOST returned %Rrc instead of VERR_BUFFER_OVERFLOW on too small buffer, pattern number %d.", rc2, i);
349
350 /* Make a successfull call. */
351 aParms[0].setPointer((void *)g_aEnumStrings[i].pszPatterns, g_aEnumStrings[i].cchPatterns);
352 aParms[1].setPointer((void *)abBuffer, g_aEnumStrings[i].cbBuffer);
353 memset(abBuffer, 0x55, sizeof(abBuffer));
354 rc2 = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST, 3, aParms);
355 if (rc2 == VINF_SUCCESS)
356 {
357 /* Look for each of the result strings in the buffer which was returned */
358 for (unsigned j = 0; g_aEnumStrings[i].papchResult[j] != NULL; ++j)
359 {
360 bool found = false;
361 for (unsigned k = 0; !found && k < g_aEnumStrings[i].cbBuffer
362 - g_aEnumStrings[i].pacchResult[j];
363 ++k)
364 if (memcmp(abBuffer + k, g_aEnumStrings[i].papchResult[j],
365 g_aEnumStrings[i].pacchResult[j]) == 0)
366 found = true;
367 if (!found)
368 RTTestIFailed("ENUM_PROPS_HOST did not produce the expected output for pattern %d.", i);
369 }
370 }
371 else
372 RTTestIFailed("ENUM_PROPS_HOST returned %Rrc instead of VINF_SUCCESS, pattern number %d.", rc2, i);
373 }
374}
375
376/**
377 * Set a property by calling the service
378 * @returns the status returned by the call to the service
379 *
380 * @param pTable the service instance handle
381 * @param pcszName the name of the property to set
382 * @param pcszValue the value to set the property to
383 * @param pcszFlags the flag string to set if one of the SET_PROP[_HOST]
384 * commands is used
385 * @param isHost whether the SET_PROP[_VALUE]_HOST commands should be
386 * used, rather than the guest ones
387 * @param useSetProp whether SET_PROP[_HOST] should be used rather than
388 * SET_PROP_VALUE[_HOST]
389 */
390int doSetProperty(VBOXHGCMSVCFNTABLE *pTable, const char *pcszName,
391 const char *pcszValue, const char *pcszFlags, bool isHost,
392 bool useSetProp)
393{
394 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
395 int command = SET_PROP_VALUE;
396 if (isHost)
397 {
398 if (useSetProp)
399 command = SET_PROP_HOST;
400 else
401 command = SET_PROP_VALUE_HOST;
402 }
403 else if (useSetProp)
404 command = SET_PROP;
405 VBOXHGCMSVCPARM aParms[3];
406 /* Work around silly constant issues - we ought to allow passing
407 * constant strings in the hgcm parameters. */
408 char szName[MAX_NAME_LEN];
409 char szValue[MAX_VALUE_LEN];
410 char szFlags[MAX_FLAGS_LEN];
411 RTStrPrintf(szName, sizeof(szName), "%s", pcszName);
412 RTStrPrintf(szValue, sizeof(szValue), "%s", pcszValue);
413 RTStrPrintf(szFlags, sizeof(szFlags), "%s", pcszFlags);
414 aParms[0].setString(szName);
415 aParms[1].setString(szValue);
416 aParms[2].setString(szFlags);
417 if (isHost)
418 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command,
419 useSetProp ? 3 : 2, aParms);
420 else
421 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command,
422 useSetProp ? 3 : 2, aParms);
423 return callHandle.rc;
424}
425
426/**
427 * Test the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST
428 * functions.
429 * @returns iprt status value to indicate whether the test went as expected.
430 * @note prints its own diagnostic information to stdout.
431 */
432static void testSetProp(VBOXHGCMSVCFNTABLE *pTable)
433{
434 RTTestISub("SET_PROP, _VALUE, _HOST, _VALUE_HOST");
435
436 /** Array of properties for testing SET_PROP_HOST and _GUEST. */
437 static const struct
438 {
439 /** Property name */
440 const char *pcszName;
441 /** Property value */
442 const char *pcszValue;
443 /** Property flags */
444 const char *pcszFlags;
445 /** Should this be set as the host or the guest? */
446 bool isHost;
447 /** Should we use SET_PROP or SET_PROP_VALUE? */
448 bool useSetProp;
449 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
450 bool isAllowed;
451 }
452 s_aSetProperties[] =
453 {
454 { "Red", "Stop!", "transient", false, true, true },
455 { "Amber", "Caution!", "", false, false, true },
456 { "Green", "Go!", "readonly", true, true, true },
457 { "Blue", "What on earth...?", "", true, false, true },
458 { "/test/name", "test", "", false, true, false },
459 { "TEST NAME", "test", "", true, true, false },
460 { "Green", "gone out...", "", false, false, false },
461 { "Green", "gone out...", "", true, false, false },
462 };
463
464 for (unsigned i = 0; i < RT_ELEMENTS(s_aSetProperties); ++i)
465 {
466 int rc = doSetProperty(pTable,
467 s_aSetProperties[i].pcszName,
468 s_aSetProperties[i].pcszValue,
469 s_aSetProperties[i].pcszFlags,
470 s_aSetProperties[i].isHost,
471 s_aSetProperties[i].useSetProp);
472 if (s_aSetProperties[i].isAllowed && RT_FAILURE(rc))
473 RTTestIFailed("Setting property '%s' failed with rc=%Rrc.",
474 s_aSetProperties[i].pcszName, rc);
475 else if ( !s_aSetProperties[i].isAllowed
476 && rc != VERR_PERMISSION_DENIED)
477 RTTestIFailed("Setting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.",
478 s_aSetProperties[i].pcszName, rc);
479 }
480}
481
482/**
483 * Delete a property by calling the service
484 * @returns the status returned by the call to the service
485 *
486 * @param pTable the service instance handle
487 * @param pcszName the name of the property to delete
488 * @param isHost whether the DEL_PROP_HOST command should be used, rather
489 * than the guest one
490 */
491static int doDelProp(VBOXHGCMSVCFNTABLE *pTable, const char *pcszName, bool isHost)
492{
493 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
494 int command = DEL_PROP;
495 if (isHost)
496 command = DEL_PROP_HOST;
497 VBOXHGCMSVCPARM aParms[1];
498 aParms[0].setString(pcszName);
499 if (isHost)
500 callHandle.rc = pTable->pfnHostCall(pTable->pvService, command, 1, aParms);
501 else
502 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command, 1, aParms);
503 return callHandle.rc;
504}
505
506/**
507 * Test the DEL_PROP, and DEL_PROP_HOST functions.
508 * @returns iprt status value to indicate whether the test went as expected.
509 * @note prints its own diagnostic information to stdout.
510 */
511static void testDelProp(VBOXHGCMSVCFNTABLE *pTable)
512{
513 RTTestISub("DEL_PROP, DEL_PROP_HOST");
514
515 /** Array of properties for testing DEL_PROP_HOST and _GUEST. */
516 static const struct
517 {
518 /** Property name */
519 const char *pcszName;
520 /** Should this be set as the host or the guest? */
521 bool isHost;
522 /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
523 bool isAllowed;
524 }
525 s_aDelProperties[] =
526 {
527 { "Red", false, true },
528 { "Amber", true, true },
529 { "Red2", false, true },
530 { "Amber2", true, true },
531 { "Green", false, false },
532 { "Green", true, false },
533 { "/test/name", false, false },
534 { "TEST NAME", true, false },
535 };
536
537 for (unsigned i = 0; i < RT_ELEMENTS(s_aDelProperties); ++i)
538 {
539 int rc = doDelProp(pTable, s_aDelProperties[i].pcszName,
540 s_aDelProperties[i].isHost);
541 if (s_aDelProperties[i].isAllowed && RT_FAILURE(rc))
542 RTTestIFailed("Deleting property '%s' failed with rc=%Rrc.",
543 s_aDelProperties[i].pcszName, rc);
544 else if ( !s_aDelProperties[i].isAllowed
545 && rc != VERR_PERMISSION_DENIED )
546 RTTestIFailed("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.",
547 s_aDelProperties[i].pcszName, rc);
548 }
549}
550
551/**
552 * Test the GET_PROP_HOST function.
553 * @returns iprt status value to indicate whether the test went as expected.
554 * @note prints its own diagnostic information to stdout.
555 */
556static void testGetProp(VBOXHGCMSVCFNTABLE *pTable)
557{
558 RTTestISub("GET_PROP_HOST");
559
560 /** Array of properties for testing GET_PROP_HOST. */
561 static const struct
562 {
563 /** Property name */
564 const char *pcszName;
565 /** What value/flags pattern do we expect back? */
566 const char *pchValue;
567 /** What size should the value/flags array be? */
568 uint32_t cchValue;
569 /** Should this property exist? */
570 bool exists;
571 /** Do we expect a particular timestamp? */
572 bool hasTimestamp;
573 /** What timestamp if any do ex expect? */
574 uint64_t u64Timestamp;
575 }
576 s_aGetProperties[] =
577 {
578 { "test/name/", "test/value/\0", sizeof("test/value/\0"), true, true, 0 },
579 { "test name", "test value\0TRANSIENT, READONLY",
580 sizeof("test value\0TRANSIENT, READONLY"), true, true, 999 },
581 { "TEST NAME", "TEST VALUE\0RDONLYHOST", sizeof("TEST VALUE\0RDONLYHOST"),
582 true, true, 999999 },
583 { "/test/name", "/test/value\0RDONLYGUEST",
584 sizeof("/test/value\0RDONLYGUEST"), true, true, UINT64_C(999999999999) },
585 { "Green", "Go!\0READONLY", sizeof("Go!\0READONLY"), true, false, 0 },
586 { "Blue", "What on earth...?\0", sizeof("What on earth...?\0"), true,
587 false, 0 },
588 { "Red", "", 0, false, false, 0 },
589 };
590
591 for (unsigned i = 0; i < RT_ELEMENTS(s_aGetProperties); ++i)
592 {
593 VBOXHGCMSVCPARM aParms[4];
594 /* Work around silly constant issues - we ought to allow passing
595 * constant strings in the hgcm parameters. */
596 char szBuffer[MAX_VALUE_LEN + MAX_FLAGS_LEN];
597 RTTESTI_CHECK_RETV(s_aGetProperties[i].cchValue < sizeof(szBuffer));
598
599 aParms[0].setString(s_aGetProperties[i].pcszName);
600 memset(szBuffer, 0x55, sizeof(szBuffer));
601 aParms[1].setPointer(szBuffer, sizeof(szBuffer));
602 int rc2 = pTable->pfnHostCall(pTable->pvService, GET_PROP_HOST, 4, aParms);
603
604 if (s_aGetProperties[i].exists && RT_FAILURE(rc2))
605 {
606 RTTestIFailed("Getting property '%s' failed with rc=%Rrc.",
607 s_aGetProperties[i].pcszName, rc2);
608 continue;
609 }
610
611 if (!s_aGetProperties[i].exists && rc2 != VERR_NOT_FOUND)
612 {
613 RTTestIFailed("Getting property '%s' returned %Rrc instead of VERR_NOT_FOUND.",
614 s_aGetProperties[i].pcszName, rc2);
615 continue;
616 }
617
618 if (s_aGetProperties[i].exists)
619 {
620 AssertRC(rc2);
621
622 uint32_t u32ValueLen = UINT32_MAX;
623 RTTESTI_CHECK_RC(rc2 = aParms[3].getUInt32(&u32ValueLen), VINF_SUCCESS);
624 if (RT_SUCCESS(rc2))
625 {
626 RTTESTI_CHECK_MSG(u32ValueLen <= sizeof(szBuffer), ("u32ValueLen=%d", u32ValueLen));
627 if (memcmp(szBuffer, s_aGetProperties[i].pchValue, s_aGetProperties[i].cchValue) != 0)
628 RTTestIFailed("Unexpected result '%.*s' for property '%s', expected '%.*s'.",
629 u32ValueLen, szBuffer, s_aGetProperties[i].pcszName,
630 s_aGetProperties[i].cchValue, s_aGetProperties[i].pchValue);
631 }
632
633 if (s_aGetProperties[i].hasTimestamp)
634 {
635 uint64_t u64Timestamp = UINT64_MAX;
636 RTTESTI_CHECK_RC(rc2 = aParms[2].getUInt64(&u64Timestamp), VINF_SUCCESS);
637 if (u64Timestamp != s_aGetProperties[i].u64Timestamp)
638 RTTestIFailed("Bad timestamp %llu for property '%s', expected %llu.",
639 u64Timestamp, s_aGetProperties[i].pcszName,
640 s_aGetProperties[i].u64Timestamp);
641 }
642 }
643 }
644}
645
646/** Array of properties for testing GET_PROP_HOST. */
647static const struct
648{
649 /** Buffer returned */
650 const char *pchBuffer;
651 /** What size should the buffer be? */
652 uint32_t cbBuffer;
653}
654g_aGetNotifications[] =
655{
656 { "Red\0Stop!\0TRANSIENT", sizeof("Red\0Stop!\0TRANSIENT") },
657 { "Amber\0Caution!\0", sizeof("Amber\0Caution!\0") },
658 { "Green\0Go!\0READONLY", sizeof("Green\0Go!\0READONLY") },
659 { "Blue\0What on earth...?\0", sizeof("Blue\0What on earth...?\0") },
660 { "Red\0\0", sizeof("Red\0\0") },
661 { "Amber\0\0", sizeof("Amber\0\0") },
662};
663
664/**
665 * Test the GET_NOTIFICATION function.
666 * @returns iprt status value to indicate whether the test went as expected.
667 * @note prints its own diagnostic information to stdout.
668 */
669static void testGetNotification(VBOXHGCMSVCFNTABLE *pTable)
670{
671 RTTestISub("GET_NOTIFICATION");
672
673 /* Test "buffer too small" */
674 static char s_szPattern[] = "";
675 VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
676 VBOXHGCMSVCPARM aParms[4];
677 uint32_t cbRetNeeded;
678
679 for (uint32_t cbBuf = 1;
680 cbBuf < g_aGetNotifications[0].cbBuffer - 1;
681 cbBuf++)
682 {
683 void *pvBuf = RTTestGuardedAllocTail(g_hTest, cbBuf);
684 RTTESTI_CHECK_BREAK(pvBuf);
685 memset(pvBuf, 0x55, cbBuf);
686
687 aParms[0].setPointer((void *)s_szPattern, sizeof(s_szPattern));
688 aParms[1].setUInt64(1);
689 aParms[2].setPointer(pvBuf, cbBuf);
690 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, GET_NOTIFICATION, 4, aParms);
691
692 if ( callHandle.rc != VERR_BUFFER_OVERFLOW
693 || RT_FAILURE(aParms[3].getUInt32(&cbRetNeeded))
694 || cbRetNeeded != g_aGetNotifications[0].cbBuffer
695 )
696 {
697 RTTestIFailed("Getting notification for property '%s' with a too small buffer did not fail correctly: %Rrc",
698 g_aGetNotifications[0].pchBuffer, callHandle.rc);
699 }
700 RTTestGuardedFree(g_hTest, pvBuf);
701 }
702
703 /* Test successful notification queries. Start with an unknown timestamp
704 * to get the oldest available notification. */
705 uint64_t u64Timestamp = 1;
706 for (unsigned i = 0; i < RT_ELEMENTS(g_aGetNotifications); ++i)
707 {
708 uint32_t cbBuf = g_aGetNotifications[i].cbBuffer + _1K;
709 void *pvBuf = RTTestGuardedAllocTail(g_hTest, cbBuf);
710 RTTESTI_CHECK_BREAK(pvBuf);
711 memset(pvBuf, 0x55, cbBuf);
712
713 aParms[0].setPointer((void *)s_szPattern, sizeof(s_szPattern));
714 aParms[1].setUInt64(u64Timestamp);
715 aParms[2].setPointer(pvBuf, cbBuf);
716 pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, GET_NOTIFICATION, 4, aParms);
717 if ( RT_FAILURE(callHandle.rc)
718 || (i == 0 && callHandle.rc != VWRN_NOT_FOUND)
719 || RT_FAILURE(aParms[1].getUInt64(&u64Timestamp))
720 || RT_FAILURE(aParms[3].getUInt32(&cbRetNeeded))
721 || cbRetNeeded != g_aGetNotifications[i].cbBuffer
722 || memcmp(pvBuf, g_aGetNotifications[i].pchBuffer, cbRetNeeded) != 0
723 )
724 {
725 RTTestIFailed("Failed to get notification for property '%s' (rc=%Rrc).",
726 g_aGetNotifications[i].pchBuffer, callHandle.rc);
727 }
728 RTTestGuardedFree(g_hTest, pvBuf);
729 }
730}
731
732/** Parameters for the asynchronous guest notification call */
733struct asyncNotification_
734{
735 /** Call parameters */
736 VBOXHGCMSVCPARM aParms[4];
737 /** Result buffer */
738 char abBuffer[MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN];
739 /** Return value */
740 VBOXHGCMCALLHANDLE_TYPEDEF callHandle;
741} g_AsyncNotification;
742
743/**
744 * Set up the test for the asynchronous GET_NOTIFICATION function.
745 */
746static void setupAsyncNotification(VBOXHGCMSVCFNTABLE *pTable)
747{
748 RTTestISub("Async GET_NOTIFICATION without notifications");
749 static char s_szPattern[] = "";
750
751 g_AsyncNotification.aParms[0].setPointer((void *)s_szPattern, sizeof(s_szPattern));
752 g_AsyncNotification.aParms[1].setUInt64(0);
753 g_AsyncNotification.aParms[2].setPointer((void *)g_AsyncNotification.abBuffer,
754 sizeof(g_AsyncNotification.abBuffer));
755 g_AsyncNotification.callHandle.rc = VINF_HGCM_ASYNC_EXECUTE;
756 pTable->pfnCall(pTable->pvService, &g_AsyncNotification.callHandle, 0, NULL,
757 GET_NOTIFICATION, 4, g_AsyncNotification.aParms);
758 if (RT_FAILURE(g_AsyncNotification.callHandle.rc))
759 RTTestIFailed("GET_NOTIFICATION call failed, rc=%Rrc.", g_AsyncNotification.callHandle.rc);
760 else if (g_AsyncNotification.callHandle.rc != VINF_HGCM_ASYNC_EXECUTE)
761 RTTestIFailed("GET_NOTIFICATION call completed when no new notifications should be available.");
762}
763
764/**
765 * Test the asynchronous GET_NOTIFICATION function.
766 */
767static void testAsyncNotification(VBOXHGCMSVCFNTABLE *pTable)
768{
769 uint64_t u64Timestamp;
770 uint32_t u32Size;
771 if ( g_AsyncNotification.callHandle.rc != VINF_SUCCESS
772 || RT_FAILURE(g_AsyncNotification.aParms[1].getUInt64(&u64Timestamp))
773 || RT_FAILURE(g_AsyncNotification.aParms[3].getUInt32(&u32Size))
774 || u32Size != g_aGetNotifications[0].cbBuffer
775 || memcmp(g_AsyncNotification.abBuffer, g_aGetNotifications[0].pchBuffer, u32Size) != 0
776 )
777 {
778 RTTestIFailed("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc.",
779 g_AsyncNotification.callHandle.rc);
780 }
781}
782
783
784static void test2(void)
785{
786 VBOXHGCMSVCFNTABLE svcTable;
787 VBOXHGCMSVCHELPERS svcHelpers;
788 initTable(&svcTable, &svcHelpers);
789
790 /* The function is inside the service, not HGCM. */
791 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(&svcTable));
792
793 testSetPropsHost(&svcTable);
794 testEnumPropsHost(&svcTable);
795
796 /* Set up the asynchronous notification test */
797 setupAsyncNotification(&svcTable);
798 testSetProp(&svcTable);
799 RTTestISub("Async notification call data");
800 testAsyncNotification(&svcTable); /* Our previous notification call should have completed by now. */
801
802 testDelProp(&svcTable);
803 testGetProp(&svcTable);
804 testGetNotification(&svcTable);
805
806 /* Cleanup */
807 RTTESTI_CHECK_RC_OK(svcTable.pfnUnload(svcTable.pvService));
808}
809
810/**
811 * Set the global flags value by calling the service
812 * @returns the status returned by the call to the service
813 *
814 * @param pTable the service instance handle
815 * @param eFlags the flags to set
816 */
817static int doSetGlobalFlags(VBOXHGCMSVCFNTABLE *pTable, ePropFlags eFlags)
818{
819 VBOXHGCMSVCPARM paParm;
820 paParm.setUInt32(eFlags);
821 int rc = pTable->pfnHostCall(pTable->pvService, SET_GLOBAL_FLAGS_HOST, 1, &paParm);
822 if (RT_FAILURE(rc))
823 {
824 char szFlags[MAX_FLAGS_LEN];
825 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
826 RTTestIFailed("Failed to set the global flags.");
827 else
828 RTTestIFailed("Failed to set the global flags \"%s\".", szFlags);
829 }
830 return rc;
831}
832
833/**
834 * Test the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST
835 * functions.
836 * @returns iprt status value to indicate whether the test went as expected.
837 * @note prints its own diagnostic information to stdout.
838 */
839static void testSetPropROGuest(VBOXHGCMSVCFNTABLE *pTable)
840{
841 RTTestISub("global READONLYGUEST and SET_PROP*");
842
843 /** Array of properties for testing SET_PROP_HOST and _GUEST with the
844 * READONLYGUEST global flag set. */
845 static const struct
846 {
847 /** Property name */
848 const char *pcszName;
849 /** Property value */
850 const char *pcszValue;
851 /** Property flags */
852 const char *pcszFlags;
853 /** Should this be set as the host or the guest? */
854 bool isHost;
855 /** Should we use SET_PROP or SET_PROP_VALUE? */
856 bool useSetProp;
857 /** Should this succeed or be rejected with VERR_ (NOT VINF_!)
858 * PERMISSION_DENIED? The global check is done after the property one. */
859 bool isAllowed;
860 }
861 s_aSetPropertiesROGuest[] =
862 {
863 { "Red", "Stop!", "transient", false, true, true },
864 { "Amber", "Caution!", "", false, false, true },
865 { "Green", "Go!", "readonly", true, true, true },
866 { "Blue", "What on earth...?", "", true, false, true },
867 { "/test/name", "test", "", false, true, true },
868 { "TEST NAME", "test", "", true, true, true },
869 { "Green", "gone out...", "", false, false, false },
870 { "Green", "gone out....", "", true, false, false },
871 };
872
873 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(pTable));
874 int rc = doSetGlobalFlags(pTable, RDONLYGUEST);
875 if (RT_SUCCESS(rc))
876 {
877 for (unsigned i = 0; i < RT_ELEMENTS(s_aSetPropertiesROGuest); ++i)
878 {
879 rc = doSetProperty(pTable, s_aSetPropertiesROGuest[i].pcszName,
880 s_aSetPropertiesROGuest[i].pcszValue,
881 s_aSetPropertiesROGuest[i].pcszFlags,
882 s_aSetPropertiesROGuest[i].isHost,
883 s_aSetPropertiesROGuest[i].useSetProp);
884 if (s_aSetPropertiesROGuest[i].isAllowed && RT_FAILURE(rc))
885 RTTestIFailed("Setting property '%s' to '%s' failed with rc=%Rrc.",
886 s_aSetPropertiesROGuest[i].pcszName,
887 s_aSetPropertiesROGuest[i].pcszValue, rc);
888 else if ( !s_aSetPropertiesROGuest[i].isAllowed
889 && rc != VERR_PERMISSION_DENIED)
890 RTTestIFailed("Setting property '%s' to '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
891 s_aSetPropertiesROGuest[i].pcszName,
892 s_aSetPropertiesROGuest[i].pcszValue, rc);
893 else if ( !s_aSetPropertiesROGuest[i].isHost
894 && s_aSetPropertiesROGuest[i].isAllowed
895 && rc != VINF_PERMISSION_DENIED)
896 RTTestIFailed("Setting property '%s' to '%s' returned %Rrc instead of VINF_PERMISSION_DENIED.\n",
897 s_aSetPropertiesROGuest[i].pcszName,
898 s_aSetPropertiesROGuest[i].pcszValue, rc);
899 }
900 }
901 RTTESTI_CHECK_RC_OK(pTable->pfnUnload(pTable->pvService));
902}
903
904/**
905 * Test the DEL_PROP, and DEL_PROP_HOST functions.
906 * @returns iprt status value to indicate whether the test went as expected.
907 * @note prints its own diagnostic information to stdout.
908 */
909static void testDelPropROGuest(VBOXHGCMSVCFNTABLE *pTable)
910{
911 RTTestISub("global READONLYGUEST and DEL_PROP*");
912
913 /** Array of properties for testing DEL_PROP_HOST and _GUEST with
914 * READONLYGUEST set globally. */
915 static const struct
916 {
917 /** Property name */
918 const char *pcszName;
919 /** Should this be deleted as the host (or the guest)? */
920 bool isHost;
921 /** Should this property be created first? (As host, obviously) */
922 bool shouldCreate;
923 /** And with what flags? */
924 const char *pcszFlags;
925 /** Should this succeed or be rejected with VERR_ (NOT VINF_!)
926 * PERMISSION_DENIED? The global check is done after the property one. */
927 bool isAllowed;
928 }
929 s_aDelPropertiesROGuest[] =
930 {
931 { "Red", true, true, "", true },
932 { "Amber", false, true, "", true },
933 { "Red2", true, false, "", true },
934 { "Amber2", false, false, "", true },
935 { "Red3", true, true, "READONLY", false },
936 { "Amber3", false, true, "READONLY", false },
937 { "Red4", true, true, "RDONLYHOST", false },
938 { "Amber4", false, true, "RDONLYHOST", true },
939 };
940
941 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(pTable));
942 int rc = doSetGlobalFlags(pTable, RDONLYGUEST);
943 if (RT_SUCCESS(rc))
944 {
945 for (unsigned i = 0; i < RT_ELEMENTS(s_aDelPropertiesROGuest); ++i)
946 {
947 if (s_aDelPropertiesROGuest[i].shouldCreate)
948 rc = doSetProperty(pTable, s_aDelPropertiesROGuest[i].pcszName,
949 "none", s_aDelPropertiesROGuest[i].pcszFlags,
950 true, true);
951 rc = doDelProp(pTable, s_aDelPropertiesROGuest[i].pcszName,
952 s_aDelPropertiesROGuest[i].isHost);
953 if (s_aDelPropertiesROGuest[i].isAllowed && RT_FAILURE(rc))
954 RTTestIFailed("Deleting property '%s' failed with rc=%Rrc.",
955 s_aDelPropertiesROGuest[i].pcszName, rc);
956 else if ( !s_aDelPropertiesROGuest[i].isAllowed
957 && rc != VERR_PERMISSION_DENIED)
958 RTTestIFailed("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.",
959 s_aDelPropertiesROGuest[i].pcszName, rc);
960 else if ( !s_aDelPropertiesROGuest[i].isHost
961 && s_aDelPropertiesROGuest[i].shouldCreate
962 && s_aDelPropertiesROGuest[i].isAllowed
963 && rc != VINF_PERMISSION_DENIED)
964 RTTestIFailed("Deleting property '%s' as guest returned %Rrc instead of VINF_PERMISSION_DENIED.",
965 s_aDelPropertiesROGuest[i].pcszName, rc);
966 }
967 }
968 RTTESTI_CHECK_RC_OK(pTable->pfnUnload(pTable->pvService));
969}
970
971static void test3(void)
972{
973 VBOXHGCMSVCFNTABLE svcTable;
974 VBOXHGCMSVCHELPERS svcHelpers;
975 initTable(&svcTable, &svcHelpers);
976 testSetPropROGuest(&svcTable);
977 testDelPropROGuest(&svcTable);
978}
979
980static void test4(void)
981{
982 RTTestISub("GET_PROP_HOST buffer handling");
983
984 VBOXHGCMSVCFNTABLE svcTable;
985 VBOXHGCMSVCHELPERS svcHelpers;
986 initTable(&svcTable, &svcHelpers);
987 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(&svcTable));
988
989 /* Insert a property that we can mess around with. */
990 static char const s_szProp[] = "/MyProperties/Sub/Sub/Sub/Sub/Sub/Sub/Sub/Property";
991 static char const s_szValue[] = "Property Value";
992 RTTESTI_CHECK_RC_OK(doSetProperty(&svcTable, s_szProp, s_szValue, "", true, true));
993
994
995 /* Get the value with buffer sizes up to 1K. */
996 for (unsigned iVariation = 0; iVariation < 2; iVariation++)
997 {
998 for (uint32_t cbBuf = 0; cbBuf < _1K; cbBuf++)
999 {
1000 void *pvBuf;
1001 RTTESTI_CHECK_RC_BREAK(RTTestGuardedAlloc(g_hTest, cbBuf, 1, iVariation == 0, &pvBuf), VINF_SUCCESS);
1002
1003 VBOXHGCMSVCPARM aParms[4];
1004 aParms[0].setString(s_szProp);
1005 aParms[1].setPointer(pvBuf, cbBuf);
1006 int rc = svcTable.pfnHostCall(svcTable.pvService, GET_PROP_HOST, RT_ELEMENTS(aParms), aParms);
1007
1008 RTTestGuardedFree(g_hTest, pvBuf);
1009 }
1010 }
1011
1012 /* Done. */
1013 RTTESTI_CHECK_RC_OK(svcTable.pfnUnload(svcTable.pvService));
1014}
1015
1016static void test5(void)
1017{
1018 RTTestISub("ENUM_PROPS_HOST buffer handling");
1019
1020 VBOXHGCMSVCFNTABLE svcTable;
1021 VBOXHGCMSVCHELPERS svcHelpers;
1022 initTable(&svcTable, &svcHelpers);
1023 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(&svcTable));
1024
1025 /* Insert a few property that we can mess around with. */
1026 RTTESTI_CHECK_RC_OK(doSetProperty(&svcTable, "/MyProperties/Sub/Sub/Sub/Sub/Sub/Sub/Sub/Property", "Property Value", "", true, true));
1027 RTTESTI_CHECK_RC_OK(doSetProperty(&svcTable, "/MyProperties/12357", "83848569", "", true, true));
1028 RTTESTI_CHECK_RC_OK(doSetProperty(&svcTable, "/MyProperties/56678", "abcdefghijklm", "", true, true));
1029 RTTESTI_CHECK_RC_OK(doSetProperty(&svcTable, "/MyProperties/932769", "n", "", true, true));
1030
1031 /* Get the value with buffer sizes up to 1K. */
1032 for (unsigned iVariation = 0; iVariation < 2; iVariation++)
1033 {
1034 for (uint32_t cbBuf = 0; cbBuf < _1K; cbBuf++)
1035 {
1036 void *pvBuf;
1037 RTTESTI_CHECK_RC_BREAK(RTTestGuardedAlloc(g_hTest, cbBuf, 1, iVariation == 0, &pvBuf), VINF_SUCCESS);
1038
1039 VBOXHGCMSVCPARM aParms[3];
1040 aParms[0].setString("*");
1041 aParms[1].setPointer(pvBuf, cbBuf);
1042 int rc2 = svcTable.pfnHostCall(svcTable.pvService, ENUM_PROPS_HOST, RT_ELEMENTS(aParms), aParms);
1043
1044 RTTestGuardedFree(g_hTest, pvBuf);
1045 }
1046 }
1047
1048 /* Done. */
1049 RTTESTI_CHECK_RC_OK(svcTable.pfnUnload(svcTable.pvService));
1050}
1051
1052static void test6(void)
1053{
1054 RTTestISub("Max properties");
1055
1056 VBOXHGCMSVCFNTABLE svcTable;
1057 VBOXHGCMSVCHELPERS svcHelpers;
1058 initTable(&svcTable, &svcHelpers);
1059 RTTESTI_CHECK_RC_OK_RETV(VBoxHGCMSvcLoad(&svcTable));
1060
1061 /* Insert the max number of properties. */
1062 static char const s_szPropFmt[] = "/MyProperties/Sub/Sub/Sub/Sub/Sub/Sub/Sub/PropertyNo#%u";
1063 char szProp[80];
1064 unsigned cProps = 0;
1065 for (;;)
1066 {
1067 RTStrPrintf(szProp, sizeof(szProp), s_szPropFmt, cProps);
1068 int rc = doSetProperty(&svcTable, szProp, "myvalue", "", true, true);
1069 if (rc == VERR_TOO_MUCH_DATA)
1070 break;
1071 if (RT_FAILURE(rc))
1072 {
1073 RTTestIFailed("Unexpected error %Rrc setting property number %u", rc, cProps);
1074 break;
1075 }
1076 cProps++;
1077 }
1078 RTTestIValue("Max Properties", cProps, RTTESTUNIT_OCCURRENCES);
1079
1080 /* Touch them all again. */
1081 for (unsigned iProp = 0; iProp < cProps; iProp++)
1082 {
1083 RTStrPrintf(szProp, sizeof(szProp), s_szPropFmt, iProp);
1084 int rc;
1085 RTTESTI_CHECK_MSG((rc = doSetProperty(&svcTable, szProp, "myvalue", "", true, true)) == VINF_SUCCESS,
1086 ("%Rrc - #%u\n", rc, iProp));
1087 RTTESTI_CHECK_MSG((rc = doSetProperty(&svcTable, szProp, "myvalue", "", true, false)) == VINF_SUCCESS,
1088 ("%Rrc - #%u\n", rc, iProp));
1089 RTTESTI_CHECK_MSG((rc = doSetProperty(&svcTable, szProp, "myvalue", "", false, true)) == VINF_SUCCESS,
1090 ("%Rrc - #%u\n", rc, iProp));
1091 RTTESTI_CHECK_MSG((rc = doSetProperty(&svcTable, szProp, "myvalue", "", false, false)) == VINF_SUCCESS,
1092 ("%Rrc - #%u\n", rc, iProp));
1093 }
1094
1095 /* Benchmark. */
1096 uint64_t cNsMax = 0;
1097 uint64_t cNsMin = UINT64_MAX;
1098 uint64_t cNsAvg = 0;
1099 for (unsigned iProp = 0; iProp < cProps; iProp++)
1100 {
1101 size_t cchProp = RTStrPrintf(szProp, sizeof(szProp), s_szPropFmt, iProp);
1102
1103 uint64_t cNsElapsed = RTTimeNanoTS();
1104 unsigned iCall;
1105 for (iCall = 0; iCall < 1000; iCall++)
1106 {
1107 VBOXHGCMSVCPARM aParms[4];
1108 char szBuffer[256];
1109 aParms[0].setPointer(szProp, cchProp + 1);
1110 aParms[1].setPointer(szBuffer, sizeof(szBuffer));
1111 RTTESTI_CHECK_RC_BREAK(svcTable.pfnHostCall(svcTable.pvService, GET_PROP_HOST, 4, aParms), VINF_SUCCESS);
1112 }
1113 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1114 if (iCall)
1115 {
1116 uint64_t cNsPerCall = cNsElapsed / iCall;
1117 cNsAvg += cNsPerCall;
1118 if (cNsPerCall < cNsMin)
1119 cNsMin = cNsPerCall;
1120 if (cNsPerCall > cNsMax)
1121 cNsMax = cNsPerCall;
1122 }
1123 }
1124 if (cProps)
1125 cNsAvg /= cProps;
1126 RTTestIValue("GET_PROP_HOST Min", cNsMin, RTTESTUNIT_NS_PER_CALL);
1127 RTTestIValue("GET_PROP_HOST Avg", cNsAvg, RTTESTUNIT_NS_PER_CALL);
1128 RTTestIValue("GET_PROP_HOST Max", cNsMax, RTTESTUNIT_NS_PER_CALL);
1129
1130 /* Done. */
1131 RTTESTI_CHECK_RC_OK(svcTable.pfnUnload(svcTable.pvService));
1132}
1133
1134
1135
1136
1137int main(int argc, char **argv)
1138{
1139 RTEXITCODE rcExit = RTTestInitAndCreate("tstGuestPropSvc", &g_hTest);
1140 if (rcExit != RTEXITCODE_SUCCESS)
1141 return rcExit;
1142 RTTestBanner(g_hTest);
1143
1144 testConvertFlags();
1145 test2();
1146 test3();
1147 test4();
1148 test5();
1149 test6();
1150
1151 return RTTestSummaryAndDestroy(g_hTest);
1152}
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