Skip to content

Testing and debugging AUpdater#

Unit-testing your UI#

checkForUpdatesImpl and downloadUpdateImpl are pure virtual, so a GMock subclass is all that is needed to drive your UI without network access. Assign AUpdater::status directly to simulate a state, and change progress of StatusDownloading to simulate a download. The status view from Update UI: progress, apply and restart is tested this way in aui.updater/tests/UpdaterStatusTest.cpp; combine it with aui::uitests (see Writing tests) to click on the buttons.

class MyUpdater : public AUpdater {
public:
    MOCK_METHOD(AFuture<void>, checkForUpdatesImpl, (), (override));
    MOCK_METHOD(AFuture<void>, downloadUpdateImpl, (const APath& unpackedUpdateDir), (override));
};

Testing version logic#

aui::updater::Semver and aui::updater::AppropriatePortablePackagePredicate are plain value types and are trivially testable; feed them tag names and file names captured from your real releases.

Testing the deployment#

The deployment replaces your application's files, so it cannot be tested in-process. The framework's own test (UpdaterTest.ApplyUpdate) launches a helper executable, aui.updater.test, with a --test=<dir> argument. A copy of the executable plus a marker file is placed in a temporary directory in advance, which imitates a downloaded update. The updater applies it, and the test checks the marker file appeared next to the original executable. To do the same in your app, override getUnpackedUpdateDir() and loadInstallCmdline() (protected virtuals of AUpdater) so the updater picks up a directory you prepared.

Note

The deployment test is compiled only for static AUI builds.

Debugging a failed update#

Deployment is performed by a separate process after your application exits, so errors do not show up in your log. The process id is logged by applyUpdateAndRestart, and the deployment log is the log file of that pid. See the "Debugging update deployment" section of AUpdater for an annotated example. A typical failure is "Text file busy" or "Access denied": the old process had not exited yet or an antivirus locks the file.

Common reasons why nothing happens:

  • AUpdater::isAvailable() is false: the executable is not writable, or the platform is unsupported.
  • The release has no archive matching the platform; getQualifierDebug() of the predicate prints what was expected.
  • The archive is not a ZIP, or does not contain the executable under the name returned by getModuleName().