blob: e843a3610aa7dae817da765adb377fe1447fba37 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::puppet::PuppetProxyExt;
use crate::test_topology;
use fidl_fuchsia_archivist_test as ftest;
use fidl_fuchsia_diagnostics::Severity;
use futures::StreamExt;
use tracing::warn;
#[fuchsia::test]
async fn logs_from_crashing_component() -> Result<(), anyhow::Error> {
const REALM_NAME: &str = "logs_from_crashing_component";
const PUPPET_NAME: &str = "puppet";
const PUPPET_CRASH_MESSAGE: &str = "this is an expected panic";
const LOG_MESSAGE: &str = "logged before crashing";
let puppet_moniker: String =
format!("realm_factory/realm_builder:{REALM_NAME}/test/{PUPPET_NAME}");
// Create the test realm.
let realm_proxy = test_topology::create_realm(ftest::RealmOptions {
realm_name: Some(REALM_NAME.to_string()),
puppets: Some(vec![test_topology::PuppetDeclBuilder::new(PUPPET_NAME).into()]),
..Default::default()
})
.await
.expect("create test topology");
// Connect to the puppet, tell it to log some messages and then crash itself.
let puppet = test_topology::connect_to_puppet(&realm_proxy, PUPPET_NAME)
.await
.expect("connect to puppet");
puppet.wait_for_interest_change().await.unwrap(); // Wait for initial interest.
puppet.log_messages(vec![(Severity::Info, LOG_MESSAGE)]).await;
// Ensure the puppet logged before crashing.
// The crash's stacktrace and panic message appear in the log output, so check for the
// subsequence of expected logs rather than a contiguous list of matching lines.
let mut log_buf: Vec<String> = vec![];
let mut found_log_message = false;
let mut found_crash_message = false;
let mut logs = crate::utils::snapshot_and_stream_logs(&realm_proxy).await;
// Check for the log message.
while let Some(Ok(logs_data)) = logs.next().await {
log_buf.push(logs_data.msg().unwrap().to_string().clone());
if logs_data.moniker == PUPPET_NAME
&& logs_data.msg().unwrap() == LOG_MESSAGE
&& logs_data.metadata.severity == Severity::Info
{
found_log_message = true;
break;
}
}
// Only print the logs on failure to avoid spam.
if !found_log_message {
dump_logs_and_fail(log_buf, format!("Did not find log '{LOG_MESSAGE}'"));
return Ok(());
}
puppet.crash(PUPPET_CRASH_MESSAGE)?;
crate::utils::wait_for_component_to_crash(&puppet_moniker).await;
drop(realm_proxy); // Closes the puppet's log stream so we don't loop forever.
// Check for the panic message.
while let Some(Ok(logs_data)) = logs.next().await {
log_buf.push(logs_data.msg().unwrap().to_string().clone());
let payload = logs_data.payload.clone().unwrap();
if logs_data.moniker == PUPPET_NAME
&& logs_data.msg().unwrap() == "PANIC"
&& payload
.get_property_by_path(&["keys", "info"])
.unwrap()
.string()
.unwrap()
.contains(PUPPET_CRASH_MESSAGE)
{
found_crash_message = true;
break;
}
}
// Only print the logs on failure to avoid spam.
if !found_crash_message {
dump_logs_and_fail(log_buf, format!("Did not find log '{PUPPET_CRASH_MESSAGE}'"));
}
Ok(())
}
fn dump_logs_and_fail(logs: Vec<String>, message: String) {
warn!("Failing this test. It received these logs:");
for (line, message) in logs.iter().enumerate() {
warn!("{line}: {message}");
}
panic!("ERROR: {message}");
}