commit 597ff721069b65e46c26c0cf059f5cdb36255751
parent 7a067618e9b94f6303e65dc7a2505fca48106a30
Author: Robin Steuber <bytesized@mozilla.com>
Date: Thu, 9 Oct 2025 23:58:23 +0000
Bug 1984458 - Add test utilities for `update.status` I/O failures r=cdupuis,nrishel
Differential Revision: https://phabricator.services.mozilla.com/D247858
Diffstat:
3 files changed, 121 insertions(+), 0 deletions(-)
diff --git a/toolkit/mozapps/update/tests/moz.build b/toolkit/mozapps/update/tests/moz.build
@@ -34,6 +34,9 @@ SimplePrograms(
]
)
+if CONFIG["OS_ARCH"] == "WINNT":
+ SimplePrograms(["test_file_change_mtime", "test_file_hold_open"])
+
LOCAL_INCLUDES += [
"/toolkit/mozapps/update",
"/toolkit/mozapps/update/common",
diff --git a/toolkit/mozapps/update/tests/test_file_change_mtime.cpp b/toolkit/mozapps/update/tests/test_file_change_mtime.cpp
@@ -0,0 +1,65 @@
+#include <windows.h>
+#include <iostream>
+#include <string>
+
+void usage(int argc, wchar_t** argv) {
+ std::wcout << L"Usage:\n"
+ << L" " << argv[0] << L" filename age\n\n"
+ << L" filename\n"
+ << L" The path of the file to change.\n"
+ << L" age\n"
+ << L" The number of seconds in the past to set the file's \n"
+ << L" modification time to.\n\n";
+}
+
+static const ULONGLONG FILETIME_TICKS_PER_SECOND = 10'000'000;
+
+static ULARGE_INTEGER secondsAgoTimestamp(ULONGLONG secondsAgo) {
+ FILETIME now{};
+ GetSystemTimeAsFileTime(&now);
+ ULARGE_INTEGER systemTime;
+ systemTime.LowPart = now.dwLowDateTime;
+ systemTime.HighPart = now.dwHighDateTime;
+ systemTime.QuadPart -= secondsAgo * FILETIME_TICKS_PER_SECOND;
+ return systemTime;
+}
+
+int wmain(int argc, wchar_t** argv) {
+ HANDLE handle;
+ FILE_BASIC_INFO fileBasicInfo{};
+ long ageInSeconds;
+ if (argc != 3) {
+ usage(argc, argv);
+ return 1;
+ }
+ if (!swscanf(argv[2], L"%lu", &ageInSeconds)) {
+ std::wcout << "Invalid seconds: " << argv[2] << std::endl;
+ return 2;
+ }
+ if ((handle = CreateFileW(argv[1], GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, nullptr)) ==
+ INVALID_HANDLE_VALUE) {
+ std::wcout << "Error opening file: " << argv[1] << ", " << GetLastError()
+ << std::endl;
+ return 3;
+ }
+ if (!GetFileInformationByHandleEx(handle, FileBasicInfo, &fileBasicInfo,
+ sizeof(fileBasicInfo))) {
+ std::wcout << "Error getting file info: " << GetLastError() << std::endl;
+ return 4;
+ }
+
+ ULARGE_INTEGER desiredTimestamp = secondsAgoTimestamp(ageInSeconds);
+ fileBasicInfo.LastWriteTime.QuadPart = desiredTimestamp.QuadPart;
+
+ if (!SetFileInformationByHandle(handle, FileBasicInfo, &fileBasicInfo,
+ sizeof(fileBasicInfo))) {
+ std::wcout << "Error setting file mtime: " << GetLastError() << std::endl;
+ return 5;
+ }
+ if (!CloseHandle(handle)) {
+ std::wcout << "Error closing handle: " << GetLastError() << std::endl;
+ return 6;
+ }
+ return 0;
+}
diff --git a/toolkit/mozapps/update/tests/test_file_hold_open.cpp b/toolkit/mozapps/update/tests/test_file_hold_open.cpp
@@ -0,0 +1,53 @@
+#include <windows.h>
+#include <iostream>
+#include <string>
+
+// Opens a file and holds it open until the caller sends input.
+// Then it closes the file and exits.
+
+void usage(int argc, wchar_t** argv) {
+ std::wcout << L"Usage:\n"
+ << L" " << argv[0] << L" filename [sharing]\n\n"
+ << L" filename\n"
+ << L" The path of the file to hold open.\n"
+ << L" sharing\n"
+ << L" File sharing flags. 'r', 'w', and/or 'd' can be\n"
+ << L" specified. Defaults to no sharing.\n\n";
+}
+
+int wmain(int argc, wchar_t** argv) {
+ DWORD dwShareMode = 0;
+
+ if (argc < 2 || argc > 3) {
+ usage(argc, argv);
+ exit(1);
+ }
+ if (argc >= 3) {
+ for (wchar_t* curr = argv[2]; *curr; ++curr) {
+ switch (*curr) {
+ case L'w':
+ dwShareMode |= FILE_SHARE_WRITE;
+ break;
+ case L'r':
+ dwShareMode |= FILE_SHARE_READ;
+ break;
+ case L'd':
+ dwShareMode |= FILE_SHARE_DELETE;
+ break;
+ default:
+ usage(argc, argv);
+ return 1;
+ }
+ }
+ }
+ HANDLE handle = CreateFileW(argv[1], GENERIC_READ, dwShareMode, nullptr,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (handle == INVALID_HANDLE_VALUE) {
+ std::wcout << L"failed to open file " << argv[1] << std::endl;
+ return 1;
+ }
+ std::wcout << "Locked" << std::endl;
+ (void)std::wcin.get();
+ CloseHandle(handle);
+ return 0;
+}