def parse(root_path, data): """ Creates and returns a RepositoryDefinition object. :param root_path: Reports descriptor root path. :type root_path: str :param data: Reports descriptor content. :type data: dict :returns: A repository definition object. :rtype: RepositoryDefinition """ reports = data.pop('reports') reports_definitions = [] for report in reports: parameters_definitions = [] for param in report.pop('parameters'): cls = ChoicesParameterDefinition if 'choices' in param else ParameterDefinition parameters_definitions.append(cls(**param)) if report['report_spec'] == '1': default_renderer = DEFAULT_RENDERER_ID template = report.pop('template') start_row = report.pop('start_row') start_col = report.pop('start_col') renderers_definitions = [ RendererDefinition(root_path=root_path, id=default_renderer, type='xlsx', description='Render report to Excel.', default=True, template=template, args={ 'start_row': start_row, 'start_col': start_col, }), ] if report['report_spec'] == '2': renderers_definitions = [ RendererDefinition(root_path=root_path, **renderer) for renderer in report.pop('renderers') ] reports_definitions.append( ReportDefinition( root_path=root_path, parameters=parameters_definitions, renderers=renderers_definitions, **report, ), ) return RepositoryDefinition( root_path=root_path, reports=reports_definitions, **data, )
def test_report_get_renderers_multiple(mocker, report_v2_json, renderer_json): report_json = report_v2_json() xls_renderer = RendererDefinition( root_path='root_path', **renderer_json(id='xlsx_renderer', default=False), ) json_renderer = RendererDefinition( root_path='root_path', **renderer_json( id='json_renderer', type='json', default=True, description='Json renderer', ), ) csv_renderer = RendererDefinition( root_path='root_path', **renderer_json( id='csv_renderer', type='csv', default=False, description='Csv renderer', ), ) pdf_renderer = RendererDefinition( root_path='root_path', **renderer_json( id='pdf_renderer', type='pdf', default=False, description='Pdf renderer', template='template.j2', args={ 'key1': 'value1', 'key2': 'value2' }, ), ) report_json['renderers'] = [ xls_renderer, json_renderer, csv_renderer, pdf_renderer ] defs = ReportDefinition(root_path='root_path', **report_json) data = defs.get_renderers() assert isinstance(data, list) assert len(data) == 4 assert data[0]['id'] == 'xlsx_renderer' for renderer in data: if renderer['default']: assert renderer['id'] == 'json_renderer'
def test_validator_renderer_unknown_type(param_json, renderer_type): report_dict = { 'name': 'Report', 'readme_file': 'readme.md', 'entrypoint': 'reports.report_package.entrypoint', 'audience': ['vendor', 'provider'], 'parameters': [param_json()], 'report_spec': '2', } tmp_fs = _get_tmpfs_with_readme_and_entry(report_dict['entrypoint']) renderer_dict = { 'root_path': tmp_fs.root_path, 'id': '123', 'type': renderer_type, 'default': True, 'description': 'Renderer', } renderer = RendererDefinition(**renderer_dict) errors = _validate_renderer('report_one', renderer) if renderer_type == 'json': assert len(errors) == 0 else: assert len(errors) != 0 assert 'not known' in errors[0] assert 'report_one' in errors[0]
def test_validator_empty_parameter_list(param_json): report_dict = { 'name': 'Report', 'readme_file': 'readme.md', 'entrypoint': 'reports.report_package.entrypoint', 'audience': ['vendor', 'provider'], 'report_spec': '2', } tmp_fs = _get_tmpfs_with_readme_and_entry(report_dict['entrypoint']) renderer_csv_dict = { 'root_path': tmp_fs.root_path, 'id': '123', 'type': 'csv', 'description': 'CSV Renderer', 'default': True, } csv_renderer = RendererDefinition(**renderer_csv_dict) report = ReportDefinition( root_path=tmp_fs.root_path, **report_dict, parameters=[], renderers=[csv_renderer], ) errors = _validate_report(report) assert len(errors) == 0
def test_validator_repo_readme_file_missing(param_json): report_dict = { 'name': 'Report', 'readme_file': 'readme.md', 'entrypoint': 'reports.report_package.entrypoint', 'audience': ['vendor', 'provider'], 'report_spec': '2', } renderer_csv_dict = { 'root_path': 'root_path', 'id': '123', 'type': 'csv', 'description': 'CSV Renderer', 'default': True, } csv_renderer = RendererDefinition(**renderer_csv_dict) parameter = ParameterDefinition(**param_json()) report = ReportDefinition( root_path='root_path', **report_dict, renderers=[csv_renderer], parameters=[parameter], ) repo_dict = { 'name': 'Reports Repository', 'readme_file': 'readme.md', 'version': '1.0.0', 'language': 'python', 'reports': [report], } repo = RepositoryDefinition(root_path='root_path', **repo_dict) errors = validate(repo) assert len(errors) != 0 assert 'repository property `readme_file` cannot be resolved' in errors[0]
def test_execute_report_invalid_renderer(mocker): config = Config() config.add_account( 'VA-000-001', 'Account 1', 'ApiKey XXXX:YYYY', ) config.activate('VA-000-001') mocker.patch('connect.cli.plugins.report.helpers.load_repo') mocker.patch( 'connect.cli.plugins.report.helpers.get_report_by_id', return_value=mocker.MagicMock( renderers=[ RendererDefinition('path', 'pdf', 'pdf', 'test'), ], audience=['vendor'], ), ) with pytest.raises(ClickException) as cv: execute_report(config, 'root_dir', 'local_id', 'out_file', 'out_format') assert str(cv.value) == 'The format out_format is not available for report local_id'
def test_validator_duplicate_renderers_error(param_json): report_dict = { 'name': 'Report', 'readme_file': 'readme.md', 'entrypoint': 'reports.report_package.entrypoint', 'audience': ['vendor', 'provider'], 'report_spec': '2', } tmp_fs = _get_tmpfs_with_readme_and_entry(report_dict['entrypoint']) renderer_dict = { 'root_path': tmp_fs.root_path, 'id': '123', 'type': 'csv', 'description': 'CSV Renderer', 'default': True, } renderer = RendererDefinition(**renderer_dict) parameter = ParameterDefinition(**param_json()) report = ReportDefinition( root_path=tmp_fs.root_path, **report_dict, renderers=[renderer, renderer], parameters=[parameter], ) errors = _validate_report(report) assert len(errors) != 0 assert 'duplicated renderer' in errors[0]
def test_validator_entrypoint_bad_directory_structure(report_v2_json, param_json): tmp_filesystem = TempFS() tmp_filesystem.create('readme.md') renderer_json_dict = { 'root_path': tmp_filesystem.root_path, 'id': '321', 'type': 'json', 'description': 'JSON Renderer', 'default': True, } renderer = RendererDefinition(**renderer_json_dict) parameter = ParameterDefinition(**param_json()) report_dict = report_v2_json( readme_file='readme.md', renderers=[renderer], parameters=[parameter], ) report = ReportDefinition( root_path=tmp_filesystem.root_path, **report_dict, ) errors = _validate_report(report) assert len(errors) != 0 assert 'directory structure does not match' in errors[0]
def test_report_definition_default_renderer(mocker, report_v2_json, renderer_json): report_json = report_v2_json(renderers=[ RendererDefinition(root_path='root_path', **renderer_json()) ], ) defs = ReportDefinition(root_path='root_path', **report_json) assert defs.default_renderer == defs.renderers[0].id
def parse(root_path, data): reports = data.pop('reports') reports_definitions = [] for report in reports: parameters_definitions = [] for param in report.pop('parameters'): cls = ChoicesParameterDefinition if 'choices' in param else ParameterDefinition parameters_definitions.append(cls(**param)) if report['report_spec'] == '1': default_renderer = 'default_xlsx_renderer' template = report.pop('template') start_row = report.pop('start_row') start_col = report.pop('start_col') renderers_definitions = [ RendererDefinition( root_path=root_path, id=default_renderer, type='xlsx', description='Render report to Excel.', default=True, template=template, args={ 'start_row': start_row, 'start_col': start_col, }), ] if report['report_spec'] == '2': renderers_definitions = [ RendererDefinition(root_path=root_path, **renderer) for renderer in report.pop('renderers') ] reports_definitions.append( ReportDefinition( root_path=root_path, parameters=parameters_definitions, renderers=renderers_definitions, **report, ), ) return RepositoryDefinition( root_path=root_path, reports=reports_definitions, **data, )
def test_validator_repo_duplicated_reports(mocker, param_json): mocker.patch( 'connect.reports.validator._validate_report', return_value=[], ) report_dict_1 = { 'name': 'Report', 'readme_file': 'readme.md', 'entrypoint': 'reports.report_package.entrypoint', 'audience': ['vendor', 'provider'], 'parameters': [param_json()], 'report_spec': '2', } report_dict_2 = { 'name': 'Report', 'readme_file': 'readme.md', 'entrypoint': 'reports.report_package.entrypoint', 'audience': ['vendor', 'provider'], 'parameters': [param_json()], 'report_spec': '2', } renderer_csv_dict = { 'root_path': 'root_path', 'id': '123', 'type': 'csv', 'description': 'CSV Renderer', 'default': True, } csv_renderer = RendererDefinition(**renderer_csv_dict) report_1 = ReportDefinition( root_path='root_path', **report_dict_1, renderers=[csv_renderer], ) report_2 = ReportDefinition( root_path='root_path', **report_dict_2, renderers=[csv_renderer], ) tmp_filesystem = TempFS() tmp_filesystem.create('readme.md') repo_dict = { 'name': 'Reports Repository', 'readme_file': 'readme.md', 'version': '1.0.0', 'language': 'python', 'reports': [report_1, report_2], } repo = RepositoryDefinition( root_path=tmp_filesystem.root_path, **repo_dict, ) errors = validate(repo) assert len(errors) != 0 assert 'Multiple reports within single module found' in errors[0]
def test_validate_ok(): defs = RendererDefinition( root_path='root_path', id='renderer_id', type='json', description='description', ) assert BaseRenderer.validate(defs) == []
def test_validate_no_template(): defs = RendererDefinition( root_path='root_path', id='renderer_id', type='xlsx', description='description', ) assert XLSXRenderer.validate(defs) == [ '`template` is required for xlsx renderer.' ]
def test_report_get_renderers(mocker, report_v2_json, renderer_json): report_json = report_v2_json() renderer = RendererDefinition(root_path='root_path', **renderer_json()) report_json['renderers'] = [renderer] defs = ReportDefinition(root_path='root_path', **report_json) data = defs.get_renderers() assert data[0]['id'] == renderer.id assert data[0]['type'] == renderer.type assert data[0]['description'] == renderer.description assert 'root_path' not in data[0]
def test_validate_invalid_args(mocker, args, error): tmp_fs = TempFS() defs = RendererDefinition( root_path=tmp_fs.root_path, id='renderer_id', type='xlsx', description='description', template='template.xlsx', args=args, ) _create_xlsx_doc(f'{tmp_fs.root_path}/{defs.template}') assert XLSXRenderer.validate(defs) == [error]
def test_validate_ok(mocker): mocker.patch('connect.reports.renderers.j2.os.path.isfile', return_value=True) defs = RendererDefinition( root_path='root_path', id='renderer_id', type='jinja2', description='description', template='template.csv.j2', ) assert Jinja2Renderer.validate(defs) == []
def test_validator_multiple_default_renderer(param_json): report_dict = { 'name': 'Report', 'readme_file': 'readme.md', 'entrypoint': 'reports.report_package.entrypoint', 'audience': ['vendor', 'provider'], 'report_spec': '2', } tmp_fs = _get_tmpfs_with_readme_and_entry(report_dict['entrypoint']) renderer_json_dict = { 'root_path': tmp_fs.root_path, 'id': '321', 'type': 'json', 'description': 'JSON Renderer', 'default': True, } renderer_csv_dict = { 'root_path': tmp_fs.root_path, 'id': '123', 'type': 'csv', 'description': 'CSV Renderer', 'default': True, } csv_renderer = RendererDefinition(**renderer_csv_dict) json_renderer = RendererDefinition(**renderer_json_dict) parameter = ParameterDefinition(**param_json()) report = ReportDefinition( root_path=tmp_fs.root_path, **report_dict, renderers=[csv_renderer, json_renderer], parameters=[parameter], ) errors = _validate_report(report) assert len(errors) != 0 assert f'report {report.local_id} has multiple default renderers:' in errors[ 0]
def test_validate_template_not_found(mocker): mocker.patch('connect.reports.renderers.xlsx.os.path.isfile', return_value=False) defs = RendererDefinition( root_path='root_path', id='renderer_id', type='xlsx', description='description', template='template.xlsx', ) assert XLSXRenderer.validate(defs) == [ 'template `template.xlsx` not found.' ]
def test_validate_tempfs_ok(): tmp_fs = TempFS() tmplate_filename = 'template.csv.j2' tmp_fs.create(tmplate_filename) defs = RendererDefinition( root_path=tmp_fs.root_path, id='renderer_id', type='jinja2', description='description', template=tmplate_filename, ) assert Jinja2Renderer.validate(defs) == []
def test_validate_ok(mocker, args): mocker.patch('connect.reports.renderers.pdf.os.path.isfile', return_value=True) defs = RendererDefinition( root_path='root_path', id='renderer_id', type='pdf', description='description', template='template.html.j2', args=args, ) assert PDFRenderer.validate(defs) == []
def test_validate_tmpfs_css_missing(): tmp_fs = TempFS() tmp_fs.makedirs('package/report') tmp_fs.create('package/report/template.html.j2') definition = RendererDefinition( root_path=tmp_fs.root_path, id='renderer_id', type='pdf', description='description', template='package/report/template.html.j2', args={'css_file': 'package/report/css_file.css'}, ) errors = PDFRenderer.validate(definition) assert f"css_file `{definition.args['css_file']}` not found." == errors[0]
def test_validate_template_invalid_name(mocker): mocker.patch('connect.reports.renderers.j2.os.path.isfile', return_value=True) defs = RendererDefinition( root_path='root_path', id='renderer_id', type='jinja2', description='description', template='template.j3', ) assert Jinja2Renderer.validate(defs) == [ 'invalid template name: `template.j3` ' '(must be in the form <name>.<ext>.j2).', ]
def test_validate_tmpfs_template_wrong_name(): tmp_fs = TempFS() tmp_fs.makedirs('package/report') tmp_fs.create('package/report/template.html.j3') tmp_fs.create('css_file.css') definition = RendererDefinition( root_path=tmp_fs.root_path, id='renderer_id', type='pdf', description='description', template='package/report/template.html.j3', args={'css_file': 'css_file.css'}, ) errors = PDFRenderer.validate(definition) assert f"invalid template name: `{definition.template}`" in errors[0]
def test_validate_template_not_valid(): tmp_filesystem = TempFS() tmp_filesystem.create('test.xlsx') defs = RendererDefinition( root_path=tmp_filesystem.root_path, id='renderer_id', type='xlsx', description='description', template='test.xlsx', ) errors = XLSXRenderer.validate(defs) assert 'not valid or empty' in errors[0]
def test_validate_css_not_found(mocker): mocker.patch('connect.reports.renderers.pdf.os.path.isfile', side_effect=[True, False]) defs = RendererDefinition( root_path='root_path', id='renderer_id', type='pdf', description='description', template='template.html.j2', args={'css_file': 'my/css_file.css'}, ) assert PDFRenderer.validate(defs) == [ 'css_file `my/css_file.css` not found.' ]
def test_validate_tempfs_template_invalid_name(): tmp_fs = TempFS() tmplate_filename = 'template.j3' tmp_fs.create(tmplate_filename) defs = RendererDefinition( root_path=tmp_fs.root_path, id='renderer_id', type='jinja2', description='description', template=tmplate_filename, ) assert Jinja2Renderer.validate(defs) == [ f'invalid template name: `{tmplate_filename}` ' '(must be in the form <name>.<ext>.j2).', ]
def test_validator_readme_file_not_existing(report_v2_json, param_json): renderer_json_dict = { 'root_path': 'root_path', 'id': '321', 'type': 'json', 'description': 'JSON Renderer', 'default': True, } renderer = RendererDefinition(**renderer_json_dict) parameter = ParameterDefinition(**param_json()) report_dict = report_v2_json(renderers=[renderer], parameters=[parameter]) report = ReportDefinition( root_path='root_path', **report_dict, ) errors = _validate_report(report) assert len(errors) != 0 assert 'property `readme_file` cannot be resolved' in errors[0]
def test_validator_entrypoint_bad_format(report_v2_json): tmp_filesystem = TempFS() tmp_filesystem.create('readme.md') renderer_json_dict = { 'root_path': tmp_filesystem.root_path, 'id': '321', 'type': 'json', 'description': 'JSON Renderer', } renderer = RendererDefinition(**renderer_json_dict) report_dict = report_v2_json( readme_file='readme.md', entrypoint='mypackage', renderers=[renderer], ) report = ReportDefinition( root_path=tmp_filesystem.root_path, **report_dict, ) errors = _validate_report(report) assert len(errors) != 0 assert 'does not follow the package structure' in errors[0]