def test_authorisation():
    key = PrivateKey()

    resource = uuid.uuid4()

    auth = Authorisation(resource=resource, testing_key=key)

    auth.verify(resource=resource, testing_key=key.public_key())

    wrong_key = PrivateKey()

    with pytest.raises(PermissionError):
        auth.verify(resource=resource, testing_key=wrong_key.public_key())

    wrong_resource = uuid.uuid4()

    with pytest.raises(PermissionError):
        auth.verify(resource=wrong_resource, testing_key=key.public_key())

    data = auth.to_data()

    new_auth = Authorisation.from_data(data)

    new_auth.verify(resource=resource, testing_key=key.public_key())

    with pytest.raises(PermissionError):
        new_auth.verify(resource=resource, testing_key=wrong_key.public_key())

    with pytest.raises(PermissionError):
        new_auth.verify(resource=wrong_resource, testing_key=key.public_key())
    def perform_transaction(key, result):
        delta1 = zero
        delta2 = zero

        # need to work with thread-local copies of the accounts
        my_account1 = Account(uid=account1.uid())
        my_account2 = Account(uid=account2.uid())

        for i in range(0, 10):
            transaction = Transaction(value=create_decimal(random.random()),
                                      description="Transaction %d" % i)

            if random.randint(0, 1):
                auth = Authorisation(
                    resource=transaction.fingerprint(),
                    testing_key=testing_key,
                    testing_user_guid=my_account1.group_name())

                Ledger.perform(transaction=transaction,
                               debit_account=my_account1,
                               credit_account=my_account2,
                               authorisation=auth)
                delta1 -= transaction.value()
                delta2 += transaction.value()
            else:
                auth = Authorisation(
                    resource=transaction.fingerprint(),
                    testing_key=testing_key,
                    testing_user_guid=my_account2.group_name())

                Ledger.perform(transaction=transaction,
                               debit_account=my_account2,
                               credit_account=my_account1,
                               authorisation=auth)
                delta1 += transaction.value()
                delta2 -= transaction.value()

        with rlock:
            result[key] = (delta1, delta2)
def test_authorisation(bucket):
    push_is_running_service()

    try:
        key = get_private_key("testing")

        resource = uuid.uuid4()

        auth = Authorisation(resource=resource, testing_key=key)

        auth.assert_once()

        with pytest.raises(PermissionError):
            auth.assert_once()

        auth.verify(resource=resource)

        wrong_resource = uuid.uuid4()

        with pytest.raises(PermissionError):
            auth.verify(resource=wrong_resource)

        data = auth.to_data()

        new_auth = Authorisation.from_data(data)

        with pytest.raises(PermissionError):
            new_auth.verify(resource=resource)

        new_auth._testing_key = key

        new_auth.verify(resource=resource)

        with pytest.raises(PermissionError):
            new_auth.assert_once()

        with pytest.raises(PermissionError):
            new_auth.verify(resource=wrong_resource)
    except:
        pop_is_running_service()
        raise

    pop_is_running_service()
Beispiel #4
0
def test_accounts(bucket):
    for user_guid in [None, "chris@something", "ƒ˚®ø©∆∂µ@¨^ø¨^ø"]:
        if user_guid is None:
            accounts = Accounts(group=user_guid,
                                aclrules=ACLRules.owner(user_guid=None))
        else:
            accounts = Accounts(user_guid=user_guid)

        account_names = [
            "new account", "chris's checking account", "å∫ç∂´® account"
        ]

        created_accounts = {}

        testing_key = get_private_key("testing")

        for name in account_names:
            authorisation = Authorisation(resource="create_account %s" % name,
                                          testing_key=testing_key,
                                          testing_user_guid=user_guid)

            account = accounts.create_account(name,
                                              description="Account: %s" % name,
                                              bucket=bucket,
                                              authorisation=authorisation)

            assert (name == account.name())

            created_accounts[name] = account

        names = accounts.list_accounts()

        for name in account_names:
            assert (name in names)

        for name in account_names:
            account = accounts.get_account(name, bucket=bucket)
            assert (name == account.name())

            assert (account == created_accounts[name])
