diff --git a/nomad/app/v1/routers/entries.py b/nomad/app/v1/routers/entries.py index 22b46108c20a5930fbc8f83c9413839959a51af9..82dea922b18d39f2c8dd31aba6d8b4d90be21c61 100644 --- a/nomad/app/v1/routers/entries.py +++ b/nomad/app/v1/routers/entries.py @@ -202,6 +202,7 @@ class EntryRawDir(BaseModel): entry_id: str = Field(None) upload_id: str = Field(None) mainfile: str = Field(None) + mainfile_key: Optional[str] = Field(None) files: List[EntryRawDirFile] = Field(None) @@ -467,6 +468,7 @@ def _create_entry_rawdir(entry_metadata: Dict[str, Any], uploads: _Uploads): entry_id = entry_metadata['entry_id'] upload_id = entry_metadata['upload_id'] mainfile = entry_metadata['mainfile'] + mainfile_key = entry_metadata.get('mainfile_key') upload_files = uploads.get_upload_files(upload_id) mainfile_dir = os.path.dirname(mainfile) @@ -475,7 +477,8 @@ def _create_entry_rawdir(entry_metadata: Dict[str, Any], uploads: _Uploads): for path_info in upload_files.raw_directory_list(mainfile_dir, files_only=True): files.append(EntryRawDirFile(path=path_info.path, size=path_info.size)) - return EntryRawDir(entry_id=entry_id, upload_id=upload_id, mainfile=mainfile, files=files) + return EntryRawDir( + entry_id=entry_id, upload_id=upload_id, mainfile=mainfile, mainfile_key=mainfile_key, files=files) def _answer_entries_rawdir_request( diff --git a/nomad/app/v1/routers/uploads.py b/nomad/app/v1/routers/uploads.py index e149d105667c416d5bfec57866ebc4fea7154a6c..4858bce7ab13a188823f8ddfea512e1f395686e6 100644 --- a/nomad/app/v1/routers/uploads.py +++ b/nomad/app/v1/routers/uploads.py @@ -125,6 +125,7 @@ class EntryProcData(ProcData): entry_id: str = Field() entry_create_time: datetime = Field() mainfile: str = Field() + mainfile_key: Optional[str] = Field() upload_id: str = Field() parser_name: str = Field() entry_metadata: Optional[dict] = Field() @@ -1040,15 +1041,19 @@ async def get_upload_entry_archive_mainfile( mainfile: str = Path( ..., description='The mainfile path within the upload\'s raw files.'), + mainfile_key: Optional[str] = FastApiQuery( + None, + description='The mainfile_key, for accessing child entries.'), user: User = Depends(create_user_dependency(required=False))): ''' For the upload specified by `upload_id`, gets the full archive of a single entry that is identified by the given `mainfile`. ''' _get_upload_with_read_access(upload_id, user, include_others=True) - return await answer_entry_archive_request( - dict(upload_id=upload_id, mainfile=mainfile), - required='*', user=user) + query = dict(upload_id=upload_id, mainfile=mainfile) + if mainfile_key: + query.update(mainfile_key=mainfile_key) + return await answer_entry_archive_request(query, required='*', user=user) @router.get( diff --git a/tests/app/v1/routers/common.py b/tests/app/v1/routers/common.py index 7705b2ce612ab2fbe2f68bcf4b8f5135d84348a1..9867113c8164a7adb3ad55db8c140d312439b3a4 100644 --- a/tests/app/v1/routers/common.py +++ b/tests/app/v1/routers/common.py @@ -590,6 +590,11 @@ def assert_metadata(response_json): for metadata in metadatas: if 'required' not in response_json: assert 'license' in metadata + if 'entry_id' in metadata: + if metadata['entry_id'].startswith('id_child_entries_child'): + assert metadata['mainfile_key'] + else: + assert 'mainfile_key' not in metadata if 'main_author' in metadata: assert 'email' not in metadata['main_author'] diff --git a/tests/app/v1/routers/test_datasets.py b/tests/app/v1/routers/test_datasets.py index 5841ebe6d001668bab2e5d4c25748445aaf19e53..3ed825344526369e908b8ac9be5b0cab1bc4cfdb 100644 --- a/tests/app/v1/routers/test_datasets.py +++ b/tests/app/v1/routers/test_datasets.py @@ -29,7 +29,7 @@ from nomad.utils.exampledata import ExampleData from tests.conftest import admin_user_id -from .test_entries import data as example_entries # pylint: disable=unused-import +from tests.conftest import example_data # pylint: disable=unused-import from .common import assert_response ''' @@ -220,7 +220,7 @@ def test_dataset(client, data, dataset_id, result, status_code): pytest.param('another test dataset', 'foreign', None, ['id_01', 'id_02'], 'test_user', 200, id='foreign-entries') ]) def test_post_datasets( - client, data, example_entries, test_user, test_user_auth, other_test_user, + client, data, example_data, test_user, test_user_auth, other_test_user, other_test_user_auth, dataset_name, dataset_type, query, entries, user, status_code): dataset = {'dataset_name': dataset_name, 'dataset_type': dataset_type} if query is not None: diff --git a/tests/app/v1/routers/test_entries.py b/tests/app/v1/routers/test_entries.py index 1740daac8d97d1b5e5d991503be2a9453361ad56..e5a547e260a2c4eb72e1bff33a4e467f2393df7d 100644 --- a/tests/app/v1/routers/test_entries.py +++ b/tests/app/v1/routers/test_entries.py @@ -34,7 +34,7 @@ from .common import ( perform_metadata_test, post_query_test_parameters, get_query_test_parameters, perform_owner_test, owner_test_parameters, pagination_test_parameters, aggregation_test_parameters) -from tests.conftest import example_data as data # pylint: disable=unused-import +from tests.conftest import example_data # pylint: disable=unused-import ''' These are the tests for all API operations below ``entries``. The tests are organized @@ -317,7 +317,7 @@ n_code_names = results.Simulation.program_name.a_elasticsearch[0].default_aggreg program_name = 'results.method.simulation.program_name' -def test_entries_all_metrics(client, data): +def test_entries_all_metrics(client, example_data): aggregations = { quantity: { 'terms': { @@ -352,7 +352,7 @@ def test_entries_all_metrics(client, data): {'terms': {'quantity': 'entry_id', 'include': '.*_0.*'}}, -1, -1, 422, None, id='bad-filter') ]) -def test_entries_aggregations(client, data, test_user_auth, aggregation, total, size, status_code, user): +def test_entries_aggregations(client, example_data, test_user_auth, aggregation, total, size, status_code, user): headers = {} if user == 'test_user': headers = test_user_auth @@ -376,7 +376,7 @@ def test_entries_aggregations(client, data, test_user_auth, aggregation, total, @pytest.mark.parametrize( 'query,agg_data,total,status_code', aggregation_exclude_from_search_test_parameters(resource='entries', total_per_entity=1, total=23)) -def test_entries_aggregations_exclude_from_search(client, data, query, agg_data, total, status_code): +def test_entries_aggregations_exclude_from_search(client, example_data, query, agg_data, total, status_code): aggs, types, lengths = agg_data response_json = perform_entries_metadata_test( client, owner='visible', @@ -404,7 +404,7 @@ def test_entries_aggregations_exclude_from_search(client, data, query, agg_data, pytest.param({'include': ['upload_id']}, 200, id='include-id') ]) @pytest.mark.parametrize('http_method', ['post', 'get']) -def test_entries_required(client, data, required, status_code, http_method): +def test_entries_required(client, example_data, required, status_code, http_method): response_json = perform_entries_metadata_test( client, required=required, pagination={'page_size': 1}, status_code=status_code, http_method=http_method) @@ -414,15 +414,17 @@ def test_entries_required(client, data, required, status_code, http_method): assert_required(response_json['data'][0], required, default_key='entry_id') -@pytest.mark.parametrize('entry_id, required, status_code', [ - pytest.param('id_01', {}, 200, id='id'), - pytest.param('doesnotexist', {}, 404, id='404'), - pytest.param('id_01', {'include': ['entry_id', 'upload_id']}, 200, id='include'), - pytest.param('id_01', {'exclude': ['upload_id']}, 200, id='exclude'), - pytest.param('id_01', {'exclude': ['entry_id', 'upload_id']}, 200, id='exclude-entry-id') +@pytest.mark.parametrize('user, entry_id, required, status_code', [ + pytest.param(None, 'id_01', {}, 200, id='id'), + pytest.param('test_user', 'id_child_entries_child1', {}, 200, id='id-child-entry'), + pytest.param(None, 'doesnotexist', {}, 404, id='404'), + pytest.param(None, 'id_01', {'include': ['entry_id', 'upload_id']}, 200, id='include'), + pytest.param(None, 'id_01', {'exclude': ['upload_id']}, 200, id='exclude'), + pytest.param(None, 'id_01', {'exclude': ['entry_id', 'upload_id']}, 200, id='exclude-entry-id') ]) -def test_entry_metadata(client, data, entry_id, required, status_code): - response = client.get('entries/%s?%s' % (entry_id, urlencode(required, doseq=True))) +def test_entry_metadata(client, example_data, test_auth_dict, user, entry_id, required, status_code): + user_auth, _ = test_auth_dict[user] + response = client.get('entries/%s?%s' % (entry_id, urlencode(required, doseq=True)), headers=user_auth) response_json = assert_metadata_response(response, status_code=status_code) if response_json is None: @@ -431,71 +433,83 @@ def test_entry_metadata(client, data, entry_id, required, status_code): assert_required(response_json['data'], required, default_key='entry_id') -@pytest.mark.parametrize('query, files, total, files_per_entry, status_code', [ - pytest.param({}, {}, 23, 5, 200, id='all'), - pytest.param({'entry_id': 'id_01'}, {}, 1, 5, 200, id='all'), - pytest.param({program_name: 'DOESNOTEXIST'}, {}, 0, 5, 200, id='empty') +@pytest.mark.parametrize('user, owner, query, files, total, files_per_entry, status_code', [ + pytest.param(None, None, {}, {}, 23, 5, 200, id='all'), + pytest.param(None, None, {'entry_id': 'id_01'}, {}, 1, 5, 200, id='one-entry'), + pytest.param('test_user', 'visible', {'upload_id': 'id_child_entries'}, {}, 3, 5, 200, id='child-entries'), + pytest.param(None, None, {program_name: 'DOESNOTEXIST'}, {}, 0, 5, 200, id='empty') ]) @pytest.mark.parametrize('http_method', ['post', 'get']) -def test_entries_rawdir(client, data, query, files, total, files_per_entry, status_code, http_method): +def test_entries_rawdir( + client, example_data, test_auth_dict, + user, owner, query, files, total, files_per_entry, status_code, http_method): + user_auth, _ = test_auth_dict[user] perform_entries_rawdir_test( - client, status_code=status_code, query=query, files=files, total=total, - files_per_entry=files_per_entry, http_method=http_method) - - -@pytest.mark.parametrize('query, files, total, files_per_entry, status_code', [ - pytest.param({}, {}, 23, 5, 200, id='all'), - pytest.param({program_name: 'DOESNOTEXIST'}, {}, 0, 5, 200, id='empty'), - pytest.param({}, {'glob_pattern': '*.json'}, 23, 1, 200, id='glob'), - pytest.param({}, {'re_pattern': '[a-z]*\\.aux'}, 23, 4, 200, id='re'), - pytest.param({}, {'re_pattern': 'test_entry_02'}, 1, 5, 200, id='re-filter-entries'), - pytest.param({}, {'re_pattern': 'test_entry_02/.*\\.json'}, 1, 1, 200, id='re-filter-entries-and-files'), - pytest.param({}, {'glob_pattern': '*.json', 're_pattern': '.*\\.aux'}, 23, 4, 200, id='re-overwrites-glob'), - pytest.param({}, {'re_pattern': '**'}, -1, -1, 422, id='bad-re-pattern'), - pytest.param({}, {'compress': True}, 23, 5, 200, id='compress'), - pytest.param({}, {'include_files': ['1.aux']}, 23, 1, 200, id='file'), - pytest.param({}, {'include_files': ['1.aux', '2.aux']}, 23, 2, 200, id='files') + client, owner=owner, status_code=status_code, query=query, files=files, total=total, + files_per_entry=files_per_entry, http_method=http_method, headers=user_auth) + + +@pytest.mark.parametrize('user, owner, query, files, total, files_per_entry, status_code', [ + pytest.param(None, None, {}, {}, 23, 5, 200, id='all'), + pytest.param('test_user', 'visible', {'upload_id': 'id_child_entries'}, {}, (3, 1), 5, 200, id='child-entries'), + pytest.param(None, None, {program_name: 'DOESNOTEXIST'}, {}, 0, 5, 200, id='empty'), + pytest.param(None, None, {}, {'glob_pattern': '*.json'}, 23, 1, 200, id='glob'), + pytest.param(None, None, {}, {'re_pattern': '[a-z]*\\.aux'}, 23, 4, 200, id='re'), + pytest.param(None, None, {}, {'re_pattern': 'test_entry_02'}, 1, 5, 200, id='re-filter-entries'), + pytest.param(None, None, {}, {'re_pattern': 'test_entry_02/.*\\.json'}, 1, 1, 200, id='re-filter-entries-and-files'), + pytest.param(None, None, {}, {'glob_pattern': '*.json', 're_pattern': '.*\\.aux'}, 23, 4, 200, id='re-overwrites-glob'), + pytest.param(None, None, {}, {'re_pattern': '**'}, -1, -1, 422, id='bad-re-pattern'), + pytest.param(None, None, {}, {'compress': True}, 23, 5, 200, id='compress'), + pytest.param(None, None, {}, {'include_files': ['1.aux']}, 23, 1, 200, id='file'), + pytest.param(None, None, {}, {'include_files': ['1.aux', '2.aux']}, 23, 2, 200, id='files') ]) @pytest.mark.parametrize('http_method', ['post', 'get']) -def test_entries_raw(client, data, query, files, total, files_per_entry, status_code, http_method): +def test_entries_raw( + client, example_data, test_auth_dict, + user, owner, query, files, total, files_per_entry, status_code, http_method): + user_auth, _ = test_auth_dict[user] perform_entries_raw_test( - client, status_code=status_code, query=query, files=files, total=total, - files_per_entry=files_per_entry, http_method=http_method) + client, headers=user_auth, owner=owner, status_code=status_code, query=query, + files=files, total=total, files_per_entry=files_per_entry, http_method=http_method) @pytest.mark.parametrize('http_method', ['post', 'get']) @pytest.mark.parametrize('test_method', [ pytest.param(perform_entries_raw_test, id='raw'), pytest.param(perform_entries_archive_download_test, id='archive-download')]) -def test_entries_download_max(monkeypatch, client, data, test_method, http_method): +def test_entries_download_max(monkeypatch, client, example_data, test_method, http_method): monkeypatch.setattr('nomad.config.max_entry_download', 20) test_method(client, status_code=400, http_method=http_method) -@pytest.mark.parametrize('entry_id, files_per_entry, status_code', [ - pytest.param('id_01', 5, 200, id='id'), - pytest.param('id_embargo', -1, 404, id='404'), - pytest.param('doesnotexist', -1, 404, id='404')]) -def test_entry_rawdir(client, data, entry_id, files_per_entry, status_code): - response = client.get('entries/%s/rawdir' % entry_id) +@pytest.mark.parametrize('user, entry_id, files_per_entry, status_code', [ + pytest.param(None, 'id_01', 5, 200, id='id'), + pytest.param('test_user', 'id_child_entries_child1', 5, 200, id='child-entries'), + pytest.param(None, 'id_embargo', -1, 404, id='embargoed'), + pytest.param(None, 'doesnotexist', -1, 404, id='bad-entry_id')]) +def test_entry_rawdir(client, example_data, test_auth_dict, user, entry_id, files_per_entry, status_code): + user_auth, _ = test_auth_dict[user] + response = client.get('entries/%s/rawdir' % entry_id, headers=user_auth) assert_response(response, status_code) if status_code == 200: assert_entry_rawdir_response(response.json(), files_per_entry=files_per_entry) -@pytest.mark.parametrize('entry_id, files, files_per_entry, status_code', [ - pytest.param('id_01', {}, 5, 200, id='id'), - pytest.param('doesnotexist', {}, -1, 404, id='404'), - pytest.param('id_01', {'glob_pattern': '*.json'}, 1, 200, id='glob'), - pytest.param('id_01', {'re_pattern': '[a-z]*\\.aux'}, 4, 200, id='re'), - pytest.param('id_01', {'re_pattern': '**'}, -1, 422, id='bad-re-pattern'), - pytest.param('id_01', {'compress': True}, 5, 200, id='compress'), - pytest.param('id_01', {'include_files': ['1.aux']}, 1, 200, id='file'), - pytest.param('id_01', {'include_files': ['1.aux', '2.aux']}, 2, 200, id='files') +@pytest.mark.parametrize('user, entry_id, files, files_per_entry, status_code', [ + pytest.param(None, 'id_01', {}, 5, 200, id='id'), + pytest.param('test_user', 'id_child_entries_child1', {}, 5, 200, id='child-entry'), + pytest.param(None, 'doesnotexist', {}, -1, 404, id='404'), + pytest.param(None, 'id_01', {'glob_pattern': '*.json'}, 1, 200, id='glob'), + pytest.param(None, 'id_01', {'re_pattern': '[a-z]*\\.aux'}, 4, 200, id='re'), + pytest.param(None, 'id_01', {'re_pattern': '**'}, -1, 422, id='bad-re-pattern'), + pytest.param(None, 'id_01', {'compress': True}, 5, 200, id='compress'), + pytest.param(None, 'id_01', {'include_files': ['1.aux']}, 1, 200, id='file'), + pytest.param(None, 'id_01', {'include_files': ['1.aux', '2.aux']}, 2, 200, id='files') ]) -def test_entry_raw(client, data, entry_id, files, files_per_entry, status_code): - response = client.get('entries/%s/raw?%s' % (entry_id, urlencode(files, doseq=True))) +def test_entry_raw(client, example_data, test_auth_dict, user, entry_id, files, files_per_entry, status_code): + user_auth, _ = test_auth_dict[user] + response = client.get('entries/%s/raw?%s' % (entry_id, urlencode(files, doseq=True)), headers=user_auth) assert_response(response, status_code) if status_code == 200: assert_raw_zip_file( @@ -546,6 +560,7 @@ def example_data_with_compressed_files(elastic_module, raw_files_module, mongo_m @pytest.mark.parametrize('entry_id, path, params, status_code', [ pytest.param('id_01', 'mainfile.json', {}, 200, id='id'), + pytest.param('id_child_entries_child1', 'mainfile_w_children.json', {'user': 'test_user'}, 200, id='child-entry'), pytest.param('doesnotexist', 'mainfile.json', {}, 404, id='404-entry'), pytest.param('id_01', 'doesnot.exist', {}, 404, id='404-file'), pytest.param('id_01', 'mainfile.json', {'offset': 10, 'length': 10}, 200, id='offset-length'), @@ -556,32 +571,27 @@ def example_data_with_compressed_files(elastic_module, raw_files_module, mongo_m pytest.param('id_01', 'mainfile.json', {'decompress': True}, 200, id='decompress-json'), pytest.param('with_compr_published', 'mainfile.xz', {'decompress': True}, 200, id='decompress-xz-published'), pytest.param('with_compr_published', 'mainfile.gz', {'decompress': True}, 200, id='decompress-gz-published'), - pytest.param('with_compr_unpublished', 'mainfile.xz', {'decompress': True, 'user': 'test-user'}, 200, id='decompress-xz-unpublished'), - pytest.param('with_compr_unpublished', 'mainfile.gz', {'decompress': True, 'user': 'test-user'}, 200, id='decompress-gz-unpublished'), + pytest.param('with_compr_unpublished', 'mainfile.xz', {'decompress': True, 'user': 'test_user'}, 200, id='decompress-xz-unpublished'), + pytest.param('with_compr_unpublished', 'mainfile.gz', {'decompress': True, 'user': 'test_user'}, 200, id='decompress-gz-unpublished'), pytest.param('id_unpublished', 'mainfile.json', {}, 404, id='404-unpublished'), pytest.param('id_embargo_1', 'mainfile.json', {}, 404, id='404-embargo-no-user'), - pytest.param('id_embargo_1', 'mainfile.json', {'user': 'other-test-user'}, 404, id='404-embargo-no-access'), - pytest.param('id_embargo_1', 'mainfile.json', {'user': 'test-user'}, 200, id='embargo-main_author'), - pytest.param('id_embargo_w_coauthor_1', 'mainfile.json', {'user': 'other-test-user'}, 200, id='embargo-coauthor'), - pytest.param('id_embargo_w_reviewer_1', 'mainfile.json', {'user': 'other-test-user'}, 200, id='embargo-reviewer') + pytest.param('id_embargo_1', 'mainfile.json', {'user': 'other_test_user'}, 404, id='404-embargo-no-access'), + pytest.param('id_embargo_1', 'mainfile.json', {'user': 'test_user'}, 200, id='embargo-main_author'), + pytest.param('id_embargo_w_coauthor_1', 'mainfile.json', {'user': 'other_test_user'}, 200, id='embargo-coauthor'), + pytest.param('id_embargo_w_reviewer_1', 'mainfile.json', {'user': 'other_test_user'}, 200, id='embargo-reviewer') ]) def test_entry_raw_file( - client, data, example_data_with_compressed_files, example_mainfile_contents, test_user_auth, other_test_user_auth, + client, example_data, example_data_with_compressed_files, example_mainfile_contents, test_auth_dict, entry_id, path, params, status_code): user = params.get('user') + user_auth, _ = test_auth_dict[user] if user: del(params['user']) - if user == 'test-user': - headers = test_user_auth - elif user == 'other-test-user': - headers = other_test_user_auth - else: - headers = {} response = client.get( f'entries/{entry_id}/raw/{path}?{urlencode(params, doseq=True)}', - headers=headers) + headers=user_auth) assert_response(response, status_code) if status_code == 200: @@ -594,16 +604,19 @@ def test_entry_raw_file( assert content == 'test content\n' -@pytest.mark.parametrize('query, files, total, status_code', [ - pytest.param({}, {}, 23, 200, id='all'), - pytest.param({program_name: 'DOESNOTEXIST'}, {}, -1, 200, id='empty'), - pytest.param({}, {'compress': True}, 23, 200, id='compress') +@pytest.mark.parametrize('user, owner, query, files, total, status_code', [ + pytest.param(None, None, {}, {}, 23, 200, id='all'), + pytest.param('test_user', 'visible', {'upload_id': 'id_child_entries'}, {}, 3, 200, id='child-entries'), + pytest.param(None, None, {program_name: 'DOESNOTEXIST'}, {}, -1, 200, id='empty'), + pytest.param(None, None, {}, {'compress': True}, 23, 200, id='compress') ]) @pytest.mark.parametrize('http_method', ['post', 'get']) -def test_entries_archive_download(client, data, query, files, total, status_code, http_method): +def test_entries_archive_download( + client, example_data, test_auth_dict, user, owner, query, files, total, status_code, http_method): + user_auth, _ = test_auth_dict[user] perform_entries_archive_download_test( - client, status_code=status_code, query=query, files=files, total=total, - http_method=http_method) + client, headers=user_auth, owner=owner, status_code=status_code, query=query, http_method=http_method, + files=files, total=total) @pytest.mark.parametrize('required, status_code', [ @@ -613,28 +626,32 @@ def test_entries_archive_download(client, data, query, files, total, status_code pytest.param({'metadata': {'viewers[NOTANINT]': '*'}}, 422, id='bad-required-2'), pytest.param({'DOESNOTEXIST': '*'}, 422, id='bad-required-3') ]) -def test_entries_archive(client, data, required, status_code): +def test_entries_archive(client, example_data, required, status_code): perform_entries_archive_test( client, status_code=status_code, required=required, http_method='post') -@pytest.mark.parametrize('entry_id, status_code', [ - pytest.param('id_01', 200, id='id'), - pytest.param('id_02', 404, id='404-not-visible'), - pytest.param('doesnotexist', 404, id='404-does-not-exist')]) -def test_entry_archive(client, data, entry_id, status_code): - response = client.get('entries/%s/archive' % entry_id) +@pytest.mark.parametrize('user, entry_id, status_code', [ + pytest.param(None, 'id_01', 200, id='id'), + pytest.param('test_user', 'id_child_entries_child1', 200, id='child-entry'), + pytest.param(None, 'id_02', 404, id='404-not-visible'), + pytest.param(None, 'doesnotexist', 404, id='404-does-not-exist')]) +def test_entry_archive(client, example_data, test_auth_dict, user, entry_id, status_code): + user_auth, _ = test_auth_dict[user] + response = client.get('entries/%s/archive' % entry_id, headers=user_auth) assert_response(response, status_code) if status_code == 200: assert_archive_response(response.json()) -@pytest.mark.parametrize('entry_id, status_code', [ - pytest.param('id_01', 200, id='id'), - pytest.param('id_02', 404, id='404-not-visible'), - pytest.param('doesnotexist', 404, id='404-does-not-exist')]) -def test_entry_archive_download(client, data, entry_id, status_code): - response = client.get('entries/%s/archive/download' % entry_id) +@pytest.mark.parametrize('user, entry_id, status_code', [ + pytest.param(None, 'id_01', 200, id='id'), + pytest.param('test_user', 'id_child_entries_child1', 200, id='child-entry'), + pytest.param(None, 'id_02', 404, id='404-not-visible'), + pytest.param(None, 'doesnotexist', 404, id='404-does-not-exist')]) +def test_entry_archive_download(client, example_data, test_auth_dict, user, entry_id, status_code): + user_auth, _ = test_auth_dict[user] + response = client.get('entries/%s/archive/download' % entry_id, headers=user_auth) assert_response(response, status_code) if status_code == 200: archive = response.json() @@ -642,20 +659,22 @@ def test_entry_archive_download(client, data, entry_id, status_code): assert 'run' in archive -@pytest.mark.parametrize('entry_id, required, status_code', [ - pytest.param('id_01', '*', 200, id='full'), - pytest.param('id_02', '*', 404, id='404'), - pytest.param('id_01', {'metadata': '*'}, 200, id='partial'), - pytest.param('id_01', {'run': {'system[NOTANINT]': '*'}}, 422, id='bad-required-1'), - pytest.param('id_01', {'metadata': {'viewers[NOTANINT]': '*'}}, 422, id='bad-required-2'), - pytest.param('id_01', {'DOESNOTEXIST': '*'}, 422, id='bad-required-3'), - pytest.param('id_01', {'resolve-inplace': 'NotBool', 'workflow': '*'}, 422, id='bad-required-4'), - pytest.param('id_01', {'resolve-inplace': True, 'metadata': 'include-resolved'}, 200, id='resolve-inplace') +@pytest.mark.parametrize('user, entry_id, required, status_code', [ + pytest.param(None, 'id_01', '*', 200, id='full'), + pytest.param('test_user', 'id_child_entries_child1', '*', 200, id='full-child-entry'), + pytest.param(None, 'id_02', '*', 404, id='404'), + pytest.param(None, 'id_01', {'metadata': '*'}, 200, id='partial'), + pytest.param(None, 'id_01', {'run': {'system[NOTANINT]': '*'}}, 422, id='bad-required-1'), + pytest.param(None, 'id_01', {'metadata': {'viewers[NOTANINT]': '*'}}, 422, id='bad-required-2'), + pytest.param(None, 'id_01', {'DOESNOTEXIST': '*'}, 422, id='bad-required-3'), + pytest.param(None, 'id_01', {'resolve-inplace': 'NotBool', 'workflow': '*'}, 422, id='bad-required-4'), + pytest.param(None, 'id_01', {'resolve-inplace': True, 'metadata': 'include-resolved'}, 200, id='resolve-inplace') ]) -def test_entry_archive_query(client, data, entry_id, required, status_code): +def test_entry_archive_query(client, example_data, test_auth_dict, user, entry_id, required, status_code): + user_auth, _ = test_auth_dict[user] response = client.post('entries/%s/archive/query' % entry_id, json={ 'required': required - }) + }, headers=user_auth) assert_response(response, status_code) if status_code == 200: assert_archive_response(response.json(), required=required) @@ -679,7 +698,7 @@ n_elements = 'results.material.n_elements' pytest.param(perform_entries_rawdir_test, id='rawdir'), pytest.param(perform_entries_archive_test, id='archive'), pytest.param(perform_entries_archive_download_test, id='archive-download')]) -def test_entries_post_query(client, data, query, status_code, total, test_method): +def test_entries_post_query(client, example_data, query, status_code, total, test_method): response_json = test_method(client, query=query, status_code=status_code, total=total, http_method='post') response = client.post('entries/query', json={'query': query}) @@ -708,7 +727,7 @@ def test_entries_post_query(client, data, query, status_code, total, test_method pytest.param(perform_entries_rawdir_test, id='rawdir'), pytest.param(perform_entries_archive_test, id='archive'), pytest.param(perform_entries_archive_download_test, id='archive-download')]) -def test_entries_get_query(client, data, query, status_code, total, test_method): +def test_entries_get_query(client, example_data, query, status_code, total, test_method): response_json = test_method( client, query=query, status_code=status_code, total=total, http_method='get') @@ -744,7 +763,7 @@ def test_entries_get_query(client, data, query, status_code, total, test_method) pytest.param(perform_entries_archive_test, id='archive'), pytest.param(perform_entries_archive_download_test, id='archive-download')]) def test_entries_owner( - client, data, test_user_auth, other_test_user_auth, admin_user_auth, + client, example_data, test_user_auth, other_test_user_auth, admin_user_auth, owner, user, status_code, total_entries, total_mainfiles, total_materials, http_method, test_method): @@ -764,7 +783,7 @@ def test_entries_owner( pytest.param(perform_entries_metadata_test, id='metadata'), pytest.param(perform_entries_rawdir_test, id='rawdir'), pytest.param(perform_entries_archive_test, id='archive')]) -def test_entries_pagination(client, data, pagination, response_pagination, status_code, http_method, test_method): +def test_entries_pagination(client, example_data, pagination, response_pagination, status_code, http_method, test_method): response_json = test_method( client, pagination=pagination, status_code=status_code, http_method=http_method) diff --git a/tests/app/v1/routers/test_materials.py b/tests/app/v1/routers/test_materials.py index 0ba36e8d6395c4903d944574afe4f56d23f83cca..5013799dfca98bd871b2c5d916cc6c205282bb15 100644 --- a/tests/app/v1/routers/test_materials.py +++ b/tests/app/v1/routers/test_materials.py @@ -28,7 +28,7 @@ from .common import ( perform_metadata_test, perform_owner_test, owner_test_parameters, post_query_test_parameters, get_query_test_parameters, pagination_test_parameters, aggregation_test_parameters) -from tests.conftest import example_data as data # pylint: disable=unused-import +from tests.conftest import example_data # pylint: disable=unused-import ''' These are the tests for all API operations below ``entries``. The tests are organized @@ -53,7 +53,7 @@ program_name = 'entries.results.method.simulation.program_name' 'aggregation, total, size, status_code, user', aggregation_test_parameters( entity_id='material_id', material_prefix='', entry_prefix='entries.', total=6)) -def test_materials_aggregations(client, data, test_user_auth, aggregation, total, size, status_code, user): +def test_materials_aggregations(client, example_data, test_user_auth, aggregation, total, size, status_code, user): headers = {} if user == 'test_user': headers = test_user_auth @@ -82,7 +82,7 @@ def test_materials_aggregations(client, data, test_user_auth, aggregation, total @pytest.mark.parametrize( 'query,agg_data,total,status_code', aggregation_exclude_from_search_test_parameters(resource='materials', total_per_entity=3, total=6)) -def test_materials_aggregations_exclude_from_search(client, data, query, agg_data, total, status_code): +def test_materials_aggregations_exclude_from_search(client, example_data, query, agg_data, total, status_code): aggs, types, lengths = agg_data response_json = perform_materials_metadata_test( client, owner='visible', @@ -110,7 +110,7 @@ def test_materials_aggregations_exclude_from_search(client, data, query, agg_dat pytest.param({'include': [program_name]}, 200, id='include-id') ]) @pytest.mark.parametrize('http_method', ['post', 'get']) -def test_materials_required(client, data, required, status_code, http_method): +def test_materials_required(client, example_data, required, status_code, http_method): response_json = perform_materials_metadata_test( client, required=required, pagination={'page_size': 1}, status_code=status_code, http_method=http_method) @@ -127,7 +127,7 @@ def test_materials_required(client, data, required, status_code, http_method): pytest.param('id_01', {'exclude': ['n_elements']}, 200, id='exclude'), pytest.param('id_01', {'exclude': ['material_id', 'n_elements']}, 200, id='exclude-id') ]) -def test_material_metadata(client, data, material_id, required, status_code): +def test_material_metadata(client, example_data, material_id, required, status_code): response = client.get('materials/%s?%s' % (material_id, urlencode(required, doseq=True))) response_json = assert_metadata_response(response, status_code=status_code) @@ -164,7 +164,7 @@ def test_material_metadata(client, data, material_id, required, status_code): pytest.param({'entry_id': 'id_01'}, 422, 0, id='not-material-quantity'), pytest.param({'entries.material_id': 'id_01'}, 422, 0, id='not-entry-quantity') ]) -def test_materials_post_query(client, data, query, status_code, total): +def test_materials_post_query(client, example_data, query, status_code, total): response_json = perform_materials_metadata_test( client, query=query, status_code=status_code, total=total, http_method='post') @@ -188,7 +188,7 @@ def test_materials_post_query(client, data, query, status_code, total): @pytest.mark.parametrize('query, status_code, total', get_query_test_parameters( 'material_id', total=6, material_prefix='', entry_prefix='entries.')) -def test_materials_get_query(client, data, query, status_code, total): +def test_materials_get_query(client, example_data, query, status_code, total): assert 'entries.upload_create_time' in material_entry_type.quantities response_json = perform_materials_metadata_test( @@ -222,7 +222,7 @@ def test_materials_get_query(client, data, query, status_code, total): @pytest.mark.parametrize('test_method', [ pytest.param(perform_materials_metadata_test, id='metadata')]) def test_materials_owner( - client, data, test_user_auth, other_test_user_auth, admin_user_auth, + client, example_data, test_user_auth, other_test_user_auth, admin_user_auth, owner, user, status_code, total_entries, total_mainfiles, total_materials, http_method, test_method): @@ -235,7 +235,7 @@ def test_materials_owner( elements='elements', n_elements='n_elements', crystal_system='symmetry.crystal_system', total=6)) @pytest.mark.parametrize('http_method', ['post', 'get']) -def test_materials_pagination(client, data, pagination, response_pagination, status_code, http_method): +def test_materials_pagination(client, example_data, pagination, response_pagination, status_code, http_method): response_json = perform_materials_metadata_test( client, pagination=pagination, status_code=status_code, http_method=http_method) diff --git a/tests/app/v1/routers/test_uploads.py b/tests/app/v1/routers/test_uploads.py index c208f57a4c2e95fed5bbcbfacd19157cb78b3047..64b9c2c0ea21d887541cbb69e33afeb155a91d31 100644 --- a/tests/app/v1/routers/test_uploads.py +++ b/tests/app/v1/routers/test_uploads.py @@ -476,6 +476,7 @@ def test_get_uploads( @pytest.mark.parametrize('user, upload_id, expected_status_code', [ pytest.param('test_user', 'id_unpublished', 200, id='valid-upload_id'), + pytest.param('test_user', 'id_child_entries', 200, id='valid-upload_id-w-child-entries'), pytest.param('test_user', 'silly_value', 404, id='invalid-upload_id'), pytest.param(None, 'id_unpublished', 401, id='no-credentials'), pytest.param('invalid', 'id_unpublished', 401, id='invalid-credentials'), @@ -501,6 +502,15 @@ def test_get_upload( 'total': 1, 'page': 1, 'page_after_value': None, 'next_page_after_value': None, 'page_url': Any, 'next_page_url': None, 'prev_page_url': None, 'first_page_url': Any}), id='no-args'), + pytest.param( + dict( + upload_id='id_child_entries', + expected_data_len=3, + expected_response={'processing_successful': 3, 'processing_failed': 0}, + expected_pagination={ + 'total': 3, 'page': 1, 'page_after_value': None, 'next_page_after_value': None, + 'page_url': Any, 'next_page_url': None, 'prev_page_url': None, 'first_page_url': Any}), + id='upload-w-child-entries'), pytest.param( dict( user=None, @@ -643,6 +653,7 @@ def test_get_upload_entries( @pytest.mark.parametrize('upload_id, entry_id, user, expected_status_code', [ pytest.param('id_embargo', 'id_embargo_1', 'test_user', 200, id='ok'), + pytest.param('id_child_entries', 'id_child_entries_child1', 'test_user', 200, id='child-entry'), pytest.param('id_embargo', 'id_embargo_1', None, 401, id='no-credentials'), pytest.param('id_embargo', 'id_embargo_1', 'invalid', 401, id='invalid-credentials'), pytest.param('id_embargo', 'id_embargo_1', 'other_test_user', 401, id='no-access'), @@ -857,6 +868,10 @@ def test_get_upload_raw_path( 'test_user', 'id_unpublished', 'test_content/id_unpublished_1/', {'include_entry_info': True}, 200, ['1.aux', '2.aux', '3.aux', '4.aux', 'mainfile.json'], None, {'total': 5}, id='unpublished-dir-include_entry_info'), + pytest.param( + 'test_user', 'id_child_entries', 'test_content', {'include_entry_info': True}, + 200, ['1.aux', '2.aux', '3.aux', '4.aux', 'mainfile_w_children.json'], None, {'total': 5}, + id='dir-child-entries-include_entry_info'), pytest.param( 'test_user', 'id_unpublished', '', {}, 200, ['test_content'], None, {'total': 1}, @@ -926,7 +941,8 @@ def test_get_upload_rawdir_path( pytest.param('id_published', 'test_content/doesnotexist.json', None, 404, id='bad-mainfile'), pytest.param('id_doesnotexist', 'test_content/subdir/test_entry_01/mainfile.json', None, 404, id='bad-upload-id'), pytest.param('id_unpublished', 'test_content/id_unpublished_1/mainfile.json', None, 401, id='unpublished'), - pytest.param('id_unpublished', 'test_content/id_unpublished_1/mainfile.json', 'test_user', 200, id='auth') + pytest.param('id_unpublished', 'test_content/id_unpublished_1/mainfile.json', 'test_user', 200, id='auth'), + pytest.param('id_child_entries', 'test_content/mainfile_w_children.json', 'test_user', 200, id='entry-w-child-entries') ]) def test_get_upload_entry_archive_mainfile( client, example_data, test_auth_dict, @@ -944,7 +960,8 @@ def test_get_upload_entry_archive_mainfile( pytest.param('id_published', 'doesnotexist', None, 404, id='bad-entry-id'), pytest.param('id_doesnotexist', 'id_01', None, 404, id='bad-upload-id'), pytest.param('id_unpublished', 'id_unpublished_1', None, 401, id='unpublished'), - pytest.param('id_unpublished', 'id_unpublished_1', 'test_user', 200, id='auth') + pytest.param('id_unpublished', 'id_unpublished_1', 'test_user', 200, id='auth'), + pytest.param('id_child_entries', 'id_child_entries_child1', 'test_user', 200, id='child-entry') ]) def test_get_upload_entry_archive( client, example_data, test_auth_dict, diff --git a/tests/app/v1/routers/test_users.py b/tests/app/v1/routers/test_users.py index a08c2bfcbe7f8592b980dbacdb5c7c6c0f5fad24..092ea1379942982d40e97f93571419efa2058f47 100644 --- a/tests/app/v1/routers/test_users.py +++ b/tests/app/v1/routers/test_users.py @@ -75,9 +75,7 @@ def test_invite(client, test_user_auth, no_warn): [conf_test_users[conf_test_user_uuid(1)]], id='wrong-user-id') ]) -def test_users( - client, example_data, test_auth_dict, - args, expected_status_code, expected_content): +def test_users(client, args, expected_status_code, expected_content): prefix = args.get('prefix', None) user_id = args.get('user_id', None) @@ -116,9 +114,7 @@ def test_users( user_id=conf_test_user_uuid(1)), 200, conf_test_users[conf_test_user_uuid(1)], id='valid-user')]) -def test_users_id( - client, example_data, test_auth_dict, - args, expected_status_code, expected_content): +def test_users_id(client, args, expected_status_code, expected_content): user_id = args['user_id'] rv = client.get(f'users/{user_id}') assert rv.status_code == expected_status_code