44
55//! Testing virtio-fs.
66
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 ;
714use fixture:: vm:: Config ;
815use fixture:: vm:: TestVm ;
16+ use tempfile:: NamedTempFile ;
17+ use tempfile:: TempDir ;
918
10- /// Tests file copy on virtiofs
19+ /// Tests file copy
1120///
1221/// 1. Create `original.txt` on a temporal directory.
1322/// 2. Start a VM with a virtiofs device for the temporal directory.
1423/// 3. Copy `original.txt` to `new.txt` in the guest.
1524/// 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 ) {
1826 const ORIGINAL_FILE_NAME : & str = "original.txt" ;
1927 const NEW_FILE_NAME : & str = "new.txt" ;
2028 const TEST_DATA : & str = "virtiofs works!" ;
2129
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 ) ;
2431
2532 std:: fs:: write ( orig_file, TEST_DATA ) . unwrap ( ) ;
2633
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 ( ) {
2779 let tag = "mtdtest" ;
80+ let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
2881
2982 let config = Config :: new ( ) . extra_args ( vec ! [
3083 "--shared-dir" . to_string( ) ,
@@ -34,17 +87,25 @@ fn copy_file() {
3487 ) ,
3588 ] ) ;
3689
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+ }
4493
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)
48109}
49110
50111/// Tests file ownership seen by the VM.
@@ -54,15 +115,14 @@ fn copy_file() {
54115/// 3. Start a VM with a virtiofs device for the temporal directory.
55116/// 4. Check that `user_file.txt`'s uid is <mapped-uid> in the VM.
56117/// 5. Verify gid similarly.
57- #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
58118#[ test]
59119fn file_ugid ( ) {
60120 const FILE_NAME : & str = "user_file.txt" ;
61121 let uid = base:: geteuid ( ) ;
62122 let gid = base:: getegid ( ) ;
63123 let mapped_uid: u32 = rand:: random ( ) ;
64124 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) ;
66126 let gid_map = format ! ( "{} {} 1" , mapped_gid, gid) ;
67127
68128 let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
@@ -101,3 +161,55 @@ fn file_ugid() {
101161 assert ! ( output. stdout. contains( & format!( "Uid: ({}/" , mapped_uid) ) ) ;
102162 assert ! ( output. stdout. contains( & format!( "Gid: ({}/" , mapped_gid) ) ) ;
103163}
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