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

Code before:
            start_expecting_error(err_fragment)

            for dir in dirs:
                shutil.rmtree(node.chain_path / dir)
                shutil.move(node.chain_path / f"{dir}_bak", node.chain_path / dir)

    def init_pid_test(self):
        BITCOIN_PID_FILENAME_CUSTOM = "my_fancy_bitcoin_pid_file.foobar"

        self.log.info("Test specifying custom pid file via -pid command line option")
        custom_pidfile_relative = BITCOIN_PID_FILENAME_CUSTOM
        self.log.info(f"-> path relative to datadir ({custom_pidfile_relative})")
        self.restart_node(0, [f"-pid={custom_pidfile_relative}"])
        datadir = self.nodes[0].chain_path
        assert not (datadir / BITCOIN_PID_FILENAME_DEFAULT).exists()
        assert (datadir / custom_pidfile_relative).exists()
        self.stop_node(0)
        assert not (datadir / custom_pidfile_relative).exists()

        custom_pidfile_absolute = Path(self.options.tmpdir) / BITCOIN_PID_FILENAME_CUSTOM
        self.log.info(f"-> absolute path ({custom_pidfile_absolute})")
        self.restart_node(0, [f"-pid={custom_pidfile_absolute}"])
        assert not (datadir / BITCOIN_PID_FILENAME_DEFAULT).exists()
        assert custom_pidfile_absolute.exists()
        self.stop_node(0)
        assert not custom_pidfile_absolute.exists()

    def run_test(self):
        self.init_pid_test()
        self.init_stress_test()


if __name__ == '__main__':
    InitTest(__file__).main()


Review comment (suggestion):
nit: It might be good to send in the same `startup_args` to `check_clean_start()` further down in the loop?
https://github.com/bitcoin/bitcoin/blob/e36e0b1aebe437c090ff897d27bbec0a7c5a100a/test/functional/feature_init.py#L192

(Side remark: It is unbalanced that we don't call `check_clean_start()` at the bottom of the perturbation-loop, but saves execution time and should be alright as we check for different error messages).

Code after:
            {
                'filepath_glob': 'indexes/txindex/*.log',
                'error_message': 'LevelDB error: Corruption',
                'startup_args': ['-txindex=1'],
            },
            {
                'filepath_glob': 'indexes/txindex/CURRENT',
                'error_message': 'LevelDB error: Corruption',
                'startup_args': ['-txindex=1'],
            },
            # Perturbing these files does not result in a startup error:
            # 'indexes/blockfilter/basic/*.dat', 'indexes/txindex/MANIFEST*', 'indexes/txindex/LOCK'
        ]

        for round_info in deletion_rounds:
            file_patt = round_info['filepath_glob']
            err_fragment = round_info['error_message']
            startup_args = round_info['startup_args']
            target_files = list(node.chain_path.glob(file_patt))

            for target_file in target_files:
                self.log.info(f"Deleting file to ensure failure {target_file}")
                bak_path = str(target_file) + ".bak"
                target_file.rename(bak_path)

            start_expecting_error(err_fragment, startup_args)

            for target_file in target_files:
                bak_path = str(target_file) + ".bak"
                self.log.debug(f"Restoring file from {bak_path} and restarting")
                Path(bak_path).rename(target_file)

            check_clean_start(args)
            self.stop_node(0)

        self.log.info("Test startup errors after perturbing certain essential files")
        dirs = ["blocks", "chainstate", "indexes"]
        for round_info in perturbation_rounds:
            file_patt = round_info['filepath_glob']
            err_fragment = round_info['error_message']
            startup_args = round_info['startup_args']

            for dir in dirs:
                shutil.copytree(node.chain_path / dir, node.chain_path / f"{dir}_bak")
            target_files = list(node.chain_path.glob(file_patt))

            for target_file in target_files:
                self.log.info(f"Perturbing file to ensure failure {target_file}")
                with open(target_file, "r+b") as tf:
                    # Since the genesis block is not checked by -checkblocks, the
                    # perturbation window must be chosen such that a higher block