def test_access_wallet_with_bad_data(self): ''' Test access wallet with bad data ''' MINUTE = 60 WAIT_SECONDS = 10 MAX_SECONDS = 3 * MINUTE # remove a block from the blockchain block_filename = os.path.join(get_data_dir(), 'blocks', 'blk00000.dat') if os.path.exists(block_filename): os.remove(block_filename) request = self.factory.get('/bitcoin/access_wallet/') response = AccessWallet.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nAccessing Bitcoin Core Wallet | Blockchain Backup\n</title>" in response.content) self.assertTrue( b"WARNING: Do not shut down your computer until Bitcoin-QT stops completely." in response.content) self.assertTrue( b'Bitcoin-QT will start in another window.' in response.content) self.assertFalse( b'Shutting down before this window says it is safe <em>could damage the blockchain</em>.' in response.content) done = False error_found = False error_message = None secs = 0 while not done: shutdown, error_message = test_utils.check_bitcoin_log() if error_message: error = error_message.strip(' ') error_found = 'Fatal LevelDB error' in error or 'Error opening block database' in error done = shutdown or error_found or not get_backups_enabled( ) or secs > MAX_SECONDS if not done: sleep(WAIT_SECONDS) secs += WAIT_SECONDS if not error_found: shutdown, error_message = test_utils.check_bitcoin_log() self.assertTrue(shutdown) error = error_message.strip(' ') error_found = 'Fatal LevelDB error' in error or 'Error opening block database' in error self.assertTrue(error_found) test_utils.stop_bitcoin_qt() self.assertFalse(get_backups_enabled())
def test_update_with_task_running(self): ''' Test updating with another task running. ''' # start the backup task request = self.factory.get('/bitcoin/backup/') Backup.as_view()(request) request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) # stop the task before we start tests in case something fails self.factory.get('/bitcoin/interrupt_backup/') InterruptBackup.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nBackup Task Is Running | Blockchain Backup\n</title>" in response.content) self.assertTrue( b'The backup task appears to be running' in response.content) self.assertFalse( b'The update task appears to be running' in response.content) self.assertFalse(b'The access wallet task appears to be running' in response.content) self.assertFalse( b'The restore task appears to be running' in response.content) self.assertTrue(get_backups_enabled())
def test_update_with_bitcoin_d_running(self): ''' Test updating with bitcoind already running. ''' # start bitcoind and wait for it to get started test_utils.start_bitcoind() while not is_bitcoind_running(): sleep(1) log('bitcoind is running') request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nBitcoinD Is Running | Blockchain Backup\n</title>" in response.content) self.assertTrue( b'BitcoinD, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse( b'Bitcoin-QT, one of the Bitcoin Core programs, appears to be running' in response.content) self.assertFalse( b'Bitcoin-TX, one of the Bitcoin Core programs, appears to be running' in response.content) if is_bitcoind_running(): test_utils.stop_bitcoind() self.assertTrue(get_backups_enabled())
def test_update_with_bad_data_dir(self): ''' Test updating with a bad data directory. ''' prefs = get_preferences() prefs.data_dir = '/bad/bitcoin/data/' prefs.bin_dir = '/tmp/bitcoin/bin/' prefs.backup_dir = '/tmp/bitcoin/data/backups/' save_preferences(prefs) request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nUpdating Bitcoin's Blockchain | Blockchain Backup\n</title>" in response.content) self.assertFalse( b'The Bitcoin binary directory is not valid.' in response.content) self.assertTrue( b'The Bitcoin data directory is not valid.' in response.content) self.assertFalse( b'The Bitcoin backup directory is not valid.' in response.content) self.assertTrue( b'Click <a class="btn btn-secondary" role="button" href="/bitcoin/preferences/" title="Click to change your preferences">Preferences</a> to set it.' in response.content) self.assertTrue(get_backups_enabled())
def post_page(self, request): backups_enabled = ('enable-backups-button' in request.POST or 'leave-backups-enabled-button' in request.POST) if state.get_backups_enabled() != backups_enabled: state.set_backups_enabled(backups_enabled) if backups_enabled: messages.success(request, BACKUPS_ENABLED) else: messages.success(request, BACKUPS_DISABLED) # send them back to the home page response = HttpResponseRedirect('/') return response
def test_restore_with_bad_backup(self): ''' Test restore from a bad back up. ''' MINUTE = 60 MAX_SECONDS = 2 * MINUTE # change the data and backup dirs prefs = test_utils.get_preferences() prefs.data_dir = '/tmp/bitcoin/data-with-missing-file/testnet3/' prefs.backup_dir = '/tmp/bitcoin/data-with-missing-file/testnet3/backups/' preferences.save_preferences(prefs) __, preselected_date_dir = state.get_backup_dates_and_dirs() request = self.factory.get('/bitcoin/restore/') response = views.Restore.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue(b"<title>\nAre you sure you want to restore the Bitcoin blockchain? | Blockchain Backup\n</title>" in response.content) self.assertTrue(b'Select backup to restore:' in response.content) self.assertTrue(b'<input type="submit" value="Yes, start restoring" name="yes-start-restoring-button" id="yes-start-restoring-id" alt="Yes, start restoring" class="btn btn-primary font-weight-bold " role="button" title="Restore the blockchain now"/>' in response.content) self.assertTrue(b'<input type="submit" value="No, cancel restore" name="no-cancel-restore-button" id="no-cancel-restore-id" alt="No, cancel restore" class="btn btn-secondary font-weight-bold " role="button" title="Do not restore the blockchain."/>' in response.content) client = Client() response = client.post('/bitcoin/restore/', {'backup_dates_with_dirs': preselected_date_dir[0] }) self.assertEqual(response.status_code, 200) self.assertTrue(b"<title>\nRestoring Bitcoin Blockchain | Blockchain Backup\n</title>" in response.content) self.assertTrue(b'WARNING: Do not shut down your computer until the restore finishes.' in response.content) self.assertTrue(b'Starting to restore the blockchain' in response.content) self.assertFalse(b'<input type="submit" value="Yes, start restoring" name="yes-start-restoring-button" id="yes-start-restoring-id" alt="Yes, start restoring" class="btn btn-primary font-weight-bold " role="button" title="Restore the blockchain now"/>' in response.content) # wait until the restore finishes seconds = 0 while not is_restore_running() and seconds < MAX_SECONDS: sleep(MINUTE) seconds += MINUTE self.assertFalse(is_bitcoind_running()) self.assertFalse(state.get_backups_enabled()) name = 'last-updated-2020-01-17 14:41' last_updated_file = os.path.join(prefs.backup_dir, 'level1', name) self.assertFalse(os.path.exists(last_updated_file))
def test_update_with_missing_links(self): ''' Start the update with missing links. ''' # remove links from the chainstate dirname = os.path.join(get_data_dir(), 'chainstate') entries = os.scandir(dirname) for entry in entries: if entry.name.endswith('.ldb'): os.remove(entry.path) request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nUpdating Bitcoin's Blockchain | Blockchain Backup\n</title>" in response.content) self.assertTrue(b"WARNING: Don't shut down your computer before you" in response.content) self.assertTrue( b'<a class="btn btn-secondary " role="button" id="stop_button" href="/bitcoin/interrupt_update/" title="Click to stop updating the blockchain">Stop update</a>' in response.content) self.assertTrue( b'Shutting down before this window says it is safe <em>could damage the blockchain</em>.' in response.content) sleep(60) self.assertFalse(is_bitcoind_running()) shutdown, error_message = test_utils.check_bitcoin_log( is_bitcoind_running) self.assertTrue(shutdown) log(error_message) self.assertTrue( 'Aborted block database rebuild. Exiting.' in error_message or 'Error opening block database.' in error_message or 'Fatal LevelDB error' in error_message) self.assertFalse(get_backups_enabled())
def get_page(self, request): log('change whether backups enabled or not') clear_action_updates() form = Form() context = {} backups_enabled = state.get_backups_enabled() if backups_enabled: context[ 'header'] = 'Blockchain Backup currently backups the blockchain on your schedule.' context[ 'notice'] = 'WARNING: If you disable backups, then Blockchain Backup cannot keep your copy of the blockchain safe.' context['status'] = 'Enabled' else: context[ 'header'] = 'Blockchain Backup temporarily disabled backups the blockchain.' context[ 'notice'] = 'WARNING: Do <i>not</i> enable backups until Bitcoin Core runs successfully.' context['status'] = 'Disabled' context['header'] = f"Backups {context['status']}" context['form'] = form return render(request, self.form_url, context=context)
def test_update_with_missing_blocks(self): ''' Start the update with missing blocks. ''' # remove a block from the blockchain block_filename = os.path.join(get_data_dir(), 'blocks', 'blk00000.dat') if os.path.exists(block_filename): os.remove(block_filename) request = self.factory.get('/bitcoin/update/') response = Update.as_view()(request) self.assertEqual(response.status_code, 200) self.assertTrue( b"<title>\nUpdating Bitcoin's Blockchain | Blockchain Backup\n</title>" in response.content) self.assertTrue(b"WARNING: Don't shut down your computer before you" in response.content) self.assertTrue( b'<a class="btn btn-secondary " role="button" id="stop_button" href="/bitcoin/interrupt_update/" title="Click to stop updating the blockchain">Stop update</a>' in response.content) self.assertTrue( b'Shutting down before this window says it is safe <em>could damage the blockchain</em>.' in response.content) sleep(60) self.assertFalse(is_bitcoind_running()) shutdown, error_message = test_utils.check_bitcoin_log( is_bitcoind_running) self.assertTrue(shutdown) error = error_message.strip(' ') error_found = 'Fatal LevelDB error' in error or 'Error opening block database' in error self.assertTrue(error_found) self.assertFalse(get_backups_enabled())
def get_page(self, request): global backup_task log('backing up blockchain') clear_action_updates() # check that no other bitcoin-core app is running if bitcoin_utils.is_bitcoin_core_running(): message = NO_BACKUP_IF_CORE_RUNNING response = warn_core_running(request, message=message) # tell user if another app is running elif bitcoin_utils.is_restore_running(): response = warn_bcb_app_running(request, app=constants.RESTORE_PROGRAM) # tell user if another task is running elif accessing_wallet() or updating() or restoring(): response = warn_bcb_task_running(request) # tell user if backups have been disabled elif not state.get_backups_enabled(): response = HttpResponseRedirect('/bitcoin/change_backup_status/') log('tried to backup when backups disabled') log(f'response: {response}') else: SUBNOTICE1 = 'If you need to stop the backup, then <a class="btn btn-secondary " href="/bitcoin/interrupt_backup/"' SUBNOTICE2 = 'role="button" id="stop-button" title="Click to stop backing up the blockchain">click here</a>.' SUBNOTICE = f'{SUBNOTICE1} {SUBNOTICE2}' context = bitcoin_utils.get_blockchain_context() data_dir_ok, error = preferences.data_dir_ok() if not preferences.bin_dir_ok(): context['notice'] = BAD_BIN_DIR context['subnotice'] = '' elif not data_dir_ok: context['notice'] = BAD_DATA_DIR context['subnotice'] = error else: context['header'] = "Backing up bitcoin's blockchain" context[ 'notice'] = 'WARNING: Stopping the backup could damage the ability to restore the blockchain.' context['subnotice'] = SUBNOTICE context['progress'] = 'Starting to back up the blockchain' context['update_interval'] = '1000' if backing_up(): log('already backing_up blockchain') else: from blockchain_backup.bitcoin.backup import BackupTask backup_task = BackupTask() backup_task.start() log('backup started') # make sure the button doesn't appear any more bitcoin_utils.send_socketio_message('button', ' ') response = render(request, 'bitcoin/backup.html', context=context) return response