From: "Kun Qin" <kuqin12@gmail.com>
To: Michael Kubacki <mikuback@linux.microsoft.com>,
devel@edk2.groups.io,
Michael D Kinney <michael.d.kinney@intel.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Subject: Re: [edk2-devel] [PATCH v3 1/1] UnitTestFrameworkPkg: UnitTestPersistenceLib: Save Unit Test Cache Option
Date: Fri, 7 Jul 2023 08:45:09 -0700 [thread overview]
Message-ID: <13d47b57-29dd-007c-a9f2-e5bde74480db@gmail.com> (raw)
In-Reply-To: <06c10e6c-bca1-4266-1c77-e73127077c97@linux.microsoft.com>
Hi Mike,
It has been a week since the last movement on this. Could you please
provide feedback on this patch when you have a chance? Any input is
appreciated.
Regards,
Kun
On 6/30/2023 4:00 PM, Michael Kubacki wrote:
> Reviewed-by: Michael Kubacki <michael.kubacki@microsoft.com>
>
> I haven't seen Mike Kinney acknowledge the changes made in response to
> his v1 request so we'll need to get that before merging the patch.
>
> Thanks,
> Michael
>
> On 6/30/2023 2:14 PM, Kun Qin wrote:
>> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4467
>>
>> Current implementation of UnitTestFrameworkPkg for shell-based unit test
>> will save the unit test cache to the same volume as the test application
>> itself. This works as long as the test application is on a writable
>> volume, such as USB or EFI partition.
>>
>> Instead of saving the files to the same file system of unit test
>> application, this change will save the cache file to the path where the
>> user ran this test application.
>>
>> This change then added an input argument to allow user to specify where
>> to save such cache file through `--CachePath` shell argument to allow
>> even more flexibility.
>>
>> This change was tested on proprietary physical hardware platforms and
>> QEMU based virtual platform.
>>
>> Cc: Sean Brogan <sean.brogan@microsoft.com>
>> Cc: Michael Kubacki <mikuback@linux.microsoft.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>>
>> Signed-off-by: Kun Qin <kuqin12@gmail.com>
>> ---
>>
>> Notes:
>> v2:
>> - Adding input argument [Mike Kinney]
>> v3:
>> - No review, no change
>>
>> UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c
>> | 232 +++++++++++++-------
>> 1 file changed, 157 insertions(+), 75 deletions(-)
>>
>> diff --git
>> a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c
>> b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c
>>
>> index b59991683f48..8f7f03646cd5 100644
>> ---
>> a/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c
>> +++
>> b/UnitTestFrameworkPkg/Library/UnitTestPersistenceLibSimpleFileSystem/UnitTestPersistenceLibSimpleFileSystem.c
>> @@ -16,13 +16,16 @@
>> #include <Library/UefiBootServicesTableLib.h>
>>
>> #include <Library/DevicePathLib.h>
>>
>> #include <Library/ShellLib.h>
>>
>> +#include <Library/UefiLib.h>
>>
>> #include <Protocol/LoadedImage.h>
>>
>> #include <UnitTestFrameworkTypes.h>
>>
>>
>> #define CACHE_FILE_SUFFIX L"_Cache.dat"
>>
>>
>> +CHAR16 *mCachePath = NULL;
>>
>> +
>>
>> /**
>>
>> - Generate the device path to the cache file.
>>
>> + Generate the file name and path to the cache file.
>>
>>
>> @param[in] FrameworkHandle A pointer to the framework that is
>> being persisted.
>>
>>
>> @@ -31,8 +34,8 @@
>>
>> **/
>>
>> STATIC
>>
>> -EFI_DEVICE_PATH_PROTOCOL *
>>
>> -GetCacheFileDevicePath (
>>
>> +CHAR16 *
>>
>> +GetCacheFileName (
>>
>> IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
>>
>> )
>>
>> {
>>
>> @@ -44,13 +47,11 @@ GetCacheFileDevicePath (
>> CHAR16 *TestName;
>>
>> UINTN DirectorySlashOffset;
>>
>> UINTN CacheFilePathLength;
>>
>> - EFI_DEVICE_PATH_PROTOCOL *CacheFileDevicePath;
>>
>>
>> - Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
>>
>> - AppPath = NULL;
>>
>> - CacheFilePath = NULL;
>>
>> - TestName = NULL;
>>
>> - CacheFileDevicePath = NULL;
>>
>> + Framework = (UNIT_TEST_FRAMEWORK *)FrameworkHandle;
>>
>> + AppPath = NULL;
>>
>> + CacheFilePath = NULL;
>>
>> + TestName = NULL;
>>
>>
>> //
>>
>> // First, we need to get some information from the loaded image.
>>
>> @@ -85,35 +86,62 @@ GetCacheFileDevicePath (
>> // PathCleanUpDirectories (FileNameCopy);
>>
>> // if (PathRemoveLastItem (FileNameCopy)) {
>>
>> //
>>
>> - AppPath = ConvertDevicePathToText
>> (LoadedImage->FilePath, TRUE, TRUE); // NOTE: This must be freed.
>>
>> - DirectorySlashOffset = StrLen (AppPath);
>>
>> - //
>>
>> - // Make sure we didn't get any weird data.
>>
>> - //
>>
>> - if (DirectorySlashOffset == 0) {
>>
>> - DEBUG ((DEBUG_ERROR, "%a - Weird 0-length string when processing
>> app path.\n", __func__));
>>
>> - goto Exit;
>>
>> - }
>>
>> + if (mCachePath == NULL) {
>>
>> + AppPath = ConvertDevicePathToText (LoadedImage->FilePath, TRUE,
>> TRUE); // NOTE: This must be freed.
>>
>> + if (AppPath == NULL) {
>>
>> + goto Exit;
>>
>> + }
>>
>>
>> - //
>>
>> - // Now that we know we have a decent string, let's take a deeper
>> look.
>>
>> - //
>>
>> - do {
>>
>> - if (AppPath[DirectorySlashOffset] == L'\\') {
>>
>> - break;
>>
>> + DirectorySlashOffset = StrLen (AppPath);
>>
>> + //
>>
>> + // Make sure we didn't get any weird data.
>>
>> + //
>>
>> + if (DirectorySlashOffset == 0) {
>>
>> + DEBUG ((DEBUG_ERROR, "%a - Weird 0-length string when
>> processing app path.\n", __func__));
>>
>> + goto Exit;
>>
>> }
>>
>>
>> - DirectorySlashOffset--;
>>
>> - } while (DirectorySlashOffset > 0);
>>
>> + //
>>
>> + // Now that we know we have a decent string, let's take a deeper
>> look.
>>
>> + //
>>
>> + do {
>>
>> + if (AppPath[DirectorySlashOffset] == L'\\') {
>>
>> + break;
>>
>> + }
>>
>> +
>>
>> + DirectorySlashOffset--;
>>
>> + } while (DirectorySlashOffset > 0);
>>
>>
>> - //
>>
>> - // After that little maneuver, DirectorySlashOffset should be
>> pointing at the last '\' in AppString.
>>
>> - // That would be the path to the parent directory that the test
>> app is executing from.
>>
>> - // Let's check and make sure that's right.
>>
>> - //
>>
>> - if (AppPath[DirectorySlashOffset] != L'\\') {
>>
>> - DEBUG ((DEBUG_ERROR, "%a - Could not find a single directory
>> separator in app path.\n", __func__));
>>
>> - goto Exit;
>>
>> + //
>>
>> + // After that little maneuver, DirectorySlashOffset should be
>> pointing at the last '\' in AppString.
>>
>> + // That would be the path to the parent directory that the test
>> app is executing from.
>>
>> + // Let's check and make sure that's right.
>>
>> + //
>>
>> + if (AppPath[DirectorySlashOffset] != L'\\') {
>>
>> + DEBUG ((DEBUG_ERROR, "%a - Could not find a single directory
>> separator in app path.\n", __func__));
>>
>> + goto Exit;
>>
>> + }
>>
>> + } else {
>>
>> + AppPath = FullyQualifyPath (mCachePath); // NOTE: This must be
>> freed.
>>
>> + if (AppPath == NULL) {
>>
>> + goto Exit;
>>
>> + }
>>
>> +
>>
>> + DirectorySlashOffset = StrLen (AppPath);
>>
>> +
>>
>> + if (AppPath[DirectorySlashOffset - 1] != L'\\') {
>>
>> + // Set the slash if user did not specify it on the newly
>> allocated pool
>>
>> + AppPath = ReallocatePool (
>>
>> + (DirectorySlashOffset + 1) * sizeof (CHAR16),
>>
>> + (DirectorySlashOffset + 2) * sizeof (CHAR16),
>>
>> + AppPath
>>
>> + );
>>
>> + AppPath[DirectorySlashOffset] = L'\\';
>>
>> + AppPath[DirectorySlashOffset + 1] = L'\0';
>>
>> + } else {
>>
>> + // Otherwise the user input is good enough to go, mostly
>>
>> + DirectorySlashOffset--;
>>
>> + }
>>
>> }
>>
>>
>> //
>>
>> @@ -135,11 +163,6 @@ GetCacheFileDevicePath (
>> StrCatS (CacheFilePath, CacheFilePathLength,
>> TestName); // Copy the base name for the
>> test cache.
>>
>> StrCatS (CacheFilePath, CacheFilePathLength,
>> CACHE_FILE_SUFFIX); // Copy the file suffix.
>>
>>
>> - //
>>
>> - // Finally, try to create the device path for the thing thing.
>>
>> - //
>>
>> - CacheFileDevicePath = FileDevicePath (LoadedImage->DeviceHandle,
>> CacheFilePath);
>>
>> -
>>
>> Exit:
>>
>> //
>>
>> // Free allocated buffers.
>>
>> @@ -148,15 +171,11 @@ Exit:
>> FreePool (AppPath);
>>
>> }
>>
>>
>> - if (CacheFilePath != NULL) {
>>
>> - FreePool (CacheFilePath);
>>
>> - }
>>
>> -
>>
>> if (TestName != NULL) {
>>
>> FreePool (TestName);
>>
>> }
>>
>>
>> - return CacheFileDevicePath;
>>
>> + return CacheFilePath;
>>
>> }
>>
>>
>> /**
>>
>> @@ -175,21 +194,24 @@ DoesCacheExist (
>> IN UNIT_TEST_FRAMEWORK_HANDLE FrameworkHandle
>>
>> )
>>
>> {
>>
>> - EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
>>
>> - EFI_STATUS Status;
>>
>> - SHELL_FILE_HANDLE FileHandle;
>>
>> + CHAR16 *FileName;
>>
>> + EFI_STATUS Status;
>>
>> + SHELL_FILE_HANDLE FileHandle;
>>
>>
>> //
>>
>> // NOTE: This devpath is allocated and must be freed.
>>
>> //
>>
>> - FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
>>
>> + FileName = GetCacheFileName (FrameworkHandle);
>>
>> + if (FileName == NULL) {
>>
>> + return FALSE;
>>
>> + }
>>
>>
>> //
>>
>> // Check to see whether the file exists. If the file can be
>> opened for
>>
>> // reading, it exists. Otherwise, probably not.
>>
>> //
>>
>> - Status = ShellOpenFileByDevicePath (
>>
>> - &FileDevicePath,
>>
>> + Status = ShellOpenFileByName (
>>
>> + FileName,
>>
>> &FileHandle,
>>
>> EFI_FILE_MODE_READ,
>>
>> 0
>>
>> @@ -198,8 +220,8 @@ DoesCacheExist (
>> ShellCloseFile (&FileHandle);
>>
>> }
>>
>>
>> - if (FileDevicePath != NULL) {
>>
>> - FreePool (FileDevicePath);
>>
>> + if (FileName != NULL) {
>>
>> + FreePool (FileName);
>>
>> }
>>
>>
>> DEBUG ((DEBUG_VERBOSE, "%a - Returning %d\n", __func__,
>> !EFI_ERROR (Status)));
>>
>> @@ -229,10 +251,10 @@ SaveUnitTestCache (
>> IN UINTN SaveStateSize
>>
>> )
>>
>> {
>>
>> - EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
>>
>> - EFI_STATUS Status;
>>
>> - SHELL_FILE_HANDLE FileHandle;
>>
>> - UINTN WriteCount;
>>
>> + CHAR16 *FileName;
>>
>> + EFI_STATUS Status;
>>
>> + SHELL_FILE_HANDLE FileHandle;
>>
>> + UINTN WriteCount;
>>
>>
>> //
>>
>> // Check the inputs for sanity.
>>
>> @@ -245,13 +267,16 @@ SaveUnitTestCache (
>> // Determine the path for the cache file.
>>
>> // NOTE: This devpath is allocated and must be freed.
>>
>> //
>>
>> - FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
>>
>> + FileName = GetCacheFileName (FrameworkHandle);
>>
>> + if (FileName == NULL) {
>>
>> + return EFI_INVALID_PARAMETER;
>>
>> + }
>>
>>
>> //
>>
>> // First lets open the file if it exists so we can delete
>> it...This is the work around for truncation
>>
>> //
>>
>> - Status = ShellOpenFileByDevicePath (
>>
>> - &FileDevicePath,
>>
>> + Status = ShellOpenFileByName (
>>
>> + FileName,
>>
>> &FileHandle,
>>
>> (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE),
>>
>> 0
>>
>> @@ -270,8 +295,8 @@ SaveUnitTestCache (
>> //
>>
>> // Now that we know the path to the file... let's open it for
>> writing.
>>
>> //
>>
>> - Status = ShellOpenFileByDevicePath (
>>
>> - &FileDevicePath,
>>
>> + Status = ShellOpenFileByName (
>>
>> + FileName,
>>
>> &FileHandle,
>>
>> (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
>> EFI_FILE_MODE_CREATE),
>>
>> 0
>>
>> @@ -304,8 +329,8 @@ SaveUnitTestCache (
>> ShellCloseFile (&FileHandle);
>>
>>
>> Exit:
>>
>> - if (FileDevicePath != NULL) {
>>
>> - FreePool (FileDevicePath);
>>
>> + if (FileName != NULL) {
>>
>> + FreePool (FileName);
>>
>> }
>>
>>
>> return Status;
>>
>> @@ -334,13 +359,13 @@ LoadUnitTestCache (
>> OUT UINTN *SaveStateSize
>>
>> )
>>
>> {
>>
>> - EFI_STATUS Status;
>>
>> - EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
>>
>> - SHELL_FILE_HANDLE FileHandle;
>>
>> - BOOLEAN IsFileOpened;
>>
>> - UINT64 LargeFileSize;
>>
>> - UINTN FileSize;
>>
>> - VOID *Buffer;
>>
>> + EFI_STATUS Status;
>>
>> + CHAR16 *FileName;
>>
>> + SHELL_FILE_HANDLE FileHandle;
>>
>> + BOOLEAN IsFileOpened;
>>
>> + UINT64 LargeFileSize;
>>
>> + UINTN FileSize;
>>
>> + VOID *Buffer;
>>
>>
>> IsFileOpened = FALSE;
>>
>> Buffer = NULL;
>>
>> @@ -356,13 +381,16 @@ LoadUnitTestCache (
>> // Determine the path for the cache file.
>>
>> // NOTE: This devpath is allocated and must be freed.
>>
>> //
>>
>> - FileDevicePath = GetCacheFileDevicePath (FrameworkHandle);
>>
>> + FileName = GetCacheFileName (FrameworkHandle);
>>
>> + if (FileName == NULL) {
>>
>> + return EFI_INVALID_PARAMETER;
>>
>> + }
>>
>>
>> //
>>
>> // Now that we know the path to the file... let's open it for
>> writing.
>>
>> //
>>
>> - Status = ShellOpenFileByDevicePath (
>>
>> - &FileDevicePath,
>>
>> + Status = ShellOpenFileByName (
>>
>> + FileName,
>>
>> &FileHandle,
>>
>> EFI_FILE_MODE_READ,
>>
>> 0
>>
>> @@ -407,8 +435,8 @@ Exit:
>> //
>>
>> // Free allocated buffers
>>
>> //
>>
>> - if (FileDevicePath != NULL) {
>>
>> - FreePool (FileDevicePath);
>>
>> + if (FileName != NULL) {
>>
>> + FreePool (FileName);
>>
>> }
>>
>>
>> if (IsFileOpened) {
>>
>> @@ -426,3 +454,57 @@ Exit:
>> *SaveData = Buffer;
>>
>> return Status;
>>
>> }
>>
>> +
>>
>> +/**
>>
>> + Shell based UnitTestPersistenceLib library constructor.
>>
>> +
>>
>> + @param[in] ImageHandle The firmware allocated handle for the EFI
>> image.
>>
>> + @param[in] SystemTable A pointer to the EFI System Table.
>>
>> +
>>
>> + @retval EFI_SUCCESS The constructor finished successfully.
>>
>> + @retval Others Error codes returned from
>> gBS->HandleProtocol.
>>
>> + **/
>>
>> +EFI_STATUS
>>
>> +EFIAPI
>>
>> +UnitTestPersistenceLibConstructor (
>>
>> + IN EFI_HANDLE ImageHandle,
>>
>> + IN EFI_SYSTEM_TABLE *SystemTable
>>
>> + )
>>
>> +{
>>
>> + UINTN Index;
>>
>> + UINTN Argc;
>>
>> + CHAR16 **Argv;
>>
>> + EFI_STATUS Status;
>>
>> + EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
>>
>> +
>>
>> + Status = gBS->HandleProtocol (
>>
>> + gImageHandle,
>>
>> + &gEfiShellParametersProtocolGuid,
>>
>> + (VOID **)&ShellParameters
>>
>> + );
>>
>> + if (EFI_ERROR (Status)) {
>>
>> + ASSERT_EFI_ERROR (Status);
>>
>> + goto Done;
>>
>> + }
>>
>> +
>>
>> + Argc = ShellParameters->Argc;
>>
>> + Argv = ShellParameters->Argv;
>>
>> +
>>
>> + Status = EFI_SUCCESS;
>>
>> + if ((Argc > 1) && (Argv != NULL)) {
>>
>> + // This might be our cue, check for whether we need to do anything
>>
>> + for (Index = 1; Index < Argc; Index++) {
>>
>> + if (StrCmp (Argv[Index], L"--CachePath") == 0) {
>>
>> + // Need to update the potential cache path to designated path
>>
>> + if (Index < Argc - 1) {
>>
>> + mCachePath = Argv[Index + 1];
>>
>> + } else {
>>
>> + Print (L" --CachePath <Path of where to save unit test
>> cache files, i.e. FS0:TestFolder>\n");
>>
>> + }
>>
>> + }
>>
>> + }
>>
>> + }
>>
>> +
>>
>> +Done:
>>
>> + return Status;
>>
>> +}
>>
next prev parent reply other threads:[~2023-07-07 15:45 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-30 18:14 [PATCH v3 0/1] Add support for running shell test application in an immutable volume Kun Qin
2023-06-30 18:14 ` [PATCH v3 1/1] UnitTestFrameworkPkg: UnitTestPersistenceLib: Save Unit Test Cache Option Kun Qin
2023-06-30 23:00 ` [edk2-devel] " Michael Kubacki
2023-07-07 15:45 ` Kun Qin [this message]
2023-07-20 0:48 ` Michael D Kinney
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=13d47b57-29dd-007c-a9f2-e5bde74480db@gmail.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox