Example #1
0
def test_add_one():
    crdt = CRDT()
    crdt.add('a', 1)

    assert len(crdt.log) == 1
    assert crdt.data == {'a': 1}
    assert crdt.log[0].op == ADD
Example #2
0
def test_add_many(ans):
    crdt = CRDT()

    for k, v, in ans.items():
        crdt.add(k, v)

    assert len(crdt.log) == len(ans)
    assert crdt.data == ans
Example #3
0
def test_invalid_op():
    crdt = CRDT()

    operation = Operation(ts=datetime.utcnow().timestamp(), key='a', value=1, op=-1)

    # Append should fail if the operation is invalid
    try:
        crdt.append(operation)
        assert False
    except AssertionError as e:
        assert str(e) == INVALID_OP
Example #4
0
def test_add_same_key_twice():
    crdt = CRDT()
    key = 'a'
    values = [1, 2, 3]

    for v in values:
        crdt.add(key, v)

    assert len(crdt.log) == len(values)

    # Only the updated value should be present
    assert crdt.data == {key: values[-1]}
Example #5
0
def test_merge_add_only(ans):
    crdt_1, crdt_2 = CRDT(), CRDT()
    ans_1, ans_2 = slice_dict(ans, 0, len(ans) // 2), slice_dict(ans, len(ans) // 2, len(ans))

    for k, v in ans_1.items():
        crdt_1.add(k, v)
    
    for k, v in ans_2.items():
        crdt_2.add(k, v)

    merged = merge(crdt_1, crdt_2)

    assert len(merged.log) == len(crdt_1.log) + len(crdt_2.log)
    assert merged.data == ans
Example #6
0
def test_merge_add_same_key_diff_values(ans):
    crdt_1, crdt_2 = CRDT(), CRDT()
    ans_alt = {k:v + 1 for k, v in ans.items()}

    for k, v in ans.items():
        crdt_1.add(k, v)
    
    for k, v in ans_alt.items():
        crdt_2.add(k, v)

    merged = merge(crdt_1, crdt_2)

    assert len(merged.log) == len(crdt_1.log) + len(crdt_2.log)

    # Only the values updated later should be present
    assert merged.data == ans_alt
Example #7
0
class Editor:
    def __init__(self, mailbox):
        self.crdt = CRDT()
        self.lamport = 0
        self.siteID = uuid1()
        self.mailbox = mailbox

    def applyLocalChange(self, change):
        #print(change.added + change.removed)
        self.lamport = self.lamport + 1
        changes = updateLocalToRemote(self.crdt, self.lamport, self.siteID.int,
                                      change)

        # serialize RemoteChange object to json
        change_message = jsonpickle.encode(changes)

        self.mailbox.broadcast_message(change_message)

    def applyRemoteChange(self, change):
        self.lamport = max(self.lamport, change.char.lamport) + 1
        newCrdtString = updateRemoteToLocal(self.crdt, change)
        #print("applyRemoteChange: " + newCrdtString)
        return newCrdtString

    def getString(self):
        return self.crdt.toString()
Example #8
0
def test_merge_add_remove(ans):
    crdt_1, crdt_2 = CRDT(), CRDT()
    ans_1, ans_2 = slice_dict(ans, 0, len(ans) // 2), slice_dict(ans, len(ans) // 2, len(ans))

    # Both CRDTs contain the same data initially
    for k, v in ans.items():
        crdt_1.add(k, v)
        crdt_2.add(k, v)

    # Remove second half of the ans set in crdt_2
    for k in ans_2:
        crdt_2.remove(k)
    
    merged = merge(crdt_1, crdt_2)

    # Only first half of the ans set should remain
    assert merged.data == ans_1
Example #9
0
def test_merge_add_update(ans, upd):
    crdt_1, crdt_2 = CRDT(), CRDT()
    ans_1, ans_2 = slice_dict(ans, 0, len(ans) // 2), slice_dict(ans, len(ans) // 2, len(ans))

    for k, v in ans_1.items():
        crdt_1.add(k, v)
    
    for k, v in ans_2.items():
        crdt_2.add(k, v)

    for k in ans_2:
        crdt_2.update(k, upd[k])
    
    merged = merge(crdt_1, crdt_2)

    # Only keys in the second half of the ans set should be updated
    ans_1.update({upd[k]:v for k, v in ans_2.items()})
    assert merged.data == ans_1
Example #10
0
def test_update_after_remove():
    crdt = CRDT()

    crdt.add('a', 1)

    try:
        crdt.update('a', 'b')
        crdt.remove('a')

        # In the same instance, this operation should fail
        assert False
    except KeyError:
        pass
Example #11
0
def test_remove_one():
    crdt = CRDT()
    crdt.add('a', 1)
    crdt.remove('a')

    assert len(crdt.log) == 2
    assert len(crdt.data) == 0
    assert crdt.log[1].op == REMOVE
Example #12
0
def test_update_one():
    crdt = CRDT()
    crdt.add('a', 1)
    crdt.update('a', 'b')

    assert len(crdt.log) == 2
    assert crdt.data == {'b': 1}
    assert crdt.log[1].op == UPDATE
Example #13
0
def test_merge_update_key_collision():
    crdt_1, crdt_2 = CRDT(), CRDT()

    crdt_1.add('a', 1)
    crdt_2.add('b', 2)

    crdt_1.update('a', 'b')

    merged = merge(crdt_1, crdt_2)

    # In this implementation of LWW the update should overwrite the original key if the key already exists
    assert merged.data == {'b': 1}
Example #14
0
def test_merge_update_same_key_twice():
    crdt_1, crdt_2 = CRDT(), CRDT()

    crdt_1.add('a', 1)
    crdt_2.add('a', 2)

    crdt_1.update('a', 'b')
    crdt_2.update('a', 'c')

    merged = merge(crdt_1, crdt_2)

    # In a LWW merge, only the latest update should be present
    assert merged.data == {'c': 2}
Example #15
0
def test_merge_remove_same_key_twice():
    crdt_1, crdt_2 = CRDT(), CRDT()

    crdt_1.add('a', 1)
    crdt_2.add('a', 1)

    crdt_1.remove('a')
    crdt_2.remove('a')

    # In a merged set, since the key is removed before, the later remove should be ignored
    merged = merge(crdt_1, crdt_2)

    assert len(merged.data) == 0
Example #16
0
def test_update_key_collision():
    crdt = CRDT()

    crdt.add('a', 1)
    crdt.add('b', 2)

    crdt.update('a', 'b')

    # In this implementation of LWW the update should overwrite the original key if the key already exists
    assert crdt.data == {'b': 1}
Example #17
0
def test_update_many(ans, upd):
    crdt = CRDT()

    for k, v in ans.items():
        crdt.add(k, v)

    for k, v in upd.items():
        crdt.update(k, v)

    # The keys are added then updated, the length of the log should be the sum of the lengths of the ans and upd set
    assert len(crdt.log) == len(ans) + len(upd)
    assert crdt.data == {upd[k]:v for k, v in ans.items()}
Example #18
0
def test_remove_many(ans):
    crdt = CRDT()

    for k, v in ans.items():
        crdt.add(k, v)
    
    for k in ans:
        crdt.remove(k)
    
    # The same set of keys is added and removed, the length of the log should be twice that of the ans set
    assert len(crdt.log) == len(ans) * 2
    assert len(crdt.data) == 0
Example #19
0
def test_remove_same_key_twice():
    crdt = CRDT()

    crdt.add('a', 1)

    try:
        crdt.remove('a')
        crdt.remove('a')
        
        # In the same instance, this operation should fail
        assert False
    except KeyError:
        pass
Example #20
0
def test_out_of_order_append():
    crdt = CRDT()

    crdt.add('a', 1)
    inserted = crdt.log[-1]

    operation = Operation(ts=inserted.ts - 1, key=inserted.key, value=inserted.value, op=inserted.op)

    # Append should fail if the timestamp of the operation is earlier than the last inserted operation
    try:
        crdt.append(operation)
        assert False
    except AssertionError as e:
        assert str(e) == INVALID_TS
Example #21
0
def test_merge_add_update_remove(ans, upd):
    crdt_1, crdt_2 = CRDT(), CRDT()
    ans_1, ans_2 = slice_dict(ans, 0, len(ans) // 2), slice_dict(ans, len(ans) // 2, len(ans))

    for k, v in ans.items():
        crdt_1.add(k, v)
        crdt_2.add(k, v)

    # Update the elements in the second half of the ans set in crdt_1 (opposite of test_merge_add_remove_update())
    for k in ans_2:
        crdt_1.update(k, upd[k])

    # Remove old keys that are updated in crdt_1 in crdt_2 (opposite of test_merge_add_remove_update())
    for k in ans_2:
        crdt_2.remove(k)

    merged = merge(crdt_1, crdt_2)

    # Since this is a LWW set, the **removes** will overwrite the **updates** since they're executed later
    assert merged.data == ans_1
Example #22
0
 def __init__(self, mailbox):
     self.crdt = CRDT()
     self.lamport = 0
     self.siteID = uuid1()
     self.mailbox = mailbox