Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writeable data files in Bazel tests

I use Bazel and googletest in my C++ project. I'd like to write some tests that require opening some files with initial data and possibly modifying those files. I'd like the tests to not overwrite the original files obviously. My current (wrong) rules are like this:

filegroup(
  name = "test_data",
  srcs = glob(["test_data/*"]),
)


cc_test(
  name = "sample_test",
  srcs = ["sample_test.cc"],
  data = [":test_data"],
  deps = [ ... ]
)

In the sample_test.cc I try to open a file from test_data/ with RW permissions. Running bazel test //sample_test fails, as open in sample_test.cc returns EROFS (read-only filesystem). I can open the files read-only.

I found this: https://bazel.build/reference/test-encyclopedia#test-interaction-filesystem. It seems test files can only write to some very specific TEST_TMPDIR directory. Is this possible then to make bazel copy the test data files to this directory before running each test?

I guess I could create a fixture and copy the data files to the tmp directory, but this seems like a hack solution and I'd have to add this logic to every test file. It'd be much better to do it from bazel build files directly.

like image 495
Franciszek Malinka Avatar asked Oct 16 '25 14:10

Franciszek Malinka


1 Answers

To fix this issue, I have written the following utility function to get the test's temporary directory, writing the generated files to that in my tests. Then moving the generated files after running the tests to the desired directory.

#pragma once

#include <cstdlib>
#include <filesystem>

namespace test_utils {

using std::filesystem::path, std::getenv;

/**
  Get the TEST_TMPDIR environment variable set by bazel

  Since the bazel test doesn't allow writing to the data directories, the generated files need to be written
  to the test temp directory.

  @return the path to the test temp directory
*/
inline path test_tmpdir() {
  // NOLINTNEXTLINE(concurrency-mt-unsafe) reading an unchaning environment variable
  const auto test_tmpdir = getenv("TEST_TMPDIR");
  if (test_tmpdir == nullptr) {
    // if it's not set, use the current directory
    return path("./");
  }
  return path(test_tmpdir);
}

} // namespace test_utils

Then use test_utils::test_tmpdir() in your tests when you want to write the files.

Then, run the tests with your usual command with --test_tmpdir=./test/

bazel test ... --test_tmpdir=./test/

Then move the generated files to the root directory and remove the temporary directory

(test -f ./test/_tmp/*/** && cp -r ./test/_tmp/*/** ./ || true) && rm -rf ./test/_tmp
like image 177
Amin Avatar answered Oct 19 '25 03:10

Amin