]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c
MdeModulePkg: Change OPTIONAL keyword usage style
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / RuntimeDxeUnitTest / VariableLockRequestToLockUnitTest.c
CommitLineData
dcaa9393
MK
1/** @file\r
2 This is a host-based unit test for the VariableLockRequestToLock shim.\r
3\r
4 Copyright (c) Microsoft Corporation.\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include <stdio.h>\r
10#include <string.h>\r
11#include <stdarg.h>\r
12#include <stddef.h>\r
13#include <setjmp.h>\r
14#include <cmocka.h>\r
15\r
16#include <Uefi.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/UnitTestLib.h>\r
21#include <Library/VariablePolicyLib.h>\r
22#include <Library/VariablePolicyHelperLib.h>\r
23\r
24#include <Protocol/VariableLock.h>\r
25\r
26#define UNIT_TEST_NAME "VarPol/VarLock Shim Unit Test"\r
27#define UNIT_TEST_VERSION "1.0"\r
28\r
29///=== CODE UNDER TEST ===========================================================================\r
30\r
31EFI_STATUS\r
32EFIAPI\r
33VariableLockRequestToLock (\r
34 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
35 IN CHAR16 *VariableName,\r
36 IN EFI_GUID *VendorGuid\r
37 );\r
38\r
39///=== TEST DATA ==================================================================================\r
40\r
41//\r
42// Test GUID 1 {F955BA2D-4A2C-480C-BFD1-3CC522610592}\r
43//\r
44EFI_GUID mTestGuid1 = {\r
45 0xf955ba2d, 0x4a2c, 0x480c, {0xbf, 0xd1, 0x3c, 0xc5, 0x22, 0x61, 0x5, 0x92}\r
46};\r
47\r
48//\r
49// Test GUID 2 {2DEA799E-5E73-43B9-870E-C945CE82AF3A}\r
50//\r
51EFI_GUID mTestGuid2 = {\r
52 0x2dea799e, 0x5e73, 0x43b9, {0x87, 0xe, 0xc9, 0x45, 0xce, 0x82, 0xaf, 0x3a}\r
53};\r
54\r
55//\r
56// Test GUID 3 {698A2BFD-A616-482D-B88C-7100BD6682A9}\r
57//\r
58EFI_GUID mTestGuid3 = {\r
59 0x698a2bfd, 0xa616, 0x482d, {0xb8, 0x8c, 0x71, 0x0, 0xbd, 0x66, 0x82, 0xa9}\r
60};\r
61\r
62#define TEST_VAR_1_NAME L"TestVar1"\r
63#define TEST_VAR_2_NAME L"TestVar2"\r
64#define TEST_VAR_3_NAME L"TestVar3"\r
65\r
66#define TEST_POLICY_ATTRIBUTES_NULL 0\r
67#define TEST_POLICY_MIN_SIZE_NULL 0\r
68#define TEST_POLICY_MAX_SIZE_NULL MAX_UINT32\r
69\r
70#define TEST_POLICY_MIN_SIZE_10 10\r
71#define TEST_POLICY_MAX_SIZE_200 200\r
72\r
73///=== HELPER FUNCTIONS ===========================================================================\r
74\r
75/**\r
76 Mocked version of GetVariable, for testing.\r
77\r
78 @param VariableName\r
79 @param VendorGuid\r
80 @param Attributes\r
81 @param DataSize\r
82 @param Data\r
83**/\r
84EFI_STATUS\r
85EFIAPI\r
86StubGetVariableNull (\r
87 IN CHAR16 *VariableName,\r
88 IN EFI_GUID *VendorGuid,\r
e3917e22 89 OUT UINT32 *Attributes OPTIONAL,\r
dcaa9393
MK
90 IN OUT UINTN *DataSize,\r
91 OUT VOID *Data OPTIONAL\r
92 )\r
93{\r
94 UINT32 MockedAttr;\r
95 UINTN MockedDataSize;\r
96 VOID *MockedData;\r
97 EFI_STATUS MockedReturn;\r
98\r
99 check_expected_ptr (VariableName);\r
100 check_expected_ptr (VendorGuid);\r
101 check_expected_ptr (DataSize);\r
102\r
103 MockedAttr = (UINT32)mock();\r
104 MockedDataSize = (UINTN)mock();\r
105 MockedData = (VOID*)(UINTN)mock();\r
106 MockedReturn = (EFI_STATUS)mock();\r
107\r
108 if (Attributes != NULL) {\r
109 *Attributes = MockedAttr;\r
110 }\r
111 if (Data != NULL && !EFI_ERROR (MockedReturn)) {\r
112 CopyMem (Data, MockedData, MockedDataSize);\r
113 }\r
114\r
115 *DataSize = MockedDataSize;\r
116\r
117 return MockedReturn;\r
118}\r
119\r
120//\r
121// Anything you think might be helpful that isn't a test itself.\r
122//\r
123\r
124/**\r
125 This is a common setup function that will ensure the library is always\r
126 initialized with the stubbed GetVariable.\r
127\r
128 Not used by all test cases, but by most.\r
129\r
130 @param[in] Context Unit test case context\r
131**/\r
132STATIC\r
133UNIT_TEST_STATUS\r
134EFIAPI\r
135LibInitMocked (\r
136 IN UNIT_TEST_CONTEXT Context\r
137 )\r
138{\r
139 return EFI_ERROR (InitVariablePolicyLib (StubGetVariableNull)) ? UNIT_TEST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED;\r
140}\r
141\r
142/**\r
143 Common cleanup function to make sure that the library is always de-initialized\r
144 prior to the next test case.\r
145\r
146 @param[in] Context Unit test case context\r
147**/\r
148STATIC\r
149VOID\r
150EFIAPI\r
151LibCleanup (\r
152 IN UNIT_TEST_CONTEXT Context\r
153 )\r
154{\r
155 DeinitVariablePolicyLib();\r
156}\r
157\r
158///=== TEST CASES =================================================================================\r
159\r
160///===== SHIM SUITE ===========================================================\r
161\r
162/**\r
163 Test Case that locks a single variable using the Variable Lock Protocol.\r
164 The call is expected to succeed.\r
165\r
166 @param[in] Context Unit test case context\r
167**/\r
168UNIT_TEST_STATUS\r
169EFIAPI\r
170LockingWithoutAnyPoliciesShouldSucceed (\r
171 IN UNIT_TEST_CONTEXT Context\r
172 )\r
173{\r
174 EFI_STATUS Status;\r
175\r
176 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
177 UT_ASSERT_NOT_EFI_ERROR (Status);\r
178\r
179 return UNIT_TEST_PASSED;\r
180}\r
181\r
182/**\r
183 Test Case that locks the same variable twice using the Variable Lock Protocol.\r
184 Both calls are expected to succeed.\r
185\r
186 @param[in] Context Unit test case context\r
187 **/\r
188UNIT_TEST_STATUS\r
189EFIAPI\r
190LockingTwiceShouldSucceed (\r
191 IN UNIT_TEST_CONTEXT Context\r
192 )\r
193{\r
194 EFI_STATUS Status;\r
195\r
196 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
197 UT_ASSERT_NOT_EFI_ERROR (Status);\r
198\r
199 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
200 UT_ASSERT_NOT_EFI_ERROR (Status);\r
201\r
202 return UNIT_TEST_PASSED;\r
203}\r
204\r
205/**\r
206 Test Case that locks a variable using the Variable Policy Protocol then locks\r
207 the same variable using the Variable Lock Protocol.\r
208 Both calls are expected to succeed.\r
209\r
210 @param[in] Context Unit test case context\r
211 **/\r
212UNIT_TEST_STATUS\r
213EFIAPI\r
214LockingALockedVariableShouldSucceed (\r
215 IN UNIT_TEST_CONTEXT Context\r
216 )\r
217{\r
218 EFI_STATUS Status;\r
219 VARIABLE_POLICY_ENTRY *NewEntry;\r
220\r
221 //\r
222 // Create a variable policy that locks the variable.\r
223 //\r
224 Status = CreateBasicVariablePolicy (\r
225 &mTestGuid1,\r
226 TEST_VAR_1_NAME,\r
227 TEST_POLICY_MIN_SIZE_NULL,\r
228 TEST_POLICY_MAX_SIZE_200,\r
229 TEST_POLICY_ATTRIBUTES_NULL,\r
230 TEST_POLICY_ATTRIBUTES_NULL,\r
231 VARIABLE_POLICY_TYPE_LOCK_NOW,\r
232 &NewEntry\r
233 );\r
234 UT_ASSERT_NOT_EFI_ERROR (Status);\r
235\r
236 //\r
237 // Register the new policy.\r
238 //\r
239 Status = RegisterVariablePolicy (NewEntry);\r
240\r
241 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
242 UT_ASSERT_NOT_EFI_ERROR (Status);\r
243\r
244 FreePool (NewEntry);\r
245\r
246 return UNIT_TEST_PASSED;\r
247}\r
248\r
249/**\r
250 Test Case that locks a variable using the Variable Policy Protocol with a\r
251 policy other than LOCK_NOW then attempts to lock the same variable using the\r
252 Variable Lock Protocol. The call to Variable Policy is expected to succeed\r
253 and the call to Variable Lock is expected to fail.\r
254\r
255 @param[in] Context Unit test case context\r
256 **/\r
257UNIT_TEST_STATUS\r
258EFIAPI\r
259LockingAnUnlockedVariableShouldFail (\r
260 IN UNIT_TEST_CONTEXT Context\r
261 )\r
262{\r
263 EFI_STATUS Status;\r
264 VARIABLE_POLICY_ENTRY *NewEntry;\r
265\r
266 // Create a variable policy that locks the variable.\r
267 Status = CreateVarStateVariablePolicy (&mTestGuid1,\r
268 TEST_VAR_1_NAME,\r
269 TEST_POLICY_MIN_SIZE_NULL,\r
270 TEST_POLICY_MAX_SIZE_200,\r
271 TEST_POLICY_ATTRIBUTES_NULL,\r
272 TEST_POLICY_ATTRIBUTES_NULL,\r
273 &mTestGuid2,\r
274 1,\r
275 TEST_VAR_2_NAME,\r
276 &NewEntry);\r
277 UT_ASSERT_NOT_EFI_ERROR (Status);\r
278\r
279 // Register the new policy.\r
280 Status = RegisterVariablePolicy (NewEntry);\r
281\r
282 // Configure the stub to not care about parameters. We're testing errors.\r
283 expect_any_always( StubGetVariableNull, VariableName );\r
284 expect_any_always( StubGetVariableNull, VendorGuid );\r
285 expect_any_always( StubGetVariableNull, DataSize );\r
286\r
287 // With a policy, make sure that writes still work, since the variable doesn't exist.\r
288 will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // Attributes\r
289 will_return( StubGetVariableNull, 0 ); // Size\r
4050c873 290 will_return( StubGetVariableNull, (UINTN)NULL ); // DataPtr\r
dcaa9393
MK
291 will_return( StubGetVariableNull, EFI_NOT_FOUND); // Status\r
292\r
293 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
294 UT_ASSERT_TRUE (EFI_ERROR (Status));\r
295\r
296 FreePool (NewEntry);\r
297\r
298 return UNIT_TEST_PASSED;\r
299}\r
300\r
301/**\r
302 Test Case that locks a variable using the Variable Policy Protocol with a\r
303 policy other than LOCK_NOW, but is currently locked. Then attempts to lock\r
304 the same variable using the Variable Lock Protocol. The call to Variable\r
305 Policy is expected to succeed and the call to Variable Lock also expected to\r
306 succeed.\r
307\r
308 @param[in] Context Unit test case context\r
309 **/\r
310UNIT_TEST_STATUS\r
311EFIAPI\r
312LockingALockedVariableWithMatchingDataShouldSucceed (\r
313 IN UNIT_TEST_CONTEXT Context\r
314 )\r
315{\r
316 EFI_STATUS Status;\r
317 VARIABLE_POLICY_ENTRY *NewEntry;\r
318 UINT8 Data;\r
319\r
320 // Create a variable policy that locks the variable.\r
321 Status = CreateVarStateVariablePolicy (&mTestGuid1,\r
322 TEST_VAR_1_NAME,\r
323 TEST_POLICY_MIN_SIZE_NULL,\r
324 TEST_POLICY_MAX_SIZE_200,\r
325 TEST_POLICY_ATTRIBUTES_NULL,\r
326 TEST_POLICY_ATTRIBUTES_NULL,\r
327 &mTestGuid2,\r
328 1,\r
329 TEST_VAR_2_NAME,\r
330 &NewEntry);\r
331 UT_ASSERT_NOT_EFI_ERROR (Status);\r
332\r
333 // Register the new policy.\r
334 Status = RegisterVariablePolicy (NewEntry);\r
335\r
336 // Configure the stub to not care about parameters. We're testing errors.\r
337 expect_any_always( StubGetVariableNull, VariableName );\r
338 expect_any_always( StubGetVariableNull, VendorGuid );\r
339 expect_any_always( StubGetVariableNull, DataSize );\r
340\r
341 // With a policy, make sure that writes still work, since the variable doesn't exist.\r
342 Data = 1;\r
343 will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // Attributes\r
344 will_return( StubGetVariableNull, sizeof (Data) ); // Size\r
4050c873 345 will_return( StubGetVariableNull, (UINTN)&Data ); // DataPtr\r
dcaa9393
MK
346 will_return( StubGetVariableNull, EFI_SUCCESS); // Status\r
347\r
348 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
349 UT_ASSERT_TRUE (!EFI_ERROR (Status));\r
350\r
351 FreePool (NewEntry);\r
352\r
353 return UNIT_TEST_PASSED;\r
354}\r
355\r
356/**\r
357 Test Case that locks a variable using the Variable Policy Protocol with a\r
358 policy other than LOCK_NOW, but variable data does not match. Then attempts\r
359 to lock the same variable using the Variable Lock Protocol. The call to\r
360 Variable Policy is expected to succeed and the call to Variable Lock is\r
361 expected to fail.\r
362\r
363 @param[in] Context Unit test case context\r
364 **/\r
365UNIT_TEST_STATUS\r
366EFIAPI\r
367LockingALockedVariableWithNonMatchingDataShouldFail (\r
368 IN UNIT_TEST_CONTEXT Context\r
369 )\r
370{\r
371 EFI_STATUS Status;\r
372 VARIABLE_POLICY_ENTRY *NewEntry;\r
373 UINT8 Data;\r
374\r
375 // Create a variable policy that locks the variable.\r
376 Status = CreateVarStateVariablePolicy (&mTestGuid1,\r
377 TEST_VAR_1_NAME,\r
378 TEST_POLICY_MIN_SIZE_NULL,\r
379 TEST_POLICY_MAX_SIZE_200,\r
380 TEST_POLICY_ATTRIBUTES_NULL,\r
381 TEST_POLICY_ATTRIBUTES_NULL,\r
382 &mTestGuid2,\r
383 1,\r
384 TEST_VAR_2_NAME,\r
385 &NewEntry);\r
386 UT_ASSERT_NOT_EFI_ERROR (Status);\r
387\r
388 // Register the new policy.\r
389 Status = RegisterVariablePolicy (NewEntry);\r
390\r
391 // Configure the stub to not care about parameters. We're testing errors.\r
392 expect_any_always( StubGetVariableNull, VariableName );\r
393 expect_any_always( StubGetVariableNull, VendorGuid );\r
394 expect_any_always( StubGetVariableNull, DataSize );\r
395\r
396 // With a policy, make sure that writes still work, since the variable doesn't exist.\r
397 Data = 2;\r
398 will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // Attributes\r
399 will_return( StubGetVariableNull, sizeof (Data) ); // Size\r
4050c873 400 will_return( StubGetVariableNull, (UINTN)&Data ); // DataPtr\r
dcaa9393
MK
401 will_return( StubGetVariableNull, EFI_SUCCESS); // Status\r
402\r
403 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
404 UT_ASSERT_TRUE (EFI_ERROR (Status));\r
405\r
406 FreePool (NewEntry);\r
407\r
408 return UNIT_TEST_PASSED;\r
409}\r
410\r
411/**\r
412 Test Case that locks a variable using Variable Lock Protocol Policy Protocol\r
413 then and then attempts to lock the same variable using the Variable Policy\r
414 Protocol. The call to Variable Lock is expected to succeed and the call to\r
415 Variable Policy is expected to fail.\r
416\r
417 @param[in] Context Unit test case context\r
418 **/\r
419UNIT_TEST_STATUS\r
420EFIAPI\r
421SettingPolicyForALockedVariableShouldFail (\r
422 IN UNIT_TEST_CONTEXT Context\r
423 )\r
424{\r
425 EFI_STATUS Status;\r
426 VARIABLE_POLICY_ENTRY *NewEntry;\r
427\r
428 // Lock the variable.\r
429 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);\r
430 UT_ASSERT_NOT_EFI_ERROR (Status);\r
431\r
432 // Create a variable policy that locks the variable.\r
433 Status = CreateVarStateVariablePolicy (&mTestGuid1,\r
434 TEST_VAR_1_NAME,\r
435 TEST_POLICY_MIN_SIZE_NULL,\r
436 TEST_POLICY_MAX_SIZE_200,\r
437 TEST_POLICY_ATTRIBUTES_NULL,\r
438 TEST_POLICY_ATTRIBUTES_NULL,\r
439 &mTestGuid2,\r
440 1,\r
441 TEST_VAR_2_NAME,\r
442 &NewEntry);\r
443 UT_ASSERT_NOT_EFI_ERROR (Status);\r
444\r
445 // Register the new policy.\r
446 Status = RegisterVariablePolicy (NewEntry);\r
447 UT_ASSERT_TRUE (EFI_ERROR (Status));\r
448\r
449 FreePool (NewEntry);\r
450\r
451 return UNIT_TEST_PASSED;\r
452}\r
453\r
454/**\r
455 Main entry point to this unit test application.\r
456\r
457 Sets up and runs the test suites.\r
458**/\r
459VOID\r
460EFIAPI\r
461UnitTestMain (\r
462 VOID\r
463 )\r
464{\r
465 EFI_STATUS Status;\r
466 UNIT_TEST_FRAMEWORK_HANDLE Framework;\r
467 UNIT_TEST_SUITE_HANDLE ShimTests;\r
468\r
469 Framework = NULL;\r
470\r
471 DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION));\r
472\r
473 //\r
474 // Start setting up the test framework for running the tests.\r
475 //\r
476 Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);\r
477 if (EFI_ERROR (Status)) {\r
478 DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));\r
479 goto EXIT;\r
480 }\r
481\r
482 //\r
483 // Add all test suites and tests.\r
484 //\r
485 Status = CreateUnitTestSuite (\r
486 &ShimTests, Framework,\r
487 "Variable Lock Shim Tests", "VarPolicy.VarLockShim", NULL, NULL\r
488 );\r
489 if (EFI_ERROR (Status)) {\r
490 DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ShimTests\n"));\r
491 Status = EFI_OUT_OF_RESOURCES;\r
492 goto EXIT;\r
493 }\r
494 AddTestCase (\r
495 ShimTests,\r
496 "Locking a variable with no matching policies should always work", "EmptyPolicies",\r
497 LockingWithoutAnyPoliciesShouldSucceed, LibInitMocked, LibCleanup, NULL\r
498 );\r
499 AddTestCase (\r
500 ShimTests,\r
501 "Locking a variable twice should always work", "DoubleLock",\r
502 LockingTwiceShouldSucceed, LibInitMocked, LibCleanup, NULL\r
503 );\r
504 AddTestCase (\r
505 ShimTests,\r
506 "Locking a variable that's already locked by another policy should work", "LockAfterPolicy",\r
507 LockingALockedVariableShouldSucceed, LibInitMocked, LibCleanup, NULL\r
508 );\r
509 AddTestCase (\r
510 ShimTests,\r
511 "Locking a variable that already has an unlocked policy should fail", "LockAfterUnlockedPolicy",\r
512 LockingAnUnlockedVariableShouldFail, LibInitMocked, LibCleanup, NULL\r
513 );\r
514 AddTestCase (\r
515 ShimTests,\r
516 "Locking a variable that already has an locked policy should succeed", "LockAfterLockedPolicyMatchingData",\r
517 LockingALockedVariableWithMatchingDataShouldSucceed, LibInitMocked, LibCleanup, NULL\r
518 );\r
519 AddTestCase (\r
520 ShimTests,\r
521 "Locking a variable that already has an locked policy with matching data should succeed", "LockAfterLockedPolicyNonMatchingData",\r
522 LockingALockedVariableWithNonMatchingDataShouldFail, LibInitMocked, LibCleanup, NULL\r
523 );\r
524 AddTestCase (\r
525 ShimTests,\r
526 "Adding a policy for a variable that has previously been locked should always fail", "SetPolicyAfterLock",\r
527 SettingPolicyForALockedVariableShouldFail, LibInitMocked, LibCleanup, NULL\r
528 );\r
529\r
530 //\r
531 // Execute the tests.\r
532 //\r
533 Status = RunAllTestSuites (Framework);\r
534\r
535EXIT:\r
536 if (Framework != NULL) {\r
537 FreeUnitTestFramework (Framework);\r
538 }\r
539\r
540 return;\r
541}\r
542\r
543///\r
544/// Avoid ECC error for function name that starts with lower case letter\r
545///\r
546#define Main main\r
547\r
548/**\r
549 Standard POSIX C entry point for host based unit test execution.\r
550\r
551 @param[in] Argc Number of arguments\r
552 @param[in] Argv Array of pointers to arguments\r
553\r
554 @retval 0 Success\r
555 @retval other Error\r
556**/\r
557INT32\r
558Main (\r
559 IN INT32 Argc,\r
560 IN CHAR8 *Argv[]\r
561 )\r
562{\r
563 UnitTestMain ();\r
564 return 0;\r
565}\r