diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d8fdb4a16e..55e73354198 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -168,6 +168,7 @@ jobs: env: PYTHONUTF8: 1 TEST_RUNNER_TIMEOUT_FACTOR: 40 + DOWNLOAD_PREVIOUS_RELEASES: "true" strategy: fail-fast: false @@ -334,6 +335,8 @@ jobs: env: PYTHONUTF8: 1 TEST_RUNNER_TIMEOUT_FACTOR: 40 + DOWNLOAD_PREVIOUS_RELEASES: "true" + PREVIOUS_RELEASES_DIR: ${{ github.workspace }}/releases steps: - name: Checkout @@ -372,10 +375,24 @@ jobs: - name: Run rpcauth test run: py -3 test/util/rpcauth-test.py + - name: Download previous releases + if: env.DOWNLOAD_PREVIOUS_RELEASES == 'true' + shell: bash + run: | + mkdir -p ${{ env.PREVIOUS_RELEASES_DIR }} + python test/get_previous_releases.py -b -t "${{ env.PREVIOUS_RELEASES_DIR }}" + + - name: Run wallet_migration.py test + if: env.DOWNLOAD_PREVIOUS_RELEASES == 'true' + env: + PYTHONIOENCODING: utf-8 + run: py -3 test/functional/wallet_migration.py --previous-releases + - name: Run functional tests env: # TODO: Fix the excluded test and re-enable it. EXCLUDE: '--exclude wallet_multiwallet.py' + PYTHONIOENCODING: utf-8 TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }} run: py -3 test/functional/test_runner.py --jobs $NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix="$RUNNER_TEMP" --combinedlogslen=99999999 --timeout-factor=$TEST_RUNNER_TIMEOUT_FACTOR $EXCLUDE $TEST_RUNNER_EXTRA diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py index 2f5c3b1548c..eec187ba348 100755 --- a/test/functional/wallet_migration.py +++ b/test/functional/wallet_migration.py @@ -8,6 +8,7 @@ import random import shutil import struct import time +import os from test_framework.address import ( key_to_p2pkh, @@ -104,10 +105,27 @@ class WalletMigrationTest(BitcoinTestFramework): assert_equal(self.old_node.get_wallet_rpc(wallet_name).getwalletinfo()["descriptors"], False) # Now unload so we can copy it to the master node for the migration test self.old_node.unloadwallet(wallet_name) + if wallet_name == "": - shutil.copyfile(self.old_node.wallets_path / "wallet.dat", self.master_node.wallets_path / "wallet.dat") + src_path = self.old_node.wallets_path / "wallet.dat" + dst_path = self.master_node.wallets_path / "wallet.dat" + shutil.copyfile(src_path, dst_path) else: - shutil.copytree(self.old_node.wallets_path / wallet_name, self.master_node.wallets_path / wallet_name) + src_path = self.old_node.wallets_path / wallet_name + dst_path = self.master_node.wallets_path / wallet_name + + # Create the directory first if it doesn't exist + os.makedirs(dst_path, exist_ok=True) + + # Copy the files individually + for item in os.listdir(src_path): + s = os.path.join(src_path, item) + d = os.path.join(dst_path, item) + if os.path.isfile(s): + shutil.copy2(s, d) + else: + shutil.copytree(s, d, dirs_exist_ok=True) + # Migrate, checking that rescan does not occur with self.master_node.assert_debug_log(expected_msgs=[], unexpected_msgs=["Rescanning"]): migrate_info = self.master_node.migratewallet(wallet_name=wallet_name, **kwargs) diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py index 27ca6990b8e..cf86b62d56d 100755 --- a/test/get_previous_releases.py +++ b/test/get_previous_releases.py @@ -79,6 +79,12 @@ SHA256_SUMS = { "6ee1a520b638132a16725020146abea045db418ce91c02493f02f541cd53062a": {"tag": "v28.0", "tarball": "bitcoin-28.0-riscv64-linux-gnu.tar.gz"}, "77e931bbaaf47771a10c376230bf53223f5380864bad3568efc7f4d02e40a0f7": {"tag": "v28.0", "tarball": "bitcoin-28.0-x86_64-apple-darwin.tar.gz"}, "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc": {"tag": "v28.0", "tarball": "bitcoin-28.0-x86_64-linux-gnu.tar.gz"}, + + "bff531650dcf859c27d8428dc5f98f3f93d9b6d54e4c1401e0ea9651f1edd7a3": {"tag": "v22.0", "tarball": "bitcoin-22.0-win64.zip"}, + "e16fdbdc4ee953969df1ce8f82380e9c61658b1a64801bd21e2e87063e93bc6a": {"tag": "v23.0", "tarball": "bitcoin-23.0-win64.zip"}, + "97de6e2a4d91531c057537e83bb7e72b1cf9ab777601eb481f3f4a6d9e7b9c67": {"tag": "v24.0.1", "tarball": "bitcoin-24.0.1-win64.zip"}, + "c0d22e9d37d0238215676af1c4e358c8af3a43fe7a25c57499b4c66ca80381da": {"tag": "v25.0", "tarball": "bitcoin-25.0-win64.zip"}, + "f2974a7df505cff14ca92dd7a23ba7e47f1b97ae7e7a12a6fc2f5f5c0a66ca10": {"tag": "v28.0", "tarball": "bitcoin-28.0-win64.zip"}, } @@ -109,6 +115,9 @@ def download_binary(tag, args) -> int: platform = "osx64" tarball = 'bitcoin-{tag}-{platform}.tar.gz'.format( tag=tag[1:], platform=platform) + if platform == "win64" and tag >= "v22.0": + tarball = 'bitcoin-{tag}-{platform}.zip'.format( + tag=tag[1:], platform=platform) tarballUrl = 'https://bitcoincore.org/{bin_path}/{tarball}'.format( bin_path=bin_path, tarball=tarball) @@ -133,12 +142,25 @@ def download_binary(tag, args) -> int: print("Checksum matched") # Extract tarball - ret = subprocess.run(['tar', '-zxf', tarball, '-C', tag, - '--strip-components=1', - 'bitcoin-{tag}'.format(tag=tag[1:])]).returncode - if ret != 0: - print(f"Failed to extract the {tag} tarball") - return ret + if platform == "win64" and tag >= "v22.0": + # Handle zip files for Windows + import zipfile + with zipfile.ZipFile(tarball, 'r') as zip_ref: + zip_ref.extractall(tag) + # Rename the directory to match expected structure + extracted_dir = Path(tag) / f"bitcoin-{tag[1:]}" + if extracted_dir.exists(): + for item in extracted_dir.iterdir(): + shutil.move(str(item), str(Path(tag) / item.name)) + extracted_dir.rmdir() + else: + # Standard tar extraction + ret = subprocess.run(['tar', '-zxf', tarball, '-C', tag, + '--strip-components=1', + 'bitcoin-{tag}'.format(tag=tag[1:])]).returncode + if ret != 0: + print(f"Failed to extract the {tag} tarball") + return ret Path(tarball).unlink() @@ -221,8 +243,12 @@ def build_release(tag, args) -> int: def check_host(args) -> int: - args.host = os.environ.get('HOST', subprocess.check_output( - './depends/config.guess').decode()) + # On Windows, config.guess script doesn't work, so we set host manually + if sys.platform == 'win32': + args.host = 'x86_64-w64-mingw32' + else: + args.host = os.environ.get('HOST', subprocess.check_output( + './depends/config.guess').decode()) if args.download_binary: platforms = { 'aarch64-*-linux*': 'aarch64-linux-gnu', @@ -231,6 +257,8 @@ def check_host(args) -> int: 'x86_64-*-linux*': 'x86_64-linux-gnu', 'x86_64-apple-darwin*': 'x86_64-apple-darwin', 'aarch64-apple-darwin*': 'arm64-apple-darwin', + 'x86_64-w64-mingw32': 'win64', + 'x86_64-*-win*': 'win64', } args.platform = '' for pattern, target in platforms.items():