From 41e4044cab50cf94d97a4e6c37a7a653fa825ed4 Mon Sep 17 00:00:00 2001 From: Markus Scheidgen <markus.scheidgen@gmail.com> Date: Tue, 12 Feb 2019 14:49:31 +0100 Subject: [PATCH] Refactored test fixtures. Added search tests. --- .vscode/launch.json | 2 +- docs/reference.rst | 4 + docs/test_fixtures.png | Bin 0 -> 81605 bytes nomad/coe_repo/calc.py | 59 ++-- nomad/coe_repo/user.py | 2 +- nomad/datamodel.py | 20 ++ nomad/infrastructure.py | 4 + nomad/migration.py | 6 +- nomad/processing/data.py | 52 ++-- nomad/search.py | 66 +++-- tests/__init__.py | 33 +++ tests/{bravado_flaks.py => bravado_flask.py} | 0 tests/conftest.py | 272 +++++++++++++------ tests/processing/test_base.py | 12 +- tests/processing/test_data.py | 51 ++-- tests/test_api.py | 107 ++------ tests/test_client.py | 26 +- tests/test_coe_repo.py | 132 +++++---- tests/test_files.py | 16 -- tests/test_migration.py | 31 +-- tests/test_search.py | 39 ++- 21 files changed, 549 insertions(+), 385 deletions(-) create mode 100644 docs/test_fixtures.png rename tests/{bravado_flaks.py => bravado_flask.py} (100%) diff --git a/.vscode/launch.json b/.vscode/launch.json index 45f353f603..7b93487017 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -44,7 +44,7 @@ "cwd": "${workspaceFolder}", "program": "${workspaceFolder}/.pyenv/bin/pytest", "args": [ - "-sv", "tests/test_api.py::TestUploads::test_put[None-multipart-tests/data/proc/examples_template.zip]" + "-sv", "tests/test_api.py::TestUploads::test_post[tests/data/proc/empty.zip]" ] }, { diff --git a/docs/reference.rst b/docs/reference.rst index 00c9e28636..db8b7b75ff 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -57,3 +57,7 @@ nomad.utils nomad.migration --------------- .. automodule:: nomad.migration + +tests +----- +.. automodule:: tests diff --git a/docs/test_fixtures.png b/docs/test_fixtures.png new file mode 100644 index 0000000000000000000000000000000000000000..3ade0e7335913fcabd61fb5848159c6f59a6f5bd GIT binary patch literal 81605 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%0A%y+oBmg(v8 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 literal 0 HcmV?d00001 diff --git a/nomad/coe_repo/calc.py b/nomad/coe_repo/calc.py index 76cecefc35..f1a949d276 100644 --- a/nomad/coe_repo/calc.py +++ b/nomad/coe_repo/calc.py @@ -17,6 +17,7 @@ import json from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship, aliased from sqlalchemy.sql.expression import literal +from datetime import datetime from nomad import infrastructure, utils from nomad.datamodel import CalcWithMetadata @@ -149,9 +150,16 @@ class Calc(Base): code_version_obj = CodeVersion(content=source_code_version) repo_db.add(code_version_obj) + if calc.upload_time is not None: + added_time = calc.upload_time + elif self.upload is not None and self.upload.upload_time is not None: + added_time = self.upload.upload_time + else: + added_time = datetime.now() + metadata = CalcMetaData( calc=self, - added=calc.upload_time if calc.upload_time is not None else self.upload.upload_time, + added=added_time, chemical_formula=calc.formula, filenames=('[%s]' % ','.join(['"%s"' % filename for filename in calc.files])).encode('utf-8'), location=calc.mainfile, @@ -183,41 +191,45 @@ class Calc(Base): self._set_value(base.topic_basis_set_type, calc.basis_set) # user relations - if calc.uploader is not None: - uploader = repo_db.query(User).get(calc.uploader.id) - else: - uploader = self.upload.user + def add_users_to_relation(source_users, relation): + for source_user in source_users: + coe_user = repo_db.query(User).get(source_user.id) + source_user.update(coe_user.to_popo()) + relation.append(coe_user) - self.owners.append(uploader) - - for coauthor in calc.coauthors: - self.coauthors.append(repo_db.query(User).get(coauthor.id)) + if calc.uploader is not None: + add_users_to_relation([calc.uploader], self.owners) + elif self.upload is not None and self.upload.user is not None: + self.owners.append(self.upload.user) + calc.uploader = self.upload.user.to_popo() - for shared_with in calc.shared_with: - self.shared_with.append(repo_db.query(User).get(shared_with.id)) + add_users_to_relation(calc.coauthors, self.coauthors) + add_users_to_relation(calc.shared_with, self.shared_with) # datasets for dataset in calc.datasets: dataset_id = dataset.id - coe_dataset = repo_db.query(Calc).get(dataset_id) - if coe_dataset is None: - coe_dataset = Calc(coe_calc_id=dataset_id) - repo_db.add(coe_dataset) + coe_dataset_calc: Calc = repo_db.query(Calc).get(dataset_id) + if coe_dataset_calc is None: + coe_dataset_calc = Calc(coe_calc_id=dataset_id) + repo_db.add(coe_dataset_calc) metadata = CalcMetaData( - calc=coe_dataset, + calc=coe_dataset_calc, added=self.upload.upload_time, chemical_formula=dataset.name) repo_db.add(metadata) if dataset.doi is not None: - self._add_citation(coe_dataset, dataset.doi['value'], 'INTERNAL') + self._add_citation(coe_dataset_calc, dataset.doi['value'], 'INTERNAL') # cause a flush to avoid future inconsistencies - coe_dataset = repo_db.query(Calc).get(dataset_id) + coe_dataset_calc = repo_db.query(Calc).get(dataset_id) - dataset = CalcSet(parent_calc_id=dataset_id, children_calc_id=self.coe_calc_id) - repo_db.add(dataset) + coe_dataset_rel = CalcSet(parent_calc_id=dataset_id, children_calc_id=self.coe_calc_id) + repo_db.add(coe_dataset_rel) + + dataset.update(DataSet(coe_dataset_calc).to_popo()) # references for reference in calc.references: @@ -284,9 +296,7 @@ class Calc(Base): result.pid = self.pid result.uploader = self.uploader.to_popo() result.upload_time = self.calc_metadata.added - result.datasets = list( - utils.POPO(id=ds.id, doi=ds.doi.to_popo(), name=ds.name) - for ds in datasets) + result.datasets = list(ds.to_popo() for ds in datasets) result.with_embargo = self.with_embargo result.comment = self.comment result.references = list( @@ -320,3 +330,6 @@ class DataSet: @property def name(self): return self._dataset_calc.calc_metadata.chemical_formula + + def to_popo(self): + return utils.POPO(id=self.id, doi=self.doi.to_popo(), name=self.name) diff --git a/nomad/coe_repo/user.py b/nomad/coe_repo/user.py index 23820f8de8..f3c8244fc4 100644 --- a/nomad/coe_repo/user.py +++ b/nomad/coe_repo/user.py @@ -150,7 +150,7 @@ class User(Base): # type: ignore def to_popo(self) -> utils.POPO: return utils.POPO( - user_id=self.user_id, + id=self.user_id, first_name=self.first_name, last_name=self.last_name, email=self.email, diff --git a/nomad/datamodel.py b/nomad/datamodel.py index 1e06cbc04f..2df4069f63 100644 --- a/nomad/datamodel.py +++ b/nomad/datamodel.py @@ -122,3 +122,23 @@ class CalcWithMetadata(): key: value for key, value in self.__dict__.items() if value is not None } + + def apply_user_metadata(self, metadata: dict): + """ + Applies a user provided metadata dict to this calc. + """ + self.pid = metadata.get('_pid') + self.comment = metadata.get('comment') + self.upload_time = metadata.get('_upload_time') + uploader_id = metadata.get('_uploader') + if uploader_id is not None: + self.uploader = utils.POPO(id=uploader_id) + self.references = [utils.POPO(value=ref) for ref in metadata.get('references', [])] + self.with_embargo = metadata.get('with_embargo', False) + self.coauthors = [ + utils.POPO(id=user) for user in metadata.get('coauthors', [])] + self.shared_with = [ + utils.POPO(id=user) for user in metadata.get('shared_with', [])] + self.datasets = [ + utils.POPO(id=ds['id'], doi=utils.POPO(value=ds.get('_doi')), name=ds.get('_name')) + for ds in metadata.get('datasets', [])] diff --git a/nomad/infrastructure.py b/nomad/infrastructure.py index 22f23fc9a1..de85924b40 100644 --- a/nomad/infrastructure.py +++ b/nomad/infrastructure.py @@ -90,6 +90,8 @@ def setup_elastic(): try: from nomad.search import Entry Entry.init(index=config.elastic.index_name) + Entry._index._name = config.elastic.index_name + logger.info('initialized elastic index', index_name=config.elastic.index_name) except RequestError as e: if e.status_code == 400 and 'resource_already_exists_exception' in e.error: @@ -99,6 +101,8 @@ def setup_elastic(): else: logger.info('init elastic index') + return elastic_client + def setup_repository_db(**kwargs): """ Creates a connection and stores it in the module variables. """ diff --git a/nomad/migration.py b/nomad/migration.py index c2a579b1d2..427e418b92 100644 --- a/nomad/migration.py +++ b/nomad/migration.py @@ -423,7 +423,7 @@ class NomadCOEMigration: """ Transforms to a dict that fullfils the API's uploade metadata model. """ return dict( _upload_time=source.upload_time, - _uploader=source.uploader['user_id'], + _uploader=source.uploader['id'], _pid=source.pid, references=[ref['value'] for ref in source.references], datasets=[dict( @@ -433,8 +433,8 @@ class NomadCOEMigration: mainfile=source.mainfile, with_embargo=source.with_embargo, comment=source.comment, - coauthors=list(user['user_id'] for user in source.coauthors), - shared_with=list(user['user_id'] for user in source.shared_with) + coauthors=list(user['id'] for user in source.coauthors), + shared_with=list(user['id'] for user in source.shared_with) ) def index(self, *args, **kwargs): diff --git a/nomad/processing/data.py b/nomad/processing/data.py index 84adbc8b6e..11517ce755 100644 --- a/nomad/processing/data.py +++ b/nomad/processing/data.py @@ -30,7 +30,7 @@ import logging from structlog import wrap_logger from contextlib import contextmanager -from nomad import utils, coe_repo, config, infrastructure +from nomad import utils, coe_repo, config, infrastructure, search from nomad.files import PathObject, UploadFiles, ExtractError, ArchiveBasedStagingUploadFiles from nomad.processing.base import Proc, Chord, process, task, PENDING, SUCCESS, FAILURE from nomad.parsing import parsers, parser_dict @@ -231,14 +231,19 @@ class Calc(Proc): def archiving(self): logger = self.get_logger() + calc_with_metadata = self._parser_backend.to_calc_with_metadata() + # persist the repository metadata - with utils.timer(logger, 'indexed', step='index'): - self.upload_files.metadata.insert( - self._parser_backend.to_calc_with_metadata().to_dict()) + with utils.timer(logger, 'saved repo metadata', step='persist'): + self.upload_files.metadata.insert(calc_with_metadata.to_dict()) + + # index in search + with utils.timer(logger, 'indexed', step='persist'): + search.Entry.from_calc_with_metadata(calc_with_metadata, published=False).persist() # persist the archive with utils.timer( - logger, 'archived', step='archive', + logger, 'archived', step='persist', input_size=self.mainfile_file.size) as log_data: with self.upload_files.archive_file(self.calc_id, 'wt') as out: self._parser_backend.write_json(out, pretty=True) @@ -248,7 +253,7 @@ class Calc(Proc): # close loghandler if self._calc_proc_logwriter is not None: with utils.timer( - logger, 'archived log', step='archive_log', + logger, 'archived log', step='persist', input_size=self.mainfile_file.size) as log_data: self._calc_proc_logwriter_ctx.__exit__(None, None, None) # pylint: disable=E1101 self._calc_proc_logwriter = None @@ -350,6 +355,11 @@ class Upload(Chord): logger = self.get_logger() with utils.lnr(logger, 'staged upload delete failed'): + with utils.timer( + logger, 'upload deleted from index', step='delete', + upload_size=self.upload_files.size): + search.Entry.delete_upload(self.upload_id) + with utils.timer( logger, 'staged upload deleted', step='delete', upload_size=self.upload_files.size): @@ -369,16 +379,23 @@ class Upload(Chord): logger = self.get_logger() with utils.lnr(logger, 'publish failed'): + upload_with_metadata = self.to_upload_with_metadata() + with utils.timer( logger, 'upload added to repository', step='publish', upload_size=self.upload_files.size): - coe_repo.Upload.add(self.to_upload_with_metadata()) + coe_repo.Upload.add(upload_with_metadata) with utils.timer( logger, 'staged upload files packed', step='publish', upload_size=self.upload_files.size): self.upload_files.pack() + with utils.timer( + logger, 'index updated', step='publish', + upload_size=self.upload_files.size): + search.Entry.publish_upload(upload_with_metadata) + with utils.timer( logger, 'staged upload deleted', step='publish', upload_size=self.upload_files.size): @@ -523,25 +540,8 @@ class Upload(Chord): def apply_metadata(calc): metadata = calc_metadata.get(calc.mainfile, self.metadata) - if metadata is None: - return calc - - calc.pid = metadata.get('_pid') - calc.comment = metadata.get('comment') - calc.upload_time = metadata.get('_upload_time') - uploader_id = metadata.get('_uploader') - if uploader_id is not None: - calc.uploader = utils.POPO(id=uploader_id) - calc.references = [utils.POPO(value=ref) for ref in metadata.get('references', [])] - calc.with_embargo = metadata.get('with_embargo', False) - calc.coauthors = [ - utils.POPO(id=user) for user in metadata.get('coauthors', [])] - calc.shared_with = [ - utils.POPO(id=user) for user in metadata.get('shared_with', [])] - calc.datasets = [ - utils.POPO(id=ds['id'], doi=utils.POPO(value=ds.get('_doi')), name=ds.get('_name')) - for ds in metadata.get('datasets', [])] - + if metadata is not None: + calc.apply_user_metadata(metadata) return calc result = UploadWithMetadata( diff --git a/nomad/search.py b/nomad/search.py index 474ec68342..c30f4efc30 100644 --- a/nomad/search.py +++ b/nomad/search.py @@ -20,20 +20,27 @@ from elasticsearch.exceptions import ConflictError, ConnectionTimeout from datetime import datetime import time from elasticsearch_dsl import Document, InnerDoc, Keyword, Text, Date, \ - Nested + Nested, Boolean, Search -from nomad import config, datamodel, infrastructure, datamodel +from nomad import config, datamodel, infrastructure, datamodel, coe_repo class AlreadyExists(Exception): pass class User(InnerDoc): - def __init__(self, user): - super().__init__( - id=user.user_id, - name='%s %s' % (user.first_name, user.last_name), - name_keyword='%s %s' % (user.first_name, user.last_name)) + + @classmethod + def from_user_popo(cls, user): + self = cls(id=user.id) + + if 'first_name' not in user: + user = coe_repo.User.from_user_id(user.id).to_popo() + + self.name = '%s %s' % (user['first_name'], user['last_name']) + self.name_keyword = '%s %s' % (user['first_name'], user['last_name']) + + return self id = Keyword() name = Text() @@ -41,8 +48,10 @@ class User(InnerDoc): class Dataset(InnerDoc): - def __init__(self, dataset): - super().__init__( + + @classmethod + def from_dataset_popo(cls, dataset): + return cls( id=dataset.id, doi=dataset.doi.value if dataset.doi is not None else None, name=dataset.name) @@ -57,15 +66,17 @@ class Entry(Document): name = config.elastic.index_name upload_id = Keyword() - upload_time = Date(format='epoch_millis') + upload_time = Date() calc_id = Keyword() calc_hash = Keyword() pid = Keyword() mainfile = Keyword() - files = Keyword() + files = Keyword(multi=True) uploader = Nested(User) - with_embargo = Keyword() + with_embargo = Boolean() + published = Boolean() + coauthors = Nested(User) shared_with = Nested(User) comment = Text() @@ -73,7 +84,7 @@ class Entry(Document): datasets = Nested(Dataset) formula = Keyword() - atoms = Keyword() + atoms = Keyword(multi=True) basis_set = Keyword() xc_functional = Keyword() system = Keyword() @@ -83,7 +94,7 @@ class Entry(Document): code_version = Keyword() @classmethod - def from_calc_with_metadata(cls, source: datamodel.CalcWithMetadata) -> 'Entry': + def from_calc_with_metadata(cls, source: datamodel.CalcWithMetadata, published: bool = False) -> 'Entry': return Entry( meta=dict(id=source.calc_id), upload_id=source.upload_id, @@ -93,14 +104,15 @@ class Entry(Document): pid=str(source.pid), mainfile=source.mainfile, files=source.files, - uploader=User(source.uploader) if source.uploader is not None else None, + uploader=User.from_user_popo(source.uploader) if source.uploader is not None else None, with_embargo=source.with_embargo, - coauthors=[User(user) for user in source.coauthors], - shared_with=[User(user) for user in source.shared_with], + published=published, + coauthors=[User.from_user_popo(user) for user in source.coauthors], + shared_with=[User.from_user_popo(user) for user in source.shared_with], comment=source.comment, references=[ref.value for ref in source.references], - datasets=[Dataset(ds) for ds in source.datasets], + datasets=[Dataset.from_dataset_popo(ds) for ds in source.datasets], formula=source.formula, atoms=list(set(source.atoms)), @@ -112,6 +124,11 @@ class Entry(Document): code_name=source.code_name, code_version=source.code_version) + @classmethod + def add_upload(cls, source: datamodel.UploadWithMetadata): + for calc in source.calcs: + cls.from_calc_with_metadata(calc).save(op_type='create') + def persist(self, **kwargs): """ Persist this entry to elastic search. Kwargs are passed to elastic search. @@ -160,6 +177,16 @@ class Entry(Document): } conn.update_by_query(index, doc_type=[doc_type], body=body) + @classmethod + def publish_upload(cls, upload: datamodel.UploadWithMetadata): + cls.update_by_query(upload.upload_id, 'ctx._source["published"] = true') + # TODO run update on all calcs with their new metadata + + @classmethod + def delete_upload(cls, upload_id): + index = cls._default_index() + Search(index=index).query('match', upload_id=upload_id).delete() + @staticmethod def es_search(body): """ Perform an elasticsearch and not elasticsearch_dsl search on the Calc index. """ @@ -175,6 +202,3 @@ class Entry(Document): data['upload_time'] = data['upload_time'].isoformat() return {key: value for key, value in data.items() if value is not None} - - -# Entry.register_mapping(datamodel.CalcWithMetadata, Entry.from_calc_with_metadata) diff --git a/tests/__init__.py b/tests/__init__.py index e69de29bb2..d0a8968a51 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,33 @@ +# Copyright 2018 Markus Scheidgen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an"AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +The nomad@FAIRDI tests are based on the pytest library. Pytest uses *fixtures* to +modularize setup and teardown of mocks, infrastructure, and other context objects. +The following depicts the used hierarchy of fixtures: + +.. image:: test_fixtures.png + +Otherwise the test submodules follow the names of the nomad code modules. +""" + +from nomad import config + +# For convinience we test the api without path prefix. +# This should be setup with a fixture with in conftest.py, but it will be too late. +# After importing the api module, the config values have already been used and +# changing them afterwards does not change anything anymore. +services_config = config.services._asdict() +services_config.update(api_base_path='') +config.services = config.NomadServicesConfig(**services_config) diff --git a/tests/bravado_flaks.py b/tests/bravado_flask.py similarity index 100% rename from tests/bravado_flaks.py rename to tests/bravado_flask.py diff --git a/tests/conftest.py b/tests/conftest.py index 3416451c4a..dc01e9ec59 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,18 @@ +# Copyright 2018 Markus Scheidgen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an"AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Tuple import pytest import logging from sqlalchemy.orm import Session @@ -10,9 +25,20 @@ from threading import Lock, Thread import asyncore import time import pytest -import elasticsearch.exceptions +import shutil +import os.path +import datetime +import base64 +from bravado.client import SwaggerClient -from nomad import config, infrastructure +from nomad import config, infrastructure, files, parsing, processing, coe_repo, api + +from tests import test_parsing, test_normalizing +from tests.processing import test_data as test_processing +from tests.test_files import example_file, empty_file +from tests.bravado_flask import FlaskTestHttpClient + +example_files = [empty_file, example_file] @pytest.fixture(scope="session") @@ -23,12 +49,6 @@ def monkeysession(request): mpatch.undo() -@pytest.fixture(scope='session', autouse=True) -def nomad_files(monkeysession): - monkeysession.setattr('nomad.config.fs', config.FSConfig( - tmp='.volumes/test_fs/tmp', objects='.volumes/test_fs/objects')) - - @pytest.fixture(scope='session', autouse=True) def nomad_logging(): config.logstash = config.logstash._replace(enabled=False) @@ -36,6 +56,36 @@ def nomad_logging(): infrastructure.setup_logging() +@pytest.fixture(scope='session', autouse=True) +def raw_files_infra(monkeysession): + monkeysession.setattr('nomad.config.fs', config.FSConfig( + tmp='.volumes/test_fs/tmp', objects='.volumes/test_fs/objects')) + + +@pytest.fixture(scope='function') +def raw_files(raw_files_infra): + """ Provides cleaned out files directory structure per function. Clears files after test. """ + try: + yield + finally: + try: + shutil.rmtree(config.fs.objects) + except FileNotFoundError: + pass + try: + shutil.rmtree(config.fs.tmp) + except FileNotFoundError: + pass + + +@pytest.fixture(scope='function') +def client(monkeysession): + api.app.config['TESTING'] = True + client = api.app.test_client() + + yield client + + @pytest.fixture(scope='session') def celery_includes(): return ['nomad.processing.base'] @@ -49,57 +99,14 @@ def celery_config(): @pytest.fixture(scope='session') -def purged_app(celery_session_app): - """ - Purges all pending tasks of the celery app before test. This is necessary to - remove tasks from the queue that might be 'left over' from prior tests. - """ - celery_session_app.control.purge() - yield celery_session_app - - -@pytest.fixture() -def patched_celery(monkeypatch): - # There is a bug in celery, which prevents to use the celery_worker for multiple - # tests: https://github.com/celery/celery/issues/4088 - # The bug has a fix from Aug 2018, but it is not yet released (TODO). - # We monkeypatch a similar solution here. - def add_reader(self, fds, callback, *args): - from kombu.utils.eventio import ERR, READ, poll - - if self.poller is None: - self.poller = poll() - - return self.add(fds, callback, READ | ERR, args) - - monkeypatch.setattr('kombu.asynchronous.hub.Hub.add_reader', add_reader) - yield - - -@pytest.fixture(scope='session') -def celery_inspect(purged_app): - yield purged_app.control.inspect() - - -@pytest.fixture() -def worker(patched_celery, celery_inspect, celery_session_worker): - """ - Extension of the celery_session_worker fixture that ensures a clean task queue. - """ - yield - - # wait until there no more active tasks, to leave clean worker and queues for the next - # test. - while True: - empty = True - for value in celery_inspect.active().values(): - empty = empty and len(value) == 0 - if empty: - break +def worker(celery_session_worker): + """ Provides a clean worker (no old tasks) per function. Waits for all tasks to be completed. """ + pass @pytest.fixture(scope='function') -def mockmongo(monkeypatch): +def mongo(monkeypatch): + """ Provides a cleaned mocked mongo per function. """ disconnect() connection = connect('test_db', host='mongomock://localhost') @@ -110,22 +117,25 @@ def mockmongo(monkeypatch): connection.drop_database('test_db') -@pytest.fixture(scope='function') -def elastic(monkeysession): +@pytest.fixture(scope='session') +def elastic_infra(monkeysession): + """ Provides elastic infrastructure to the session """ monkeysession.setattr('nomad.config.elastic', config.elastic._replace(index_name='test_nomad_fairdi_calcs')) - infrastructure.setup_elastic() - try: - from nomad.search import Entry - Entry._index.delete() - Entry.init(index=config.elastic.index_name) - except elasticsearch.exceptions.NotFoundError: - pass + return infrastructure.setup_elastic() + +@pytest.fixture(scope='function') +def elastic(elastic_infra): + """ Provides a clean elastic per function. Clears elastic before test. """ + elastic_infra.delete_by_query( + index='test_nomad_fairdi_calcs', body=dict(query=dict(match_all={})), + wait_for_completion=True, refresh=True) assert infrastructure.elastic_client is not None + return elastic_infra @contextmanager -def create_repository_db(monkeysession=None, **kwargs): +def create_postgres_infra(monkeysession=None, **kwargs): """ A generator that sets up and tears down a test db and monkeypatches it to the respective global infrastructure variables. @@ -176,42 +186,83 @@ def create_repository_db(monkeysession=None, **kwargs): @pytest.fixture(scope='module') -def repository_db(monkeysession): - with create_repository_db(monkeysession, exists=False) as db: +def postgres_infra(monkeysession): + """ Provides a clean coe repository db per module """ + with create_postgres_infra(monkeysession, exists=False) as db: yield db @pytest.fixture(scope='function') -def expandable_repo_db(monkeysession, repository_db): - with create_repository_db(monkeysession, dbname='test_nomad_fairdi_expandable_repo_db', exists=False) as db: +def proc_infra(postgres, elastic, mongo, worker): + """ Combines all fixtures necessary for processing (postgres, elastic, worker, files, mongo) """ + return dict( + postgres=postgres, + elastic=elastic) + + +@pytest.fixture(scope='function') +def expandable_postgres(monkeysession, postgres_infra): + """ Provides a coe repository db that can be deleted during test """ + with create_postgres_infra(monkeysession, dbname='test_nomad_fairdi_expandable_repo_db', exists=False) as db: yield db @pytest.fixture(scope='function') -def clean_repository_db(repository_db): +def postgres(postgres_infra): + """ Provides a clean coe repository db per function. Clears db before test. """ # do not wonder, this will not setback the id counters - repository_db.execute('TRUNCATE uploads CASCADE;') - yield repository_db + postgres_infra.execute('TRUNCATE uploads CASCADE;') + yield postgres_infra @pytest.fixture(scope='module') -def test_user(repository_db): +def test_user(postgres_infra): from nomad import coe_repo return coe_repo.ensure_test_user(email='sheldon.cooper@nomad-fairdi.tests.de') @pytest.fixture(scope='module') -def other_test_user(repository_db): +def other_test_user(postgres_infra): from nomad import coe_repo return coe_repo.ensure_test_user(email='leonard.hofstadter@nomad-fairdi.tests.de') @pytest.fixture(scope='module') -def admin_user(repository_db): +def admin_user(postgres_infra): from nomad import coe_repo return coe_repo.admin_user() +def create_auth_headers(user): + basic_auth_str = '%s:password' % user.email + basic_auth_bytes = basic_auth_str.encode('utf-8') + basic_auth_base64 = base64.b64encode(basic_auth_bytes).decode('utf-8') + return { + 'Authorization': 'Basic %s' % basic_auth_base64 + } + + +@pytest.fixture(scope='module') +def test_user_auth(test_user: coe_repo.User): + return create_auth_headers(test_user) + + +@pytest.fixture(scope='module') +def test_other_user_auth(other_test_user: coe_repo.User): + return create_auth_headers(other_test_user) + + +@pytest.fixture(scope='module') +def admin_user_auth(admin_user: coe_repo.User): + return create_auth_headers(admin_user) + + +@pytest.fixture(scope='function') +def bravado(client, postgres, test_user_auth): + http_client = FlaskTestHttpClient(client, headers=test_user_auth) + return SwaggerClient.from_url('/swagger.json', http_client=http_client) + + @pytest.fixture(scope='function') def no_warn(caplog): yield caplog @@ -231,6 +282,17 @@ def with_error(caplog): assert count > 0 +@pytest.fixture(scope='function') +def with_warn(caplog): + yield caplog + count = 0 + for record in caplog.get_records(when='call'): + if record.levelname in ['WARNING']: + count += 1 + + assert count > 0 + + """ Fixture for mocked SMTP server for testing. Based on https://gist.github.com/akheron/cf3863cdc424f08929e4cb7dc365ef23. @@ -342,3 +404,61 @@ def mails(smtpd, monkeypatch): monkeypatch.setattr('nomad.config.mail', new_config) yield smtpd + + +@pytest.fixture(scope='session') +def example_mainfile() -> Tuple[str, str]: + return ('parsers/template', 'tests/data/parsers/template.json') + + +@pytest.fixture(scope='session', params=example_files) +def example_upload(request) -> str: + return request.param + + +@pytest.fixture(scope='module') +def example_user_metadata(other_test_user, test_user) -> dict: + return { + 'comment': 'test comment', + 'with_embargo': True, + 'references': ['http://external.ref/one', 'http://external.ref/two'], + '_uploader': other_test_user.user_id, + 'coauthors': [test_user.user_id], + '_upload_time': datetime.datetime.now(), + '_pid': 256 + } + + +@pytest.fixture(scope='function') +def parsed(example_mainfile: Tuple[str, str]) -> parsing.LocalBackend: + """ Provides a parsed calculation in the form of a LocalBackend. """ + parser, mainfile = example_mainfile + return test_parsing.run_parser(parser, mainfile) + + +@pytest.fixture(scope='function') +def normalized(parsed: parsing.LocalBackend) -> parsing.LocalBackend: + """ Provides a normalized calculation in the form of a LocalBackend. """ + return test_normalizing.run_normalize(parsed) + + +@pytest.fixture(scope='function') +def uploaded(example_upload: str, raw_files) -> str: + """ + Provides a uploaded with uploaded example file and gives the upload_id. + Clears files after test. + """ + example_upload_id = os.path.basename(example_upload).replace('.zip', '') + upload_files = files.ArchiveBasedStagingUploadFiles(example_upload_id, create=True) + shutil.copyfile(example_upload, upload_files.upload_file_os_path) + + return example_upload_id + + +@pytest.mark.timeout(10) +@pytest.fixture(scope='function') +def processed(uploaded: str, test_user: coe_repo.User, proc_infra) -> processing.Upload: + """ + Provides a processed upload. Upload was uploaded with test_user. + """ + return test_processing.run_processing(uploaded, test_user) diff --git a/tests/processing/test_base.py b/tests/processing/test_base.py index e873a42986..ec524b0547 100644 --- a/tests/processing/test_base.py +++ b/tests/processing/test_base.py @@ -34,7 +34,7 @@ class SingleTask(Proc): pass -def test_tasks(mockmongo): +def test_tasks(mongo): p = Tasks.create() assert p.tasks == ['a', 'b'] assert_proc(p, None, PENDING) @@ -56,7 +56,7 @@ class FailTasks(Proc): self.fail('fail fail fail') -def test_fail(mockmongo, with_error): +def test_fail(mongo, with_error): p = FailTasks.create() p.will_fail() @@ -84,7 +84,7 @@ class SimpleProc(Proc): pass -def test_simple_process(mockmongo, worker, no_warn): +def test_simple_process(mongo, worker, no_warn): p = SimpleProc.create() p.process() p.block_until_complete() @@ -99,7 +99,7 @@ class TaskInProc(Proc): @pytest.mark.timeout(5) -def test_task_as_proc(mockmongo, worker, no_warn): +def test_task_as_proc(mongo, worker, no_warn): p = TaskInProc.create() p.process() p.block_until_complete() @@ -118,7 +118,7 @@ class ProcInProc(Proc): pass -def test_fail_on_proc_in_proc(mockmongo, worker): +def test_fail_on_proc_in_proc(mongo, worker): p = ProcInProc.create() p.one() p.block_until_complete() @@ -152,7 +152,7 @@ class ChildProc(Proc): @pytest.mark.timeout(10) -def test_counter(mockmongo, worker, no_warn): +def test_counter(mongo, worker, no_warn): p = ParentProc.create() p.spawn_children() p.block_until_complete() diff --git a/tests/processing/test_data.py b/tests/processing/test_data.py index f45a822286..770c122a26 100644 --- a/tests/processing/test_data.py +++ b/tests/processing/test_data.py @@ -31,13 +31,6 @@ from nomad.files import ArchiveBasedStagingUploadFiles, UploadFiles, StagingUplo from nomad.processing import Upload, Calc from nomad.processing.base import task as task_decorator, FAILURE, SUCCESS -from tests.test_files import example_file, empty_file - -# import fixtures -from tests.test_files import clear_files # pylint: disable=unused-import - -example_files = [empty_file, example_file] - def test_send_mail(mails): infrastructure.send_mail('test name', 'test@email.de', 'test message', 'subjct') @@ -47,22 +40,12 @@ def test_send_mail(mails): @pytest.fixture(scope='function', autouse=True) -def mocks_forall(mockmongo): +def mongo_forall(mongo): pass -@pytest.fixture(scope='function', params=example_files) -def uploaded_id(request, clear_files) -> Generator[str, None, None]: - example_file = request.param - example_upload_id = os.path.basename(example_file).replace('.zip', '') - upload_files = ArchiveBasedStagingUploadFiles(example_upload_id, create=True) - shutil.copyfile(example_file, upload_files.upload_file_os_path) - - yield example_upload_id - - @pytest.fixture -def uploaded_id_with_warning(request, clear_files) -> Generator[str, None, None]: +def uploaded_id_with_warning(raw_files) -> Generator[str, None, None]: example_file = 'tests/data/proc/examples_with_warning_template.zip' example_upload_id = os.path.basename(example_file).replace('.zip', '') upload_files = ArchiveBasedStagingUploadFiles(example_upload_id, create=True) @@ -84,11 +67,6 @@ def run_processing(uploaded_id: str, test_user) -> Upload: return upload -@pytest.fixture -def processed_upload(uploaded_id, test_user, worker, no_warn) -> Upload: - return run_processing(uploaded_id, test_user) - - def assert_processing(upload: Upload): assert not upload.tasks_running assert upload.current_task == 'cleanup' @@ -119,22 +97,25 @@ def assert_processing(upload: Upload): assert upload_files.metadata.get(calc.calc_id) is not None -@pytest.mark.timeout(30) -def test_processing(uploaded_id, worker, test_user, no_warn, mails): - upload = run_processing(uploaded_id, test_user) - assert_processing(upload) +def test_processing(processed, no_warn, mails): + assert_processing(processed) assert len(mails.messages) == 1 assert re.search(r'Processing completed', mails.messages[0].data.decode('utf-8')) is not None -@pytest.mark.timeout(30) -def test_processing_with_warning(uploaded_id_with_warning, worker, test_user): - upload = run_processing(uploaded_id_with_warning, test_user) +@pytest.mark.timeout(10) +def test_processing_with_warning(raw_files, worker, test_user, with_warn): + example_file = 'tests/data/proc/examples_with_warning_template.zip' + example_upload_id = os.path.basename(example_file).replace('.zip', '') + upload_files = ArchiveBasedStagingUploadFiles(example_upload_id, create=True) + shutil.copyfile(example_file, upload_files.upload_file_os_path) + + upload = run_processing(example_upload_id, test_user) assert_processing(upload) -@pytest.mark.timeout(30) +@pytest.mark.timeout(10) def test_process_non_existing(worker, test_user, with_error): upload = run_processing('__does_not_exist', test_user) @@ -145,8 +126,8 @@ def test_process_non_existing(worker, test_user, with_error): @pytest.mark.parametrize('task', ['extracting', 'parse_all', 'cleanup', 'parsing']) -@pytest.mark.timeout(30) -def test_task_failure(monkeypatch, uploaded_id, worker, task, test_user, with_error): +@pytest.mark.timeout(10) +def test_task_failure(monkeypatch, uploaded, worker, task, test_user, with_error): # mock the task method to through exceptions if hasattr(Upload, task): cls = Upload @@ -163,7 +144,7 @@ def test_task_failure(monkeypatch, uploaded_id, worker, task, test_user, with_er monkeypatch.setattr('nomad.processing.data.%s.%s' % (cls.__name__, task), mock) # run the test - upload = run_processing(uploaded_id, test_user) + upload = run_processing(uploaded, test_user) assert not upload.tasks_running diff --git a/tests/test_api.py b/tests/test_api.py index d1f2b04310..782fa002b8 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -15,45 +15,20 @@ import pytest import time import json -from mongoengine import connect -from mongoengine.connection import disconnect import base64 import zipfile import io import inspect -from nomad import config -# for convinience we test the api without path prefix -services_config = config.services._asdict() -services_config.update(api_base_path='') -config.services = config.NomadServicesConfig(**services_config) +from nomad import config, coe_repo +from nomad.files import UploadFiles, PublicUploadFiles +from nomad.processing import Upload, Calc, SUCCESS +from nomad.coe_repo import User -from nomad import api, coe_repo # noqa -from nomad.files import UploadFiles, PublicUploadFiles # noqa -from nomad.processing import Upload, Calc, SUCCESS # noqa -from nomad.coe_repo import User # noqa - -from tests.processing.test_data import example_files # noqa -from tests.test_files import example_file, example_file_mainfile, example_file_contents # noqa -from tests.test_files import create_staging_upload, create_public_upload # noqa - -# import fixtures -from tests.test_normalizing import normalized_template_example # noqa pylint: disable=unused-import -from tests.test_parsing import parsed_template_example # noqa pylint: disable=unused-import -# from tests.test_repo import example_elastic_calc # noqa pylint: disable=unused-import -from tests.test_coe_repo import assert_coe_upload # noqa - - -@pytest.fixture(scope='function') -def client(mockmongo): - disconnect() - connect('users_test', host=config.mongo.host, port=config.mongo.port, is_mock=True) - - api.app.config['TESTING'] = True - client = api.app.test_client() - - yield client - Upload._get_collection().drop() +from tests.conftest import create_auth_headers +from tests.test_files import example_file, example_file_mainfile, example_file_contents +from tests.test_files import create_staging_upload, create_public_upload +from tests.test_coe_repo import assert_coe_upload def test_alive(client): @@ -61,30 +36,6 @@ def test_alive(client): assert rv.status_code == 200 -def create_auth_headers(user): - basic_auth_str = '%s:password' % user.email - basic_auth_bytes = basic_auth_str.encode('utf-8') - basic_auth_base64 = base64.b64encode(basic_auth_bytes).decode('utf-8') - return { - 'Authorization': 'Basic %s' % basic_auth_base64 - } - - -@pytest.fixture(scope='module') -def test_user_auth(test_user: User): - return create_auth_headers(test_user) - - -@pytest.fixture(scope='module') -def test_other_user_auth(other_test_user: User): - return create_auth_headers(other_test_user) - - -@pytest.fixture(scope='module') -def admin_user_auth(admin_user: User): - return create_auth_headers(admin_user) - - @pytest.fixture(scope='function') def test_user_signature_token(client, test_user_auth): rv = client.get('/auth/token', headers=test_user_auth) @@ -95,13 +46,12 @@ def test_user_signature_token(client, test_user_auth): class TestAdmin: @pytest.mark.timeout(10) - def test_reset(self, client, admin_user_auth, expandable_repo_db): + def test_reset(self, client, admin_user_auth, expandable_postgres): rv = client.post('/admin/reset', headers=admin_user_auth) assert rv.status_code == 200 - # TODO disabled as this will destroy the session repository_db beyond repair. @pytest.mark.timeout(10) - def test_remove(self, client, admin_user_auth, expandable_repo_db): + def test_remove(self, client, admin_user_auth, expandable_postgres): rv = client.post('/admin/remove', headers=admin_user_auth) assert rv.status_code == 200 @@ -128,7 +78,7 @@ class TestAdmin: yield None monkeypatch.setattr(config, 'services', old_config) - def test_disabled(self, client, admin_user_auth, disable_reset, repository_db): + def test_disabled(self, client, admin_user_auth, disable_reset, postgres): rv = client.post('/admin/reset', headers=admin_user_auth) assert rv.status_code == 400 @@ -141,7 +91,7 @@ class TestAuth: assert rv.status_code == 200 - def test_xtoken_auth_denied(self, client, no_warn, repository_db): + def test_xtoken_auth_denied(self, client, no_warn, postgres): rv = client.get('/uploads/', headers={ 'X-Token': 'invalid' }) @@ -178,10 +128,6 @@ class TestAuth: class TestUploads: - @pytest.fixture(scope='function') - def proc_infra(self, repository_db, worker, no_warn): - return dict(repository_db=repository_db) - def assert_uploads(self, upload_json_str, count=0, **kwargs): data = json.loads(upload_json_str) assert isinstance(data, list) @@ -237,7 +183,6 @@ class TestUploads: def assert_unstage(self, client, test_user_auth, upload_id, proc_infra, metadata={}): rv = client.get('/uploads/%s' % upload_id, headers=test_user_auth) upload = self.assert_upload(rv.data) - empty_upload = upload['calcs']['pagination']['total'] == 0 rv = client.post( '/uploads/%s' % upload_id, @@ -250,7 +195,7 @@ class TestUploads: assert upload['process_running'] self.assert_upload_does_not_exist(client, upload_id, test_user_auth) - assert_coe_upload(upload_id, empty=empty_upload, metadata=metadata) + assert_coe_upload(upload_id, user_metadata=metadata) def assert_upload_does_not_exist(self, client, upload_id: str, test_user_auth): # poll until publish/delete completed @@ -289,11 +234,10 @@ class TestUploads: rv = client.get('/uploads/123456789012123456789012', headers=test_user_auth) assert rv.status_code == 404 - @pytest.mark.timeout(30) - @pytest.mark.parametrize('file', example_files) @pytest.mark.parametrize('mode', ['multipart', 'stream', 'local_path']) @pytest.mark.parametrize('name', [None, 'test_name']) - def test_put(self, client, test_user_auth, proc_infra, file, mode, name): + def test_put(self, client, test_user_auth, proc_infra, example_upload, mode, name): + file = example_upload if name: url = '/uploads/?name=%s' % name else: @@ -345,7 +289,7 @@ class TestUploads: assert rv.status_code == 400 self.assert_processing(client, test_user_auth, upload['upload_id']) - def test_delete_unstaged(self, client, test_user_auth, proc_infra, clean_repository_db): + def test_delete_unstaged(self, client, test_user_auth, proc_infra): rv = client.put('/uploads/?local_path=%s' % example_file, headers=test_user_auth) upload = self.assert_upload(rv.data) self.assert_processing(client, test_user_auth, upload['upload_id']) @@ -361,23 +305,22 @@ class TestUploads: assert rv.status_code == 200 self.assert_upload_does_not_exist(client, upload['upload_id'], test_user_auth) - @pytest.mark.parametrize('example_file', example_files) - def test_post(self, client, test_user_auth, example_file, proc_infra, clean_repository_db): - rv = client.put('/uploads/?local_path=%s' % example_file, headers=test_user_auth) + def test_post(self, client, test_user_auth, example_upload, proc_infra): + rv = client.put('/uploads/?local_path=%s' % example_upload, headers=test_user_auth) upload = self.assert_upload(rv.data) self.assert_processing(client, test_user_auth, upload['upload_id']) self.assert_unstage(client, test_user_auth, upload['upload_id'], proc_infra) def test_post_metadata( self, client, proc_infra, admin_user_auth, test_user_auth, test_user, - other_test_user, clean_repository_db): + other_test_user): rv = client.put('/uploads/?local_path=%s' % example_file, headers=test_user_auth) upload = self.assert_upload(rv.data) self.assert_processing(client, test_user_auth, upload['upload_id']) metadata = dict(comment='test comment') self.assert_unstage(client, admin_user_auth, upload['upload_id'], proc_infra, metadata) - def test_post_metadata_forbidden(self, client, proc_infra, test_user_auth, clean_repository_db): + def test_post_metadata_forbidden(self, client, proc_infra, test_user_auth): rv = client.put('/uploads/?local_path=%s' % example_file, headers=test_user_auth) upload = self.assert_upload(rv.data) self.assert_processing(client, test_user_auth, upload['upload_id']) @@ -389,7 +332,7 @@ class TestUploads: assert rv.status_code == 401 # TODO validate metadata (or all input models in API for that matter) - # def test_post_bad_metadata(self, client, proc_infra, test_user_auth, clean_repository_db): + # def test_post_bad_metadata(self, client, proc_infra, test_user_auth, postgres): # rv = client.put('/uploads/?local_path=%s' % example_file, headers=test_user_auth) # upload = self.assert_upload(rv.data) # self.assert_processing(client, test_user_auth, upload['upload_id']) @@ -457,7 +400,7 @@ class UploadFilesBasedTests: return wrapper @pytest.fixture(scope='function') - def test_data(self, request, clean_repository_db, no_warn, test_user, other_test_user): + def test_data(self, request, postgres, mongo, no_warn, test_user, other_test_user): # delete potential old test files for _ in [0, 1]: upload_files = UploadFiles.get('test_upload') @@ -484,12 +427,12 @@ class UploadFilesBasedTests: upload_files = create_staging_upload('test_upload', calc_specs=calc_specs) else: upload_files = create_public_upload('test_upload', calc_specs=calc_specs) - clean_repository_db.begin() + postgres.begin() coe_upload = coe_repo.Upload( upload_name='test_upload', user_id=test_user.user_id, is_processed=True) - clean_repository_db.add(coe_upload) - clean_repository_db.commit() + postgres.add(coe_upload) + postgres.commit() yield 'test_upload', authorized, auth_headers diff --git a/tests/test_client.py b/tests/test_client.py index 95c6348433..ad9a09f94c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -12,40 +12,30 @@ # See the License for the specific language governing permissions and # limitations under the License. -import pytest -from bravado.client import SwaggerClient import time from nomad.processing import SUCCESS -from tests.test_files import example_file, create_public_upload, clear_files # noqa pylint: disable=unused-import -from tests.test_api import client as flask_client, test_user_auth # noqa pylint: disable=unused-import -from tests.bravado_flaks import FlaskTestHttpClient +from tests.test_files import example_file, create_public_upload -@pytest.fixture(scope='function') -def client(flask_client, repository_db, test_user_auth): - http_client = FlaskTestHttpClient(flask_client, headers=test_user_auth) - return SwaggerClient.from_url('/swagger.json', http_client=http_client) +def test_get_upload_command(bravado): + assert bravado.uploads.get_upload_command().response().result.upload_command is not None -def test_get_upload_command(client): - assert client.uploads.get_upload_command().response().result.upload_command is not None - - -def test_upload(client, worker): +def test_upload(bravado, proc_infra): with open(example_file, 'rb') as f: - upload = client.uploads.upload(file=f, name='test_upload').response().result + upload = bravado.uploads.upload(file=f, name='test_upload').response().result while upload.tasks_running: - upload = client.uploads.get_upload(upload_id=upload.upload_id).response().result + upload = bravado.uploads.get_upload(upload_id=upload.upload_id).response().result time.sleep(0.1) assert upload.tasks_status == SUCCESS -def test_get_repo_calc(client, clear_files): +def test_get_repo_calc(bravado, raw_files): create_public_upload('test_upload', 'pp') - repo = client.repo.get_repo_calc(upload_id='test_upload', calc_id='0').response().result + repo = bravado.repo.get_repo_calc(upload_id='test_upload', calc_id='0').response().result assert repo is not None assert repo['calc_id'] is not None diff --git a/tests/test_coe_repo.py b/tests/test_coe_repo.py index 2894d612fc..20a481af81 100644 --- a/tests/test_coe_repo.py +++ b/tests/test_coe_repo.py @@ -13,15 +13,9 @@ # limitations under the License. import pytest -import datetime from nomad.coe_repo import User, Calc, Upload -from nomad import processing - -from tests.processing.test_data import processed_upload # pylint: disable=unused-import -from tests.processing.test_data import uploaded_id # pylint: disable=unused-import -from tests.processing.test_data import mocks_forall # pylint: disable=unused-import -from tests.test_files import clear_files # pylint: disable=unused-import +from nomad import processing, parsing, datamodel def assert_user(user, reference): @@ -40,79 +34,103 @@ def test_password_authorize(test_user): assert_user(user, test_user) -def assert_coe_upload(upload_id, empty=False, metadata={}): +def assert_coe_upload(upload_id, upload: datamodel.UploadWithMetadata = None, user_metadata: dict = None): coe_upload = Upload.from_upload_id(upload_id) - if empty: + if upload is not None: + calcs = list(upload.calcs) + elif coe_upload is None: + calcs = [] + else: + calcs = list(calc.to_calc_with_metadata() for calc in coe_upload.calcs) + + if len(calcs) == 0: assert coe_upload is None else: assert coe_upload is not None - assert len(coe_upload.calcs) > 0 - for calc in coe_upload.calcs: - assert_coe_calc(calc, metadata=metadata) + assert len(coe_upload.calcs) == len(calcs) + for coe_calc, calc in zip(coe_upload.calcs, calcs): + if user_metadata is not None: + calc.apply_user_metadata(user_metadata) + + assert_coe_calc(coe_calc, calc) - if '_upload_time' in metadata: - assert coe_upload.created.isoformat()[:26] == metadata['_upload_time'] + if upload is not None and upload.upload_time is not None: + assert coe_upload.created.isoformat()[:26] == upload.upload_time.isoformat() -def assert_coe_calc(calc: Calc, metadata={}): - assert calc.pid == int(metadata.get('_pid', calc.pid)) +def assert_coe_calc(coe_calc: Calc, calc: datamodel.CalcWithMetadata): + if calc.pid is not None: + assert coe_calc.pid == calc.pid # calc data - assert len(calc.files) == 5 - assert calc.formula is not None + assert len(coe_calc.files) == len(calc.files) + assert coe_calc.formula == calc.formula # user meta data - assert calc.comment == metadata.get('comment', None) - assert sorted(calc.references) == sorted(metadata.get('references', [])) - assert calc.uploader is not None - assert calc.uploader.user_id == metadata.get('_uploader', calc.uploader.user_id) - assert sorted(user.user_id for user in calc.coauthors) == sorted(metadata.get('coauthors', [])) - assert sorted(user.user_id for user in calc.shared_with) == sorted(metadata.get('shared_with', [])) - assert calc.with_embargo == metadata.get('with_embargo', False) - - -@pytest.mark.timeout(10) -def test_add_upload(clean_repository_db, processed_upload: processing.Upload): - empty = processed_upload.total_calcs == 0 - - Upload.add(processed_upload.to_upload_with_metadata()) - assert_coe_upload(processed_upload.upload_id, empty=empty) - - -@pytest.mark.timeout(10) -def test_add_upload_metadata(clean_repository_db, processed_upload, other_test_user, test_user): - empty = processed_upload.total_calcs == 0 - - processed_upload.metadata = { - 'comment': 'test comment', - 'with_embargo': True, - 'references': ['http://external.ref/one', 'http://external.ref/two'], - '_uploader': other_test_user.user_id, - 'coauthors': [test_user.user_id], - '_upload_time': datetime.datetime.now().isoformat(), - '_pid': 256 - } - - Upload.add(processed_upload.to_upload_with_metadata()) + assert coe_calc.comment == calc.comment + assert len(coe_calc.references) == len(calc.references) + assert coe_calc.uploader is not None + if calc.uploader is not None: + assert coe_calc.uploader.user_id == calc.uploader.id + assert sorted(user.user_id for user in coe_calc.coauthors) == sorted(user.id for user in calc.coauthors) + assert sorted(user.user_id for user in coe_calc.shared_with) == sorted(user.id for user in calc.shared_with) + if calc.with_embargo is not None: + assert coe_calc.with_embargo == calc.with_embargo + else: + assert not coe_calc.with_embargo + + +def test_add_normalized_calc(postgres, normalized: parsing.LocalBackend, test_user): + calc_with_metadata = normalized.to_calc_with_metadata() + calc_with_metadata.uploader = test_user.to_popo() + calc_with_metadata.files = [calc_with_metadata.mainfile, '1', '2', '3', '4'] + coe_calc = Calc() + coe_calc.apply_calc_with_metadata(calc_with_metadata) + + assert_coe_calc(coe_calc, calc_with_metadata) + + +def test_add_normalized_calc_with_metadata( + postgres, normalized: parsing.LocalBackend, example_user_metadata: dict): + + calc_with_metadata = normalized.to_calc_with_metadata() + calc_with_metadata.files = [calc_with_metadata.mainfile, '1', '2', '3', '4'] + calc_with_metadata.apply_user_metadata(example_user_metadata) + coe_calc = Calc(coe_calc_id=calc_with_metadata.pid) + coe_calc.apply_calc_with_metadata(calc_with_metadata) + + assert_coe_calc(coe_calc, calc_with_metadata) + + +def test_add_upload(processed: processing.Upload): + upload_with_metadata = processed.to_upload_with_metadata() + Upload.add(upload_with_metadata) + assert_coe_upload(processed.upload_id, upload_with_metadata) + + +def test_add_upload_with_metadata(processed, example_user_metadata): + processed.metadata = example_user_metadata + upload_with_metadata = processed.to_upload_with_metadata() + Upload.add(upload_with_metadata) assert_coe_upload( - processed_upload.upload_id, empty=empty, metadata=processed_upload.metadata) + processed.upload_id, upload_with_metadata) class TestDataSets: @pytest.fixture(scope='function') - def datasets(self, clean_repository_db): - clean_repository_db.begin() + def datasets(self, postgres): + postgres.begin() one = Calc() two = Calc() three = Calc() - clean_repository_db.add(one) - clean_repository_db.add(two) - clean_repository_db.add(three) + postgres.add(one) + postgres.add(two) + postgres.add(three) one.children.append(two) two.children.append(three) - clean_repository_db.commit() + postgres.commit() return one, two, three diff --git a/tests/test_files.py b/tests/test_files.py index 888b447cab..3dbc936759 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -42,22 +42,6 @@ example_bucket = 'test_bucket' example_data = dict(test_key='test_value') -@pytest.fixture(scope='function') -def clear_files(): - """ Utility fixture that removes all files from files and tmp after test. """ - try: - yield - finally: - try: - shutil.rmtree(config.fs.objects) - except FileNotFoundError: - pass - try: - shutil.rmtree(config.fs.tmp) - except FileNotFoundError: - pass - - class TestObjects: @pytest.fixture(scope='function') diff --git a/tests/test_migration.py b/tests/test_migration.py index 59ea6ebbd2..9957195e40 100644 --- a/tests/test_migration.py +++ b/tests/test_migration.py @@ -23,17 +23,16 @@ from nomad import infrastructure, coe_repo from nomad.migration import NomadCOEMigration, SourceCalc from nomad.infrastructure import repository_db_connection -from .bravado_flaks import FlaskTestHttpClient -from tests.conftest import create_repository_db -from tests.test_api import client as flask_client, create_auth_headers # noqa pylint: disable=unused-import -from tests.test_client import client as bravado_client # noqa pylint: disable=unused-import +from tests.conftest import create_postgres_infra, create_auth_headers +from tests.bravado_flask import FlaskTestHttpClient +from tests.test_api import create_auth_headers test_source_db_name = 'test_nomad_fair_migration_source' test_target_db_name = 'test_nomad_fair_migration_target' @pytest.fixture(scope='module') -def source_repo(monkeysession, repository_db): +def source_repo(monkeysession, postgres_infra): """ Fixture for an example migration source db with: - two user @@ -63,13 +62,13 @@ def source_repo(monkeysession, repository_db): with open(sql_file, 'r') as f: cur.execute(f.read()) - with create_repository_db(monkeysession, exists=True, readonly=True, dbname=test_source_db_name) as db: + with create_postgres_infra(monkeysession, exists=True, readonly=True, dbname=test_source_db_name) as db: yield db @pytest.fixture(scope='function') -def target_repo(repository_db): - with create_repository_db(readonly=False, exists=False, dbname=test_target_db_name) as db: +def target_repo(postgres): + with create_postgres_infra(readonly=False, exists=False, dbname=test_target_db_name) as db: db.execute('TRUNCATE users CASCADE;') yield db db.execute('TRUNCATE uploads CASCADE;') @@ -103,23 +102,23 @@ def perform_index(migration, has_indexed, with_metadata, **kwargs): assert test_calc is not None if with_metadata: - assert test_calc.metadata['uploader']['user_id'] == 1 + assert test_calc.metadata['uploader']['id'] == 1 assert test_calc.metadata['comment'] == 'label1' @pytest.mark.parametrize('with_metadata', [False, True]) -def test_create_index(migration, mockmongo, with_metadata: bool): +def test_create_index(migration, mongo, with_metadata: bool): perform_index(migration, has_indexed=True, drop=True, with_metadata=with_metadata) @pytest.mark.parametrize('with_metadata', [True, False]) -def test_update_index(migration, mockmongo, with_metadata: bool): +def test_update_index(migration, mongo, with_metadata: bool): perform_index(migration, has_indexed=True, drop=True, with_metadata=with_metadata) perform_index(migration, has_indexed=False, drop=False, with_metadata=with_metadata) @pytest.fixture(scope='function') -def migrate_infra(migration, target_repo, flask_client, worker, monkeysession): +def migrate_infra(migration, target_repo, proc_infra, client, monkeysession): """ Parameters to test - missing upload, extracted, archive, broken archive @@ -143,7 +142,7 @@ def migrate_infra(migration, target_repo, flask_client, worker, monkeysession): # target repo is the infrastructure repo def create_client(): admin = target_repo.query(coe_repo.User).filter_by(email='admin').first() - http_client = FlaskTestHttpClient(flask_client, headers=create_auth_headers(admin)) + http_client = FlaskTestHttpClient(client, headers=create_auth_headers(admin)) return SwaggerClient.from_url('/swagger.json', http_client=http_client) old_repo = infrastructure.repository_db @@ -193,7 +192,7 @@ def test_migrate(migrate_infra, test, assertions, caplog): assert calc_1 is not None metadata = calc_1.to_calc_with_metadata() assert metadata.pid <= 2 - assert metadata.uploader['user_id'] == 1 + assert metadata.uploader['id'] == 1 assert metadata.upload_time.isoformat() == '2019-01-01T12:00:00+00:00' assert len(metadata.datasets) == 1 assert metadata.datasets[0]['id'] == 3 @@ -201,7 +200,7 @@ def test_migrate(migrate_infra, test, assertions, caplog): assert metadata.datasets[0]['doi']['value'] == 'internal_ref' assert metadata.comment == 'label1' assert len(metadata.coauthors) == 1 - assert metadata.coauthors[0]['user_id'] == 2 + assert metadata.coauthors[0]['id'] == 2 assert len(metadata.references) == 1 assert metadata.references[0]['value'] == 'external_ref' @@ -210,7 +209,7 @@ def test_migrate(migrate_infra, test, assertions, caplog): assert calc_1 is not None metadata = calc_2.to_calc_with_metadata() assert len(metadata.shared_with) == 1 - assert metadata.shared_with[0]['user_id'] == 1 + assert metadata.shared_with[0]['id'] == 1 # assert pid prefix of new calcs if assertions.get('new', 0) > 0: diff --git a/tests/test_search.py b/tests/test_search.py index c3c5a7e907..8de0ef9e21 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -12,13 +12,44 @@ # See the License for the specific language governing permissions and # limitations under the License. -from nomad import datamodel, search +from nomad import datamodel, search, processing, parsing +from nomad.search import Entry def test_init_mapping(elastic): pass -def test_index_calc(elastic): - calc = datamodel.CalcWithMetadata(upload_id='test_upload', calc_id='test_calc') - search.Entry.from_calc_with_metadata(calc).save(op_type='create') +def test_index_skeleton_calc(elastic): + calc_with_metadata = datamodel.CalcWithMetadata(upload_id='test_upload', calc_id='test_calc') + + create_entry(calc_with_metadata) + + +def test_index_normalized_calc(elastic, normalized: parsing.LocalBackend): + calc_with_metadata = normalized.to_calc_with_metadata() + + create_entry(calc_with_metadata) + + +def test_index_normalized_calc_with_metadata( + elastic, normalized: parsing.LocalBackend, example_user_metadata: dict): + + calc_with_metadata = normalized.to_calc_with_metadata() + calc_with_metadata.apply_user_metadata(example_user_metadata) + + create_entry(calc_with_metadata) + + +def test_index_upload(elastic, processed: processing.Upload): + pass + + +def create_entry(calc_with_metadata: datamodel.CalcWithMetadata): + search.Entry.from_calc_with_metadata(calc_with_metadata).save(op_type='create') + assert_entry(calc_with_metadata.calc_id) + + +def assert_entry(calc_id): + calc = Entry.get(calc_id) + assert calc is not None -- GitLab