diff --git a/MANIFEST.in b/MANIFEST.in index 84c29b7..c4b5962 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ -include *.py *.md -recursive-include namekoplus/chassis *.py -recursive-include namekoplus/templates *.py *.yml -recursive-include namekoplus/chassis-agent *.py *.yml \ No newline at end of file +include *.py *.md *.mako +recursive-include namekoplus/chassis *.py *.mako +recursive-include namekoplus/templates *.py *.yml *.mako +recursive-include namekoplus/chassis-agent *.py *.yml *.mako +recursive-include namekoplus/tests *.py *.mako \ No newline at end of file diff --git a/namekoplus/command.py b/namekoplus/command.py index de238b4..012be9f 100644 --- a/namekoplus/command.py +++ b/namekoplus/command.py @@ -7,6 +7,9 @@ from python_on_whales import DockerException, ClientNotFoundError, DockerClient, def check_docker(): + """ + Check if docker and docker compose are installed and running. + """ try: docker_testing.ps() except ClientNotFoundError: @@ -23,6 +26,9 @@ def check_docker(): @contextmanager def status(status_msg: str, newline: bool = False, quiet: bool = False): + """ + Show status message and yield. + """ msg_suffix = ' ...' if not newline else ' ...\n' click.echo(status_msg + msg_suffix) try: @@ -36,24 +42,25 @@ def status(status_msg: str, newline: bool = False, quiet: bool = False): click.echo(' Done\n') -def get_template_directory() -> str: +def get_directory(dir_name: str) -> str: """ - Return the directory where nameko_plus setup templates are found. + Return the directory path of the given nameko-plus directory name. """ import namekoplus package_dir = os.path.abspath(os.path.dirname(namekoplus.__file__)) - return os.path.join(package_dir, 'templates') + return os.path.join(package_dir, dir_name) -def get_agent_directory() -> str: - """ - Return the directory where nameko_plus setup agent are found. - """ - import namekoplus +def copy_files(src_dir, dest_dir): + for file_ in os.listdir(src_dir): + if file_ == '__pycache__': + continue - package_dir = os.path.abspath(os.path.dirname(namekoplus.__file__)) - return os.path.join(package_dir, 'chassis-agent') + src_file_path = os.path.join(src_dir, file_) + output_file = os.path.join(dest_dir, file_) + with status(f'Generating {os.path.abspath(output_file)}'): + shutil.copy(src_file_path, output_file) @click.group() @@ -78,24 +85,16 @@ def init(directory, _type): click.echo('Directory {} already exists and is not empty'.format(directory), err=True) return - template_dir = os.path.join(get_template_directory(), _type) + template_dir = os.path.join(get_directory('templates'), _type) if not os.access(template_dir, os.F_OK): click.echo('No such template type {}'.format(_type), err=True) return - # 创建目录 if not os.access(directory, os.F_OK): with status(f'Creating directory {os.path.abspath(directory)!r}'): os.makedirs(directory) - # 把 templates 放入新建的目录 - for file_ in os.listdir(template_dir): - if file_ == '__pycache__': - continue - src_file_path = os.path.join(template_dir, file_) - output_file = os.path.join(directory, file_) - with status(f'Generating {os.path.abspath(output_file)}'): - shutil.copy(src_file_path, output_file) + copy_files(template_dir, directory) @cli.command() @@ -119,7 +118,7 @@ def start(middleware, user, password): os.environ['RABBITMQ_DEFAULT_USER'] = user os.environ['RABBITMQ_DEFAULT_PASS'] = password - docker_compose_file_dir = os.path.join(get_agent_directory(), middleware) + docker_compose_file_dir = os.path.join(get_directory('chassis-agent'), middleware) for file_ in os.listdir(docker_compose_file_dir): compose_file_path = os.path.join(docker_compose_file_dir, file_) with status(f'Starting {middleware}'): @@ -138,7 +137,7 @@ def stop(middleware): """ check_docker() - docker_compose_file_dir = os.path.join(get_agent_directory(), middleware) + docker_compose_file_dir = os.path.join(get_directory('chassis-agent'), middleware) for file_ in os.listdir(docker_compose_file_dir): compose_file_path = os.path.join(docker_compose_file_dir, file_) with status(f'Stopping {middleware}'): @@ -146,5 +145,30 @@ def stop(middleware): docker.compose.down() +@cli.command() +@click.option('-e', '--existed_dir', 'directory', + required=True, + help='The existed directory name of the nameko service') +@click.option('-t', '--type', '_type', + default='unit', + show_default=True, + type=click.Choice(['unit'], case_sensitive=False), + help='The test type of the nameko service') +def test_gen(directory, _type): + """ + Generate test files for nameko services. + """ + if not os.access(directory, os.F_OK) or not os.listdir(directory): + click.echo('Directory {} dose not exist or is empty'.format(directory), err=True) + return + + tests_dir = os.path.join(get_directory('tests'), _type) + if not os.access(tests_dir, os.F_OK): + click.echo('No such test type {}'.format(_type), err=True) + return + + copy_files(tests_dir, directory) + + if __name__ == '__main__': cli() \ No newline at end of file diff --git a/namekoplus/tests/__init__.py b/namekoplus/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/namekoplus/tests/unit/__init__.py b/namekoplus/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/namekoplus/tests/unit/test_service.py b/namekoplus/tests/unit/test_service.py new file mode 100644 index 0000000..e595e58 --- /dev/null +++ b/namekoplus/tests/unit/test_service.py @@ -0,0 +1,20 @@ +""" +Service unit testing best practice. +""" + +from nameko.testing.services import worker_factory + + +def test_example_service(): + """ + Test example service. + """ + # create worker with mock dependencies + service = worker_factory(ServiceName) # TODO replace ServiceName with the name of the service and import it + + # add side effects to the mock rpc dependency on the "remote" service + service.remote.hello.side_effect = lambda name: "Hello, {}!".format(name) + + # test remote_hello business logic + assert service.remote_hello("Bryant") == "Hello, Bryant!" + service.remote.hello.assert_called_once_with("Bryant") \ No newline at end of file diff --git a/setup.py b/setup.py index 3cbaba3..35820a9 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ with open(path.join(here, 'README.md'), encoding='utf-8') as f: setup( name='namekoplus', - version='0.2.4', + version='0.3.0', description='A lightweight Python distributed microservice solution', long_description=long_description, long_description_content_type='text/markdown', @@ -71,7 +71,7 @@ setup( 'sqlalchemy==2.0.15', 'sqlacodegen==2.3.0', 'alembic==1.11.1'], - 'ssl': ['cryptography'], + 'security': ['cryptography'], 'dev': ['mako==1.2.4', 'environs==9.5.0'] },