Files
Sheerka-Old/tests/sdp/test_sheerkaDataProvider.py
T

481 lines
14 KiB
Python

import json
import os
import shutil
from datetime import date, datetime
from os import path
import pytest
from sdp.sheerkaDataProvider import SheerkaDataProvider, Event
from sdp.sheerkaSerializer import PickleSerializer
tests_root = path.abspath("../../build/tests")
evt_digest = "3a571cb6034ef6fc8d7fe91948d0d29728eed74de02bac7968b0e9facca2c2d7"
def read_json_file(sdp, file_name):
with sdp.io.open(file_name, "r") as f:
return json.load(f)
class ObjNoKey:
"""
Object with no key, they won't be ordered
Not suitable for Json dump as there is no to_dict() method
"""
def __init__(self, a, b):
self.a = a
self.b = b
def __hash__(self):
return hash((self.a, self.b))
def __eq__(self, obj):
return isinstance(obj, ObjNoKey) and \
self.a == obj.a and \
self.b == obj.b
def __repr__(self):
return f"ObjNoKey({self.a}, {self.b})"
class ObjWithDigestWithKey:
"""
Object with a key that can compute its digest.
It can be used to test objects sharing the same key (but that are different)
Not suitable for Json dump as there is no to_dict() method
"""
def __init__(self, a, b):
self.a = a
self.b = b
def __hash__(self):
return hash((self.a, self.b))
def __eq__(self, obj):
return isinstance(obj, ObjWithDigestWithKey) and \
self.a == obj.a and \
self.b == obj.b
def __repr__(self):
return f"ObjWithDigestWithKey({self.a}, {self.b})"
def get_key(self):
return self.a
def get_digest(self):
return str(self.a) + str(self.b)
@pytest.fixture(autouse=True)
def init_test():
if path.exists(tests_root):
shutil.rmtree(tests_root)
if not path.exists(tests_root):
os.makedirs(tests_root)
current_pwd = os.getcwd()
os.chdir(tests_root)
yield None
os.chdir(current_pwd)
@pytest.mark.parametrize("root, expected", [
(".sheerka", path.abspath(path.join(tests_root, ".sheerka"))),
("mem://", "")
])
def test_i_can_init_the_data_provider(root, expected):
sdp = SheerkaDataProvider(root)
assert sdp.io.root == expected
assert sdp.io.exists(sdp.io.root)
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_save_and_load_an_event(root):
sdp = SheerkaDataProvider(root)
event = Event("hello world", date=date(year=2007, month=9, day=10), user_id="kodjo")
evt_digest = sdp.save_event(event)
evt = sdp.load_event(evt_digest)
assert evt.version == 1
assert evt.date == datetime(year=2007, month=9, day=10)
assert evt.user_id == "kodjo"
assert evt.message == "hello world"
assert evt.parents is None
assert sdp.io.exists(path.join(sdp.io.root, SheerkaDataProvider.EventFolder, evt_digest[0:24], evt_digest))
# I can get the last event
evt = sdp.load_event()
assert evt.message == "hello world"
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_get_event_history(root):
sdp = SheerkaDataProvider(root)
event = Event("hello world", date=date(year=2007, month=9, day=10), user_id="kodjo")
event2 = Event("hello world 2", date=date(year=2007, month=9, day=10), user_id="kodjo")
evt_digest1 = sdp.save_event(event)
evt_digest2 = sdp.save_event(event2)
evt = sdp.load_event(evt_digest2)
assert evt.version == 1
assert evt.date == datetime(year=2007, month=9, day=10)
assert evt.user_id == "kodjo"
assert evt.message == "hello world 2"
assert evt.parents == [evt_digest1]
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_load_events(root):
sdp = SheerkaDataProvider(root)
for i in range(15):
sdp.save_event(Event(f"Hello {i}"))
events = list(sdp.load_events(10)) # first ten
assert len(events) == 10
assert events[0].message == "Hello 14"
assert events[9].message == "Hello 5"
events = list(sdp.load_events(10, 5)) # skip first 5, then take 10
assert len(events) == 10
assert events[0].message == "Hello 9"
assert events[9].message == "Hello 0"
events = list(sdp.load_events(20, 10)) # skip first 10, take 20,(but only 5 remaining)
assert len(events) == 5
assert events[0].message == "Hello 4"
assert events[4].message == "Hello 0"
events = list(sdp.load_events(1, 20)) # skip first 20, take one
assert len(events) == 0
events = list(sdp.load_events(0)) # all
assert len(events) == 15
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_load_events_when_no_event(root):
sdp = SheerkaDataProvider(root)
events = list(sdp.load_events(1))
assert len(events) == 0
events = list(sdp.load_events(1, 5))
assert len(events) == 0
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_add_and_reload_one_item(root):
sdp = SheerkaDataProvider(root)
event = Event("hello world", date=date(year=2007, month=9, day=10), user_id="kodjo")
with sdp.get_transaction(event) as transaction:
transaction.add("entry", "key", "foo => bar")
transaction.add("entry", "key2", ObjNoKey("a", "b"))
transaction.add("entry2", "key", "value2")
last_commit = sdp.get_snapshot(SheerkaDataProvider.HeadFile)
state = sdp.load_state(last_commit)
loaded1 = sdp.get("entry", "key")
loaded2 = sdp.get("entry", "key2")
loaded3 = sdp.get("entry2", "key")
load_entry = sdp.get("entry")
# check that the event is saved
evt_digest = event.get_digest()
assert sdp.io.exists(path.join(sdp.io.root, SheerkaDataProvider.EventFolder, evt_digest[0:24], evt_digest))
# check the values
assert loaded1 == "foo => bar"
assert loaded2 == ObjNoKey("a", "b")
assert loaded3 == "value2"
assert load_entry == {
"key": "foo => bar",
"key2": ObjNoKey("a", "b")
}
assert sdp.io.exists(path.join(sdp.io.root, SheerkaDataProvider.StateFolder, last_commit[0:24], last_commit))
assert sdp.io.exists(path.join(sdp.io.root, SheerkaDataProvider.HeadFile))
assert state.date is not None
assert state.parents == []
assert state.events == [evt_digest]
assert state.data == {"entry": {'key': 'foo => bar', 'key2': ObjNoKey("a", "b")},
'entry2': {'key': 'value2'}}
assert sdp.io.read_text(path.join(sdp.io.root, SheerkaDataProvider.HeadFile)) == last_commit
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_load_an_entry(root):
sdp = SheerkaDataProvider(root)
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key1", "foo")
transaction.add("entry", "key2", "bar")
transaction.add("entry", "key3", "baz")
item = sdp.get("entry", "key1")
assert item == "foo"
load_entry = sdp.get("entry")
assert load_entry == {
"key1": "foo",
"key2": "bar",
"key3": "baz",
}
# load entry was a copy
load_entry["key1"] = "another foo"
assert sdp.get("entry", "key1") == "foo"
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_add_and_reload_a_list_of_items(root):
sdp = SheerkaDataProvider(root)
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key", ["foo => bar", ObjNoKey("a", "b")])
last_commit = sdp.get_snapshot(SheerkaDataProvider.HeadFile)
state = sdp.load_state(last_commit)
loaded = sdp.get("entry", "key")
# check the values
assert loaded == ["foo => bar", ObjNoKey("a", "b")]
assert state.date is not None
assert state.parents == []
assert state.events == [evt_digest]
assert state.data == {"entry": {'key': ['foo => bar', ObjNoKey('a', 'b')]}}
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_add_and_reload_a_set_of_items(root):
sdp = SheerkaDataProvider(root)
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key", {"foo => bar", ObjNoKey("a", "b")})
last_commit = sdp.get_snapshot(SheerkaDataProvider.HeadFile)
state = sdp.load_state(last_commit)
loaded = sdp.get("entry", "key")
# check the values
assert loaded == {"foo => bar", ObjNoKey("a", "b")}
assert state.date is not None
assert state.parents == []
assert state.events == [evt_digest]
assert state.data == {"entry": {'key': {'foo => bar', ObjNoKey('a', 'b')}}}
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_add_and_reload_an_entry(root):
sdp = SheerkaDataProvider(root)
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry1", None, "foo")
transaction.add("entry2", None, {"key": "foo", "key1": "bar"})
transaction.add("entry3", None, {"foo", "bar"})
transaction.add("entry4", None, ["foo", "bar"])
loaded_entry1 = sdp.get("entry1")
loaded_entry2 = sdp.get("entry2")
loaded_entry3 = sdp.get("entry3")
loaded_entry4 = sdp.get("entry4")
assert loaded_entry1 == "foo"
assert loaded_entry2 == {"key": "foo", "key1": "bar"}
assert loaded_entry3 == {"foo", "bar"}
assert loaded_entry4 == ["foo", "bar"]
# loaded values are copies
loaded_entry2["key"] = "foo2"
assert sdp.get("entry2", "key") == "foo"
loaded_entry3.remove("foo")
assert sdp.get("entry3") == {"foo", "bar"}
loaded_entry4[0] = "foo2"
assert sdp.get("entry4")[0] == "foo"
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_override_values(root):
sdp = SheerkaDataProvider(root)
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key", {"foo => bar", ObjNoKey("a", "b")})
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key", "new_value")
loaded = sdp.get("entry", "key")
assert loaded == "new_value"
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_add_an_object_and_save_it_as_a_reference(root):
sdp = SheerkaDataProvider(root)
sdp.serializer.register(PickleSerializer(lambda o: isinstance(o, ObjNoKey)))
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key1", ObjNoKey("a", "b"), use_ref=True)
transaction.add("entry", "key2", [ObjNoKey("a", "b"), ObjNoKey("c", "d")], use_ref=True)
transaction.add("entry", "key3", {ObjNoKey("a", "b"), ObjNoKey("c", "d")}, use_ref=True)
assert sdp.get("entry", "key1") == ObjNoKey("a", "b")
assert sdp.get("entry", "key2") == [ObjNoKey("a", "b"), ObjNoKey("c", "d")]
assert sdp.get("entry", "key3") == {ObjNoKey("a", "b"), ObjNoKey("c", "d")}
# I can ask for the whole entry
assert sdp.get("entry") == {"key1": ObjNoKey("a", "b"),
"key2": [ObjNoKey("a", "b"), ObjNoKey("c", "d")],
"key3": {ObjNoKey("a", "b"), ObjNoKey("c", "d")}}
state = sdp.load_state(sdp.get_snapshot(SheerkaDataProvider.HeadFile))
assert state.data == {
"entry": {'key1': '##REF##:8fac7e801d08361c3449c594b4261ab9c45ef47f1a08df68eb717db2b6919774',
'key2': ['##REF##:8fac7e801d08361c3449c594b4261ab9c45ef47f1a08df68eb717db2b6919774',
'##REF##:2a07d90eefd71a1fc5fae4d4745ab969b2d9a3e7dd159da6d47ec69630b2acf2'],
'key3': {'##REF##:2a07d90eefd71a1fc5fae4d4745ab969b2d9a3e7dd159da6d47ec69630b2acf2',
'##REF##:8fac7e801d08361c3449c594b4261ab9c45ef47f1a08df68eb717db2b6919774'}}
}
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_add_an_object_as_a_reference_using_its_own_digest(root):
sdp = SheerkaDataProvider(root)
sdp.serializer.register(PickleSerializer(lambda o: isinstance(o, ObjWithDigestWithKey)))
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key1", ObjWithDigestWithKey("a", "b"), use_ref=True)
assert sdp.get("entry", "key1") == ObjWithDigestWithKey("a", "b")
state = sdp.load_state(sdp.get_snapshot(SheerkaDataProvider.HeadFile))
assert state.data == {
"entry": {'key1': '##REF##:ab'}
}
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_remove_elements(root):
sdp = SheerkaDataProvider(root)
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key", "value")
transaction.add("entry", "key2", "value2")
with sdp.get_transaction(evt_digest) as transaction:
transaction.remove("entry", "key")
assert sdp.get("entry", "key") is None
state = sdp.load_state(sdp.get_snapshot(SheerkaDataProvider.HeadFile))
assert state.data == {
"entry": {'key2': 'value2'}
}
@pytest.mark.parametrize("root", [
".sheerka",
"mem://"
])
def test_i_can_keep_state_history(root):
sdp = SheerkaDataProvider(root)
with sdp.get_transaction(Event("first event")) as transaction:
transaction.add("entry", "key", "value")
state_digest1 = transaction.snapshot
with sdp.get_transaction(Event("second event")) as transaction:
transaction.add("entry", "key2", "value2")
state_digest2 = transaction.snapshot
with sdp.get_transaction(Event("third event")) as transaction:
transaction.add("entry", "key2", "value2")
state_digest3 = transaction.snapshot
state = sdp.load_state(state_digest3)
assert state.parents == [state_digest2]
state = sdp.load_state(state_digest2)
assert state.parents == [state_digest1]
state = sdp.load_state(state_digest1)
assert state.parents == []
def test_i_can_remove_even_if_not_exist():
sdp = SheerkaDataProvider("mem://")
with sdp.get_transaction(evt_digest) as transaction:
transaction.remove("entry", None)
transaction.remove(None, "key")
transaction.remove("entry", "key")
def test_i_get_default_value_if_entry_is_missing():
sdp = SheerkaDataProvider("mem://")
assert sdp.get("fake_entry", "fake_key", "default_value") == "default_value"
def test_exists():
sdp = SheerkaDataProvider("mem://")
with sdp.get_transaction(evt_digest) as transaction:
transaction.add("entry", "key", "value")
assert not sdp.exists("entry2")
assert not sdp.exists("entry", "key2")
assert sdp.exists("entry", "key")