obnam_benchmark/
specification.rs1use crate::step::Step;
11use serde::{Deserialize, Serialize};
12use std::collections::HashSet;
13use std::fs::File;
14use std::path::{Path, PathBuf};
15
16#[derive(Debug, Serialize, Deserialize)]
18#[serde(deny_unknown_fields)]
19pub struct Specification {
20 benchmarks: Vec<Benchmark>,
21}
22
23#[derive(Debug, thiserror::Error)]
25pub enum SpecificationError {
26 #[error("Duplicate benchmark name {0}")]
28 DuplicateBenchmark(
29 String,
31 ),
32
33 #[error("Couldn't open {0}: {1}")]
35 Open(
36 PathBuf,
38 std::io::Error,
40 ),
41
42 #[error("Couldn't read YAML specification from {0}:\n {1}")]
44 Yaml(
45 PathBuf,
47 serde_yaml::Error,
49 ),
50}
51
52#[derive(Debug, Serialize, Deserialize)]
53struct Benchmark {
54 benchmark: String,
55 backups: Vec<Backup>,
56}
57
58#[derive(Debug, Serialize, Deserialize)]
59struct Backup {
60 pub changes: Vec<Change>,
61}
62
63#[derive(Debug, Serialize, Deserialize)]
64pub(crate) enum Change {
65 #[serde(rename = "create")]
66 Create(Create),
67
68 #[serde(rename = "delete")]
69 Delete(FileCount),
70
71 #[serde(rename = "rename")]
72 Rename(FileCount),
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct Create {
78 pub files: u64,
80 pub file_size: u64,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct FileCount {
87 pub files: u64,
89}
90
91impl Specification {
92 pub fn from_file(filename: &Path) -> Result<Self, SpecificationError> {
94 let f = File::open(filename)
95 .map_err(|err| SpecificationError::Open(filename.to_path_buf(), err))?;
96 let spec: Specification = serde_yaml::from_reader(f)
97 .map_err(|err| SpecificationError::Yaml(filename.to_path_buf(), err))?;
98 spec.check()?;
99 Ok(spec)
100 }
101
102 fn check(&self) -> Result<(), SpecificationError> {
103 let mut names = HashSet::new();
104 for name in self.benchmarks.iter().map(|b| b.benchmark.to_string()) {
105 if names.contains(&name) {
106 return Err(SpecificationError::DuplicateBenchmark(name));
107 }
108 names.insert(name);
109 }
110 Ok(())
111 }
112
113 pub fn steps(&self) -> Vec<Step> {
115 let mut steps = vec![];
116 for b in self.benchmarks.iter() {
117 let n = b.backups.len();
118 let after_base = n;
119 let restore_base = 2 * n;
120
121 steps.push(Step::Start(b.benchmark.to_string()));
122 for (i, backup) in b.backups.iter().enumerate() {
123 for change in backup.changes.iter() {
124 steps.push(Step::from(change));
125 }
126 steps.push(Step::ManifestLive(i));
127 steps.push(Step::Backup(i));
128 let after = after_base + i;
129 steps.push(Step::ManifestLive(after));
130 steps.push(Step::CompareManifests(i, after));
131 }
132 for (i, _) in b.backups.iter().enumerate() {
133 steps.push(Step::Restore(i));
134 let restored = restore_base + i;
135 steps.push(Step::ManifestRestored(restored));
136 steps.push(Step::CompareManifests(i, restored));
137 }
138 steps.push(Step::Stop(b.benchmark.to_string()));
139 }
140 steps
141 }
142}