Search code examples
bazel

How to run test on the source tree in bazel?


I am migrating a project from cmake to bazel. I have a folder contains some python code and some genrules. I had a test script run all the python tests in this folder recursively. So basically I need all py files under this folder as data for the test script. But given there are some genrule I need to run, there are some BUILD files, so that glob(["**/*.py"]) can't get through.

For example, we have a folder python contains following files.

  • python/BUILD

  • python/test_a.py

  • python/folder_a/BUILD this one has genrule in it.

  • python/folder_a/folder_b/BUILD this one has genrule as well.

  • python/folder_a/folder_b/folder_c/test_b.py

I want to run the test script under python/, it will run all the test_*.py recursively. Now we want to wrap it as a sh_test in bazel. So we need to specify all the test_*.py in the data field. But there is no easy way to do that since glob() can't get through python/folder_a/BUILD and python/folder_a/folder_b/BUILD.

It will be quite convenience if I can run this script in the source tree. But it seems that bazel didn't provide this. Adding local = 1 in sh_test only make the runfiles tree writable.

I know it is not a good way to use bazel to test, but sometimes it is too much work for migrating everything at the same time.


Solution

  • I can't think of an easy way to obtain all of the target names in a BUILD file, but there is a Bazel query you can run to get the target names, which you can then collect in a filegroup target to reference in the sh_test.data attribute.

    bazel query 'filter(".*:test_.*\.py", kind("source file", //python/...:*) + kind("generated file", //python/...:*))'
    

    Breaking this down:

    1. kind("source file", //python/...:*) queries all source file targets in the //python package recursively. This collects the normal source files.

    2. kind("generated file", //python/...:*) queries all generated file targets in the //python package recursively. This collects the genrule'd files.

    3. filter(".*:test_.*\.py", ...) filters the results that contain only targets in the form of //any/package:test_name.py

    For example, running

    bazel query 'filter(".*:test_.*\.py", kind("source file", //src/...:* + //tools/...:*) + kind("generated file", //src/...:* + //tools/...:*))'
    

    on Bazel's own source tree finds one target: //src/test/py/bazel:test_base.py