def test_obj_ref_max_depth(historian: mincepy.Historian): """Test object references max depth""" # Set up the chain: three -> two -> one -> zero zero = mincepy.ObjRef() one = mincepy.ObjRef(zero) two = mincepy.ObjRef(one) three = mincepy.ObjRef(two) zero_id, one_id, two_id, three_id = historian.save(zero, one, two, three) # No max depth graph = historian.archive.get_obj_ref_graph(two_id) assert len(graph.nodes) == 3 assert len(graph.edges) == 2 assert (one_id, zero_id) in graph.edges assert (two_id, one_id) in graph.edges graph = historian.archive.get_obj_ref_graph(three_id, max_dist=3) assert len(graph.nodes) == 4 assert len(graph.edges) == 3 assert (one_id, zero_id) in graph.edges assert (two_id, one_id) in graph.edges assert (three_id, two_id) in graph.edges graph = historian.archive.get_obj_ref_graph(two_id, max_dist=1) assert len(graph.edges) == 1 assert (two_id, one_id) in graph.edges graph = historian.archive.get_obj_ref_graph(two_id, max_dist=0) assert len(graph.nodes) == 1 assert len(graph.edges) == 0
def test_get_obj_graph_current(historian: mincepy.Historian): """Test that when changing a reference the reference graph is returned correctly""" car = Car() garage = Garage(mincepy.ObjRef(car)) gid = garage.save() garage_graph = historian.archive.get_obj_ref_graph(gid) assert len(garage_graph.edges) == 1 assert (gid, car.obj_id) in garage_graph.edges # Now, modify the garage car2 = Car() garage.car = mincepy.ObjRef(car2) garage.save() # Check that the reference graph is correct garage_graph = historian.archive.get_obj_ref_graph(gid) assert len(garage_graph.edges) == 1 assert (gid, car2.obj_id) in garage_graph.edges # Finally, set the reference to None garage.car = mincepy.ObjRef() garage.save() # Check that the reference graph is correct garage_graph = historian.archive.get_obj_ref_graph(gid) assert len(garage_graph.edges) == 0 assert len(garage_graph.nodes) == 1
def test_get_obj_referencing_simple(historian: mincepy.Historian): car = Car() garage = Garage(mincepy.ObjRef(car)) gid = garage.save() car_graph = historian.archive.get_obj_ref_graph(car.obj_id, direction=mincepy.INCOMING) assert len(car_graph.edges) == 1 assert len(car_graph.nodes) == 2 assert (gid, car.obj_id) in car_graph.edges # Now, create a new garage garage2 = Garage(mincepy.ObjRef(car)) g2id = garage2.save() # Check that the reference graph is correct car_graph = historian.archive.get_obj_ref_graph(car.obj_id, direction=mincepy.INCOMING) assert len(car_graph.nodes) == 3 assert len(car_graph.edges) == 2 assert (gid, car.obj_id) in car_graph.edges assert (g2id, car.obj_id) in car_graph.edges # Finally, set the references to None garage.car = mincepy.ObjRef() garage.save() garage2.car = mincepy.ObjRef() garage2.save() # Check that the reference graph is correct car_graph = historian.archive.get_obj_ref_graph(gid) assert len(car_graph.edges) == 0 assert len(car_graph.nodes) == 1
def test_null_ref(historian: mincepy.Historian): null = mincepy.ObjRef() null2 = mincepy.ObjRef() assert null == null2 nid1, _nid2 = historian.save(null, null2) del null loaded = historian.load(nid1) assert loaded == null2
def test_obj_ref_snapshot(historian: mincepy.Historian): """Check that a historic snapshot still works with references""" ns = Namespace() car = testing.Car('honda', 'white') ns.car = mincepy.ObjRef(car) historian.save(ns) honda_ns_sid = historian.get_snapshot_id(ns) car.make = 'fiat' historian.save(ns) fiat_ns_sid = historian.get_snapshot_id(ns) del ns assert fiat_ns_sid.version == honda_ns_sid.version + 1 loaded = historian.load(honda_ns_sid) assert loaded.car().make == 'honda' loaded2 = historian.load(fiat_ns_sid) assert loaded2.car().make == 'fiat' assert loaded2.car() is not car # Load the 'live' namespace loaded3 = historian.load(honda_ns_sid.obj_id) assert loaded3.car() is car
def test_purge(historian: mincepy.Historian): car = Car() garage = testing.Garage(mincepy.ObjRef(car)) car_id, _ = historian.save(car, garage) # Now update the car car.colour = 'blue' car.save() records_count = historian.records.find().count() # This should not perge anything as v0 of the car has a reference from the garage, while # v1 is the current, live, version res = historian.purge(dry_run=False) assert not res.deleted_purged assert not res.unreferenced_purged assert records_count == historian.records.find().count() # Now mutate the car, save and purge again car.colour = 'white' car.save() # This time, version 1 is unreferenced by anything and so can be safely deleted res = historian.purge(dry_run=False) assert not res.deleted_purged assert res.unreferenced_purged == {mincepy.SnapshotId(car_id, 1)} assert records_count == historian.records.find().count()
def test_obj_ref_simple(historian: mincepy.Historian): a = testing.Cycle() a.ref = mincepy.ObjRef(a) aid = historian.save(a) del a loaded = historian.load(aid) assert loaded.ref() is loaded
def test_get_snapshot_graph_simple(historian: mincepy.Historian): car = Car() garage = Garage(mincepy.ObjRef(car)) garage.save() garage_sid = historian.get_snapshot_id(garage) garage_graph = historian.archive.get_snapshot_ref_graph(garage_sid) assert len(garage_graph.edges) == 1 assert (garage_sid, historian.get_snapshot_id(car)) in garage_graph.edges
def test_get_object_graph(historian: mincepy.Historian): """Try getting the reference graph for live objects""" car = Car() garage = Garage(mincepy.ObjRef(car)) gid = garage.save() garage_graph = historian.archive.get_obj_ref_graph(gid) assert len(garage_graph.edges) == 1 assert (gid, car.obj_id) in garage_graph.edges
def test_saving_creator_that_owns_child(historian: mincepy.Historian): class TestProc(mincepy.Process): ATTRS = ('child', ) def __init__(self): super().__init__('test_proc') self.child = None test_proc = TestProc() with test_proc.running(): test_proc.child = mincepy.ObjRef(testing.Car()) historian.save(test_proc)
def test_delete_referenced(historian: mincepy.Historian): car = testing.Car() garage = testing.Garage(mincepy.ObjRef(car)) garage.save() # Should be prevented from deleting the car as it is referenced by the garage try: historian.delete(car) except mincepy.ReferenceError as exc: assert exc.references == {car.obj_id} else: assert False, 'Reference error should have been raised' historian.delete(garage) # Now safe to delete car historian.delete(car) car = testing.Car() garage = testing.Garage(mincepy.ObjRef(car)) garage.save() # Now, check that deleting both together works historian.delete(car, garage)
def test_obj_sid_complex(historian: mincepy.Historian): honda = testing.Car('honda') nested1 = Namespace() nested2 = Namespace() parent = Namespace() # Both the nested refer to the same car nested1.car = mincepy.ObjRef(honda) nested2.car = mincepy.ObjRef(honda) # Now put them in their containers parent.ns1 = mincepy.ObjRef(nested1) parent.ns2 = mincepy.ObjRef(nested2) parent_id = historian.save(parent) del parent loaded = historian.load(parent_id) assert loaded.ns1() is nested1 assert loaded.ns2() is nested2 assert loaded.ns1().car() is loaded.ns2().car() fiat = testing.Car('fiat') loaded.ns2().car = mincepy.ObjRef(fiat) historian.save(loaded) parent_sid = historian.get_snapshot_id(loaded) del loaded loaded2 = historian.load_snapshot(mincepy.records.SnapshotId(parent_id, 0)) assert loaded2.ns1().car().make == 'honda' assert loaded2.ns2().car().make == 'honda' del loaded2 loaded3 = historian.load_snapshot(parent_sid) assert loaded3.ns1().car().make == 'honda' assert loaded3.ns2().car().make == 'fiat'
def test_get_snapshot_graph_twice(historian: mincepy.Historian): """Check for a bug that arise when asking for references twice""" car = Car() garage = Garage(mincepy.ObjRef(car)) garage.save() garage_sid = historian.get_snapshot_id(garage) def make_checks(graph): assert len(graph.edges) == 1 assert (garage_sid, historian.get_snapshot_id(car)) in graph.edges ref_graphs = historian.archive.get_snapshot_ref_graph(garage_sid) make_checks(ref_graphs) # Check again ref_graphs = historian.archive.get_snapshot_ref_graph(garage_sid) make_checks(ref_graphs)
def test_ref_load_save_load(historian: mincepy.Historian): """This is here to catch a bug that manifested when a reference was saved, loaded and then re-saved without being dereferenced in-between. This would result in the second saved state being that of a null reference. This can only be tested if the reference is stored by value as otherwise the historian will not re-save a reference that has not been mutated.""" ref_list = mincepy.List((mincepy.ObjRef(testing.Car()), )) assert isinstance(ref_list[0](), testing.Car) list_id = ref_list.save() # pylint: disable=no-member del ref_list loaded = historian.load(list_id) # Re-save loaded.save() del loaded # Re-load reloaded = historian.load(list_id) # Should still be our car but because of a bug this was a None reference assert isinstance(reloaded[0](), testing.Car)
def upgrade(cls, saved_state, loader: 'mincepy.Loader') -> dict: # Replace the value stored version with a reference saved_state['ref'] = mincepy.ObjRef(saved_state['ref']) return saved_state
def upgrade(cls, saved_state, loader: 'mincepy.Loader'): # Create a reference to the live car object saved_state['ref'] = mincepy.ObjRef(car) return saved_state
def ref(self, value): self._ref = mincepy.ObjRef(value)
def __init__(self, ref=None): super().__init__() self._ref = mincepy.ObjRef(ref)