Esempio n. 1
0
def test_merge_local_user_manifest_no_changes_in_diverged_placeholder(
    gen_date, alice, alice2, with_ignored_changes
):
    w1 = WorkspaceEntry.new(name="w1")
    d1, d2, d3, d4 = [gen_date() for _ in range(4)]

    base = UserManifest(
        author=alice.device_id,
        timestamp=d2,
        id=alice.user_manifest_id,
        version=1,
        created=d1,
        updated=d2,
        last_processed_message=0,
        workspaces=(w1,),
    )

    diverged = LocalUserManifest.from_remote(base)
    if with_ignored_changes:
        diverged = diverged.evolve(updated=d4, need_sync=True)

    target = UserManifest(
        author=alice2.device_id,
        timestamp=d2,
        id=alice2.user_manifest_id,
        version=2,
        created=d1,
        updated=d3,
        last_processed_message=0,
        workspaces=(w1,),
    )

    expected_merged = LocalUserManifest.from_remote(target)
    merged = merge_local_user_manifests(diverged, target)
    assert merged == expected_merged
Esempio n. 2
0
def test_created_field_modified_by_remote(gen_date, alice, with_local_changes):
    d1, d2, d3, d4 = [gen_date() for _ in range(4)]

    w1 = WorkspaceEntry.new(name=EntryName("w1"), timestamp=d2)
    base = UserManifest(
        author=alice.device_id,
        timestamp=d2,
        id=alice.user_manifest_id,
        version=1,
        created=d1,
        updated=d2,
        last_processed_message=0,
        workspaces=(w1,),
    )

    local = LocalUserManifest.from_remote(base)
    if with_local_changes:
        w2 = WorkspaceEntry.new(name=EntryName("w1"), timestamp=d3)
        local = local.evolve(
            need_sync=True, updated=d3, last_processed_message=1, workspaces=(w1, w2)
        )

    target = base.evolve(created=d4, version=2)

    expected_merged = local.evolve(base=target)
    merged = merge_local_user_manifests(local, target)
    # Remote always control the value of the create field
    assert merged == expected_merged
Esempio n. 3
0
async def test_sync(running_backend, alice2_user_fs, alice2):
    with freeze_time("2000-01-02"):
        wid = await alice2_user_fs.workspace_create("w1")

    with freeze_time("2000-01-03"):
        await alice2_user_fs.sync()

    um = alice2_user_fs.get_user_manifest()
    expected_base_um = UserManifest(
        author=alice2.device_id,
        timestamp=datetime(2000, 1, 3),
        id=alice2.user_manifest_id,
        version=2,
        created=datetime(2000, 1, 1),
        updated=datetime(2000, 1, 2),
        last_processed_message=0,
        workspaces=(WorkspaceEntry(
            name="w1",
            id=wid,
            key=ANY,
            encryption_revision=1,
            encrypted_on=datetime(2000, 1, 2),
            role_cached_on=datetime(2000, 1, 2),
            role=WorkspaceRole.OWNER,
        ), ),
    )
    expected_um = LocalUserManifest.from_remote(expected_base_um)
    assert um == expected_um
Esempio n. 4
0
def test_merge_local_user_manifest_changes_placeholder(gen_date, alice, speculative_placeholder):
    d1, d2, d3, d4 = [gen_date() for _ in range(4)]

    w1 = WorkspaceEntry.new(name=EntryName("w1"), timestamp=d2)
    w2 = WorkspaceEntry.new(name=EntryName("w2"), timestamp=d2)
    w3 = WorkspaceEntry.new(name=EntryName("w3"), timestamp=d2)

    diverged = LocalUserManifest.new_placeholder(
        alice.device_id,
        id=alice.user_manifest_id,
        timestamp=d4,
        speculative=speculative_placeholder,
    ).evolve(last_processed_message=30, workspaces=(w1, w3))
    target = UserManifest(
        author=alice.device_id,
        timestamp=d2,
        id=alice.user_manifest_id,
        version=3,
        created=d1,
        updated=d3,
        last_processed_message=20,
        workspaces=(w1, w2),
    )
    expected_merged = LocalUserManifest(
        base=target,
        updated=d4,
        last_processed_message=30,
        workspaces=(w1, w2, w3),
        need_sync=True,
        speculative=False,
    )

    merged = merge_local_user_manifests(diverged, target)
    assert merged == expected_merged
