def test_single_transactions(self): user1 = self.session.query(models.User).get(1) user4 = self.session.query(models.User).get(4) user1_balance = user1.balance user4_balance = user4.balance # Negative or zero amount is forbidden for v in [0, -1, -2, -52, 0.3, 0.9, -1e7]: with self.assertRaises(ValueError): transactions.create_transaction(user1, user4, v, "", self.session, logging.getLogger()) self.assertEqual(user1_balance, user1.balance) self.assertEqual(user4_balance, user4.balance) # Don't allow transactions of unknown users with self.assertRaises(ValueError): transactions.create_transaction(models.User(), user1, 42, "", self.session, logging.getLogger()) total = 0 for i, v in enumerate([3, 41, 51, 9, 3]): t = transactions.create_transaction(user4, user1, v, "", self.session, logging.getLogger()) total += v self.assertEqual(t.id, i+1) self.assertEqual(t.amount, v) self.assertEqual(t.multi_transaction, None) self.assertEqual(user1.balance, user1_balance + total) self.assertEqual(user4.balance, user4_balance - total) self.assertEqual(i+1, len(self.session.query(models.Transaction).all()))
def get_sample_users() -> List[models.User]: return [ models.User(name="user1", balance=-42, external=True), models.User(name="user2", balance=51, external=False), models.User(name="user3", external=True), models.User(name="user4", balance=2, external=False), models.User(name="user5", permission=False, active=False, external=False, voucher_id=2), models.User(external=False), models.User(name="community", external=False, special=True, balance=2, permission=True) ]
def make_special_user(self, community_name: str = "Community"): opts = {"echo": conf.SQLALCHEMY_ECHOING} if self.database_url.startswith("sqlite:"): opts = {"connect_args": {"check_same_thread": False}} engine = sqlalchemy.create_engine(self.database_url, **opts) session = sqlalchemy.orm.sessionmaker(autocommit=False, autoflush=False, bind=engine)() specials = session.query(models.User).filter_by(special=True).all() if len(specials) > 1: self.fail("CRITICAL ERROR. Please drop a bug report.") if len(specials) == 0: session.add( models.User(active=True, special=True, external=False, permission=False, name=community_name)) session.commit() session.close()
def test_multi_transactions(self): self.session.add_all(self.get_sample_users()) self.session.commit() # Three people donate their money to one m1 = models.MultiTransaction(base_amount=4) self.session.add(m1) self.session.commit() self.session.add_all([ models.Transaction(sender_id=2, receiver_id=1, amount=4, multi_transaction_id=1), models.Transaction(sender_id=3, receiver_id=1, amount=4, multi_transaction_id=1), models.Transaction(sender_id=4, receiver_id=1, amount=4, multi_transaction_id=1) ]) self.session.commit() self.assertEqual(m1.base_amount, 4) self.assertEqual(m1.schema.total_amount, 12) # Four people get paid by one equally m2 = models.MultiTransaction(base_amount=3) self.session.add(m2) self.session.commit() self.session.add_all([ models.Transaction(sender_id=2, receiver_id=1, amount=2, multi_transaction_id=2), models.Transaction(sender_id=2, receiver_id=3, amount=2, multi_transaction_id=2), models.Transaction(sender_id=2, receiver_id=5, amount=2, multi_transaction_id=2), models.Transaction(sender_id=2, receiver_id=6, amount=2, multi_transaction_id=2) ]) self.session.commit() self.assertEqual(m2.schema.total_amount, 8) # Six people pay to two guys unequally (6th person payer pays twice) self.session.add(models.User(balance=-132, external=False)) self.session.add(models.User(balance=3, external=False)) m3 = models.MultiTransaction(base_amount=10) self.session.add(m3) self.session.commit() self.session.add_all([ models.Transaction(sender_id=1, receiver_id=8, amount=10, multi_transaction_id=3), models.Transaction(sender_id=1, receiver_id=9, amount=10, multi_transaction_id=3), models.Transaction(sender_id=2, receiver_id=8, amount=10, multi_transaction_id=3), models.Transaction(sender_id=2, receiver_id=9, amount=10, multi_transaction_id=3), models.Transaction(sender_id=3, receiver_id=8, amount=10, multi_transaction_id=3), models.Transaction(sender_id=3, receiver_id=9, amount=10, multi_transaction_id=3), models.Transaction(sender_id=4, receiver_id=8, amount=10, multi_transaction_id=3), models.Transaction(sender_id=4, receiver_id=9, amount=10, multi_transaction_id=3), models.Transaction(sender_id=5, receiver_id=8, amount=10, multi_transaction_id=3), models.Transaction(sender_id=5, receiver_id=9, amount=10, multi_transaction_id=3), models.Transaction(sender_id=6, receiver_id=8, amount=20, multi_transaction_id=3), models.Transaction(sender_id=6, receiver_id=9, amount=20, multi_transaction_id=3) ]) self.session.commit() self.assertEqual(len(m3.transactions), 12) self.assertEqual(m3.schema.total_amount, 140)
def init_project(args: argparse.Namespace) -> int: settings = _settings.read_settings_from_json_source(False) if not settings: print( "No settings file found. A basic config will be created now interactively." ) settings = _settings.get_default_config() if args.database: settings["database"]["connection"] = args.database else: print( "\nEnter the full database connection string below. It's required to make the " "project persistent. It uses an in-memory sqlite3 database by default (press " "Enter to use that default). Note that the in-memory database does not work " "properly in all environments. A persistent database is highly recommended." ) settings["database"]["connection"] = input( "> ") or settings["database"]["connection"] with open(_settings.CONFIG_PATHS[0], "w") as f: json.dump(settings, f, indent=4) else: print( "A config file has been found. Consider removing it before continuing to avoid inconsistencies." ) config = _settings.config.CoreConfig( **_settings.read_settings_from_json_source(False)) database.init(config.database.connection, config.database.echo) session = database.get_new_session() if not args.no_community: specials = session.query(models.User).filter_by(special=True).all() if len(specials) > 1: raise RuntimeError("CRITICAL ERROR. Please drop a bug report.") if len(specials) == 0: session.add( models.User(active=True, special=True, external=False, permission=False, name=args.community)) session.commit() if len(session.query(models.Application).all()) == 0 or args.application: name = args.application if not name: print( "\nThere's no registered application yet. Nobody can use the API " "without an application account. Skip this step by pressing Enter. " "Otherwise type in the name of the new application account below." ) name = input("> ") if len(session.query( models.Application).filter_by(name=name).all()) > 0: print( f"An application with the given name {name!r} already " f"exists. Therefore, it can't be created. Exiting.", file=sys.stderr) session.flush() session.close() return 1 passwd = args.password if not passwd and name: print( f"\nThe new application {name!r} needs a password to properly authenticate " "against the API in production later on. Enter the password below. " "Make sure that the password meets good length & strength standards. " "Note that pressing Enter will not create the new application!" ) passwd = input("> ") if name and not passwd: print("No new application account created!") elif name and passwd: salt = secrets.token_urlsafe(16) password = models.Password(salt=salt, passwd=auth.hash_password(passwd, salt)) session.add(models.Application(name=name, password=password)) session.commit() session.flush() session.close() print("Done.") return 0