[cli][tests] Changed the routes names and wrote the tests according to current configuration
This commit is contained in:
parent
ad1304f8d4
commit
c4872ec0b3
|
@ -11,11 +11,6 @@ def cli(ctx, version):
|
||||||
import halfapi
|
import halfapi
|
||||||
return click.echo(halfapi.version)
|
return click.echo(halfapi.version)
|
||||||
|
|
||||||
#if not IS_PROJECT:
|
|
||||||
# return init()
|
|
||||||
#if ctx.invoked_subcommand is None:
|
|
||||||
# return run()
|
|
||||||
|
|
||||||
if IS_PROJECT:
|
if IS_PROJECT:
|
||||||
import halfapi.cli.domain
|
import halfapi.cli.domain
|
||||||
import halfapi.cli.run
|
import halfapi.cli.run
|
||||||
|
|
|
@ -15,48 +15,15 @@ from halfapi.db import (
|
||||||
|
|
||||||
logger = logging.getLogger('halfapi')
|
logger = logging.getLogger('halfapi')
|
||||||
|
|
||||||
|
#################
|
||||||
|
# domain create #
|
||||||
|
#################
|
||||||
|
def create_domain(name):
|
||||||
|
pass
|
||||||
|
|
||||||
def delete_domain(domain):
|
###############
|
||||||
d = Domain(name=domain)
|
# domain read #
|
||||||
if len(d) != 1:
|
###############
|
||||||
return False
|
|
||||||
|
|
||||||
d.delete(delete_all=True)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
@click.option('--domain', '-d', default=None, multiple=True)
|
|
||||||
@click.option('--update', default=False, is_flag=True)
|
|
||||||
@cli.command()
|
|
||||||
def domain(domain, update):
|
|
||||||
"""
|
|
||||||
Lists routes for the specified domains, or update them in the database
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
domain (List[str]|None): The list of the domains to list/update
|
|
||||||
|
|
||||||
The parameter has a misleading name as it is a multiple option
|
|
||||||
but this would be strange to use it several times named as "domains"
|
|
||||||
|
|
||||||
update (boolean): If set, update the database for the selected domains
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not domain:
|
|
||||||
domain = DOMAINS
|
|
||||||
else:
|
|
||||||
for domain_name in domain:
|
|
||||||
if domain_name in DOMAINS:
|
|
||||||
continue
|
|
||||||
click.echo(
|
|
||||||
f'Domain {domain}s is not activated in the configuration')
|
|
||||||
|
|
||||||
if update:
|
|
||||||
update_db(domain)
|
|
||||||
else:
|
|
||||||
for domain_name in domain:
|
|
||||||
list_routes(domain)
|
|
||||||
|
|
||||||
|
|
||||||
def list_routes(domain):
|
def list_routes(domain):
|
||||||
click.echo(f'\nDomain : {domain}')
|
click.echo(f'\nDomain : {domain}')
|
||||||
routers = APIRouter(domain=domain)
|
routers = APIRouter(domain=domain)
|
||||||
|
@ -69,7 +36,9 @@ def list_routes(domain):
|
||||||
route['acls'] = acls
|
route['acls'] = acls
|
||||||
click.echo('- [{http_verb}] {path} ({acls})'.format(**route))
|
click.echo('- [{http_verb}] {path} ({acls})'.format(**route))
|
||||||
|
|
||||||
|
#################
|
||||||
|
# domain update #
|
||||||
|
#################
|
||||||
def update_db(domains):
|
def update_db(domains):
|
||||||
|
|
||||||
def add_domain(domain):
|
def add_domain(domain):
|
||||||
|
@ -279,3 +248,63 @@ def update_db(domains):
|
||||||
# @TODO : Insertion exception handling
|
# @TODO : Insertion exception handling
|
||||||
print(e)
|
print(e)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
#################
|
||||||
|
# domain delete #
|
||||||
|
#################
|
||||||
|
def delete_domain(domain):
|
||||||
|
d = Domain(name=domain)
|
||||||
|
if len(d) != 1:
|
||||||
|
return False
|
||||||
|
|
||||||
|
d.delete(delete_all=True)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@click.option('--read',default=False, is_flag=True)
|
||||||
|
@click.option('--create',default=False, is_flag=True)
|
||||||
|
@click.option('--update',default=False, is_flag=True)
|
||||||
|
@click.option('--delete',default=False, is_flag=True)
|
||||||
|
@click.option('--domains',default=None)
|
||||||
|
@cli.command()
|
||||||
|
def domain(domains, delete, update, create, read): #, domains, read, create, update, delete):
|
||||||
|
"""
|
||||||
|
Lists routes for the specified domains, or update them in the database
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
domain (List[str]|None): The list of the domains to list/update
|
||||||
|
|
||||||
|
The parameter has a misleading name as it is a multiple option
|
||||||
|
but this would be strange to use it several times named as "domains"
|
||||||
|
|
||||||
|
update (boolean): If set, update the database for the selected domains
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not domains:
|
||||||
|
if create:
|
||||||
|
return create_domain()
|
||||||
|
|
||||||
|
domains = DOMAINS
|
||||||
|
else:
|
||||||
|
domains_ = []
|
||||||
|
for domain_name in domains.split(','):
|
||||||
|
if domain_name in DOMAINS:
|
||||||
|
domains.append(domain_name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
click.echo(
|
||||||
|
f'Domain {domain_name}s is not activated in the configuration')
|
||||||
|
|
||||||
|
domains = domains_
|
||||||
|
|
||||||
|
update = False
|
||||||
|
for domain in domains:
|
||||||
|
if update:
|
||||||
|
update_db(domain)
|
||||||
|
if delete:
|
||||||
|
delete_domain(domain)
|
||||||
|
else:
|
||||||
|
list_routes(domain)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,8 @@ from .cli import cli
|
||||||
|
|
||||||
logger = logging.getLogger('halfapi')
|
logger = logging.getLogger('halfapi')
|
||||||
|
|
||||||
TMPL_HALFAPI_ETC = """Insert this into the HALFAPI_CONF_DIR/{project} file
|
TMPL_HALFAPI_ETC = """[project]
|
||||||
|
name = {project}
|
||||||
[project]
|
|
||||||
host = 127.0.0.1
|
host = 127.0.0.1
|
||||||
port = 8000
|
port = 8000
|
||||||
secret = /path/to/secret_file
|
secret = /path/to/secret_file
|
||||||
|
@ -22,6 +21,12 @@ production = False
|
||||||
base_dir = {base_dir}
|
base_dir = {base_dir}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def format_halfapi_etc(project, path):
|
||||||
|
return TMPL_HALFAPI_ETC.format(
|
||||||
|
project=project,
|
||||||
|
base_dir=path
|
||||||
|
)
|
||||||
|
|
||||||
TMPL_HALFAPI_CONFIG = """[project]
|
TMPL_HALFAPI_CONFIG = """[project]
|
||||||
name = {name}
|
name = {name}
|
||||||
halfapi_version = {halfapi_version}
|
halfapi_version = {halfapi_version}
|
||||||
|
@ -59,8 +64,8 @@ def init(project):
|
||||||
halfapi_version=__version__
|
halfapi_version=__version__
|
||||||
))
|
))
|
||||||
|
|
||||||
print(TMPL_HALFAPI_ETC.format(
|
click.echo(f'Insert this into the HALFAPI_CONF_DIR/{project} file')
|
||||||
project=project,
|
click.echo(format_halfapi_etc(
|
||||||
base_dir=os.path.abspath(project)
|
project,
|
||||||
))
|
os.path.abspath(project)))
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ from configparser import ConfigParser
|
||||||
IS_PROJECT = os.path.isfile('.halfapi/config')
|
IS_PROJECT = os.path.isfile('.halfapi/config')
|
||||||
|
|
||||||
if IS_PROJECT:
|
if IS_PROJECT:
|
||||||
|
|
||||||
default_config = {
|
default_config = {
|
||||||
'project': {
|
'project': {
|
||||||
'host': '127.0.0.1',
|
'host': '127.0.0.1',
|
||||||
|
@ -35,17 +36,25 @@ if IS_PROJECT:
|
||||||
|
|
||||||
CONF_DIR = environ.get('HALFAPI_CONF_DIR', '/etc/half_api')
|
CONF_DIR = environ.get('HALFAPI_CONF_DIR', '/etc/half_api')
|
||||||
|
|
||||||
config.read(filenames=[os.path.join(
|
HALFAPI_CONF_FILE=os.path.join(
|
||||||
CONF_DIR,
|
CONF_DIR,
|
||||||
PROJECT_NAME
|
PROJECT_NAME
|
||||||
)])
|
)
|
||||||
|
if not os.path.isfile(HALFAPI_CONF_FILE):
|
||||||
|
print(f'Missing {HALFAPI_CONF_FILE}, exiting')
|
||||||
|
sys.exit(1)
|
||||||
|
config.read(filenames=[HALFAPI_CONF_FILE])
|
||||||
|
|
||||||
HOST = config.get('project', 'host')
|
HOST = config.get('project', 'host')
|
||||||
PORT = config.getint('project', 'port')
|
PORT = config.getint('project', 'port')
|
||||||
DB_NAME = f'halfapi_{PROJECT_NAME}'
|
DB_NAME = f'halfapi_{PROJECT_NAME}'
|
||||||
|
|
||||||
|
try:
|
||||||
with open(config.get('project', 'secret')) as secret_file:
|
with open(config.get('project', 'secret')) as secret_file:
|
||||||
SECRET = secret_file.read()
|
SECRET = secret_file.read()
|
||||||
|
except FileNotFoundError:
|
||||||
|
print('There is no file like {}'.format(config.get('project', 'secret')))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
PRODUCTION = config.getboolean('project', 'production')
|
PRODUCTION = config.getboolean('project', 'production')
|
||||||
BASE_DIR = config.get('project', 'base_dir')
|
BASE_DIR = config.get('project', 'base_dir')
|
||||||
|
|
|
@ -1,7 +1,57 @@
|
||||||
# content of conftest.py
|
#!/usr/bin/env python3
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import importlib
|
||||||
|
import tempfile
|
||||||
|
from unittest.mock import patch
|
||||||
from typing import Dict, Tuple
|
from typing import Dict, Tuple
|
||||||
import pytest
|
import pytest
|
||||||
|
from uuid import uuid1
|
||||||
|
from click.testing import CliRunner
|
||||||
|
from halfapi import __version__
|
||||||
|
from halfapi.cli import cli
|
||||||
|
from halfapi.cli.init import format_halfapi_etc
|
||||||
|
Cli = cli.cli
|
||||||
|
|
||||||
|
PROJNAME = os.environ.get('PROJ','tmp_api')
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def runner():
|
||||||
|
return CliRunner()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def dropdb():
|
||||||
|
p = subprocess.Popen(['dropdb', f'halfapi_{PROJNAME}'])
|
||||||
|
p.wait()
|
||||||
|
yield
|
||||||
|
|
||||||
|
p = subprocess.Popen(['dropdb', f'halfapi_{PROJNAME}'])
|
||||||
|
p.wait()
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def createdb():
|
||||||
|
p = subprocess.Popen(['createdb', f'halfapi_{PROJNAME}'])
|
||||||
|
p.wait()
|
||||||
|
return
|
||||||
|
|
||||||
|
def confdir(dirname):
|
||||||
|
d = os.environ.get(dirname)
|
||||||
|
if not d:
|
||||||
|
os.environ[dirname] = tempfile.mkdtemp(prefix='halfapi_')
|
||||||
|
return os.environ.get(dirname)
|
||||||
|
if not os.path.isdir(d):
|
||||||
|
os.mkdir(d)
|
||||||
|
return d
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def halform_conf_dir():
|
||||||
|
return confdir('HALFORM_CONF_DIR')
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def halfapi_conf_dir():
|
||||||
|
return confdir('HALFAPI_CONF_DIR')
|
||||||
|
|
||||||
# store history of failures per test class name and per index in parametrize (if
|
# store history of failures per test class name and per index in parametrize (if
|
||||||
# parametrize used)
|
# parametrize used)
|
||||||
|
@ -51,3 +101,28 @@ def pytest_runtest_setup(item):
|
||||||
# test name
|
# test name
|
||||||
if test_name is not None:
|
if test_name is not None:
|
||||||
pytest.xfail("previous test failed ({})".format(test_name))
|
pytest.xfail("previous test failed ({})".format(test_name))
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def project_runner(runner, dropdb, createdb, halform_conf_dir, halfapi_conf_dir):
|
||||||
|
env = {
|
||||||
|
'HALFORM_CONF_DIR': halform_conf_dir,
|
||||||
|
'HALFAPI_CONF_DIR': halfapi_conf_dir
|
||||||
|
}
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
res = runner.invoke(Cli, ['init', PROJNAME],
|
||||||
|
env=env,
|
||||||
|
catch_exceptions=True)
|
||||||
|
assert res.exit_code == 0
|
||||||
|
|
||||||
|
os.chdir(PROJNAME)
|
||||||
|
secret = tempfile.mkstemp()
|
||||||
|
SECRET_PATH = secret[1]
|
||||||
|
with open(SECRET_PATH, 'w') as f:
|
||||||
|
f.write(str(uuid1()))
|
||||||
|
|
||||||
|
with open(os.path.join(halfapi_conf_dir, PROJNAME), 'w') as f:
|
||||||
|
PROJ_CONFIG = re.sub('secret = .*', f'secret = {SECRET_PATH}',
|
||||||
|
format_halfapi_etc(PROJNAME, os.getcwd()))
|
||||||
|
f.write(PROJ_CONFIG)
|
||||||
|
|
||||||
|
yield lambda args: runner.invoke(Cli, args, env=env)
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import importlib
|
import importlib
|
||||||
|
import tempfile
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from click.testing import CliRunner
|
from click.testing import CliRunner
|
||||||
|
@ -13,26 +15,6 @@ Cli = cli.cli
|
||||||
|
|
||||||
PROJNAME = os.environ.get('PROJ','tmp_api')
|
PROJNAME = os.environ.get('PROJ','tmp_api')
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def runner():
|
|
||||||
return CliRunner()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def dropdb():
|
|
||||||
p = subprocess.Popen(['dropdb', f'halfapi_{PROJNAME}'])
|
|
||||||
p.wait()
|
|
||||||
yield
|
|
||||||
|
|
||||||
p = subprocess.Popen(['dropdb', f'halfapi_{PROJNAME}'])
|
|
||||||
p.wait()
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def createdb():
|
|
||||||
p = subprocess.Popen(['createdb', f'halfapi_{PROJNAME}'])
|
|
||||||
p.wait()
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.incremental
|
@pytest.mark.incremental
|
||||||
class TestCli():
|
class TestCli():
|
||||||
|
@ -79,12 +61,12 @@ class TestCli():
|
||||||
r = runner.invoke(Cli, ['init', testproject])
|
r = runner.invoke(Cli, ['init', testproject])
|
||||||
assert r.exit_code == 1
|
assert r.exit_code == 1
|
||||||
|
|
||||||
def test_init_project(self, runner, dropdb, createdb):
|
def test_init_project(self, runner, dropdb, createdb, halform_conf_dir, halfapi_conf_dir):
|
||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
with runner.isolated_filesystem():
|
with runner.isolated_filesystem():
|
||||||
env = {
|
env = {
|
||||||
'HALFORM_CONF_DIR': os.environ.get('HALFORM_CONF_DIR', os.getcwd()),
|
'HALFORM_CONF_DIR': halform_conf_dir,
|
||||||
'HALFAPI_CONF_DIR': os.environ.get('HALFAPI_CONF_DIR', os.getcwd()),
|
'HALFAPI_CONF_DIR': halfapi_conf_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME], env=env)
|
res = runner.invoke(Cli, ['init', PROJNAME], env=env)
|
||||||
|
@ -105,96 +87,10 @@ class TestCli():
|
||||||
assert os.path.isfile(os.path.join(PROJNAME, '.halfapi', 'domains'))
|
assert os.path.isfile(os.path.join(PROJNAME, '.halfapi', 'domains'))
|
||||||
cp.read(os.path.join(PROJNAME, '.halfapi', 'domains'))
|
cp.read(os.path.join(PROJNAME, '.halfapi', 'domains'))
|
||||||
assert cp.has_section('domains')
|
assert cp.has_section('domains')
|
||||||
except AssertionError:
|
except AssertionError as e:
|
||||||
subprocess.run(['tree', '-a', os.getcwd()])
|
subprocess.run(['tree', '-a', os.getcwd()])
|
||||||
|
raise e
|
||||||
|
|
||||||
assert res.exit_code == 0
|
assert res.exit_code == 0
|
||||||
assert res.exception is None
|
assert res.exception is None
|
||||||
|
|
||||||
def test_run_commands(self, runner, dropdb, createdb):
|
|
||||||
def reloadcli():
|
|
||||||
importlib.reload(cli)
|
|
||||||
return cli.cli
|
|
||||||
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
assert res.exit_code == 0
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
Cli2 = reloadcli()
|
|
||||||
res = runner.invoke(Cli2, ['run', '--help'])
|
|
||||||
assert res.exception is None
|
|
||||||
assert res.exit_code == 0
|
|
||||||
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
res = runner.invoke(Cli, ['run', 'foobar'])
|
|
||||||
assert res.exit_code == 2
|
|
||||||
|
|
||||||
|
|
||||||
def test_domain_commands(self, runner, dropdb, createdb):
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
res = runner.invoke(Cli, ['domain', 'foobar'])
|
|
||||||
assert res.exit_code == 2
|
|
||||||
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
res = runner.invoke(Cli, ['domain', '--help'])
|
|
||||||
assert r.exit_code == 0
|
|
||||||
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
res = runner.invoke(Cli, ['domain', 'create', '--help'])
|
|
||||||
assert r.exit_code == 0
|
|
||||||
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
res = runner.invoke(Cli, ['domain', 'read', '--help'])
|
|
||||||
assert r.exit_code == 0
|
|
||||||
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
res = runner.invoke(Cli, ['domain', 'update', '--help'])
|
|
||||||
assert r.exit_code == 0
|
|
||||||
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
res = runner.invoke(Cli, ['domain', 'delete', '--help'])
|
|
||||||
assert r.exit_code == 0
|
|
||||||
|
|
||||||
def test_domain_create(self, runner, dropdb):
|
|
||||||
with runner.isolated_filesystem():
|
|
||||||
res = runner.invoke(Cli, ['init', PROJNAME])
|
|
||||||
assert res.exit_code == 0
|
|
||||||
|
|
||||||
os.chdir(PROJNAME)
|
|
||||||
|
|
||||||
DOMNAME='tmp_domain'
|
|
||||||
res = runner.invoke(Cli, ['domain', 'create', DOMNAME])
|
|
||||||
srcdir = os.path.join('domains', 'src', DOMNAME)
|
|
||||||
assert os.path.isdir(srcdir)
|
|
||||||
moddir = os.path.join(srcdir, DOMNAME)
|
|
||||||
assert os.path.isdir(moddir)
|
|
||||||
setup = os.path.join(srcdir, 'setup.py')
|
|
||||||
assert os.path.isfile(setup)
|
|
||||||
initfile = os.path.join(moddir, '__init__.py')
|
|
||||||
assert os.path.isfile(initfile)
|
|
||||||
aclfile = os.path.join(moddir, 'acl.py')
|
|
||||||
assert os.path.isfile(aclfile)
|
|
||||||
aclsdir = os.path.join(moddir, 'acls')
|
|
||||||
assert os.path.isdir(aclsdir)
|
|
||||||
routersdir = os.path.join(moddir, 'routers')
|
|
||||||
assert os.path.isdir(routersdir)
|
|
||||||
|
|
||||||
try:
|
|
||||||
dom_mod = importlib.import_module(DOMNAME, srcdir)
|
|
||||||
assert hasattr(dom_mod, 'ROUTERS')
|
|
||||||
except ImportError:
|
|
||||||
assert False
|
|
||||||
|
|
Loading…
Reference in New Issue