Example #1
0
def test_meta_set_update_many(historian: mincepy.Historian):
    car1 = Car()
    car2 = Car()
    car1id, car2id = historian.save(car1, car2)
    historian.archive.meta_set_many({
        car1id: {
            'reg': 'car1'
        },
        car2id: {
            'reg': 'car2'
        }
    })

    results = historian.archive.meta_get_many((car1id, car2id))
    assert results == {car1id: {'reg': 'car1'}, car2id: {'reg': 'car2'}}

    historian.archive.meta_update_many({
        car1id: {
            'colour': 'red'
        },
        car2id: {
            'reg': 'car2updated'
        }
    })

    metas = historian.archive.meta_get_many((car1id, car2id))
    assert metas == {
        car1id: {
            'reg': 'car1',
            'colour': 'red'
        },
        car2id: {
            'reg': 'car2updated'
        }
    }
Example #2
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
Example #3
0
def test_meta_set_update_many(historian: mincepy.Historian):
    archive = historian.archive
    # Use the historian to simplify saving of some data
    car1 = Car()
    car2 = Car()
    car1id, car2id = historian.save(car1, car2)

    archive.meta_set_many({car1id: {'reg': 'car1'}, car2id: {'reg': 'car2'}})

    results = archive.meta_get_many((car1id, car2id))
    assert results == {car1id: {'reg': 'car1'}, car2id: {'reg': 'car2'}}

    archive.meta_update_many({
        car1id: {
            'colour': 'red'
        },
        car2id: {
            'reg': 'car2updated'
        }
    })

    metas = archive.meta_get_many((car1id, car2id))
    assert metas == {
        car1id: {
            'reg': 'car1',
            'colour': 'red'
        },
        car2id: {
            'reg': 'car2updated'
        }
    }
Example #4
0
def test_nested_references(historian: mincepy.Historian):
    car = Car()
    garage = Garage(car)

    car_id = historian.save(car)
    garage_id = historian.save(garage)

    # Now change the car
    car.make = 'fiat'
    car.colour = 'white'

    historian.save(car)
    # Try loading while the object is still alive
    loaded_garage = historian.load(garage_id)
    assert loaded_garage is garage

    # Now delete and load
    del garage
    del car
    loaded_garage2 = historian.load(garage_id)
    # Should be the last version fo the car
    assert loaded_garage2.car.make == 'fiat'

    assert len(historian.history(car_id)) == 2
    # The following may seem counter intuitive that we only have one history
    # entry for garage.  But above we only saved it once.  It's just that when
    # we load the garage again we get the 'latest' version it's contents i.e.
    # the newer version of the car
    assert len(historian.history(garage_id)) == 1
Example #5
0
def test_replace_simple(historian: mincepy.Historian):
    def paint_shop(car, colour):
        """An imaginary function that modifies an object but returns a copy rather than an in
        place modification"""
        return Car(car.make, colour)

    honda = Car('honda', 'yellow')
    honda_id = historian.save(honda)

    # Now paint the honda
    new_honda = paint_shop(honda, 'green')
    assert historian.get_obj_id(honda) == honda_id

    # Now we know that this is a 'continuation' of the history of the original honda, so replace
    historian.replace(honda, new_honda)
    assert historian.get_obj_id(honda) is None

    assert historian.get_obj_id(new_honda) == honda_id
    historian.save(new_honda)
    del honda, new_honda

    loaded = historian.load(honda_id)
    assert loaded.make == 'honda'
    assert loaded.colour == 'green'

    with pytest.raises(RuntimeError):
        # Check that we can't replace in a transaction
        with historian.transaction():
            historian.replace(loaded, Car())
Example #6
0
def test_distinct(historian):
    colours = {'red', 'green', 'blue'}
    for colour in colours:
        Car('ferrari', colour=colour).save()
        Car('skoda', colour=colour).save()

    assert set(historian.records.distinct(Car.colour)) == colours
