from perspective import Server
import random
import threading
PARENTS = {
"flat": dict(filter=[["y", ">", 2]]),
"group_by": dict(
group_by=["g"],
columns=["x", "y"],
aggregates={"x": "sum", "y": "mean"},
group_rollup_mode="flat",
),
"split_by": dict(
group_by=["g"],
split_by=["s"],
columns=["x"],
group_rollup_mode="flat",
),
}
def _row(rand, i):
return {
"id": i,
"g": rand.choice(["a", "b", "c", "d"]),
"s": rand.choice(["Mon", "Tue", "Wed"]),
"x": rand.randint(0, 4000) / 4,
"y": rand.randint(0, 9),
}
def _key(row):
return sorted((k, str(v)) for k, v in row.items())
def _run(config):
rand = random.Random(7)
client = Server().new_local_client()
table = client.table(
{"id": "integer", "g": "string", "s": "string", "x": "float", "y": "integer"},
index="id",
)
table.update([_row(rand, i) for i in range(60)])
view = table.view(**config)
derived = client.table(view)
child = derived.view()
errors = []
done = threading.Event()
def read():
try:
while not done.is_set():
child.to_columns()
derived.size()
except Exception as e:
errors.append(e)
readers = [threading.Thread(target=read) for _ in range(4)]
for reader in readers:
reader.start()
try:
for _ in range(500):
if rand.random() < 0.2:
table.remove([rand.randint(0, 59) for _ in range(3)])
else:
table.update([_row(rand, rand.randint(0, 59)) for _ in range(4)])
finally:
done.set()
for reader in readers:
reader.join()
assert errors == []
fresh = client.table(view)
expected = fresh.view().to_records()
actual = child.to_records()
assert sorted(map(_key, actual)) == sorted(map(_key, expected))
class TestDerivedTableThreaded(object):
def test_flat_parent(self):
_run(PARENTS["flat"])
def test_group_by_parent(self):
_run(PARENTS["group_by"])
def test_split_by_parent(self):
_run(PARENTS["split_by"])