def test_divide_pool_uneven_5(self): POOL_BANK_ID = 14 CHOICE_SET = [21, 22, 23] USER_IDS = [1, 2, 3, 4, 5] USER_BANK_IDS = [101, 102, 103, 104, 105] self.mock_cursor.fetchone.side_effect = [("poll1", True, 45), (POOL_BANK_ID, 225)] self.mock_cursor.fetchall.side_effect = [[ (1, 21, 101), (2, 22, 102), (3, 22, 103), (4, 22, 104), (5, 22, 105), ]] result = divide_pool(10, 22, self.mock_cursor, self.mock_conn) user1_transaction = Transaction(14, 101, 'payout', 0) user2_transaction = Transaction(14, 102, 'payout', 56) user3_transaction = Transaction(14, 103, 'payout', 57) user4_transaction = Transaction(14, 104, 'payout', 56) user5_transaction = Transaction(14, 105, 'payout', 56) expected_transactions = [ user1_transaction, user2_transaction, user3_transaction, user4_transaction, user5_transaction ] self.assertTrue(check_equal(expected_transactions, result))
def test_generate_sql(self): transaction = Transaction(self.from_id, self.to_id, self.category, self.amount) result = transaction.generate_sql() self.assertEqual( "INSERT INTO transactions (from_entity, to_entity, type, balance) " "values (31, 21, 'bet', 50)", result)
def test_create_single_list(self): transaction1 = Transaction(self.from_id, self.to_id, self.category, self.amount) all_transactions = [transaction1] result = Transaction.create_list_sql(all_transactions) expected_result = "INSERT INTO transactions (from_entity, to_entity, type, balance) values " \ "(31, 21, 'bet', 50)" self.assertEqual(expected_result, result)
def send_transactions(poll_id: int, correct_id: int, transactions: List[Transaction], cursor, connection): """ this method takes transactions, puts them into the db and marks the poll as paid out. it also asks you to verify :param poll_id: :param transactions: :param cursor: :param connection: :return: """ total = 0 sys.stdout.write("\n\nThese are the transactions that are going to be written to the db:\n") for idx, transaction in enumerate(transactions): sys.stdout.write("%d) %s\n" % (idx+1, str(transaction))) total += transaction.amount sys.stdout.write("A total of %d coins are going to sent from the poll.\n\n" % total) result = input("Does this look correct to you? ") if result in no: sys.stderr.write("\nUser-initiated abort. Closing..\n\n") sys.exit() elif result in yes: pass else: sys.stderr.write("\nPlease respond with 'yes' or 'no'.\n\n") sys.exit() # write sql to insert these try: insert_query = Transaction.create_list_sql(transactions) print(insert_query) cursor.execute(insert_query) for transaction in transactions: update_user_bank_sql = "UPDATE banks SET balance=balance + %d WHERE id=%d" % (transaction.amount, transaction.to_id) print(update_user_bank_sql) cursor.execute(update_user_bank_sql) update_poll_bank_sql = "UPDATE banks SET balance=0 WHERE id=%d" % transactions[0].from_id print(update_poll_bank_sql) cursor.execute(update_poll_bank_sql) update_poll_sql = "UPDATE polls SET has_paid=true, correct_answer=%d WHERE id=%d" % (correct_id, poll_id) print(update_poll_sql) cursor.execute(update_poll_sql) except Exception as e: connection.rollback() sys.stderr.write("\nCaught an error: %s" % e) sys.stderr.write("\nAborting now, and rolling back all changes..\n\n") sys.exit() # update poll balance, update balance of respective users # update poll to be paid out, along with correct choice id connection.commit() print("bomb")
def test_transaction_constructor(self): transaction = Transaction(self.from_id, self.to_id, self.category, self.amount) self.assertEqual(self.from_id, transaction.from_id) self.assertEqual(self.to_id, transaction.to_id) self.assertEqual(self.category, transaction.category) self.assertEqual(self.amount, transaction.amount)
def test_from_user_transaction(self): test_transaction = Transaction(self.user_bank_id, self.poll_bank_id, 'bet', 130) notification = Notification.from_transaction(test_transaction, self.mock_cursor, self.mock_connection) self.assertIsNone(notification) self.mock_cursor.execute.assert_not_called()
def test_divide_pool_two_winners(self): POOL_BANK_ID = 14 CHOICE_SET = [21, 22, 23] USER_IDS = [1, 2, 3, 4, 5] USER_BANK_IDS = [101, 102, 103, 104, 105] self.mock_cursor.fetchone.side_effect = [("poll1", True, 100), (POOL_BANK_ID, 200)] self.mock_cursor.fetchall.side_effect = [[ (1, 22, 101), (2, 22, 102), ]] result = divide_pool(10, 22, self.mock_cursor, self.mock_conn) user1_transaction = Transaction(14, 101, 'payout', 100) user2_transaction = Transaction(14, 102, 'payout', 100) expected_transactions = [user1_transaction, user2_transaction] self.assertTrue(check_equal(expected_transactions, result))
def test_from_transaction(self): test_transaction = Transaction(self.poll_bank_id, self.user_bank_id, 'payout', 121) self.mock_cursor.fetchone.side_effect = [[21]] notification = Notification.from_transaction(test_transaction, self.mock_cursor, self.mock_connection) self.mock_cursor.execute.assert_called_once_with( "SELECT entity_id FROM banks WHERE id=%s and type='user'", (self.user_bank_id, )) self.assertEqual(21, notification.user_id) self.assertEqual("You just won 121 coins from your latest bet!", notification.message)
def test_batch_generate_sql(self): transaction = Transaction(self.from_id, self.to_id, self.category, self.amount) result = transaction.generate_sql(is_batch=True) self.assertEqual("(31, 21, 'bet', 50)", result)
def divide_pool(poll_id: int, correct_id: int, cursor, conn) -> List[Transaction]: """ this method collects all the bets and divides up :param poll_id: integer poll id :param correct_id: int choice id :param cursor: psycopg2 cursor :param conn: psycopg2 connection :return: list of transaction objects """ poll_query = "SELECT title, finished, buy_in FROM polls WHERE id=%d" % poll_id cursor.execute(poll_query) poll_result = cursor.fetchone() poll_buyin = poll_result[2] banks_query = "SELECT id, balance FROM banks WHERE entity_id=%d and type='poll' limit 1" % poll_id cursor.execute(banks_query) bank_result = cursor.fetchone() poll_bank_id = bank_result[0] balance_pool_size = bank_result[1] transactions_query = "SELECT user_id, choice_id, banks.id FROM bets left join banks on " \ "banks.entity_id=bets.user_id where banks.type='user' and poll_id=%d" % poll_id cursor.execute(transactions_query) transactions_results = cursor.fetchall() pool_size = len(transactions_results) * poll_buyin print("balance pool size: %d" % balance_pool_size) print("pool size: %d" % pool_size) if pool_size != balance_pool_size: print("the balance records don't match.. womp womp") raise Exception("transaction mismatch") answer_sums = {} payout_map = {} # a dict with bank ids with their respective balances winner_payout_array = [] loser_payout_array = [] for bet in transactions_results: answer_sums[bet[1]] = answer_sums.get(bet[1], 0) + 1 if bet[1] == correct_id: payout_map[bet[2]] = 0 winner_payout_array.append(bet[2]) else: loser_payout_array.append(bet[2]) if len(winner_payout_array) < 1: # no winners... return all the money to the losers losing_transactions = [] loser_total = 0 for loser in loser_payout_array: new_lose_transaction = Transaction(poll_bank_id, loser, 'payout', poll_buyin) losing_transactions.append(new_lose_transaction) loser_total += poll_buyin if loser_total != pool_size: print('we got a problem, no winners, and loser transactions didn\'t add up') raise Exception("transaction mismatch") return losing_transactions for coin in range(1, pool_size+1): bank_id = winner_payout_array[coin % len(winner_payout_array)] payout_map[bank_id] += 1 print(payout_map) new_total = 0 transactions = [] # add the winner transactions for key in payout_map: new_transactions = Transaction(poll_bank_id, key, 'payout', payout_map[key]) new_total += payout_map[key] transactions.append(new_transactions) # add the loser transactions for loser in loser_payout_array: new_transaction = Transaction(poll_bank_id, loser, 'payout', 0) transactions.append(new_transaction) if new_total != pool_size: sys.stderr.write("transactions distribution doesn't match up.. expected %d but got %d" % ( pool_size, new_total )) sys.exit() return transactions