aboutsummaryrefslogtreecommitdiff
path: root/src/test/BurnUnitTest/RegistrationTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/BurnUnitTest/RegistrationTest.cpp')
-rw-r--r--src/test/BurnUnitTest/RegistrationTest.cpp655
1 files changed, 655 insertions, 0 deletions
diff --git a/src/test/BurnUnitTest/RegistrationTest.cpp b/src/test/BurnUnitTest/RegistrationTest.cpp
new file mode 100644
index 00000000..1ab6b8e9
--- /dev/null
+++ b/src/test/BurnUnitTest/RegistrationTest.cpp
@@ -0,0 +1,655 @@
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 WixTest;
55 using namespace Xunit;
56
57 public ref class RegistrationTest : BurnUnitTest
58 {
59 public:
60 [NamedFact]
61 void RegisterBasicTest()
62 {
63 HRESULT hr = S_OK;
64 IXMLDOMElement* pixeBundle = NULL;
65 LPWSTR sczCurrentProcess = NULL;
66 BURN_VARIABLES variables = { };
67 BURN_USER_EXPERIENCE userExperience = { };
68 BOOTSTRAPPER_COMMAND command = { };
69 BURN_REGISTRATION registration = { };
70 BURN_LOGGING logging = { };
71 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
72 try
73 {
74 // set mock API's
75 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
76
77 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
78
79 logging.sczPath = L"BurnUnitTest.txt";
80
81 LPCWSTR wzDocument =
82 L"<Bundle>"
83 L" <UX>"
84 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
85 L" </UX>"
86 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'>"
87 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
88 L" </Registration>"
89 L"</Bundle>";
90
91 // load XML document
92 LoadBundleXmlHelper(wzDocument, &pixeBundle);
93
94 hr = VariableInitialize(&variables);
95 TestThrowOnFailure(hr, L"Failed to initialize variables.");
96
97 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
98 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
99
100 hr = RegistrationParseFromXml(&registration, pixeBundle);
101 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
102
103 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
104 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
105
106 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
107 TestThrowOnFailure(hr, L"Failed to get current process path.");
108
109 // write registration
110 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
111 TestThrowOnFailure(hr, L"Failed to register bundle.");
112
113 // verify that registration was created
114 Assert::True(Directory::Exists(cacheDirectory));
115 Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe"))));
116
117 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
118 Assert::Equal(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)));
119
120 // end session
121 hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
122 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
123
124 // verify that registration was removed
125 Assert::False(Directory::Exists(cacheDirectory));
126
127 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
128 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
129 }
130 finally
131 {
132 ReleaseStr(sczCurrentProcess);
133 ReleaseObject(pixeBundle);
134 UserExperienceUninitialize(&userExperience);
135 RegistrationUninitialize(&registration);
136 VariablesUninitialize(&variables);
137
138 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
139 if (Directory::Exists(cacheDirectory))
140 {
141 Directory::Delete(cacheDirectory, true);
142 }
143
144 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
145 }
146 }
147
148 [NamedFact]
149 void RegisterArpMinimumTest()
150 {
151 HRESULT hr = S_OK;
152 IXMLDOMElement* pixeBundle = NULL;
153 LPWSTR sczCurrentProcess = NULL;
154 BURN_VARIABLES variables = { };
155 BURN_USER_EXPERIENCE userExperience = { };
156 BOOTSTRAPPER_COMMAND command = { };
157 BURN_REGISTRATION registration = { };
158 BURN_LOGGING logging = { };
159 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
160 try
161 {
162 // set mock API's
163 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
164
165 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
166
167 logging.sczPath = L"BurnUnitTest.txt";
168
169 LPCWSTR wzDocument =
170 L"<Bundle>"
171 L" <UX>"
172 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
173 L" </UX>"
174 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'>"
175 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' DisplayVersion='1.0.0.0' />"
176 L" </Registration>"
177 L"</Bundle>";
178
179 // load XML document
180 LoadBundleXmlHelper(wzDocument, &pixeBundle);
181
182 hr = VariableInitialize(&variables);
183 TestThrowOnFailure(hr, L"Failed to initialize variables.");
184
185 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
186 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
187
188 hr = RegistrationParseFromXml(&registration, pixeBundle);
189 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
190
191 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
192 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
193
194 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
195 TestThrowOnFailure(hr, L"Failed to get current process path.");
196
197 //
198 // install
199 //
200
201 // write registration
202 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
203 TestThrowOnFailure(hr, L"Failed to register bundle.");
204
205 // verify that registration was created
206 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
207 Assert::Equal(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));
208
209 // complete registration
210 hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
211 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
212
213 // verify that registration was updated
214 Assert::Equal(Int32(BURN_RESUME_MODE_ARP), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
215 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
216 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
217
218 //
219 // uninstall
220 //
221
222 // write registration
223 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER, 0);
224 TestThrowOnFailure(hr, L"Failed to register bundle.");
225
226 // verify that registration was updated
227 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
228 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
229 Assert::Equal(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));
230
231 // delete registration
232 hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
233 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
234
235 // verify that registration was removed
236 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
237 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
238 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
239 }
240 finally
241 {
242 ReleaseStr(sczCurrentProcess);
243 ReleaseObject(pixeBundle);
244 UserExperienceUninitialize(&userExperience);
245 RegistrationUninitialize(&registration);
246 VariablesUninitialize(&variables);
247
248 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
249 if (Directory::Exists(cacheDirectory))
250 {
251 Directory::Delete(cacheDirectory, true);
252 }
253
254 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
255 }
256 }
257
258 [NamedFact]
259 void RegisterArpFullTest()
260 {
261 HRESULT hr = S_OK;
262 IXMLDOMElement* pixeBundle = NULL;
263 LPWSTR sczCurrentProcess = NULL;
264 BURN_VARIABLES variables = { };
265 BURN_USER_EXPERIENCE userExperience = { };
266 BOOTSTRAPPER_COMMAND command = { };
267 BURN_REGISTRATION registration = { };
268 BURN_LOGGING logging = { };
269 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
270 try
271 {
272 // set mock API's
273 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
274
275 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
276
277 logging.sczPath = L"BurnUnitTest.txt";
278
279 LPCWSTR wzDocument =
280 L"<Bundle>"
281 L" <UX UxDllPayloadId='ux.dll'>"
282 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
283 L" </UX>"
284 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'>"
285 L" <Arp Register='yes' DisplayName='DisplayName1' DisplayVersion='1.2.3.4' Publisher='Publisher1' HelpLink='http://www.microsoft.com/help'"
286 L" HelpTelephone='555-555-5555' AboutUrl='http://www.microsoft.com/about' UpdateUrl='http://www.microsoft.com/update'"
287 L" Comments='Comments1' Contact='Contact1' DisableModify='yes' DisableRemove='yes' />"
288 L" </Registration>"
289 L"</Bundle>";
290
291 // load XML document
292 LoadBundleXmlHelper(wzDocument, &pixeBundle);
293
294 hr = VariableInitialize(&variables);
295 TestThrowOnFailure(hr, L"Failed to initialize variables.");
296
297 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
298 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
299
300 hr = RegistrationParseFromXml(&registration, pixeBundle);
301 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
302
303 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
304 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
305
306 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
307 TestThrowOnFailure(hr, L"Failed to get current process path.");
308
309 //
310 // install
311 //
312
313 // write registration
314 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
315 TestThrowOnFailure(hr, L"Failed to register bundle.");
316
317 // verify that registration was created
318 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
319 Assert::Equal(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));
320
321 // finish registration
322 hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
323 TestThrowOnFailure(hr, L"Failed to register bundle.");
324
325 // verify that registration was updated
326 Assert::Equal(Int32(BURN_RESUME_MODE_ARP), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
327 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
328 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
329
330 Assert::Equal(gcnew String(L"DisplayName1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"DisplayName"), nullptr));
331 Assert::Equal(gcnew String(L"1.2.3.4"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"DisplayVersion"), nullptr));
332 Assert::Equal(gcnew String(L"Publisher1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Publisher"), nullptr));
333 Assert::Equal(gcnew String(L"http://www.microsoft.com/help"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"HelpLink"), nullptr));
334 Assert::Equal(gcnew String(L"555-555-5555"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"HelpTelephone"), nullptr));
335 Assert::Equal(gcnew String(L"http://www.microsoft.com/about"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"URLInfoAbout"), nullptr));
336 Assert::Equal(gcnew String(L"http://www.microsoft.com/update"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"URLUpdateInfo"), nullptr));
337 Assert::Equal(gcnew String(L"Comments1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Comments"), nullptr));
338 Assert::Equal(gcnew String(L"Contact1"), (String^)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Contact"), nullptr));
339 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"NoModify"), nullptr));
340 Assert::Equal(1, (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"NoRemove"), nullptr));
341
342 //
343 // uninstall
344 //
345
346 // write registration
347 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER, 0);
348 TestThrowOnFailure(hr, L"Failed to register bundle.");
349
350 // verify that registration was updated
351 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
352 Assert::Equal(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));
353
354 // delete registration
355 hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
356 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
357
358 // verify that registration was removed
359 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
360 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
361 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
362 }
363 finally
364 {
365 ReleaseStr(sczCurrentProcess);
366 ReleaseObject(pixeBundle);
367 UserExperienceUninitialize(&userExperience);
368 RegistrationUninitialize(&registration);
369 VariablesUninitialize(&variables);
370
371 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
372 if (Directory::Exists(cacheDirectory))
373 {
374 Directory::Delete(cacheDirectory, true);
375 }
376
377 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
378 }
379 }
380
381 [NamedFact]
382 void ResumeTest()
383 {
384 HRESULT hr = S_OK;
385 IXMLDOMElement* pixeBundle = NULL;
386 LPWSTR sczCurrentProcess = NULL;
387 BURN_VARIABLES variables = { };
388 BURN_USER_EXPERIENCE userExperience = { };
389 BOOTSTRAPPER_COMMAND command = { };
390 BURN_REGISTRATION registration = { };
391 BURN_LOGGING logging = { };
392 BYTE rgbData[256] = { };
393 BOOTSTRAPPER_RESUME_TYPE resumeType = BOOTSTRAPPER_RESUME_TYPE_NONE;
394 BYTE* pbBuffer = NULL;
395 DWORD cbBuffer = 0;
396 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
397 try
398 {
399 for (DWORD i = 0; i < 256; ++i)
400 {
401 rgbData[i] = (BYTE)i;
402 }
403
404 // set mock API's
405 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
406
407 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
408
409 logging.sczPath = L"BurnUnitTest.txt";
410
411 LPCWSTR wzDocument =
412 L"<Bundle>"
413 L" <UX>"
414 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
415 L" </UX>"
416 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'>"
417 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
418 L" </Registration>"
419 L"</Bundle>";
420
421 // load XML document
422 LoadBundleXmlHelper(wzDocument, &pixeBundle);
423
424 hr = VariableInitialize(&variables);
425 TestThrowOnFailure(hr, L"Failed to initialize variables.");
426
427 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
428 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
429
430 hr = RegistrationParseFromXml(&registration, pixeBundle);
431 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
432
433 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
434 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
435
436 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
437 TestThrowOnFailure(hr, L"Failed to get current process path.");
438
439 // read resume type before session
440 hr = RegistrationDetectResumeType(&registration, &resumeType);
441 TestThrowOnFailure(hr, L"Failed to read resume type.");
442
443 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
444
445 // begin session
446 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
447 TestThrowOnFailure(hr, L"Failed to register bundle.");
448
449 hr = RegistrationSaveState(&registration, rgbData, sizeof(rgbData));
450 TestThrowOnFailure(hr, L"Failed to save state.");
451
452 // read interrupted resume type
453 hr = RegistrationDetectResumeType(&registration, &resumeType);
454 TestThrowOnFailure(hr, L"Failed to read interrupted resume type.");
455
456 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED, (int)resumeType);
457
458 // suspend session
459 hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_SUSPEND, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
460 TestThrowOnFailure(hr, L"Failed to suspend session.");
461
462 // verify that run key was removed
463 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
464
465 // read suspend resume type
466 hr = RegistrationDetectResumeType(&registration, &resumeType);
467 TestThrowOnFailure(hr, L"Failed to read suspend resume type.");
468
469 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_SUSPEND, (int)resumeType);
470
471 // read state back
472 hr = RegistrationLoadState(&registration, &pbBuffer, &cbBuffer);
473 TestThrowOnFailure(hr, L"Failed to load state.");
474
475 Assert::Equal((DWORD)sizeof(rgbData), cbBuffer);
476 Assert::True(0 == memcmp(pbBuffer, rgbData, sizeof(rgbData)));
477
478 // write active resume mode
479 hr = RegistrationSessionResume(&registration, &variables);
480 TestThrowOnFailure(hr, L"Failed to write active resume mode.");
481
482 // verify that run key was put back
483 Assert::NotEqual((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
484
485 // end session
486 hr = RegistrationSessionEnd(&registration, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
487 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
488
489 // read resume type after session
490 hr = RegistrationDetectResumeType(&registration, &resumeType);
491 TestThrowOnFailure(hr, L"Failed to read resume type.");
492
493 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
494 }
495 finally
496 {
497 ReleaseStr(sczCurrentProcess);
498 ReleaseObject(pixeBundle);
499 UserExperienceUninitialize(&userExperience);
500 RegistrationUninitialize(&registration);
501 VariablesUninitialize(&variables);
502
503 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
504 if (Directory::Exists(cacheDirectory))
505 {
506 Directory::Delete(cacheDirectory, true);
507 }
508
509 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
510 }
511 }
512
513 //BOOTSTRAPPER_RESUME_TYPE_NONE,
514 //BOOTSTRAPPER_RESUME_TYPE_INVALID, // resume information is present but invalid
515 //BOOTSTRAPPER_RESUME_TYPE_UNEXPECTED, // relaunched after an unexpected interruption
516 //BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING, // reboot has not taken place yet
517 //BOOTSTRAPPER_RESUME_TYPE_REBOOT, // relaunched after reboot
518 //BOOTSTRAPPER_RESUME_TYPE_SUSPEND, // relaunched after suspend
519 //BOOTSTRAPPER_RESUME_TYPE_ARP, // launched from ARP
520 };
521}
522}
523}
524}
525}
526
527
528static LSTATUS APIENTRY RegistrationTest_RegCreateKeyExW(
529 __in HKEY hKey,
530 __in LPCWSTR lpSubKey,
531 __reserved DWORD Reserved,
532 __in_opt LPWSTR lpClass,
533 __in DWORD dwOptions,
534 __in REGSAM samDesired,
535 __in_opt CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
536 __out PHKEY phkResult,
537 __out_opt LPDWORD lpdwDisposition
538 )
539{
540 LSTATUS ls = ERROR_SUCCESS;
541 LPCWSTR wzRoot = NULL;
542 HKEY hkRoot = NULL;
543
544 if (HKEY_LOCAL_MACHINE == hKey)
545 {
546 wzRoot = HKLM_PATH;
547 }
548 else if (HKEY_CURRENT_USER == hKey)
549 {
550 wzRoot = HKCU_PATH;
551 }
552 else
553 {
554 hkRoot = hKey;
555 }
556
557 if (wzRoot)
558 {
559 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE, &hkRoot);
560 if (ERROR_SUCCESS != ls)
561 {
562 ExitFunction();
563 }
564 }
565
566 ls = ::RegCreateKeyExW(hkRoot, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
567
568LExit:
569 ReleaseRegKey(hkRoot);
570
571 return ls;
572}
573
574static LSTATUS APIENTRY RegistrationTest_RegOpenKeyExW(
575 __in HKEY hKey,
576 __in_opt LPCWSTR lpSubKey,
577 __reserved DWORD ulOptions,
578 __in REGSAM samDesired,
579 __out PHKEY phkResult
580 )
581{
582 LSTATUS ls = ERROR_SUCCESS;
583 LPCWSTR wzRoot = NULL;
584 HKEY hkRoot = NULL;
585
586 if (HKEY_LOCAL_MACHINE == hKey)
587 {
588 wzRoot = HKLM_PATH;
589 }
590 else if (HKEY_CURRENT_USER == hKey)
591 {
592 wzRoot = HKCU_PATH;
593 }
594 else
595 {
596 hkRoot = hKey;
597 }
598
599 if (wzRoot)
600 {
601 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE, &hkRoot);
602 if (ERROR_SUCCESS != ls)
603 {
604 ExitFunction();
605 }
606 }
607
608 ls = ::RegOpenKeyExW(hkRoot, lpSubKey, ulOptions, samDesired, phkResult);
609
610LExit:
611 ReleaseRegKey(hkRoot);
612
613 return ls;
614}
615
616static LSTATUS APIENTRY RegistrationTest_RegDeleteKeyExW(
617 __in HKEY hKey,
618 __in LPCWSTR lpSubKey,
619 __in REGSAM samDesired,
620 __reserved DWORD Reserved
621 )
622{
623 LSTATUS ls = ERROR_SUCCESS;
624 LPCWSTR wzRoot = NULL;
625 HKEY hkRoot = NULL;
626
627 if (HKEY_LOCAL_MACHINE == hKey)
628 {
629 wzRoot = HKLM_PATH;
630 }
631 else if (HKEY_CURRENT_USER == hKey)
632 {
633 wzRoot = HKCU_PATH;
634 }
635 else
636 {
637 hkRoot = hKey;
638 }
639
640 if (wzRoot)
641 {
642 ls = ::RegOpenKeyExW(HKEY_CURRENT_USER, wzRoot, 0, KEY_WRITE | samDesired, &hkRoot);
643 if (ERROR_SUCCESS != ls)
644 {
645 ExitFunction();
646 }
647 }
648
649 ls = ::RegDeleteKeyExW(hkRoot, lpSubKey, samDesired, Reserved);
650
651LExit:
652 ReleaseRegKey(hkRoot);
653
654 return ls;
655}