def init_db(qapp): vorta.models.db.drop_tables(models) vorta.models.init_db() new_repo = RepoModel(url='[email protected]:repo') new_repo.save() profile = BackupProfileModel.get(id=1) profile.repo = new_repo.id profile.save() test_archive = ArchiveModel(snapshot_id='99999', name='test-archive', time=dt(2000, 1, 1, 0, 0), repo=1) test_archive.save() test_archive1 = ArchiveModel(snapshot_id='99998', name='test-archive1', time=dt(2000, 1, 1, 0, 0), repo=1) test_archive1.save() source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo) source_dir.save() qapp.open_main_window_action()
def app(tmpdir, qtbot, mocker): tmp_db = tmpdir.join('settings.sqlite') mock_db = peewee.SqliteDatabase(str(tmp_db)) vorta.models.init_db(mock_db) mocker.patch.object(vorta.application.VortaApp, 'set_borg_details_action', return_value=None) new_repo = RepoModel(url='[email protected]:repo') new_repo.save() profile = BackupProfileModel.get(id=1) profile.repo = new_repo.id profile.save() test_archive = ArchiveModel(snapshot_id='99999', name='test-archive', time=dt(2000, 1, 1, 0, 0), repo=1) test_archive.save() source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo) source_dir.save() app = VortaApp([]) app.open_main_window_action() qtbot.addWidget(app.main_window) app.main_window.tests_running = True return app
def app(tmpdir, qtbot): tmp_db = tmpdir.join('settings.sqlite') mock_db = peewee.SqliteDatabase(str(tmp_db)) vorta.models.init_db(mock_db) new_repo = RepoModel(url='[email protected]:repo') new_repo.save() profile = BackupProfileModel.get(id=1) profile.repo = new_repo.id profile.save() test_archive = ArchiveModel(snapshot_id='99999', name='test-archive', time=dt(2000, 1, 1, 0, 0), repo=1) test_archive.save() source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo) source_dir.save() app = VortaApp([]) app.main_window.show() qtbot.addWidget(app.main_window) return app
def init_db(qapp): vorta.models.db.drop_tables(models) vorta.models.init_db() new_repo = RepoModel(url='[email protected]:repo') new_repo.encryption = 'none' new_repo.save() profile = BackupProfileModel.get(id=1) profile.repo = new_repo.id profile.dont_run_on_metered_networks = False profile.save() test_archive = ArchiveModel(snapshot_id='99999', name='test-archive', time=dt(2000, 1, 1, 0, 0), repo=1) test_archive.save() test_archive1 = ArchiveModel(snapshot_id='99998', name='test-archive1', time=dt(2000, 1, 1, 0, 0), repo=1) test_archive1.save() source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo, dir_size=100, dir_files_count=18, path_isdir=True) source_dir.save() qapp.main_window = MainWindow( qapp) # Re-open main window to apply mock data in UI
def from_db(cls, profile, store_password=True, include_settings=True): profile_dict = model_to_dict(profile, exclude=[RepoModel.id]) # Have to retain profile ID keyring = VortaKeyring.get_keyring() if store_password: profile_dict['password'] = keyring.get_password('vorta-repo', profile.repo.url) # For all below, exclude ids to prevent collisions. DB will automatically reassign ids # Add SourceFileModel profile_dict['SourceFileModel'] = [ model_to_dict( source, recurse=False, exclude=[SourceFileModel.id]) for source in SourceFileModel.select().where( SourceFileModel.profile == profile)] # Add SchemaVersion profile_dict['SchemaVersion'] = model_to_dict(SchemaVersion.get(id=1)) if include_settings: # Add WifiSettingModel profile_dict['WifiSettingModel'] = [ model_to_dict( wifi, recurse=False) for wifi in WifiSettingModel.select().where( WifiSettingModel.profile == profile.id)] # Add SettingsModel profile_dict['SettingsModel'] = [ model_to_dict(s, exclude=[SettingsModel.id]) for s in SettingsModel] return ProfileExport(profile_dict)
def init_db(qapp, qtbot, tmpdir_factory): tmp_db = tmpdir_factory.mktemp('Vorta').join('settings.sqlite') mock_db = peewee.SqliteDatabase(str(tmp_db), pragmas={ 'journal_mode': 'wal', }) vorta.models.init_db(mock_db) default_profile = BackupProfileModel(name='Default') default_profile.save() new_repo = RepoModel(url='[email protected]:repo') new_repo.encryption = 'none' new_repo.save() default_profile.repo = new_repo.id default_profile.dont_run_on_metered_networks = False default_profile.save() test_archive = ArchiveModel(snapshot_id='99999', name='test-archive', time=dt(2000, 1, 1, 0, 0), repo=1) test_archive.save() test_archive1 = ArchiveModel(snapshot_id='99998', name='test-archive1', time=dt(2000, 1, 1, 0, 0), repo=1) test_archive1.save() source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo, dir_size=100, dir_files_count=18, path_isdir=True) source_dir.save() qapp.main_window.deleteLater() del qapp.main_window qapp.main_window = MainWindow( qapp) # Re-open main window to apply mock data in UI yield qapp.backup_cancelled_event.emit() qtbot.waitUntil(lambda: not vorta.borg.borg_thread.BorgThread.is_running()) mock_db.close()
def test_import_bootstrap_success(qapp, mocker): mocked_unlink = mocker.MagicMock() mocker.patch.object(Path, 'unlink', mocked_unlink) qapp.bootstrap_profile(Path(VALID_IMPORT_FILE)) assert mocked_unlink.called restored_profile = BackupProfileModel.get_or_none( name="Test Profile Restoration") assert restored_profile is not None restored_repo = restored_profile.repo assert restored_repo is not None assert len(SourceFileModel.select().where( SourceFileModel.profile == restored_profile)) == 3 assert BackupProfileModel.select().count() == 2
def test_import_success(qapp, qtbot, rootdir, monkeypatch): monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args: [VALID_IMPORT_FILE]) monkeypatch.setattr(QMessageBox, 'information', lambda *args: None) main = qapp.main_window main.profile_import_action() import_dialog: ImportWindow = main.window import_dialog.overwriteExistingSettings.setChecked(True) qtbot.mouseClick(import_dialog.buttonBox.button(QDialogButtonBox.Ok), QtCore.Qt.LeftButton) qtbot.waitSignal(import_dialog.profile_imported, **pytest._wait_defaults) restored_profile = BackupProfileModel.get_or_none( name="Test Profile Restoration") assert restored_profile is not None restored_repo = restored_profile.repo assert restored_repo is not None assert len(SourceFileModel.select().where( SourceFileModel.profile == restored_profile)) == 3
def to_db(self, overwrite_profile=False, overwrite_settings=True): profile_schema = self._profile_dict['SchemaVersion']['version'] keyring = VortaKeyring.get_keyring() if SCHEMA_VERSION < profile_schema: raise VersionException() elif SCHEMA_VERSION > profile_schema: # Add model upgrading code here, only needed if not adding columns if profile_schema < 16: for sourcedir in self._profile_dict['SourceFileModel']: sourcedir['dir_files_count'] = -1 sourcedir['dir_size'] = -1 sourcedir['path_isdir'] = False existing_profile = None if overwrite_profile: existing_profile = BackupProfileModel.get_or_none(BackupProfileModel.name == self.name) if existing_profile: self._profile_dict['id'] = existing_profile.id if not overwrite_profile or not existing_profile: # Guarantee uniqueness of ids while BackupProfileModel.get_or_none(BackupProfileModel.id == self.id) is not None: self._profile_dict['id'] += 1 # Add suffix incase names are the same if BackupProfileModel.get_or_none(BackupProfileModel.name == self.name) is not None: suffix = 1 while BackupProfileModel.get_or_none(BackupProfileModel.name == f"{self.name}-{suffix}") is not None: suffix += 1 self._profile_dict['name'] = f"{self.name}-{suffix}" # Load existing repo or restore it if self._profile_dict['repo']: repo = RepoModel.get_or_none(RepoModel.url == self.repo_url) if repo is None: # Load repo from export repo = dict_to_model(RepoModel, self._profile_dict['repo']) repo.save(force_insert=True) self._profile_dict['repo'] = model_to_dict(repo) if self.repo_password: keyring.set_password('vorta-repo', self.repo_url, self.repo_password) del self._profile_dict['password'] # Delete and recreate the tables to clear them if overwrite_settings: db.drop_tables([SettingsModel, WifiSettingModel]) db.create_tables([SettingsModel, WifiSettingModel]) SettingsModel.insert_many(self._profile_dict['SettingsModel']).execute() WifiSettingModel.insert_many(self._profile_dict['WifiSettingModel']).execute() # Set the profile ids to be match new profile for source in self._profile_dict['SourceFileModel']: source['profile'] = self.id SourceFileModel.insert_many(self._profile_dict['SourceFileModel']).execute() # Delete added dictionaries to make it match BackupProfileModel del self._profile_dict['SettingsModel'] del self._profile_dict['SourceFileModel'] del self._profile_dict['WifiSettingModel'] del self._profile_dict['SchemaVersion'] # dict to profile new_profile = dict_to_model(BackupProfileModel, self._profile_dict) if overwrite_profile and existing_profile: force_insert = False else: force_insert = True new_profile.save(force_insert=force_insert) init_db() # rerun db init code to perform the same operations on the new as as on application boot return new_profile
def prepare(cls, profile): """ `borg create` is called from different places and needs some preparation. Centralize it here and return the required arguments to the caller. """ ret = super().prepare(profile) if not ret['ok']: return ret else: ret['ok'] = False # Set back to False, so we can do our own checks here. n_backup_folders = SourceFileModel.select().count() if n_backup_folders == 0: ret['message'] = trans_late('messages', 'Add some folders to back up first.') return ret network_status_monitor = get_network_status_monitor() current_wifi = network_status_monitor.get_current_wifi() if current_wifi is not None: wifi_is_disallowed = WifiSettingModel.select().where( (WifiSettingModel.ssid == current_wifi) & ( WifiSettingModel.allowed == False # noqa ) & (WifiSettingModel.profile == profile)) if wifi_is_disallowed.count() > 0 and profile.repo.is_remote_repo( ): ret['message'] = trans_late('messages', 'Current Wifi is not allowed.') return ret if profile.repo.is_remote_repo() and profile.dont_run_on_metered_networks \ and network_status_monitor.is_network_metered(): ret['message'] = trans_late( 'messages', 'Not running backup over metered connection.') return ret ret['profile'] = profile ret['repo'] = profile.repo # Run user-supplied pre-backup command if cls.pre_post_backup_cmd(ret) != 0: ret['message'] = trans_late( 'messages', 'Pre-backup command returned non-zero exit code.') return ret if not profile.repo.is_remote_repo() and not os.path.exists( profile.repo.url): ret['message'] = trans_late('messages', 'Repo folder not mounted or moved.') return ret if 'zstd' in profile.compression and not borg_compat.check('ZSTD'): ret['message'] = trans_late( 'messages', 'Your current Borg version does not support ZStd compression.') return ret cmd = [ 'borg', 'create', '--list', '--progress', '--info', '--log-json', '--json', '--filter=AM', '-C', profile.compression, ] # Add excludes # Partly inspired by borgmatic/borgmatic/borg/create.py if profile.exclude_patterns is not None: exclude_dirs = [] for p in profile.exclude_patterns.split('\n'): if p.strip(): expanded_directory = os.path.expanduser(p.strip()) exclude_dirs.append(expanded_directory) if exclude_dirs: pattern_file = tempfile.NamedTemporaryFile('w', delete=False) pattern_file.write('\n'.join(exclude_dirs)) pattern_file.flush() cmd.extend(['--exclude-from', pattern_file.name]) if profile.exclude_if_present is not None: for f in profile.exclude_if_present.split('\n'): if f.strip(): cmd.extend(['--exclude-if-present', f.strip()]) # Add repo url and source dirs. new_archive_name = format_archive_name(profile, profile.new_archive_name) cmd.append(f"{profile.repo.url}::{new_archive_name}") for f in SourceFileModel.select().where( SourceFileModel.profile == profile.id): cmd.append(f.dir) ret['message'] = trans_late('messages', 'Starting backup...') ret['ok'] = True ret['cmd'] = cmd return ret