def test_service(service_url, aaai_services):
    # get the public service from the default API frontend
    privkey = get_private_key("testing")
    response = call_function(service_url, response_key=privkey)
    service = Service.from_data(response["service_info"])

    # also read the service from the object store directly
    push_testing_objstore(aaai_services["_services"][service_url])
    push_is_running_service()
    private_service = get_this_service(need_private_access=True)
    pop_is_running_service()
    pop_testing_objstore()

    # create some test data that contain unicode characters for
    # testing encryption, signing and both encryption and signing
    data = {"hello": "'å∫ç∂ƒ©˙˚'", "key": privkey.public_key().to_data()}

    encrypted = service.encrypt_data(data)
    decrypted = private_service.decrypt_data(encrypted)

    assert(data == decrypted)

    signed = private_service.sign_data(data)
    verified = service.verify_data(signed)

    assert(data == verified)

    enc_sign = service.encrypt_data(private_service.sign_data(data))
    dec_ver = service.verify_data(private_service.decrypt_data(enc_sign))

    assert(data == dec_ver)

    service.call_function("admin/test")

    admin_user = aaai_services[service_url]["user"]
    auth = Authorisation(user=admin_user,
                         resource="dump_keys %s" % service.uid())

    service.call_function(
        function="dump_keys", args={"authorisation": auth.to_data()})
    def perform_transaction(key, result):
        delta1 = zero
        delta2 = zero
        auth = Authorisation()

        # need to work with thread-local copies of the accounts
        my_account1 = Account(uid=account1.uid())
        my_account2 = Account(uid=account2.uid())

        for i in range(0, 5):
            transaction = Transaction(value=create_decimal(random.random()),
                                      description="Transaction %d" % i)

            if random.randint(0, 1):
                Ledger.perform(transaction, my_account1, my_account2, auth)
                delta1 -= transaction.value()
                delta2 += transaction.value()
            else:
                Ledger.perform(transaction, my_account2, my_account1, auth)
                delta1 += transaction.value()
                delta2 -= transaction.value()

        with rlock:
            result[key] = (delta1, delta2)
Beispiel #7
0
def test_login(username, password, aaai_services, tmpdir):
    # register the new user
    result = User.register(username=username,
                           password=password,
                           identity_url="identity")

    assert(type(result) is dict)

    otpsecret = result["otpsecret"]

    otp = OTP(otpsecret)

    user = User(username=username, identity_url="identity",
                auto_logout=False)

    result = user.request_login()

    assert(type(result) is dict)

    login_url = result["login_url"]
    print(login_url)

    wallet = Wallet()

    wallet.send_password(url=login_url, username=username,
                         password=password, otpcode=otp.generate(),
                         remember_password=True)

    user.wait_for_login()
    assert(user.is_logged_in())

    auth = Authorisation(user=user, resource="test")

    auth.verify("test")

    user.logout()

    # now try to log in, using the remembered password
    user = User(username=username, identity_url="identity",
                auto_logout=False)

    result = user.request_login()

    login_url = result["login_url"]

    # the test has to specify the username as we can't choose...
    wallet.send_password(url=login_url, username=username,
                         otpcode=otp.generate(),
                         remember_device=True)

    user.wait_for_login()
    assert(user.is_logged_in())

    auth = Authorisation(user=user, resource="test")

    auth.verify("test")

    user.logout()

    # now see if the wallet can send all login info
    # now try to log in, using the remembered password
    user = User(username=username, identity_url="identity",
                auto_logout=False)

    result = user.request_login()

    login_url = result["login_url"]

    # the test has to specify the username as we can't choose...
    wallet.send_password(url=login_url, username=username)

    user.wait_for_login()
    assert(user.is_logged_in())

    auth = Authorisation(user=user, resource="test")

    auth.verify("test")

    user.logout()
