use super::start_server;
use ic_host_process::tool::{OutputLimit, OutputLimits, capture_command};
use ic_logging::{EntryInput, Filter, Level, Limits, Log, PageRequest};
use ic_testkit::pocket_ic::PocketIc;
use std::{
num::NonZeroUsize,
path::Path,
process::Command,
sync::{Arc, Mutex},
time::Duration,
};
use tracing::{Event, Subscriber};
use tracing_subscriber::{Layer, layer::Context, prelude::*};
struct ApplicationLog(Arc<Mutex<Log>>);
impl<S: Subscriber> Layer<S> for ApplicationLog {
fn on_event(&self, event: &Event<'_>, _: Context<'_, S>) {
if event
.metadata()
.target()
.starts_with("ic_testkit::pocket_ic")
{
self.0
.lock()
.unwrap()
.append(EntryInput {
created_at_secs: 1,
level: Level::Debug,
source: "pocket-ic",
topic: None,
message: event.metadata().name(),
})
.unwrap();
}
}
}
#[test]
#[ignore = "requires an explicitly admitted PocketIC 16.1 server"]
fn clients_preserve_application_logging_and_ignore_legacy_environment() {
let (_server, url) = start_server();
let fixture = ic_host_fs::testing::FixtureDirectory::new(
Path::new(env!("CARGO_TARGET_TMPDIR")),
"client-logging",
)
.unwrap();
let blocked = fixture.path().join("regular-file");
std::fs::write(&blocked, b"caller-owned bytes").unwrap();
let absent = fixture.path().join("must-not-be-created");
for (mode, path) in [("early", &blocked), ("late", &absent)] {
let mut command = Command::new(std::env::current_exe().unwrap());
command
.args([
"--ignored",
"--exact",
"logging::logging_child",
"--nocapture",
])
.env("IC_TESTKIT_LOGGING_URL", &url)
.env("IC_TESTKIT_LOGGING_MODE", mode)
.env("POCKET_IC_LOG_DIR", path)
.env("POCKET_IC_LOG_DIR_LEVELS", "invalid[filter");
capture_command(
&mut command,
OutputLimits {
stdout: OutputLimit::Terminate(64 * 1024),
stderr: OutputLimit::Terminate(64 * 1024),
timeout: Some(Duration::from_secs(60)),
},
)
.unwrap()
.require_success()
.unwrap();
}
assert_eq!(std::fs::read(blocked).unwrap(), b"caller-owned bytes");
assert!(!absent.exists());
}
#[tokio::test]
#[ignore = "isolated child of the installed logging owner test"]
async fn logging_child() {
let Some(url) = std::env::var_os("IC_TESTKIT_LOGGING_URL") else {
return;
};
let url = url
.into_string()
.expect("parent supplies a UTF-8 server URL")
.parse()
.unwrap();
let early = std::env::var("IC_TESTKIT_LOGGING_MODE").unwrap() == "early";
let log = Arc::new(Mutex::new(Log::new(Limits {
max_entries: NonZeroUsize::new(64).unwrap(),
max_message_bytes: 256,
max_label_bytes: 32,
max_text_bytes: 16 * 1024,
})));
let install = || {
tracing::subscriber::set_global_default(
tracing_subscriber::registry().with(ApplicationLog(log.clone())),
)
.unwrap();
};
if early {
install();
}
let first = PocketIc::new(url).await.unwrap();
let borrowed = PocketIc::new_from_existing_instance(
first.get_server_url(),
first.instance_id,
Some(5_000),
);
let second = PocketIc::new(first.get_server_url()).await.unwrap();
borrowed.drop().await.unwrap();
first.topology().await.unwrap(); second.drop().await.unwrap();
first.drop().await.unwrap();
if !early {
install();
} tracing::info!(target: "ic_testkit::pocket_ic::application", "caller-selected logging");
let rows = log
.lock()
.unwrap()
.page(
Filter::default(),
PageRequest {
before: None,
max_results: NonZeroUsize::new(64).unwrap(),
max_scanned: NonZeroUsize::new(64).unwrap(),
},
)
.entries
.len();
assert!(rows >= if early { 3 } else { 1 });
}