diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /toolkit/mozapps/update/tests | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/mozapps/update/tests')
184 files changed, 18408 insertions, 0 deletions
diff --git a/toolkit/mozapps/update/tests/Makefile.in b/toolkit/mozapps/update/tests/Makefile.in new file mode 100644 index 000000000..0b8d19aa2 --- /dev/null +++ b/toolkit/mozapps/update/tests/Makefile.in @@ -0,0 +1,39 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +XPCSHELLTESTROOT = $(topobjdir)/_tests/xpcshell/$(relativesrcdir) + +pp_const_file = $(srcdir)/data/xpcshellConstantsPP.js + +PP_TARGETS += aus-test-const +aus-test-const := $(pp_const_file) +aus-test-const_PATH := $(XPCSHELLTESTROOT)/data +aus-test-const_FLAGS := -Fsubstitution $(DEFINES) $(ACDEFINES) +aus-test-const_TARGET := misc + +INI_TEST_FILES = \ + TestAUSReadStrings1.ini \ + TestAUSReadStrings2.ini \ + TestAUSReadStrings3.ini \ + $(NULL) + +MOZ_WINCONSOLE = 1 + +include $(topsrcdir)/config/rules.mk + +# TestAUSReadStrings runs during check in the following directory with a Unicode +# char in order to test bug 473417 on Windows. +ifeq ($(OS_ARCH),WINNT) +bug473417dir = test_bug473417-ó +else +bug473417dir = test_bug473417 +endif + +check:: + $(RM) -rf $(DEPTH)/_tests/updater/ && $(NSINSTALL) -D $(DEPTH)/_tests/updater/$(bug473417dir)/ + for i in $(INI_TEST_FILES); do \ + $(INSTALL) $(srcdir)/$$i $(DEPTH)/_tests/updater/$(bug473417dir)/; \ + done + $(INSTALL) $(FINAL_TARGET)/TestAUSReadStrings$(BIN_SUFFIX) $(DEPTH)/_tests/updater/$(bug473417dir)/ + @$(RUN_TEST_PROGRAM) $(DEPTH)/_tests/updater/$(bug473417dir)/TestAUSReadStrings$(BIN_SUFFIX) diff --git a/toolkit/mozapps/update/tests/TestAUSHelper.cpp b/toolkit/mozapps/update/tests/TestAUSHelper.cpp new file mode 100644 index 000000000..f71103b7a --- /dev/null +++ b/toolkit/mozapps/update/tests/TestAUSHelper.cpp @@ -0,0 +1,423 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +#ifdef XP_WIN +# include <windows.h> +# include <wintrust.h> +# include <tlhelp32.h> +# include <softpub.h> +# include <direct.h> +# include <io.h> + typedef WCHAR NS_tchar; +# define NS_main wmain +# ifndef F_OK +# define F_OK 00 +# endif +# ifndef W_OK +# define W_OK 02 +# endif +# ifndef R_OK +# define R_OK 04 +# endif +# if defined(_MSC_VER) && _MSC_VER < 1900 +# define stat _stat +# endif +# define NS_T(str) L ## str +# define NS_tsnprintf(dest, count, fmt, ...) \ + { \ + int _count = count - 1; \ + _snwprintf(dest, _count, fmt, ##__VA_ARGS__); \ + dest[_count] = L'\0'; \ + } +# define NS_taccess _waccess +# define NS_tchdir _wchdir +# define NS_tfopen _wfopen +# define NS_tstrcmp wcscmp +# define NS_ttoi _wtoi +# define NS_tstat _wstat +# define NS_tgetcwd _wgetcwd +# define LOG_S "%S" + +#include "../common/updatehelper.h" +#include "../common/certificatecheck.h" + +#else +# include <unistd.h> +# define NS_main main + typedef char NS_tchar; +# define NS_T(str) str +# define NS_tsnprintf snprintf +# define NS_taccess access +# define NS_tchdir chdir +# define NS_tfopen fopen +# define NS_tstrcmp strcmp +# define NS_ttoi atoi +# define NS_tstat stat +# define NS_tgetcwd getcwd +# define NS_tfputs fputs +# define LOG_S "%s" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# elif defined(MAX_PATH) +# define MAXPATHLEN MAX_PATH +# elif defined(_MAX_PATH) +# define MAXPATHLEN _MAX_PATH +# elif defined(CCHMAXPATH) +# define MAXPATHLEN CCHMAXPATH +# else +# define MAXPATHLEN 1024 +# endif +#endif + +static void +WriteMsg(const NS_tchar *path, const char *status) +{ + FILE* outFP = NS_tfopen(path, NS_T("wb")); + if (!outFP) { + return; + } + + fprintf(outFP, "%s\n", status); + fclose(outFP); + outFP = nullptr; +} + +static bool +CheckMsg(const NS_tchar *path, const char *expected) +{ + if (NS_taccess(path, F_OK)) { + return false; + } + + FILE *inFP = NS_tfopen(path, NS_T("rb")); + if (!inFP) { + return false; + } + + struct stat ms; + if (fstat(fileno(inFP), &ms)) { + fclose(inFP); + inFP = nullptr; + return false; + } + + char *mbuf = (char *) malloc(ms.st_size + 1); + if (!mbuf) { + fclose(inFP); + inFP = nullptr; + return false; + } + + size_t r = ms.st_size; + char *rb = mbuf; + size_t c = fread(rb, sizeof(char), 50, inFP); + r -= c; + rb += c; + if (c == 0 && r) { + free(mbuf); + fclose(inFP); + inFP = nullptr; + return false; + } + mbuf[ms.st_size] = '\0'; + rb = mbuf; + + bool isMatch = strcmp(rb, expected) == 0; + free(mbuf); + fclose(inFP); + inFP = nullptr; + return isMatch; +} + +int NS_main(int argc, NS_tchar **argv) +{ + if (argc == 2) { + if (!NS_tstrcmp(argv[1], NS_T("post-update-async")) || + !NS_tstrcmp(argv[1], NS_T("post-update-sync"))) { + NS_tchar exePath[MAXPATHLEN]; +#ifdef XP_WIN + if (!::GetModuleFileNameW(0, exePath, MAXPATHLEN)) { + return 1; + } +#else + strcpy(exePath, argv[0]); +#endif + NS_tchar runFilePath[MAXPATHLEN]; + NS_tsnprintf(runFilePath, sizeof(runFilePath)/sizeof(runFilePath[0]), + NS_T("%s.running"), exePath); +#ifdef XP_WIN + if (!NS_taccess(runFilePath, F_OK)) { + // This makes it possible to check if the post update process was + // launched twice which happens when the service performs an update. + NS_tchar runFilePathBak[MAXPATHLEN]; + NS_tsnprintf(runFilePathBak, sizeof(runFilePathBak)/sizeof(runFilePathBak[0]), + NS_T("%s.bak"), runFilePath); + MoveFileExW(runFilePath, runFilePathBak, MOVEFILE_REPLACE_EXISTING); + } +#endif + WriteMsg(runFilePath, "running"); + + if (!NS_tstrcmp(argv[1], NS_T("post-update-sync"))) { +#ifdef XP_WIN + Sleep(2000); +#else + sleep(2); +#endif + } + + NS_tchar logFilePath[MAXPATHLEN]; + NS_tsnprintf(logFilePath, sizeof(logFilePath)/sizeof(logFilePath[0]), + NS_T("%s.log"), exePath); + WriteMsg(logFilePath, "post-update"); + return 0; + } + } + + if (argc < 3) { + fprintf(stderr, \ + "\n" \ + "Application Update Service Test Helper\n" \ + "\n" \ + "Usage: WORKINGDIR INFILE OUTFILE -s SECONDS [FILETOLOCK]\n" \ + " or: WORKINGDIR LOGFILE [ARG2 ARG3...]\n" \ + " or: signature-check filepath\n" \ + " or: setup-symlink dir1 dir2 file symlink\n" \ + " or: remove-symlink dir1 dir2 file symlink\n" \ + " or: check-symlink symlink\n" \ + " or: post-update\n" \ + "\n" \ + " WORKINGDIR \tThe relative path to the working directory to use.\n" \ + " INFILE \tThe relative path from the working directory for the file to\n" \ + " \tread actions to perform such as finish.\n" \ + " OUTFILE \tThe relative path from the working directory for the file to\n" \ + " \twrite status information.\n" \ + " SECONDS \tThe number of seconds to sleep.\n" \ + " FILETOLOCK \tThe relative path from the working directory to an existing\n" \ + " \tfile to open exlusively.\n" \ + " \tOnly available on Windows platforms and silently ignored on\n" \ + " \tother platforms.\n" \ + " LOGFILE \tThe relative path from the working directory to log the\n" \ + " \tcommand line arguments.\n" \ + " ARG2 ARG3...\tArguments to write to the LOGFILE after the preceding command\n" \ + " \tline arguments.\n" \ + "\n" \ + "Note: All paths must be relative.\n" \ + "\n"); + return 1; + } + + if (!NS_tstrcmp(argv[1], NS_T("check-signature"))) { +#if defined(XP_WIN) && defined(MOZ_MAINTENANCE_SERVICE) + if (ERROR_SUCCESS == VerifyCertificateTrustForFile(argv[2])) { + return 0; + } else { + return 1; + } +#else + // Not implemented on non-Windows platforms + return 1; +#endif + } + + if (!NS_tstrcmp(argv[1], NS_T("setup-symlink"))) { +#ifdef XP_UNIX + NS_tchar path[MAXPATHLEN]; + NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), + NS_T("%s/%s"), NS_T("/tmp"), argv[2]); + mkdir(path, 0755); + NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), + NS_T("%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3]); + mkdir(path, 0755); + NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), + NS_T("%s/%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3], argv[4]); + FILE * file = NS_tfopen(path, NS_T("w")); + if (file) { + NS_tfputs(NS_T("test"), file); + fclose(file); + } + if (symlink(path, argv[5]) != 0) { + return 1; + } + NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), + NS_T("%s/%s"), NS_T("/tmp"), argv[2]); + if (argc > 6 && !NS_tstrcmp(argv[6], NS_T("change-perm"))) { + chmod(path, 0644); + } + return 0; +#else + // Not implemented on non-Unix platforms + return 1; +#endif + } + + if (!NS_tstrcmp(argv[1], NS_T("remove-symlink"))) { +#ifdef XP_UNIX + NS_tchar path[MAXPATHLEN]; + NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), + NS_T("%s/%s"), NS_T("/tmp"), argv[2]); + chmod(path, 0755); + NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), + NS_T("%s/%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3], argv[4]); + unlink(path); + NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), + NS_T("%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3]); + rmdir(path); + NS_tsnprintf(path, sizeof(path)/sizeof(path[0]), + NS_T("%s/%s"), NS_T("/tmp"), argv[2]); + rmdir(path); + return 0; +#else + // Not implemented on non-Unix platforms + return 1; +#endif + } + + if (!NS_tstrcmp(argv[1], NS_T("check-symlink"))) { +#ifdef XP_UNIX + struct stat ss; + lstat(argv[2], &ss); + return S_ISLNK(ss.st_mode) ? 0 : 1; +#else + // Not implemented on non-Unix platforms + return 1; +#endif + } + + if (!NS_tstrcmp(argv[1], NS_T("wait-for-service-stop"))) { +#ifdef XP_WIN + const int maxWaitSeconds = NS_ttoi(argv[3]); + LPCWSTR serviceName = argv[2]; + DWORD serviceState = WaitForServiceStop(serviceName, maxWaitSeconds); + if (SERVICE_STOPPED == serviceState) { + return 0; + } else { + return serviceState; + } +#else + // Not implemented on non-Windows platforms + return 1; +#endif + } + + if (!NS_tstrcmp(argv[1], NS_T("wait-for-application-exit"))) { +#ifdef XP_WIN + const int maxWaitSeconds = NS_ttoi(argv[3]); + LPCWSTR application = argv[2]; + DWORD ret = WaitForProcessExit(application, maxWaitSeconds); + if (ERROR_SUCCESS == ret) { + return 0; + } else if (WAIT_TIMEOUT == ret) { + return 1; + } else { + return 2; + } +#else + // Not implemented on non-Windows platforms + return 1; +#endif + } + + if (!NS_tstrcmp(argv[1], NS_T("is-process-running"))) { +#ifdef XP_WIN + LPCWSTR application = argv[2]; + return (ERROR_NOT_FOUND == IsProcessRunning(application)) ? 0 : 1; +#else + // Not implemented on non-Windows platforms + return 1; +#endif + } + + if (!NS_tstrcmp(argv[1], NS_T("launch-service"))) { +#ifdef XP_WIN + DWORD ret = LaunchServiceSoftwareUpdateCommand(argc - 2, (LPCWSTR *)argv + 2); + if (ret != ERROR_SUCCESS) { + // 192 is used to avoid reusing a possible return value from the call to + // WaitForServiceStop + return 0x000000C0; + } + // Wait a maximum of 120 seconds. + DWORD lastState = WaitForServiceStop(SVC_NAME, 120); + if (SERVICE_STOPPED == lastState) { + return 0; + } + return lastState; +#else + // Not implemented on non-Windows platforms + return 1; +#endif + } + + if (NS_tchdir(argv[1]) != 0) { + return 1; + } + + // File in use test helper section + if (!NS_tstrcmp(argv[4], NS_T("-s"))) { + NS_tchar *cwd = NS_tgetcwd(nullptr, 0); + NS_tchar inFilePath[MAXPATHLEN]; + NS_tsnprintf(inFilePath, sizeof(inFilePath)/sizeof(inFilePath[0]), + NS_T("%s/%s"), cwd, argv[2]); + NS_tchar outFilePath[MAXPATHLEN]; + NS_tsnprintf(outFilePath, sizeof(outFilePath)/sizeof(outFilePath[0]), + NS_T("%s/%s"), cwd, argv[3]); + + int seconds = NS_ttoi(argv[5]); +#ifdef XP_WIN + HANDLE hFile = INVALID_HANDLE_VALUE; + if (argc == 7) { + hFile = CreateFileW(argv[6], + DELETE | GENERIC_WRITE, 0, + nullptr, OPEN_EXISTING, 0, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + WriteMsg(outFilePath, "error_locking"); + return 1; + } + } + + WriteMsg(outFilePath, "sleeping"); + int i = 0; + while (!CheckMsg(inFilePath, "finish\n") && i++ <= seconds) { + Sleep(1000); + } + + if (argc == 7) { + CloseHandle(hFile); + } +#else + WriteMsg(outFilePath, "sleeping"); + int i = 0; + while (!CheckMsg(inFilePath, "finish\n") && i++ <= seconds) { + sleep(1); + } +#endif + WriteMsg(outFilePath, "finished"); + return 0; + } + + { + // Command line argument test helper section + NS_tchar logFilePath[MAXPATHLEN]; + NS_tsnprintf(logFilePath, sizeof(logFilePath)/sizeof(logFilePath[0]), + NS_T("%s"), argv[2]); + + FILE* logFP = NS_tfopen(logFilePath, NS_T("wb")); + for (int i = 1; i < argc; ++i) { + fprintf(logFP, LOG_S "\n", argv[i]); + } + + fclose(logFP); + logFP = nullptr; + } + + return 0; +} diff --git a/toolkit/mozapps/update/tests/TestAUSReadStrings.cpp b/toolkit/mozapps/update/tests/TestAUSReadStrings.cpp new file mode 100644 index 000000000..c1de44f8e --- /dev/null +++ b/toolkit/mozapps/update/tests/TestAUSReadStrings.cpp @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This binary tests the updater's ReadStrings ini parser and should run in a + * directory with a Unicode character to test bug 473417. + */ +#ifdef XP_WIN + #include <windows.h> + #define NS_main wmain + #define NS_tstrrchr wcsrchr + #define NS_T(str) L ## str + #define PATH_SEPARATOR_CHAR L'\\' + // On Windows, argv[0] can also have forward slashes instead + #define ALT_PATH_SEPARATOR_CHAR L'/' +#else + #include <unistd.h> + #define NS_main main + #define NS_tstrrchr strrchr + #define NS_T(str) str + #define PATH_SEPARATOR_CHAR '/' +#endif + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include "updater/resource.h" +#include "updater/progressui.h" +#include "common/readstrings.h" +#include "common/errors.h" +#include "mozilla/ArrayUtils.h" + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# elif defined(MAX_PATH) +# define MAXPATHLEN MAX_PATH +# elif defined(_MAX_PATH) +# define MAXPATHLEN _MAX_PATH +# elif defined(CCHMAXPATH) +# define MAXPATHLEN CCHMAXPATH +# else +# define MAXPATHLEN 1024 +# endif +#endif + +#define TEST_NAME "Updater ReadStrings" + +using namespace mozilla; + +static int gFailCount = 0; + +/** + * Prints the given failure message and arguments using printf, prepending + * "TEST-UNEXPECTED-FAIL " for the benefit of the test harness and + * appending "\n" to eliminate having to type it at each call site. + */ +void fail(const char* msg, ...) +{ + va_list ap; + + printf("TEST-UNEXPECTED-FAIL | "); + + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + + putchar('\n'); + ++gFailCount; +} + +int NS_main(int argc, NS_tchar **argv) +{ + printf("Running TestAUSReadStrings tests\n"); + + int rv = 0; + int retval; + NS_tchar inifile[MAXPATHLEN]; + StringTable testStrings; + + NS_tchar *slash = NS_tstrrchr(argv[0], PATH_SEPARATOR_CHAR); +#ifdef ALT_PATH_SEPARATOR_CHAR + NS_tchar *altslash = NS_tstrrchr(argv[0], ALT_PATH_SEPARATOR_CHAR); + slash = (slash > altslash) ? slash : altslash; +#endif // ALT_PATH_SEPARATOR_CHAR + + if (!slash) { + fail("%s | unable to find platform specific path separator (check 1)", TEST_NAME); + return 20; + } + + *(++slash) = '\0'; + // Test success when the ini file exists with both Title and Info in the + // Strings section and the values for Title and Info. + NS_tsnprintf(inifile, ArrayLength(inifile), NS_T("%sTestAUSReadStrings1.ini"), argv[0]); + retval = ReadStrings(inifile, &testStrings); + if (retval == OK) { + if (strcmp(testStrings.title, "Title Test - \xD0\x98\xD1\x81\xD0\xBF\xD1\x8B" \ + "\xD1\x82\xD0\xB0\xD0\xBD\xD0\xB8\xD0\xB5 " \ + "\xCE\x94\xCE\xBF\xCE\xBA\xCE\xB9\xCE\xBC\xCE\xAE " \ + "\xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88 " \ + "\xE6\xB8\xAC\xE8\xA9\xA6 " \ + "\xE6\xB5\x8B\xE8\xAF\x95") != 0) { + rv = 21; + fail("%s | Title ini value incorrect (check 3)", TEST_NAME); + } + + if (strcmp(testStrings.info, "Info Test - \xD0\x98\xD1\x81\xD0\xBF\xD1\x8B" \ + "\xD1\x82\xD0\xB0\xD0\xBD\xD0\xB8\xD0\xB5 " \ + "\xCE\x94\xCE\xBF\xCE\xBA\xCE\xB9\xCE\xBC\xCE\xAE " \ + "\xE3\x83\x86\xE3\x82\xB9\xE3\x83\x88 " \ + "\xE6\xB8\xAC\xE8\xA9\xA6 " \ + "\xE6\xB5\x8B\xE8\xAF\x95\xE2\x80\xA6") != 0) { + rv = 22; + fail("%s | Info ini value incorrect (check 4)", TEST_NAME); + } + } else { + fail("%s | ReadStrings returned %i (check 2)", TEST_NAME, retval); + rv = 23; + } + + // Test failure when the ini file exists without Title and with Info in the + // Strings section. + NS_tsnprintf(inifile, ArrayLength(inifile), NS_T("%sTestAUSReadStrings2.ini"), argv[0]); + retval = ReadStrings(inifile, &testStrings); + if (retval != PARSE_ERROR) { + rv = 24; + fail("%s | ReadStrings returned %i (check 5)", TEST_NAME, retval); + } + + // Test failure when the ini file exists with Title and without Info in the + // Strings section. + NS_tsnprintf(inifile, ArrayLength(inifile), NS_T("%sTestAUSReadStrings3.ini"), argv[0]); + retval = ReadStrings(inifile, &testStrings); + if (retval != PARSE_ERROR) { + rv = 25; + fail("%s | ReadStrings returned %i (check 6)", TEST_NAME, retval); + } + + // Test failure when the ini file doesn't exist + NS_tsnprintf(inifile, ArrayLength(inifile), NS_T("%sTestAUSReadStringsBogus.ini"), argv[0]); + retval = ReadStrings(inifile, &testStrings); + if (retval != READ_ERROR) { + rv = 26; + fail("%s | ini file doesn't exist (check 7)", TEST_NAME); + } + + // Test reading a non-default section name + NS_tsnprintf(inifile, ArrayLength(inifile), NS_T("%sTestAUSReadStrings3.ini"), argv[0]); + retval = ReadStrings(inifile, "Title\0", 1, &testStrings.title, "BogusSection2"); + if (retval == OK) { + if (strcmp(testStrings.title, "Bogus Title") != 0) { + rv = 27; + fail("%s | Title ini value incorrect (check 9)", TEST_NAME); + } + } else { + fail("%s | ReadStrings returned %i (check 8)", TEST_NAME, retval); + rv = 28; + } + + + if (rv == 0) { + printf("TEST-PASS | %s | all checks passed\n", TEST_NAME); + } else { + fail("%s | %i out of 9 checks failed", TEST_NAME, gFailCount); + } + + return rv; +} diff --git a/toolkit/mozapps/update/tests/TestAUSReadStrings1.ini b/toolkit/mozapps/update/tests/TestAUSReadStrings1.ini new file mode 100644 index 000000000..5ab13c185 --- /dev/null +++ b/toolkit/mozapps/update/tests/TestAUSReadStrings1.ini @@ -0,0 +1,47 @@ +; This file is in the UTF-8 encoding + +[BogusSection1] + +; Comment + +Title=Bogus Title + +; Comment + +Info=Bogus Info + +; Comment + +[Strings] + +Bogus1=Bogus1 + +; Comment + +Title=Title Test - ИÑпытание Δοκιμή テスト 測試 测试 + +; Comment + +Bogus2=Bogus2 + +; Comment + +Info=Info Test - ИÑпытание Δοκιμή テスト 測試 测试… + +; Comment + +Bogus3=Bogus3 + +; Comment + +[BogusSection2] + +; Comment + +Title=Bogus Title + +; Comment + +Info=Bogus Info + +; Comment diff --git a/toolkit/mozapps/update/tests/TestAUSReadStrings2.ini b/toolkit/mozapps/update/tests/TestAUSReadStrings2.ini new file mode 100644 index 000000000..8291a7c94 --- /dev/null +++ b/toolkit/mozapps/update/tests/TestAUSReadStrings2.ini @@ -0,0 +1,39 @@ +; This file is in the UTF-8 encoding + +[BogusSection1] + +; Comment + +Title=Bogus Title + +; Comment + +Info=Bogus Info + +; Comment + +[Strings] + +Bogus1=Bogus1 + +; Comment + +Info=Info + +; Comment + +Bogus2=Bogus2 + +; Comment + +[BogusSection2] + +; Comment + +Title=Bogus Title + +; Comment + +Info=Bogus Info + +; Comment diff --git a/toolkit/mozapps/update/tests/TestAUSReadStrings3.ini b/toolkit/mozapps/update/tests/TestAUSReadStrings3.ini new file mode 100644 index 000000000..a64d1232e --- /dev/null +++ b/toolkit/mozapps/update/tests/TestAUSReadStrings3.ini @@ -0,0 +1,39 @@ +; This file is in the UTF-8 encoding + +[BogusSection1] + +; Comment + +Title=Bogus Title + +; Comment + +Info=Bogus Info + +; Comment + +[Strings] + +Bogus1=Bogus1 + +; Comment + +Title=Title + +; Comment + +Bogus2=Bogus2 + +; Comment + +[BogusSection2] + +; Comment + +Title=Bogus Title + +; Comment + +Info=Bogus Info + +; Comment diff --git a/toolkit/mozapps/update/tests/chrome/.eslintrc.js b/toolkit/mozapps/update/tests/chrome/.eslintrc.js new file mode 100644 index 000000000..8c0f4f574 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/mochitest/chrome.eslintrc.js" + ] +}; diff --git a/toolkit/mozapps/update/tests/chrome/chrome.ini b/toolkit/mozapps/update/tests/chrome/chrome.ini new file mode 100644 index 000000000..88e3dd4e8 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/chrome.ini @@ -0,0 +1,64 @@ +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. + +[DEFAULT] +tags = appupdate +support-files = + utils.js + update.sjs + +; mochitest-chrome tests must start with "test_" and are executed in sorted +; order and not in the order specified in the manifest. +[test_0010_background_basic.xul] +[test_0011_check_basic.xul] +[test_0012_check_basic_staging.xul] +skip-if = asan +reason = Bug 1168003 +[test_0013_check_no_updates.xul] +[test_0014_check_error_xml_malformed.xul] +[test_0061_check_verifyFailPartial_noComplete.xul] +[test_0062_check_verifyFailComplete_noPartial.xul] +[test_0063_check_verifyFailPartialComplete.xul] +[test_0064_check_verifyFailPartial_successComplete.xul] +[test_0071_notify_verifyFailPartial_noComplete.xul] +[test_0072_notify_verifyFailComplete_noPartial.xul] +[test_0073_notify_verifyFailPartialComplete.xul] +[test_0074_notify_verifyFailPartial_successComplete.xul] +[test_0081_error_patchApplyFailure_partial_only.xul] +[test_0082_error_patchApplyFailure_complete_only.xul] +[test_0083_error_patchApplyFailure_partial_complete.xul] +[test_0084_error_patchApplyFailure_verify_failed.xul] +[test_0085_error_patchApplyFailure_partial_complete_staging.xul] +skip-if = asan +reason = Bug 1168003 +[test_0092_finishedBackground.xul] +[test_0093_restartNotification.xul] +[test_0094_restartNotification_remote.xul] +[test_0095_restartNotification_remoteInvalidNumber.xul] +[test_0096_restartNotification_stagedBackground.xul] +skip-if = asan +reason = Bug 1168003 +[test_0097_restartNotification_stagedServiceBackground.xul] +skip-if = os != 'win' +reason = only Windows has the maintenance service. +[test_0101_background_restartNotification.xul] +[test_0102_background_restartNotification_staging.xul] +skip-if = asan +reason = Bug 1168003 +[test_0103_background_restartNotification_stagingService.xul] +skip-if = os != 'win' +reason = only Windows has the maintenance service. +[test_0111_neverButton_basic.xul] +[test_0113_showNeverForVersionRemovedWithPref.xul] +[test_0151_notify_backgroundCheckError.xul] +[test_0152_notify_backgroundCheckOfflineRetry.xul] +[test_0161_check_unsupported.xul] +[test_0162_notify_unsupported.xul] +[test_0171_check_noPerms_manual.xul] +skip-if = os != 'win' +reason = test must be able to prevent file deletion. +[test_0172_notify_noPerms_manual.xul] +skip-if = os != 'win' +reason = test must be able to prevent file deletion. +[test_9999_cleanup.xul] diff --git a/toolkit/mozapps/update/tests/chrome/test_0010_background_basic.xul b/toolkit/mozapps/update/tests/chrome/test_0010_background_basic.xul new file mode 100644 index 000000000..8d088cc8a --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0010_background_basic.xul @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: basic, download, and finished" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FOUND_BASIC, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING +}, { + pageid: PAGEID_FINISHED, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1&showPrompt=1" + + getVersionParams(); + setUpdateURL(url); + + gAUS.checkForBackgroundUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0011_check_basic.xul b/toolkit/mozapps/update/tests/chrome/test_0011_check_basic.xul new file mode 100644 index 000000000..12b5302a4 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0011_check_basic.xul @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check, basic, download, and finished" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_FOUND_BASIC, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING +}, { + pageid: PAGEID_FINISHED, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1" + getVersionParams(); + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0012_check_basic_staging.xul b/toolkit/mozapps/update/tests/chrome/test_0012_check_basic_staging.xul new file mode 100644 index 000000000..d910adc08 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0012_check_basic_staging.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check, basic, download with staging, and finished" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_FOUND_BASIC, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING +}, { + pageid: PAGEID_FINISHED, + buttonClick: "extra1" +} ]; + +gUseTestUpdater = true; + +function runTest() { + debugDump("entering"); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1" + getVersionParams(); + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0013_check_no_updates.xul b/toolkit/mozapps/update/tests/chrome/test_0013_check_no_updates.xul new file mode 100644 index 000000000..c3f024c73 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0013_check_no_updates.xul @@ -0,0 +1,46 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check and no updates found" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_NO_UPDATES_FOUND, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?noUpdates=1"; + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0014_check_error_xml_malformed.xul b/toolkit/mozapps/update/tests/chrome/test_0014_check_error_xml_malformed.xul new file mode 100644 index 000000000..f399a0096 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0014_check_error_xml_malformed.xul @@ -0,0 +1,46 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check and error (xml malformed)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?xmlMalformed=1"; + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0061_check_verifyFailPartial_noComplete.xul b/toolkit/mozapps/update/tests/chrome/test_0061_check_verifyFailPartial_noComplete.xul new file mode 100644 index 000000000..1040c19e3 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0061_check_verifyFailPartial_noComplete.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check, basic, download, and errors (partial patch with an invalid size)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_FOUND_BASIC, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING +}, { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1&partialPatchOnly=1" + + "&invalidPartialSize=1" + getVersionParams(); + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0062_check_verifyFailComplete_noPartial.xul b/toolkit/mozapps/update/tests/chrome/test_0062_check_verifyFailComplete_noPartial.xul new file mode 100644 index 000000000..9221a4b98 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0062_check_verifyFailComplete_noPartial.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check, basic, download, and errors (complete patch with an invalid size)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_FOUND_BASIC, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING +}, { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1&completePatchOnly=1" + + "&invalidCompleteSize=1" + getVersionParams(); + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0063_check_verifyFailPartialComplete.xul b/toolkit/mozapps/update/tests/chrome/test_0063_check_verifyFailPartialComplete.xul new file mode 100644 index 000000000..8da5c7e97 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0063_check_verifyFailPartialComplete.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check, basic, download, and errors (partial and complete patches with invalid sizes)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_FOUND_BASIC, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING +}, { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1&invalidPartialSize=1" + + "&invalidCompleteSize=1" + getVersionParams(); + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0064_check_verifyFailPartial_successComplete.xul b/toolkit/mozapps/update/tests/chrome/test_0064_check_verifyFailPartial_successComplete.xul new file mode 100644 index 000000000..db0f33d2f --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0064_check_verifyFailPartial_successComplete.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check, basic, download, and finished (partial patch with an invalid size and successful complete patch)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_FOUND_BASIC, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING +}, { + pageid: PAGEID_FINISHED, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1&invalidPartialSize=1" + + getVersionParams(); + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0071_notify_verifyFailPartial_noComplete.xul b/toolkit/mozapps/update/tests/chrome/test_0071_notify_verifyFailPartial_noComplete.xul new file mode 100644 index 000000000..736df13a3 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0071_notify_verifyFailPartial_noComplete.xul @@ -0,0 +1,53 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: errors (partial patch with an invalid size)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("partial", null, null, null, "1234", null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, + Services.appinfo.platformVersion); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_DOWNLOADING); + reloadUpdateManagerData(); + + testPostUpdateProcessing(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0072_notify_verifyFailComplete_noPartial.xul b/toolkit/mozapps/update/tests/chrome/test_0072_notify_verifyFailComplete_noPartial.xul new file mode 100644 index 000000000..cafab4d27 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0072_notify_verifyFailComplete_noPartial.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: errors (complete patch with an invalid size)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("complete", null, null, null, "1234", null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_DOWNLOADING); + reloadUpdateManagerData(); + + testPostUpdateProcessing(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0073_notify_verifyFailPartialComplete.xul b/toolkit/mozapps/update/tests/chrome/test_0073_notify_verifyFailPartialComplete.xul new file mode 100644 index 000000000..c1db983a3 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0073_notify_verifyFailPartialComplete.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: errors (partial and complete patches with invalid sizes)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("partial", null, null, null, "1234", null, + STATE_DOWNLOADING) + + getLocalPatchString("complete", null, null, null, "1234", + "false"); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, null, + null, null, null, null, "false"); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_DOWNLOADING); + reloadUpdateManagerData(); + + testPostUpdateProcessing(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0074_notify_verifyFailPartial_successComplete.xul b/toolkit/mozapps/update/tests/chrome/test_0074_notify_verifyFailPartial_successComplete.xul new file mode 100644 index 000000000..2c28da768 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0074_notify_verifyFailPartial_successComplete.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: finishedBackground (partial patch with an invalid size and successful complete patch)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("partial", null, null, null, "1234", null, + STATE_DOWNLOADING) + + getLocalPatchString("complete", null, null, null, null, + "false"); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, null, + null, null, null, null, "false"); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_DOWNLOADING); + reloadUpdateManagerData(); + + testPostUpdateProcessing(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0081_error_patchApplyFailure_partial_only.xul b/toolkit/mozapps/update/tests/chrome/test_0081_error_patchApplyFailure_partial_only.xul new file mode 100644 index 000000000..10c34f63b --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0081_error_patchApplyFailure_partial_only.xul @@ -0,0 +1,53 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: errors (partial only patch apply failure)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("partial", null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, null, + null, null, null, null, "false"); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_FAILED_CRC_ERROR); + reloadUpdateManagerData(); + + testPostUpdateProcessing(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0082_error_patchApplyFailure_complete_only.xul b/toolkit/mozapps/update/tests/chrome/test_0082_error_patchApplyFailure_complete_only.xul new file mode 100644 index 000000000..2c4b389f4 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0082_error_patchApplyFailure_complete_only.xul @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: errors (complete only patch apply failure)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_ERRORS, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("complete", null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_FAILED_CRC_ERROR); + reloadUpdateManagerData(); + + testPostUpdateProcessing(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0083_error_patchApplyFailure_partial_complete.xul b/toolkit/mozapps/update/tests/chrome/test_0083_error_patchApplyFailure_partial_complete.xul new file mode 100644 index 000000000..01adb1c3d --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0083_error_patchApplyFailure_partial_complete.xul @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: error patching, download, and finished (partial failed and download complete)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_ERROR_PATCHING, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING, + extraStartFunction: createContinueFile +}, { + pageid: PAGEID_FINISHED, + buttonClick: "extra1", + extraStartFunction: removeContinueFile +} ]; + +function runTest() { + debugDump("entering"); + + removeContinueFile(); + + // Specify the url to update.sjs with a slowDownloadMar param so the ui can + // load before the download completes. + let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1"; + let patches = getLocalPatchString("partial", null, null, null, null, null, + STATE_PENDING) + + getLocalPatchString("complete", slowDownloadURL, null, null, + null, "false"); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, null, + null, null, null, null, "false"); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_FAILED_CRC_ERROR); + reloadUpdateManagerData(); + + testPostUpdateProcessing(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0084_error_patchApplyFailure_verify_failed.xul b/toolkit/mozapps/update/tests/chrome/test_0084_error_patchApplyFailure_verify_failed.xul new file mode 100644 index 000000000..2e0c2b41e --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0084_error_patchApplyFailure_verify_failed.xul @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: error patching, download, and errors (partial failed and download complete verification failure)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_ERROR_PATCHING, + buttonClick: "next" +}, { + pageid: PAGEID_DOWNLOADING, + extraStartFunction: createContinueFile +}, { + pageid: PAGEID_ERRORS, + buttonClick: "finish", + extraStartFunction: removeContinueFile +} ]; + +function runTest() { + debugDump("entering"); + + removeContinueFile(); + + // Specify the url to update.sjs with a slowDownloadMar param so the ui can + // load before the download completes. + let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1"; + let patches = getLocalPatchString("partial", null, null, null, null, null, + STATE_PENDING) + + getLocalPatchString("complete", slowDownloadURL, "MD5", + null, "1234", + "false"); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, null, + null, null, null, null, "false"); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_FAILED_CRC_ERROR); + reloadUpdateManagerData(); + + testPostUpdateProcessing(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0085_error_patchApplyFailure_partial_complete_staging.xul b/toolkit/mozapps/update/tests/chrome/test_0085_error_patchApplyFailure_partial_complete_staging.xul new file mode 100644 index 000000000..fc83505f9 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0085_error_patchApplyFailure_partial_complete_staging.xul @@ -0,0 +1,94 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: error patching, download with staging, and finished (partial failed and download complete), with fast MAR download" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +// This test forces the download to complete before the "next" button on the +// errorpatching wizard page is clicked. This is done by creating the continue +// file when the wizard loads to start the download, then clicking the "next" +// button in the download's onStopRequest event listener. + +const testDownloadListener = { + onStartRequest(aRequest, aContext) { }, + + onProgress(aRequest, aContext, aProgress, aMaxProgress) { }, + + onStatus(aRequest, aContext, aStatus, aStatusText) { }, + + onStopRequest(aRequest, aContext, aStatus) { + debugDump("clicking errorpatching page next button"); + gDocElem.getButton("next").click(); + gAUS.removeDownloadListener(this); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver, + Ci.nsIProgressEventSink]) +}; + +let TESTS = [ { + pageid: PAGEID_ERROR_PATCHING, + extraCheckFunction: createContinueFile +}, { + pageid: PAGEID_DOWNLOADING +}, { + pageid: PAGEID_FINISHED, + buttonClick: "extra1", + extraStartFunction: removeContinueFile +} ]; + +gUseTestUpdater = true; + +function runTest() { + debugDump("entering"); + + removeContinueFile(); + + // Specify the url to update.sjs with a slowDownloadMar param so the ui can + // load before the download completes. + let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1"; + let patches = getLocalPatchString("partial", null, null, null, null, null, + STATE_PENDING) + + getLocalPatchString("complete", slowDownloadURL, null, null, + null, "false"); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, null, + null, null, null, null, "false"); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_FAILED_READ_ERROR); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true); + + reloadUpdateManagerData(); + + testPostUpdateProcessing(); + + gAUS.addDownloadListener(testDownloadListener); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0092_finishedBackground.xul b/toolkit/mozapps/update/tests/chrome/test_0092_finishedBackground.xul new file mode 100644 index 000000000..a0b29ddea --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0092_finishedBackground.xul @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: finished background" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("complete", null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, + Services.appinfo.platformVersion); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_SUCCEEDED); + + reloadUpdateManagerData(); + + is(gUpdateManager.activeUpdate.state, "pending", + "The active update should have a state of pending"); + + gUP.showUpdateDownloaded(gUpdateManager.activeUpdate); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0093_restartNotification.xul b/toolkit/mozapps/update/tests/chrome/test_0093_restartNotification.xul new file mode 100644 index 000000000..6db5b9897 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0093_restartNotification.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: restart notification pref promptWaitTime" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("complete", null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_SUCCEEDED); + + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 1); + + reloadUpdateManagerData(); + + is(gUpdateManager.activeUpdate.state, STATE_PENDING, + "The active update should have a state of " + STATE_PENDING); + + ok(gUpdateManager.activeUpdate.promptWaitTime == 1, "Checking that the " + + "update's promptWaitTime attribute value was set from the " + + PREF_APP_UPDATE_PROMPTWAITTIME + " preference"); + + gUP.showUpdateDownloaded(gUpdateManager.activeUpdate, true); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0094_restartNotification_remote.xul b/toolkit/mozapps/update/tests/chrome/test_0094_restartNotification_remote.xul new file mode 100644 index 000000000..6e72a42c1 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0094_restartNotification_remote.xul @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: restart notification xml promptWaitTime" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("complete", null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, null, + null, null, null, null, false, + null, false, false, false, 1); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_SUCCEEDED); + + reloadUpdateManagerData(); + + is(gUpdateManager.activeUpdate.state, STATE_PENDING, + "The active update should have a state of " + STATE_PENDING); + + ok(gUpdateManager.activeUpdate.promptWaitTime == 1, "Checking that the " + + "update's promptWaitTime attribute value was set by the XML"); + + gUP.showUpdateDownloaded(gUpdateManager.activeUpdate, true); + +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0095_restartNotification_remoteInvalidNumber.xul b/toolkit/mozapps/update/tests/chrome/test_0095_restartNotification_remoteInvalidNumber.xul new file mode 100644 index 000000000..5b1b826a5 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0095_restartNotification_remoteInvalidNumber.xul @@ -0,0 +1,66 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: restart notification xml promptWaitTime with invalid number" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("complete", null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, + null, null, + null, null, null, + null, false, null, + false, false, + false, "invalidNumber"); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_SUCCEEDED); + + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 1); + + reloadUpdateManagerData(); + + is(gUpdateManager.activeUpdate.state, STATE_PENDING, + "The active update should have a state of " + STATE_PENDING); + + ok(gUpdateManager.activeUpdate.promptWaitTime == 1, "Checking that the " + + "update's promptWaitTime attribute value was set from the " + + PREF_APP_UPDATE_PROMPTWAITTIME + " preference"); + + gUP.showUpdateDownloaded(gUpdateManager.activeUpdate, true); + +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0096_restartNotification_stagedBackground.xul b/toolkit/mozapps/update/tests/chrome/test_0096_restartNotification_stagedBackground.xul new file mode 100644 index 000000000..b86861012 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0096_restartNotification_stagedBackground.xul @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: restart notification staged w/o service" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +gUseTestUpdater = true; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("complete", null, null, null, null, null, + STATE_APPLIED); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, + Services.appinfo.platformVersion); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_APPLIED); + + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 1); + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true); + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false); + + reloadUpdateManagerData(); + + is(gUpdateManager.activeUpdate.state, STATE_APPLIED, + "The active update should have a state of " + STATE_APPLIED); + + ok(gUpdateManager.activeUpdate.promptWaitTime == 1, "Checking that the " + + "update's promptWaitTime attribute value was set from the " + + PREF_APP_UPDATE_PROMPTWAITTIME + " preference"); + + gUpdateManager.refreshUpdateStatus(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0097_restartNotification_stagedServiceBackground.xul b/toolkit/mozapps/update/tests/chrome/test_0097_restartNotification_stagedServiceBackground.xul new file mode 100644 index 000000000..9f7a602c4 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0097_restartNotification_stagedServiceBackground.xul @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: restart notification staged with service" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +gUseTestUpdater = true; + +function runTest() { + debugDump("entering"); + + let patches = getLocalPatchString("complete", null, null, null, null, null, + STATE_APPLIED_SVC); + let updates = getLocalUpdateString(patches, null, null, null, + Services.appinfo.version, + Services.appinfo.platformVersion); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + writeStatusFile(STATE_APPLIED_SVC); + + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 1); + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true); + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, true); + + reloadUpdateManagerData(); + + is(gUpdateManager.activeUpdate.state, STATE_APPLIED_SVC, + "The active update should have a state of " + STATE_APPLIED_SVC); + + ok(gUpdateManager.activeUpdate.promptWaitTime == 1, "Checking that the " + + "update's promptWaitTime attribute value was set from the " + + PREF_APP_UPDATE_PROMPTWAITTIME + " preference"); + + gUpdateManager.refreshUpdateStatus(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0101_background_restartNotification.xul b/toolkit/mozapps/update/tests/chrome/test_0101_background_restartNotification.xul new file mode 100644 index 000000000..faa60c08b --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0101_background_restartNotification.xul @@ -0,0 +1,46 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: background finish with a background download" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 1); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1" + getVersionParams(); + setUpdateURL(url); + + gAUS.notify(null); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0102_background_restartNotification_staging.xul b/toolkit/mozapps/update/tests/chrome/test_0102_background_restartNotification_staging.xul new file mode 100644 index 000000000..3e6f0fec8 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0102_background_restartNotification_staging.xul @@ -0,0 +1,49 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: background finish with a background download and update staging" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +gUseTestUpdater = true; + +function runTest() { + debugDump("entering"); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true); + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 1); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1" + getVersionParams(); + setUpdateURL(url); + + gAUS.notify(null); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0103_background_restartNotification_stagingService.xul b/toolkit/mozapps/update/tests/chrome/test_0103_background_restartNotification_stagingService.xul new file mode 100644 index 000000000..c60a9fe49 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0103_background_restartNotification_stagingService.xul @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: background finish with a background download and update staging and servicefs" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FINISHED_BKGRD, + buttonClick: "extra1" +} ]; + +gUseTestUpdater = true; + +function runTest() { + debugDump("entering"); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true); + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, true); + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 1); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1" + getVersionParams(); + setUpdateURL(url); + + gAUS.notify(null); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0111_neverButton_basic.xul b/toolkit/mozapps/update/tests/chrome/test_0111_neverButton_basic.xul new file mode 100644 index 000000000..adca621d9 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0111_neverButton_basic.xul @@ -0,0 +1,61 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update check and basic (never button test)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +gPrefToCheck = PREFBRANCH_APP_UPDATE_NEVER + Services.appinfo.version; + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_FOUND_BASIC, + extraDelayedCheckFunction: checkPrefHasUserValue, + prefHasUserValue: false, + neverButton: true, + buttonClick: "extra2" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showNever=1&showDetails=1" + + getVersionParams(); + setUpdateURL(url); + + // add the never preference for this version to verify that checking for + // updates clears the preference. + Services.prefs.setBoolPref(gPrefToCheck, true) + + gUP.checkForUpdates(); +} + +function finishTest() { + checkPrefHasUserValue(true); + finishTestDefault(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0113_showNeverForVersionRemovedWithPref.xul b/toolkit/mozapps/update/tests/chrome/test_0113_showNeverForVersionRemovedWithPref.xul new file mode 100644 index 000000000..89dd55ea1 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0113_showNeverForVersionRemovedWithPref.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: update available with never pref and without showNeverForVersion" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +gPrefToCheck = PREFBRANCH_APP_UPDATE_NEVER + Services.appinfo.version; + +const TESTS = [ { + pageid: PAGEID_FOUND_BASIC, + extraDelayedCheckFunction: checkPrefHasUserValue, + prefHasUserValue: true, + buttonClick: "extra1" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1&showPrompt=1" + + getVersionParams(); + setUpdateURL(url); + + // add the never preference for this version to verify that checking for + // updates clears the preference. + Services.prefs.setBoolPref(gPrefToCheck, true) + + gAUS.notify(null); +} + +function finishTest() { + Services.prefs.clearUserPref(gPrefToCheck) + finishTestDefault(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0151_notify_backgroundCheckError.xul b/toolkit/mozapps/update/tests/chrome/test_0151_notify_backgroundCheckError.xul new file mode 100644 index 000000000..13798e5c9 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0151_notify_backgroundCheckError.xul @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Test notification when multiple background check errors occur (bug 595455)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_ERROR_EXTRA, + extraDelayedCheckFunction: checkErrorExtraPage, + shouldBeHidden: false, + displayedTextElem: "bgErrorLabel", + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?xmlMalformed=1"; + setUpdateURL(url); + + errorsPrefObserver.init(PREF_APP_UPDATE_BACKGROUNDERRORS, + PREF_APP_UPDATE_BACKGROUNDMAXERRORS); + + gAUS.notify(null); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0152_notify_backgroundCheckOfflineRetry.xul b/toolkit/mozapps/update/tests/chrome/test_0152_notify_backgroundCheckOfflineRetry.xul new file mode 100644 index 000000000..04e613418 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0152_notify_backgroundCheckOfflineRetry.xul @@ -0,0 +1,96 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Test that an update check that fails due to being offline is performed after going online" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_FOUND_BASIC, + buttonClick: "extra1" +} ]; + +const NETWORK_ERROR_OFFLINE = 111; +var gProxyPrefValue; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1" + getVersionParams(); + setUpdateURL(url); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true); + Services.prefs.setBoolPref(PREF_APP_UPDATE_AUTO, false); + + Services.io.offline = true; + gProxyPrefValue = Services.prefs.getIntPref("network.proxy.type"); + Services.prefs.setIntPref("network.proxy.type", 0); + + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function resetOffline() { + Services.prefs.setIntPref("network.proxy.type", gProxyPrefValue); + Services.io.offline = false; +} + +/* Update check listener */ +const updateCheckListener = { + onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) { + }, + + onCheckComplete: function UCL_onCheckComplete(aRequest, aUpdates, aUpdateCount) { + let status = aRequest.status; + if (status == 0) { + status = aRequest.channel.QueryInterface(Ci.nsIRequest).status; + } + debugDump("url = " + aRequest.channel.originalURI.spec + ", " + + "request.status = " + status + ", " + + "updateCount = " + aUpdateCount); + ok(false, "Unexpected updateCheckListener::onCheckComplete called"); + }, + + onError: function UCL_onError(aRequest, aUpdate) { + let status = aRequest.status; + if (status == 0) { + status = aRequest.channel.QueryInterface(Ci.nsIRequest).status; + } + is(status, Cr.NS_ERROR_OFFLINE, + "checking the request status value"); + is(aUpdate.errorCode, NETWORK_ERROR_OFFLINE, + "checking the update error code"); + debugDump("url = " + aRequest.channel.originalURI.spec + ", " + + "request.status = " + status + ", " + + "update.statusText = " + + (aUpdate.statusText ? aUpdate.statusText : "null")); + gAUS.onError(aRequest, aUpdate); + // Use a timeout to allow the XHR to complete + SimpleTest.executeSoon(resetOffline); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateCheckListener]) +}; + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0161_check_unsupported.xul b/toolkit/mozapps/update/tests/chrome/test_0161_check_unsupported.xul new file mode 100644 index 000000000..c8e8d837b --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0161_check_unsupported.xul @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Test checking for updates when system is no longer supported (bug 843497)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_UNSUPPORTED, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + // When checking manually the unsupported page should still be shown even if + // it was shown previously. + Services.prefs.setBoolPref(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED, true); + + let url = URL_HTTP_UPDATE_XML + "?unsupported=1"; + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0162_notify_unsupported.xul b/toolkit/mozapps/update/tests/chrome/test_0162_notify_unsupported.xul new file mode 100644 index 000000000..d88d2092d --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0162_notify_unsupported.xul @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Test notification of updates when system is no longer supported (bug 843497)" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_UNSUPPORTED, + buttonClick: "finish" +} ]; + +function runTest() { + debugDump("entering"); + + let url = URL_HTTP_UPDATE_XML + "?unsupported=1"; + setUpdateURL(url); + + gAUS.notify(null); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0171_check_noPerms_manual.xul b/toolkit/mozapps/update/tests/chrome/test_0171_check_noPerms_manual.xul new file mode 100644 index 000000000..142c02baa --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0171_check_noPerms_manual.xul @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: manual" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_CHECKING +}, { + pageid: PAGEID_MANUAL_UPDATE, + buttonClick: "finish", + extraCheckFunction: getWriteTestFile +} ]; + +function runTest() { + debugDump("entering"); + + let file = getWriteTestFile(); + file.create(file.NORMAL_FILE_TYPE, 0o444); + file.fileAttributesWin |= file.WFA_READONLY; + file.fileAttributesWin &= ~file.WFA_READWRITE; + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1" + getVersionParams(); + setUpdateURL(url); + + gUP.checkForUpdates(); +} + +function getWriteTestFile() { + let file = getAppBaseDir(); + file.append(FILE_UPDATE_TEST); + file.QueryInterface(Ci.nsILocalFileWin); + if (file.exists()) { + file.fileAttributesWin |= file.WFA_READWRITE; + file.fileAttributesWin &= ~file.WFA_READONLY; + file.remove(true); + } + return file; +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_0172_notify_noPerms_manual.xul b/toolkit/mozapps/update/tests/chrome/test_0172_notify_noPerms_manual.xul new file mode 100644 index 000000000..6784b9c90 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_0172_notify_noPerms_manual.xul @@ -0,0 +1,63 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Update Wizard pages: manual" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTestDefault();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +const TESTS = [ { + pageid: PAGEID_MANUAL_UPDATE, + buttonClick: "finish", + extraCheckFunction: getWriteTestFile +} ]; + +function runTest() { + debugDump("entering"); + + let file = getWriteTestFile(); + file.create(file.NORMAL_FILE_TYPE, 0o444); + file.fileAttributesWin |= file.WFA_READONLY; + file.fileAttributesWin &= ~file.WFA_READWRITE; + + let url = URL_HTTP_UPDATE_XML + "?showDetails=1&showPrompt=1" + + getVersionParams(); + setUpdateURL(url); + + gAUS.checkForBackgroundUpdates(); +} + +function getWriteTestFile() { + let file = getAppBaseDir(); + file.append(FILE_UPDATE_TEST); + file.QueryInterface(Ci.nsILocalFileWin); + if (file.exists()) { + file.fileAttributesWin |= file.WFA_READWRITE; + file.fileAttributesWin &= ~file.WFA_READONLY; + file.remove(true); + } + return file; +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul b/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul new file mode 100644 index 000000000..a55263eb2 --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/test_9999_cleanup.xul @@ -0,0 +1,112 @@ +<?xml version="1.0"?> +<!-- +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Removes files and preferences for previous application update tests in case + * any of them had a fatal error. The test name ensures that it will run after + * all other tests as long as the test naming uses the same format as the + * existing tests. + */ +--> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + +<window title="Application Update test cleanup" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTest();"> +<script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> +<script type="application/javascript" + src="utils.js"/> + +<script type="application/javascript"> +<![CDATA[ + +/** + * If the application update tests left behind any of the files it uses it could + * be a very bad thing. The purpose of this test is to prevent that from + * happening. + */ +function runTest() { + debugDump("entering"); + + SimpleTest.waitForExplicitFinish(); + + if (DEBUG_AUS_TEST) { + Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true); + } + + closeUpdateWindow(); + + // Always leave the app.update.enabled and app.update.staging.enabled + // preferences set to false when cleaning up. + Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, false); + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false); + + resetFiles(); + removeUpdateDirsAndFiles(); + reloadUpdateManagerData(); + + let file = getUpdatesXMLFile(true); + ok(!file.exists(), file.path + " should not exist"); + + file = getUpdatesXMLFile(false); + ok(!file.exists(), file.path + " should not exist"); + + let dir = getUpdatesDir(); + + file = dir.clone(); + file.append(FILE_UPDATE_STATUS); + ok(!file.exists(), file.path + " should not exist"); + + file = dir.clone(); + file.append(FILE_UPDATE_MAR); + ok(!file.exists(), file.path + " should not exist"); + + cleanupRestoreUpdaterBackup(); +} + +/** + * After all tests finish this will repeatedly attempt to restore the real + * updater if it exists and then call finishTest after the restore is + * successful. + */ +function cleanupRestoreUpdaterBackup() { + debugDump("entering"); + + try { + // Windows debug builds keep the updater file in use for a short period of + // time after the updater process exits. + restoreUpdaterBackup(); + } catch (e) { + logTestInfo("Attempt to restore the backed up updater failed... " + + "will try again, Exception: " + e); + SimpleTest.executeSoon(cleanupRestoreUpdaterBackup); + return; + } + + SimpleTest.executeSoon(finishTest); +} + +function finishTest() { + debugDump("entering"); + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_LOG)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_LOG); + } + SimpleTest.finish(); +} + +]]> +</script> + +<body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"></pre> +</body> +</window> diff --git a/toolkit/mozapps/update/tests/chrome/update.sjs b/toolkit/mozapps/update/tests/chrome/update.sjs new file mode 100644 index 000000000..78bb1b93f --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/update.sjs @@ -0,0 +1,194 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Server side http server script for application update tests. + */ + +const { classes: Cc, interfaces: Ci } = Components; + +const REL_PATH_DATA = "chrome/toolkit/mozapps/update/tests/data/"; + +function getTestDataFile(aFilename) { + let file = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties).get("CurWorkD", Ci.nsILocalFile); + let pathParts = REL_PATH_DATA.split("/"); + for (let i = 0; i < pathParts.length; ++i) { + file.append(pathParts[i]); + } + if (aFilename) { + file.append(aFilename); + } + return file; +} + +function loadHelperScript() { + let scriptFile = getTestDataFile("sharedUpdateXML.js"); + let io = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService2); + let scriptSpec = io.newFileURI(scriptFile).spec; + let scriptloader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. + getService(Ci.mozIJSSubScriptLoader); + scriptloader.loadSubScript(scriptSpec, this); +} +loadHelperScript(); + +const URL_HOST = "http://example.com"; +const URL_PATH_UPDATE_XML = "/chrome/toolkit/mozapps/update/tests/chrome/update.sjs"; +const URL_HTTP_UPDATE_SJS = URL_HOST + URL_PATH_UPDATE_XML; +const SERVICE_URL = URL_HOST + "/" + REL_PATH_DATA + FILE_SIMPLE_MAR; + +const SLOW_MAR_DOWNLOAD_INTERVAL = 100; +var gTimer; + +function handleRequest(aRequest, aResponse) { + let params = { }; + if (aRequest.queryString) { + params = parseQueryString(aRequest.queryString); + } + + let statusCode = params.statusCode ? parseInt(params.statusCode) : 200; + let statusReason = params.statusReason ? params.statusReason : "OK"; + aResponse.setStatusLine(aRequest.httpVersion, statusCode, statusReason); + aResponse.setHeader("Cache-Control", "no-cache", false); + + // When a mar download is started by the update service it can finish + // downloading before the ui has loaded. By specifying a serviceURL for the + // update patch that points to this file and has a slowDownloadMar param the + // mar will be downloaded asynchronously which will allow the ui to load + // before the download completes. + if (params.slowDownloadMar) { + aResponse.processAsync(); + aResponse.setHeader("Content-Type", "binary/octet-stream"); + aResponse.setHeader("Content-Length", SIZE_SIMPLE_MAR); + var continueFile = getTestDataFile("continue"); + var contents = readFileBytes(getTestDataFile(FILE_SIMPLE_MAR)); + gTimer = Cc["@mozilla.org/timer;1"]. + createInstance(Ci.nsITimer); + gTimer.initWithCallback(function(aTimer) { + if (continueFile.exists()) { + gTimer.cancel(); + aResponse.write(contents); + aResponse.finish(); + } + }, SLOW_MAR_DOWNLOAD_INTERVAL, Ci.nsITimer.TYPE_REPEATING_SLACK); + return; + } + + if (params.uiURL) { + let remoteType = ""; + if (!params.remoteNoTypeAttr && params.uiURL == "BILLBOARD") { + remoteType = " " + params.uiURL.toLowerCase() + "=\"1\""; + } + aResponse.write("<html><head><meta http-equiv=\"content-type\" content=" + + "\"text/html; charset=utf-8\"></head><body" + + remoteType + ">" + params.uiURL + + "<br><br>this is a test mar that will not affect your " + + "build.</body></html>"); + return; + } + + if (params.xmlMalformed) { + aResponse.write("xml error"); + return; + } + + if (params.noUpdates) { + aResponse.write(getRemoteUpdatesXMLString("")); + return; + } + + if (params.unsupported) { + aResponse.write(getRemoteUpdatesXMLString(" <update type=\"major\" " + + "unsupported=\"true\" " + + "detailsURL=\"" + URL_HOST + + "\"></update>\n")); + return; + } + + let size; + let patches = ""; + if (!params.partialPatchOnly) { + size = SIZE_SIMPLE_MAR + (params.invalidCompleteSize ? "1" : ""); + patches += getRemotePatchString("complete", SERVICE_URL, "SHA512", + SHA512_HASH_SIMPLE_MAR, size); + } + + if (!params.completePatchOnly) { + size = SIZE_SIMPLE_MAR + (params.invalidPartialSize ? "1" : ""); + patches += getRemotePatchString("partial", SERVICE_URL, "SHA512", + SHA512_HASH_SIMPLE_MAR, size); + } + + let type = params.type ? params.type : "major"; + let name = params.name ? params.name : "App Update Test"; + let appVersion = params.appVersion ? params.appVersion : "999999.9"; + let displayVersion = params.displayVersion ? params.displayVersion + : "version " + appVersion; + let buildID = params.buildID ? params.buildID : "01234567890123"; + // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 +// let detailsURL = params.showDetails ? URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS" : null; + let detailsURL = URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS"; + let showPrompt = params.showPrompt ? "true" : null; + let showNever = params.showNever ? "true" : null; + let promptWaitTime = params.promptWaitTime ? params.promptWaitTime : null; + + let updates = getRemoteUpdateString(patches, type, "App Update Test", + displayVersion, appVersion, buildID, + detailsURL, showPrompt, showNever, + promptWaitTime); + aResponse.write(getRemoteUpdatesXMLString(updates)); +} + +/** + * Helper function to create a JS object representing the url parameters from + * the request's queryString. + * + * @param aQueryString + * The request's query string. + * @return A JS object representing the url parameters from the request's + * queryString. + */ +function parseQueryString(aQueryString) { + let paramArray = aQueryString.split("&"); + let regex = /^([^=]+)=(.*)$/; + let params = {}; + for (let i = 0, sz = paramArray.length; i < sz; i++) { + let match = regex.exec(paramArray[i]); + if (!match) { + throw "Bad parameter in queryString! '" + paramArray[i] + "'"; + } + params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); + } + + return params; +} + +/** + * Reads the binary contents of a file and returns it as a string. + * + * @param aFile + * The file to read from. + * @return The contents of the file as a string. + */ +function readFileBytes(aFile) { + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + fis.init(aFile, -1, -1, false); + let bis = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); + bis.setInputStream(fis); + let data = []; + let count = fis.available(); + while (count > 0) { + let bytes = bis.readByteArray(Math.min(65535, count)); + data.push(String.fromCharCode.apply(null, bytes)); + count -= bytes.length; + if (bytes.length == 0) { + throw "Nothing read from input stream!"; + } + } + data.join(''); + fis.close(); + return data.toString(); +} diff --git a/toolkit/mozapps/update/tests/chrome/utils.js b/toolkit/mozapps/update/tests/chrome/utils.js new file mode 100644 index 000000000..31d0d2e5a --- /dev/null +++ b/toolkit/mozapps/update/tests/chrome/utils.js @@ -0,0 +1,1011 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test Definition + * + * Most tests can use an array named TESTS that will perform most if not all of + * the necessary checks. Each element in the array must be an object with the + * following possible properties. Additional properties besides the ones listed + * below can be added as needed. + * + * overrideCallback (optional) + * The function to call for the next test. This is typically called when the + * wizard page changes but can also be called for other events by the previous + * test. If this property isn't defined then the defaultCallback function will + * be called. If this property is defined then all other properties are + * optional. + * + * pageid (required unless overrideCallback is specified) + * The expected pageid for the wizard. This property is required unless the + * overrideCallback property is defined. + * + * extraStartFunction (optional) + * The function to call at the beginning of the defaultCallback function. If + * the function returns true the defaultCallback function will return early + * which allows waiting for a specific condition to be evaluated in the + * function specified in the extraStartFunction property before continuing + * with the test. + * + * extraCheckFunction (optional) + * The function to call to perform extra checks in the defaultCallback + * function. + * + * extraDelayedCheckFunction (optional) + * The function to call to perform extra checks in the delayedDefaultCallback + * function. + * + * buttonStates (optional) + * A javascript object representing the expected hidden and disabled attribute + * values for the buttons of the current wizard page. The values are checked + * in the delayedDefaultCallback function. For information about the structure + * of this object refer to the getExpectedButtonStates and checkButtonStates + * functions. + * + * buttonClick (optional) + * The current wizard page button to click at the end of the + * delayedDefaultCallback function. If the buttonClick property is defined + * then the extraDelayedFinishFunction property can't be specified due to race + * conditions in some of the tests and if both of them are specified the test + * will intentionally throw. + * + * extraDelayedFinishFunction (optional) + * The function to call at the end of the delayedDefaultCallback function. + * If the extraDelayedFinishFunction property is defined then the buttonClick + * property can't be specified due to race conditions in some of the tests and + * if both of them are specified the test will intentionally throw. + * + * ranTest (should not be specified) + * When delayedDefaultCallback is called a property named ranTest is added to + * the current test so it is possible to verify that each test in the TESTS + * array has ran. + * + * prefHasUserValue (optional) + * For comparing the expected value defined by this property with the return + * value of prefHasUserValue using gPrefToCheck for the preference name in the + * checkPrefHasUserValue function. + */ + +'use strict'; + +/* globals TESTS, runTest, finishTest */ + +const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, + utils: Cu } = Components; + +Cu.import("resource://gre/modules/Services.jsm", this); + +const IS_MACOSX = ("nsILocalFileMac" in Ci); +const IS_WIN = ("@mozilla.org/windows-registry-key;1" in Cc); + +// The tests have to use the pageid instead of the pageIndex due to the +// app update wizard's access method being random. +const PAGEID_DUMMY = "dummy"; // Done +const PAGEID_CHECKING = "checking"; // Done +const PAGEID_NO_UPDATES_FOUND = "noupdatesfound"; // Done +const PAGEID_MANUAL_UPDATE = "manualUpdate"; // Done +const PAGEID_UNSUPPORTED = "unsupported"; // Done +const PAGEID_FOUND_BASIC = "updatesfoundbasic"; // Done +const PAGEID_DOWNLOADING = "downloading"; // Done +const PAGEID_ERRORS = "errors"; // Done +const PAGEID_ERROR_EXTRA = "errorextra"; // Done +const PAGEID_ERROR_PATCHING = "errorpatching"; // Done +const PAGEID_FINISHED = "finished"; // Done +const PAGEID_FINISHED_BKGRD = "finishedBackground"; // Done + +const UPDATE_WINDOW_NAME = "Update:Wizard"; + +const URL_HOST = "http://example.com"; +const URL_PATH_UPDATE_XML = "/chrome/toolkit/mozapps/update/tests/chrome/update.sjs"; +const REL_PATH_DATA = "chrome/toolkit/mozapps/update/tests/data"; + +// These two URLs must not contain parameters since tests add their own +// test specific parameters. +const URL_HTTP_UPDATE_XML = URL_HOST + URL_PATH_UPDATE_XML; +const URL_HTTPS_UPDATE_XML = "https://example.com" + URL_PATH_UPDATE_XML; + +const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul"; + +const PREF_APP_UPDATE_INTERVAL = "app.update.interval"; +const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-update-timer"; + +const LOG_FUNCTION = info; + +const BIN_SUFFIX = (IS_WIN ? ".exe" : ""); +const FILE_UPDATER_BIN = "updater" + (IS_MACOSX ? ".app" : BIN_SUFFIX); +const FILE_UPDATER_BIN_BAK = FILE_UPDATER_BIN + ".bak"; + +var gURLData = URL_HOST + "/" + REL_PATH_DATA + "/"; + +var gTestTimeout = 240000; // 4 minutes +var gTimeoutTimer; + +// The number of SimpleTest.executeSoon calls to perform when waiting on an +// update window to close before giving up. +const CLOSE_WINDOW_TIMEOUT_MAXCOUNT = 10; +// Counter for the SimpleTest.executeSoon when waiting on an update window to +// close before giving up. +var gCloseWindowTimeoutCounter = 0; + +// The following vars are for restoring previous preference values (if present) +// when the test finishes. +var gAppUpdateEnabled; // app.update.enabled +var gAppUpdateServiceEnabled; // app.update.service.enabled +var gAppUpdateStagingEnabled; // app.update.staging.enabled +var gAppUpdateURLDefault; // app.update.url (default prefbranch) + +var gTestCounter = -1; +var gWin; +var gDocElem; +var gPrefToCheck; +var gUseTestUpdater = false; + +// Set to true to log additional information for debugging. To log additional +// information for an individual test set DEBUG_AUS_TEST to true in the test's +// onload function. +var DEBUG_AUS_TEST = true; + +const DATA_URI_SPEC = "chrome://mochitests/content/chrome/toolkit/mozapps/update/tests/data/"; +/* import-globals-from ../data/shared.js */ +Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this); + +/** + * The current test in TESTS array. + */ +this.__defineGetter__("gTest", function() { + return TESTS[gTestCounter]; +}); + +/** + * The current test's callback. This will either return the callback defined in + * the test's overrideCallback property or defaultCallback if the + * overrideCallback property is undefined. + */ +this.__defineGetter__("gCallback", function() { + return gTest.overrideCallback ? gTest.overrideCallback + : defaultCallback; +}); + +/** + * nsIObserver for receiving window open and close notifications. + */ +const gWindowObserver = { + observe: function WO_observe(aSubject, aTopic, aData) { + let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget); + + if (aTopic == "domwindowclosed") { + if (win.location != URI_UPDATE_PROMPT_DIALOG) { + debugDump("domwindowclosed event for window not being tested - " + + "location: " + win.location + "... returning early"); + return; + } + // Allow tests the ability to provide their own function (it must be + // named finishTest) for finishing the test. + try { + finishTest(); + } + catch (e) { + finishTestDefault(); + } + return; + } + + win.addEventListener("load", function WO_observe_onLoad() { + win.removeEventListener("load", WO_observe_onLoad, false); + // Ignore windows other than the update UI window. + if (win.location != URI_UPDATE_PROMPT_DIALOG) { + debugDump("load event for window not being tested - location: " + + win.location + "... returning early"); + return; + } + + // The first wizard page should always be the dummy page. + let pageid = win.document.documentElement.currentPage.pageid; + if (pageid != PAGEID_DUMMY) { + // This should never happen but if it does this will provide a clue + // for diagnosing the cause. + ok(false, "Unexpected load event - pageid got: " + pageid + + ", expected: " + PAGEID_DUMMY + "... returning early"); + return; + } + + gWin = win; + gDocElem = gWin.document.documentElement; + gDocElem.addEventListener("pageshow", onPageShowDefault, false); + }, false); + } +}; + +/** + * Default test run function that can be used by most tests. This function uses + * protective measures to prevent the test from failing provided by + * |runTestDefaultWaitForWindowClosed| helper functions to prevent failure due + * to a previous test failure. + */ +function runTestDefault() { + debugDump("entering"); + + if (!("@mozilla.org/zipwriter;1" in Cc)) { + ok(false, "nsIZipWriter is required to run these tests"); + return; + } + + SimpleTest.waitForExplicitFinish(); + + runTestDefaultWaitForWindowClosed(); +} + +/** + * If an update window is found SimpleTest.executeSoon can callback before the + * update window is fully closed especially with debug builds. If an update + * window is found this function will call itself using SimpleTest.executeSoon + * up to the amount declared in CLOSE_WINDOW_TIMEOUT_MAXCOUNT until the update + * window has closed before continuing the test. + */ +function runTestDefaultWaitForWindowClosed() { + gCloseWindowTimeoutCounter++; + if (gCloseWindowTimeoutCounter > CLOSE_WINDOW_TIMEOUT_MAXCOUNT) { + try { + finishTest(); + } + catch (e) { + finishTestDefault(); + } + return; + } + + // The update window should not be open at this time. If it is the call to + // |closeUpdateWindow| will close it and cause the test to fail. + if (closeUpdateWindow()) { + SimpleTest.executeSoon(runTestDefaultWaitForWindowClosed); + } else { + Services.ww.registerNotification(gWindowObserver); + + gCloseWindowTimeoutCounter = 0; + + setupFiles(); + setupPrefs(); + gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1"); + removeUpdateDirsAndFiles(); + reloadUpdateManagerData(); + setupTimer(gTestTimeout); + SimpleTest.executeSoon(setupTestUpdater); + } +} + +/** + * Default test finish function that can be used by most tests. This function + * uses protective measures to prevent the next test from failing provided by + * |finishTestDefaultWaitForWindowClosed| helper functions to prevent failure + * due to an update window being left open. + */ +function finishTestDefault() { + debugDump("entering"); + if (gTimeoutTimer) { + gTimeoutTimer.cancel(); + gTimeoutTimer = null; + } + + if (gChannel) { + debugDump("channel = " + gChannel); + gChannel = null; + gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer); + } + + verifyTestsRan(); + + resetPrefs(); + gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", ""); + resetFiles(); + removeUpdateDirsAndFiles(); + reloadUpdateManagerData(); + + Services.ww.unregisterNotification(gWindowObserver); + if (gDocElem) { + gDocElem.removeEventListener("pageshow", onPageShowDefault, false); + } + + finishTestRestoreUpdaterBackup(); +} + +/** + * nsITimerCallback for the timeout timer to cleanly finish a test if the Update + * Window doesn't close for a test. This allows the next test to run properly if + * a previous test fails. + * + * @param aTimer + * The nsITimer that fired. + */ +function finishTestTimeout(aTimer) { + ok(false, "Test timed out. Maximum time allowed is " + (gTestTimeout / 1000) + + " seconds"); + + try { + finishTest(); + } + catch (e) { + finishTestDefault(); + } +} + +/** + * When a test finishes this will repeatedly attempt to restore the real updater + * for tests that use the test updater and then call + * finishTestDefaultWaitForWindowClosed after the restore is successful. + */ +function finishTestRestoreUpdaterBackup() { + if (gUseTestUpdater) { + try { + // Windows debug builds keep the updater file in use for a short period of + // time after the updater process exits. + restoreUpdaterBackup(); + } catch (e) { + logTestInfo("Attempt to restore the backed up updater failed... " + + "will try again, Exception: " + e); + SimpleTest.executeSoon(finishTestRestoreUpdaterBackup); + return; + } + } + + finishTestDefaultWaitForWindowClosed(); +} + +/** + * If an update window is found SimpleTest.executeSoon can callback before the + * update window is fully closed especially with debug builds. If an update + * window is found this function will call itself using SimpleTest.executeSoon + * up to the amount declared in CLOSE_WINDOW_TIMEOUT_MAXCOUNT until the update + * window has closed before finishing the test. + */ +function finishTestDefaultWaitForWindowClosed() { + gCloseWindowTimeoutCounter++; + if (gCloseWindowTimeoutCounter > CLOSE_WINDOW_TIMEOUT_MAXCOUNT) { + SimpleTest.requestCompleteLog(); + SimpleTest.finish(); + return; + } + + // The update window should not be open at this time. If it is the call to + // |closeUpdateWindow| will close it and cause the test to fail. + if (closeUpdateWindow()) { + SimpleTest.executeSoon(finishTestDefaultWaitForWindowClosed); + } else { + SimpleTest.finish(); + } +} + +/** + * Default callback for the wizard's documentElement pageshow listener. This + * will return early for event's where the originalTarget's nodeName is not + * wizardpage. + */ +function onPageShowDefault(aEvent) { + if (!gTimeoutTimer) { + debugDump("gTimeoutTimer is null... returning early"); + return; + } + + // Return early if the event's original target isn't for a wizardpage element. + // This check is necessary due to the remotecontent element firing pageshow. + if (aEvent.originalTarget.nodeName != "wizardpage") { + debugDump("only handles events with an originalTarget nodeName of " + + "|wizardpage|. aEvent.originalTarget.nodeName = " + + aEvent.originalTarget.nodeName + "... returning early"); + return; + } + + gTestCounter++; + gCallback(aEvent); +} + +/** + * Default callback that can be used by most tests. + */ +function defaultCallback(aEvent) { + if (!gTimeoutTimer) { + debugDump("gTimeoutTimer is null... returning early"); + return; + } + + debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid + + ", aEvent.originalTarget.nodeName: " + + aEvent.originalTarget.nodeName); + + if (gTest && gTest.extraStartFunction) { + debugDump("calling extraStartFunction " + gTest.extraStartFunction.name); + if (gTest.extraStartFunction(aEvent)) { + debugDump("extraStartFunction early return"); + return; + } + } + + is(gDocElem.currentPage.pageid, gTest.pageid, + "Checking currentPage.pageid equals " + gTest.pageid + " in pageshow"); + + // Perform extra checks if specified by the test + if (gTest.extraCheckFunction) { + debugDump("calling extraCheckFunction " + gTest.extraCheckFunction.name); + gTest.extraCheckFunction(); + } + + // The wizard page buttons' disabled and hidden attributes are set after the + // pageshow event so use executeSoon to allow them to be set so their disabled + // and hidden attribute values can be checked. + SimpleTest.executeSoon(delayedDefaultCallback); +} + +/** + * Delayed default callback called using executeSoon in defaultCallback which + * allows the wizard page buttons' disabled and hidden attributes to be set + * before checking their values. + */ +function delayedDefaultCallback() { + if (!gTimeoutTimer) { + debugDump("gTimeoutTimer is null... returning early"); + return; + } + + if (!gTest) { + debugDump("gTest is null... returning early"); + return; + } + + debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid); + + // Verify the pageid hasn't changed after executeSoon was called. + is(gDocElem.currentPage.pageid, gTest.pageid, + "Checking currentPage.pageid equals " + gTest.pageid + " after " + + "executeSoon"); + + checkButtonStates(); + + // Perform delayed extra checks if specified by the test + if (gTest.extraDelayedCheckFunction) { + debugDump("calling extraDelayedCheckFunction " + + gTest.extraDelayedCheckFunction.name); + gTest.extraDelayedCheckFunction(); + } + + // Used to verify that this test has been performed + gTest.ranTest = true; + + if (gTest.buttonClick) { + debugDump("clicking " + gTest.buttonClick + " button"); + if (gTest.extraDelayedFinishFunction) { + throw ("Tests cannot have a buttonClick and an extraDelayedFinishFunction property"); + } + gDocElem.getButton(gTest.buttonClick).click(); + } else if (gTest.extraDelayedFinishFunction) { + debugDump("calling extraDelayedFinishFunction " + + gTest.extraDelayedFinishFunction.name); + gTest.extraDelayedFinishFunction(); + } +} + +/** + * Gets the continue file used to signal the mock http server to continue + * downloading for slow download mar file tests without creating it. + * + * @return nsILocalFile for the continue file. + */ +function getContinueFile() { + let continueFile = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties). + get("CurWorkD", Ci.nsILocalFile); + let continuePath = REL_PATH_DATA + "/continue"; + let continuePathParts = continuePath.split("/"); + for (let i = 0; i < continuePathParts.length; ++i) { + continueFile.append(continuePathParts[i]); + } + return continueFile; +} + +/** + * Creates the continue file used to signal the mock http server to continue + * downloading for slow download mar file tests. + */ +function createContinueFile() { + debugDump("creating 'continue' file for slow mar downloads"); + writeFile(getContinueFile(), ""); +} + +/** + * Removes the continue file used to signal the mock http server to continue + * downloading for slow download mar file tests. + */ +function removeContinueFile() { + let continueFile = getContinueFile(); + if (continueFile.exists()) { + debugDump("removing 'continue' file for slow mar downloads"); + continueFile.remove(false); + } +} + +/** + * Checks the wizard page buttons' disabled and hidden attributes values are + * correct. If an expected button id is not specified then the expected disabled + * and hidden attribute value is true. + */ +function checkButtonStates() { + debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid); + + const buttonNames = ["extra1", "extra2", "back", "next", "finish", "cancel"]; + let buttonStates = getExpectedButtonStates(); + buttonNames.forEach(function(aButtonName) { + let button = gDocElem.getButton(aButtonName); + let hasHidden = aButtonName in buttonStates && + "hidden" in buttonStates[aButtonName]; + let hidden = hasHidden ? buttonStates[aButtonName].hidden : true; + let hasDisabled = aButtonName in buttonStates && + "disabled" in buttonStates[aButtonName]; + let disabled = hasDisabled ? buttonStates[aButtonName].disabled : true; + is(button.hidden, hidden, "Checking " + aButtonName + " button " + + "hidden attribute value equals " + (hidden ? "true" : "false")); + is(button.disabled, disabled, "Checking " + aButtonName + " button " + + "disabled attribute value equals " + (disabled ? "true" : "false")); + }); +} + +/** + * Returns the expected disabled and hidden attribute values for the buttons of + * the current wizard page. + */ +function getExpectedButtonStates() { + // Allow individual tests to override the expected button states. + if (gTest.buttonStates) { + return gTest.buttonStates; + } + + switch (gTest.pageid) { + case PAGEID_CHECKING: + return {cancel: {disabled: false, hidden: false}}; + case PAGEID_FOUND_BASIC: + if (gTest.neverButton) { + return {extra1: {disabled: false, hidden: false}, + extra2: {disabled: false, hidden: false}, + next: {disabled: false, hidden: false}}; + } + return {extra1: {disabled: false, hidden: false}, + next: {disabled: false, hidden: false}}; + case PAGEID_DOWNLOADING: + return {extra1: {disabled: false, hidden: false}}; + case PAGEID_NO_UPDATES_FOUND: + case PAGEID_MANUAL_UPDATE: + case PAGEID_UNSUPPORTED: + case PAGEID_ERRORS: + case PAGEID_ERROR_EXTRA: + return {finish: {disabled: false, hidden: false}}; + case PAGEID_ERROR_PATCHING: + return {next: { disabled: false, hidden: false}}; + case PAGEID_FINISHED: + case PAGEID_FINISHED_BKGRD: + return {extra1: { disabled: false, hidden: false}, + finish: { disabled: false, hidden: false}}; + } + return null; +} + +/** + * Compares the return value of prefHasUserValue for the preference specified in + * gPrefToCheck with the value passed in the aPrefHasValue parameter or the + * value specified in the current test's prefHasUserValue property if + * aPrefHasValue is undefined. + * + * @param aPrefHasValue (optional) + * The expected value returned from prefHasUserValue for the preference + * specified in gPrefToCheck. If aPrefHasValue is undefined the value + * of the current test's prefHasUserValue property will be used. + */ +function checkPrefHasUserValue(aPrefHasValue) { + let prefHasUserValue = aPrefHasValue === undefined ? gTest.prefHasUserValue + : aPrefHasValue; + is(Services.prefs.prefHasUserValue(gPrefToCheck), prefHasUserValue, + "Checking prefHasUserValue for preference " + gPrefToCheck + " equals " + + (prefHasUserValue ? "true" : "false")); +} + +/** + * Checks whether the link is hidden for a general background update check error + * or not on the errorextra page and that the app.update.backgroundErrors + * preference does not have a user value. + * + * @param aShouldBeHidden (optional) + * The expected value for the label's hidden attribute for the link. If + * aShouldBeHidden is undefined the value of the current test's + * shouldBeHidden property will be used. + */ +function checkErrorExtraPage(aShouldBeHidden) { + let shouldBeHidden = aShouldBeHidden === undefined ? gTest.shouldBeHidden + : aShouldBeHidden; + is(gWin.document.getElementById("errorExtraLinkLabel").hidden, shouldBeHidden, + "Checking errorExtraLinkLabel hidden attribute equals " + + (shouldBeHidden ? "true" : "false")); + + is(gWin.document.getElementById(gTest.displayedTextElem).hidden, false, + "Checking " + gTest.displayedTextElem + " should not be hidden"); + + ok(!Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS), + "Preference " + PREF_APP_UPDATE_BACKGROUNDERRORS + " should not have a " + + "user value"); +} + +/** + * Gets the update version info for the update url parameters to send to + * update.sjs. + * + * @param aAppVersion (optional) + * The application version for the update snippet. If not specified the + * current application version will be used. + * @return The url parameters for the application and platform version to send + * to update.sjs. + */ +function getVersionParams(aAppVersion) { + let appInfo = Services.appinfo; + return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version); +} + +/** + * Verifies that all tests ran. + */ +function verifyTestsRan() { + debugDump("entering"); + + // Return early if there are no tests defined. + if (!TESTS) { + return; + } + + gTestCounter = -1; + for (let i = 0; i < TESTS.length; ++i) { + gTestCounter++; + let test = TESTS[i]; + let msg = "Checking if TESTS[" + i + "] test was performed... " + + "callback function name = " + gCallback.name + ", " + + "pageid = " + test.pageid; + ok(test.ranTest, msg); + } +} + +/** + * Creates a backup of files the tests need to modify so they can be restored to + * the original file when the test has finished and then modifies the files. + */ +function setupFiles() { + // Backup the updater-settings.ini file if it exists by moving it. + let baseAppDir = getGREDir(); + let updateSettingsIni = baseAppDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + if (updateSettingsIni.exists()) { + updateSettingsIni.moveTo(baseAppDir, FILE_UPDATE_SETTINGS_INI_BAK); + } + updateSettingsIni = baseAppDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); + writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); +} + +/** + * For tests that use the test updater restores the backed up real updater if + * it exists and tries again on failure since Windows debug builds at times + * leave the file in use. After success moveRealUpdater is called to continue + * the setup of the test updater. For tests that don't use the test updater + * runTest will be called. + */ +function setupTestUpdater() { + if (!gUseTestUpdater) { + runTest(); + return; + } + + try { + restoreUpdaterBackup(); + } catch (e) { + logTestInfo("Attempt to restore the backed up updater failed... " + + "will try again, Exception: " + e); + SimpleTest.executeSoon(setupTestUpdater); + return; + } + moveRealUpdater(); +} + +/** + * Backs up the real updater and tries again on failure since Windows debug + * builds at times leave the file in use. After success it will call + * copyTestUpdater to continue the setup of the test updater. + */ +function moveRealUpdater() { + try { + // Move away the real updater + let baseAppDir = getAppBaseDir(); + let updater = baseAppDir.clone(); + updater.append(FILE_UPDATER_BIN); + updater.moveTo(baseAppDir, FILE_UPDATER_BIN_BAK); + } catch (e) { + logTestInfo("Attempt to move the real updater out of the way failed... " + + "will try again, Exception: " + e); + SimpleTest.executeSoon(moveRealUpdater); + return; + } + + copyTestUpdater(); +} + +/** + * Copies the test updater so it can be used by tests and tries again on failure + * since Windows debug builds at times leave the file in use. After success it + * will call runTest to continue the test. + */ +function copyTestUpdater() { + try { + // Copy the test updater + let baseAppDir = getAppBaseDir(); + let testUpdaterDir = Services.dirsvc.get("CurWorkD", Ci.nsILocalFile); + let relPath = REL_PATH_DATA; + let pathParts = relPath.split("/"); + for (let i = 0; i < pathParts.length; ++i) { + testUpdaterDir.append(pathParts[i]); + } + + let testUpdater = testUpdaterDir.clone(); + testUpdater.append(FILE_UPDATER_BIN); + testUpdater.copyToFollowingLinks(baseAppDir, FILE_UPDATER_BIN); + } catch (e) { + logTestInfo("Attempt to copy the test updater failed... " + + "will try again, Exception: " + e); + SimpleTest.executeSoon(copyTestUpdater); + return; + } + + runTest(); +} + +/** + * Restores the updater that was backed up. This is called in setupTestUpdater + * before the backup of the real updater is done in case the previous test + * failed to restore the updater, in finishTestDefaultWaitForWindowClosed when + * the test has finished, and in test_9999_cleanup.xul after all tests have + * finished. + */ +function restoreUpdaterBackup() { + let baseAppDir = getAppBaseDir(); + let updater = baseAppDir.clone(); + let updaterBackup = baseAppDir.clone(); + updater.append(FILE_UPDATER_BIN); + updaterBackup.append(FILE_UPDATER_BIN_BAK); + if (updaterBackup.exists()) { + if (updater.exists()) { + updater.remove(true); + } + updaterBackup.moveTo(baseAppDir, FILE_UPDATER_BIN); + } +} + +/** + * Sets the most common preferences used by tests to values used by the majority + * of the tests and when necessary saves the preference's original values if + * present so they can be set back to the original values when the test has + * finished. + */ +function setupPrefs() { + if (DEBUG_AUS_TEST) { + Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true); + } + + // Prevent nsIUpdateTimerManager from notifying nsIApplicationUpdateService + // to check for updates by setting the app update last update time to the + // current time minus one minute in seconds and the interval time to 12 hours + // in seconds. + let now = Math.round(Date.now() / 1000) - 60; + Services.prefs.setIntPref(PREF_APP_UPDATE_LASTUPDATETIME, now); + Services.prefs.setIntPref(PREF_APP_UPDATE_INTERVAL, 43200); + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ENABLED)) { + gAppUpdateEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED); + } + Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true); + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ENABLED)) { + gAppUpdateServiceEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED); + } + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false); + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_STAGING_ENABLED)) { + gAppUpdateStagingEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED); + } + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false); + + Services.prefs.setIntPref(PREF_APP_UPDATE_IDLETIME, 0); + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 0); + Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false); + Services.prefs.setIntPref(PREF_APP_UPDATE_DOWNLOADBACKGROUNDINTERVAL, 0); +} + +/** + * Restores files that were backed up for the tests and general file cleanup. + */ +function resetFiles() { + // Restore the backed up updater-settings.ini if it exists. + let baseAppDir = getGREDir(); + let updateSettingsIni = baseAppDir.clone(); + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK); + if (updateSettingsIni.exists()) { + updateSettingsIni.moveTo(baseAppDir, FILE_UPDATE_SETTINGS_INI); + } + + // Not being able to remove the "updated" directory will not adversely affect + // subsequent tests so wrap it in a try block and don't test whether its + // removal was successful. + let updatedDir; + if (IS_MACOSX) { + updatedDir = getUpdatesDir(); + updatedDir.append(DIR_PATCH); + } else { + updatedDir = getAppBaseDir(); + } + updatedDir.append(DIR_UPDATED); + if (updatedDir.exists()) { + try { + removeDirRecursive(updatedDir); + } + catch (e) { + logTestInfo("Unable to remove directory. Path: " + updatedDir.path + + ", Exception: " + e); + } + } +} + +/** + * Resets the most common preferences used by tests to their original values. + */ +function resetPrefs() { + if (gAppUpdateURLDefault) { + gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_URL, gAppUpdateURLDefault); + } + + if (gAppUpdateEnabled !== undefined) { + Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, gAppUpdateEnabled); + } else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ENABLED)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_ENABLED); + } + + if (gAppUpdateServiceEnabled !== undefined) { + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, gAppUpdateServiceEnabled); + } else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ENABLED)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ENABLED); + } + + if (gAppUpdateStagingEnabled !== undefined) { + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, gAppUpdateStagingEnabled); + } else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_STAGING_ENABLED)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_STAGING_ENABLED); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_IDLETIME)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_IDLETIME); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_PROMPTWAITTIME)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_PROMPTWAITTIME); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_DETAILS)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_URL_DETAILS); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_LOG)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_LOG); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SILENT)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_SILENT); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDERRORS); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDMAXERRORS)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDMAXERRORS); + } + + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_DOWNLOADBACKGROUNDINTERVAL)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_DOWNLOADBACKGROUNDINTERVAL); + } + + try { + Services.prefs.deleteBranch(PREFBRANCH_APP_UPDATE_NEVER); + } + catch (e) { + } +} + +function setupTimer(aTestTimeout) { + gTestTimeout = aTestTimeout; + if (gTimeoutTimer) { + gTimeoutTimer.cancel(); + gTimeoutTimer = null; + } + gTimeoutTimer = Cc["@mozilla.org/timer;1"]. + createInstance(Ci.nsITimer); + gTimeoutTimer.initWithCallback(finishTestTimeout, gTestTimeout, + Ci.nsITimer.TYPE_ONE_SHOT); +} + +/** + * Closes the update window if it is open and causes the test to fail if an + * update window is found. + * + * @return true if an update window was found, otherwise false. + */ +function closeUpdateWindow() { + let updateWindow = getUpdateWindow(); + if (!updateWindow) { + return false; + } + + ok(false, "Found an existing Update Window from the current or a previous " + + "test... attempting to close it."); + updateWindow.close(); + return true; +} + +/** + * Gets the update window. + * + * @return The nsIDOMWindow for the Update Window if it is open and null + * if it isn't. + */ +function getUpdateWindow() { + return Services.wm.getMostRecentWindow(UPDATE_WINDOW_NAME); +} + +/** + * Helper for background check errors. + */ +const errorsPrefObserver = { + observedPref: null, + maxErrorPref: null, + + /** + * Sets up a preference observer and sets the associated maximum errors + * preference used for background notification. + * + * @param aObservePref + * The preference to observe. + * @param aMaxErrorPref + * The maximum errors preference. + * @param aMaxErrorCount + * The value to set the maximum errors preference to. + */ + init: function(aObservePref, aMaxErrorPref, aMaxErrorCount) { + this.observedPref = aObservePref; + this.maxErrorPref = aMaxErrorPref; + + let maxErrors = aMaxErrorCount ? aMaxErrorCount : 2; + Services.prefs.setIntPref(aMaxErrorPref, maxErrors); + Services.prefs.addObserver(aObservePref, this, false); + }, + + /** + * Preference observer for the preference specified in |this.observedPref|. + */ + observe: function XPI_observe(aSubject, aTopic, aData) { + if (aData == this.observedPref) { + let errCount = Services.prefs.getIntPref(this.observedPref); + let errMax = Services.prefs.getIntPref(this.maxErrorPref); + if (errCount >= errMax) { + debugDump("removing pref observer"); + Services.prefs.removeObserver(this.observedPref, this); + } else { + debugDump("notifying AUS"); + SimpleTest.executeSoon(function() { + gAUS.notify(null); + }); + } + } + } +}; diff --git a/toolkit/mozapps/update/tests/data/complete.exe b/toolkit/mozapps/update/tests/data/complete.exe Binary files differnew file mode 100644 index 000000000..da9cdf0cc --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete.exe diff --git a/toolkit/mozapps/update/tests/data/complete.mar b/toolkit/mozapps/update/tests/data/complete.mar Binary files differnew file mode 100644 index 000000000..52306e0a2 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete.mar diff --git a/toolkit/mozapps/update/tests/data/complete.png b/toolkit/mozapps/update/tests/data/complete.png Binary files differnew file mode 100644 index 000000000..2990a539f --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete.png diff --git a/toolkit/mozapps/update/tests/data/complete_log_success_mac b/toolkit/mozapps/update/tests/data/complete_log_success_mac new file mode 100644 index 000000000..4f992a137 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete_log_success_mac @@ -0,0 +1,332 @@ +UPDATE TYPE complete +PREPARE REMOVEFILE Contents/Resources/searchplugins/searchpluginstext0 +PREPARE REMOVEFILE Contents/Resources/searchplugins/searchpluginspng0.png +PREPARE REMOVEFILE Contents/Resources/removed-files +PREPARE REMOVEFILE Contents/Resources/precomplete +PREPARE REMOVEFILE Contents/Resources/2/20/20text0 +PREPARE REMOVEFILE Contents/Resources/2/20/20png0.png +PREPARE REMOVEFILE Contents/Resources/0/0exe0.exe +PREPARE REMOVEFILE Contents/Resources/0/00/00text0 +PREPARE REMOVEFILE Contents/MacOS/exe0.exe +PREPARE REMOVEDIR Contents/Resources/searchplugins/ +PREPARE REMOVEDIR Contents/Resources/defaults/pref/ +PREPARE REMOVEDIR Contents/Resources/defaults/ +PREPARE REMOVEDIR Contents/Resources/2/20/ +PREPARE REMOVEDIR Contents/Resources/2/ +PREPARE REMOVEDIR Contents/Resources/0/00/ +PREPARE REMOVEDIR Contents/Resources/0/ +PREPARE REMOVEDIR Contents/Resources/ +PREPARE REMOVEDIR Contents/MacOS/ +PREPARE REMOVEDIR Contents/ +PREPARE ADD Contents/Resources/searchplugins/searchpluginstext0 +PREPARE ADD Contents/Resources/searchplugins/searchpluginspng1.png +PREPARE ADD Contents/Resources/searchplugins/searchpluginspng0.png +PREPARE ADD Contents/Resources/removed-files +PREPARE ADD Contents/Resources/precomplete +PREPARE ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +PREPARE ADD Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +PREPARE ADD Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +PREPARE ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +PREPARE ADD Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +PREPARE ADD Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +PREPARE ADD Contents/Resources/1/10/10text0 +PREPARE ADD Contents/Resources/0/0exe0.exe +PREPARE ADD Contents/Resources/0/00/00text1 +PREPARE ADD Contents/Resources/0/00/00text0 +PREPARE ADD Contents/Resources/0/00/00png0.png +PREPARE ADD Contents/MacOS/exe0.exe +PREPARE REMOVEDIR Contents/Resources/9/99/ +PREPARE REMOVEDIR Contents/Resources/9/99/ +PREPARE REMOVEDIR Contents/Resources/9/98/ +PREPARE REMOVEFILE Contents/Resources/9/97/970/97xtext0 +PREPARE REMOVEFILE Contents/Resources/9/97/970/97xtext1 +PREPARE REMOVEDIR Contents/Resources/9/97/970/ +PREPARE REMOVEFILE Contents/Resources/9/97/971/97xtext0 +PREPARE REMOVEFILE Contents/Resources/9/97/971/97xtext1 +PREPARE REMOVEDIR Contents/Resources/9/97/971/ +PREPARE REMOVEDIR Contents/Resources/9/97/ +PREPARE REMOVEFILE Contents/Resources/9/96/96text0 +PREPARE REMOVEFILE Contents/Resources/9/96/96text1 +PREPARE REMOVEDIR Contents/Resources/9/96/ +PREPARE REMOVEDIR Contents/Resources/9/95/ +PREPARE REMOVEDIR Contents/Resources/9/95/ +PREPARE REMOVEDIR Contents/Resources/9/94/ +PREPARE REMOVEDIR Contents/Resources/9/94/ +PREPARE REMOVEDIR Contents/Resources/9/93/ +PREPARE REMOVEDIR Contents/Resources/9/92/ +PREPARE REMOVEDIR Contents/Resources/9/91/ +PREPARE REMOVEDIR Contents/Resources/9/90/ +PREPARE REMOVEDIR Contents/Resources/9/90/ +PREPARE REMOVEDIR Contents/Resources/8/89/ +PREPARE REMOVEDIR Contents/Resources/8/89/ +PREPARE REMOVEDIR Contents/Resources/8/88/ +PREPARE REMOVEFILE Contents/Resources/8/87/870/87xtext0 +PREPARE REMOVEFILE Contents/Resources/8/87/870/87xtext1 +PREPARE REMOVEDIR Contents/Resources/8/87/870/ +PREPARE REMOVEFILE Contents/Resources/8/87/871/87xtext0 +PREPARE REMOVEFILE Contents/Resources/8/87/871/87xtext1 +PREPARE REMOVEDIR Contents/Resources/8/87/871/ +PREPARE REMOVEDIR Contents/Resources/8/87/ +PREPARE REMOVEFILE Contents/Resources/8/86/86text0 +PREPARE REMOVEFILE Contents/Resources/8/86/86text1 +PREPARE REMOVEDIR Contents/Resources/8/86/ +PREPARE REMOVEDIR Contents/Resources/8/85/ +PREPARE REMOVEDIR Contents/Resources/8/85/ +PREPARE REMOVEDIR Contents/Resources/8/84/ +PREPARE REMOVEDIR Contents/Resources/8/84/ +PREPARE REMOVEDIR Contents/Resources/8/83/ +PREPARE REMOVEDIR Contents/Resources/8/82/ +PREPARE REMOVEDIR Contents/Resources/8/81/ +PREPARE REMOVEDIR Contents/Resources/8/80/ +PREPARE REMOVEDIR Contents/Resources/8/80/ +PREPARE REMOVEFILE Contents/Resources/7/70/7xtest.exe +PREPARE REMOVEFILE Contents/Resources/7/70/7xtext0 +PREPARE REMOVEFILE Contents/Resources/7/70/7xtext1 +PREPARE REMOVEDIR Contents/Resources/7/70/ +PREPARE REMOVEFILE Contents/Resources/7/71/7xtest.exe +PREPARE REMOVEFILE Contents/Resources/7/71/7xtext0 +PREPARE REMOVEFILE Contents/Resources/7/71/7xtext1 +PREPARE REMOVEDIR Contents/Resources/7/71/ +PREPARE REMOVEFILE Contents/Resources/7/7text0 +PREPARE REMOVEFILE Contents/Resources/7/7text1 +PREPARE REMOVEDIR Contents/Resources/7/ +PREPARE REMOVEDIR Contents/Resources/6/ +PREPARE REMOVEFILE Contents/Resources/5/5text1 +PREPARE REMOVEFILE Contents/Resources/5/5text0 +PREPARE REMOVEFILE Contents/Resources/5/5test.exe +PREPARE REMOVEFILE Contents/Resources/5/5text0 +PREPARE REMOVEFILE Contents/Resources/5/5text1 +PREPARE REMOVEDIR Contents/Resources/5/ +PREPARE REMOVEFILE Contents/Resources/4/4text1 +PREPARE REMOVEFILE Contents/Resources/4/4text0 +PREPARE REMOVEDIR Contents/Resources/4/ +PREPARE REMOVEFILE Contents/Resources/3/3text1 +PREPARE REMOVEFILE Contents/Resources/3/3text0 +EXECUTE REMOVEFILE Contents/Resources/searchplugins/searchpluginstext0 +EXECUTE REMOVEFILE Contents/Resources/searchplugins/searchpluginspng0.png +EXECUTE REMOVEFILE Contents/Resources/removed-files +EXECUTE REMOVEFILE Contents/Resources/precomplete +EXECUTE REMOVEFILE Contents/Resources/2/20/20text0 +EXECUTE REMOVEFILE Contents/Resources/2/20/20png0.png +EXECUTE REMOVEFILE Contents/Resources/0/0exe0.exe +EXECUTE REMOVEFILE Contents/Resources/0/00/00text0 +EXECUTE REMOVEFILE Contents/MacOS/exe0.exe +EXECUTE REMOVEDIR Contents/Resources/searchplugins/ +EXECUTE REMOVEDIR Contents/Resources/defaults/pref/ +EXECUTE REMOVEDIR Contents/Resources/defaults/ +EXECUTE REMOVEDIR Contents/Resources/2/20/ +EXECUTE REMOVEDIR Contents/Resources/2/ +EXECUTE REMOVEDIR Contents/Resources/0/00/ +EXECUTE REMOVEDIR Contents/Resources/0/ +EXECUTE REMOVEDIR Contents/Resources/ +EXECUTE REMOVEDIR Contents/MacOS/ +EXECUTE REMOVEDIR Contents/ +EXECUTE ADD Contents/Resources/searchplugins/searchpluginstext0 +EXECUTE ADD Contents/Resources/searchplugins/searchpluginspng1.png +EXECUTE ADD Contents/Resources/searchplugins/searchpluginspng0.png +EXECUTE ADD Contents/Resources/removed-files +EXECUTE ADD Contents/Resources/precomplete +EXECUTE ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +EXECUTE ADD Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +EXECUTE ADD Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +EXECUTE ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +EXECUTE ADD Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +EXECUTE ADD Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +EXECUTE ADD Contents/Resources/1/10/10text0 +EXECUTE ADD Contents/Resources/0/0exe0.exe +EXECUTE ADD Contents/Resources/0/00/00text1 +EXECUTE ADD Contents/Resources/0/00/00text0 +EXECUTE ADD Contents/Resources/0/00/00png0.png +EXECUTE ADD Contents/MacOS/exe0.exe +EXECUTE REMOVEDIR Contents/Resources/9/99/ +EXECUTE REMOVEDIR Contents/Resources/9/99/ +EXECUTE REMOVEDIR Contents/Resources/9/98/ +EXECUTE REMOVEFILE Contents/Resources/9/97/970/97xtext0 +EXECUTE REMOVEFILE Contents/Resources/9/97/970/97xtext1 +EXECUTE REMOVEDIR Contents/Resources/9/97/970/ +EXECUTE REMOVEFILE Contents/Resources/9/97/971/97xtext0 +EXECUTE REMOVEFILE Contents/Resources/9/97/971/97xtext1 +EXECUTE REMOVEDIR Contents/Resources/9/97/971/ +EXECUTE REMOVEDIR Contents/Resources/9/97/ +EXECUTE REMOVEFILE Contents/Resources/9/96/96text0 +EXECUTE REMOVEFILE Contents/Resources/9/96/96text1 +EXECUTE REMOVEDIR Contents/Resources/9/96/ +EXECUTE REMOVEDIR Contents/Resources/9/95/ +EXECUTE REMOVEDIR Contents/Resources/9/95/ +EXECUTE REMOVEDIR Contents/Resources/9/94/ +EXECUTE REMOVEDIR Contents/Resources/9/94/ +EXECUTE REMOVEDIR Contents/Resources/9/93/ +EXECUTE REMOVEDIR Contents/Resources/9/92/ +EXECUTE REMOVEDIR Contents/Resources/9/91/ +EXECUTE REMOVEDIR Contents/Resources/9/90/ +EXECUTE REMOVEDIR Contents/Resources/9/90/ +EXECUTE REMOVEDIR Contents/Resources/8/89/ +EXECUTE REMOVEDIR Contents/Resources/8/89/ +EXECUTE REMOVEDIR Contents/Resources/8/88/ +EXECUTE REMOVEFILE Contents/Resources/8/87/870/87xtext0 +EXECUTE REMOVEFILE Contents/Resources/8/87/870/87xtext1 +EXECUTE REMOVEDIR Contents/Resources/8/87/870/ +EXECUTE REMOVEFILE Contents/Resources/8/87/871/87xtext0 +EXECUTE REMOVEFILE Contents/Resources/8/87/871/87xtext1 +EXECUTE REMOVEDIR Contents/Resources/8/87/871/ +EXECUTE REMOVEDIR Contents/Resources/8/87/ +EXECUTE REMOVEFILE Contents/Resources/8/86/86text0 +EXECUTE REMOVEFILE Contents/Resources/8/86/86text1 +EXECUTE REMOVEDIR Contents/Resources/8/86/ +EXECUTE REMOVEDIR Contents/Resources/8/85/ +EXECUTE REMOVEDIR Contents/Resources/8/85/ +EXECUTE REMOVEDIR Contents/Resources/8/84/ +EXECUTE REMOVEDIR Contents/Resources/8/84/ +EXECUTE REMOVEDIR Contents/Resources/8/83/ +EXECUTE REMOVEDIR Contents/Resources/8/82/ +EXECUTE REMOVEDIR Contents/Resources/8/81/ +EXECUTE REMOVEDIR Contents/Resources/8/80/ +EXECUTE REMOVEDIR Contents/Resources/8/80/ +EXECUTE REMOVEFILE Contents/Resources/7/70/7xtest.exe +EXECUTE REMOVEFILE Contents/Resources/7/70/7xtext0 +EXECUTE REMOVEFILE Contents/Resources/7/70/7xtext1 +EXECUTE REMOVEDIR Contents/Resources/7/70/ +EXECUTE REMOVEFILE Contents/Resources/7/71/7xtest.exe +EXECUTE REMOVEFILE Contents/Resources/7/71/7xtext0 +EXECUTE REMOVEFILE Contents/Resources/7/71/7xtext1 +EXECUTE REMOVEDIR Contents/Resources/7/71/ +EXECUTE REMOVEFILE Contents/Resources/7/7text0 +EXECUTE REMOVEFILE Contents/Resources/7/7text1 +EXECUTE REMOVEDIR Contents/Resources/7/ +EXECUTE REMOVEDIR Contents/Resources/6/ +EXECUTE REMOVEFILE Contents/Resources/5/5text1 +EXECUTE REMOVEFILE Contents/Resources/5/5text0 +EXECUTE REMOVEFILE Contents/Resources/5/5test.exe +EXECUTE REMOVEFILE Contents/Resources/5/5text0 +file cannot be removed because it does not exist; skipping +EXECUTE REMOVEFILE Contents/Resources/5/5text1 +file cannot be removed because it does not exist; skipping +EXECUTE REMOVEDIR Contents/Resources/5/ +EXECUTE REMOVEFILE Contents/Resources/4/4text1 +EXECUTE REMOVEFILE Contents/Resources/4/4text0 +EXECUTE REMOVEDIR Contents/Resources/4/ +EXECUTE REMOVEFILE Contents/Resources/3/3text1 +EXECUTE REMOVEFILE Contents/Resources/3/3text0 +FINISH REMOVEFILE Contents/Resources/searchplugins/searchpluginstext0 +FINISH REMOVEFILE Contents/Resources/searchplugins/searchpluginspng0.png +FINISH REMOVEFILE Contents/Resources/removed-files +FINISH REMOVEFILE Contents/Resources/precomplete +FINISH REMOVEFILE Contents/Resources/2/20/20text0 +FINISH REMOVEFILE Contents/Resources/2/20/20png0.png +FINISH REMOVEFILE Contents/Resources/0/0exe0.exe +FINISH REMOVEFILE Contents/Resources/0/00/00text0 +FINISH REMOVEFILE Contents/MacOS/exe0.exe +FINISH REMOVEDIR Contents/Resources/searchplugins/ +removing directory: Contents/Resources/searchplugins/, rv: 0 +FINISH REMOVEDIR Contents/Resources/defaults/pref/ +removing directory: Contents/Resources/defaults/pref/, rv: 0 +FINISH REMOVEDIR Contents/Resources/defaults/ +removing directory: Contents/Resources/defaults/, rv: 0 +FINISH REMOVEDIR Contents/Resources/2/20/ +FINISH REMOVEDIR Contents/Resources/2/ +FINISH REMOVEDIR Contents/Resources/0/00/ +removing directory: Contents/Resources/0/00/, rv: 0 +FINISH REMOVEDIR Contents/Resources/0/ +removing directory: Contents/Resources/0/, rv: 0 +FINISH REMOVEDIR Contents/Resources/ +removing directory: Contents/Resources/, rv: 0 +FINISH REMOVEDIR Contents/MacOS/ +removing directory: Contents/MacOS/, rv: 0 +FINISH REMOVEDIR Contents/ +removing directory: Contents/, rv: 0 +FINISH ADD Contents/Resources/searchplugins/searchpluginstext0 +FINISH ADD Contents/Resources/searchplugins/searchpluginspng1.png +FINISH ADD Contents/Resources/searchplugins/searchpluginspng0.png +FINISH ADD Contents/Resources/removed-files +FINISH ADD Contents/Resources/precomplete +FINISH ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +FINISH ADD Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +FINISH ADD Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +FINISH ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +FINISH ADD Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +FINISH ADD Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +FINISH ADD Contents/Resources/1/10/10text0 +FINISH ADD Contents/Resources/0/0exe0.exe +FINISH ADD Contents/Resources/0/00/00text1 +FINISH ADD Contents/Resources/0/00/00text0 +FINISH ADD Contents/Resources/0/00/00png0.png +FINISH ADD Contents/MacOS/exe0.exe +FINISH REMOVEDIR Contents/Resources/9/99/ +FINISH REMOVEDIR Contents/Resources/9/99/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/9/98/ +FINISH REMOVEFILE Contents/Resources/9/97/970/97xtext0 +FINISH REMOVEFILE Contents/Resources/9/97/970/97xtext1 +FINISH REMOVEDIR Contents/Resources/9/97/970/ +FINISH REMOVEFILE Contents/Resources/9/97/971/97xtext0 +FINISH REMOVEFILE Contents/Resources/9/97/971/97xtext1 +FINISH REMOVEDIR Contents/Resources/9/97/971/ +FINISH REMOVEDIR Contents/Resources/9/97/ +FINISH REMOVEFILE Contents/Resources/9/96/96text0 +FINISH REMOVEFILE Contents/Resources/9/96/96text1 +FINISH REMOVEDIR Contents/Resources/9/96/ +FINISH REMOVEDIR Contents/Resources/9/95/ +FINISH REMOVEDIR Contents/Resources/9/95/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/9/94/ +FINISH REMOVEDIR Contents/Resources/9/94/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/9/93/ +FINISH REMOVEDIR Contents/Resources/9/92/ +removing directory: Contents/Resources/9/92/, rv: 0 +FINISH REMOVEDIR Contents/Resources/9/91/ +removing directory: Contents/Resources/9/91/, rv: 0 +FINISH REMOVEDIR Contents/Resources/9/90/ +FINISH REMOVEDIR Contents/Resources/9/90/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/8/89/ +FINISH REMOVEDIR Contents/Resources/8/89/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/8/88/ +FINISH REMOVEFILE Contents/Resources/8/87/870/87xtext0 +FINISH REMOVEFILE Contents/Resources/8/87/870/87xtext1 +FINISH REMOVEDIR Contents/Resources/8/87/870/ +FINISH REMOVEFILE Contents/Resources/8/87/871/87xtext0 +FINISH REMOVEFILE Contents/Resources/8/87/871/87xtext1 +FINISH REMOVEDIR Contents/Resources/8/87/871/ +FINISH REMOVEDIR Contents/Resources/8/87/ +FINISH REMOVEFILE Contents/Resources/8/86/86text0 +FINISH REMOVEFILE Contents/Resources/8/86/86text1 +FINISH REMOVEDIR Contents/Resources/8/86/ +FINISH REMOVEDIR Contents/Resources/8/85/ +FINISH REMOVEDIR Contents/Resources/8/85/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/8/84/ +FINISH REMOVEDIR Contents/Resources/8/84/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/8/83/ +FINISH REMOVEDIR Contents/Resources/8/82/ +removing directory: Contents/Resources/8/82/, rv: 0 +FINISH REMOVEDIR Contents/Resources/8/81/ +removing directory: Contents/Resources/8/81/, rv: 0 +FINISH REMOVEDIR Contents/Resources/8/80/ +FINISH REMOVEDIR Contents/Resources/8/80/ +directory no longer exists; skipping +FINISH REMOVEFILE Contents/Resources/7/70/7xtest.exe +FINISH REMOVEFILE Contents/Resources/7/70/7xtext0 +FINISH REMOVEFILE Contents/Resources/7/70/7xtext1 +FINISH REMOVEDIR Contents/Resources/7/70/ +FINISH REMOVEFILE Contents/Resources/7/71/7xtest.exe +FINISH REMOVEFILE Contents/Resources/7/71/7xtext0 +FINISH REMOVEFILE Contents/Resources/7/71/7xtext1 +FINISH REMOVEDIR Contents/Resources/7/71/ +FINISH REMOVEFILE Contents/Resources/7/7text0 +FINISH REMOVEFILE Contents/Resources/7/7text1 +FINISH REMOVEDIR Contents/Resources/7/ +FINISH REMOVEDIR Contents/Resources/6/ +FINISH REMOVEFILE Contents/Resources/5/5text1 +FINISH REMOVEFILE Contents/Resources/5/5text0 +FINISH REMOVEFILE Contents/Resources/5/5test.exe +FINISH REMOVEDIR Contents/Resources/5/ +FINISH REMOVEFILE Contents/Resources/4/4text1 +FINISH REMOVEFILE Contents/Resources/4/4text0 +FINISH REMOVEDIR Contents/Resources/4/ +FINISH REMOVEFILE Contents/Resources/3/3text1 +FINISH REMOVEFILE Contents/Resources/3/3text0 +succeeded +calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/data/complete_log_success_win b/toolkit/mozapps/update/tests/data/complete_log_success_win new file mode 100644 index 000000000..c5a03dc9d --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete_log_success_win @@ -0,0 +1,320 @@ +UPDATE TYPE complete +PREPARE REMOVEFILE searchplugins/searchpluginstext0 +PREPARE REMOVEFILE searchplugins/searchpluginspng0.png +PREPARE REMOVEFILE removed-files +PREPARE REMOVEFILE precomplete +PREPARE REMOVEFILE exe0.exe +PREPARE REMOVEFILE 2/20/20text0 +PREPARE REMOVEFILE 2/20/20png0.png +PREPARE REMOVEFILE 0/0exe0.exe +PREPARE REMOVEFILE 0/00/00text0 +PREPARE REMOVEDIR searchplugins/ +PREPARE REMOVEDIR defaults/pref/ +PREPARE REMOVEDIR defaults/ +PREPARE REMOVEDIR 2/20/ +PREPARE REMOVEDIR 2/ +PREPARE REMOVEDIR 0/00/ +PREPARE REMOVEDIR 0/ +PREPARE ADD searchplugins/searchpluginstext0 +PREPARE ADD searchplugins/searchpluginspng1.png +PREPARE ADD searchplugins/searchpluginspng0.png +PREPARE ADD removed-files +PREPARE ADD precomplete +PREPARE ADD exe0.exe +PREPARE ADD distribution/extensions/extensions1/extensions1text0 +PREPARE ADD distribution/extensions/extensions1/extensions1png1.png +PREPARE ADD distribution/extensions/extensions1/extensions1png0.png +PREPARE ADD distribution/extensions/extensions0/extensions0text0 +PREPARE ADD distribution/extensions/extensions0/extensions0png1.png +PREPARE ADD distribution/extensions/extensions0/extensions0png0.png +PREPARE ADD 1/10/10text0 +PREPARE ADD 0/0exe0.exe +PREPARE ADD 0/00/00text1 +PREPARE ADD 0/00/00text0 +PREPARE ADD 0/00/00png0.png +PREPARE REMOVEDIR 9/99/ +PREPARE REMOVEDIR 9/99/ +PREPARE REMOVEDIR 9/98/ +PREPARE REMOVEFILE 9/97/970/97xtext0 +PREPARE REMOVEFILE 9/97/970/97xtext1 +PREPARE REMOVEDIR 9/97/970/ +PREPARE REMOVEFILE 9/97/971/97xtext0 +PREPARE REMOVEFILE 9/97/971/97xtext1 +PREPARE REMOVEDIR 9/97/971/ +PREPARE REMOVEDIR 9/97/ +PREPARE REMOVEFILE 9/96/96text0 +PREPARE REMOVEFILE 9/96/96text1 +PREPARE REMOVEDIR 9/96/ +PREPARE REMOVEDIR 9/95/ +PREPARE REMOVEDIR 9/95/ +PREPARE REMOVEDIR 9/94/ +PREPARE REMOVEDIR 9/94/ +PREPARE REMOVEDIR 9/93/ +PREPARE REMOVEDIR 9/92/ +PREPARE REMOVEDIR 9/91/ +PREPARE REMOVEDIR 9/90/ +PREPARE REMOVEDIR 9/90/ +PREPARE REMOVEDIR 8/89/ +PREPARE REMOVEDIR 8/89/ +PREPARE REMOVEDIR 8/88/ +PREPARE REMOVEFILE 8/87/870/87xtext0 +PREPARE REMOVEFILE 8/87/870/87xtext1 +PREPARE REMOVEDIR 8/87/870/ +PREPARE REMOVEFILE 8/87/871/87xtext0 +PREPARE REMOVEFILE 8/87/871/87xtext1 +PREPARE REMOVEDIR 8/87/871/ +PREPARE REMOVEDIR 8/87/ +PREPARE REMOVEFILE 8/86/86text0 +PREPARE REMOVEFILE 8/86/86text1 +PREPARE REMOVEDIR 8/86/ +PREPARE REMOVEDIR 8/85/ +PREPARE REMOVEDIR 8/85/ +PREPARE REMOVEDIR 8/84/ +PREPARE REMOVEDIR 8/84/ +PREPARE REMOVEDIR 8/83/ +PREPARE REMOVEDIR 8/82/ +PREPARE REMOVEDIR 8/81/ +PREPARE REMOVEDIR 8/80/ +PREPARE REMOVEDIR 8/80/ +PREPARE REMOVEFILE 7/70/7xtest.exe +PREPARE REMOVEFILE 7/70/7xtext0 +PREPARE REMOVEFILE 7/70/7xtext1 +PREPARE REMOVEDIR 7/70/ +PREPARE REMOVEFILE 7/71/7xtest.exe +PREPARE REMOVEFILE 7/71/7xtext0 +PREPARE REMOVEFILE 7/71/7xtext1 +PREPARE REMOVEDIR 7/71/ +PREPARE REMOVEFILE 7/7text0 +PREPARE REMOVEFILE 7/7text1 +PREPARE REMOVEDIR 7/ +PREPARE REMOVEDIR 6/ +PREPARE REMOVEFILE 5/5text1 +PREPARE REMOVEFILE 5/5text0 +PREPARE REMOVEFILE 5/5test.exe +PREPARE REMOVEFILE 5/5text0 +PREPARE REMOVEFILE 5/5text1 +PREPARE REMOVEDIR 5/ +PREPARE REMOVEFILE 4/4text1 +PREPARE REMOVEFILE 4/4text0 +PREPARE REMOVEDIR 4/ +PREPARE REMOVEFILE 3/3text1 +PREPARE REMOVEFILE 3/3text0 +EXECUTE REMOVEFILE searchplugins/searchpluginstext0 +EXECUTE REMOVEFILE searchplugins/searchpluginspng0.png +EXECUTE REMOVEFILE removed-files +EXECUTE REMOVEFILE precomplete +EXECUTE REMOVEFILE exe0.exe +EXECUTE REMOVEFILE 2/20/20text0 +EXECUTE REMOVEFILE 2/20/20png0.png +EXECUTE REMOVEFILE 0/0exe0.exe +EXECUTE REMOVEFILE 0/00/00text0 +EXECUTE REMOVEDIR searchplugins/ +EXECUTE REMOVEDIR defaults/pref/ +EXECUTE REMOVEDIR defaults/ +EXECUTE REMOVEDIR 2/20/ +EXECUTE REMOVEDIR 2/ +EXECUTE REMOVEDIR 0/00/ +EXECUTE REMOVEDIR 0/ +EXECUTE ADD searchplugins/searchpluginstext0 +EXECUTE ADD searchplugins/searchpluginspng1.png +EXECUTE ADD searchplugins/searchpluginspng0.png +EXECUTE ADD removed-files +EXECUTE ADD precomplete +EXECUTE ADD exe0.exe +EXECUTE ADD distribution/extensions/extensions1/extensions1text0 +EXECUTE ADD distribution/extensions/extensions1/extensions1png1.png +EXECUTE ADD distribution/extensions/extensions1/extensions1png0.png +EXECUTE ADD distribution/extensions/extensions0/extensions0text0 +EXECUTE ADD distribution/extensions/extensions0/extensions0png1.png +EXECUTE ADD distribution/extensions/extensions0/extensions0png0.png +EXECUTE ADD 1/10/10text0 +EXECUTE ADD 0/0exe0.exe +EXECUTE ADD 0/00/00text1 +EXECUTE ADD 0/00/00text0 +EXECUTE ADD 0/00/00png0.png +EXECUTE REMOVEDIR 9/99/ +EXECUTE REMOVEDIR 9/99/ +EXECUTE REMOVEDIR 9/98/ +EXECUTE REMOVEFILE 9/97/970/97xtext0 +EXECUTE REMOVEFILE 9/97/970/97xtext1 +EXECUTE REMOVEDIR 9/97/970/ +EXECUTE REMOVEFILE 9/97/971/97xtext0 +EXECUTE REMOVEFILE 9/97/971/97xtext1 +EXECUTE REMOVEDIR 9/97/971/ +EXECUTE REMOVEDIR 9/97/ +EXECUTE REMOVEFILE 9/96/96text0 +EXECUTE REMOVEFILE 9/96/96text1 +EXECUTE REMOVEDIR 9/96/ +EXECUTE REMOVEDIR 9/95/ +EXECUTE REMOVEDIR 9/95/ +EXECUTE REMOVEDIR 9/94/ +EXECUTE REMOVEDIR 9/94/ +EXECUTE REMOVEDIR 9/93/ +EXECUTE REMOVEDIR 9/92/ +EXECUTE REMOVEDIR 9/91/ +EXECUTE REMOVEDIR 9/90/ +EXECUTE REMOVEDIR 9/90/ +EXECUTE REMOVEDIR 8/89/ +EXECUTE REMOVEDIR 8/89/ +EXECUTE REMOVEDIR 8/88/ +EXECUTE REMOVEFILE 8/87/870/87xtext0 +EXECUTE REMOVEFILE 8/87/870/87xtext1 +EXECUTE REMOVEDIR 8/87/870/ +EXECUTE REMOVEFILE 8/87/871/87xtext0 +EXECUTE REMOVEFILE 8/87/871/87xtext1 +EXECUTE REMOVEDIR 8/87/871/ +EXECUTE REMOVEDIR 8/87/ +EXECUTE REMOVEFILE 8/86/86text0 +EXECUTE REMOVEFILE 8/86/86text1 +EXECUTE REMOVEDIR 8/86/ +EXECUTE REMOVEDIR 8/85/ +EXECUTE REMOVEDIR 8/85/ +EXECUTE REMOVEDIR 8/84/ +EXECUTE REMOVEDIR 8/84/ +EXECUTE REMOVEDIR 8/83/ +EXECUTE REMOVEDIR 8/82/ +EXECUTE REMOVEDIR 8/81/ +EXECUTE REMOVEDIR 8/80/ +EXECUTE REMOVEDIR 8/80/ +EXECUTE REMOVEFILE 7/70/7xtest.exe +EXECUTE REMOVEFILE 7/70/7xtext0 +EXECUTE REMOVEFILE 7/70/7xtext1 +EXECUTE REMOVEDIR 7/70/ +EXECUTE REMOVEFILE 7/71/7xtest.exe +EXECUTE REMOVEFILE 7/71/7xtext0 +EXECUTE REMOVEFILE 7/71/7xtext1 +EXECUTE REMOVEDIR 7/71/ +EXECUTE REMOVEFILE 7/7text0 +EXECUTE REMOVEFILE 7/7text1 +EXECUTE REMOVEDIR 7/ +EXECUTE REMOVEDIR 6/ +EXECUTE REMOVEFILE 5/5text1 +EXECUTE REMOVEFILE 5/5text0 +EXECUTE REMOVEFILE 5/5test.exe +EXECUTE REMOVEFILE 5/5text0 +file cannot be removed because it does not exist; skipping +EXECUTE REMOVEFILE 5/5text1 +file cannot be removed because it does not exist; skipping +EXECUTE REMOVEDIR 5/ +EXECUTE REMOVEFILE 4/4text1 +EXECUTE REMOVEFILE 4/4text0 +EXECUTE REMOVEDIR 4/ +EXECUTE REMOVEFILE 3/3text1 +EXECUTE REMOVEFILE 3/3text0 +FINISH REMOVEFILE searchplugins/searchpluginstext0 +FINISH REMOVEFILE searchplugins/searchpluginspng0.png +FINISH REMOVEFILE removed-files +FINISH REMOVEFILE precomplete +FINISH REMOVEFILE exe0.exe +FINISH REMOVEFILE 2/20/20text0 +FINISH REMOVEFILE 2/20/20png0.png +FINISH REMOVEFILE 0/0exe0.exe +FINISH REMOVEFILE 0/00/00text0 +FINISH REMOVEDIR searchplugins/ +removing directory: searchplugins/, rv: 0 +FINISH REMOVEDIR defaults/pref/ +removing directory: defaults/pref/, rv: 0 +FINISH REMOVEDIR defaults/ +removing directory: defaults/, rv: 0 +FINISH REMOVEDIR 2/20/ +FINISH REMOVEDIR 2/ +FINISH REMOVEDIR 0/00/ +removing directory: 0/00/, rv: 0 +FINISH REMOVEDIR 0/ +removing directory: 0/, rv: 0 +FINISH ADD searchplugins/searchpluginstext0 +FINISH ADD searchplugins/searchpluginspng1.png +FINISH ADD searchplugins/searchpluginspng0.png +FINISH ADD removed-files +FINISH ADD precomplete +FINISH ADD exe0.exe +FINISH ADD distribution/extensions/extensions1/extensions1text0 +FINISH ADD distribution/extensions/extensions1/extensions1png1.png +FINISH ADD distribution/extensions/extensions1/extensions1png0.png +FINISH ADD distribution/extensions/extensions0/extensions0text0 +FINISH ADD distribution/extensions/extensions0/extensions0png1.png +FINISH ADD distribution/extensions/extensions0/extensions0png0.png +FINISH ADD 1/10/10text0 +FINISH ADD 0/0exe0.exe +FINISH ADD 0/00/00text1 +FINISH ADD 0/00/00text0 +FINISH ADD 0/00/00png0.png +FINISH REMOVEDIR 9/99/ +FINISH REMOVEDIR 9/99/ +directory no longer exists; skipping +FINISH REMOVEDIR 9/98/ +FINISH REMOVEFILE 9/97/970/97xtext0 +FINISH REMOVEFILE 9/97/970/97xtext1 +FINISH REMOVEDIR 9/97/970/ +FINISH REMOVEFILE 9/97/971/97xtext0 +FINISH REMOVEFILE 9/97/971/97xtext1 +FINISH REMOVEDIR 9/97/971/ +FINISH REMOVEDIR 9/97/ +FINISH REMOVEFILE 9/96/96text0 +FINISH REMOVEFILE 9/96/96text1 +FINISH REMOVEDIR 9/96/ +FINISH REMOVEDIR 9/95/ +FINISH REMOVEDIR 9/95/ +directory no longer exists; skipping +FINISH REMOVEDIR 9/94/ +FINISH REMOVEDIR 9/94/ +directory no longer exists; skipping +FINISH REMOVEDIR 9/93/ +FINISH REMOVEDIR 9/92/ +removing directory: 9/92/, rv: 0 +FINISH REMOVEDIR 9/91/ +removing directory: 9/91/, rv: 0 +FINISH REMOVEDIR 9/90/ +FINISH REMOVEDIR 9/90/ +directory no longer exists; skipping +FINISH REMOVEDIR 8/89/ +FINISH REMOVEDIR 8/89/ +directory no longer exists; skipping +FINISH REMOVEDIR 8/88/ +FINISH REMOVEFILE 8/87/870/87xtext0 +FINISH REMOVEFILE 8/87/870/87xtext1 +FINISH REMOVEDIR 8/87/870/ +FINISH REMOVEFILE 8/87/871/87xtext0 +FINISH REMOVEFILE 8/87/871/87xtext1 +FINISH REMOVEDIR 8/87/871/ +FINISH REMOVEDIR 8/87/ +FINISH REMOVEFILE 8/86/86text0 +FINISH REMOVEFILE 8/86/86text1 +FINISH REMOVEDIR 8/86/ +FINISH REMOVEDIR 8/85/ +FINISH REMOVEDIR 8/85/ +directory no longer exists; skipping +FINISH REMOVEDIR 8/84/ +FINISH REMOVEDIR 8/84/ +directory no longer exists; skipping +FINISH REMOVEDIR 8/83/ +FINISH REMOVEDIR 8/82/ +removing directory: 8/82/, rv: 0 +FINISH REMOVEDIR 8/81/ +removing directory: 8/81/, rv: 0 +FINISH REMOVEDIR 8/80/ +FINISH REMOVEDIR 8/80/ +directory no longer exists; skipping +FINISH REMOVEFILE 7/70/7xtest.exe +FINISH REMOVEFILE 7/70/7xtext0 +FINISH REMOVEFILE 7/70/7xtext1 +FINISH REMOVEDIR 7/70/ +FINISH REMOVEFILE 7/71/7xtest.exe +FINISH REMOVEFILE 7/71/7xtext0 +FINISH REMOVEFILE 7/71/7xtext1 +FINISH REMOVEDIR 7/71/ +FINISH REMOVEFILE 7/7text0 +FINISH REMOVEFILE 7/7text1 +FINISH REMOVEDIR 7/ +FINISH REMOVEDIR 6/ +FINISH REMOVEFILE 5/5text1 +FINISH REMOVEFILE 5/5text0 +FINISH REMOVEFILE 5/5test.exe +FINISH REMOVEDIR 5/ +FINISH REMOVEFILE 4/4text1 +FINISH REMOVEFILE 4/4text0 +FINISH REMOVEDIR 4/ +FINISH REMOVEFILE 3/3text1 +FINISH REMOVEFILE 3/3text0 +succeeded +calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/data/complete_mac.mar b/toolkit/mozapps/update/tests/data/complete_mac.mar Binary files differnew file mode 100644 index 000000000..ca1497f4f --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete_mac.mar diff --git a/toolkit/mozapps/update/tests/data/complete_precomplete b/toolkit/mozapps/update/tests/data/complete_precomplete new file mode 100644 index 000000000..ae7a0013f --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete_precomplete @@ -0,0 +1,18 @@ +remove "searchplugins/searchpluginstext0" +remove "searchplugins/searchpluginspng1.png" +remove "searchplugins/searchpluginspng0.png" +remove "removed-files" +remove "precomplete" +remove "exe0.exe" +remove "1/10/10text0" +remove "0/0exe0.exe" +remove "0/00/00text1" +remove "0/00/00text0" +remove "0/00/00png0.png" +rmdir "searchplugins/" +rmdir "defaults/pref/" +rmdir "defaults/" +rmdir "1/10/" +rmdir "1/" +rmdir "0/00/" +rmdir "0/" diff --git a/toolkit/mozapps/update/tests/data/complete_precomplete_mac b/toolkit/mozapps/update/tests/data/complete_precomplete_mac new file mode 100644 index 000000000..8d81a36d6 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete_precomplete_mac @@ -0,0 +1,21 @@ +remove "Contents/Resources/searchplugins/searchpluginstext0" +remove "Contents/Resources/searchplugins/searchpluginspng1.png" +remove "Contents/Resources/searchplugins/searchpluginspng0.png" +remove "Contents/Resources/removed-files" +remove "Contents/Resources/precomplete" +remove "Contents/Resources/1/10/10text0" +remove "Contents/Resources/0/0exe0.exe" +remove "Contents/Resources/0/00/00text1" +remove "Contents/Resources/0/00/00text0" +remove "Contents/Resources/0/00/00png0.png" +remove "Contents/MacOS/exe0.exe" +rmdir "Contents/Resources/searchplugins/" +rmdir "Contents/Resources/defaults/pref/" +rmdir "Contents/Resources/defaults/" +rmdir "Contents/Resources/1/10/" +rmdir "Contents/Resources/1/" +rmdir "Contents/Resources/0/00/" +rmdir "Contents/Resources/0/" +rmdir "Contents/Resources/" +rmdir "Contents/MacOS/" +rmdir "Contents/" diff --git a/toolkit/mozapps/update/tests/data/complete_removed-files b/toolkit/mozapps/update/tests/data/complete_removed-files new file mode 100644 index 000000000..e45c43c1f --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete_removed-files @@ -0,0 +1,41 @@ +text0 +text1 +3/3text0 +3/3text1 +4/exe0.exe +4/4text0 +4/4text1 +4/ +5/5text0 +5/5text1 +5/* +6/ +7/* +8/80/ +8/81/ +8/82/ +8/83/ +8/84/ +8/85/* +8/86/* +8/87/* +8/88/* +8/89/* +8/80/ +8/84/* +8/85/* +8/89/ +9/90/ +9/91/ +9/92/ +9/93/ +9/94/ +9/95/* +9/96/* +9/97/* +9/98/* +9/99/* +9/90/ +9/94/* +9/95/* +9/99/ diff --git a/toolkit/mozapps/update/tests/data/complete_removed-files_mac b/toolkit/mozapps/update/tests/data/complete_removed-files_mac new file mode 100644 index 000000000..955dc5b34 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete_removed-files_mac @@ -0,0 +1,41 @@ +Contents/Resources/text0 +Contents/Resources/text1 +Contents/Resources/3/3text0 +Contents/Resources/3/3text1 +Contents/Resources/4/exe0.exe +Contents/Resources/4/4text0 +Contents/Resources/4/4text1 +Contents/Resources/4/ +Contents/Resources/5/5text0 +Contents/Resources/5/5text1 +Contents/Resources/5/* +Contents/Resources/6/ +Contents/Resources/7/* +Contents/Resources/8/80/ +Contents/Resources/8/81/ +Contents/Resources/8/82/ +Contents/Resources/8/83/ +Contents/Resources/8/84/ +Contents/Resources/8/85/* +Contents/Resources/8/86/* +Contents/Resources/8/87/* +Contents/Resources/8/88/* +Contents/Resources/8/89/* +Contents/Resources/8/80/ +Contents/Resources/8/84/* +Contents/Resources/8/85/* +Contents/Resources/8/89/ +Contents/Resources/9/90/ +Contents/Resources/9/91/ +Contents/Resources/9/92/ +Contents/Resources/9/93/ +Contents/Resources/9/94/ +Contents/Resources/9/95/* +Contents/Resources/9/96/* +Contents/Resources/9/97/* +Contents/Resources/9/98/* +Contents/Resources/9/99/* +Contents/Resources/9/90/ +Contents/Resources/9/94/* +Contents/Resources/9/95/* +Contents/Resources/9/99/ diff --git a/toolkit/mozapps/update/tests/data/complete_update_manifest b/toolkit/mozapps/update/tests/data/complete_update_manifest new file mode 100644 index 000000000..383a324f6 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/complete_update_manifest @@ -0,0 +1,59 @@ +type "complete" +add "precomplete" +add "searchplugins/searchpluginstext0" +add "searchplugins/searchpluginspng1.png" +add "searchplugins/searchpluginspng0.png" +add "removed-files" +add-if "extensions/extensions1" "extensions/extensions1/extensions1text0" +add-if "extensions/extensions1" "extensions/extensions1/extensions1png1.png" +add-if "extensions/extensions1" "extensions/extensions1/extensions1png0.png" +add-if "extensions/extensions0" "extensions/extensions0/extensions0text0" +add-if "extensions/extensions0" "extensions/extensions0/extensions0png1.png" +add-if "extensions/extensions0" "extensions/extensions0/extensions0png0.png" +add "exe0.exe" +add "1/10/10text0" +add "0/0exe0.exe" +add "0/00/00text1" +add "0/00/00text0" +add "0/00/00png0.png" +remove "text1" +remove "text0" +rmrfdir "9/99/" +rmdir "9/99/" +rmrfdir "9/98/" +rmrfdir "9/97/" +rmrfdir "9/96/" +rmrfdir "9/95/" +rmrfdir "9/95/" +rmrfdir "9/94/" +rmdir "9/94/" +rmdir "9/93/" +rmdir "9/92/" +rmdir "9/91/" +rmdir "9/90/" +rmdir "9/90/" +rmrfdir "8/89/" +rmdir "8/89/" +rmrfdir "8/88/" +rmrfdir "8/87/" +rmrfdir "8/86/" +rmrfdir "8/85/" +rmrfdir "8/85/" +rmrfdir "8/84/" +rmdir "8/84/" +rmdir "8/83/" +rmdir "8/82/" +rmdir "8/81/" +rmdir "8/80/" +rmdir "8/80/" +rmrfdir "7/" +rmdir "6/" +remove "5/5text1" +remove "5/5text0" +rmrfdir "5/" +remove "4/exe0.exe" +remove "4/4text1" +remove "4/4text0" +rmdir "4/" +remove "3/3text1" +remove "3/3text0" diff --git a/toolkit/mozapps/update/tests/data/old_version.mar b/toolkit/mozapps/update/tests/data/old_version.mar Binary files differnew file mode 100644 index 000000000..31550698a --- /dev/null +++ b/toolkit/mozapps/update/tests/data/old_version.mar diff --git a/toolkit/mozapps/update/tests/data/partial.exe b/toolkit/mozapps/update/tests/data/partial.exe Binary files differnew file mode 100644 index 000000000..3949fd2a0 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial.exe diff --git a/toolkit/mozapps/update/tests/data/partial.mar b/toolkit/mozapps/update/tests/data/partial.mar Binary files differnew file mode 100644 index 000000000..789d3d98d --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial.mar diff --git a/toolkit/mozapps/update/tests/data/partial.png b/toolkit/mozapps/update/tests/data/partial.png Binary files differnew file mode 100644 index 000000000..9246f586c --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial.png diff --git a/toolkit/mozapps/update/tests/data/partial_log_failure_mac b/toolkit/mozapps/update/tests/data/partial_log_failure_mac new file mode 100644 index 000000000..3b2933ebd --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_log_failure_mac @@ -0,0 +1,192 @@ +UPDATE TYPE partial +PREPARE ADD Contents/Resources/searchplugins/searchpluginstext0 +PREPARE PATCH Contents/Resources/searchplugins/searchpluginspng1.png +PREPARE PATCH Contents/Resources/searchplugins/searchpluginspng0.png +PREPARE ADD Contents/Resources/precomplete +PREPARE ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +PREPARE PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +PREPARE PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +PREPARE ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +PREPARE PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +PREPARE PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +PREPARE PATCH Contents/Resources/0/0exe0.exe +PREPARE ADD Contents/Resources/0/00/00text0 +PREPARE PATCH Contents/Resources/0/00/00png0.png +PREPARE PATCH Contents/MacOS/exe0.exe +PREPARE ADD Contents/Resources/2/20/20text0 +PREPARE ADD Contents/Resources/2/20/20png0.png +PREPARE ADD Contents/Resources/0/00/00text2 +PREPARE REMOVEFILE Contents/Resources/1/10/10text0 +PREPARE REMOVEFILE Contents/Resources/0/00/00text1 +PREPARE REMOVEDIR Contents/Resources/9/99/ +PREPARE REMOVEDIR Contents/Resources/9/99/ +PREPARE REMOVEDIR Contents/Resources/9/98/ +PREPARE REMOVEFILE Contents/Resources/9/97/970/97xtext0 +PREPARE REMOVEFILE Contents/Resources/9/97/970/97xtext1 +PREPARE REMOVEDIR Contents/Resources/9/97/970/ +PREPARE REMOVEFILE Contents/Resources/9/97/971/97xtext0 +PREPARE REMOVEFILE Contents/Resources/9/97/971/97xtext1 +PREPARE REMOVEDIR Contents/Resources/9/97/971/ +PREPARE REMOVEDIR Contents/Resources/9/97/ +PREPARE REMOVEFILE Contents/Resources/9/96/96text0 +PREPARE REMOVEFILE Contents/Resources/9/96/96text1 +PREPARE REMOVEDIR Contents/Resources/9/96/ +PREPARE REMOVEDIR Contents/Resources/9/95/ +PREPARE REMOVEDIR Contents/Resources/9/95/ +PREPARE REMOVEDIR Contents/Resources/9/94/ +PREPARE REMOVEDIR Contents/Resources/9/94/ +PREPARE REMOVEDIR Contents/Resources/9/93/ +PREPARE REMOVEDIR Contents/Resources/9/92/ +PREPARE REMOVEDIR Contents/Resources/9/91/ +PREPARE REMOVEDIR Contents/Resources/9/90/ +PREPARE REMOVEDIR Contents/Resources/9/90/ +PREPARE REMOVEDIR Contents/Resources/8/89/ +PREPARE REMOVEDIR Contents/Resources/8/89/ +PREPARE REMOVEDIR Contents/Resources/8/88/ +PREPARE REMOVEFILE Contents/Resources/8/87/870/87xtext0 +PREPARE REMOVEFILE Contents/Resources/8/87/870/87xtext1 +PREPARE REMOVEDIR Contents/Resources/8/87/870/ +PREPARE REMOVEFILE Contents/Resources/8/87/871/87xtext0 +PREPARE REMOVEFILE Contents/Resources/8/87/871/87xtext1 +PREPARE REMOVEDIR Contents/Resources/8/87/871/ +PREPARE REMOVEDIR Contents/Resources/8/87/ +PREPARE REMOVEFILE Contents/Resources/8/86/86text0 +PREPARE REMOVEFILE Contents/Resources/8/86/86text1 +PREPARE REMOVEDIR Contents/Resources/8/86/ +PREPARE REMOVEDIR Contents/Resources/8/85/ +PREPARE REMOVEDIR Contents/Resources/8/85/ +PREPARE REMOVEDIR Contents/Resources/8/84/ +PREPARE REMOVEDIR Contents/Resources/8/84/ +PREPARE REMOVEDIR Contents/Resources/8/83/ +PREPARE REMOVEDIR Contents/Resources/8/82/ +PREPARE REMOVEDIR Contents/Resources/8/81/ +PREPARE REMOVEDIR Contents/Resources/8/80/ +PREPARE REMOVEDIR Contents/Resources/8/80/ +PREPARE REMOVEFILE Contents/Resources/7/70/7xtest.exe +PREPARE REMOVEFILE Contents/Resources/7/70/7xtext0 +PREPARE REMOVEFILE Contents/Resources/7/70/7xtext1 +PREPARE REMOVEDIR Contents/Resources/7/70/ +PREPARE REMOVEFILE Contents/Resources/7/71/7xtest.exe +PREPARE REMOVEFILE Contents/Resources/7/71/7xtext0 +PREPARE REMOVEFILE Contents/Resources/7/71/7xtext1 +PREPARE REMOVEDIR Contents/Resources/7/71/ +PREPARE REMOVEFILE Contents/Resources/7/7text0 +PREPARE REMOVEFILE Contents/Resources/7/7text1 +PREPARE REMOVEDIR Contents/Resources/7/ +PREPARE REMOVEDIR Contents/Resources/6/ +PREPARE REMOVEFILE Contents/Resources/5/5text1 +PREPARE REMOVEFILE Contents/Resources/5/5text0 +PREPARE REMOVEFILE Contents/Resources/5/5test.exe +PREPARE REMOVEFILE Contents/Resources/5/5text0 +PREPARE REMOVEFILE Contents/Resources/5/5text1 +PREPARE REMOVEDIR Contents/Resources/5/ +PREPARE REMOVEFILE Contents/Resources/4/4text1 +PREPARE REMOVEFILE Contents/Resources/4/4text0 +PREPARE REMOVEDIR Contents/Resources/4/ +PREPARE REMOVEFILE Contents/Resources/3/3text1 +PREPARE REMOVEFILE Contents/Resources/3/3text0 +PREPARE REMOVEDIR Contents/Resources/1/10/ +PREPARE REMOVEDIR Contents/Resources/1/ +EXECUTE ADD Contents/Resources/searchplugins/searchpluginstext0 +EXECUTE PATCH Contents/Resources/searchplugins/searchpluginspng1.png +EXECUTE PATCH Contents/Resources/searchplugins/searchpluginspng0.png +EXECUTE ADD Contents/Resources/precomplete +EXECUTE ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +EXECUTE PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +EXECUTE PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +EXECUTE ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +EXECUTE PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +EXECUTE PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +EXECUTE PATCH Contents/Resources/0/0exe0.exe +LoadSourceFile: destination file size 776 does not match expected size 79872 +LoadSourceFile failed +### execution failed +FINISH ADD Contents/Resources/searchplugins/searchpluginstext0 +FINISH PATCH Contents/Resources/searchplugins/searchpluginspng1.png +FINISH PATCH Contents/Resources/searchplugins/searchpluginspng0.png +FINISH ADD Contents/Resources/precomplete +FINISH ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +backup_restore: backup file doesn't exist: Contents/Resources/distribution/extensions/extensions1/extensions1text0.moz-backup +FINISH PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +FINISH PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +FINISH ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +FINISH PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +FINISH PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +FINISH PATCH Contents/Resources/0/0exe0.exe +backup_restore: backup file doesn't exist: Contents/Resources/0/0exe0.exe.moz-backup +FINISH ADD Contents/Resources/0/00/00text0 +backup_restore: backup file doesn't exist: Contents/Resources/0/00/00text0.moz-backup +FINISH PATCH Contents/Resources/0/00/00png0.png +backup_restore: backup file doesn't exist: Contents/Resources/0/00/00png0.png.moz-backup +FINISH PATCH Contents/MacOS/exe0.exe +backup_restore: backup file doesn't exist: Contents/MacOS/exe0.exe.moz-backup +FINISH ADD Contents/Resources/2/20/20text0 +backup_restore: backup file doesn't exist: Contents/Resources/2/20/20text0.moz-backup +FINISH ADD Contents/Resources/2/20/20png0.png +backup_restore: backup file doesn't exist: Contents/Resources/2/20/20png0.png.moz-backup +FINISH ADD Contents/Resources/0/00/00text2 +backup_restore: backup file doesn't exist: Contents/Resources/0/00/00text2.moz-backup +FINISH REMOVEFILE Contents/Resources/1/10/10text0 +backup_restore: backup file doesn't exist: Contents/Resources/1/10/10text0.moz-backup +FINISH REMOVEFILE Contents/Resources/0/00/00text1 +backup_restore: backup file doesn't exist: Contents/Resources/0/00/00text1.moz-backup +FINISH REMOVEFILE Contents/Resources/9/97/970/97xtext0 +backup_restore: backup file doesn't exist: Contents/Resources/9/97/970/97xtext0.moz-backup +FINISH REMOVEFILE Contents/Resources/9/97/970/97xtext1 +backup_restore: backup file doesn't exist: Contents/Resources/9/97/970/97xtext1.moz-backup +FINISH REMOVEFILE Contents/Resources/9/97/971/97xtext0 +backup_restore: backup file doesn't exist: Contents/Resources/9/97/971/97xtext0.moz-backup +FINISH REMOVEFILE Contents/Resources/9/97/971/97xtext1 +backup_restore: backup file doesn't exist: Contents/Resources/9/97/971/97xtext1.moz-backup +FINISH REMOVEFILE Contents/Resources/9/96/96text0 +backup_restore: backup file doesn't exist: Contents/Resources/9/96/96text0.moz-backup +FINISH REMOVEFILE Contents/Resources/9/96/96text1 +backup_restore: backup file doesn't exist: Contents/Resources/9/96/96text1.moz-backup +FINISH REMOVEFILE Contents/Resources/8/87/870/87xtext0 +backup_restore: backup file doesn't exist: Contents/Resources/8/87/870/87xtext0.moz-backup +FINISH REMOVEFILE Contents/Resources/8/87/870/87xtext1 +backup_restore: backup file doesn't exist: Contents/Resources/8/87/870/87xtext1.moz-backup +FINISH REMOVEFILE Contents/Resources/8/87/871/87xtext0 +backup_restore: backup file doesn't exist: Contents/Resources/8/87/871/87xtext0.moz-backup +FINISH REMOVEFILE Contents/Resources/8/87/871/87xtext1 +backup_restore: backup file doesn't exist: Contents/Resources/8/87/871/87xtext1.moz-backup +FINISH REMOVEFILE Contents/Resources/8/86/86text0 +backup_restore: backup file doesn't exist: Contents/Resources/8/86/86text0.moz-backup +FINISH REMOVEFILE Contents/Resources/8/86/86text1 +backup_restore: backup file doesn't exist: Contents/Resources/8/86/86text1.moz-backup +FINISH REMOVEFILE Contents/Resources/7/70/7xtest.exe +backup_restore: backup file doesn't exist: Contents/Resources/7/70/7xtest.exe.moz-backup +FINISH REMOVEFILE Contents/Resources/7/70/7xtext0 +backup_restore: backup file doesn't exist: Contents/Resources/7/70/7xtext0.moz-backup +FINISH REMOVEFILE Contents/Resources/7/70/7xtext1 +backup_restore: backup file doesn't exist: Contents/Resources/7/70/7xtext1.moz-backup +FINISH REMOVEFILE Contents/Resources/7/71/7xtest.exe +backup_restore: backup file doesn't exist: Contents/Resources/7/71/7xtest.exe.moz-backup +FINISH REMOVEFILE Contents/Resources/7/71/7xtext0 +backup_restore: backup file doesn't exist: Contents/Resources/7/71/7xtext0.moz-backup +FINISH REMOVEFILE Contents/Resources/7/71/7xtext1 +backup_restore: backup file doesn't exist: Contents/Resources/7/71/7xtext1.moz-backup +FINISH REMOVEFILE Contents/Resources/7/7text0 +backup_restore: backup file doesn't exist: Contents/Resources/7/7text0.moz-backup +FINISH REMOVEFILE Contents/Resources/7/7text1 +backup_restore: backup file doesn't exist: Contents/Resources/7/7text1.moz-backup +FINISH REMOVEFILE Contents/Resources/5/5text1 +backup_restore: backup file doesn't exist: Contents/Resources/5/5text1.moz-backup +FINISH REMOVEFILE Contents/Resources/5/5text0 +backup_restore: backup file doesn't exist: Contents/Resources/5/5text0.moz-backup +FINISH REMOVEFILE Contents/Resources/5/5test.exe +backup_restore: backup file doesn't exist: Contents/Resources/5/5test.exe.moz-backup +FINISH REMOVEFILE Contents/Resources/5/5text0 +backup_restore: backup file doesn't exist: Contents/Resources/5/5text0.moz-backup +FINISH REMOVEFILE Contents/Resources/5/5text1 +backup_restore: backup file doesn't exist: Contents/Resources/5/5text1.moz-backup +FINISH REMOVEFILE Contents/Resources/4/4text1 +backup_restore: backup file doesn't exist: Contents/Resources/4/4text1.moz-backup +FINISH REMOVEFILE Contents/Resources/4/4text0 +backup_restore: backup file doesn't exist: Contents/Resources/4/4text0.moz-backup +FINISH REMOVEFILE Contents/Resources/3/3text1 +backup_restore: backup file doesn't exist: Contents/Resources/3/3text1.moz-backup +FINISH REMOVEFILE Contents/Resources/3/3text0 +backup_restore: backup file doesn't exist: Contents/Resources/3/3text0.moz-backup +failed: 2 +calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/data/partial_log_failure_win b/toolkit/mozapps/update/tests/data/partial_log_failure_win new file mode 100644 index 000000000..e3d683dc1 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_log_failure_win @@ -0,0 +1,192 @@ +UPDATE TYPE partial +PREPARE ADD searchplugins/searchpluginstext0 +PREPARE PATCH searchplugins/searchpluginspng1.png +PREPARE PATCH searchplugins/searchpluginspng0.png +PREPARE ADD precomplete +PREPARE PATCH exe0.exe +PREPARE ADD distribution/extensions/extensions1/extensions1text0 +PREPARE PATCH distribution/extensions/extensions1/extensions1png1.png +PREPARE PATCH distribution/extensions/extensions1/extensions1png0.png +PREPARE ADD distribution/extensions/extensions0/extensions0text0 +PREPARE PATCH distribution/extensions/extensions0/extensions0png1.png +PREPARE PATCH distribution/extensions/extensions0/extensions0png0.png +PREPARE PATCH 0/0exe0.exe +PREPARE ADD 0/00/00text0 +PREPARE PATCH 0/00/00png0.png +PREPARE ADD 2/20/20text0 +PREPARE ADD 2/20/20png0.png +PREPARE ADD 0/00/00text2 +PREPARE REMOVEFILE 1/10/10text0 +PREPARE REMOVEFILE 0/00/00text1 +PREPARE REMOVEDIR 9/99/ +PREPARE REMOVEDIR 9/99/ +PREPARE REMOVEDIR 9/98/ +PREPARE REMOVEFILE 9/97/970/97xtext0 +PREPARE REMOVEFILE 9/97/970/97xtext1 +PREPARE REMOVEDIR 9/97/970/ +PREPARE REMOVEFILE 9/97/971/97xtext0 +PREPARE REMOVEFILE 9/97/971/97xtext1 +PREPARE REMOVEDIR 9/97/971/ +PREPARE REMOVEDIR 9/97/ +PREPARE REMOVEFILE 9/96/96text0 +PREPARE REMOVEFILE 9/96/96text1 +PREPARE REMOVEDIR 9/96/ +PREPARE REMOVEDIR 9/95/ +PREPARE REMOVEDIR 9/95/ +PREPARE REMOVEDIR 9/94/ +PREPARE REMOVEDIR 9/94/ +PREPARE REMOVEDIR 9/93/ +PREPARE REMOVEDIR 9/92/ +PREPARE REMOVEDIR 9/91/ +PREPARE REMOVEDIR 9/90/ +PREPARE REMOVEDIR 9/90/ +PREPARE REMOVEDIR 8/89/ +PREPARE REMOVEDIR 8/89/ +PREPARE REMOVEDIR 8/88/ +PREPARE REMOVEFILE 8/87/870/87xtext0 +PREPARE REMOVEFILE 8/87/870/87xtext1 +PREPARE REMOVEDIR 8/87/870/ +PREPARE REMOVEFILE 8/87/871/87xtext0 +PREPARE REMOVEFILE 8/87/871/87xtext1 +PREPARE REMOVEDIR 8/87/871/ +PREPARE REMOVEDIR 8/87/ +PREPARE REMOVEFILE 8/86/86text0 +PREPARE REMOVEFILE 8/86/86text1 +PREPARE REMOVEDIR 8/86/ +PREPARE REMOVEDIR 8/85/ +PREPARE REMOVEDIR 8/85/ +PREPARE REMOVEDIR 8/84/ +PREPARE REMOVEDIR 8/84/ +PREPARE REMOVEDIR 8/83/ +PREPARE REMOVEDIR 8/82/ +PREPARE REMOVEDIR 8/81/ +PREPARE REMOVEDIR 8/80/ +PREPARE REMOVEDIR 8/80/ +PREPARE REMOVEFILE 7/70/7xtest.exe +PREPARE REMOVEFILE 7/70/7xtext0 +PREPARE REMOVEFILE 7/70/7xtext1 +PREPARE REMOVEDIR 7/70/ +PREPARE REMOVEFILE 7/71/7xtest.exe +PREPARE REMOVEFILE 7/71/7xtext0 +PREPARE REMOVEFILE 7/71/7xtext1 +PREPARE REMOVEDIR 7/71/ +PREPARE REMOVEFILE 7/7text0 +PREPARE REMOVEFILE 7/7text1 +PREPARE REMOVEDIR 7/ +PREPARE REMOVEDIR 6/ +PREPARE REMOVEFILE 5/5text1 +PREPARE REMOVEFILE 5/5text0 +PREPARE REMOVEFILE 5/5test.exe +PREPARE REMOVEFILE 5/5text0 +PREPARE REMOVEFILE 5/5text1 +PREPARE REMOVEDIR 5/ +PREPARE REMOVEFILE 4/4text1 +PREPARE REMOVEFILE 4/4text0 +PREPARE REMOVEDIR 4/ +PREPARE REMOVEFILE 3/3text1 +PREPARE REMOVEFILE 3/3text0 +PREPARE REMOVEDIR 1/10/ +PREPARE REMOVEDIR 1/ +EXECUTE ADD searchplugins/searchpluginstext0 +EXECUTE PATCH searchplugins/searchpluginspng1.png +EXECUTE PATCH searchplugins/searchpluginspng0.png +EXECUTE ADD precomplete +EXECUTE PATCH exe0.exe +EXECUTE ADD distribution/extensions/extensions1/extensions1text0 +EXECUTE PATCH distribution/extensions/extensions1/extensions1png1.png +EXECUTE PATCH distribution/extensions/extensions1/extensions1png0.png +EXECUTE ADD distribution/extensions/extensions0/extensions0text0 +EXECUTE PATCH distribution/extensions/extensions0/extensions0png1.png +EXECUTE PATCH distribution/extensions/extensions0/extensions0png0.png +EXECUTE PATCH 0/0exe0.exe +LoadSourceFile: destination file size 776 does not match expected size 79872 +LoadSourceFile failed +### execution failed +FINISH ADD searchplugins/searchpluginstext0 +FINISH PATCH searchplugins/searchpluginspng1.png +FINISH PATCH searchplugins/searchpluginspng0.png +FINISH ADD precomplete +FINISH PATCH exe0.exe +FINISH ADD distribution/extensions/extensions1/extensions1text0 +backup_restore: backup file doesn't exist: distribution/extensions/extensions1/extensions1text0.moz-backup +FINISH PATCH distribution/extensions/extensions1/extensions1png1.png +FINISH PATCH distribution/extensions/extensions1/extensions1png0.png +FINISH ADD distribution/extensions/extensions0/extensions0text0 +FINISH PATCH distribution/extensions/extensions0/extensions0png1.png +FINISH PATCH distribution/extensions/extensions0/extensions0png0.png +FINISH PATCH 0/0exe0.exe +backup_restore: backup file doesn't exist: 0/0exe0.exe.moz-backup +FINISH ADD 0/00/00text0 +backup_restore: backup file doesn't exist: 0/00/00text0.moz-backup +FINISH PATCH 0/00/00png0.png +backup_restore: backup file doesn't exist: 0/00/00png0.png.moz-backup +FINISH ADD 2/20/20text0 +backup_restore: backup file doesn't exist: 2/20/20text0.moz-backup +FINISH ADD 2/20/20png0.png +backup_restore: backup file doesn't exist: 2/20/20png0.png.moz-backup +FINISH ADD 0/00/00text2 +backup_restore: backup file doesn't exist: 0/00/00text2.moz-backup +FINISH REMOVEFILE 1/10/10text0 +backup_restore: backup file doesn't exist: 1/10/10text0.moz-backup +FINISH REMOVEFILE 0/00/00text1 +backup_restore: backup file doesn't exist: 0/00/00text1.moz-backup +FINISH REMOVEFILE 9/97/970/97xtext0 +backup_restore: backup file doesn't exist: 9/97/970/97xtext0.moz-backup +FINISH REMOVEFILE 9/97/970/97xtext1 +backup_restore: backup file doesn't exist: 9/97/970/97xtext1.moz-backup +FINISH REMOVEFILE 9/97/971/97xtext0 +backup_restore: backup file doesn't exist: 9/97/971/97xtext0.moz-backup +FINISH REMOVEFILE 9/97/971/97xtext1 +backup_restore: backup file doesn't exist: 9/97/971/97xtext1.moz-backup +FINISH REMOVEFILE 9/96/96text0 +backup_restore: backup file doesn't exist: 9/96/96text0.moz-backup +FINISH REMOVEFILE 9/96/96text1 +backup_restore: backup file doesn't exist: 9/96/96text1.moz-backup +FINISH REMOVEFILE 8/87/870/87xtext0 +backup_restore: backup file doesn't exist: 8/87/870/87xtext0.moz-backup +FINISH REMOVEFILE 8/87/870/87xtext1 +backup_restore: backup file doesn't exist: 8/87/870/87xtext1.moz-backup +FINISH REMOVEFILE 8/87/871/87xtext0 +backup_restore: backup file doesn't exist: 8/87/871/87xtext0.moz-backup +FINISH REMOVEFILE 8/87/871/87xtext1 +backup_restore: backup file doesn't exist: 8/87/871/87xtext1.moz-backup +FINISH REMOVEFILE 8/86/86text0 +backup_restore: backup file doesn't exist: 8/86/86text0.moz-backup +FINISH REMOVEFILE 8/86/86text1 +backup_restore: backup file doesn't exist: 8/86/86text1.moz-backup +FINISH REMOVEFILE 7/70/7xtest.exe +backup_restore: backup file doesn't exist: 7/70/7xtest.exe.moz-backup +FINISH REMOVEFILE 7/70/7xtext0 +backup_restore: backup file doesn't exist: 7/70/7xtext0.moz-backup +FINISH REMOVEFILE 7/70/7xtext1 +backup_restore: backup file doesn't exist: 7/70/7xtext1.moz-backup +FINISH REMOVEFILE 7/71/7xtest.exe +backup_restore: backup file doesn't exist: 7/71/7xtest.exe.moz-backup +FINISH REMOVEFILE 7/71/7xtext0 +backup_restore: backup file doesn't exist: 7/71/7xtext0.moz-backup +FINISH REMOVEFILE 7/71/7xtext1 +backup_restore: backup file doesn't exist: 7/71/7xtext1.moz-backup +FINISH REMOVEFILE 7/7text0 +backup_restore: backup file doesn't exist: 7/7text0.moz-backup +FINISH REMOVEFILE 7/7text1 +backup_restore: backup file doesn't exist: 7/7text1.moz-backup +FINISH REMOVEFILE 5/5text1 +backup_restore: backup file doesn't exist: 5/5text1.moz-backup +FINISH REMOVEFILE 5/5text0 +backup_restore: backup file doesn't exist: 5/5text0.moz-backup +FINISH REMOVEFILE 5/5test.exe +backup_restore: backup file doesn't exist: 5/5test.exe.moz-backup +FINISH REMOVEFILE 5/5text0 +backup_restore: backup file doesn't exist: 5/5text0.moz-backup +FINISH REMOVEFILE 5/5text1 +backup_restore: backup file doesn't exist: 5/5text1.moz-backup +FINISH REMOVEFILE 4/4text1 +backup_restore: backup file doesn't exist: 4/4text1.moz-backup +FINISH REMOVEFILE 4/4text0 +backup_restore: backup file doesn't exist: 4/4text0.moz-backup +FINISH REMOVEFILE 3/3text1 +backup_restore: backup file doesn't exist: 3/3text1.moz-backup +FINISH REMOVEFILE 3/3text0 +backup_restore: backup file doesn't exist: 3/3text0.moz-backup +failed: 2 +calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/data/partial_log_success_mac b/toolkit/mozapps/update/tests/data/partial_log_success_mac new file mode 100644 index 000000000..fb5272ad2 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_log_success_mac @@ -0,0 +1,279 @@ +UPDATE TYPE partial +PREPARE ADD Contents/Resources/searchplugins/searchpluginstext0 +PREPARE PATCH Contents/Resources/searchplugins/searchpluginspng1.png +PREPARE PATCH Contents/Resources/searchplugins/searchpluginspng0.png +PREPARE ADD Contents/Resources/precomplete +PREPARE ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +PREPARE PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +PREPARE PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +PREPARE ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +PREPARE PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +PREPARE PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +PREPARE PATCH Contents/Resources/0/0exe0.exe +PREPARE ADD Contents/Resources/0/00/00text0 +PREPARE PATCH Contents/Resources/0/00/00png0.png +PREPARE PATCH Contents/MacOS/exe0.exe +PREPARE ADD Contents/Resources/2/20/20text0 +PREPARE ADD Contents/Resources/2/20/20png0.png +PREPARE ADD Contents/Resources/0/00/00text2 +PREPARE REMOVEFILE Contents/Resources/1/10/10text0 +PREPARE REMOVEFILE Contents/Resources/0/00/00text1 +PREPARE REMOVEDIR Contents/Resources/9/99/ +PREPARE REMOVEDIR Contents/Resources/9/99/ +PREPARE REMOVEDIR Contents/Resources/9/98/ +PREPARE REMOVEFILE Contents/Resources/9/97/970/97xtext0 +PREPARE REMOVEFILE Contents/Resources/9/97/970/97xtext1 +PREPARE REMOVEDIR Contents/Resources/9/97/970/ +PREPARE REMOVEFILE Contents/Resources/9/97/971/97xtext0 +PREPARE REMOVEFILE Contents/Resources/9/97/971/97xtext1 +PREPARE REMOVEDIR Contents/Resources/9/97/971/ +PREPARE REMOVEDIR Contents/Resources/9/97/ +PREPARE REMOVEFILE Contents/Resources/9/96/96text0 +PREPARE REMOVEFILE Contents/Resources/9/96/96text1 +PREPARE REMOVEDIR Contents/Resources/9/96/ +PREPARE REMOVEDIR Contents/Resources/9/95/ +PREPARE REMOVEDIR Contents/Resources/9/95/ +PREPARE REMOVEDIR Contents/Resources/9/94/ +PREPARE REMOVEDIR Contents/Resources/9/94/ +PREPARE REMOVEDIR Contents/Resources/9/93/ +PREPARE REMOVEDIR Contents/Resources/9/92/ +PREPARE REMOVEDIR Contents/Resources/9/91/ +PREPARE REMOVEDIR Contents/Resources/9/90/ +PREPARE REMOVEDIR Contents/Resources/9/90/ +PREPARE REMOVEDIR Contents/Resources/8/89/ +PREPARE REMOVEDIR Contents/Resources/8/89/ +PREPARE REMOVEDIR Contents/Resources/8/88/ +PREPARE REMOVEFILE Contents/Resources/8/87/870/87xtext0 +PREPARE REMOVEFILE Contents/Resources/8/87/870/87xtext1 +PREPARE REMOVEDIR Contents/Resources/8/87/870/ +PREPARE REMOVEFILE Contents/Resources/8/87/871/87xtext0 +PREPARE REMOVEFILE Contents/Resources/8/87/871/87xtext1 +PREPARE REMOVEDIR Contents/Resources/8/87/871/ +PREPARE REMOVEDIR Contents/Resources/8/87/ +PREPARE REMOVEFILE Contents/Resources/8/86/86text0 +PREPARE REMOVEFILE Contents/Resources/8/86/86text1 +PREPARE REMOVEDIR Contents/Resources/8/86/ +PREPARE REMOVEDIR Contents/Resources/8/85/ +PREPARE REMOVEDIR Contents/Resources/8/85/ +PREPARE REMOVEDIR Contents/Resources/8/84/ +PREPARE REMOVEDIR Contents/Resources/8/84/ +PREPARE REMOVEDIR Contents/Resources/8/83/ +PREPARE REMOVEDIR Contents/Resources/8/82/ +PREPARE REMOVEDIR Contents/Resources/8/81/ +PREPARE REMOVEDIR Contents/Resources/8/80/ +PREPARE REMOVEDIR Contents/Resources/8/80/ +PREPARE REMOVEFILE Contents/Resources/7/70/7xtest.exe +PREPARE REMOVEFILE Contents/Resources/7/70/7xtext0 +PREPARE REMOVEFILE Contents/Resources/7/70/7xtext1 +PREPARE REMOVEDIR Contents/Resources/7/70/ +PREPARE REMOVEFILE Contents/Resources/7/71/7xtest.exe +PREPARE REMOVEFILE Contents/Resources/7/71/7xtext0 +PREPARE REMOVEFILE Contents/Resources/7/71/7xtext1 +PREPARE REMOVEDIR Contents/Resources/7/71/ +PREPARE REMOVEFILE Contents/Resources/7/7text0 +PREPARE REMOVEFILE Contents/Resources/7/7text1 +PREPARE REMOVEDIR Contents/Resources/7/ +PREPARE REMOVEDIR Contents/Resources/6/ +PREPARE REMOVEFILE Contents/Resources/5/5text1 +PREPARE REMOVEFILE Contents/Resources/5/5text0 +PREPARE REMOVEFILE Contents/Resources/5/5test.exe +PREPARE REMOVEFILE Contents/Resources/5/5text0 +PREPARE REMOVEFILE Contents/Resources/5/5text1 +PREPARE REMOVEDIR Contents/Resources/5/ +PREPARE REMOVEFILE Contents/Resources/4/4text1 +PREPARE REMOVEFILE Contents/Resources/4/4text0 +PREPARE REMOVEDIR Contents/Resources/4/ +PREPARE REMOVEFILE Contents/Resources/3/3text1 +PREPARE REMOVEFILE Contents/Resources/3/3text0 +PREPARE REMOVEDIR Contents/Resources/1/10/ +PREPARE REMOVEDIR Contents/Resources/1/ +EXECUTE ADD Contents/Resources/searchplugins/searchpluginstext0 +EXECUTE PATCH Contents/Resources/searchplugins/searchpluginspng1.png +EXECUTE PATCH Contents/Resources/searchplugins/searchpluginspng0.png +EXECUTE ADD Contents/Resources/precomplete +EXECUTE ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +EXECUTE PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +EXECUTE PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +EXECUTE ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +EXECUTE PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +EXECUTE PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +EXECUTE PATCH Contents/Resources/0/0exe0.exe +EXECUTE ADD Contents/Resources/0/00/00text0 +EXECUTE PATCH Contents/Resources/0/00/00png0.png +EXECUTE PATCH Contents/MacOS/exe0.exe +EXECUTE ADD Contents/Resources/2/20/20text0 +EXECUTE ADD Contents/Resources/2/20/20png0.png +EXECUTE ADD Contents/Resources/0/00/00text2 +EXECUTE REMOVEFILE Contents/Resources/1/10/10text0 +EXECUTE REMOVEFILE Contents/Resources/0/00/00text1 +EXECUTE REMOVEDIR Contents/Resources/9/99/ +EXECUTE REMOVEDIR Contents/Resources/9/99/ +EXECUTE REMOVEDIR Contents/Resources/9/98/ +EXECUTE REMOVEFILE Contents/Resources/9/97/970/97xtext0 +EXECUTE REMOVEFILE Contents/Resources/9/97/970/97xtext1 +EXECUTE REMOVEDIR Contents/Resources/9/97/970/ +EXECUTE REMOVEFILE Contents/Resources/9/97/971/97xtext0 +EXECUTE REMOVEFILE Contents/Resources/9/97/971/97xtext1 +EXECUTE REMOVEDIR Contents/Resources/9/97/971/ +EXECUTE REMOVEDIR Contents/Resources/9/97/ +EXECUTE REMOVEFILE Contents/Resources/9/96/96text0 +EXECUTE REMOVEFILE Contents/Resources/9/96/96text1 +EXECUTE REMOVEDIR Contents/Resources/9/96/ +EXECUTE REMOVEDIR Contents/Resources/9/95/ +EXECUTE REMOVEDIR Contents/Resources/9/95/ +EXECUTE REMOVEDIR Contents/Resources/9/94/ +EXECUTE REMOVEDIR Contents/Resources/9/94/ +EXECUTE REMOVEDIR Contents/Resources/9/93/ +EXECUTE REMOVEDIR Contents/Resources/9/92/ +EXECUTE REMOVEDIR Contents/Resources/9/91/ +EXECUTE REMOVEDIR Contents/Resources/9/90/ +EXECUTE REMOVEDIR Contents/Resources/9/90/ +EXECUTE REMOVEDIR Contents/Resources/8/89/ +EXECUTE REMOVEDIR Contents/Resources/8/89/ +EXECUTE REMOVEDIR Contents/Resources/8/88/ +EXECUTE REMOVEFILE Contents/Resources/8/87/870/87xtext0 +EXECUTE REMOVEFILE Contents/Resources/8/87/870/87xtext1 +EXECUTE REMOVEDIR Contents/Resources/8/87/870/ +EXECUTE REMOVEFILE Contents/Resources/8/87/871/87xtext0 +EXECUTE REMOVEFILE Contents/Resources/8/87/871/87xtext1 +EXECUTE REMOVEDIR Contents/Resources/8/87/871/ +EXECUTE REMOVEDIR Contents/Resources/8/87/ +EXECUTE REMOVEFILE Contents/Resources/8/86/86text0 +EXECUTE REMOVEFILE Contents/Resources/8/86/86text1 +EXECUTE REMOVEDIR Contents/Resources/8/86/ +EXECUTE REMOVEDIR Contents/Resources/8/85/ +EXECUTE REMOVEDIR Contents/Resources/8/85/ +EXECUTE REMOVEDIR Contents/Resources/8/84/ +EXECUTE REMOVEDIR Contents/Resources/8/84/ +EXECUTE REMOVEDIR Contents/Resources/8/83/ +EXECUTE REMOVEDIR Contents/Resources/8/82/ +EXECUTE REMOVEDIR Contents/Resources/8/81/ +EXECUTE REMOVEDIR Contents/Resources/8/80/ +EXECUTE REMOVEDIR Contents/Resources/8/80/ +EXECUTE REMOVEFILE Contents/Resources/7/70/7xtest.exe +EXECUTE REMOVEFILE Contents/Resources/7/70/7xtext0 +EXECUTE REMOVEFILE Contents/Resources/7/70/7xtext1 +EXECUTE REMOVEDIR Contents/Resources/7/70/ +EXECUTE REMOVEFILE Contents/Resources/7/71/7xtest.exe +EXECUTE REMOVEFILE Contents/Resources/7/71/7xtext0 +EXECUTE REMOVEFILE Contents/Resources/7/71/7xtext1 +EXECUTE REMOVEDIR Contents/Resources/7/71/ +EXECUTE REMOVEFILE Contents/Resources/7/7text0 +EXECUTE REMOVEFILE Contents/Resources/7/7text1 +EXECUTE REMOVEDIR Contents/Resources/7/ +EXECUTE REMOVEDIR Contents/Resources/6/ +EXECUTE REMOVEFILE Contents/Resources/5/5text1 +EXECUTE REMOVEFILE Contents/Resources/5/5text0 +EXECUTE REMOVEFILE Contents/Resources/5/5test.exe +EXECUTE REMOVEFILE Contents/Resources/5/5text0 +file cannot be removed because it does not exist; skipping +EXECUTE REMOVEFILE Contents/Resources/5/5text1 +file cannot be removed because it does not exist; skipping +EXECUTE REMOVEDIR Contents/Resources/5/ +EXECUTE REMOVEFILE Contents/Resources/4/4text1 +EXECUTE REMOVEFILE Contents/Resources/4/4text0 +EXECUTE REMOVEDIR Contents/Resources/4/ +EXECUTE REMOVEFILE Contents/Resources/3/3text1 +EXECUTE REMOVEFILE Contents/Resources/3/3text0 +EXECUTE REMOVEDIR Contents/Resources/1/10/ +EXECUTE REMOVEDIR Contents/Resources/1/ +FINISH ADD Contents/Resources/searchplugins/searchpluginstext0 +FINISH PATCH Contents/Resources/searchplugins/searchpluginspng1.png +FINISH PATCH Contents/Resources/searchplugins/searchpluginspng0.png +FINISH ADD Contents/Resources/precomplete +FINISH ADD Contents/Resources/distribution/extensions/extensions1/extensions1text0 +FINISH PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png1.png +FINISH PATCH Contents/Resources/distribution/extensions/extensions1/extensions1png0.png +FINISH ADD Contents/Resources/distribution/extensions/extensions0/extensions0text0 +FINISH PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png1.png +FINISH PATCH Contents/Resources/distribution/extensions/extensions0/extensions0png0.png +FINISH PATCH Contents/Resources/0/0exe0.exe +FINISH ADD Contents/Resources/0/00/00text0 +FINISH PATCH Contents/Resources/0/00/00png0.png +FINISH PATCH Contents/MacOS/exe0.exe +FINISH ADD Contents/Resources/2/20/20text0 +FINISH ADD Contents/Resources/2/20/20png0.png +FINISH ADD Contents/Resources/0/00/00text2 +FINISH REMOVEFILE Contents/Resources/1/10/10text0 +FINISH REMOVEFILE Contents/Resources/0/00/00text1 +FINISH REMOVEDIR Contents/Resources/9/99/ +FINISH REMOVEDIR Contents/Resources/9/99/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/9/98/ +FINISH REMOVEFILE Contents/Resources/9/97/970/97xtext0 +FINISH REMOVEFILE Contents/Resources/9/97/970/97xtext1 +FINISH REMOVEDIR Contents/Resources/9/97/970/ +FINISH REMOVEFILE Contents/Resources/9/97/971/97xtext0 +FINISH REMOVEFILE Contents/Resources/9/97/971/97xtext1 +FINISH REMOVEDIR Contents/Resources/9/97/971/ +FINISH REMOVEDIR Contents/Resources/9/97/ +FINISH REMOVEFILE Contents/Resources/9/96/96text0 +FINISH REMOVEFILE Contents/Resources/9/96/96text1 +FINISH REMOVEDIR Contents/Resources/9/96/ +FINISH REMOVEDIR Contents/Resources/9/95/ +FINISH REMOVEDIR Contents/Resources/9/95/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/9/94/ +FINISH REMOVEDIR Contents/Resources/9/94/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/9/93/ +FINISH REMOVEDIR Contents/Resources/9/92/ +removing directory: Contents/Resources/9/92/, rv: 0 +FINISH REMOVEDIR Contents/Resources/9/91/ +removing directory: Contents/Resources/9/91/, rv: 0 +FINISH REMOVEDIR Contents/Resources/9/90/ +FINISH REMOVEDIR Contents/Resources/9/90/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/8/89/ +FINISH REMOVEDIR Contents/Resources/8/89/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/8/88/ +FINISH REMOVEFILE Contents/Resources/8/87/870/87xtext0 +FINISH REMOVEFILE Contents/Resources/8/87/870/87xtext1 +FINISH REMOVEDIR Contents/Resources/8/87/870/ +FINISH REMOVEFILE Contents/Resources/8/87/871/87xtext0 +FINISH REMOVEFILE Contents/Resources/8/87/871/87xtext1 +FINISH REMOVEDIR Contents/Resources/8/87/871/ +FINISH REMOVEDIR Contents/Resources/8/87/ +FINISH REMOVEFILE Contents/Resources/8/86/86text0 +FINISH REMOVEFILE Contents/Resources/8/86/86text1 +FINISH REMOVEDIR Contents/Resources/8/86/ +FINISH REMOVEDIR Contents/Resources/8/85/ +FINISH REMOVEDIR Contents/Resources/8/85/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/8/84/ +FINISH REMOVEDIR Contents/Resources/8/84/ +directory no longer exists; skipping +FINISH REMOVEDIR Contents/Resources/8/83/ +FINISH REMOVEDIR Contents/Resources/8/82/ +removing directory: Contents/Resources/8/82/, rv: 0 +FINISH REMOVEDIR Contents/Resources/8/81/ +removing directory: Contents/Resources/8/81/, rv: 0 +FINISH REMOVEDIR Contents/Resources/8/80/ +FINISH REMOVEDIR Contents/Resources/8/80/ +directory no longer exists; skipping +FINISH REMOVEFILE Contents/Resources/7/70/7xtest.exe +FINISH REMOVEFILE Contents/Resources/7/70/7xtext0 +FINISH REMOVEFILE Contents/Resources/7/70/7xtext1 +FINISH REMOVEDIR Contents/Resources/7/70/ +FINISH REMOVEFILE Contents/Resources/7/71/7xtest.exe +FINISH REMOVEFILE Contents/Resources/7/71/7xtext0 +FINISH REMOVEFILE Contents/Resources/7/71/7xtext1 +FINISH REMOVEDIR Contents/Resources/7/71/ +FINISH REMOVEFILE Contents/Resources/7/7text0 +FINISH REMOVEFILE Contents/Resources/7/7text1 +FINISH REMOVEDIR Contents/Resources/7/ +FINISH REMOVEDIR Contents/Resources/6/ +FINISH REMOVEFILE Contents/Resources/5/5text1 +FINISH REMOVEFILE Contents/Resources/5/5text0 +FINISH REMOVEFILE Contents/Resources/5/5test.exe +FINISH REMOVEDIR Contents/Resources/5/ +FINISH REMOVEFILE Contents/Resources/4/4text1 +FINISH REMOVEFILE Contents/Resources/4/4text0 +FINISH REMOVEDIR Contents/Resources/4/ +FINISH REMOVEFILE Contents/Resources/3/3text1 +FINISH REMOVEFILE Contents/Resources/3/3text0 +FINISH REMOVEDIR Contents/Resources/1/10/ +FINISH REMOVEDIR Contents/Resources/1/ +succeeded +calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/data/partial_log_success_win b/toolkit/mozapps/update/tests/data/partial_log_success_win new file mode 100644 index 000000000..1f5c4b3b4 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_log_success_win @@ -0,0 +1,279 @@ +UPDATE TYPE partial +PREPARE ADD searchplugins/searchpluginstext0 +PREPARE PATCH searchplugins/searchpluginspng1.png +PREPARE PATCH searchplugins/searchpluginspng0.png +PREPARE ADD precomplete +PREPARE PATCH exe0.exe +PREPARE ADD distribution/extensions/extensions1/extensions1text0 +PREPARE PATCH distribution/extensions/extensions1/extensions1png1.png +PREPARE PATCH distribution/extensions/extensions1/extensions1png0.png +PREPARE ADD distribution/extensions/extensions0/extensions0text0 +PREPARE PATCH distribution/extensions/extensions0/extensions0png1.png +PREPARE PATCH distribution/extensions/extensions0/extensions0png0.png +PREPARE PATCH 0/0exe0.exe +PREPARE ADD 0/00/00text0 +PREPARE PATCH 0/00/00png0.png +PREPARE ADD 2/20/20text0 +PREPARE ADD 2/20/20png0.png +PREPARE ADD 0/00/00text2 +PREPARE REMOVEFILE 1/10/10text0 +PREPARE REMOVEFILE 0/00/00text1 +PREPARE REMOVEDIR 9/99/ +PREPARE REMOVEDIR 9/99/ +PREPARE REMOVEDIR 9/98/ +PREPARE REMOVEFILE 9/97/970/97xtext0 +PREPARE REMOVEFILE 9/97/970/97xtext1 +PREPARE REMOVEDIR 9/97/970/ +PREPARE REMOVEFILE 9/97/971/97xtext0 +PREPARE REMOVEFILE 9/97/971/97xtext1 +PREPARE REMOVEDIR 9/97/971/ +PREPARE REMOVEDIR 9/97/ +PREPARE REMOVEFILE 9/96/96text0 +PREPARE REMOVEFILE 9/96/96text1 +PREPARE REMOVEDIR 9/96/ +PREPARE REMOVEDIR 9/95/ +PREPARE REMOVEDIR 9/95/ +PREPARE REMOVEDIR 9/94/ +PREPARE REMOVEDIR 9/94/ +PREPARE REMOVEDIR 9/93/ +PREPARE REMOVEDIR 9/92/ +PREPARE REMOVEDIR 9/91/ +PREPARE REMOVEDIR 9/90/ +PREPARE REMOVEDIR 9/90/ +PREPARE REMOVEDIR 8/89/ +PREPARE REMOVEDIR 8/89/ +PREPARE REMOVEDIR 8/88/ +PREPARE REMOVEFILE 8/87/870/87xtext0 +PREPARE REMOVEFILE 8/87/870/87xtext1 +PREPARE REMOVEDIR 8/87/870/ +PREPARE REMOVEFILE 8/87/871/87xtext0 +PREPARE REMOVEFILE 8/87/871/87xtext1 +PREPARE REMOVEDIR 8/87/871/ +PREPARE REMOVEDIR 8/87/ +PREPARE REMOVEFILE 8/86/86text0 +PREPARE REMOVEFILE 8/86/86text1 +PREPARE REMOVEDIR 8/86/ +PREPARE REMOVEDIR 8/85/ +PREPARE REMOVEDIR 8/85/ +PREPARE REMOVEDIR 8/84/ +PREPARE REMOVEDIR 8/84/ +PREPARE REMOVEDIR 8/83/ +PREPARE REMOVEDIR 8/82/ +PREPARE REMOVEDIR 8/81/ +PREPARE REMOVEDIR 8/80/ +PREPARE REMOVEDIR 8/80/ +PREPARE REMOVEFILE 7/70/7xtest.exe +PREPARE REMOVEFILE 7/70/7xtext0 +PREPARE REMOVEFILE 7/70/7xtext1 +PREPARE REMOVEDIR 7/70/ +PREPARE REMOVEFILE 7/71/7xtest.exe +PREPARE REMOVEFILE 7/71/7xtext0 +PREPARE REMOVEFILE 7/71/7xtext1 +PREPARE REMOVEDIR 7/71/ +PREPARE REMOVEFILE 7/7text0 +PREPARE REMOVEFILE 7/7text1 +PREPARE REMOVEDIR 7/ +PREPARE REMOVEDIR 6/ +PREPARE REMOVEFILE 5/5text1 +PREPARE REMOVEFILE 5/5text0 +PREPARE REMOVEFILE 5/5test.exe +PREPARE REMOVEFILE 5/5text0 +PREPARE REMOVEFILE 5/5text1 +PREPARE REMOVEDIR 5/ +PREPARE REMOVEFILE 4/4text1 +PREPARE REMOVEFILE 4/4text0 +PREPARE REMOVEDIR 4/ +PREPARE REMOVEFILE 3/3text1 +PREPARE REMOVEFILE 3/3text0 +PREPARE REMOVEDIR 1/10/ +PREPARE REMOVEDIR 1/ +EXECUTE ADD searchplugins/searchpluginstext0 +EXECUTE PATCH searchplugins/searchpluginspng1.png +EXECUTE PATCH searchplugins/searchpluginspng0.png +EXECUTE ADD precomplete +EXECUTE PATCH exe0.exe +EXECUTE ADD distribution/extensions/extensions1/extensions1text0 +EXECUTE PATCH distribution/extensions/extensions1/extensions1png1.png +EXECUTE PATCH distribution/extensions/extensions1/extensions1png0.png +EXECUTE ADD distribution/extensions/extensions0/extensions0text0 +EXECUTE PATCH distribution/extensions/extensions0/extensions0png1.png +EXECUTE PATCH distribution/extensions/extensions0/extensions0png0.png +EXECUTE PATCH 0/0exe0.exe +EXECUTE ADD 0/00/00text0 +EXECUTE PATCH 0/00/00png0.png +EXECUTE ADD 2/20/20text0 +EXECUTE ADD 2/20/20png0.png +EXECUTE ADD 0/00/00text2 +EXECUTE REMOVEFILE 1/10/10text0 +EXECUTE REMOVEFILE 0/00/00text1 +EXECUTE REMOVEDIR 9/99/ +EXECUTE REMOVEDIR 9/99/ +EXECUTE REMOVEDIR 9/98/ +EXECUTE REMOVEFILE 9/97/970/97xtext0 +EXECUTE REMOVEFILE 9/97/970/97xtext1 +EXECUTE REMOVEDIR 9/97/970/ +EXECUTE REMOVEFILE 9/97/971/97xtext0 +EXECUTE REMOVEFILE 9/97/971/97xtext1 +EXECUTE REMOVEDIR 9/97/971/ +EXECUTE REMOVEDIR 9/97/ +EXECUTE REMOVEFILE 9/96/96text0 +EXECUTE REMOVEFILE 9/96/96text1 +EXECUTE REMOVEDIR 9/96/ +EXECUTE REMOVEDIR 9/95/ +EXECUTE REMOVEDIR 9/95/ +EXECUTE REMOVEDIR 9/94/ +EXECUTE REMOVEDIR 9/94/ +EXECUTE REMOVEDIR 9/93/ +EXECUTE REMOVEDIR 9/92/ +EXECUTE REMOVEDIR 9/91/ +EXECUTE REMOVEDIR 9/90/ +EXECUTE REMOVEDIR 9/90/ +EXECUTE REMOVEDIR 8/89/ +EXECUTE REMOVEDIR 8/89/ +EXECUTE REMOVEDIR 8/88/ +EXECUTE REMOVEFILE 8/87/870/87xtext0 +EXECUTE REMOVEFILE 8/87/870/87xtext1 +EXECUTE REMOVEDIR 8/87/870/ +EXECUTE REMOVEFILE 8/87/871/87xtext0 +EXECUTE REMOVEFILE 8/87/871/87xtext1 +EXECUTE REMOVEDIR 8/87/871/ +EXECUTE REMOVEDIR 8/87/ +EXECUTE REMOVEFILE 8/86/86text0 +EXECUTE REMOVEFILE 8/86/86text1 +EXECUTE REMOVEDIR 8/86/ +EXECUTE REMOVEDIR 8/85/ +EXECUTE REMOVEDIR 8/85/ +EXECUTE REMOVEDIR 8/84/ +EXECUTE REMOVEDIR 8/84/ +EXECUTE REMOVEDIR 8/83/ +EXECUTE REMOVEDIR 8/82/ +EXECUTE REMOVEDIR 8/81/ +EXECUTE REMOVEDIR 8/80/ +EXECUTE REMOVEDIR 8/80/ +EXECUTE REMOVEFILE 7/70/7xtest.exe +EXECUTE REMOVEFILE 7/70/7xtext0 +EXECUTE REMOVEFILE 7/70/7xtext1 +EXECUTE REMOVEDIR 7/70/ +EXECUTE REMOVEFILE 7/71/7xtest.exe +EXECUTE REMOVEFILE 7/71/7xtext0 +EXECUTE REMOVEFILE 7/71/7xtext1 +EXECUTE REMOVEDIR 7/71/ +EXECUTE REMOVEFILE 7/7text0 +EXECUTE REMOVEFILE 7/7text1 +EXECUTE REMOVEDIR 7/ +EXECUTE REMOVEDIR 6/ +EXECUTE REMOVEFILE 5/5text1 +EXECUTE REMOVEFILE 5/5text0 +EXECUTE REMOVEFILE 5/5test.exe +EXECUTE REMOVEFILE 5/5text0 +file cannot be removed because it does not exist; skipping +EXECUTE REMOVEFILE 5/5text1 +file cannot be removed because it does not exist; skipping +EXECUTE REMOVEDIR 5/ +EXECUTE REMOVEFILE 4/4text1 +EXECUTE REMOVEFILE 4/4text0 +EXECUTE REMOVEDIR 4/ +EXECUTE REMOVEFILE 3/3text1 +EXECUTE REMOVEFILE 3/3text0 +EXECUTE REMOVEDIR 1/10/ +EXECUTE REMOVEDIR 1/ +FINISH ADD searchplugins/searchpluginstext0 +FINISH PATCH searchplugins/searchpluginspng1.png +FINISH PATCH searchplugins/searchpluginspng0.png +FINISH ADD precomplete +FINISH PATCH exe0.exe +FINISH ADD distribution/extensions/extensions1/extensions1text0 +FINISH PATCH distribution/extensions/extensions1/extensions1png1.png +FINISH PATCH distribution/extensions/extensions1/extensions1png0.png +FINISH ADD distribution/extensions/extensions0/extensions0text0 +FINISH PATCH distribution/extensions/extensions0/extensions0png1.png +FINISH PATCH distribution/extensions/extensions0/extensions0png0.png +FINISH PATCH 0/0exe0.exe +FINISH ADD 0/00/00text0 +FINISH PATCH 0/00/00png0.png +FINISH ADD 2/20/20text0 +FINISH ADD 2/20/20png0.png +FINISH ADD 0/00/00text2 +FINISH REMOVEFILE 1/10/10text0 +FINISH REMOVEFILE 0/00/00text1 +FINISH REMOVEDIR 9/99/ +FINISH REMOVEDIR 9/99/ +directory no longer exists; skipping +FINISH REMOVEDIR 9/98/ +FINISH REMOVEFILE 9/97/970/97xtext0 +FINISH REMOVEFILE 9/97/970/97xtext1 +FINISH REMOVEDIR 9/97/970/ +FINISH REMOVEFILE 9/97/971/97xtext0 +FINISH REMOVEFILE 9/97/971/97xtext1 +FINISH REMOVEDIR 9/97/971/ +FINISH REMOVEDIR 9/97/ +FINISH REMOVEFILE 9/96/96text0 +FINISH REMOVEFILE 9/96/96text1 +FINISH REMOVEDIR 9/96/ +FINISH REMOVEDIR 9/95/ +FINISH REMOVEDIR 9/95/ +directory no longer exists; skipping +FINISH REMOVEDIR 9/94/ +FINISH REMOVEDIR 9/94/ +directory no longer exists; skipping +FINISH REMOVEDIR 9/93/ +FINISH REMOVEDIR 9/92/ +removing directory: 9/92/, rv: 0 +FINISH REMOVEDIR 9/91/ +removing directory: 9/91/, rv: 0 +FINISH REMOVEDIR 9/90/ +FINISH REMOVEDIR 9/90/ +directory no longer exists; skipping +FINISH REMOVEDIR 8/89/ +FINISH REMOVEDIR 8/89/ +directory no longer exists; skipping +FINISH REMOVEDIR 8/88/ +FINISH REMOVEFILE 8/87/870/87xtext0 +FINISH REMOVEFILE 8/87/870/87xtext1 +FINISH REMOVEDIR 8/87/870/ +FINISH REMOVEFILE 8/87/871/87xtext0 +FINISH REMOVEFILE 8/87/871/87xtext1 +FINISH REMOVEDIR 8/87/871/ +FINISH REMOVEDIR 8/87/ +FINISH REMOVEFILE 8/86/86text0 +FINISH REMOVEFILE 8/86/86text1 +FINISH REMOVEDIR 8/86/ +FINISH REMOVEDIR 8/85/ +FINISH REMOVEDIR 8/85/ +directory no longer exists; skipping +FINISH REMOVEDIR 8/84/ +FINISH REMOVEDIR 8/84/ +directory no longer exists; skipping +FINISH REMOVEDIR 8/83/ +FINISH REMOVEDIR 8/82/ +removing directory: 8/82/, rv: 0 +FINISH REMOVEDIR 8/81/ +removing directory: 8/81/, rv: 0 +FINISH REMOVEDIR 8/80/ +FINISH REMOVEDIR 8/80/ +directory no longer exists; skipping +FINISH REMOVEFILE 7/70/7xtest.exe +FINISH REMOVEFILE 7/70/7xtext0 +FINISH REMOVEFILE 7/70/7xtext1 +FINISH REMOVEDIR 7/70/ +FINISH REMOVEFILE 7/71/7xtest.exe +FINISH REMOVEFILE 7/71/7xtext0 +FINISH REMOVEFILE 7/71/7xtext1 +FINISH REMOVEDIR 7/71/ +FINISH REMOVEFILE 7/7text0 +FINISH REMOVEFILE 7/7text1 +FINISH REMOVEDIR 7/ +FINISH REMOVEDIR 6/ +FINISH REMOVEFILE 5/5text1 +FINISH REMOVEFILE 5/5text0 +FINISH REMOVEFILE 5/5test.exe +FINISH REMOVEDIR 5/ +FINISH REMOVEFILE 4/4text1 +FINISH REMOVEFILE 4/4text0 +FINISH REMOVEDIR 4/ +FINISH REMOVEFILE 3/3text1 +FINISH REMOVEFILE 3/3text0 +FINISH REMOVEDIR 1/10/ +FINISH REMOVEDIR 1/ +succeeded +calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/data/partial_mac.mar b/toolkit/mozapps/update/tests/data/partial_mac.mar Binary files differnew file mode 100644 index 000000000..5a702ed4a --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_mac.mar diff --git a/toolkit/mozapps/update/tests/data/partial_precomplete b/toolkit/mozapps/update/tests/data/partial_precomplete new file mode 100644 index 000000000..3ec201463 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_precomplete @@ -0,0 +1,19 @@ +remove "searchplugins/searchpluginstext0" +remove "searchplugins/searchpluginspng1.png" +remove "searchplugins/searchpluginspng0.png" +remove "removed-files" +remove "precomplete" +remove "exe0.exe" +remove "2/20/20text0" +remove "2/20/20png0.png" +remove "0/0exe0.exe" +remove "0/00/00text2" +remove "0/00/00text0" +remove "0/00/00png0.png" +rmdir "searchplugins/" +rmdir "defaults/pref/" +rmdir "defaults/" +rmdir "2/20/" +rmdir "2/" +rmdir "0/00/" +rmdir "0/" diff --git a/toolkit/mozapps/update/tests/data/partial_precomplete_mac b/toolkit/mozapps/update/tests/data/partial_precomplete_mac new file mode 100644 index 000000000..c65b6e4e3 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_precomplete_mac @@ -0,0 +1,22 @@ +remove "Contents/Resources/searchplugins/searchpluginstext0" +remove "Contents/Resources/searchplugins/searchpluginspng1.png" +remove "Contents/Resources/searchplugins/searchpluginspng0.png" +remove "Contents/Resources/removed-files" +remove "Contents/Resources/precomplete" +remove "Contents/Resources/2/20/20text0" +remove "Contents/Resources/2/20/20png0.png" +remove "Contents/Resources/0/0exe0.exe" +remove "Contents/Resources/0/00/00text2" +remove "Contents/Resources/0/00/00text0" +remove "Contents/Resources/0/00/00png0.png" +remove "Contents/MacOS/exe0.exe" +rmdir "Contents/Resources/searchplugins/" +rmdir "Contents/Resources/defaults/pref/" +rmdir "Contents/Resources/defaults/" +rmdir "Contents/Resources/2/20/" +rmdir "Contents/Resources/2/" +rmdir "Contents/Resources/0/00/" +rmdir "Contents/Resources/0/" +rmdir "Contents/Resources/" +rmdir "Contents/MacOS/" +rmdir "Contents/" diff --git a/toolkit/mozapps/update/tests/data/partial_removed-files b/toolkit/mozapps/update/tests/data/partial_removed-files new file mode 100644 index 000000000..881311b82 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_removed-files @@ -0,0 +1,41 @@ +a/b/text0 +a/b/text1 +a/b/3/3text0 +a/b/3/3text1 +a/b/4/4exe0.exe +a/b/4/4text0 +a/b/4/4text1 +a/b/4/ +a/b/5/5text0 +a/b/5/5text1 +a/b/5/* +a/b/6/ +a/b/7/* +a/b/8/80/ +a/b/8/81/ +a/b/8/82/ +a/b/8/83/ +a/b/8/84/ +a/b/8/85/* +a/b/8/86/* +a/b/8/87/* +a/b/8/88/* +a/b/8/89/* +a/b/8/80/ +a/b/8/84/* +a/b/8/85/* +a/b/8/89/ +a/b/9/90/ +a/b/9/91/ +a/b/9/92/ +a/b/9/93/ +a/b/9/94/ +a/b/9/95/* +a/b/9/96/* +a/b/9/97/* +a/b/9/98/* +a/b/9/99/* +a/b/9/90/ +a/b/9/94/* +a/b/9/95/* +a/b/9/99/ diff --git a/toolkit/mozapps/update/tests/data/partial_removed-files_mac b/toolkit/mozapps/update/tests/data/partial_removed-files_mac new file mode 100644 index 000000000..955dc5b34 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_removed-files_mac @@ -0,0 +1,41 @@ +Contents/Resources/text0 +Contents/Resources/text1 +Contents/Resources/3/3text0 +Contents/Resources/3/3text1 +Contents/Resources/4/exe0.exe +Contents/Resources/4/4text0 +Contents/Resources/4/4text1 +Contents/Resources/4/ +Contents/Resources/5/5text0 +Contents/Resources/5/5text1 +Contents/Resources/5/* +Contents/Resources/6/ +Contents/Resources/7/* +Contents/Resources/8/80/ +Contents/Resources/8/81/ +Contents/Resources/8/82/ +Contents/Resources/8/83/ +Contents/Resources/8/84/ +Contents/Resources/8/85/* +Contents/Resources/8/86/* +Contents/Resources/8/87/* +Contents/Resources/8/88/* +Contents/Resources/8/89/* +Contents/Resources/8/80/ +Contents/Resources/8/84/* +Contents/Resources/8/85/* +Contents/Resources/8/89/ +Contents/Resources/9/90/ +Contents/Resources/9/91/ +Contents/Resources/9/92/ +Contents/Resources/9/93/ +Contents/Resources/9/94/ +Contents/Resources/9/95/* +Contents/Resources/9/96/* +Contents/Resources/9/97/* +Contents/Resources/9/98/* +Contents/Resources/9/99/* +Contents/Resources/9/90/ +Contents/Resources/9/94/* +Contents/Resources/9/95/* +Contents/Resources/9/99/ diff --git a/toolkit/mozapps/update/tests/data/partial_update_manifest b/toolkit/mozapps/update/tests/data/partial_update_manifest new file mode 100644 index 000000000..8d4e60ed2 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/partial_update_manifest @@ -0,0 +1,63 @@ +type "partial" +add "precomplete" +add "a/b/searchplugins/searchpluginstext0" +patch-if "a/b/searchplugins/searchpluginspng1.png" "a/b/searchplugins/searchpluginspng1.png.patch" "a/b/searchplugins/searchpluginspng1.png" +patch-if "a/b/searchplugins/searchpluginspng0.png" "a/b/searchplugins/searchpluginspng0.png.patch" "a/b/searchplugins/searchpluginspng0.png" +add-if "a/b/extensions/extensions1" "a/b/extensions/extensions1/extensions1text0" +patch-if "a/b/extensions/extensions1" "a/b/extensions/extensions1/extensions1png1.png.patch" "a/b/extensions/extensions1/extensions1png1.png" +patch-if "a/b/extensions/extensions1" "a/b/extensions/extensions1/extensions1png0.png.patch" "a/b/extensions/extensions1/extensions1png0.png" +add-if "a/b/extensions/extensions0" "a/b/extensions/extensions0/extensions0text0" +patch-if "a/b/extensions/extensions0" "a/b/extensions/extensions0/extensions0png1.png.patch" "a/b/extensions/extensions0/extensions0png1.png" +patch-if "a/b/extensions/extensions0" "a/b/extensions/extensions0/extensions0png0.png.patch" "a/b/extensions/extensions0/extensions0png0.png" +patch "a/b/exe0.exe.patch" "a/b/exe0.exe" +patch "a/b/0/0exe0.exe.patch" "a/b/0/0exe0.exe" +add "a/b/0/00/00text0" +patch "a/b/0/00/00png0.png.patch" "a/b/0/00/00png0.png" +add "a/b/2/20/20text0" +add "a/b/2/20/20png0.png" +add "a/b/0/00/00text2" +remove "a/b/1/10/10text0" +remove "a/b/0/00/00text1" +remove "a/b/text1" +remove "a/b/text0" +rmrfdir "a/b/9/99/" +rmdir "a/b/9/99/" +rmrfdir "a/b/9/98/" +rmrfdir "a/b/9/97/" +rmrfdir "a/b/9/96/" +rmrfdir "a/b/9/95/" +rmrfdir "a/b/9/95/" +rmrfdir "a/b/9/94/" +rmdir "a/b/9/94/" +rmdir "a/b/9/93/" +rmdir "a/b/9/92/" +rmdir "a/b/9/91/" +rmdir "a/b/9/90/" +rmdir "a/b/9/90/" +rmrfdir "a/b/8/89/" +rmdir "a/b/8/89/" +rmrfdir "a/b/8/88/" +rmrfdir "a/b/8/87/" +rmrfdir "a/b/8/86/" +rmrfdir "a/b/8/85/" +rmrfdir "a/b/8/85/" +rmrfdir "a/b/8/84/" +rmdir "a/b/8/84/" +rmdir "a/b/8/83/" +rmdir "a/b/8/82/" +rmdir "a/b/8/81/" +rmdir "a/b/8/80/" +rmdir "a/b/8/80/" +rmrfdir "a/b/7/" +rmdir "a/b/6/" +remove "a/b/5/5text1" +remove "a/b/5/5text0" +rmrfdir "a/b/5/" +remove "a/b/4/4text1" +remove "a/b/4/4text0" +remove "a/b/4/4exe0.exe" +rmdir "a/b/4/" +remove "a/b/3/3text1" +remove "a/b/3/3text0" +rmdir "a/b/1/10/" +rmdir "a/b/1/" diff --git a/toolkit/mozapps/update/tests/data/replace_log_success b/toolkit/mozapps/update/tests/data/replace_log_success new file mode 100644 index 000000000..323f1db41 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/replace_log_success @@ -0,0 +1,6 @@ +Performing a replace request +rename_file: proceeding to rename the directory +rename_file: proceeding to rename the directory +Now, remove the tmpDir +succeeded +calling QuitProgressUI diff --git a/toolkit/mozapps/update/tests/data/shared.js b/toolkit/mozapps/update/tests/data/shared.js new file mode 100644 index 000000000..e9a10da06 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/shared.js @@ -0,0 +1,632 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Shared code for xpcshell and mochitests-chrome */ +/* eslint-disable no-undef */ + +Cu.import("resource://gre/modules/FileUtils.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +const PREF_APP_UPDATE_AUTO = "app.update.auto"; +const PREF_APP_UPDATE_BACKGROUNDERRORS = "app.update.backgroundErrors"; +const PREF_APP_UPDATE_BACKGROUNDMAXERRORS = "app.update.backgroundMaxErrors"; +const PREF_APP_UPDATE_CHANNEL = "app.update.channel"; +const PREF_APP_UPDATE_DOWNLOADBACKGROUNDINTERVAL = "app.update.download.backgroundInterval"; +const PREF_APP_UPDATE_ENABLED = "app.update.enabled"; +const PREF_APP_UPDATE_IDLETIME = "app.update.idletime"; +const PREF_APP_UPDATE_LOG = "app.update.log"; +const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED = "app.update.notifiedUnsupported"; +const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime"; +const PREF_APP_UPDATE_RETRYTIMEOUT = "app.update.socket.retryTimeout"; +const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled"; +const PREF_APP_UPDATE_SILENT = "app.update.silent"; +const PREF_APP_UPDATE_SOCKET_MAXERRORS = "app.update.socket.maxErrors"; +const PREF_APP_UPDATE_STAGING_ENABLED = "app.update.staging.enabled"; +const PREF_APP_UPDATE_URL = "app.update.url"; +const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details"; + +const PREFBRANCH_APP_UPDATE_NEVER = "app.update.never."; + +const PREFBRANCH_APP_PARTNER = "app.partner."; +const PREF_DISTRIBUTION_ID = "distribution.id"; +const PREF_DISTRIBUTION_VERSION = "distribution.version"; +const PREF_TOOLKIT_TELEMETRY_ENABLED = "toolkit.telemetry.enabled"; + +const NS_APP_PROFILE_DIR_STARTUP = "ProfDS"; +const NS_APP_USER_PROFILE_50_DIR = "ProfD"; +const NS_GRE_DIR = "GreD"; +const NS_GRE_BIN_DIR = "GreBinD"; +const NS_XPCOM_CURRENT_PROCESS_DIR = "XCurProcD"; +const XRE_EXECUTABLE_FILE = "XREExeF"; +const XRE_UPDATE_ROOT_DIR = "UpdRootD"; + +const DIR_PATCH = "0"; +const DIR_TOBEDELETED = "tobedeleted"; +const DIR_UPDATES = "updates"; +const DIR_UPDATED = IS_MACOSX ? "Updated.app" : "updated"; + +const FILE_ACTIVE_UPDATE_XML = "active-update.xml"; +const FILE_APPLICATION_INI = "application.ini"; +const FILE_BACKUP_UPDATE_LOG = "backup-update.log"; +const FILE_LAST_UPDATE_LOG = "last-update.log"; +const FILE_UPDATE_SETTINGS_INI = "update-settings.ini"; +const FILE_UPDATE_SETTINGS_INI_BAK = "update-settings.ini.bak"; +const FILE_UPDATER_INI = "updater.ini"; +const FILE_UPDATES_XML = "updates.xml"; +const FILE_UPDATE_LOG = "update.log"; +const FILE_UPDATE_MAR = "update.mar"; +const FILE_UPDATE_STATUS = "update.status"; +const FILE_UPDATE_TEST = "update.test"; +const FILE_UPDATE_VERSION = "update.version"; + +const UPDATE_SETTINGS_CONTENTS = "[Settings]\n" + + "ACCEPTED_MAR_CHANNEL_IDS=xpcshell-test\n"; + +const PR_RDWR = 0x04; +const PR_CREATE_FILE = 0x08; +const PR_TRUNCATE = 0x20; + +const DEFAULT_UPDATE_VERSION = "999999.0"; + +var gChannel; + +/* import-globals-from ../data/sharedUpdateXML.js */ +Services.scriptloader.loadSubScript(DATA_URI_SPEC + "sharedUpdateXML.js", this); + +const PERMS_FILE = FileUtils.PERMS_FILE; +const PERMS_DIRECTORY = FileUtils.PERMS_DIRECTORY; + +const MODE_WRONLY = FileUtils.MODE_WRONLY; +const MODE_CREATE = FileUtils.MODE_CREATE; +const MODE_APPEND = FileUtils.MODE_APPEND; +const MODE_TRUNCATE = FileUtils.MODE_TRUNCATE; + +const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properties"; +const gUpdateBundle = Services.strings.createBundle(URI_UPDATES_PROPERTIES); + +XPCOMUtils.defineLazyGetter(this, "gAUS", function test_gAUS() { + return Cc["@mozilla.org/updates/update-service;1"]. + getService(Ci.nsIApplicationUpdateService). + QueryInterface(Ci.nsITimerCallback). + QueryInterface(Ci.nsIObserver). + QueryInterface(Ci.nsIUpdateCheckListener); +}); + +XPCOMUtils.defineLazyServiceGetter(this, "gUpdateManager", + "@mozilla.org/updates/update-manager;1", + "nsIUpdateManager"); + +XPCOMUtils.defineLazyGetter(this, "gUpdateChecker", function test_gUC() { + return Cc["@mozilla.org/updates/update-checker;1"]. + createInstance(Ci.nsIUpdateChecker); +}); + +XPCOMUtils.defineLazyGetter(this, "gUP", function test_gUP() { + return Cc["@mozilla.org/updates/update-prompt;1"]. + createInstance(Ci.nsIUpdatePrompt); +}); + +XPCOMUtils.defineLazyGetter(this, "gDefaultPrefBranch", function test_gDPB() { + return Services.prefs.getDefaultBranch(null); +}); + +XPCOMUtils.defineLazyGetter(this, "gPrefRoot", function test_gPR() { + return Services.prefs.getBranch(null); +}); + +XPCOMUtils.defineLazyServiceGetter(this, "gEnv", + "@mozilla.org/process/environment;1", + "nsIEnvironment"); + +XPCOMUtils.defineLazyGetter(this, "gZipW", function test_gZipW() { + return Cc["@mozilla.org/zipwriter;1"]. + createInstance(Ci.nsIZipWriter); +}); + +/* Triggers post-update processing */ +function testPostUpdateProcessing() { + gAUS.observe(null, "test-post-update-processing", ""); +} + +/* Initializes the update service stub */ +function initUpdateServiceStub() { + Cc["@mozilla.org/updates/update-service-stub;1"]. + createInstance(Ci.nsISupports); +} + +/* Reloads the update metadata from disk */ +function reloadUpdateManagerData() { + gUpdateManager.QueryInterface(Ci.nsIObserver). + observe(null, "um-reload-update-data", ""); +} + +const observer = { + observe: function(aSubject, aTopic, aData) { + if (aTopic == "nsPref:changed" && aData == PREF_APP_UPDATE_CHANNEL) { + let channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); + if (channel != gChannel) { + debugDump("Changing channel from " + channel + " to " + gChannel); + gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel); + } + } + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) +}; + +/** + * Sets the app.update.channel preference. + * + * @param aChannel + * The update channel. + */ +function setUpdateChannel(aChannel) { + gChannel = aChannel; + debugDump("setting default pref " + PREF_APP_UPDATE_CHANNEL + " to " + gChannel); + gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel); + gPrefRoot.addObserver(PREF_APP_UPDATE_CHANNEL, observer, false); +} + +/** + * Sets the app.update.url default preference. + * + * @param aURL + * The update url. If not specified 'URL_HOST + "/update.xml"' will be + * used. + */ +function setUpdateURL(aURL) { + let url = aURL ? aURL : URL_HOST + "/update.xml"; + debugDump("setting " + PREF_APP_UPDATE_URL + " to " + url); + gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_URL, url); +} + +/** + * Returns either the active or regular update database XML file. + * + * @param isActiveUpdate + * If true this will return the active-update.xml otherwise it will + * return the updates.xml file. + */ +function getUpdatesXMLFile(aIsActiveUpdate) { + let file = getUpdatesRootDir(); + file.append(aIsActiveUpdate ? FILE_ACTIVE_UPDATE_XML : FILE_UPDATES_XML); + return file; +} + +/** + * Writes the updates specified to either the active-update.xml or the + * updates.xml. + * + * @param aContent + * The updates represented as a string to write to the XML file. + * @param isActiveUpdate + * If true this will write to the active-update.xml otherwise it will + * write to the updates.xml file. + */ +function writeUpdatesToXMLFile(aContent, aIsActiveUpdate) { + writeFile(getUpdatesXMLFile(aIsActiveUpdate), aContent); +} + +/** + * Writes the current update operation/state to a file in the patch + * directory, indicating to the patching system that operations need + * to be performed. + * + * @param aStatus + * The status value to write. + */ +function writeStatusFile(aStatus) { + let file = getUpdatesPatchDir(); + file.append(FILE_UPDATE_STATUS); + writeFile(file, aStatus + "\n"); +} + +/** + * Writes the current update version to a file in the patch directory, + * indicating to the patching system the version of the update. + * + * @param aVersion + * The version value to write. + */ +function writeVersionFile(aVersion) { + let file = getUpdatesPatchDir(); + file.append(FILE_UPDATE_VERSION); + writeFile(file, aVersion + "\n"); +} + +/** + * Gets the root directory for the updates directory. + * + * @return nsIFile for the updates root directory. + */ +function getUpdatesRootDir() { + return Services.dirsvc.get(XRE_UPDATE_ROOT_DIR, Ci.nsIFile); +} + +/** + * Gets the updates directory. + * + * @return nsIFile for the updates directory. + */ +function getUpdatesDir() { + let dir = getUpdatesRootDir(); + dir.append(DIR_UPDATES); + return dir; +} + +/** + * Gets the directory for update patches. + * + * @return nsIFile for the updates directory. + */ +function getUpdatesPatchDir() { + let dir = getUpdatesDir(); + dir.append(DIR_PATCH); + return dir; +} + +/** + * Writes text to a file. This will replace existing text if the file exists + * and create the file if it doesn't exist. + * + * @param aFile + * The file to write to. Will be created if it doesn't exist. + * @param aText + * The text to write to the file. If there is existing text it will be + * replaced. + */ +function writeFile(aFile, aText) { + let fos = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + if (!aFile.exists()) { + aFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + fos.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0); + fos.write(aText, aText.length); + fos.close(); +} + +/** + * Reads the current update operation/state in the status file in the patch + * directory including the error code if it is present. + * + * @return The status value. + */ +function readStatusFile() { + let file = getUpdatesPatchDir(); + file.append(FILE_UPDATE_STATUS); + + if (!file.exists()) { + debugDump("update status file does not exists! Path: " + file.path); + return STATE_NONE; + } + + return readFile(file).split("\n")[0]; +} + +/** + * Reads the current update operation/state in the status file in the patch + * directory without the error code if it is present. + * + * @return The state value. + */ +function readStatusState() { + return readStatusFile().split(": ")[0]; +} + +/** + * Reads the current update operation/state in the status file in the patch + * directory with the error code. + * + * @return The state value. + */ +function readStatusFailedCode() { + return readStatusFile().split(": ")[1]; +} + +/** + * Reads text from a file and returns the string. + * + * @param aFile + * The file to read from. + * @return The string of text read from the file. + */ +function readFile(aFile) { + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + if (!aFile.exists()) { + return null; + } + // Specifying -1 for ioFlags will open the file with the default of PR_RDONLY. + // Specifying -1 for perm will open the file with the default of 0. + fis.init(aFile, -1, -1, Ci.nsIFileInputStream.CLOSE_ON_EOF); + let sis = Cc["@mozilla.org/scriptableinputstream;1"]. + createInstance(Ci.nsIScriptableInputStream); + sis.init(fis); + let text = sis.read(sis.available()); + sis.close(); + return text; +} + +/** + * Reads the binary contents of a file and returns it as a string. + * + * @param aFile + * The file to read from. + * @return The contents of the file as a string. + */ +function readFileBytes(aFile) { + debugDump("attempting to read file, path: " + aFile.path); + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + // Specifying -1 for ioFlags will open the file with the default of PR_RDONLY. + // Specifying -1 for perm will open the file with the default of 0. + fis.init(aFile, -1, -1, Ci.nsIFileInputStream.CLOSE_ON_EOF); + let bis = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); + bis.setInputStream(fis); + let data = []; + let count = fis.available(); + while (count > 0) { + let bytes = bis.readByteArray(Math.min(65535, count)); + data.push(String.fromCharCode.apply(null, bytes)); + count -= bytes.length; + if (bytes.length == 0) { + throw "Nothing read from input stream!"; + } + } + data.join(''); + fis.close(); + return data.toString(); +} + +/* Returns human readable status text from the updates.properties bundle */ +function getStatusText(aErrCode) { + return getString("check_error-" + aErrCode); +} + +/* Returns a string from the updates.properties bundle */ +function getString(aName) { + try { + return gUpdateBundle.GetStringFromName(aName); + } catch (e) { + } + return null; +} + +/** + * Gets the file extension for an nsIFile. + * + * @param aFile + * The file to get the file extension for. + * @return The file extension. + */ +function getFileExtension(aFile) { + return Services.io.newFileURI(aFile).QueryInterface(Ci.nsIURL). + fileExtension; +} + +/** + * Removes the updates.xml file, active-update.xml file, and all files and + * sub-directories in the updates directory except for the "0" sub-directory. + * This prevents some tests from failing due to files being left behind when the + * tests are interrupted. + */ +function removeUpdateDirsAndFiles() { + let file = getUpdatesXMLFile(true); + try { + if (file.exists()) { + file.remove(false); + } + } catch (e) { + logTestInfo("Unable to remove file. Path: " + file.path + + ", Exception: " + e); + } + + file = getUpdatesXMLFile(false); + try { + if (file.exists()) { + file.remove(false); + } + } catch (e) { + logTestInfo("Unable to remove file. Path: " + file.path + + ", Exception: " + e); + } + + // This fails sporadically on Mac OS X so wrap it in a try catch + let updatesDir = getUpdatesDir(); + try { + cleanUpdatesDir(updatesDir); + } catch (e) { + logTestInfo("Unable to remove files / directories from directory. Path: " + + updatesDir.path + ", Exception: " + e); + } +} + +/** + * Removes all files and sub-directories in the updates directory except for + * the "0" sub-directory. + * + * @param aDir + * nsIFile for the directory to be deleted. + */ +function cleanUpdatesDir(aDir) { + if (!aDir.exists()) { + return; + } + + let dirEntries = aDir.directoryEntries; + while (dirEntries.hasMoreElements()) { + let entry = dirEntries.getNext().QueryInterface(Ci.nsIFile); + + if (entry.isDirectory()) { + if (entry.leafName == DIR_PATCH && entry.parent.leafName == DIR_UPDATES) { + cleanUpdatesDir(entry); + entry.permissions = PERMS_DIRECTORY; + } else { + try { + entry.remove(true); + return; + } catch (e) { + } + cleanUpdatesDir(entry); + entry.permissions = PERMS_DIRECTORY; + try { + entry.remove(true); + } catch (e) { + logTestInfo("cleanUpdatesDir: unable to remove directory. Path: " + + entry.path + ", Exception: " + e); + throw (e); + } + } + } else { + entry.permissions = PERMS_FILE; + try { + entry.remove(false); + } catch (e) { + logTestInfo("cleanUpdatesDir: unable to remove file. Path: " + + entry.path + ", Exception: " + e); + throw (e); + } + } + } +} + +/** + * Deletes a directory and its children. First it tries nsIFile::Remove(true). + * If that fails it will fall back to recursing, setting the appropriate + * permissions, and deleting the current entry. + * + * @param aDir + * nsIFile for the directory to be deleted. + */ +function removeDirRecursive(aDir) { + if (!aDir.exists()) { + return; + } + + try { + debugDump("attempting to remove directory. Path: " + aDir.path); + aDir.remove(true); + return; + } catch (e) { + logTestInfo("non-fatal error removing directory. Exception: " + e); + } + + let dirEntries = aDir.directoryEntries; + while (dirEntries.hasMoreElements()) { + let entry = dirEntries.getNext().QueryInterface(Ci.nsIFile); + + if (entry.isDirectory()) { + removeDirRecursive(entry); + } else { + entry.permissions = PERMS_FILE; + try { + debugDump("attempting to remove file. Path: " + entry.path); + entry.remove(false); + } catch (e) { + logTestInfo("error removing file. Exception: " + e); + throw (e); + } + } + } + + aDir.permissions = PERMS_DIRECTORY; + try { + debugDump("attempting to remove directory. Path: " + aDir.path); + aDir.remove(true); + } catch (e) { + logTestInfo("error removing directory. Exception: " + e); + throw (e); + } +} + +/** + * Returns the directory for the currently running process. This is used to + * clean up after the tests and to locate the active-update.xml and updates.xml + * files. + * + * @return nsIFile for the current process directory. + */ +function getCurrentProcessDir() { + return Services.dirsvc.get(NS_XPCOM_CURRENT_PROCESS_DIR, Ci.nsIFile); +} + +/** + * Gets the application base directory. + * + * @return nsIFile object for the application base directory. + */ +function getAppBaseDir() { + return Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile).parent; +} + +/** + * Returns the Gecko Runtime Engine directory where files other than executable + * binaries are located. On Mac OS X this will be <bundle>/Contents/Resources/ + * and the installation directory on all other platforms. + * + * @return nsIFile for the Gecko Runtime Engine directory. + */ +function getGREDir() { + return Services.dirsvc.get(NS_GRE_DIR, Ci.nsIFile); +} + +/** + * Returns the Gecko Runtime Engine Binary directory where the executable + * binaries are located such as the updater binary (Windows and Linux) or + * updater package (Mac OS X). On Mac OS X this will be + * <bundle>/Contents/MacOS/ and the installation directory on all other + * platforms. + * + * @return nsIFile for the Gecko Runtime Engine Binary directory. + */ +function getGREBinDir() { + return Services.dirsvc.get(NS_GRE_BIN_DIR, Ci.nsIFile); +} + +/** + * Logs TEST-INFO messages. + * + * @param aText + * The text to log. + * @param aCaller (optional) + * An optional Components.stack.caller. If not specified + * Components.stack.caller will be used. + */ +function logTestInfo(aText, aCaller) { + let caller = aCaller ? aCaller : Components.stack.caller; + let now = new Date(); + let hh = now.getHours(); + let mm = now.getMinutes(); + let ss = now.getSeconds(); + let ms = now.getMilliseconds(); + let time = (hh < 10 ? "0" + hh : hh) + ":" + + (mm < 10 ? "0" + mm : mm) + ":" + + (ss < 10 ? "0" + ss : ss) + ":"; + if (ms < 10) { + time += "00"; + } else if (ms < 100) { + time += "0"; + } + time += ms; + let msg = time + " | TEST-INFO | " + caller.filename + " | [" + caller.name + + " : " + caller.lineNumber + "] " + aText; + LOG_FUNCTION(msg); +} + +/** + * Logs TEST-INFO messages when DEBUG_AUS_TEST evaluates to true. + * + * @param aText + * The text to log. + * @param aCaller (optional) + * An optional Components.stack.caller. If not specified + * Components.stack.caller will be used. + */ +function debugDump(aText, aCaller) { + if (DEBUG_AUS_TEST) { + let caller = aCaller ? aCaller : Components.stack.caller; + logTestInfo(aText, caller); + } +} diff --git a/toolkit/mozapps/update/tests/data/sharedUpdateXML.js b/toolkit/mozapps/update/tests/data/sharedUpdateXML.js new file mode 100644 index 000000000..3aa01eff4 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/sharedUpdateXML.js @@ -0,0 +1,364 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Helper functions for creating xml strings used by application update tests. + * + * !IMPORTANT - This file contains everything needed (along with dependencies) + * by the updates.sjs file used by the mochitest-chrome tests. Since xpcshell + * used by the http server is launched with -v 170 this file must not use + * features greater than JavaScript 1.7. + */ + +/* eslint-disable no-undef */ + +const FILE_SIMPLE_MAR = "simple.mar"; +const SIZE_SIMPLE_MAR = "1031"; +const MD5_HASH_SIMPLE_MAR = "1f8c038577bb6845d94ccec4999113ee"; +const SHA1_HASH_SIMPLE_MAR = "5d49a672c87f10f31d7e326349564a11272a028b"; +const SHA256_HASH_SIMPLE_MAR = "1aabbed5b1dd6e16e139afc5b43d479e254e0c26" + + "3c8fb9249c0a1bb93071c5fb"; +const SHA384_HASH_SIMPLE_MAR = "26615014ea034af32ef5651492d5f493f5a7a1a48522e" + + "d24c366442a5ec21d5ef02e23fb58d79729b8ca2f9541" + + "99dd53"; +const SHA512_HASH_SIMPLE_MAR = "922e5ae22081795f6e8d65a3c508715c9a314054179a8" + + "bbfe5f50dc23919ad89888291bc0a07586ab17dd0304a" + + "b5347473601127571c66f61f5080348e05c36b"; + +const STATE_NONE = "null"; +const STATE_DOWNLOADING = "downloading"; +const STATE_PENDING = "pending"; +const STATE_PENDING_SVC = "pending-service"; +const STATE_APPLYING = "applying"; +const STATE_APPLIED = "applied"; +const STATE_APPLIED_SVC = "applied-service"; +const STATE_SUCCEEDED = "succeeded"; +const STATE_DOWNLOAD_FAILED = "download-failed"; +const STATE_FAILED = "failed"; + +const LOADSOURCE_ERROR_WRONG_SIZE = 2; +const CRC_ERROR = 4; +const READ_ERROR = 6; +const WRITE_ERROR = 7; +const MAR_CHANNEL_MISMATCH_ERROR = 22; +const VERSION_DOWNGRADE_ERROR = 23; +const SERVICE_COULD_NOT_COPY_UPDATER = 49; +const SERVICE_INVALID_APPLYTO_DIR_STAGED_ERROR = 52; +const SERVICE_INVALID_APPLYTO_DIR_ERROR = 54; +const SERVICE_INVALID_INSTALL_DIR_PATH_ERROR = 55; +const SERVICE_INVALID_WORKING_DIR_PATH_ERROR = 56; +const INVALID_APPLYTO_DIR_STAGED_ERROR = 72; +const INVALID_APPLYTO_DIR_ERROR = 74; +const INVALID_INSTALL_DIR_PATH_ERROR = 75; +const INVALID_WORKING_DIR_PATH_ERROR = 76; +const INVALID_CALLBACK_PATH_ERROR = 77; +const INVALID_CALLBACK_DIR_ERROR = 78; + +const STATE_FAILED_DELIMETER = ": "; + +const STATE_FAILED_LOADSOURCE_ERROR_WRONG_SIZE = + STATE_FAILED + STATE_FAILED_DELIMETER + LOADSOURCE_ERROR_WRONG_SIZE; +const STATE_FAILED_CRC_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + CRC_ERROR; +const STATE_FAILED_READ_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + READ_ERROR; +const STATE_FAILED_WRITE_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + WRITE_ERROR; +const STATE_FAILED_MAR_CHANNEL_MISMATCH_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + MAR_CHANNEL_MISMATCH_ERROR; +const STATE_FAILED_VERSION_DOWNGRADE_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + VERSION_DOWNGRADE_ERROR; +const STATE_FAILED_SERVICE_COULD_NOT_COPY_UPDATER = + STATE_FAILED + STATE_FAILED_DELIMETER + SERVICE_COULD_NOT_COPY_UPDATER +const STATE_FAILED_SERVICE_INVALID_APPLYTO_DIR_STAGED_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + SERVICE_INVALID_APPLYTO_DIR_STAGED_ERROR; +const STATE_FAILED_SERVICE_INVALID_APPLYTO_DIR_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + SERVICE_INVALID_APPLYTO_DIR_ERROR; +const STATE_FAILED_SERVICE_INVALID_INSTALL_DIR_PATH_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + SERVICE_INVALID_INSTALL_DIR_PATH_ERROR; +const STATE_FAILED_SERVICE_INVALID_WORKING_DIR_PATH_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + SERVICE_INVALID_WORKING_DIR_PATH_ERROR; +const STATE_FAILED_INVALID_APPLYTO_DIR_STAGED_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + INVALID_APPLYTO_DIR_STAGED_ERROR; +const STATE_FAILED_INVALID_APPLYTO_DIR_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + INVALID_APPLYTO_DIR_ERROR; +const STATE_FAILED_INVALID_INSTALL_DIR_PATH_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + INVALID_INSTALL_DIR_PATH_ERROR; +const STATE_FAILED_INVALID_WORKING_DIR_PATH_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + INVALID_WORKING_DIR_PATH_ERROR; +const STATE_FAILED_INVALID_CALLBACK_PATH_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + INVALID_CALLBACK_PATH_ERROR; +const STATE_FAILED_INVALID_CALLBACK_DIR_ERROR = + STATE_FAILED + STATE_FAILED_DELIMETER + INVALID_CALLBACK_DIR_ERROR; + +/** + * Constructs a string representing a remote update xml file. + * + * @param aUpdates + * The string representing the update elements. + * @return The string representing a remote update xml file. + */ +function getRemoteUpdatesXMLString(aUpdates) { + return "<?xml version=\"1.0\"?>\n" + + "<updates>\n" + + aUpdates + + "</updates>\n"; +} + +/** + * Constructs a string representing an update element for a remote update xml + * file. See getUpdateString for parameter information not provided below. + * + * @param aPatches + * String representing the application update patches. + * @return The string representing an update element for an update xml file. + */ +function getRemoteUpdateString(aPatches, aType, aName, aDisplayVersion, + aAppVersion, aBuildID, aDetailsURL, aShowPrompt, + aShowNeverForVersion, aPromptWaitTime, + aBackgroundInterval, aCustom1, aCustom2) { + return getUpdateString(aType, aName, aDisplayVersion, aAppVersion, + aBuildID, aDetailsURL, aShowPrompt, + aShowNeverForVersion, aPromptWaitTime, + aBackgroundInterval, aCustom1, aCustom2) + ">\n" + + aPatches + + " </update>\n"; +} + +/** + * Constructs a string representing a patch element for a remote update xml + * file. See getPatchString for parameter information not provided below. + * + * @return The string representing a patch element for a remote update xml file. + */ +function getRemotePatchString(aType, aURL, aHashFunction, aHashValue, aSize) { + return getPatchString(aType, aURL, aHashFunction, aHashValue, aSize) + + "/>\n"; +} + +/** + * Constructs a string representing a local update xml file. + * + * @param aUpdates + * The string representing the update elements. + * @return The string representing a local update xml file. + */ +function getLocalUpdatesXMLString(aUpdates) { + if (!aUpdates || aUpdates == "") { + return "<updates xmlns=\"http://www.mozilla.org/2005/app-update\"/>"; + } + return ("<updates xmlns=\"http://www.mozilla.org/2005/app-update\">" + + aUpdates + + "</updates>").replace(/>\s+\n*</g, '><'); +} + +/** + * Constructs a string representing an update element for a local update xml + * file. See getUpdateString for parameter information not provided below. + * + * @param aPatches + * String representing the application update patches. + * @param aServiceURL (optional) + * The update's xml url. + * If not specified it will default to 'http://test_service/'. + * @param aIsCompleteUpdate (optional) + * The string 'true' if this update was a complete update or the string + * 'false' if this update was a partial update. + * If not specified it will default to 'true'. + * @param aChannel (optional) + * The update channel name. + * If not specified it will default to the default preference value of + * app.update.channel. + * @param aForegroundDownload (optional) + * The string 'true' if this update was manually downloaded or the + * string 'false' if this update was automatically downloaded. + * If not specified it will default to 'true'. + * @param aPreviousAppVersion (optional) + * The application version prior to applying the update. + * If not specified it will not be present. + * @return The string representing an update element for an update xml file. + */ +function getLocalUpdateString(aPatches, aType, aName, aDisplayVersion, + aAppVersion, aBuildID, aDetailsURL, aServiceURL, + aInstallDate, aStatusText, aIsCompleteUpdate, + aChannel, aForegroundDownload, aShowPrompt, + aShowNeverForVersion, aPromptWaitTime, + aBackgroundInterval, aPreviousAppVersion, + aCustom1, aCustom2) { + let serviceURL = aServiceURL ? aServiceURL : "http://test_service/"; + let installDate = aInstallDate ? aInstallDate : "1238441400314"; + let statusText = aStatusText ? aStatusText : "Install Pending"; + let isCompleteUpdate = + typeof aIsCompleteUpdate == "string" ? aIsCompleteUpdate : "true"; + let channel = aChannel ? aChannel + : gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); + let foregroundDownload = + typeof aForegroundDownload == "string" ? aForegroundDownload : "true"; + let previousAppVersion = aPreviousAppVersion ? "previousAppVersion=\"" + + aPreviousAppVersion + "\" " + : ""; + return getUpdateString(aType, aName, aDisplayVersion, aAppVersion, aBuildID, + aDetailsURL, aShowPrompt, aShowNeverForVersion, + aPromptWaitTime, aBackgroundInterval, aCustom1, aCustom2) + + " " + + previousAppVersion + + "serviceURL=\"" + serviceURL + "\" " + + "installDate=\"" + installDate + "\" " + + "statusText=\"" + statusText + "\" " + + "isCompleteUpdate=\"" + isCompleteUpdate + "\" " + + "channel=\"" + channel + "\" " + + "foregroundDownload=\"" + foregroundDownload + "\">" + + aPatches + + " </update>"; +} + +/** + * Constructs a string representing a patch element for a local update xml file. + * See getPatchString for parameter information not provided below. + * + * @param aSelected (optional) + * Whether this patch is selected represented or not. The string 'true' + * denotes selected and the string 'false' denotes not selected. + * If not specified it will default to the string 'true'. + * @param aState (optional) + * The patch's state. + * If not specified it will default to STATE_SUCCEEDED. + * @return The string representing a patch element for a local update xml file. + */ +function getLocalPatchString(aType, aURL, aHashFunction, aHashValue, aSize, + aSelected, aState) { + let selected = typeof aSelected == "string" ? aSelected : "true"; + let state = aState ? aState : STATE_SUCCEEDED; + return getPatchString(aType, aURL, aHashFunction, aHashValue, aSize) + " " + + "selected=\"" + selected + "\" " + + "state=\"" + state + "\"/>\n"; +} + +/** + * Constructs a string representing an update element for a remote update xml + * file. + * + * @param aType (optional) + * The update's type which should be major or minor. If not specified it + * will default to 'major'. + * @param aName (optional) + * The update's name. + * If not specified it will default to 'App Update Test'. + * @param aDisplayVersion (optional) + * The update's display version. + * If not specified it will default to 'version #' where # is the value + * of DEFAULT_UPDATE_VERSION. + * @param aAppVersion (optional) + * The update's application version. + * If not specified it will default to the value of + * DEFAULT_UPDATE_VERSION. + * @param aBuildID (optional) + * The update's build id. + * If not specified it will default to '20080811053724'. + * @param aDetailsURL (optional) + * The update's details url. + * If not specified it will default to 'http://test_details/' due to due + * to bug 470244. + * @param aShowPrompt (optional) + * Whether to show the prompt for the update when auto update is + * enabled. + * If not specified it will not be present and the update service will + * default to false. + * @param aShowNeverForVersion (optional) + * Whether to show the 'No Thanks' button in the update prompt. + * If not specified it will not be present and the update service will + * default to false. + * @param aPromptWaitTime (optional) + * Override for the app.update.promptWaitTime preference. + * @param aBackgroundInterval (optional) + * Override for the app.update.download.backgroundInterval preference. + * @param aCustom1 (optional) + * A custom attribute name and attribute value to add to the xml. + * Example: custom1_attribute="custom1 value" + * If not specified it will not be present. + * @param aCustom2 (optional) + * A custom attribute name and attribute value to add to the xml. + * Example: custom2_attribute="custom2 value" + * If not specified it will not be present. + * @return The string representing an update element for an update xml file. + */ +function getUpdateString(aType, aName, aDisplayVersion, aAppVersion, aBuildID, + aDetailsURL, aShowPrompt, aShowNeverForVersion, + aPromptWaitTime, aBackgroundInterval, aCustom1, + aCustom2) { + let type = aType ? aType : "major"; + let name = aName ? aName : "App Update Test"; + let displayVersion = aDisplayVersion ? "displayVersion=\"" + + aDisplayVersion + "\" " + : ""; + let appVersion = "appVersion=\"" + + (aAppVersion ? aAppVersion : DEFAULT_UPDATE_VERSION) + + "\" "; + let buildID = aBuildID ? aBuildID : "20080811053724"; + // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 +// let detailsURL = aDetailsURL ? "detailsURL=\"" + aDetailsURL + "\" " : ""; + let detailsURL = "detailsURL=\"" + + (aDetailsURL ? aDetailsURL + : "http://test_details/") + "\" "; + let showPrompt = aShowPrompt ? "showPrompt=\"" + aShowPrompt + "\" " : ""; + let showNeverForVersion = aShowNeverForVersion ? "showNeverForVersion=\"" + + aShowNeverForVersion + "\" " + : ""; + let promptWaitTime = aPromptWaitTime ? "promptWaitTime=\"" + aPromptWaitTime + + "\" " + : ""; + let backgroundInterval = aBackgroundInterval ? "backgroundInterval=\"" + + aBackgroundInterval + "\" " + : ""; + let custom1 = aCustom1 ? aCustom1 + " " : ""; + let custom2 = aCustom2 ? aCustom2 + " " : ""; + return " <update type=\"" + type + "\" " + + "name=\"" + name + "\" " + + displayVersion + + appVersion + + detailsURL + + showPrompt + + showNeverForVersion + + promptWaitTime + + backgroundInterval + + custom1 + + custom2 + + "buildID=\"" + buildID + "\""; +} + +/** + * Constructs a string representing a patch element for an update xml file. + * + * @param aType (optional) + * The patch's type which should be complete or partial. + * If not specified it will default to 'complete'. + * @param aURL (optional) + * The patch's url to the mar file. + * If not specified it will default to the value of: + * gURLData + FILE_SIMPLE_MAR + * @param aHashFunction (optional) + * The patch's hash function used to verify the mar file. + * If not specified it will default to 'MD5'. + * @param aHashValue (optional) + * The patch's hash value used to verify the mar file. + * If not specified it will default to the value of MD5_HASH_SIMPLE_MAR + * which is the MD5 hash value for the file specified by FILE_SIMPLE_MAR. + * @param aSize (optional) + * The patch's file size for the mar file. + * If not specified it will default to the file size for FILE_SIMPLE_MAR + * specified by SIZE_SIMPLE_MAR. + * @return The string representing a patch element for an update xml file. + */ +function getPatchString(aType, aURL, aHashFunction, aHashValue, aSize) { + let type = aType ? aType : "complete"; + let url = aURL ? aURL : gURLData + FILE_SIMPLE_MAR; + let hashFunction = aHashFunction ? aHashFunction : "MD5"; + let hashValue = aHashValue ? aHashValue : MD5_HASH_SIMPLE_MAR; + let size = aSize ? aSize : SIZE_SIMPLE_MAR; + return " <patch type=\"" + type + "\" " + + "URL=\"" + url + "\" " + + "hashFunction=\"" + hashFunction + "\" " + + "hashValue=\"" + hashValue + "\" " + + "size=\"" + size + "\""; +} diff --git a/toolkit/mozapps/update/tests/data/simple.mar b/toolkit/mozapps/update/tests/data/simple.mar Binary files differnew file mode 100644 index 000000000..b2ccbd8d2 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/simple.mar diff --git a/toolkit/mozapps/update/tests/data/wrong_product_channel.mar b/toolkit/mozapps/update/tests/data/wrong_product_channel.mar Binary files differnew file mode 100644 index 000000000..1e39cc214 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/wrong_product_channel.mar diff --git a/toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js b/toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js new file mode 100644 index 000000000..e5f0fce58 --- /dev/null +++ b/toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Preprocessed constants used by xpcshell tests */ + +const INSTALL_LOCALE = "@AB_CD@"; +const MOZ_APP_NAME = "@MOZ_APP_NAME@"; +const BIN_SUFFIX = "@BIN_SUFFIX@"; + +// MOZ_APP_VENDOR is optional. +#ifdef MOZ_APP_VENDOR +const MOZ_APP_VENDOR = "@MOZ_APP_VENDOR@"; +#else +const MOZ_APP_VENDOR = ""; +#endif + +// MOZ_APP_BASENAME is not optional for tests. +const MOZ_APP_BASENAME = "@MOZ_APP_BASENAME@"; +const APP_BIN_SUFFIX = "@BIN_SUFFIX@"; + +const APP_INFO_NAME = "XPCShell"; +const APP_INFO_VENDOR = "Mozilla"; + +#ifdef XP_WIN +const IS_WIN = true; +#else +const IS_WIN = false; +#endif + +#ifdef XP_MACOSX +const IS_MACOSX = true; +#else +const IS_MACOSX = false; +#endif + +#ifdef XP_UNIX +const IS_UNIX = true; +#else +const IS_UNIX = false; +#endif + +#ifdef MOZ_VERIFY_MAR_SIGNATURE +const MOZ_VERIFY_MAR_SIGNATURE = true; +#else +const MOZ_VERIFY_MAR_SIGNATURE = false; +#endif + +#ifdef DISABLE_UPDATER_AUTHENTICODE_CHECK + const IS_AUTHENTICODE_CHECK_ENABLED = false; +#else + const IS_AUTHENTICODE_CHECK_ENABLED = true; +#endif diff --git a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js new file mode 100644 index 000000000..ada08f0ae --- /dev/null +++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js @@ -0,0 +1,4047 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Test log warnings that happen before the test has started + * "Couldn't get the user appdata directory. Crash events may not be produced." + * in nsExceptionHandler.cpp (possibly bug 619104) + * + * Test log warnings that happen after the test has finished + * "OOPDeinit() without successful OOPInit()" in nsExceptionHandler.cpp + * (bug 619104) + * "XPCOM objects created/destroyed from static ctor/dtor" in nsTraceRefcnt.cpp + * (possibly bug 457479) + * + * Other warnings printed to the test logs + * "site security information will not be persisted" in + * nsSiteSecurityService.cpp and the error in nsSystemInfo.cpp preceding this + * error are due to not having a profile when running some of the xpcshell + * tests. Since most xpcshell tests also log these errors these tests don't + * call do_get_profile unless necessary for the test. + * The "This method is lossy. Use GetCanonicalPath !" warning on Windows in + * nsLocalFileWin.cpp is from the call to GetNSSProfilePath in + * nsNSSComponent.cpp due to it using GetNativeCanonicalPath. + * "!mMainThread" in nsThreadManager.cpp are due to using timers and it might be + * possible to fix some or all of these in the test itself. + * "NS_FAILED(rv)" in nsThreadUtils.cpp are due to using timers and it might be + * possible to fix some or all of these in the test itself. + */ + +'use strict'; +/* eslint-disable no-undef */ + +const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, + utils: Cu } = Components; + +/* global INSTALL_LOCALE, MOZ_APP_NAME, BIN_SUFFIX, MOZ_APP_VENDOR */ +/* global MOZ_APP_BASENAME, APP_BIN_SUFFIX, APP_INFO_NAME, APP_INFO_VENDOR */ +/* global IS_WIN, IS_MACOSX, IS_UNIX, MOZ_VERIFY_MAR_SIGNATURE */ +/* global IS_AUTHENTICODE_CHECK_ENABLED */ +load("../data/xpcshellConstantsPP.js"); + +function getLogSuffix() { + if (IS_WIN) { + return "_win"; + } + if (IS_MACOSX) { + return "_mac"; + } + return "_linux"; +} + +Cu.import("resource://gre/modules/Services.jsm", this); +Cu.import("resource://gre/modules/ctypes.jsm", this); + +const DIR_MACOS = IS_MACOSX ? "Contents/MacOS/" : ""; +const DIR_RESOURCES = IS_MACOSX ? "Contents/Resources/" : ""; +const TEST_FILE_SUFFIX = IS_MACOSX ? "_mac" : ""; +const FILE_COMPLETE_MAR = "complete" + TEST_FILE_SUFFIX + ".mar"; +const FILE_PARTIAL_MAR = "partial" + TEST_FILE_SUFFIX + ".mar"; +const FILE_COMPLETE_PRECOMPLETE = "complete_precomplete" + TEST_FILE_SUFFIX; +const FILE_PARTIAL_PRECOMPLETE = "partial_precomplete" + TEST_FILE_SUFFIX; +const FILE_COMPLETE_REMOVEDFILES = "complete_removed-files" + TEST_FILE_SUFFIX; +const FILE_PARTIAL_REMOVEDFILES = "partial_removed-files" + TEST_FILE_SUFFIX; +const FILE_UPDATE_IN_PROGRESS_LOCK = "updated.update_in_progress.lock"; +const COMPARE_LOG_SUFFIX = getLogSuffix(); +const LOG_COMPLETE_SUCCESS = "complete_log_success" + COMPARE_LOG_SUFFIX; +const LOG_PARTIAL_SUCCESS = "partial_log_success" + COMPARE_LOG_SUFFIX; +const LOG_PARTIAL_FAILURE = "partial_log_failure" + COMPARE_LOG_SUFFIX; +const LOG_REPLACE_SUCCESS = "replace_log_success"; + +const USE_EXECV = IS_UNIX && !IS_MACOSX; + +const URL_HOST = "http://localhost"; + +const FILE_APP_BIN = MOZ_APP_NAME + APP_BIN_SUFFIX; +const FILE_COMPLETE_EXE = "complete.exe"; +const FILE_HELPER_BIN = "TestAUSHelper" + BIN_SUFFIX; +const FILE_MAINTENANCE_SERVICE_BIN = "maintenanceservice.exe"; +const FILE_MAINTENANCE_SERVICE_INSTALLER_BIN = "maintenanceservice_installer.exe"; +const FILE_OLD_VERSION_MAR = "old_version.mar"; +const FILE_PARTIAL_EXE = "partial.exe"; +const FILE_UPDATER_BIN = "updater" + BIN_SUFFIX; +const FILE_WRONG_CHANNEL_MAR = "wrong_product_channel.mar"; + +const PERFORMING_STAGED_UPDATE = "Performing a staged update"; +const CALL_QUIT = "calling QuitProgressUI"; +const REMOVE_OLD_DIST_DIR = "removing old distribution directory"; +const MOVE_OLD_DIST_DIR = "Moving old distribution directory to new location"; +const ERR_UPDATE_IN_PROGRESS = "Update already in progress! Exiting"; +const ERR_RENAME_FILE = "rename_file: failed to rename file"; +const ERR_ENSURE_COPY = "ensure_copy: failed to copy the file"; +const ERR_UNABLE_OPEN_DEST = "unable to open destination file"; +const ERR_BACKUP_DISCARD = "backup_discard: unable to remove"; +const ERR_MOVE_DESTDIR_7 = "Moving destDir to tmpDir failed, err: 7"; +const ERR_BACKUP_CREATE_7 = "backup_create failed: 7"; +const ERR_LOADSOURCEFILE_FAILED = "LoadSourceFile failed"; + +const LOG_SVC_SUCCESSFUL_LAUNCH = "Process was started... waiting on result."; + +// Typical end of a message when calling assert +const MSG_SHOULD_EQUAL = " should equal the expected value"; +const MSG_SHOULD_EXIST = "the file or directory should exist"; +const MSG_SHOULD_NOT_EXIST = "the file or directory should not exist"; + +// All we care about is that the last modified time has changed so that Mac OS +// X Launch Services invalidates its cache so the test allows up to one minute +// difference in the last modified time. +const MAC_MAX_TIME_DIFFERENCE = 60000; + +// How many of do_execute_soon calls to wait before the test is aborted. +const MAX_TIMEOUT_RUNS = 20000; + +// Time in seconds the helper application should sleep before exiting. The +// helper can also be made to exit by writing |finish| to its input file. +const HELPER_SLEEP_TIMEOUT = 180; + +// Maximum number of milliseconds the process that is launched can run before +// the test will try to kill it. +const APP_TIMER_TIMEOUT = 120000; + +// How many of do_timeout calls using FILE_IN_USE_TIMEOUT_MS to wait before the +// test is aborted. +const FILE_IN_USE_MAX_TIMEOUT_RUNS = 60; +const FILE_IN_USE_TIMEOUT_MS = 1000; + +const PIPE_TO_NULL = IS_WIN ? ">nul" : "> /dev/null 2>&1"; + +const LOG_FUNCTION = do_print; + +const gHTTPHandlerPath = "updates.xml"; + +// This default value will be overridden when using the http server. +var gURLData = URL_HOST + "/"; + +var gTestID; + +var gTestserver; + +var gRegisteredServiceCleanup; + +var gCheckFunc; +var gResponseBody; +var gResponseStatusCode = 200; +var gRequestURL; +var gUpdateCount; +var gUpdates; +var gStatusCode; +var gStatusText; +var gStatusResult; + +var gProcess; +var gAppTimer; +var gHandle; + +var gGREDirOrig; +var gGREBinDirOrig; +var gAppDirOrig; + +// Variables are used instead of contants so tests can override these values if +// necessary. +var gCallbackBinFile = "callback_app" + BIN_SUFFIX; +var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"]; +var gPostUpdateBinFile = "postup_app" + BIN_SUFFIX; +var gSvcOriginalLogContents; +var gUseTestAppDir = true; +// Some update staging failures can remove the update. This allows tests to +// specify that the status file and the active update should not be checked +// after an update is staged. +var gStagingRemovedUpdate = false; + +var gTimeoutRuns = 0; +var gFileInUseTimeoutRuns = 0; + +// Environment related globals +var gShouldResetEnv = undefined; +var gAddedEnvXRENoWindowsCrashDialog = false; +var gEnvXPCOMDebugBreak; +var gEnvXPCOMMemLeakLog; +var gEnvDyldLibraryPath; +var gEnvLdLibraryPath; +var gASanOptions; + +// Set to true to log additional information for debugging. To log additional +// information for an individual test set DEBUG_AUS_TEST to true in the test's +// run_test function. +var DEBUG_AUS_TEST = true; + +const DATA_URI_SPEC = Services.io.newFileURI(do_get_file("../data", false)).spec; +/* import-globals-from ../data/shared.js */ +Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this); + +var gTestFiles = []; +var gTestDirs = []; + +// Common files for both successful and failed updates. +var gTestFilesCommon = [ + { + description: "Should never change", + fileName: FILE_UPDATE_SETTINGS_INI, + relPathDir: DIR_RESOURCES, + originalContents: UPDATE_SETTINGS_CONTENTS, + compareContents: UPDATE_SETTINGS_CONTENTS, + originalFile: null, + compareFile: null, + originalPerms: 0o767, + comparePerms: 0o767 + }, { + description: "Should never change", + fileName: "channel-prefs.js", + relPathDir: DIR_RESOURCES + "defaults/pref/", + originalContents: "ShouldNotBeReplaced\n", + compareContents: "ShouldNotBeReplaced\n", + originalFile: null, + compareFile: null, + originalPerms: 0o767, + comparePerms: 0o767 + }]; + + // Files for a complete successful update. This can be used for a complete + // failed update by calling setTestFilesAndDirsForFailure. +var gTestFilesCompleteSuccess = [ + { + description: "Added by update.manifest (add)", + fileName: "precomplete", + relPathDir: DIR_RESOURCES, + originalContents: null, + compareContents: null, + originalFile: FILE_PARTIAL_PRECOMPLETE, + compareFile: FILE_COMPLETE_PRECOMPLETE, + originalPerms: 0o666, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "searchpluginstext0", + relPathDir: DIR_RESOURCES + "searchplugins/", + originalContents: "ToBeReplacedWithFromComplete\n", + compareContents: "FromComplete\n", + originalFile: null, + compareFile: null, + originalPerms: 0o775, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "searchpluginspng1.png", + relPathDir: DIR_RESOURCES + "searchplugins/", + originalContents: null, + compareContents: null, + originalFile: null, + compareFile: "complete.png", + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "searchpluginspng0.png", + relPathDir: DIR_RESOURCES + "searchplugins/", + originalContents: null, + compareContents: null, + originalFile: "partial.png", + compareFile: "complete.png", + originalPerms: 0o666, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "removed-files", + relPathDir: DIR_RESOURCES, + originalContents: null, + compareContents: null, + originalFile: FILE_PARTIAL_REMOVEDFILES, + compareFile: FILE_COMPLETE_REMOVEDFILES, + originalPerms: 0o666, + comparePerms: 0o644 + }, { + description: "Added by update.manifest if the parent directory exists (add-if)", + fileName: "extensions1text0", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents: null, + compareContents: "FromComplete\n", + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Added by update.manifest if the parent directory exists (add-if)", + fileName: "extensions1png1.png", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents: null, + compareContents: null, + originalFile: "partial.png", + compareFile: "complete.png", + originalPerms: 0o666, + comparePerms: 0o644 + }, { + description: "Added by update.manifest if the parent directory exists (add-if)", + fileName: "extensions1png0.png", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents: null, + compareContents: null, + originalFile: null, + compareFile: "complete.png", + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Added by update.manifest if the parent directory exists (add-if)", + fileName: "extensions0text0", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents: "ToBeReplacedWithFromComplete\n", + compareContents: "FromComplete\n", + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Added by update.manifest if the parent directory exists (add-if)", + fileName: "extensions0png1.png", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents: null, + compareContents: null, + originalFile: null, + compareFile: "complete.png", + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Added by update.manifest if the parent directory exists (add-if)", + fileName: "extensions0png0.png", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents: null, + compareContents: null, + originalFile: null, + compareFile: "complete.png", + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "exe0.exe", + relPathDir: DIR_MACOS, + originalContents: null, + compareContents: null, + originalFile: FILE_HELPER_BIN, + compareFile: FILE_COMPLETE_EXE, + originalPerms: 0o777, + comparePerms: 0o755 + }, { + description: "Added by update.manifest (add)", + fileName: "10text0", + relPathDir: DIR_RESOURCES + "1/10/", + originalContents: "ToBeReplacedWithFromComplete\n", + compareContents: "FromComplete\n", + originalFile: null, + compareFile: null, + originalPerms: 0o767, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "0exe0.exe", + relPathDir: DIR_RESOURCES + "0/", + originalContents: null, + compareContents: null, + originalFile: FILE_HELPER_BIN, + compareFile: FILE_COMPLETE_EXE, + originalPerms: 0o777, + comparePerms: 0o755 + }, { + description: "Added by update.manifest (add)", + fileName: "00text1", + relPathDir: DIR_RESOURCES + "0/00/", + originalContents: "ToBeReplacedWithFromComplete\n", + compareContents: "FromComplete\n", + originalFile: null, + compareFile: null, + originalPerms: 0o677, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "00text0", + relPathDir: DIR_RESOURCES + "0/00/", + originalContents: "ToBeReplacedWithFromComplete\n", + compareContents: "FromComplete\n", + originalFile: null, + compareFile: null, + originalPerms: 0o775, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "00png0.png", + relPathDir: DIR_RESOURCES + "0/00/", + originalContents: null, + compareContents: null, + originalFile: null, + compareFile: "complete.png", + originalPerms: 0o776, + comparePerms: 0o644 + }, { + description: "Removed by precomplete (remove)", + fileName: "20text0", + relPathDir: DIR_RESOURCES + "2/20/", + originalContents: "ToBeDeleted\n", + compareContents: null, + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: null + }, { + description: "Removed by precomplete (remove)", + fileName: "20png0.png", + relPathDir: DIR_RESOURCES + "2/20/", + originalContents: "ToBeDeleted\n", + compareContents: null, + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: null + }]; + +// Concatenate the common files to the end of the array. +gTestFilesCompleteSuccess = gTestFilesCompleteSuccess.concat(gTestFilesCommon); + +// Files for a partial successful update. This can be used for a partial failed +// update by calling setTestFilesAndDirsForFailure. +var gTestFilesPartialSuccess = [ + { + description: "Added by update.manifest (add)", + fileName: "precomplete", + relPathDir: DIR_RESOURCES, + originalContents: null, + compareContents: null, + originalFile: FILE_COMPLETE_PRECOMPLETE, + compareFile: FILE_PARTIAL_PRECOMPLETE, + originalPerms: 0o666, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "searchpluginstext0", + relPathDir: DIR_RESOURCES + "searchplugins/", + originalContents: "ToBeReplacedWithFromPartial\n", + compareContents: "FromPartial\n", + originalFile: null, + compareFile: null, + originalPerms: 0o775, + comparePerms: 0o644 + }, { + description: "Patched by update.manifest if the file exists (patch-if)", + fileName: "searchpluginspng1.png", + relPathDir: DIR_RESOURCES + "searchplugins/", + originalContents: null, + compareContents: null, + originalFile: "complete.png", + compareFile: "partial.png", + originalPerms: 0o666, + comparePerms: 0o666 + }, { + description: "Patched by update.manifest if the file exists (patch-if)", + fileName: "searchpluginspng0.png", + relPathDir: DIR_RESOURCES + "searchplugins/", + originalContents: null, + compareContents: null, + originalFile: "complete.png", + compareFile: "partial.png", + originalPerms: 0o666, + comparePerms: 0o666 + }, { + description: "Added by update.manifest if the parent directory exists (add-if)", + fileName: "extensions1text0", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents: null, + compareContents: "FromPartial\n", + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Patched by update.manifest if the parent directory exists (patch-if)", + fileName: "extensions1png1.png", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents: null, + compareContents: null, + originalFile: "complete.png", + compareFile: "partial.png", + originalPerms: 0o666, + comparePerms: 0o666 + }, { + description: "Patched by update.manifest if the parent directory exists (patch-if)", + fileName: "extensions1png0.png", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", + originalContents: null, + compareContents: null, + originalFile: "complete.png", + compareFile: "partial.png", + originalPerms: 0o666, + comparePerms: 0o666 + }, { + description: "Added by update.manifest if the parent directory exists (add-if)", + fileName: "extensions0text0", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents: "ToBeReplacedWithFromPartial\n", + compareContents: "FromPartial\n", + originalFile: null, + compareFile: null, + originalPerms: 0o644, + comparePerms: 0o644 + }, { + description: "Patched by update.manifest if the parent directory exists (patch-if)", + fileName: "extensions0png1.png", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents: null, + compareContents: null, + originalFile: "complete.png", + compareFile: "partial.png", + originalPerms: 0o644, + comparePerms: 0o644 + }, { + description: "Patched by update.manifest if the parent directory exists (patch-if)", + fileName: "extensions0png0.png", + relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", + originalContents: null, + compareContents: null, + originalFile: "complete.png", + compareFile: "partial.png", + originalPerms: 0o644, + comparePerms: 0o644 + }, { + description: "Patched by update.manifest (patch)", + fileName: "exe0.exe", + relPathDir: DIR_MACOS, + originalContents: null, + compareContents: null, + originalFile: FILE_COMPLETE_EXE, + compareFile: FILE_PARTIAL_EXE, + originalPerms: 0o755, + comparePerms: 0o755 + }, { + description: "Patched by update.manifest (patch)", + fileName: "0exe0.exe", + relPathDir: DIR_RESOURCES + "0/", + originalContents: null, + compareContents: null, + originalFile: FILE_COMPLETE_EXE, + compareFile: FILE_PARTIAL_EXE, + originalPerms: 0o755, + comparePerms: 0o755 + }, { + description: "Added by update.manifest (add)", + fileName: "00text0", + relPathDir: DIR_RESOURCES + "0/00/", + originalContents: "ToBeReplacedWithFromPartial\n", + compareContents: "FromPartial\n", + originalFile: null, + compareFile: null, + originalPerms: 0o644, + comparePerms: 0o644 + }, { + description: "Patched by update.manifest (patch)", + fileName: "00png0.png", + relPathDir: DIR_RESOURCES + "0/00/", + originalContents: null, + compareContents: null, + originalFile: "complete.png", + compareFile: "partial.png", + originalPerms: 0o666, + comparePerms: 0o666 + }, { + description: "Added by update.manifest (add)", + fileName: "20text0", + relPathDir: DIR_RESOURCES + "2/20/", + originalContents: null, + compareContents: "FromPartial\n", + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "20png0.png", + relPathDir: DIR_RESOURCES + "2/20/", + originalContents: null, + compareContents: null, + originalFile: null, + compareFile: "partial.png", + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Added by update.manifest (add)", + fileName: "00text2", + relPathDir: DIR_RESOURCES + "0/00/", + originalContents: null, + compareContents: "FromPartial\n", + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: 0o644 + }, { + description: "Removed by update.manifest (remove)", + fileName: "10text0", + relPathDir: DIR_RESOURCES + "1/10/", + originalContents: "ToBeDeleted\n", + compareContents: null, + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: null + }, { + description: "Removed by update.manifest (remove)", + fileName: "00text1", + relPathDir: DIR_RESOURCES + "0/00/", + originalContents: "ToBeDeleted\n", + compareContents: null, + originalFile: null, + compareFile: null, + originalPerms: null, + comparePerms: null + }]; + +// Concatenate the common files to the end of the array. +gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon); + +var gTestDirsCommon = [ + { + relPathDir: DIR_RESOURCES + "3/", + dirRemoved: false, + files: ["3text0", "3text1"], + filesRemoved: true + }, { + relPathDir: DIR_RESOURCES + "4/", + dirRemoved: true, + files: ["4text0", "4text1"], + filesRemoved: true + }, { + relPathDir: DIR_RESOURCES + "5/", + dirRemoved: true, + files: ["5test.exe", "5text0", "5text1"], + filesRemoved: true + }, { + relPathDir: DIR_RESOURCES + "6/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "7/", + dirRemoved: true, + files: ["7text0", "7text1"], + subDirs: ["70/", "71/"], + subDirFiles: ["7xtest.exe", "7xtext0", "7xtext1"] + }, { + relPathDir: DIR_RESOURCES + "8/", + dirRemoved: false + }, { + relPathDir: DIR_RESOURCES + "8/80/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "8/81/", + dirRemoved: false, + files: ["81text0", "81text1"] + }, { + relPathDir: DIR_RESOURCES + "8/82/", + dirRemoved: false, + subDirs: ["820/", "821/"] + }, { + relPathDir: DIR_RESOURCES + "8/83/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "8/84/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "8/85/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "8/86/", + dirRemoved: true, + files: ["86text0", "86text1"] + }, { + relPathDir: DIR_RESOURCES + "8/87/", + dirRemoved: true, + subDirs: ["870/", "871/"], + subDirFiles: ["87xtext0", "87xtext1"] + }, { + relPathDir: DIR_RESOURCES + "8/88/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "8/89/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "9/90/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "9/91/", + dirRemoved: false, + files: ["91text0", "91text1"] + }, { + relPathDir: DIR_RESOURCES + "9/92/", + dirRemoved: false, + subDirs: ["920/", "921/"] + }, { + relPathDir: DIR_RESOURCES + "9/93/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "9/94/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "9/95/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "9/96/", + dirRemoved: true, + files: ["96text0", "96text1"] + }, { + relPathDir: DIR_RESOURCES + "9/97/", + dirRemoved: true, + subDirs: ["970/", "971/"], + subDirFiles: ["97xtext0", "97xtext1"] + }, { + relPathDir: DIR_RESOURCES + "9/98/", + dirRemoved: true + }, { + relPathDir: DIR_RESOURCES + "9/99/", + dirRemoved: true + }]; + +// Directories for a complete successful update. This array can be used for a +// complete failed update by calling setTestFilesAndDirsForFailure. +var gTestDirsCompleteSuccess = [ + { + description: "Removed by precomplete (rmdir)", + relPathDir: DIR_RESOURCES + "2/20/", + dirRemoved: true + }, { + description: "Removed by precomplete (rmdir)", + relPathDir: DIR_RESOURCES + "2/", + dirRemoved: true + }]; + +// Concatenate the common files to the beginning of the array. +gTestDirsCompleteSuccess = gTestDirsCommon.concat(gTestDirsCompleteSuccess); + +// Directories for a partial successful update. This array can be used for a +// partial failed update by calling setTestFilesAndDirsForFailure. +var gTestDirsPartialSuccess = [ + { + description: "Removed by update.manifest (rmdir)", + relPathDir: DIR_RESOURCES + "1/10/", + dirRemoved: true + }, { + description: "Removed by update.manifest (rmdir)", + relPathDir: DIR_RESOURCES + "1/", + dirRemoved: true + }]; + +// Concatenate the common files to the beginning of the array. +gTestDirsPartialSuccess = gTestDirsCommon.concat(gTestDirsPartialSuccess); + +// This makes it possible to run most tests on xulrunner where the update +// channel default preference is not set. +if (MOZ_APP_NAME == "xulrunner") { + try { + gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); + } catch (e) { + setUpdateChannel("test_channel"); + } +} + +/** + * Helper function for setting up the test environment. + */ +function setupTestCommon() { + debugDump("start - general test setup"); + + Assert.strictEqual(gTestID, undefined, + "gTestID should be 'undefined' (setupTestCommon should " + + "only be called once)"); + + let caller = Components.stack.caller; + gTestID = caller.filename.toString().split("/").pop().split(".")[0]; + + // Tests that don't work with XULRunner. + const XUL_RUNNER_INCOMPATIBLE = ["marAppApplyUpdateAppBinInUseStageSuccess_win", + "marAppApplyUpdateStageSuccess", + "marAppApplyUpdateSuccess", + "marAppApplyUpdateAppBinInUseStageSuccessSvc_win", + "marAppApplyUpdateStageSuccessSvc", + "marAppApplyUpdateSuccessSvc"]; + // Replace with Array.prototype.includes when it has stabilized. + if (MOZ_APP_NAME == "xulrunner" && + XUL_RUNNER_INCOMPATIBLE.indexOf(gTestID) != -1) { + logTestInfo("Unable to run this test on xulrunner"); + return false; + } + + if (IS_SERVICE_TEST && !shouldRunServiceTest()) { + return false; + } + + do_test_pending(); + + setDefaultPrefs(); + + // Don't attempt to show a prompt when an update finishes. + Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true); + + gGREDirOrig = getGREDir(); + gGREBinDirOrig = getGREBinDir(); + gAppDirOrig = getAppBaseDir(); + + let applyDir = getApplyDirFile(null, true).parent; + + // Try to remove the directory used to apply updates and the updates directory + // on platforms other than Windows. Since the test hasn't ran yet and the + // directory shouldn't exist finished this is non-fatal for the test. + if (applyDir.exists()) { + debugDump("attempting to remove directory. Path: " + applyDir.path); + try { + removeDirRecursive(applyDir); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + applyDir.path + ", Exception: " + e); + // When the application doesn't exit properly it can cause the test to + // fail again on the second run with an NS_ERROR_FILE_ACCESS_DENIED error + // along with no useful information in the test log. To prevent this use + // a different directory for the test when it isn't possible to remove the + // existing test directory (bug 1294196). + gTestID += "_new"; + logTestInfo("using a new directory for the test by changing gTestID " + + "since there is an existing test directory that can't be " + + "removed, gTestID: " + gTestID); + } + } + + if (IS_WIN) { + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, + IS_SERVICE_TEST ? true : false); + } + + // adjustGeneralPaths registers a cleanup function that calls end_test when + // it is defined as a function. + adjustGeneralPaths(); + // Logged once here instead of in the mock directory provider to lessen test + // log spam. + debugDump("Updates Directory (UpdRootD) Path: " + getMockUpdRootD().path); + + // This prevents a warning about not being able to find the greprefs.js file + // from being logged. + let grePrefsFile = getGREDir(); + if (!grePrefsFile.exists()) { + grePrefsFile.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + grePrefsFile.append("greprefs.js"); + if (!grePrefsFile.exists()) { + grePrefsFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + + // Remove the updates directory on Windows and Mac OS X which is located + // outside of the application directory after the call to adjustGeneralPaths + // has set it up. Since the test hasn't ran yet and the directory shouldn't + // exist this is non-fatal for the test. + if (IS_WIN || IS_MACOSX) { + let updatesDir = getMockUpdRootD(); + if (updatesDir.exists()) { + debugDump("attempting to remove directory. Path: " + updatesDir.path); + try { + removeDirRecursive(updatesDir); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + updatesDir.path + ", Exception: " + e); + } + } + } + + debugDump("finish - general test setup"); + return true; +} + +/** + * Nulls out the most commonly used global vars used by tests to prevent leaks + * as needed and attempts to restore the system to its original state. + */ +function cleanupTestCommon() { + debugDump("start - general test cleanup"); + + // Force the update manager to reload the update data to prevent it from + // writing the old data to the files that have just been removed. + reloadUpdateManagerData(); + + if (gChannel) { + gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer); + } + + // Call app update's observe method passing xpcom-shutdown to test that the + // shutdown of app update runs without throwing or leaking. The observer + // method is used directly instead of calling notifyObservers so components + // outside of the scope of this test don't assert and thereby cause app update + // tests to fail. + gAUS.observe(null, "xpcom-shutdown", ""); + + gTestserver = null; + + if (IS_UNIX) { + // This will delete the launch script if it exists. + getLaunchScript(); + } + + if (IS_WIN && MOZ_APP_BASENAME) { + let appDir = getApplyDirFile(null, true); + let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla"; + const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME + + "\\TaskBarIDs"; + let key = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + try { + key.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_ALL); + if (key.hasValue(appDir.path)) { + key.removeValue(appDir.path); + } + } catch (e) { + } + try { + key.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_ALL); + if (key.hasValue(appDir.path)) { + key.removeValue(appDir.path); + } + } catch (e) { + } + } + + // The updates directory is located outside of the application directory and + // needs to be removed on Windows and Mac OS X. + if (IS_WIN || IS_MACOSX) { + let updatesDir = getMockUpdRootD(); + // Try to remove the directory used to apply updates. Since the test has + // already finished this is non-fatal for the test. + if (updatesDir.exists()) { + debugDump("attempting to remove directory. Path: " + updatesDir.path); + try { + removeDirRecursive(updatesDir); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + updatesDir.path + ", Exception: " + e); + } + if (IS_MACOSX) { + let updatesRootDir = gUpdatesRootDir.clone(); + while (updatesRootDir.path != updatesDir.path) { + if (updatesDir.exists()) { + debugDump("attempting to remove directory. Path: " + + updatesDir.path); + try { + // Try to remove the directory without the recursive flag set + // since the top level directory has already had its contents + // removed and the parent directory might still be used by a + // different test. + updatesDir.remove(false); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + updatesDir.path + ", Exception: " + e); + if (e == Cr.NS_ERROR_FILE_DIR_NOT_EMPTY) { + break; + } + } + } + updatesDir = updatesDir.parent; + } + } + } + } + + let applyDir = getApplyDirFile(null, true).parent; + + // Try to remove the directory used to apply updates. Since the test has + // already finished this is non-fatal for the test. + if (applyDir.exists()) { + debugDump("attempting to remove directory. Path: " + applyDir.path); + try { + removeDirRecursive(applyDir); + } catch (e) { + logTestInfo("non-fatal error removing directory. Path: " + + applyDir.path + ", Exception: " + e); + } + } + + resetEnvironment(); + + debugDump("finish - general test cleanup"); +} + +/** + * Helper function that calls do_test_finished that tracks whether a parallel + * run of a test passed when it runs synchronously so the log output can be + * inspected. + */ +function doTestFinish() { + if (DEBUG_AUS_TEST) { + // This prevents do_print errors from being printed by the xpcshell test + // harness due to nsUpdateService.js logging to the console when the + // app.update.log preference is true. + Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, false); + gAUS.observe(null, "nsPref:changed", PREF_APP_UPDATE_LOG); + } + do_execute_soon(do_test_finished); +} + +/** + * Sets the most commonly used preferences used by tests + */ +function setDefaultPrefs() { + Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true); + if (DEBUG_AUS_TEST) { + // Enable Update logging + Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true); + } else { + // Some apps set this preference to true by default + Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, false); + } + // In case telemetry is enabled for xpcshell tests. + Services.prefs.setBoolPref(PREF_TOOLKIT_TELEMETRY_ENABLED, false); +} + +/** + * Helper function for updater binary tests that sets the appropriate values + * to check for update failures. + */ +function setTestFilesAndDirsForFailure() { + gTestFiles.forEach(function STFADFF_Files(aTestFile) { + aTestFile.compareContents = aTestFile.originalContents; + aTestFile.compareFile = aTestFile.originalFile; + aTestFile.comparePerms = aTestFile.originalPerms; + }); + + gTestDirs.forEach(function STFADFF_Dirs(aTestDir) { + aTestDir.dirRemoved = false; + if (aTestDir.filesRemoved) { + aTestDir.filesRemoved = false; + } + }); +} + +/** + * Helper function for updater binary tests that prevents the distribution + * directory files from being created. + */ +function preventDistributionFiles() { + gTestFiles = gTestFiles.filter(function(aTestFile) { + return aTestFile.relPathDir.indexOf("distribution/") == -1; + }); + + gTestDirs = gTestDirs.filter(function(aTestDir) { + return aTestDir.relPathDir.indexOf("distribution/") == -1; + }); +} + +/** + * On Mac OS X this sets the last modified time for the app bundle directory to + * a date in the past to test that the last modified time is updated when an + * update has been successfully applied (bug 600098). + */ +function setAppBundleModTime() { + if (!IS_MACOSX) { + return; + } + let now = Date.now(); + let yesterday = now - (1000 * 60 * 60 * 24); + let applyToDir = getApplyDirFile(); + applyToDir.lastModifiedTime = yesterday; +} + +/** + * On Mac OS X this checks that the last modified time for the app bundle + * directory has been updated when an update has been successfully applied + * (bug 600098). + */ +function checkAppBundleModTime() { + if (!IS_MACOSX) { + return; + } + let now = Date.now(); + let applyToDir = getApplyDirFile(); + let timeDiff = Math.abs(applyToDir.lastModifiedTime - now); + Assert.ok(timeDiff < MAC_MAX_TIME_DIFFERENCE, + "the last modified time on the apply to directory should " + + "change after a successful update"); +} + +/** + * On Mac OS X and Windows this checks if the post update '.running' file exists + * to determine if the post update binary was launched. + * + * @param aShouldExist + * Whether the post update '.running' file should exist. + */ +function checkPostUpdateRunningFile(aShouldExist) { + if (!IS_WIN && !IS_MACOSX) { + return; + } + let postUpdateRunningFile = getPostUpdateFile(".running"); + if (aShouldExist) { + Assert.ok(postUpdateRunningFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(postUpdateRunningFile.path)); + } else { + Assert.ok(!postUpdateRunningFile.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(postUpdateRunningFile.path)); + } +} + +/** + * Initializes the most commonly used settings and creates an instance of the + * update service stub. + */ +function standardInit() { + createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0"); + // Initialize the update service stub component + initUpdateServiceStub(); +} + +/** + * Helper function for getting the application version from the application.ini + * file. This will look in both the GRE and the application directories for the + * application.ini file. + * + * @return The version string from the application.ini file. + */ +function getAppVersion() { + // Read the application.ini and use its application version. + let iniFile = gGREDirOrig.clone(); + iniFile.append(FILE_APPLICATION_INI); + if (!iniFile.exists()) { + iniFile = gGREBinDirOrig.clone(); + iniFile.append(FILE_APPLICATION_INI); + } + Assert.ok(iniFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(iniFile.path)); + let iniParser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]. + getService(Ci.nsIINIParserFactory). + createINIParser(iniFile); + return iniParser.getString("App", "Version"); +} + +/** + * Helper function for getting the relative path to the directory where the + * application binary is located (e.g. <test_file_leafname>/dir.app/). + * + * Note: The dir.app subdirectory under <test_file_leafname> is needed for + * platforms other than Mac OS X so the tests can run in parallel due to + * update staging creating a lock file named moz_update_in_progress.lock in + * the parent directory of the installation directory. + * + * @return The relative path to the directory where application binary is + * located. + */ +function getApplyDirPath() { + return gTestID + "/dir.app/"; +} + +/** + * Helper function for getting the nsIFile for a file in the directory where the + * update will be applied. + * + * The files for the update are located two directories below the apply to + * directory since Mac OS X sets the last modified time for the root directory + * to the current time and if the update changes any files in the root directory + * then it wouldn't be possible to test (bug 600098). + * + * @param aRelPath (optional) + * The relative path to the file or directory to get from the root of + * the test's directory. If not specified the test's directory will be + * returned. + * @param aAllowNonexistent (optional) + * Whether the file must exist. If false or not specified the file must + * exist or the function will throw. + * @return The nsIFile for the file in the directory where the update will be + * applied. + * @throws If aAllowNonexistent is not specified or is false and the file or + * directory does not exist. + */ +function getApplyDirFile(aRelPath, aAllowNonexistent) { + let relpath = getApplyDirPath() + (aRelPath ? aRelPath : ""); + return do_get_file(relpath, aAllowNonexistent); +} + +/** + * Helper function for getting the nsIFile for a file in the directory where the + * update will be staged. + * + * The files for the update are located two directories below the stage + * directory since Mac OS X sets the last modified time for the root directory + * to the current time and if the update changes any files in the root directory + * then it wouldn't be possible to test (bug 600098). + * + * @param aRelPath (optional) + * The relative path to the file or directory to get from the root of + * the stage directory. If not specified the stage directory will be + * returned. + * @param aAllowNonexistent (optional) + * Whether the file must exist. If false or not specified the file must + * exist or the function will throw. + * @return The nsIFile for the file in the directory where the update will be + * staged. + * @throws If aAllowNonexistent is not specified or is false and the file or + * directory does not exist. + */ +function getStageDirFile(aRelPath, aAllowNonexistent) { + if (IS_MACOSX) { + let file = getMockUpdRootD(); + file.append(DIR_UPDATES); + file.append(DIR_PATCH); + file.append(DIR_UPDATED); + if (aRelPath) { + let pathParts = aRelPath.split("/"); + for (let i = 0; i < pathParts.length; i++) { + if (pathParts[i]) { + file.append(pathParts[i]); + } + } + } + if (!aAllowNonexistent) { + Assert.ok(file.exists(), + MSG_SHOULD_EXIST + getMsgPath(file.path)); + } + return file; + } + + let relpath = getApplyDirPath() + DIR_UPDATED + "/" + (aRelPath ? aRelPath : ""); + return do_get_file(relpath, aAllowNonexistent); +} + +/** + * Helper function for getting the relative path to the directory where the + * test data files are located. + * + * @return The relative path to the directory where the test data files are + * located. + */ +function getTestDirPath() { + return "../data/"; +} + +/** + * Helper function for getting the nsIFile for a file in the test data + * directory. + * + * @param aRelPath (optional) + * The relative path to the file or directory to get from the root of + * the test's data directory. If not specified the test's data + * directory will be returned. + * @param aAllowNonExists (optional) + * Whether or not to throw an error if the path exists. + * If not specified, then false is used. + * @return The nsIFile for the file in the test data directory. + * @throws If the file or directory does not exist. + */ +function getTestDirFile(aRelPath, aAllowNonExists) { + let relpath = getTestDirPath() + (aRelPath ? aRelPath : ""); + return do_get_file(relpath, !!aAllowNonExists); +} + +/** + * Helper function for getting the nsIFile for the maintenance service + * directory on Windows. + * + * @return The nsIFile for the maintenance service directory. + */ +function getMaintSvcDir() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + const CSIDL_PROGRAM_FILES = 0x26; + const CSIDL_PROGRAM_FILESX86 = 0x2A; + // This will return an empty string on our Win XP build systems. + let maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILESX86); + if (maintSvcDir) { + maintSvcDir.append("Mozilla Maintenance Service"); + debugDump("using CSIDL_PROGRAM_FILESX86 - maintenance service install " + + "directory path: " + maintSvcDir.path); + } + if (!maintSvcDir || !maintSvcDir.exists()) { + maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILES); + if (maintSvcDir) { + maintSvcDir.append("Mozilla Maintenance Service"); + debugDump("using CSIDL_PROGRAM_FILES - maintenance service install " + + "directory path: " + maintSvcDir.path); + } + } + if (!maintSvcDir) { + do_throw("Unable to find the maintenance service install directory"); + } + + return maintSvcDir; +} + +/** + * Get the nsILocalFile for a Windows special folder determined by the CSIDL + * passed. + * + * @param aCSIDL + * The CSIDL for the Windows special folder. + * @return The nsILocalFile for the Windows special folder. + * @throws If called from a platform other than Windows. + */ +function getSpecialFolderDir(aCSIDL) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let lib = ctypes.open("shell32"); + let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW", + ctypes.winapi_abi, + ctypes.bool, /* bool(return) */ + ctypes.int32_t, /* HWND hwndOwner */ + ctypes.char16_t.ptr, /* LPTSTR lpszPath */ + ctypes.int32_t, /* int csidl */ + ctypes.bool /* BOOL fCreate */); + + let aryPath = ctypes.char16_t.array()(260); + let rv = SHGetSpecialFolderPath(0, aryPath, aCSIDL, false); + lib.close(); + + let path = aryPath.readString(); // Convert the c-string to js-string + if (!path) { + return null; + } + debugDump("SHGetSpecialFolderPath returned path: " + path); + let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); + dir.initWithPath(path); + return dir; +} + +XPCOMUtils.defineLazyGetter(this, "gInstallDirPathHash", function test_gIDPH() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + // Figure out where we should check for a cached hash value + if (!MOZ_APP_BASENAME) { + return null; + } + + let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla"; + let appDir = getApplyDirFile(null, true); + + const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME + + "\\TaskBarIDs"; + let regKey = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + try { + regKey.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_ALL); + regKey.writeStringValue(appDir.path, gTestID); + return gTestID; + } catch (e) { + } + + try { + regKey.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_ALL); + regKey.writeStringValue(appDir.path, gTestID); + return gTestID; + } catch (e) { + logTestInfo("failed to create registry key. Registry Path: " + REG_PATH + + ", Key Name: " + appDir.path + ", Key Value: " + gTestID + + ", Exception " + e); + } + return null; +}); + +XPCOMUtils.defineLazyGetter(this, "gLocalAppDataDir", function test_gLADD() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + const CSIDL_LOCAL_APPDATA = 0x1c; + return getSpecialFolderDir(CSIDL_LOCAL_APPDATA); +}); + +XPCOMUtils.defineLazyGetter(this, "gProgFilesDir", function test_gPFD() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + const CSIDL_PROGRAM_FILES = 0x26; + return getSpecialFolderDir(CSIDL_PROGRAM_FILES); +}); + +/** + * Helper function for getting the update root directory used by the tests. This + * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir + * in nsXREDirProvider.cpp so an application will be able to find the update + * when running a test that launches the application. + */ +function getMockUpdRootD() { + if (IS_WIN) { + return getMockUpdRootDWin(); + } + + if (IS_MACOSX) { + return getMockUpdRootDMac(); + } + + return getApplyDirFile(DIR_MACOS, true); +} + +/** + * Helper function for getting the update root directory used by the tests. This + * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir + * in nsXREDirProvider.cpp so an application will be able to find the update + * when running a test that launches the application. + */ +function getMockUpdRootDWin() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let localAppDataDir = gLocalAppDataDir.clone(); + let progFilesDir = gProgFilesDir.clone(); + let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile).parent; + + let appDirPath = appDir.path; + let relPathUpdates = ""; + if (gInstallDirPathHash && (MOZ_APP_VENDOR || MOZ_APP_BASENAME)) { + relPathUpdates += (MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME) + + "\\" + DIR_UPDATES + "\\" + gInstallDirPathHash; + } + + if (!relPathUpdates && progFilesDir) { + if (appDirPath.length > progFilesDir.path.length) { + if (appDirPath.substr(0, progFilesDir.path.length) == progFilesDir.path) { + if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) { + relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME; + } else { + relPathUpdates += MOZ_APP_BASENAME; + } + relPathUpdates += appDirPath.substr(progFilesDir.path.length); + } + } + } + + if (!relPathUpdates) { + if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) { + relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME; + } else { + relPathUpdates += MOZ_APP_BASENAME; + } + relPathUpdates += "\\" + MOZ_APP_NAME; + } + + let updatesDir = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + updatesDir.initWithPath(localAppDataDir.path + "\\" + relPathUpdates); + return updatesDir; +} + +XPCOMUtils.defineLazyGetter(this, "gUpdatesRootDir", function test_gURD() { + if (!IS_MACOSX) { + do_throw("Mac OS X only function called by a different platform!"); + } + + let dir = Services.dirsvc.get("ULibDir", Ci.nsILocalFile); + dir.append("Caches"); + if (MOZ_APP_VENDOR || MOZ_APP_BASENAME) { + dir.append(MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME); + } else { + dir.append("Mozilla"); + } + dir.append(DIR_UPDATES); + return dir; +}); + +/** + * Helper function for getting the update root directory used by the tests. This + * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir + * in nsXREDirProvider.cpp so an application will be able to find the update + * when running a test that launches the application. + */ +function getMockUpdRootDMac() { + if (!IS_MACOSX) { + do_throw("Mac OS X only function called by a different platform!"); + } + + let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile). + parent.parent.parent; + let appDirPath = appDir.path; + appDirPath = appDirPath.substr(0, appDirPath.length - 4); + + let pathUpdates = gUpdatesRootDir.path + appDirPath; + let updatesDir = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + updatesDir.initWithPath(pathUpdates); + return updatesDir; +} + +/** + * Creates an update in progress lock file in the specified directory on + * Windows. + * + * @param aDir + * The nsIFile for the directory where the lock file should be created. + */ +function createUpdateInProgressLockFile(aDir) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let file = aDir.clone(); + file.append(FILE_UPDATE_IN_PROGRESS_LOCK); + file.create(file.NORMAL_FILE_TYPE, 0o444); + file.QueryInterface(Ci.nsILocalFileWin); + file.fileAttributesWin |= file.WFA_READONLY; + file.fileAttributesWin &= ~file.WFA_READWRITE; + Assert.ok(file.exists(), + MSG_SHOULD_EXIST + getMsgPath(file.path)); + Assert.ok(!file.isWritable(), + "the lock file should not be writeable"); +} + +/** + * Removes an update in progress lock file in the specified directory on + * Windows. + * + * @param aDir + * The nsIFile for the directory where the lock file is located. + */ +function removeUpdateInProgressLockFile(aDir) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let file = aDir.clone(); + file.append(FILE_UPDATE_IN_PROGRESS_LOCK); + file.QueryInterface(Ci.nsILocalFileWin); + file.fileAttributesWin |= file.WFA_READWRITE; + file.fileAttributesWin &= ~file.WFA_READONLY; + file.remove(false); + Assert.ok(!file.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(file.path)); +} + +/** + * Gets the test updater from the test data direcory. + * + * @return nsIFIle for the test updater. + */ +function getTestUpdater() { + let updater = getTestDirFile("updater.app", true); + if (!updater.exists()) { + updater = getTestDirFile(FILE_UPDATER_BIN); + if (!updater.exists()) { + do_throw("Unable to find the updater binary!"); + } + } + Assert.ok(updater.exists(), + MSG_SHOULD_EXIST + getMsgPath(updater.path)); + return updater; +} + +/** + * Copies the test updater to the GRE binary directory and returns the nsIFile + * for the copied test updater. + * + * @return nsIFIle for the copied test updater. + */ +function copyTestUpdaterToBinDir() { + let testUpdater = getTestUpdater(); + let updater = getGREBinDir(); + updater.append(testUpdater.leafName); + if (!updater.exists()) { + testUpdater.copyToFollowingLinks(updater.parent, updater.leafName); + } + return updater; +} + +/** + * Copies the test updater to the location where it will be launched to apply an + * update and returns the nsIFile for the copied test updater. + * + * @return nsIFIle for the copied test updater. + */ +function copyTestUpdaterForRunUsingUpdater() { + if (IS_WIN) { + return copyTestUpdaterToBinDir(); + } + + let testUpdater = getTestUpdater(); + let updater = getUpdatesPatchDir(); + updater.append(testUpdater.leafName); + if (!updater.exists()) { + testUpdater.copyToFollowingLinks(updater.parent, updater.leafName); + } + + if (IS_MACOSX) { + updater.append("Contents"); + updater.append("MacOS"); + updater.append("org.mozilla.updater"); + } + return updater; +} + +/** + * Logs the contents of an update log and for maintenance service tests this + * will log the contents of the latest maintenanceservice.log. + * + * @param aLogLeafName + * The leaf name of the update log. + */ +function logUpdateLog(aLogLeafName) { + let updateLog = getUpdateLog(aLogLeafName); + if (updateLog.exists()) { + // xpcshell tests won't display the entire contents so log each line. + let updateLogContents = readFileBytes(updateLog).replace(/\r\n/g, "\n"); + updateLogContents = replaceLogPaths(updateLogContents); + let aryLogContents = updateLogContents.split("\n"); + logTestInfo("contents of " + updateLog.path + ":"); + aryLogContents.forEach(function RU_LC_FE(aLine) { + logTestInfo(aLine); + }); + } else { + logTestInfo("update log doesn't exist, path: " + updateLog.path); + } + + if (IS_SERVICE_TEST) { + let serviceLog = getMaintSvcDir(); + serviceLog.append("logs"); + serviceLog.append("maintenanceservice.log"); + if (serviceLog.exists()) { + // xpcshell tests won't display the entire contents so log each line. + let serviceLogContents = readFileBytes(serviceLog).replace(/\r\n/g, "\n"); + serviceLogContents = replaceLogPaths(serviceLogContents); + let aryLogContents = serviceLogContents.split("\n"); + logTestInfo("contents of " + serviceLog.path + ":"); + aryLogContents.forEach(function RU_LC_FE(aLine) { + logTestInfo(aLine); + }); + } else { + logTestInfo("maintenance service log doesn't exist, path: " + + serviceLog.path); + } + } +} + +/** + * Gets the maintenance service log contents. + */ +function readServiceLogFile() { + let file = getMaintSvcDir(); + file.append("logs"); + file.append("maintenanceservice.log"); + return readFile(file); +} + +/** + * Launches the updater binary to apply an update for updater tests. + * + * @param aExpectedStatus + * The expected value of update.status when the test finishes. For + * service tests passing STATE_PENDING or STATE_APPLIED will change the + * value to STATE_PENDING_SVC and STATE_APPLIED_SVC respectively. + * @param aSwitchApp + * If true the update should switch the application with an updated + * staged application and if false the update should be applied to the + * installed application. + * @param aExpectedExitValue + * The expected exit value from the updater binary for non-service + * tests. + * @param aCheckSvcLog + * Whether the service log should be checked for service tests. + * @param aPatchDirPath (optional) + * When specified the patch directory path to use for invalid argument + * tests otherwise the normal path will be used. + * @param aInstallDirPath (optional) + * When specified the install directory path to use for invalid + * argument tests otherwise the normal path will be used. + * @param aApplyToDirPath (optional) + * When specified the apply to / working directory path to use for + * invalid argument tests otherwise the normal path will be used. + * @param aCallbackPath (optional) + * When specified the callback path to use for invalid argument tests + * otherwise the normal path will be used. + */ +function runUpdate(aExpectedStatus, aSwitchApp, aExpectedExitValue, aCheckSvcLog, + aPatchDirPath, aInstallDirPath, aApplyToDirPath, + aCallbackPath) { + let isInvalidArgTest = !!aPatchDirPath || !!aInstallDirPath || + !!aApplyToDirPath || aCallbackPath; + + let svcOriginalLog; + if (IS_SERVICE_TEST) { + copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN, false); + copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, false); + if (aCheckSvcLog) { + svcOriginalLog = readServiceLogFile(); + } + } + + // Copy the updater binary to the directory where it will apply updates. + let updateBin = copyTestUpdaterForRunUsingUpdater(); + Assert.ok(updateBin.exists(), + MSG_SHOULD_EXIST + getMsgPath(updateBin.path)); + + let updatesDirPath = aPatchDirPath || getUpdatesPatchDir().path; + let installDirPath = aInstallDirPath || getApplyDirFile(null, true).path; + let applyToDirPath = aApplyToDirPath || getApplyDirFile(null, true).path; + let stageDirPath = aApplyToDirPath || getStageDirFile(null, true).path; + + let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile); + callbackApp.permissions = PERMS_DIRECTORY; + + setAppBundleModTime(); + + let args = [updatesDirPath, installDirPath]; + if (aSwitchApp) { + args[2] = stageDirPath; + args[3] = "0/replace"; + } else { + args[2] = applyToDirPath; + args[3] = "0"; + } + + let launchBin = IS_SERVICE_TEST && isInvalidArgTest ? callbackApp : updateBin; + + if (!isInvalidArgTest) { + args = args.concat([callbackApp.parent.path, callbackApp.path]); + args = args.concat(gCallbackArgs); + } else if (IS_SERVICE_TEST) { + args = ["launch-service", updateBin.path].concat(args); + } else if (aCallbackPath) { + args = args.concat([callbackApp.parent.path, aCallbackPath]); + } + + debugDump("launching the program: " + launchBin.path + " " + args.join(" ")); + + if (aSwitchApp && !isInvalidArgTest) { + // We want to set the env vars again + gShouldResetEnv = undefined; + } + + setEnvironment(); + + let process = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + process.init(launchBin); + process.run(true, args, args.length); + + resetEnvironment(); + + let status = readStatusFile(); + if ((!IS_SERVICE_TEST && process.exitValue != aExpectedExitValue) || + status != aExpectedStatus) { + if (process.exitValue != aExpectedExitValue) { + logTestInfo("updater exited with unexpected value! Got: " + + process.exitValue + ", Expected: " + aExpectedExitValue); + } + if (status != aExpectedStatus) { + logTestInfo("update status is not the expected status! Got: " + status + + ", Expected: " + aExpectedStatus); + } + logUpdateLog(FILE_LAST_UPDATE_LOG); + } + + if (!IS_SERVICE_TEST) { + Assert.equal(process.exitValue, aExpectedExitValue, + "the process exit value" + MSG_SHOULD_EQUAL); + } + Assert.equal(status, aExpectedStatus, + "the update status" + MSG_SHOULD_EQUAL); + + if (IS_SERVICE_TEST && aCheckSvcLog) { + let contents = readServiceLogFile(); + Assert.notEqual(contents, svcOriginalLog, + "the contents of the maintenanceservice.log should not " + + "be the same as the original contents"); + if (!isInvalidArgTest) { + Assert.notEqual(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1, + "the contents of the maintenanceservice.log should " + + "contain the successful launch string"); + } + } + + do_execute_soon(runUpdateFinished); +} + +/** + * Launches the helper binary synchronously with the specified arguments for + * updater tests. + * + * @param aArgs + * The arguments to pass to the helper binary. + * @return the process exit value returned by the helper binary. + */ +function runTestHelperSync(aArgs) { + let helperBin = getTestDirFile(FILE_HELPER_BIN); + let process = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + process.init(helperBin); + debugDump("Running " + helperBin.path + " " + aArgs.join(" ")); + process.run(true, aArgs, aArgs.length); + return process.exitValue; +} + +/** + * Creates a symlink for updater tests. + */ +function createSymlink() { + let args = ["setup-symlink", "moz-foo", "moz-bar", "target", + getApplyDirFile().path + "/" + DIR_RESOURCES + "link"]; + let exitValue = runTestHelperSync(args); + Assert.equal(exitValue, 0, + "the helper process exit value should be 0"); + getApplyDirFile(DIR_RESOURCES + "link", false).permissions = 0o666; + args = ["setup-symlink", "moz-foo2", "moz-bar2", "target2", + getApplyDirFile().path + "/" + DIR_RESOURCES + "link2", "change-perm"]; + exitValue = runTestHelperSync(args); + Assert.equal(exitValue, 0, + "the helper process exit value should be 0"); +} + +/** + * Removes a symlink for updater tests. + */ +function removeSymlink() { + let args = ["remove-symlink", "moz-foo", "moz-bar", "target", + getApplyDirFile().path + "/" + DIR_RESOURCES + "link"]; + let exitValue = runTestHelperSync(args); + Assert.equal(exitValue, 0, + "the helper process exit value should be 0"); + args = ["remove-symlink", "moz-foo2", "moz-bar2", "target2", + getApplyDirFile().path + "/" + DIR_RESOURCES + "link2"]; + exitValue = runTestHelperSync(args); + Assert.equal(exitValue, 0, + "the helper process exit value should be 0"); +} + +/** + * Checks a symlink for updater tests. + */ +function checkSymlink() { + let args = ["check-symlink", + getApplyDirFile().path + "/" + DIR_RESOURCES + "link"]; + let exitValue = runTestHelperSync(args); + Assert.equal(exitValue, 0, + "the helper process exit value should be 0"); +} + +/** + * Sets the active update and related information for updater tests. + */ +function setupActiveUpdate() { + let state = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + let channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); + let patches = getLocalPatchString(null, null, null, null, null, "true", + state); + let updates = getLocalUpdateString(patches, null, null, null, null, null, + null, null, null, null, "true", channel); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeVersionFile(DEFAULT_UPDATE_VERSION); + writeStatusFile(state); + reloadUpdateManagerData(); + Assert.ok(!!gUpdateManager.activeUpdate, + "the active update should be defined"); +} + +/** + * Gets the specified update log. + * + * @param aLogLeafName + * The leaf name of the log to get. + * @return nsIFile for the update log. + */ +function getUpdateLog(aLogLeafName) { + let updateLog = getUpdatesDir(); + if (aLogLeafName == FILE_UPDATE_LOG) { + updateLog.append(DIR_PATCH); + } + updateLog.append(aLogLeafName); + return updateLog; +} + +/** + * The update-staged observer for the call to nsIUpdateProcessor:processUpdate. + */ +const gUpdateStagedObserver = { + observe: function(aSubject, aTopic, aData) { + debugDump("observe called with topic: " + aTopic + ", data: " + aData); + if (aTopic == "update-staged") { + Services.obs.removeObserver(gUpdateStagedObserver, "update-staged"); + // The environment is reset after the update-staged observer topic because + // processUpdate in nsIUpdateProcessor uses a new thread and clearing the + // environment immediately after calling processUpdate can clear the + // environment before the updater is launched. + resetEnvironment(); + // Use do_execute_soon to prevent any failures from propagating to the + // update service. + do_execute_soon(checkUpdateStagedState.bind(null, aData)); + } + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) +}; + +/** + * Stages an update using nsIUpdateProcessor:processUpdate for updater tests. + * + * @param aCheckSvcLog + * Whether the service log should be checked for service tests. + */ +function stageUpdate(aCheckSvcLog) { + debugDump("start - attempting to stage update"); + + if (IS_SERVICE_TEST && aCheckSvcLog) { + gSvcOriginalLogContents = readServiceLogFile(); + } + + Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false); + + setAppBundleModTime(); + setEnvironment(); + // Stage the update. + Cc["@mozilla.org/updates/update-processor;1"]. + createInstance(Ci.nsIUpdateProcessor). + processUpdate(gUpdateManager.activeUpdate); + + // The environment is not reset here because processUpdate in + // nsIUpdateProcessor uses a new thread and clearing the environment + // immediately after calling processUpdate can clear the environment before + // the updater is launched. Instead it is reset after the update-staged + // observer topic. + + debugDump("finish - attempting to stage update"); +} + +/** + * Checks that the update state is correct as well as the expected files are + * present after staging and update for updater tests and then calls + * stageUpdateFinished. + * + * @param aUpdateState + * The update state received by the observer notification. + */ +function checkUpdateStagedState(aUpdateState) { + if (IS_WIN) { + if (IS_SERVICE_TEST) { + waitForServiceStop(false); + } else { + let updater = getApplyDirFile(FILE_UPDATER_BIN, true); + if (isFileInUse(updater)) { + do_timeout(FILE_IN_USE_TIMEOUT_MS, + checkUpdateStagedState.bind(null, aUpdateState)); + return; + } + } + } + + Assert.equal(aUpdateState, STATE_AFTER_STAGE, + "the notified state" + MSG_SHOULD_EQUAL); + + if (!gStagingRemovedUpdate) { + Assert.equal(readStatusState(), STATE_AFTER_STAGE, + "the status file state" + MSG_SHOULD_EQUAL); + + Assert.equal(gUpdateManager.activeUpdate.state, STATE_AFTER_STAGE, + "the update state" + MSG_SHOULD_EQUAL); + } + + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_STAGE, + "the update state" + MSG_SHOULD_EQUAL); + + let log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + let stageDir = getStageDirFile(null, true); + if (STATE_AFTER_STAGE == STATE_APPLIED || + STATE_AFTER_STAGE == STATE_APPLIED_SVC) { + Assert.ok(stageDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(stageDir.path)); + } else { + Assert.ok(!stageDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(stageDir.path)); + } + + if (IS_SERVICE_TEST && gSvcOriginalLogContents !== undefined) { + let contents = readServiceLogFile(); + Assert.notEqual(contents, gSvcOriginalLogContents, + "the contents of the maintenanceservice.log should not " + + "be the same as the original contents"); + Assert.notEqual(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1, + "the contents of the maintenanceservice.log should " + + "contain the successful launch string"); + } + + do_execute_soon(stageUpdateFinished); +} + +/** + * Helper function to check whether the maintenance service updater tests should + * run. See bug 711660 for more details. + * + * @return true if the test should run and false if it shouldn't. + */ +function shouldRunServiceTest() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let binDir = getGREBinDir(); + let updaterBin = binDir.clone(); + updaterBin.append(FILE_UPDATER_BIN); + Assert.ok(updaterBin.exists(), + MSG_SHOULD_EXIST + ", leafName: " + updaterBin.leafName); + + let updaterBinPath = updaterBin.path; + if (/ /.test(updaterBinPath)) { + updaterBinPath = '"' + updaterBinPath + '"'; + } + + let isBinSigned = isBinarySigned(updaterBinPath); + + const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" + + "3932ecacee736d366d6436db0f55bce4"; + let key = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + try { + key.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, + Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64); + } catch (e) { + // The build system could sign the files and not have the test registry key + // in which case we should fail the test if the updater binary is signed so + // the build system can be fixed by adding the registry key. + if (IS_AUTHENTICODE_CHECK_ENABLED) { + Assert.ok(!isBinSigned, + "the updater.exe binary should not be signed when the test " + + "registry key doesn't exist (if it is, build system " + + "configuration bug?)"); + } + + logTestInfo("this test can only run on the buildbot build system at this " + + "time"); + return false; + } + + // Check to make sure the service is installed + let args = ["wait-for-service-stop", "MozillaMaintenance", "10"]; + let exitValue = runTestHelperSync(args); + Assert.notEqual(exitValue, 0xEE, "the maintenance service should be " + + "installed (if not, build system configuration bug?)"); + + if (IS_AUTHENTICODE_CHECK_ENABLED) { + // The test registry key exists and IS_AUTHENTICODE_CHECK_ENABLED is true + // so the binaries should be signed. To run the test locally + // DISABLE_UPDATER_AUTHENTICODE_CHECK can be defined. + Assert.ok(isBinSigned, + "the updater.exe binary should be signed (if not, build system " + + "configuration bug?)"); + } + + // In case the machine is running an old maintenance service or if it + // is not installed, and permissions exist to install it. Then install + // the newer bin that we have since all of the other checks passed. + return attemptServiceInstall(); +} + +/** + * Helper function to check whether the a binary is signed. + * + * @param aBinPath + * The path to the file to check if it is signed. + * @return true if the file is signed and false if it isn't. + */ +function isBinarySigned(aBinPath) { + let args = ["check-signature", aBinPath]; + let exitValue = runTestHelperSync(args); + if (exitValue != 0) { + logTestInfo("binary is not signed. " + FILE_HELPER_BIN + " returned " + + exitValue + " for file " + aBinPath); + return false; + } + return true; +} + +/** + * Helper function for asynchronously setting up the application files required + * to launch the application for the updater tests by either copying or creating + * symlinks for the files. This is needed for Windows debug builds which can + * lock a file that is being copied so that the tests can run in parallel. After + * the files have been copied the setupUpdaterTestFinished function will be + * called. + */ +function setupAppFilesAsync() { + gTimeoutRuns++; + try { + setupAppFiles(); + } catch (e) { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while trying to setup application " + + "files! Exception: " + e); + } + do_execute_soon(setupAppFilesAsync); + return; + } + + do_execute_soon(setupUpdaterTestFinished); +} + +/** + * Helper function for setting up the application files required to launch the + * application for the updater tests by either copying or creating symlinks to + * the files. + */ +function setupAppFiles() { + debugDump("start - copying or creating symlinks to application files " + + "for the test"); + + let destDir = getApplyDirFile(null, true); + if (!destDir.exists()) { + try { + destDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } catch (e) { + logTestInfo("unable to create directory! Path: " + destDir.path + + ", Exception: " + e); + do_throw(e); + } + } + + // Required files for the application or the test that aren't listed in the + // dependentlibs.list file. + let appFiles = [{relPath: FILE_APP_BIN, + inGreDir: false}, + {relPath: FILE_APPLICATION_INI, + inGreDir: true}, + {relPath: "dependentlibs.list", + inGreDir: true}]; + + // On Linux the updater.png must also be copied + if (IS_UNIX && !IS_MACOSX) { + appFiles.push({relPath: "icons/updater.png", + inGreDir: true}); + } + + // Read the dependent libs file leafnames from the dependentlibs.list file + // into the array. + let deplibsFile = gGREDirOrig.clone(); + deplibsFile.append("dependentlibs.list"); + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + fis.init(deplibsFile, 0x01, 0o444, Ci.nsIFileInputStream.CLOSE_ON_EOF); + fis.QueryInterface(Ci.nsILineInputStream); + + let hasMore; + let line = {}; + do { + hasMore = fis.readLine(line); + appFiles.push({relPath: line.value, + inGreDir: false}); + } while (hasMore); + + fis.close(); + + appFiles.forEach(function CMAF_FLN_FE(aAppFile) { + copyFileToTestAppDir(aAppFile.relPath, aAppFile.inGreDir); + }); + + copyTestUpdaterToBinDir(); + + debugDump("finish - copying or creating symlinks to application files " + + "for the test"); +} + +/** + * Copies the specified files from the dist/bin directory into the test's + * application directory. + * + * @param aFileRelPath + * The relative path to the source and the destination of the file to + * copy. + * @param aInGreDir + * Whether the file is located in the GRE directory which is + * <bundle>/Contents/Resources on Mac OS X and is the installation + * directory on all other platforms. If false the file must be in the + * GRE Binary directory which is <bundle>/Contents/MacOS on Mac OS X + * and is the installation directory on on all other platforms. + */ +function copyFileToTestAppDir(aFileRelPath, aInGreDir) { + // gGREDirOrig and gGREBinDirOrig must always be cloned when changing its + // properties + let srcFile = aInGreDir ? gGREDirOrig.clone() : gGREBinDirOrig.clone(); + let destFile = aInGreDir ? getGREDir() : getGREBinDir(); + let fileRelPath = aFileRelPath; + let pathParts = fileRelPath.split("/"); + for (let i = 0; i < pathParts.length; i++) { + if (pathParts[i]) { + srcFile.append(pathParts[i]); + destFile.append(pathParts[i]); + } + } + + if (IS_MACOSX && !srcFile.exists()) { + debugDump("unable to copy file since it doesn't exist! Checking if " + + fileRelPath + ".app exists. Path: " + srcFile.path); + // gGREDirOrig and gGREBinDirOrig must always be cloned when changing its + // properties + srcFile = aInGreDir ? gGREDirOrig.clone() : gGREBinDirOrig.clone(); + destFile = aInGreDir ? getGREDir() : getGREBinDir(); + for (let i = 0; i < pathParts.length; i++) { + if (pathParts[i]) { + srcFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : "")); + destFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : "")); + } + } + fileRelPath = fileRelPath + ".app"; + } + Assert.ok(srcFile.exists(), + MSG_SHOULD_EXIST + ", leafName: " + srcFile.leafName); + + // Symlink libraries. Note that the XUL library on Mac OS X doesn't have a + // file extension and shouldSymlink will always be false on Windows. + let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" || + fileRelPath.substr(fileRelPath.length - 3) == ".so" || + fileRelPath.substr(fileRelPath.length - 6) == ".dylib"); + if (!shouldSymlink) { + if (!destFile.exists()) { + try { + srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName); + } catch (e) { + // Just in case it is partially copied + if (destFile.exists()) { + try { + destFile.remove(true); + } catch (ex) { + logTestInfo("unable to remove file that failed to copy! Path: " + + destFile.path); + } + } + do_throw("Unable to copy file! Path: " + srcFile.path + + ", Exception: " + ex); + } + } + } else { + try { + if (destFile.exists()) { + destFile.remove(false); + } + let ln = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); + ln.initWithPath("/bin/ln"); + let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); + process.init(ln); + let args = ["-s", srcFile.path, destFile.path]; + process.run(true, args, args.length); + Assert.ok(destFile.isSymlink(), + destFile.leafName + " should be a symlink"); + } catch (e) { + do_throw("Unable to create symlink for file! Path: " + srcFile.path + + ", Exception: " + e); + } + } +} + +/** + * Attempts to upgrade the maintenance service if permissions are allowed. + * This is useful for XP where we have permission to upgrade in case an + * older service installer exists. Also if the user manually installed into + * a unprivileged location. + * + * @return true if the installed service is from this build. If the installed + * service is not from this build the test will fail instead of + * returning false. + */ +function attemptServiceInstall() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let maintSvcDir = getMaintSvcDir(); + Assert.ok(maintSvcDir.exists(), + MSG_SHOULD_EXIST + ", leafName: " + maintSvcDir.leafName); + let oldMaintSvcBin = maintSvcDir.clone(); + oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); + Assert.ok(oldMaintSvcBin.exists(), + MSG_SHOULD_EXIST + ", leafName: " + oldMaintSvcBin.leafName); + let buildMaintSvcBin = getGREBinDir(); + buildMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); + if (readFileBytes(oldMaintSvcBin) == readFileBytes(buildMaintSvcBin)) { + debugDump("installed maintenance service binary is the same as the " + + "build's maintenance service binary"); + return true; + } + let backupMaintSvcBin = maintSvcDir.clone(); + backupMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN + ".backup"); + try { + if (backupMaintSvcBin.exists()) { + backupMaintSvcBin.remove(false); + } + oldMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN + ".backup"); + buildMaintSvcBin.copyTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN); + backupMaintSvcBin.remove(false); + } catch (e) { + // Restore the original file in case the moveTo was successful. + if (backupMaintSvcBin.exists()) { + oldMaintSvcBin = maintSvcDir.clone(); + oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); + if (!oldMaintSvcBin.exists()) { + backupMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN); + } + } + Assert.ok(false, "should be able copy the test maintenance service to " + + "the maintenance service directory (if not, build system " + + "configuration bug?), path: " + maintSvcDir.path); + } + + return true; +} + +/** + * Waits for the applications that are launched by the maintenance service to + * stop. + */ +function waitServiceApps() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + // maintenanceservice_installer.exe is started async during updates. + waitForApplicationStop("maintenanceservice_installer.exe"); + // maintenanceservice_tmp.exe is started async from the service installer. + waitForApplicationStop("maintenanceservice_tmp.exe"); + // In case the SCM thinks the service is stopped, but process still exists. + waitForApplicationStop("maintenanceservice.exe"); +} + +/** + * Waits for the maintenance service to stop. + */ +function waitForServiceStop(aFailTest) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + waitServiceApps(); + debugDump("waiting for the maintenance service to stop if necessary"); + // Use the helper bin to ensure the service is stopped. If not stopped, then + // wait for the service to stop (at most 120 seconds). + let args = ["wait-for-service-stop", "MozillaMaintenance", "120"]; + let exitValue = runTestHelperSync(args); + Assert.notEqual(exitValue, 0xEE, + "the maintenance service should exist"); + if (exitValue != 0) { + if (aFailTest) { + Assert.ok(false, "the maintenance service should stop, process exit " + + "value: " + exitValue); + } + logTestInfo("maintenance service did not stop which may cause test " + + "failures later, process exit value: " + exitValue); + } else { + debugDump("service stopped"); + } + waitServiceApps(); +} + +/** + * Waits for the specified application to stop. + * + * @param aApplication + * The application binary name to wait until it has stopped. + */ +function waitForApplicationStop(aApplication) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + debugDump("waiting for " + aApplication + " to stop if necessary"); + // Use the helper bin to ensure the application is stopped. If not stopped, + // then wait for it to stop (at most 120 seconds). + let args = ["wait-for-application-exit", aApplication, "120"]; + let exitValue = runTestHelperSync(args); + Assert.equal(exitValue, 0, + "the process should have stopped, process name: " + + aApplication); +} + + +/** + * Gets the platform specific shell binary that is launched using nsIProcess and + * in turn launches a binary used for the test (e.g. application, updater, + * etc.). A shell is used so debug console output can be redirected to a file so + * it doesn't end up in the test log. + * + * @return nsIFile for the shell binary to launch using nsIProcess. + */ +function getLaunchBin() { + let launchBin; + if (IS_WIN) { + launchBin = Services.dirsvc.get("WinD", Ci.nsIFile); + launchBin.append("System32"); + launchBin.append("cmd.exe"); + } else { + launchBin = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + launchBin.initWithPath("/bin/sh"); + } + Assert.ok(launchBin.exists(), + MSG_SHOULD_EXIST + getMsgPath(launchBin.path)); + + return launchBin; +} + + +/** + * Locks a Windows directory. + * + * @param aDirPath + * The test file object that describes the file to make in use. + */ +function lockDirectory(aDirPath) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + debugDump("start - locking installation directory"); + const LPCWSTR = ctypes.char16_t.ptr; + const DWORD = ctypes.uint32_t; + const LPVOID = ctypes.voidptr_t; + const GENERIC_READ = 0x80000000; + const FILE_SHARE_READ = 1; + const FILE_SHARE_WRITE = 2; + const OPEN_EXISTING = 3; + const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; + const INVALID_HANDLE_VALUE = LPVOID(0xffffffff); + let kernel32 = ctypes.open("kernel32"); + let CreateFile = kernel32.declare("CreateFileW", ctypes.default_abi, + LPVOID, LPCWSTR, DWORD, DWORD, + LPVOID, DWORD, DWORD, LPVOID); + gHandle = CreateFile(aDirPath, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, LPVOID(0), + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, LPVOID(0)); + Assert.notEqual(gHandle.toString(), INVALID_HANDLE_VALUE.toString(), + "the handle should not equal INVALID_HANDLE_VALUE"); + kernel32.close(); + debugDump("finish - locking installation directory"); +} + +/** + * Launches the test helper binary to make it in use for updater tests and then + * calls waitForHelperSleep. + * + * @param aTestFile + * The test file object that describes the file to make in use. + */ +function runHelperFileInUse(aRelPath, aCopyTestHelper) { + logTestInfo("aRelPath: " + aRelPath); + // Launch an existing file so it is in use during the update. + let helperBin = getTestDirFile(FILE_HELPER_BIN); + let fileInUseBin = getApplyDirFile(aRelPath); + if (aCopyTestHelper) { + fileInUseBin.remove(false); + helperBin.copyTo(fileInUseBin.parent, fileInUseBin.leafName); + } + fileInUseBin.permissions = PERMS_DIRECTORY; + let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", + HELPER_SLEEP_TIMEOUT]; + let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + fileInUseProcess.init(fileInUseBin); + fileInUseProcess.run(false, args, args.length); + + do_execute_soon(waitForHelperSleep); +} + +/** + * Launches the test helper binary and locks a file specified on the command + * line for updater tests and then calls waitForHelperSleep. + * + * @param aTestFile + * The test file object that describes the file to lock. + */ +function runHelperLockFile(aTestFile) { + // Exclusively lock an existing file so it is in use during the update. + let helperBin = getTestDirFile(FILE_HELPER_BIN); + let helperDestDir = getApplyDirFile(DIR_RESOURCES); + helperBin.copyTo(helperDestDir, FILE_HELPER_BIN); + helperBin = getApplyDirFile(DIR_RESOURCES + FILE_HELPER_BIN); + // Strip off the first two directories so the path has to be from the helper's + // working directory. + let lockFileRelPath = aTestFile.relPathDir.split("/"); + if (IS_MACOSX) { + lockFileRelPath = lockFileRelPath.slice(2); + } + lockFileRelPath = lockFileRelPath.join("/") + "/" + aTestFile.fileName; + let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", + HELPER_SLEEP_TIMEOUT, lockFileRelPath]; + let helperProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + helperProcess.init(helperBin); + helperProcess.run(false, args, args.length); + + do_execute_soon(waitForHelperSleep); +} + +/** + * Helper function that waits until the helper has completed its operations and + * calls waitForHelperSleepFinished when it is finished. + */ +function waitForHelperSleep() { + gTimeoutRuns++; + // Give the lock file process time to lock the file before updating otherwise + // this test can fail intermittently on Windows debug builds. + let output = getApplyDirFile(DIR_RESOURCES + "output", true); + if (readFile(output) != "sleeping\n") { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper to " + + "finish its operation. Path: " + output.path); + } + // Uses do_timeout instead of do_execute_soon to lessen log spew. + do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperSleep); + return; + } + try { + output.remove(false); + } catch (e) { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper " + + "message file to no longer be in use. Path: " + output.path); + } + debugDump("failed to remove file. Path: " + output.path); + // Uses do_timeout instead of do_execute_soon to lessen log spew. + do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperSleep); + return; + } + waitForHelperSleepFinished(); +} + +/** + * Helper function that waits until the helper has finished its operations + * before calling waitForHelperFinishFileUnlock to verify that the helper's + * input and output directories are no longer in use. + */ +function waitForHelperFinished() { + // Give the lock file process time to lock the file before updating otherwise + // this test can fail intermittently on Windows debug builds. + let output = getApplyDirFile(DIR_RESOURCES + "output", true); + if (readFile(output) != "finished\n") { + // Uses do_timeout instead of do_execute_soon to lessen log spew. + do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperFinished); + return; + } + // Give the lock file process time to unlock the file before deleting the + // input and output files. + waitForHelperFinishFileUnlock(); +} + +/** + * Helper function that waits until the helper's input and output files are no + * longer in use before calling waitForHelperExitFinished. + */ +function waitForHelperFinishFileUnlock() { + try { + let output = getApplyDirFile(DIR_RESOURCES + "output", true); + if (output.exists()) { + output.remove(false); + } + let input = getApplyDirFile(DIR_RESOURCES + "input", true); + if (input.exists()) { + input.remove(false); + } + } catch (e) { + // Give the lock file process time to unlock the file before deleting the + // input and output files. + do_execute_soon(waitForHelperFinishFileUnlock); + return; + } + do_execute_soon(waitForHelperExitFinished); +} + +/** + * Helper function to tell the helper to finish and exit its sleep state. + */ +function waitForHelperExit() { + let input = getApplyDirFile(DIR_RESOURCES + "input", true); + writeFile(input, "finish\n"); + waitForHelperFinished(); +} + +/** + * Helper function for updater binary tests that creates the files and + * directories used by the test. + * + * @param aMarFile + * The mar file for the update test. + * @param aPostUpdateAsync + * When null the updater.ini is not created otherwise this parameter + * is passed to createUpdaterINI. + * @param aPostUpdateExeRelPathPrefix + * When aPostUpdateAsync null this value is ignored otherwise it is + * passed to createUpdaterINI. + */ +function setupUpdaterTest(aMarFile, aPostUpdateAsync, + aPostUpdateExeRelPathPrefix = "") { + let updatesPatchDir = getUpdatesPatchDir(); + if (!updatesPatchDir.exists()) { + updatesPatchDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + // Copy the mar that will be applied + let mar = getTestDirFile(aMarFile); + mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_MAR); + + let helperBin = getTestDirFile(FILE_HELPER_BIN); + helperBin.permissions = PERMS_DIRECTORY; + let afterApplyBinDir = getApplyDirFile(DIR_RESOURCES, true); + helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile); + helperBin.copyToFollowingLinks(afterApplyBinDir, gPostUpdateBinFile); + + gTestFiles.forEach(function SUT_TF_FE(aTestFile) { + if (aTestFile.originalFile || aTestFile.originalContents) { + let testDir = getApplyDirFile(aTestFile.relPathDir, true); + if (!testDir.exists()) { + testDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + + let testFile; + if (aTestFile.originalFile) { + testFile = getTestDirFile(aTestFile.originalFile); + testFile.copyToFollowingLinks(testDir, aTestFile.fileName); + testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName); + } else { + testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName, + true); + writeFile(testFile, aTestFile.originalContents); + } + + // Skip these tests on Windows since chmod doesn't really set permissions + // on Windows. + if (!IS_WIN && aTestFile.originalPerms) { + testFile.permissions = aTestFile.originalPerms; + // Store the actual permissions on the file for reference later after + // setting the permissions. + if (!aTestFile.comparePerms) { + aTestFile.comparePerms = testFile.permissions; + } + } + } + }); + + // Add the test directory that will be updated for a successful update or left + // in the initial state for a failed update. + gTestDirs.forEach(function SUT_TD_FE(aTestDir) { + let testDir = getApplyDirFile(aTestDir.relPathDir, true); + if (!testDir.exists()) { + testDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + + if (aTestDir.files) { + aTestDir.files.forEach(function SUT_TD_F_FE(aTestFile) { + let testFile = getApplyDirFile(aTestDir.relPathDir + aTestFile, true); + if (!testFile.exists()) { + testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + }); + } + + if (aTestDir.subDirs) { + aTestDir.subDirs.forEach(function SUT_TD_SD_FE(aSubDir) { + let testSubDir = getApplyDirFile(aTestDir.relPathDir + aSubDir, true); + if (!testSubDir.exists()) { + testSubDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + + if (aTestDir.subDirFiles) { + aTestDir.subDirFiles.forEach(function SUT_TD_SDF_FE(aTestFile) { + let testFile = getApplyDirFile(aTestDir.relPathDir + aSubDir + aTestFile, true); + if (!testFile.exists()) { + testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + } + }); + } + }); + } + }); + + setupActiveUpdate(); + + if (aPostUpdateAsync !== null) { + createUpdaterINI(aPostUpdateAsync, aPostUpdateExeRelPathPrefix); + } + + setupAppFilesAsync(); +} + +/** + * Helper function for updater binary tests that creates the update-settings.ini + * file. + */ +function createUpdateSettingsINI() { + let ini = getApplyDirFile(DIR_RESOURCES + FILE_UPDATE_SETTINGS_INI, true); + writeFile(ini, UPDATE_SETTINGS_CONTENTS); +} + +/** + * Helper function for updater binary tests that creates the updater.ini + * file. + * + * @param aIsExeAsync + * True or undefined if the post update process should be async. If + * undefined ExeAsync will not be added to the updater.ini file in + * order to test the default launch behavior which is async. + * @param aExeRelPathPrefix + * A string to prefix the ExeRelPath values in the updater.ini. + */ +function createUpdaterINI(aIsExeAsync, aExeRelPathPrefix) { + let exeArg = "ExeArg=post-update-async\n"; + let exeAsync = ""; + if (aIsExeAsync !== undefined) { + if (aIsExeAsync) { + exeAsync = "ExeAsync=true\n"; + } else { + exeArg = "ExeArg=post-update-sync\n"; + exeAsync = "ExeAsync=false\n"; + } + } + + if (aExeRelPathPrefix && IS_WIN) { + aExeRelPathPrefix = aExeRelPathPrefix.replace("/", "\\"); + } + + let exeRelPathMac = "ExeRelPath=" + aExeRelPathPrefix + DIR_RESOURCES + + gPostUpdateBinFile + "\n"; + let exeRelPathWin = "ExeRelPath=" + aExeRelPathPrefix + gPostUpdateBinFile + "\n"; + let updaterIniContents = "[Strings]\n" + + "Title=Update Test\n" + + "Info=Running update test " + gTestID + "\n\n" + + "[PostUpdateMac]\n" + + exeRelPathMac + + exeArg + + exeAsync + + "\n" + + "[PostUpdateWin]\n" + + exeRelPathWin + + exeArg + + exeAsync; + let updaterIni = getApplyDirFile(DIR_RESOURCES + FILE_UPDATER_INI, true); + writeFile(updaterIni, updaterIniContents); +} + +/** + * Gets the message log path used for assert checks to lessen the length printed + * to the log file. + * + * @param aPath + * The path to shorten for the log file. + * @return the message including the shortened path for the log file. + */ +function getMsgPath(aPath) { + return ", path: " + replaceLogPaths(aPath); +} + +/** + * Helper function that replaces the common part of paths in the update log's + * contents with <test_dir_path> for paths to the the test directory and + * <update_dir_path> for paths to the update directory. This is needed since + * Assert.equal will truncate what it prints to the xpcshell log file. + * + * @param aLogContents + * The update log file's contents. + * @return the log contents with the paths replaced. + */ +function replaceLogPaths(aLogContents) { + let logContents = aLogContents; + // Remove the majority of the path up to the test directory. This is needed + // since Assert.equal won't print long strings to the test logs. + let testDirPath = do_get_file(gTestID, false).path; + if (IS_WIN) { + // Replace \\ with \\\\ so the regexp works. + testDirPath = testDirPath.replace(/\\/g, "\\\\"); + } + logContents = logContents.replace(new RegExp(testDirPath, "g"), + "<test_dir_path>/" + gTestID); + let updatesDirPath = getMockUpdRootD().path; + if (IS_WIN) { + // Replace \\ with \\\\ so the regexp works. + updatesDirPath = updatesDirPath.replace(/\\/g, "\\\\"); + } + logContents = logContents.replace(new RegExp(updatesDirPath, "g"), + "<update_dir_path>/" + gTestID); + if (IS_WIN) { + // Replace \ with / + logContents = logContents.replace(/\\/g, "/"); + } + return logContents; +} + +/** + * Helper function for updater binary tests for verifying the contents of the + * update log after a successful update. + * + * @param aCompareLogFile + * The log file to compare the update log with. + * @param aStaged + * If the update log file is for a staged update. + * @param aReplace + * If the update log file is for a replace update. + * @param aExcludeDistDir + * Removes lines containing the distribution directory from the log + * file to compare the update log with. + */ +function checkUpdateLogContents(aCompareLogFile, aStaged = false, + aReplace = false, aExcludeDistDir = false) { + if (IS_UNIX && !IS_MACOSX) { + // The order that files are returned when enumerating the file system on + // Linux is not deterministic so skip checking the logs. + return; + } + + let updateLog = getUpdateLog(FILE_LAST_UPDATE_LOG); + let updateLogContents = readFileBytes(updateLog); + + // The channel-prefs.js is defined in gTestFilesCommon which will always be + // located to the end of gTestFiles when it is present. + if (gTestFiles.length > 1 && + gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && + !gTestFiles[gTestFiles.length - 1].originalContents) { + updateLogContents = updateLogContents.replace(/.*defaults\/.*/g, ""); + } + + if (gTestFiles.length > 2 && + gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && + !gTestFiles[gTestFiles.length - 2].originalContents) { + updateLogContents = updateLogContents.replace(/.*update-settings.ini.*/g, ""); + } + + // Skip the source/destination lines since they contain absolute paths. + // These could be changed to relative paths using <test_dir_path> and + // <update_dir_path> + updateLogContents = updateLogContents.replace(/PATCH DIRECTORY.*/g, ""); + updateLogContents = updateLogContents.replace(/INSTALLATION DIRECTORY.*/g, ""); + updateLogContents = updateLogContents.replace(/WORKING DIRECTORY.*/g, ""); + // Skip lines that log failed attempts to open the callback executable. + updateLogContents = updateLogContents.replace(/NS_main: callback app file .*/g, ""); + + if (IS_MACOSX) { + // Skip lines that log moving the distribution directory for Mac v2 signing. + updateLogContents = updateLogContents.replace(/Moving old [^\n]*\nrename_file: .*/g, ""); + updateLogContents = updateLogContents.replace(/New distribution directory .*/g, ""); + } + + if (IS_WIN) { + // The FindFile results when enumerating the filesystem on Windows is not + // determistic so the results matching the following need to be fixed. + let re = new RegExp("([^\n]* 7\/7text1[^\n]*)\n" + + "([^\n]* 7\/7text0[^\n]*)\n", "g"); + updateLogContents = updateLogContents.replace(re, "$2\n$1\n"); + } + + if (aReplace) { + // Remove the lines which contain absolute paths + updateLogContents = updateLogContents.replace(/^Begin moving.*$/mg, ""); + updateLogContents = updateLogContents.replace(/^ensure_remove: failed to remove file: .*$/mg, ""); + updateLogContents = updateLogContents.replace(/^ensure_remove_recursive: unable to remove directory: .*$/mg, ""); + updateLogContents = updateLogContents.replace(/^Removing tmpDir failed, err: -1$/mg, ""); + updateLogContents = updateLogContents.replace(/^remove_recursive_on_reboot: .*$/mg, ""); + } + + // Remove carriage returns. + updateLogContents = updateLogContents.replace(/\r/g, ""); + // Replace error codes since they are different on each platform. + updateLogContents = updateLogContents.replace(/, err:.*\n/g, "\n"); + // Replace to make the log parsing happy. + updateLogContents = updateLogContents.replace(/non-fatal error /g, ""); + // Remove consecutive newlines + updateLogContents = updateLogContents.replace(/\n+/g, "\n"); + // Remove leading and trailing newlines + updateLogContents = updateLogContents.replace(/^\n|\n$/g, ""); + // Replace the log paths with <test_dir_path> and <update_dir_path> + updateLogContents = replaceLogPaths(updateLogContents); + + let compareLogContents = ""; + if (aCompareLogFile) { + compareLogContents = readFileBytes(getTestDirFile(aCompareLogFile)); + } + + if (aStaged) { + compareLogContents = PERFORMING_STAGED_UPDATE + "\n" + compareLogContents; + } + + // The channel-prefs.js is defined in gTestFilesCommon which will always be + // located to the end of gTestFiles. + if (gTestFiles.length > 1 && + gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && + !gTestFiles[gTestFiles.length - 1].originalContents) { + compareLogContents = compareLogContents.replace(/.*defaults\/.*/g, ""); + } + + if (gTestFiles.length > 2 && + gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && + !gTestFiles[gTestFiles.length - 2].originalContents) { + compareLogContents = compareLogContents.replace(/.*update-settings.ini.*/g, ""); + } + + if (aExcludeDistDir) { + compareLogContents = compareLogContents.replace(/.*distribution\/.*/g, ""); + } + + // Remove leading and trailing newlines + compareLogContents = compareLogContents.replace(/\n+/g, "\n"); + // Remove leading and trailing newlines + compareLogContents = compareLogContents.replace(/^\n|\n$/g, ""); + + // Don't write the contents of the file to the log to reduce log spam + // unless there is a failure. + if (compareLogContents == updateLogContents) { + Assert.ok(true, "the update log contents" + MSG_SHOULD_EQUAL); + } else { + logTestInfo("the update log contents are not correct"); + logUpdateLog(FILE_LAST_UPDATE_LOG); + let aryLog = updateLogContents.split("\n"); + let aryCompare = compareLogContents.split("\n"); + // Pushing an empty string to both arrays makes it so either array's length + // can be used in the for loop below without going out of bounds. + aryLog.push(""); + aryCompare.push(""); + // xpcshell tests won't display the entire contents so log the first + // incorrect line. + for (let i = 0; i < aryLog.length; ++i) { + if (aryLog[i] != aryCompare[i]) { + logTestInfo("the first incorrect line in the update log is: " + + aryLog[i]); + Assert.equal(aryLog[i], aryCompare[i], + "the update log contents" + MSG_SHOULD_EQUAL); + } + } + // This should never happen! + do_throw("Unable to find incorrect update log contents!"); + } +} + +/** + * Helper function to check if the update log contains a string. + * + * @param aCheckString + * The string to check if the update log contains. + */ +function checkUpdateLogContains(aCheckString) { + let updateLog = getUpdateLog(FILE_LAST_UPDATE_LOG); + let updateLogContents = readFileBytes(updateLog).replace(/\r\n/g, "\n"); + updateLogContents = replaceLogPaths(updateLogContents); + Assert.notEqual(updateLogContents.indexOf(aCheckString), -1, + "the update log contents should contain value: " + + aCheckString); +} + +/** + * Helper function for updater binary tests for verifying the state of files and + * directories after a successful update. + * + * @param aGetFileFunc + * The function used to get the files in the directory to be checked. + * @param aStageDirExists + * If true the staging directory will be tested for existence and if + * false the staging directory will be tested for non-existence. + * @param aToBeDeletedDirExists + * On Windows, if true the tobedeleted directory will be tested for + * existence and if false the tobedeleted directory will be tested for + * non-existence. On all othere platforms it will be tested for + * non-existence. + */ +function checkFilesAfterUpdateSuccess(aGetFileFunc, aStageDirExists = false, + aToBeDeletedDirExists = false) { + debugDump("testing contents of files after a successful update"); + gTestFiles.forEach(function CFAUS_TF_FE(aTestFile) { + let testFile = aGetFileFunc(aTestFile.relPathDir + aTestFile.fileName, true); + debugDump("testing file: " + testFile.path); + if (aTestFile.compareFile || aTestFile.compareContents) { + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + // Skip these tests on Windows since chmod doesn't really set permissions + // on Windows. + if (!IS_WIN && aTestFile.comparePerms) { + // Check if the permssions as set in the complete mar file are correct. + Assert.equal(testFile.permissions & 0xfff, + aTestFile.comparePerms & 0xfff, + "the file permissions" + MSG_SHOULD_EQUAL); + } + + let fileContents1 = readFileBytes(testFile); + let fileContents2 = aTestFile.compareFile ? + readFileBytes(getTestDirFile(aTestFile.compareFile)) : + aTestFile.compareContents; + // Don't write the contents of the file to the log to reduce log spam + // unless there is a failure. + if (fileContents1 == fileContents2) { + Assert.ok(true, "the file contents" + MSG_SHOULD_EQUAL); + } else { + Assert.equal(fileContents1, fileContents2, + "the file contents" + MSG_SHOULD_EQUAL); + } + } else { + Assert.ok(!testFile.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(testFile.path)); + } + }); + + debugDump("testing operations specified in removed-files were performed " + + "after a successful update"); + gTestDirs.forEach(function CFAUS_TD_FE(aTestDir) { + let testDir = aGetFileFunc(aTestDir.relPathDir, true); + debugDump("testing directory: " + testDir.path); + if (aTestDir.dirRemoved) { + Assert.ok(!testDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(testDir.path)); + } else { + Assert.ok(testDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(testDir.path)); + + if (aTestDir.files) { + aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) { + let testFile = aGetFileFunc(aTestDir.relPathDir + aTestFile, true); + if (aTestDir.filesRemoved) { + Assert.ok(!testFile.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(testFile.path)); + } else { + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + } + }); + } + + if (aTestDir.subDirs) { + aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) { + let testSubDir = aGetFileFunc(aTestDir.relPathDir + aSubDir, true); + Assert.ok(testSubDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(testSubDir.path)); + if (aTestDir.subDirFiles) { + aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) { + let testFile = aGetFileFunc(aTestDir.relPathDir + + aSubDir + aTestFile, true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + }); + } + }); + } + } + }); + + checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, + aToBeDeletedDirExists); +} + +/** + * Helper function for updater binary tests for verifying the state of files and + * directories after a failed update. + * + * @param aGetFileFunc + * The function used to get the files in the directory to be checked. + * @param aStageDirExists + * If true the staging directory will be tested for existence and if + * false the staging directory will be tested for non-existence. + * @param aToBeDeletedDirExists + * On Windows, if true the tobedeleted directory will be tested for + * existence and if false the tobedeleted directory will be tested for + * non-existence. On all othere platforms it will be tested for + * non-existence. + */ +function checkFilesAfterUpdateFailure(aGetFileFunc, aStageDirExists = false, + aToBeDeletedDirExists = false) { + debugDump("testing contents of files after a failed update"); + gTestFiles.forEach(function CFAUF_TF_FE(aTestFile) { + let testFile = aGetFileFunc(aTestFile.relPathDir + aTestFile.fileName, true); + debugDump("testing file: " + testFile.path); + if (aTestFile.compareFile || aTestFile.compareContents) { + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + // Skip these tests on Windows since chmod doesn't really set permissions + // on Windows. + if (!IS_WIN && aTestFile.comparePerms) { + // Check the original permssions are retained on the file. + Assert.equal(testFile.permissions & 0xfff, + aTestFile.comparePerms & 0xfff, + "the file permissions" + MSG_SHOULD_EQUAL); + } + + let fileContents1 = readFileBytes(testFile); + let fileContents2 = aTestFile.compareFile ? + readFileBytes(getTestDirFile(aTestFile.compareFile)) : + aTestFile.compareContents; + // Don't write the contents of the file to the log to reduce log spam + // unless there is a failure. + if (fileContents1 == fileContents2) { + Assert.ok(true, "the file contents" + MSG_SHOULD_EQUAL); + } else { + Assert.equal(fileContents1, fileContents2, + "the file contents" + MSG_SHOULD_EQUAL); + } + } else { + Assert.ok(!testFile.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(testFile.path)); + } + }); + + debugDump("testing operations specified in removed-files were not " + + "performed after a failed update"); + gTestDirs.forEach(function CFAUF_TD_FE(aTestDir) { + let testDir = aGetFileFunc(aTestDir.relPathDir, true); + Assert.ok(testDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(testDir.path)); + + if (aTestDir.files) { + aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) { + let testFile = aGetFileFunc(aTestDir.relPathDir + aTestFile, true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + }); + } + + if (aTestDir.subDirs) { + aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) { + let testSubDir = aGetFileFunc(aTestDir.relPathDir + aSubDir, true); + Assert.ok(testSubDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(testSubDir.path)); + if (aTestDir.subDirFiles) { + aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) { + let testFile = aGetFileFunc(aTestDir.relPathDir + + aSubDir + aTestFile, true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + }); + } + }); + } + }); + + checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, + aToBeDeletedDirExists); +} + +/** + * Helper function for updater binary tests for verifying the state of common + * files and directories after a successful or failed update. + * + * @param aGetFileFunc + * the function used to get the files in the directory to be checked. + * @param aStageDirExists + * If true the staging directory will be tested for existence and if + * false the staging directory will be tested for non-existence. + * @param aToBeDeletedDirExists + * On Windows, if true the tobedeleted directory will be tested for + * existence and if false the tobedeleted directory will be tested for + * non-existence. On all othere platforms it will be tested for + * non-existence. + */ +function checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, + aToBeDeletedDirExists) { + debugDump("testing extra directories"); + let stageDir = getStageDirFile(null, true); + if (aStageDirExists) { + Assert.ok(stageDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(stageDir.path)); + } else { + Assert.ok(!stageDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(stageDir.path)); + } + + let toBeDeletedDirExists = IS_WIN ? aToBeDeletedDirExists : false; + let toBeDeletedDir = getApplyDirFile(DIR_TOBEDELETED, true); + if (toBeDeletedDirExists) { + Assert.ok(toBeDeletedDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(toBeDeletedDir.path)); + } else { + Assert.ok(!toBeDeletedDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(toBeDeletedDir.path)); + } + + let updatingDir = getApplyDirFile("updating", true); + Assert.ok(!updatingDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(updatingDir.path)); + + if (stageDir.exists()) { + updatingDir = stageDir.clone(); + updatingDir.append("updating"); + Assert.ok(!updatingDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(updatingDir.path)); + } + + debugDump("testing backup files should not be left behind in the " + + "application directory"); + let applyToDir = getApplyDirFile(null, true); + checkFilesInDirRecursive(applyToDir, checkForBackupFiles); + + if (stageDir.exists()) { + debugDump("testing backup files should not be left behind in the " + + "staging directory"); + applyToDir = getApplyDirFile(null, true); + checkFilesInDirRecursive(stageDir, checkForBackupFiles); + } +} + +/** + * Helper function for updater binary tests for verifying the contents of the + * updater callback application log which should contain the arguments passed to + * the callback application. + */ +function checkCallbackLog() { + let appLaunchLog = getApplyDirFile(DIR_RESOURCES + gCallbackArgs[1], true); + if (!appLaunchLog.exists()) { + // Uses do_timeout instead of do_execute_soon to lessen log spew. + do_timeout(FILE_IN_USE_TIMEOUT_MS, checkCallbackLog); + return; + } + + let expectedLogContents = gCallbackArgs.join("\n") + "\n"; + let logContents = readFile(appLaunchLog); + // It is possible for the log file contents check to occur before the log file + // contents are completely written so wait until the contents are the expected + // value. If the contents are never the expected value then the test will + // fail by timing out after gTimeoutRuns is greater than MAX_TIMEOUT_RUNS or + // the test harness times out the test. + if (logContents != expectedLogContents) { + gTimeoutRuns++; + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + logTestInfo("callback log contents are not correct"); + // This file doesn't contain full paths so there is no need to call + // replaceLogPaths. + let aryLog = logContents.split("\n"); + let aryCompare = expectedLogContents.split("\n"); + // Pushing an empty string to both arrays makes it so either array's length + // can be used in the for loop below without going out of bounds. + aryLog.push(""); + aryCompare.push(""); + // xpcshell tests won't display the entire contents so log the incorrect + // line. + for (let i = 0; i < aryLog.length; ++i) { + if (aryLog[i] != aryCompare[i]) { + logTestInfo("the first incorrect line in the callback log is: " + + aryLog[i]); + Assert.equal(aryLog[i], aryCompare[i], + "the callback log contents" + MSG_SHOULD_EQUAL); + } + } + // This should never happen! + do_throw("Unable to find incorrect callback log contents!"); + } + // Uses do_timeout instead of do_execute_soon to lessen log spew. + do_timeout(FILE_IN_USE_TIMEOUT_MS, checkCallbackLog); + return; + } + Assert.ok(true, "the callback log contents" + MSG_SHOULD_EQUAL); + + waitForFilesInUse(); +} + +/** + * Helper function for updater binary tests for getting the log and running + * files created by the test helper binary file when called with the post-update + * command line argument. + * + * @param aSuffix + * The string to append to the post update test helper binary path. + */ +function getPostUpdateFile(aSuffix) { + return getApplyDirFile(DIR_RESOURCES + gPostUpdateBinFile + aSuffix, true); +} + +/** + * Checks the contents of the updater post update binary log. When completed + * checkPostUpdateAppLogFinished will be called. + */ +function checkPostUpdateAppLog() { + // Only Mac OS X and Windows support post update. + if (IS_MACOSX || IS_WIN) { + gTimeoutRuns++; + let postUpdateLog = getPostUpdateFile(".log"); + if (!postUpdateLog.exists()) { + debugDump("postUpdateLog does not exist. Path: " + postUpdateLog.path); + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the post update " + + "process to create the post update log. Path: " + + postUpdateLog.path); + } + do_execute_soon(checkPostUpdateAppLog); + return; + } + + let logContents = readFile(postUpdateLog); + // It is possible for the log file contents check to occur before the log file + // contents are completely written so wait until the contents are the expected + // value. If the contents are never the expected value then the test will + // fail by timing out after gTimeoutRuns is greater than MAX_TIMEOUT_RUNS or + // the test harness times out the test. + if (logContents != "post-update\n") { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the post update " + + "process to create the expected contents in the post update log. Path: " + + postUpdateLog.path); + } + do_execute_soon(checkPostUpdateAppLog); + return; + } + Assert.ok(true, "the post update log contents" + MSG_SHOULD_EQUAL); + } + + do_execute_soon(checkPostUpdateAppLogFinished); +} + +/** + * Helper function to check if a file is in use on Windows by making a copy of + * a file and attempting to delete the original file. If the deletion is + * successful the copy of the original file is renamed to the original file's + * name and if the deletion is not successful the copy of the original file is + * deleted. + * + * @param aFile + * An nsIFile for the file to be checked if it is in use. + * @return true if the file can't be deleted and false otherwise. + */ +function isFileInUse(aFile) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + if (!aFile.exists()) { + debugDump("file does not exist, path: " + aFile.path); + return false; + } + + let fileBak = aFile.parent; + fileBak.append(aFile.leafName + ".bak"); + try { + if (fileBak.exists()) { + fileBak.remove(false); + } + aFile.copyTo(aFile.parent, fileBak.leafName); + aFile.remove(false); + fileBak.moveTo(aFile.parent, aFile.leafName); + debugDump("file is not in use, path: " + aFile.path); + return false; + } catch (e) { + debugDump("file in use, path: " + aFile.path + ", exception: " + e); + try { + if (fileBak.exists()) { + fileBak.remove(false); + } + } catch (ex) { + logTestInfo("unable to remove backup file, path: " + + fileBak.path + ", exception: " + ex); + } + } + return true; +} + +/** + * Waits until files that are in use that break tests are no longer in use and + * then calls doTestFinish to end the test. + */ +function waitForFilesInUse() { + if (IS_WIN) { + let fileNames = [FILE_APP_BIN, FILE_UPDATER_BIN, + FILE_MAINTENANCE_SERVICE_INSTALLER_BIN]; + for (let i = 0; i < fileNames.length; ++i) { + let file = getApplyDirFile(fileNames[i], true); + if (isFileInUse(file)) { + do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForFilesInUse); + return; + } + } + } + + debugDump("calling doTestFinish"); + doTestFinish(); +} + +/** + * Helper function for updater binary tests for verifying there are no update + * backup files left behind after an update. + * + * @param aFile + * An nsIFile to check if it has moz-backup for its extension. + */ +function checkForBackupFiles(aFile) { + Assert.notEqual(getFileExtension(aFile), "moz-backup", + "the file's extension should not equal moz-backup" + + getMsgPath(aFile.path)); +} + +/** + * Helper function for updater binary tests for recursively enumerating a + * directory and calling a callback function with the file as a parameter for + * each file found. + * + * @param aDir + * A nsIFile for the directory to be deleted + * @param aCallback + * A callback function that will be called with the file as a + * parameter for each file found. + */ +function checkFilesInDirRecursive(aDir, aCallback) { + if (!aDir.exists()) { + do_throw("Directory must exist!"); + } + + let dirEntries = aDir.directoryEntries; + while (dirEntries.hasMoreElements()) { + let entry = dirEntries.getNext().QueryInterface(Ci.nsIFile); + + if (entry.exists()) { + if (entry.isDirectory()) { + checkFilesInDirRecursive(entry, aCallback); + } else { + aCallback(entry); + } + } + } +} + + +/** + * Helper function to override the update prompt component to verify whether it + * is called or not. + * + * @param aCallback + * The callback to call if the update prompt component is called. + */ +function overrideUpdatePrompt(aCallback) { + Cu.import("resource://testing-common/MockRegistrar.jsm"); + MockRegistrar.register("@mozilla.org/updates/update-prompt;1", UpdatePrompt, [aCallback]); +} + +function UpdatePrompt(aCallback) { + this._callback = aCallback; + + let fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded", + "showUpdateError", "showUpdateHistory", "showUpdateInstalled"]; + + fns.forEach(function UP_fns(aPromptFn) { + UpdatePrompt.prototype[aPromptFn] = function() { + if (!this._callback) { + return; + } + + let callback = this._callback[aPromptFn]; + if (!callback) { + return; + } + + callback.apply(this._callback, + Array.prototype.slice.call(arguments)); + }; + }); +} + +UpdatePrompt.prototype = { + flags: Ci.nsIClassInfo.SINGLETON, + getScriptableHelper: () => null, + getInterfaces: function(aCount) { + let interfaces = [Ci.nsISupports, Ci.nsIUpdatePrompt]; + aCount.value = interfaces.length; + return interfaces; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIClassInfo, Ci.nsIUpdatePrompt]) +}; + +/* Update check listener */ +const updateCheckListener = { + onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) { + }, + + onCheckComplete: function UCL_onCheckComplete(aRequest, aUpdates, aUpdateCount) { + gRequestURL = aRequest.channel.originalURI.spec; + gUpdateCount = aUpdateCount; + gUpdates = aUpdates; + debugDump("url = " + gRequestURL + ", " + + "request.status = " + aRequest.status + ", " + + "updateCount = " + aUpdateCount); + // Use a timeout to allow the XHR to complete + do_execute_soon(gCheckFunc); + }, + + onError: function UCL_onError(aRequest, aUpdate) { + gRequestURL = aRequest.channel.originalURI.spec; + gStatusCode = aRequest.status; + if (gStatusCode == 0) { + gStatusCode = aRequest.channel.QueryInterface(Ci.nsIRequest).status; + } + gStatusText = aUpdate.statusText ? aUpdate.statusText : null; + debugDump("url = " + gRequestURL + ", " + + "request.status = " + gStatusCode + ", " + + "update.statusText = " + gStatusText); + // Use a timeout to allow the XHR to complete + do_execute_soon(gCheckFunc.bind(null, aRequest, aUpdate)); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateCheckListener]) +}; + +/* Update download listener - nsIRequestObserver */ +const downloadListener = { + onStartRequest: function DL_onStartRequest(aRequest, aContext) { + }, + + onProgress: function DL_onProgress(aRequest, aContext, aProgress, aMaxProgress) { + }, + + onStatus: function DL_onStatus(aRequest, aContext, aStatus, aStatusText) { + }, + + onStopRequest: function DL_onStopRequest(aRequest, aContext, aStatus) { + gStatusResult = aStatus; + // Use a timeout to allow the request to complete + do_execute_soon(gCheckFunc); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver, + Ci.nsIProgressEventSink]) +}; + +/** + * Helper for starting the http server used by the tests + */ +function start_httpserver() { + let dir = getTestDirFile(); + debugDump("http server directory path: " + dir.path); + + if (!dir.isDirectory()) { + do_throw("A file instead of a directory was specified for HttpServer " + + "registerDirectory! Path: " + dir.path); + } + + let { HttpServer } = Cu.import("resource://testing-common/httpd.js", {}); + gTestserver = new HttpServer(); + gTestserver.registerDirectory("/", dir); + gTestserver.registerPathHandler("/" + gHTTPHandlerPath, pathHandler); + gTestserver.start(-1); + let testserverPort = gTestserver.identity.primaryPort; + gURLData = URL_HOST + ":" + testserverPort + "/"; + debugDump("http server port = " + testserverPort); +} + +/** + * Custom path handler for the http server + * + * @param aMetadata + * The http metadata for the request. + * @param aResponse + * The http response for the request. + */ +function pathHandler(aMetadata, aResponse) { + aResponse.setHeader("Content-Type", "text/xml", false); + aResponse.setStatusLine(aMetadata.httpVersion, gResponseStatusCode, "OK"); + aResponse.bodyOutputStream.write(gResponseBody, gResponseBody.length); +} + +/** + * Helper for stopping the http server used by the tests + * + * @param aCallback + * The callback to call after stopping the http server. + */ +function stop_httpserver(aCallback) { + Assert.ok(!!aCallback, "the aCallback parameter should be defined"); + gTestserver.stop(aCallback); +} + +/** + * Creates an nsIXULAppInfo + * + * @param aID + * The ID of the test application + * @param aName + * A name for the test application + * @param aVersion + * The version of the application + * @param aPlatformVersion + * The gecko version of the application + */ +function createAppInfo(aID, aName, aVersion, aPlatformVersion) { + const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; + const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"); + let ifaces = [Ci.nsIXULAppInfo, Ci.nsIXULRuntime]; + if (IS_WIN) { + ifaces.push(Ci.nsIWinAppHelper); + } + const XULAppInfo = { + vendor: APP_INFO_VENDOR, + name: aName, + ID: aID, + version: aVersion, + appBuildID: "2007010101", + platformVersion: aPlatformVersion, + platformBuildID: "2007010101", + inSafeMode: false, + logConsoleErrors: true, + OS: "XPCShell", + XPCOMABI: "noarch-spidermonkey", + + QueryInterface: XPCOMUtils.generateQI(ifaces) + }; + + const XULAppInfoFactory = { + createInstance: function(aOuter, aIID) { + if (aOuter == null) { + return XULAppInfo.QueryInterface(aIID); + } + throw Cr.NS_ERROR_NO_AGGREGATION; + } + }; + + let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); + registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo", + XULAPPINFO_CONTRACTID, XULAppInfoFactory); +} + +/** + * Returns the platform specific arguments used by nsIProcess when launching + * the application. + * + * @param aExtraArgs (optional) + * An array of extra arguments to append to the default arguments. + * @return an array of arguments to be passed to nsIProcess. + * + * Note: a shell is necessary to pipe the application's console output which + * would otherwise pollute the xpcshell log. + * + * Command line arguments used when launching the application: + * -no-remote prevents shell integration from being affected by an existing + * application process. + * -test-process-updates makes the application exit after being relaunched by + * the updater. + * the platform specific string defined by PIPE_TO_NULL to output both stdout + * and stderr to null. This is needed to prevent output from the application + * from ending up in the xpchsell log. + */ +function getProcessArgs(aExtraArgs) { + if (!aExtraArgs) { + aExtraArgs = []; + } + + let appBinPath = getApplyDirFile(DIR_MACOS + FILE_APP_BIN, false).path; + if (/ /.test(appBinPath)) { + appBinPath = '"' + appBinPath + '"'; + } + + let args; + if (IS_UNIX) { + let launchScript = getLaunchScript(); + // Precreate the script with executable permissions + launchScript.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY); + + let scriptContents = "#! /bin/sh\n"; + scriptContents += appBinPath + " -no-remote -test-process-updates " + + aExtraArgs.join(" ") + " " + PIPE_TO_NULL; + writeFile(launchScript, scriptContents); + debugDump("created " + launchScript.path + " containing:\n" + + scriptContents); + args = [launchScript.path]; + } else { + args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-test-process-updates"]. + concat(aExtraArgs).concat([PIPE_TO_NULL]); + } + return args; +} + +/** + * Gets a file path for the application to dump its arguments into. This is used + * to verify that a callback application is launched. + * + * @return the file for the application to dump its arguments into. + */ +function getAppArgsLogPath() { + let appArgsLog = do_get_file("/" + gTestID + "_app_args_log", true); + if (appArgsLog.exists()) { + appArgsLog.remove(false); + } + let appArgsLogPath = appArgsLog.path; + if (/ /.test(appArgsLogPath)) { + appArgsLogPath = '"' + appArgsLogPath + '"'; + } + return appArgsLogPath; +} + +/** + * Gets the nsIFile reference for the shell script to launch the application. If + * the file exists it will be removed by this function. + * + * @return the nsIFile for the shell script to launch the application. + */ +function getLaunchScript() { + let launchScript = do_get_file("/" + gTestID + "_launch.sh", true); + if (launchScript.exists()) { + launchScript.remove(false); + } + return launchScript; +} + +/** + * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so + * xpcshell tests can run in parallel and to keep the environment clean. + */ +function adjustGeneralPaths() { + let dirProvider = { + getFile: function AGP_DP_getFile(aProp, aPersistent) { + aPersistent.value = true; + switch (aProp) { + case NS_GRE_DIR: + if (gUseTestAppDir) { + return getApplyDirFile(DIR_RESOURCES, true); + } + break; + case NS_GRE_BIN_DIR: + if (gUseTestAppDir) { + return getApplyDirFile(DIR_MACOS, true); + } + break; + case XRE_EXECUTABLE_FILE: + if (gUseTestAppDir) { + return getApplyDirFile(DIR_MACOS + FILE_APP_BIN, true); + } + break; + case XRE_UPDATE_ROOT_DIR: + return getMockUpdRootD(); + } + return null; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]) + }; + let ds = Services.dirsvc.QueryInterface(Ci.nsIDirectoryService); + ds.QueryInterface(Ci.nsIProperties).undefine(NS_GRE_DIR); + ds.QueryInterface(Ci.nsIProperties).undefine(NS_GRE_BIN_DIR); + ds.QueryInterface(Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE); + ds.registerProvider(dirProvider); + do_register_cleanup(function AGP_cleanup() { + debugDump("start - unregistering directory provider"); + + if (gAppTimer) { + debugDump("start - cancel app timer"); + gAppTimer.cancel(); + gAppTimer = null; + debugDump("finish - cancel app timer"); + } + + if (gProcess && gProcess.isRunning) { + debugDump("start - kill process"); + try { + gProcess.kill(); + } catch (e) { + debugDump("kill process failed. Exception: " + e); + } + gProcess = null; + debugDump("finish - kill process"); + } + + if (gHandle) { + try { + debugDump("start - closing handle"); + let kernel32 = ctypes.open("kernel32"); + let CloseHandle = kernel32.declare("CloseHandle", ctypes.default_abi, + ctypes.bool, /* return*/ + ctypes.voidptr_t /* handle*/); + if (!CloseHandle(gHandle)) { + debugDump("call to CloseHandle failed"); + } + kernel32.close(); + gHandle = null; + debugDump("finish - closing handle"); + } catch (e) { + debugDump("call to CloseHandle failed. Exception: " + e); + } + } + + // Call end_test first before the directory provider is unregistered + if (typeof end_test == typeof Function) { + debugDump("calling end_test"); + end_test(); + } + + ds.unregisterProvider(dirProvider); + cleanupTestCommon(); + + debugDump("finish - unregistering directory provider"); + }); +} + +/** + * The timer callback to kill the process if it takes too long. + */ +const gAppTimerCallback = { + notify: function TC_notify(aTimer) { + gAppTimer = null; + if (gProcess.isRunning) { + logTestInfo("attempting to kill process"); + gProcess.kill(); + } + Assert.ok(false, "launch application timer expired"); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) +}; + +/** + * Launches an application to apply an update. + */ +function runUpdateUsingApp(aExpectedStatus) { + /** + * The observer for the call to nsIProcess:runAsync. When completed + * runUpdateFinished will be called. + */ + const processObserver = { + observe: function PO_observe(aSubject, aTopic, aData) { + debugDump("topic: " + aTopic + ", process exitValue: " + + gProcess.exitValue); + resetEnvironment(); + if (gAppTimer) { + gAppTimer.cancel(); + gAppTimer = null; + } + Assert.equal(gProcess.exitValue, 0, + "the application process exit value should be 0"); + Assert.equal(aTopic, "process-finished", + "the application process observer topic should be " + + "process-finished"); + + if (IS_SERVICE_TEST) { + waitForServiceStop(false); + } + + do_execute_soon(afterAppExits); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) + }; + + function afterAppExits() { + gTimeoutRuns++; + + if (IS_WIN) { + waitForApplicationStop(FILE_UPDATER_BIN); + } + + let status; + try { + status = readStatusFile(); + } catch (e) { + logTestInfo("error reading status file, exception: " + e); + } + // Don't proceed until the update's status is the expected value. + if (status != aExpectedStatus) { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + logUpdateLog(FILE_UPDATE_LOG); + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " + + "status to equal: " + + aExpectedStatus + + ", current status: " + status); + } else { + do_timeout(FILE_IN_USE_TIMEOUT_MS, afterAppExits); + } + return; + } + + // Don't check for an update log when the code in nsUpdateDriver.cpp skips + // updating. + if (aExpectedStatus != STATE_PENDING && + aExpectedStatus != STATE_PENDING_SVC && + aExpectedStatus != STATE_APPLIED && + aExpectedStatus != STATE_APPLIED_SVC) { + // Don't proceed until the update log has been created. + let log = getUpdateLog(FILE_UPDATE_LOG); + if (!log.exists()) { + if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " + + "log to be created. Path: " + log.path); + } + do_timeout(FILE_IN_USE_TIMEOUT_MS, afterAppExits); + return; + } + } + + do_execute_soon(runUpdateFinished); + } + + debugDump("start - launching application to apply update"); + + let appBin = getApplyDirFile(DIR_MACOS + FILE_APP_BIN, false); + + let launchBin = getLaunchBin(); + let args = getProcessArgs(); + debugDump("launching " + launchBin.path + " " + args.join(" ")); + + gProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + gProcess.init(launchBin); + + gAppTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gAppTimer.initWithCallback(gAppTimerCallback, APP_TIMER_TIMEOUT, + Ci.nsITimer.TYPE_ONE_SHOT); + + setEnvironment(); + debugDump("launching application"); + gProcess.runAsync(args, args.length, processObserver); + + debugDump("finish - launching application to apply update"); +} + +/** + * Sets the environment that will be used by the application process when it is + * launched. + */ +function setEnvironment() { + // Prevent setting the environment more than once. + if (gShouldResetEnv !== undefined) { + return; + } + + gShouldResetEnv = true; + + // See bug 1279108. + if (gEnv.exists("ASAN_OPTIONS")) { + gASanOptions = gEnv.get("ASAN_OPTIONS"); + gEnv.set("ASAN_OPTIONS", gASanOptions + ":detect_leaks=0"); + } else { + gEnv.set("ASAN_OPTIONS", "detect_leaks=0"); + } + + if (IS_WIN && !gEnv.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) { + gAddedEnvXRENoWindowsCrashDialog = true; + debugDump("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " + + "variable to 1... previously it didn't exist"); + gEnv.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1"); + } + + if (IS_UNIX) { + let appGreBinDir = gGREBinDirOrig.clone(); + let envGreBinDir = Cc["@mozilla.org/file/local;1"]. + createInstance(Ci.nsILocalFile); + let shouldSetEnv = true; + if (IS_MACOSX) { + if (gEnv.exists("DYLD_LIBRARY_PATH")) { + gEnvDyldLibraryPath = gEnv.get("DYLD_LIBRARY_PATH"); + envGreBinDir.initWithPath(gEnvDyldLibraryPath); + if (envGreBinDir.path == appGreBinDir.path) { + gEnvDyldLibraryPath = null; + shouldSetEnv = false; + } + } + + if (shouldSetEnv) { + debugDump("setting DYLD_LIBRARY_PATH environment variable value to " + + appGreBinDir.path); + gEnv.set("DYLD_LIBRARY_PATH", appGreBinDir.path); + } + } else { + if (gEnv.exists("LD_LIBRARY_PATH")) { + gEnvLdLibraryPath = gEnv.get("LD_LIBRARY_PATH"); + envGreBinDir.initWithPath(gEnvLdLibraryPath); + if (envGreBinDir.path == appGreBinDir.path) { + gEnvLdLibraryPath = null; + shouldSetEnv = false; + } + } + + if (shouldSetEnv) { + debugDump("setting LD_LIBRARY_PATH environment variable value to " + + appGreBinDir.path); + gEnv.set("LD_LIBRARY_PATH", appGreBinDir.path); + } + } + } + + if (gEnv.exists("XPCOM_MEM_LEAK_LOG")) { + gEnvXPCOMMemLeakLog = gEnv.get("XPCOM_MEM_LEAK_LOG"); + debugDump("removing the XPCOM_MEM_LEAK_LOG environment variable... " + + "previous value " + gEnvXPCOMMemLeakLog); + gEnv.set("XPCOM_MEM_LEAK_LOG", ""); + } + + if (gEnv.exists("XPCOM_DEBUG_BREAK")) { + gEnvXPCOMDebugBreak = gEnv.get("XPCOM_DEBUG_BREAK"); + debugDump("setting the XPCOM_DEBUG_BREAK environment variable to " + + "warn... previous value " + gEnvXPCOMDebugBreak); + } else { + debugDump("setting the XPCOM_DEBUG_BREAK environment variable to " + + "warn... previously it didn't exist"); + } + + gEnv.set("XPCOM_DEBUG_BREAK", "warn"); + + if (IS_SERVICE_TEST) { + debugDump("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1"); + gEnv.set("MOZ_NO_SERVICE_FALLBACK", "1"); + } +} + +/** + * Sets the environment back to the original values after launching the + * application. + */ +function resetEnvironment() { + // Prevent resetting the environment more than once. + if (gShouldResetEnv !== true) { + return; + } + + gShouldResetEnv = false; + + // Restore previous ASAN_OPTIONS if there were any. + gEnv.set("ASAN_OPTIONS", gASanOptions ? gASanOptions : ""); + + if (gEnvXPCOMMemLeakLog) { + debugDump("setting the XPCOM_MEM_LEAK_LOG environment variable back to " + + gEnvXPCOMMemLeakLog); + gEnv.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog); + } + + if (gEnvXPCOMDebugBreak) { + debugDump("setting the XPCOM_DEBUG_BREAK environment variable back to " + + gEnvXPCOMDebugBreak); + gEnv.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak); + } else if (gEnv.exists("XPCOM_DEBUG_BREAK")) { + debugDump("clearing the XPCOM_DEBUG_BREAK environment variable"); + gEnv.set("XPCOM_DEBUG_BREAK", ""); + } + + if (IS_UNIX) { + if (IS_MACOSX) { + if (gEnvDyldLibraryPath) { + debugDump("setting DYLD_LIBRARY_PATH environment variable value " + + "back to " + gEnvDyldLibraryPath); + gEnv.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath); + } else if (gEnvDyldLibraryPath !== null) { + debugDump("removing DYLD_LIBRARY_PATH environment variable"); + gEnv.set("DYLD_LIBRARY_PATH", ""); + } + } else if (gEnvLdLibraryPath) { + debugDump("setting LD_LIBRARY_PATH environment variable value back " + + "to " + gEnvLdLibraryPath); + gEnv.set("LD_LIBRARY_PATH", gEnvLdLibraryPath); + } else if (gEnvLdLibraryPath !== null) { + debugDump("removing LD_LIBRARY_PATH environment variable"); + gEnv.set("LD_LIBRARY_PATH", ""); + } + } + + if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) { + debugDump("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " + + "variable"); + gEnv.set("XRE_NO_WINDOWS_CRASH_DIALOG", ""); + } + + if (IS_SERVICE_TEST) { + debugDump("removing MOZ_NO_SERVICE_FALLBACK environment variable"); + gEnv.set("MOZ_NO_SERVICE_FALLBACK", ""); + } +} diff --git a/toolkit/mozapps/update/tests/moz.build b/toolkit/mozapps/update/tests/moz.build new file mode 100644 index 000000000..842ec7f90 --- /dev/null +++ b/toolkit/mozapps/update/tests/moz.build @@ -0,0 +1,101 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +HAS_MISC_RULE = True + +FINAL_TARGET = '_tests/xpcshell/toolkit/mozapps/update/tests/data' + +MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini'] + +XPCSHELL_TESTS_MANIFESTS += [ + 'unit_aus_update/xpcshell.ini', + 'unit_base_updater/xpcshell.ini' +] + +if CONFIG['MOZ_MAINTENANCE_SERVICE']: + XPCSHELL_TESTS_MANIFESTS += ['unit_service_updater/xpcshell.ini'] + +SimplePrograms([ + 'TestAUSHelper', + 'TestAUSReadStrings', +]) + +LOCAL_INCLUDES += [ + '/toolkit/mozapps/update', + '/toolkit/mozapps/update/common', +] + +if CONFIG['OS_ARCH'] == 'WINNT': + USE_LIBS += [ + 'updatecommon-standalone', + ] + + OS_LIBS += [ + 'shlwapi', + ] +else: + USE_LIBS += [ + 'updatecommon', + ] + +for var in ('MOZ_APP_NAME', 'MOZ_APP_BASENAME', 'MOZ_APP_DISPLAYNAME', + 'MOZ_APP_VENDOR', 'BIN_SUFFIX', 'MOZ_DEBUG'): + DEFINES[var] = CONFIG[var] + +DEFINES['NS_NO_XPCOM'] = True + +if CONFIG['MOZ_MAINTENANCE_SERVICE']: + DEFINES['MOZ_MAINTENANCE_SERVICE'] = CONFIG['MOZ_MAINTENANCE_SERVICE'] + +# For debugging purposes only +#DEFINES['DISABLE_UPDATER_AUTHENTICODE_CHECK'] = True + +if CONFIG['OS_ARCH'] == 'WINNT': + DEFINES['UNICODE'] = True + DEFINES['_UNICODE'] = True + USE_STATIC_LIBS = True + if CONFIG['GNU_CC']: + WIN32_EXE_LDFLAGS += ['-municode'] + +TEST_HARNESS_FILES.testing.mochitest.chrome.toolkit.mozapps.update.tests.data += [ + 'data/shared.js', + 'data/sharedUpdateXML.js', + 'data/simple.mar', +] + +FINAL_TARGET_FILES += [ + 'data/complete.exe', + 'data/complete.mar', + 'data/complete.png', + 'data/complete_log_success_mac', + 'data/complete_log_success_win', + 'data/complete_mac.mar', + 'data/complete_precomplete', + 'data/complete_precomplete_mac', + 'data/complete_removed-files', + 'data/complete_removed-files_mac', + 'data/complete_update_manifest', + 'data/old_version.mar', + 'data/partial.exe', + 'data/partial.mar', + 'data/partial.png', + 'data/partial_log_failure_mac', + 'data/partial_log_failure_win', + 'data/partial_log_success_mac', + 'data/partial_log_success_win', + 'data/partial_mac.mar', + 'data/partial_precomplete', + 'data/partial_precomplete_mac', + 'data/partial_removed-files', + 'data/partial_removed-files_mac', + 'data/partial_update_manifest', + 'data/replace_log_success', + 'data/shared.js', + 'data/sharedUpdateXML.js', + 'data/simple.mar', + 'data/wrong_product_channel.mar', + 'data/xpcshellUtilsAUS.js', +] diff --git a/toolkit/mozapps/update/tests/unit_aus_update/.eslintrc.js b/toolkit/mozapps/update/tests/unit_aus_update/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js new file mode 100644 index 000000000..1985df959 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js @@ -0,0 +1,138 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +function run_test() { + setupTestCommon(); + + // Verify write access to the custom app dir + debugDump("testing write access to the application directory"); + let testFile = getCurrentProcessDir(); + testFile.append("update_write_access_test"); + testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); + Assert.ok(testFile.exists(), MSG_SHOULD_EXIST); + testFile.remove(false); + Assert.ok(!testFile.exists(), MSG_SHOULD_NOT_EXIST); + + standardInit(); + + if (IS_WIN) { + // Create a mutex to prevent being able to check for or apply updates. + debugDump("attempting to create mutex"); + let handle = createMutex(getPerInstallationMutexName()); + Assert.ok(!!handle, "the update mutex should have been created"); + + // Check if available updates cannot be checked for when there is a mutex + // for this installation. + Assert.ok(!gAUS.canCheckForUpdates, "should not be able to check for " + + "updates when there is an update mutex"); + + // Check if updates cannot be applied when there is a mutex for this + // installation. + Assert.ok(!gAUS.canApplyUpdates, "should not be able to apply updates " + + "when there is an update mutex"); + + debugDump("destroying mutex"); + closeHandle(handle); + } + + // Check if available updates can be checked for + Assert.ok(gAUS.canCheckForUpdates, "should be able to check for updates"); + // Check if updates can be applied + Assert.ok(gAUS.canApplyUpdates, "should be able to apply updates"); + + if (IS_WIN) { + // Attempt to create a mutex when application update has already created one + // with the same name. + debugDump("attempting to create mutex"); + let handle = createMutex(getPerInstallationMutexName()); + + Assert.ok(!handle, "should not be able to create the update mutex when " + + "the application has created the update mutex"); + } + + doTestFinish(); +} + +/** + * Determines a unique mutex name for the installation. + * + * @return Global mutex path. + */ +function getPerInstallationMutexName() { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let hasher = Cc["@mozilla.org/security/hash;1"]. + createInstance(Ci.nsICryptoHash); + hasher.init(hasher.SHA1); + + let exeFile = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsILocalFile); + + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. + createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + let data = converter.convertToByteArray(exeFile.path.toLowerCase()); + + hasher.update(data, data.length); + return "Global\\MozillaUpdateMutex-" + hasher.finish(true); +} + +/** + * Closes a Win32 handle. + * + * @param aHandle + * The handle to close. + */ +function closeHandle(aHandle) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + let lib = ctypes.open("kernel32.dll"); + let CloseHandle = lib.declare("CloseHandle", + ctypes.winapi_abi, + ctypes.int32_t, /* success */ + ctypes.void_t.ptr); /* handle */ + CloseHandle(aHandle); + lib.close(); +} + +/** + * Creates a mutex. + * + * @param aName + * The name for the mutex. + * @return The Win32 handle to the mutex. + */ +function createMutex(aName) { + if (!IS_WIN) { + do_throw("Windows only function called by a different platform!"); + } + + const INITIAL_OWN = 1; + const ERROR_ALREADY_EXISTS = 0xB7; + let lib = ctypes.open("kernel32.dll"); + let CreateMutexW = lib.declare("CreateMutexW", + ctypes.winapi_abi, + ctypes.void_t.ptr, /* return handle */ + ctypes.void_t.ptr, /* security attributes */ + ctypes.int32_t, /* initial owner */ + ctypes.char16_t.ptr); /* name */ + + let handle = CreateMutexW(null, INITIAL_OWN, aName); + lib.close(); + let alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS; + if (handle && !handle.isNull() && alreadyExists) { + closeHandle(handle); + handle = null; + } + + if (handle && handle.isNull()) { + handle = null; + } + + return handle; +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js new file mode 100644 index 000000000..a0a95af1b --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Update Manager Tests */ + +function run_test() { + setupTestCommon(); + + debugDump("testing removal of an active update for a channel that is not" + + "valid due to switching channels (Bug 486275)."); + + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0"); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_DOWNLOADING); + + patches = getLocalPatchString(null, null, null, null, null, null, + STATE_FAILED); + updates = getLocalUpdateString(patches, null, "Existing", "version 3.0", + "3.0", "3.0", null, null, null, null, + getString("patchApplyFailure")); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), false); + + setUpdateChannel("original_channel"); + + standardInit(); + + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager update count" + MSG_SHOULD_EQUAL); + let update = gUpdateManager.getUpdateAt(0); + Assert.equal(update.name, "Existing", + "the update's name" + MSG_SHOULD_EQUAL); + + Assert.ok(!gUpdateManager.activeUpdate, + "there should not be an active update"); + // Verify that the active-update.xml file has had the update from the old + // channel removed. + let file = getUpdatesXMLFile(true); + Assert.equal(readFile(file), getLocalUpdatesXMLString(""), + "the contents of active-update.xml" + MSG_SHOULD_EQUAL); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js new file mode 100644 index 000000000..fc4f09787 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + + +function run_test() { + setupTestCommon(); + + debugDump("testing cleanup of an update download in progress for an " + + "older version of the application on startup (Bug 485624)"); + + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, "version 0.9", "0.9"); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_DOWNLOADING); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + + standardInit(); + + Assert.ok(!gUpdateManager.activeUpdate, + "there should not be an active update"); + Assert.equal(gUpdateManager.updateCount, 0, + "the update manager update count" + MSG_SHOULD_EQUAL); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js new file mode 100644 index 000000000..b2d8ecbc6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +function run_test() { + setupTestCommon(); + + debugDump("testing removal of an update download in progress for the " + + "same version of the application with the same application " + + "build id on startup (Bug 536547)"); + + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0", + "2007010101"); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_DOWNLOADING); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + + standardInit(); + + Assert.ok(!gUpdateManager.activeUpdate, + "there should not be an active update"); + Assert.equal(gUpdateManager.updateCount, 0, + "the update manager update count" + MSG_SHOULD_EQUAL); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js new file mode 100644 index 000000000..13e4aeaf6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +function run_test() { + setupTestCommon(); + + debugDump("testing update cleanup when reading the status file returns " + + "STATUS_NONE and the update xml has an update with " + + "STATE_DOWNLOADING (Bug 539717)."); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_NONE); + + standardInit(); + + let dir = getUpdatesDir(); + dir.append(DIR_PATCH); + Assert.ok(dir.exists(), MSG_SHOULD_EXIST); + + let statusFile = dir.clone(); + statusFile.append(FILE_UPDATE_STATUS); + Assert.ok(!statusFile.exists(), MSG_SHOULD_NOT_EXIST); + + Assert.ok(!gUpdateManager.activeUpdate, + "there should not be an active update"); + Assert.equal(gUpdateManager.updateCount, 0, + "the update manager update count" + MSG_SHOULD_EQUAL); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js new file mode 100644 index 000000000..7661da82d --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +function run_test() { + setupTestCommon(); + + debugDump("testing update cleanup when reading the status file returns " + + "STATUS_NONE, the version file is for a newer version, and the " + + "update xml has an update with STATE_PENDING (Bug 601701)."); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeVersionFile("99.9"); + + standardInit(); + + // Check that there is no activeUpdate first so the updates directory is + // cleaned up by the UpdateManager before the remaining tests. + Assert.ok(!gUpdateManager.activeUpdate, + "there should not be an active update"); + Assert.equal(gUpdateManager.updateCount, 0, + "the update manager update count" + MSG_SHOULD_EQUAL); + + let dir = getUpdatesDir(); + dir.append(DIR_PATCH); + Assert.ok(dir.exists(), MSG_SHOULD_EXIST); + + let versionFile = dir.clone(); + versionFile.append(FILE_UPDATE_VERSION); + Assert.ok(!versionFile.exists(), MSG_SHOULD_NOT_EXIST); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js new file mode 100644 index 000000000..d683b9931 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +function run_test() { + setupTestCommon(); + + debugDump("testing that the update.log is moved after a successful update"); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_SUCCEEDED); + + let log = getUpdateLog(FILE_UPDATE_LOG); + writeFile(log, "Last Update Log"); + + standardInit(); + + Assert.ok(!log.exists(), MSG_SHOULD_NOT_EXIST); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), MSG_SHOULD_EXIST); + Assert.equal(readFile(log), "Last Update Log", + "the last update log contents" + MSG_SHOULD_EQUAL); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(!log.exists(), MSG_SHOULD_NOT_EXIST); + + let dir = getUpdatesPatchDir(); + Assert.ok(dir.exists(), MSG_SHOULD_EXIST); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js new file mode 100644 index 000000000..8be93d0ff --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +function run_test() { + setupTestCommon(); + + debugDump("testing update logs are first in first out deleted"); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_PENDING); + let updates = getLocalUpdateString(patches); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_SUCCEEDED); + + let log = getUpdateLog(FILE_LAST_UPDATE_LOG); + writeFile(log, "Backup Update Log"); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + writeFile(log, "To Be Deleted Backup Update Log"); + + log = getUpdateLog(FILE_UPDATE_LOG); + writeFile(log, "Last Update Log"); + + standardInit(); + + Assert.ok(!log.exists(), MSG_SHOULD_NOT_EXIST); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), MSG_SHOULD_EXIST); + Assert.equal(readFile(log), "Last Update Log", + "the last update log contents" + MSG_SHOULD_EQUAL); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(log.exists(), MSG_SHOULD_EXIST); + Assert.equal(readFile(log), "Backup Update Log", + "the backup update log contents" + MSG_SHOULD_EQUAL); + + let dir = getUpdatesPatchDir(); + Assert.ok(dir.exists(), MSG_SHOULD_EXIST); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js new file mode 100644 index 000000000..b715fb56e --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js @@ -0,0 +1,161 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +var gNextRunFunc; +var gExpectedStatusResult; + +function run_test() { + // The network code that downloads the mar file accesses the profile to cache + // the download, but the profile is only available after calling + // do_get_profile in xpcshell tests. This prevents an error from being logged. + do_get_profile(); + + setupTestCommon(); + + debugDump("testing mar download and mar hash verification"); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false); + start_httpserver(); + setUpdateURL(gURLData + gHTTPHandlerPath); + standardInit(); + // Only perform the non hash check tests when mar signing is enabled since the + // update service doesn't perform hash checks when mar signing is enabled. + if (MOZ_VERIFY_MAR_SIGNATURE) { + do_execute_soon(run_test_pt11); + } else { + do_execute_soon(run_test_pt1); + } +} + +// The HttpServer must be stopped before calling do_test_finished +function finish_test() { + stop_httpserver(doTestFinish); +} + +// Helper function for testing mar downloads that have the correct size +// specified in the update xml. +function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) { + gUpdates = null; + gUpdateCount = null; + gStatusResult = null; + gCheckFunc = check_test_helper_pt1_1; + gNextRunFunc = aNextRunFunc; + gExpectedStatusResult = aExpectedStatusResult; + debugDump(aMsg, Components.stack.caller); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_helper_pt1_1() { + Assert.equal(gUpdateCount, 1, + "the update count" + MSG_SHOULD_EQUAL); + gCheckFunc = check_test_helper_pt1_2; + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + let state = gAUS.downloadUpdate(bestUpdate, false); + if (state == STATE_NONE || state == STATE_FAILED) { + do_throw("nsIApplicationUpdateService:downloadUpdate returned " + state); + } + gAUS.addDownloadListener(downloadListener); +} + +function check_test_helper_pt1_2() { + Assert.equal(gStatusResult, gExpectedStatusResult, + "the download status result" + MSG_SHOULD_EQUAL); + gAUS.removeDownloadListener(downloadListener); + gNextRunFunc(); +} + +function setResponseBody(aHashFunction, aHashValue, aSize) { + let patches = getRemotePatchString(null, null, + aHashFunction, aHashValue, aSize); + let updates = getRemoteUpdateString(patches); + gResponseBody = getRemoteUpdatesXMLString(updates); +} + +// mar download with a valid MD5 hash +function run_test_pt1() { + setResponseBody("MD5", MD5_HASH_SIMPLE_MAR); + run_test_helper_pt1("mar download with a valid MD5 hash", + Cr.NS_OK, run_test_pt2); +} + +// mar download with an invalid MD5 hash +function run_test_pt2() { + setResponseBody("MD5", MD5_HASH_SIMPLE_MAR + "0"); + run_test_helper_pt1("mar download with an invalid MD5 hash", + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt3); +} + +// mar download with a valid SHA1 hash +function run_test_pt3() { + setResponseBody("SHA1", SHA1_HASH_SIMPLE_MAR); + run_test_helper_pt1("mar download with a valid SHA1 hash", + Cr.NS_OK, run_test_pt4); +} + +// mar download with an invalid SHA1 hash +function run_test_pt4() { + setResponseBody("SHA1", SHA1_HASH_SIMPLE_MAR + "0"); + run_test_helper_pt1("mar download with an invalid SHA1 hash", + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt5); +} + +// mar download with a valid SHA256 hash +function run_test_pt5() { + setResponseBody("SHA256", SHA256_HASH_SIMPLE_MAR); + run_test_helper_pt1("mar download with a valid SHA256 hash", + Cr.NS_OK, run_test_pt6); +} + +// mar download with an invalid SHA256 hash +function run_test_pt6() { + setResponseBody("SHA256", SHA256_HASH_SIMPLE_MAR + "0"); + run_test_helper_pt1("mar download with an invalid SHA256 hash", + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt7); +} + +// mar download with a valid SHA384 hash +function run_test_pt7() { + setResponseBody("SHA384", SHA384_HASH_SIMPLE_MAR); + run_test_helper_pt1("mar download with a valid SHA384 hash", + Cr.NS_OK, run_test_pt8); +} + +// mar download with an invalid SHA384 hash +function run_test_pt8() { + setResponseBody("SHA384", SHA384_HASH_SIMPLE_MAR + "0"); + run_test_helper_pt1("mar download with an invalid SHA384 hash", + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt9); +} + +// mar download with a valid SHA512 hash +function run_test_pt9() { + setResponseBody("SHA512", SHA512_HASH_SIMPLE_MAR); + run_test_helper_pt1("mar download with a valid SHA512 hash", + Cr.NS_OK, run_test_pt10); +} + +// mar download with an invalid SHA512 hash +function run_test_pt10() { + setResponseBody("SHA512", SHA512_HASH_SIMPLE_MAR + "0"); + run_test_helper_pt1("mar download with an invalid SHA512 hash", + Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt11); +} + +// mar download with the mar not found +function run_test_pt11() { + let patches = getRemotePatchString(null, gURLData + "missing.mar"); + let updates = getRemoteUpdateString(patches); + gResponseBody = getRemoteUpdatesXMLString(updates); + run_test_helper_pt1("mar download with the mar not found", + Cr.NS_ERROR_UNEXPECTED, run_test_pt12); +} + +// mar download with a valid MD5 hash but invalid file size +function run_test_pt12() { + const arbitraryFileSize = 1024000; + setResponseBody("MD5", MD5_HASH_SIMPLE_MAR, arbitraryFileSize); + run_test_helper_pt1("mar download with a valid MD5 hash but invalid file size", + Cr.NS_ERROR_UNEXPECTED, finish_test); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js new file mode 100644 index 000000000..159033792 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js @@ -0,0 +1,66 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Components.utils.import("resource://testing-common/MockRegistrar.jsm"); + +const WindowWatcher = { + getNewPrompter: function WW_getNewPrompter(aParent) { + Assert.ok(!aParent, + "the aParent parameter should not be defined"); + return { + alert: function WW_GNP_alert(aTitle, aText) { + let title = getString("updaterIOErrorTitle"); + Assert.equal(aTitle, title, + "the ui string for title" + MSG_SHOULD_EQUAL); + let text = gUpdateBundle.formatStringFromName("updaterIOErrorMsg", + [Services.appinfo.name, + Services.appinfo.name], 2); + Assert.equal(aText, text, + "the ui string for message" + MSG_SHOULD_EQUAL); + + doTestFinish(); + } + }; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]) +}; + +function run_test() { + setupTestCommon(); + + debugDump("testing download a complete on partial failure. Calling " + + "nsIUpdatePrompt::showUpdateError should call getNewPrompter " + + "and alert on the object returned by getNewPrompter when the " + + "update.state == " + STATE_FAILED + " and the update.errorCode " + + "== " + WRITE_ERROR + " (Bug 595059)."); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false); + + let windowWatcherCID = + MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", + WindowWatcher); + do_register_cleanup(() => { + MockRegistrar.unregister(windowWatcherCID); + }); + + standardInit(); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + let url = URL_HOST + "/" + FILE_COMPLETE_MAR; + let patches = getLocalPatchString("complete", url, null, null, null, null, + STATE_FAILED); + let updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0", + null, null, null, null, url); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_FAILED); + + reloadUpdateManagerData(); + + let update = gUpdateManager.activeUpdate; + update.errorCode = WRITE_ERROR; + let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. + createInstance(Ci.nsIUpdatePrompt); + prompter.showUpdateError(update); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js new file mode 100644 index 000000000..ef2da26af --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js @@ -0,0 +1,225 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General MAR File Download Tests */ + +Components.utils.import("resource://testing-common/MockRegistrar.jsm"); +const INC_CONTRACT_ID = "@mozilla.org/network/incremental-download;1"; + +// gIncrementalDownloadErrorType is used to loop through each of the connection +// error types in the Mock incremental downloader. +var gIncrementalDownloadErrorType = 0; + +var gNextRunFunc; +var gExpectedStatusResult; + +function run_test() { + setupTestCommon(); + + debugDump("testing mar downloads, mar hash verification, and " + + "mar download interrupted recovery"); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false); + start_httpserver(); + setUpdateURL(gURLData + gHTTPHandlerPath); + standardInit(); + do_execute_soon(run_test_pt1); +} + +// The HttpServer must be stopped before calling do_test_finished +function finish_test() { + stop_httpserver(doTestFinish); +} + +// Helper function for testing mar downloads that have the correct size +// specified in the update xml. +function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) { + gUpdates = null; + gUpdateCount = null; + gStatusResult = null; + gCheckFunc = check_test_helper_pt1_1; + gNextRunFunc = aNextRunFunc; + gExpectedStatusResult = aExpectedStatusResult; + debugDump(aMsg, Components.stack.caller); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_helper_pt1_1() { + Assert.equal(gUpdateCount, 1, + "the update count" + MSG_SHOULD_EQUAL); + gCheckFunc = check_test_helper_pt1_2; + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + let state = gAUS.downloadUpdate(bestUpdate, false); + if (state == STATE_NONE || state == STATE_FAILED) { + do_throw("nsIApplicationUpdateService:downloadUpdate returned " + state); + } + gAUS.addDownloadListener(downloadListener); +} + +function check_test_helper_pt1_2() { + Assert.equal(gStatusResult, gExpectedStatusResult, + "the download status result" + MSG_SHOULD_EQUAL); + gAUS.removeDownloadListener(downloadListener); + gNextRunFunc(); +} + +function setResponseBody(aHashFunction, aHashValue, aSize) { + let patches = getRemotePatchString(null, null, + aHashFunction, aHashValue, aSize); + let updates = getRemoteUpdateString(patches); + gResponseBody = getRemoteUpdatesXMLString(updates); +} + +function initMockIncrementalDownload() { + let incrementalDownloadCID = + MockRegistrar.register(INC_CONTRACT_ID, IncrementalDownload); + do_register_cleanup(() => { + MockRegistrar.unregister(incrementalDownloadCID); + }); +} + +/* This Mock incremental downloader is used to verify that connection + * interrupts work correctly in updater code. The implementation of + * the mock incremental downloader is very simple, it simply copies + * the file to the destination location. + */ + +function IncrementalDownload() { + this.wrappedJSObject = this; +} + +IncrementalDownload.prototype = { + /* nsIIncrementalDownload */ + init: function(uri, file, chunkSize, intervalInSeconds) { + this._destination = file; + this._URI = uri; + this._finalURI = uri; + }, + + start: function(observer, ctxt) { + let tm = Cc["@mozilla.org/thread-manager;1"]. + getService(Ci.nsIThreadManager); + // Do the actual operation async to give a chance for observers + // to add themselves. + tm.mainThread.dispatch(function() { + this._observer = observer.QueryInterface(Ci.nsIRequestObserver); + this._ctxt = ctxt; + this._observer.onStartRequest(this, this._ctxt); + let mar = getTestDirFile(FILE_SIMPLE_MAR); + mar.copyTo(this._destination.parent, this._destination.leafName); + let status = Cr.NS_OK; + switch (gIncrementalDownloadErrorType++) { + case 0: + status = Cr.NS_ERROR_NET_RESET; + break; + case 1: + status = Cr.NS_ERROR_CONNECTION_REFUSED; + break; + case 2: + status = Cr.NS_ERROR_NET_RESET; + break; + case 3: + status = Cr.NS_OK; + break; + case 4: + status = Cr.NS_ERROR_OFFLINE; + // After we report offline, we want to eventually show offline + // status being changed to online. + let tm2 = Cc["@mozilla.org/thread-manager;1"]. + getService(Ci.nsIThreadManager); + tm2.mainThread.dispatch(function() { + Services.obs.notifyObservers(gAUS, + "network:offline-status-changed", + "online"); + }, Ci.nsIThread.DISPATCH_NORMAL); + break; + } + this._observer.onStopRequest(this, this._ctxt, status); + }.bind(this), Ci.nsIThread.DISPATCH_NORMAL); + }, + + get URI() { + return this._URI; + }, + + get currentSize() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + + get destination() { + return this._destination; + }, + + get finalURI() { + return this._finalURI; + }, + + get totalSize() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + + /* nsIRequest */ + cancel: function(aStatus) { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + suspend: function() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + isPending: function() { + throw Cr.NS_ERROR_NOT_IMPLEMENTED; + }, + _loadFlags: 0, + get loadFlags() { + return this._loadFlags; + }, + set loadFlags(val) { + this._loadFlags = val; + }, + + _loadGroup: null, + get loadGroup() { + return this._loadGroup; + }, + set loadGroup(val) { + this._loadGroup = val; + }, + + _name: "", + get name() { + return this._name; + }, + + _status: 0, + get status() { + return this._status; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIIncrementalDownload]) +}; + +// Test disconnecting during an update +function run_test_pt1() { + initMockIncrementalDownload(); + setResponseBody("MD5", MD5_HASH_SIMPLE_MAR); + run_test_helper_pt1("mar download with connection interruption", + Cr.NS_OK, run_test_pt2); +} + +// Test disconnecting during an update +function run_test_pt2() { + gIncrementalDownloadErrorType = 0; + Services.prefs.setIntPref(PREF_APP_UPDATE_SOCKET_MAXERRORS, 2); + Services.prefs.setIntPref(PREF_APP_UPDATE_RETRYTIMEOUT, 0); + setResponseBody("MD5", MD5_HASH_SIMPLE_MAR); + run_test_helper_pt1("mar download with connection interruption without recovery", + Cr.NS_ERROR_NET_RESET, run_test_pt3); +} + +// Test entering offline mode while downloading +function run_test_pt3() { + gIncrementalDownloadErrorType = 4; + setResponseBody("MD5", MD5_HASH_SIMPLE_MAR); + run_test_helper_pt1("mar download with offline mode", + Cr.NS_OK, finish_test); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js new file mode 100644 index 000000000..ca065f573 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +function run_test() { + setupTestCommon(); + + debugDump("testing resuming an update download in progress for the same " + + "version of the application on startup (Bug 485624)"); + + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_DOWNLOADING); + let updates = getLocalUpdateString(patches, null, null, "1.0", "1.0"); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_DOWNLOADING); + + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + + standardInit(); + + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.activeUpdate.state, STATE_DOWNLOADING, + "the update manager activeUpdate state attribute" + + MSG_SHOULD_EQUAL); + + // Pause the download and reload the Update Manager with an empty update so + // the Application Update Service doesn't write the update xml files during + // xpcom-shutdown which will leave behind the test directory. + gAUS.pauseDownload(); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + reloadUpdateManagerData(); + + do_execute_soon(doTestFinish); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js new file mode 100644 index 000000000..9715c5828 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js @@ -0,0 +1,8 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const IS_SERVICE_TEST = false; + +/* import-globals-from ../data/xpcshellUtilsAUS.js */ +load("../data/xpcshellUtilsAUS.js"); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js new file mode 100644 index 000000000..831c87257 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js @@ -0,0 +1,285 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +var gNextRunFunc; +var gExpectedCount; + +function run_test() { + setupTestCommon(); + + debugDump("testing remote update xml attributes"); + + start_httpserver(); + setUpdateURL(gURLData + gHTTPHandlerPath); + setUpdateChannel("test_channel"); + + // This test expects that the app.update.download.backgroundInterval + // preference doesn't already exist. + Services.prefs.deleteBranch("app.update.download.backgroundInterval"); + + standardInit(); + do_execute_soon(run_test_pt01); +} + +// Helper function for testing update counts returned from an update xml +function run_test_helper_pt1(aMsg, aExpectedCount, aNextRunFunc) { + gUpdates = null; + gUpdateCount = null; + gCheckFunc = check_test_helper_pt1; + gNextRunFunc = aNextRunFunc; + gExpectedCount = aExpectedCount; + debugDump(aMsg, Components.stack.caller); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_helper_pt1() { + Assert.equal(gUpdateCount, gExpectedCount, + "the update count" + MSG_SHOULD_EQUAL); + gNextRunFunc(); +} + +// update xml not found +function run_test_pt01() { + run_test_helper_pt1("testing update xml not available", + null, run_test_pt02); +} + +// one update available and the update's property values +function run_test_pt02() { + debugDump("testing one update available and the update's property values"); + gUpdates = null; + gUpdateCount = null; + gCheckFunc = check_test_pt02; + let patches = getRemotePatchString("complete", "http://complete/", "SHA1", + "98db9dad8e1d80eda7e1170d0187d6f53e477059", + "9856459"); + patches += getRemotePatchString("partial", "http://partial/", "SHA1", + "e6678ca40ae7582316acdeddf3c133c9c8577de4", + "1316138"); + let updates = getRemoteUpdateString(patches, "minor", "Minor Test", + "version 2.1a1pre", "2.1a1pre", + "20080811053724", + "http://details/", + "true", + "true", "345600", "1200", + "custom1_attr=\"custom1 value\"", + "custom2_attr=\"custom2 value\""); + gResponseBody = getRemoteUpdatesXMLString(updates); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt02() { + // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 + // and until this is fixed this will not test the value for detailsURL when it + // isn't specified in the update xml. +// let defaultDetailsURL; +// try { + // Try using a default details URL supplied by the distribution + // if the update XML does not supply one. +// let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]. +// getService(Ci.nsIURLFormatter); +// defaultDetailsURL = formatter.formatURLPref(PREF_APP_UPDATE_URL_DETAILS); +// } catch (e) { +// defaultDetailsURL = ""; +// } + + Assert.equal(gUpdateCount, 1, + "the update count" + MSG_SHOULD_EQUAL); + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount).QueryInterface(Ci.nsIPropertyBag); + Assert.equal(bestUpdate.type, "minor", + "the update type attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.name, "Minor Test", + "the update name attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.displayVersion, "version 2.1a1pre", + "the update displayVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.appVersion, "2.1a1pre", + "the update appVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.buildID, "20080811053724", + "the update buildID attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.detailsURL, "http://details/", + "the update detailsURL attribute" + MSG_SHOULD_EQUAL); + Assert.ok(bestUpdate.showPrompt, + "the update showPrompt attribute" + MSG_SHOULD_EQUAL); + Assert.ok(bestUpdate.showNeverForVersion, + "the update showNeverForVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.promptWaitTime, "345600", + "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL); + // The default and maximum value for backgroundInterval is 600 + Assert.equal(bestUpdate.getProperty("backgroundInterval"), "600", + "the update backgroundInterval attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.serviceURL, gURLData + gHTTPHandlerPath + "?force=1", + "the update serviceURL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.channel, "test_channel", + "the update channel attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!bestUpdate.isCompleteUpdate, + "the update isCompleteUpdate attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!bestUpdate.isSecurityUpdate, + "the update isSecurityUpdate attribute" + MSG_SHOULD_EQUAL); + // Check that installDate is within 10 seconds of the current date. + Assert.ok((Date.now() - bestUpdate.installDate) < 10000, + "the update installDate attribute should be within 10 seconds of " + + "the current time"); + Assert.ok(!bestUpdate.statusText, + "the update statusText attribute" + MSG_SHOULD_EQUAL); + // nsIUpdate:state returns an empty string when no action has been performed + // on an available update + Assert.equal(bestUpdate.state, "", + "the update state attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.errorCode, 0, + "the update errorCode attribute" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.patchCount, 2, + "the update patchCount attribute" + MSG_SHOULD_EQUAL); + // XXX TODO - test nsIUpdate:serialize + + Assert.equal(bestUpdate.getProperty("custom1_attr"), "custom1 value", + "the update custom1_attr property" + MSG_SHOULD_EQUAL); + Assert.equal(bestUpdate.getProperty("custom2_attr"), "custom2 value", + "the update custom2_attr property" + MSG_SHOULD_EQUAL); + + let patch = bestUpdate.getPatchAt(0); + Assert.equal(patch.type, "complete", + "the update patch type attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.URL, "http://complete/", + "the update patch URL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.hashFunction, "SHA1", + "the update patch hashFunction attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.hashValue, "98db9dad8e1d80eda7e1170d0187d6f53e477059", + "the update patch hashValue attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.size, 9856459, + "the update patch size attribute" + MSG_SHOULD_EQUAL); + // The value for patch.state can be the string 'null' as a valid value. This + // is confusing if it returns null which is an invalid value since the test + // failure output will show a failure for null == null. To lessen the + // confusion first check that the typeof for patch.state is string. + Assert.equal(typeof patch.state, "string", + "the update patch state typeof value should equal |string|"); + Assert.equal(patch.state, STATE_NONE, + "the update patch state attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!patch.selected, + "the update patch selected attribute" + MSG_SHOULD_EQUAL); + // XXX TODO - test nsIUpdatePatch:serialize + + patch = bestUpdate.getPatchAt(1); + Assert.equal(patch.type, "partial", + "the update patch type attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.URL, "http://partial/", + "the update patch URL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.hashFunction, "SHA1", + "the update patch hashFunction attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.hashValue, "e6678ca40ae7582316acdeddf3c133c9c8577de4", + "the update patch hashValue attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.size, 1316138, + "the update patch size attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.state, STATE_NONE, + "the update patch state attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!patch.selected, + "the update patch selected attribute" + MSG_SHOULD_EQUAL); + // XXX TODO - test nsIUpdatePatch:serialize + + run_test_pt03(); +} + +// Empty update xml (an empty xml file returns a root node name of parsererror) +function run_test_pt03() { + gResponseBody = "<parsererror/>"; + run_test_helper_pt1("testing empty update xml", + null, run_test_pt04); +} + +// no updates available +function run_test_pt04() { + gResponseBody = getRemoteUpdatesXMLString(""); + run_test_helper_pt1("testing no updates available", + 0, run_test_pt05); +} + +// one update available with two patches +function run_test_pt05() { + let patches = getRemotePatchString("complete"); + patches += getRemotePatchString("partial"); + let updates = getRemoteUpdateString(patches); + gResponseBody = getRemoteUpdatesXMLString(updates); + run_test_helper_pt1("testing one update available", + 1, run_test_pt06); +} + +// three updates available each with two patches +function run_test_pt06() { + let patches = getRemotePatchString("complete"); + patches += getRemotePatchString("partial"); + let updates = getRemoteUpdateString(patches); + updates += getRemoteUpdateString(patches); + updates += getRemoteUpdateString(patches); + gResponseBody = getRemoteUpdatesXMLString(updates); + run_test_helper_pt1("testing three updates available", + 3, run_test_pt07); +} + +// one update with complete and partial patches with size 0 specified in the +// update xml +function run_test_pt07() { + let patches = getRemotePatchString("complete", null, null, null, "0"); + patches += getRemotePatchString("partial", null, null, null, "0"); + let updates = getRemoteUpdateString(patches); + gResponseBody = getRemoteUpdatesXMLString(updates); + run_test_helper_pt1("testing one update with complete and partial " + + "patches with size 0", 0, run_test_pt08); +} + +// one update with complete patch with size 0 specified in the update xml +function run_test_pt08() { + let patches = getRemotePatchString("complete", null, null, null, "0"); + let updates = getRemoteUpdateString(patches); + gResponseBody = getRemoteUpdatesXMLString(updates); + run_test_helper_pt1("testing one update with complete patch with size 0", + 0, run_test_pt9); +} + +// one update with partial patch with size 0 specified in the update xml +function run_test_pt9() { + let patches = getRemotePatchString("partial", null, null, null, "0"); + let updates = getRemoteUpdateString(patches); + gResponseBody = getRemoteUpdatesXMLString(updates); + run_test_helper_pt1("testing one update with partial patch with size 0", + 0, run_test_pt10); +} + +// check that updates for older versions of the application aren't selected +function run_test_pt10() { + let patches = getRemotePatchString("complete"); + patches += getRemotePatchString("partial"); + let updates = getRemoteUpdateString(patches, "minor", null, null, "1.0pre"); + updates += getRemoteUpdateString(patches, "minor", null, null, "1.0a"); + gResponseBody = getRemoteUpdatesXMLString(updates); + run_test_helper_pt1("testing two updates older than the current version", + 2, check_test_pt10); +} + +function check_test_pt10() { + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + Assert.ok(!bestUpdate, + "there should be no update available"); + run_test_pt11(); +} + +// check that updates for the current version of the application are selected +function run_test_pt11() { + let patches = getRemotePatchString("complete"); + patches += getRemotePatchString("partial"); + let updates = getRemoteUpdateString(patches, "minor", null, "version 1.0"); + gResponseBody = getRemoteUpdatesXMLString(updates); + run_test_helper_pt1("testing one update equal to the current version", + 1, check_test_pt11); +} + +function check_test_pt11() { + let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount); + Assert.ok(!!bestUpdate, + "there should be one update available"); + Assert.equal(bestUpdate.displayVersion, "version 1.0", + "the update displayVersion attribute" + MSG_SHOULD_EQUAL); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiAutoPref.js b/toolkit/mozapps/update/tests/unit_aus_update/uiAutoPref.js new file mode 100644 index 000000000..ee1c40bfd --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiAutoPref.js @@ -0,0 +1,75 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Components.utils.import("resource://testing-common/MockRegistrar.jsm"); + +const WindowWatcher = { + openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) { + gCheckFunc(); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]) +}; + +const WindowMediator = { + getMostRecentWindow: function(aWindowType) { + do_execute_soon(check_status); + return { getInterface: XPCOMUtils.generateQI([Ci.nsIDOMWindow]) }; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediator]) +}; + +function run_test() { + setupTestCommon(); + // Calling do_get_profile prevents an error from being logged + do_get_profile(); + + debugDump("testing that an update download doesn't start when the " + + PREF_APP_UPDATE_AUTO + " preference is false"); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_AUTO, false); + Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false); + + start_httpserver(); + setUpdateURL(gURLData + gHTTPHandlerPath); + standardInit(); + + let windowWatcherCID = + MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", + WindowWatcher); + let windowMediatorCID = + MockRegistrar.register("@mozilla.org/appshell/window-mediator;1", + WindowMediator); + do_register_cleanup(() => { + MockRegistrar.unregister(windowWatcherCID); + MockRegistrar.unregister(windowMediatorCID); + }); + + gCheckFunc = check_showUpdateAvailable; + let patches = getRemotePatchString("complete"); + let updates = getRemoteUpdateString(patches, "minor", null, null, "1.0"); + gResponseBody = getRemoteUpdatesXMLString(updates); + gAUS.notify(null); +} + +function check_status() { + let status = readStatusFile(); + Assert.notEqual(status, STATE_DOWNLOADING, + "the update state" + MSG_SHOULD_EQUAL); + + // Pause the download and reload the Update Manager with an empty update so + // the Application Update Service doesn't write the update xml files during + // xpcom-shutdown which will leave behind the test directory. + gAUS.pauseDownload(); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), true); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + reloadUpdateManagerData(); + + do_execute_soon(doTestFinish); +} + +function check_showUpdateAvailable() { + do_throw("showUpdateAvailable should not have called openWindow!"); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js new file mode 100644 index 000000000..25110be8c --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js @@ -0,0 +1,76 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Components.utils.import("resource://testing-common/MockRegistrar.jsm"); + +/** + * Test that nsIUpdatePrompt doesn't display UI for showUpdateAvailable and + * showUpdateError when the app.update.silent preference is true. + */ + +const WindowWatcher = { + openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) { + gCheckFunc(); + }, + + getNewPrompter: function(aParent) { + gCheckFunc(); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]) +}; + +function run_test() { + setupTestCommon(); + + debugDump("testing nsIUpdatePrompt notifications should not be seen " + + "when the " + PREF_APP_UPDATE_SILENT + " preference is true"); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true); + + let windowWatcherCID = + MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", + WindowWatcher); + do_register_cleanup(() => { + MockRegistrar.unregister(windowWatcherCID); + }); + + standardInit(); + + debugDump("testing showUpdateAvailable should not call openWindow"); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false); + let patches = getLocalPatchString(null, null, null, null, null, null, + STATE_FAILED); + let updates = getLocalUpdateString(patches); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_FAILED); + reloadUpdateManagerData(); + + gCheckFunc = check_showUpdateAvailable; + let update = gUpdateManager.activeUpdate; + gUP.showUpdateAvailable(update); + // Report a successful check after the call to showUpdateAvailable since it + // didn't throw and otherwise it would report no tests run. + Assert.ok(true, + "calling showUpdateAvailable should not attempt to open a window"); + + debugDump("testing showUpdateError should not call getNewPrompter"); + gCheckFunc = check_showUpdateError; + update.errorCode = WRITE_ERROR; + gUP.showUpdateError(update); + // Report a successful check after the call to showUpdateError since it + // didn't throw and otherwise it would report no tests run. + Assert.ok(true, + "calling showUpdateError should not attempt to open a window"); + + doTestFinish(); +} + +function check_showUpdateAvailable() { + do_throw("showUpdateAvailable should not have called openWindow!"); +} + +function check_showUpdateError() { + do_throw("showUpdateError should not have seen getNewPrompter!"); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js new file mode 100644 index 000000000..5b694ed30 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Cu.import("resource://testing-common/MockRegistrar.jsm"); + +const WindowWatcher = { + openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) { + check_showUpdateAvailable(); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]) +}; + +const WindowMediator = { + getMostRecentWindow: function(aWindowType) { + return null; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediator]) +}; + +function run_test() { + setupTestCommon(); + + debugDump("testing nsIUpdatePrompt notifications should not be displayed " + + "when showUpdateAvailable is called for an unsupported system " + + "update when the unsupported notification has already been " + + "shown (bug 843497)"); + + start_httpserver(); + setUpdateURL(gURLData + gHTTPHandlerPath); + standardInit(); + + let windowWatcherCID = + MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", + WindowWatcher); + let windowMediatorCID = + MockRegistrar.register("@mozilla.org/appshell/window-mediator;1", + WindowMediator); + do_register_cleanup(() => { + MockRegistrar.unregister(windowWatcherCID); + MockRegistrar.unregister(windowMediatorCID); + }); + + Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false); + Services.prefs.setBoolPref(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED, true); + // This preference is used to determine when the background update check has + // completed since a successful check will clear the preference. + Services.prefs.setIntPref(PREF_APP_UPDATE_BACKGROUNDERRORS, 1); + + gResponseBody = getRemoteUpdatesXMLString(" <update type=\"major\" " + + "name=\"Unsupported Update\" " + + "unsupported=\"true\" " + + "detailsURL=\"" + URL_HOST + + "\"></update>\n"); + gAUS.notify(null); + do_execute_soon(check_test); +} + +function check_test() { + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS)) { + do_execute_soon(check_test); + return; + } + Assert.ok(true, + PREF_APP_UPDATE_BACKGROUNDERRORS + " preference should not exist"); + + stop_httpserver(doTestFinish); +} + +function check_showUpdateAvailable() { + do_throw("showUpdateAvailable should not have called openWindow!"); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js new file mode 100644 index 000000000..e46469455 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js @@ -0,0 +1,177 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +function run_test() { + setupTestCommon(); + + debugDump("testing addition of a successful update to " + FILE_UPDATES_XML + + " and verification of update properties including the format " + + "prior to bug 530872"); + + setUpdateChannel("test_channel"); + + // This test expects that the app.update.download.backgroundInterval + // preference doesn't already exist. + Services.prefs.deleteBranch("app.update.download.backgroundInterval"); + + // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 + // and until bug 470244 is fixed this will not test the value for detailsURL + // when it isn't specified in the update xml. + let patches = getLocalPatchString("partial", "http://partial/", "SHA256", + "cd43", "86", "true", STATE_PENDING); + let updates = getLocalUpdateString(patches, "major", "New", "version 4", + "4.0", "20070811053724", + "http://details1/", + "http://service1/", "1238441300314", + "test status text", "false", + "test_channel", "true", "true", "true", + "345600", "300", "3.0", + "custom1_attr=\"custom1 value\"", + "custom2_attr=\"custom2 value\""); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + writeStatusFile(STATE_SUCCEEDED); + + patches = getLocalPatchString("complete", "http://complete/", "SHA1", "6232", + "75", "true", STATE_FAILED); + updates = getLocalUpdateString(patches, "major", "Existing", null, "3.0", + null, + "http://details2/", + "http://service2/", null, + getString("patchApplyFailure"), "true", + "test_channel", "false", null, null, "691200", + null, null, + "custom3_attr=\"custom3 value\"", + "custom4_attr=\"custom4 value\""); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), false); + + standardInit(); + + Assert.ok(!gUpdateManager.activeUpdate, + "the update manager activeUpdate attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 2, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + + debugDump("checking the activeUpdate properties"); + let update = gUpdateManager.getUpdateAt(0).QueryInterface(Ci.nsIPropertyBag); + Assert.equal(update.state, STATE_SUCCEEDED, + "the update state attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.type, "major", + "the update type attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.name, "New", + "the update name attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.displayVersion, "version 4", + "the update displayVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.appVersion, "4.0", + "the update appVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.buildID, "20070811053724", + "the update buildID attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.detailsURL, "http://details1/", + "the update detailsURL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.serviceURL, "http://service1/", + "the update serviceURL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.installDate, "1238441300314", + "the update installDate attribute" + MSG_SHOULD_EQUAL); + // statusText is updated + Assert.equal(update.statusText, getString("installSuccess"), + "the update statusText attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!update.isCompleteUpdate, + "the update isCompleteUpdate attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.channel, "test_channel", + "the update channel attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!!update.showPrompt, + "the update showPrompt attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!!update.showNeverForVersion, + "the update showNeverForVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.promptWaitTime, "345600", + "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.getProperty("backgroundInterval"), "300", + "the update backgroundInterval attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.previousAppVersion, "3.0", + "the update previousAppVersion attribute" + MSG_SHOULD_EQUAL); + // Custom attributes + Assert.equal(update.getProperty("custom1_attr"), "custom1 value", + "the update custom1_attr property" + MSG_SHOULD_EQUAL); + Assert.equal(update.getProperty("custom2_attr"), "custom2 value", + "the update custom2_attr property" + MSG_SHOULD_EQUAL); + + debugDump("checking the activeUpdate patch properties"); + let patch = update.selectedPatch; + Assert.equal(patch.type, "partial", + "the update patch type attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.URL, "http://partial/", + "the update patch URL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.hashFunction, "SHA256", + "the update patch hashFunction attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.hashValue, "cd43", + "the update patch hashValue attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.size, "86", + "the update patch size attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!!patch.selected, + "the update patch selected attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.state, STATE_SUCCEEDED, + "the update patch state attribute" + MSG_SHOULD_EQUAL); + + debugDump("checking the first update properties"); + update = gUpdateManager.getUpdateAt(1).QueryInterface(Ci.nsIPropertyBag); + Assert.equal(update.state, STATE_FAILED, + "the update state attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.name, "Existing", + "the update name attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.type, "major", + "the update type attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.displayVersion, "3.0", + "the update displayVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.appVersion, "3.0", + "the update appVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.detailsURL, "http://details2/", + "the update detailsURL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.serviceURL, "http://service2/", + "the update serviceURL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.installDate, "1238441400314", + "the update installDate attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.statusText, getString("patchApplyFailure"), + "the update statusText attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.buildID, "20080811053724", + "the update buildID attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!!update.isCompleteUpdate, + "the update isCompleteUpdate attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.channel, "test_channel", + "the update channel attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!update.showPrompt, + "the update showPrompt attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!update.showNeverForVersion, + "the update showNeverForVersion attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.promptWaitTime, "691200", + "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL); + // The default and maximum value for backgroundInterval is 600 + Assert.equal(update.getProperty("backgroundInterval"), "600", + "the update backgroundInterval attribute" + MSG_SHOULD_EQUAL); + Assert.equal(update.previousAppVersion, null, + "the update previousAppVersion attribute" + MSG_SHOULD_EQUAL); + // Custom attributes + Assert.equal(update.getProperty("custom3_attr"), "custom3 value", + "the update custom3_attr property" + MSG_SHOULD_EQUAL); + Assert.equal(update.getProperty("custom4_attr"), "custom4 value", + "the update custom4_attr property" + MSG_SHOULD_EQUAL); + + debugDump("checking the first update patch properties"); + patch = update.selectedPatch; + Assert.equal(patch.type, "complete", + "the update patch type attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.URL, "http://complete/", + "the update patch URL attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.hashFunction, "SHA1", + "the update patch hashFunction attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.hashValue, "6232", + "the update patch hashValue attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.size, "75", + "the update patch size attribute" + MSG_SHOULD_EQUAL); + Assert.ok(!!patch.selected, + "the update patch selected attribute" + MSG_SHOULD_EQUAL); + Assert.equal(patch.state, STATE_FAILED, + "the update patch state attribute" + MSG_SHOULD_EQUAL); + + doTestFinish(); +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js b/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js new file mode 100644 index 000000000..db7d90094 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js @@ -0,0 +1,305 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General URL Construction Tests */ + +const URL_PREFIX = URL_HOST + "/"; + +var gAppInfo; + +// Since gUpdateChecker.checkForUpdates uses XMLHttpRequest and XMLHttpRequest +// can be slow it combines the checks whenever possible. +function run_test() { + // This test needs access to omni.ja to read the update.locale file so don't + // use a custom directory for the application directory. + gUseTestAppDir = false; + setupTestCommon(); + + standardInit(); + gAppInfo = Cc["@mozilla.org/xre/app-info;1"]. + getService(Ci.nsIXULAppInfo). + QueryInterface(Ci.nsIXULRuntime); + do_execute_soon(run_test_pt1); +} + + +// url constructed with: +// %PRODUCT% +// %VERSION% +// %BUILD_ID% +// %BUILD_TARGET% +// %LOCALE% +// %CHANNEL% +// %PLATFORM_VERSION% +// %OS_VERSION% +// %SYSTEM_CAPABILITIES% +// %DISTRIBUTION% +// %DISTRIBUTION_VERSION% +function run_test_pt1() { + gCheckFunc = check_test_pt1; + // The code that gets the locale accesses the profile which is only available + // after calling do_get_profile in xpcshell tests. This prevents an error from + // being logged. + do_get_profile(); + + setUpdateChannel("test_channel"); + gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_ID, "test_distro"); + gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_VERSION, "test_distro_version"); + + let url = URL_PREFIX + "%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/" + + "%LOCALE%/%CHANNEL%/%PLATFORM_VERSION%/%OS_VERSION%/" + + "%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/" + + "updates.xml"; + debugDump("testing url construction - url: " + url); + setUpdateURL(url); + try { + gUpdateChecker.checkForUpdates(updateCheckListener, true); + } catch (e) { + debugDump("The following error is most likely due to a missing " + + "update.locale file"); + do_throw(e); + } +} + +function check_test_pt1() { + let url = URL_PREFIX + gAppInfo.name + "/" + gAppInfo.version + "/" + + gAppInfo.appBuildID + "/" + gAppInfo.OS + "_" + getABI() + "/" + + INSTALL_LOCALE + "/test_channel/" + gAppInfo.platformVersion + "/" + + getOSVersion() + "/" + getSystemCapabilities() + + "/test_distro/test_distro_version/updates.xml?force=1"; + // Log the urls since Assert.equal won't print the entire urls to the log. + if (gRequestURL != url) { + logTestInfo("expected url: " + url); + logTestInfo("returned url: " + gRequestURL); + } + Assert.equal(gRequestURL, url, + "the url" + MSG_SHOULD_EQUAL); + run_test_pt2(); +} + +// url constructed with: +// %CHANNEL% with distribution partners +// %CUSTOM% parameter +// force param when there already is a param - bug 454357 +function run_test_pt2() { + gCheckFunc = check_test_pt2; + let url = URL_PREFIX + "%CHANNEL%/updates.xml?custom=%CUSTOM%"; + debugDump("testing url constructed with %CHANNEL% - " + url); + setUpdateURL(url); + gDefaultPrefBranch.setCharPref(PREFBRANCH_APP_PARTNER + "test_partner1", + "test_partner1"); + gDefaultPrefBranch.setCharPref(PREFBRANCH_APP_PARTNER + "test_partner2", + "test_partner2"); + Services.prefs.setCharPref("app.update.custom", "custom"); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt2() { + let url = URL_PREFIX + "test_channel-cck-test_partner1-test_partner2/" + + "updates.xml?custom=custom&force=1"; + Assert.equal(gRequestURL, url, + "the url" + MSG_SHOULD_EQUAL); + doTestFinish(); +} + +function getABI() { + let abi; + try { + abi = gAppInfo.XPCOMABI; + } catch (e) { + do_throw("nsIXULAppInfo:XPCOMABI not defined\n"); + } + + if (IS_MACOSX) { + // Mac universal build should report a different ABI than either macppc + // or mactel. This is necessary since nsUpdateService.js will set the ABI to + // Universal-gcc3 for Mac universal builds. + let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. + getService(Ci.nsIMacUtils); + + if (macutils.isUniversalBinary) { + abi += "-u-" + macutils.architecturesInBinary; + } + } else if (IS_WIN) { + // Windows build should report the CPU architecture that it's running on. + abi += "-" + getProcArchitecture(); + } + return abi; +} + +function getOSVersion() { + let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); + let osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version"); + + if (IS_WIN) { + try { + let servicePack = getServicePack(); + osVersion += "." + servicePack; + } catch (e) { + do_throw("Failure obtaining service pack: " + e); + } + + if ("5.0" === sysInfo.getProperty("version")) { // Win2K + osVersion += " (unknown)"; + } else { + try { + osVersion += " (" + getProcArchitecture() + ")"; + } catch (e) { + do_throw("Failed to obtain processor architecture: " + e); + } + } + } + + if (osVersion) { + try { + osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")"; + } catch (e) { + // Not all platforms have a secondary widget library, so an error is + // nothing to worry about. + } + osVersion = encodeURIComponent(osVersion); + } + return osVersion; +} + +function getServicePack() { + // NOTE: This function is a helper function and not a test. Thus, + // it uses throw() instead of do_throw(). Any tests that use this function + // should catch exceptions thrown in this function and deal with them + // appropriately (usually by calling do_throw). + const BYTE = ctypes.uint8_t; + const WORD = ctypes.uint16_t; + const DWORD = ctypes.uint32_t; + const WCHAR = ctypes.char16_t; + const BOOL = ctypes.int; + + // This structure is described at: + // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx + const SZCSDVERSIONLENGTH = 128; + const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', + [ + {dwOSVersionInfoSize: DWORD}, + {dwMajorVersion: DWORD}, + {dwMinorVersion: DWORD}, + {dwBuildNumber: DWORD}, + {dwPlatformId: DWORD}, + {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, + {wServicePackMajor: WORD}, + {wServicePackMinor: WORD}, + {wSuiteMask: WORD}, + {wProductType: BYTE}, + {wReserved: BYTE} + ]); + + let kernel32 = ctypes.open("kernel32"); + try { + let GetVersionEx = kernel32.declare("GetVersionExW", + ctypes.default_abi, + BOOL, + OSVERSIONINFOEXW.ptr); + let winVer = OSVERSIONINFOEXW(); + winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; + + if (0 === GetVersionEx(winVer.address())) { + // Using "throw" instead of "do_throw" (see NOTE above) + throw ("Failure in GetVersionEx (returned 0)"); + } + + return winVer.wServicePackMajor + "." + winVer.wServicePackMinor; + } finally { + kernel32.close(); + } +} + +function getProcArchitecture() { + // NOTE: This function is a helper function and not a test. Thus, + // it uses throw() instead of do_throw(). Any tests that use this function + // should catch exceptions thrown in this function and deal with them + // appropriately (usually by calling do_throw). + const WORD = ctypes.uint16_t; + const DWORD = ctypes.uint32_t; + + // This structure is described at: + // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx + const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO', + [ + {wProcessorArchitecture: WORD}, + {wReserved: WORD}, + {dwPageSize: DWORD}, + {lpMinimumApplicationAddress: ctypes.voidptr_t}, + {lpMaximumApplicationAddress: ctypes.voidptr_t}, + {dwActiveProcessorMask: DWORD.ptr}, + {dwNumberOfProcessors: DWORD}, + {dwProcessorType: DWORD}, + {dwAllocationGranularity: DWORD}, + {wProcessorLevel: WORD}, + {wProcessorRevision: WORD} + ]); + + let kernel32 = ctypes.open("kernel32"); + try { + let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo", + ctypes.default_abi, + ctypes.void_t, + SYSTEM_INFO.ptr); + let sysInfo = SYSTEM_INFO(); + // Default to unknown + sysInfo.wProcessorArchitecture = 0xffff; + + GetNativeSystemInfo(sysInfo.address()); + switch (sysInfo.wProcessorArchitecture) { + case 9: + return "x64"; + case 6: + return "IA64"; + case 0: + return "x86"; + default: + // Using "throw" instead of "do_throw" (see NOTE above) + throw ("Unknown architecture returned from GetNativeSystemInfo: " + sysInfo.wProcessorArchitecture); + } + } finally { + kernel32.close(); + } +} + +/** + * Provides system capability information for application update though it may + * be used by other consumers. + */ +function getSystemCapabilities() { + if (IS_WIN) { + const PF_MMX_INSTRUCTIONS_AVAILABLE = 3; // MMX + const PF_XMMI_INSTRUCTIONS_AVAILABLE = 6; // SSE + const PF_XMMI64_INSTRUCTIONS_AVAILABLE = 10; // SSE2 + const PF_SSE3_INSTRUCTIONS_AVAILABLE = 13; // SSE3 + + let lib = ctypes.open("kernel32.dll"); + let IsProcessorFeaturePresent = lib.declare("IsProcessorFeaturePresent", + ctypes.winapi_abi, + ctypes.int32_t, /* success */ + ctypes.uint32_t); /* DWORD */ + let instructionSet = "unknown"; + try { + if (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE)) { + instructionSet = "SSE3"; + } else if (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) { + instructionSet = "SSE2"; + } else if (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) { + instructionSet = "SSE"; + } else if (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE)) { + instructionSet = "MMX"; + } + } catch (e) { + Cu.reportError("Error getting processor instruction set. " + + "Exception: " + e); + } + + lib.close(); + return instructionSet; + } + + return "NA"; +} diff --git a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini new file mode 100644 index 000000000..0d2205046 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini @@ -0,0 +1,27 @@ +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. + +[DEFAULT] +tags = appupdate +head = head_update.js +tail = + +[canCheckForAndCanApplyUpdates.js] +[urlConstruction.js] +[updateManagerXML.js] +[remoteUpdateXML.js] +[downloadAndHashCheckMar.js] +[cleanupDownloadingForOlderAppVersion.js] +[cleanupDownloadingForDifferentChannel.js] +[cleanupDownloadingForSameVersionAndBuildID.js] +[cleanupDownloadingIncorrectStatus.js] +[cleanupPendingVersionFileIncorrectStatus.js] +[cleanupSuccessLogMove.js] +[cleanupSuccessLogsFIFO.js] +[downloadInterruptedRecovery.js] +[downloadResumeForSameAppVersion.js] +[downloadCompleteAfterPartialFailure.js] +[uiSilentPref.js] +[uiUnsupportedAlreadyNotified.js] +[uiAutoPref.js] diff --git a/toolkit/mozapps/update/tests/unit_base_updater/.eslintrc.js b/toolkit/mozapps/update/tests/unit_base_updater/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/toolkit/mozapps/update/tests/unit_base_updater/head_update.js b/toolkit/mozapps/update/tests/unit_base_updater/head_update.js new file mode 100644 index 000000000..9715c5828 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/head_update.js @@ -0,0 +1,8 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const IS_SERVICE_TEST = false; + +/* import-globals-from ../data/xpcshellUtilsAUS.js */ +load("../data/xpcshellUtilsAUS.js"); diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgCallbackFileNotInInstallDirFailure.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgCallbackFileNotInInstallDirFailure.js new file mode 100644 index 000000000..f3f767394 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgCallbackFileNotInInstallDirFailure.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Callback file not in install directory or a sub-directory of the install + directory failure */ + +const STATE_AFTER_RUNUPDATE = STATE_FAILED_INVALID_CALLBACK_DIR_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = getTestDirFile(FILE_HELPER_BIN).path; + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, null, null, path); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgCallbackFilePathTooLongFailure.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgCallbackFilePathTooLongFailure.js new file mode 100644 index 000000000..969f84f9d --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgCallbackFilePathTooLongFailure.js @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Too long callback file path failure test */ + +const STATE_AFTER_RUNUPDATE = STATE_FAILED_INVALID_CALLBACK_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = "123456789"; + if (IS_WIN) { + path = "\\" + path; + path = path.repeat(30); // 300 characters + path = "C:" + path; + } else { + path = "/" + path; + path = path.repeat(1000); // 10000 characters + } + + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, null, null, path); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallDirPathTooLongFailure.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallDirPathTooLongFailure.js new file mode 100644 index 000000000..70e03646a --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallDirPathTooLongFailure.js @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Too long install directory path failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_INSTALL_DIR_PATH_ERROR + : STATE_FAILED_INVALID_INSTALL_DIR_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = "123456789"; + if (IS_WIN) { + path = "\\" + path; + path = path.repeat(30); // 300 characters + path = "C:" + path; + } else { + path = "/" + path; + path = path.repeat(1000); // 10000 characters + } + + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, path, null, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallDirPathTraversalFailure.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallDirPathTraversalFailure.js new file mode 100644 index 000000000..330578de6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallDirPathTraversalFailure.js @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Install directory path traversal failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_INSTALL_DIR_PATH_ERROR + : STATE_FAILED_INVALID_INSTALL_DIR_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = "123456789"; + if (IS_WIN) { + path = "C:\\" + path + "\\..\\" + path; + } else { + path = "/" + path + "/../" + path; + } + + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, path, null, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallWorkingDirPathNotSameFailure_win.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallWorkingDirPathNotSameFailure_win.js new file mode 100644 index 000000000..8ddb34af0 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgInstallWorkingDirPathNotSameFailure_win.js @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Different install and working directories for a regular update failure */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_APPLYTO_DIR_ERROR + : STATE_FAILED_INVALID_APPLYTO_DIR_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = getApplyDirFile("..", false).path; + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, null, path, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgPatchDirPathTraversalFailure.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgPatchDirPathTraversalFailure.js new file mode 100644 index 000000000..c8ae3f0c6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgPatchDirPathTraversalFailure.js @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Patch directory path traversal failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = getUpdatesPatchDir(); + if (IS_WIN) { + path = path + "\\..\\"; + } else { + path = path + "/../"; + } + + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, path, null, null, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgStageDirNotInInstallDirFailure_win.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgStageDirNotInInstallDirFailure_win.js new file mode 100644 index 000000000..e9b227657 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgStageDirNotInInstallDirFailure_win.js @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Different install and working directories for a regular update failure */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_APPLYTO_DIR_STAGED_ERROR + : STATE_FAILED_INVALID_APPLYTO_DIR_STAGED_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = getApplyDirFile("..", false).path; + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true, null, null, path, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgWorkingDirPathLocalUNCFailure_win.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgWorkingDirPathLocalUNCFailure_win.js new file mode 100644 index 000000000..87bbad4aa --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgWorkingDirPathLocalUNCFailure_win.js @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Working directory path local UNC failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_WORKING_DIR_PATH_ERROR + : STATE_FAILED_INVALID_WORKING_DIR_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = "\\\\.\\" + getApplyDirFile(null, false).path; + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, null, path, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/invalidArgWorkingDirPathRelativeFailure.js b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgWorkingDirPathRelativeFailure.js new file mode 100644 index 000000000..a550909b2 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/invalidArgWorkingDirPathRelativeFailure.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Relative working directory path failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_WORKING_DIR_PATH_ERROR + : STATE_FAILED_INVALID_WORKING_DIR_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, null, "test", null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyDirLockedStageFailure_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyDirLockedStageFailure_win.js new file mode 100644 index 000000000..b9f793236 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyDirLockedStageFailure_win.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test applying an update by staging an update and launching an application to + * apply it. + */ + +const STATE_AFTER_STAGE = STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + createUpdateInProgressLockFile(getAppBaseDir()); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(false); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + removeUpdateInProgressLockFile(getAppBaseDir()); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(PERFORMING_STAGED_UPDATE); + checkUpdateLogContains(ERR_UPDATE_IN_PROGRESS); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js new file mode 100644 index 000000000..a606720b7 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test applying an update by staging an update and launching an application to + * apply it. + */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, undefined); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true, false); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + lockDirectory(getAppBaseDir().path); + // Switch the application to the staged application that was updated. + runUpdateUsingApp(STATE_SUCCEEDED); +} + +/** + * Called after the call to runUpdateUsingApp finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + + let updatesDir = getUpdatesPatchDir(); + Assert.ok(updatesDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(updatesDir.path)); + + let log = getUpdateLog(FILE_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js new file mode 100644 index 000000000..00b38adc7 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageOldVersionFailure.js @@ -0,0 +1,88 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test a replace request for a staged update with a version file that specifies + * an older version failure. The same check is used in nsUpdateDriver.cpp for + * all update types which is why there aren't tests for the maintenance service + * as well as for other update types. + */ + +const STATE_AFTER_STAGE = STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(false); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Change the active update to an older version to simulate installing a new + // version of the application while there is an update that has been staged. + let channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); + let patches = getLocalPatchString(null, null, null, null, null, "true", + STATE_AFTER_STAGE); + let updates = getLocalUpdateString(patches, null, null, null, "1.0", null, + null, null, null, null, "true", channel); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + // Change the version file to an older version to simulate installing a new + // version of the application while there is an update that has been staged. + writeVersionFile("1.0"); + reloadUpdateManagerData(); + // Try to switch the application to the staged application that was updated. + runUpdateUsingApp(STATE_AFTER_STAGE); +} + +/** + * Called after the call to runUpdateUsingApp finishes. + */ +function runUpdateFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_STAGE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile, IS_MACOSX ? false : true, false); + + let updatesDir = getUpdatesPatchDir(); + Assert.ok(updatesDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(updatesDir.path)); + + let log = getUpdateLog(FILE_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageSuccess.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageSuccess.js new file mode 100644 index 000000000..5b9b08156 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageSuccess.js @@ -0,0 +1,82 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test applying an update by staging an update and launching an application to + * apply it. + */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, true); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdateUsingApp(STATE_SUCCEEDED); +} + +/** + * Called after the call to runUpdateUsingApp finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + + let updatesDir = getUpdatesPatchDir(); + Assert.ok(updatesDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(updatesDir.path)); + + let log = getUpdateLog(FILE_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateSuccess.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateSuccess.js new file mode 100644 index 000000000..e76233fe6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateSuccess.js @@ -0,0 +1,65 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test applying an update by staging an update and launching an application to + * apply it. + */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + // The third parameter will test that a full path to the post update binary + // doesn't execute. + setupUpdaterTest(FILE_COMPLETE_MAR, undefined, + getApplyDirFile(null, true).path + "/"); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdateUsingApp(STATE_SUCCEEDED); +} + +/** + * Called after the call to runUpdateUsingApp finishes. + */ +function runUpdateFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + + let updatesDir = getUpdatesPatchDir(); + Assert.ok(updatesDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(updatesDir.path)); + + let log = getUpdateLog(FILE_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js new file mode 100644 index 000000000..b1505d58e --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js @@ -0,0 +1,70 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Application in use complete MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(DIR_RESOURCES + gCallbackBinFile, false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js new file mode 100644 index 000000000..a1cc7d043 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js @@ -0,0 +1,113 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Application in use complete MAR file staged patch apply success test */ + +const START_STATE = STATE_PENDING; +const STATE_AFTER_STAGE = STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestFiles[gTestFiles.length - 1].originalContents = null; + gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n"; + gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, true); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + setupSymLinks(); + runHelperFileInUse(DIR_RESOURCES + gCallbackBinFile, false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + checkSymLinks(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + checkCallbackLog(); +} + +/** + * Setup symlinks for the test. + */ +function setupSymLinks() { + if (IS_UNIX) { + removeSymlink(); + createSymlink(); + do_register_cleanup(removeSymlink); + gTestFiles.splice(gTestFiles.length - 3, 0, + { + description: "Readable symlink", + fileName: "link", + relPathDir: DIR_RESOURCES, + originalContents: "test", + compareContents: "test", + originalFile: null, + compareFile: null, + originalPerms: 0o666, + comparePerms: 0o666 + }); + } +} + +/** + * Checks the state of the symlinks for the test. + */ +function checkSymLinks() { + if (IS_UNIX) { + checkSymlink(); + } +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js new file mode 100644 index 000000000..93333cade --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js @@ -0,0 +1,62 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Application in use complete MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(DIR_RESOURCES + gCallbackBinFile, false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js new file mode 100644 index 000000000..79e54c182 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Replace app binary complete MAR file staged patch apply success test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + gCallbackBinFile = "exe0.exe"; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js new file mode 100644 index 000000000..b1f84715f --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Patch app binary partial MAR file staged patch apply success test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + gCallbackBinFile = "exe0.exe"; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js new file mode 100644 index 000000000..85e92d290 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Replace app binary complete MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + gCallbackBinFile = "exe0.exe"; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js new file mode 100644 index 000000000..1212c9ba2 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Patch app binary partial MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + gCallbackBinFile = "exe0.exe"; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js new file mode 100644 index 000000000..960c96f7b --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Partial MAR File Patch Apply Failure Test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestFiles[11].originalFile = "partial.png"; + gTestDirs = gTestDirsPartialSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + // If execv is used the updater process will turn into the callback process + // and the updater's return code will be that of the callback process. + runUpdate(STATE_FAILED_LOADSOURCE_ERROR_WRONG_SIZE, false, (USE_EXECV ? 0 : 1), + true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusFile(), STATE_NONE, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_FAILED, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, LOADSOURCE_ERROR_WRONG_SIZE, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContents(LOG_PARTIAL_FAILURE); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js new file mode 100644 index 000000000..b39595f92 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailureComplete_win.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use complete MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestFiles[13].relPathDir + gTestFiles[13].fileName, + false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js new file mode 100644 index 000000000..06d386ad6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageFailurePartial_win.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use partial MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestFiles[11].relPathDir + gTestFiles[11].fileName, + false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js new file mode 100644 index 000000000..89a2fff5e --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use complete MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestFiles[13].relPathDir + gTestFiles[13].fileName, + false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + checkUpdateLogContains(STATE_SUCCEEDED + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js new file mode 100644 index 000000000..ea85ddccc --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use partial MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestFiles[11].relPathDir + gTestFiles[11].fileName, + false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + checkUpdateLogContains(STATE_SUCCEEDED + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js new file mode 100644 index 000000000..c5efaa8c0 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked complete MAR file patch apply failure test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperLockFile(gTestFiles[3]); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_FAILED_WRITE_ERROR, false, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusFile(), STATE_PENDING, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_PENDING, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, WRITE_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_BACKUP_CREATE_7); + checkUpdateLogContains(STATE_FAILED_WRITE_ERROR + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js new file mode 100644 index 000000000..4fdbadb5b --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked partial MAR file patch apply failure test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperLockFile(gTestFiles[2]); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_FAILED_READ_ERROR, false, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusFile(), STATE_NONE, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_FAILED, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, READ_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_UNABLE_OPEN_DEST); + checkUpdateLogContains(STATE_FAILED_READ_ERROR + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js new file mode 100644 index 000000000..4d12f4e42 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked complete MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperLockFile(gTestFiles[3]); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + // Files aren't checked after staging since this test locks a file which + // prevents reading the file. + checkUpdateLogContains(ERR_ENSURE_COPY); + // Switch the application to the staged application that was updated. + runUpdate(STATE_FAILED_WRITE_ERROR, false, 1, false); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusFile(), STATE_PENDING, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 2, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_PENDING, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, WRITE_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_BACKUP_CREATE_7); + checkUpdateLogContains(STATE_FAILED_WRITE_ERROR + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js new file mode 100644 index 000000000..5f64df34c --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js @@ -0,0 +1,70 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked partial MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperLockFile(gTestFiles[2]); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + // Files aren't checked after staging since this test locks a file which + // prevents reading the file. + checkUpdateLogContains(ERR_ENSURE_COPY); + // Switch the application to the staged application that was updated. + runUpdate(STATE_FAILED_READ_ERROR, false, 1, false); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusFile(), STATE_NONE, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 2, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_FAILED, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, READ_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_UNABLE_OPEN_DEST); + checkUpdateLogContains(STATE_FAILED_READ_ERROR + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailureComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailureComplete_win.js new file mode 100644 index 000000000..b83bafccc --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailureComplete_win.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir complete MAR file staged patch apply failure + test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestDirs[4].relPathDir + gTestDirs[4].subDirs[0] + + gTestDirs[4].subDirFiles[0], true); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailurePartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailurePartial_win.js new file mode 100644 index 000000000..39ea485cd --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageFailurePartial_win.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir partial MAR file staged patch apply failure + test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestDirs[2].relPathDir + gTestDirs[2].files[0], true); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js new file mode 100644 index 000000000..a71bb8d49 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir complete MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestDirs[4].relPathDir + gTestDirs[4].subDirs[0] + + gTestDirs[4].subDirFiles[0], true); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + checkUpdateLogContains(STATE_SUCCEEDED + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js new file mode 100644 index 000000000..2cbe70ed8 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js @@ -0,0 +1,62 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir partial MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestDirs[2].relPathDir + gTestDirs[2].files[0], true); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + checkUpdateLogContains(STATE_SUCCEEDED + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js new file mode 100644 index 000000000..a9ce23420 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Partial MAR File Staged Patch Apply Failure Test */ + +const STATE_AFTER_STAGE = STATE_FAILED; +gStagingRemovedUpdate = true; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestFiles[11].originalFile = "partial.png"; + gTestDirs = gTestDirsPartialSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, LOADSOURCE_ERROR_WRONG_SIZE, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_LOADSOURCEFILE_FAILED); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js new file mode 100644 index 000000000..f7745f68f --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js @@ -0,0 +1,132 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Complete MAR File Staged Patch Apply Test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestFiles[gTestFiles.length - 1].originalContents = null; + gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n"; + gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + gTestDirs = gTestDirsCompleteSuccess; + setupDistributionDir(); + setupSymLinks(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + checkSymLinks(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + checkDistributionDir(); + checkCallbackLog(); +} + +/** + * Setup the state of the distribution directory for the test. + */ +function setupDistributionDir() { + if (IS_MACOSX) { + // Create files in the old distribution directory location to verify that + // the directory and its contents are removed when there is a distribution + // directory in the new location. + let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true); + writeFile(testFile, "test\n"); + testFile = getApplyDirFile(DIR_MACOS + "distribution/test1/testFile", true); + writeFile(testFile, "test\n"); + } +} + +/** + * Checks the state of the distribution directory for the test. + */ +function checkDistributionDir() { + if (IS_MACOSX) { + let distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + checkUpdateLogContains(REMOVE_OLD_DIST_DIR); + } +} + +/** + * Setup symlinks for the test. + */ +function setupSymLinks() { + // Don't test symlinks on Mac OS X in this test since it tends to timeout. + // It is tested on Mac OS X in marAppInUseStageSuccessComplete_unix.js + if (IS_UNIX && !IS_MACOSX) { + removeSymlink(); + createSymlink(); + do_register_cleanup(removeSymlink); + gTestFiles.splice(gTestFiles.length - 3, 0, + { + description: "Readable symlink", + fileName: "link", + relPathDir: DIR_RESOURCES, + originalContents: "test", + compareContents: "test", + originalFile: null, + compareFile: null, + originalPerms: 0o666, + comparePerms: 0o666 + }); + } +} + +/** + * Checks the state of the symlinks for the test. + */ +function checkSymLinks() { + // Don't test symlinks on Mac OS X in this test since it tends to timeout. + // It is tested on Mac OS X in marAppInUseStageSuccessComplete_unix.js + if (IS_UNIX && !IS_MACOSX) { + checkSymlink(); + } +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js new file mode 100644 index 000000000..ef15326de --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js @@ -0,0 +1,112 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Partial MAR File Staged Patch Apply Test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestFiles[gTestFiles.length - 2].originalContents = null; + gTestFiles[gTestFiles.length - 2].compareContents = "FromPartial\n"; + gTestFiles[gTestFiles.length - 2].comparePerms = 0o644; + gTestDirs = gTestDirsPartialSuccess; + preventDistributionFiles(); + setupDistributionDir(); + setupUpdaterTest(FILE_PARTIAL_MAR, true); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true, false, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true, true); + checkDistributionDir(); + checkCallbackLog(); +} + +/** + * Setup the state of the distribution directory for the test. + */ +function setupDistributionDir() { + if (IS_MACOSX) { + // Create files in the old distribution directory location to verify that + // the directory and its contents are moved to the new location on update. + let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true); + writeFile(testFile, "test\n"); + testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true); + writeFile(testFile, "test\n"); + } +} + +/** + * Checks the state of the distribution directory. + */ +function checkDistributionDir() { + let distributionDir = getApplyDirFile(DIR_RESOURCES + "distribution", true); + if (IS_MACOSX) { + Assert.ok(distributionDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(distributionDir.path)); + + let testFile = getApplyDirFile(DIR_RESOURCES + "distribution/testFile", true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + testFile = getApplyDirFile(DIR_RESOURCES + "distribution/test/testFile", true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + + checkUpdateLogContains(MOVE_OLD_DIST_DIR); + } else { + debugDump("testing that files aren't added with an add-if instruction " + + "when the file's destination directory doesn't exist"); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + } +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js new file mode 100644 index 000000000..1008e867f --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js @@ -0,0 +1,96 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Complete MAR File Patch Apply Test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + preventDistributionFiles(); + setupDistributionDir(); + setupUpdaterTest(FILE_COMPLETE_MAR, true); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, false, false, true); + checkDistributionDir(); + checkCallbackLog(); +} + +/** + * Setup the state of the distribution directory for the test. + */ +function setupDistributionDir() { + if (IS_MACOSX) { + // Create files in the old distribution directory location to verify that + // the directory and its contents are moved to the new location on update. + let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true); + writeFile(testFile, "test\n"); + testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true); + writeFile(testFile, "test\n"); + } +} + +/** + * Checks the state of the distribution directory. + */ +function checkDistributionDir() { + let distributionDir = getApplyDirFile(DIR_RESOURCES + "distribution", true); + if (IS_MACOSX) { + Assert.ok(distributionDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(distributionDir.path)); + + let testFile = getApplyDirFile(DIR_RESOURCES + "distribution/testFile", true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + testFile = getApplyDirFile(DIR_RESOURCES + "distribution/test/testFile", true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + + checkUpdateLogContains(MOVE_OLD_DIST_DIR); + } else { + debugDump("testing that files aren't added with an add-if instruction " + + "when the file's destination directory doesn't exist"); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + } +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js new file mode 100644 index 000000000..616390f55 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js @@ -0,0 +1,79 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Partial MAR File Patch Apply Test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestFiles[gTestFiles.length - 1].originalContents = null; + gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n"; + gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + gTestFiles[gTestFiles.length - 2].originalContents = null; + gTestFiles[gTestFiles.length - 2].compareContents = "FromPartial\n"; + gTestFiles[gTestFiles.length - 2].comparePerms = 0o644; + gTestDirs = gTestDirsPartialSuccess; + setupDistributionDir(); + // The third parameter will test that a relative path that contains a + // directory traversal to the post update binary doesn't execute. + setupUpdaterTest(FILE_PARTIAL_MAR, false, "test/../"); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS); + checkDistributionDir(); + checkCallbackLog(); +} + +/** + * Setup the state of the distribution directory for the test. + */ +function setupDistributionDir() { + if (IS_MACOSX) { + // Create files in the old distribution directory location to verify that + // the directory and its contents are removed when there is a distribution + // directory in the new location. + let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true); + writeFile(testFile, "test\n"); + testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true); + writeFile(testFile, "test\n"); + } +} + +/** + * Checks the state of the distribution directory. + */ +function checkDistributionDir() { + if (IS_MACOSX) { + let distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + checkUpdateLogContains(REMOVE_OLD_DIST_DIR); + } +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js b/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js new file mode 100644 index 000000000..86a2eb821 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Test version downgrade MAR security check */ + +function run_test() { + if (!MOZ_VERIFY_MAR_SIGNATURE) { + return; + } + + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_OLD_VERSION_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + // If execv is used the updater process will turn into the callback process + // and the updater's return code will be that of the callback process. + runUpdate(STATE_FAILED_VERSION_DOWNGRADE_ERROR, false, (USE_EXECV ? 0 : 1), + false); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_FAILED, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, VERSION_DOWNGRADE_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(STATE_FAILED_VERSION_DOWNGRADE_ERROR); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js new file mode 100644 index 000000000..6db906fbc --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js @@ -0,0 +1,51 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Test product/channel MAR security check */ + +function run_test() { + if (!MOZ_VERIFY_MAR_SIGNATURE) { + return; + } + + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_WRONG_CHANNEL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + // If execv is used the updater process will turn into the callback process + // and the updater's return code will be that of the callback process. + runUpdate(STATE_FAILED_MAR_CHANNEL_MISMATCH_ERROR, false, (USE_EXECV ? 0 : 1), + false); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_FAILED, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, MAR_CHANNEL_MISMATCH_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(STATE_FAILED_MAR_CHANNEL_MISMATCH_ERROR); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini new file mode 100644 index 000000000..2b77bee7a --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini @@ -0,0 +1,136 @@ +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. + +; Tests that require the updater binary. These tests should never run on Android +; which doesn't use the updater binary as other applications do and are excluded +; from running the tests in the moz.build file. + +[DEFAULT] +tags = appupdate +head = head_update.js +tail = + +[invalidArgCallbackFileNotInInstallDirFailure.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[invalidArgCallbackFilePathTooLongFailure.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[invalidArgInstallDirPathTooLongFailure.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[invalidArgInstallDirPathTraversalFailure.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[invalidArgInstallWorkingDirPathNotSameFailure_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[invalidArgPatchDirPathTraversalFailure.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[invalidArgStageDirNotInInstallDirFailure_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[invalidArgWorkingDirPathLocalUNCFailure_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[invalidArgWorkingDirPathRelativeFailure.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marSuccessComplete.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marSuccessPartial.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marFailurePartial.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marStageSuccessComplete.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marStageSuccessPartial.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marVersionDowngrade.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 and mar signing +[marWrongChannel.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 and mar signing +[marStageFailurePartial.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marCallbackAppSuccessComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marCallbackAppSuccessPartial_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marCallbackAppStageSuccessComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marCallbackAppStageSuccessPartial_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marAppInUseSuccessComplete.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marAppInUseStageSuccessComplete_unix.js] +skip-if = os == 'win' +reason = not a Windows test +[marAppInUseStageFailureComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marFileLockedFailureComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marFileLockedFailurePartial_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marFileLockedStageFailureComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marFileLockedStageFailurePartial_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marFileInUseSuccessComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marFileInUseSuccessPartial_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marRMRFDirFileInUseSuccessComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marRMRFDirFileInUseSuccessPartial_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marFileInUseStageFailureComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marFileInUseStageFailurePartial_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marRMRFDirFileInUseStageFailureComplete_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marRMRFDirFileInUseStageFailurePartial_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marAppApplyDirLockedStageFailure_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marAppApplyUpdateAppBinInUseStageSuccess_win.js] +skip-if = os != 'win' || debug && (os_version == '5.1' || os_version == '5.2') +reason = Windows only test and bug 1291985 +[marAppApplyUpdateSuccess.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marAppApplyUpdateStageSuccess.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +[marAppApplyUpdateStageOldVersionFailure.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 diff --git a/toolkit/mozapps/update/tests/unit_service_updater/.eslintrc.js b/toolkit/mozapps/update/tests/unit_service_updater/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/toolkit/mozapps/update/tests/unit_service_updater/bootstrapSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/bootstrapSvc.js new file mode 100644 index 000000000..015fbd0cb --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/bootstrapSvc.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Bootstrap the tests using the service by installing our own version of the service */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + // We don't actually care if the MAR has any data, we only care about the + // application return code and update.status result. + gTestFiles = gTestFilesCommon; + gTestDirs = []; + setupUpdaterTest(FILE_COMPLETE_MAR, null); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdateUsingService finishes. + */ +function runUpdateFinished() { + checkFilesAfterUpdateSuccess(getApplyDirFile, false, false); + + // We need to check the service log even though this is a bootstrap + // because the app bin could be in use by this test by the time the next + // test runs. + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/checkUpdaterSigSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/checkUpdaterSigSvc.js new file mode 100644 index 000000000..bf765ee78 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/checkUpdaterSigSvc.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * We skip authenticode cert checks from the service udpates + * so that we can use updater-xpcshell with the wrong certs for testing. + * This tests that code path. */ + +function run_test() { + if (!IS_AUTHENTICODE_CHECK_ENABLED) { + return; + } + + let binDir = getGREBinDir(); + let maintenanceServiceBin = binDir.clone(); + maintenanceServiceBin.append(FILE_MAINTENANCE_SERVICE_BIN); + + let updaterBin = binDir.clone(); + updaterBin.append(FILE_UPDATER_BIN); + + debugDump("Launching maintenance service bin: " + + maintenanceServiceBin.path + " to check updater: " + + updaterBin.path + " signature."); + + // Bypass the manifest and run as invoker + gEnv.set("__COMPAT_LAYER", "RunAsInvoker"); + + let dummyInstallPath = "---"; + let maintenanceServiceBinArgs = ["check-cert", dummyInstallPath, + updaterBin.path]; + let maintenanceServiceBinProcess = Cc["@mozilla.org/process/util;1"]. + createInstance(Ci.nsIProcess); + maintenanceServiceBinProcess.init(maintenanceServiceBin); + maintenanceServiceBinProcess.run(true, maintenanceServiceBinArgs, + maintenanceServiceBinArgs.length); + Assert.equal(maintenanceServiceBinProcess.exitValue, 0, + "the maintenance service exit value should be 0"); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/head_update.js b/toolkit/mozapps/update/tests/unit_service_updater/head_update.js new file mode 100644 index 000000000..38be4ee39 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/head_update.js @@ -0,0 +1,8 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const IS_SERVICE_TEST = true; + +/* import-globals-from ../data/xpcshellUtilsAUS.js */ +load("../data/xpcshellUtilsAUS.js"); diff --git a/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallDirPathTooLongFailureSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallDirPathTooLongFailureSvc.js new file mode 100644 index 000000000..70e03646a --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallDirPathTooLongFailureSvc.js @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Too long install directory path failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_INSTALL_DIR_PATH_ERROR + : STATE_FAILED_INVALID_INSTALL_DIR_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = "123456789"; + if (IS_WIN) { + path = "\\" + path; + path = path.repeat(30); // 300 characters + path = "C:" + path; + } else { + path = "/" + path; + path = path.repeat(1000); // 10000 characters + } + + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, path, null, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallDirPathTraversalFailureSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallDirPathTraversalFailureSvc.js new file mode 100644 index 000000000..330578de6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallDirPathTraversalFailureSvc.js @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Install directory path traversal failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_INSTALL_DIR_PATH_ERROR + : STATE_FAILED_INVALID_INSTALL_DIR_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = "123456789"; + if (IS_WIN) { + path = "C:\\" + path + "\\..\\" + path; + } else { + path = "/" + path + "/../" + path; + } + + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, path, null, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallWorkingDirPathNotSameFailureSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallWorkingDirPathNotSameFailureSvc_win.js new file mode 100644 index 000000000..8ddb34af0 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgInstallWorkingDirPathNotSameFailureSvc_win.js @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Different install and working directories for a regular update failure */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_APPLYTO_DIR_ERROR + : STATE_FAILED_INVALID_APPLYTO_DIR_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = getApplyDirFile("..", false).path; + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, null, path, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/invalidArgPatchDirPathTraversalFailureSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgPatchDirPathTraversalFailureSvc.js new file mode 100644 index 000000000..c8ae3f0c6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgPatchDirPathTraversalFailureSvc.js @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Patch directory path traversal failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = getUpdatesPatchDir(); + if (IS_WIN) { + path = path + "\\..\\"; + } else { + path = path + "/../"; + } + + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, path, null, null, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/invalidArgStageDirNotInInstallDirFailureSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgStageDirNotInInstallDirFailureSvc_win.js new file mode 100644 index 000000000..e9b227657 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgStageDirNotInInstallDirFailureSvc_win.js @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Different install and working directories for a regular update failure */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_APPLYTO_DIR_STAGED_ERROR + : STATE_FAILED_INVALID_APPLYTO_DIR_STAGED_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = getApplyDirFile("..", false).path; + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true, null, null, path, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/invalidArgWorkingDirPathLocalUNCFailureSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgWorkingDirPathLocalUNCFailureSvc_win.js new file mode 100644 index 000000000..87bbad4aa --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgWorkingDirPathLocalUNCFailureSvc_win.js @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Working directory path local UNC failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_WORKING_DIR_PATH_ERROR + : STATE_FAILED_INVALID_WORKING_DIR_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + let path = "\\\\.\\" + getApplyDirFile(null, false).path; + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, null, path, null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/invalidArgWorkingDirPathRelativeFailureSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgWorkingDirPathRelativeFailureSvc.js new file mode 100644 index 000000000..a550909b2 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/invalidArgWorkingDirPathRelativeFailureSvc.js @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* Relative working directory path failure test */ + +const STATE_AFTER_RUNUPDATE = + IS_SERVICE_TEST ? STATE_FAILED_SERVICE_INVALID_WORKING_DIR_PATH_ERROR + : STATE_FAILED_INVALID_WORKING_DIR_PATH_ERROR; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_AFTER_RUNUPDATE, false, 1, true, null, null, "test", null); +} + +/** + * Called after the call to runUpdateUsingUpdater finishes. + */ +function runUpdateFinished() { + standardInit(); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyDirLockedStageFailureSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyDirLockedStageFailureSvc_win.js new file mode 100644 index 000000000..b9f793236 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyDirLockedStageFailureSvc_win.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test applying an update by staging an update and launching an application to + * apply it. + */ + +const STATE_AFTER_STAGE = STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + createUpdateInProgressLockFile(getAppBaseDir()); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(false); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + removeUpdateInProgressLockFile(getAppBaseDir()); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(PERFORMING_STAGED_UPDATE); + checkUpdateLogContains(ERR_UPDATE_IN_PROGRESS); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js new file mode 100644 index 000000000..a606720b7 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js @@ -0,0 +1,83 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test applying an update by staging an update and launching an application to + * apply it. + */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, undefined); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true, false); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + lockDirectory(getAppBaseDir().path); + // Switch the application to the staged application that was updated. + runUpdateUsingApp(STATE_SUCCEEDED); +} + +/** + * Called after the call to runUpdateUsingApp finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + + let updatesDir = getUpdatesPatchDir(); + Assert.ok(updatesDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(updatesDir.path)); + + let log = getUpdateLog(FILE_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateStageSuccessSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateStageSuccessSvc.js new file mode 100644 index 000000000..5b9b08156 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateStageSuccessSvc.js @@ -0,0 +1,82 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test applying an update by staging an update and launching an application to + * apply it. + */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, true); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdateUsingApp(STATE_SUCCEEDED); +} + +/** + * Called after the call to runUpdateUsingApp finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + + let updatesDir = getUpdatesPatchDir(); + Assert.ok(updatesDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(updatesDir.path)); + + let log = getUpdateLog(FILE_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateSuccessSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateSuccessSvc.js new file mode 100644 index 000000000..e76233fe6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateSuccessSvc.js @@ -0,0 +1,65 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/** + * Test applying an update by staging an update and launching an application to + * apply it. + */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + // The third parameter will test that a full path to the post update binary + // doesn't execute. + setupUpdaterTest(FILE_COMPLETE_MAR, undefined, + getApplyDirFile(null, true).path + "/"); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdateUsingApp(STATE_SUCCEEDED); +} + +/** + * Called after the call to runUpdateUsingApp finishes. + */ +function runUpdateFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + + let updatesDir = getUpdatesPatchDir(); + Assert.ok(updatesDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(updatesDir.path)); + + let log = getUpdateLog(FILE_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_LAST_UPDATE_LOG); + Assert.ok(log.exists(), + MSG_SHOULD_EXIST + getMsgPath(log.path)); + + log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); + Assert.ok(!log.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); + + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marAppInUseStageFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marAppInUseStageFailureCompleteSvc_win.js new file mode 100644 index 000000000..b1505d58e --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marAppInUseStageFailureCompleteSvc_win.js @@ -0,0 +1,70 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Application in use complete MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(DIR_RESOURCES + gCallbackBinFile, false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marAppInUseSuccessCompleteSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marAppInUseSuccessCompleteSvc.js new file mode 100644 index 000000000..93333cade --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marAppInUseSuccessCompleteSvc.js @@ -0,0 +1,62 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Application in use complete MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(DIR_RESOURCES + gCallbackBinFile, false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessCompleteSvc_win.js new file mode 100644 index 000000000..79e54c182 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessCompleteSvc_win.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Replace app binary complete MAR file staged patch apply success test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + gCallbackBinFile = "exe0.exe"; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessPartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessPartialSvc_win.js new file mode 100644 index 000000000..b1f84715f --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessPartialSvc_win.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Patch app binary partial MAR file staged patch apply success test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + gCallbackBinFile = "exe0.exe"; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessCompleteSvc_win.js new file mode 100644 index 000000000..85e92d290 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessCompleteSvc_win.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Replace app binary complete MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + gCallbackBinFile = "exe0.exe"; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessPartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessPartialSvc_win.js new file mode 100644 index 000000000..1212c9ba2 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessPartialSvc_win.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Patch app binary partial MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + gCallbackBinFile = "exe0.exe"; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js new file mode 100644 index 000000000..960c96f7b --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Partial MAR File Patch Apply Failure Test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestFiles[11].originalFile = "partial.png"; + gTestDirs = gTestDirsPartialSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + // If execv is used the updater process will turn into the callback process + // and the updater's return code will be that of the callback process. + runUpdate(STATE_FAILED_LOADSOURCE_ERROR_WRONG_SIZE, false, (USE_EXECV ? 0 : 1), + true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusFile(), STATE_NONE, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_FAILED, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, LOADSOURCE_ERROR_WRONG_SIZE, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContents(LOG_PARTIAL_FAILURE); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js new file mode 100644 index 000000000..b39595f92 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailureCompleteSvc_win.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use complete MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestFiles[13].relPathDir + gTestFiles[13].fileName, + false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js new file mode 100644 index 000000000..06d386ad6 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageFailurePartialSvc_win.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use partial MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestFiles[11].relPathDir + gTestFiles[11].fileName, + false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js new file mode 100644 index 000000000..89a2fff5e --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use complete MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestFiles[13].relPathDir + gTestFiles[13].fileName, + false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + checkUpdateLogContains(STATE_SUCCEEDED + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js new file mode 100644 index 000000000..ea85ddccc --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use partial MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestFiles[11].relPathDir + gTestFiles[11].fileName, + false); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + checkUpdateLogContains(STATE_SUCCEEDED + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js new file mode 100644 index 000000000..c5efaa8c0 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked complete MAR file patch apply failure test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperLockFile(gTestFiles[3]); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_FAILED_WRITE_ERROR, false, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusFile(), STATE_PENDING, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_PENDING, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, WRITE_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_BACKUP_CREATE_7); + checkUpdateLogContains(STATE_FAILED_WRITE_ERROR + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js new file mode 100644 index 000000000..4fdbadb5b --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked partial MAR file patch apply failure test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperLockFile(gTestFiles[2]); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_FAILED_READ_ERROR, false, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusFile(), STATE_NONE, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_FAILED, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, READ_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_UNABLE_OPEN_DEST); + checkUpdateLogContains(STATE_FAILED_READ_ERROR + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js new file mode 100644 index 000000000..4d12f4e42 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked complete MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperLockFile(gTestFiles[3]); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + // Files aren't checked after staging since this test locks a file which + // prevents reading the file. + checkUpdateLogContains(ERR_ENSURE_COPY); + // Switch the application to the staged application that was updated. + runUpdate(STATE_FAILED_WRITE_ERROR, false, 1, false); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusFile(), STATE_PENDING, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 2, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_PENDING, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, WRITE_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_BACKUP_CREATE_7); + checkUpdateLogContains(STATE_FAILED_WRITE_ERROR + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js new file mode 100644 index 000000000..5f64df34c --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js @@ -0,0 +1,70 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked partial MAR file staged patch apply failure test */ + +const STATE_AFTER_STAGE = STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperLockFile(gTestFiles[2]); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + // Files aren't checked after staging since this test locks a file which + // prevents reading the file. + checkUpdateLogContains(ERR_ENSURE_COPY); + // Switch the application to the staged application that was updated. + runUpdate(STATE_FAILED_READ_ERROR, false, 1, false); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusFile(), STATE_NONE, + "the status file failure code" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.updateCount, 2, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_FAILED, + "the update state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, READ_ERROR, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_UNABLE_OPEN_DEST); + checkUpdateLogContains(STATE_FAILED_READ_ERROR + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageFailureCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageFailureCompleteSvc_win.js new file mode 100644 index 000000000..b83bafccc --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageFailureCompleteSvc_win.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir complete MAR file staged patch apply failure + test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestDirs[4].relPathDir + gTestDirs[4].subDirs[0] + + gTestDirs[4].subDirFiles[0], true); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageFailurePartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageFailurePartialSvc_win.js new file mode 100644 index 000000000..39ea485cd --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageFailurePartialSvc_win.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir partial MAR file staged patch apply failure + test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; +const STATE_AFTER_RUNUPDATE = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestDirs[2].relPathDir + gTestDirs[2].files[0], true); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_AFTER_RUNUPDATE, true, 1, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_RUNUPDATE, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + setTestFilesAndDirsForFailure(); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_RENAME_FILE); + checkUpdateLogContains(ERR_MOVE_DESTDIR_7 + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessCompleteSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessCompleteSvc_win.js new file mode 100644 index 000000000..a71bb8d49 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessCompleteSvc_win.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir complete MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestDirs[4].relPathDir + gTestDirs[4].subDirs[0] + + gTestDirs[4].subDirFiles[0], true); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + checkUpdateLogContains(STATE_SUCCEEDED + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessPartialSvc_win.js b/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessPartialSvc_win.js new file mode 100644 index 000000000..2cbe70ed8 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessPartialSvc_win.js @@ -0,0 +1,62 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir partial MAR file patch apply success test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestDirs = gTestDirsPartialSuccess; + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runHelperFileInUse(gTestDirs[2].relPathDir + gTestDirs[2].files[0], true); +} + +/** + * Called after the call to waitForHelperSleep finishes. + */ +function waitForHelperSleepFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + waitForHelperExit(); +} + +/** + * Called after the call to waitForHelperExit finishes. + */ +function waitForHelperExitFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + checkUpdateLogContains(STATE_SUCCEEDED + "\n" + CALL_QUIT); + checkCallbackLog(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js new file mode 100644 index 000000000..a9ce23420 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Partial MAR File Staged Patch Apply Failure Test */ + +const STATE_AFTER_STAGE = STATE_FAILED; +gStagingRemovedUpdate = true; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestFiles[11].originalFile = "partial.png"; + gTestDirs = gTestDirsPartialSuccess; + setTestFilesAndDirsForFailure(); + setupUpdaterTest(FILE_PARTIAL_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).errorCode, LOADSOURCE_ERROR_WRONG_SIZE, + "the update errorCode" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateFailure(getApplyDirFile); + checkUpdateLogContains(ERR_LOADSOURCEFILE_FAILED); + waitForFilesInUse(); +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js new file mode 100644 index 000000000..f7745f68f --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js @@ -0,0 +1,132 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Complete MAR File Staged Patch Apply Test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestFiles[gTestFiles.length - 1].originalContents = null; + gTestFiles[gTestFiles.length - 1].compareContents = "FromComplete\n"; + gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + gTestDirs = gTestDirsCompleteSuccess; + setupDistributionDir(); + setupSymLinks(); + setupUpdaterTest(FILE_COMPLETE_MAR, false); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + checkSymLinks(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true); + checkDistributionDir(); + checkCallbackLog(); +} + +/** + * Setup the state of the distribution directory for the test. + */ +function setupDistributionDir() { + if (IS_MACOSX) { + // Create files in the old distribution directory location to verify that + // the directory and its contents are removed when there is a distribution + // directory in the new location. + let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true); + writeFile(testFile, "test\n"); + testFile = getApplyDirFile(DIR_MACOS + "distribution/test1/testFile", true); + writeFile(testFile, "test\n"); + } +} + +/** + * Checks the state of the distribution directory for the test. + */ +function checkDistributionDir() { + if (IS_MACOSX) { + let distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + checkUpdateLogContains(REMOVE_OLD_DIST_DIR); + } +} + +/** + * Setup symlinks for the test. + */ +function setupSymLinks() { + // Don't test symlinks on Mac OS X in this test since it tends to timeout. + // It is tested on Mac OS X in marAppInUseStageSuccessComplete_unix.js + if (IS_UNIX && !IS_MACOSX) { + removeSymlink(); + createSymlink(); + do_register_cleanup(removeSymlink); + gTestFiles.splice(gTestFiles.length - 3, 0, + { + description: "Readable symlink", + fileName: "link", + relPathDir: DIR_RESOURCES, + originalContents: "test", + compareContents: "test", + originalFile: null, + compareFile: null, + originalPerms: 0o666, + comparePerms: 0o666 + }); + } +} + +/** + * Checks the state of the symlinks for the test. + */ +function checkSymLinks() { + // Don't test symlinks on Mac OS X in this test since it tends to timeout. + // It is tested on Mac OS X in marAppInUseStageSuccessComplete_unix.js + if (IS_UNIX && !IS_MACOSX) { + checkSymlink(); + } +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js new file mode 100644 index 000000000..ef15326de --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js @@ -0,0 +1,112 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Partial MAR File Staged Patch Apply Test */ + +const STATE_AFTER_STAGE = IS_SERVICE_TEST ? STATE_APPLIED_SVC : STATE_APPLIED; + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestFiles[gTestFiles.length - 2].originalContents = null; + gTestFiles[gTestFiles.length - 2].compareContents = "FromPartial\n"; + gTestFiles[gTestFiles.length - 2].comparePerms = 0o644; + gTestDirs = gTestDirsPartialSuccess; + preventDistributionFiles(); + setupDistributionDir(); + setupUpdaterTest(FILE_PARTIAL_MAR, true); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + stageUpdate(true); +} + +/** + * Called after the call to stageUpdate finishes. + */ +function stageUpdateFinished() { + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getStageDirFile, true); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS, true, false, true); + // Switch the application to the staged application that was updated. + runUpdate(STATE_SUCCEEDED, true, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile, false, true); + checkUpdateLogContents(LOG_REPLACE_SUCCESS, false, true, true); + checkDistributionDir(); + checkCallbackLog(); +} + +/** + * Setup the state of the distribution directory for the test. + */ +function setupDistributionDir() { + if (IS_MACOSX) { + // Create files in the old distribution directory location to verify that + // the directory and its contents are moved to the new location on update. + let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true); + writeFile(testFile, "test\n"); + testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true); + writeFile(testFile, "test\n"); + } +} + +/** + * Checks the state of the distribution directory. + */ +function checkDistributionDir() { + let distributionDir = getApplyDirFile(DIR_RESOURCES + "distribution", true); + if (IS_MACOSX) { + Assert.ok(distributionDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(distributionDir.path)); + + let testFile = getApplyDirFile(DIR_RESOURCES + "distribution/testFile", true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + testFile = getApplyDirFile(DIR_RESOURCES + "distribution/test/testFile", true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + + checkUpdateLogContains(MOVE_OLD_DIST_DIR); + } else { + debugDump("testing that files aren't added with an add-if instruction " + + "when the file's destination directory doesn't exist"); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + } +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marSuccessCompleteSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marSuccessCompleteSvc.js new file mode 100644 index 000000000..1008e867f --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marSuccessCompleteSvc.js @@ -0,0 +1,96 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Complete MAR File Patch Apply Test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesCompleteSuccess; + gTestDirs = gTestDirsCompleteSuccess; + preventDistributionFiles(); + setupDistributionDir(); + setupUpdaterTest(FILE_COMPLETE_MAR, true); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkPostUpdateAppLog(); +} + +/** + * Called after the call to checkPostUpdateAppLog finishes. + */ +function checkPostUpdateAppLogFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(true); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS, false, false, true); + checkDistributionDir(); + checkCallbackLog(); +} + +/** + * Setup the state of the distribution directory for the test. + */ +function setupDistributionDir() { + if (IS_MACOSX) { + // Create files in the old distribution directory location to verify that + // the directory and its contents are moved to the new location on update. + let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true); + writeFile(testFile, "test\n"); + testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true); + writeFile(testFile, "test\n"); + } +} + +/** + * Checks the state of the distribution directory. + */ +function checkDistributionDir() { + let distributionDir = getApplyDirFile(DIR_RESOURCES + "distribution", true); + if (IS_MACOSX) { + Assert.ok(distributionDir.exists(), + MSG_SHOULD_EXIST + getMsgPath(distributionDir.path)); + + let testFile = getApplyDirFile(DIR_RESOURCES + "distribution/testFile", true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + testFile = getApplyDirFile(DIR_RESOURCES + "distribution/test/testFile", true); + Assert.ok(testFile.exists(), + MSG_SHOULD_EXIST + getMsgPath(testFile.path)); + + distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + + checkUpdateLogContains(MOVE_OLD_DIST_DIR); + } else { + debugDump("testing that files aren't added with an add-if instruction " + + "when the file's destination directory doesn't exist"); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + } +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js b/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js new file mode 100644 index 000000000..616390f55 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js @@ -0,0 +1,79 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* General Partial MAR File Patch Apply Test */ + +function run_test() { + if (!setupTestCommon()) { + return; + } + gTestFiles = gTestFilesPartialSuccess; + gTestFiles[gTestFiles.length - 1].originalContents = null; + gTestFiles[gTestFiles.length - 1].compareContents = "FromPartial\n"; + gTestFiles[gTestFiles.length - 1].comparePerms = 0o644; + gTestFiles[gTestFiles.length - 2].originalContents = null; + gTestFiles[gTestFiles.length - 2].compareContents = "FromPartial\n"; + gTestFiles[gTestFiles.length - 2].comparePerms = 0o644; + gTestDirs = gTestDirsPartialSuccess; + setupDistributionDir(); + // The third parameter will test that a relative path that contains a + // directory traversal to the post update binary doesn't execute. + setupUpdaterTest(FILE_PARTIAL_MAR, false, "test/../"); +} + +/** + * Called after the call to setupUpdaterTest finishes. + */ +function setupUpdaterTestFinished() { + runUpdate(STATE_SUCCEEDED, false, 0, true); +} + +/** + * Called after the call to runUpdate finishes. + */ +function runUpdateFinished() { + checkAppBundleModTime(); + standardInit(); + Assert.equal(readStatusState(), STATE_NONE, + "the status file state" + MSG_SHOULD_EQUAL); + Assert.ok(!gUpdateManager.activeUpdate, + "the active update should not be defined"); + Assert.equal(gUpdateManager.updateCount, 1, + "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); + Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_SUCCEEDED, + "the update state" + MSG_SHOULD_EQUAL); + checkPostUpdateRunningFile(false); + checkFilesAfterUpdateSuccess(getApplyDirFile); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS); + checkDistributionDir(); + checkCallbackLog(); +} + +/** + * Setup the state of the distribution directory for the test. + */ +function setupDistributionDir() { + if (IS_MACOSX) { + // Create files in the old distribution directory location to verify that + // the directory and its contents are removed when there is a distribution + // directory in the new location. + let testFile = getApplyDirFile(DIR_MACOS + "distribution/testFile", true); + writeFile(testFile, "test\n"); + testFile = getApplyDirFile(DIR_MACOS + "distribution/test/testFile", true); + writeFile(testFile, "test\n"); + } +} + +/** + * Checks the state of the distribution directory. + */ +function checkDistributionDir() { + if (IS_MACOSX) { + let distributionDir = getApplyDirFile(DIR_MACOS + "distribution", true); + Assert.ok(!distributionDir.exists(), + MSG_SHOULD_NOT_EXIST + getMsgPath(distributionDir.path)); + checkUpdateLogContains(REMOVE_OLD_DIST_DIR); + } +} diff --git a/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini b/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini new file mode 100644 index 000000000..1d63f8583 --- /dev/null +++ b/toolkit/mozapps/update/tests/unit_service_updater/xpcshell.ini @@ -0,0 +1,156 @@ +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. + +; Tests that require the updater binary and the maintenance service. + +[DEFAULT] +tags = appupdate +head = head_update.js +tail = + +[bootstrapSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[invalidArgInstallDirPathTooLongFailureSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[invalidArgInstallDirPathTraversalFailureSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[invalidArgInstallWorkingDirPathNotSameFailureSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[invalidArgPatchDirPathTraversalFailureSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[invalidArgStageDirNotInInstallDirFailureSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[invalidArgWorkingDirPathLocalUNCFailureSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[invalidArgWorkingDirPathRelativeFailureSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marSuccessCompleteSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marSuccessPartialSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFailurePartialSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marStageSuccessCompleteSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marStageSuccessPartialSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marStageFailurePartialSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marCallbackAppSuccessCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marCallbackAppSuccessPartialSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marCallbackAppStageSuccessCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marCallbackAppStageSuccessPartialSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marAppInUseSuccessCompleteSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marAppInUseStageFailureCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFileLockedFailureCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFileLockedFailurePartialSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFileLockedStageFailureCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFileLockedStageFailurePartialSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFileInUseSuccessCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFileInUseSuccessPartialSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marRMRFDirFileInUseSuccessCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marRMRFDirFileInUseSuccessPartialSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFileInUseStageFailureCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marFileInUseStageFailurePartialSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marRMRFDirFileInUseStageFailureCompleteSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marRMRFDirFileInUseStageFailurePartialSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marAppApplyDirLockedStageFailureSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marAppApplyUpdateSuccessSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[marAppApplyUpdateStageSuccessSvc.js] +skip-if = os == 'win' && debug && (os_version == '5.1' || os_version == '5.2') +reason = bug 1291985 +run-sequentially = Uses the Mozilla Maintenance Service. +[checkUpdaterSigSvc.js] |