Compare commits

...

12 Commits

Author SHA1 Message Date
Maxime Alves LIRMM@home eba8919d97 [release] 0.6.21 2022-08-08 20:19:54 +02:00
Maxime Alves LIRMM@home d3c0970a0e [test][domain_middleware] tests for middleware 2022-08-08 20:19:25 +02:00
Maxime Alves LIRMM@home bc37b2c4b7 [lib/domain_middleware] takes full domain config in constructor 2022-08-08 20:16:03 +02:00
Maxime Alves LIRMM@home 782a489042 [testing] MODULE and CONFIG attributes 2022-08-08 20:01:48 +02:00
Maxime Alves LIRMM@home 6bb6abcbd4 [changelog] module 2022-08-05 09:42:14 +02:00
Maxime Alves LIRMM@home ff90e591aa [test][fix] configuration in halfapi route argument 2022-08-05 09:37:17 +02:00
Maxime Alves LIRMM 4991684ffe [testing] fix test with MODULE attribute 2022-08-05 08:55:12 +02:00
Maxime Alves LIRMM b2fbfd19cb [testing] disable dryrun test (non working) 2022-08-05 08:55:12 +02:00
Maxime Alves LIRMM 380b90c077 [cli] fix domain command and add config_file argument (as json) 2022-08-05 08:55:12 +02:00
Maxime Alves LIRMM 463c89c801 [docker] 3.10.5-slim-bullseye 2022-08-05 08:55:12 +02:00
Maxime Alves LIRMM@home 7e4436a2de [acl] ajout du parametre "out" dans les kwargs d'une route 2022-08-05 08:50:59 +02:00
Maxime Alves LIRMM@home 409bb400ab [release] 0.6.20 2022-07-18 23:23:09 +02:00
14 changed files with 147 additions and 58 deletions

View File

@ -1,5 +1,14 @@
# HalfAPI
## 0.6.21
- Store only domain's config in halfapi['config']
- Should run halfapi domain with config_file argument
- Testing : You can specify a "MODULE" attribute to point out the path to the Api's base module
- Testing : You can specify a "CONFIG" attribute to set the domain's testing configuration
- Environment : HALFAPI_DOMAIN_MODULE can be set to specify Api's base module
- Config : 'module' attribute can be set to specify Api's base module
## 0.6.20
- Fix arguments handling

View File

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM docker.io/python:3.8.12-slim-bullseye
FROM docker.io/python:3.10.5-slim-bullseye
COPY . /halfapi
WORKDIR /halfapi
RUN apt-get update > /dev/null && apt-get -y install git > /dev/null

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
__version__ = '0.6.20-rc0'
__version__ = '0.6.21'
def version():
return f'HalfAPI version:{__version__}'

View File

