Example #1
0
def test_iter_and_sort():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db, cars=Cars)
    mgr.cars = mgr[Cars]
    mgr.cars.add(Car(gas_level=2, color="green"))
    car = mgr.cars.add(Car(gas_level=3, color="green"))
    with car:
        car.doors.add(gen_objs.doors_row(type="z"))
        car.doors.add(gen_objs.doors_row(type="x"))

    # tables, caches and relations are all sortable, and iterable
    for door in car.doors:
        assert door
    sorted(car.doors)
    sorted(mgr.cars)

    cars = ObjCache(mgr.cars)
    mgr.cars = cars
    sorted(mgr.cars)
Example #2
0
def test_cache():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db, cars=Cars)
    mgr.cars = Cars(mgr)
    orig = mgr.cars
    cars = ObjCache(mgr.cars)

    # replace the table with a cache
    mgr.cars = cars
    mgr.cars.add(Car(gas_level=2, color="green"))
    mgr.cars.add(Car(gas_level=3, color="green"))

    assert cars.select_one(id=1)

    assert cars.count() == 2

    assert orig._cache

    mgr.db.insert("cars", id=99, gas_level=99, color="green")
    mgr.db.insert("cars", id=98, gas_level=98, color="green")

    # this won't hit the db
    # noinspection PyUnresolvedReferences
    assert not any(car.id == 99 for car in mgr.cars.select())

    # this won't hit the db
    assert not cars.select_one(id=99)

    # this will
    assert cars.table.select(id=99)

    # now the cache is full
    assert cars.select(id=99)

    # but still missing others
    assert not cars.select_one(id=98)

    assert cars.reload() == 4

    log.debug(orig._cache)

    # until now
    assert cars.select_one(id=98)
Example #3
0
def test_nested_with():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db, cars=Cars)
    mgr.cars = mgr[Cars]
    car = mgr.cars.add(Car(id=4, gas_level=2))
    with car:
        car.gas_level = 3
        with pytest.raises(OmenLockingError):
            with car:
                car.color = "blx"
    assert db.select_one("cars", id=4).gas_level == 3
Example #4
0
def test_underlying_delete():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db)
    mgr.cars = Cars(mgr)
    car = Car(id=44, gas_level=0, color="green")
    mgr.cars.add(car)
    assert db.select_one("cars", id=car.id)
    db.delete("cars", id=car.id)
    car2 = Car(id=44, gas_level=0, color="green")
    mgr.cars.add(car2)
    assert car2 is not car
    assert mgr.cars.get(id=44) is car2
Example #5
0
def test_unbound_add():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db)
    mgr.cars = Cars(mgr)
    car = Car(id=44, gas_level=0, color="green")
    door = gen_objs.doors_row(type="a")
    car.doors.add(door)
    assert door.carid == car.id
    assert door.carid
    assert door in car.doors
    assert car.doors.select_one(type="a")
    mgr.cars.add(car)
    assert db.select_one("doors", carid=car.id, type="a")
Example #6
0
def test_reload_from_disk():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db)
    mgr.cars = Cars(mgr)
    car = mgr.cars.add(Car(gas_level=0, color="green"))
    assert db.select_one("cars", id=1).color == "green"
    db.update("cars", id=1, color="blue")
    # doesn't notice db change because we have a weakref-cache
    assert car.color == "green"
    car2 = mgr.cars.select_one(id=1)
    # weakref cache
    assert car2 is car
    # db fills to cache on select
    assert car.color == "blue"
Example #7
0
def test_update_only():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db, cars=Cars)
    mgr.cars = mgr[Cars]
    car = mgr.cars.add(Car(id=4, gas_level=2))
    with car:
        car.gas_level = 3
        # hack in the color....
        car.__dict__["color"] = "blue"
        assert "gas_level" in car._changes
        assert "color" not in car._changes
    # color doesn't change in db, because we only update "normally-changed" attributes
    assert db.select_one("cars", id=4).gas_level == 3
    assert db.select_one("cars", id=4).color == "black"
Example #8
0
def test_remove_driver():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db, cars=Cars)
    mgr.cars = mgr[Cars]
    mgr.car_drivers = CarDrivers(mgr)
    Driver = gen_objs.drivers
    mgr.drivers = mgr[Driver]

    car1 = mgr.cars.add(Car(id=1, gas_level=2, color="green"))
    car2 = mgr.cars.add(Car(id=2, gas_level=2, color="green"))

    driver1 = mgr.drivers.new(name="bob")
    driver2 = mgr.drivers.new(name="joe")

    car1.car_drivers.add(CarDriver(carid=car1.id, driverid=driver1.id))
    car2.car_drivers.add(CarDriver(carid=car2.id, driverid=driver1.id))

    assert len(car1.car_drivers) == 1
    assert len(car2.car_drivers) == 1

    for cd in car1.car_drivers:
        car1.car_drivers.remove(cd)

    assert len(car1.car_drivers) == 0
    assert len(car2.car_drivers) == 1

    assert len(list(mgr.db.select("drivers"))) == 2
    assert len(list(mgr.db.select("car_drivers"))) == 1

    car1.car_drivers.add(CarDriver(carid=car1.id, driverid=driver1.id))
    assert len(car1.car_drivers) == 1
    mgr.car_drivers.remove(carid=car1.id, driverid=driver1.id)
    # ok to double-remove
    mgr.car_drivers.remove(carid=car1.id, driverid=driver1.id)
    # removing None is a no-op (ie: remove.(select_one(criteria....)))
    mgr.car_drivers.remove(None)
    assert len(car1.car_drivers) == 0
    assert len(car2.car_drivers) == 1

    car2.car_drivers.add(CarDriver(carid=car2.id, driverid=driver2.id))
    assert len(list(mgr.db.select("car_drivers"))) == 2
    with pytest.raises(OmenMoreThanOneError):
        # kwargs remove is not a generic method for removing all matching things
        # make your own loop if that's what you want
        mgr.car_drivers.remove(carid=car2.id)
