test: Explicitly specify directory where to search tests for #27561

pull hebasto wants to merge 1 commits into bitcoin:master from hebasto:230503-path changing 1 files +6 −2
  1. hebasto commented at 10:23 AM on May 3, 2023: member

    For out-of-source builds, the test/functional/test_runner.py is supposed to be run from the build directory which allows it to pick the test/config.ini file generated by the build system. Currently, it works accidently for the following reasons:

    • on POSIX systems, when running a created by Autoconf symlink to the test/functional/test_runner.py in the source directory, it actually has the source directory location in the sys.path.
    • on Windows (the build_msvc directory) VS project puts and copies every build artifact into the source tree (which is wrong and ugly).

    This PR makes test/functional/test_runner.py work from a build directory in any form (a symbolic link, a hard link, a copy) on all supported platforms, which is highly desirable in the upcoming CMake-based build system.

    For the current master branch, this PR has no behaviour change.

    Required for https://github.com/hebasto/bitcoin/pull/15.


    Steps to reproduce the issue

    While the issue is mostly specific to Windows and CMake builds, it is still possible to reproduce it on the current master branch.

    1. Make an out-of-source build:
    $ ./autogen.sh
    $ mkdir ../build && cd ../build
    $ ../bitcoin/configure
    $ make
    
    1. Note that Autoconf created a symbolic link test/functional/test_runner.py in the ../build directory:
    $ ls -l test/functional/test_runner.py 
    lrwxrwxrwx 1 hebasto hebasto 47 May  5 17:40 test/functional/test_runner.py -> ../../../bitcoin/test/functional/test_runner.py
    

    which works flawlessly.

    1. However, replacing this symbolic link with a hard link or a copy of test/functional/test_runner.py from the source tree will cause the following error:
    $ cp ../bitcoin/test/functional/test_runner.py test/functional/test_runner.py
    $ ls -l test/functional/test_runner.py
    $ ./test/functional/test_runner.py 
    Temporary test directory at /tmp/test_runner_₿_🏃_20230505_175104
    Running Unit Tests for Test Framework Modules
    E
    ======================================================================
    ERROR: test_framework (unittest.loader._FailedTest)
    ----------------------------------------------------------------------
    ImportError: Failed to import test module: test_framework
    Traceback (most recent call last):
      File "/usr/lib/python3.10/unittest/loader.py", line 154, in loadTestsFromName
        module = __import__(module_name)
    ModuleNotFoundError: No module named 'test_framework'
    
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    FAILED (errors=1)
    Early exiting after failure in TestFramework unit tests
    
  2. DrahtBot commented at 10:23 AM on May 3, 2023: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK stickies-v, MarcoFalke
    Concept ACK theuni

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

  3. DrahtBot added the label Tests on May 3, 2023
  4. hebasto commented at 10:26 AM on May 3, 2023: member

    Friendly ping @stickies-v :)

  5. in test/functional/test_runner.py:1 in a3108880fa


    stickies-v commented at 2:50 PM on May 5, 2023:

    Found two more instances in test_runner.py:

    diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
    index 0c9a7173c..d495615fc 100755
    --- a/test/functional/test_runner.py
    +++ b/test/functional/test_runner.py
    @@ -412,7 +412,7 @@ def main():
     
         # Read config generated by configure.
         config = configparser.ConfigParser()
    -    configfile = os.path.abspath(os.path.dirname(__file__)) + "/../config.ini"
    +    configfile = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "config.ini"))
         config.read_file(open(configfile, encoding="utf8"))
     
         passon_args.append("--configfile=%s" % configfile)
    @@ -779,7 +779,7 @@ def check_script_list(*, src_dir, fail_on_warn):
     
         Check that there are no scripts in the functional tests directory which are
         not being run by pull-tester.py."""
    -    script_dir = src_dir + '/test/functional/'
    +    script_dir = os.path.join(src_dir, 'test', 'functional')
         python_files = set([test_file for test_file in os.listdir(script_dir) if test_file.endswith(".py")])
         missed_tests = list(python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS)))
         if len(missed_tests) != 0:
    
    

    hebasto commented at 5:01 PM on May 5, 2023:

    Thanks! Updated.

  6. stickies-v commented at 3:17 PM on May 5, 2023: contributor

    Would it be possible to provide instructions on replicating how to make this fail withoutsys.path.append(tests_dir)? Often times, messing with system.path is treating the symptoms when actually the package structure needs to be improved. May not be true in this case, though.

  7. hebasto commented at 4:53 PM on May 5, 2023: member

    @stickies-v

    Would it be possible to provide instructions on replicating how to make this fail withoutsys.path.append(tests_dir)?

    Sure. I've updated the PR description with steps to replicate the failure.

  8. hebasto force-pushed on May 5, 2023
  9. hebasto commented at 5:00 PM on May 5, 2023: member

    Updated a3108880fac89d4472fe3b24d133e9645bed41cf -> fdff2156e1ebc11818f34759bff80e7d37dfff7d (pr27561.01 -> pr27561.02, diff):

  10. theuni commented at 8:07 PM on May 18, 2023: member

    Concept ACK for CMake.

    The path.join change is easy, but I'll defer to someone more familiar with the test framework on the path change.

  11. in test/functional/test_runner.py:539 in 4ff065d085 outdated
     535 | @@ -536,7 +536,7 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
     536 |          logging.debug("Early exiting after failure in TestFramework unit tests")
     537 |          sys.exit(False)
     538 |  
     539 | -    tests_dir = src_dir + '/test/functional/'
     540 | +    tests_dir = os.path.join(src_dir, 'test', 'functional')
    


    maflcko commented at 7:48 AM on May 19, 2023:

    what is the point of changing this? I'd say to either leave as-is or change to Pathlib, which can use the / operator?


    hebasto commented at 10:46 AM on May 19, 2023:

    Leaved as is.

  12. maflcko approved
  13. maflcko commented at 7:48 AM on May 19, 2023: member

    lgtm

  14. hebasto force-pushed on May 19, 2023
  15. hebasto commented at 10:45 AM on May 19, 2023: member

    Dropped non-required refactoring commit.

  16. maflcko commented at 11:27 AM on May 19, 2023: member

    lgtm ACK 342a0c865d8b4b00a088af7b70b1ee0df1864f5c

    This just adds a duplicate entry in the normal case, because the symlink from configure is already followed by python, see https://docs.python.org/3/library/sys.html#sys.path, so the duplicate should be harmless.

    Didn't check what Cmake does. I presume it copies?

  17. hebasto commented at 11:37 AM on May 19, 2023: member
  18. maflcko commented at 12:04 PM on May 19, 2023: member

    Any reason to change it? I presume this would lead to copies instead of hard links when the build dir is on a different storage device? symbolic links could be used to follow to a different storage device.

  19. hebasto commented at 12:42 PM on May 19, 2023: member

    Any reason to change it? I presume this would lead to copies instead of hard links when the build dir is on a different storage device?

    1. The SeCreateSymbolicLinkPrivilege policy is disabled by default for non-administartors on Windows.
    2. Even with the SeCreateSymbolicLinkPrivilege enabled, this change is still required on Windows.

    symbolic links could be used to follow to a different storage device.

    OK. I'll revert to my previous variant which uses the file(CREATE_LINK ... COPY_ON_ERROR SYMBOLIC) command.

  20. maflcko commented at 12:45 PM on May 19, 2023: member

    Anyway, should be unrelated to this pull request.

  21. maflcko approved
  22. stickies-v commented at 1:35 PM on May 19, 2023: contributor

    Sure. I've updated the PR description with steps to replicate the failure.

    Thanks, this helped a lot with my understanding.

    I'm not a huge fan of the build system leaking into the test code, if we can avoid it. Someone reading this without knowledge of the build system wouldn't understand why we're appending to sys.path, so at the very least I'd suggest adding some documentation and/or a link to this PR.

    An alternative approach could be to add a bitcoin/test/functional/setup.py file to make the test framework an installable package. When installing the package in editable mode (-e, acts kind of like a symlink), that would prevent developers having to reinstall the package for every change made to the test framework.

    <details> <summary>bitcoin/test/functional/setup.py example:</summary>

    from setuptools import setup, find_packages
    
    setup(
        name='bitcoin_functional_tests',
        version='0.1',
        packages=find_packages(),
    )
    

    </details>

    Install the package in editable mode:

    pip install -e ../bitcoin/test/functional/
    

    For me, this fixes the problem with the steps you've provided to reproduce the issue. I'm very unfamiliar with the build process though, so this may not be the best solution either. It's definitely more pythonic, and as another upside makes it easier to use the test framework as a library.

  23. hebasto commented at 3:43 PM on May 19, 2023: member

    Install the package in editable mode:

    The drawback of such an approach is that it creates additional files in the source tree.

  24. in test/functional/test_runner.py:535 in 342a0c865d outdated
     527 | @@ -528,6 +528,10 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
     528 |  
     529 |      # Test Framework Tests
     530 |      print("Running Unit Tests for Test Framework Modules")
     531 | +
     532 | +    tests_dir = src_dir + '/test/functional/'
     533 | +    sys.path.append(tests_dir)
    


    stickies-v commented at 5:03 PM on May 19, 2023:

    Suggested documentation since it's not immediately obvious why this is necessary.

        # This allows `test_runner.py` to work from an out-of-source build directory using a symlink,
        # hard link or a copy on any platform. See [#27561](/bitcoin-bitcoin/27561/).
        sys.path.append(tests_dir)
    

    hebasto commented at 6:24 PM on May 19, 2023:

    Thanks! Updated.

  25. stickies-v approved
  26. stickies-v commented at 5:05 PM on May 19, 2023: contributor

    ACK 342a0c865d8b4b00a088af7b70b1ee0df1864f5c modulo improved documentation (left a suggestion).

    The drawback of such an approach is that it creates additional files in the source tree.

    You're right, I can't find a way to install the package without it affecting the source tree in one way or another. So the current approach is probably the best approach.

  27. test: Explicitly specify directory where to search tests for
    This change allows `test_runner.py` to work from an out-of-source build
    directory using a symlink, a hard link or a copy on any platform.
    c44f3f2319
  28. hebasto force-pushed on May 19, 2023
  29. hebasto commented at 6:23 PM on May 19, 2023: member

    Updated 342a0c865d8b4b00a088af7b70b1ee0df1864f5c -> c44f3f231988dc05c4c7a8a96bc2e7b1a54da277 (pr27561.03 -> pr27561.04, diff):

  30. stickies-v approved
  31. DrahtBot requested review from maflcko on May 19, 2023
  32. maflcko commented at 7:24 AM on May 22, 2023: member

    lgtm ACK c44f3f231988dc05c4c7a8a96bc2e7b1a54da277 💸

    <details><summary>Show signature</summary>

    Signature:

    untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
    RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
    trusted comment: lgtm ACK c44f3f231988dc05c4c7a8a96bc2e7b1a54da277 💸
    H4uXJb9dCevTXQH5BFAvev56kkzUC6o51P3Mw7DA5MkLu5BfuD8loNRLNiQngaa0PIbX0MUDxQ1sSHObwvcKBQ==
    

    </details>

  33. fanquake merged this on May 22, 2023
  34. fanquake closed this on May 22, 2023

  35. hebasto deleted the branch on May 22, 2023
  36. fanquake referenced this in commit 5ef2c1ee7a on May 23, 2023
  37. sidhujag referenced this in commit 183a37a3b7 on May 23, 2023
  38. sidhujag referenced this in commit c2228804b5 on May 23, 2023
  39. bitcoin locked this on May 21, 2024

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-24 21:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me