def test_access_run_result_files_local(database, tmpdir):
    """Test accessing run result files."""
    # -- Setup ----------------------------------------------------------------
    env = Config().basedir(tmpdir).auth()
    fs = FS(env=env)
    workflow_id, group_id, run_id, user_id = success_run(database, fs, tmpdir)
    local_service = LocalAPIFactory(env=env, db=database, engine=StateEngine())
    # -- Read result files ----------------------------------------------------
    with local_service(user_id=user_id) as api:
        # Map file names to file handles.
        r = api.runs().get_run(run_id=run_id)
        files = dict()
        for fh in r['files']:
            files[fh['name']] = fh['id']
        # Read content of result files.
        fh = api.runs().get_result_file(run_id=run_id,
                                        file_id=files['run/results/B.json'])
        results = util.read_object(fh.open())
        assert results == {'B': 1}
    # -- Error when user 2 attempts to read file ------------------------------
    with database.session() as session:
        user_2 = create_user(session, active=True)
    with local_service(user_id=user_2) as api:
        with pytest.raises(err.UnauthorizedAccessError):
            api.runs().get_result_file(run_id=run_id,
                                       file_id=files['run/results/B.json'])
    # -- With an open access policy user 2 can read the data file -------------
    env = Config().basedir(tmpdir).open_access()
    local_service = LocalAPIFactory(env=env, db=database, engine=StateEngine())
    with local_service(user_id=user_2) as api:
        api.runs().get_result_file(run_id=run_id,
                                   file_id=files['run/results/B.json'])
def test_update_workflow_name(database, tmpdir):
    """Test updating workflow names."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create two workflow templates. Workflow 1 does not have a description
    # and instructions while workflow 2 has.
    fs = FileSystemStore(env=Config().basedir(tmpdir))
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        # Initialize the repository
        wf = manager.create_workflow(name='A', source=BENCHMARK_DIR)
        workflow_1 = wf.workflow_id
        wf = manager.create_workflow(name='My benchmark',
                                     description='desc',
                                     instructions=INSTRUCTION_FILE,
                                     source=BENCHMARK_DIR)
        workflow_2 = wf.workflow_id
    # -- Test update workflow name --------------------------------------------
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.update_workflow(workflow_id=workflow_1, name='B')
        assert wf.name == 'B'
        # It is possible to change the name to an existing name only if it is
        # the same workflow.
        wf = manager.update_workflow(workflow_id=workflow_2,
                                     name='My benchmark')
        assert wf.name == 'My benchmark'
    # -- Error cases ----------------------------------------------------------
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        # Cannot change name to existing name.
        with pytest.raises(err.ConstraintViolationError):
            manager.update_workflow(workflow_id=workflow_2, name='B')
Example #3
0
def test_run_remote_workflow_error(is_async, tmpdir):
    """Execute the remote workflow example synchronized and in asynchronous
    mode when execution results in an error state.
    """
    # -- Setup ----------------------------------------------------------------
    env = Config().volume(FStore(basedir=str(tmpdir))).auth()
    engine = RemoteWorkflowController(client=RemoteTestClient(
        runcount=3, error='some error'),
                                      poll_interval=0.1,
                                      is_async=is_async)
    service = LocalAPIFactory(env=env, engine=engine)
    # Need to set the association between the engine and the service explicitly
    # after the API is created.
    engine.service = service
    with service() as api:
        workflow_id = create_workflow(api, source=BENCHMARK_DIR)
        user_id = create_user(api)
    with service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id)
    # -- Unit test ------------------------------------------------------------
    # Start a new run
    with service(user_id=user_id) as api:
        run_id = start_run(api, group_id)
    # Poll workflow state every second.
    with service(user_id=user_id) as api:
        run = api.runs().get_run(run_id=run_id)
    watch_dog = 30
    while run['state'] in st.ACTIVE_STATES and watch_dog:
        time.sleep(1)
        watch_dog -= 1
        with service(user_id=user_id) as api:
            run = api.runs().get_run(run_id=run_id)
    serialize.validate_run_handle(run, state=st.STATE_ERROR)
    assert run['messages'] == ['some error']
def test_get_workflow(fscls, database, tmpdir):
    """Test retrieving workflows from the repository."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create two workflows.
    fs = fscls(env=Config().basedir(tmpdir))
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.create_workflow(name='A', source=BENCHMARK_DIR)
        workflow_1 = wf.workflow_id
        wf = manager.create_workflow(name='B',
                                     description='Workflow B',
                                     source=BENCHMARK_DIR,
                                     instructions=INSTRUCTION_FILE,
                                     specfile=TEMPLATE_WITHOUT_SCHEMA)
        workflow_2 = wf.workflow_id
    # -- Test getting workflow handles ----------------------------------------
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.get_workflow(workflow_1)
        assert wf.name == 'A'
        assert wf.description is None
        assert wf.instructions is None
        template = wf.get_template()
        assert template.result_schema is not None
        wf = manager.get_workflow(workflow_2)
        assert wf.name == 'B'
        assert wf.description == 'Workflow B'
        assert wf.instructions == '# Hello World'
        template = wf.get_template()
        assert template.result_schema is None
