• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / alioth / 17185180867

24 Aug 2025 06:16AM UTC coverage: 13.911% (+0.02%) from 13.887%
17185180867

Pull #277

github

web-flow
Merge 15d9ad867 into 861f19073
Pull Request #277: feat: Unix domain socket based vsock device

50 of 86 new or added lines in 9 files covered. (58.14%)

69 existing lines in 6 files now uncovered.

977 of 7023 relevant lines covered (13.91%)

17.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.66
/alioth/src/virtio/queue/queue_test.rs
1
// Copyright 2025 Google LLC
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
//     https://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::io::{ErrorKind, IoSlice, IoSliceMut, Read, Write};
16
use std::ptr::eq as ptr_eq;
17
use std::sync::mpsc::{self, TryRecvError};
18

19
use assert_matches::assert_matches;
20
use rstest::rstest;
21

22
use crate::mem::mapped::RamBus;
23
use crate::virtio::Error;
24
use crate::virtio::queue::split::SplitQueue;
25
use crate::virtio::queue::{
26
    DescChain, Queue, QueueReg, Status, VirtQueue, copy_from_reader, copy_to_writer,
27
};
28
use crate::virtio::tests::{DATA_ADDR, FakeIrqSender, fixture_queue, fixture_ram_bus};
29

30
pub trait VirtQueueGuest<'m>: VirtQueue<'m> {
31
    fn add_desc(
32
        &mut self,
33
        index: Self::Index,
34
        id: u16,
35
        readable: &[(u64, u32)],
36
        writable: &[(u64, u32)],
37
    );
38
}
39

40
impl<'m, Q> Queue<'m, Q>
41
where
42
    Q: VirtQueueGuest<'m>,
43
{
44
    pub fn add_desc(
25✔
45
        &mut self,
46
        index: Q::Index,
47
        id: u16,
48
        readable: &[(u64, u32)],
49
        writable: &[(u64, u32)],
50
    ) {
51
        self.q.add_desc(index, id, readable, writable);
145✔
52
    }
53
}
54

55
#[derive(Debug)]
56
enum ReaderData<'a> {
57
    Buf(&'a [u8]),
58
    Err(ErrorKind),
59
}
60

61
#[derive(Debug)]
62
struct Reader<'a> {
63
    data: &'a [ReaderData<'a>],
64
    index: usize,
65
    pos: usize,
66
}
67

68
impl<'a> Read for Reader<'a> {
69
    fn read(&mut self, _: &mut [u8]) -> std::io::Result<usize> {
70
        unreachable!()
71
    }
72

73
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> std::io::Result<usize> {
13✔
74
        let mut count = 0;
25✔
75
        let mut buf_iter = bufs.iter_mut();
37✔
76
        let Some(s) = buf_iter.next() else {
23✔
77
            return Ok(0);
3✔
78
        };
79
        let mut buf = s.as_mut();
1✔
80
        loop {
×
81
            let Some(data) = self.data.get(self.index) else {
35✔
82
                break;
2✔
83
            };
84
            match data {
1✔
85
                ReaderData::Buf(data) => {
7✔
86
                    let c = buf.write(&data[self.pos..]).unwrap();
1✔
87
                    self.pos += c;
1✔
88
                    if self.pos == data.len() {
8✔
89
                        self.index += 1;
7✔
90
                        self.pos = 0;
7✔
91
                    }
92
                    count += c;
2✔
93
                    if buf.len() == 0 {
2✔
94
                        let Some(s) = buf_iter.next() else {
9✔
95
                            break;
4✔
96
                        };
97
                        buf = s.as_mut();
1✔
98
                    }
99
                }
100
                ReaderData::Err(kind) => {
5✔
101
                    if count > 0 {
5✔
102
                        break;
×
103
                    }
104
                    self.index += 1;
1✔
105
                    return Err((*kind).into());
1✔
106
                }
107
            }
108
        }
109
        Ok(count)
7✔
110
    }
111
}
112

