4
4
5
5
//! Testing virtio-fs.
6
6
7
+ #![ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
8
+
9
+ use std:: path:: Path ;
10
+
11
+ use fixture:: vhost_user:: CmdType ;
12
+ use fixture:: vhost_user:: Config as VuConfig ;
13
+ use fixture:: vhost_user:: VhostUserBackend ;
7
14
use fixture:: vm:: Config ;
8
15
use fixture:: vm:: TestVm ;
16
+ use tempfile:: NamedTempFile ;
17
+ use tempfile:: TempDir ;
9
18
10
- /// Tests file copy on virtiofs
19
+ /// Tests file copy
11
20
///
12
21
/// 1. Create `original.txt` on a temporal directory.
13
22
/// 2. Start a VM with a virtiofs device for the temporal directory.
14
23
/// 3. Copy `original.txt` to `new.txt` in the guest.
15
24
/// 4. Check that `new.txt` is created in the host.
16
- #[ test]
17
- fn copy_file ( ) {
25
+ fn copy_file ( mut vm : TestVm , tag : & str , dir : TempDir ) {
18
26
const ORIGINAL_FILE_NAME : & str = "original.txt" ;
19
27
const NEW_FILE_NAME : & str = "new.txt" ;
20
28
const TEST_DATA : & str = "virtiofs works!" ;
21
29
22
- let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
23
- let orig_file = temp_dir. path ( ) . join ( ORIGINAL_FILE_NAME ) ;
30
+ let orig_file = dir. path ( ) . join ( ORIGINAL_FILE_NAME ) ;
24
31
25
32
std:: fs:: write ( orig_file, TEST_DATA ) . unwrap ( ) ;
26
33
34
+ // TODO(b/269137600): Split this into multiple lines instead of connecting commands with `&&`.
35
+ vm. exec_in_guest ( & format ! (
36
+ "mount -t virtiofs {tag} /mnt && cp /mnt/{} /mnt/{} && sync" ,
37
+ ORIGINAL_FILE_NAME , NEW_FILE_NAME ,
38
+ ) )
39
+ . unwrap ( ) ;
40
+
41
+ let new_file = dir. path ( ) . join ( NEW_FILE_NAME ) ;
42
+ let contents = std:: fs:: read ( new_file) . unwrap ( ) ;
43
+ assert_eq ! ( TEST_DATA . as_bytes( ) , & contents) ;
44
+ }
45
+
46
+ /// Tests mount/read/create/write
47
+ /// 1. Create `read_file.txt` with test data in host's temporal directory.
48
+ /// 2. Start a VM with a virtiofs device for the temporal directory.
49
+ /// 3. Guest reads read_file.txt file & verify the content is test data
50
+ /// 4. Guest creates a write_file.txt file in shared directory
51
+ /// 5. Host reads file from host's temporal directory & verify content is test data
52
+ fn mount_rw ( mut vm : TestVm , tag : & str , dir : TempDir ) {
53
+ const READ_FILE_NAME : & str = "read_test.txt" ;
54
+ const WRITE_FILE_NAME : & str = "write_test.txt" ;
55
+ const TEST_DATA : & str = "hello world" ;
56
+
57
+ let read_test_file = dir. path ( ) . join ( READ_FILE_NAME ) ;
58
+ let write_test_file = dir. path ( ) . join ( WRITE_FILE_NAME ) ;
59
+ std:: fs:: write ( read_test_file, TEST_DATA ) . unwrap ( ) ;
60
+
61
+ assert_eq ! (
62
+ vm. exec_in_guest( & format!(
63
+ "mount -t virtiofs {tag} /mnt && cat /mnt/read_test.txt"
64
+ ) )
65
+ . unwrap( )
66
+ . stdout
67
+ . trim( ) ,
68
+ TEST_DATA
69
+ ) ;
70
+
71
+ const IN_FS_WRITE_FILE_PATH : & str = "/mnt/write_test.txt" ;
72
+ let _ = vm. exec_in_guest ( & format ! ( "echo -n {TEST_DATA} > {IN_FS_WRITE_FILE_PATH}" ) ) ;
73
+ let read_contents = std:: fs:: read ( write_test_file) . unwrap ( ) ;
74
+ assert_eq ! ( TEST_DATA . as_bytes( ) , & read_contents) ;
75
+ }
76
+
77
+ #[ test]
78
+ fn fs_copy_file ( ) {
27
79
let tag = "mtdtest" ;
80
+ let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
28
81
29
82
let config = Config :: new ( ) . extra_args ( vec ! [
30
83
"--shared-dir" . to_string( ) ,
@@ -34,17 +87,25 @@ fn copy_file() {
34
87
) ,
35
88
] ) ;
36
89
37
- let mut vm = TestVm :: new ( config) . unwrap ( ) ;
38
- // TODO(b/269137600): Split this into multiple lines instead of connecting commands with `&&`.
39
- vm. exec_in_guest ( & format ! (
40
- "mount -t virtiofs {tag} /mnt && cp /mnt/{} /mnt/{} && sync" ,
41
- ORIGINAL_FILE_NAME , NEW_FILE_NAME ,
42
- ) )
43
- . unwrap ( ) ;
90
+ let vm = TestVm :: new ( config) . unwrap ( ) ;
91
+ copy_file ( vm, tag, temp_dir)
92
+ }
44
93
45
- let new_file = temp_dir. path ( ) . join ( NEW_FILE_NAME ) ;
46
- let contents = std:: fs:: read ( new_file) . unwrap ( ) ;
47
- assert_eq ! ( TEST_DATA . as_bytes( ) , & contents) ;
94
+ #[ test]
95
+ fn fs_mount_rw ( ) {
96
+ let tag = "mtdtest" ;
97
+ let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
98
+
99
+ let config = Config :: new ( ) . extra_args ( vec ! [
100
+ "--shared-dir" . to_string( ) ,
101
+ format!(
102
+ "{}:{tag}:type=fs:cache=auto" ,
103
+ temp_dir. path( ) . to_str( ) . unwrap( )
104
+ ) ,
105
+ ] ) ;
106
+
107
+ let vm = TestVm :: new ( config) . unwrap ( ) ;
108
+ mount_rw ( vm, tag, temp_dir)
48
109
}
49
110
50
111
/// Tests file ownership seen by the VM.
@@ -54,15 +115,14 @@ fn copy_file() {
54
115
/// 3. Start a VM with a virtiofs device for the temporal directory.
55
116
/// 4. Check that `user_file.txt`'s uid is <mapped-uid> in the VM.
56
117
/// 5. Verify gid similarly.
57
- #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
58
118
#[ test]
59
119
fn file_ugid ( ) {
60
120
const FILE_NAME : & str = "user_file.txt" ;
61
121
let uid = base:: geteuid ( ) ;
62
122
let gid = base:: getegid ( ) ;
63
123
let mapped_uid: u32 = rand:: random ( ) ;
64
124
let mapped_gid: u32 = rand:: random ( ) ;
65
- let uid_map = format ! ( "{} {} 1" , mapped_uid, uid) ;
125
+ let uid_map: String = format ! ( "{} {} 1" , mapped_uid, uid) ;
66
126
let gid_map = format ! ( "{} {} 1" , mapped_gid, gid) ;
67
127
68
128
let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
@@ -101,3 +161,55 @@ fn file_ugid() {
101
161
assert ! ( output. stdout. contains( & format!( "Uid: ({}/" , mapped_uid) ) ) ;
102
162
assert ! ( output. stdout. contains( & format!( "Gid: ({}/" , mapped_gid) ) ) ;
103
163
}
164
+
165
+ pub fn create_vu_fs_config ( socket : & Path , shared_dir : & Path , tag : & str ) -> VuConfig {
166
+ let uid = base:: geteuid ( ) ;
167
+ let gid = base:: getegid ( ) ;
168
+ let socket_path = socket. to_str ( ) . unwrap ( ) ;
169
+ let shared_dir_path = shared_dir. to_str ( ) . unwrap ( ) ;
170
+ println ! ( "socket={socket_path}, tag={tag}, shared_dir={shared_dir_path}" ) ;
171
+ VuConfig :: new ( CmdType :: Device , "vhost-user-fs" ) . extra_args ( vec ! [
172
+ "fs" . to_string( ) ,
173
+ format!( "--socket={socket_path}" ) ,
174
+ format!( "--shared-dir={shared_dir_path}" ) ,
175
+ format!( "--tag={tag}" ) ,
176
+ format!( "--uid-map=0 {uid} 1" ) ,
177
+ format!( "--gid-map=0 {gid} 1" ) ,
178
+ ] )
179
+ }
180
+
181
+ /// Tests vhost-user fs device copy file.
182
+ #[ test]
183
+ fn vhost_user_fs_copy_file ( ) {
184
+ let socket = NamedTempFile :: new ( ) . unwrap ( ) ;
185
+ let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
186
+
187
+ let config = Config :: new ( ) ;
188
+ let tag = "mtdtest" ;
189
+
190
+ let vu_config = create_vu_fs_config ( socket. path ( ) , temp_dir. path ( ) , tag) ;
191
+ let _vu_device = VhostUserBackend :: new ( vu_config) . unwrap ( ) ;
192
+
193
+ let config = config. with_vhost_user_fs ( socket. path ( ) , tag) ;
194
+ let vm = TestVm :: new ( config) . unwrap ( ) ;
195
+
196
+ copy_file ( vm, tag, temp_dir) ;
197
+ }
198
+
199
+ /// Tests vhost-user fs device mount and read write.
200
+ #[ test]
201
+ fn vhost_user_fs_mount_rw ( ) {
202
+ let socket = NamedTempFile :: new ( ) . unwrap ( ) ;
203
+ let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
204
+
205
+ let config = Config :: new ( ) ;
206
+ let tag = "mtdtest" ;
207
+
208
+ let vu_config = create_vu_fs_config ( socket. path ( ) , temp_dir. path ( ) , tag) ;
209
+ let _vu_device = VhostUserBackend :: new ( vu_config) . unwrap ( ) ;
210
+
211
+ let config = config. with_vhost_user_fs ( socket. path ( ) , tag) ;
212
+ let vm = TestVm :: new ( config) . unwrap ( ) ;
213
+
214
+ mount_rw ( vm, tag, temp_dir) ;
215
+ }
0 commit comments