Beispiel #8
0
def aaai_services(tmpdir_factory):
    """This function creates mocked versions of all of the main services
       of the system, returning the json describing each service as
       a dictionary (which is passed to the test functions as the
       fixture)
    """
    from Acquire.Identity import Authorisation
    from Acquire.Crypto import PrivateKey, OTP
    from Acquire.Service import call_function, Service

    _services = {}
    _services["registry"] = tmpdir_factory.mktemp("registry")
    _services["identity"] = tmpdir_factory.mktemp("identity")
    _services["accounting"] = tmpdir_factory.mktemp("accounting")
    _services["access"] = tmpdir_factory.mktemp("access")
    _services["storage"] = tmpdir_factory.mktemp("storage")
    _services["userdata"] = tmpdir_factory.mktemp("userdata")
    _services["compute"] = tmpdir_factory.mktemp("compute")
    _services["hugs"] = tmpdir_factory.mktemp("hugs")

    wallet_dir = tmpdir_factory.mktemp("wallet")
    wallet_password = PrivateKey.random_passphrase()

    _set_services(_services, wallet_dir, wallet_password)

    password = PrivateKey.random_passphrase()
    args = {"password": password}

    responses = {}

    os.environ["SERVICE_PASSWORD"] = "******"
    os.environ["STORAGE_COMPARTMENT"] = str(_services["userdata"])

    args["canonical_url"] = "registry"
    args["service_type"] = "registry"
    args["registry_uid"] = "Z9-Z9"  # UID of testing registry
    response = call_function("registry", function="admin/setup", args=args)

    registry_service = Service.from_data(response["service"])
    registry_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    registry_user = _login_admin("registry", "admin", password, registry_otp)
    responses["registry"] = {
        "service": registry_service,
        "user": registry_user,
        "response": response,
    }

    assert registry_service.registry_uid() == registry_service.uid()
    service_uids = [registry_service.uid()]

    args["canonical_url"] = "identity"
    args["service_type"] = "identity"
    response = call_function("identity", function="admin/setup", args=args)

    identity_service = Service.from_data(response["service"])
    identity_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    identity_user = _login_admin("identity", "admin", password, identity_otp)
    responses["identity"] = {
        "service": identity_service,
        "user": identity_user,
        "response": response,
    }

    assert identity_service.registry_uid() == registry_service.uid()
    assert identity_service.uid() not in service_uids
    service_uids.append(identity_service.uid())

    args["canonical_url"] = "accounting"
    args["service_type"] = "accounting"
    response = call_function("accounting", function="admin/setup", args=args)
    accounting_service = Service.from_data(response["service"])
    accounting_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    accounting_user = _login_admin("accounting", "admin", password,
                                   accounting_otp)
    responses["accounting"] = {
        "service": accounting_service,
        "user": accounting_user,
        "response": response,
    }

    assert accounting_service.registry_uid() == registry_service.uid()
    assert accounting_service.uid() not in service_uids
    service_uids.append(accounting_service.uid())

    args["canonical_url"] = "access"
    args["service_type"] = "access"
    response = call_function("access", function="admin/setup", args=args)
    responses["access"] = response
    access_service = Service.from_data(response["service"])
    access_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    access_user = _login_admin("access", "admin", password, access_otp)
    responses["access"] = {
        "service": access_service,
        "user": access_user,
        "response": response,
    }

    assert access_service.registry_uid() == registry_service.uid()
    assert access_service.uid() not in service_uids
    service_uids.append(access_service.uid())

    args["canonical_url"] = "compute"
    args["service_type"] = "compute"
    response = call_function("compute", function="admin/setup", args=args)
    responses["compute"] = response
    compute_service = Service.from_data(response["service"])
    compute_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    compute_user = _login_admin("compute", "admin", password, compute_otp)
    responses["compute"] = {
        "service": compute_service,
        "user": compute_user,
        "response": response,
    }

    assert compute_service.registry_uid() == registry_service.uid()
    assert compute_service.uid() not in service_uids
    service_uids.append(compute_service.uid())

    args["canonical_url"] = "storage"
    args["service_type"] = "storage"
    response = call_function("storage", function="admin/setup", args=args)
    storage_service = Service.from_data(response["service"])
    storage_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    storage_user = _login_admin("storage", "admin", password, storage_otp)
    responses["storage"] = {
        "service": storage_service,
        "user": storage_user,
        "response": response,
    }

    assert storage_service.registry_uid() == registry_service.uid()
    assert storage_service.uid() not in service_uids
    service_uids.append(storage_service.uid())

    args["canonical_url"] = "hugs"
    args["service_type"] = "hugs"
    response = call_function("hugs", function="admin/setup", args=args)
    responses["hugs"] = response
    hugs_service = Service.from_data(response["service"])
    hugs_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    hugs_user = _login_admin("hugs", "admin", password, hugs_otp)
    responses["hugs"] = {
        "service": hugs_service,
        "user": hugs_user,
        "response": response,
    }

    resource = "trust_accounting_service %s" % accounting_service.uid()
    args = {
        "service_url":
        accounting_service.canonical_url(),
        "authorisation":
        Authorisation(user=access_user, resource=resource).to_data(),
    }
    access_service.call_function(function="admin/trust_accounting_service",
                                 args=args)

    responses["_services"] = _services

    return responses
