1use crate::model::{self, Resources};
5
6pub const DEFAULT_CPUS: u32 = 1;
9pub const DEFAULT_MEMORY_MB: u32 = 1024;
11pub const DEFAULT_DISK_GB: u32 = 20;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
16pub struct Totals {
17 pub machines: u32,
19 pub cpus: u32,
21 pub memory_mb: u32,
23 pub disk_gb: u32,
25}
26
27#[must_use]
30pub fn totals(spec: &model::Spec) -> Totals {
31 spec.machines.values().fold(Totals::default(), |t, m| {
32 let r = m.resources.unwrap_or(Resources {
33 cpus: None,
34 memory_mb: None,
35 disk_gb: None,
36 });
37 Totals {
40 machines: t.machines + 1,
41 cpus: t.cpus.saturating_add(r.cpus.unwrap_or(DEFAULT_CPUS)),
42 memory_mb: t.memory_mb.saturating_add(r.memory_mb.unwrap_or(DEFAULT_MEMORY_MB)),
43 disk_gb: t.disk_gb.saturating_add(r.disk_gb.unwrap_or(DEFAULT_DISK_GB)),
44 }
45 })
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn totals_add_each_machines_size_or_the_defaults() {
54 let spec = crate::testing::model(&crate::testing::lab(
55 "machines:\n a: { networks: { lan: 10 }, docker: { image: x }, resources: { cpus: 4, memory_mb: 512, disk_gb: 5 } }\n b: { networks: { lan: 11 }, docker: { image: x }, resources: { cpus: 2 } }\n c: { networks: { lan: 12 }, docker: { image: x } }\n",
56 ))
57 .unwrap();
58 assert_eq!(
59 totals(&spec),
60 Totals {
61 machines: 3,
62 cpus: 4 + 2 + DEFAULT_CPUS,
63 memory_mb: 512 + 2 * DEFAULT_MEMORY_MB,
64 disk_gb: 5 + 2 * DEFAULT_DISK_GB,
65 }
66 );
67 }
68
69 #[test]
70 fn totals_saturate_instead_of_overflowing() {
71 let huge = u32::MAX;
72 let spec = crate::testing::model(&crate::testing::lab(&format!(
73 "machines:\n a: {{ networks: {{ lan: 10 }}, docker: {{ image: x }}, resources: {{ cpus: {huge} }} }}\n b: {{ networks: {{ lan: 11 }}, docker: {{ image: x }}, resources: {{ cpus: 3 }} }}\n"
74 )))
75 .unwrap();
76 assert_eq!(totals(&spec).cpus, u32::MAX);
77 }
78}