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=' ')
Exemple #2
0
def test_run_helloworld_sync(sync_service, specfile, state):
    """Execute the helloworld example."""
    # -- Setup ----------------------------------------------------------------
    #
    # Start a new run for the workflow template.
    with sync_service() as api:
        workflow_id = create_workflow(api,
                                      source=TEMPLATE_DIR,
                                      specfile=specfile)
        user_id = create_user(api)
    with sync_service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id)
        names = io_file(data=['Alice', 'Bob'], format='plain/text')
        file_id = upload_file(api, group_id, names)
        args = [
            serialize_arg('names', serialize_fh(file_id, 'data/names.txt')),
            serialize_arg('sleeptime', 3)
        ]
        run_id = start_run(api, group_id, arguments=args)
    # -- Validate the run handle against the expected state -------------------
    with sync_service(user_id=user_id) as api:
        r = api.runs().get_run(run_id)
        serialize.validate_run_handle(r, state=state)
        if state == st.STATE_SUCCESS:
            # The run should have the greetings.txt file as a result.
            files = dict()
            for obj in r['files']:
                files[obj['name']] = obj['id']
            assert len(files) == 1
            fh = api.runs().get_result_file(
                run_id=run_id, file_id=files['results/greetings.txt'])
            value = fh.open().read().decode('utf-8').strip()
            assert 'Hello Alice!' in value
            assert 'Hello Bob!' in value
Exemple #3
0
def start_hello_world(api, group_id):
    """Start a new run for the Hello World template. Returns the run identifier
    and the identifier for the input file.

    Parameters
    ----------
    api: flowserv.service.api.API
        Service API manager.
    group_id: string
        Unique group identifier.

    Returns
    -------
    string, string
    """
    file_id = api.uploads().upload_file(group_id=group_id,
                                        file=io_file(data=['Alice', 'Bob'],
                                                     format='txt/plain'),
                                        name='n.txt')['id']
    run_id = api.runs().start_run(group_id=group_id,
                                  arguments=[{
                                      'name':
                                      'names',
                                      'value':
                                      serialize_fh(file_id=file_id)
                                  }])['id']
    api.runs().backend.start(run_id)
    return run_id, file_id