def test_delete_workflow(fscls, database, tmpdir):
    """Test deleting a workflows from the repository."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create two workflows.
    fs = fscls(env=Config().basedir(tmpdir))
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.create_workflow(name='A', source=BENCHMARK_DIR)
        workflow_1 = wf.workflow_id
        wf = manager.create_workflow(name='B', source=BENCHMARK_DIR)
        workflow_2 = wf.workflow_id
    # -- Test delete first workflow -------------------------------------------
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        manager.delete_workflow(workflow_1)
    with database.session() as session:
        # The second workflow still exists.
        manager = WorkflowManager(session=session, fs=fs)
        manager.get_workflow(workflow_2) is not None
    # -- Deleting the same repository multiple times raises an error ----------
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        with pytest.raises(err.UnknownWorkflowError):
            manager.delete_workflow(workflow_id=workflow_1)
def test_run_remote_workflow_with_error(tmpdir):
    """Execute the remote workflow example that will end in an error state in
    asynchronous mode.
    """
    # -- Setup ----------------------------------------------------------------
    #
    # Start a new run for the workflow template.
    env = Config().basedir(tmpdir)
    engine = RemoteTestController(client=RemoteTestClient(runcount=3,
                                                          error='some error'),
                                  poll_interval=1,
                                  is_async=True)
    service = LocalAPIFactory(env=env, engine=engine)
    engine.service = service
    with service() as api:
        workflow_id = create_workflow(api, source=TEMPLATE_DIR)
        user_id = create_user(api)
    with service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id)
        run_id = start_run(api, group_id)
    # Poll workflow state every second.
    with service(user_id=user_id) as api:
        run = api.runs().get_run(run_id=run_id)
    while run['state'] in st.ACTIVE_STATES:
        time.sleep(1)
        with service(user_id=user_id) as api:
            run = api.runs().get_run(run_id=run_id)
    serialize.validate_run_handle(run, state=st.STATE_ERROR)
    assert run['messages'][0] == 'some error'
def test_delete_file(fscls, database, tmpdir):
    """Test deleting an uploaded file."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create a database with two groups for a single workflow. Upload one file
    # for each group.
    file = io_file(data={'A': 1})
    fn = 'data.json'
    fs = fscls(env=Config().basedir(tmpdir))
    with database.session() as session:
        user_1 = model.create_user(session, active=True)
        workflow_id = model.create_workflow(session)
        group_1 = model.create_group(session, workflow_id, users=[user_1])
        group_2 = model.create_group(session, workflow_id, users=[user_1])
        manager = WorkflowGroupManager(session=session, fs=fs)
        fh = manager.upload_file(group_id=group_1, file=file, name=fn)
        file_1 = fh.file_id
        fh = manager.upload_file(group_id=group_2, file=file, name=fn)
        file_2 = fh.file_id
    # -- Test delete file -----------------------------------------------------
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        fh = manager.get_uploaded_file(group_id=group_1, file_id=file_1)
        manager.delete_file(group_id=group_1, file_id=file_1)
        # File 1 can no longer be accessed while file 2 is still present.
        with pytest.raises(err.UnknownFileError):
            manager.get_uploaded_file(group_id=group_1, file_id=file_1).open()
        fh = manager.get_uploaded_file(group_id=group_2, file_id=file_2)
    # -- Error cases ----------------------------------------------------------
    with database.session() as session:
        # - Delete unknown file
        manager = WorkflowGroupManager(session=session, fs=fs)
        with pytest.raises(err.UnknownFileError):
            manager.delete_file(group_id=group_1, file_id=file_1)
