aboutsummaryrefslogtreecommitdiff
path: root/src/burn/test/BurnUnitTest/RegistrationTest.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:06:54 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:36:06 -0700
commitaf10c45d7b3a44af0b461a557847fe03263dcc10 (patch)
tree6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/test/BurnUnitTest/RegistrationTest.cpp
parent9c2aed97299fb96aeee3f1471ce40225437aaecf (diff)
downloadwix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip
Move burn into burn
Diffstat (limited to 'src/burn/test/BurnUnitTest/RegistrationTest.cpp')
-rw-r--r--src/burn/test/BurnUnitTest/RegistrationTest.cpp772
1 files changed, 772 insertions, 0 deletions
diff --git a/src/burn/test/BurnUnitTest/RegistrationTest.cpp b/src/burn/test/BurnUnitTest/RegistrationTest.cpp
new file mode 100644
index 00000000..7b126f61
--- /dev/null
+++ b/src/burn/test/BurnUnitTest/RegistrationTest.cpp
@@ -0,0 +1,772 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6#define ROOT_PATH L"SOFTWARE\\WiX_Burn_UnitTest"
7#define HKLM_PATH L"SOFTWARE\\WiX_Burn_UnitTest\\HKLM"
8#define HKCU_PATH L"SOFTWARE\\WiX_Burn_UnitTest\\HKCU"
9#define REGISTRY_UNINSTALL_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
10#define REGISTRY_RUN_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"
11
12#define TEST_UNINSTALL_KEY L"HKEY_CURRENT_USER\\" HKCU_PATH L"\\" REGISTRY_UNINSTALL_KEY L"\\{D54F896D-1952-43e6-9C67-B5652240618C}"
13#define TEST_RUN_KEY L"HKEY_CURRENT_USER\\" HKCU_PATH L"\\" REGISTRY_RUN_KEY
14
15
16static LSTATUS APIENTRY RegistrationTest_RegCreateKeyExW(
17 __in HKEY hKey,
18 __in LPCWSTR lpSubKey,
19 __reserved DWORD Reserved,
20 __in_opt LPWSTR lpClass,
21 __in DWORD dwOptions,
22 __in REGSAM samDesired,
23 __in_opt CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
24 __out PHKEY phkResult,
25 __out_opt LPDWORD lpdwDisposition
26 );
27static LSTATUS APIENTRY RegistrationTest_RegOpenKeyExW(
28 __in HKEY hKey,
29 __in_opt LPCWSTR lpSubKey,
30 __reserved DWORD ulOptions,
31 __in REGSAM samDesired,
32 __out PHKEY phkResult
33 );
34static LSTATUS APIENTRY RegistrationTest_RegDeleteKeyExW(
35 __in HKEY hKey,
36 __in LPCWSTR lpSubKey,
37 __in REGSAM samDesired,
38 __reserved DWORD Reserved
39 );
40
41namespace Microsoft
42{
43namespace Tools
44{
45namespace WindowsInstallerXml
46{
47namespace Test
48{
49namespace Bootstrapper
50{
51 using namespace Microsoft::Win32;
52 using namespace System;
53 using namespace System::IO;
54 using namespace Xunit;
55
56 public ref class RegistrationTest : BurnUnitTest
57 {
58 public:
59 RegistrationTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture)
60 {
61 }
62
63 [Fact]
64 void RegisterBasicTest()
65 {
66 HRESULT hr = S_OK;
67 IXMLDOMElement* pixeBundle = NULL;
68 LPWSTR sczCurrentProcess = NULL;
69 BURN_VARIABLES variables = { };
70 BURN_USER_EXPERIENCE userExperience = { };
71 BOOTSTRAPPER_COMMAND command = { };
72 BURN_REGISTRATION registration = { };
73 BURN_LOGGING logging = { };
74 BURN_PACKAGES packages = { };
75 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
76
77 try
78 {
79 // set mock API's
80 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
81
82 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
83
84 logging.sczPath = L"BurnUnitTest.txt";
85
86 LPCWSTR wzDocument =
87 L"<Bundle>"
88 L" <UX>"
89 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
90 L" </UX>"
91 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
92 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
93 L" </Registration>"
94 L"</Bundle>";
95
96 // load XML document
97 LoadBundleXmlHelper(wzDocument, &pixeBundle);
98
99 hr = VariableInitialize(&variables);
100 TestThrowOnFailure(hr, L"Failed to initialize variables.");
101
102 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
103 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
104
105 hr = RegistrationParseFromXml(&registration, pixeBundle);
106 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
107
108 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
109 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
110
111 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
112 TestThrowOnFailure(hr, L"Failed to get current process path.");
113
114 // write registration
115 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
116 TestThrowOnFailure(hr, L"Failed to register bundle.");
117
118 // verify that registration was created
119 Assert::True(Directory::Exists(cacheDirectory));
120 Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe"))));
121
122 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
123 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)(Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr)));
124
125 // end session
126 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
127 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
128
129 // verify that registration was removed
130 Assert::False(Directory::Exists(cacheDirectory));
131
132 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
133 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
134 }
135 finally
136 {
137 ReleaseStr(sczCurrentProcess);
138 ReleaseObject(pixeBundle);
139 UserExperienceUninitialize(&userExperience);
140 RegistrationUninitialize(&registration);
141 VariablesUninitialize(&variables);
142
143 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
144 if (Directory::Exists(cacheDirectory))
145 {
146 Directory::Delete(cacheDirectory, true);
147 }
148
149 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
150 }
151 }
152
153 [Fact]
154 void RegisterArpMinimumTest()
155 {
156 HRESULT hr = S_OK;
157 IXMLDOMElement* pixeBundle = NULL;
158 LPWSTR sczCurrentProcess = NULL;
159 BURN_VARIABLES variables = { };
160 BURN_USER_EXPERIENCE userExperience = { };
161 BOOTSTRAPPER_COMMAND command = { };
162 BURN_REGISTRATION registration = { };
163 BURN_LOGGING logging = { };
164 BURN_PACKAGES packages = { };
165 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
166 try
167 {
168 // set mock API's
169 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
170
171 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
172
173 logging.sczPath = L"BurnUnitTest.txt";
174
175 LPCWSTR wzDocument =
176 L"<Bundle>"
177 L" <UX>"
178 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
179 L" </UX>"
180 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
181 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' DisplayVersion='1.0.0.0' />"
182 L" </Registration>"
183 L"</Bundle>";
184
185 // load XML document
186 LoadBundleXmlHelper(wzDocument, &pixeBundle);
187
188 hr = VariableInitialize(&variables);
189 TestThrowOnFailure(hr, L"Failed to initialize variables.");
190
191 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
192 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
193
194 hr = RegistrationParseFromXml(&registration, pixeBundle);
195 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
196
197 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
198 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
199
200 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
201 TestThrowOnFailure(hr, L"Failed to get current process path.");
202
203 //
204 // install
205 //
206
207 // write registration
208 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
209 TestThrowOnFailure(hr, L"Failed to register bundle.");
210
211 // verify that registration was created
212 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
213 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
214
215 // complete registration
216 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
217 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
218
219 // verify that registration was updated
220 Assert::Equal(Int32(BURN_RESUME_MODE_ARP), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
221 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
222 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
223
224 //
225 // uninstall
226 //
227
228 // write registration
229 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER, 0);
230 TestThrowOnFailure(hr, L"Failed to register bundle.");
231
232 // verify that registration was updated
233 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
234 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
235 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
236
237 // delete registration
238 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
239 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
240
241 // verify that registration was removed
242 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
243 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
244 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
245 }
246 finally
247 {
248 ReleaseStr(sczCurrentProcess);
249 ReleaseObject(pixeBundle);
250 UserExperienceUninitialize(&userExperience);
251 RegistrationUninitialize(&registration);
252 VariablesUninitialize(&variables);
253
254 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
255 if (Directory::Exists(cacheDirectory))
256 {
257 Directory::Delete(cacheDirectory, true);
258 }
259
260 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
261 }
262 }
263
264 [Fact]
265 void RegisterVariablesTest()
266 {
267 HRESULT hr = S_OK;
268 IXMLDOMElement* pixeBundle = NULL;
269 LPWSTR sczCurrentProcess = NULL;
270 BURN_VARIABLES variables = { };
271 BURN_USER_EXPERIENCE userExperience = { };
272 BOOTSTRAPPER_COMMAND command = { };
273 BURN_REGISTRATION registration = { };
274 BURN_LOGGING logging = { };
275 BURN_PACKAGES packages = { };
276 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
277 try
278 {
279 // set mock API's
280 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
281
282 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
283
284 logging.sczPath = L"BurnUnitTest.txt";
285
286 LPCWSTR wzDocument =
287 L"<Bundle>"
288 L" <UX>"
289 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
290 L" </UX>"
291 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='bar' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
292 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' DisplayVersion='1.0.0.0' />"
293 L" </Registration>"
294 L"</Bundle>";
295
296 // load XML document
297 LoadBundleXmlHelper(wzDocument, &pixeBundle);
298
299 hr = VariableInitialize(&variables);
300 TestThrowOnFailure(hr, L"Failed to initialize variables.");
301
302 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
303 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
304
305 hr = RegistrationParseFromXml(&registration, pixeBundle);
306 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
307
308 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
309 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
310
311 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
312 TestThrowOnFailure(hr, L"Failed to get current process path.");
313
314 //
315 // install
316 //
317
318 // write registration
319 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
320 TestThrowOnFailure(hr, L"Failed to register bundle.");
321
322 // verify that registration was created
323 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
324 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
325
326 // complete registration
327 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
328 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
329
330 // verify that registration variables were updated
331 registration.fInstalled = TRUE;
332
333 hr = RegistrationSetVariables(&registration, &variables);
334 TestThrowOnFailure(hr, L"Failed to set registration variables.");
335
336 Assert::Equal(1ll, VariableGetNumericHelper(&variables, BURN_BUNDLE_INSTALLED));
337 Assert::Equal(1ll, VariableGetNumericHelper(&variables, BURN_REBOOT_PENDING));
338 Assert::Equal<String^>(gcnew String(L"foo"), VariableGetStringHelper(&variables, BURN_BUNDLE_TAG));
339 Assert::Equal<String^>(gcnew String(L"bar"), VariableGetStringHelper(&variables, BURN_BUNDLE_PROVIDER_KEY));
340 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, BURN_BUNDLE_VERSION));
341
342 //
343 // uninstall
344 //
345
346 // delete registration
347 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
348 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
349
350 // verify that registration was removed
351 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
352 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
353 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
354 }
355 finally
356 {
357 ReleaseStr(sczCurrentProcess);
358 ReleaseObject(pixeBundle);
359 UserExperienceUninitialize(&userExperience);
360 RegistrationUninitialize(&registration);
361 VariablesUninitialize(&variables);
362
363 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
364 if (Directory::Exists(cacheDirectory))
365 {
366 Directory::Delete(cacheDirectory, true);
367 }
368
369 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
370 }
371 }
372
373 [Fact]
374 void RegisterArpFullTest()
375 {
376 HRESULT hr = S_OK;
377 IXMLDOMElement* pixeBundle = NULL;
378 LPWSTR sczCurrentProcess = NULL;
379 BURN_VARIABLES variables = { };
380 BURN_USER_EXPERIENCE userExperience = { };
381 BOOTSTRAPPER_COMMAND command = { };
382 BURN_REGISTRATION registration = { };
383 BURN_LOGGING logging = { };
384 BURN_PACKAGES packages = { };
385 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
386 try
387 {
388 // set mock API's
389 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
390
391 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
392
393 logging.sczPath = L"BurnUnitTest.txt";
394
395 LPCWSTR wzDocument =
396 L"<Bundle>"
397 L" <UX UxDllPayloadId='ux.dll'>"
398 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
399 L" </UX>"
400 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
401 L" <Arp Register='yes' DisplayName='DisplayName1' DisplayVersion='1.2.3.4' Publisher='Publisher1' HelpLink='http://www.microsoft.com/help'"
402 L" HelpTelephone='555-555-5555' AboutUrl='http://www.microsoft.com/about' UpdateUrl='http://www.microsoft.com/update'"
403 L" Comments='Comments1' Contact='Contact1' DisableModify='yes' DisableRemove='yes' />"
404 L" </Registration>"
405 L"</Bundle>";
406
407 // load XML document
408 LoadBundleXmlHelper(wzDocument, &pixeBundle);
409
410 hr = VariableInitialize(&variables);
411 TestThrowOnFailure(hr, L"Failed to initialize variables.");
412
413 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
414 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
415
416 hr = RegistrationParseFromXml(&registration, pixeBundle);
417 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
418
419 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
420 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
421
422 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
423 TestThrowOnFailure(hr, L"Failed to get current process path.");
424
425 //
426 // install
427 //
428
429 // write registration
430 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
431 TestThrowOnFailure(hr, L"Failed to register bundle.");
432
433 // verify that registration was created
434 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
435 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
436
437 // finish registration
438 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
439 TestThrowOnFailure(hr, L"Failed to register bundle.");
440
441 // verify that registration was updated
442 Assert::Equal(Int32(BURN_RESUME_MODE_ARP), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
443 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
444 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
445
446 Assert::Equal<String^>(gcnew String(L"DisplayName1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"DisplayName"), nullptr));
447 Assert::Equal<String^>(gcnew String(L"1.2.3.4"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"DisplayVersion"), nullptr));
448 Assert::Equal<String^>(gcnew String(L"Publisher1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Publisher"), nullptr));
449 Assert::Equal<String^>(gcnew String(L"http://www.microsoft.com/help"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"HelpLink"), nullptr));
450 Assert::Equal<String^>(gcnew String(L"555-555-5555"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"HelpTelephone"), nullptr));
451 Assert::Equal<String^>(gcnew String(L"http://www.microsoft.com/about"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"URLInfoAbout"), nullptr));
452 Assert::Equal<String^>(gcnew String(L"http://www.microsoft.com/update"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"URLUpdateInfo"), nullptr));
453 Assert::Equal<String^>(gcnew String(L"Comments1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Comments"), nullptr));
454 Assert::Equal<String^>(gcnew String(L"Contact1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Contact"), nullptr));
455 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"NoModify"), nullptr));
456 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"NoRemove"), nullptr));
457
458 //
459 // uninstall
460 //
461
462 // write registration
463 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER, 0);
464 TestThrowOnFailure(hr, L"Failed to register bundle.");
465
466 // verify that registration was updated
467 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
468 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
469
470 // delete registration
471 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
472 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
473
474 // verify that registration was removed
475 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
476 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
477 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
478 }
479 finally
480 {
481 ReleaseStr(sczCurrentProcess);
482 ReleaseObject(pixeBundle);
483 UserExperienceUninitialize(&userExperience);
484 RegistrationUninitialize(&registration);
485 VariablesUninitialize(&variables);
486
487 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
488 if (Directory::Exists(cacheDirectory))
489 {
490 Directory::Delete(cacheDirectory, true);
491 }
492
493 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
494 }
495 }
496
497 [Fact(Skip = "Currently fails")]
498 void ResumeTest()
499 {
500 HRESULT hr = S_OK;
501 IXMLDOMElement* pixeBundle = NULL;
502 LPWSTR sczCurrentProcess = NULL;
503 BURN_VARIABLES variables = { };
504 BURN_USER_EXPERIENCE userExperience = { };
505 BOOTSTRAPPER_COMMAND command = { };
506 BURN_REGISTRATION registration = { };
507 BURN_LOGGING logging = { };
508 BURN_PACKAGES packages = { };
509 BYTE rgbData[256] = { };
510 BOOTSTRAPPER_RESUME_TYPE resumeType = BOOTSTRAPPER_RESUME_TYPE_NONE;
511 BYTE* pbBuffer = NULL;
512 SIZE_T cbBuffer = 0;
513 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
514 try
515 {
516 for (DWORD i = 0; i < 256; ++i)
517 {
518 rgbData[i] = (BYTE)i;
519 }
520
521 // set mock API's
522 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
523
524 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
525
526 logging.sczPath = L"BurnUnitTest.txt";
527
528 LPCWSTR wzDocument =
529 L"<Bundle>"
530 L" <UX>"
531 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
532 L" </UX>"
533 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
534 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
535 L" </Registration>"
536 L"</Bundle>";
537
538 // load XML document
539 LoadBundleXmlHelper(wzDocument, &pixeBundle);
540
541 hr = VariableInitialize(&variables);
542 TestThrowOnFailure(hr, L"Failed to initialize variables.");
543
544 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
545 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
546
547 hr = RegistrationParseFromXml(&registration, pixeBundle);
548 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
549
550 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
551 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
552
553 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
554 TestThrowOnFailure(hr, L"Failed to get current process path.");
555
556 // read resume type before session
557 hr = RegistrationDetectResumeType(&registration, &resumeType);
558 TestThrowOnFailure(hr, L"Failed to read resume type.");
559
560 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
561
562 // begin session
563 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
564 TestThrowOnFailure(hr, L"Failed to register bundle.");
565
566 hr = RegistrationSaveState(&registration, rgbData, sizeof(rgbData));
567 TestThrowOnFailure(hr, L"Failed to save state.");
568
569 // read interrupted resume type
570 hr = RegistrationDetectResumeType(&registration, &resumeType);
571 TestThrowOnFailure(hr, L"Failed to read interrupted resume type.");
572
573 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED, (int)resumeType);
574
575 // suspend session
576 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_SUSPEND, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
577 TestThrowOnFailure(hr, L"Failed to suspend session.");
578
579 // verify that run key was removed
580 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
581
582 // read suspend resume type
583 hr = RegistrationDetectResumeType(&registration, &resumeType);
584 TestThrowOnFailure(hr, L"Failed to read suspend resume type.");
585
586 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_SUSPEND, (int)resumeType);
587
588 // read state back
589 hr = RegistrationLoadState(&registration, &pbBuffer, &cbBuffer);
590 TestThrowOnFailure(hr, L"Failed to load state.");
591
592 Assert::Equal((SIZE_T)sizeof(rgbData), cbBuffer);
593 Assert::True(0 == memcmp(pbBuffer, rgbData, sizeof(rgbData)));
594
595 // write active resume mode
596 hr = RegistrationSessionResume(&registration, &variables);
597 TestThrowOnFailure(hr, L"Failed to write active resume mode.");
598
599 // verify that run key was put back
600 Assert::NotEqual((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
601
602 // end session
603 hr = RegistrationSessionEnd(&registration, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
604 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
605
606 // read resume type after session
607 hr = RegistrationDetectResumeType(&registration, &resumeType);
608 TestThrowOnFailure(hr, L"Failed to read resume type.");
609
610 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
611 }
612 finally
613 {
614 ReleaseStr(sczCurrentProcess);
615 ReleaseObject(pixeBundle);
616 UserExperienceUninitialize(&userExperience);
617 RegistrationUninitialize(&registration);
618 VariablesUninitialize(&variables);
619
620 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
621 if (Directory::Exists(cacheDirectory))
622 {
623 Directory::Delete(cacheDirectory, true);
624 }
625
626 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
627 }
628 }
629
630 //BOOTSTRAPPER_RESUME_TYPE_NONE,
631 //BOOTSTRAPPER_RESUME_TYPE_INVALID, // resume information is present but invalid
632 //BOOTSTRAPPER_RESUME_TYPE_UNEXPECTED, // relaunched after an unexpected interruption
633 //BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING, // reboot has not taken place yet
634 //BOOTSTRAPPER_RESUME_TYPE_REBOOT, // relaunched after reboot
635 //BOOTSTRAPPER_RESUME_TYPE_SUSPEND, // relaunched after suspend
636 //BOOTSTRAPPER_RESUME_TYPE_ARP, // launched from ARP
637 };
638}
639}
640}
641}
642}
643
644
645static LSTATUS APIENTRY RegistrationTest_RegCreateKeyExW(
646 __in HKEY hKey,
647 __in LPCWSTR lpSubKey,
648 __reserved DWORD Reserved,
649 __in_opt LPWSTR lpClass,
650 __in DWORD dwOptions,
651 __in REGSAM samDesired,
652 __in_opt CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
653 __out PHKEY phkResult,
654 __out_opt LPDWORD lpdwDisposition
655 )
656{
657 LSTATUS ls = ERROR_SUCCESS;
658 LPCWSTR wzRoot = NULL;
659 HKEY hkRoot = NULL;
660
661 if (HKEY_LOCAL_MACHINE == hKey)
662 {
663 wzRoot = HKLM_PATH;
664 }
665 else if (HKEY_CURRENT_USER == hKey)
666 {
667 wzRoot = HKCU_PATH;
668 }
669 else
670 {
671 hkRoot = hKey;
672 }
673
674 if (wzRoot)
675 {
676 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE, &hkRoot);
677 if (ERROR_SUCCESS != ls)
678 {
679 ExitFunction();
680 }
681 }
682
683 ls = ::RegCreateKeyExW(hkRoot, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
684
685LExit:
686 ReleaseRegKey(hkRoot);
687
688 return ls;
689}
690
691static LSTATUS APIENTRY RegistrationTest_RegOpenKeyExW(
692 __in HKEY hKey,
693 __in_opt LPCWSTR lpSubKey,
694 __reserved DWORD ulOptions,
695 __in REGSAM samDesired,
696 __out PHKEY phkResult
697 )
698{
699 LSTATUS ls = ERROR_SUCCESS;
700 LPCWSTR wzRoot = NULL;
701 HKEY hkRoot = NULL;
702
703 if (HKEY_LOCAL_MACHINE == hKey)
704 {
705 wzRoot = HKLM_PATH;
706 }
707 else if (HKEY_CURRENT_USER == hKey)
708 {
709 wzRoot = HKCU_PATH;
710 }
711 else
712 {
713 hkRoot = hKey;
714 }
715
716 if (wzRoot)
717 {
718 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE, &hkRoot);
719 if (ERROR_SUCCESS != ls)
720 {
721 ExitFunction();
722 }
723 }
724
725 ls = ::RegOpenKeyExW(hkRoot, lpSubKey, ulOptions, samDesired, phkResult);
726
727LExit:
728 ReleaseRegKey(hkRoot);
729
730 return ls;
731}
732
733static LSTATUS APIENTRY RegistrationTest_RegDeleteKeyExW(
734 __in HKEY hKey,
735 __in LPCWSTR lpSubKey,
736 __in REGSAM samDesired,
737 __reserved DWORD Reserved
738 )
739{
740 LSTATUS ls = ERROR_SUCCESS;
741 LPCWSTR wzRoot = NULL;
742 HKEY hkRoot = NULL;
743
744 if (HKEY_LOCAL_MACHINE == hKey)
745 {
746 wzRoot = HKLM_PATH;
747 }
748 else if (HKEY_CURRENT_USER == hKey)
749 {
750 wzRoot = HKCU_PATH;
751 }
752 else
753 {
754 hkRoot = hKey;
755 }
756
757 if (wzRoot)
758 {
759 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE | samDesired, &hkRoot);
760 if (ERROR_SUCCESS != ls)
761 {
762 ExitFunction();
763 }
764 }
765
766 ls = ::RegDeleteKeyExW(hkRoot, lpSubKey, samDesired, Reserved);
767
768LExit:
769 ReleaseRegKey(hkRoot);
770
771 return ls;
772}