def test_temporal_transactions(account1, account2, bucket):
    if not have_freezetime:
        return

    zero = create_decimal(0)

    balance1 = zero
    balance2 = zero
    final_balance1 = zero
    final_balance2 = zero
    liability1 = zero
    liability2 = zero
    receivable1 = zero
    receivable2 = zero

    # generate some random times for the transactions
    random_dates = []
    now = get_datetime_now()
    for i in range(0, 50):
        if i == 0:
            # this is an evil edge-case datetime
            s = "2019-01-20 20:59:59.092627+00:00"
            r = datetime.datetime.fromisoformat(s)
        else:
            r = start_time + random.random() * (now - start_time)

        while (r.minute == 59 and r.second >= 58) or \
              (r.minute == 0 and r.second == 0 and r.microsecond < 10):
            r = r + datetime.timedelta(seconds=1)

        random_dates.append(r)

    random_dates.sort()

    # (which must be applied in time order!)
    random_dates.sort()

    provisionals = []

    for (i, transaction_time) in enumerate(random_dates):
        with freeze_time(transaction_time) as _frozen_datetime:
            now = get_datetime_now()
            assert (transaction_time == now)

            is_provisional = (random.randint(0, 3) <= 2)

            # check search for transaction is not O(n^2) lookup scanning
            # through the keys...

            transaction = Transaction(25 * random.random(),
                                      "test transaction %d" % i)

            if random.randint(0, 1):
                debit_account = account1
                credit_account = account2

                if is_provisional:
                    liability1 += transaction.value()
                    receivable2 += transaction.value()
                else:
                    balance1 -= transaction.value()
                    balance2 += transaction.value()

                final_balance1 -= transaction.value()
                final_balance2 += transaction.value()
            else:
                debit_account = account2
                credit_account = account1

                if is_provisional:
                    receivable1 += transaction.value()
                    liability2 += transaction.value()
                else:
                    balance1 += transaction.value()
                    balance2 -= transaction.value()

                final_balance1 += transaction.value()
                final_balance2 -= transaction.value()

            auth = Authorisation(resource=transaction.fingerprint(),
                                 testing_key=testing_key,
                                 testing_user_guid=debit_account.group_name())

            records = Ledger.perform(transaction=transaction,
                                     debit_account=debit_account,
                                     credit_account=credit_account,
                                     authorisation=auth,
                                     is_provisional=is_provisional,
                                     bucket=bucket)

            for record in records:
                assert (record.datetime() == now)

            if is_provisional:
                for record in records:
                    provisionals.append((credit_account, record))
            elif (random.randint(0, 3) <= 2):
                # receipt pending transactions
                balance1 = Balance(balance=balance1,
                                   liability=liability1,
                                   receivable=receivable1)

                balance2 = Balance(balance=balance2,
                                   liability=liability2,
                                   receivable=receivable2)

                assert (account1.balance() == balance1)
                assert (account2.balance() == balance2)

                for (credit_account, record) in provisionals:
                    credit_note = record.credit_note()
                    auth = Authorisation(
                        resource=credit_note.fingerprint(),
                        testing_key=testing_key,
                        testing_user_guid=credit_account.group_name())

                    receipted_value = create_decimal(
                        random.random() * float(credit_note.value()))

                    delta_value = credit_note.value() - receipted_value

                    Ledger.receipt(Receipt(credit_note=credit_note,
                                           receipted_value=receipted_value,
                                           authorisation=auth),
                                   bucket=bucket)

                    if credit_note.debit_account_uid() == account1.uid():
                        final_balance1 += delta_value
                        final_balance2 -= delta_value
                    else:
                        final_balance2 += delta_value
                        final_balance1 -= delta_value

                assert (account1.balance() == Balance(balance=final_balance1))
                assert (account2.balance() == Balance(balance=final_balance2))

                provisionals = []
                balance1 = final_balance1
                balance2 = final_balance2
                liability1 = zero
                liability2 = zero
                receivable1 = zero
                receivable2 = zero

    balance1 = Balance(balance=balance1,
                       liability=liability1,
                       receivable=receivable1)

    balance2 = Balance(balance=balance2,
                       liability=liability2,
                       receivable=receivable2)

    assert (account1.balance() == balance1)
    assert (account2.balance() == balance2)

    for (credit_account, record) in provisionals:
        credit_note = record.credit_note()
        auth = Authorisation(resource=record.credit_note().fingerprint(),
                             testing_key=testing_key,
                             testing_user_guid=credit_account.group_name())

        receipted_value = create_decimal(random.random() *
                                         float(credit_note.value()))

        delta_value = credit_note.value() - receipted_value

        Ledger.receipt(Receipt(credit_note=credit_note,
                               authorisation=auth,
                               receipted_value=receipted_value),
                       bucket=bucket)

        if credit_note.debit_account_uid() == account1.uid():
            final_balance1 += delta_value
            final_balance2 -= delta_value
        else:
            final_balance2 += delta_value
            final_balance1 -= delta_value

    assert (account1.balance() == Balance(balance=final_balance1))
    assert (account2.balance() == Balance(balance=final_balance2))
