Move watchlist api tests to seperate module

kivy_mainline_and_py3.8
K0nstantine 2018-03-30 23:48:43 -04:00
parent e859222df4
commit 11f25958ba
4 changed files with 125 additions and 139 deletions

View File

@ -154,9 +154,8 @@ def watch(loglevel, broker, rate, name):
@click.option('--loglevel', '-l', default='warning', help='Logging level') @click.option('--loglevel', '-l', default='warning', help='Logging level')
@click.pass_context @click.pass_context
def watchlists(ctx, loglevel): def watchlists(ctx, loglevel):
"""Watchlists cl commands and operations """Watchlists commands and operations
""" """
# import pdb; pdb.set_trace()
get_console_log(loglevel) # activate console logging get_console_log(loglevel) # activate console logging
wl.make_config_dir(_config_dir) wl.make_config_dir(_config_dir)
ctx.obj = wl.ensure_watchlists(_watchlists_data_path) ctx.obj = wl.ensure_watchlists(_watchlists_data_path)
@ -168,7 +167,7 @@ def watchlists(ctx, loglevel):
def show(ctx, name): def show(ctx, name):
watchlist = ctx.obj watchlist = ctx.obj
click.echo(colorize_json( click.echo(colorize_json(
watchlist if name is None else watchlist[name])) watchlist if name is None else watchlist[name]))
@watchlists.command(help='load passed in watchlist') @watchlists.command(help='load passed in watchlist')
@ -176,17 +175,10 @@ def show(ctx, name):
@click.pass_context @click.pass_context
def load(ctx, data): def load(ctx, data):
try: try:
wl.load_watchlists(data, _watchlists_data_path) wl.write_watchlists(data, _watchlists_data_path)
except (json.JSONDecodeError, IndexError): except (json.JSONDecodeError, IndexError):
click.echo('You must pass in a text respresentation of a json object. Try again.') click.echo('You have passed an invalid text respresentation of a '
'JSON object. Try again.')
@watchlists.command(help='add a new watchlist')
@click.argument('name', nargs=1, required=True)
@click.pass_context
def new(ctx, name):
watchlist = ctx.obj
wl.new_group(name, watchlist, _watchlists_data_path)
@watchlists.command(help='add ticker to watchlist') @watchlists.command(help='add ticker to watchlist')
@ -207,7 +199,7 @@ def remove(ctx, name, ticker_name):
wl.remove_ticker(name, ticker_name, watchlist, _watchlists_data_path) wl.remove_ticker(name, ticker_name, watchlist, _watchlists_data_path)
@watchlists.command(help='delete watchlist') @watchlists.command(help='delete watchlist group')
@click.argument('name', nargs=1, required=True) @click.argument('name', nargs=1, required=True)
@click.pass_context @click.pass_context
def delete(ctx, name): def delete(ctx, name):
@ -223,9 +215,9 @@ def merge(ctx, watchlist_to_merge):
wl.merge_watchlist(watchlist_to_merge, watchlist, _watchlists_data_path) wl.merge_watchlist(watchlist_to_merge, watchlist, _watchlists_data_path)
@watchlists.command(help='dump a text respresentation of a watchlist to console') @watchlists.command(help='dump text respresentation of a watchlist to console')
@click.argument('name', nargs=1, required=False) @click.argument('name', nargs=1, required=False)
@click.pass_context @click.pass_context
def dump(ctx, name): def dump(ctx, name):
watchlist = ctx.obj watchlist = ctx.obj
print(json.dumps(watchlist)) click.echo(json.dumps(watchlist))

View File

@ -6,11 +6,10 @@ from .log import get_logger
log = get_logger(__name__) log = get_logger(__name__)
def write_sorted_json(watchlist, path): def write_sorted_json(watchlist, path):
for key in watchlist: for key in watchlist:
s = set(watchlist[key]) watchlist[key] = sorted(list(set(watchlist[key])))
watchlist[key] = list(s)
watchlist[key].sort()
with open(path, 'w') as f: with open(path, 'w') as f:
json.dump(watchlist, f, sort_keys=True) json.dump(watchlist, f, sort_keys=True)
@ -24,29 +23,23 @@ def make_config_dir(dir_path):
def ensure_watchlists(file_path): def ensure_watchlists(file_path):
mode = 'r' if os.path.isfile(file_path) else 'w' mode = 'r' if os.path.isfile(file_path) else 'w'
with open(file_path, mode) as f: with open(file_path, mode) as f:
data = json.load(f) if not os.stat(file_path).st_size == 0 else {} return json.load(f) if not os.stat(file_path).st_size == 0 else {}
return data
def load_watchlists(watchlist, path): def write_watchlists(watchlist, path):
watchlist = json.loads(watchlist) write_sorted_json(json.loads(watchlist), path)
write_sorted_json(watchlist, path)
def new_group(name, watchlist, path):
watchlist.setdefault(name, [])
write_sorted_json(watchlist, path)
def add_ticker(name, ticker_name, watchlist, path): def add_ticker(name, ticker_name, watchlist, path):
if name in watchlist: watchlist.setdefault(name, []).append(str(ticker_name).upper())
watchlist[name].append(str(ticker_name).upper())
write_sorted_json(watchlist, path) write_sorted_json(watchlist, path)
def remove_ticker(name, ticker_name, watchlist, path): def remove_ticker(name, ticker_name, watchlist, path):
if name in watchlist: if name in watchlist:
watchlist[name].remove(str(ticker_name).upper()) watchlist[name].remove(str(ticker_name).upper())
if watchlist[name] == []:
del watchlist[name]
write_sorted_json(watchlist, path) write_sorted_json(watchlist, path)

