def test_invite_device_confirmation(): from parsec.api.data.invite import ( _RsInviteDeviceConfirmation, InviteDeviceConfirmation, _PyInviteDeviceConfirmation, ) assert InviteDeviceConfirmation is _RsInviteDeviceConfirmation di = DeviceID("a@b") dl = DeviceLabel("label") hh = HumanHandle("*****@*****.**", "Hubert Farnsworth") profile = UserProfile.STANDARD pk = PrivateKey.generate() umi = EntryID.new() umk = SecretKey.generate() sk = SigningKey.generate() vk = sk.verify_key sek = SecretKey.generate() py_idc = _PyInviteDeviceConfirmation( device_id=di, device_label=dl, human_handle=hh, profile=profile, private_key=pk, user_manifest_id=umi, user_manifest_key=umk, root_verify_key=vk, ) rs_idc = InviteDeviceConfirmation( device_id=di, device_label=dl, human_handle=hh, profile=profile, private_key=pk, user_manifest_id=umi, user_manifest_key=umk, root_verify_key=vk, ) assert rs_idc.device_label.str == py_idc.device_label.str assert str(rs_idc.human_handle) == str(py_idc.human_handle) assert rs_idc.device_id.str == py_idc.device_id.str assert rs_idc.profile == py_idc.profile assert rs_idc.user_manifest_id.hex == py_idc.user_manifest_id.hex rs_encrypted = rs_idc.dump_and_encrypt(key=sek) py_encrypted = py_idc.dump_and_encrypt(key=sek) # Decrypt Rust-encrypted with Rust rs_idc2 = InviteDeviceConfirmation.decrypt_and_load(rs_encrypted, sek) assert rs_idc.device_label.str == rs_idc2.device_label.str assert str(rs_idc.human_handle) == str(rs_idc2.human_handle) assert rs_idc.device_id.str == rs_idc2.device_id.str assert rs_idc.profile == rs_idc2.profile assert rs_idc.user_manifest_id.hex == rs_idc2.user_manifest_id.hex # Decrypt Python-encrypted with Python rs_idc3 = InviteDeviceConfirmation.decrypt_and_load(py_encrypted, sek) assert rs_idc.device_label.str == rs_idc3.device_label.str assert str(rs_idc.human_handle) == str(rs_idc3.human_handle) assert rs_idc.device_id.str == rs_idc3.device_id.str assert rs_idc.profile == rs_idc3.profile assert rs_idc.user_manifest_id.hex == rs_idc3.user_manifest_id.hex # Decrypt Rust-encrypted with Python py_idc2 = _PyInviteDeviceConfirmation.decrypt_and_load(rs_encrypted, sek) assert rs_idc.device_label.str == py_idc2.device_label.str assert str(rs_idc.human_handle) == str(py_idc2.human_handle) assert rs_idc.device_id.str == py_idc2.device_id.str assert rs_idc.profile == py_idc2.profile assert rs_idc.user_manifest_id.hex == rs_idc2.user_manifest_id.hex # With human_handle and device_label as None py_idc = _PyInviteDeviceConfirmation( device_id=di, device_label=None, human_handle=None, profile=profile, private_key=pk, user_manifest_id=umi, user_manifest_key=umk, root_verify_key=vk, ) rs_idc = InviteDeviceConfirmation( device_id=di, device_label=None, human_handle=None, profile=profile, private_key=pk, user_manifest_id=umi, user_manifest_key=umk, root_verify_key=vk, ) assert py_idc.device_label is None assert rs_idc.device_label is None assert py_idc.human_handle is None assert rs_idc.human_handle is None
async def test_rename_unknown_workspace(alice_user_fs): dummy_id = EntryID.new() with pytest.raises(FSWorkspaceNotFoundError): await alice_user_fs.workspace_rename(dummy_id, EntryName("whatever"))
def test_file_table_sort(qtbot, core_config): switch_language(core_config, "en") w = FileTable(parent=None) qtbot.add_widget(w) w.add_parent_workspace() w.add_folder(EntryName("Dir1"), EntryID.new(), True, False) w.add_file( EntryName("File1.txt"), EntryID.new(), 100, pendulum.datetime(2000, 1, 15), pendulum.datetime(2000, 1, 20), True, False, ) w.add_file( EntryName("AnotherFile.txt"), EntryID.new(), 80, pendulum.datetime(2000, 1, 10), pendulum.datetime(2000, 1, 25), True, False, ) assert w.rowCount() == 4 assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "Dir1" assert w.item(2, 1).text() == "File1.txt" assert w.item(3, 1).text() == "AnotherFile.txt" # Name w.sortByColumn(1, QtCore.Qt.AscendingOrder) assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "AnotherFile.txt" assert w.item(2, 1).text() == "Dir1" assert w.item(3, 1).text() == "File1.txt" w.sortByColumn(1, QtCore.Qt.DescendingOrder) assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "File1.txt" assert w.item(2, 1).text() == "Dir1" assert w.item(3, 1).text() == "AnotherFile.txt" # Created w.sortByColumn(2, QtCore.Qt.AscendingOrder) assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "Dir1" assert w.item(2, 1).text() == "AnotherFile.txt" assert w.item(3, 1).text() == "File1.txt" w.sortByColumn(2, QtCore.Qt.DescendingOrder) assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "File1.txt" assert w.item(2, 1).text() == "AnotherFile.txt" assert w.item(3, 1).text() == "Dir1" # Updated w.sortByColumn(3, QtCore.Qt.AscendingOrder) assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "Dir1" assert w.item(2, 1).text() == "File1.txt" assert w.item(3, 1).text() == "AnotherFile.txt" w.sortByColumn(3, QtCore.Qt.DescendingOrder) assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "AnotherFile.txt" assert w.item(2, 1).text() == "File1.txt" assert w.item(3, 1).text() == "Dir1" # Size w.sortByColumn(4, QtCore.Qt.AscendingOrder) assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "Dir1" assert w.item(2, 1).text() == "AnotherFile.txt" assert w.item(3, 1).text() == "File1.txt" w.sortByColumn(4, QtCore.Qt.DescendingOrder) assert w.item(0, 1).text() == "Workspaces list" assert w.item(1, 1).text() == "File1.txt" assert w.item(2, 1).text() == "AnotherFile.txt" assert w.item(3, 1).text() == "Dir1"
def test_workspace_manifest(): from parsec.api.data.manifest import ( _RsWorkspaceManifest, WorkspaceManifest, _PyWorkspaceManifest, ) assert WorkspaceManifest is _RsWorkspaceManifest def _assert_workspace_manifest_eq(py, rs): assert isinstance(py, _PyWorkspaceManifest) assert isinstance(rs, _RsWorkspaceManifest) assert py.author == rs.author assert py.id == rs.id assert py.version == rs.version assert py.timestamp == rs.timestamp assert py.created == rs.created assert py.updated == rs.updated assert py.children == rs.children kwargs = { "author": DeviceID("user@device"), "id": EntryID.new(), "version": 42, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "children": { EntryName("file1.txt"): EntryID.new() }, } py_wm = _PyWorkspaceManifest(**kwargs) rs_wm = WorkspaceManifest(**kwargs) _assert_workspace_manifest_eq(py_wm, rs_wm) kwargs = { "author": DeviceID("a@b"), "id": EntryID.new(), "version": 1337, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "children": { EntryName("file2.mp4"): EntryID.new() }, } py_wm = py_wm.evolve(**kwargs) rs_wm = rs_wm.evolve(**kwargs) _assert_workspace_manifest_eq(py_wm, rs_wm) signing_key = SigningKey(b"a" * 32) secret_key = SecretKey.generate() py_signed_and_encrypted = py_wm.dump_sign_and_encrypt( signing_key, secret_key) rs_signed_and_encrypted = rs_wm.dump_sign_and_encrypt( signing_key, secret_key) wm1 = WorkspaceManifest.decrypt_verify_and_load(py_signed_and_encrypted, secret_key, signing_key.verify_key, py_wm.author, py_wm.timestamp) wm2 = _PyWorkspaceManifest.decrypt_verify_and_load(rs_signed_and_encrypted, secret_key, signing_key.verify_key, py_wm.author, py_wm.timestamp) assert isinstance(wm1, WorkspaceManifest) assert isinstance(wm2, WorkspaceManifest) assert wm1 == wm2
def test_user_manifest(): from parsec.api.data.manifest import ( _RsUserManifest, UserManifest, _PyUserManifest, WorkspaceEntry, ) assert UserManifest is _RsUserManifest def _assert_user_manifest_eq(py, rs): assert isinstance(py, _PyUserManifest) assert isinstance(rs, _RsUserManifest) assert py.author == rs.author assert py.version == rs.version assert py.id == rs.id assert py.timestamp == rs.timestamp assert py.created == rs.created assert py.updated == rs.updated assert py.last_processed_message == rs.last_processed_message assert py.workspaces == rs.workspaces kwargs = { "author": DeviceID("user@device"), "id": EntryID.new(), "version": 42, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "last_processed_message": 4, "workspaces": [ WorkspaceEntry( name=EntryName("name"), id=EntryID.new(), key=SecretKey.generate(), encryption_revision=1, encrypted_on=pendulum.now(), role_cached_on=pendulum.now(), role=RealmRole.OWNER, ) ], } py_um = _PyUserManifest(**kwargs) rs_um = UserManifest(**kwargs) _assert_user_manifest_eq(py_um, rs_um) kwargs = { "author": DeviceID("a@b"), "id": EntryID.new(), "version": 1337, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "last_processed_message": 7, "workspaces": [ WorkspaceEntry( name=EntryName("name"), id=EntryID.new(), key=SecretKey.generate(), encryption_revision=1, encrypted_on=pendulum.now(), role_cached_on=pendulum.now(), role=RealmRole.OWNER, ), WorkspaceEntry( name=EntryName("other_name"), id=EntryID.new(), key=SecretKey.generate(), encryption_revision=2, encrypted_on=pendulum.now(), role_cached_on=pendulum.now(), role=RealmRole.CONTRIBUTOR, ), ], } py_wm = py_um.evolve(**kwargs) rs_wm = rs_um.evolve(**kwargs) _assert_user_manifest_eq(py_wm, rs_wm)
def test_file_manifest(): from parsec.api.data.manifest import _RsFileManifest, FileManifest, _PyFileManifest, BlockAccess assert FileManifest is _RsFileManifest def _assert_file_manifest_eq(py, rs): assert isinstance(py, _PyFileManifest) assert isinstance(rs, _RsFileManifest) assert py.author == rs.author assert py.id == rs.id assert py.parent == rs.parent assert py.version == rs.version assert py.size == rs.size assert py.blocksize == rs.blocksize assert py.timestamp == rs.timestamp assert py.created == rs.created assert py.updated == rs.updated assert len(py.blocks) == len(rs.blocks) assert all( isinstance(b2, BlockAccess) and b1.id == b2.id and b1.offset == b2.offset and b1.size == b2.size for (b1, b2) in zip(py.blocks, rs.blocks)) kwargs = { "author": DeviceID("user@device"), "id": EntryID.new(), "parent": EntryID.new(), "version": 42, "size": 1337, "blocksize": 64, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "blocks": (BlockAccess( id=BlockID.new(), key=SecretKey.generate(), offset=0, size=1024, digest=HashDigest.from_data(b"a"), ), ), } py_fm = _PyFileManifest(**kwargs) rs_fm = FileManifest(**kwargs) _assert_file_manifest_eq(py_fm, rs_fm) kwargs = { "author": DeviceID("a@b"), "id": EntryID.new(), "parent": EntryID.new(), "version": 1337, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "blocks": (BlockAccess( id=BlockID.new(), key=SecretKey.generate(), offset=64, size=2048, digest=HashDigest.from_data(b"b"), ), ), } py_fm = py_fm.evolve(**kwargs) rs_fm = rs_fm.evolve(**kwargs) _assert_file_manifest_eq(py_fm, rs_fm)
async def test_update_file(alice_workspace, monkeypatch): block_mock1 = mock.Mock() block_mock1.digest = b"block1" block_mock2 = mock.Mock() block_mock2.digest = b"block2" manifest_mock = mock.Mock(spec=FolderManifest) manifest_mock.blocks = [block_mock1, block_mock2] load_manifest_mock = AsyncMock(spec=mock.Mock, side_effect=lambda x: manifest_mock) alice_workspace.remote_loader.load_manifest = load_manifest_mock write_bytes_mock = AsyncMock(spec=mock.Mock) alice_workspace.write_bytes = write_bytes_mock sync_by_id_mock = AsyncMock(spec=mock.Mock) alice_workspace.sync_by_id = sync_by_id_mock monkeypatch.setattr(HashDigest, "from_data", mock.Mock(side_effect=lambda x: x)) with mock.patch( "parsec.core.cli.rsync._chunks_from_path", AsyncMock(spec=mock.Mock, side_effect=[[b"block1", b"block2"]]), ): entry_id = EntryID.new() await rsync._update_file(alice_workspace, entry_id, FsPath("/src_file"), FsPath("/path_in_workspace")) rsync._chunks_from_path.assert_called_once_with(FsPath("/src_file")) load_manifest_mock.assert_called_once_with(entry_id) write_bytes_mock.assert_not_called() sync_by_id_mock.assert_called_once_with(entry_id, remote_changed=False, recursive=False) load_manifest_mock.reset_mock() sync_by_id_mock.reset_mock() with mock.patch( "parsec.core.cli.rsync._chunks_from_path", AsyncMock(spec=mock.Mock, side_effect=[[b"block1", b"block3"]]), ): await rsync._update_file(alice_workspace, entry_id, FsPath("/src_file"), FsPath("/path_in_workspace")) rsync._chunks_from_path.assert_called_once_with(FsPath("/src_file")) load_manifest_mock.assert_called_once_with(entry_id) write_bytes_mock.assert_called_once_with(FsPath("/path_in_workspace"), b"block3", len("block1")) sync_by_id_mock.assert_called_once_with(entry_id, remote_changed=False, recursive=False) load_manifest_mock.reset_mock() sync_by_id_mock.reset_mock() write_bytes_mock.reset_mock() with mock.patch( "parsec.core.cli.rsync._chunks_from_path", AsyncMock(spec=mock.Mock, side_effect=[[b"block3", b"block4"]]), ): await rsync._update_file(alice_workspace, entry_id, FsPath("/src_file"), FsPath("/path_in_workspace")) rsync._chunks_from_path.assert_called_once_with(FsPath("/src_file")) alice_workspace.remote_loader.load_manifest.assert_called_once_with( entry_id) write_bytes_mock.assert_has_calls([ mock.call(FsPath("/path_in_workspace"), b"block3", 0), mock.call(FsPath("/path_in_workspace"), b"block4", len("block3")), ]) sync_by_id_mock.assert_called_once_with(entry_id, remote_changed=False, recursive=False)
def test_local_user_manifest(): from parsec.core.types.manifest import ( _RsLocalUserManifest, LocalUserManifest, _PyLocalUserManifest, ) assert LocalUserManifest is _RsLocalUserManifest def _assert_local_user_manifest_eq(py, rs, exclude_base=False, exclude_id=False): assert isinstance(py, _PyLocalUserManifest) assert isinstance(rs, _RsLocalUserManifest) if not exclude_base: assert py.base == rs.base if not exclude_id: assert py.id == rs.id assert py.need_sync == rs.need_sync assert py.updated == rs.updated assert py.last_processed_message == rs.last_processed_message assert len(py.workspaces) == len(rs.workspaces) assert isinstance(rs.workspaces, type(py.workspaces)) assert py.workspaces == rs.workspaces assert py.speculative == rs.speculative def _assert_user_manifest_eq(py, rs): assert py.author == rs.author assert py.version == rs.version assert py.timestamp == rs.timestamp assert py.created == rs.created assert py.updated == rs.updated assert py.last_processed_message == rs.last_processed_message assert py.workspaces == rs.workspaces assert isinstance(rs.workspaces, type(py.workspaces)) kwargs = { "base": UserManifest( author=DeviceID("user@device"), id=EntryID.new(), version=42, timestamp=pendulum.now(), created=pendulum.now(), updated=pendulum.now(), last_processed_message=0, workspaces=(WorkspaceEntry.new(EntryName("user"), pendulum.now()), ), ), "need_sync": True, "updated": pendulum.now(), "last_processed_message": 0, "workspaces": (), "speculative": True, } py_lum = _PyLocalUserManifest(**kwargs) rs_lum = LocalUserManifest(**kwargs) _assert_local_user_manifest_eq(py_lum, rs_lum) kwargs = { "base": kwargs["base"].evolve( **{ "author": DeviceID("a@b"), "id": EntryID.new(), "version": 1337, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "last_processed_message": 1, "workspaces": ( WorkspaceEntry.new(EntryName("user"), pendulum.now()), ), }), "need_sync": False, "updated": pendulum.now(), "last_processed_message": 1, "workspaces": (WorkspaceEntry.new(EntryName("wk"), pendulum.now()), ), "speculative": False, } py_lum = py_lum.evolve(**kwargs) rs_lum = rs_lum.evolve(**kwargs) _assert_local_user_manifest_eq(py_lum, rs_lum) sk = SecretKey.generate() py_enc = py_lum.dump_and_encrypt(sk) rs_enc = py_lum.dump_and_encrypt(sk) # Decrypt rust encrypted with Python and vice versa lum1 = _PyLocalUserManifest.decrypt_and_load(rs_enc, sk) lum2 = LocalUserManifest.decrypt_and_load(py_enc, sk) assert isinstance(lum1, LocalUserManifest) assert isinstance(lum2, LocalUserManifest) assert lum1 == lum2 assert py_lum.to_stats() == rs_lum.to_stats() assert py_lum.asdict() == rs_lum.asdict() ts = pendulum.now() ei = EntryID.new() di = DeviceID("a@b") # With optional parameters py_lum = _PyLocalUserManifest.new_placeholder(author=di, id=ei, timestamp=ts, speculative=True) rs_lum = LocalUserManifest.new_placeholder(author=di, id=ei, timestamp=ts, speculative=True) _assert_local_user_manifest_eq(py_lum, rs_lum, exclude_base=True, exclude_id=True) # Without optional parameters py_lum = _PyLocalUserManifest.new_placeholder(author=di, timestamp=ts) rs_lum = LocalUserManifest.new_placeholder(author=di, timestamp=ts) _assert_local_user_manifest_eq(py_lum, rs_lum, exclude_base=True, exclude_id=True) py_rum = py_lum.to_remote(author=di, timestamp=ts) rs_rum = rs_lum.to_remote(author=di, timestamp=ts) _assert_user_manifest_eq(py_rum, rs_rum) assert py_lum.match_remote(py_rum) == rs_lum.match_remote(rs_rum) py_lum2 = _PyLocalUserManifest.from_remote(py_rum) rs_lum2 = LocalUserManifest.from_remote(rs_rum) _assert_local_user_manifest_eq(py_lum2, rs_lum2, exclude_base=True, exclude_id=True) _PyLocalUserManifest.from_remote_with_local_context( remote=py_rum, prevent_sync_pattern=r".+", local_manifest=py_lum2, timestamp=ts) LocalUserManifest.from_remote_with_local_context( remote=rs_rum, prevent_sync_pattern=r".+", local_manifest=rs_lum2, timestamp=ts)
def test_local_workspace_manifest(): from parsec.core.types.manifest import ( _RsLocalWorkspaceManifest, LocalWorkspaceManifest, _PyLocalWorkspaceManifest, ) assert LocalWorkspaceManifest is _RsLocalWorkspaceManifest def _assert_local_workspace_manifest_eq(py, rs, exclude_base=False, exclude_id=False): assert isinstance(py, _PyLocalWorkspaceManifest) assert isinstance(rs, _RsLocalWorkspaceManifest) if not exclude_base: assert py.base == rs.base if not exclude_id: assert py.id == rs.id assert py.need_sync == rs.need_sync assert py.updated == rs.updated assert py.speculative == rs.speculative assert len(py.children) == len(rs.children) assert isinstance(rs.children, type( py.children)), "Rust type is {}, should be {}".format( type(rs.children), type(py.children)) assert all( isinstance(name1, EntryName) and isinstance(id1, EntryID) and name1 == name2 and id1 == id2 for ((name1, id1), (name2, id2)) in zip( sorted(py.children.items()), sorted(rs.children.items()))) assert len(py.local_confinement_points) == len( rs.local_confinement_points) assert py.local_confinement_points == rs.local_confinement_points assert len(py.remote_confinement_points) == len( rs.remote_confinement_points) assert py.remote_confinement_points == rs.remote_confinement_points def _assert_workspace_manifest_eq(py, rs): assert py.author == rs.author assert py.version == rs.version assert py.timestamp == rs.timestamp assert py.created == rs.created assert py.updated == rs.updated assert py.children == rs.children kwargs = { "base": WorkspaceManifest( author=DeviceID("user@device"), id=EntryID.new(), version=42, timestamp=pendulum.now(), created=pendulum.now(), updated=pendulum.now(), children={EntryName("file1.txt"): EntryID.new()}, ), "need_sync": True, "updated": pendulum.now(), "children": { EntryName("wksp2"): EntryID.new() }, "local_confinement_points": frozenset({EntryID.new()}), "remote_confinement_points": frozenset({EntryID.new()}), "speculative": True, } py_lwm = _PyLocalWorkspaceManifest(**kwargs) rs_lwm = LocalWorkspaceManifest(**kwargs) _assert_local_workspace_manifest_eq(py_lwm, rs_lwm) kwargs = { "base": kwargs["base"].evolve( **{ "author": DeviceID("a@b"), "id": EntryID.new(), "version": 1337, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "children": { EntryName("file2.mp4"): EntryID.new() }, }), "need_sync": False, "updated": pendulum.now(), "children": { EntryName("wksp1"): EntryID.new() }, "local_confinement_points": frozenset({EntryID.new()}), "remote_confinement_points": frozenset({EntryID.new()}), "speculative": False, } py_lwm = py_lwm.evolve(**kwargs) rs_lwm = rs_lwm.evolve(**kwargs) _assert_local_workspace_manifest_eq(py_lwm, rs_lwm) sk = SecretKey.generate() py_enc = py_lwm.dump_and_encrypt(sk) rs_enc = py_lwm.dump_and_encrypt(sk) # Decrypt rust encrypted with Python and vice versa lwm1 = _PyLocalWorkspaceManifest.decrypt_and_load(rs_enc, sk) lwm2 = LocalWorkspaceManifest.decrypt_and_load(py_enc, sk) assert isinstance(lwm1, LocalWorkspaceManifest) assert isinstance(lwm2, LocalWorkspaceManifest) assert lwm1 == lwm2 assert py_lwm.to_stats() == rs_lwm.to_stats() assert py_lwm.asdict() == rs_lwm.asdict() ts = pendulum.now() ei = EntryID.new() di = DeviceID("a@b") # With optional parameters py_lwm = _PyLocalWorkspaceManifest.new_placeholder(author=di, id=ei, timestamp=ts, speculative=True) rs_lwm = LocalWorkspaceManifest.new_placeholder(author=di, id=ei, timestamp=ts, speculative=True) _assert_local_workspace_manifest_eq(py_lwm, rs_lwm, exclude_base=True, exclude_id=True) # Without optional parameters py_lwm = _PyLocalWorkspaceManifest.new_placeholder(author=di, timestamp=ts) rs_lwm = LocalWorkspaceManifest.new_placeholder(author=di, timestamp=ts) _assert_local_workspace_manifest_eq(py_lwm, rs_lwm, exclude_base=True, exclude_id=True) py_rwm = py_lwm.to_remote(author=di, timestamp=ts) rs_rwm = rs_lwm.to_remote(author=di, timestamp=ts) _assert_workspace_manifest_eq(py_rwm, rs_rwm) children = {EntryName("wksp1"): EntryID.new()} py_lwm = py_lwm.evolve_and_mark_updated(timestamp=ts, children=children) rs_lwm = rs_lwm.evolve_and_mark_updated(timestamp=ts, children=children) _assert_local_workspace_manifest_eq(py_lwm, rs_lwm, exclude_base=True, exclude_id=True) with pytest.raises(TypeError) as excinfo: py_lwm.evolve_and_mark_updated(timestamp=ts, need_sync=True) assert str(excinfo.value) == "Unexpected keyword argument `need_sync`" with pytest.raises(TypeError) as excinfo: rs_lwm.evolve_and_mark_updated(timestamp=ts, need_sync=True) assert str(excinfo.value) == "Unexpected keyword argument `need_sync`" py_lwm2 = _PyLocalWorkspaceManifest.from_remote(py_rwm, r".+") rs_lwm2 = LocalWorkspaceManifest.from_remote(rs_rwm, r".+") _assert_local_workspace_manifest_eq(py_lwm2, rs_lwm2, exclude_base=True, exclude_id=True) py_lwm2 = _PyLocalWorkspaceManifest.from_remote_with_local_context( remote=py_rwm, prevent_sync_pattern=r".+", local_manifest=py_lwm2, timestamp=ts) rs_lwm2 = LocalWorkspaceManifest.from_remote_with_local_context( remote=rs_rwm, prevent_sync_pattern=r".+", local_manifest=rs_lwm2, timestamp=ts) assert py_lwm.match_remote(py_rwm) == rs_lwm.match_remote(rs_rwm)
def test_local_file_manifest(): from parsec.api.data.manifest import BlockAccess from parsec.core.types.manifest import ( _RsLocalFileManifest, LocalFileManifest, _PyLocalFileManifest, Chunk, ) assert LocalFileManifest is _RsLocalFileManifest def _assert_local_file_manifest_eq(py, rs, exclude_base=False, exclude_id=False): assert isinstance(py, _PyLocalFileManifest) assert isinstance(rs, _RsLocalFileManifest) if not exclude_base: assert py.base == rs.base assert py.need_sync == rs.need_sync assert py.updated == rs.updated assert py.size == rs.size assert py.blocksize == rs.blocksize assert len(py.blocks) == len(rs.blocks) assert isinstance(rs.blocks, type(py.blocks)) if len(py.blocks): assert isinstance(rs.blocks[0], type(py.blocks[0])) if not exclude_id: assert py.id == rs.id assert py.created == rs.created assert py.base_version == rs.base_version assert py.is_placeholder == rs.is_placeholder assert py.is_reshaped() == rs.is_reshaped() for (b1, b2) in zip(sorted(py.blocks), sorted(rs.blocks)): assert len(b1) == len(b2) assert all( isinstance(c2, Chunk) and c1.id == c2.id and c1.start == c2. start and c1.stop == c2.stop and c1.raw_offset == c2.raw_offset and c1.raw_size == c2.raw_size and c1.access == c2.access for (c1, c2) in zip(b1, b2)) def _assert_file_manifest_eq(py, rs): assert py.author == rs.author assert py.parent == rs.parent assert py.version == rs.version assert py.size == rs.size assert py.blocksize == rs.blocksize assert py.timestamp == rs.timestamp assert py.created == rs.created assert py.updated == rs.updated assert len(py.blocks) == len(rs.blocks) assert isinstance(rs.blocks, type(py.blocks)) assert all( isinstance(b2, BlockAccess) and b1.id == b2.id and b1.offset == b2.offset and b1.size == b2.size for (b1, b2) in zip(sorted(py.blocks), sorted(rs.blocks))) kwargs = { "base": FileManifest( author=DeviceID("user@device"), id=EntryID.new(), parent=EntryID.new(), version=42, size=1337, blocksize=85, timestamp=pendulum.now(), created=pendulum.now(), updated=pendulum.now(), blocks=(BlockAccess( id=BlockID.new(), key=SecretKey.generate(), offset=0, size=1024, digest=HashDigest.from_data(b"a"), ), ), ), "need_sync": True, "updated": pendulum.now(), "size": 42, "blocksize": 64, "blocks": (( Chunk( id=ChunkID.new(), start=0, stop=250, raw_offset=0, raw_size=512, access=BlockAccess( id=BlockID.new(), key=SecretKey.generate(), offset=0, size=512, digest=HashDigest.from_data(b"aa"), ), ), Chunk(id=ChunkID.new(), start=0, stop=250, raw_offset=250, raw_size=250, access=None), ), ), } py_lfm = _PyLocalFileManifest(**kwargs) rs_lfm = LocalFileManifest(**kwargs) _assert_local_file_manifest_eq(py_lfm, rs_lfm) kwargs = { "base": kwargs["base"].evolve( **{ "author": DeviceID("a@b"), "id": EntryID.new(), "parent": EntryID.new(), "version": 1337, "size": 4096, "blocksize": 512, "timestamp": pendulum.now(), "created": pendulum.now(), "updated": pendulum.now(), "blocks": (BlockAccess( id=BlockID.new(), key=SecretKey.generate(), offset=64, size=2048, digest=HashDigest.from_data(b"b"), ), ), }), "need_sync": False, "updated": pendulum.now(), "size": 2048, "blocksize": 1024, "blocks": (( Chunk( id=ChunkID.new(), start=0, stop=1024, raw_offset=0, raw_size=1024, access=BlockAccess( id=BlockID.new(), key=SecretKey.generate(), offset=0, size=1024, digest=HashDigest.from_data(b"bb"), ), ), Chunk( id=ChunkID.new(), start=1024, stop=2048, raw_offset=1024, raw_size=1024, access=None, ), ), ), } py_lfm = py_lfm.evolve(**kwargs) rs_lfm = rs_lfm.evolve(**kwargs) _assert_local_file_manifest_eq(py_lfm, rs_lfm) sk = SecretKey.generate() py_enc = py_lfm.dump_and_encrypt(sk) rs_enc = rs_lfm.dump_and_encrypt(sk) # Decrypt rust encrypted with Python and vice versa lfm1 = _PyLocalFileManifest.decrypt_and_load(rs_enc, sk) lfm2 = LocalFileManifest.decrypt_and_load(py_enc, sk) assert isinstance(lfm1, LocalFileManifest) assert isinstance(lfm2, LocalFileManifest) assert lfm1 == lfm2 py_lfm = py_lfm.evolve(**{"size": 1337}) rs_lfm = rs_lfm.evolve(**{"size": 1337}) _assert_local_file_manifest_eq(py_lfm, rs_lfm) with pytest.raises(AssertionError): py_lfm.assert_integrity() with pytest.raises(AssertionError): rs_lfm.assert_integrity() assert py_lfm.to_stats() == rs_lfm.to_stats() assert py_lfm.parent == rs_lfm.parent assert py_lfm.get_chunks(0) == rs_lfm.get_chunks(0) assert py_lfm.get_chunks(1000) == rs_lfm.get_chunks(1000) assert py_lfm.asdict() == rs_lfm.asdict() di = DeviceID("a@b") ts = pendulum.now() kwargs = { "size": 1024, "blocksize": 1024, "blocks": ((Chunk( id=ChunkID.new(), start=0, stop=1024, raw_offset=0, raw_size=1024, access=BlockAccess( id=BlockID.new(), key=SecretKey.generate(), offset=0, size=1024, digest=HashDigest.from_data(b"bb"), ), ), ), ), } py_lfm = py_lfm.evolve(**kwargs) rs_lfm = rs_lfm.evolve(**kwargs) _assert_local_file_manifest_eq(py_lfm, rs_lfm) py_rfm = py_lfm.to_remote(author=di, timestamp=ts) rs_rfm = rs_lfm.to_remote(author=di, timestamp=ts) _assert_file_manifest_eq(py_rfm, rs_rfm) py_lfm2 = _PyLocalFileManifest.from_remote(py_rfm) rs_lfm2 = LocalFileManifest.from_remote(rs_rfm) _assert_local_file_manifest_eq(py_lfm2, rs_lfm2, exclude_base=True, exclude_id=True) py_lfm2 = _PyLocalFileManifest.from_remote_with_local_context( remote=py_rfm, prevent_sync_pattern=r".+", local_manifest=py_lfm2, timestamp=ts) rs_lfm2 = LocalFileManifest.from_remote_with_local_context( remote=rs_rfm, prevent_sync_pattern=r".+", local_manifest=rs_lfm2, timestamp=ts) assert py_lfm.match_remote(py_rfm) == rs_lfm.match_remote(rs_rfm) py_lfm = py_lfm.evolve_and_mark_updated(timestamp=ts, size=4096) rs_lfm = rs_lfm.evolve_and_mark_updated(timestamp=ts, size=4096) _assert_local_file_manifest_eq(py_lfm, rs_lfm, exclude_base=True, exclude_id=True) with pytest.raises(TypeError) as excinfo: py_lfm.evolve_and_mark_updated(timestamp=ts, need_sync=True) assert str(excinfo.value) == "Unexpected keyword argument `need_sync`" with pytest.raises(TypeError) as excinfo: rs_lfm.evolve_and_mark_updated(timestamp=ts, need_sync=True) assert str(excinfo.value) == "Unexpected keyword argument `need_sync`" ei = EntryID.new() # Without blocksize py_lfm = _PyLocalFileManifest.new_placeholder(author=di, parent=ei, timestamp=ts) rs_lfm = LocalFileManifest.new_placeholder(author=di, parent=ei, timestamp=ts) _assert_local_file_manifest_eq(py_lfm, rs_lfm, exclude_base=True, exclude_id=True) # With blocksize py_lfm = _PyLocalFileManifest.new_placeholder(author=di, parent=ei, timestamp=ts, blocksize=1024) rs_lfm = LocalFileManifest.new_placeholder(author=di, parent=ei, timestamp=ts, blocksize=1024) _assert_local_file_manifest_eq(py_lfm, rs_lfm, exclude_base=True, exclude_id=True)