def test_pending_transactions(random_transaction):
    (transaction, account1, account2) = random_transaction

    starting_balance1 = account1.balance()
    starting_balance2 = account2.balance()

    authorisation = Authorisation(resource=transaction.fingerprint(),
                                  testing_key=testing_key,
                                  testing_user_guid=account1.group_name())

    records = Ledger.perform(transactions=transaction,
                             debit_account=account1,
                             credit_account=account2,
                             authorisation=authorisation,
                             is_provisional=True)

    assert (len(records) == 1)
    record = records[0]

    ending_balance1 = account1.balance()
    ending_balance2 = account2.balance()

    assert (ending_balance1.liability() == starting_balance1.liability() +
            transaction.value())
    assert (ending_balance2.receivable() == starting_balance2.receivable() +
            transaction.value())
    assert (starting_balance1.balance() == ending_balance1.balance())
    assert (starting_balance2.balance() == ending_balance2.balance())
    assert (starting_balance2.liability() == ending_balance2.liability())
    assert (starting_balance1.receivable() == ending_balance1.receivable())

    assert (record.debit_account_uid() == account1.uid())
    assert (record.credit_account_uid() == account2.uid())

    debit_note = record.debit_note()
    credit_note = record.credit_note()

    assert (not debit_note.is_null())
    assert (not credit_note.is_null())

    assert (debit_note.account_uid() == account1.uid())
    assert (credit_note.account_uid() == account2.uid())

    assert (debit_note.is_provisional())
    assert (credit_note.is_provisional())

    assert (debit_note.value() == transaction.value())
    assert (credit_note.value() == transaction.value())

    now = get_datetime_now()

    assert (debit_note.datetime() < now)
    assert (credit_note.datetime() < now)
    assert (debit_note.datetime() <= credit_note.datetime())

    assert_packable(debit_note)
    assert_packable(credit_note)

    # now receipt a random amount of the transaction
    authorisation = Authorisation(resource=credit_note.fingerprint(),
                                  testing_key=testing_key,
                                  testing_user_guid=account2.group_name())

    with pytest.raises(ValueError):
        receipt = Receipt(
            credit_note, authorisation,
            create_decimal(random.random()) + credit_note.value())

    if random.randint(0, 1):
        value = credit_note.value()
        receipt = Receipt(credit_note, authorisation)
    else:
        value = create_decimal(
            create_decimal(random.random()) * credit_note.value())
        receipt = Receipt(credit_note, authorisation, value)

    assert (not receipt.is_null())
    assert (receipt.authorisation() == authorisation)
    assert (receipt.receipted_value() == value)
    assert (receipt.credit_note() == credit_note)
    assert_packable(receipt)

    rrecords = Ledger.receipt(receipt)

    assert (len(rrecords) == 1)
    rrecord = rrecords[0]

    assert (not rrecord.is_null())
    assert_packable(rrecord)

    assert (not rrecord.is_provisional())
    assert (rrecord.is_direct())
    assert (rrecord.get_receipt_info() == receipt)
    assert (rrecord.is_receipt())
    assert (rrecord.original_transaction() == transaction)

    # the original transaction record has now been updated to
    # say that it has been receipted...
    assert (record.is_provisional())
    record.reload()
    assert (record.is_receipted())

    assert (rrecord.original_transaction_record() == record)

    ending_balance1 = account1.balance()
    ending_balance2 = account2.balance()

    assert (ending_balance1.liability() == starting_balance1.liability())
    assert (ending_balance2.receivable() == starting_balance2.receivable())
    assert (starting_balance1.balance() - value == ending_balance1.balance())
    assert (starting_balance2.balance() + value == ending_balance2.balance())
    assert (starting_balance2.liability() == ending_balance2.liability())
    assert (starting_balance1.receivable() == ending_balance1.receivable())
