Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp --follow-exec #962

Merged
merged 21 commits into from
Mar 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
env:
RUST_BACKTRACE: 1
- name: test
run: cargo test
run: cargo test
env:
RUST_BACKTRACE: 1
- name: ignored test
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
# will have compiled files and executables
**/target
*.swp
*.swo
**/*.rs.bk
*.log
*.profdata
*.profraw
*.profdata
# Generated by IntelliJ IDEs
.idea
tarpaulin*.json
tarpaulin-report.html
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ file.
### Changed
- Stop adding `LD_LIBRARY_PATHS` to process env twice
- [Internal] can now run `cargo test` on tarpaulin without need of `--test-threads 1`
- Force --test-threads 1 for --follow-exec unless there's `--implicit-test-threads`
- Add markers to event log to show where state machine iterations start and end, fix fork parent tracing
- Handle exec following in vfork children
- Continue vfork parents so test execution isn't stalled when tracing children
- Make `--forward` default signal behaviour
- Fix follow-exec aliasing for config file

## [0.19.1] 2022-01-16
### Added
Expand Down
6 changes: 4 additions & 2 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ pub struct Config {
/// Colouring of logging
pub color: Color,
/// Follow traced executables down
#[serde(rename = "follow-exec")]
pub follow_exec: bool,
/// Number of jobs used for building the tests
pub jobs: Option<usize>,
Expand Down Expand Up @@ -209,7 +210,7 @@ impl Default for Config {
coveralls: None,
ci_tool: None,
report_uri: None,
forward_signals: false,
forward_signals: true,
no_default_features: false,
features: None,
unstable_features: vec![],
Expand Down Expand Up @@ -302,7 +303,7 @@ impl<'a> From<&'a ArgMatches<'a>> for ConfigWrapper {
coveralls: get_coveralls(args),
ci_tool: get_ci(args),
report_uri: get_report_uri(args),
forward_signals: args.is_present("forward"),
forward_signals: true, // No longer an option
all_features: args.is_present("all-features"),
no_default_features: args.is_present("no-default-features"),
features,
Expand Down Expand Up @@ -540,6 +541,7 @@ impl Config {
self.no_run |= other.no_run;
self.no_default_features |= other.no_default_features;
self.ignore_panics |= other.ignore_panics;
// Since true is the default
self.forward_signals |= other.forward_signals;
self.run_ignored |= other.run_ignored;
self.release |= other.release;
Expand Down
46 changes: 34 additions & 12 deletions src/event_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ use crate::ptrace_control::*;
use crate::statemachine::ProcessInfo;
use crate::statemachine::TracerAction;
use crate::traces::{Location, TraceMap};
use chrono::offset::Local;
use chrono::{offset::Local, SecondsFormat};
#[cfg(target_os = "linux")]
use nix::libc::*;
#[cfg(target_os = "linux")]
use nix::sys::{signal::Signal, wait::WaitStatus};
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashSet;
use std::fs::File;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::time::Instant;
use tracing::{info, warn};

Expand All @@ -22,6 +23,7 @@ pub enum Event {
ConfigLaunch(String),
BinaryLaunch(TestBinary),
Trace(TraceEvent),
Marker(Option<()>),
}

#[derive(Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
Expand Down Expand Up @@ -53,7 +55,7 @@ pub struct TraceEvent {
impl TraceEvent {
#[cfg(target_os = "linux")]
pub(crate) fn new_from_action(action: &TracerAction<ProcessInfo>) -> Self {
match *action {
match action {
TracerAction::TryContinue(t) => TraceEvent {
pid: Some(t.pid.as_raw().into()),
signal: t.signal.map(|x| x.to_string()),
Expand Down Expand Up @@ -122,9 +124,15 @@ impl TraceEvent {
}
PTRACE_EVENT_FORK => {
event.description = "Ptrace fork".to_string();
if *sig == Signal::SIGTRAP {
event.child = get_event_data(*pid).ok();
}
}
PTRACE_EVENT_VFORK => {
event.description = "Ptrace vfork".to_string();
if *sig == Signal::SIGTRAP {
event.child = get_event_data(*pid).ok();
}
}
PTRACE_EVENT_EXEC => {
event.description = "Ptrace exec".to_string();
Expand All @@ -151,24 +159,20 @@ impl TraceEvent {
}
}

#[derive(Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct EventLog {
events: RefCell<Vec<EventWrapper>>,
#[serde(skip)]
start: Option<Instant>,
}

impl Default for EventLog {
fn default() -> Self {
Self::new()
}
manifest_paths: HashSet<PathBuf>,
}

impl EventLog {
pub fn new() -> Self {
pub fn new(manifest_paths: HashSet<PathBuf>) -> Self {
Self {
events: RefCell::new(vec![]),
start: Some(Instant::now()),
manifest_paths,
}
}

Expand All @@ -191,11 +195,29 @@ impl EventLog {
self.start.unwrap(),
));
}

pub fn push_marker(&self) {
// Prevent back to back markers when we spend a lot of time waiting on events
if self
.events
.borrow()
.last()
.filter(|x| matches!(x.event, Event::Marker(_)))
.is_none()
{
self.events
.borrow_mut()
.push(EventWrapper::new(Event::Marker(None), self.start.unwrap()));
}
}
}

impl Drop for EventLog {
fn drop(&mut self) {
let fname = format!("tarpaulin-run-{}.json", Local::now().to_rfc3339());
let fname = format!(
"tarpaulin_{}.json",
Local::now().to_rfc3339_opts(SecondsFormat::Secs, false)
);
let path = Path::new(&fname);
info!("Serializing tarpaulin debug log to {}", path.display());
if let Ok(output) = File::create(path) {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub fn trace(configs: &[Config]) -> Result<TraceMap, RunError> {
let mut tarpaulin_result = Ok(());
let mut ret = 0i32;
let logger = if configs.iter().any(|c| c.dump_traces) {
Some(EventLog::new())
Some(EventLog::new(configs.iter().map(|x| x.root()).collect()))
} else {
None
};
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fn main() -> Result<(), String> {
--force-clean 'Adds a clean stage to work around cargo bugs that may affect coverage results'
--fail-under [PERCENTAGE] 'Sets a percentage threshold for failure ranging from 0-100, if coverage is below exit with a non-zero code'
--branch -b 'Branch coverage: NOT IMPLEMENTED'
--forward -f 'Forwards unexpected signals to test. Tarpaulin will still take signals it is expecting.'
--forward -f 'Forwards unexpected signals to test. This is now the default behaviour'
--coveralls [KEY] 'Coveralls key, either the repo token, or if you're using travis use $TRAVIS_JOB_ID and specify travis-{ci|pro} in --ciserver'
--report-uri [URI] 'URI to send report to, only used if the option --coveralls is used'
--no-default-features 'Do not include default features'
Expand Down
7 changes: 5 additions & 2 deletions src/process_handling/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ pub fn get_test_coverage(
warn!("Test at {} doesn't exist", test.path().display());
return Ok(None);
}
let cpus = Some(*NUM_CPUS);

// Solves CI issue when fixing #953 and #966 in PR #962
let threads = if config.follow_exec { 1 } else { *NUM_CPUS };

if let Err(e) = limit_affinity() {
warn!("Failed to set processor affinity {}", e);
}
Expand All @@ -56,7 +59,7 @@ pub fn get_test_coverage(
Mode::Build => "binary",
};
info!("Launching {}", bin_type);
execute_test(test, ignored, config, cpus)?;
execute_test(test, ignored, config, Some(threads))?;
Ok(None)
}
Err(err) => Err(RunError::TestCoverage(format!(
Expand Down
3 changes: 3 additions & 0 deletions src/process_handling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ pub(crate) fn collect_coverage(
ret_code = i;
}
break;
} else if let Some(event_logger) = logger {
event_logger.push_marker();
}
}
}
Expand Down Expand Up @@ -224,6 +226,7 @@ fn execute_test(
} else {
true
};

if no_test_env
&& test.is_test_type()
&& !config.implicit_test_threads
Expand Down
4 changes: 4 additions & 0 deletions src/statemachine/instrumented.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ impl<'a> StateData for LlvmInstrumentedData<'a> {
unreachable!();
}

fn last_wait_attempt(&mut self) -> Result<Option<TestState>, RunError> {
unreachable!();
}

fn wait(&mut self) -> Result<Option<TestState>, RunError> {
if let Some(parent) = self.process.as_mut() {
match parent.child.wait() {
Expand Down
Loading