Repository: bitcoin/bitcoin
File: test/functional/wallet_migration.py (Python)

Code before:
        assert_equal(bals, wallet.getbalances())

    def test_default_wallet(self):
        self.log.info("Test migration of the wallet named as the empty string")
        wallet = self.create_legacy_wallet("")

        # Set time to verify backup existence later
        curr_time = int(time.time())
        self.master_node.setmocktime(curr_time)

        res, wallet = self.migrate_and_get_rpc("")
        self.master_node.setmocktime(0)
        info = wallet.getwalletinfo()
        assert_equal(info["descriptors"], True)
        assert_equal(info["format"], "sqlite")

        walletdir_list = wallet.listwalletdir()
        assert {"name": info["walletname"]} in [{"name": w["name"]} for w in walletdir_list["wallets"]]

        # Check backup existence and its non-empty wallet filename
        backup_filename = f"default_wallet_{curr_time}.legacy.bak"
        backup_path = self.master_node.wallets_path / backup_filename
        assert backup_path.exists()
        assert_equal(str(backup_path), res['backup_path'])
        assert {"name": backup_filename} not in walletdir_list["wallets"]

        self.master_node.setmocktime(0)

    def test_direct_file(self):
        self.log.info("Test migration of a wallet that is not in a wallet directory")
        wallet = self.create_legacy_wallet("plainfile")
        wallet.unloadwallet()

        shutil.copyfile(
            self.old_node.wallets_path / "plainfile" / "wallet.dat" ,
            self.master_node.wallets_path / "plainfile"
        )
        assert (self.master_node.wallets_path / "plainfile").is_file()

        self.master_node.migratewallet("plainfile")
        wallet = self.master_node.get_wallet_rpc("plainfile")
        info = wallet.getwalletinfo()
        assert_equal(info["descriptors"], True)
        assert_equal(info["format"], "sqlite")

        assert (self.master_node.wallets_path / "plainfile").is_dir()
        assert (self.master_node.wallets_path / "plainfile" / "wallet.dat").is_file()

    def test_addressbook(self):
        df_wallet = self.master_node.get_wallet_rpc(self.default_wallet_name)


Review comment (bug):
In commit "test: Migration of a wallet ending in `/`" (499099320b138c3d895d3ad8a622a08e404008d6)

This fails on my system because the test is racy. By the time backup is created time.time() is higher than the backup time.

Also the os.path.exists() return value is discarded here so this doesn't actually check anything.

Here are the changes I made to fix these problems. (Another approach might be to set a mock time instead)

<details><summary>diff</summary>
<p>

```diff
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -5,6 +5,7 @@
 """Test Migrating a wallet from legacy to descriptor."""
 import os.path
 import random
+import re
 import shutil
 import struct
 import time
@@ -23,6 +24,7 @@ from test_framework.script import hash160
 from test_framework.script_util import key_to_p2pkh_script, key_to_p2pk_script, script_to_p2sh_script, script_to_p2wsh_script
 from test_framework.util import (
     assert_equal,
+    assert_not_equal,
     assert_raises_rpc_error,
     find_vout_for_address,
     sha256sum_file,
@@ -567,9 +569,8 @@ class WalletMigrationTest(BitcoinTestFramework):
 
         wallet_ending_in_rel_path = f"{self.old_node.wallets_path}/{wallet_ending_in_relative}"
         migrate_res = self.master_node.migratewallet(wallet_ending_in_rel_path)
-        expected_backup_path = self.master_node.wallets_path / f"ends_{int(time.time())}.legacy.bak"
-        os.path.exists(expected_backup_path)
-        assert_equal(f"{expected_backup_path}", migrate_res['backup_path'])
+        assert_not_equal(re.fullmatch(re.escape(str(self.master_node.wallets_path / "ends")) + r"_\d+\.legacy\.bak", migrate_res['backup_path']), None)
+        assert_equal(os.path.exists(migrate_res['backup_path']), True)
 
         wallet = self.master_node.get_wallet_rpc(wallet_ending_in_rel_path)
         info = wallet.getwalletinfo()
@@ -598,9 +599,8 @@ class WalletMigrationTest(BitcoinTestFramework):
 
         wallet_path = f"{self.old_node.wallets_path}/{wallet_name}"
         migrate_res = self.master_node.migratewallet(wallet_path)
-        expected_backup_path = self.master_node.wallets_path / f"{final_dir}_{int(time.time())}.legacy.bak"
-        os.path.exists(expected_backup_path)
-        assert_equal(f"{expected_backup_path}", migrate_res['backup_path'])
+        assert_not_equal(re.fullmatch(re.escape(str(self.master_node.wallets_path / final_dir)) + r"_\d+\.legacy\.bak", migrate_res['backup_path']), None)
+        assert_equal(os.path.exists(migrate_res['backup_path']), True)
 
         wallet = self.master_node.get_wallet_rpc(wallet_path)
 
```
</p>
</details>





Code after:
        self.generate(self.master_node, 1)
        bals = wallet.getbalances()

        wallet.unloadwallet()

        wallet_file_path = self.old_node.wallets_path / "notloaded2"
        self.master_node.migratewallet(wallet_file_path)

        # Because we gave the name by full path, the loaded wallet's name is that path too.
        wallet = self.master_node.get_wallet_rpc(str(wallet_file_path))

        info = wallet.getwalletinfo()
        assert_equal(info["descriptors"], True)
        assert_equal(info["format"], "sqlite")
        wallet.gettransaction(txid)

        assert_equal(bals, wallet.getbalances())

    def test_wallet_with_relative_path(self):
        self.log.info("Test migration of a wallet that isn't loaded, specified by a relative path")

        # Get the nearest common path of both nodes' wallet paths.
        common_parent = os.path.commonpath([self.master_node.wallets_path, self.old_node.wallets_path])

        # This test assumes that the relative path from each wallet directory to the common path is identical.
        assert_equal(os.path.relpath(common_parent, start=self.master_node.wallets_path), os.path.relpath(common_parent, start=self.old_node.wallets_path))

        wallet_name = "relative"
        absolute_path = os.path.abspath(os.path.join(common_parent, wallet_name))
        relative_name = os.path.relpath(absolute_path, start=self.master_node.wallets_path)

        wallet = self.create_legacy_wallet(relative_name)
        # listwalletdirs only returns wallets in the wallet directory
        assert {"name": relative_name} not in wallet.listwalletdir()["wallets"]
        assert relative_name in wallet.listwallets()

        default = self.master_node.get_wallet_rpc(self.default_wallet_name)
        addr = wallet.getnewaddress()
        txid = default.sendtoaddress(addr, 1)
        self.generate(self.master_node, 1)
        bals = wallet.getbalances()

        # migratewallet uses current time in naming the backup file, set a mock time
        # to check that this works correctly.
        curr_time = int(time.time())
        self.master_node.setmocktime(curr_time)
        migrate_res, wallet = self.migrate_and_get_rpc(relative_name)
        self.master_node.setmocktime(0)

        # Check that the wallet was migrated, knows the right txid, and has the right balance.
        assert wallet.gettransaction(txid)