def test_transactions(random_transaction, bucket):

    (transaction, account1, account2) = random_transaction

    starting_balance1 = account1.balance()

    starting_balance2 = account2.balance()

    authorisation = Authorisation(resource=transaction.fingerprint(),
                                  testing_key=testing_key,
                                  testing_user_guid=account1.group_name())

    records = Ledger.perform(transaction=transaction,
                             debit_account=account1,
                             credit_account=account2,
                             authorisation=authorisation,
                             is_provisional=False,
                             bucket=bucket)

    assert (len(records) == 1)

    record = records[0]

    ending_balance1 = account1.balance()
    ending_balance2 = account2.balance()

    assert (ending_balance1 == starting_balance1 - transaction)
    assert (ending_balance2 == starting_balance2 + transaction)

    assert (record.debit_account_uid() == account1.uid())
    assert (record.credit_account_uid() == account2.uid())

    debit_note = record.debit_note()
    credit_note = record.credit_note()

    assert (debit_note.account_uid() == account1.uid())
    assert (credit_note.account_uid() == account2.uid())

    assert (not debit_note.is_provisional())
    assert (not credit_note.is_provisional())

    assert (debit_note.value() == transaction.value())
    assert (credit_note.value() == transaction.value())

    now = get_datetime_now()

    assert (debit_note.datetime() < now)
    assert (credit_note.datetime() < now)
    assert (debit_note.datetime() <= credit_note.datetime())

    assert_packable(debit_note)
    assert_packable(credit_note)

    # now test refunding this transaction
    # now receipt a random amount of the transaction
    authorisation = Authorisation(resource=credit_note.fingerprint(),
                                  testing_key=testing_key,
                                  testing_user_guid=account2.group_name())

    refund = Refund(credit_note, authorisation)

    assert (not refund.is_null())
    assert (refund.authorisation() == authorisation)
    assert (refund.value() == transaction.value())
    assert (refund.credit_note() == credit_note)
    assert_packable(refund)

    rrecords = Ledger.refund(refund)

    assert (len(rrecords) == 1)
    rrecord = rrecords[0]

    assert (not rrecord.is_null())
    assert_packable(rrecord)

    assert (not rrecord.is_provisional())
    assert (rrecord.is_direct())
    assert (rrecord.get_refund_info() == refund)
    assert (rrecord.is_refund())
    assert (rrecord.original_transaction() == transaction)

    # the original transaction record has now been updated to
    # say that it has been receipted...
    assert (record.is_direct())
    record.reload()
    assert (record.is_refunded())

    assert (rrecord.original_transaction_record() == record)

    ending_balance1 = account1.balance()
    ending_balance2 = account2.balance()

    assert (ending_balance1.liability() == starting_balance1.liability())
    assert (ending_balance2.receivable() == starting_balance2.receivable())
    assert (starting_balance1.balance() == ending_balance1.balance())
    assert (starting_balance2.balance() == ending_balance2.balance())
    assert (starting_balance2.liability() == ending_balance2.liability())
    assert (starting_balance1.receivable() == ending_balance1.receivable())
def test_temporal_transactions(account1, account2, bucket):
    if not have_freezetime:
        return

    zero = create_decimal(0)

    balance1 = zero
    balance2 = zero
    final_balance1 = zero
    final_balance2 = zero
    liability1 = zero
    liability2 = zero
    receivable1 = zero
    receivable2 = zero

    # generate some random times for the transactions
    random_dates = []
    now = datetime.datetime.now()
    for i in range(0, 100):
        random_dates.append(start_time + random.random() * (now - start_time))

    # (which must be applied in time order!)
    random_dates.sort()

    records = []

    for (i, transaction_time) in enumerate(random_dates):
        with freeze_time(transaction_time) as frozen_datetime:
            now = datetime.datetime.now()
            assert (frozen_datetime() == now)

            is_provisional = random.randint(0, 5)

            transaction = Transaction(25 * random.random(),
                                      "test transaction %d" % i)
            auth = Authorisation()

            if random.randint(0, 10):
                record = Ledger.perform(transaction,
                                        account1,
                                        account2,
                                        auth,
                                        is_provisional,
                                        bucket=bucket)

                if is_provisional:
                    liability1 += transaction.value()
                    receivable2 += transaction.value()
                else:
                    balance1 -= transaction.value()
                    balance2 += transaction.value()

                final_balance1 -= transaction.value()
                final_balance2 += transaction.value()
            else:
                record = Ledger.perform(transaction,
                                        account2,
                                        account1,
                                        auth,
                                        is_provisional,
                                        bucket=bucket)

                if is_provisional:
                    receivable1 += transaction.value()
                    liability2 += transaction.value()
                else:
                    balance1 += transaction.value()
                    balance2 -= transaction.value()

                final_balance1 += transaction.value()
                final_balance2 -= transaction.value()

            if is_provisional:
                records.append(record)

            assert (record.timestamp() == now.timestamp())

    assert (account1.balance() == balance1)
    assert (account2.balance() == balance2)
    assert (account1.liability() == liability1)
    assert (account1.receivable() == receivable1)
    assert (account2.liability() == liability2)
    assert (account2.receivable() == receivable2)

    for record in records:
        Ledger.receipt(Receipt(record.credit_note(), Authorisation()),
                       bucket=bucket)

    assert (account1.balance() == final_balance1)
    assert (account2.balance() == final_balance2)

    assert (account1.liability() == zero)
    assert (account1.receivable() == zero)
    assert (account2.liability() == zero)
    assert (account2.receivable() == zero)
