Skip to content

Commit 6f6404d

Browse files
committed
Refactor AuthMonitor::update() to simplify implementation
1 parent 58adc66 commit 6f6404d

File tree

3 files changed

+48
-47
lines changed

3 files changed

+48
-47
lines changed

src/auth_monitor.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ pub struct AuthMonitor {
1414
last_failed_auth_timestamp: i64,
1515
}
1616

17+
#[derive(PartialEq, Debug)]
18+
pub enum AuthState {
19+
AuthFailureLimitNotReached,
20+
AuthFailureLimitReached,
21+
}
22+
1723
impl AuthMonitor {
1824
pub fn new(params: AuthMonitorParams) -> Result<AuthMonitor, Box<dyn Error>> {
1925
params.validate()?;
@@ -26,7 +32,7 @@ impl AuthMonitor {
2632
});
2733
}
2834

29-
pub fn update(&mut self, on_max_failed_attempts: impl FnOnce()) {
35+
pub fn update(&mut self) -> AuthState {
3036
if self.should_reset_failed_attempts() {
3137
self.reset_failed_attempts();
3238
}
@@ -59,8 +65,10 @@ impl AuthMonitor {
5965
});
6066

6167
if failed_attempts > 0 {
62-
self.increase_failed_attempts(failed_attempts, on_max_failed_attempts);
68+
return self.increase_failed_attempts(failed_attempts);
6369
}
70+
71+
return AuthState::AuthFailureLimitNotReached;
6472
}
6573

6674
fn should_reset_failed_attempts(&self) -> bool {
@@ -82,17 +90,14 @@ impl AuthMonitor {
8290
self.last_failed_auth_timestamp = 0;
8391
}
8492

85-
fn increase_failed_attempts(
86-
&mut self,
87-
failed_attempts: i32,
88-
on_max_failed_attempts: impl FnOnce(),
89-
) {
93+
fn increase_failed_attempts(&mut self, failed_attempts: i32) -> AuthState {
9094
self.failed_attempts += failed_attempts;
9195
println!("Authentication failed {} time(s)", self.failed_attempts);
9296
if self.failed_attempts >= self.options.max_failed_attempts {
9397
println!("Authentication fail limit reached, shutting down");
94-
on_max_failed_attempts();
98+
return AuthState::AuthFailureLimitReached;
9599
}
100+
return AuthState::AuthFailureLimitNotReached;
96101
}
97102
}
98103

src/auth_monitor_tests.rs

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::ops::Range;
22
use std::thread::sleep;
33
use std::time::Duration;
44

5-
use crate::auth_monitor::AuthMonitor;
5+
use crate::auth_monitor::{AuthMonitor, AuthState};
66
use crate::auth_monitor_options::AuthMonitorOptions;
77
use crate::auth_monitor_params::AuthMonitorParams;
88
use crate::test_utils::test_file::TestFile;
@@ -22,18 +22,12 @@ impl AuthMonitorTest {
2222
return AuthMonitorTest { auth_monitor };
2323
}
2424

25-
pub fn expect_no_update_callback_call(&mut self) {
26-
self.auth_monitor.update(|| {
27-
panic!("Callback call was not expected");
28-
});
25+
pub fn expect_auth_failure_limit_not_reached(&mut self) {
26+
assert_eq!(self.auth_monitor.update(), AuthState::AuthFailureLimitNotReached);
2927
}
3028

31-
pub fn expect_update_callback_is_called_once(&mut self) {
32-
let mut call_count = 0;
33-
self.auth_monitor.update(|| {
34-
call_count += 1;
35-
});
36-
assert_eq!(call_count, 1, "One callback call was expected")
29+
pub fn expect_auth_failure_limit_reached(&mut self) {
30+
assert_eq!(self.auth_monitor.update(), AuthState::AuthFailureLimitReached);
3731
}
3832
}
3933

@@ -46,17 +40,17 @@ fn when_file_does_not_exist_then_changes_are_monitored_after_it_is_created() {
4640

4741
let options = AuthMonitorOptions::default();
4842
let mut test = AuthMonitorTest::new(file.path(), options);
49-
test.expect_no_update_callback_call();
43+
test.expect_auth_failure_limit_not_reached();
5044

5145
file.create();
5246

5347
for i in 0usize..(options.max_failed_attempts - 1) as usize {
5448
file.write_auth_failed_message(i);
55-
test.expect_no_update_callback_call();
49+
test.expect_auth_failure_limit_not_reached();
5650
}
5751

5852
file.write_auth_failed_message(0);
59-
test.expect_update_callback_is_called_once();
53+
test.expect_auth_failure_limit_reached();
6054
}
6155

6256
#[test]
@@ -68,20 +62,20 @@ pub fn when_auth_failure_limit_is_reached_then_update_callback_is_invoked() {
6862
..AuthMonitorOptions::default()
6963
};
7064
let mut test = AuthMonitorTest::new(file.path(), options);
71-
test.expect_no_update_callback_call();
65+
test.expect_auth_failure_limit_not_reached();
7266

7367
for i in 0usize..(max_failed_attempts - 1) as usize {
7468
file.write_auth_failed_message(i);
75-
test.expect_no_update_callback_call();
69+
test.expect_auth_failure_limit_not_reached();
7670
}
7771

7872
for i in 0usize..(max_failed_attempts * 2) as usize {
7973
file.write_other_message(i);
80-
test.expect_no_update_callback_call();
74+
test.expect_auth_failure_limit_not_reached();
8175
}
8276

8377
file.write_auth_failed_message(0);
84-
test.expect_update_callback_is_called_once();
78+
test.expect_auth_failure_limit_reached();
8579
}
8680
}
8781

