Add benchmarks
This commit is contained in:
301
tests/benchmark/helpers.py
Normal file
301
tests/benchmark/helpers.py
Normal file
@@ -0,0 +1,301 @@
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from dibbler.models import Product, Transaction, TransactionType, User
|
||||
from dibbler.queries import joint_buy_product
|
||||
|
||||
|
||||
def insert_users_and_products(
|
||||
sql_session: Session, user_count: int = 10, product_count: int = 10
|
||||
) -> tuple[list[User], list[Product]]:
|
||||
users = []
|
||||
for i in range(user_count):
|
||||
user = User(f"User{i + 1}")
|
||||
sql_session.add(user)
|
||||
users.append(user)
|
||||
sql_session.commit()
|
||||
|
||||
products = []
|
||||
for i in range(product_count):
|
||||
barcode = str(1000000000000 + i)
|
||||
product = Product(barcode, f"Product{i + 1}")
|
||||
sql_session.add(product)
|
||||
products.append(product)
|
||||
sql_session.commit()
|
||||
|
||||
return users, products
|
||||
|
||||
|
||||
def generate_random_transactions(
|
||||
sql_session: Session,
|
||||
n: int,
|
||||
seed: int = 42,
|
||||
transaction_type_filter: list[TransactionType] | None = None,
|
||||
distribution: dict[TransactionType, float] | None = None,
|
||||
) -> list[Transaction]:
|
||||
random.seed(seed)
|
||||
|
||||
if transaction_type_filter is None:
|
||||
transaction_type_filter = list(TransactionType)
|
||||
|
||||
if TransactionType.JOINT_BUY_PRODUCT in transaction_type_filter:
|
||||
transaction_type_filter.remove(TransactionType.JOINT_BUY_PRODUCT)
|
||||
|
||||
# TODO: implement me
|
||||
if TransactionType.THROW_PRODUCT in transaction_type_filter:
|
||||
transaction_type_filter.remove(TransactionType.THROW_PRODUCT)
|
||||
|
||||
if distribution is None:
|
||||
distribution = {t: 1 / len(transaction_type_filter) for t in transaction_type_filter}
|
||||
transaction_types = list(distribution.keys())
|
||||
weights = list(distribution.values())
|
||||
transactions: list[Transaction] = []
|
||||
last_time = datetime(2023, 1, 1, 0, 0, 0)
|
||||
for _ in range(n):
|
||||
transaction_type = random.choices(transaction_types, weights=weights, k=1)[0]
|
||||
generator = RANDOM_GENERATORS[transaction_type]
|
||||
transaction_or_transactions = generator(sql_session, last_time)
|
||||
if isinstance(transaction_or_transactions, list):
|
||||
transactions.extend(transaction_or_transactions)
|
||||
last_time = max(t.time for t in transaction_or_transactions)
|
||||
else:
|
||||
transactions.append(transaction_or_transactions)
|
||||
last_time = transaction_or_transactions.time
|
||||
return transactions
|
||||
|
||||
|
||||
EXCEPTION_LIMIT = 15
|
||||
|
||||
|
||||
def random_add_product_transaction(sql_session: Session, last_time: datetime) -> Transaction:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
user = random.choice(sql_session.query(User).all())
|
||||
product = random.choice(sql_session.query(Product).all())
|
||||
product_count = random.randint(1, 10)
|
||||
product_price = random.randint(15, 45)
|
||||
amount = product_count * product_price + random.randint(-7, 0)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
try:
|
||||
transaction = Transaction.add_product(
|
||||
amount,
|
||||
user.id,
|
||||
product.id,
|
||||
product_price,
|
||||
product_count,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transaction
|
||||
|
||||
|
||||
def random_adjust_balance_transaction(sql_session: Session, last_time: datetime) -> Transaction:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
user = random.choice(sql_session.query(User).all())
|
||||
amount = random.randint(-50, 100)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
try:
|
||||
transaction = Transaction.adjust_balance(
|
||||
amount,
|
||||
user.id,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transaction
|
||||
|
||||
|
||||
def random_adjust_interest_transaction(sql_session: Session, last_time: datetime) -> Transaction:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
user = random.choice(sql_session.query(User).all())
|
||||
amount = random.randint(-5, 5)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
try:
|
||||
transaction = Transaction.adjust_interest(
|
||||
amount,
|
||||
user.id,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transaction
|
||||
|
||||
|
||||
def random_adjust_penalty_transaction(sql_session: Session, last_time: datetime) -> Transaction:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
user = random.choice(sql_session.query(User).all())
|
||||
penalty_multiplier_percent = random.randint(100, 200)
|
||||
penalty_threshold = random.randint( -150, -50)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
try:
|
||||
transaction = Transaction.adjust_penalty(
|
||||
penalty_multiplier_percent,
|
||||
penalty_threshold,
|
||||
user.id,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transaction
|
||||
|
||||
|
||||
def random_adjust_stock_transaction(sql_session: Session, last_time: datetime) -> Transaction:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
user = random.choice(sql_session.query(User).all())
|
||||
product = random.choice(sql_session.query(Product).all())
|
||||
stock_change = random.randint(-5, 6)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
try:
|
||||
transaction = Transaction.adjust_stock(
|
||||
user_id=user.id,
|
||||
product_id=product.id,
|
||||
product_count=stock_change,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transaction
|
||||
|
||||
|
||||
def random_buy_product_transaction(sql_session: Session, last_time: datetime) -> Transaction:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
user = random.choice(sql_session.query(User).all())
|
||||
product = random.choice(sql_session.query(Product).all())
|
||||
product_count = random.randint(1, 5)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
try:
|
||||
transaction = Transaction.buy_product(
|
||||
user_id=user.id,
|
||||
product_id=product.id,
|
||||
product_count=product_count,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transaction
|
||||
|
||||
|
||||
def random_joint_transaction(sql_session: Session, last_time: datetime) -> list[Transaction]:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
user_count = random.randint(2, 4)
|
||||
users = random.sample(sql_session.query(User).all(), k=user_count)
|
||||
product = random.choice(sql_session.query(Product).all())
|
||||
product_count = random.randint(1, 5)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
|
||||
try:
|
||||
transactions = joint_buy_product(
|
||||
sql_session,
|
||||
product=product,
|
||||
product_count=product_count,
|
||||
instigator=users[0],
|
||||
users=users,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transactions
|
||||
|
||||
|
||||
def random_transfer_transaction(sql_session: Session, last_time: datetime) -> Transaction:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
sender, receiver = random.sample(sql_session.query(User).all(), k=2)
|
||||
amount = random.randint(1, 50)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
try:
|
||||
transaction = Transaction.transfer(
|
||||
amount,
|
||||
sender.id,
|
||||
receiver.id,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transaction
|
||||
|
||||
|
||||
def random_throw_product_transaction(sql_session: Session, last_time: datetime) -> Transaction:
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
user = random.choice(sql_session.query(User).all())
|
||||
product = random.choice(sql_session.query(Product).all())
|
||||
product_count = random.randint(1, 5)
|
||||
new_datetime = last_time + timedelta(minutes=random.randint(1, 60))
|
||||
try:
|
||||
transaction = Transaction.throw_product(
|
||||
user_id=user.id,
|
||||
product_id=product.id,
|
||||
product_count=product_count,
|
||||
time=new_datetime,
|
||||
)
|
||||
except Exception:
|
||||
if i > EXCEPTION_LIMIT:
|
||||
raise RuntimeError(
|
||||
"Too many failed attempts to create a valid transaction, consider changing the seed"
|
||||
)
|
||||
continue
|
||||
return transaction
|
||||
|
||||
|
||||
RANDOM_GENERATORS = {
|
||||
TransactionType.ADD_PRODUCT: random_add_product_transaction,
|
||||
TransactionType.ADJUST_BALANCE: random_adjust_balance_transaction,
|
||||
TransactionType.ADJUST_INTEREST: random_adjust_interest_transaction,
|
||||
TransactionType.ADJUST_PENALTY: random_adjust_penalty_transaction,
|
||||
TransactionType.ADJUST_STOCK: random_adjust_stock_transaction,
|
||||
TransactionType.BUY_PRODUCT: random_buy_product_transaction,
|
||||
TransactionType.JOINT: random_joint_transaction,
|
||||
TransactionType.TRANSFER: random_transfer_transaction,
|
||||
TransactionType.THROW_PRODUCT: random_throw_product_transaction,
|
||||
}
|
||||
Reference in New Issue
Block a user