Skip to content

Commit a435eca

Browse files
committed
Auto merge of #520 - Zeegomo:advanced-report, r=pietroalbini
Advanced report #519 and other changes (additions of new local crates, waiting on #519 merge too) need to be merged before this. This pr updates the html report to display more advanced info like root dependencies. Currently the detailed report is active for `Regressed` and `Fixed` but it can be changed easily.
2 parents 72cfb88 + 1208bbf commit a435eca

File tree

9 files changed

+489
-67
lines changed

9 files changed

+489
-67
lines changed

assets/report.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,24 @@ div.category div.header {
139139
padding: 0.5em 0.8em;
140140
border-radius: 0.2em;
141141
box-shadow: 0 0.1em 0.2em rgba(0, 0, 0, 0.5);
142+
}
142143

144+
.flex {
145+
display: flex;
143146
position: -webkit-sticky;
144147
position: sticky;
145148
top: 0.5em;
146149
}
147150

151+
div.category div.subheader.header {
152+
border-radius: 0.2em 0 0 0.2em;
153+
}
154+
155+
div.category div.subheader + div.header {
156+
flex-grow: 1;
157+
border-radius: 0 0.2em 0.2em 0;
158+
}
159+
148160
div.category div.header.header-background {
149161
background: #292929;
150162
}