View File

@ -4,11 +4,9 @@ CLI testing, dawg.
import json import json
import subprocess import subprocess
import pytest import pytest
import tempfile
import os.path import os.path
import logging import logging
import piker.watchlists as wl
def run(cmd): def run(cmd):
"""Run cmd and check for zero return code. """Run cmd and check for zero return code.
@ -89,109 +87,3 @@ def test_api_method_not_found(nyse_tickers, capfd):
out, err = capfd.readouterr() out, err = capfd.readouterr()
assert 'null' in out assert 'null' in out
assert f'No api method `{bad_meth}` could be found?' in err assert f'No api method `{bad_meth}` could be found?' in err
@pytest.fixture
def temp_dir():
#Create temporary directory
with tempfile.TemporaryDirectory() as tempdir:
config_dir = os.path.join(tempdir, 'piker')
yield config_dir
@pytest.fixture
def piker_dir(temp_dir):
wl.make_config_dir(temp_dir)
path = os.path.join(temp_dir, 'watchlists.json')
yield path
def test_watchlist_is_sorted_and_saved_to_file(piker_dir):
"""Ensure that watchlist is sorted and saved to file
"""
wl_temp = {'test': ['TEST.CN', 'AAA'], 'AA': ['TEST.CN']}
wl_sort = {'AA': ['TEST.CN'], 'test': ['AAA', 'TEST.CN']}
wl.write_sorted_json(wl_temp, piker_dir)
temp_sorted = wl.ensure_watchlists(piker_dir)
assert temp_sorted == wl_sort
def test_watchlists_config_dir_created(caplog, temp_dir):
"""Ensure that a config directory is created
"""
with caplog.at_level(logging.DEBUG):
wl.make_config_dir(temp_dir)
assert len(caplog.records) == 1
record = caplog.records[0]
assert record.levelname == 'DEBUG'
assert record.message == f"Creating config dir {temp_dir}"
assert os.path.isdir(temp_dir)
#Test that there is no error and that a log message is not generatd
#when trying to create a directory that already exists
with caplog.at_level(logging.DEBUG):
wl.make_config_dir(temp_dir)
assert len(caplog.records) == 1
def test_watchlist_is_read_from_file(piker_dir):
"""Ensure json info is read from file or an empty dict is generated
"""
wl_temp = wl.ensure_watchlists(piker_dir)
assert wl_temp == {}
wl_temp2 = '{"AA": ["TEST.CN"]}'
wl.load_watchlists(wl_temp2, piker_dir)
assert json.loads(wl_temp2) == wl.ensure_watchlists(piker_dir)
def test_watchlist_loaded(piker_dir):
"""Ensure that text respresentation of a watchlist is loaded to file
"""
wl_temp = '{"test": ["TEST.CN"]}'
wl.load_watchlists(wl_temp, piker_dir)
wl_temp2 = wl.ensure_watchlists(piker_dir)
assert wl_temp == json.dumps(wl_temp2)
def test_new_watchlist_group_added(piker_dir):
"""Ensure that a new watchlist key is added to the watchlists dictionary
"""
wl_temp = {}
wl.new_group('test', wl_temp, piker_dir)
wl_temp = wl.ensure_watchlists(piker_dir)
assert len(wl_temp.keys()) == 1
def test_new_ticker_added(piker_dir):
"""Ensure that a new ticker is added to a watchlist
"""
wl_temp = {'test': []}
wl.add_ticker('test', 'TEST.CN', wl_temp, piker_dir)
wl_temp = wl.ensure_watchlists(piker_dir)
assert len(wl_temp['test']) == 1
def test_ticker_is_removed(piker_dir):
"""Verify that passed in ticker is removed
"""
wl_temp = {'test': ['TEST.CN']}
wl.remove_ticker('test', 'TEST.CN', wl_temp, piker_dir)
wl_temp = wl.ensure_watchlists(piker_dir)
assert wl_temp == {'test': []}
def test_group_is_deleted(piker_dir):
"""Check that watchlist group is removed
"""
wl_temp = {'test': ['TEST.CN']}
wl.delete_group('test', wl_temp, piker_dir)
wl_temp = wl.ensure_watchlists(piker_dir)
assert wl_temp.get('test') == None
def test_watchlist_is_merged(piker_dir):
"""Ensure that watchlist is merged
"""
wl_temp = {'test': ['TEST.CN']}
wl_temp2 = '{"test2": ["TEST2.CN"]}'
wl.merge_watchlist(wl_temp2, wl_temp, piker_dir)
wl_temp3 = wl.ensure_watchlists(piker_dir)
assert wl_temp3 == {'test': ['TEST.CN'], 'test2': ['TEST2.CN']}