113
#[rstest]
114
fn test_copy_from_reader(fixture_ram_bus: RamBus, fixture_queue: QueueReg) {
115
    let ram = fixture_ram_bus.lock_layout();
116
    let mut q = Queue::new(
117
        SplitQueue::new(&fixture_queue, &*ram, false)
118
            .unwrap()
119
            .unwrap(),
120
    );
121
    assert!(ptr_eq(q.reg(), &fixture_queue));
122

123
    let (irq_tx, irq_rx) = mpsc::channel();
124
    let irq_sender = FakeIrqSender { q_tx: irq_tx };
125

126
    let str_0 = "Hello, World!";
127
    let str_1 = "Goodbye, World!";
128
    let str_2 = "Bose-Einstein condensate";
129
    let addr_0 = DATA_ADDR;
130
    let addr_1 = addr_0 + str_0.len() as u64;
131
    let addr_2 = addr_1 + str_1.len() as u64;
132
    let addr_3 = addr_2 + str_2.len() as u64;
133

134
    let mut reader = Reader {
135
        data: &[
136
            ReaderData::Buf(str_0.as_bytes()),
137
            ReaderData::Buf(str_1.as_bytes()),
138
            ReaderData::Err(ErrorKind::WouldBlock),
139
            ReaderData::Buf(str_2.as_bytes()),
140
            ReaderData::Err(ErrorKind::Interrupted),
141
        ],
142
        pos: 0,
143
        index: 0,
144
    };
145

146
    // no writable descriptors
147
    q.handle_desc(0, &irq_sender, copy_from_reader(&mut reader))
148
        .unwrap();
149
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
150

151
    // empty writable descripter
152
    q.add_desc(0, 0, &[], &[(addr_0, 0)]);
153
    q.handle_desc(0, &irq_sender, copy_from_reader(&mut reader))
154
        .unwrap();
155
    assert_eq!(irq_rx.try_recv(), Ok(0));
156

157
    q.add_desc(
158
        1,
159
        0,
160
        &[],
161
        &[(addr_0, str_0.len() as u32), (addr_1, str_1.len() as u32)],
162
    );
163
    q.handle_desc(0, &irq_sender, copy_from_reader(&mut reader))
164
        .unwrap();
165
    assert_eq!(irq_rx.try_recv(), Ok(0));
166

167
    // no writable descriptors
168
    q.handle_desc(0, &irq_sender, copy_from_reader(&mut reader))
169
        .unwrap();
170
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
171

172
    q.add_desc(2, 2, &[], &[(addr_2, str_2.len() as u32)]);
173
    // will hit ErrorKind::WouldBlock
174
    q.handle_desc(0, &irq_sender, copy_from_reader(&mut reader))
175
        .unwrap();
176
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
177

178
    q.handle_desc(0, &irq_sender, copy_from_reader(&mut reader))
179
        .unwrap();
180
    assert_eq!(irq_rx.try_recv(), Ok(0));
181

182
    q.add_desc(3, 3, &[], &[(addr_3, 12)]);
183

184
    // will hit ErrorKind::Interrupted
185
    assert_matches!(
186
        q.handle_desc(0, &irq_sender, copy_from_reader(&mut reader)),
187
        Err(Error::System { error, .. }) if error.kind() == ErrorKind::Interrupted
188
    );
189

190
    q.handle_desc(0, &irq_sender, copy_from_reader(&mut reader))
191
        .unwrap();
192
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
193

194
    for (s, addr) in [(str_0, addr_0), (str_1, addr_1), (str_2, addr_2)] {
195
        let mut buf = vec![0u8; s.len()];
196
        ram.read(addr, &mut buf).unwrap();
197
        assert_eq!(String::from_utf8_lossy(buf.as_slice()), s);
198
    }
199
}
200

201
#[derive(Debug)]
202
enum WriterData<'a> {
203
    Buf(&'a mut [u8]),
204
    Err(ErrorKind),
205
}
206

207
#[derive(Debug)]
208
struct Writer<'a> {
209
    data: &'a mut [WriterData<'a>],
210
    index: usize,
211
    pos: usize,
212
}
213

214
impl<'a> Write for Writer<'a> {
215
    fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
216
        unreachable!()
217
    }
218

219
    fn flush(&mut self) -> std::io::Result<()> {
×
UNCOV
220
        Ok(())
×
221
    }
222