Example #7
0
def test_sync(historian: mincepy.Historian, archive_uri):
    historian2 = mincepy.connect(archive_uri)
    historian2.register_types(mincepy.testing.HISTORIAN_TYPES)

    car = Car('ferrari', 'red')
    historian.save_one(car)

    # Simulate saving the car from another connection
    same_car = historian2.load(car.obj_id)
    same_car.make = 'honda'
    same_car.colour = 'black'
    same_car.save()
    honda_record = historian2.get_current_record(same_car)
    del same_car

    # Now update and check the state
    historian.sync(car)
    assert car.make == 'honda'
    assert car.colour == 'black'

    # Also, check the cached record
    car_record = historian.get_current_record(car)
    assert car_record.snapshot_hash == honda_record.snapshot_hash
    assert car_record.state == honda_record.state

    # Check that syncing an unsaved object returns False (because there's nothing to do)
    assert historian.sync(Car()) is False

    # Test syncing an object that is deleted
    historian2.delete(car.obj_id)
    with pytest.raises(mincepy.NotFound):
        car.sync()
Example #8
0
def test_history(historian: mincepy.Historian):
    rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']

    car = Car()
    car_id = None
    for colour in rainbow:
        car.colour = colour
        car_id = historian.save(car)

    car_history = historian.history(car_id)
    assert len(car_history) == len(rainbow)
    for i, entry in enumerate(car_history):
        assert entry[1].colour == rainbow[i]

    # Test loading directly from snapshot id
    assert historian.load_snapshot(car_history[2].ref) == car_history[2].obj

    # Test slicing
    assert historian.history(car_id, -1)[0].obj.colour == rainbow[-1]

    # Try changing history
    old_version = car_history[2].obj
    old_version.colour = 'black'
    with pytest.raises(mincepy.ModificationError):
        historian.save(old_version)
Example #9
0
def test_meta_on_delete(historian: mincepy.Historian):
    """Test that metadata gets deleted when the object does"""
    car = Car()
    car_id = car.save(meta={'reg': '1234'})

    assert historian.meta.get(car_id) == {'reg': '1234'}
    historian.delete(car_id)
    assert historian.meta.get(car_id) is None
Example #10
0
def test_metadata_find_objects(historian: mincepy.Historian):
    honda = Car('honda', 'white')
    honda2 = Car('honda', 'white')
    historian.save_one(honda, meta={'reg': 'H123', 'vin': 1234})
    historian.save(honda2)

    results = list(historian.find(Car, meta={'reg': 'H123'}))
    assert len(results) == 1
Example #11
0
def test_metadata_multiple(historian: mincepy.Historian):
    honda = Car('honda', 'white')
    zonda = Car('zonda', 'yellow')

    historian.save((honda, {'reg': 'H123'}), (zonda, {'reg': 'Z456'}))

    assert historian.meta.get(honda) == {'reg': 'H123'}
    assert historian.meta.get(zonda) == {'reg': 'Z456'}
Example #12
0
def test_meta_find(historian: mincepy.Historian):
    car1 = Car()
    car2 = Car()

    car1id, _ = historian.save(car1, car2)
    historian.archive.meta_set(car1id, {'reg': 'car1'})

    results = dict(historian.archive.meta_find({}, (car1id, )))
    assert results == {car1id: {'reg': 'car1'}}
Example #13
0
def test_meta_unique_index(historian: mincepy.Historian):
    historian.meta.create_index('reg', True)
    car = Car()
    car.save(meta={'reg': 'VD495'})

    historian.archive.meta_find(dict(reg='VD495'))

    with pytest.raises(mincepy.DuplicateKeyError):
        Car().save(meta={'reg': 'VD495'})
Example #14
0
def test_to_obj_id(historian: mincepy.Historian):
    car = Car()
    car_id = car.save()

    assert historian.to_obj_id(car_id) is car_id
    assert historian.to_obj_id(car) == car_id
    assert historian.to_obj_id(str(car_id)) == car_id
    assert historian.to_obj_id('carrot') is None
    assert historian.to_obj_id(historian.get_snapshot_id(car)) == car_id
Example #15
0
def test_tuple_helper(historian: mincepy.Historian):
    historian.register_type(mincepy.common_helpers.TupleHelper())

    container = mincepy.builtins.List()
    container.append((Car('ferrari'), ))

    container_id = historian.save(container)
    del container
    loaded = historian.load(container_id)
    assert loaded[0][0] == Car('ferrari')
