Skip to content

Commit 1aeefbf

Browse files
committed
Statistic testing mode (build-and-stat-test) performing one build and count test runs for each crate
1 parent 1a2e31f commit 1aeefbf

File tree

18 files changed

+234
-45
lines changed

18 files changed

+234
-45
lines changed

src/actions/experiments/create.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub struct CreateExperiment {
1616
pub ignore_blacklist: bool,
1717
pub assign: Option<Assignee>,
1818
pub requirement: Option<String>,
19+
pub stat_run: Option<i32>,
1920
}
2021

2122
impl CreateExperiment {
@@ -34,6 +35,7 @@ impl CreateExperiment {
3435
ignore_blacklist: false,
3536
assign: None,
3637
requirement: None,
38+
stat_run: None,
3739
}
3840
}
3941
}
@@ -57,8 +59,8 @@ impl Action for CreateExperiment {
5759
"INSERT INTO experiments \
5860
(name, mode, cap_lints, toolchain_start, toolchain_end, priority, created_at, \
5961
status, github_issue, github_issue_url, github_issue_number, ignore_blacklist, \
60-
assigned_to, requirement) \
61-
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14);",
62+
assigned_to, requirement, stat_run) \
63+
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15);",
6264
&[
6365
&self.name,
6466
&self.mode.to_str(),
@@ -74,6 +76,7 @@ impl Action for CreateExperiment {
7476
&self.ignore_blacklist,
7577
&self.assign.map(|a| a.to_string()),
7678
&self.requirement,
79+
&self.stat_run,
7780
],
7881
)?;
7982

@@ -130,6 +133,7 @@ mod tests {
130133
ignore_blacklist: true,
131134
assign: None,
132135
requirement: Some("linux".to_string()),
136+
stat_run: None,
133137
}
134138
.apply(&ctx)
135139
.unwrap();
@@ -253,6 +257,7 @@ mod tests {
253257
ignore_blacklist: false,
254258
assign: None,
255259
requirement: None,
260+
stat_run: None,
256261
}
257262
.apply(&ctx)
258263
.unwrap_err();
@@ -283,6 +288,7 @@ mod tests {
283288
ignore_blacklist: false,
284289
assign: None,
285290
requirement: None,
291+
stat_run: None,
286292
}
287293
.apply(&ctx)
288294
.unwrap();
@@ -299,6 +305,7 @@ mod tests {
299305
ignore_blacklist: false,
300306
assign: None,
301307
requirement: None,
308+
stat_run: None,
302309
}
303310
.apply(&ctx)
304311
.unwrap_err();

src/actions/experiments/edit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ mod tests {
205205
ignore_blacklist: false,
206206
assign: None,
207207
requirement: None,
208+
stat_run: None,
208209
}
209210
.apply(&ctx)
210211
.unwrap();

src/cli.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ pub enum Crater {
116116
assign: Option<Assignee>,
117117
#[clap(name = "requirement", long = "requirement")]
118118
requirement: Option<String>,
119+
#[clap(
120+
name = "stat-run",
121+
long = "stat-run",
122+
help = "For statistic testing mode (build-and-stat-test), amount of test runs."
123+
)]
124+
stat_run: Option<i32>,
119125
},
120126

121127
#[clap(name = "edit", about = "edit an experiment configuration")]
@@ -305,6 +311,7 @@ impl Crater {
305311
ref ignore_blacklist,
306312
ref assign,
307313
ref requirement,
314+
ref stat_run,
308315
} => {
309316
let config = Config::load()?;
310317
let db = Database::open()?;
@@ -321,6 +328,7 @@ impl Crater {
321328
ignore_blacklist: *ignore_blacklist,
322329
assign: assign.clone(),
323330
requirement: requirement.clone(),
331+
stat_run: *stat_run,
324332
}
325333
.apply(&ctx)?;
326334
}

src/db/migrations.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,18 @@ fn migrations() -> Vec<(&'static str, MigrationKind)> {
363363
MigrationKind::SQL("alter table agents add column latest_work_for text;"),
364364
));
365365

366+
// `results` table analog for statistic runs.
367+
// statistic run performs one build and several test runs.
368+
// run_num == 0 keeps build log.
369+
migrations.push((
370+
"add_statistic_results",
371+
MigrationKind::SQL(
372+
"
373+
ALTER TABLE experiments ADD COLUMN stat_run INTEGER DEFAULT 0;
374+
",
375+
),
376+
));
377+
366378
migrations
367379
}
368380

