Beispiel #1
0
def test_delete_collection(api, collection_batch, scopes, collection_auth):
    authorized = ODPScope.COLLECTION_ADMIN in scopes and \
                 collection_auth in (CollectionAuth.NONE, CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = collection_batch[2]
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = collection_batch[1]
    else:
        api_client_collection = None

    modified_collection_batch = collection_batch.copy()
    del modified_collection_batch[2]

    r = api(scopes, api_client_collection).delete(
        f'/collection/{(collection_id := collection_batch[2].id)}')

    if authorized:
        assert_empty_result(r)
        assert_db_state(modified_collection_batch)
        assert_audit_log('delete', collection_id=collection_id)
    else:
        assert_forbidden(r)
        assert_db_state(collection_batch)
        assert_no_audit_log()
Beispiel #2
0
def test_create_collection_conflict(api, collection_batch, collection_auth):
    scopes = [ODPScope.COLLECTION_ADMIN]
    authorized = collection_auth == CollectionAuth.NONE

    if collection_auth == CollectionAuth.NONE:
        api_client_collection = None
    else:
        api_client_collection = collection_batch[2]

    collection = collection_build(id=collection_batch[2].id)

    r = api(scopes,
            api_client_collection).post('/collection/',
                                        json=dict(
                                            id=collection.id,
                                            name=collection.name,
                                            doi_key=collection.doi_key,
                                            provider_id=collection.provider_id,
                                        ))

    if authorized:
        assert_conflict(r, 'Collection id is already in use')
    else:
        assert_forbidden(r)

    assert_db_state(collection_batch)
    assert_no_audit_log()
Beispiel #3
0
def test_update_collection_not_found(api, collection_batch_no_projects,
                                     collection_auth):
    scopes = [ODPScope.COLLECTION_ADMIN]
    authorized = collection_auth == CollectionAuth.NONE

    if collection_auth == CollectionAuth.NONE:
        api_client_collection = None
    else:
        api_client_collection = collection_batch_no_projects[2]

    collection = collection_build(id='foo')

    r = api(scopes,
            api_client_collection).put('/collection/',
                                       json=dict(
                                           id=collection.id,
                                           name=collection.name,
                                           doi_key=collection.doi_key,
                                           provider_id=collection.provider_id,
                                       ))

    if authorized:
        assert_not_found(r)
    else:
        assert_forbidden(r)

    assert_db_state(collection_batch_no_projects)
    assert_no_audit_log()
Beispiel #4
0
def test_update_role(api, role_batch, scopes, collection_auth):
    authorized = ODPScope.ROLE_ADMIN in scopes and \
                 collection_auth in (CollectionAuth.NONE, CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = role_batch[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = role_batch[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        modified_role_collection = role_batch[2].collection
    else:
        modified_role_collection = None

    modified_role_batch = role_batch.copy()
    modified_role_batch[2] = (role := role_build(
        id=role_batch[2].id,
        collection=modified_role_collection,
    ))

    r = api(scopes, api_client_collection).put('/role/', json=dict(
        id=role.id,
        scope_ids=scope_ids(role),
        collection_id=role.collection_id,
    ))

    if authorized:
        assert_empty_result(r)
        assert_db_state(modified_role_batch)
    else:
        assert_forbidden(r)
        assert_db_state(role_batch)
Beispiel #5
0
def test_create_collection(api, collection_batch, scopes, collection_auth):
    # note that collection-specific auth will never allow creating a new collection
    authorized = ODPScope.COLLECTION_ADMIN in scopes and \
                 collection_auth == CollectionAuth.NONE

    if collection_auth == CollectionAuth.NONE:
        api_client_collection = None
    else:
        api_client_collection = collection_batch[2]

    modified_collection_batch = collection_batch + [
        collection := collection_build()
    ]

    r = api(scopes,
            api_client_collection).post('/collection/',
                                        json=dict(
                                            id=collection.id,
                                            name=collection.name,
                                            doi_key=collection.doi_key,
                                            provider_id=collection.provider_id,
                                        ))

    if authorized:
        assert_empty_result(r)
        assert_db_state(modified_collection_batch)
        assert_audit_log('insert', collection)
    else:
        assert_forbidden(r)
        assert_db_state(collection_batch)
        assert_no_audit_log()
Beispiel #6
0
def test_create_role_conflict(api, role_batch, collection_auth):
    scopes = [ODPScope.ROLE_ADMIN]
    authorized = collection_auth in (CollectionAuth.NONE, CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = role_batch[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = role_batch[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        new_role_collection = role_batch[2].collection
    else:
        new_role_collection = None

    role = role_build(
        id=role_batch[2].id,
        collection=new_role_collection,
    )

    r = api(scopes, api_client_collection).post('/role/', json=dict(
        id=role.id,
        scope_ids=scope_ids(role),
        collection_id=role.collection_id,
    ))

    if authorized:
        assert_conflict(r, 'Role id is already in use')
    else:
        assert_forbidden(r)

    assert_db_state(role_batch)
Beispiel #7
0
def test_update_role_not_found(api, role_batch, collection_auth):
    scopes = [ODPScope.ROLE_ADMIN]
    authorized = collection_auth in (CollectionAuth.NONE, CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = role_batch[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = role_batch[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        modified_role_collection = role_batch[2].collection
    else:
        modified_role_collection = None

    role = role_build(
        id='foo',
        collection=modified_role_collection,
    )

    r = api(scopes, api_client_collection).put('/role/', json=dict(
        id=role.id,
        scope_ids=scope_ids(role),
        collection_id=role.collection_id,
    ))

    if authorized:
        assert_not_found(r)
    else:
        assert_forbidden(r)

    assert_db_state(role_batch)
Beispiel #8
0
def test_untag_record(api, record_batch_no_tags, admin_route, scopes,
                      collection_auth, tag_cardinality, same_user):
    route = '/record/admin/' if admin_route else '/record/'

    authorized = admin_route and ODPScope.RECORD_ADMIN in scopes or \
                 not admin_route and ODPScope.RECORD_QC in scopes
    authorized = authorized and collection_auth in (CollectionAuth.NONE,
                                                    CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = record_batch_no_tags[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = record_batch_no_tags[1].collection
    else:
        api_client_collection = None

    client = api(scopes, api_client_collection)
    record = record_batch_no_tags[2]
    record_tags = RecordTagFactory.create_batch(randint(1, 3), record=record)

    tag = new_generic_tag(tag_cardinality)
    if same_user:
        record_tag_1 = RecordTagFactory(
            record=record,
            tag=tag,
            user=None,
        )
    else:
        record_tag_1 = RecordTagFactory(
            record=record,
            tag=tag,
        )
    record_tag_1_dict = {
        'tag_id': record_tag_1.tag_id,
        'user_id': record_tag_1.user_id,
        'data': record_tag_1.data,
    }

    r = client.delete(f'{route}{record.id}/tag/{record_tag_1.id}')

    if authorized:
        if not admin_route and not same_user:
            assert_forbidden(r)
            assert_db_tag_state(record.id, *record_tags, record_tag_1)
            assert_tag_audit_log()
        else:
            assert_empty_result(r)
            assert_db_tag_state(record.id, *record_tags)
            assert_tag_audit_log(
                dict(command='delete',
                     record_id=record.id,
                     record_tag=record_tag_1_dict), )
    else:
        assert_forbidden(r)
        assert_db_tag_state(record.id, *record_tags, record_tag_1)
        assert_tag_audit_log()

    assert_db_state(record_batch_no_tags)
    assert_no_audit_log()
Beispiel #9
0
def test_update_record_doi_change(api, record_batch_with_ids, admin,
                                  collection_auth, doi_change, published_doi):
    route = '/record/admin/' if admin else '/record/'
    scopes = [ODPScope.RECORD_ADMIN] if admin else [ODPScope.RECORD_WRITE]
    authorized = collection_auth in (CollectionAuth.NONE, CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = record_batch_with_ids[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = record_batch_with_ids[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        modified_record_collection = record_batch_with_ids[2].collection
    else:
        modified_record_collection = None  # new collection

    if published_doi:
        PublishedDOI(doi=record_batch_with_ids[2].doi).save()

    modified_record_batch = record_batch_with_ids.copy()
    if doi_change == 'change':
        modified_record_batch[2] = (record := record_build(
            identifiers='doi',
            id=record_batch_with_ids[2].id,
            collection=modified_record_collection,
        ))
    elif doi_change == 'remove':
        modified_record_batch[2] = (record := record_build(
            identifiers='sid',
            id=record_batch_with_ids[2].id,
            collection=modified_record_collection,
        ))

    r = api(scopes,
            api_client_collection).put(route + record.id,
                                       json=dict(
                                           doi=record.doi,
                                           sid=record.sid,
                                           collection_id=record.collection_id,
                                           schema_id=record.schema_id,
                                           metadata=record.metadata_,
                                       ))

    if authorized:
        if published_doi:
            assert_unprocessable(
                r, 'The DOI has been published and cannot be modified.')
            assert_db_state(record_batch_with_ids)
            assert_no_audit_log()
        else:
            assert_json_record_result(r, r.json(), record)
            assert_db_state(modified_record_batch)
            assert_audit_log('update', record)
    else:
        assert_forbidden(r)
        assert_db_state(record_batch_with_ids)
        assert_no_audit_log()
Beispiel #10
0
def test_get_user(api, user_batch, scopes):
    authorized = ODPScope.USER_READ in scopes
    r = api(scopes).get(f'/user/{user_batch[2].id}')
    if authorized:
        assert_json_result(r, r.json(), user_batch[2])
    else:
        assert_forbidden(r)
    assert_db_state(user_batch)
Beispiel #11
0
def test_get_catalog(api, catalog_batch, scopes):
    authorized = ODPScope.CATALOG_READ in scopes
    r = api(scopes).get(f'/catalog/{catalog_batch[2].id}')
    if authorized:
        assert_json_result(r, r.json(), catalog_batch[2])
    else:
        assert_forbidden(r)
    assert_db_state(catalog_batch)
Beispiel #12
0
def test_get_schema(api, schema_batch, scopes):
    authorized = ODPScope.SCHEMA_READ in scopes
    r = api(scopes).get(f'/schema/{schema_batch[2].id}')
    if authorized:
        assert_json_result(r, r.json(), schema_batch[2])
    else:
        assert_forbidden(r)
    assert_db_state(schema_batch)
Beispiel #13
0
def test_list_catalogs(api, catalog_batch, scopes):
    authorized = ODPScope.CATALOG_READ in scopes
    r = api(scopes).get('/catalog/')
    if authorized:
        assert_json_results(r, r.json(), catalog_batch)
    else:
        assert_forbidden(r)
    assert_db_state(catalog_batch)
Beispiel #14
0
def test_list_users(api, user_batch, scopes):
    authorized = ODPScope.USER_READ in scopes
    r = api(scopes).get('/user/')
    if authorized:
        assert_json_results(r, r.json(), user_batch)
    else:
        assert_forbidden(r)
    assert_db_state(user_batch)
def test_list_providers(api, provider_batch, scopes):
    authorized = ODPScope.PROVIDER_READ in scopes
    r = api(scopes).get('/provider/')
    if authorized:
        assert_json_results(r, r.json(), provider_batch)
    else:
        assert_forbidden(r)
    assert_db_state(provider_batch)
Beispiel #16
0
def test_get_tag(api, tag_batch, scopes):
    authorized = ODPScope.TAG_READ in scopes
    r = api(scopes).get(f'/tag/{tag_batch[2].id}')
    if authorized:
        assert_json_result(r, r.json(), tag_batch[2])
    else:
        assert_forbidden(r)
    assert_db_state(tag_batch)
def test_get_provider(api, provider_batch, scopes):
    authorized = ODPScope.PROVIDER_READ in scopes
    r = api(scopes).get(f'/provider/{provider_batch[2].id}')
    if authorized:
        assert_json_result(r, r.json(), provider_batch[2])
    else:
        assert_forbidden(r)
    assert_db_state(provider_batch)
Beispiel #18
0
def test_list_tags(api, tag_batch, scopes):
    authorized = ODPScope.TAG_READ in scopes
    r = api(scopes).get('/tag/')
    if authorized:
        assert_json_results(r, r.json(), tag_batch)
    else:
        assert_forbidden(r)
    assert_db_state(tag_batch)
Beispiel #19
0
def test_list_schemas(api, schema_batch, scopes):
    authorized = ODPScope.SCHEMA_READ in scopes
    r = api(scopes).get('/schema/')
    if authorized:
        assert_json_results(r, r.json(), schema_batch)
    else:
        assert_forbidden(r)
    assert_db_state(schema_batch)
Beispiel #20
0
def test_update_record_conflict(api, record_batch_with_ids, admin,
                                collection_auth, conflict):
    route = '/record/admin/' if admin else '/record/'
    scopes = [ODPScope.RECORD_ADMIN] if admin else [ODPScope.RECORD_WRITE]
    authorized = collection_auth in (CollectionAuth.NONE, CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = record_batch_with_ids[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = record_batch_with_ids[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        modified_record_collection = record_batch_with_ids[2].collection
    else:
        modified_record_collection = None  # new collection

    if conflict == 'doi':
        record = record_build(
            id=record_batch_with_ids[2].id,
            doi=record_batch_with_ids[0].doi,
            collection=modified_record_collection,
        )
    elif conflict == 'sid':
        record = record_build(
            id=record_batch_with_ids[2].id,
            sid=record_batch_with_ids[0].sid,
            collection=modified_record_collection,
        )
    else:
        record = record_build(
            id=record_batch_with_ids[2].id,
            doi=record_batch_with_ids[0].doi,
            sid=record_batch_with_ids[1].sid,
            collection=modified_record_collection,
        )

    r = api(scopes,
            api_client_collection).put(route + record.id,
                                       json=dict(
                                           doi=record.doi,
                                           sid=record.sid,
                                           collection_id=record.collection_id,
                                           schema_id=record.schema_id,
                                           metadata=record.metadata_,
                                       ))

    if authorized:
        if conflict in ('doi', 'both'):
            assert_conflict(r, 'DOI is already in use')
        else:
            assert_conflict(r, 'SID is already in use')
    else:
        assert_forbidden(r)

    assert_db_state(record_batch_with_ids)
    assert_no_audit_log()
Beispiel #21
0
def test_update_record(api, record_batch, admin_route, scopes, collection_tags,
                       collection_auth):
    route = '/record/admin/' if admin_route else '/record/'

    authorized = admin_route and ODPScope.RECORD_ADMIN in scopes or \
                 not admin_route and ODPScope.RECORD_WRITE in scopes
    authorized = authorized and collection_auth in (CollectionAuth.NONE,
                                                    CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = record_batch[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = record_batch[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        modified_record_collection = record_batch[2].collection
    else:
        modified_record_collection = None  # new collection

    modified_record_batch = record_batch.copy()
    modified_record_batch[2] = (record := record_build(
        id=record_batch[2].id,
        doi=record_batch[2].doi,
        collection=modified_record_collection,
        collection_tags=collection_tags,
    ))

    r = api(scopes,
            api_client_collection).put(route + record.id,
                                       json=dict(
                                           doi=record.doi,
                                           sid=record.sid,
                                           collection_id=record.collection_id,
                                           schema_id=record.schema_id,
                                           metadata=record.metadata_,
                                       ))

    if authorized:
        if not admin_route and set(collection_tags) & {
                ODPCollectionTag.FROZEN, ODPCollectionTag.READY
        }:
            assert_unprocessable(
                r,
                'Cannot update a record belonging to a ready or frozen collection'
            )
            assert_db_state(record_batch)
            assert_no_audit_log()
        else:
            assert_json_record_result(r, r.json(), record)
            assert_db_state(modified_record_batch)
            assert_audit_log('update', record)
    else:
        assert_forbidden(r)
        assert_db_state(record_batch)
        assert_no_audit_log()
Beispiel #22
0
def test_delete_user(api, user_batch, scopes):
    authorized = ODPScope.USER_ADMIN in scopes
    modified_user_batch = user_batch.copy()
    del modified_user_batch[2]
    r = api(scopes).delete(f'/user/{user_batch[2].id}')
    if authorized:
        assert_empty_result(r)
        assert_db_state(modified_user_batch)
    else:
        assert_forbidden(r)
        assert_db_state(user_batch)
Beispiel #23
0
def test_delete_record(api, record_batch_with_ids, admin_route, scopes,
                       collection_tags, collection_auth, published_doi):
    route = '/record/admin/' if admin_route else '/record/'

    authorized = admin_route and ODPScope.RECORD_ADMIN in scopes or \
                 not admin_route and ODPScope.RECORD_WRITE in scopes
    authorized = authorized and collection_auth in (CollectionAuth.NONE,
                                                    CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = record_batch_with_ids[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = record_batch_with_ids[1].collection
    else:
        api_client_collection = None

    for ct in collection_tags:
        CollectionTagFactory(
            collection=record_batch_with_ids[2].collection,
            tag=TagFactory(id=ct, type='collection'),
        )

    if published_doi:
        PublishedDOI(doi=record_batch_with_ids[2].doi).save()

    modified_record_batch = record_batch_with_ids.copy()
    del modified_record_batch[2]

    r = api(scopes, api_client_collection).delete(
        f'{route}{(record_id := record_batch_with_ids[2].id)}')

    if authorized:
        if not admin_route and set(collection_tags) & {
                ODPCollectionTag.FROZEN, ODPCollectionTag.READY
        }:
            assert_unprocessable(
                r,
                'Cannot delete a record belonging to a ready or frozen collection'
            )
            assert_db_state(record_batch_with_ids)
            assert_no_audit_log()
        elif published_doi:
            assert_unprocessable(
                r, 'The DOI has been published and cannot be deleted.')
            assert_db_state(record_batch_with_ids)
            assert_no_audit_log()
        else:
            assert_empty_result(r)
            assert_db_state(modified_record_batch)
            assert_audit_log('delete', record_id=record_id)
    else:
        assert_forbidden(r)
        assert_db_state(record_batch_with_ids)
        assert_no_audit_log()
def test_delete_provider(api, provider_batch, scopes):
    authorized = ODPScope.PROVIDER_ADMIN in scopes
    modified_provider_batch = provider_batch.copy()
    del modified_provider_batch[2]
    r = api(scopes).delete(f'/provider/{provider_batch[2].id}')
    if authorized:
        assert_empty_result(r)
        assert_db_state(modified_provider_batch)
    else:
        assert_forbidden(r)
        assert_db_state(provider_batch)
Beispiel #25
0
def test_list_scopes(api, scope_batch, scopes):
    authorized = ODPScope.SCOPE_READ in scopes
    # add the parameterized scopes to the batch of expected scopes,
    # as they will be created by the api fixture
    scope_batch += [ScopeFactory.build(id=s.value, type='odp') for s in scopes]
    r = api(scopes).get('/scope/')
    if authorized:
        assert_json_results(r, r.json(), scope_batch)
    else:
        assert_forbidden(r)
    assert_db_state(scope_batch)
Beispiel #26
0
def test_create_record(api, record_batch, admin_route, scopes, collection_tags,
                       collection_auth):
    route = '/record/admin/' if admin_route else '/record/'

    authorized = admin_route and ODPScope.RECORD_ADMIN in scopes or \
                 not admin_route and ODPScope.RECORD_WRITE in scopes
    authorized = authorized and collection_auth in (CollectionAuth.NONE,
                                                    CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = record_batch[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = record_batch[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        new_record_collection = record_batch[2].collection
    else:
        new_record_collection = None  # new collection

    modified_record_batch = record_batch + [
        record := record_build(
            collection=new_record_collection,
            collection_tags=collection_tags,
        )
    ]

    r = api(scopes,
            api_client_collection).post(route,
                                        json=dict(
                                            doi=record.doi,
                                            sid=record.sid,
                                            collection_id=record.collection_id,
                                            schema_id=record.schema_id,
                                            metadata=record.metadata_,
                                        ))

    if authorized:
        if not admin_route and ODPCollectionTag.FROZEN in collection_tags:
            assert_unprocessable(
                r, 'A record cannot be added to a frozen collection')
            assert_db_state(record_batch)
            assert_no_audit_log()
        else:
            record.id = r.json().get('id')
            assert_json_record_result(r, r.json(), record)
            assert_db_state(modified_record_batch)
            assert_audit_log('insert', record)
    else:
        assert_forbidden(r)
        assert_db_state(record_batch)
        assert_no_audit_log()
def test_create_provider(api, provider_batch, scopes):
    authorized = ODPScope.PROVIDER_ADMIN in scopes
    modified_provider_batch = provider_batch + [provider := provider_build()]
    r = api(scopes).post('/provider/',
                         json=dict(
                             id=provider.id,
                             name=provider.name,
                         ))
    if authorized:
        assert_empty_result(r)
        assert_db_state(modified_provider_batch)
    else:
        assert_forbidden(r)
        assert_db_state(provider_batch)
Beispiel #28
0
def test_create_project(api, project_batch, scopes):
    authorized = ODPScope.PROJECT_ADMIN in scopes
    modified_project_batch = project_batch + [project := project_build()]
    r = api(scopes).post('/project/',
                         json=dict(
                             id=project.id,
                             name=project.name,
                             collection_ids=collection_ids(project),
                         ))
    if authorized:
        assert_empty_result(r)
        assert_db_state(modified_project_batch)
    else:
        assert_forbidden(r)
        assert_db_state(project_batch)
Beispiel #29
0
def test_update_record_not_found(api, record_batch, admin, collection_auth):
    # if not found on the admin route, the record is created!
    route = '/record/admin/' if admin else '/record/'
    scopes = [ODPScope.RECORD_ADMIN] if admin else [ODPScope.RECORD_WRITE]
    authorized = collection_auth in (CollectionAuth.NONE, CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = record_batch[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = record_batch[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        modified_record_collection = record_batch[2].collection
    else:
        modified_record_collection = None  # new collection

    modified_record_batch = record_batch + [
        record := record_build(
            id=str(uuid.uuid4()),
            collection=modified_record_collection,
        )
    ]

    r = api(scopes,
            api_client_collection).put(route + record.id,
                                       json=dict(
                                           doi=record.doi,
                                           sid=record.sid,
                                           collection_id=record.collection_id,
                                           schema_id=record.schema_id,
                                           metadata=record.metadata_,
                                       ))

    if authorized:
        if admin:
            assert_json_record_result(r, r.json(), record)
            assert_db_state(modified_record_batch)
            assert_audit_log('insert', record)
        else:
            assert_not_found(r)
            assert_db_state(record_batch)
            assert_no_audit_log()
    else:
        assert_forbidden(r)
        assert_db_state(record_batch)
        assert_no_audit_log()
def test_update_client(api, client_batch, scopes, collection_auth):
    authorized = ODPScope.CLIENT_ADMIN in scopes and \
                 collection_auth in (CollectionAuth.NONE, CollectionAuth.MATCH)

    if collection_auth == CollectionAuth.MATCH:
        api_client_collection = client_batch[2].collection
    elif collection_auth == CollectionAuth.MISMATCH:
        api_client_collection = client_batch[1].collection
    else:
        api_client_collection = None

    if collection_auth in (CollectionAuth.MATCH, CollectionAuth.MISMATCH):
        modified_client_collection = client_batch[2].collection
    else:
        modified_client_collection = None

    modified_client_batch = client_batch.copy()
    modified_client_batch[2] = (client := client_build(
        id=client_batch[2].id,
        collection=modified_client_collection,
    ))

    r = api(scopes, api_client_collection).put(
        '/client/',
        json=dict(
            id=client.id,
            name=fake.catch_phrase(),
            secret=fake.password(),
            scope_ids=scope_ids(client),
            collection_id=client.collection_id,
            grant_types=[],
            response_types=[],
            redirect_uris=[],
            post_logout_redirect_uris=[],
            token_endpoint_auth_method=TokenEndpointAuthMethod.
            CLIENT_SECRET_BASIC,
            allowed_cors_origins=[],
        ))

    if authorized:
        assert_empty_result(r)
        assert_db_state(modified_client_batch)
    else:
        assert_forbidden(r)
        assert_db_state(client_batch)