@ -8,6 +8,8 @@ import sys
import importlib
import subprocess
import json
import click
import orjson
@ -120,9 +122,10 @@ def list_api_routes():
@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.argument('config_file', type=click.File(mode='rb'), required=False)
@click.argument('domain',default=None, required=False)
@cli.command()
def domain(domain, delete, update, create, read): #, domains, read, create, update, delete):
def domain(domain, config_file, delete, update, create, read): #, domains, read, create, update, delete):
"""
The "halfapi domain" command
@ -147,17 +150,14 @@ def domain(domain, delete, update, create, read): #, domains, read, create, upd
from ..conf import CONFIG
from ..halfapi import HalfAPI
try:
config_domain = CONFIG.pop('domain').get(domain, {})
except KeyError:
config_domain = {}
if config_file:
CONFIG = json.loads(''.join(
[ line.decode() for line in config_file.readlines() ]
))
halfapi = HalfAPI(CONFIG)
half_domain = halfapi.add_domain(domain, config=config_domain)
click.echo(orjson.dumps(
half_domain.schema(),
halfapi.domains[domain].schema(),
option=orjson.OPT_NON_STR_KEYS,
default=ORJSONResponse.default_cast)
)

View File

@ -83,7 +83,7 @@ class HalfDomain(Starlette):
'id': self.id,
'version': self.version,
'halfapi_version': self.halfapi_version,
'config': self.config.get('domain', {}).get(self.name, {}).get('config', {})
'config': self.config['domain'][self.name]
}
})
]

View File

@ -84,6 +84,8 @@ class HalfRoute(Route):
logger.debug(
'Args for current route (%s)', param.get('args'))
if 'out' in param:
req.scope['out'] = param['out']
if 'out' in param:
req.scope['out'] = param['out'].copy()

View File

@ -122,12 +122,12 @@ class HalfAPI(Starlette):
domain_key = domain.get('name', key)
self.add_domain(
domain_key,
domain.get('module'),
domain.get('router'),
domain.get('acl'),
path)
add_domain_args = {
**domain,
'path': path
}
self.add_domain(**add_domain_args)
schemas.append(self.__domains[domain_key].schema())
@ -246,28 +246,26 @@ class HalfAPI(Starlette):
def domains(self):
return self.__domains
def add_domain(self, name, module=None, router=None, acl=None, path='/', config=None):
def add_domain(self, **kwargs):
# logger.debug('HalfApi.add_domain %s %s %s %s %s',
# name,
# module,
# router,
# acl,
# path,
# config)
if not kwargs.get('enabled'):
raise Exception(f'Domain not enabled ({kwargs})')
if config:
self.config['domain'][name] = config
name = kwargs['name']
if not module:
self.config['domain'][name] = kwargs.get('config', {})
if not kwargs.get('module'):
module = name
else:
module = kwargs.get('module')
try:
self.__domains[name] = HalfDomain(
name,
module=importlib.import_module(module),
router=router,
acl=acl,
router=kwargs.get('router'),
acl=kwargs.get('acl'),
app=self
)
@ -279,6 +277,6 @@ class HalfAPI(Starlette):
))
raise exc
self.mount(path, self.__domains[name])
self.mount(kwargs.get('path', name), self.__domains[name])
return self.__domains[name]

View File

@ -108,8 +108,9 @@ def args_check(fct):
kwargs['data'] = data
if req.scope.get('out'):
kwargs['out'] = req.scope.get('out').copy()
out_s = req.scope.get('out')
if out_s:
kwargs['out'] = list(out_s)
return await fct(req, *args, **kwargs)

View File

@ -22,10 +22,15 @@ class DomainMiddleware(BaseHTTPMiddleware):
"""
logger.info('DomainMiddleware app:%s domain:%s', app, domain)
super().__init__(app)
self.domain = domain
self.domain = domain.copy()
self.name = domain['name']
self.request = None
@property
def config(self):
return { **self.domain['config'] }
async def dispatch(self, request: Request,
call_next: RequestResponseEndpoint) -> Response:
"""
@ -35,7 +40,21 @@ class DomainMiddleware(BaseHTTPMiddleware):
request.scope['domain'] = self.domain['name']
if hasattr(request.app, 'config') \
and isinstance(request.app.config, dict):
request.scope['config'] = { **request.app.config }
# Set the config scope to the domain's config
request.scope['config'] = request.app.config.get(
'domain', {}
).get(
self.domain['name'], {}
).copy()
# TODO: Remove in 0.7.0
config = request.scope['config'].copy()
request.scope['config']['domain'] = {}
request.scope['config']['domain'][self.domain['name']] = {}
request.scope['config']['domain'][self.domain['name']]['config'] = config
else:
logger.debug('%s', request.app)
logger.debug('%s', getattr(request.app, 'config', None))

View File

@ -11,11 +11,29 @@ from ..cli.cli import cli
from ..halfapi import HalfAPI
from ..half_domain import HalfDomain
from pprint import pprint
import tempfile
class TestDomain(TestCase):
@property
def domain_name(self):
return getattr(self, 'DOMAIN')
@property
def module_name(self):
return getattr(self, 'MODULE', self.domain_name)
@property
def acl_path(self):
return getattr(self, 'ACL', '.acl')
@property
def router_path(self):
return getattr(self, 'ROUTERS', '.routers')
@property
def router_module(self):
return '.'.join((self.DOMAIN, self.ROUTERS))
return '.'.join((self.module_name, self.ROUTERS))
def setUp(self):
# CLI
@ -49,23 +67,26 @@ class TestDomain(TestCase):
'domain': {}
}
self.halfapi_conf['domain'][self.DOMAIN] = {
'name': self.DOMAIN,
'router': self.ROUTERS,
'acl': self.ACL,
self.halfapi_conf['domain'][self.domain_name] = {
'name': self.domain_name,
'router': self.router_path,
'acl': self.acl_path,
'module': self.module_name,
'prefix': False,
'enabled': True,
'config': {
'test': True
}
'config': getattr(self, 'CONFIG', {})
}
_, self.config_file = tempfile.mkstemp()
with open(self.config_file, 'w') as fh:
fh.write(json.dumps(self.halfapi_conf))
self.halfapi = HalfAPI(self.halfapi_conf)
self.client = TestClient(self.halfapi.application)
self.module = importlib.import_module(
getattr(self, 'MODULE', self.DOMAIN)
self.module_name
)
@ -77,13 +98,13 @@ class TestDomain(TestCase):
try:
result = self.runner.invoke(cli, '--version')
self.assertEqual(result.exit_code, 0)
result = self.runner.invoke(cli, ['domain', self.DOMAIN])
result = self.runner.invoke(cli, ['domain', self.DOMAIN, self.config_file])
self.assertEqual(result.exit_code, 0)
result_d = json.loads(result.stdout)
result = self.runner.invoke(cli, ['run', '--help'])
self.assertEqual(result.exit_code, 0)
result = self.runner.invoke(cli, ['run', '--dryrun', self.DOMAIN])
self.assertEqual(result.exit_code, 0)
# result = self.runner.invoke(cli, ['run', '--dryrun', self.DOMAIN])
# self.assertEqual(result.exit_code, 0)
except AssertionError as exc:
print(f'Result {result}')
print(f'Stdout {result.stdout}')
@ -111,14 +132,16 @@ class TestDomain(TestCase):
assert 'domain' in schema
r = self.client.get('/halfapi/acls')
"""
assert r.status_code == 200
d_r = r.json()
assert isinstance(d_r, dict)
assert self.DOMAIN in d_r.keys()
assert self.domain_name in d_r.keys()
ACLS = HalfDomain.acls(self.module, self.ACL)
assert len(ACLS) == len(d_r[self.DOMAIN])
ACLS = HalfDomain.acls(self.module, self.acl_path)
assert len(ACLS) == len(d_r[self.domain_name])
for acl_name in ACLS:
assert acl_name[0] in d_r[self.DOMAIN]
assert acl_name[0] in d_r[self.domain_name]
"""

View File

@ -4,6 +4,7 @@ import subprocess
import importlib
import tempfile
from unittest.mock import patch
import json
import pytest
from click.testing import CliRunner
@ -25,7 +26,20 @@ class TestCliProj():
r = project_runner('domain')
print(r.stdout)
assert r.exit_code == 1
r = project_runner('domain dummy_domain')
_, tmp_conf = tempfile.mkstemp()
with open(tmp_conf, 'w') as fh:
fh.write(
json.dumps({
'domain': {
'dummy_domain': {
'name': 'dummy_domain',
'enabled': True
}
}
})
)
r = project_runner(f'domain dummy_domain {tmp_conf}')
print(r.stdout)
assert r.exit_code == 0

View File

@ -14,4 +14,17 @@ def get(halfapi):
returns the configuration of the domain
"""
logger.error('%s', halfapi)
return halfapi['config']['domain']['dummy_domain']['config']
# TODO: Remove in 0.7.0
try:
assert 'test' in halfapi['config']['domain']['dummy_domain']['config']
except AssertionError as exc:
logger.error('No TEST in halfapi[config][domain][dummy_domain][config]')
raise exc
try:
assert 'test' in halfapi['config']
except AssertionError as exc:
logger.error('No TEST in halfapi[config]')
raise exc
return halfapi['config']

View File

@ -5,8 +5,7 @@ class TestDummyDomain(TestDomain):
from .dummy_domain import __name__, __routers__
DOMAIN = __name__
ROUTERS = __routers__
ACL = '.acl'
CONFIG = {'test': True}
def test_domain(self):
self.check_domain()

View File

@ -2,12 +2,23 @@ from starlette.testclient import TestClient
from starlette.middleware.base import BaseHTTPMiddleware
from unittest.mock import patch
from halfapi.lib.domain_middleware import DomainMiddleware
from halfapi import __version__
def test_init():
with patch('starlette.middleware.base.BaseHTTPMiddleware.__init__') as init:
mw = DomainMiddleware('app', 'domain')
mw = DomainMiddleware('app', {
'name': 'test',
'id': 'randomid',
'version': '0.0.0',
'halfapi_version': __version__,
'config': {}
})
init.assert_called_once_with('app')
assert mw.domain == 'domain'
assert isinstance(mw.domain, dict)
assert isinstance(mw.name, str)
assert mw.name == 'test'
assert isinstance(mw.config, dict)
assert len(mw.config) == 0
assert mw.request == None
def test_call(application_debug):