def test_pending_transactions(random_transaction):
    (transaction, account1, account2) = random_transaction

    starting_balance1 = account1.balance()
    starting_liability1 = account1.liability()
    starting_receivable1 = account1.receivable()

    starting_balance2 = account2.balance()
    starting_liability2 = account2.liability()
    starting_receivable2 = account2.receivable()

    record = Ledger.perform(transaction,
                            account1,
                            account2,
                            Authorisation(),
                            is_provisional=True)

    ending_balance1 = account1.balance()
    ending_liability1 = account1.liability()
    ending_receivable1 = account1.receivable()

    ending_balance2 = account2.balance()
    ending_liability2 = account2.liability()
    ending_receivable2 = account2.receivable()

    assert (ending_liability1 == starting_liability1 + transaction.value())
    assert (ending_receivable2 == starting_receivable2 + transaction.value())
    assert (starting_balance1 == ending_balance1)
    assert (starting_balance2 == ending_balance2)
    assert (starting_liability2 == ending_liability2)
    assert (starting_receivable1 == ending_receivable1)

    assert (record.debit_account_uid() == account1.uid())
    assert (record.credit_account_uid() == account2.uid())

    debit_note = record.debit_note()
    credit_note = record.credit_note()

    assert (not debit_note.is_null())
    assert (not credit_note.is_null())

    assert (debit_note.account_uid() == account1.uid())
    assert (credit_note.account_uid() == account2.uid())

    assert (debit_note.is_provisional())
    assert (credit_note.is_provisional())

    assert (debit_note.value() == transaction.value())
    assert (credit_note.value() == transaction.value())

    now = datetime.datetime.now()

    assert (debit_note.timestamp() < now.timestamp())
    assert (credit_note.timestamp() < now.timestamp())
    assert (debit_note.timestamp() <= credit_note.timestamp())

    assert_packable(debit_note)
    assert_packable(credit_note)

    # now receipt a random amount of the transaction
    auth = Authorisation()

    with pytest.raises(ValueError):
        receipt = Receipt(
            credit_note, auth,
            create_decimal(random.random()) + credit_note.value())

    if random.randint(0, 1):
        value = credit_note.value()
        receipt = Receipt(credit_note, auth)
    else:
        value = create_decimal(
            create_decimal(random.random()) * credit_note.value())
        receipt = Receipt(credit_note, auth, value)

    assert (not receipt.is_null())
    assert (receipt.authorisation() == auth)
    assert (receipt.receipted_value() == value)
    assert (receipt.credit_note() == credit_note)
    assert_packable(receipt)

    rrecord = Ledger.receipt(receipt)

    assert (not rrecord.is_null())
    assert_packable(rrecord)

    assert (not rrecord.is_provisional())
    assert (rrecord.is_direct())
    assert (rrecord.get_receipt_info() == receipt)
    assert (rrecord.is_receipt())
    assert (rrecord.original_transaction() == transaction)

    # the original transaction record has now been updated to
    # say that it has been receipted...
    assert (record.is_provisional())
    record.reload()
    assert (record.is_receipted())

    assert (rrecord.original_transaction_record() == record)

    ending_balance1 = account1.balance()
    ending_liability1 = account1.liability()
    ending_receivable1 = account1.receivable()

    ending_balance2 = account2.balance()
    ending_liability2 = account2.liability()
    ending_receivable2 = account2.receivable()

    assert (ending_liability1 == starting_liability1)
    assert (ending_receivable2 == starting_receivable2)
    assert (starting_balance1 - value == ending_balance1)
    assert (starting_balance2 + value == ending_balance2)
    assert (starting_liability2 == ending_liability2)
    assert (starting_receivable1 == ending_receivable1)
