在Linux上伪造IO错误

Tom*_*Tom 7 c python linux unit-testing

我在Linux上有一个Python和C应用程序,它应该在从磁盘读取文件时正确处理IO错误.应用程序的大部分是用Python编写的,带有C扩展,用于执行IO.在此扩展中,检测到IO错误.

有两种情况可能会出现错误.

  1. 文件丢失.
  2. 磁盘上的文件(使用stat)比使用时读取的文件大fread.

我可以很容易地测试和处理1号案例.但是,我还想为案例2编写单元测试.但是,我不知道如何为测试触发"假的"IO错误.这甚至可能吗?有没有更好的方法来测试这种错误?

Bas*_*tch 6

errno(3)仅设置EIO

   EIO    Input/output error (POSIX.1)
Run Code Online (Sandbox Code Playgroud)

另外,根据阅读(2):

   EIO    I/O error.  This will happen for example when the process is
          in a background process group, tries to read from its
          controlling terminal, and either it is ignoring or blocking
          SIGTTIN or its process group is orphaned.  It may also occur
          when there is a low-level I/O error while reading from a 
          disk or tape.
Run Code Online (Sandbox Code Playgroud)

并根据写(2):

   EIO    A low-level I/O error occurred while modifying the inode.
Run Code Online (Sandbox Code Playgroud)

因此,模拟特定的错误代码可能很困难; 注意到有其他系统调用用于I/O,特别是writev可以获得(2)和(间接)MMAP(2) ,但read(2)write(2)是最常见的.

另请注意,文件系统Linux内核(例如其VFS层)都是缓存数据.你可以得到EIO更晚或永远.请参阅sync(2)fsync(2)

但是,一般来说,大多数软件并不EIO特别处理其他错误代码; 你可能通过获取另一个错误代码来测试,例如

  EDQUOT The user's quota of disk blocks on the filesystem containing
          the file referred to by fd has been exhausted.
Run Code Online (Sandbox Code Playgroud)

因此,您可能通过限制磁盘配额(参见quotactl(2),setquota(8)等...)和文件空间(参见setrlimit(2) with RLIMIT_FSIZE,prlimit(1),ulimit内置bash(1)等进行测试. ...)

如果你真的想特意伪装,EIO 你可能会对设备造成物理损坏(或者可能只是在错误的时刻拔掉USB磁盘),或者在用户空间(FUSE)中编写自己的文件系统来模拟它.我不认为这是值得的努力(因为当某些东西得到EIO 整个计算机变得非常快速无法使用,并且用户将注意到无论如何....并且因为大多数软件同样处理所有错误代码 - 除了EINTR)

在代码的C部分中,您可能希望使用strerror(3)(可能使用syslog(3))和/或perror(3).我不确定是否值得努力处理EIO大多数其他错误.

注意:许多关键领域都有标准,用于定义如何处理错误以及应该开发和测试代码,例如汽车中的ISO26262或航空电子设备中的DO-178B.遵循您的域名标准.


ber*_*eal 2

据我了解,TDD 的经典警告我们不要为第 3 方接口(包括标准库)编写模拟/存根,请参见此处。主要问题是应用程序代码和通用第三方库之间通常存在差距,很难与模拟对象结合起来。此外,这会阻止您使用测试来得出设计问题。

(即使在您的情况下,C 库并不完全是第三方,但单元测试意味着您单独测试实体)。

这个想法是,您可以编写一个适配器类来封装所有低级逻辑并公开一个接近您的应用程序所需的接口(例如,引发更有意义的异常,例如FileIsTooBig)。然后,您根据您的领域编写模拟对象。至于测试适配器本身,它是通过一些简单的系统测试进行测试的。