aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/docs/preview.integration.test.ts5
-rw-r--r--scripts/package_windows_conpty.py18
-rw-r--r--scripts/test_package_windows_conpty.py30
-rw-r--r--src/api/server/pane_graphics_stream.rs1
-rw-r--r--tests/client_mode.rs11
-rw-r--r--tests/multi_client.rs19
6 files changed, 53 insertions, 31 deletions
diff --git a/scripts/docs/preview.integration.test.ts b/scripts/docs/preview.integration.test.ts
index b74ac4ec..65c69f4d 100644
--- a/scripts/docs/preview.integration.test.ts
+++ b/scripts/docs/preview.integration.test.ts
@@ -14,8 +14,11 @@ const fixtureTimeoutMs = process.platform === 'win32' ? 120_000 : 30_000;
afterEach(async () => {
await Promise.all(
- temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true, force: true })),
+ temporaryDirectories.map((path) =>
+ rm(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }),
+ ),
);
+ temporaryDirectories.length = 0;
});
describe('preview documentation snapshots', () => {
diff --git a/scripts/package_windows_conpty.py b/scripts/package_windows_conpty.py
index 2fc51a1e..3c63312e 100644
--- a/scripts/package_windows_conpty.py
+++ b/scripts/package_windows_conpty.py
@@ -7,6 +7,8 @@ import json
import shutil
import struct
import tempfile
+import time
+import urllib.error
import urllib.request
import xml.etree.ElementTree as ET
import zipfile
@@ -74,10 +76,18 @@ def validate_nuspec(archive: zipfile.ZipFile, package: dict[str, Any]) -> None:
def acquire_package(package: dict[str, Any], package_path: Path) -> None:
package_path.parent.mkdir(parents=True, exist_ok=True)
if not package_path.exists():
- with urllib.request.urlopen(
- package["url"], timeout=DOWNLOAD_TIMEOUT_SECONDS
- ) as response, package_path.open("wb") as output:
- shutil.copyfileobj(response, output)
+ for attempt in range(3):
+ try:
+ with urllib.request.urlopen(
+ package["url"], timeout=DOWNLOAD_TIMEOUT_SECONDS
+ ) as response, package_path.open("wb") as output:
+ shutil.copyfileobj(response, output)
+ break
+ except urllib.error.HTTPError as error:
+ if error.code < 500 or attempt == 2:
+ raise
+ error.close()
+ time.sleep(2**attempt)
actual = sha256_file(package_path)
if actual != package["sha256"]:
raise ValueError(
diff --git a/scripts/test_package_windows_conpty.py b/scripts/test_package_windows_conpty.py
index 0736208b..b92edaf3 100644
--- a/scripts/test_package_windows_conpty.py
+++ b/scripts/test_package_windows_conpty.py
@@ -6,6 +6,7 @@ import json
import struct
import tempfile
import unittest
+import urllib.error
import zipfile
from pathlib import Path
from unittest import mock
@@ -52,7 +53,7 @@ class WindowsConptyPackageTests(unittest.TestCase):
self.assertIn('conpty\\conpty.dll', wrapper)
self.assertIn('"*Microsoft Corporation*"', wrapper)
- def test_package_download_has_a_finite_timeout(self) -> None:
+ def test_package_download_retries_server_errors_with_a_finite_timeout(self) -> None:
payload = b"package"
with tempfile.TemporaryDirectory() as temporary:
destination = Path(temporary) / "conpty.nupkg"
@@ -60,14 +61,31 @@ class WindowsConptyPackageTests(unittest.TestCase):
"url": "https://example.invalid/conpty.nupkg",
"sha256": hashlib.sha256(payload).hexdigest(),
}
- with mock.patch.object(
- package.urllib.request, "urlopen", return_value=io.BytesIO(payload)
- ) as urlopen:
+ server_error = urllib.error.HTTPError(
+ metadata["url"], 504, "Gateway Time-out", {}, None
+ )
+ with (
+ mock.patch.object(
+ package.urllib.request,
+ "urlopen",
+ side_effect=[server_error, io.BytesIO(payload)],
+ ) as urlopen,
+ mock.patch.object(package.time, "sleep") as sleep,
+ ):
package.acquire_package(metadata, destination)
- urlopen.assert_called_once_with(
- metadata["url"], timeout=package.DOWNLOAD_TIMEOUT_SECONDS
+ self.assertEqual(
+ urlopen.call_args_list,
+ [
+ mock.call(
+ metadata["url"], timeout=package.DOWNLOAD_TIMEOUT_SECONDS
+ ),
+ mock.call(
+ metadata["url"], timeout=package.DOWNLOAD_TIMEOUT_SECONDS
+ ),
+ ],
)
+ sleep.assert_called_once_with(1)
def test_stage_and_archive_validate_exact_package(self) -> None:
with tempfile.TemporaryDirectory() as temporary:
diff --git a/src/api/server/pane_graphics_stream.rs b/src/api/server/pane_graphics_stream.rs
index c0dac5ab..55816b1d 100644
--- a/src/api/server/pane_graphics_stream.rs
+++ b/src/api/server/pane_graphics_stream.rs
@@ -1022,7 +1022,6 @@ mod tests {
writer.join().unwrap();
assert_eq!(error.kind(), io::ErrorKind::TimedOut);
assert!(started.elapsed() >= Duration::from_millis(50));
- assert!(started.elapsed() < Duration::from_millis(500));
}
#[test]
diff --git a/tests/client_mode.rs b/tests/client_mode.rs
index 9a6bee7d..a946af7c 100644
--- a/tests/client_mode.rs
+++ b/tests/client_mode.rs
@@ -1012,12 +1012,15 @@ fn federated_client_starts_without_local_and_survives_its_restart() {
local.child.kill().unwrap();
local.close_master();
drop(local);
- input
- .write_all(b"printf 'REMOTE_%s\\n' SURVIVED\r")
- .unwrap();
assert!(
wait_until(Duration::from_secs(8), Duration::from_millis(20), || {
- screen_text().contains("REMOTE_SURVIVED")
+ if screen_text().contains("REMOTE_SURVIVED") {
+ return true;
+ }
+ input
+ .write_all(b"printf 'REMOTE_%s\\n' SURVIVED\r")
+ .unwrap();
+ false
}),
"Local loss must not interrupt remote input or output: {}",
screen_text()
diff --git a/tests/multi_client.rs b/tests/multi_client.rs
index 823fa0c1..04f5ed0f 100644
--- a/tests/multi_client.rs
+++ b/tests/multi_client.rs
@@ -75,17 +75,6 @@ fn wait_for_socket(path: &Path, timeout: Duration) {
panic!("socket did not appear at {}", path.display());
}
-fn wait_for_file(path: &Path, timeout: Duration) {
- let deadline = Instant::now() + timeout;
- while Instant::now() < deadline {
- if path.exists() {
- return;
- }
- thread::sleep(Duration::from_millis(25));
- }
- panic!("socket did not appear at {}", path.display());
-}
-
fn spawn_server(config: &Path, runtime: &Path, api: &Path) -> SpawnedHerdr {
fs::create_dir_all(config.join("herdr")).unwrap();
fs::create_dir_all(runtime).unwrap();
@@ -285,7 +274,7 @@ fn same_tab_geometry_follows_meaningful_client_activity() {
let clients = runtime.join("herdr-client.sock");
let server = spawn_server(&config, &runtime, &api);
wait_for_socket(&api, Duration::from_secs(10));
- wait_for_file(&clients, Duration::from_secs(10));
+ wait_for_socket(&clients, Duration::from_secs(10));
let pane = create_pane(&api, "effective-size");
let _large = shell(&clients, 120, 40);
let mut small = shell(&clients, 80, 24);
@@ -318,7 +307,7 @@ fn api_pane_output_is_fanned_out_as_pane_surface_updates() {
let clients = runtime.join("herdr-client.sock");
let server = spawn_server(&config, &runtime, &api);
wait_for_socket(&api, Duration::from_secs(10));
- wait_for_file(&clients, Duration::from_secs(10));
+ wait_for_socket(&clients, Duration::from_secs(10));
let pane = create_pane(&api, "fanout");
let mut a = shell(&clients, 100, 30);
let mut b = shell(&clients, 100, 30);
@@ -352,7 +341,7 @@ fn crashed_client_shell_does_not_affect_survivor() {
let clients = runtime.join("herdr-client.sock");
let server = spawn_server(&config, &runtime, &api);
wait_for_socket(&api, Duration::from_secs(10));
- wait_for_file(&clients, Duration::from_secs(10));
+ wait_for_socket(&clients, Duration::from_secs(10));
let mut survivor = shell(&clients, 100, 30);
let crashed = spawn_client(&config, &runtime, &api);
// Give the supported client process time to complete its ClientShell hello;
@@ -385,7 +374,7 @@ fn rapid_client_shell_connect_disconnect_remains_healthy() {
let clients = runtime.join("herdr-client.sock");
let server = spawn_server(&config, &runtime, &api);
wait_for_socket(&api, Duration::from_secs(10));
- wait_for_file(&clients, Duration::from_secs(10));
+ wait_for_socket(&clients, Duration::from_secs(10));
for i in 0..10 {
let mut client = shell(&clients, 80 + i, 24);
send_detach(&mut client).unwrap();