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

Code before:
        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()
        wallet.unloadwallet()

        # 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 = self.master_node.migratewallet(relative_name)
        self.master_node.setmocktime(0)

        # Check that the wallet was migrated, knows the right txid, and has the right balance.
        wallet = self.master_node.get_wallet_rpc(relative_name)
        assert wallet.gettransaction(txid)
        assert_equal(bals, wallet.getbalances())

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

        # The migrated wallet should not be in the wallet dir, but should be in the list of wallets.
        walletlist = wallet.listwallets()
        walletdirlist = wallet.listwalletdir()
        assert {"name": info["walletname"]} not in walletdirlist["wallets"]
        assert info["walletname"] in walletlist

        # Check that backup exists where expected and isn't in the wallet list.
        backup_filename = f"{wallet_name}_{curr_time}.legacy.bak"
        backup_path = os.path.join(common_parent, wallet_name, backup_filename)
        assert os.path.exists(backup_path)
        assert_equal(os.path.realpath(backup_path), os.path.realpath(migrate_res['backup_path']))
        assert {"name": backup_filename} not in walletdirlist["wallets"]

        # Check that old node can restore from the backup.
        self.old_node.restorewallet("relative_restored", migrate_res['backup_path'])
        wallet = self.old_node.get_wallet_rpc("relative_restored")
        assert wallet.gettransaction(txid)
        assert_equal(bals, wallet.getbalances())

        info = wallet.getwalletinfo()
        assert_equal(info["descriptors"], False)
        assert_equal(info["format"], "bdb")


Review comment (bug):
If this assumption ever fails (say due to environment setup differences), the test will break early.
Consider failing gracefully with a more informative message:

```
assert_equal(..., ..., "Relative paths from wallet dirs to common parent must be identical for this test.")
```

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)