tstGuestPropSvc.cpp revision 34cd76de9b73367dfe5a4055585d2a5bb5d980a4
/* $Id$ */
/** @file
*
* Testcase for the guest property service.
*/
/*
* Copyright (C) 2008 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/initterm.h>
using namespace guestProp;
/** Simple call handle structure for the guest call completion callback */
struct VBOXHGCMCALLHANDLE_TYPEDEF
{
/** Where to store the result code */
};
/** Call completion callback for guest calls. */
{
}
/**
* Initialise the HGCM service table as much as we need to start the
* service
* @param pTable the table to initialise
*/
{
}
/**
* A list of valid flag strings for testConvertFlags. The flag conversion
* functions should accept these and convert them from string to a flag type
* and back without errors.
*/
struct flagStrings
{
/** Flag string in a format the functions should recognise */
const char *pcszIn;
/** How the functions should output the string again */
const char *pcszOut;
}
validFlagStrings[] =
{
{ " ", "" },
{ "transient, ", "TRANSIENT" },
{ " rdOnLyHOST, transIENT , READONLY ", "TRANSIENT, READONLY" },
{ " rdonlyguest", "RDONLYGUEST" },
{ "rdonlyhost ", "RDONLYHOST" }
};
/**
* A list of invalid flag strings for testConvertFlags. The flag conversion
* functions should reject these.
*/
const char *invalidFlagStrings[] =
{
"RDONLYHOST,,",
" TRANSIENT READONLY"
};
/**
* Test the flag conversion functions.
* @returns iprt status value to indicate whether the test went as expected.
* @note prints its own diagnostic information to stdout.
*/
int testConvertFlags()
{
int rc = VINF_SUCCESS;
RTPrintf("tstGuestPropSvc: Testing conversion of valid flags strings.\n");
{
if (RT_FAILURE(rc))
RTPrintf("tstGuestPropSvc: FAILURE - Failed to validate flag string '%s'.\n", validFlagStrings[i].pcszIn);
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
RTPrintf("tstGuestPropSvc: FAILURE - Failed to convert flag string '%s' back to a string.\n",
validFlagStrings[i].pcszIn);
}
{
RTPrintf("tstGuestPropSvc: FAILURE - String '%s' converts back to a flag string which is too long.\n",
validFlagStrings[i].pcszIn);
}
{
RTPrintf("tstGuestPropSvc: FAILURE - String '%s' converts back to '%s' instead of to '%s'\n",
validFlagStrings[i].pcszOut);
}
}
if (RT_SUCCESS(rc))
{
RTPrintf("Testing rejection of invalid flags strings.\n");
{
/* This is required to fail. */
{
RTPrintf("String '%s' was incorrectly accepted as a valid flag string.\n",
invalidFlagStrings[i]);
}
}
}
if (RT_SUCCESS(rc))
{
RTPrintf("Testing rejection of an invalid flags field.\n");
/* This is required to fail. */
{
RTPrintf("Flags 0x%x were incorrectly written out as '%.*s'\n",
}
}
return rc;
}
/**
* List of property names for testSetPropsHost.
*/
const char *apcszNameBlock[] =
{
"test name",
"TEST NAME",
};
/**
* List of property values for testSetPropsHost.
*/
const char *apcszValueBlock[] =
{
"test value",
"TEST VALUE",
};
/**
* List of property timestamps for testSetPropsHost.
*/
{
};
/**
* List of property flags for testSetPropsHost.
*/
const char *apcszFlagsBlock[] =
{
"",
"readonly, transient",
"RDONLYHOST",
"RdOnlyGuest",
};
/**
* Test the SET_PROPS_HOST function.
* @returns iprt status value to indicate whether the test went as expected.
* @note prints its own diagnostic information to stdout.
*/
{
int rc = VINF_SUCCESS;
RTPrintf("Testing the SET_PROPS_HOST call.\n");
{
RTPrintf("Invalid pfnHostCall() pointer\n");
}
if (RT_SUCCESS(rc))
{
paParms);
if (RT_FAILURE(rc))
}
return rc;
}
/** Result strings for zeroth enumeration test */
static const char *pcchEnumResult0[] =
{
"test name\0test value\0""999\0TRANSIENT, READONLY",
"TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST",
};
/** Result string sizes for zeroth enumeration test */
static const size_t cchEnumResult0[] =
{
sizeof("test name\0test value\0""999\0TRANSIENT, READONLY"),
sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"),
0
};
/**
* The size of the buffer returned by the zeroth enumeration test -
* the - 1 at the end is because of the hidden zero terminator
*/
static const size_t cchEnumBuffer0 =
"test name\0test value\0""999\0TRANSIENT, READONLY\0"
"TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"
/** Result strings for first and second enumeration test */
static const char *pcchEnumResult1[] =
{
"TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST",
};
/** Result string sizes for first and second enumeration test */
static const size_t cchEnumResult1[] =
{
sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"),
0
};
/**
* The size of the buffer returned by the first enumeration test -
* the - 1 at the end is because of the hidden zero terminator
*/
static const size_t cchEnumBuffer1 =
sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"
static const struct enumStringStruct
{
/** The enumeration pattern to test */
const char *pcszPatterns;
/** The size of the pattern string */
const size_t cchPatterns;
/** The expected enumeration output strings */
const char **ppcchResult;
/** The size of the output strings */
const size_t *pcchResult;
/** The size of the buffer needed for the enumeration */
}
enumStrings[] =
{
{
"", sizeof(""),
},
{
"/*\0?E*", sizeof("/*\0?E*"),
},
{
"/*|?E*", sizeof("/*|?E*"),
}
};
/**
* Test the ENUM_PROPS_HOST function.
* @returns iprt status value to indicate whether the test went as expected.
* @note prints its own diagnostic information to stdout.
*/
{
int rc = VINF_SUCCESS;
RTPrintf("Testing the ENUM_PROPS_HOST call.\n");
{
RTPrintf("Invalid pfnHostCall() pointer\n");
}
++i)
{
char buffer[2048];
enumStrings[i].cchPatterns);
if (RT_SUCCESS(rc))
{
/* This should fail as the buffer is too small. */
3, paParms);
if (rc2 != VERR_BUFFER_OVERFLOW)
{
RTPrintf("ENUM_PROPS_HOST returned %Rrc instead of VERR_BUFFER_OVERFLOW on too small buffer, pattern number %d\n", rc2, i);
}
else
{
{
RTPrintf("ENUM_PROPS_HOST requested a buffer size of %lu instead of %lu for pattern number %d\n", cchBufferActual, enumStrings[i].cchBuffer, i);
}
else if (RT_FAILURE(rc))
RTPrintf("ENUM_PROPS_HOST did not return the required buffer size properly for pattern %d\n", i);
}
}
if (RT_SUCCESS(rc))
{
3, paParms);
if (RT_FAILURE(rc))
else
/* Look for each of the result strings in the buffer which was returned */
++j)
{
bool found = false;
- enumStrings[i].pcchResult[j];
++k)
enumStrings[i].pcchResult[j]) == 0)
found = true;
if (!found)
{
RTPrintf("ENUM_PROPS_HOST did not produce the expected output for pattern %d\n",
i);
}
}
}
}
return rc;
}
/** Array of properties for testing SET_PROP_HOST and _GUEST. */
static const struct
{
/** Property name */
const char *pcszName;
/** Property value */
const char *pcszValue;
/** Property flags */
const char *pcszFlags;
/** Should this be set as the host or the guest? */
bool isHost;
/** Should we use SET_PROP or SET_PROP_VALUE? */
bool useSetProp;
/** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
bool isAllowed;
}
setProperties[] =
{
{ "Red", "Stop!", "transient", false, true, true },
{ "Amber", "Caution!", "", false, false, true },
{ "Green", "Go!", "readonly", true, true, true },
{ "Blue", "What on earth...?", "", true, false, true },
{ "TEST NAME", "test", "", true, true, false },
{ "Green", "gone out...", "", false, false, false },
{ "Green", "gone out...", "", true, false, false },
};
/**
* Test the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST
* functions.
* @returns iprt status value to indicate whether the test went as expected.
* @note prints its own diagnostic information to stdout.
*/
{
int rc = VINF_SUCCESS;
RTPrintf("Testing the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls.\n");
++i)
{
int command = SET_PROP_VALUE;
if (setProperties[i].isHost)
{
if (setProperties[i].useSetProp)
else
}
else if (setProperties[i].useSetProp)
/* Work around silly constant issues - we ought to allow passing
* constant strings in the hgcm parameters. */
if (setProperties[i].isHost)
else
{
RTPrintf("Setting property '%s' failed with rc=%Rrc.\n",
}
else if ( !setProperties[i].isAllowed
)
{
RTPrintf("Setting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
}
}
return rc;
}
/** Array of properties for testing DEL_PROP_HOST and _GUEST. */
static const struct
{
/** Property name */
const char *pcszName;
/** Should this be set as the host or the guest? */
bool isHost;
/** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
bool isAllowed;
}
delProperties[] =
{
{ "Red", false, true },
{ "Amber", true, true },
{ "Red2", false, true },
{ "Amber2", true, true },
{ "Green", false, false },
{ "Green", true, false },
{ "TEST NAME", true, false },
{ NULL, false, false }
};
/**
* Test the DEL_PROP, and DEL_PROP_HOST functions.
* @returns iprt status value to indicate whether the test went as expected.
* @note prints its own diagnostic information to stdout.
*/
{
int rc = VINF_SUCCESS;
RTPrintf("Testing the DEL_PROP and DEL_PROP_HOST calls.\n");
++i)
{
if (delProperties[i].isHost)
/* Work around silly constant issues - we ought to allow passing
* constant strings in the hgcm parameters. */
if (delProperties[i].isHost)
1, paParms);
else
1, paParms);
{
RTPrintf("Deleting property '%s' failed with rc=%Rrc.\n",
}
else if ( !delProperties[i].isAllowed
)
{
RTPrintf("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
}
}
return rc;
}
/** Array of properties for testing GET_PROP_HOST. */
static const struct
{
/** Property name */
const char *pcszName;
const char *pcchValue;
/** Should this proeprty exist? */
bool exists;
/** Do we expect a particular timestamp? */
bool hasTimestamp;
/** What timestamp if any do ex expect? */
}
getProperties[] =
{
{ "test name", "test value\0TRANSIENT, READONLY",
sizeof("test value\0TRANSIENT, READONLY"), true, true, 999 },
{ "TEST NAME", "TEST VALUE\0RDONLYHOST", sizeof("TEST VALUE\0RDONLYHOST"),
true, true, 999999 },
{ "Green", "Go!\0READONLY", sizeof("Go!\0READONLY"), true, false, 0 },
{ "Blue", "What on earth...?\0", sizeof("What on earth...?\0"), true,
false, 0 },
{ "Red", "", 0, false, false, 0 },
};
/**
* Test the GET_PROP_HOST function.
* @returns iprt status value to indicate whether the test went as expected.
* @note prints its own diagnostic information to stdout.
*/
{
RTPrintf("Testing the GET_PROP_HOST call.\n");
++i)
{
/* Work around silly constant issues - we ought to allow passing
* constant strings in the hgcm parameters. */
paParms);
{
RTPrintf("Getting property '%s' failed with rc=%Rrc.\n",
}
{
RTPrintf("Getting property '%s' returned %Rrc instead of VERR_NOT_FOUND.\n",
}
{
if (RT_FAILURE(rc))
RTPrintf("Failed to get the size of the output buffer for property '%s'\n",
getProperties[i].pcszName);
if ( RT_SUCCESS(rc)
getProperties[i].cchValue) != 0)
)
{
RTPrintf("Unexpected result '%.*s' for property '%s', expected '%.*s'.\n",
}
{
if (RT_FAILURE(rc))
RTPrintf("Failed to get the timestamp for property '%s'\n",
getProperties[i].pcszName);
if ( RT_SUCCESS(rc)
)
{
RTPrintf("Bad timestamp %llu for property '%s', expected %llu.\n",
}
}
}
}
return rc;
}
/** Array of properties for testing GET_PROP_HOST. */
static const struct
{
/** Buffer returned */
const char *pchBuffer;
/** What size should the buffer be? */
}
getNotifications[] =
{
{ "Red\0Stop!\0TRANSIENT", sizeof("Red\0Stop!\0TRANSIENT") },
{ "Amber\0Caution!\0", sizeof("Amber\0Caution!\0") },
{ "Green\0Go!\0READONLY", sizeof("Green\0Go!\0READONLY") },
{ "Blue\0What on earth...?\0", sizeof("Blue\0What on earth...?\0") },
{ "Red\0\0", sizeof("Red\0\0") },
{ "Amber\0\0", sizeof("Amber\0\0") },
{ NULL, 0 }
};
/**
* Test the GET_NOTIFICATION function.
* @returns iprt status value to indicate whether the test went as expected.
* @note prints its own diagnostic information to stdout.
*/
{
int rc = VINF_SUCCESS;
RTPrintf("Testing the GET_NOTIFICATION call.\n");
uint64_t u64Timestamp = 0;
/* Test "buffer too small" */
)
{
RTPrintf("Getting notification for property '%s' with a too small buffer did not fail correctly.\n",
}
/* Test successful notification queries */
++i)
{
)
{
RTPrintf("Failed to get notification for property '%s'.\n",
}
}
/* Test a query with an unknown timestamp */
if (RT_SUCCESS(rc))
if ( RT_SUCCESS(rc)
)
)
{
RTPrintf("Problem getting notification for property '%s' with unknown timestamp, rc=%Rrc.\n",
}
return rc;
}
/**
* Test the GET_NOTIFICATION function when no notifications are available.
* @returns iprt status value to indicate whether the test went as expected.
* @note prints its own diagnostic information to stdout.
*/
{
int rc = VINF_SUCCESS;
RTPrintf("Testing the asynchronous GET_NOTIFICATION call with no notifications are available.\n");
uint64_t u64Timestamp = 0;
{
RTPrintf("GET_NOTIFICATION call completed when new notifications should be available.\n");
}
return rc;
}
{
/* Paramters for the asynchronous guest notification call */
RTR3Init();
if (RT_FAILURE(testConvertFlags()))
return 1;
/* The function is inside the service, not HGCM. */
{
RTPrintf("Failed to start HGCM service.\n");
return 1;
}
return 1;
return 1;
/* Asynchronous notification call */
return 1;
return 1;
RTPrintf("Checking the data returned by the asynchronous notification call.\n");
/* Our previous notification call should have completed by now. */
)
{
RTPrintf("Asynchronous GET_NOTIFICATION call did not complete as expected, rc=%Rrc\n",
return 1;
}
return 1;
return 1;
return 1;
RTPrintf("tstGuestPropSvc: SUCCEEDED.\n");
return 0;
}