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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With