Testing your deferred and rollback custom actions

When you include deferred custom actions — that somehow modify the machine — in your setup, you have two big responsibilities:

  1. Provide rollback custom actions that "undo" what the deferred CAs do so that the installation transaction is actually transactional.
  2. Test.
  3. Test.
  4. Test.

OK, so numbers 2 through 4 are kinda the same but not really: Even a simple installation (say, without patching or upgrades) has three different scenarios you need to test when you have deferred/rollback custom actions:

  1. Installation rollback.
  2. Repair rollback.
  3. Uninstallation rollback.
  4. All of the above.

The right behavior for each kind of rollback is usually the opposite action. Rolling back installation is uninstallation. Rolling back uninstallation is installation. Rolling back repair is usually installation. Mixing installation, repair, and uninstallation is possible if your package has user-selectable features and users go into maintenance mode to turn on and off features. And, of course, it’s always an option from the msiexec.exe command line using the ADDLOCAL/ADDSOURCE/ADDDEFAULT, REMOVE, and REINSTALL properties.

Testing rollback means testing failure

Windows Installer initiates rollback when an action fails, so to test rollback you need to cause a failure. WiX includes an easy way to trigger failure: The WixFailWhenDeferred custom action, part of WixUtilExtension, triggers a failure when it’s executed. Include it in your package by referencing WixUtilExtension (in your Votive .wixproj or via the -ext switch to the light.exe command line) and adding a CustomActionRef to your package authoring:

<CustomActionRef Id="WixFailWhenDeferred" />

WixFailWhenDeferred automatically schedules itself in InstallExecuteSequence before InstallFinalize, with a condition of:

WIXFAILWHENDEFERRED=1

The condition means that you can have one package to test all the different possible combinations of "normal" installation and rollback. Just pass the WIXFAILWHENDEFERRED=1 property value on the msiexec.exe command line to trigger rollback. For example:

msiexec /qb- /i intermediate.msi /L*vx installfail.log WIXFAILWHENDEFERRED=1
msiexec /qb- /i intermediate.msi /L*vx install.log
msiexec /qb- /fvamus intermediate.msi /L*vx repairfail.log WIXFAILWHENDEFERRED=1
msiexec /qb- /fvamus intermediate.msi /L*vx repair.log
msiexec /qb- /x intermediate.msi /L*vx uninstallfail.log WIXFAILWHENDEFERRED=1
msiexec /qb- /x intermediate.msi /L*vx uninstall.log

WixFailWhenDeferred has been in WiX v3 weekly releases since April.

5 thoughts on “Testing your deferred and rollback custom actions”

  1. Your missing a test case: Rollback disabled by policy. That’s going to break a lot of CA’s where people have been choosing Commit execution because the underlying API doesn’t support transactional changes.

    The problem is, this isn’t really what Commit was meant for. It was meant for cleaning up rollback data.

  2. I would think a better solution would be to either block the package as suggested by MSDN doco or have a conditionalized alternative custom action that schedules as Deferred execution instead of Commit execution in the event rollback is disabled by policy.

    Your suggestion that you don’t need to test for rollback policy and it’s the admins fault for doing it would lead to a very poor user experience IMO.

    http://msdn.microsoft.com/en-us/library/aa367991(VS.85).aspx

    “Rollback and commit custom actions do not run when rollback is disabled. If a package author requires these types of custom actions for proper installation, they should use the RollbackDisabled Property in a condition that prevents the installation from continuing when rollback is disabled.”

Comments are closed.