Esempio n. 5
0
def test_merge_local_user_manifest_no_changes_in_diverged_placeholder(
    gen_date, alice, alice2, with_ignored_changes
):
    d1, d2, d3, d4, d5, d6, d7 = [gen_date() for _ in range(7)]

    w1 = WorkspaceEntry.new(name=EntryName("w1"), timestamp=d2)
    base = UserManifest(
        author=alice.device_id,
        timestamp=d4,
        id=alice.user_manifest_id,
        version=1,
        created=d1,
        updated=d3,
        last_processed_message=0,
        workspaces=(w1,),
    )

    diverged = LocalUserManifest.from_remote(base)
    if with_ignored_changes:
        w1_bis = WorkspaceEntry(
            name=w1.name,
            id=w1.id,
            key=w1.key,
            # Same encryption revision than remote (so encryption date should be ignored)
            encryption_revision=1,
            encrypted_on=d5,
            # Cache older than remote
            role_cached_on=d1,
            role=RealmRole.MANAGER,
        )
        diverged = diverged.evolve(updated=d4, need_sync=True, workspaces=(w1_bis,))

    target = UserManifest(
        author=alice2.device_id,
        timestamp=d7,
        id=alice2.user_manifest_id,
        version=2,
        created=d1,
        updated=d6,
        last_processed_message=0,
        workspaces=(w1,),
    )

    expected_merged = LocalUserManifest.from_remote(target)
    merged = merge_local_user_manifests(diverged, target)
    assert merged == expected_merged
Esempio n. 6
0
async def test_sync_placeholder(
    running_backend, backend_data_binder, local_device_factory, user_fs_factory, with_workspace
):
    device = local_device_factory()
    await backend_data_binder.bind_device(device, initial_user_manifest_in_v0=True)

    async with user_fs_factory(device, initialize_in_v0=True) as user_fs:
        um_v0 = user_fs.get_user_manifest()

        expected_um = LocalUserManifest.new_placeholder(
            id=device.user_manifest_id, now=um_v0.created
        )
        assert um_v0 == expected_um

        if with_workspace:
            with freeze_time("2000-01-02"):
                wid = await user_fs.workspace_create("w1")
            um = user_fs.get_user_manifest()
            expected_um = um_v0.evolve(
                updated=Pendulum(2000, 1, 2),
                workspaces=(
                    WorkspaceEntry(
                        name="w1",
                        id=wid,
                        key=ANY,
                        encryption_revision=1,
                        encrypted_on=Pendulum(2000, 1, 2),
                        role_cached_on=Pendulum(2000, 1, 2),
                        role=WorkspaceRole.OWNER,
                    ),
                ),
            )
            assert um == expected_um

        with freeze_time("2000-01-02"):
            await user_fs.sync()
        um = user_fs.get_user_manifest()
        expected_base_um = UserManifest(
            author=device.device_id,
            timestamp=Pendulum(2000, 1, 2),
            id=device.user_manifest_id,
            version=1,
            created=expected_um.created,
            updated=expected_um.updated,
            last_processed_message=0,
            workspaces=expected_um.workspaces,
        )
        expected_um = LocalUserManifest(
            base=expected_base_um,
            need_sync=False,
            updated=expected_um.updated,
            last_processed_message=0,
            workspaces=expected_base_um.workspaces,
        )
        assert um == expected_um
