Skip to content

Commit d845844

Browse files
authored
fix: onhost supervisor reloading test (#2681)
* fix: fix onhost supervisor reloading test * fix nits
1 parent 42084aa commit d845844

7 files changed

Lines changed: 41 additions & 24 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ chrono = "0.4.45"
4444
jsonwebtoken = { version = "10.4.0", features = ["aws_lc_rs"] }
4545
reqwest = { version = "0.13.4", features = ["blocking", "socks"] }
4646
rstest = "0.26.1"
47+
serial_test = "3.5.0"
4748
windows = "0.62.2"
4849
windows-sys = "0.61.2"
4950
aws-lc-rs = "1.17.1"

agent-control/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ fs = { path = "../fs", features = ["mocks"] }
116116
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
117117
fake = { version = "5.1.0", features = ["derive", "http"] }
118118
httpmock = { version = "0.8.3", features = ["proxy"] }
119-
serial_test = "3.5.0"
119+
serial_test = { workspace = true }
120120
futures = "0.3.32"
121121
rcgen = { version = "0.14.8", features = ["crypto"] }
122122
rstest = { workspace = true }

agent-control/tests/on_host/scenarios/file_logging.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ use std::{fs, io, path::Path, time::Duration};
22

33
use crate::{
44
common::{
5-
agent_control::start_agent_control_with_custom_config, base_paths::TempBasePaths,
6-
retry::retry, runtime::tokio_runtime,
5+
agent_control::{StartedAgentControl, start_agent_control_with_custom_config},
6+
base_paths::TempBasePaths,
7+
retry::retry,
8+
runtime::tokio_runtime,
79
},
810
on_host::tools::{
911
config::{OnHostAgentControlConfigBuilder, create_file, create_local_config},
@@ -123,7 +125,7 @@ fn run_file_logging_scenario(
123125
initial_message: &str,
124126
reload_file_logging: bool,
125127
reload_message: &str,
126-
) -> TempBasePaths {
128+
) -> (TempBasePaths, StartedAgentControl) {
127129
let mut opamp_server = FakeServer::start(tokio_runtime().handle());
128130

129131
let dirs = TempBasePaths::default();
@@ -154,13 +156,13 @@ fn run_file_logging_scenario(
154156
dirs.local_dir(),
155157
);
156158

157-
let _agent_control =
159+
let agent_control =
158160
start_agent_control_with_custom_config(dirs.base_paths(), AGENT_CONTROL_MODE_ON_HOST);
159161

160162
let sub_agent_instance_id =
161163
get_instance_id(&AgentID::try_from(agent_id).unwrap(), dirs.base_paths());
162164

163-
// Give some time for the echo output to be captured in the log files
165+
// Let the first run write its log before the reload can change/disable logging.
164166
std::thread::sleep(Duration::from_secs(5));
165167

166168
// Trigger a reload by sending a new remote config via OpAMP with updated values
@@ -169,10 +171,8 @@ fn run_file_logging_scenario(
169171
format!("message: \"{reload_message}\"\nenable_file_logging: \"{reload_file_logging}\"\n"),
170172
);
171173

172-
// Give some time for the echo output to be captured in the log files
173-
std::thread::sleep(Duration::from_secs(5));
174-
175-
dirs
174+
// AC stays alive via the returned handle; the caller's retry waits for the post-reload logs.
175+
(dirs, agent_control)
176176
}
177177

178178
/// File logging enable/disable combinations with before and after reload checks
@@ -188,7 +188,8 @@ fn test_file_logging_reload(
188188
) {
189189
let agent_id = format!("file-logging-agent-{first_run_enabled}-{second_run_enabled}");
190190

191-
let dirs = run_file_logging_scenario(
191+
// Keep the handle alive so AC keeps running during the wait below.
192+
let (dirs, _agent_control) = run_file_logging_scenario(
192193
&agent_id,
193194
first_run_enabled,
194195
first_run_message,
@@ -197,24 +198,25 @@ fn test_file_logging_reload(
197198
);
198199

199200
let log_dir_path = dirs.log_dir();
200-
let agent_logs_dir = log_dir_path.join(&agent_id);
201-
assert!(
202-
agent_logs_dir.exists(),
203-
"Log directory {agent_logs_dir:?} does not exist"
204-
);
205201

206202
let all_contents = retry(60, Duration::from_secs(1), || {
207-
Ok(collect_stdout_logs(&log_dir_path, &agent_id)?)
203+
let contents = collect_stdout_logs(&log_dir_path, &agent_id)?;
204+
if first_run_enabled == contents.contains(first_run_message)
205+
&& second_run_enabled == contents.contains(second_run_message)
206+
{
207+
Ok(contents)
208+
} else {
209+
Err(format!("log state not settled yet. Log contents: {contents}").into())
210+
}
208211
});
209212

210-
// If the logs are enabled for the run the string must be found, same for disabled and not found
211213
assert!(
212214
first_run_enabled == all_contents.contains(first_run_message),
213-
"First run log not found (pre-reload). Log contents: {all_contents}"
215+
"First run log mismatch (pre-reload). Log contents: {all_contents}"
214216
);
215217
assert!(
216218
second_run_enabled == all_contents.contains(second_run_message),
217-
"Second run log not found (post-reload). Log contents: {all_contents}"
219+
"Second run log mismatch (post-reload). Log contents: {all_contents}"
218220
);
219221
}
220222

@@ -226,7 +228,8 @@ fn onhost_supervisor_reloading_keeps_file_logging_disabled() {
226228
let unique_str_2 = "keeps_disabled_run2";
227229
let agent_id = "test-agent-logs-always-disabled";
228230

229-
let dirs = run_file_logging_scenario(agent_id, false, unique_str_1, false, unique_str_2);
231+
let (dirs, _agent_control) =
232+
run_file_logging_scenario(agent_id, false, unique_str_1, false, unique_str_2);
230233

231234
let log_dir_path = dirs.log_dir();
232235
let agent_logs_dir = log_dir_path.join(agent_id);

self-replacer/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ tempfile = { workspace = true }
1515

1616
[dev-dependencies]
1717
assert_matches = { workspace = true }
18-
assert_cmd = "2.2.2"
19-
predicates = "3.1.4"
18+
assert_cmd = { workspace = true }
19+
predicates = { workspace = true }
20+
serial_test = { workspace = true }
2021

2122
[target.'cfg(target_os = "windows")'.dev-dependencies]
2223
windows = { workspace = true, features = [

self-replacer/tests/integration_tests.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use tempfile::TempDir;
1010

1111
mod test_helpers;
1212
use self_replacer::{BinaryReplacer, SelfReplacer};
13+
use serial_test::serial;
1314
use test_helpers::{copy_example_binary, create_modified_binary};
1415

1516
use self_replacer::BACKUP_SUFFIX;
@@ -18,7 +19,14 @@ use self_replacer::BACKUP_SUFFIX;
1819
// Common tests that run on all platforms
1920
// ============================================================================
2021

22+
// Must run serially: this test writes an executable and then execs it. If another test runs
23+
// in parallel, its `Command` fork+exec can inherit our still-open write fd to the freshly
24+
// written binary during the fork->exec window, so our exec fails with ETXTBSY ("text file
25+
// busy", os error 26). O_CLOEXEC does not help because the fd is only closed on exec, not fork.
26+
// Serializing removes the write/exec overlap. (test_rollback_on_invalid_path needs no serial:
27+
// it never execs a freshly written binary.)
2128
#[test]
29+
#[serial]
2230
fn test_self_replacement_with_real_binary() {
2331
let temp_dir = TempDir::new().unwrap();
2432
let test_dir = temp_dir.path();
@@ -128,7 +136,10 @@ mod unix_specific {
128136

129137
const TEST_EXEC_MODE: u32 = 0o754; // rwxr-xr--
130138

139+
// Serial for the same reason as test_self_replacement_with_real_binary: writing then
140+
// exec-ing a binary races another test's fork+exec and hits ETXTBSY (os error 26).
131141
#[test]
142+
#[serial]
132143
fn test_permission_preservation_with_real_binary() {
133144
let temp_dir = TempDir::new().unwrap();
134145
let test_dir = temp_dir.path();

self-replacer/tests/test_helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub fn get_example_binary() -> PathBuf {
2929
};
3030
path.push(binary_name);
3131

32-
// Build the example if it doesn't exist
32+
// Build the example if it doesn't exist.
3333
if !path.exists() {
3434
eprintln!("Example binary not found, building it...");
3535
let output = std::process::Command::new("cargo")

0 commit comments

Comments
 (0)