View File

@ -0,0 +1,109 @@
"""
Watchlists testing.
"""
import json
import pytest
import tempfile
import os.path
import logging
import piker.watchlists as wl
@pytest.fixture
def temp_dir():
"""Creates a path to a pretend config dir in a temporary directory for
testing.
"""
with tempfile.TemporaryDirectory() as tempdir:
config_dir = os.path.join(tempdir, 'piker')
yield config_dir
@pytest.fixture
def piker_dir(temp_dir):
wl.make_config_dir(temp_dir)
yield os.path.join(temp_dir, 'watchlists.json')
def test_watchlist_is_sorted_no_dups_and_saved_to_file(piker_dir):
wl_temp = {'test': ['TEST.CN', 'AAA'], 'AA': ['TEST.CN', 'TEST.CN'],
'AA': ['TEST.CN']}
wl_sort = {'AA': ['TEST.CN'], 'test': ['AAA', 'TEST.CN']}
wl.write_sorted_json(wl_temp, piker_dir)
temp_sorted = wl.ensure_watchlists(piker_dir)
assert temp_sorted == wl_sort
def test_watchlists_config_dir_created(caplog, temp_dir):
"""Ensure that a config directory is created.
"""
with caplog.at_level(logging.DEBUG):
wl.make_config_dir(temp_dir)
assert len(caplog.records) == 1
record = caplog.records[0]
assert record.levelname == 'DEBUG'
assert record.message == f"Creating config dir {temp_dir}"
assert os.path.isdir(temp_dir)
# Test that there is no error and that a log message is not generatd
# when trying to create a directory that already exists
with caplog.at_level(logging.DEBUG):
wl.make_config_dir(temp_dir)
# There should be no additional log message.
assert len(caplog.records) == 1
def test_watchlist_is_read_from_file(piker_dir):
"""Ensure json info is read from file or an empty dict is generated
and that text respresentation of a watchlist is saved to file.
"""
wl_temp = wl.ensure_watchlists(piker_dir)
assert wl_temp == {}
wl_temp2 = '{"AA": ["TEST.CN"]}'
wl.write_watchlists(wl_temp2, piker_dir)
assert json.loads(wl_temp2) == wl.ensure_watchlists(piker_dir)
def test_new_ticker_added(piker_dir):
"""Ensure that a new ticker is added to a watchlist for both cases.
"""
wl.add_ticker('test', 'TEST.CN', {'test': ['TEST2.CN']}, piker_dir)
wl_temp = wl.ensure_watchlists(piker_dir)
assert len(wl_temp['test']) == 2
wl.add_ticker('test2', 'TEST.CN', wl_temp, piker_dir)
wl_temp = wl.ensure_watchlists(piker_dir)
assert wl_temp['test2']
def test_ticker_is_removed(piker_dir):
"""Verify that passed in ticker is removed and that a group is removed
if no tickers left.
"""
wl_temp = {'test': ['TEST.CN', 'TEST2.CN'], 'test2': ['TEST.CN']}
wl.remove_ticker('test', 'TEST.CN', wl_temp, piker_dir)
wl.remove_ticker('test2', 'TEST.CN', wl_temp, piker_dir)
wl_temp = wl.ensure_watchlists(piker_dir)
assert wl_temp == {'test': ['TEST2.CN']}
assert not wl_temp.get('test2')
def test_group_is_deleted(piker_dir):
"""Check that watchlist group is removed.
"""
wl_temp = {'test': ['TEST.CN']}
wl.delete_group('test', wl_temp, piker_dir)
wl_temp = wl.ensure_watchlists(piker_dir)
assert not wl_temp.get('test')
def test_watchlist_is_merged(piker_dir):
"""Ensure that watchlist is merged.
"""
wl_temp = {'test': ['TEST.CN']}
wl_temp2 = '{"test2": ["TEST2.CN"]}'
wl.merge_watchlist(wl_temp2, wl_temp, piker_dir)
wl_temp3 = wl.ensure_watchlists(piker_dir)
assert wl_temp3 == {'test': ['TEST.CN'], 'test2': ['TEST2.CN']}