src/experiments.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ string_enum!(pub enum Status {
2525

2626
string_enum!(pub enum Mode {
2727
BuildAndTest => "build-and-test",
28+
BuildAndStatTest => "build-and-stat-test",
2829
BuildOnly => "build-only",
2930
CheckOnly => "check-only",
3031
Clippy => "clippy",
@@ -259,6 +260,7 @@ pub struct Experiment {
259260
pub report_url: Option<String>,
260261
pub ignore_blacklist: bool,
261262
pub requirement: Option<String>,
263+
pub stat_run: Option<i32>,
262264
}
263265

264266
impl Experiment {
@@ -678,6 +680,7 @@ pub struct ExperimentDBRecord {
678680
report_url: Option<String>,
679681
ignore_blacklist: bool,
680682
requirement: Option<String>,
683+
stat_run: Option<i32>,
681684
}
682685

683686
impl ExperimentDBRecord {
@@ -700,6 +703,7 @@ impl ExperimentDBRecord {
700703
report_url: row.get("report_url")?,
701704
ignore_blacklist: row.get("ignore_blacklist")?,
702705
requirement: row.get("requirement")?,
706+
stat_run: row.get("stat_run")?,
703707
})
704708
}
705709

@@ -735,6 +739,7 @@ impl ExperimentDBRecord {
735739
report_url: self.report_url,
736740
ignore_blacklist: self.ignore_blacklist,
737741
requirement: self.requirement,
742+
stat_run: self.stat_run,
738743
})
739744
}
740745
}

src/report/analyzer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ mod tests {
166166
report_url: None,
167167
ignore_blacklist: false,
168168
requirement: None,
169+
stat_run: None,
169170
};
170171

171172
let crates = record_crates! {db, ex,

src/report/display.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::prelude::*;
22
use crate::report::Comparison;
3-
use crate::results::{BrokenReason, FailureReason, TestResult};
3+
use crate::results::{BrokenReason, FailureReason, StatFailureReasons, TestResult};
4+
use std::collections::HashMap;
45

56
pub trait ResultName {
67
fn short_name(&self) -> String;
@@ -38,6 +39,41 @@ impl ResultName for FailureReason {
3839
}
3940
}
4041

42+
impl ResultName for StatFailureReasons {
43+
fn short_name(&self) -> String {
44+
let StatFailureReasons::Reasons(vec) = self else {
45+
return String::new();
46+
};
47+
// ex: "failed (unknown) x2 | OOM x4 | ICE x1"
48+
let unique_counts: HashMap<String, usize> =
49+
vec.iter().fold(HashMap::new(), |mut map, val| {
50+
*map.entry(val.short_name()).or_insert(0) += 1;
51+
map
52+
});
53+
unique_counts
54+
.iter()
55+
.map(|v| format!("{} x{}", v.0, v.1))
56+
.collect::<Vec<_>>()
57+
.join(" | ")
58+
}
59+
60+
fn long_name(&self) -> String {
61+
let StatFailureReasons::Reasons(vec) = self else {
62+
return String::new();
63+
};
64+
let unique_counts: HashMap<String, usize> =
65+
vec.iter().fold(HashMap::new(), |mut map, val| {
66+
*map.entry(val.long_name()).or_insert(0) += 1;
67+
map
68+
});
69+
unique_counts
70+
.iter()
71+
.map(|v| format!("{} x{}", v.0, v.1))
72+
.collect::<Vec<_>>()
73+
.join(" | ")
74+
}
75+
}
76+
4177
impl ResultName for BrokenReason {
4278
fn short_name(&self) -> String {
4379
match self {
@@ -61,6 +97,7 @@ impl ResultName for TestResult {
6197
TestResult::PrepareFail(reason) => format!("prepare {}", reason.short_name()),
6298
TestResult::BuildFail(reason) => format!("build {}", reason.short_name()),
6399
TestResult::TestFail(reason) => format!("test {}", reason.short_name()),
100+
TestResult::TestsFail(reason) => format!("tests: {}", reason.short_name()),
64101
TestResult::TestSkipped => "test skipped".into(),
65102
TestResult::TestPass => "test passed".into(),
66103
TestResult::Error => "error".into(),
@@ -73,6 +110,7 @@ impl ResultName for TestResult {
73110
TestResult::PrepareFail(reason) => format!("prepare {}", reason.long_name()),
74111
TestResult::BuildFail(reason) => format!("build {}", reason.long_name()),
75112
TestResult::TestFail(reason) => format!("test {}", reason.long_name()),
113+
TestResult::TestsFail(reason) => format!("tests: {}", reason.long_name()),
76114
TestResult::BrokenCrate(reason) => reason.long_name(),
77115
TestResult::TestSkipped
78116
| TestResult::TestPass
@@ -118,6 +156,7 @@ impl ResultColor for TestResult {
118156
TestResult::BrokenCrate(_) => Color::Single("#44176e"),
119157
TestResult::BuildFail(_) => Color::Single("#db3026"),
120158
TestResult::TestFail(_) => Color::Single("#65461e"),
159+
TestResult::TestsFail(_) => Color::Single("#65461e"),
121160
TestResult::TestSkipped | TestResult::TestPass => Color::Single("#62a156"),
122161
TestResult::Error => Color::Single("#d77026"),
123162
TestResult::PrepareFail(_) => Color::Striped("#44176e", "#d77026"),

src/report/mod.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use crate::dirs::WORK_DIR;
44
use crate::experiments::Experiment;
55
use crate::prelude::*;
66
use crate::report::analyzer::{analyze_report, ReportConfig, ToolchainSelect};
7-
use crate::results::{EncodedLog, EncodingType, FailureReason, ReadResults, TestResult};
7+
use crate::results::{
8+
EncodedLog, EncodingType, FailureReason, ReadResults, StatFailureReasons, TestResult,
9+
};
810
use crate::toolchain::Toolchain;
911
use crate::utils;
1012
use crates_index::SparseIndex;
@@ -514,32 +516,61 @@ fn compare(
514516
(TestPass, TestPass) => Comparison::SameTestPass,
515517

516518
// (spurious) fixed
517-
(BuildFail(reason), TestSkipped | TestFail(_) | TestPass)
519+
(BuildFail(reason), TestSkipped | TestFail(_) | TestsFail(_) | TestPass)
518520
| (TestFail(reason), TestPass) => {
519521
if reason.is_spurious() {
520522
Comparison::SpuriousFixed
521523
} else {
522524
Comparison::Fixed
523525
}
524526
}
527+
(TestsFail(reason), TestPass) => {
528+
if reason.is_spurious() {
529+
Comparison::SpuriousFixed
530+
} else {
531+
Comparison::Fixed
532+
}
533+
}
525534

526535
// (spurious) regressed
527-
(TestSkipped | TestFail(_) | TestPass, BuildFail(reason))
536+
(TestSkipped | TestFail(_) | TestsFail(_) | TestPass, BuildFail(reason))
528537
| (TestPass, TestFail(reason)) => {
529538
if reason.is_spurious() {
530539
Comparison::SpuriousRegressed
531540
} else {
532541
Comparison::Regressed
533542
}
534543
}
544+
(TestPass, TestsFail(reason)) => {
545+
if reason.is_spurious() {
546+
Comparison::SpuriousRegressed
547+
} else {
548+
Comparison::Regressed
549+
}
550+
}
535551

536552
(Skipped, _) | (_, Skipped) => Comparison::Skipped,
537553
(BrokenCrate(_), _) | (_, BrokenCrate(_)) => Comparison::Broken,
538554
(PrepareFail(_), _) | (_, PrepareFail(_)) => Comparison::PrepareFail,
539555
(Error, _) | (_, Error) => Comparison::Error,
540-
(TestFail(_) | TestPass, TestSkipped) | (TestSkipped, TestFail(_) | TestPass) => {
556+
(TestFail(_) | TestsFail(_) | TestPass, TestSkipped)
557+
| (TestSkipped, TestFail(_) | TestsFail(_) | TestPass) => {
541558
panic!("can't compare {res1} and {res2}");
542559
}
560+
561+
// Stat tests comparison
562+
(TestsFail(v1), TestsFail(v2)) => {
563+
let (StatFailureReasons::Reasons(v1), StatFailureReasons::Reasons(v2)) = (v1, v2)
564+
else {
565+
panic!("can't compare {res1} and {res2}");
566+
};
567+
if v2.len() > v1.len() {
568+
Comparison::Regressed
569+
} else {
570+
Comparison::SameTestFail
571+
}
572+
}
573+
(TestsFail(_), TestFail(_)) | (TestFail(_), TestsFail(_)) => Comparison::SameTestFail,
543574
},
544575
_ if config.should_skip(krate) => Comparison::Skipped,
545576
_ => Comparison::Unknown,
@@ -940,6 +971,7 @@ mod tests {
940971
report_url: None,
941972
ignore_blacklist: false,
942973
requirement: None,
974+
stat_run: None,
943975
};
944976

945977
let mut db = DummyDB::default();

src/results/db.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,13 @@ impl crate::runner::RecordProgress for DatabaseDB<'_> {
266266
result: &TestResult,
267267
version: Option<(&Crate, &Crate)>,
268268
) -> Fallible<()> {
269-
self.store_result(ex, krate, toolchain, result, log, EncodingType::Plain)?;
270-
if let Some((old, new)) = version {
269+
let krate = if let Some((old, new)) = version {
271270
self.update_crate_version(ex, old, new)?;
272-
}
271+
new
272+
} else {
273+
krate
274+
};
275+
self.store_result(ex, krate, toolchain, result, log, EncodingType::Plain)?;
273276
Ok(())
274277
}
275278
}

0 commit comments

Comments
 (0)