Esempio n. 7
0
async def test_sync_under_concurrency(running_backend, alice_user_fs,
                                      alice2_user_fs, alice, alice2):
    with freeze_time("2000-01-02"):
        waid = await alice_user_fs.workspace_create(EntryName("wa"))

    with freeze_time("2000-01-03"):
        wa2id = await alice2_user_fs.workspace_create(EntryName("wa2"))

    with freeze_time("2000-01-04"):
        await alice_user_fs.sync()
    with freeze_time("2000-01-05"):
        await alice2_user_fs.sync()
    # Fetch back alice2's changes
    with freeze_time("2000-01-06"):
        await alice_user_fs.sync()

    um = alice_user_fs.get_user_manifest()
    um2 = alice2_user_fs.get_user_manifest()

    expected_base_um = UserManifest(
        author=alice2.device_id,
        timestamp=datetime(2000, 1, 5),
        id=alice2.user_manifest_id,
        version=3,
        created=datetime(2000, 1, 1),
        updated=datetime(2000, 1, 3),
        last_processed_message=0,
        workspaces=(
            WorkspaceEntry(
                name=EntryName("wa"),
                id=waid,
                key=KEY,
                encryption_revision=1,
                encrypted_on=datetime(2000, 1, 2),
                role_cached_on=datetime(2000, 1, 2),
                role=WorkspaceRole.OWNER,
            ),
            WorkspaceEntry(
                name=EntryName("wa2"),
                id=wa2id,
                key=KEY,
                encryption_revision=1,
                encrypted_on=datetime(2000, 1, 3),
                role_cached_on=datetime(2000, 1, 3),
                role=WorkspaceRole.OWNER,
            ),
        ),
    )
    expected_um = LocalUserManifest.from_remote(expected_base_um)

    um = _update_user_manifest_key(um)
    um2 = _update_user_manifest_key(um2)

    assert um == expected_um
    assert um2 == expected_um
Esempio n. 8
0
    async def _fetch_remote_user_manifest(self,
                                          version: int = None) -> UserManifest:
        """
        Raises:
            FSError
            FSWorkspaceInMaintenance
            FSBackendOfflineError
        """
        try:
            # Note encryption_revision is always 1 given we never reencrypt
            # the user manifest's realm
            rep = await self.backend_cmds.vlob_read(1, self.user_manifest_id,
                                                    version)

        except BackendNotAvailable as exc:
            raise FSBackendOfflineError(str(exc)) from exc

        if rep["status"] == "in_maintenance":
            raise FSWorkspaceInMaintenance(
                "Cannot access workspace data while it is in maintenance")
        elif rep["status"] != "ok":
            raise FSError(f"Cannot fetch user manifest from backend: {rep}")

        expected_author = rep["author"]
        expected_timestamp = rep["timestamp"]
        expected_version = rep["version"]
        blob = rep["blob"]

        try:
            author = await self.remote_devices_manager.get_device(
                expected_author)

        except RemoteDevicesManagerBackendOfflineError as exc:
            raise FSBackendOfflineError(str(exc)) from exc

        except RemoteDevicesManagerError as exc:
            raise FSError(f"Cannot retrieve author public key: {exc}") from exc

        try:
            manifest = UserManifest.decrypt_verify_and_load(
                blob,
                key=self.device.user_manifest_key,
                author_verify_key=author.verify_key,
                expected_id=self.device.user_manifest_id,
                expected_author=expected_author,
                expected_timestamp=expected_timestamp,
                expected_version=version
                if version is not None else expected_version,
            )

        except DataError as exc:
            raise FSError(f"Invalid user manifest: {exc}") from exc

        return manifest
Esempio n. 9
0
async def test_sync_remote_changes(running_backend, alice_user_fs,
                                   alice2_user_fs, alice, alice2):
    # Alice 2 update the user manifest
    with freeze_time("2000-01-02"):
        wid = await alice2_user_fs.workspace_create(EntryName("wa"))
    with freeze_time("2000-01-03"):
        await alice2_user_fs.sync()

    # Alice retrieve the changes
    um = alice_user_fs.get_user_manifest()
    await alice_user_fs.sync()

    um = alice_user_fs.get_user_manifest()
    um2 = alice2_user_fs.get_user_manifest()

    expected_base_um = UserManifest(
        author=alice2.device_id,
        timestamp=datetime(2000, 1, 3),
        id=alice2.user_manifest_id,
        version=2,
        created=datetime(2000, 1, 1),
        updated=datetime(2000, 1, 2),
        last_processed_message=0,
        workspaces=(WorkspaceEntry(
            name=EntryName("wa"),
            id=wid,
            key=KEY,
            encryption_revision=1,
            encrypted_on=datetime(2000, 1, 2),
            role_cached_on=datetime(2000, 1, 2),
            role=WorkspaceRole.OWNER,
        ), ),
    )
    expected_um = LocalUserManifest(
        base=expected_base_um,
        need_sync=False,
        updated=datetime(2000, 1, 2),
        last_processed_message=0,
        workspaces=expected_base_um.workspaces,
        speculative=False,
    )
    um = _update_user_manifest_key(um)
    um2 = _update_user_manifest_key(um2)

    assert um == expected_um
    assert um2 == expected_um
