Compare commits

..

1 Commits

Author SHA1 Message Date
NimBold 90e35ed54e test(startup): validate pre-fix release baseline (#37)
- Issue #37: run the delayed packaged stability check against the original v1.4.0 release commit.\n- Keep the control limited to the smoke harness so the release feature set remains unchanged.\n\nRefs #37.
2026-08-27 19:16:46 +03:30
5 changed files with 15 additions and 102 deletions
+6 -4
View File
@@ -332,16 +332,18 @@ async function terminateChild() {
}
}
}
const childExited = await waitForChildExit(5000);
const processGroupExited = await waitForProcessGroupExit(child.pid, 5000);
if (childExited && processGroupExited) {
if (await waitForChildExit(5000) && await waitForProcessGroupExit(child.pid, 5000)) {
return true;
}
if (!childWasRunning || childExit) {
return false;
}
try {
process.kill(-child.pid, 'SIGKILL');
} catch {
if (!childExited) {
if (!childExit) {
child.kill('SIGKILL');
}
}
-51
View File
@@ -2523,57 +2523,6 @@ mod tests {
}));
}
#[test]
fn migrates_v1_database_and_creates_backup() {
let temp = TempDir::new().unwrap();
let path = temp.path().join(DATABASE_NAME);
let connection = Connection::open(&path).unwrap();
connection
.execute_batch(
"
CREATE TABLE downloads (
id TEXT PRIMARY KEY,
status TEXT NOT NULL,
queue_id TEXT,
data TEXT NOT NULL
);
CREATE TABLE settings (id INTEGER PRIMARY KEY, data TEXT NOT NULL);
CREATE TABLE queues (id TEXT PRIMARY KEY, data TEXT NOT NULL);
CREATE TABLE download_ownership (
id TEXT PRIMARY KEY,
primary_path TEXT NOT NULL
);
INSERT INTO download_ownership VALUES ('download-1', '/downloads/file.bin');
PRAGMA user_version = 1;
",
)
.unwrap();
drop(connection);
let state = init_at_path(temp.path()).unwrap();
let connection = state.lock().unwrap();
let version: i64 = connection
.pragma_query_value(None, "user_version", |row| row.get(0))
.unwrap();
assert_eq!(version, CURRENT_SCHEMA_VERSION);
assert!(table_exists(&connection, "download_owned_paths").unwrap());
assert!(table_exists(&connection, "download_removal_paths").unwrap());
assert_eq!(
load_ownership(&connection).unwrap(),
vec![(
"download-1".to_string(),
"/downloads/file.bin".to_string(),
vec!["/downloads/file.bin".to_string()]
)]
);
assert!(fs::read_dir(temp.path()).unwrap().flatten().any(|entry| {
entry
.file_name()
.to_string_lossy()
.starts_with("firelink.sqlite.backup-schema-v1-")
}));
}
#[cfg(unix)]
#[test]
fn refuses_to_open_a_database_symlink() {
+8 -16
View File
@@ -3328,21 +3328,6 @@ fn metadata_is_link_or_reparse(metadata: &std::fs::Metadata) -> bool {
}
pub(crate) fn path_has_symlink_component(path: &std::path::Path) -> bool {
path_has_component_matching(path, metadata_is_link_or_reparse)
}
/// Detect only symbolic-link components, without treating every Windows
/// reparse point as a link. Trusted application-data directories may use
/// junctions for Windows folder redirection; user-selected download and
/// recovery paths continue to use the stricter helper above.
pub(crate) fn path_has_symbolic_link_component(path: &std::path::Path) -> bool {
path_has_component_matching(path, |metadata| metadata.file_type().is_symlink())
}
fn path_has_component_matching(
path: &std::path::Path,
matches: impl Fn(&std::fs::Metadata) -> bool,
) -> bool {
use std::path::Component;
let mut current = std::path::PathBuf::new();
@@ -3354,7 +3339,7 @@ fn path_has_component_matching(
Component::Normal(name) => {
current.push(name);
if std::fs::symlink_metadata(&current)
.is_ok_and(|metadata| matches(&metadata))
.is_ok_and(|metadata| metadata_is_link_or_reparse(&metadata))
{
return true;
}
@@ -18523,6 +18508,13 @@ pub fn run() {
collect_opened_torrent_paths(std::env::args_os().skip(1)),
);
#[cfg(target_os = "windows")]
if let Some(window) = app.get_webview_window("main") {
window
.set_decorations(false)
.map_err(|error| format!("failed to disable Windows native frame: {error}"))?;
}
let deep_link_app = app.handle().clone();
#[cfg(target_os = "linux")]
if let Err(error) = app.deep_link().register_all() {
-2
View File
@@ -437,8 +437,6 @@ pub fn open_download_properties_window(
// native window becomes visible. Showing an opaque native surface
// here exposes the webview's unpainted white background.
.visible(false)
// A hidden WebView2 must not request focus during construction. The
// native reveal path focuses it after the window is visible.
.transparent(true);
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
let builder = builder.decorations(false);
+1 -29
View File
@@ -251,7 +251,7 @@ fn aria2_server_stat_is_valid(contents: &str) -> bool {
}
fn canonicalize_storage_path(path: &Path) -> Result<PathBuf, String> {
if crate::path_has_symbolic_link_component(path) {
if crate::path_has_symlink_component(path) {
return Err(format!(
"storage path contains a symlinked component: '{}'",
path.display()
@@ -455,32 +455,4 @@ mod tests {
assert!(canonicalize_storage_path(Path::new(&redirected)).is_err());
}
#[cfg(windows)]
#[test]
fn accepts_windows_junctions_for_redirected_storage_paths() {
use std::process::Command;
let parent = TempDir::new().unwrap();
let spaced_parent = parent.path().join("firelink test data");
fs::create_dir(&spaced_parent).unwrap();
let root = TempDir::new_in(&spaced_parent).unwrap();
let target = TempDir::new_in(&spaced_parent).unwrap();
let redirected = root.path().join("redirected");
let target_storage = target.path().join("firelink");
fs::create_dir(&target_storage).unwrap();
let status = Command::new("cmd")
.args(["/D", "/C", "mklink", "/J"])
.arg(&redirected)
.arg(target.path())
.status()
.expect("Windows junction creation command should start");
assert!(status.success(), "mklink /J failed with status {status}");
assert_eq!(
canonicalize_storage_path(&redirected.join("firelink")).unwrap(),
fs::canonicalize(target_storage).unwrap()
);
}
}