Example #16
0
def test_meta_stick_copy(historian: mincepy.Historian):
    """Test that sticky meta is applied to objects that are copied.  Issue #13:
    https://github.com/muhrin/mincepy/issues/13"""
    car = Car()
    historian.meta.sticky.update({'owner': 'martin'})
    car.save()
    car_copy = mincepy.copy(car)
    car_copy.save()

    assert historian.meta.get(car) == {'owner': 'martin'}
    assert historian.meta.get(car_copy) == {'owner': 'martin'}
Example #17
0
def test_count(historian: mincepy.Historian):
    archive = historian.archive
    car1 = Car('ferrari')
    car2 = Car('skoda')
    car1id, car2id = historian.save(car1, car2)

    archive.meta_set_many({car1id: {'reg': 'car1'}, car2id: {'reg': 'car2'}})

    assert archive.count() == 2
    assert archive.count(state=dict(make='ferrari')) == 1
    assert archive.count(meta=dict(reg='car1')) == 1
Example #18
0
def test_meta_update_many(historian: mincepy.Historian):
    archive = historian.archive
    car1 = Car()
    car2 = Car()
    car1id, car2id = historian.save(car1, car2)

    archive.meta_set_many({car1id: {'reg': 'car1'}, car2id: {'reg': 'car2'}})

    results = archive.meta_get_many((car1id, car2id))
    assert results[car1id] == {'reg': 'car1'}
    assert results[car2id] == {'reg': 'car2'}
Example #19
0
def test_meta_set(historian: mincepy.Historian):
    archive = historian.archive
    # Use the historian to simplify saving of some data
    car1 = Car()
    car1.save()

    archive.meta_set(car1.obj_id, {'some': 'meta'})
    assert archive.meta_get(car1.obj_id) == {'some': 'meta'}

    # Try settings invalid id
    with pytest.raises(mincepy.NotFound):
        archive.meta_set(bson.ObjectId(), {'some': 'meta'})
Example #20
0
def test_meta_transaction(historian: mincepy.Historian):
    """Check that metadata respects transaction boundaries"""
    car1 = Car()

    with historian.transaction():
        car1.save()
        with historian.transaction() as trans:
            historian.meta.set(car1.obj_id, {'spurious': True})
            assert historian.meta.get(car1.obj_id) == {'spurious': True}
            trans.rollback()
        assert not historian.meta.get(car1)
    assert not historian.meta.get(car1)
Example #21
0
def test_metadata_using_object_instance(historian: mincepy.Historian):
    car = Car()
    historian.save((car, {'reg': 'VD395'}))
    # Check that we get back what we just set
    assert historian.meta.get(car) == {'reg': 'VD395'}

    car.make = 'fiat'
    historian.save(car)
    # Check that the metadata is shared
    assert historian.meta.get(car) == {'reg': 'VD395'}

    historian.meta.set(car, {'reg': 'N317'})
    assert historian.meta.get(car) == {'reg': 'N317'}
Example #22
0
def test_meta_delete(historian: mincepy.Historian):
    """Test that when an object is delete so is its metadata"""
    car = Car()
    car_id = car.save(meta={'reg': '1234'})
    results = dict(historian.meta.get(car))
    assert results == {'reg': '1234'}

    historian.delete(car)

    assert historian.meta.get(car_id) is None

    results = tuple(historian.meta.find({}, obj_id=car_id))
    assert len(results) == 0
Example #23
0
def test_meta_find(historian: mincepy.Historian):
    archive = historian.archive
    car1 = Car()
    car2 = Car()

    car1id, _ = historian.save(car1, car2)
    archive.meta_set(car1id, {'reg': 'car1'})

    results = dict(archive.meta_find({}, (car1id, )))
    assert results == {car1id: {'reg': 'car1'}}

    # No metadata on car2
    assert not list(archive.meta_find(obj_id=car2.obj_id))
