Skip to content

Commit d48d3bd

Browse files
committed
Queries for partial status page data tested
1 parent 7be3e39 commit d48d3bd

File tree

3 files changed

+257
-35
lines changed

3 files changed

+257
-35
lines changed

database/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,10 @@ impl BenchmarkJob {
11581158
pub fn deque_count(&self) -> u32 {
11591159
self.deque_counter
11601160
}
1161+
1162+
pub fn status(&self) -> BenchmarkJobStatus {
1163+
&self.status
1164+
}
11611165
}
11621166

11631167
/// Describes the final state of a job
@@ -1218,6 +1222,5 @@ impl CollectorConfig {
12181222
#[derive(Debug, PartialEq)]
12191223
pub struct PartialStatusPageData {
12201224
pub completed_requests: Vec<(BenchmarkRequest, String, Vec<String>)>,
1221-
pub in_progress_jobs: Vec<BenchmarkJob>,
1222-
pub in_progress_requests: Vec<BenchmarkRequest>,
1225+
pub in_progress: Vec<(BenchmarkRequest, Vec<BenchmarkJob>)>,
12231226
}

database/src/pool.rs

Lines changed: 99 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ mod tests {
395395
use super::*;
396396
use crate::metric::Metric;
397397
use crate::tests::run_postgres_test;
398+
use crate::BenchmarkJobStatus;
398399
use crate::{tests::run_db_test, BenchmarkRequestType, Commit, CommitType, Date};
399400
use chrono::Utc;
400401
use std::str::FromStr;
@@ -991,6 +992,7 @@ mod tests {
991992
let benchmark_set = BenchmarkSet(0u32);
992993
let time = chrono::DateTime::from_str("2021-09-01T00:00:00.000Z").unwrap();
993994
let tag = "sha-1";
995+
let tag_two = "sha-2";
994996
let collector_name = "collector-1";
995997
let target = Target::X86_64UnknownLinuxGnu;
996998

@@ -1003,43 +1005,117 @@ mod tests {
10031005
.await
10041006
.unwrap();
10051007

1006-
/* Create job for the request */
1008+
complete_request(&*db, tag, collector_name, benchmark_set.0, &target).await;
1009+
// record a couple of errors against the tag
1010+
let artifact_id = db.artifact_id(&ArtifactId::Tag(tag.to_string())).await;
1011+
1012+
db.record_error(artifact_id, "example-1", "This is an error")
1013+
.await;
1014+
db.record_error(artifact_id, "example-2", "This is another error")
1015+
.await;
1016+
1017+
let benchmark_request_two = BenchmarkRequest::create_release(tag_two, time);
1018+
db.insert_benchmark_request(&benchmark_request_two)
1019+
.await
1020+
.unwrap();
1021+
10071022
db.enqueue_benchmark_job(
1008-
benchmark_request.tag().unwrap(),
1023+
benchmark_request_two.tag().unwrap(),
10091024
&target,
10101025
&CodegenBackend::Llvm,
10111026
&Profile::Opt,
10121027
benchmark_set.0,
10131028
)
10141029
.await
10151030
.unwrap();
1031+
db.enqueue_benchmark_job(
1032+
benchmark_request_two.tag().unwrap(),
1033+
&target,
1034+
&CodegenBackend::Llvm,
1035+
&Profile::Debug,
1036+
benchmark_set.0,
1037+
)
1038+
.await
1039+
.unwrap();
10161040

1017-
let job = db
1018-
.dequeue_benchmark_job(collector_name, &target, &benchmark_set)
1019-
.await
1020-
.unwrap()
1021-
.unwrap();
1022-
1023-
assert_eq!(job.request_tag(), benchmark_request.tag().unwrap());
1024-
1025-
/* Mark the job as complete */
1026-
db.mark_benchmark_job_as_completed(job.id(), &BenchmarkJobConclusion::Success)
1027-
.await
1028-
.unwrap();
1041+
db.update_benchmark_request_status(
1042+
benchmark_request_two.tag().unwrap(),
1043+
BenchmarkRequestStatus::InProgress,
1044+
)
1045+
.await
1046+
.unwrap();
10291047

1030-
// record a couple of errors against the tag
1031-
let artifact_id = db.artifact_id(&ArtifactId::Tag(tag.to_string())).await;
1048+
let status_page_data = db.get_status_page_data().await.unwrap();
10321049

1033-
db.record_error(artifact_id, "example-1", "This is an error")
1034-
.await;
1035-
db.record_error(artifact_id, "example-2", "This is another error")
1036-
.await;
1050+
assert!(status_page_data.completed_requests.len() == 1);
1051+
assert_eq!(status_page_data.completed_requests[0].0.tag().unwrap(), tag);
1052+
assert!(matches!(
1053+
status_page_data.completed_requests[0].0.status(),
1054+
BenchmarkRequestStatus::Completed { .. }
1055+
));
1056+
// can't really test duration
1057+
// ensure errors are correct
1058+
assert_eq!(
1059+
status_page_data.completed_requests[0].2[0],
1060+
"This is an error".to_string()
1061+
);
1062+
assert_eq!(
1063+
status_page_data.completed_requests[0].2[1],
1064+
"This is another error".to_string()
1065+
);
10371066

1038-
db.mark_benchmark_request_as_completed(tag).await.unwrap();
1067+
assert!(status_page_data.in_progress.len() == 1);
1068+
// we should have 2 jobs
1069+
assert!(status_page_data.in_progress[0].1.len() == 2);
1070+
// the request should be in progress
1071+
assert!(matches!(
1072+
status_page_data.in_progress[0].0.status(),
1073+
BenchmarkRequestStatus::InProgress
1074+
));
10391075

1040-
let status_page_data = db.get_status_page_data().await.unwrap();
1076+
// Test the first job
1077+
assert!(matches!(
1078+
status_page_data.in_progress[0].1[0].target(),
1079+
Target::X86_64UnknownLinuxGnu
1080+
));
1081+
assert!(matches!(
1082+
status_page_data.in_progress[0].1[0].status(),
1083+
BenchmarkJobStatus::Queued
1084+
));
1085+
assert!(matches!(
1086+
status_page_data.in_progress[0].1[0].backend(),
1087+
CodegenBackend::Llvm
1088+
));
1089+
assert!(matches!(
1090+
status_page_data.in_progress[0].1[0].profile(),
1091+
Profile::Opt
1092+
));
1093+
assert_eq!(
1094+
status_page_data.in_progress[0].1[0].benchmark_set(),
1095+
&benchmark_set
1096+
);
10411097

1042-
dbg!("{:?}", status_page_data);
1098+
// test the second job
1099+
assert!(matches!(
1100+
status_page_data.in_progress[0].1[1].target(),
1101+
Target::X86_64UnknownLinuxGnu
1102+
));
1103+
assert!(matches!(
1104+
status_page_data.in_progress[0].1[1].status(),
1105+
BenchmarkJobStatus::Queued
1106+
));
1107+
assert!(matches!(
1108+
status_page_data.in_progress[0].1[1].backend(),
1109+
CodegenBackend::Llvm
1110+
));
1111+
assert!(matches!(
1112+
status_page_data.in_progress[0].1[1].profile(),
1113+
Profile::Debug
1114+
));
1115+
assert_eq!(
1116+
status_page_data.in_progress[0].1[1].benchmark_set(),
1117+
&benchmark_set
1118+
);
10431119

10441120
Ok(ctx)
10451121
})

database/src/pool/postgres.rs

Lines changed: 153 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,15 +1957,57 @@ where
19571957

19581958
async fn get_status_page_data(&self) -> anyhow::Result<PartialStatusPageData> {
19591959
let max_completed_requests = 7;
1960-
let in_progress_requests_query = format!(
1960+
1961+
// Returns in progress requests along with their associated jobs
1962+
let in_progress_query = format!(
19611963
"
1962-
SELECT {BENCHMARK_REQUEST_COLUMNS}
1963-
FROM benchmark_request
1964-
WHERE status = '{BENCHMARK_REQUEST_STATUS_IN_PROGRESS_STR}'
1964+
WITH in_progress_requests AS (
1965+
SELECT
1966+
{BENCHMARK_REQUEST_COLUMNS}
1967+
FROM
1968+
benchmark_request
1969+
WHERE
1970+
status = '{BENCHMARK_REQUEST_STATUS_IN_PROGRESS_STR}'
1971+
ORDER BY
1972+
completed_at
1973+
), in_progress_jobs AS (
1974+
SELECT
1975+
request_tag AS tag,
1976+
ARRAY_AGG(
1977+
ROW(
1978+
job_queue.id,
1979+
job_queue.request_tag,
1980+
job_queue.target,
1981+
job_queue.backend,
1982+
job_queue.profile,
1983+
job_queue.benchmark_set,
1984+
job_queue.status,
1985+
job_queue.created_at,
1986+
job_queue.started_at,
1987+
job_queue.completed_at,
1988+
job_queue.retry,
1989+
job_queue.collector_name
1990+
)::TEXT
1991+
) AS jobs
1992+
FROM
1993+
job_queue
1994+
LEFT JOIN in_progress_requests ON job_queue.request_tag = in_progress_requests.tag
1995+
GROUP BY
1996+
job_queue.request_tag
1997+
)
1998+
SELECT
1999+
in_progress_requests.*,
2000+
in_progress_jobs.jobs
2001+
FROM
2002+
in_progress_requests
2003+
LEFT JOIN
2004+
in_progress_jobs ON in_progress_requests.tag = in_progress_jobs.tag;
19652005
"
19662006
);
2007+
19672008
// Gets requests along with how long the request took (latest job finish
1968-
// - earliest job start) and associated errors with the request
2009+
// - earliest job start) and associated errors with the request if they
2010+
// exist
19692011
let completed_requests_query = format!(
19702012
"
19712013
WITH completed AS (
@@ -2023,12 +2065,20 @@ where
20232065
"
20242066
);
20252067

2026-
let in_progress_requests: Vec<BenchmarkRequest> = self
2068+
let in_progress: Vec<(BenchmarkRequest, Vec<BenchmarkJob>)> = self
20272069
.conn()
2028-
.query(&in_progress_requests_query, &[])
2070+
.query(&in_progress_query, &[])
20292071
.await?
20302072
.iter()
2031-
.map(row_to_benchmark_request)
2073+
.map(|it| {
2074+
let benchmark_request = row_to_benchmark_request(it);
2075+
let jobs: Vec<BenchmarkJob> = it
2076+
.get::<_, Vec<String>>("jobs")
2077+
.iter()
2078+
.map(|it| benchmark_job_str_to_type(it).unwrap())
2079+
.collect();
2080+
(benchmark_request, jobs)
2081+
})
20322082
.collect();
20332083

20342084
let completed_requests: Vec<(BenchmarkRequest, String, Vec<String>)> = self
@@ -2039,7 +2089,10 @@ where
20392089
.map(|it| {
20402090
(
20412091
row_to_benchmark_request(it),
2092+
// Duration being a string feels odd, but we don't need to
2093+
// perform any computations on it
20422094
it.get::<_, String>(9),
2095+
// The errors, if there are none this will be an empty vector
20432096
it.get::<_, Vec<String>>(10),
20442097
)
20452098
})
@@ -2115,10 +2168,10 @@ where
21152168
in_progress_jobs.push(job);
21162169
}
21172170

2171+
21182172
Ok(PartialStatusPageData {
21192173
completed_requests,
2120-
in_progress_jobs,
2121-
in_progress_requests,
2174+
in_progress,
21222175
})
21232176
}
21242177
}
@@ -2179,6 +2232,96 @@ fn row_to_benchmark_request(row: &Row) -> BenchmarkRequest {
21792232
}
21802233
}
21812234

2235+
fn parse_timestamp(cell: &str) -> anyhow::Result<Option<DateTime<Utc>>> {
2236+
if cell.is_empty() {
2237+
Ok(None)
2238+
} else {
2239+
// Massage postgres date string into something we can parse in Rust
2240+
// to a date
2241+
let raw_date = cell.trim_matches('"').replace(' ', "T") + ":00";
2242+
Ok(Some(
2243+
DateTime::parse_from_rfc3339(&raw_date)?.with_timezone(&Utc),
2244+
))
2245+
}
2246+
}
2247+
2248+
fn benchmark_job_str_to_type(src: &str) -> anyhow::Result<BenchmarkJob> {
2249+
let line = src.trim_start_matches('(').trim_end_matches(')');
2250+
2251+
let mut col = line.split(',');
2252+
2253+
let id: u32 = col.next().ok_or_else(|| anyhow::anyhow!("id"))?.parse()?;
2254+
let request_tag = col
2255+
.next()
2256+
.ok_or_else(|| anyhow::anyhow!("request_tag"))?
2257+
.to_owned();
2258+
let target = col
2259+
.next()
2260+
.ok_or_else(|| anyhow::anyhow!("target"))?
2261+
.parse::<Target>()
2262+
.map_err(|e| anyhow::anyhow!(e))?;
2263+
let backend = col
2264+
.next()
2265+
.ok_or_else(|| anyhow::anyhow!("backend"))?
2266+
.parse::<CodegenBackend>()
2267+
.map_err(|e| anyhow::anyhow!(e))?;
2268+
let profile = col
2269+
.next()
2270+
.ok_or_else(|| anyhow::anyhow!("profile"))?
2271+
.parse::<Profile>()
2272+
.map_err(|e| anyhow::anyhow!(e))?;
2273+
let benchmark_set = BenchmarkSet(
2274+
col.next()
2275+
.ok_or_else(|| anyhow::anyhow!("benchmark_set"))?
2276+
.parse()?,
2277+
);
2278+
2279+
let status_str = col.next().ok_or_else(|| anyhow::anyhow!("status"))?;
2280+
let created_at = parse_timestamp(col.next().ok_or_else(|| anyhow::anyhow!("created_at"))?)?
2281+
.ok_or_else(|| anyhow::anyhow!("created_at missing"))?;
2282+
2283+
let started_at = parse_timestamp(col.next().unwrap_or(""))?;
2284+
let completed_at = parse_timestamp(col.next().unwrap_or(""))?;
2285+
let retry: u32 = col
2286+
.next()
2287+
.ok_or_else(|| anyhow::anyhow!("retry"))?
2288+
.parse()?;
2289+
let collector_name_raw = col.next().unwrap_or("").to_owned();
2290+
2291+
let status = match status_str {
2292+
BENCHMARK_JOB_STATUS_QUEUED_STR => BenchmarkJobStatus::Queued,
2293+
2294+
BENCHMARK_JOB_STATUS_IN_PROGRESS_STR => BenchmarkJobStatus::InProgress {
2295+
started_at: started_at.ok_or_else(|| anyhow::anyhow!("started_at missing"))?,
2296+
collector_name: collector_name_raw,
2297+
},
2298+
2299+
BENCHMARK_JOB_STATUS_SUCCESS_STR | BENCHMARK_JOB_STATUS_FAILURE_STR => {
2300+
BenchmarkJobStatus::Completed {
2301+
started_at: started_at.ok_or_else(|| anyhow::anyhow!("started_at missing"))?,
2302+
completed_at: completed_at
2303+
.ok_or_else(|| anyhow::anyhow!("completed_at missing"))?,
2304+
collector_name: collector_name_raw,
2305+
success: status_str == BENCHMARK_JOB_STATUS_SUCCESS_STR,
2306+
}
2307+
}
2308+
2309+
_ => anyhow::bail!("unknown status `{status_str}`"),
2310+
};
2311+
2312+
Ok(BenchmarkJob {
2313+
id,
2314+
target,
2315+
backend,
2316+
profile,
2317+
request_tag,
2318+
benchmark_set,
2319+
created_at,
2320+
status,
2321+
deque_counter: retry,
2322+
})
2323+
}
2324+
21822325
fn parse_artifact_id(ty: &str, sha: &str, date: Option<DateTime<Utc>>) -> ArtifactId {
21832326
match ty {
21842327
"master" => ArtifactId::Commit(Commit {

0 commit comments

Comments
 (0)