def test_workflow_leaderboard_serialization(database, tmpdir):
    """Test serialization of a workflow leaderboard."""
    config = Config().basedir(tmpdir)
    schema = validator('WorkflowLeaderboard')
    view = WorkflowSerializer()
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=FileSystemStore(config))
        workflow = manager.create_workflow(source=BENCHMARK_DIR,
                                           name='Test',
                                           specfile=SPEC_FILE)
        ts = util.utc_now()
        ranking = [
            RunResult(run_id='0',
                      group_id='1',
                      group_name='A',
                      created_at=ts,
                      started_at=ts,
                      finished_at=ts,
                      values={
                          'len': 1,
                          'count': 10
                      })
        ]
        doc = view.workflow_leaderboard(workflow, ranking=ranking)
        schema.validate(doc)
def test_list_files(fscls, database, tmpdir):
    """Test listing uploaded files."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create a database with two groups for a single workflow. The first group
    # has one uploaded file and the second group has one file.
    file = io_file(data={'A': 1})
    fn = 'data.json'
    fs = fscls(env=Config().basedir(tmpdir))
    with database.session() as session:
        user_1 = model.create_user(session, active=True)
        workflow_id = model.create_workflow(session)
        group_1 = model.create_group(session, workflow_id, users=[user_1])
        group_2 = model.create_group(session, workflow_id, users=[user_1])
        manager = WorkflowGroupManager(session=session, fs=fs)
        manager.upload_file(group_id=group_1, file=file, name=fn)
        manager.upload_file(group_id=group_1, file=file, name=fn)
        manager.upload_file(group_id=group_2, file=file, name=fn)
    # -- Test list files for groups -------------------------------------------
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        files = manager.list_uploaded_files(group_id=group_1)
        assert len(files) == 2
        files = manager.list_uploaded_files(group_id=group_2)
        assert len(files) == 1
def test_cancel_remote_workflow(tmpdir):
    """Cancel the execution of a remote workflow."""
    # -- Setup ----------------------------------------------------------------
    #
    env = Config().basedir(tmpdir)
    engine = RemoteTestController(client=RemoteTestClient(runcount=100),
                                  poll_interval=1,
                                  is_async=True)
    service = LocalAPIFactory(env=env, engine=engine)
    engine.service = service
    # -- Start a new run for the workflow template.
    with service() as api:
        workflow_id = create_workflow(api, source=TEMPLATE_DIR)
        user_id = create_user(api)
    with service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id)
        run_id = start_run(api, group_id)
    # -- Poll workflow state every second.
    with service(user_id=user_id) as api:
        run = api.runs().get_run(run_id=run_id)
    while run['state'] == st.STATE_PENDING:
        time.sleep(1)
        with service(user_id=user_id) as api:
            run = api.runs().get_run(run_id=run_id)
    serialize.validate_run_handle(run, state=st.STATE_RUNNING)
    with service(user_id=user_id) as api:
        api.runs().cancel_run(run_id=run_id, reason='test')
    # Sleep to ensure that the workflow monitor polls the state and makes an
    # attempt to update the run state. This should raise an error for the
    # monitor. The error is not propagated here or to the run.
    time.sleep(3)
    with service(user_id=user_id) as api:
        run = api.runs().get_run(run_id=run_id)
    serialize.validate_run_handle(run, state=st.STATE_CANCELED)
    assert run['messages'][0] == 'test'
Example #11
0
def test_cancel_run(fscls, database, tmpdir):
    """Test setting run state to canceled."""
    # -- Setup ----------------------------------------------------------------
    fs = fscls(env=Config().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])
    # -- Test set run to error state ------------------------------------------
    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))
        run_id = run.run_id
        state = run.state()
        runs.update_run(run_id=run_id, state=state.cancel())
    with database.session() as session:
        runs = RunManager(session=session, fs=fs)
        run = runs.get_run(run_id)
        state = run.state()
        assert not state.is_active()
        assert not state.is_pending()
        assert not state.is_running()
        assert state.is_canceled()
        assert not state.is_error()
        assert not state.is_success()
        assert len(state.messages) == 1
Example #12
0
def test_obsolete_runs(fscls, database, tmpdir):
    """Test deleting runs that were created before a given date."""
    # -- Setup ----------------------------------------------------------------
    fs = fscls(env=Config().basedir(tmpdir))
    # Create two runs (one SUCCESS and one ERROR) before a timestamp t1
    _, _, run_1, _ = success_run(database, fs, tmpdir)
    _, _, run_2 = error_run(database, fs, ['There were errors'])
    time.sleep(1)
    t1 = util.utc_now()
    # Create another SUCCESS run after timestamp t1
    _, _, run_3, _ = success_run(database, fs, tmpdir)
    # -- Test delete run with state filter ------------------------------------
    with database.session() as session:
        runs = RunManager(session=session, fs=fs)
        assert runs.delete_obsolete_runs(date=t1, state=st.STATE_ERROR) == 1
        # After deleting the error run the two success runs still exist.
        runs.get_run(run_id=run_1)
        with pytest.raises(err.UnknownRunError):
            runs.get_run(run_id=run_2)
        runs.get_run(run_id=run_3)
    # -- Test delete all runs prior to a given date ---------------------------
    with database.session() as session:
        runs = RunManager(session=session, fs=fs)
        assert runs.delete_obsolete_runs(date=t1) == 1
        # After deleting the run the only one success runs still exist.
        with pytest.raises(err.UnknownRunError):
            runs.get_run(run_id=run_1)
        runs.get_run(run_id=run_3)
Example #13
0
def test_list_runs(fscls, database, tmpdir):
    """Test retrieving a list of run descriptors."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create two runs: one in running state and one in error state.
    fs = fscls(env=Config().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])
        groups = WorkflowGroupManager(session=session, fs=fs)
        runs = RunManager(session=session, fs=fs)
        group = groups.get_group(group_id)
        # Run 1 in running state
        r = runs.create_run(group=group)
        run_1 = r.run_id
        runs.update_run(run_id=run_1, state=r.state().start())
        r = runs.create_run(group=group)
        run_2 = r.run_id
        runs.update_run(run_id=run_2, state=r.state().error())
    # -- Test get listing -----------------------------------------------------
    with database.session() as session:
        runs = RunManager(session=session, fs=fs)
        run_index = dict()
        for run in runs.list_runs(group_id):
            run_index[run.run_id] = run
        assert len(run_index) == 2
        assert run_index[run_1].state().is_running()
        assert run_index[run_2].state().is_error()
    # -- Test polling runs ----------------------------------------------------
    with database.session() as session:
        runs = RunManager(session=session, fs=fs)
        assert len(runs.list_runs(group_id)) == 2
        assert len(runs.list_runs(group_id, state=st.STATE_ERROR)) == 1
        assert len(runs.list_runs(group_id, state=st.STATE_SUCCESS)) == 0
