oven_cli/pipeline/
state.rs1use crate::db::RunStatus;
2
3impl RunStatus {
4 #[must_use]
15 pub const fn next(self, has_findings: bool, cycle: u32) -> Self {
16 match self {
17 Self::Pending => Self::Implementing,
18 Self::Implementing | Self::Fixing => Self::Reviewing,
19 Self::Reviewing if has_findings && cycle < 2 => Self::Fixing,
20 Self::Reviewing => Self::AwaitingMerge,
21 Self::AwaitingMerge => Self::Merging,
22 Self::Merging => Self::Complete,
23 Self::Complete | Self::Failed => Self::Failed,
24 }
25 }
26
27 pub const fn is_terminal(self) -> bool {
28 matches!(self, Self::Complete | Self::Failed)
29 }
30}
31
32#[cfg(test)]
33mod tests {
34 use proptest::prelude::*;
35
36 use super::*;
37
38 const ALL_STATUSES: [RunStatus; 8] = [
39 RunStatus::Pending,
40 RunStatus::Implementing,
41 RunStatus::Reviewing,
42 RunStatus::Fixing,
43 RunStatus::AwaitingMerge,
44 RunStatus::Merging,
45 RunStatus::Complete,
46 RunStatus::Failed,
47 ];
48
49 proptest! {
50 #[test]
51 fn next_never_panics(idx in 0..8usize, has_findings: bool, cycle in 0..50u32) {
52 let status = ALL_STATUSES[idx];
53 let _ = status.next(has_findings, cycle);
55 }
56
57 #[test]
58 fn terminal_states_stay_terminal(has_findings: bool, cycle in 0..50u32) {
59 assert!(RunStatus::Complete.next(has_findings, cycle).is_terminal());
60 assert!(RunStatus::Failed.next(has_findings, cycle).is_terminal());
61 }
62
63 #[test]
64 fn reviewing_with_findings_past_max_awaits_merge(cycle in 2..50u32) {
65 assert_eq!(RunStatus::Reviewing.next(true, cycle), RunStatus::AwaitingMerge);
66 }
67
68 #[test]
69 fn reviewing_clean_always_awaits_merge(cycle in 0..50u32) {
70 assert_eq!(RunStatus::Reviewing.next(false, cycle), RunStatus::AwaitingMerge);
71 }
72 }
73
74 #[test]
75 fn pending_to_implementing() {
76 assert_eq!(RunStatus::Pending.next(false, 0), RunStatus::Implementing);
77 }
78
79 #[test]
80 fn implementing_to_reviewing() {
81 assert_eq!(RunStatus::Implementing.next(false, 0), RunStatus::Reviewing);
82 }
83
84 #[test]
85 fn clean_review_to_awaiting_merge() {
86 assert_eq!(RunStatus::Reviewing.next(false, 1), RunStatus::AwaitingMerge);
87 }
88
89 #[test]
90 fn awaiting_merge_to_merging() {
91 assert_eq!(RunStatus::AwaitingMerge.next(false, 0), RunStatus::Merging);
92 }
93
94 #[test]
95 fn findings_under_max_cycles_to_fixing() {
96 assert_eq!(RunStatus::Reviewing.next(true, 1), RunStatus::Fixing);
97 }
98
99 #[test]
100 fn findings_at_max_cycles_to_awaiting_merge() {
101 assert_eq!(RunStatus::Reviewing.next(true, 2), RunStatus::AwaitingMerge);
102 }
103
104 #[test]
105 fn fixing_back_to_reviewing() {
106 assert_eq!(RunStatus::Fixing.next(false, 1), RunStatus::Reviewing);
107 }
108
109 #[test]
110 fn merging_to_complete() {
111 assert_eq!(RunStatus::Merging.next(false, 0), RunStatus::Complete);
112 }
113
114 #[test]
115 fn terminal_states_go_to_failed() {
116 assert_eq!(RunStatus::Complete.next(false, 0), RunStatus::Failed);
117 assert_eq!(RunStatus::Failed.next(false, 0), RunStatus::Failed);
118 }
119
120 #[test]
121 fn is_terminal() {
122 assert!(RunStatus::Complete.is_terminal());
123 assert!(RunStatus::Failed.is_terminal());
124 assert!(!RunStatus::Pending.is_terminal());
125 assert!(!RunStatus::Implementing.is_terminal());
126 assert!(!RunStatus::Reviewing.is_terminal());
127 assert!(!RunStatus::Fixing.is_terminal());
128 assert!(!RunStatus::AwaitingMerge.is_terminal());
129 assert!(!RunStatus::Merging.is_terminal());
130 }
131}