def test_notify_level(config_name): start_maestral_daemon_process(config_name, timeout=20) m = MaestralProxy(config_name) runner = CliRunner() result = runner.invoke(main, ["notify", "level", "-c", m.config_name]) level_name = level_number_to_name(m.notification_level) assert result.exit_code == 0 assert level_name in result.output level_name = "SYNCISSUE" level_number = level_name_to_number(level_name) result = runner.invoke( main, ["notify", "level", level_name, "-c", m.config_name]) assert result.exit_code == 0 assert level_name in result.output assert m.notification_level == level_number result = runner.invoke(main, ["notify", "level", "INVALID", "-c", m.config_name]) assert result.exit_code == 2 assert isinstance(result.exception, SystemExit)
def test_remote_exceptions(config_name): # start daemon process start_maestral_daemon_process(config_name, timeout=20) # create proxy and call a remote method which raises an error with MaestralProxy(config_name) as m: with pytest.raises(NotLinkedError): m.get_account_info() # stop daemon stop_maestral_daemon_process(config_name)
def test_remote_exceptions(self): # start daemon process start_maestral_daemon_process(self.config_name) # create proxy and call a remote method which raises an error with MaestralProxy(self.config_name) as m: with self.assertRaises(NotLinkedError): m.get_account_info() # stop daemon stop_maestral_daemon_process(self.config_name) # clean up config remove_configuration(self.config_name)
def test_notify_snooze(config_name): start_maestral_daemon_process(config_name, timeout=20) m = MaestralProxy(config_name) runner = CliRunner() result = runner.invoke(main, ["notify", "snooze", "20", "-c", m.config_name]) assert result.exit_code == 0 assert 0 < m.notification_snooze <= 20 result = runner.invoke(main, ["notify", "snooze", "0", "-c", m.config_name]) assert result.exit_code == 0 assert m.notification_snooze == 0
def test_stop(config_name): res = start_maestral_daemon_process(config_name, timeout=20) assert res is Start.Ok runner = CliRunner() result = runner.invoke(main, ["stop", "-c", config_name]) assert result.exit_code == 0
def test_start(config_name): res = start_maestral_daemon_process(config_name, timeout=20) assert res is Start.Ok runner = CliRunner() result = runner.invoke(main, ["start", "-c", config_name]) assert result.exit_code == 0, result.output assert "already running" in result.output
def start_daemon_subprocess_with_cli_feedback(config_name): """Wrapper around `daemon.start_maestral_daemon_process` with command line feedback.""" from maestral.daemon import start_maestral_daemon_process, Start click.echo('Starting Maestral...', nl=False) res = start_maestral_daemon_process(config_name) if res == Start.Ok: click.echo('\rStarting Maestral... ' + OK) else: click.echo('\rStarting Maestral... ' + FAILED)
def test_lifecycle(config_name): # start daemon process res = start_maestral_daemon_process(config_name, timeout=20) assert res is Start.Ok # retry start daemon process res = start_maestral_daemon_process(config_name, timeout=20) assert res is Start.AlreadyRunning # retry start daemon in-process with pytest.raises(RuntimeError): start_maestral_daemon(config_name) # stop daemon res = stop_maestral_daemon_process(config_name) assert res is Stop.Ok # retry stop daemon res = stop_maestral_daemon_process(config_name) assert res is Stop.NotRunning
def test_lifecycle_detached(self): # start daemon process res = start_maestral_daemon_process(self.config_name) self.assertEqual(res, Start.Ok) # retry start daemon process res = start_maestral_daemon_process(self.config_name) self.assertEqual(res, Start.AlreadyRunning) # retry start daemon in-process with self.assertRaises(RuntimeError): start_maestral_daemon(self.config_name) # stop daemon res = stop_maestral_daemon_process(self.config_name) self.assertEqual(res, Stop.Ok) # retry stop daemon res = stop_maestral_daemon_process(self.config_name) self.assertEqual(res, Stop.NotRunning) # clean up config remove_configuration(self.config_name)
def test_connection(config_name): # start daemon process res = start_maestral_daemon_process(config_name, timeout=20) assert res is Start.Ok # create proxy with MaestralProxy(config_name) as m: assert m.config_name == config_name assert not m._is_fallback assert isinstance(m._m, Proxy) # stop daemon res = stop_maestral_daemon_process(config_name) assert res is Stop.Ok
def test_lifecycle_attached(config_name): # start daemon process res = start_maestral_daemon_process(config_name, detach=False) assert res is Start.Ok # check that we have attached process ctx = mp.get_context("spawn" if IS_MACOS else "fork") daemon = ctx.active_children()[0] assert daemon.name == "maestral-daemon" # stop daemon res = stop_maestral_daemon_process(config_name) assert res is Stop.Ok # retry stop daemon res = stop_maestral_daemon_process(config_name) assert res is Stop.NotRunning
def test_connection(self): # start daemon process res = start_maestral_daemon_process(self.config_name) self.assertEqual(Start.Ok, res) # create proxy with MaestralProxy(self.config_name) as m: self.assertEqual(m.config_name, self.config_name) self.assertFalse(m._is_fallback) self.assertIsInstance(m._m, Proxy) # stop daemon res = stop_maestral_daemon_process(self.config_name) self.assertEqual(res, Stop.Ok) # clean up config remove_configuration(self.config_name)
def get_or_start_maestral_daemon(self) -> MaestralProxy: res = start_maestral_daemon_process(self.config_name) if res == Start.Failed: title = "Could not start Maestral" message = ( "Could not start or connect to sync daemon. Please try again " "and contact the developer if this issue persists.") self.alert(title, message, level="error") stop_maestral_daemon_process(self.config_name) super().exit() elif res == Start.AlreadyRunning: self._started = False elif res == Start.Ok: self._started = True return MaestralProxy(self.config_name)
def test_lifecycle_attached(self): # start daemon process res = start_maestral_daemon_process(self.config_name, detach=False) self.assertEqual(res, Start.Ok) # check that we have attached process ctx = mp.get_context("spawn" if IS_MACOS else "fork") daemon = ctx.active_children()[0] self.assertEqual(daemon.name, "maestral-daemon") # stop daemon res = stop_maestral_daemon_process(self.config_name) self.assertEqual(res, Stop.Ok) # retry stop daemon res = stop_maestral_daemon_process(self.config_name) self.assertEqual(res, Stop.NotRunning) # clean up config remove_configuration(self.config_name)
def _get_or_start_maestral_daemon(self): pid = get_maestral_pid(self.config_name) if pid: self._started = False else: if IS_MACOS_BUNDLE: res = start_maestral_daemon_thread(self.config_name) else: res = start_maestral_daemon_process(self.config_name) if res == Start.Failed: title = 'Could not start Maestral' message = ('Could not start or connect to sync daemon. Please try again ' 'and contact the developer if this issue persists.') show_dialog(title, message, level='error') self.quit() elif res == Start.AlreadyRunning: self._started = False elif res == Start.Ok: self._started = True return get_maestral_proxy(self.config_name)
def proxy(m): m.stop_sync() start_maestral_daemon_process(m.config_name, timeout=20) yield MaestralProxy(m.config_name) stop_maestral_daemon_process(m.config_name)
def start(foreground: bool, verbose: bool, config_name: str) -> None: # ---- run setup if necessary ------------------------------------------------------ # We run the setup in the current process. This avoids starting a subprocess despite # running with the --foreground flag, prevents leaving a zombie process if the setup # fails with an exception and does not confuse systemd. from maestral.main import Maestral m = Maestral(config_name, log_to_stdout=verbose) if m.pending_link: # this may raise KeyringAccessError link_dialog(m) if m.pending_dropbox_folder: path = select_dbx_path_dialog(config_name, allow_merge=True) while True: try: m.create_dropbox_directory(path) break except OSError: click.echo( "Could not create folder. Please make sure that you have " "permissions to write to the selected location or choose a " "different location." ) exclude_folders_q = click.confirm( "Would you like to exclude any folders from syncing?", ) if exclude_folders_q: click.echo( "Please choose which top-level folders to exclude. You can exclude\n" 'individual files or subfolders later with "maestral excluded add".\n' ) click.echo("Loading...", nl=False) # get all top-level Dropbox folders entries = m.list_folder("/", recursive=False) excluded_items: List[str] = [] click.echo("\rLoading... Done") # paginate through top-level folders, ask to exclude for e in entries: if e["type"] == "FolderMetadata": yes = click.confirm( 'Exclude "{path_display}" from sync?'.format(**e) ) if yes: path_lower = cast(str, e["path_lower"]) excluded_items.append(path_lower) m.set_excluded_items(excluded_items) # free resources del m if foreground: # stop daemon process after setup and restart in our current process stop_maestral_daemon_process(config_name) start_maestral_daemon(config_name, log_to_stdout=verbose, start_sync=True) else: # start daemon process click.echo("Starting Maestral...", nl=False) res = start_maestral_daemon_process( config_name, log_to_stdout=verbose, start_sync=True ) if res == Start.Ok: click.echo("\rStarting Maestral... " + OK) elif res == Start.AlreadyRunning: click.echo("\rStarting Maestral... Already running.") else: click.echo("\rStarting Maestral... " + FAILED) click.echo("Please check logs for more information.")