• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use std::sync::LockResult;
16 use std::sync::MutexGuard;
17 
18 use mockall::predicate::*;
19 use mockall::Sequence;
20 
21 use super::*;
22 use crate::os::MockMeminfoApi;
23 use crate::os::MEMINFO_API_MTX;
24 use crate::time::TimeApi;
25 use crate::time::TimeApiImpl;
26 use crate::zram::MockSysfsZramApi;
27 use crate::zram::ZRAM_API_MTX;
28 
29 struct MockContext<'a> {
30     read_recomp_algorithm:
31         crate::zram::__mock_MockSysfsZramApi_SysfsZramApi::__read_recomp_algorithm::Context,
32     recompress: crate::zram::__mock_MockSysfsZramApi_SysfsZramApi::__recompress::Context,
33     set_idle: crate::zram::__mock_MockSysfsZramApi_SysfsZramApi::__set_idle::Context,
34     read_meminfo: crate::os::__mock_MockMeminfoApi_MeminfoApi::__read_meminfo::Context,
35     // Lock will be released after mock contexts are dropped.
36     _meminfo_lock: LockResult<MutexGuard<'a, ()>>,
37     _zram_lock: LockResult<MutexGuard<'a, ()>>,
38 }
39 
40 impl MockContext<'_> {
new() -> Self41     fn new() -> Self {
42         let _zram_lock = ZRAM_API_MTX.lock();
43         let _meminfo_lock = MEMINFO_API_MTX.lock();
44         Self {
45             read_recomp_algorithm: MockSysfsZramApi::read_recomp_algorithm_context(),
46             recompress: MockSysfsZramApi::recompress_context(),
47             set_idle: MockSysfsZramApi::set_idle_context(),
48             read_meminfo: MockMeminfoApi::read_meminfo_context(),
49             _meminfo_lock,
50             _zram_lock,
51         }
52     }
53 
setup_default_meminfo(&self)54     fn setup_default_meminfo(&self) {
55         let meminfo = "MemTotal: 8144296 kB
56             MemAvailable: 346452 kB";
57         self.read_meminfo.expect().returning(|| Ok(meminfo.to_string()));
58     }
59 }
60 
61 #[test]
get_zram_recompression_status_not_configured()62 fn get_zram_recompression_status_not_configured() {
63     let mock = MockContext::new();
64     mock.read_recomp_algorithm.expect().returning(|| Ok("".to_string()));
65     assert_eq!(
66         get_zram_recompression_status::<MockSysfsZramApi>().unwrap(),
67         ZramRecompressionStatus::NotConfigured
68     );
69 }
70 
71 #[test]
get_zram_recompression_status_activated()72 fn get_zram_recompression_status_activated() {
73     let mock = MockContext::new();
74     mock.read_recomp_algorithm.expect().returning(|| Ok("zstd".to_string()));
75     assert_eq!(
76         get_zram_recompression_status::<MockSysfsZramApi>().unwrap(),
77         ZramRecompressionStatus::Activated
78     );
79 }
80 
81 #[test]
get_zram_recompression_status_unsupported()82 fn get_zram_recompression_status_unsupported() {
83     let mock = MockContext::new();
84     mock.read_recomp_algorithm
85         .expect()
86         .returning(|| Err(std::io::Error::from_raw_os_error(libc::ENOENT)));
87     assert_eq!(
88         get_zram_recompression_status::<MockSysfsZramApi>().unwrap(),
89         ZramRecompressionStatus::Unsupported
90     );
91 }
92 
93 #[test]
test_get_zram_recompression_status_failure()94 fn test_get_zram_recompression_status_failure() {
95     let mock = MockContext::new();
96     mock.read_recomp_algorithm.expect().returning(|| Err(std::io::Error::other("error")));
97 
98     assert!(get_zram_recompression_status::<MockSysfsZramApi>().is_err());
99 }
100 
101 #[test]
mark_and_recompress()102 fn mark_and_recompress() {
103     let mock = MockContext::new();
104     let mut seq = Sequence::new();
105     mock.setup_default_meminfo();
106     let params = Params { threshold_bytes: 0, ..Default::default() };
107     let suspend_history = SuspendHistory::new();
108     let mut zram_recompression = ZramRecompression::new();
109 
110     mock.set_idle.expect().times(1).in_sequence(&mut seq).returning(|_| Ok(()));
111     mock.recompress
112         .expect()
113         .with(eq("type=huge_idle"))
114         .times(1)
115         .in_sequence(&mut seq)
116         .returning(|_| Ok(()));
117     mock.set_idle.expect().times(1).in_sequence(&mut seq).returning(|_| Ok(()));
118     mock.recompress
119         .expect()
120         .with(eq("type=idle"))
121         .times(1)
122         .in_sequence(&mut seq)
123         .returning(|_| Ok(()));
124     mock.recompress
125         .expect()
126         .with(eq("type=huge"))
127         .times(1)
128         .in_sequence(&mut seq)
129         .returning(|_| Ok(()));
130 
131     assert!(zram_recompression
132         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
133             &params,
134             &suspend_history,
135             TimeApiImpl::get_boot_time()
136         )
137         .is_ok());
138 }
139 
140 #[test]
mark_and_recompress_with_threshold()141 fn mark_and_recompress_with_threshold() {
142     let mock = MockContext::new();
143     mock.set_idle.expect().returning(|_| Ok(()));
144     mock.setup_default_meminfo();
145     let params = Params { threshold_bytes: 12345, ..Default::default() };
146     let suspend_history = SuspendHistory::new();
147     let mut zram_recompression = ZramRecompression::new();
148 
149     mock.recompress
150         .expect()
151         .with(eq("type=huge_idle threshold=12345"))
152         .times(1)
153         .returning(|_| Ok(()));
154     mock.recompress.expect().with(eq("type=idle threshold=12345")).times(1).returning(|_| Ok(()));
155     mock.recompress.expect().with(eq("type=huge threshold=12345")).times(1).returning(|_| Ok(()));
156 
157     assert!(zram_recompression
158         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
159             &params,
160             &suspend_history,
161             TimeApiImpl::get_boot_time(),
162         )
163         .is_ok());
164 }
165 
166 #[test]
mark_and_recompress_before_backoff()167 fn mark_and_recompress_before_backoff() {
168     let mock = MockContext::new();
169     mock.recompress.expect().returning(|_| Ok(()));
170     mock.set_idle.expect().returning(|_| Ok(()));
171     mock.setup_default_meminfo();
172     let params = Params {
173         backoff_duration: Duration::from_secs(100),
174         threshold_bytes: 0,
175         ..Default::default()
176     };
177     let suspend_history = SuspendHistory::new();
178     let base_time = TimeApiImpl::get_boot_time();
179     let mut zram_recompression = ZramRecompression::new();
180     assert!(zram_recompression
181         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
182             &params,
183             &suspend_history,
184             base_time,
185         )
186         .is_ok());
187     mock.recompress.checkpoint();
188 
189     mock.recompress.expect().times(0);
190 
191     assert!(matches!(
192         zram_recompression.mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
193             &params,
194             &suspend_history,
195             base_time.checked_add(Duration::from_secs(99)).unwrap(),
196         ),
197         Err(Error::BackoffTime)
198     ));
199 }
200 
201 #[test]
mark_and_recompress_after_backoff()202 fn mark_and_recompress_after_backoff() {
203     let mock = MockContext::new();
204     mock.recompress.expect().returning(|_| Ok(()));
205     mock.set_idle.expect().returning(|_| Ok(()));
206     mock.setup_default_meminfo();
207     let params = Params {
208         backoff_duration: Duration::from_secs(100),
209         threshold_bytes: 0,
210         ..Default::default()
211     };
212     let suspend_history = SuspendHistory::new();
213     let base_time = TimeApiImpl::get_boot_time();
214     let mut zram_recompression = ZramRecompression::new();
215     assert!(zram_recompression
216         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
217             &params,
218             &suspend_history,
219             base_time,
220         )
221         .is_ok());
222     mock.recompress.checkpoint();
223     mock.set_idle.expect().returning(|_| Ok(()));
224     mock.setup_default_meminfo();
225 
226     mock.recompress.expect().times(3).returning(|_| Ok(()));
227 
228     assert!(zram_recompression
229         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
230             &params,
231             &suspend_history,
232             base_time.checked_add(Duration::from_secs(100)).unwrap()
233         )
234         .is_ok());
235 }
236 
237 #[test]
mark_and_recompress_idle_time()238 fn mark_and_recompress_idle_time() {
239     let mock = MockContext::new();
240     mock.recompress.expect().returning(|_| Ok(()));
241     let meminfo = "MemTotal: 10000 kB
242         MemAvailable: 8000 kB";
243     mock.read_meminfo.expect().returning(|| Ok(meminfo.to_string()));
244     let params = Params {
245         min_idle: Duration::from_secs(3600),
246         max_idle: Duration::from_secs(4000),
247         threshold_bytes: 0,
248         ..Default::default()
249     };
250     let suspend_history = SuspendHistory::new();
251     let mut zram_recompression = ZramRecompression::new();
252 
253     mock.set_idle.expect().with(eq("3747")).times(2).returning(|_| Ok(()));
254 
255     assert!(zram_recompression
256         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
257             &params,
258             &suspend_history,
259             TimeApiImpl::get_boot_time()
260         )
261         .is_ok());
262 }
263 
264 #[test]
mark_and_recompress_idle_time_adjusted_by_suspend_duration()265 fn mark_and_recompress_idle_time_adjusted_by_suspend_duration() {
266     let mock = MockContext::new();
267     mock.recompress.expect().returning(|_| Ok(()));
268     let meminfo = "MemTotal: 10000 kB
269         MemAvailable: 8000 kB";
270     mock.read_meminfo.expect().returning(|| Ok(meminfo.to_string()));
271     let params = Params {
272         min_idle: Duration::from_secs(3600),
273         max_idle: Duration::from_secs(4000),
274         threshold_bytes: 0,
275         ..Default::default()
276     };
277     let mut suspend_history = SuspendHistory::new();
278     let boot_now = BootTime::from_duration(Duration::from_secs(12345));
279     suspend_history.record_suspend_duration(Duration::from_secs(1000), boot_now, params.max_idle);
280     let mut zram_recompression = ZramRecompression::new();
281 
282     mock.set_idle.expect().with(eq("4747")).times(2).returning(|_| Ok(()));
283 
284     assert!(zram_recompression
285         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
286             &params,
287             &suspend_history,
288             boot_now
289         )
290         .is_ok());
291 }
292 
293 #[test]
mark_and_recompress_calculate_idle_failure()294 fn mark_and_recompress_calculate_idle_failure() {
295     let mock = MockContext::new();
296     mock.recompress.expect().returning(|_| Ok(()));
297     let params = Params {
298         min_idle: Duration::from_secs(4000),
299         max_idle: Duration::from_secs(3600),
300         threshold_bytes: 0,
301         ..Default::default()
302     };
303     let suspend_history = SuspendHistory::new();
304     let mut zram_recompression = ZramRecompression::new();
305 
306     assert!(matches!(
307         zram_recompression.mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
308             &params,
309             &suspend_history,
310             TimeApiImpl::get_boot_time()
311         ),
312         Err(Error::CalculateIdle(_))
313     ));
314 }
315 
316 #[test]
mark_and_recompress_mark_idle_failure()317 fn mark_and_recompress_mark_idle_failure() {
318     let mock = MockContext::new();
319     mock.setup_default_meminfo();
320     let params = Params { threshold_bytes: 0, ..Default::default() };
321     let suspend_history = SuspendHistory::new();
322     let mut zram_recompression = ZramRecompression::new();
323 
324     mock.set_idle.expect().returning(|_| Err(std::io::Error::other("error")));
325 
326     assert!(matches!(
327         zram_recompression.mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
328             &params,
329             &suspend_history,
330             TimeApiImpl::get_boot_time()
331         ),
332         Err(Error::MarkIdle(_))
333     ));
334 }
335 
336 #[test]
mark_and_recompress_skip_huge_idle()337 fn mark_and_recompress_skip_huge_idle() {
338     let mock = MockContext::new();
339     mock.set_idle.expect().returning(|_| Ok(()));
340     mock.setup_default_meminfo();
341     let params = Params { huge_idle: false, threshold_bytes: 0, ..Default::default() };
342     let suspend_history = SuspendHistory::new();
343     let mut zram_recompression = ZramRecompression::new();
344 
345     mock.recompress.expect().with(eq("type=huge_idle")).times(0).returning(|_| Ok(()));
346     mock.recompress.expect().with(eq("type=idle")).times(1).returning(|_| Ok(()));
347     mock.recompress.expect().with(eq("type=huge")).times(1).returning(|_| Ok(()));
348 
349     assert!(zram_recompression
350         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
351             &params,
352             &suspend_history,
353             TimeApiImpl::get_boot_time()
354         )
355         .is_ok());
356 }
357 
358 #[test]
mark_and_recompress_skip_idle()359 fn mark_and_recompress_skip_idle() {
360     let mock = MockContext::new();
361     mock.set_idle.expect().returning(|_| Ok(()));
362     mock.setup_default_meminfo();
363     let params = Params { idle: false, threshold_bytes: 0, ..Default::default() };
364     let suspend_history = SuspendHistory::new();
365     let mut zram_recompression = ZramRecompression::new();
366 
367     mock.recompress.expect().with(eq("type=huge_idle")).times(1).returning(|_| Ok(()));
368     mock.recompress.expect().with(eq("type=idle")).times(0).returning(|_| Ok(()));
369     mock.recompress.expect().with(eq("type=huge")).times(1).returning(|_| Ok(()));
370 
371     assert!(zram_recompression
372         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
373             &params,
374             &suspend_history,
375             TimeApiImpl::get_boot_time()
376         )
377         .is_ok());
378 }
379 
380 #[test]
mark_and_recompress_skip_huge()381 fn mark_and_recompress_skip_huge() {
382     let mock = MockContext::new();
383     mock.set_idle.expect().returning(|_| Ok(()));
384     mock.setup_default_meminfo();
385     let params = Params { huge: false, threshold_bytes: 0, ..Default::default() };
386     let suspend_history = SuspendHistory::new();
387     let mut zram_recompression = ZramRecompression::new();
388 
389     mock.recompress.expect().with(eq("type=huge_idle")).times(1).returning(|_| Ok(()));
390     mock.recompress.expect().with(eq("type=idle")).times(1).returning(|_| Ok(()));
391     mock.recompress.expect().with(eq("type=huge")).times(0).returning(|_| Ok(()));
392 
393     assert!(zram_recompression
394         .mark_and_recompress::<MockSysfsZramApi, MockMeminfoApi>(
395             &params,
396             &suspend_history,
397             TimeApiImpl::get_boot_time()
398         )
399         .is_ok());
400 }
401