def test_backend_addr_bad_value(url, exc_msg): with pytest.raises(ValueError) as exc: BackendAddr.from_url(url) if isinstance(exc_msg, str): assert str(exc.value) == exc_msg else: assert str(exc.value) in exc_msg
def validate(self, string, pos): try: if len(string) == 0: return QValidator.Intermediate, string, pos BackendAddr.from_url(string) return QValidator.Acceptable, string, pos except ValueError: return QValidator.Invalid, string, pos
def core_config(tmpdir, backend_addr, unused_tcp_port, fixtures_customization): if fixtures_customization.get("fake_preferred_org_creation_backend_addr", False): backend_addr = BackendAddr.from_url(f"parsec://127.0.0.1:{unused_tcp_port}") tmpdir = Path(tmpdir) return CoreConfig( config_dir=tmpdir / "config", data_base_dir=tmpdir / "data", mountpoint_base_dir=tmpdir / "mnt", preferred_org_creation_backend_addr=backend_addr, gui_language=fixtures_customization.get("gui_language"), )
def test_backend_organization_addr_good(base_url, expected, verify_key): org = OrganizationID("org") backend_addr = BackendAddr.from_url(base_url) addr = BackendOrganizationAddr.build(backend_addr, organization_id=org, root_verify_key=verify_key) assert addr.hostname == "foo" assert addr.port == expected["port"] assert addr.use_ssl == expected["ssl"] assert addr.organization_id == org assert addr.root_verify_key == verify_key addr2 = BackendOrganizationAddr.from_url(addr.to_url()) assert addr == addr2
def test_build_addrs(): backend_addr = BackendAddr.from_url(BackendAddrTestbed.url) assert backend_addr.hostname == "parsec.cloud.com" assert backend_addr.port == 443 assert backend_addr.use_ssl is True organization_id = OrganizationID("MyOrg") root_verify_key = SigningKey.generate().verify_key organization_addr = BackendOrganizationAddr.build( backend_addr=backend_addr, organization_id=organization_id, root_verify_key=root_verify_key ) assert organization_addr.organization_id == organization_id assert organization_addr.root_verify_key == root_verify_key organization_bootstrap_addr = BackendOrganizationBootstrapAddr.build( backend_addr=backend_addr, organization_id=organization_id, token="a0000000000000000000000000000001", ) assert organization_bootstrap_addr.token == "a0000000000000000000000000000001" assert organization_bootstrap_addr.organization_id == organization_id organization_bootstrap_addr2 = BackendOrganizationBootstrapAddr.build( backend_addr=backend_addr, organization_id=organization_id, token=None ) assert organization_bootstrap_addr2.organization_id == organization_id assert organization_bootstrap_addr2.token == "" organization_file_link_addr = BackendOrganizationFileLinkAddr.build( organization_addr=organization_addr, workspace_id=EntryID.from_hex("2d4ded12-7406-4608-833b-7f57f01156e2"), encrypted_path=b"<encrypted_payload>", ) assert organization_file_link_addr.workspace_id == EntryID.from_hex( "2d4ded12-7406-4608-833b-7f57f01156e2" ) assert organization_file_link_addr.encrypted_path == b"<encrypted_payload>" invitation_addr = BackendInvitationAddr.build( backend_addr=backend_addr, organization_id=organization_id, invitation_type=InvitationType.USER, token=InvitationToken.from_hex("a0000000000000000000000000000001"), ) assert invitation_addr.organization_id == organization_id assert invitation_addr.token == InvitationToken.from_hex("a0000000000000000000000000000001") assert invitation_addr.invitation_type == InvitationType.USER
async def restart_local_backend(administration_token, backend_port, email_host, db, blockstore): pattern = f"parsec.* backend.* run.* -P {backend_port}" command = ( f"{sys.executable} -Wignore -m parsec.cli backend run --log-level=WARNING " f"-b {blockstore} --db {db} " f"--email-host={email_host} -P {backend_port} " f"--spontaneous-organization-bootstrap " f"--administration-token {administration_token} --backend-addr parsec://localhost:{backend_port}?no_ssl=true" ) # Trio does not support subprocess in windows yet def _windows_target(): for proc in psutil.process_iter(): if "python" in proc.name(): arguments = " ".join(proc.cmdline()) if re.search(pattern, arguments): proc.kill() backend_process = subprocess.Popen(command.split(), stdout=subprocess.PIPE) for data in backend_process.stdout: print(data.decode(), end="") break backend_process.stdout.close() # Windows restart if sys.platform == "win32": await trio.to_thread.run_sync(_windows_target) # Linux restart else: await trio.run_process(["pkill", "-f", pattern], check=False) backend_process = await trio.open_process(command.split(), stdout=subprocess.PIPE) async with backend_process.stdout: async for data in backend_process.stdout: print(data.decode(), end="") break # Make sure the backend is actually started await trio.sleep(0.2) url = f"parsec://localhost:{backend_port}?no_ssl=true" return BackendAddr.from_url(url)
def test_backend_organization_bootstrap_addr_good(base_url, expected, verify_key): org = OrganizationID("org") backend_addr = BackendAddr.from_url(base_url) addr = BackendOrganizationBootstrapAddr.build(backend_addr, org, "token-123") assert addr.hostname == "foo" assert addr.port == expected["port"] assert addr.use_ssl == expected["ssl"] assert addr.organization_id == org assert addr.token == "token-123" addr2 = BackendOrganizationBootstrapAddr.from_url(str(addr)) assert addr == addr2 org_addr = addr.generate_organization_addr(verify_key) assert isinstance(org_addr, BackendOrganizationAddr) assert org_addr.root_verify_key == verify_key assert org_addr.hostname == addr.hostname assert org_addr.port == addr.port assert org_addr.use_ssl == addr.use_ssl assert org_addr.organization_id == addr.organization_id
async def restart_local_backend(administration_token, backend_port): pattern = f"parsec.* backend.* run.* -P {backend_port}" command = ( f"python -Wignore -m parsec.cli backend run -b MOCKED --db MOCKED " f"-P {backend_port} --administration-token {administration_token}") # Trio does not support subprocess in windows yet def _windows_target(): for proc in psutil.process_iter(): if "python" in proc.name(): arguments = " ".join(proc.cmdline()) if re.search(pattern, arguments): proc.kill() backend_process = subprocess.Popen(command.split(), stdout=subprocess.PIPE) for data in backend_process.stdout: print(data.decode(), end="") break backend_process.stdout.close() # Windows restart if os.name == "nt" or True: await trio.to_thread.run_sync(_windows_target) # Linux restart else: await trio.run_process(["pkill", "-f", pattern], check=False) backend_process = await trio.open_process(command.split(), stdout=subprocess.PIPE) async with backend_process.stdout: async for data in backend_process.stdout: print(data.decode(), end="") break # Make sure the backend is actually started await trio.sleep(0.2) url = f"parsec://localhost:{backend_port}?no_ssl=true" return BackendAddr.from_url(url)
def backend_addr(self): return (BackendAddr.from_url(self.line_edit_backend_addr.text()) if self.check_use_custom_backend.isChecked() else None)
def config_factory( config_dir: Path = None, data_base_dir: Path = None, cache_base_dir: Path = None, mountpoint_base_dir: Path = None, prevent_sync_pattern_path: Optional[Path] = None, mountpoint_enabled: bool = False, disabled_workspaces: FrozenSet[EntryID] = frozenset(), backend_max_cooldown: int = 30, backend_connection_keepalive: Optional[int] = 29, backend_max_connections: int = 4, telemetry_enabled: bool = True, debug: bool = False, gui_last_device: str = None, gui_tray_enabled: bool = True, gui_language: str = None, gui_first_launch: bool = True, gui_last_version: str = None, gui_check_version_at_startup: bool = True, gui_check_version_allow_pre_release: bool = False, gui_workspace_color: bool = False, gui_allow_multiple_instances: bool = False, preferred_org_creation_backend_addr: Optional[BackendAddr] = None, gui_show_confined: bool = False, gui_geometry: bytes = None, environ: dict = {}, **_, ) -> CoreConfig: # The environment variable we always be used first, and if it is not present, # we'll use the value from the configuration file. backend_addr_env = environ.get("PREFERRED_ORG_CREATION_BACKEND_ADDR") if backend_addr_env: preferred_org_creation_backend_addr = BackendAddr.from_url( backend_addr_env) if not preferred_org_creation_backend_addr: preferred_org_creation_backend_addr = BackendAddr.from_url( "parsec://localhost:6777?no_ssl=true") data_base_dir = data_base_dir or get_default_data_base_dir(environ) core_config = CoreConfig( config_dir=config_dir or get_default_config_dir(environ), data_base_dir=data_base_dir, cache_base_dir=cache_base_dir or get_default_cache_base_dir(environ), mountpoint_base_dir=get_default_mountpoint_base_dir(environ), prevent_sync_pattern_path=prevent_sync_pattern_path, mountpoint_enabled=mountpoint_enabled, disabled_workspaces=disabled_workspaces, backend_max_cooldown=backend_max_cooldown, backend_connection_keepalive=backend_connection_keepalive, backend_max_connections=backend_max_connections, telemetry_enabled=telemetry_enabled, debug=debug, sentry_url=environ.get("SENTRY_URL") or None, gui_last_device=gui_last_device, gui_tray_enabled=gui_tray_enabled, gui_language=gui_language, gui_first_launch=gui_first_launch, gui_last_version=gui_last_version, gui_check_version_at_startup=gui_check_version_at_startup, gui_check_version_allow_pre_release=gui_check_version_allow_pre_release, gui_workspace_color=gui_workspace_color, gui_allow_multiple_instances=gui_allow_multiple_instances, preferred_org_creation_backend_addr=preferred_org_creation_backend_addr, gui_show_confined=gui_show_confined, gui_geometry=gui_geometry, ipc_socket_file=data_base_dir / "parsec-cloud.lock", ipc_win32_mutex_name="parsec-cloud", ) # Make sure the directories exist on the system core_config.config_dir.mkdir(mode=0o700, parents=True, exist_ok=True) core_config.data_base_dir.mkdir(mode=0o700, parents=True, exist_ok=True) core_config.cache_base_dir.mkdir(mode=0o700, parents=True, exist_ok=True) # Mountpoint base directory is not used on windows if os.name != "nt": core_config.mountpoint_base_dir.mkdir(mode=0o700, parents=True, exist_ok=True) return core_config
def load_config(config_dir: Path, **extra_config) -> CoreConfig: config_file = config_dir / "config.json" try: raw_conf = config_file.read_text() data_conf = json.loads(raw_conf) except OSError: # Config file not created yet, fallback to default data_conf = {} except (ValueError, json.JSONDecodeError) as exc: # Config file broken, fallback to default logger.warning(f"Ignoring invalid config in {config_file} ({exc})") data_conf = {} try: data_conf["data_base_dir"] = Path(data_conf["data_base_dir"]) except (KeyError, ValueError): pass try: data_conf["cache_base_dir"] = Path(data_conf["cache_base_dir"]) except (KeyError, ValueError): pass try: data_conf["prevent_sync_pattern_path"] = Path( data_conf["prevent_sync_pattern_path"]) except (KeyError, ValueError): pass try: data_conf["disabled_workspaces"] = frozenset( map(EntryID, data_conf["disabled_workspaces"])) except (KeyError, ValueError): pass try: data_conf[ "preferred_org_creation_backend_addr"] = BackendAddr.from_url( data_conf["preferred_org_creation_backend_addr"]) except KeyError: pass except ValueError as exc: logger.warning( f"Invalid value for `preferred_org_creation_backend_addr` ({exc})") data_conf["preferred_org_creation_backend_addr"] = None try: data_conf["gui_geometry"] = base64.b64decode( data_conf["gui_geometry"].encode("ascii")) except (AttributeError, KeyError, UnicodeEncodeError, binascii.Error): data_conf["gui_geometry"] = None # Work around versionning issue with parsec releases: # - v1.12.0, v1.11.4, v1.11.3, v1.11.2, v1.11.1, v1.11.0 and v1.10.0 # A `v` has been incorrectly added to `parsec.__version__`, potentially # affecting the `gui_last_version` entry in the configuration file. if data_conf.get("gui_last_version"): data_conf["gui_last_version"] = data_conf["gui_last_version"].lstrip( "v") return config_factory(config_dir=config_dir, **data_conf, **extra_config, environ=os.environ)
def test_backend_addr_good(url, expected): addr = BackendAddr.from_url(url) assert addr.hostname == "foo" assert addr.port == expected["port"] assert addr.use_ssl == expected["ssl"]
def test_backend_addr_bad_value(url, exc_msg): with pytest.raises(ValueError) as exc: BackendAddr.from_url(url) assert str(exc.value) == exc_msg
def backend_addr(self): return (BackendAddr.from_url(self.line_edit_backend_addr.text(), allow_http_redirection=True) if self.radio_use_custom.isChecked() else None)