Skip to content

Commit

Permalink
Adding more tests and streamlining code based on test results (#2)
Browse files Browse the repository at this point in the history
* Added more tests, updated scripts for better test coverage

Signed-off-by: Edwin Hermans <edwin@madtech.cx>

* Started removing settings config

Signed-off-by: Edwin Hermans <edwin@madtech.cx>

* Removed unused config file code

Signed-off-by: Edwin Hermans <edwin@madtech.cx>
  • Loading branch information
madeddie committed Mar 20, 2018
1 parent cecf513 commit f5bf19b
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 105 deletions.
59 changes: 0 additions & 59 deletions madcc/conf.py

This file was deleted.

12 changes: 0 additions & 12 deletions madcc/const.py

This file was deleted.

28 changes: 14 additions & 14 deletions madcc/entrypoints/crypto_assets.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
from ..utils import crypto_assets

import configparser
import json
import sys

from clint import resources
Expand All @@ -11,22 +11,22 @@

def main():
resources.init('madtech', 'madcc')
if not resources.user.read('config.ini'):
config = configparser.ConfigParser()
config['crypto_assets'] = {}
if not resources.user.read('config.json'):
config = dict()
config['crypto_assets'] = dict()
config['crypto_assets']['crypto_file'] = resources.user.path + '/crypto.txt'
config['crypto_assets']['currency'] = 'eur'
with resources.user.open('config.ini', 'w') as configfile:
config.write(configfile)

configfile = resources.user.open('config.json', 'w')
configfile.write(json.dumps(config, sort_keys=True, indent=4))
else:
config = configparser.ConfigParser()
with resources.user.open('config.ini', 'r') as configfile:
config.read_file(configfile)
configfile = resources.user.open('config.json', 'r')
config = json.loads(configfile.read())

args = Args()

if next(iter(args.grouped.get('--currency', [])), '').upper() in crypto_assets.CURRENCIES:
currency = args.grouped.get('--currency', {}).get(0)
currency = next(iter(args.grouped.get('--currency', [])), '')
elif str(args.last or '').upper() in crypto_assets.CURRENCIES:
currency = args.last
else:
Expand All @@ -39,11 +39,11 @@ def main():

crypto_data = crypto_assets.parse_crypto_file(config['crypto_assets']['crypto_file'])
if not crypto_data:
sys.exit(1)
return False

headers, crypto_table = crypto_assets.generate_crypto_table(currency, crypto_data)
print(tabulate(crypto_table, headers=headers, floatfmt='.{}f'.format(decimals)))
return tabulate(crypto_table, headers=headers, floatfmt='.{}f'.format(decimals))


if __name__ == "__main__":
main()
if __name__ == "__main__": # pragma: no cover
print(main())
12 changes: 8 additions & 4 deletions madcc/entrypoints/kraken_limits.py
@@ -1,10 +1,14 @@
from ..kraken.kraken import KrakenUtils


def main():
k = KrakenUtils()
def main(authfile=None):
k = KrakenUtils(authfile=authfile)
deposit_limit = k.deposit_limit()
withdraw_limit = k.withdraw_limit()

print('deposit max: {} EUR'.format(deposit_limit))
print('withdraw max: {} BTC'.format(withdraw_limit))
return 'deposit max: {} EUR\nwithdraw max: {} BTC'.format(deposit_limit,
withdraw_limit)


if __name__ == "__main__": # pragma: no cover
print(main())
25 changes: 17 additions & 8 deletions madcc/kraken/kraken.py
Expand Up @@ -6,15 +6,16 @@

import krakenex
import requests

from ..conf import settings
from clint import resources


class KrakenUtils(object):
def __init__(self):
# TODO: get config somewhere else, don't load it in the module?
settings.init()
self._set_auth(str(settings.user_dir.joinpath('kraken.auth')))
def __init__(self, authfile=None):
self._auth_file = authfile
self._set_auth()
if not self.api_key or not self.api_secret:
print('No api key or secret found')
sys.exit(1)
self.api = krakenex.API(key=self.api_key, secret=self.api_secret)
if not self.api_live():
# TODO: use logging instead of print
Expand All @@ -37,9 +38,17 @@ def _init_auth_file(self):
else:
print('Only public api calls allowed')

def _set_auth(self, auth_file=None):
def _set_auth(self):
self.api_key = None
self.api_secret = None
"""Read the api auth data from file"""
self.api_key, self.api_secret = open(auth_file).read().splitlines()
if self._auth_file:
self.api_key, self.api_secret = open(self._auth_file).read().splitlines()
else:
resources.init('madtech', 'madcc')
self._auth_file = resources.user.path + '/kraken.auth'
if resources.user.read('kraken.auth'):
self.api_key, self.api_secret = resources.user.read('kraken.auth').splitlines()

def api_live(self):
res = self.api.query_public('Time')
Expand Down
104 changes: 96 additions & 8 deletions tests/test_crypto_assets.py
@@ -1,5 +1,3 @@
from unittest.mock import patch

import pytest

from madcc.utils import crypto_assets
Expand Down Expand Up @@ -45,7 +43,7 @@
]
)