Example #14
0
def test_invalid_state_transitions(fscls, database, tmpdir):
    """Test error cases for invalid state transitions."""
    # -- Setup ----------------------------------------------------------------
    fs = fscls(env=Config().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])
    # -- Test set active run to pending ---------------------------------------
    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))
        run_id = run.run_id
        state = run.state()
        runs.update_run(run_id=run_id, state=state.start())
        with pytest.raises(err.ConstraintViolationError):
            runs.update_run(run_id=run_id, state=st.StatePending())
    # Cancel run
    with database.session() as session:
        runs = RunManager(session=session, fs=fs)
        runs.update_run(run_id=run_id, state=state.cancel())
    # -- Test cannot set run to any of the inactive states --------------------
    with database.session() as session:
        groups = WorkflowGroupManager(session=session, fs=fs)
        runs = RunManager(session=session, fs=fs)
        assert runs.update_run(run_id=run_id, state=state.cancel()) is None
        with pytest.raises(err.ConstraintViolationError):
            runs.update_run(run_id=run_id, state=state.error())
        with pytest.raises(err.ConstraintViolationError):
            runs.update_run(run_id=run_id, state=state.success())
def test_upload_file(fscls, database, tmpdir):
    """Test uploading files."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create a database with two groups for a single workflow. Upload one file
    # for each group.
    fs = fscls(env=Config().basedir(tmpdir))
    with database.session() as session:
        user_1 = model.create_user(session, active=True)
        workflow_id = model.create_workflow(session)
        group_1 = model.create_group(session, workflow_id, users=[user_1])
    # -- Test upload file -----------------------------------------------------
    data = {'A': 1}
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        fh = manager.upload_file(group_id=group_1,
                                 file=io_file(data={'A': 1}),
                                 name='A.json')
        assert fh.name == 'A.json'
        assert fh.mime_type == 'application/json'
        fh = manager.get_uploaded_file(group_id=group_1, file_id=fh.file_id)
        assert json.load(fh.open()) == data
    # -- Test error case ------------------------------------------------------
    data = {'A': 1}
    with database.session() as session:
        with pytest.raises(err.ConstraintViolationError):
            manager.upload_file(group_id=group_1,
                                file=io_file(data={'A': 1}),
                                name=' ')
        with pytest.raises(err.UnknownWorkflowGroupError):
            manager.upload_file(group_id='UNKNOWN',
                                file=io_file(data={'A': 1}),
                                name=' ')
Example #16
0
def test_delete_group(fscls, database, tmpdir):
    """Test creating and deleting workflow groups."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create a database with two groups for a single workflow.
    fs = fscls(env=Config().basedir(tmpdir))
    with database.session() as session:
        user_id = model.create_user(session, active=True)
        wf_id = model.create_workflow(session)
        manager = WorkflowGroupManager(session=session, fs=fs)
        group_1 = manager.create_group(workflow_id=wf_id,
                                       name='A',
                                       user_id=user_id,
                                       parameters=ParameterIndex(),
                                       workflow_spec=dict()).group_id
        group_2 = manager.create_group(workflow_id=wf_id,
                                       name='B',
                                       user_id=user_id,
                                       parameters=ParameterIndex(),
                                       workflow_spec=dict()).group_id
    # -- Delete group ---------------------------------------------------------
    with database.session() as session:
        # Ensure that group directores are deleted.
        manager = WorkflowGroupManager(session=session, fs=fs)
        manager.delete_group(group_1)
        # Access to group 1 raises error while group 2 is still accessible.
        with pytest.raises(err.UnknownWorkflowGroupError):
            manager.get_group(group_1)
        assert manager.get_group(group_2) is not None