223
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> std::io::Result<usize> {
13✔
224
        let mut count = 0;
25✔
225
        let mut buf_iter = bufs.iter();
37✔
226
        let Some(s) = buf_iter.next() else {
23✔
227
            return Ok(0);
3✔
228
        };
229
        let mut buf = s.as_ref();
1✔
UNCOV
230
        loop {
×
231
            let Some(data) = self.data.get_mut(self.index) else {
35✔
232
                break;
2✔
233
            };
UNCOV
234
            match data {
1✔
235
                WriterData::Buf(data) => {
7✔
236
                    let c = buf.read(&mut data[self.pos..]).unwrap();
1✔
UNCOV
237
                    self.pos += c;
1✔
238
                    if self.pos == data.len() {
8✔
239
                        self.index += 1;
7✔
240
                        self.pos = 0;
7✔
241
                    }
242
                    count += c;
2✔
UNCOV
243
                    if buf.len() == 0 {
2✔
244
                        let Some(s) = buf_iter.next() else {
9✔
245
                            break;
4✔
246
                        };
UNCOV
247
                        buf = s.as_ref();
1✔
248
                    }
249
                }
250
                WriterData::Err(kind) => {
5✔
251
                    if count > 0 {
5✔
UNCOV
252
                        break;
×
253
                    }
254
                    self.index += 1;
1✔
UNCOV
255
                    return Err((*kind).into());
1✔
256
                }
257
            }
258
        }
259
        Ok(count)
7✔
260
    }
261
}
262

263
#[rstest]
264
fn test_copy_to_writer(fixture_ram_bus: RamBus, fixture_queue: QueueReg) {
265
    let ram = fixture_ram_bus.lock_layout();
266
    let q = SplitQueue::new(&fixture_queue, &*ram, false)
267
        .unwrap()
268
        .unwrap();
269
    let mut q = Queue::new(q);
270
    let (irq_tx, irq_rx) = mpsc::channel();
271
    let irq_sender = FakeIrqSender { q_tx: irq_tx };
272

273
    let str_0 = "Hello, World!";
274
    let str_1 = "Goodbye, World!";
275
    let str_2 = "Bose-Einstein condensate";
276
    let addr_0 = DATA_ADDR;
277
    let addr_1 = addr_0 + str_0.len() as u64;
278
    let addr_2 = addr_1 + str_1.len() as u64;
279
    let addr_3 = addr_2 + str_2.len() as u64;
280
    for (s, addr) in [(str_0, addr_0), (str_1, addr_1), (str_2, addr_2)] {
281
        ram.write(addr, s.as_bytes()).unwrap();
282
    }
283

284
    let mut buf_0 = vec![0u8; str_0.len()];
285
    let mut buf_1 = vec![0u8; str_1.len()];
286
    let mut buf_2 = vec![0u8; str_2.len()];
287
    let mut writer = Writer {
288
        data: &mut [
289
            WriterData::Buf(buf_0.as_mut_slice()),
290
            WriterData::Buf(buf_1.as_mut_slice()),
291
            WriterData::Err(ErrorKind::WouldBlock),
292
            WriterData::Buf(buf_2.as_mut_slice()),
293
            WriterData::Err(ErrorKind::Interrupted),
294
        ],
295
        pos: 0,
296
        index: 0,
297
    };
298

299
    // no readable descriptors
300
    q.handle_desc(0, &irq_sender, copy_to_writer(&mut writer))
301
        .unwrap();
302
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
303

304
    // empty readble descripter
305
    q.add_desc(0, 0, &[(addr_0, 0)], &[]);
306
    q.handle_desc(0, &irq_sender, copy_to_writer(&mut writer))
307
        .unwrap();
308
    assert_eq!(irq_rx.try_recv(), Ok(0));
309

310
    q.add_desc(
311
        1,
312
        0,
313
        &[(addr_0, str_0.len() as u32), (addr_1, str_1.len() as u32)],
314
        &[],
315
    );
316
    q.handle_desc(0, &irq_sender, copy_to_writer(&mut writer))
317
        .unwrap();
318
    assert_eq!(irq_rx.try_recv(), Ok(0));
319

320
    // no readable descriptors
321
    q.handle_desc(0, &irq_sender, copy_to_writer(&mut writer))
322
        .unwrap();
323
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
324

325
    q.add_desc(2, 2, &[(addr_2, str_2.len() as u32)], &[]);
326
    // will hit ErrorKind::WouldBlock
327
    q.handle_desc(0, &irq_sender, copy_to_writer(&mut writer))
328
        .unwrap();
329
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
330

331
    q.handle_desc(0, &irq_sender, copy_to_writer(&mut writer))
332
        .unwrap();
333
    assert_eq!(irq_rx.try_recv(), Ok(0));
334

335
    q.add_desc(3, 3, &[(addr_3, 12)], &[]);
336

337
    // will hit ErrorKind::Interrupted
338
    assert_matches!(
339
        q.handle_desc(0, &irq_sender, copy_to_writer(&mut writer)),
340
        Err(Error::System { error, .. }) if error.kind() == ErrorKind::Interrupted
341
    );
342

343
    q.handle_desc(0, &irq_sender, copy_to_writer(&mut writer))
344
        .unwrap();
345
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
346

347
    for (buf, s) in [(buf_0, str_0), (buf_1, str_1), (buf_2, str_2)] {
348
        assert_eq!(String::from_utf8_lossy(buf.as_slice()), s)
349
    }
350
}
351