Example #9
0
def test_race_sync(tmp_path):
    fname = str(tmp_path / "test.txt")
    db = SqliteDb(fname)
    mgr = MyOmen(db, cars=Cars)
    mgr.cars = mgr[Cars]
    ids = []

    def insert(i):
        h = mgr.cars.row_type(gas_level=i)
        mgr.cars.add(h)
        ids.append(h.id)

    num = 10
    pool = ThreadPool(10)

    pool.map(insert, range(num))

    assert mgr.cars.count() == num
Example #10
0
def test_rollback():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db, cars=Cars)
    mgr.cars = mgr[Cars]
    car = mgr.cars.add(Car(gas_level=2))

    with suppress(ValueError):
        with car:
            car.gas_level = 3
            raise ValueError

    assert car.gas_level == 2

    with car:
        car.gas_level = 3
        raise OmenRollbackError

    assert car.gas_level == 2
Example #11
0
def test_threaded():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db)
    mgr.cars = Cars(mgr)
    car = mgr.cars.add(Car(gas_level=0))
    pool = ThreadPool(10)

    def update_stuff(_i):
        with car:
            car.gas_level += 1

    # lots of threads can update stuff
    num_t = 10
    pool.map(update_stuff, range(num_t))
    assert car.gas_level == num_t

    # written to db
    assert mgr.db.select_one("cars", id=car.id).gas_level == num_t
Example #12
0
def test_weak_cache(caplog):
    # important to disable log capturing/reporting otherwise refs to car() could be out there!
    caplog.clear()
    caplog.set_level("ERROR")

    db = SqliteDb(":memory:")
    mgr = MyOmen(db)
    mgr.cars = Cars(mgr)
    car = mgr.cars.add(Car(gas_level=0))

    # cache works
    car2 = mgr.cars.select_one(gas_level=0)
    assert id(car2) == id(car)
    assert len(mgr.cars._cache.data) == 1

    # weak dict cleans up
    del car
    del car2

    gc.collect()

    assert not mgr.cars._cache.data
Example #13
0
def test_cache_sharing():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db)
    mgr.cars = Cars(mgr)
    cache = ObjCache(mgr.cars)
    car = Car(id=44, gas_level=0, color="green")
    cache.add(car)
    assert car in mgr.cars
    assert car in cache
    db.insert("cars", id=45, gas_level=45, color="blue")
    db.insert("cars", id=46, gas_level=46, color="red")
    assert cache.get(id=44)
    assert not cache.select_one(id=45)
    assert not cache.select_one(id=46)
    assert mgr.cars.select_one(id=45)
    assert cache.select_one(id=45)
    assert mgr.cars.select_one(id=46)
    assert cache.select_one(id=46)

    db.delete("cars", id=44)
    # still cached
    assert cache.get(id=44)
    assert cache.select_one(id=44)
    # still cached, select with a different filter does not clear cache
    assert mgr.cars.select_one(id=45)
    assert cache.select_one(id=44)
    # cache updated by select with matching filter
    assert not mgr.cars.select_one(id=44)
    assert not cache.select_one(id=44)
    # select() with no filter clears cache
    db.delete("cars", id=46)
    assert len(list(mgr.cars.select())) == 1
    assert not cache.select_one(id=46)
    # reload() clears cache
    assert cache.get(id=45)
    db.delete("cars", id=45)
    cache.reload()
    assert not cache.select_one(id=45)
Example #14
0
def test_cache_sharing_threaded():
    db = SqliteDb(":memory:")
    mgr = MyOmen(db)
    mgr.cars = Cars(mgr)
    cache = ObjCache(mgr.cars)
    db.insert("cars", id=12, gas_level=0, color="green")
    assert mgr.cars.select_one(id=12)
    assert cache.select_one(id=12)

    # all threads update gas_level of cached car, only the first thread reloads the cache
    def update_stuff(_i):
        if _i == 0:
            cache.reload()

        # if the cache was cleared in in another thread, this returns None (behavior we want to avoid)
        c = cache.select_one(id=12)
        assert c
        with c:
            c.gas_level += 1

    num_t = 10
    pool = ThreadPool(num_t)
    pool.map(update_stuff, range(num_t))
    assert cache.select_one(id=12).gas_level == num_t