def basedir(tmpdir): """Create the following file structure in a given base directory for unit tests: A.json -> DATA_A docs/D.json -> DATA_D examples/B.json -> DATA_B examples/C.json -> DATA_C examples/data/data.json -> DATA_E Returns the base directory containing the created files. """ tmpdir = os.path.join(tmpdir, 'inputs') os.makedirs(tmpdir) # A.json fileA = os.path.join(tmpdir, FILE_A) util.write_object(obj=DATA_A, filename=fileA) # examples/B.json fileB = os.path.join(tmpdir, FILE_B) os.makedirs(os.path.dirname(fileB)) util.write_object(obj=DATA_B, filename=fileB) # examples/C.json fileC = os.path.join(tmpdir, FILE_C) util.write_object(obj=DATA_C, filename=fileC) # examples/data/data.json fileE = os.path.join(tmpdir, FILE_E) os.makedirs(os.path.dirname(fileE)) util.write_object(obj=DATA_E, filename=fileE) # docs/D.json fileD = os.path.join(tmpdir, FILE_D) os.makedirs(os.path.dirname(fileD)) util.write_object(obj=DATA_D, filename=fileD) return tmpdir
def test_run_parameters(database, tmpdir): """Test creating run with template arguments.""" # -- Setup ---------------------------------------------------------------- fs = FileSystemStorage(basedir=tmpdir) with database.session() as session: user_id = model.create_user(session, active=True) workflow_id = model.create_workflow(session) group_id = model.create_group(session, workflow_id, users=[user_id]) # Prepare run arguments filename = os.path.join(str(tmpdir), 'results.json') util.write_object(filename=filename, obj={'A': 1}) arguments = [{'id': 'A', 'value': 10}, {'id': 'B', 'value': True}] # -- Test create run with arguments --------------------------------------- with database.session() as session: groups = WorkflowGroupManager(session=session, fs=fs) runs = RunManager(session=session, fs=fs) run = runs.create_run( group=groups.get_group(group_id), arguments=arguments ) run_id = run.run_id with database.session() as session: runs = RunManager(session=session, fs=fs) run = runs.get_run(run_id) assert run.arguments == arguments
def test_cli_group_files(flowserv_cli, tmpdir): """Test CLI workflow group files command.""" # Create app in a fresh database. cmd = ['app', 'install', '--key', 'mykey', TEMPLATE_DIR] result = flowserv_cli.invoke(cli, cmd) assert result.exit_code == 0 app_key = result.output[result.output.rfind('=') + 1:].strip() # -- Upload file ---------------------------------------------------------- filename = os.path.join(tmpdir, 'myfile.json') util.write_object(filename=filename, obj=[]) cmd = ['files', 'upload', '-g', app_key, '-i', filename] result = flowserv_cli.invoke(cli, cmd) assert result.exit_code == 0 assert 'myfile.json' in result.output file_id = result.output.split()[-1][:-1] # Ensure that the file is included in the group descriptor cmd = ['groups', 'show', '-g', app_key] result = flowserv_cli.invoke(cli, cmd) assert result.exit_code == 0 assert file_id in result.output # -- List files ----------------------------------------------------------- cmd = ['files', 'list', '-g', app_key] result = flowserv_cli.invoke(cli, cmd) assert result.exit_code == 0 assert 'myfile.json' in result.output # -- Download file -------------------------------------------------------- cmd = ['files', 'download', '-g', app_key, '-f', file_id, '-o', filename] result = flowserv_cli.invoke(cli, cmd) assert result.exit_code == 0 # -- Delete file ---------------------------------------------------------- cmd = ['files', 'delete', '-g', app_key, '-f', file_id, '--force'] result = flowserv_cli.invoke(cli, cmd) assert result.exit_code == 0
def test_success_state(tmpdir): """Test creating instances of the success state class.""" # Create new file resource for test purposes filename = os.path.join(str(tmpdir), 'res.json') util.write_object(filename=filename, obj={'A': 1}) # Create instance of successfule workflow state without a file resource created_at = dt.datetime.now() started_at = created_at + dt.timedelta(seconds=10) finished_at = started_at + dt.timedelta(seconds=10) state = StateSuccess(created_at=created_at, started_at=started_at, finished_at=finished_at) assert state.is_success() assert not state.is_error() assert not state.is_pending() assert not state.is_running() assert not state.is_active() assert state.created_at == created_at assert state.started_at == started_at assert state.finished_at == finished_at assert len(state.files) == 0 # Create state instance with file resource state = StateSuccess(created_at=created_at, started_at=started_at, finished_at=finished_at, files=['myfile.json']) assert state.created_at == created_at assert state.started_at == started_at assert state.finished_at == finished_at assert len(state.files) == 1 assert 'myfile.json' in state.files
def success_run(database: DB, fs: FileStore, basedir: str) -> Tuple[str, str, str, str]: """Create a successful run with two result files: - A.json - run/results/B.json Returns the identifier of the created workflow, group, run, and user. """ # Setup temporary run folder. tmprundir = os.path.join(basedir, 'tmprun') tmpresultsdir = os.path.join(tmprundir, 'run', 'results') os.makedirs(tmprundir) os.makedirs(tmpresultsdir) f1 = os.path.join(tmprundir, 'A.json') util.write_object(f1, {'A': 1}) f2 = os.path.join(tmpresultsdir, 'B.json') util.write_object(f2, {'B': 1}) with database.session() as session: user_id = create_user(session, active=True) workflow_id = create_workflow(session) group_id = create_group(session, workflow_id, users=[user_id]) groups = WorkflowGroupManager(session=session, fs=fs) runs = RunManager(session=session, fs=fs) run = runs.create_run(group=groups.get_group(group_id)) run_id = run.run_id state = run.state() runs.update_run( run_id, state.start().success(files=['A.json', 'run/results/B.json']), rundir=tmprundir) assert not os.path.exists(tmprundir) return workflow_id, group_id, run_id, user_id
def test_env_worker(tmpdir): """Test getting values for the METANOME_WORKER variable.""" # -- Setup ---------------------------------------------------------------- filename = os.path.join(tmpdir, 'worker.json') write_object(obj={'x': 1}, filename=filename) # -- Unit tests ----------------------------------------------------------- os.environ[config.METANOME_WORKER] = filename assert config.WORKER() == {'x': 1} del os.environ[config.METANOME_WORKER] assert config.WORKER() is None assert config.WORKER(env={config.METANOME_WORKER: {'y': 2}}) == {'y': 2}
def test_env_volume(tmpdir): """Test getting values for the METANOME_VOLUME variable.""" # -- Setup ---------------------------------------------------------------- filename = os.path.join(tmpdir, 'volume.json') write_object(obj={'x': 1}, filename=filename) # -- Unit tests ----------------------------------------------------------- os.environ[config.METANOME_VOLUME] = filename assert config.VOLUME() == {'x': 1} del os.environ[config.METANOME_VOLUME] assert config.VOLUME() is None assert config.VOLUME(env={config.METANOME_VOLUME: {'y': 2}}) == {'y': 2}
def test_storage_volume_config(tmpdir): """Test storage volume configuration objects.""" # Default config. conf = config.env() assert isinstance(conf.get(config.FLOWSERV_FILESTORE), dict) doc = {'type': 'fs'} conf.volume(config=doc) assert conf.get(config.FLOWSERV_FILESTORE) == doc # Configure from file. filename = os.path.join(tmpdir, 'config.json') util.write_object(filename=filename, obj=doc) os.environ[config.FLOWSERV_FILESTORE] = filename conf = config.env() assert conf.get(config.FLOWSERV_FILESTORE) == doc del os.environ[config.FLOWSERV_FILESTORE]
def download_file(self, workflow_id, source, target): """Download file from relative location in the base directory to a given target path. Since the workflow is executed in the run directory no files need to be copied. Parameters ---------- workflow_id: string Unique workflow identifier. source: string Relative path to source file in workflow workspace. target: string Path to target file on local disk. """ os.makedirs(os.path.dirname(target), exist_ok=True) util.write_object(obj=self.data, filename=target)
def test_success_state(tmpdir): """Test serialization/deserialization of success states.""" filename = os.path.join(str(tmpdir), 'results.json') util.write_object(filename=filename, obj={'A': 1}) s = state.StateSuccess(created_at=util.to_datetime(CREATED_AT), started_at=util.to_datetime(STARTED_AT), finished_at=util.to_datetime(FINISHED_AT), files=['myfile1', 'myfile2']) s = state.deserialize_state(state.serialize_state(s)) assert s.is_success() assert len(s.files) == 2 assert 'myfile1' in s.files assert 'myfile2' in s.files validate_date(s.created_at, util.to_datetime(CREATED_AT)) validate_date(s.started_at, util.to_datetime(STARTED_AT)) validate_date(s.finished_at, util.to_datetime(FINISHED_AT))
def run_success(run_manager, run_id, rundir, values): """Set given run into success state with the given result data.""" os.makedirs(rundir) filename = os.path.join(rundir, RESULT_FILE_ID) util.write_object(filename=filename, obj=values) ts = util.utc_now() run_manager.update_run( run_id=run_id, state=st.StateSuccess( created_at=ts, started_at=ts, finished_at=ts, files=[RESULT_FILE_ID] ), rundir=rundir )
def copy_postproc_files(runs: List[Tuple[str, str, List[Tuple[str, IOHandle]]]], outputdir: str): """Copy files for runs that are included as input for a post-processing workflow to a given output folder. The list of runs contains 3-tuples of (run_id, group_name, files). The files element is a list of tuples of (file key, file object). This method also creates a metadata file in the outptu folder listing the included runs and run result files. Parameters ---------- input_files: list(string) List of identifier for benchmark run output files that are copied into the input directory for each submission. ranking: list(flowserv.model.ranking.RunResult) List of runs in the current result ranking run_manager: flowserv.model.run.RunManager Manager for workflow runs """ # Create the output directory if it does not exist. os.makedirs(outputdir, exist_ok=True) # Copy the given files from all workflow runs to a subfolder for each run # in the output directory. The output directory will also contain the # 'runs.json' file containing the run metadata. run_listing = list() for run_id, group_name, files in runs: # Create a sub-folder for the run in the output directory. Then copy # all given files into the created directory. rundir = os.path.join(outputdir, run_id) os.makedirs(rundir, exist_ok=True) for key, file in files: # Create target file parent directory if it does not exist. dst = os.path.join(rundir, key) os.makedirs(os.path.dirname(dst), exist_ok=True) # Copy run file to target file. file.store(dst) run_listing.append({ base.LABEL_ID: run_id, base.LABEL_NAME: group_name, base.LABEL_FILES: [key for key, _ in files] }) # Write the runs metadata to file util.write_object(filename=os.path.join(outputdir, base.RUNS_FILE), obj=run_listing)
def test_run_serialization(database, tmpdir): """Test serialization of run handles and run listings.""" config = Config().basedir(tmpdir) view = RunSerializer() fs = FileSystemStore(config) # Setup temporary run folder. tmprundir = os.path.join(tmpdir, 'tmprun') tmpresultsdir = os.path.join(tmprundir, 'run', 'results') os.makedirs(tmprundir) os.makedirs(tmpresultsdir) f1 = os.path.join(tmprundir, 'A.json') util.write_object(f1, {'A': 1}) # Create runs. with database.session() as session: user_id = model.create_user(session, active=True) workflow_id = model.create_workflow(session) group_id = model.create_group(session, workflow_id, users=[user_id]) # Create successful run. groups = WorkflowGroupManager(session=session, fs=fs) runs = RunManager(session=session, fs=fs) run = runs.create_run(group=groups.get_group(group_id)) run_id = run.run_id state = run.state() runs.update_run( run_id, state.start().success(files=['A.json', 'run/results/B.json']), rundir=tmprundir) run = runs.get_run(run_id) doc = view.run_handle(run) validator('RunHandle').validate(doc) # Create error run. run = runs.create_run(group=groups.get_group(group_id)) run_id = run.run_id state = run.state() runs.update_run(run_id=run_id, state=state) messages = ['There', 'were', 'many errors'] runs.update_run(run_id=run_id, state=state.error(messages)) run = runs.get_run(run_id) doc = view.run_handle(run) validator('RunHandle').validate(doc) # Validate run listing. doc = view.run_listing(runs=runs.list_runs(group_id)) validator('RunListing').validate(doc) assert len(doc[labels.RUN_LIST]) == 2
def test_running_state(tmpdir): """Test creating instances of the running state class.""" created_at = dt.datetime.now() started_at = created_at + dt.timedelta(seconds=10) state = StateRunning(created_at=created_at, started_at=started_at) assert state.is_active() assert state.is_running() assert not state.is_pending() assert not state.is_canceled() assert not state.is_error() assert not state.is_success() assert state.created_at == created_at assert state.started_at == started_at # Cancel pending run canceled = state.cancel() assert canceled.is_canceled() assert len(canceled.messages) == 1 canceled = state.cancel(messages=['by', 'user']) assert canceled.is_canceled() assert len(canceled.messages) == 2 # Set active run into error state error = state.error(messages=['Error', 'State']) assert error.created_at == state.created_at assert error.started_at == state.started_at assert len(error.messages) == 2 assert error.messages[0] == 'Error' assert error.messages[1] == 'State' # Set active run to success state filename = os.path.join(str(tmpdir), 'myfile.json') util.write_object(filename=filename, obj={'A': 1}) success = state.success(files=['results/myfile.json']) assert success.is_success() assert not success.is_error() assert not success.is_pending() assert not success.is_running() assert not success.is_active() assert success.created_at == state.created_at assert success.started_at == state.started_at assert len(success.files) == 1 assert 'results/myfile.json' in success.files
def create_files(basedir): """Create file structure: A.json -> DATA1 examples/B.json -> DATA2 examples/C.json -> DATA3 examples/data/data.json -> EXDATA docs/D.json -> DATA4 Returns the list of file objects an their relative paths. """ # Ensure that the base directory exists. os.makedirs(basedir, exist_ok=True) # Create files and keep records in file list. files = list() # A.json fileA = os.path.join(basedir, FILE_A) util.write_object(obj=DATA1, filename=fileA) files.append((FSFile(fileA), FILE_A)) # examples/B.json fileB = os.path.join(basedir, FILE_B) os.makedirs(os.path.dirname(fileB)) util.write_object(obj=DATA2, filename=fileB) files.append((FSFile(fileB), FILE_B)) # examples/C.json fileC = os.path.join(basedir, FILE_C) util.write_object(obj=DATA3, filename=fileC) files.append((FSFile(fileC), FILE_C)) # examples/data/data.json fileData = os.path.join(basedir, FILE_DATA) os.makedirs(os.path.dirname(fileData)) util.write_object(obj=EXDATA, filename=fileData) files.append((FSFile(fileData), FILE_DATA)) # docs/D.json fileD = os.path.join(basedir, FILE_D) os.makedirs(os.path.dirname(fileD)) util.write_object(obj=DATA4, filename=fileD) files.append((FSFile(fileD), FILE_D)) return files
def test_read_write_object(tmpdir): """Test reading and writing dictionary objects to file in Json format and in Yaml format. """ doc = {'A': 1, 'B': 2, 'C': {'D': 3}} json_file = os.path.join(str(tmpdir), 'file.json') txt_file = os.path.join(str(tmpdir), 'file.txt') yaml_file = os.path.join(str(tmpdir), 'file.yaml') # Read and write Json file util.write_object(filename=json_file, obj=doc) obj = util.read_object(filename=json_file) assert obj == doc obj = util.read_object(filename=json_file, format=util.FORMAT_JSON) assert obj == doc util.write_object(filename=json_file, obj=doc, format=util.FORMAT_YAML) obj = util.read_object(filename=json_file, format=util.FORMAT_YAML) assert obj == doc with pytest.raises(JSONDecodeError): util.read_object(filename=json_file) # Yaml format util.write_object(filename=yaml_file, obj=doc) obj = util.read_object(filename=yaml_file) assert obj == doc obj = util.read_object(filename=yaml_file, format=util.FORMAT_YAML) assert obj == doc util.write_object(filename=yaml_file, obj=doc, format=util.FORMAT_JSON) obj = util.read_object(filename=yaml_file, format=util.FORMAT_JSON) assert obj == doc doc = util.read_object(filename=yaml_file) buf = io.BytesIO(str(doc).encode("utf-8")) obj = util.read_object(filename=buf, format=util.FORMAT_YAML) assert doc == obj # The Yaml parser can read Json files obj = util.read_object(filename=yaml_file) assert obj == doc # File with non-standard suffix is written in Yaml format util.write_object(filename=txt_file, obj=doc) obj = util.read_object(filename=txt_file) assert obj == doc obj = util.read_object(filename=txt_file, format=util.FORMAT_YAML) assert obj == doc with pytest.raises(JSONDecodeError): util.read_object(filename=txt_file, format=util.FORMAT_JSON) with pytest.raises(ValueError): util.read_object(filename=txt_file, format='UNKNOWN') with pytest.raises(ValueError): util.write_object(filename=txt_file, obj=doc, format='UNKNOWN')
def test_empty_run_set(tmpdir): """Test initializing a client for an empty run set.""" filename = os.path.join(tmpdir, RUNS_FILE) util.write_object(filename=filename, obj=[]) runs = Runs(tmpdir) assert runs.get_run('0000') is None