src/report/analyzer.rs

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
use super::{Comparison, CrateResult, RawTestResults};
2+
use crate::crates::Crate;
3+
use crate::results::{
4+
FailureReason,
5+
TestResult::{self, BuildFail},
6+
};
7+
use std::collections::BTreeSet;
8+
use std::collections::HashMap;
9+
10+
pub enum ToolchainSelect {
11+
Start,
12+
End,
13+
}
14+
15+
pub enum ReportConfig {
16+
Simple,
17+
Complete(ToolchainSelect),
18+
}
19+
20+
#[cfg_attr(test, derive(Debug, PartialEq))]
21+
#[derive(Clone)]
22+
pub enum ReportCrates {
23+
Plain(Vec<CrateResult>),
24+
Complete {
25+
tree: HashMap<Crate, Vec<CrateResult>>,
26+
results: HashMap<TestResult, Vec<CrateResult>>,
27+
},
28+
}
29+
30+
#[cfg_attr(test, derive(Debug, PartialEq))]
31+
pub struct TestResults {
32+
pub categories: HashMap<Comparison, ReportCrates>,
33+
pub info: HashMap<Comparison, u32>,
34+
}
35+
36+
fn analyze_detailed(toolchain: usize, crates: Vec<CrateResult>) -> ReportCrates {
37+
let mut tree = HashMap::new();
38+
let mut results = HashMap::new();
39+
40+
let mut root = Vec::new();
41+
for krate in crates {
42+
if let BuildFail(FailureReason::DependsOn(ref deps)) =
43+
(&krate.runs[toolchain]).as_ref().unwrap().res
44+
{
45+
for dep in deps {
46+
tree.entry(dep.clone())
47+
.or_insert_with(Vec::new)
48+
.push(krate.clone())
49+
}
50+
} else {
51+
root.push(krate);
52+
}
53+
}
54+
55+
for krate in root {
56+
// record results only for root crates
57+
if let BuildFail(FailureReason::CompilerError(codes)) =
58+
krate.runs[toolchain].clone().unwrap().res
59+
{
60+
for code in codes {
61+
results
62+
.entry(BuildFail(FailureReason::CompilerError(btreeset![code])))
63+
.or_insert_with(Vec::new)
64+
.push(krate.clone())
65+
}
66+
} else {
67+
results
68+
.entry(krate.runs[toolchain].as_ref().unwrap().res.clone())
69+
.or_insert_with(Vec::new)
70+
.push(krate)
71+
}
72+
}
73+
74+
ReportCrates::Complete { tree, results }
75+
}
76+
77+
pub fn analyze_report(test: RawTestResults) -> TestResults {
78+
let mut comparison = HashMap::new();
79+
for krate in test.crates {
80+
comparison
81+
.entry(krate.res)
82+
.or_insert_with(Vec::new)
83+
.push(krate);
84+
}
85+
86+
let info = comparison
87+
.iter()
88+
.map(|(&key, vec)| (key, vec.len() as u32))
89+
.collect::<HashMap<_, _>>();
90+
91+
let mut categories = HashMap::new();
92+
for (cat, crates) in comparison {
93+
if let ReportConfig::Complete(toolchain) = cat.report_config() {
94+
// variants in an enum are numbered following an
95+
// increasing sequence starting from 0
96+
categories.insert(cat, analyze_detailed(toolchain as usize, crates));
97+
} else {
98+
categories.insert(cat, ReportCrates::Plain(crates));
99+
}
100+
}
101+
102+
TestResults { categories, info }
103+
}
104+
105+
#[cfg(test)]
106+
mod tests {
107+
use super::*;
108+
use crate::config::Config;
109+
use crate::crates::{Crate, RegistryCrate};
110+
use crate::experiments::{CapLints, Experiment, Mode, Status};
111+
use crate::report::{generate_report, Comparison};
112+
use crate::results::{DummyDB, FailureReason::*};
113+
use crate::toolchain::{MAIN_TOOLCHAIN, TEST_TOOLCHAIN};
114+
use failure::Fallible;
115+
116+
#[test]
117+
fn test_report_analysis() -> Fallible<()> {
118+
macro_rules! reg {
119+
($name:expr) => {
120+
Crate::Registry(RegistryCrate {
121+
name: $name.into(),
122+
version: "0.0.1".into(),
123+
})
124+
};
125+
}
126+
127+
macro_rules! record_crates {
128+
($db:expr, $ex:expr, $($name:expr => ($tc1:expr, $tc2:expr)),*) => {
129+
{
130+
let mut crates = Vec::new();
131+
$(
132+
let krate = reg!($name);
133+
$db.add_dummy_result(
134+
&$ex,
135+
krate.clone(),
136+
MAIN_TOOLCHAIN.clone(),
137+
$tc1,
138+
);
139+
$db.add_dummy_result(
140+
&$ex,
141+
krate.clone(),
142+
TEST_TOOLCHAIN.clone(),
143+
$tc2,
144+
);
145+
crates.push(krate);
146+
)*
147+
crates
148+
}
149+
};
150+
}
151+
152+
let config = Config::default();
153+
let mut db = DummyDB::default();
154+
let ex = Experiment {
155+
name: "foo".to_string(),
156+
toolchains: [MAIN_TOOLCHAIN.clone(), TEST_TOOLCHAIN.clone()],
157+
mode: Mode::BuildAndTest,
158+
cap_lints: CapLints::Forbid,
159+
priority: 0,
160+
created_at: ::chrono::Utc::now(),
161+
started_at: None,
162+
completed_at: None,
163+
github_issue: None,
164+
status: Status::GeneratingReport,
165+
assigned_to: None,
166+
report_url: None,
167+
ignore_blacklist: false,
168+
requirement: None,
169+
};
170+
171+
let crates = record_crates! {db, ex,
172+
"test-pass" => (TestResult::TestPass, TestResult::TestPass),
173+
"ce-1" => (TestResult::TestPass, TestResult::BuildFail(CompilerError(btreeset!["001".parse()?, "002".parse()?]))),
174+
"ce-2" => (TestResult::TestPass, TestResult::BuildFail(CompilerError(btreeset!["002".parse()?]))),
175+
"unknown" => (TestResult::TestPass, TestResult::BuildFail(Unknown)),
176+
"dep-1" => (TestResult::TestPass, TestResult::BuildFail(DependsOn(btreeset![reg!("ce-1"), reg!("unknown")]))),
177+
"dep-2" => (TestResult::TestPass, TestResult::BuildFail(DependsOn(btreeset![reg!("ce-1"), reg!("ce-2")]))),
178+
"fix-1" => (TestResult::BuildFail(DependsOn(btreeset![reg!("ce-1"), reg!("ce-2")])), TestResult::TestPass),
179+
"fix-2" => (TestResult::BuildFail(Unknown), TestResult::TestPass)
180+
};
181+
182+
let raw = generate_report(&db, &config, &ex, &crates)?;
183+
let mut crates = raw
184+
.crates
185+
.clone()
186+
.into_iter()
187+
.map(|krate| {
188+
if let Crate::Registry(ref registry_krate) = krate.krate {
189+
(registry_krate.name.clone(), krate)
190+
} else {
191+
panic!("invalid crate type")
192+
}
193+
})
194+
.collect::<HashMap<_, _>>();
195+
let analyzed = analyze_report(raw);
196+
197+
let mut info = HashMap::new();
198+
info.insert(Comparison::Regressed, 5);
199+
info.insert(Comparison::Fixed, 2);
200+
info.insert(Comparison::SameTestPass, 1);
201+
202+
macro_rules! create_results {
203+
($src:expr, $($key:expr => ($($krate:expr),*)),*) => {
204+
{
205+
let mut map = HashMap::new();
206+
$(
207+
let mut crates = Vec::new();
208+
$(
209+
crates.push($src.get($krate).unwrap().clone());
210+
)*
211+
map.insert($key, crates);
212+
)*
213+
map
214+
}
215+
}
216+
}
217+
218+
let regr_tree = create_results! {crates,
219+
reg!("ce-1") => ("dep-1", "dep-2"),
220+
reg!("ce-2") => ("dep-2"),
221+
reg!("unknown") => ("dep-1")
222+
};
223+
224+
let regr_root = create_results! {crates,
225+
TestResult::BuildFail(CompilerError(btreeset!["001".parse()?])) => ("ce-1"),
226+
TestResult::BuildFail(CompilerError(btreeset!["002".parse()?])) => ("ce-1", "ce-2"),
227+
TestResult::BuildFail(Unknown) => ("unknown")
228+
};
229+
230+
let regressed = ReportCrates::Complete {
231+
tree: regr_tree,
232+
results: regr_root,
233+
};
234+
235+
let fix_tree = create_results! {crates,
236+
reg!("ce-1") => ("fix-1"),
237+
reg!("ce-2") => ("fix-1")
238+
};
239+
240+
let fix_root = create_results! {crates,
241+
TestResult::BuildFail(Unknown) => ("fix-2")
242+
};
243+
244+
let fixed = ReportCrates::Complete {
245+
tree: fix_tree,
246+
results: fix_root,
247+
};
248+
249+
let test_pass = ReportCrates::Plain(vec![crates.remove("test-pass").unwrap()]);
250+
251+
let mut categories = HashMap::new();
252+
categories.insert(Comparison::Regressed, regressed);
253+
categories.insert(Comparison::Fixed, fixed);
254+
categories.insert(Comparison::SameTestPass, test_pass);
255+
256+
let expected = TestResults { categories, info };
257+
assert_eq!(expected, analyzed);
258+
259+
Ok(())
260+
}
261+
}

src/report/display.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub trait ResultName {
99
impl ResultName for FailureReason {
1010
fn name(&self) -> String {
1111
match self {
12-
FailureReason::Unknown => "failed".into(),
12+
FailureReason::Unknown => "failed (unknown)".into(),
1313
FailureReason::Timeout => "timed out".into(),
1414
FailureReason::OOM => "OOM".into(),
1515
FailureReason::ICE => "ICE".into(),

0 commit comments

Comments
 (0)