VirtualBox

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

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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