def test_create_workflow_with_alt_spec(fscls, database, tmpdir):
    """Test creating workflows with alternative specification files."""
    # -- Setup ----------------------------------------------------------------
    fs = fscls(env=Config().basedir(tmpdir))
    # -- Template without schema ----------------------------------------------
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.create_workflow(source=BENCHMARK_DIR,
                                     specfile=TEMPLATE_WITHOUT_SCHEMA)
        workflow_id = wf.workflow_id
        assert wf.name == 'Hello World'
        template = wf.get_template()
        assert template.result_schema is None
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.get_workflow(workflow_id=workflow_id)
        assert wf.name == 'Hello World'
        template = wf.get_template()
        assert template.result_schema is None
    # -- Template with post-processing step -----------------------------------
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.create_workflow(name='Top Tagger',
                                     source=BENCHMARK_DIR,
                                     specfile=TEMPLATE_TOPTAGGER)
        workflow_id = wf.workflow_id
        assert wf.get_template().postproc_spec is not None
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.get_workflow(workflow_id=workflow_id)
        assert wf.get_template().postproc_spec is not None
Example #18
0
def ClientAPI(
    env: Optional[Dict] = None, basedir: Optional[str] = None,
    database: Optional[str] = None, open_access: Optional[bool] = None,
    run_async: Optional[bool] = None, user_id: Optional[str] = None
) -> APIFactory:
    """Create an instance of the API factory that is responsible for generating
    API instances for a flowserv client.

    The main distinction here is whether a connection is made to a local instance
    of the service or to a remote instance. This distinction is made based on
    the value of the FLOWSERV_CLIENT environment variable that takes the values
    'local' or 'remote'. The default is 'local'.

    Provides the option to alter the default settings of environment variables.

    Parameters
    ----------
    env: dict, default=None
        Dictionary with configuration parameter values.
    basedir: string, default=None
        Base directory for all workflow files. If no directory is given or
        specified in the environment a temporary directory will be created.
    database: string, default=None
        Optional database connect url.
    open_access: bool, default=None
        Use an open access policy if set to True.
    run_async: bool, default=False
        Run workflows in asynchronous mode.
    user_id: string, default=None
        Optional identifier for the authenticated API user.

    Returns
    -------
    flowserv.service.api.APIFactory
    """
    # Get the base configuration settings from the environment if not given.
    env = env if env is not None else config.env()
    if not isinstance(env, Config):
        env = Config(env)
    # Update configuration based on the given optional arguments.
    if basedir is not None:
        env.basedir(basedir)
    if database is not None:
        env.database(database)
    if open_access is not None and open_access:
        env.open_access()
    # By default, the client runs all workflows synchronously.
    if run_async is not None and run_async:
        env.run_async()
    elif env.get(config.FLOWSERV_ASYNC) is None:
        env.run_sync()
    # Create local or remote API factory depending on the FLOWSERV_CLIENT value.
    client = env.get(config.FLOWSERV_CLIENT, config.LOCAL_CLIENT)
    if client == config.LOCAL_CLIENT:
        return LocalAPIFactory(env=env, user_id=user_id)
    elif client == config.REMOTE_CLIENT:
        # Not implemented yet.
        pass
    raise ValueError("inalid client type '{}'".format(client))