Esempio n. 10
0
    def _generate_or_retrieve_user_manifest_v1(self, device):
        try:
            return self._v1[device.user_id]

        except KeyError:
            now = pendulum.now()

            remote_user_manifest = UserManifest(
                author=device.device_id,
                timestamp=now,
                id=device.user_manifest_id,
                version=1,
                created=now,
                updated=now,
                last_processed_message=0,
                workspaces=(),
            )
            local_user_manifest = LocalUserManifest.from_remote(
                remote_user_manifest)
            self._v1[device.user_id] = (remote_user_manifest,
                                        local_user_manifest)
            return self._v1[device.user_id]
Esempio n. 11
0
    def _generate_or_retrieve_user_manifest_v1(self, device):
        try:
            return self._v1[(device.organization_id, device.user_id)]

        except KeyError:
            timestamp = device.timestamp()
            remote_user_manifest = UserManifest(
                author=device.device_id,
                timestamp=timestamp,
                id=device.user_manifest_id,
                version=1,
                created=timestamp,
                updated=timestamp,
                last_processed_message=0,
                workspaces=(),
            )
            local_user_manifest = LocalUserManifest.from_remote(remote_user_manifest)
            self._v1[(device.organization_id, device.user_id)] = (
                remote_user_manifest,
                local_user_manifest,
            )
            return self._v1[(device.organization_id, device.user_id)]
Esempio n. 12
0
async def test_concurrent_sync_placeholder(running_backend,
                                           backend_data_binder,
                                           local_device_factory,
                                           user_fs_factory, dev2_has_changes):
    device1 = local_device_factory("a@1")
    await backend_data_binder.bind_device(device1,
                                          initial_user_manifest_in_v0=True)

    device2 = local_device_factory("a@2")
    await backend_data_binder.bind_device(device2,
                                          initial_user_manifest_in_v0=True)

    async with user_fs_factory(
            device1, initialize_in_v0=True) as user_fs1, user_fs_factory(
                device2, initialize_in_v0=True) as user_fs2:
        # fs2's created value is different and will be overwritten when
        # merging synced manifest from fs1
        um_created_v0_fs1 = user_fs1.get_user_manifest().created

        with freeze_time("2000-01-01"):
            w1id = await user_fs1.workspace_create("w1")
        if dev2_has_changes:
            with freeze_time("2000-01-02"):
                w2id = await user_fs2.workspace_create("w2")

        with freeze_time("2000-01-03"):
            await user_fs1.sync()
        with freeze_time("2000-01-04"):
            await user_fs2.sync()
        if dev2_has_changes:
            with freeze_time("2000-01-05"):
                await user_fs1.sync()

        um1 = user_fs1.get_user_manifest()
        um2 = user_fs2.get_user_manifest()
        if dev2_has_changes:
            expected_base_um = UserManifest(
                author=device2.device_id,
                id=device2.user_manifest_id,
                timestamp=datetime(2000, 1, 4),
                version=2,
                created=um_created_v0_fs1,
                updated=datetime(2000, 1, 2),
                last_processed_message=0,
                workspaces=(
                    WorkspaceEntry(
                        name="w1",
                        id=w1id,
                        key=ANY,
                        encryption_revision=1,
                        encrypted_on=datetime(2000, 1, 1),
                        role_cached_on=datetime(2000, 1, 1),
                        role=WorkspaceRole.OWNER,
                    ),
                    WorkspaceEntry(
                        name="w2",
                        id=w2id,
                        key=ANY,
                        encryption_revision=1,
                        encrypted_on=datetime(2000, 1, 2),
                        role_cached_on=datetime(2000, 1, 2),
                        role=WorkspaceRole.OWNER,
                    ),
                ),
            )
            expected_um = LocalUserManifest(
                base=expected_base_um,
                need_sync=False,
                updated=datetime(2000, 1, 2),
                last_processed_message=0,
                workspaces=expected_base_um.workspaces,
            )

        else:
            expected_base_um = UserManifest(
                author=device1.device_id,
                timestamp=datetime(2000, 1, 3),
                id=device1.user_manifest_id,
                version=1,
                created=um_created_v0_fs1,
                updated=datetime(2000, 1, 1),
                last_processed_message=0,
                workspaces=(WorkspaceEntry(
                    name="w1",
                    id=w1id,
                    key=ANY,
                    encryption_revision=1,
                    encrypted_on=datetime(2000, 1, 1),
                    role_cached_on=datetime(2000, 1, 1),
                    role=WorkspaceRole.OWNER,
                ), ),
            )
            expected_um = LocalUserManifest(
                base=expected_base_um,
                need_sync=False,
                updated=datetime(2000, 1, 1),
                last_processed_message=0,
                workspaces=expected_base_um.workspaces,
            )

        assert um1 == expected_um
        assert um2 == expected_um
Esempio n. 13
0
async def test_share_workspace_then_conflict_on_rights(
    running_backend, alice_user_fs, alice2_user_fs, bob_user_fs, alice, alice2, bob, first_to_sync
):
    # Bob shares a workspace with Alice...
    with freeze_time("2000-01-01"):
        wid = await bob_user_fs.workspace_create("w")
    with freeze_time("2000-01-02"):
        await bob_user_fs.workspace_share(wid, alice.user_id, WorkspaceRole.MANAGER)

    # ...but only Alice's first device get the information
    with freeze_time("2000-01-03"):
        await alice_user_fs.process_last_messages()

    # Now Bob change the sharing rights...
    with freeze_time("2000-01-04"):
        await bob_user_fs.workspace_share(wid, alice.user_id, WorkspaceRole.CONTRIBUTOR)

    # ...this time it's Alice's second device which get the info
    with freeze_time("2000-01-05"):
        # Note we will process the 2 sharing messages bob sent us, this
        # will attribute role_cached_on to the first message timestamp even
        # if we cache the second message role...
        await alice2_user_fs.process_last_messages()

    if first_to_sync == "alice":
        first = alice_user_fs
        second = alice2_user_fs
        synced_timestamp = datetime(2000, 1, 7)
        synced_version = 3
    else:
        first = alice2_user_fs
        second = alice_user_fs
        synced_timestamp = datetime(2000, 1, 6)
        synced_version = 2

    # Finally Alice devices try to reconciliate
    with freeze_time("2000-01-06"):
        await first.sync()
    with freeze_time("2000-01-07"):
        await second.sync()
    # Resync first device to get changes from the 2nd
    with freeze_time("2000-01-08"):
        await first.sync()

    am = alice_user_fs.get_user_manifest()
    a2m = alice2_user_fs.get_user_manifest()
    expected_remote = UserManifest(
        author=alice2.device_id,
        timestamp=synced_timestamp,
        id=alice2.user_manifest_id,
        version=synced_version,
        created=datetime(2000, 1, 1),
        updated=datetime(2000, 1, 5),
        last_processed_message=2,
        workspaces=(
            WorkspaceEntry(
                name="w",
                id=wid,
                key=ANY,
                encryption_revision=1,
                encrypted_on=datetime(2000, 1, 1),
                role_cached_on=datetime(2000, 1, 5),
                role=WorkspaceRole.CONTRIBUTOR,
            ),
        ),
    )
    expected = LocalUserManifest(
        base=expected_remote,
        need_sync=False,
        updated=expected_remote.updated,
        last_processed_message=expected_remote.last_processed_message,
        workspaces=expected_remote.workspaces,
    )
    assert am == expected
    assert a2m == expected

    a_w = alice_user_fs.get_workspace(wid)
    a2_w = alice2_user_fs.get_workspace(wid)

    a_w_stat = await a_w.path_info("/")
    a2_w_stat = await a2_w.path_info("/")

    a_w_entry = a_w.get_workspace_entry()
    a2_w_entry = a2_w.get_workspace_entry()

    assert a_w_stat == {
        "type": "folder",
        "is_placeholder": False,
        "id": wid,
        "created": ANY,
        "updated": ANY,
        "base_version": 1,
        "need_sync": False,
        "children": [],
        "confinement_point": None,
    }
    assert a_w_stat == a2_w_stat

    assert a_w_entry == WorkspaceEntry(
        name=f"w",
        id=wid,
        key=ANY,
        encryption_revision=1,
        encrypted_on=datetime(2000, 1, 1),
        role_cached_on=datetime(2000, 1, 5),
        role=WorkspaceRole.CONTRIBUTOR,
    )
    assert a2_w_entry == a_w_entry
Esempio n. 14
0
async def test_concurrent_devices_agree_on_user_manifest(
    running_backend,
    backend_data_binder,
    data_base_dir,
    user_fs_factory,
    coolorg,
    alice,
    alice2,
    with_speculative,
):
    KEY = SecretKey.generate()

    async def _switch_running_backend_offline(task_status):
        should_switch_online = trio.Event()
        backend_online = trio.Event()

        async def _switch_backend_online():
            should_switch_online.set()
            await backend_online.wait()

        with running_backend.offline():
            task_status.started(_switch_backend_online)
            await should_switch_online.wait()
        backend_online.set()

    # I call this "diagonal programming"...
    async with trio.open_nursery() as nursery:
        switch_back_online = await nursery.start(
            _switch_running_backend_offline)

        with freeze_time("2000-01-01"):
            if with_speculative != "both":
                await user_storage_non_speculative_init(
                    data_base_dir=data_base_dir, device=alice)
            async with user_fs_factory(
                    alice, data_base_dir=data_base_dir) as user_fs1:
                wksp1_id = await user_fs1.workspace_create(EntryName("wksp1"))

                with freeze_time("2000-01-02"):
                    if with_speculative not in ("both", "alice2"):
                        await user_storage_non_speculative_init(
                            data_base_dir=data_base_dir, device=alice2)
                    async with user_fs_factory(
                            alice2, data_base_dir=data_base_dir) as user_fs2:
                        wksp2_id = await user_fs2.workspace_create(
                            EntryName("wksp2"))

                        with freeze_time("2000-01-03"):
                            # Only now the backend appear offline, this is to ensure each
                            # userfs has created a user manifest in isolation
                            await backend_data_binder.bind_organization(
                                coolorg,
                                alice,
                                initial_user_manifest="not_synced")
                            await backend_data_binder.bind_device(
                                alice2, certifier=alice)

                            await switch_back_online()

                            # Sync user_fs2 first to ensure created_on field is
                            # kept even if further syncs have an earlier value
                            with freeze_time("2000-01-04"):
                                await user_fs2.sync()
                            with freeze_time("2000-01-05"):
                                await user_fs1.sync()
                            with freeze_time("2000-01-06"):
                                await user_fs2.sync()

                            # Now, both user fs should have the same view on data
                            expected_workspaces_entries = (
                                WorkspaceEntry(
                                    name=EntryName("wksp1"),
                                    id=wksp1_id,
                                    key=KEY,
                                    encryption_revision=1,
                                    encrypted_on=datetime(2000, 1, 1),
                                    role_cached_on=datetime(2000, 1, 1),
                                    role=WorkspaceRole.OWNER,
                                ),
                                WorkspaceEntry(
                                    name=EntryName("wksp2"),
                                    id=wksp2_id,
                                    key=KEY,
                                    encryption_revision=1,
                                    encrypted_on=datetime(2000, 1, 2),
                                    role_cached_on=datetime(2000, 1, 2),
                                    role=WorkspaceRole.OWNER,
                                ),
                            )
                            expected_user_manifest = LocalUserManifest(
                                base=UserManifest(
                                    id=alice.user_manifest_id,
                                    version=2,
                                    timestamp=datetime(2000, 1, 5),
                                    author=alice.device_id,
                                    created=datetime(2000, 1, 2),
                                    updated=datetime(2000, 1, 2),
                                    last_processed_message=0,
                                    workspaces=expected_workspaces_entries,
                                ),
                                need_sync=False,
                                updated=datetime(2000, 1, 2),
                                last_processed_message=0,
                                workspaces=expected_workspaces_entries,
                                speculative=False,
                            )

                            user_fs1_manifest = user_fs1.get_user_manifest()
                            user_fs2_manifest = user_fs2.get_user_manifest()

                            # We use to use ANY for the "key" argument in expected_user_manifest,
                            # so that we could compare the two instances safely. Sadly, ANY doesn't
                            # play nicely with the Rust bindings, so we instead update the instances
                            # to change the key.
                            user_fs1_manifest = user_fs1_manifest.evolve(
                                workspaces=tuple(
                                    w.evolve(key=KEY)
                                    for w in user_fs1_manifest.workspaces),
                                base=user_fs1_manifest.base.evolve(
                                    workspaces=tuple(
                                        w.evolve(key=KEY) for w in
                                        user_fs1_manifest.base.workspaces)),
                            )
                            user_fs2_manifest = user_fs2_manifest.evolve(
                                workspaces=tuple(
                                    w.evolve(key=KEY)
                                    for w in user_fs2_manifest.workspaces),
                                base=user_fs2_manifest.base.evolve(
                                    workspaces=tuple(
                                        w.evolve(key=KEY) for w in
                                        user_fs2_manifest.base.workspaces)),
                            )

                            assert user_fs1_manifest == expected_user_manifest
                            assert user_fs2_manifest == expected_user_manifest
Esempio n. 15
0
async def test_concurrent_sync_placeholder(
    running_backend,
    backend_data_binder,
    local_device_factory,
    user_fs_factory,
    data_base_dir,
    initialize_local_user_manifest,
    dev2_has_changes,
):
    device1 = local_device_factory("a@1")
    await backend_data_binder.bind_device(device1,
                                          initial_user_manifest="not_synced")
    await initialize_local_user_manifest(
        data_base_dir, device1, initial_user_manifest="non_speculative_v0")

    device2 = local_device_factory("a@2")
    await backend_data_binder.bind_device(device2)
    await initialize_local_user_manifest(
        data_base_dir, device2, initial_user_manifest="speculative_v0")

    async with user_fs_factory(device1) as user_fs1, user_fs_factory(
            device2) as user_fs2:
        # fs2's created value is different and will be overwritten when
        # merging synced manifest from fs1
        um_created_v0_fs1 = user_fs1.get_user_manifest().created

        with freeze_time("2000-01-01"):
            # Sync user manifests now to avoid extra milliseconds from restamping
            await user_fs1.sync()
            await user_fs2.sync()
            w1id = await user_fs1.workspace_create(EntryName("w1"))
        if dev2_has_changes:
            with freeze_time("2000-01-02"):
                w2id = await user_fs2.workspace_create(EntryName("w2"))

        with freeze_time("2000-01-03"):
            await user_fs1.sync()
        with freeze_time("2000-01-04"):
            await user_fs2.sync()
        if dev2_has_changes:
            with freeze_time("2000-01-05"):
                await user_fs1.sync()

        um1 = user_fs1.get_user_manifest()
        um2 = user_fs2.get_user_manifest()
        if dev2_has_changes:
            expected_base_um = UserManifest(
                author=device2.device_id,
                id=device2.user_manifest_id,
                timestamp=datetime(2000, 1, 4),
                version=3,
                created=um_created_v0_fs1,
                updated=datetime(2000, 1, 2),
                last_processed_message=0,
                workspaces=(
                    WorkspaceEntry(
                        name=EntryName("w1"),
                        id=w1id,
                        key=KEY,
                        encryption_revision=1,
                        encrypted_on=datetime(2000, 1, 1),
                        role_cached_on=datetime(2000, 1, 1),
                        role=WorkspaceRole.OWNER,
                    ),
                    WorkspaceEntry(
                        name=EntryName("w2"),
                        id=w2id,
                        key=KEY,
                        encryption_revision=1,
                        encrypted_on=datetime(2000, 1, 2),
                        role_cached_on=datetime(2000, 1, 2),
                        role=WorkspaceRole.OWNER,
                    ),
                ),
            )
            expected_um = LocalUserManifest(
                base=expected_base_um,
                need_sync=False,
                updated=datetime(2000, 1, 2),
                last_processed_message=0,
                workspaces=expected_base_um.workspaces,
                speculative=False,
            )

        else:
            expected_base_um = UserManifest(
                author=device1.device_id,
                timestamp=datetime(2000, 1, 3),
                id=device1.user_manifest_id,
                version=2,
                created=um_created_v0_fs1,
                updated=datetime(2000, 1, 1),
                last_processed_message=0,
                workspaces=(WorkspaceEntry(
                    name=EntryName("w1"),
                    id=w1id,
                    key=KEY,
                    encryption_revision=1,
                    encrypted_on=datetime(2000, 1, 1),
                    role_cached_on=datetime(2000, 1, 1),
                    role=WorkspaceRole.OWNER,
                ), ),
            )
            expected_um = LocalUserManifest(
                base=expected_base_um,
                need_sync=False,
                updated=datetime(2000, 1, 1),
                last_processed_message=0,
                workspaces=expected_base_um.workspaces,
                speculative=False,
            )
        um1 = _update_user_manifest_key(um1)
        um2 = _update_user_manifest_key(um2)

        assert um1 == expected_um
        assert um2 == expected_um
