Example #1
0
def test_merge(historian: mincepy.Historian):
    with testing.temporary_historian(
            testing.create_archive_uri(db_name='test_historian')) as remote:
        local = historian
        # remote = clean_test_historian

        remote_skoda = testing.Car(make='skoda', colour='green')
        skoda_id = remote.save(remote_skoda)
        assert remote_skoda._historian is remote

        result = local.merge(remote.objects.find(obj_id=skoda_id))
        assert remote.get_snapshot_id(remote_skoda) in result.merged
        assert local.find(obj_id=skoda_id).count() == 1

        # Now, let's update and see if we can merge
        remote_skoda.colour = 'yellow'
        remote.save(remote_skoda)

        result = local.merge(remote.objects.find(obj_id=skoda_id))
        assert remote.get_snapshot_id(remote_skoda) in result.merged
        assert local.snapshots.find(obj_id=skoda_id).count() == 2
        assert local.find(obj_id=skoda_id).one().colour == 'yellow'

        # Now, change both to the same thing
        local_skoda = local.load(skoda_id)
        assert local_skoda._historian is local
        assert local_skoda is not remote_skoda

        local_skoda.colour = 'blue'
        local_skoda.save()

        remote_skoda.colour = 'blue'
        remote_skoda.save()
        result = local.merge(remote.objects.find(obj_id=skoda_id))
        assert not result.merged  # None should have been transferred

        # Now check that conflicts are correctly handled
        remote_skoda.colour = 'brown'
        remote_skoda.save()
        local_skoda.colour = 'grey'
        local_skoda.save()
        with pytest.raises(mincepy.MergeError):
            local.merge(remote.objects.find(obj_id=skoda_id))
Example #2
0
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)
Example #3
0
def test_delete(historian: mincepy.Historian):
    """Test deleting and then attempting to load an object"""
    car = testing.Car('lada')
    car_id = historian.save(car)
    historian.delete(car)
    with pytest.raises(mincepy.NotFound):
        historian.load(car_id)

    records = historian.history(car_id, as_objects=False)
    assert len(
        records) == 2, 'There should be two record, the initial and the delete'
    assert records[-1].is_deleted_record()

    # Check imperative deleting
    with pytest.raises(mincepy.NotFound):
        historian.delete(car_id)
    # This, should not raise:
    result = historian.delete(car_id, imperative=False)
    assert not result.deleted
    assert car_id in result.not_found
Example #4
0
def test_migrating_live_object(historian: mincepy.Historian):
    """Test that a migration including a live object works fine"""
    class V1(mincepy.ConvenientSavable):
        TYPE_ID = uuid.UUID('8b1620f6-dd6d-4d39-b8b1-4433dc2a54df')
        ref = mincepy.field()

        def __init__(self, obj):
            super().__init__()
            self.ref = obj

    car = testing.Car()
    car.save()

    class V2(mincepy.ConvenientSavable):
        TYPE_ID = uuid.UUID('8b1620f6-dd6d-4d39-b8b1-4433dc2a54df')
        ref = mincepy.field(ref=True)

        class V1toV2(mincepy.ObjectMigration):
            VERSION = 1

            @classmethod
            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

        LATEST_MIGRATION = V1toV2

    martin = testing.Person('martin', 35)
    my_obj = V1(martin)
    my_obj_id = my_obj.save()
    del my_obj

    # Now change my mind
    historian.register_type(V2)
    assert len(historian.migrations.migrate_all()) == 1

    migrated = historian.load(my_obj_id)
    assert migrated.ref is car
Example #5
0
def test_migrate_with_saved(historian: mincepy.Historian):
    """Test migrating an object that has saved references"""
    class V3(mincepy.ConvenientSavable):
        TYPE_ID = StoreByRef.TYPE_ID
        ref = mincepy.field(ref=True)
        description = mincepy.field()

        class Migration(mincepy.ObjectMigration):
            VERSION = 2
            PREVIOUS = StoreByRef.ToRefMigration

            @classmethod
            def upgrade(cls, saved_state, loader: 'mincepy.Loader'):
                saved_state['description'] = None
                return saved_state

        LATEST_MIGRATION = Migration

        def __init__(self, ref):
            super().__init__()
            self.ref = ref
            self.description = None

    obj = StoreByRef(testing.Car())
    obj_id = obj.save()
    del obj
    gc.collect()

    historian.register_type(V3)
    migrated = historian.migrations.migrate_all()
    assert len(migrated) == 1
    assert migrated[0].obj_id == obj_id

    obj = historian.load(obj_id)

    assert isinstance(obj, V3)
    assert hasattr(obj, 'description')
    assert obj.description is None
Example #6
0
def test_migrate_to_reference(historian: mincepy.Historian, caplog):
    caplog.set_level(logging.DEBUG)

    car = testing.Car()
    by_val = StoreByValue(car)
    oid = historian.save(by_val)
    del by_val

    # Now, change my mind
    historian.register_type(StoreByRef)
    # Migrate
    migrated = historian.migrations.migrate_all()
    assert len(migrated) == 1

    by_ref = historian.load(oid)
    assert isinstance(by_ref.ref, testing.Car)
    assert by_ref.ref is not car
    loaded_car = by_ref.ref
    del by_ref

    # Reload and check that ref points to the same car
    loaded = historian.load(oid)
    assert loaded.ref is loaded_car
Example #7
0
def test_objects_collection(historian: mincepy.Historian):
    ferrari = testing.Car(colour='red', make='ferrari')
    ferrari_id = ferrari.save()

    records = list(historian.objects.records.find())
    assert len(records) == 1

    objects = list(historian.objects.find())
    assert len(objects) == 1
    assert objects[0] is ferrari

    ferrari.colour = 'brown'
    ferrari.save()

    records = list(historian.objects.records.find())
    assert len(records) == 1

    objects = list(historian.objects.find())
    assert len(objects) == 1
    assert set(car.colour for car in objects) == {'brown'}

    assert historian.objects.records.find(Car.colour == 'brown',
                                          obj_id=ferrari_id).one().version == 1
Example #8
0
 def execute(self):
     return mincepy.builtins.RefList([testing.Car()])
Example #9
0
 def execute(self):  # pylint: disable=no-self-use
     return mincepy.builtins.RefList([testing.Car()])
Example #10
0
def test_delete():
    car = testing.Car()
    car_id = car.save()
    mincepy.delete(car)
    assert not list(mincepy.find(obj_id=car_id))
Example #11
0
def test_find():
    car = testing.Car()
    car_id = car.save()
    assert list(mincepy.find(obj_id=car_id))[0] is car
Example #12
0
def test_save_load():
    car = testing.Car()
    car_id = mincepy.save(car)
    del car
    # Now try loading
    mincepy.load(car_id)
Example #13
0
def test_find_from_class(historian):
    """Test that we can use the class to search for all objects of that type"""
    car = testing.Car()
    car.save()
    assert list(historian.find(testing.Car)) == [car]