def test_empty_ranking(fscls, database, tmpdir):
    """The rankings for workflows without completed runs are empty."""
    # -- Setup ----------------------------------------------------------------
    workflows = init(database, tmpdir)
    fs = fscls(env=Config().basedir(tmpdir))
    # -- Test empty listing with no successful runs ---------------------------
    with database.session() as session:
        wfrepo = WorkflowManager(session=session, fs=fs)
        rankings = RankingManager(session=session)
        for workflow_id, _ in workflows:
            wf = wfrepo.get_workflow(workflow_id)
            assert len(rankings.get_ranking(wf)) == 0
Example #20
0
def test_update_groups(fscls, database, tmpdir):
    """Test updating group name and group members."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create a database with two groups for one workflow. Group 1 has user 1 as
    # only member, group 2 has user 2 and 3 as member.
    fs = fscls(env=Config().basedir(tmpdir))
    with database.session() as session:
        user_1 = model.create_user(session, active=True)
        user_2 = model.create_user(session, active=True)
        user_3 = model.create_user(session, active=True)
        workflow_id = model.create_workflow(session)
        members_1 = [user_1]
        group_1 = model.create_group(session, workflow_id, users=members_1)
        members_2 = [user_2, user_3]
        group_2 = model.create_group(session, workflow_id, users=members_2)
    # -- Test add member ------------------------------------------------------
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        members_1 = [user_1, user_3]
        manager.update_group(group_1, members=members_1)
        members = [m.user_id for m in manager.get_group(group_1).members]
        assert set(members) == set(members_1)
        members = [m.user_id for m in manager.get_group(group_2).members]
        assert set(members) == set(members_2)
    # -- Test rename group ----------------------------------------------------
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        manager.update_group(group_2, name='My Group')
        assert manager.get_group(group_1).name == group_1
        assert manager.get_group(group_2).name == 'My Group'
    # -- Test rename group and change members ---------------------------------
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        members_2 = [user_1] + members_2
        manager.update_group(group_2, name='The Group', members=members_2)
        members = [m.user_id for m in manager.get_group(group_1).members]
        assert set(members) == set(members_1)
        members = [m.user_id for m in manager.get_group(group_2).members]
        assert set(members) == set(members_2)
        assert manager.get_group(group_1).name == group_1
        assert manager.get_group(group_2).name == 'The Group'
    # -- Test no changes ------------------------------------------------------
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        manager.update_group(group_2, name='The Group', members=members_2)
        members = [m.user_id for m in manager.get_group(group_1).members]
        assert set(members) == set(members_1)
        members = [m.user_id for m in manager.get_group(group_2).members]
        assert set(members) == set(members_2)
        assert manager.get_group(group_1).name == group_1
        assert manager.get_group(group_2).name == 'The Group'
def test_workflow_listing_serialization(database, tmpdir):
    """Test serialization of workflow listings."""
    config = Config().basedir(tmpdir)
    schema = validator('WorkflowListing')
    view = WorkflowSerializer()
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=FileSystemStore(config))
        model.create_workflow(session)
        model.create_workflow(session)
        workflows = manager.list_workflows()
        doc = view.workflow_listing(workflows)
        schema.validate(doc)
        assert len(doc[labels.WORKFLOW_LIST]) == 2
def test_postproc_workflow_errors(tmpdir):
    """Execute the modified helloworld example."""
    # -- Setup ----------------------------------------------------------------
    #
    # It is important here that we do not use the SQLite in-memory database
    # since this fails (for unknown reason; presumably due to different threads)
    # when the post-processing run is updated.
    # --
    env = Config().basedir(tmpdir).run_async().auth()
    service = LocalAPIFactory(env=env)
    # Error during data preparation
    run_erroneous_workflow(service, SPEC_FILE_ERR_1)
    # Erroneous specification
    run_erroneous_workflow(service, SPEC_FILE_ERR_2)
Example #23
0
def test_group_handle_serialization(database, tmpdir):
    """Test serialization of workflow group handles."""
    config = Config().basedir(tmpdir)
    view = WorkflowGroupSerializer()
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=FileSystemStore(config))
        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])
        manager.upload_file(group_id=group_id, file=io_file(data={'A': 1}), name='a.json')
        group = manager.get_group(group_id)
        doc = view.group_handle(group)
        validator('UserGroupHandle').validate(doc)
        assert len(doc[labels.GROUP_MEMBERS]) == 1
Example #24
0
def test_delete_run(fscls, database, tmpdir):
    """Test deleting a run."""
    # -- Setup ----------------------------------------------------------------
    fs = fscls(env=Config().basedir(tmpdir))
    _, _, run_id, _ = success_run(database, fs, tmpdir)
    # -- Test delete run ------------------------------------------------------
    with database.session() as session:
        runs = RunManager(session=session, fs=fs)
        runs.delete_run(run_id)
    # -- Error cases ----------------------------------------------------------
    with database.session() as session:
        # Error when deleting an unknown run.
        runs = RunManager(session=session, fs=fs)
        with pytest.raises(err.UnknownRunError):
            runs.delete_run(run_id)
def test_result_archive_local(database, tmpdir):
    """Test getting an archive of run results."""
    # -- Setup ----------------------------------------------------------------
    env = Config().basedir(tmpdir).auth()
    fs = FS(env=env)
    workflow_id, group_id, run_id, user_id = success_run(database, fs, tmpdir)
    local_service = LocalAPIFactory(env=env, db=database, engine=StateEngine())
    # -- Get result archive ---------------------------------------------------
    with local_service(user_id=user_id) as api:
        archive = api.runs().get_result_archive(run_id=run_id)
        tar = tarfile.open(fileobj=archive.open(), mode='r:gz')
        members = [t.name for t in tar.getmembers()]
        assert len(members) == 2
        assert 'A.json' in members
        assert 'run/results/B.json' in members
def test_create_workflow_with_alt_manifest(fscls, database, tmpdir):
    """Test creating 'Hello World' workflow with a different manifest file."""
    fs = fscls(env=Config().basedir(tmpdir))
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        wf = manager.create_workflow(source=BENCHMARK_DIR,
                                     manifestfile=ALT_MANIFEST)
        assert wf.name == 'Hello World'
        assert wf.description == 'Hello World Demo'
        assert wf.instructions == '# Hello World'
        template = wf.get_template()
        assert template.result_schema is not None
        staticdir = os.path.join(tmpdir, fs.workflow_staticdir(wf.workflow_id))
        assert os.path.isfile(os.path.join(staticdir, 'code/helloworld.py'))
        assert not os.path.isfile(os.path.join(staticdir, 'data/names.txt'))
Example #27
0
def test_initialize_filestore_from_env(tmpdir):
    """Test initializing the bucket store with a memory bucket from the
    envirnment variables.
    """
    # -- Setup ----------------------------------------------------------------
    env = Config().basedir(tmpdir)
    env[FLOWSERV_FILESTORE_MODULE] = 'flowserv.model.files.s3'
    env[FLOWSERV_FILESTORE_CLASS] = 'BucketStore'
    # -- Create bucket store instance -----------------------------------------
    fs = FS(env=env)
    assert isinstance(fs, BucketStore)
    assert isinstance(fs.bucket, DiskBucket)
    # -- Error cases ----------------------------------------------------------
    del env[FLOWSERV_FILESTORE_MODULE]
    with pytest.raises(err.MissingConfigurationError):
        FS(env=env)
    env[FLOWSERV_FILESTORE_MODULE] = 'flowserv.model.files.s3'
    del env[FLOWSERV_FILESTORE_CLASS]
    with pytest.raises(err.MissingConfigurationError):
        FS(env=env)
    # -- Default file store ---------------------------------------------------
    assert FS(env=Config().basedir(tmpdir)) is not None
    with pytest.raises(err.MissingConfigurationError):
        FS(env=Config())
Example #28
0
def test_group_listing_serialization(database, tmpdir):
    """Test serialization of workflow group listing."""
    config = Config().basedir(tmpdir)
    view = WorkflowGroupSerializer()
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=FileSystemStore(config))
        user_id = model.create_user(session, active=True)
        workflow_id = model.create_workflow(session)
        model.create_group(session, workflow_id, users=[user_id])
        model.create_group(session, workflow_id, users=[user_id])
        groups = manager.list_groups(workflow_id=workflow_id, user_id=user_id)
        assert len(groups) == 2
        doc = view.group_listing(groups)
        validator('UserGroupListing').validate(doc)
        assert len(doc[labels.GROUP_LIST]) == 2
def test_workflow_handle_serialization(database, tmpdir):
    """Test serialization of workflow handles."""
    config = Config().basedir(tmpdir)
    schema = validator('WorkflowHandle')
    view = WorkflowSerializer()
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=FileSystemStore(config))
        workflow = manager.create_workflow(source=BENCHMARK_DIR,
                                           name='Test',
                                           specfile=SPEC_FILE)
        doc = view.workflow_handle(workflow)
        schema.validate(doc)
        workflow = manager.get_workflow(workflow.workflow_id)
        schema.validate(doc)
        assert doc[labels.WORKFLOW_NAME] == 'Test'
def test_list_workflow(database, tmpdir):
    """Test deleting a workflows from the repository."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create two workflows.
    fs = FileSystemStore(env=Config().basedir(tmpdir))
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        manager.create_workflow(source=BENCHMARK_DIR)
        manager.create_workflow(source=BENCHMARK_DIR)
        manager.create_workflow(source=BENCHMARK_DIR)
    # -- Test list workflows --------------------------------------------------
    with database.session() as session:
        manager = WorkflowManager(session=session, fs=fs)
        workflows = manager.list_workflows()
        assert len(workflows) == 3