Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/e2e_tests/tests/swap.rs
5394 views
1
// Copyright 2023 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
//! Testing vmm-swap
6
7
#![cfg(any(target_os = "android", target_os = "linux"))]
8
9
use std::time::Duration;
10
use std::time::Instant;
11
12
use anyhow::bail;
13
use base::test_utils::call_test_with_sudo;
14
use fixture::vm::Config;
15
use fixture::vm::TestVm;
16
use swap::SwapState;
17
use swap::SwapStatus;
18
19
const SWAP_STATE_CHANGE_TIMEOUT: Duration = Duration::from_secs(2);
20
const SWAP_FILE_PATH: &str = "/tmp/swap_test";
21
22
fn get_swap_state(vm: &mut TestVm) -> SwapState {
23
let output = vm.swap_command("status").unwrap();
24
let status = serde_json::from_slice::<SwapStatus>(&output).unwrap();
25
status.state
26
}
27
28
fn wait_until_swap_state_change(
29
vm: &mut TestVm,
30
state: SwapState,
31
transition_state: &[SwapState],
32
timeout: Duration,
33
) -> anyhow::Result<()> {
34
let start = Instant::now();
35
loop {
36
let current_state = get_swap_state(vm);
37
if current_state == state {
38
return Ok(());
39
}
40
if start.elapsed() > timeout {
41
bail!(
42
"state change timeout: current: {:?}, target: {:?}",
43
current_state,
44
state
45
);
46
}
47
if !transition_state.contains(&current_state) {
48
bail!(
49
"unexpected state while waiting: current: {:?}, target: {:?}",
50
current_state,
51
state
52
);
53
}
54
std::thread::sleep(Duration::from_millis(100));
55
}
56
}
57
58
fn create_tmpfs_file_in_guest(vm: &mut TestVm, size: usize) {
59
vm.exec_in_guest("mount -t tmpfs -o size=64m /dev/shm /tmp")
60
.unwrap();
61
vm.exec_in_guest(&format!("head -c {size} /dev/urandom > {SWAP_FILE_PATH}"))
62
.unwrap();
63
}
64
65
fn load_checksum_tmpfs_file(vm: &mut TestVm) -> String {
66
// Use checksum to validate that the RAM on the guest is not broken. Sending the whole content
67
// does not work due to the protocol of the connection between host and guest.
68
vm.exec_in_guest(&format!("cat {SWAP_FILE_PATH} | sha256sum"))
69
.unwrap()
70
.stdout
71
}
72
73
#[ignore = "Only to be called by swap_enabled"]
74
#[test]
75
fn swap_enabled_impl() {
76
let mut config = Config::new();
77
config = config.extra_args(vec!["--swap".to_string(), ".".to_string()]);
78
let mut vm = TestVm::new_sudo(config).unwrap();
79
80
assert_eq!(get_swap_state(&mut vm), SwapState::Ready);
81
vm.swap_command("enable").unwrap();
82
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
83
vm.swap_command("trim").unwrap();
84
wait_until_swap_state_change(
85
&mut vm,
86
SwapState::Pending,
87
&[SwapState::TrimInProgress],
88
SWAP_STATE_CHANGE_TIMEOUT,
89
)
90
.unwrap();
91
vm.swap_command("out").unwrap();
92
wait_until_swap_state_change(
93
&mut vm,
94
SwapState::Active,
95
&[SwapState::SwapOutInProgress],
96
SWAP_STATE_CHANGE_TIMEOUT,
97
)
98
.unwrap();
99
vm.swap_command("disable").unwrap();
100
wait_until_swap_state_change(
101
&mut vm,
102
SwapState::Ready,
103
&[SwapState::SwapInInProgress],
104
SWAP_STATE_CHANGE_TIMEOUT,
105
)
106
.unwrap();
107
}
108
109
#[test]
110
fn swap_enabled() {
111
call_test_with_sudo("swap_enabled_impl");
112
}
113
114
#[ignore = "Only to be called by swap_out_multiple_times"]
115
#[test]
116
fn swap_out_multiple_times_impl() {
117
let mut config = Config::new();
118
config = config.extra_args(vec!["--swap".to_string(), ".".to_string()]);
119
let mut vm = TestVm::new_sudo(config).unwrap();
120
121
assert_eq!(get_swap_state(&mut vm), SwapState::Ready);
122
vm.swap_command("enable").unwrap();
123
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
124
vm.swap_command("trim").unwrap();
125
wait_until_swap_state_change(
126
&mut vm,
127
SwapState::Pending,
128
&[SwapState::TrimInProgress],
129
SWAP_STATE_CHANGE_TIMEOUT,
130
)
131
.unwrap();
132
vm.swap_command("out").unwrap();
133
wait_until_swap_state_change(
134
&mut vm,
135
SwapState::Active,
136
&[SwapState::SwapOutInProgress],
137
SWAP_STATE_CHANGE_TIMEOUT,
138
)
139
.unwrap();
140
vm.swap_command("enable").unwrap();
141
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
142
vm.swap_command("trim").unwrap();
143
wait_until_swap_state_change(
144
&mut vm,
145
SwapState::Pending,
146
&[SwapState::TrimInProgress],
147
SWAP_STATE_CHANGE_TIMEOUT,
148
)
149
.unwrap();
150
vm.swap_command("out").unwrap();
151
wait_until_swap_state_change(
152
&mut vm,
153
SwapState::Active,
154
&[SwapState::SwapOutInProgress],
155
SWAP_STATE_CHANGE_TIMEOUT,
156
)
157
.unwrap();
158
vm.swap_command("enable").unwrap();
159
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
160
vm.swap_command("disable").unwrap();
161
wait_until_swap_state_change(
162
&mut vm,
163
SwapState::Ready,
164
&[SwapState::SwapInInProgress],
165
SWAP_STATE_CHANGE_TIMEOUT,
166
)
167
.unwrap();
168
}
169
170
#[test]
171
fn swap_out_multiple_times() {
172
call_test_with_sudo("swap_out_multiple_times_impl");
173
}
174
175
#[ignore = "Only to be called by swap_disabled_without_swapped_out"]
176
#[test]
177
fn swap_disabled_without_swapped_out_impl() {
178
let mut config = Config::new();
179
config = config.extra_args(vec!["--swap".to_string(), ".".to_string()]);
180
let mut vm = TestVm::new_sudo(config).unwrap();
181
182
assert_eq!(get_swap_state(&mut vm), SwapState::Ready);
183
vm.swap_command("enable").unwrap();
184
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
185
vm.swap_command("disable").unwrap();
186
wait_until_swap_state_change(
187
&mut vm,
188
SwapState::Ready,
189
&[SwapState::SwapInInProgress],
190
SWAP_STATE_CHANGE_TIMEOUT,
191
)
192
.unwrap();
193
}
194
195
#[test]
196
fn swap_disabled_without_swapped_out() {
197
call_test_with_sudo("swap_disabled_without_swapped_out_impl");
198
}
199
200
#[ignore = "Only to be called by stopped_with_swap_enabled"]
201
#[test]
202
fn stopped_with_swap_enabled_impl() {
203
let mut config = Config::new();
204
config = config.extra_args(vec!["--swap".to_string(), ".".to_string()]);
205
let mut vm = TestVm::new_sudo(config).unwrap();
206
207
assert_eq!(get_swap_state(&mut vm), SwapState::Ready);
208
vm.swap_command("enable").unwrap();
209
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
210
vm.swap_command("trim").unwrap();
211
wait_until_swap_state_change(
212
&mut vm,
213
SwapState::Pending,
214
&[SwapState::TrimInProgress],
215
SWAP_STATE_CHANGE_TIMEOUT,
216
)
217
.unwrap();
218
vm.swap_command("out").unwrap();
219
wait_until_swap_state_change(
220
&mut vm,
221
SwapState::Active,
222
&[SwapState::SwapOutInProgress],
223
SWAP_STATE_CHANGE_TIMEOUT,
224
)
225
.unwrap();
226
// dropping TestVm sends crosvm stop command and wait until the process exits.
227
}
228
229
#[test]
230
fn stopped_with_swap_enabled() {
231
call_test_with_sudo("stopped_with_swap_enabled_impl");
232
}
233
234
#[ignore = "Only to be called by memory_contents_preserved_while_vmm_swap_enabled"]
235
#[test]
236
fn memory_contents_preserved_while_vmm_swap_enabled_impl() {
237
let mut config = Config::new();
238
config = config.extra_args(vec!["--swap".to_string(), ".".to_string()]);
239
let mut vm = TestVm::new_sudo(config).unwrap();
240
create_tmpfs_file_in_guest(&mut vm, 1024 * 1024);
241
let checksum = load_checksum_tmpfs_file(&mut vm);
242
243
assert_eq!(get_swap_state(&mut vm), SwapState::Ready);
244
vm.swap_command("enable").unwrap();
245
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
246
247
assert_eq!(load_checksum_tmpfs_file(&mut vm), checksum);
248
}
249
250
#[test]
251
fn memory_contents_preserved_while_vmm_swap_enabled() {
252
call_test_with_sudo("memory_contents_preserved_while_vmm_swap_enabled_impl");
253
}
254
255
#[ignore = "Only to be called by memory_contents_preserved_after_vmm_swap_out"]
256
#[test]
257
fn memory_contents_preserved_after_vmm_swap_out_impl() {
258
let mut config = Config::new();
259
config = config.extra_args(vec!["--swap".to_string(), ".".to_string()]);
260
let mut vm = TestVm::new_sudo(config).unwrap();
261
create_tmpfs_file_in_guest(&mut vm, 1024 * 1024);
262
let checksum = load_checksum_tmpfs_file(&mut vm);
263
264
assert_eq!(get_swap_state(&mut vm), SwapState::Ready);
265
vm.swap_command("enable").unwrap();
266
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
267
vm.swap_command("trim").unwrap();
268
wait_until_swap_state_change(
269
&mut vm,
270
SwapState::Pending,
271
&[SwapState::TrimInProgress],
272
SWAP_STATE_CHANGE_TIMEOUT,
273
)
274
.unwrap();
275
vm.swap_command("out").unwrap();
276
wait_until_swap_state_change(
277
&mut vm,
278
SwapState::Active,
279
&[SwapState::SwapOutInProgress],
280
SWAP_STATE_CHANGE_TIMEOUT,
281
)
282
.unwrap();
283
284
assert_eq!(load_checksum_tmpfs_file(&mut vm), checksum);
285
}
286
287
#[test]
288
fn memory_contents_preserved_after_vmm_swap_out() {
289
call_test_with_sudo("memory_contents_preserved_after_vmm_swap_out_impl");
290
}
291
292
#[ignore = "Only to be called by memory_contents_preserved_after_vmm_swap_disabled"]
293
#[test]
294
fn memory_contents_preserved_after_vmm_swap_disabled_impl() {
295
let mut config = Config::new();
296
config = config.extra_args(vec!["--swap".to_string(), ".".to_string()]);
297
let mut vm = TestVm::new_sudo(config).unwrap();
298
create_tmpfs_file_in_guest(&mut vm, 1024 * 1024);
299
let checksum = load_checksum_tmpfs_file(&mut vm);
300
301
assert_eq!(get_swap_state(&mut vm), SwapState::Ready);
302
vm.swap_command("enable").unwrap();
303
assert_eq!(get_swap_state(&mut vm), SwapState::Pending);
304
vm.swap_command("trim").unwrap();
305
wait_until_swap_state_change(
306
&mut vm,
307
SwapState::Pending,
308
&[SwapState::TrimInProgress],
309
SWAP_STATE_CHANGE_TIMEOUT,
310
)
311
.unwrap();
312
vm.swap_command("out").unwrap();
313
wait_until_swap_state_change(
314
&mut vm,
315
SwapState::Active,
316
&[SwapState::SwapOutInProgress],
317
SWAP_STATE_CHANGE_TIMEOUT,
318
)
319
.unwrap();
320
vm.swap_command("disable").unwrap();
321
wait_until_swap_state_change(
322
&mut vm,
323
SwapState::Ready,
324
&[SwapState::SwapInInProgress],
325
SWAP_STATE_CHANGE_TIMEOUT,
326
)
327
.unwrap();
328
329
assert_eq!(load_checksum_tmpfs_file(&mut vm), checksum);
330
}
331
332
#[test]
333
fn memory_contents_preserved_after_vmm_swap_disabled() {
334
call_test_with_sudo("memory_contents_preserved_after_vmm_swap_disabled_impl");
335
}
336
337