main
cpp 886 lines 42.7 KB
Raw
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 REGISTRY_UNINSTALL_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
7 #define REGISTRY_RUN_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"
8 #define TEST_BUNDLE_ID L"{D54F896D-1952-43E6-9C67-B5652240618C}"
9 #define TEST_BUNDLE_UPGRADE_CODE L"{89FDAE1F-8CC1-48B9-B930-3945E0D3E7F0}"
10
11
12 namespace Microsoft
13 {
14 namespace Tools
15 {
16 namespace WindowsInstallerXml
17 {
18 namespace Test
19 {
20 namespace Bootstrapper
21 {
22 using namespace Microsoft::Win32;
23 using namespace System;
24 using namespace System::IO;
25 using namespace Xunit;
26 using namespace WixInternal::TestSupport;
27
28 public ref class RegistrationTest : BurnUnitTest, IClassFixture<TestRegistryFixture^>
29 {
30 private:
31 TestRegistryFixture^ testRegistry;
32 String^ testRunKeyPath;
33 String^ testUninstallKeyPath;
34 String^ testVariableKeyPath;
35 public:
36 RegistrationTest(BurnTestFixture^ fixture, TestRegistryFixture^ registryFixture) : BurnUnitTest(fixture)
37 {
38 this->testRegistry = registryFixture;
39
40 this->testRunKeyPath = this->testRegistry->GetDirectHkcuPath(REG_KEY_DEFAULT, gcnew String(REGISTRY_RUN_KEY));
41 this->testUninstallKeyPath = this->testRegistry->GetDirectHkcuPath(REG_KEY_DEFAULT, gcnew String(REGISTRY_UNINSTALL_KEY), gcnew String(TEST_BUNDLE_ID));
42 this->testVariableKeyPath = Path::Combine(this->testUninstallKeyPath, gcnew String(L"variables"));
43 }
44
45 [Fact]
46 void RegisterBasicTest()
47 {
48 HRESULT hr = S_OK;
49 IXMLDOMElement* pixeBundle = NULL;
50 LPWSTR sczCurrentProcess = NULL;
51 BURN_VARIABLES variables = { };
52 BURN_USER_EXPERIENCE userExperience = { };
53 BOOTSTRAPPER_COMMAND command = { };
54 BURN_REGISTRATION registration = { };
55 BURN_LOGGING logging = { };
56 BURN_PACKAGES packages = { };
57 BURN_PLAN plan = { };
58 BURN_CACHE cache = { };
59 BURN_ENGINE_COMMAND internalCommand = { };
60 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(TEST_BUNDLE_ID));
61 String^ cacheExePath = Path::Combine(cacheDirectory, gcnew String(L"setup.exe"));
62 DWORD dwRegistrationOptions = BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE;
63 DWORD64 qwEstimatedSize = 1024;
64
65 try
66 {
67 this->testRegistry->SetUp();
68
69 logging.sczPath = L"BurnUnitTest.txt";
70
71 LPCWSTR wzDocument =
72 L"<Bundle>"
73 L" <UX PrimaryPayloadId='ux.exe'>"
74 L" <Payload Id='ux.exe' FilePath='ux.exe' Packaging='embedded' SourcePath='ux.exe' Hash='000000000000' />"
75 L" </UX>"
76 L" <Registration Id='{D54F896D-1952-43E6-9C67-B5652240618C}' UpgradeCode='{89FDAE1F-8CC1-48B9-B930-3945E0D3E7F0}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
77 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
78 L" </Registration>"
79 L"</Bundle>";
80
81 // load XML document
82 LoadBundleXmlHelper(wzDocument, &pixeBundle);
83
84 hr = CacheInitialize(&cache, &internalCommand);
85 TestThrowOnFailure(hr, L"Failed initialize cache.");
86
87 hr = VariableInitialize(&variables);
88 TestThrowOnFailure(hr, L"Failed to initialize variables.");
89
90 hr = BootstrapperApplicationParseFromXml(&userExperience, pixeBundle);
91 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
92
93 hr = RegistrationParseFromXml(&registration, &cache, pixeBundle);
94 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
95
96 plan.action = BOOTSTRAPPER_ACTION_INSTALL;
97 plan.pCommand = &command;
98 plan.pInternalCommand = &internalCommand;
99
100 hr = PlanSetResumeCommand(&plan, &registration, &logging);
101 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
102
103 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
104 TestThrowOnFailure(hr, L"Failed to get current process path.");
105
106 // write registration
107 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
108 TestThrowOnFailure(hr, L"Failed to register bundle.");
109
110 // verify that registration was created
111 Assert::True(Directory::Exists(cacheDirectory), "Cache directory didn't exist.");
112 Assert::True(File::Exists(Path::Combine(cacheDirectory, gcnew String(L"setup.exe"))), "Bundle exe wasn't cached.");
113
114 this->ValidateUninstallKeyString(L"InstallDate", DateTime::Now.ToString("yyyyMMdd"));
115 this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE));
116 this->ValidateRunOnceKeyEntry(cacheExePath);
117
118 // end session
119 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_NONE);
120 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
121
122 // verify that registration was removed
123 Assert::False(Directory::Exists(cacheDirectory), "Cache directory wasn't removed.");
124
125 this->ValidateUninstallKeyNull(L"InstallDate");
126 this->ValidateUninstallKeyNull(L"Resume");
127 this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr);
128 }
129 finally
130 {
131 ReleaseStr(sczCurrentProcess);
132 ReleaseObject(pixeBundle);
133 BootstrapperApplicationUninitialize(&userExperience);
134 RegistrationUninitialize(&registration);
135 VariablesUninitialize(&variables);
136
137 if (Directory::Exists(cacheDirectory))
138 {
139 Directory::Delete(cacheDirectory, true);
140 }
141
142 this->testRegistry->TearDown();
143 }
144 }
145
146 [Fact]
147 void RegisterArpMinimumTest()
148 {
149 HRESULT hr = S_OK;
150 IXMLDOMElement* pixeBundle = NULL;
151 LPWSTR sczCurrentProcess = NULL;
152 BURN_VARIABLES variables = { };
153 BURN_USER_EXPERIENCE userExperience = { };
154 BOOTSTRAPPER_COMMAND command = { };
155 BURN_REGISTRATION registration = { };
156 BURN_LOGGING logging = { };
157 BURN_PACKAGES packages = { };
158 BURN_PLAN plan = { };
159 BURN_CACHE cache = { };
160 BURN_ENGINE_COMMAND internalCommand = { };
161 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(TEST_BUNDLE_ID));
162 String^ cacheExePath = Path::Combine(cacheDirectory, gcnew String(L"setup.exe"));
163 DWORD dwRegistrationOptions = 0;
164 DWORD64 qwEstimatedSize = 1024;
165 try
166 {
167 this->testRegistry->SetUp();
168
169 logging.sczPath = L"BurnUnitTest.txt";
170
171 LPCWSTR wzDocument =
172 L"<Bundle>"
173 L" <UX PrimaryPayloadId='ux.exe'>"
174 L" <Payload Id='ux.exe' FilePath='ux.exe' Packaging='embedded' SourcePath='ux.exe' Hash='000000000000' />"
175 L" </UX>"
176 L" <Registration Id='{D54F896D-1952-43E6-9C67-B5652240618C}' UpgradeCode='{89FDAE1F-8CC1-48B9-B930-3945E0D3E7F0}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
177 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' InProgressDisplayName='Product1 Installation' DisplayVersion='1.0.0.0' />"
178 L" </Registration>"
179 L"</Bundle>";
180
181 // load XML document
182 LoadBundleXmlHelper(wzDocument, &pixeBundle);
183
184 hr = CacheInitialize(&cache, &internalCommand);
185 TestThrowOnFailure(hr, L"Failed initialize cache.");
186
187 hr = VariableInitialize(&variables);
188 TestThrowOnFailure(hr, L"Failed to initialize variables.");
189
190 hr = BootstrapperApplicationParseFromXml(&userExperience, pixeBundle);
191 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
192
193 hr = RegistrationParseFromXml(&registration, &cache, pixeBundle);
194 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
195
196 plan.action = BOOTSTRAPPER_ACTION_INSTALL;
197 plan.pCommand = &command;
198 plan.pInternalCommand = &internalCommand;
199
200 hr = PlanSetResumeCommand(&plan, &registration, &logging);
201 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
202
203 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
204 TestThrowOnFailure(hr, L"Failed to get current process path.");
205
206 //
207 // install
208 //
209
210 // write registration
211 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
212 TestThrowOnFailure(hr, L"Failed to register bundle.");
213
214 // verify that registration was created
215 this->ValidateUninstallKeyDisplayName(L"Product1 Installation");
216 this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE));
217 this->ValidateRunOnceKeyEntry(cacheExePath);
218
219 // complete registration
220 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
221 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
222
223 // verify that registration was updated
224 this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ARP));
225 this->ValidateUninstallKeyInstalled(0);
226 this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr);
227
228 //
229 // uninstall
230 //
231
232 // write registration
233 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
234 TestThrowOnFailure(hr, L"Failed to register bundle.");
235
236 // verify that registration was updated
237 this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE));
238 this->ValidateUninstallKeyInstalled(0);
239 this->ValidateRunOnceKeyEntry(cacheExePath);
240
241 // delete registration
242 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_NONE);
243 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
244
245 // verify that registration was removed
246 this->ValidateUninstallKeyNull(L"Resume");
247 this->ValidateUninstallKeyNull(L"Installed");
248 this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr);
249 }
250 finally
251 {
252 ReleaseStr(sczCurrentProcess);
253 ReleaseObject(pixeBundle);
254 BootstrapperApplicationUninitialize(&userExperience);
255 RegistrationUninitialize(&registration);
256 VariablesUninitialize(&variables);
257
258 if (Directory::Exists(cacheDirectory))
259 {
260 Directory::Delete(cacheDirectory, true);
261 }
262
263 this->testRegistry->TearDown();
264 }
265 }
266
267 [Fact]
268 void RegisterVariablesTest()
269 {
270 HRESULT hr = S_OK;
271 IXMLDOMElement* pixeBundle = NULL;
272 LPWSTR sczCurrentProcess = NULL;
273 BURN_VARIABLES variables = { };
274 BURN_USER_EXPERIENCE userExperience = { };
275 BOOTSTRAPPER_COMMAND command = { };
276 BURN_REGISTRATION registration = { };
277 BURN_LOGGING logging = { };
278 BURN_PACKAGES packages = { };
279 BURN_PLAN plan = { };
280 BURN_CACHE cache = { };
281 BURN_ENGINE_COMMAND internalCommand = { };
282 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(TEST_BUNDLE_ID));
283 String^ cacheExePath = Path::Combine(cacheDirectory, gcnew String(L"setup.exe"));
284 DWORD dwRegistrationOptions = 0;
285 DWORD64 qwEstimatedSize = 1024;
286 try
287 {
288 this->testRegistry->SetUp();
289
290 logging.sczPath = L"BurnUnitTest.txt";
291
292 LPCWSTR wzDocument =
293 L"<Bundle>"
294 L" <UX PrimaryPayloadId='ux.exe'>"
295 L" <Payload Id='ux.exe' FilePath='ux.exe' Packaging='embedded' SourcePath='ux.exe' Hash='000000000000' />"
296 L" </UX>"
297 L" <Registration Id='{D54F896D-1952-43E6-9C67-B5652240618C}' UpgradeCode='{89FDAE1F-8CC1-48B9-B930-3945E0D3E7F0}' Tag='foo' ProviderKey='bar' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
298 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' DisplayVersion='1.0.0.0' />"
299 L" </Registration>"
300 L"</Bundle>";
301
302 // load XML document
303 LoadBundleXmlHelper(wzDocument, &pixeBundle);
304
305 hr = CacheInitialize(&cache, &internalCommand);
306 TestThrowOnFailure(hr, L"Failed initialize cache.");
307
308 hr = VariableInitialize(&variables);
309 TestThrowOnFailure(hr, L"Failed to initialize variables.");
310
311 hr = BootstrapperApplicationParseFromXml(&userExperience, pixeBundle);
312 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
313
314 hr = RegistrationParseFromXml(&registration, &cache, pixeBundle);
315 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
316
317 plan.action = BOOTSTRAPPER_ACTION_INSTALL;
318 plan.pCommand = &command;
319 plan.pInternalCommand = &internalCommand;
320
321 hr = RegistrationSetVariables(&registration, &variables);
322 TestThrowOnFailure(hr, L"Failed to set registration variables.");
323
324 hr = PlanSetResumeCommand(&plan, &registration, &logging);
325 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
326
327 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
328 TestThrowOnFailure(hr, L"Failed to get current process path.");
329
330 //
331 // install
332 //
333
334 // write registration
335 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
336 TestThrowOnFailure(hr, L"Failed to register bundle.");
337
338 // verify that registration was created
339 this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE));
340 this->ValidateRunOnceKeyEntry(cacheExePath);
341
342 // complete registration
343 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_FULL);
344 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
345
346 // verify that registration variables were updated
347 this->ValidateUninstallKeyDisplayName(L"Product1");
348 registration.detectedRegistrationType = BOOTSTRAPPER_REGISTRATION_TYPE_FULL;
349
350 hr = RegistrationSetDynamicVariables(&registration, &variables);
351 TestThrowOnFailure(hr, L"Failed to set dynamic registration variables.");
352
353 Assert::Equal(1ll, VariableGetNumericHelper(&variables, BURN_BUNDLE_INSTALLED));
354 Assert::Equal<String^>(gcnew String(L"foo"), VariableGetStringHelper(&variables, BURN_BUNDLE_TAG));
355 Assert::Equal<String^>(gcnew String(L"bar"), VariableGetStringHelper(&variables, BURN_BUNDLE_PROVIDER_KEY));
356 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, BURN_BUNDLE_VERSION));
357
358 //
359 // uninstall
360 //
361
362 // delete registration
363 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_NONE);
364 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
365
366 // verify that registration was removed
367 this->ValidateUninstallKeyNull(L"Resume");
368 this->ValidateUninstallKeyNull(L"Installed");
369 this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr);
370 }
371 finally
372 {
373 ReleaseStr(sczCurrentProcess);
374 ReleaseObject(pixeBundle);
375 BootstrapperApplicationUninitialize(&userExperience);
376 RegistrationUninitialize(&registration);
377 VariablesUninitialize(&variables);
378
379 if (Directory::Exists(cacheDirectory))
380 {
381 Directory::Delete(cacheDirectory, true);
382 }
383
384 this->testRegistry->TearDown();
385 }
386 }
387
388 [Fact]
389 void RegisterArpFullTest()
390 {
391 HRESULT hr = S_OK;
392 IXMLDOMElement* pixeBundle = NULL;
393 LPWSTR sczCurrentProcess = NULL;
394 BURN_VARIABLES variables = { };
395 BURN_USER_EXPERIENCE userExperience = { };
396 BOOTSTRAPPER_COMMAND command = { };
397 BURN_REGISTRATION registration = { };
398 BURN_LOGGING logging = { };
399 BURN_PACKAGES packages = { };
400 BURN_PLAN plan = { };
401 BURN_CACHE cache = { };
402 BURN_ENGINE_COMMAND internalCommand = { };
403 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(TEST_BUNDLE_ID));
404 String^ cacheExePath = Path::Combine(cacheDirectory, gcnew String(L"setup.exe"));
405 DWORD dwRegistrationOptions = 0;
406 DWORD64 qwEstimatedSize = 1024;
407 try
408 {
409 this->testRegistry->SetUp();
410
411 logging.sczPath = L"BurnUnitTest.txt";
412
413 LPCWSTR wzDocument =
414 L"<Bundle>"
415 L" <UX PrimaryPayloadId='ux.exe'>"
416 L" <Payload Id='ux.exe' FilePath='ux.exe' Packaging='embedded' SourcePath='ux.exe' Hash='000000000000' />"
417 L" </UX>"
418 L" <Registration Id='{D54F896D-1952-43E6-9C67-B5652240618C}' UpgradeCode='{89FDAE1F-8CC1-48B9-B930-3945E0D3E7F0}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
419 L" <Arp Register='yes' DisplayName='DisplayName1' DisplayVersion='1.2.3.4' Publisher='Publisher1' HelpLink='http://www.microsoft.com/help'"
420 L" HelpTelephone='555-555-5555' AboutUrl='http://www.microsoft.com/about' UpdateUrl='http://www.microsoft.com/update'"
421 L" Comments='Comments1' Contact='Contact1' DisableModify='yes' DisableRemove='yes' />"
422 L" </Registration>"
423 L"</Bundle>";
424
425 // load XML document
426 LoadBundleXmlHelper(wzDocument, &pixeBundle);
427
428 hr = CacheInitialize(&cache, &internalCommand);
429 TestThrowOnFailure(hr, L"Failed initialize cache.");
430
431 hr = VariableInitialize(&variables);
432 TestThrowOnFailure(hr, L"Failed to initialize variables.");
433
434 hr = BootstrapperApplicationParseFromXml(&userExperience, pixeBundle);
435 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
436
437 hr = RegistrationParseFromXml(&registration, &cache, pixeBundle);
438 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
439
440 plan.action = BOOTSTRAPPER_ACTION_INSTALL;
441 plan.pCommand = &command;
442 plan.pInternalCommand = &internalCommand;
443
444 hr = PlanSetResumeCommand(&plan, &registration, &logging);
445 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
446
447 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
448 TestThrowOnFailure(hr, L"Failed to get current process path.");
449
450 //
451 // install
452 //
453
454 // write registration
455 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
456 TestThrowOnFailure(hr, L"Failed to register bundle.");
457
458 // verify that registration was created
459 this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE));
460 this->ValidateRunOnceKeyEntry(cacheExePath);
461
462 // finish registration
463 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_FULL);
464 TestThrowOnFailure(hr, L"Failed to register bundle.");
465
466 // verify that registration was updated
467 this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ARP));
468 this->ValidateUninstallKeyInstalled(1);
469 this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr);
470
471 this->ValidateUninstallKeyDisplayName(L"DisplayName1");
472 this->ValidateUninstallKeyString(L"DisplayVersion", L"1.2.3.4");
473 this->ValidateUninstallKeyString(L"Publisher", L"Publisher1");
474 this->ValidateUninstallKeyString(L"HelpLink", L"http://www.microsoft.com/help");
475 this->ValidateUninstallKeyString(L"HelpTelephone", L"555-555-5555");
476 this->ValidateUninstallKeyString(L"URLInfoAbout", L"http://www.microsoft.com/about");
477 this->ValidateUninstallKeyString(L"URLUpdateInfo", L"http://www.microsoft.com/update");
478 this->ValidateUninstallKeyString(L"Comments", L"Comments1");
479 this->ValidateUninstallKeyString(L"Contact", L"Contact1");
480 this->ValidateUninstallKeyNumber(L"NoModify", 1);
481 this->ValidateUninstallKeyNumber(L"NoRemove", 1);
482
483 //
484 // uninstall
485 //
486
487 // write registration
488 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
489 TestThrowOnFailure(hr, L"Failed to register bundle.");
490
491 // verify that registration was updated
492 this->ValidateUninstallKeyResume(Int32(BURN_RESUME_MODE_ACTIVE));
493 this->ValidateRunOnceKeyEntry(cacheExePath);
494
495 // delete registration
496 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_NONE);
497 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
498
499 // verify that registration was removed
500 this->ValidateUninstallKeyNull(L"Resume");
501 this->ValidateUninstallKeyNull(L"Installed");
502 this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr);
503 }
504 finally
505 {
506 ReleaseStr(sczCurrentProcess);
507 ReleaseObject(pixeBundle);
508 BootstrapperApplicationUninitialize(&userExperience);
509 RegistrationUninitialize(&registration);
510 VariablesUninitialize(&variables);
511
512 if (Directory::Exists(cacheDirectory))
513 {
514 Directory::Delete(cacheDirectory, true);
515 }
516
517 this->testRegistry->TearDown();
518 }
519 }
520
521 [Fact]
522 void DUtilButilTest()
523 {
524 HRESULT hr = S_OK;
525 IXMLDOMElement* pixeBundle = NULL;
526 LPWSTR sczCurrentProcess = NULL;
527 LPWSTR sczValue = NULL;
528 LPWSTR sczRelatedBundleId = NULL;
529 DWORD dwRelatedBundleIndex = 0;
530 BURN_VARIABLES variables = { };
531 BURN_USER_EXPERIENCE userExperience = { };
532 BOOTSTRAPPER_COMMAND command = { };
533 BURN_REGISTRATION registration = { };
534 BURN_LOGGING logging = { };
535 BURN_PACKAGES packages = { };
536 BURN_PLAN plan = { };
537 BURN_CACHE cache = { };
538 BURN_ENGINE_COMMAND internalCommand = { };
539 BYTE* pbBuffer = NULL;
540 SIZE_T cbBuffer = 0;
541 DWORD dwRegistrationOptions = 0;
542 DWORD64 qwEstimatedSize = 1024;
543
544 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(TEST_BUNDLE_ID));
545 try
546 {
547 this->testRegistry->SetUp();
548
549 logging.sczPath = L"BurnUnitTest.txt";
550
551 LPCWSTR wzDocument =
552 L"<Bundle>"
553 L" <UX PrimaryPayloadId='ux.exe'>"
554 L" <Payload Id='ux.exe' FilePath='ux.exe' Packaging='embedded' SourcePath='ux.exe' Hash='000000000000' />"
555 L" </UX>"
556 L" <RelatedBundle Id='" TEST_BUNDLE_UPGRADE_CODE L"' Action='Upgrade' />"
557 L" <Registration Id='" TEST_BUNDLE_ID L"' Tag='foo' ProviderKey='" TEST_BUNDLE_ID L"' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
558 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
559 L" </Registration>"
560 L" <Variable Id='MyBurnVariable1' Type='numeric' Value='0' Hidden='no' Persisted='yes' />"
561 L" <Variable Id='MyBurnVariable2' Type='string' Value='foo' Hidden='no' Persisted='yes' />"
562 L" <Variable Id='MyBurnVariable3' Type='version' Value='v1.1-alpha' Hidden='no' Persisted='yes' />"
563 L" <Variable Id='MyBurnVariable4' Type='string' Value='foo' Hidden='no' Persisted='no' />"
564 L" <Variable Id='MyBurnVariable5' Type='version' Hidden='no' Persisted='yes' />"
565 L"</Bundle>";
566
567 // load XML document
568 LoadBundleXmlHelper(wzDocument, &pixeBundle);
569
570 hr = CacheInitialize(&cache, &internalCommand);
571 TestThrowOnFailure(hr, L"Failed initialize cache.");
572
573 hr = VariableInitialize(&variables);
574 TestThrowOnFailure(hr, L"Failed to initialize variables.");
575
576 hr = VariablesParseFromXml(&variables, pixeBundle);
577 TestThrowOnFailure(hr, L"Failed to parse variables from XML.");
578
579 hr = BootstrapperApplicationParseFromXml(&userExperience, pixeBundle);
580 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
581
582 hr = RegistrationParseFromXml(&registration, &cache, pixeBundle);
583 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
584
585 plan.action = BOOTSTRAPPER_ACTION_INSTALL;
586 plan.pCommand = &command;
587 plan.pInternalCommand = &internalCommand;
588
589 hr = PlanSetResumeCommand(&plan, &registration, &logging);
590 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
591
592 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
593 TestThrowOnFailure(hr, L"Failed to get current process path.");
594
595 // begin session
596 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
597 TestThrowOnFailure(hr, L"Failed to register bundle.");
598
599 VariableSetNumericHelper(&variables, L"MyBurnVariable1", 42);
600 VariableSetStringHelper(&variables, L"MyBurnVariable2", L"bar", FALSE);
601 VariableSetVersionHelper(&variables, L"MyBurnVariable3", L"v1.0-beta");
602 VariableSetVersionHelper(&variables, L"MyBurnVariable5", L"vvv");
603
604 hr = VariableSerialize(&variables, TRUE, &pbBuffer, &cbBuffer);
605 TestThrowOnFailure(hr, "Failed to serialize variables.");
606
607 if (!Directory::Exists(cacheDirectory))
608 {
609 Directory::CreateDirectory(cacheDirectory);
610 }
611
612 hr = RegistrationSaveState(&registration, pbBuffer, cbBuffer);
613 TestThrowOnFailure(hr, L"Failed to save state.");
614
615 ReleaseNullMem(pbBuffer);
616 cbBuffer = 0;
617
618 // Verify the variables exist
619 this->ValidateVariableKey(L"MyBurnVariable1", gcnew String(L"42"));
620 this->ValidateVariableKey(L"MyBurnVariable2", gcnew String(L"bar"));
621 this->ValidateVariableKey(L"MyBurnVariable3", gcnew String(L"1.0-beta"));
622 this->ValidateVariableKey(L"MyBurnVariable5", gcnew String(L"vvv"));
623 this->ValidateVariableKeyEmpty(L"WixBundleForcedRestartPackage");
624
625 hr = StrAlloc(&sczRelatedBundleId, MAX_GUID_CHARS + 1);
626 NativeAssert::Succeeded(hr, "Failed to allocate buffer for related bundle id.");
627
628 // Verify we can find ourself via the UpgradeCode
629 hr = BundleEnumRelatedBundleFixed(TEST_BUNDLE_UPGRADE_CODE, BUNDLE_INSTALL_CONTEXT_USER, REG_KEY_DEFAULT, &dwRelatedBundleIndex, sczRelatedBundleId);
630 TestThrowOnFailure(hr, L"Failed to enumerate related bundle.");
631
632 NativeAssert::StringEqual(TEST_BUNDLE_ID, sczRelatedBundleId);
633
634 // Verify we can read the bundle variables via the API
635 hr = BundleGetBundleVariable(TEST_BUNDLE_ID, L"MyBurnVariable1", &sczValue);
636 TestThrowOnFailure(hr, L"Failed to read MyBurnVariable1.");
637
638 NativeAssert::StringEqual(L"42", sczValue);
639
640 // end session
641 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_NONE);
642 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
643 }
644 finally
645 {
646 ReleaseStr(sczRelatedBundleId);
647 ReleaseStr(sczCurrentProcess);
648 ReleaseObject(pixeBundle);
649 BootstrapperApplicationUninitialize(&userExperience);
650 RegistrationUninitialize(&registration);
651 VariablesUninitialize(&variables);
652
653 if (Directory::Exists(cacheDirectory))
654 {
655 Directory::Delete(cacheDirectory, true);
656 }
657
658 this->testRegistry->TearDown();
659 }
660 }
661
662 [Fact]
663 void ResumeTest()
664 {
665 HRESULT hr = S_OK;
666 IXMLDOMElement* pixeBundle = NULL;
667 LPWSTR sczCurrentProcess = NULL;
668 LPWSTR sczValue = NULL;
669 BURN_VARIABLES variables = { };
670 BURN_USER_EXPERIENCE userExperience = { };
671 BOOTSTRAPPER_COMMAND command = { };
672 BURN_REGISTRATION registration = { };
673 BURN_LOGGING logging = { };
674 BURN_PACKAGES packages = { };
675 BURN_PLAN plan = { };
676 BURN_CACHE cache = { };
677 BURN_ENGINE_COMMAND internalCommand = { };
678 BOOTSTRAPPER_RESUME_TYPE resumeType = BOOTSTRAPPER_RESUME_TYPE_NONE;
679 BYTE* pbBuffer = NULL;
680 SIZE_T cbBuffer = 0;
681 SIZE_T piBuffer = 0;
682 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(TEST_BUNDLE_ID));
683 String^ cacheExePath = Path::Combine(cacheDirectory, gcnew String(L"setup.exe"));
684 DWORD dwRegistrationOptions = 0;
685 DWORD64 qwEstimatedSize = 1024;
686 try
687 {
688 this->testRegistry->SetUp();
689
690 logging.sczPath = L"BurnUnitTest.txt";
691
692 LPCWSTR wzDocument =
693 L"<Bundle>"
694 L" <UX PrimaryPayloadId='ux.exe'>"
695 L" <Payload Id='ux.exe' FilePath='ux.exe' Packaging='embedded' SourcePath='ux.exe' Hash='000000000000' />"
696 L" </UX>"
697 L" <Registration Id='{D54F896D-1952-43E6-9C67-B5652240618C}' UpgradeCode='{89FDAE1F-8CC1-48B9-B930-3945E0D3E7F0}' Tag='foo' ProviderKey='foo' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
698 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='RegisterBasicTest' DisplayVersion='1.0.0.0' />"
699 L" </Registration>"
700 L" <Variable Id='MyBurnVariable1' Type='numeric' Value='0' Hidden='no' Persisted='yes' />"
701 L" <Variable Id='MyBurnVariable2' Type='string' Value='foo' Hidden='no' Persisted='yes' />"
702 L" <Variable Id='MyBurnVariable3' Type='version' Value='v1.1-alpha' Hidden='no' Persisted='yes' />"
703 L"</Bundle>";
704
705 // load XML document
706 LoadBundleXmlHelper(wzDocument, &pixeBundle);
707
708 hr = CacheInitialize(&cache, &internalCommand);
709 TestThrowOnFailure(hr, L"Failed initialize cache.");
710
711 hr = VariableInitialize(&variables);
712 TestThrowOnFailure(hr, L"Failed to initialize variables.");
713
714 hr = VariablesParseFromXml(&variables, pixeBundle);
715 TestThrowOnFailure(hr, L"Failed to parse variables from XML.");
716
717 hr = BootstrapperApplicationParseFromXml(&userExperience, pixeBundle);
718 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
719
720 hr = RegistrationParseFromXml(&registration, &cache, pixeBundle);
721 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
722
723 plan.action = BOOTSTRAPPER_ACTION_INSTALL;
724 plan.pCommand = &command;
725 plan.pInternalCommand = &internalCommand;
726
727 hr = PlanSetResumeCommand(&plan, &registration, &logging);
728 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
729
730 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
731 TestThrowOnFailure(hr, L"Failed to get current process path.");
732
733 // read resume type before session
734 hr = RegistrationDetectResumeType(&registration, &resumeType);
735 TestThrowOnFailure(hr, L"Failed to read resume type.");
736
737 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
738
739 // begin session
740 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
741 TestThrowOnFailure(hr, L"Failed to register bundle.");
742
743 VariableSetNumericHelper(&variables, L"MyBurnVariable1", 42);
744 VariableSetStringHelper(&variables, L"MyBurnVariable2", L"bar", FALSE);
745 VariableSetVersionHelper(&variables, L"MyBurnVariable3", L"v1.0-beta");
746
747 hr = VariableSerialize(&variables, TRUE, &pbBuffer, &cbBuffer);
748 TestThrowOnFailure(hr, "Failed to serialize variables.");
749
750 if (!Directory::Exists(cacheDirectory))
751 {
752 Directory::CreateDirectory(cacheDirectory);
753 }
754
755 hr = RegistrationSaveState(&registration, pbBuffer, cbBuffer);
756 TestThrowOnFailure(hr, L"Failed to save state.");
757
758 ReleaseNullMem(pbBuffer);
759 cbBuffer = 0;
760
761 // Verify the variables exist
762 this->ValidateVariableKey(L"MyBurnVariable1", gcnew String(L"42"));
763 this->ValidateVariableKey(L"MyBurnVariable2", gcnew String(L"bar"));
764 this->ValidateVariableKey(L"MyBurnVariable3", gcnew String(L"1.0-beta"));
765 this->ValidateVariableKeyEmpty(L"WixBundleForcedRestartPackage");
766
767 hr = BundleGetBundleVariable(TEST_BUNDLE_ID, L"MyBurnVariable1", &sczValue);
768 TestThrowOnFailure(hr, L"Failed to read MyBurnVariable1.");
769
770 NativeAssert::StringEqual(L"42", sczValue);
771
772 // read interrupted resume type
773 hr = RegistrationDetectResumeType(&registration, &resumeType);
774 TestThrowOnFailure(hr, L"Failed to read interrupted resume type.");
775
776 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED, (int)resumeType);
777
778 // suspend session
779 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_SUSPEND, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
780 TestThrowOnFailure(hr, L"Failed to suspend session.");
781
782 // verify that run key was removed
783 this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, nullptr);
784
785 // read suspend resume type
786 hr = RegistrationDetectResumeType(&registration, &resumeType);
787 TestThrowOnFailure(hr, L"Failed to read suspend resume type.");
788
789 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_SUSPEND, (int)resumeType);
790
791 // read state back
792 hr = RegistrationLoadState(&registration, &pbBuffer, &cbBuffer);
793 TestThrowOnFailure(hr, L"Failed to load state.");
794
795 hr = VariableDeserialize(&variables, TRUE, pbBuffer, cbBuffer, &piBuffer);
796 TestThrowOnFailure(hr, L"Failed to deserialize variables.");
797
798 // write active resume mode
799 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &cache, &variables, dwRegistrationOptions, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS);
800 TestThrowOnFailure(hr, L"Failed to write active resume mode.");
801
802 // verify that run key was put back
803 this->ValidateRunOnceKeyEntry(cacheExePath);
804
805 // end session
806 hr = RegistrationSessionEnd(&registration, &cache, &variables, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, qwEstimatedSize, BOOTSTRAPPER_REGISTRATION_TYPE_NONE);
807 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
808
809 // read resume type after session
810 hr = RegistrationDetectResumeType(&registration, &resumeType);
811 TestThrowOnFailure(hr, L"Failed to read resume type.");
812
813 Assert::Equal((int)BOOTSTRAPPER_RESUME_TYPE_NONE, (int)resumeType);
814 }
815 finally
816 {
817 ReleaseStr(sczCurrentProcess);
818 ReleaseObject(pixeBundle);
819 BootstrapperApplicationUninitialize(&userExperience);
820 RegistrationUninitialize(&registration);
821 VariablesUninitialize(&variables);
822
823 if (Directory::Exists(cacheDirectory))
824 {
825 Directory::Delete(cacheDirectory, true);
826 }
827
828 this->testRegistry->TearDown();
829 }
830 }
831
832 void ValidateRunOnceKeyString(LPCWSTR valueName, String^ expected)
833 {
834 WixAssert::StringEqual(expected, (String^)Registry::GetValue(this->testRunKeyPath, gcnew String(valueName), nullptr), false);
835 }
836
837 void ValidateRunOnceKeyEntry(String^ exePath)
838 {
839 this->ValidateRunOnceKeyString(TEST_BUNDLE_ID, String::Concat(L"\"", exePath, L"\" /burn.runonce"));
840 }
841
842 void ValidateUninstallKeyNull(LPCWSTR valueName)
843 {
844 Assert::Null(Registry::GetValue(this->testUninstallKeyPath, gcnew String(valueName), nullptr));
845 }
846
847 void ValidateUninstallKeyNumber(LPCWSTR valueName, Int32 expected)
848 {
849 Assert::Equal(expected, (Int32)Registry::GetValue(this->testUninstallKeyPath, gcnew String(valueName), nullptr));
850 }
851
852 void ValidateUninstallKeyString(LPCWSTR valueName, String^ expected)
853 {
854 WixAssert::StringEqual(expected, (String^)Registry::GetValue(this->testUninstallKeyPath, gcnew String(valueName), nullptr), false);
855 }
856
857 void ValidateUninstallKeyDisplayName(String^ expected)
858 {
859 this->ValidateUninstallKeyString(L"DisplayName", expected);
860 }
861
862 void ValidateUninstallKeyInstalled(Int32 expected)
863 {
864 this->ValidateUninstallKeyNumber(L"Installed", expected);
865 }
866
867 void ValidateUninstallKeyResume(Int32 expected)
868 {
869 this->ValidateUninstallKeyNumber(L"Resume", expected);
870 }
871
872 void ValidateVariableKey(LPCWSTR valueName, String^ expected)
873 {
874 WixAssert::StringEqual(expected, (String^)Registry::GetValue(this->testVariableKeyPath, gcnew String(valueName), nullptr), false);
875 }
876
877 void ValidateVariableKeyEmpty(LPCWSTR valueName)
878 {
879 Assert::Empty((System::Collections::IEnumerable^)Registry::GetValue(this->testVariableKeyPath, gcnew String(valueName), nullptr));
880 }
881 };
882 }
883 }
884 }
885 }
886 }