def test_cancel_run_helloworld(async_service):
    """Test cancelling a helloworld run."""
    # -- Setup ----------------------------------------------------------------
    #
    # Start a new run for the workflow template.
    with async_service() as api:
        workflow_id = create_workflow(api, source=TEMPLATE_DIR)
        user_id = create_user(api)
    with async_service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id)
        names = io_file(data=['Alice', 'Bob', 'Zoe'], format='plain/text')
        file_id = upload_file(api, group_id, names)
        args = [
            serialize_arg('names', serialize_fh(file_id)),
            serialize_arg('sleeptime', 10),
            serialize_arg('greeting', 'Hi')
        ]
        run_id = start_run(api, group_id, arguments=args)
    # Poll run after sleeping for one second.
    time.sleep(1)
    with async_service(user_id=user_id) as api:
        run = api.runs().get_run(run_id=run_id)
    assert run['state'] in st.ACTIVE_STATES
    # -- Cancel the active run ------------------------------------------------
    with async_service(user_id=user_id) as api:
        run = api.runs().cancel_run(
            run_id=run_id,
            reason='done'
        )
        assert run['state'] == st.STATE_CANCELED
        assert run['messages'][0] == 'done'
    with async_service(user_id=user_id) as api:
        run = api.runs().get_run(run_id=run_id)
        assert run['state'] == st.STATE_CANCELED
        assert run['messages'][0] == 'done'
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_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_upload_group_file_local(local_service, hello_world):
    """Test uploading files for a workflow group."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create one group with minimal metadata for the 'Hello World' workflow.
    with local_service() as api:
        user_id = create_user(api)
        workflow = hello_world(api, name='W1')
        workflow_id = workflow.workflow_id
    with local_service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id=workflow_id)
    # -- Upload first file for the group --------------------------------------
    with local_service(user_id=user_id) as api:
        r = api.uploads().upload_file(group_id=group_id,
                                      file=io_file(data={
                                          'group': 1,
                                          'file': 1
                                      }),
                                      name='group1.json')
        file_id = r['id']
        serialize.validate_file_handle(r)
        assert r['name'] == 'group1.json'
    # -- Get serialized handle for the file and the group ---------------------
    for uid in [user_id, None]:
        with local_service(user_id=uid) as api:
            fcont = api.uploads().get_uploaded_file(group_id, file_id).read()
            assert fcont == b'{"group": 1, "file": 1}'
            gh = api.groups().get_group(group_id=group_id)
            serialize.validate_group_handle(gh)
def test_list_group_files_local(local_service, hello_world):
    """Test getting a listing of uploaded files for a workflow group."""
    # -- Setup ----------------------------------------------------------------
    #
    # Upload two files for a workflow group.
    with local_service() as api:
        user_id = create_user(api)
        workflow = hello_world(api, name='W1')
        workflow_id = workflow.workflow_id
    with local_service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id=workflow_id)
        for i in range(2):
            upload_file(api=api,
                        group_id=group_id,
                        file=io_file(data={
                            'group': 1,
                            'file': i
                        }))
    # -- Get file listing -----------------------------------------------------
    with local_service(user_id=user_id) as api:
        files = api.uploads().list_uploaded_files(group_id=group_id)
        serialize.validate_file_listing(files, 2)
    # -- Error when listing files as unknonw user -----------------------------
    with local_service(user_id='UNKNOWN') as api:
        with pytest.raises(err.UnauthorizedAccessError):
            api.uploads().list_uploaded_files(group_id=group_id)
def test_delete_group_file_local(local_service, hello_world):
    """Test deleting an uploaded file for a workflow group."""
    # -- Setup ----------------------------------------------------------------
    #
    # Upload one file for a workflow group.
    with local_service() as api:
        user_id = create_user(api)
        workflow = hello_world(api, name='W1')
        workflow_id = workflow.workflow_id
    with local_service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id=workflow_id)
        file_id = upload_file(api=api,
                              group_id=group_id,
                              file=io_file(data={
                                  'group': 1,
                                  'file': 1
                              }))
    # -- Error when unknown user attempts to delete the file ------------------
    with local_service(user_id='UNKNNOWN') as api:
        with pytest.raises(err.UnauthorizedAccessError):
            api.uploads().delete_file(group_id, file_id)
    # -- Delete the uploaded file ---------------------------------------------
    with local_service(user_id=user_id) as api:
        api.uploads().delete_file(group_id, file_id)
    # After deletion the file cannot be accessed anymore.
    with local_service(user_id=user_id) as api:
        with pytest.raises(err.UnknownFileError):
            api.uploads().get_uploaded_file(group_id, file_id)
Exemple #10
0
def write_results(rundir: str, files: Tuple[Union[dict, list], str, str]):
    """Create a result files for a workflow run.


    Parameters
    ----------
    rundir: string
        Path to the temporary run directory.
    run_id: string
        Unique run identifier.
    files: list
        List of 3-tuples containing the file data, format, and relative path.
    """
    for data, format, rel_path in files:
        filename = os.path.join(rundir, rel_path)
        os.makedirs(os.path.dirname(filename), exist_ok=True)
        io_file(data=data, format=format).store(filename)
def test_get_file(fscls, database, tmpdir):
    """Test accessing uploaded files."""
    # -- Setup ----------------------------------------------------------------
    #
    # Create a database with two groups for a single workflow. Upload one file
    # for each group.
    data_1 = {'A': 1}
    data_2 = {'B': 2}
    f1 = io_file(data=data_1)
    f2 = io_file(data=data_2)
    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])
        mngr = WorkflowGroupManager(session=session, fs=fs)
        file_1 = mngr.upload_file(group_id=group_1, file=f1, name=fn).file_id
        file_2 = mngr.upload_file(group_id=group_2, file=f2, name=fn).file_id
    files = [(group_1, file_1, data_1), (group_2, file_2, data_2)]
    # -- Test get file --------------------------------------------------------
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        for g_id, f_id, data in files:
            fh = manager.get_uploaded_file(group_id=g_id, file_id=f_id)
            assert fh.name == fn
            assert fh.mime_type == 'application/json'
            assert json.load(fh.open()) == data
    # -- Test error cases -----------------------------------------------------
    # - File handle is unknown for s2
    with database.session() as session:
        manager = WorkflowGroupManager(session=session, fs=fs)
        with pytest.raises(err.UnknownFileError):
            manager.get_uploaded_file(group_id=group_2, file_id=file_1).open()
        # - Access file with unknown file identifier
        with pytest.raises(err.UnknownFileError):
            manager.get_uploaded_file(group_id=group_1, file_id='UNK').open()
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
def run_erroneous_workflow(service, specfile):
    """Execute the modified helloworld example."""
    with service() as api:
        # Create workflow template, user, and the workflow group.
        workflow_id = create_workflow(
            api,
            source=TEMPLATE_DIR,
            specfile=specfile
        )
        user_id = create_user(api)
    with service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id)
        # Upload the names file.
        names = io_file(data=NAMES, format='txt/plain')
        file_id = upload_file(api, group_id, names)
        # Run the workflow.
        arguments = [
            serialize_arg('names', serialize_fh(file_id)),
            serialize_arg('greeting', 'Hi')
        ]
        run_id = start_run(api, group_id, arguments=arguments)
    # Poll workflow state every second.
    run = poll_run(service, run_id, user_id)
    assert run['state'] == st.STATE_SUCCESS
    with service() as api:
        wh = api.workflows().get_workflow(workflow_id=workflow_id)
    attmpts = 0
    while 'postproc' not in wh:
        time.sleep(1)
        with service() as api:
            wh = api.workflows().get_workflow(workflow_id=workflow_id)
        attmpts += 1
        if attmpts > 60:
            break
    assert 'postproc' in wh
    serialize.validate_workflow_handle(wh)
    attmpts = 0
    while wh['postproc']['state'] in st.ACTIVE_STATES:
        time.sleep(1)
        with service() as api:
            wh = api.workflows().get_workflow(workflow_id=workflow_id)
        attmpts += 1
        if attmpts > 60:
            break
    assert wh['postproc']['state'] not in st.ACTIVE_STATES
    serialize.validate_workflow_handle(wh)
    assert wh['postproc']['state'] == st.STATE_ERROR
def test_run_helloworld_async(async_service, fsconfig, target):
    """Execute the helloworld example."""
    # -- Setup ----------------------------------------------------------------
    #
    # Start a new run for the workflow template.
    with async_service() as api:
        workflow_id = create_workflow(api, source=TEMPLATE_DIR)
        user_id = create_user(api)
    with async_service(user_id=user_id) as api:
        group_id = create_group(api, workflow_id)
        names = io_file(data=['Alice', 'Bob', 'Zoe'], format='plain/text')
        file_id = upload_file(api, group_id, names)
        args = [
            serialize_arg('names', serialize_fh(file_id, target)),
            serialize_arg('sleeptime', 1),
            serialize_arg('greeting', 'Hi')
        ]
        run_id = start_run(api, group_id, arguments=args)
    # Poll workflow state every second.
    with async_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 async_service(user_id=user_id) as api:
            run = api.runs().get_run(run_id=run_id)
    assert run['state'] == st.STATE_SUCCESS
    files = dict()
    for f in run['files']:
        files[f['name']] = f['id']
    fh = api.runs().get_result_file(
        run_id=run_id,
        file_id=files['results/greetings.txt']
    )
    greetings = fh.open().read().decode('utf-8').strip()
    assert 'Hi Alice' in greetings
    assert 'Hi Bob' in greetings
    assert 'Hi Zoe' in greetings
    fh = api.runs().get_result_file(
        run_id=run_id,
        file_id=files['results/analytics.json']
    )
    assert json.load(fh.open()) is not None
def test_file_listing_serialization(database, tmpdir):
    """Test serialization of file handles."""
    config = Config().basedir(tmpdir)
    view = UploadFileSerializer()
    filename = 'data.json'
    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])
        fh = manager.upload_file(group_id=group_id,
                                 file=io_file(data={'A': 1}),
                                 name=filename)
        doc = view.file_handle(group_id=group_id, fh=fh)
        assert doc[labels.FILE_NAME] == filename
        validator('FileHandle').validate(doc)
        doc = view.file_listing(
            group_id=group_id,
            files=manager.list_uploaded_files(group_id=group_id))
        validator('FileListing').validate(doc)
def test_postproc_workflow(fsconfig, 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()
    env.update(fsconfig)
    service = LocalAPIFactory(env=env)
    # Start a new run for the workflow template.
    with service() as api:
        # Need to set the file store in the backend to the new instance as
        # well. Otherwise, the post processing workflow may attempt to use
        # the backend which was initialized prior with a different file store.
        workflow_id = create_workflow(
            api,
            source=TEMPLATE_DIR,
            specfile=SPEC_FILE
        )
        user_id = create_user(api)
    # Create four groups and run the workflow with a slightly different input
    # file
    for i in range(4):
        with service(user_id=user_id) as api:
            group_id = create_group(api, workflow_id)
            names = io_file(data=NAMES[:(i + 1)], format='plain/text')
            file_id = upload_file(api, group_id, names)
            # Set the template argument values
            arguments = [
                serialize_arg('names', serialize_fh(file_id)),
                serialize_arg('greeting', 'Hi')
            ]
            run_id = start_run(api, group_id, arguments=arguments)
        # Poll workflow state every second.
        run = poll_run(service, run_id, user_id)
        assert run['state'] == st.STATE_SUCCESS
        with service() as api:
            wh = api.workflows().get_workflow(workflow_id=workflow_id)
        attmpts = 0
        while 'postproc' not in wh:
            time.sleep(1)
            with service() as api:
                wh = api.workflows().get_workflow(workflow_id=workflow_id)
            attmpts += 1
            if attmpts > 60:
                break
        assert 'postproc' in wh
        serialize.validate_workflow_handle(wh)
        attmpts = 0
        while wh['postproc']['state'] in st.ACTIVE_STATES:
            time.sleep(1)
            with service() as api:
                wh = api.workflows().get_workflow(workflow_id=workflow_id)
            attmpts += 1
            if attmpts > 60:
                break
        serialize.validate_workflow_handle(wh)
        with service() as api:
            ranking = api.workflows().get_ranking(workflow_id=workflow_id)
        serialize.validate_ranking(ranking)
        for fobj in wh['postproc']['files']:
            if fobj['name'] == 'results/compare.json':
                file_id = fobj['id']
        with service(user_id=user_id) as api:
            fh = api.workflows().get_result_file(
                workflow_id=workflow_id,
                file_id=file_id
            )
        compare = util.read_object(fh.open())
        assert len(compare) == (i + 1)
    # Access the post-processing result files.
    with service() as api:
        fh = api.workflows().get_result_archive(workflow_id=workflow_id)
    assert fh.name.startswith('run')
    assert fh.mime_type == 'application/gzip'