352
#[test]
353
fn test_written_bytes() {
354
    let str_0 = "Hello, World!";
355
    let str_1 = "Goodbye, World!";
356

357
    let mut buf = vec![0u8; str_0.len()];
358
    let mut chain = DescChain {
359
        index: 0,
360
        id: 0,
361
        delta: 1,
362
        readable: vec![],
363
        writable: vec![IoSliceMut::new(buf.as_mut_slice())],
364
    };
365
    let reader = str_0.as_bytes();
366
    assert_matches!(
367
        copy_from_reader(reader)(&mut chain),
368
        Ok(Status::Done { len: 13 })
369
    );
370
    assert_eq!(buf.as_slice(), str_0.as_bytes());
371

372
    let mut buf = vec![];
373
    let mut chain = DescChain {
374
        index: 0,
375
        id: 1,
376
        delta: 1,
377
        readable: vec![IoSlice::new(str_1.as_bytes())],
378
        writable: vec![],
379
    };
380
    assert_matches!(
381
        copy_to_writer(&mut buf)(&mut chain),
382
        Ok(Status::Done { len: 0 })
383
    );
384
    assert_eq!(buf.as_slice(), str_1.as_bytes());
385
}
386

387
#[rstest]
388
fn test_handle_deferred(fixture_ram_bus: RamBus, fixture_queue: QueueReg) {
389
    let ram = fixture_ram_bus.lock_layout();
390
    let q = SplitQueue::new(&fixture_queue, &*ram, false)
391
        .unwrap()
392
        .unwrap();
393
    let mut q = Queue::new(q);
394
    let (irq_tx, irq_rx) = mpsc::channel();
395
    let irq_sender = FakeIrqSender { q_tx: irq_tx };
396

397
    let str_0 = "Hello, World!";
398
    let str_1 = "Goodbye, World!";
399
    let str_2 = "Bose-Einstein condensate";
400
    let addr_0 = DATA_ADDR;
401
    let addr_1 = addr_0 + str_0.len() as u64;
402
    let addr_2 = addr_1 + str_1.len() as u64;
403
    for (s, addr) in [(str_0, addr_0), (str_1, addr_1), (str_2, addr_2)] {
404
        ram.write(addr, s.as_bytes()).unwrap();
405
    }
406

407
    q.add_desc(
408
        0,
409
        0,
410
        &[(addr_0, str_0.len() as u32), (addr_1, str_1.len() as u32)],
411
        &[],
412
    );
413
    q.add_desc(1, 2, &[(addr_2, str_2.len() as u32)], &[]);
414

415
    let mut ids = vec![];
416
    q.handle_desc(0, &irq_sender, |chain| {
417
        ids.push(chain.id());
418
        Ok(Status::Deferred)
419
    })
420
    .unwrap();
421

422
    assert_eq!(irq_rx.try_recv(), Err(TryRecvError::Empty));
423
    assert_eq!(ids, [0, 2]);
424

425
    q.handle_deferred(0, 0, &irq_sender, |chain| {
426
        assert_eq!(chain.id, 0);
427
        assert_eq!(&*chain.readable[0], str_0.as_bytes());
428
        assert_eq!(&*chain.readable[1], str_1.as_bytes());
429
        assert_eq!(chain.writable.len(), 0);
430
        Ok(0)
431
    })
432
    .unwrap();
433

434
    assert_matches!(
435
        q.handle_deferred(1, 0, &irq_sender, |_| Ok(0)),
436
        Err(Error::InvalidDescriptor { id: 1, .. })
437
    );
438

439
    q.handle_deferred(2, 0, &irq_sender, |chain| {
440
        assert_eq!(chain.id, 2);
441
        assert_eq!(&*chain.readable[0], str_2.as_bytes());
442
        assert_eq!(chain.writable.len(), 0);
443
        Ok(0)
444
    })
445
    .unwrap();
446
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc