def test_merge_manifests_with_a_placeholder(alice, bob):
    timestamp = alice.timestamp()
    my_device = alice.device_id
    other_device = bob.device_id
    parent = EntryID.new()

    m1 = LocalFolderManifest.new_placeholder(my_device,
                                             parent=parent,
                                             timestamp=timestamp)
    m2 = merge_manifests(my_device, timestamp, empty_pattern, m1)
    assert m2 == m1
    v1 = m1.to_remote(author=my_device, timestamp=timestamp)

    m2a = merge_manifests(my_device, timestamp, empty_pattern, m1, v1)
    assert m2a == LocalFolderManifest.from_remote(v1, empty_pattern)

    m2b = m1.evolve_children_and_mark_updated({EntryName("a"): EntryID.new()},
                                              empty_pattern,
                                              timestamp=timestamp)
    m3b = merge_manifests(my_device, timestamp, empty_pattern, m2b, v1)
    assert m3b == m2b.evolve(base=v1)

    v2 = v1.evolve(version=2,
                   author=other_device,
                   children={EntryName("b"): EntryID.new()})
    m2c = m1.evolve_children_and_mark_updated({EntryName("a"): EntryID.new()},
                                              empty_pattern,
                                              timestamp=timestamp)
    m3c = merge_manifests(my_device, timestamp, empty_pattern, m2c, v2)
    children = {**v2.children, **m2c.children}
    assert m3c == m2c.evolve(base=v2, children=children, updated=m3c.updated)
示例#2
0
def test_merge_folder_manifests():
    my_device = DeviceID("b@b")
    other_device = DeviceID("a@a")
    parent = EntryID()
    v1 = LocalFolderManifest.new_placeholder(
        my_device, parent=parent).to_remote(author=other_device)

    # Initial base manifest
    m1 = LocalFolderManifest.from_remote(v1, empty_pattern)
    assert merge_manifests(my_device, empty_pattern, m1) == m1

    # Local change
    m2 = m1.evolve_children_and_mark_updated({"a": EntryID()}, empty_pattern)
    assert merge_manifests(my_device, empty_pattern, m2) == m2

    # Successful upload
    v2 = m2.to_remote(author=my_device)
    m3 = merge_manifests(my_device, empty_pattern, m2, v2)
    assert m3 == LocalFolderManifest.from_remote(v2, empty_pattern)

    # Two local changes
    m4 = m3.evolve_children_and_mark_updated({"b": EntryID()}, empty_pattern)
    assert merge_manifests(my_device, empty_pattern, m4) == m4
    m5 = m4.evolve_children_and_mark_updated({"c": EntryID()}, empty_pattern)
    assert merge_manifests(my_device, empty_pattern, m4) == m4

    # M4 has been successfully uploaded
    v3 = m4.to_remote(author=my_device)
    m6 = merge_manifests(my_device, empty_pattern, m5, v3)
    assert m6 == m5.evolve(base=v3)

    # The remote has changed
    v4 = v3.evolve(version=4,
                   children={
                       "d": EntryID(),
                       **v3.children
                   },
                   author=other_device)
    m7 = merge_manifests(my_device, empty_pattern, m6, v4)
    assert m7.base_version == 4
    assert sorted(m7.children) == ["a", "b", "c", "d"]
    assert m7.need_sync

    # Successful upload
    v5 = m7.to_remote(author=my_device)
    m8 = merge_manifests(my_device, empty_pattern, m7, v5)
    assert m8 == LocalFolderManifest.from_remote(v5, empty_pattern)

    # The remote has changed
    v6 = v5.evolve(version=6,
                   children={
                       "e": EntryID(),
                       **v5.children
                   },
                   author=other_device)
    m9 = merge_manifests(my_device, empty_pattern, m8, v6)
    assert m9 == LocalFolderManifest.from_remote(v6, empty_pattern)
示例#3
0
def test_merge_manifests_with_a_placeholder():
    my_device = DeviceID("b@b")
    other_device = DeviceID("a@a")
    parent = EntryID()

    m1 = LocalFolderManifest.new_placeholder(my_device, parent=parent)
    m2 = merge_manifests(my_device, empty_pattern, m1)
    assert m2 == m1
    v1 = m1.to_remote(author=my_device)

    m2a = merge_manifests(my_device, empty_pattern, m1, v1)
    assert m2a == LocalFolderManifest.from_remote(v1, empty_pattern)

    m2b = m1.evolve_children_and_mark_updated({"a": EntryID()}, empty_pattern)
    m3b = merge_manifests(my_device, empty_pattern, m2b, v1)
    assert m3b == m2b.evolve(base=v1)

    v2 = v1.evolve(version=2, author=other_device, children={"b": EntryID()})
    m2c = m1.evolve_children_and_mark_updated({"a": EntryID()}, empty_pattern)
    m3c = merge_manifests(my_device, empty_pattern, m2c, v2)
    children = {**v2.children, **m2c.children}
    assert m3c == m2c.evolve(base=v2, children=children, updated=m3c.updated)
def test_merge_file_manifests(alice, bob):
    timestamp = alice.timestamp()
    my_device = alice.device_id
    other_device = bob.device_id
    parent = EntryID.new()
    v1 = LocalFileManifest.new_placeholder(my_device,
                                           parent=parent,
                                           timestamp=timestamp).to_remote(
                                               author=other_device,
                                               timestamp=timestamp)

    def evolve(m, n):
        chunk = Chunk.new(0, n).evolve_as_block(b"a" * n)
        blocks = ((chunk, ), )
        return m1.evolve_and_mark_updated(size=n,
                                          blocks=blocks,
                                          timestamp=timestamp)

    # Initial base manifest
    m1 = LocalFileManifest.from_remote(v1)
    assert merge_manifests(my_device, timestamp, empty_pattern, m1) == m1

    # Local change
    m2 = evolve(m1, 1)
    assert merge_manifests(my_device, timestamp, empty_pattern, m2) == m2

    # Successful upload
    v2 = m2.to_remote(author=my_device, timestamp=timestamp)
    m3 = merge_manifests(my_device, timestamp, empty_pattern, m2, v2)
    assert m3 == LocalFileManifest.from_remote(v2)

    # Two local changes
    m4 = evolve(m3, 2)
    assert merge_manifests(my_device, timestamp, empty_pattern, m4) == m4
    m5 = evolve(m4, 3)
    assert merge_manifests(my_device, timestamp, empty_pattern, m4) == m4

    # M4 has been successfully uploaded
    v3 = m4.to_remote(author=my_device, timestamp=timestamp)
    m6 = merge_manifests(my_device, timestamp, empty_pattern, m5, v3)
    assert m6 == m5.evolve(base=v3)

    # The remote has changed
    v4 = v3.evolve(version=4, size=0, author=other_device)
    with pytest.raises(FSFileConflictError):
        merge_manifests(my_device, timestamp, empty_pattern, m6, v4)
示例#5
0
def test_merge_speculative_with_it_unsuspected_former_self(
        local_changes, core_config):
    d1 = datetime(2000, 1, 1)
    d2 = datetime(2000, 1, 2)
    d3 = datetime(2000, 1, 3)
    d4 = datetime(2000, 1, 4)
    d5 = datetime(2000, 1, 5)
    my_device = DeviceID("a@a")

    # 1) Workspace manifest is originally created by our device
    local = LocalWorkspaceManifest.new_placeholder(author=my_device,
                                                   timestamp=d1)
    foo_id = EntryID.new()
    local = local.evolve(updated=d2,
                         children=FrozenDict({EntryName("foo"): foo_id}))

    # 2) We sync the workspace manifest
    v1 = local.to_remote(author=my_device, timestamp=d3)

    # 3) Now let's pretend we lost local storage, hence creating a new speculative manifest
    new_local = LocalWorkspaceManifest.new_placeholder(author=my_device,
                                                       id=local.id,
                                                       timestamp=d3,
                                                       speculative=True)
    if local_changes:
        bar_id = EntryID.new()
        new_local = new_local.evolve(updated=d4,
                                     children=FrozenDict(
                                         {EntryName("bar"): bar_id}))

    # 4) When syncing the manifest, we shouldn't remove any data from the remote
    merged = merge_manifests(
        local_author=my_device,
        timestamp=d5,
        prevent_sync_pattern=empty_pattern,
        local_manifest=new_local,
        remote_manifest=v1,
    )

    if local_changes:
        assert merged == LocalWorkspaceManifest(
            base=v1,
            need_sync=True,
            updated=d5,
            children=FrozenDict({
                **v1.children,
                **new_local.children
            }),
            local_confinement_points=frozenset(),
            remote_confinement_points=frozenset(),
            speculative=False,
        )
    else:
        assert merged == LocalWorkspaceManifest(
            base=v1,
            need_sync=False,
            updated=v1.updated,
            children=v1.children,
            local_confinement_points=frozenset(),
            remote_confinement_points=frozenset(),
            speculative=False,
        )
def test_merge_folder_manifests_with_concurrent_remote_change(
        local_change, remote_change, alice, bob):
    timestamp = alice.timestamp()
    my_device = alice.device_id
    other_device = bob.device_id
    parent = EntryID.new()
    foo_txt = EntryID.new()
    remote_manifest_v1 = (LocalFolderManifest.new_placeholder(
        my_device, parent=parent,
        timestamp=timestamp).evolve(children={
            EntryName("foo.txt"): foo_txt
        }).to_remote(author=my_device, timestamp=timestamp))

    prevent_sync_pattern = re.compile(r".*\.tmp\Z")

    # Load the manifest in local
    local_manifest = LocalFolderManifest.from_remote(
        remote_manifest_v1, prevent_sync_pattern=prevent_sync_pattern)

    # In local, `foo.txt` is renamed
    if local_change == "rename":
        foo_txt_new_name = EntryName("foo2.txt")
    else:
        assert local_change == "prevent_sync_rename"
        foo_txt_new_name = EntryName("foo.txt.tmp")
    local_manifest = local_manifest.evolve_children_and_mark_updated(
        data={
            EntryName("foo.txt"): None,
            foo_txt_new_name: foo_txt
        },
        prevent_sync_pattern=prevent_sync_pattern,
        timestamp=timestamp,
    )

    # In remote, a change also occurs
    if remote_change == "same_entry_moved":
        remote_manifest_v2_children = {
            EntryName("bar.txt"):
            remote_manifest_v1.children[EntryName("foo.txt")]
        }
    else:
        assert remote_change == "new_entry_added"
        remote_manifest_v2_children = {
            **remote_manifest_v1.children,
            EntryName("bar.txt"): EntryID.new(),
        }

    remote_manifest_v2 = remote_manifest_v1.evolve(
        author=other_device,
        version=remote_manifest_v1.version + 1,
        children=remote_manifest_v2_children,
    )

    # Now merging should detect the duplication
    merged_manifest = merge_manifests(
        local_author=my_device,
        timestamp=timestamp,
        prevent_sync_pattern=prevent_sync_pattern,
        local_manifest=local_manifest,
        remote_manifest=remote_manifest_v2,
        force_apply_pattern=False,
    )

    if remote_change == "same_entry_moved":
        assert list(merged_manifest.children) == [EntryName("bar.txt")]
    else:
        assert remote_change == "new_entry_added"
        if local_change == "rename":
            assert sorted(merged_manifest.children) == [
                EntryName("bar.txt"),
                EntryName("foo2.txt")
            ]
        else:
            assert local_change == "prevent_sync_rename"
            assert sorted(merged_manifest.children) == [
                EntryName("bar.txt"),
                EntryName("foo.txt.tmp"),
            ]
def test_merge_folder_manifests(alice, bob):
    timestamp = alice.timestamp()
    my_device = alice.device_id
    other_device = bob.device_id
    parent = EntryID.new()
    v1 = LocalFolderManifest.new_placeholder(my_device,
                                             parent=parent,
                                             timestamp=timestamp).to_remote(
                                                 author=other_device,
                                                 timestamp=timestamp)

    # Initial base manifest
    m1 = LocalFolderManifest.from_remote(v1, empty_pattern)
    assert merge_manifests(my_device, timestamp, empty_pattern, m1) == m1

    # Local change
    m2 = m1.evolve_children_and_mark_updated({EntryName("a"): EntryID.new()},
                                             empty_pattern,
                                             timestamp=timestamp)
    assert merge_manifests(my_device, timestamp, empty_pattern, m2) == m2

    # Successful upload
    v2 = m2.to_remote(author=my_device, timestamp=timestamp)
    m3 = merge_manifests(my_device, timestamp, empty_pattern, m2, v2)
    assert m3 == LocalFolderManifest.from_remote(v2, empty_pattern)

    # Two local changes
    m4 = m3.evolve_children_and_mark_updated({EntryName("b"): EntryID.new()},
                                             empty_pattern,
                                             timestamp=timestamp)
    assert merge_manifests(my_device, timestamp, empty_pattern, m4) == m4
    m5 = m4.evolve_children_and_mark_updated({EntryName("c"): EntryID.new()},
                                             empty_pattern,
                                             timestamp=timestamp)
    assert merge_manifests(my_device, timestamp, empty_pattern, m4) == m4

    # M4 has been successfully uploaded
    v3 = m4.to_remote(author=my_device, timestamp=timestamp)
    m6 = merge_manifests(my_device, timestamp, empty_pattern, m5, v3)
    assert m6 == m5.evolve(base=v3)

    # The remote has changed
    v4 = v3.evolve(version=4,
                   children={
                       EntryName("d"): EntryID.new(),
                       **v3.children
                   },
                   author=other_device)
    m7 = merge_manifests(my_device, timestamp, empty_pattern, m6, v4)
    assert m7.base_version == 4
    assert sorted(m7.children) == [
        EntryName("a"),
        EntryName("b"),
        EntryName("c"),
        EntryName("d")
    ]
    assert m7.need_sync

    # Successful upload
    v5 = m7.to_remote(author=my_device, timestamp=timestamp)
    m8 = merge_manifests(my_device, timestamp, empty_pattern, m7, v5)
    assert m8 == LocalFolderManifest.from_remote(v5, empty_pattern)

    # The remote has changed
    v6 = v5.evolve(version=6,
                   children={
                       EntryName("e"): EntryID.new(),
                       **v5.children
                   },
                   author=other_device)
    m9 = merge_manifests(my_device, timestamp, empty_pattern, m8, v6)
    assert m9 == LocalFolderManifest.from_remote(v6, empty_pattern)