]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/Variable/RuntimeDxe: Add Variable Lock Protocol Unit Tests
authorMichael D Kinney <michael.d.kinney@intel.com>
Fri, 11 Dec 2020 04:35:23 +0000 (20:35 -0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Tue, 15 Dec 2020 06:26:34 +0000 (06:26 +0000)
https://bugzilla.tianocore.org/show_bug.cgi?id=3111

Add host based unit tests for the multiple lock case using Variable Lock
Protocol, Variable Policy Protocol, and mixes of Variable Lock Protocol
and Variable Policy Protocol.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Bret Barkelew <Bret.Barkelew@microsoft.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
MdeModulePkg/Test/MdeModulePkgHostTest.dsc
MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c [new file with mode: 0644]
MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf [new file with mode: 0644]

index 72a119db45682dd0c68670d9feeab3593bf7ad27..4da4692c84510ccfb5ff5109833cdebc3cef5331 100644 (file)
@@ -19,6 +19,9 @@
 \r
 !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc\r
 \r
+[LibraryClasses]\r
+  SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf\r
+\r
 [Components]\r
   MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf\r
 \r
       ResetSystemLib|MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf\r
       UefiRuntimeServicesTableLib|MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf\r
   }\r
+\r
+  MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf {\r
+    <LibraryClasses>\r
+      VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf\r
+      VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf\r
+    <PcdsFixedAtBuild>\r
+      gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable|TRUE\r
+  }\r
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c
new file mode 100644 (file)
index 0000000..44d70e6
--- /dev/null
@@ -0,0 +1,565 @@
+/** @file\r
+  This is a host-based unit test for the VariableLockRequestToLock shim.\r
+\r
+  Copyright (c) Microsoft Corporation.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <stddef.h>\r
+#include <setjmp.h>\r
+#include <cmocka.h>\r
+\r
+#include <Uefi.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UnitTestLib.h>\r
+#include <Library/VariablePolicyLib.h>\r
+#include <Library/VariablePolicyHelperLib.h>\r
+\r
+#include <Protocol/VariableLock.h>\r
+\r
+#define UNIT_TEST_NAME        "VarPol/VarLock Shim Unit Test"\r
+#define UNIT_TEST_VERSION     "1.0"\r
+\r
+///=== CODE UNDER TEST ===========================================================================\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VariableLockRequestToLock (\r
+  IN CONST EDKII_VARIABLE_LOCK_PROTOCOL  *This,\r
+  IN       CHAR16                        *VariableName,\r
+  IN       EFI_GUID                      *VendorGuid\r
+  );\r
+\r
+///=== TEST DATA ==================================================================================\r
+\r
+//\r
+// Test GUID 1 {F955BA2D-4A2C-480C-BFD1-3CC522610592}\r
+//\r
+EFI_GUID  mTestGuid1 = {\r
+  0xf955ba2d, 0x4a2c, 0x480c, {0xbf, 0xd1, 0x3c, 0xc5, 0x22, 0x61, 0x5, 0x92}\r
+};\r
+\r
+//\r
+// Test GUID 2 {2DEA799E-5E73-43B9-870E-C945CE82AF3A}\r
+//\r
+EFI_GUID  mTestGuid2 = {\r
+  0x2dea799e, 0x5e73, 0x43b9, {0x87, 0xe, 0xc9, 0x45, 0xce, 0x82, 0xaf, 0x3a}\r
+};\r
+\r
+//\r
+// Test GUID 3 {698A2BFD-A616-482D-B88C-7100BD6682A9}\r
+//\r
+EFI_GUID  mTestGuid3 = {\r
+  0x698a2bfd, 0xa616, 0x482d, {0xb8, 0x8c, 0x71, 0x0, 0xbd, 0x66, 0x82, 0xa9}\r
+};\r
+\r
+#define TEST_VAR_1_NAME              L"TestVar1"\r
+#define TEST_VAR_2_NAME              L"TestVar2"\r
+#define TEST_VAR_3_NAME              L"TestVar3"\r
+\r
+#define TEST_POLICY_ATTRIBUTES_NULL  0\r
+#define TEST_POLICY_MIN_SIZE_NULL    0\r
+#define TEST_POLICY_MAX_SIZE_NULL    MAX_UINT32\r
+\r
+#define TEST_POLICY_MIN_SIZE_10      10\r
+#define TEST_POLICY_MAX_SIZE_200     200\r
+\r
+///=== HELPER FUNCTIONS ===========================================================================\r
+\r
+/**\r
+  Mocked version of GetVariable, for testing.\r
+\r
+  @param  VariableName\r
+  @param  VendorGuid\r
+  @param  Attributes\r
+  @param  DataSize\r
+  @param  Data\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StubGetVariableNull (\r
+  IN     CHAR16    *VariableName,\r
+  IN     EFI_GUID  *VendorGuid,\r
+  OUT    UINT32    *Attributes,  OPTIONAL\r
+  IN OUT UINTN     *DataSize,\r
+  OUT    VOID      *Data         OPTIONAL\r
+  )\r
+{\r
+  UINT32      MockedAttr;\r
+  UINTN       MockedDataSize;\r
+  VOID        *MockedData;\r
+  EFI_STATUS  MockedReturn;\r
+\r
+  check_expected_ptr (VariableName);\r
+  check_expected_ptr (VendorGuid);\r
+  check_expected_ptr (DataSize);\r
+\r
+  MockedAttr     = (UINT32)mock();\r
+  MockedDataSize = (UINTN)mock();\r
+  MockedData     = (VOID*)(UINTN)mock();\r
+  MockedReturn   = (EFI_STATUS)mock();\r
+\r
+  if (Attributes != NULL) {\r
+    *Attributes = MockedAttr;\r
+  }\r
+  if (Data != NULL && !EFI_ERROR (MockedReturn)) {\r
+    CopyMem (Data, MockedData, MockedDataSize);\r
+  }\r
+\r
+  *DataSize = MockedDataSize;\r
+\r
+  return MockedReturn;\r
+}\r
+\r
+//\r
+// Anything you think might be helpful that isn't a test itself.\r
+//\r
+\r
+/**\r
+  This is a common setup function that will ensure the library is always\r
+  initialized with the stubbed GetVariable.\r
+\r
+  Not used by all test cases, but by most.\r
+\r
+  @param[in]  Context  Unit test case context\r
+**/\r
+STATIC\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+LibInitMocked (\r
+  IN UNIT_TEST_CONTEXT  Context\r
+  )\r
+{\r
+  return EFI_ERROR (InitVariablePolicyLib (StubGetVariableNull)) ? UNIT_TEST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+  Common cleanup function to make sure that the library is always de-initialized\r
+  prior to the next test case.\r
+\r
+  @param[in]  Context  Unit test case context\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+LibCleanup (\r
+  IN UNIT_TEST_CONTEXT  Context\r
+  )\r
+{\r
+  DeinitVariablePolicyLib();\r
+}\r
+\r
+///=== TEST CASES =================================================================================\r
+\r
+///===== SHIM SUITE ===========================================================\r
+\r
+/**\r
+  Test Case that locks a single variable using the Variable Lock Protocol.\r
+  The call is expected to succeed.\r
+\r
+  @param[in]  Context  Unit test case context\r
+**/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+LockingWithoutAnyPoliciesShouldSucceed (\r
+  IN UNIT_TEST_CONTEXT  Context\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+  Test Case that locks the same variable twice using the Variable Lock Protocol.\r
+  Both calls are expected to succeed.\r
+\r
+  @param[in]  Context  Unit test case context\r
+  **/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+LockingTwiceShouldSucceed (\r
+  IN UNIT_TEST_CONTEXT  Context\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+  Test Case that locks a variable using the Variable Policy Protocol then locks\r
+  the same variable using the Variable Lock Protocol.\r
+  Both calls are expected to succeed.\r
+\r
+  @param[in]  Context  Unit test case context\r
+  **/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+LockingALockedVariableShouldSucceed (\r
+  IN UNIT_TEST_CONTEXT  Context\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  VARIABLE_POLICY_ENTRY  *NewEntry;\r
+\r
+  //\r
+  // Create a variable policy that locks the variable.\r
+  //\r
+  Status = CreateBasicVariablePolicy (\r
+             &mTestGuid1,\r
+             TEST_VAR_1_NAME,\r
+             TEST_POLICY_MIN_SIZE_NULL,\r
+             TEST_POLICY_MAX_SIZE_200,\r
+             TEST_POLICY_ATTRIBUTES_NULL,\r
+             TEST_POLICY_ATTRIBUTES_NULL,\r
+             VARIABLE_POLICY_TYPE_LOCK_NOW,\r
+             &NewEntry\r
+             );\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register the new policy.\r
+  //\r
+  Status = RegisterVariablePolicy (NewEntry);\r
+\r
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  FreePool (NewEntry);\r
+\r
+  return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+  Test Case that locks a variable using the Variable Policy Protocol with a\r
+  policy other than LOCK_NOW then attempts to lock the same variable using the\r
+  Variable Lock Protocol.  The call to Variable Policy is expected to succeed\r
+  and the call to Variable Lock is expected to fail.\r
+\r
+  @param[in]  Context  Unit test case context\r
+  **/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+LockingAnUnlockedVariableShouldFail (\r
+  IN UNIT_TEST_CONTEXT      Context\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VARIABLE_POLICY_ENTRY     *NewEntry;\r
+\r
+  // Create a variable policy that locks the variable.\r
+  Status = CreateVarStateVariablePolicy (&mTestGuid1,\r
+                                         TEST_VAR_1_NAME,\r
+                                         TEST_POLICY_MIN_SIZE_NULL,\r
+                                         TEST_POLICY_MAX_SIZE_200,\r
+                                         TEST_POLICY_ATTRIBUTES_NULL,\r
+                                         TEST_POLICY_ATTRIBUTES_NULL,\r
+                                         &mTestGuid2,\r
+                                         1,\r
+                                         TEST_VAR_2_NAME,\r
+                                         &NewEntry);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  // Register the new policy.\r
+  Status = RegisterVariablePolicy (NewEntry);\r
+\r
+ // Configure the stub to not care about parameters. We're testing errors.\r
+  expect_any_always( StubGetVariableNull, VariableName );\r
+  expect_any_always( StubGetVariableNull, VendorGuid );\r
+  expect_any_always( StubGetVariableNull, DataSize );\r
+\r
+  // With a policy, make sure that writes still work, since the variable doesn't exist.\r
+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes\r
+  will_return( StubGetVariableNull, 0 );                              // Size\r
+  will_return( StubGetVariableNull, NULL );                           // DataPtr\r
+  will_return( StubGetVariableNull, EFI_NOT_FOUND);                   // Status\r
+\r
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
+  UT_ASSERT_TRUE (EFI_ERROR (Status));\r
+\r
+  FreePool (NewEntry);\r
+\r
+  return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+  Test Case that locks a variable using the Variable Policy Protocol with a\r
+  policy other than LOCK_NOW, but is currently locked.  Then attempts to lock\r
+  the same variable using the Variable Lock Protocol.  The call to Variable\r
+  Policy is expected to succeed and the call to Variable Lock also expected to\r
+  succeed.\r
+\r
+  @param[in]  Context  Unit test case context\r
+  **/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+LockingALockedVariableWithMatchingDataShouldSucceed (\r
+  IN UNIT_TEST_CONTEXT      Context\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VARIABLE_POLICY_ENTRY     *NewEntry;\r
+  UINT8                     Data;\r
+\r
+  // Create a variable policy that locks the variable.\r
+  Status = CreateVarStateVariablePolicy (&mTestGuid1,\r
+                                         TEST_VAR_1_NAME,\r
+                                         TEST_POLICY_MIN_SIZE_NULL,\r
+                                         TEST_POLICY_MAX_SIZE_200,\r
+                                         TEST_POLICY_ATTRIBUTES_NULL,\r
+                                         TEST_POLICY_ATTRIBUTES_NULL,\r
+                                         &mTestGuid2,\r
+                                         1,\r
+                                         TEST_VAR_2_NAME,\r
+                                         &NewEntry);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  // Register the new policy.\r
+  Status = RegisterVariablePolicy (NewEntry);\r
+\r
+ // Configure the stub to not care about parameters. We're testing errors.\r
+  expect_any_always( StubGetVariableNull, VariableName );\r
+  expect_any_always( StubGetVariableNull, VendorGuid );\r
+  expect_any_always( StubGetVariableNull, DataSize );\r
+\r
+  // With a policy, make sure that writes still work, since the variable doesn't exist.\r
+  Data = 1;\r
+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes\r
+  will_return( StubGetVariableNull, sizeof (Data) );                  // Size\r
+  will_return( StubGetVariableNull, &Data );                          // DataPtr\r
+  will_return( StubGetVariableNull, EFI_SUCCESS);                     // Status\r
+\r
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
+  UT_ASSERT_TRUE (!EFI_ERROR (Status));\r
+\r
+  FreePool (NewEntry);\r
+\r
+  return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+  Test Case that locks a variable using the Variable Policy Protocol with a\r
+  policy other than LOCK_NOW, but variable data does not match.  Then attempts\r
+  to lock the same variable using the Variable Lock Protocol.  The call to\r
+  Variable Policy is expected to succeed and the call to Variable Lock is\r
+  expected to fail.\r
+\r
+  @param[in]  Context  Unit test case context\r
+  **/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+LockingALockedVariableWithNonMatchingDataShouldFail (\r
+  IN UNIT_TEST_CONTEXT      Context\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VARIABLE_POLICY_ENTRY     *NewEntry;\r
+  UINT8                     Data;\r
+\r
+  // Create a variable policy that locks the variable.\r
+  Status = CreateVarStateVariablePolicy (&mTestGuid1,\r
+                                         TEST_VAR_1_NAME,\r
+                                         TEST_POLICY_MIN_SIZE_NULL,\r
+                                         TEST_POLICY_MAX_SIZE_200,\r
+                                         TEST_POLICY_ATTRIBUTES_NULL,\r
+                                         TEST_POLICY_ATTRIBUTES_NULL,\r
+                                         &mTestGuid2,\r
+                                         1,\r
+                                         TEST_VAR_2_NAME,\r
+                                         &NewEntry);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  // Register the new policy.\r
+  Status = RegisterVariablePolicy (NewEntry);\r
+\r
+ // Configure the stub to not care about parameters. We're testing errors.\r
+  expect_any_always( StubGetVariableNull, VariableName );\r
+  expect_any_always( StubGetVariableNull, VendorGuid );\r
+  expect_any_always( StubGetVariableNull, DataSize );\r
+\r
+  // With a policy, make sure that writes still work, since the variable doesn't exist.\r
+  Data = 2;\r
+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes\r
+  will_return( StubGetVariableNull, sizeof (Data) );                  // Size\r
+  will_return( StubGetVariableNull, &Data );                          // DataPtr\r
+  will_return( StubGetVariableNull, EFI_SUCCESS);                     // Status\r
+\r
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
+  UT_ASSERT_TRUE (EFI_ERROR (Status));\r
+\r
+  FreePool (NewEntry);\r
+\r
+  return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+  Test Case that locks a variable using Variable Lock Protocol Policy Protocol\r
+  then and then attempts to lock the same variable using the Variable Policy\r
+  Protocol.  The call to Variable Lock is expected to succeed and the call to\r
+  Variable Policy is expected to fail.\r
+\r
+  @param[in]  Context  Unit test case context\r
+  **/\r
+UNIT_TEST_STATUS\r
+EFIAPI\r
+SettingPolicyForALockedVariableShouldFail (\r
+  IN UNIT_TEST_CONTEXT      Context\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VARIABLE_POLICY_ENTRY     *NewEntry;\r
+\r
+  // Lock the variable.\r
+  Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  // Create a variable policy that locks the variable.\r
+  Status = CreateVarStateVariablePolicy (&mTestGuid1,\r
+                                         TEST_VAR_1_NAME,\r
+                                         TEST_POLICY_MIN_SIZE_NULL,\r
+                                         TEST_POLICY_MAX_SIZE_200,\r
+                                         TEST_POLICY_ATTRIBUTES_NULL,\r
+                                         TEST_POLICY_ATTRIBUTES_NULL,\r
+                                         &mTestGuid2,\r
+                                         1,\r
+                                         TEST_VAR_2_NAME,\r
+                                         &NewEntry);\r
+  UT_ASSERT_NOT_EFI_ERROR (Status);\r
+\r
+  // Register the new policy.\r
+  Status = RegisterVariablePolicy (NewEntry);\r
+  UT_ASSERT_TRUE (EFI_ERROR (Status));\r
+\r
+  FreePool (NewEntry);\r
+\r
+  return UNIT_TEST_PASSED;\r
+}\r
+\r
+/**\r
+  Main entry point to this unit test application.\r
+\r
+  Sets up and runs the test suites.\r
+**/\r
+VOID\r
+EFIAPI\r
+UnitTestMain (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UNIT_TEST_FRAMEWORK_HANDLE  Framework;\r
+  UNIT_TEST_SUITE_HANDLE      ShimTests;\r
+\r
+  Framework = NULL;\r
+\r
+  DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION));\r
+\r
+  //\r
+  // Start setting up the test framework for running the tests.\r
+  //\r
+  Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Add all test suites and tests.\r
+  //\r
+  Status = CreateUnitTestSuite (\r
+             &ShimTests, Framework,\r
+             "Variable Lock Shim Tests", "VarPolicy.VarLockShim", NULL, NULL\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ShimTests\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto EXIT;\r
+  }\r
+  AddTestCase (\r
+    ShimTests,\r
+    "Locking a variable with no matching policies should always work", "EmptyPolicies",\r
+    LockingWithoutAnyPoliciesShouldSucceed, LibInitMocked, LibCleanup, NULL\r
+    );\r
+  AddTestCase (\r
+    ShimTests,\r
+    "Locking a variable twice should always work", "DoubleLock",\r
+    LockingTwiceShouldSucceed, LibInitMocked, LibCleanup, NULL\r
+    );\r
+  AddTestCase (\r
+    ShimTests,\r
+    "Locking a variable that's already locked by another policy should work", "LockAfterPolicy",\r
+    LockingALockedVariableShouldSucceed, LibInitMocked, LibCleanup, NULL\r
+    );\r
+  AddTestCase (\r
+    ShimTests,\r
+    "Locking a variable that already has an unlocked policy should fail", "LockAfterUnlockedPolicy",\r
+    LockingAnUnlockedVariableShouldFail, LibInitMocked, LibCleanup, NULL\r
+    );\r
+  AddTestCase (\r
+    ShimTests,\r
+    "Locking a variable that already has an locked policy should succeed", "LockAfterLockedPolicyMatchingData",\r
+    LockingALockedVariableWithMatchingDataShouldSucceed, LibInitMocked, LibCleanup, NULL\r
+    );\r
+  AddTestCase (\r
+    ShimTests,\r
+    "Locking a variable that already has an locked policy with matching data should succeed", "LockAfterLockedPolicyNonMatchingData",\r
+    LockingALockedVariableWithNonMatchingDataShouldFail, LibInitMocked, LibCleanup, NULL\r
+    );\r
+  AddTestCase (\r
+    ShimTests,\r
+    "Adding a policy for a variable that has previously been locked should always fail", "SetPolicyAfterLock",\r
+    SettingPolicyForALockedVariableShouldFail, LibInitMocked, LibCleanup, NULL\r
+    );\r
+\r
+  //\r
+  // Execute the tests.\r
+  //\r
+  Status = RunAllTestSuites (Framework);\r
+\r
+EXIT:\r
+  if (Framework != NULL) {\r
+    FreeUnitTestFramework (Framework);\r
+  }\r
+\r
+  return;\r
+}\r
+\r
+///\r
+/// Avoid ECC error for function name that starts with lower case letter\r
+///\r
+#define Main main\r
+\r
+/**\r
+  Standard POSIX C entry point for host based unit test execution.\r
+\r
+  @param[in] Argc  Number of arguments\r
+  @param[in] Argv  Array of pointers to arguments\r
+\r
+  @retval 0      Success\r
+  @retval other  Error\r
+**/\r
+INT32\r
+Main (\r
+  IN INT32  Argc,\r
+  IN CHAR8  *Argv[]\r
+  )\r
+{\r
+  UnitTestMain ();\r
+  return 0;\r
+}\r
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.inf
new file mode 100644 (file)
index 0000000..2a659d7
--- /dev/null
@@ -0,0 +1,36 @@
+## @file\r
+# This is a host-based unit test for the VariableLockRequestToLock shim.\r
+#\r
+# Copyright (c) Microsoft Corporation.\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION         = 0x00010017\r
+  BASE_NAME           = VariableLockRequestToLockUnitTest\r
+  FILE_GUID           = A7388B6C-7274-4717-9649-BDC5DFD1FCBE\r
+  VERSION_STRING      = 1.0\r
+  MODULE_TYPE         = HOST_APPLICATION\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64\r
+#\r
+\r
+[Sources]\r
+  VariableLockRequestToLockUnitTest.c\r
+  ../VariableLockRequestToLock.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+\r
+[LibraryClasses]\r
+  UnitTestLib\r
+  DebugLib\r
+  VariablePolicyLib\r
+  VariablePolicyHelperLib\r
+  BaseMemoryLib\r
+  MemoryAllocationLib\r