def test_transactions(random_transaction, bucket):
    (transaction, account1, account2) = random_transaction

    starting_balance1 = account1.balance()
    starting_liability1 = account1.liability()
    starting_receivable1 = account1.receivable()

    starting_balance2 = account2.balance()
    starting_liability2 = account2.liability()
    starting_receivable2 = account2.receivable()

    record = Ledger.perform(transaction,
                            account1,
                            account2,
                            Authorisation(),
                            is_provisional=False,
                            bucket=bucket)

    ending_balance1 = account1.balance()
    ending_liability1 = account1.liability()
    ending_receivable1 = account1.receivable()

    ending_balance2 = account2.balance()
    ending_liability2 = account2.liability()
    ending_receivable2 = account2.receivable()

    assert (ending_balance1 == starting_balance1 - transaction.value())
    assert (ending_balance2 == starting_balance2 + transaction.value())

    assert (ending_liability1 == starting_liability1)
    assert (starting_liability2 == ending_liability2)
    assert (starting_receivable1 == ending_receivable1)
    assert (starting_receivable2 == ending_receivable2)

    assert (record.debit_account_uid() == account1.uid())
    assert (record.credit_account_uid() == account2.uid())

    debit_note = record.debit_note()
    credit_note = record.credit_note()

    assert (debit_note.account_uid() == account1.uid())
    assert (credit_note.account_uid() == account2.uid())

    assert (not debit_note.is_provisional())
    assert (not credit_note.is_provisional())

    assert (debit_note.value() == transaction.value())
    assert (credit_note.value() == transaction.value())

    now = datetime.datetime.now()

    assert (debit_note.timestamp() < now.timestamp())
    assert (credit_note.timestamp() < now.timestamp())
    assert (debit_note.timestamp() <= credit_note.timestamp())

    assert_packable(debit_note)
    assert_packable(credit_note)

    # now test refunding this transaction
    # now receipt a random amount of the transaction
    auth = Authorisation()

    refund = Refund(credit_note, auth)

    assert (not refund.is_null())
    assert (refund.authorisation() == auth)
    assert (refund.value() == transaction.value())
    assert (refund.credit_note() == credit_note)
    assert_packable(refund)

    rrecord = Ledger.refund(refund)

    assert (not rrecord.is_null())
    assert_packable(rrecord)

    assert (not rrecord.is_provisional())
    assert (rrecord.is_direct())
    assert (rrecord.get_refund_info() == refund)
    assert (rrecord.is_refund())
    assert (rrecord.original_transaction() == transaction)

    # the original transaction record has now been updated to
    # say that it has been receipted...
    assert (record.is_direct())
    record.reload()
    assert (record.is_refunded())

    assert (rrecord.original_transaction_record() == record)

    ending_balance1 = account1.balance()
    ending_liability1 = account1.liability()
    ending_receivable1 = account1.receivable()

    ending_balance2 = account2.balance()
    ending_liability2 = account2.liability()
    ending_receivable2 = account2.receivable()

    assert (ending_liability1 == starting_liability1)
    assert (ending_receivable2 == starting_receivable2)
    assert (starting_balance1 == ending_balance1)
    assert (starting_balance2 == ending_balance2)
    assert (starting_liability2 == ending_liability2)
    assert (starting_receivable1 == ending_receivable1)
def test_run_calc(aaai_services, authenticated_user):
    # create and register the cluster on which this job will take place...
    cluster = Cluster.create(service_url="compute",
                             user=aaai_services["compute"]["user"])

    user = authenticated_user
    assert (user.is_logged_in())

    # ensure that the main account has money
    deposit(user,
            100.0,
            "Adding money to the account",
            accounting_url="accounting")

    # get a handle to the financial account used to pay for the job
    account = Account(user=user,
                      account_name="deposits",
                      accounting_url="accounting")

    assert (account.balance() >= 100.0)

    # Upload a directory that will contain all of the input
    creds = StorageCreds(user=user, service_url="storage")
    drive = Drive(name="sim", creds=creds, autocreate=True)

    uploaded = drive.upload(_testdata())
    location = uploaded.location()

    print(drive.list_files(dir="example_sim/input"))
    print(location)

    # create a request for a job to be run using:
    #  1. 'image_name' as the specified container image for the software
    #  2. 'location' as the location containing all input files

    # authorise it using the authenticated user (who may be different to the
    # user who pays for the job - hence the need for a different
    # authorisation for the request and for the cheque)
    r = RunRequest(image="docker://test_image:latest", input=location)

    # now write a cheque which will provide authorisation to spend money from
    # this account to pay for this request. This will be written to the access
    # service to give it the authority to create a transation in the account.
    # This cheque authorises only a single transaction, performable only
    # by the service whose canonical URL is supplied, and the access service
    # should check that the requested resource signature matches that
    # authorised by the cheque
    cheque = Cheque.write(account=account,
                          recipient_url="access",
                          resource=r.fingerprint(),
                          max_spend=50.0)

    func = "run_calculation"
    args = {}
    args["request"] = r.to_data()
    args["authorisation"] = Authorisation(user=user,
                                          resource=r.fingerprint()).to_data()
    args["cheque"] = cheque.to_data()

    access_service = Service("access")

    result = access_service.call_function(func, args)
    print(result)

    pending_uids = cluster.get_pending_job_uids()

    print(pending_uids)

    for uid in pending_uids:
        job = cluster.submit_job(uid)
        print(job)

    pending_uids = cluster.get_pending_job_uids()

    print(pending_uids)