5

I am developing a lib for a Linux project that stores files using boost::serialization. Because the files might be very large (1-50 GiB) and the program might fail writing them at some point (we are talking about thousands of them) I want to use a simple backup system to recover the files if they are not valid.

I have to test this using QtTests (the Qt unit test suite), but I could add additional libs if neccessary. The question is now how to test the backup system. In theory the test needs to let the ofstream ofs add invalid data after a given amount of data.

Here is the source code of the function in question. I am already testing the saving process itself, only the backup system could only be tested by hand.

The code (glued together and shortened to one method):

void DataStore::storeNodeData(TrajectoryDataSet data) {
   string path = getDataFileName(data);
   string oldPath = getDataFileName(data).append(".old");

   if (access(path.c_str(), F_OK) == 0 &&
      access(oldPath.c_str(), F_OK) != 0) {
      if (rename(path.c_str(), oldPath.c_str()) != 0) {
         throw FileSystemException("Unable to rename file to '.old'.");
      }
   }

   bool broken = false;
   ofstream ofs(path);
   boost::archive::text_oarchive oa(ofs);
   oa << data;
   if (!ofs.good())
      broken = true;
   ofs.close();

   //File verification
   TrajectoryDataSet fData;
   ifstream ifs(path);
   boost::archive::text_iarchive ia(ifs);
   ia >> fData;
   ifs.close();
   if (fData != data)
      broken = true;

   if (broken) {
      rename(oldPath.c_str(), path.c_str());
      throw FileSystemException("Unable write valid file.");
   } else if (access(oldPath.c_str(), F_OK) != -1 &&
      unlink(oldPath.c_str()) != 0)
      throw FileSystemException("Unable to delete backup file.");
}
  • Are you asking about unit-testing the code snippet ? how do you want to test the successful file writing- simply write it to disk ? this is not unit-testing. – Rsf Aug 17 '18 at 12:44
  • @Rfs I want to test the parts of the code triggered by broken = true; and if possible by an return value of -1 (!= 0) for rename and unlink. In general the error handling of the method. – msebas Aug 19 '18 at 10:25
1

How would you test it manually? Then wonder can I automate this later?

One scenario is that the disk it is writing to is unmounted for a short while, this probably result in some sort of error:

  • Thread the test and in parallel unmount the file system on which the data gets written.

This will result in a end-2-end test, needing a filesystem, data-files, setup time and probably is slow.

Now I can come-up with more scenarios, but I think you want to be able to inject a mock of ofs and let its good() method return false just for this test, afterwards verify your recovery system worked. E.g. decoupling and unit-testing.

  • I test it by hand using the debugger to stop the process, then modify the file by hand and let the program continue. My problem is actually the process of injecting a mock, because ofstream is inheriting the relevant methods from basic_ostream as non virtual methods. – msebas Aug 27 '18 at 9:53
  • OK, after a bit of research I think there is no way to mock ofstream without an additional wrapper class used by my code. Instead I mocked the file using posix pipes (mkfifo), which is problematic because of POSIX SIGPIPE, which might occur and result in tests that are possibly hard to control. But they are testing what I want. – msebas Aug 27 '18 at 16:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.