@@ -94,12 +88,12 @@ pub fn when_auth_failure_limit_is_reached_between_updates_then_next_update_invok
9488
..AuthMonitorOptions::default()
9589
};
9690
let mut test = AuthMonitorTest::new(file.path(), options);
97-
test.expect_no_update_callback_call();
91+
test.expect_auth_failure_limit_not_reached();
9892

9993
file.write_auth_failed_messages(max_failed_attempts as usize);
10094
file.write_other_messages(max_failed_attempts as usize);
10195

102-
test.expect_update_callback_is_called_once();
96+
test.expect_auth_failure_limit_reached();
10397
}
10498
}
10599

@@ -111,13 +105,13 @@ pub fn when_reset_time_has_passed_then_reset_failed_attempt_counter() {
111105
..AuthMonitorOptions::default()
112106
};
113107
let mut test = AuthMonitorTest::new(file.path(), options);
114-
test.expect_no_update_callback_call();
108+
test.expect_auth_failure_limit_not_reached();
115109

116110
let failed_attempts_safe_limit = (options.max_failed_attempts - 1) as usize;
117111

118112
for i in 0usize..failed_attempts_safe_limit {
119113
file.write_auth_failed_message(i);
120-
test.expect_no_update_callback_call();
114+
test.expect_auth_failure_limit_not_reached();
121115
}
122116

123117
let sleep_duration = Duration::from_secs((options.reset_after_seconds + 1) as u64);
@@ -126,11 +120,11 @@ pub fn when_reset_time_has_passed_then_reset_failed_attempt_counter() {
126120

127121
for i in 0usize..failed_attempts_safe_limit {
128122
file.write_auth_failed_message(i);
129-
test.expect_no_update_callback_call();
123+
test.expect_auth_failure_limit_not_reached();
130124
}
131125

132126
file.write_auth_failed_message(0);
133-
test.expect_update_callback_is_called_once();
127+
test.expect_auth_failure_limit_reached();
134128
}
135129

136130
#[test]
@@ -141,16 +135,16 @@ pub fn when_ignore_subsequent_fails_duration_has_not_elapsed_then_update_callbac
141135
..AuthMonitorOptions::default()
142136
};
143137
let mut test = AuthMonitorTest::new(file.path(), options);
144-
test.expect_no_update_callback_call();
138+
test.expect_auth_failure_limit_not_reached();
145139

146140
let max_failed_attempts = options.max_failed_attempts as usize;
147141