Example #24
0
def test_find_cars(historian: mincepy.Historian, benchmark, num):
    """Test finding a car as a function of the number of entries in the database"""
    # Put in the one we want to find
    historian.save(Car('honda', 'green'))

    # Put in the correct number of random other entries
    for _ in range(num):
        historian.save(Car(utils.random_str(10), utils.random_str(5)))

    result = benchmark(find,
                       historian,
                       state=dict(make='honda', colour='green'))
    assert len(result) == 1
Example #25
0
def test_loading_snapshot(historian: mincepy.Historian):
    honda = Car('honda', 'white')
    historian.save(honda)
    white_honda_sid = historian.get_snapshot_id(honda)
    honda.colour = 'red'
    historian.save(honda)
    del honda

    with historian.transaction():
        white_honda = historian.load_snapshot(white_honda_sid)
        assert white_honda.colour == 'white'
        # Make sure that if we load it again we get a different object instance
        assert white_honda is not historian.load_snapshot(white_honda_sid)
Example #26
0
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()
Example #27
0
def test_meta_sticky_children(historian: mincepy.Historian):
    """Catch bug where metadata was not being set on being references by other objects"""
    garage = mincepy.RefList()
    garage.append(Car())
    garage.append(Car())
    historian.meta.sticky['owner'] = 'martin'

    garage_id = garage.save()
    car0_id = garage[0].save(meta={'for_sale': True})
    car1_id = garage[1].save(meta={'owner': 'james'})
    del garage

    assert historian.meta.get(garage_id) == {'owner': 'martin'}
    assert historian.meta.get(car0_id) == {'owner': 'martin', 'for_sale': True}
    assert historian.meta.get(car1_id) == {'owner': 'james'}
Example #28
0
def test_metadata_simple(historian: mincepy.Historian):
    car = Car()
    ferrari_id = historian.save((car, {'reg': 'VD395'}))
    # Check that we get back what we just set
    assert historian.meta.get(ferrari_id) == {'reg': 'VD395'}

    car.make = 'fiat'
    red_fiat_id = historian.save(car)
    # Check that the metadata is shared
    assert historian.meta.get(red_fiat_id) == {'reg': 'VD395'}

    historian.meta.set(ferrari_id, {'reg': 'N317'})
    # Check that this saves the metadata on the object level i.e. both are changed
    assert historian.meta.get(ferrari_id) == {'reg': 'N317'}
    assert historian.meta.get(red_fiat_id) == {'reg': 'N317'}
Example #29
0
def test_storing_internal_object(historian: mincepy.Historian):

    class Person(mincepy.SavableObject):
        TYPE_ID = uuid.UUID('f6f83595-6375-4bc4-89f2-d8f31a1286b0')

        def __init__(self, car):
            super().__init__()
            self.car = car  # This person 'owns' the car

        def __eq__(self, other):
            return self.car == other.car

        def yield_hashables(self, hasher):
            yield from hasher.yield_hashables(self.car)

        def save_instance_state(self, _depositor):
            return {'car': self.car}

        def load_instance_state(self, saved_state, _depositor):
            self.car = saved_state['car']

    ferrari = Car('ferrari')
    mike = Person(ferrari)

    mike_id = historian.save(mike)
    del mike

    loaded_mike = historian.load(mike_id)
    assert loaded_mike.car.make == 'ferrari'

    # Default is to save by value so two cars should not be the same
    assert loaded_mike.car is not ferrari
    assert loaded_mike.car == ferrari  # But values should match
Example #30
0
def test_encode_nested(historian: mincepy.Historian):

    class CarDelegate(mincepy.SimpleSavable):
        TYPE_ID = uuid.UUID('c0148a43-c0c0-4d2b-9262-ed1c8c6ab2fc')
        ATTRS = ('car',)

        def __init__(self, car):
            super().__init__()
            self.car = car

        def save_instance_state(self, saver):
            return {'car': self.car}

        def load_instance_state(self, saved_state, _loader):
            self.car = saved_state['car']

    historian.register_type(CarDelegate)

    car = Car()
    delegate = CarDelegate(car)
    garage = Garage(delegate)

    garage_id = historian.save(garage)
    del garage

    historian.load(garage_id)