mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-08-28 13:50:26 +02:00
test: better sync coverage
This commit is contained in:
Generated
+28
-28
@@ -572,9 +572,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.23.0"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b25655df2c3cdd83c5e5b293b88acd880332b2ddadd7c30ac43144fdc0033da9"
|
||||
checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
@@ -1046,9 +1046,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.20.8"
|
||||
version = "0.20.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c"
|
||||
checksum = "fe4ece8474b5f766c63426647e7b4b316b67431ade1036a8313cee24a03ae917"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon 0.13.5",
|
||||
@@ -1149,9 +1149,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.6.4"
|
||||
version = "4.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d91e0c145792ef73a6ad36d27c75ac09f1832222a3c209689d90f534685ee5b7"
|
||||
checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -1159,9 +1159,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.6.2"
|
||||
version = "4.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b"
|
||||
checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1178,7 +1178,7 @@ dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.3",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2391,9 +2391,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.33"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae"
|
||||
checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -2401,9 +2401,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.33"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
|
||||
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
@@ -2418,9 +2418,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.33"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a"
|
||||
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
@@ -2437,32 +2437,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.33"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b"
|
||||
checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.118",
|
||||
"syn 3.0.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.33"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307"
|
||||
checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.33"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
|
||||
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.33"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
|
||||
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -6443,9 +6443,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.3"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
|
||||
checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -6536,7 +6536,7 @@ version = "7.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7"
|
||||
dependencies = [
|
||||
"cfg-expr 0.20.8",
|
||||
"cfg-expr 0.20.9",
|
||||
"heck 0.5.0",
|
||||
"pkg-config",
|
||||
"toml 1.1.2+spec-1.1.0",
|
||||
@@ -7038,7 +7038,7 @@ checksum = "535cd782aac407a0bbf593013306e89e821017e3862ddd7b36925aa80a29e649"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64 0.23.0",
|
||||
"base64 0.23.1",
|
||||
"block2",
|
||||
"cairo-rs",
|
||||
"clap",
|
||||
|
||||
@@ -212,6 +212,7 @@ export const commandCoverage = {
|
||||
commands: [
|
||||
"get_sync_settings",
|
||||
"save_sync_settings",
|
||||
"check_sync_server_connection",
|
||||
"cloud_auth::restart_sync_service",
|
||||
"set_profile_sync_mode",
|
||||
"cancel_profile_sync",
|
||||
|
||||
+28
-15
@@ -2,6 +2,7 @@
|
||||
|
||||
import { spawn, spawnSync } from "node:child_process";
|
||||
import {
|
||||
copyFileSync,
|
||||
createReadStream,
|
||||
createWriteStream,
|
||||
existsSync,
|
||||
@@ -44,6 +45,9 @@ const driverBinary = path.join(
|
||||
"bin",
|
||||
`tauri-wd${executableSuffix}`,
|
||||
);
|
||||
const appManifest = path.join(appManifestDir, "Cargo.toml");
|
||||
const appLockfile = path.join(appManifestDir, "Cargo.lock");
|
||||
const donutLockfile = path.join(projectRoot, "src-tauri", "Cargo.lock");
|
||||
|
||||
const suiteFiles = {
|
||||
smoke: ["diagnostics.test.mjs", "smoke.test.mjs", "coverage.test.mjs"],
|
||||
@@ -237,16 +241,13 @@ async function loadLocalValues(names) {
|
||||
return values;
|
||||
}
|
||||
|
||||
function lockedDriverVersion() {
|
||||
const lockfile = readFileSync(
|
||||
path.join(appManifestDir, "Cargo.lock"),
|
||||
"utf8",
|
||||
);
|
||||
const match = lockfile.match(
|
||||
/\[\[package\]\]\s*\nname = "tauri-wd"\s*\nversion = "([^"]+)"/,
|
||||
);
|
||||
function pinnedDriverVersion() {
|
||||
const manifest = readFileSync(appManifest, "utf8");
|
||||
const match = manifest.match(/^tauri-wd\s*=\s*"=([^"]+)"$/m);
|
||||
if (!match) {
|
||||
throw new Error("e2e/app/Cargo.lock does not resolve a tauri-wd version");
|
||||
throw new Error(
|
||||
'e2e/app/Cargo.toml must pin tauri-wd to an exact version, e.g. tauri-wd = "=0.1.11"',
|
||||
);
|
||||
}
|
||||
return match[1];
|
||||
}
|
||||
@@ -263,7 +264,7 @@ function installedDriverVersion() {
|
||||
}
|
||||
|
||||
function ensureDriver() {
|
||||
const version = lockedDriverVersion();
|
||||
const version = pinnedDriverVersion();
|
||||
if (installedDriverVersion() === version) {
|
||||
log(`tauri-wd ${version} already installed at ${driverBinary}`);
|
||||
return;
|
||||
@@ -285,15 +286,27 @@ function ensureDriver() {
|
||||
);
|
||||
}
|
||||
|
||||
// The harness links the Donut crate, so it has to resolve the same versions
|
||||
// Donut itself ships. Seeding the harness lockfile from src-tauri/Cargo.lock
|
||||
// keeps the two in step whenever a dependency or the app version moves; cargo
|
||||
// fills in the harness-only packages on top. It is generated, never hand-edited.
|
||||
function syncHarnessLockfile() {
|
||||
if (
|
||||
existsSync(appLockfile) &&
|
||||
statSync(appLockfile).mtimeMs >= statSync(donutLockfile).mtimeMs
|
||||
) {
|
||||
return;
|
||||
}
|
||||
copyFileSync(donutLockfile, appLockfile);
|
||||
log("seeded e2e/app/Cargo.lock from src-tauri/Cargo.lock");
|
||||
}
|
||||
|
||||
function buildAll() {
|
||||
run("pnpm", ["build"], projectRoot);
|
||||
run("pnpm", ["copy-proxy-binary"], projectRoot);
|
||||
run(process.execPath, ["src-tauri/download-xray.mjs"], projectRoot);
|
||||
run(
|
||||
"cargo",
|
||||
["build", "--locked", "--manifest-path", "e2e/app/Cargo.toml"],
|
||||
projectRoot,
|
||||
);
|
||||
syncHarnessLockfile();
|
||||
run("cargo", ["build", "--manifest-path", "e2e/app/Cargo.toml"], projectRoot);
|
||||
ensureDriver();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { createServer } from "node:http";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
import { appFromEnvironment } from "../lib/app.mjs";
|
||||
@@ -575,3 +576,85 @@ test("global config sealing and encrypted profile sync reject a wrong password,
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
// A self-hosted server reaches its storage over an address only it can
|
||||
// resolve — the documented compose file points S3_ENDPOINT at
|
||||
// http://minio:9000, a Docker service name that exists on the compose network
|
||||
// and nowhere else. Files never travel through the sync server, so every
|
||||
// presigned URL then names a host the desktop cannot open: /health and /readyz
|
||||
// stay green while every single transfer dies at connect. Reported as "the
|
||||
// endpoint connection works every time, but no MB is ever synced".
|
||||
test("the connection check fails a server whose storage host this device cannot reach", async () => {
|
||||
assert.ok(syncUrl && syncToken, "Sync infrastructure was not started");
|
||||
const app = appFromEnvironment("sync-preflight");
|
||||
|
||||
// Answers exactly like a healthy self-hosted server that signs presigned
|
||||
// URLs against a container-only host.
|
||||
const misconfigured = createServer((request, response) => {
|
||||
if (request.url === "/readyz") {
|
||||
response.writeHead(200, { "content-type": "application/json" });
|
||||
response.end(
|
||||
JSON.stringify({
|
||||
status: "ready",
|
||||
s3: true,
|
||||
storageEndpoint: "http://minio.invalid:9000",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
});
|
||||
await new Promise((resolve) => misconfigured.listen(0, "127.0.0.1", resolve));
|
||||
const misconfiguredUrl = `http://127.0.0.1:${misconfigured.address().port}`;
|
||||
|
||||
try {
|
||||
await app.start();
|
||||
|
||||
const healthy = await app.invoke("check_sync_server_connection", {
|
||||
serverUrl: syncUrl,
|
||||
});
|
||||
assert.equal(healthy.server_reachable, true, "real sync server answers");
|
||||
assert.notEqual(
|
||||
healthy.storage_reachable,
|
||||
false,
|
||||
"the suite's own storage must be reachable from the test device",
|
||||
);
|
||||
|
||||
// The regression itself: green server, storage nobody here can open.
|
||||
const broken = await app.invoke("check_sync_server_connection", {
|
||||
serverUrl: misconfiguredUrl,
|
||||
});
|
||||
assert.equal(broken.server_reachable, true, "server itself answered");
|
||||
assert.equal(broken.storage_ready, true, "server reaches its own storage");
|
||||
assert.equal(broken.storage_endpoint, "http://minio.invalid:9000");
|
||||
assert.equal(
|
||||
broken.storage_reachable,
|
||||
false,
|
||||
"an unreachable storage host must not report as a working connection",
|
||||
);
|
||||
assert.ok(
|
||||
broken.storage_error && broken.storage_error.length > 0,
|
||||
"the failure must carry a cause",
|
||||
);
|
||||
assert.notEqual(
|
||||
broken.storage_error,
|
||||
"error sending request",
|
||||
"the cause must name the transport failure, not the bare reqwest text",
|
||||
);
|
||||
|
||||
// A server that does not answer at all stays a plain connection failure,
|
||||
// so the two are never confused in the UI.
|
||||
const dead = await app.invoke("check_sync_server_connection", {
|
||||
serverUrl: "http://127.0.0.1:1",
|
||||
});
|
||||
assert.equal(dead.server_reachable, false);
|
||||
assert.equal(dead.storage_reachable, null);
|
||||
} catch (error) {
|
||||
await app.capture("failure");
|
||||
throw error;
|
||||
} finally {
|
||||
await new Promise((resolve) => misconfigured.close(resolve));
|
||||
await app.close();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user