demo_output = """symbol amount % eur price eur total
crypto_output = """symbol amount % eur price eur total
-------- -------- ----- ----------- -----------
bitcoin 12.05 52.35 6615.32 79714.56
ethereum 80.20 25.88 491.39 39409.12
Expand All @@ -57,6 +55,7 @@
def test_convert(mocker):
mocker.patch('requests.get')
crypto_assets.convert('eur', 10, 'usd')

crypto_assets.requests.get.assert_called_with(
crypto_assets.currency_api,
params={'base': 'EUR', 'symbols': 'USD'}
Expand All @@ -68,16 +67,15 @@ def test_convert_same():


def test_parse_crypto_file(mocker):
with patch('builtins.open', mocker.mock_open(read_data=raw_crypto_file)) as m:
with mocker.mock_module.patch('builtins.open', mocker.mock_open(read_data=raw_crypto_file)) as m:
result = crypto_assets.parse_crypto_file('crypto_file')

m.assert_called_once_with('crypto_file')
assert result == parsed_crypto_file


def test_parse_crypto_file_fail_open(mocker):

with patch('builtins.open', mocker.mock_open()) as m:
with mocker.mock_module.patch('builtins.open', mocker.mock_open()) as m:
m.side_effect = IOError
result = crypto_assets.parse_crypto_file('crypto_file')

Expand All @@ -94,8 +92,8 @@ def test_retrieve_ticker_data(mocker):

def test_generate_crypto_table(mocker):
mocker.patch.object(crypto_assets, 'retrieve_ticker_data', return_value=full_ticker_data)

result = crypto_assets.generate_crypto_table('eur', parsed_crypto_file)

assert result == generated_crypto_table


Expand All @@ -105,4 +103,94 @@ def test_generate_crypto_table_missing_data():

def test_demo(mocker):
mocker.patch.object(crypto_assets, 'generate_crypto_table', return_value=generated_crypto_table)
assert crypto_assets.demo() == demo_output

assert crypto_assets.demo() == crypto_output


@pytest.fixture(scope='session')
def config_dir(tmpdir_factory):
return tmpdir_factory.mktemp('madcc')


def test_crypto_assets_cli_no_config(mocker, config_dir):
mocker.patch.object(crypto_assets_cli, 'resources')
crypto_assets_cli.resources.user.read.return_value = None
crypto_assets_cli.resources.user.path = str(config_dir)
crypto_assets_cli.resources.user.open.return_value = config_dir.join('config.json')
crypto_assets_cli.main()

crypto_assets_cli.resources.user.open.assert_called_once_with('config.json', 'w')


def test_crypto_assets_cli_without_data(mocker, config_dir):
mocker.patch.object(crypto_assets_cli, 'resources')
crypto_assets_cli.resources.user.read.return_value = True
crypto_assets_cli.resources.user.open.return_value = config_dir.join('config.json')
crypto_assets_cli.main()

crypto_assets_cli.resources.user.open.assert_called_once_with('config.json', 'r')
assert crypto_assets_cli.main() is False


def test_crypto_assets_cli_with_data(mocker, config_dir):
mocker.patch.object(crypto_assets_cli, 'resources')
crypto_assets_cli.resources.user.read.return_value = None
crypto_assets_cli.resources.user.path = str(config_dir)
crypto_assets_cli.resources.user.open.return_value = config_dir.join('config.json')
mocker.patch.object(crypto_assets_cli, 'crypto_assets')
crypto_assets_cli.crypto_assets.generate_crypto_table.return_value = generated_crypto_table
config_dir.join('crypto.txt').write(raw_crypto_file)

assert crypto_assets_cli.main() == crypto_output


def test_crypto_assets_cli_currency_eur(mocker, config_dir):
mocker.patch.object(crypto_assets_cli, 'resources')
crypto_assets_cli.resources.user.read.return_value = None
crypto_assets_cli.resources.user.path = str(config_dir)
crypto_assets_cli.resources.user.open.return_value = config_dir.join('config.json')
mocker.patch('madcc.utils.crypto_assets.generate_crypto_table', autospect=True, return_value=generated_crypto_table)
mocker.patch.object(crypto_assets_cli, 'Args')
crypto_assets_cli.Args.return_value.last = 'eur'
crypto_assets_cli.main()

crypto_assets_cli.crypto_assets.generate_crypto_table.assert_called_with('eur', parsed_crypto_file)


def test_crypto_assets_cli_currency_usd(mocker, config_dir):
mocker.patch.object(crypto_assets_cli, 'resources')
crypto_assets_cli.resources.user.read.return_value = None
crypto_assets_cli.resources.user.path = str(config_dir)
crypto_assets_cli.resources.user.open.return_value = config_dir.join('config.json')
mocker.patch('madcc.utils.crypto_assets.generate_crypto_table', autospect=True, return_value=generated_crypto_table)
mocker.patch.object(crypto_assets_cli, 'Args')
crypto_assets_cli.Args.return_value.last = 'usd'
crypto_assets_cli.main()

crypto_assets_cli.crypto_assets.generate_crypto_table.assert_called_with('usd', parsed_crypto_file)


def test_crypto_assets_cli_currency_btc(mocker, config_dir):
mocker.patch.object(crypto_assets_cli, 'resources')
crypto_assets_cli.resources.user.read.return_value = None
crypto_assets_cli.resources.user.path = str(config_dir)
crypto_assets_cli.resources.user.open.return_value = config_dir.join('config.json')
mocker.patch('madcc.utils.crypto_assets.generate_crypto_table', autospect=True, return_value=generated_crypto_table)
mocker.patch.object(crypto_assets_cli, 'Args')
crypto_assets_cli.Args.return_value.last = 'btc'
crypto_assets_cli.main()

crypto_assets_cli.crypto_assets.generate_crypto_table.assert_called_with('btc', parsed_crypto_file)


def test_crypto_assets_cli_currency_unknown(mocker, config_dir):
mocker.patch.object(crypto_assets_cli, 'resources')
crypto_assets_cli.resources.user.read.return_value = None
crypto_assets_cli.resources.user.path = str(config_dir)
crypto_assets_cli.resources.user.open.return_value = config_dir.join('config.json')
mocker.patch('madcc.utils.crypto_assets.generate_crypto_table', autospect=True, return_value=generated_crypto_table)
mocker.patch.object(crypto_assets_cli, 'Args')
crypto_assets_cli.Args.return_value.last = 'abc'
crypto_assets_cli.main()

crypto_assets_cli.crypto_assets.generate_crypto_table.assert_called_with('eur', parsed_crypto_file)
23 changes: 23 additions & 0 deletions tests/test_kraken.py
Expand Up @@ -2,3 +2,26 @@

from madcc.kraken import KrakenUtils
from madcc.entrypoints import kraken_limits


# some_api_key\nsome_api_secret both base64 encoded
raw_kraken_auth = """c29tZV9hcGlfa2V5Cg==
c29tZV9hcGlfc2VjcmV0Cg=="""

wrong_credentials_result = """deposit max: False EUR
withdraw max: False BTC"""


@pytest.fixture(scope='session')
def config_dir(tmpdir_factory):
return tmpdir_factory.mktemp('madcc')


# TODO: this tests the krakenex api more than my code
# also mock the kraken api to test failures better and circumvent network
# access
def test_kraken_limits_wrong_credentials(mocker, config_dir):
config_dir.join('kraken.auth').write(raw_kraken_auth)
result = kraken_limits.main(str(config_dir.join('kraken.auth')))

assert result == wrong_credentials_result

0 comments on commit f5bf19b

Please sign in to comment.