Esempio n. 16
0
async def test_sync_placeholder(
    running_backend,
    backend_data_binder,
    local_device_factory,
    user_fs_factory,
    data_base_dir,
    initialize_local_user_manifest,
    with_workspace,
    initial_user_manifest,
):
    device = local_device_factory()
    await backend_data_binder.bind_device(device,
                                          initial_user_manifest="not_synced")
    await initialize_local_user_manifest(
        data_base_dir, device, initial_user_manifest=initial_user_manifest)

    async with user_fs_factory(device) as user_fs:
        um_v0 = user_fs.get_user_manifest()

        expected_um = LocalUserManifest.new_placeholder(
            device.device_id,
            id=device.user_manifest_id,
            timestamp=um_v0.created,
            speculative=(initial_user_manifest == "speculative_v0"),
        )
        assert um_v0 == expected_um

        if with_workspace:
            with freeze_time("2000-01-02"):
                wid = await user_fs.workspace_create(EntryName("w1"))
            um = user_fs.get_user_manifest()
            expected_um = um_v0.evolve(
                updated=datetime(2000, 1, 2),
                workspaces=(WorkspaceEntry(
                    name=EntryName("w1"),
                    id=wid,
                    key=KEY,
                    encryption_revision=1,
                    encrypted_on=datetime(2000, 1, 2),
                    role_cached_on=datetime(2000, 1, 2),
                    role=WorkspaceRole.OWNER,
                ), ),
            )
            um = _update_user_manifest_key(um)
            assert um == expected_um

        with freeze_time("2000-01-02"):
            await user_fs.sync()
        um = user_fs.get_user_manifest()
        expected_base_um = UserManifest(
            author=device.device_id,
            # Add extra time due to the user realm being already created at 2000-01-02
            timestamp=datetime(2000, 1,
                               2).add(microseconds=MANIFEST_STAMP_AHEAD_US),
            id=device.user_manifest_id,
            version=1,
            created=expected_um.created,
            updated=expected_um.updated,
            last_processed_message=0,
            workspaces=expected_um.workspaces,
        )
        expected_um = LocalUserManifest(
            base=expected_base_um,
            need_sync=False,
            updated=expected_um.updated,
            last_processed_message=0,
            workspaces=expected_base_um.workspaces,
            speculative=False,
        )

        um = _update_user_manifest_key(um)

        assert um.base == expected_base_um
        assert um == expected_um