148142
for i in 0usize..max_failed_attempts {
149143
file.write_auth_failed_message(i);
150-
test.expect_no_update_callback_call();
144+
test.expect_auth_failure_limit_not_reached();
151145
}
152146

153-
test.expect_no_update_callback_call();
147+
test.expect_auth_failure_limit_not_reached();
154148
}
155149

156150
#[test]
@@ -161,7 +155,7 @@ pub fn when_ignore_subsequent_fails_duration_has_elapsed_then_update_callback_is
161155
..AuthMonitorOptions::default()
162156
};
163157
let mut test = AuthMonitorTest::new(file.path(), options);
164-
test.expect_no_update_callback_call();
158+
test.expect_auth_failure_limit_not_reached();
165159

166160
let max_failed_attempts = options.max_failed_attempts as usize;
167161
let sleep_duration = Duration::from_millis((options.ignore_subsequent_fails_ms + 1) as u64);
@@ -172,7 +166,7 @@ pub fn when_ignore_subsequent_fails_duration_has_elapsed_then_update_callback_is
172166
sleep(sleep_duration);
173167
}
174168

175-
test.expect_update_callback_is_called_once();
169+
test.expect_auth_failure_limit_reached();
176170
}
177171

178172
#[test]
@@ -181,13 +175,13 @@ fn when_file_is_deleted_and_new_one_is_created_then_changes_are_still_monitored(
181175
let options = AuthMonitorOptions::default();
182176
let mut test = AuthMonitorTest::new(file.path(), options);
183177
file.remove();
184-
test.expect_no_update_callback_call();
178+
test.expect_auth_failure_limit_not_reached();
185179

186180
file.create();
187-
test.expect_no_update_callback_call();
181+
test.expect_auth_failure_limit_not_reached();
188182

189183
file.write_auth_failed_messages(options.max_failed_attempts as usize);
190-
test.expect_update_callback_is_called_once();
184+
test.expect_auth_failure_limit_reached();
191185
}
192186

193187
#[test]
@@ -199,12 +193,12 @@ fn when_file_is_renamed_and_new_one_is_created_then_changes_are_still_monitored(
199193
let filepath = String::from(file.path());
200194
let new_filepath = format!("{}.bak", file.path());
201195
file.rename(&new_filepath);
202-
test.expect_no_update_callback_call();
196+
test.expect_auth_failure_limit_not_reached();
203197

204198
let mut new_file = TestFile::new(&filepath);
205-
test.expect_no_update_callback_call();
199+
test.expect_auth_failure_limit_not_reached();
206200
new_file.write_auth_failed_messages(options.max_failed_attempts as usize);
207-
test.expect_update_callback_is_called_once();
201+
test.expect_auth_failure_limit_reached();
208202
}
209203

210204
#[test]
@@ -216,8 +210,8 @@ fn when_file_is_truncated_then_changes_are_still_monitored() {
216210
let mut test = AuthMonitorTest::new(file.path(), options);
217211

218212
file.truncate();
219-
test.expect_no_update_callback_call();
213+
test.expect_auth_failure_limit_not_reached();
220214

221215
file.write_auth_failed_messages(options.max_failed_attempts as usize);
222-
test.expect_update_callback_is_called_once();
216+
test.expect_auth_failure_limit_reached();
223217
}

src/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::{env, thread};
88
use signal_hook::consts::{SIGABRT, SIGINT};
99
use signal_hook::iterator::Signals;
1010

11-
use crate::auth_monitor::AuthMonitor;
11+
use crate::auth_monitor::{AuthMonitor, AuthState};
1212
use crate::auth_monitor_params::AuthMonitorParams;
1313

1414
mod auth_file_reader;
@@ -56,7 +56,9 @@ fn start_monitoring(params: AuthMonitorParams) -> ExitCode {
5656
}
5757
};
5858
loop {
59-
auth_monitor.update(shutdown);
59+
if let AuthState::AuthFailureLimitReached = auth_monitor.update() {
60+
shutdown();
61+
}
6062
match signals.pending().next() {
6163
Some(signal) => {
6264
println!("Received signal {}", signal);

0 commit comments

Comments
 (0)