def test_scan_upload_and_conversion(prepare_environment: Any, synchronous_celery: Any) -> None:
    """Test application for Scan upload and conversion."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 3}
    response = api_client.post('/api/v1/scans', data=json.dumps(payload),
                               headers=get_headers(token=user_token, json=True))
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']

    # Step 3. Send Slices
    for file in glob.glob('tests/assets/example_scan/*.dcm'):
        with open(file, 'rb') as image:
            response = api_client.post('/api/v1/scans/{}/slices'.format(scan_id), data={
                'image': (image, 'slice_1.dcm'),
            }, headers=get_headers(token=user_token, multipart=True))
            assert response.status_code == 201

    # Step 4. Check Scan & Slices in the databases
    z_slices = SlicesRepository.get_slices_by_scan_id(scan_id)
    assert len(z_slices) == 3
    y_slices = SlicesRepository.get_slices_by_scan_id(scan_id, SliceOrientation.Y)
    assert not y_slices
    x_slices = SlicesRepository.get_slices_by_scan_id(scan_id, SliceOrientation.X)
    assert not x_slices

    # Step 5.1. Slices in Z axis
    z_slice = SlicesRepository.get_slice_converted_image(z_slices[2].id)
    z_slice_image = Image.open(io.BytesIO(z_slice))
    assert z_slice_image.size == (512, 512)
Exemple #2
0
def test_add_point_label(prepare_environment: Any,
                         synchronous_celery: Any) -> None:
    """Test for adding a Label made with Point tool."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.POINT], task.id)

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 3}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']

    # Step 3. Label it with Point Tool
    payload = {
        'elements': [{
            'slice_index': 0,
            'x': 0.25,
            'y': 0.5,
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.POINT.value,
        }],
        'labeling_time':
        12.34,
    }
    data = {
        'label': json.dumps(payload),
    }
    response = api_client.post(
        '/api/v1/scans/{}/MARK_KIDNEYS/label'.format(scan_id),
        data=data,
        headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    label_id = json_response['label_id']
    assert isinstance(label_id, str)
    assert len(label_id) >= 1

    # Step 4. Fetch details about above Label
    response = api_client.get('/api/v1/labels/' + label_id,
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert len(json_response['elements']) == 1
    assert json_response['elements'][0]['x'] == 0.25
    assert json_response['elements'][0]['y'] == 0.5
Exemple #3
0
def test_ownership(prepare_environment: Any, synchronous_celery: Any) -> None:
    """Test for checking scan and label ownership."""
    api_client = get_api_client()

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('LUNGS', 'Lungs')
    task = TasksRepository.add_task('FIND_NODULES', 'Find Nodules', 'path/to/image', ['LUNGS'], '', [], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag', [LabelTool.RECTANGLE], task.id)
    admin_id, _ = create_user(ADMIN_EMAIL, ADMIN_PASSWORD, ADMIN_FIRST_NAME, ADMIN_LAST_NAME)
    set_user_role(admin_id, 'admin')

    # Step 2. Admin user logs in
    payload: Dict[str, Any] = {'email': ADMIN_EMAIL, 'password': ADMIN_PASSWORD}
    response = api_client.post('/api/v1/auth/sign-in', data=json.dumps(payload),
                               headers=get_headers(json=True))
    json_response = json.loads(response.data)
    admin_user_token = json_response['token']
    assert response.status_code == 200

    # Step 3. Add Scan to the system
    payload = {'dataset': 'LUNGS', 'number_of_slices': 1}
    response = api_client.post('/api/v1/scans', data=json.dumps(payload),
                               headers=get_headers(token=admin_user_token, json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    owner_id = json_response['owner_id']
    assert owner_id == admin_id
    scan_id = json_response['scan_id']

    # Step 4. Send slices
    with open('tests/assets/example_scan/slice_1.dcm', 'rb') as image:
        response = api_client.post('/api/v1/scans/{}/slices'.format(scan_id), data={
            'image': (image, 'slice_1.dcm'),
        }, content_type='multipart/form-data', headers=get_headers(token=admin_user_token))
    assert response.status_code == 201

    # Step 5. Label
    payload = {
        'elements': [{
            'x': 0.5,
            'y': 0.5,
            'slice_index': 0,
            'width': 0.1,
            'height': 0.1,
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.RECTANGLE.value,
        }],
        'labeling_time': 12.34,
    }
    response = api_client.post('/api/v1/scans/{}/FIND_NODULES/label'.format(scan_id),
                               data={'label': json.dumps(payload)},
                               headers=get_headers(token=admin_user_token, multipart=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    owner_id = json_response['owner_id']
    assert owner_id == admin_id
def test_add_label_with_tag_from_other_task(prepare_environment: Any,
                                            synchronous_celery: Any) -> None:
    """Test for adding a Label with Tag from other Task."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    left_task = TasksRepository.add_task('MARK_LEFT', 'Mark Left',
                                         'path/to/image', ['KIDNEYS'], '', [],
                                         [])
    right_task = TasksRepository.add_task('MARK_RIGHT', 'Mark Left',
                                          'path/to/image', ['KIDNEYS'], '', [],
                                          [])
    LabelTagsRepository.add_new_tag('TAG_LEFT', 'Tag Left', [LabelTool.POINT],
                                    left_task.id)
    LabelTagsRepository.add_new_tag('TAG_RIGHT', 'Tag Right',
                                    [LabelTool.POINT], right_task.id)

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 3}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']

    # Step 3. Label it with an element with Tag from another Task
    payload = {
        'elements': [{
            'slice_index': 0,
            'x': 0.25,
            'y': 0.5,
            'tag': 'TAG_RIGHT',
            'tool': LabelTool.POINT.value,
        }],
        'labeling_time':
        12.34,
    }
    data = {
        'label': json.dumps(payload),
    }
    response = api_client.post(
        '/api/v1/scans/{}/MARK_LEFT/label'.format(scan_id),
        data=data,
        headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 400
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['message'] == 'Invalid arguments.'
    assert json_response[
        'details'] == 'Tag TAG_RIGHT is not part of Task MARK_LEFT.'
Exemple #5
0
def test_add_task(prepare_environment: Any) -> None:
    """Test application with basic flow."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    DatasetsRepository.add_new_dataset('LUNGS', 'Lungs')

    # Step 2. Add new Task through the REST API
    payload = {
        'key':
        'MARK_NODULES',
        'name':
        'Mark nodules',
        'image_path':
        'assets/icon/my_icon.svg',
        'datasets_keys': ['KIDNEYS', 'LUNGS'],
        'tags': [{
            'key': 'SMALL_NODULE',
            'name': 'Small nodule',
            'tools': ['POINT'],
        }, {
            'key': 'BIG_NODULE',
            'name': 'Big nodule',
            'tools': ['RECTANGLE', 'BRUSH'],
        }],
    }
    response = api_client.post('/api/v1/tasks',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['key'] == 'MARK_NODULES'
    assert json_response['name'] == 'Mark nodules'
    assert json_response['image_path'] == 'assets/icon/my_icon.svg'
    assert len(json_response['tags']) == 2
    assert len(json_response['datasets_keys']) == 2

    # Step 3. Check for available Datasets through the REST API
    response = api_client.get('/api/v1/datasets',
                              headers=get_headers(token=user_token, json=True))
    json_response = json.loads(response.data)
    datasets = [
        dataset for dataset in json_response if any(
            task for task in dataset['tasks'] if task['key'] == 'MARK_NODULES')
    ]
    assert len(datasets) == 2
Exemple #6
0
def test_add_chain_label_not_enough_points(prepare_environment: Any,
                                           synchronous_celery: Any) -> None:
    """Test for adding a Label made with Chain tool."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.CHAIN], task.id)

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 3}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']

    # Step 3. Label it with Chain Tool
    payload = {
        'elements': [{
            'slice_index': 0,
            'points': [
                {
                    'x': 0.2,
                    'y': 0.3,
                },
            ],
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.CHAIN.value,
            'loop': False,
        }],
        'labeling_time':
        12.34,
    }
    data = {
        'label': json.dumps(payload),
    }
    response = api_client.post(
        '/api/v1/scans/{}/MARK_KIDNEYS/label'.format(scan_id),
        data=data,
        headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 400
Exemple #7
0
def test_get_predefined_label_for_scan_in_task__predefined_label(
        prepare_environment: Any) -> None:
    """Test for fetching Predefined Label that exists."""
    # Step 1. Prepare a structure for the test
    dataset = DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.RECTANGLE], task.id)
    scan = ScansRepository.add_new_scan(dataset, 0)
    user_id = UsersRepository.add_new_user(
        User('user@medtagger', 'HASH', 'Admin', 'Admin'))
    user = UsersRepository.get_user_by_id(user_id)

    # Step 2. Add Label which is predefined
    label = LabelsRepository.add_new_label(scan.id,
                                           task.key,
                                           user,
                                           LabelingTime(0),
                                           is_predefined=True)

    # Step 3. Check if there is is Predefined Label
    predefined_label = LabelsRepository.get_predefined_label_for_scan_in_task(
        scan, task)
    assert predefined_label
    assert predefined_label.id == label.id
Exemple #8
0
def test_get_paginated_scans_with_invalid_arguments(
        prepare_environment: Any) -> None:
    """Test for fetching Scans in the paginated way with invalid arguments."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    dataset = DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')

    # Step 2. Add example Scans to the system
    for _ in range(50):
        ScansRepository.add_new_scan(dataset, number_of_slices=3)

    # Step 3. Fetch them with MedTagger REST API in the wrong way
    response = api_client.get('/api/v1/scans?dataset_key=KIDNEYS&page=-1',
                              headers=get_headers(token=user_token))
    assert response.status_code == 400
    json_response = json.loads(response.data)
    assert json_response['message'] == 'Invalid arguments.'
    assert json_response['details'] == 'Page cannot be smaller than 1.'

    # Step 4. Make a mistake again
    response = api_client.get(
        '/api/v1/scans?dataset_key=KIDNEYS&per_page=5000',
        headers=get_headers(token=user_token))
    assert response.status_code == 400
    json_response = json.loads(response.data)
    assert json_response['message'] == 'Invalid arguments.'
    assert json_response[
        'details'] == 'Cannot fetch more than 100 entries at once.'
Exemple #9
0
def test_get_paginated_scans(prepare_environment: Any) -> None:
    """Test for fetching Scans in the paginated way."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    dataset = DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')

    # Step 2. Add example Scans to the system
    for _ in range(50):
        ScansRepository.add_new_scan(dataset, number_of_slices=3)

    # Step 3. Fetch them with MedTagger REST API
    response = api_client.get('/api/v1/scans?dataset_key=KIDNEYS',
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert json_response['pagination']['page'] == 1
    assert json_response['pagination']['per_page'] == 25
    assert json_response['pagination']['total'] == 50
    assert len(json_response['scans']) == 25

    # Step 4. Fetch the next page with different size
    response = api_client.get(
        '/api/v1/scans?dataset_key=KIDNEYS&page=2&per_page=10',
        headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert json_response['pagination']['page'] == 2
    assert json_response['pagination']['per_page'] == 10
    assert json_response['pagination']['total'] == 50
    assert len(json_response['scans']) == 10
Exemple #10
0
def test_get_predefined_brush_label_elements(prepare_environment: Any) -> None:
    """Test for fetching Predefined Brush Label Elements."""
    # Step 1. Prepare a structure for the test
    dataset = DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    label_tag = LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                                [LabelTool.RECTANGLE], task.id)
    scan = ScansRepository.add_new_scan(dataset, 3)
    user_id = UsersRepository.add_new_user(
        User('user@medtagger', 'HASH', 'Admin', 'Admin'))
    user = UsersRepository.get_user_by_id(user_id)

    # Step 2. Add Label with Brush Elements
    label = LabelsRepository.add_new_label(scan.id,
                                           task.key,
                                           user,
                                           LabelingTime(0),
                                           is_predefined=True)
    LabelsRepository.add_new_brush_label_element(label.id, 0, 0, 0, b'',
                                                 label_tag)
    LabelsRepository.add_new_brush_label_element(label.id, 1, 0, 0, b'',
                                                 label_tag)
    LabelsRepository.add_new_brush_label_element(label.id, 2, 0, 0, b'',
                                                 label_tag)

    # Step 3. Check if there is is Predefined Label
    brush_label_elements = LabelsRepository.get_predefined_brush_label_elements(
        scan.id, task.id, 0, 3)
    assert len(brush_label_elements) == 3
    brush_label_elements = LabelsRepository.get_predefined_brush_label_elements(
        scan.id, task.id, 0, 1)
    assert len(brush_label_elements) == 1
Exemple #11
0
def create_dataset(key: str, name: str) -> Dataset:
    """Create new Dataset.

    :param key: unique key representing Dataset
    :param name: name which describes this Dataset
    :return: Dataset object
    """
    return DatasetsRepository.add_new_dataset(key, name)
def test_add_label_non_existing_tag(prepare_environment: Any) -> None:
    """Test application for situation when users provides non existing tag."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], '', [], [])
    LabelTagsRepository.add_new_tag('LEFT_KIDNEY', 'Left Kidney',
                                    [LabelTool.RECTANGLE], task.id)

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 3}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']

    # Step 3. Create label
    payload = {
        'elements': [{
            'x': 0.5,
            'y': 0.5,
            'slice_index': 0,
            'width': 0.1,
            'height': 0.1,
            'tag': 'NON_EXISTING',
            'tool': LabelTool.RECTANGLE.value,
        }],
        'labeling_time':
        12.34,
    }
    response = api_client.post(
        '/api/v1/scans/{}/MARK_KIDNEYS/label'.format(scan_id),
        data={'label': json.dumps(payload)},
        headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 400
    json_response = json.loads(response.data)
    assert json_response[
        'details'] == 'Tag NON_EXISTING is not part of Task MARK_KIDNEYS.'
def test_delete_scan_without_slices(prepare_environment: Any,
                                    synchronous_celery: Any) -> None:
    """Test deleting scan without any slices."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.RECTANGLE], task.id)

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 0}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    scan_id: ScanID = json_response['scan_id']
    assert isinstance(scan_id, str)
    assert len(scan_id) >= 1

    # Step 3. Get scan
    response = api_client.get('/api/v1/scans/{}'.format(scan_id),
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['scan_id'] == scan_id
    assert json_response['number_of_slices'] == 0

    # Step 4. Delete scan from the system
    ScansRepository.delete_scan_by_id(scan_id)

    # Step 5. Check that scan has been deleted
    response = api_client.get('/api/v1/scans/{}'.format(scan_id),
                              headers=get_headers(token=user_token))
    assert response.status_code == 404
Exemple #14
0
def prepare_scan_and_tag_for_labeling() -> Tuple[models.Scan, models.LabelTag]:
    """Create needed Scan and Label Tag for labeling purpose."""
    dataset = DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    label_tag = LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                                [definitions.LabelTool.POINT],
                                                task.id)
    scan = ScansRepository.add_new_scan(dataset, number_of_slices=3)
    for _ in range(3):
        scan.add_slice()
    return scan, label_tag
def test_scan_upload_with_retrying(fixture_problems_with_storage: Any, prepare_environment: Any,
                                   synchronous_celery: Any) -> None:
    """Test application for Scan upload with retrying."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 3}
    response = api_client.post('/api/v1/scans', data=json.dumps(payload),
                               headers=get_headers(token=user_token, json=True))
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']

    # Step 3. Send Slices
    for file in glob.glob('tests/assets/example_scan/*.dcm'):
        with open(file, 'rb') as image:
            # First request to the API will fail with unknown error due to Storage issues
            fixture_problems_with_storage.side_effect = WriteTimeout('Internal Storage Error', write_type=0)
            response = api_client.post('/api/v1/scans/{}/slices'.format(scan_id), data={
                'image': (image, 'slice_1.dcm'),
            }, headers=get_headers(token=user_token, multipart=True))
            assert response.status_code == 500

            # After such error, UI will retry the request (this time it will be fine...)
            # As request will close the image file, we've got to open it again
            with open(file, 'rb') as image:
                fixture_problems_with_storage.side_effect = None
                response = api_client.post('/api/v1/scans/{}/slices'.format(scan_id), data={
                    'image': (image, 'slice_1.dcm'),
                }, headers=get_headers(token=user_token, multipart=True))
                assert response.status_code == 201

    # Step 4. Check number of Slices in the databases
    z_slices = SlicesRepository.get_slices_by_scan_id(scan_id)
    assert len(z_slices) == 3
Exemple #16
0
def test_skipping_a_scan(prepare_environment: Any,
                         synchronous_celery: Any) -> None:
    """Test for skipping a scan."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 3}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']

    # Step 3. Skip Scan
    response = api_client.post('/api/v1/scans/' + scan_id + '/skip',
                               headers=get_headers(token=user_token))
    assert response.status_code == 200
Exemple #17
0
def test_get_predefined_label_for_scan_in_task__no_predefined_label(
        prepare_environment: Any) -> None:
    """Test for fetching Predefined Label that does not exist."""
    # Step 1. Prepare a structure for the test
    dataset = DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.RECTANGLE], task.id)
    scan = ScansRepository.add_new_scan(dataset, 0)

    # Step 2. Check if there is no Predefined Label
    predefined_label = LabelsRepository.get_predefined_label_for_scan_in_task(
        scan, task)
    assert not predefined_label
def _sync_datasets(configuration: Dict) -> None:
    """Synchronize Datasets from configuration file with database entries.

    Example DataSets in the configuration file:
    ```
    datasets:
      - name: Kidneys
        key: KIDNEYS
        tasks:
          - KIDNEYS_SEGMENTATION
    ```

    :param configuration: content of YAML configuration file
    """
    datasets = configuration.get('datasets', []) or []
    configuration_datasets_keys = {dataset['key'] for dataset in datasets}
    database_datasets_keys = {dataset.key for dataset in DatasetsRepository.get_all_datasets(include_disabled=True)}

    datasets_to_add = configuration_datasets_keys - database_datasets_keys
    datasets_to_disable = database_datasets_keys - configuration_datasets_keys
    datasets_to_enable = database_datasets_keys & configuration_datasets_keys

    for dataset_key in datasets_to_add:
        dataset = next(dataset for dataset in datasets if dataset['key'] == dataset_key)
        DatasetsRepository.add_new_dataset(dataset['key'], dataset['name'])
        logger.info('New DataSet added: %s', dataset['key'])

    for dataset_key in datasets_to_enable:
        dataset = next(dataset for dataset in datasets if dataset['key'] == dataset_key)
        DatasetsRepository.enable(dataset['key'])
        DatasetsRepository.update(dataset['key'], dataset['name'])
        logger.info('DataSet enabled: %s', dataset['key'])

    for dataset_key in datasets_to_disable:
        DatasetsRepository.disable(dataset_key)
        logger.info('DataSet disabled: %s', dataset_key)
Exemple #19
0
def test_get_paginated_scans_by_volunteer(prepare_environment: Any) -> None:
    """Test for fetching Scans in the paginated way by volunteers."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('volunteer')

    # Step 1. Prepare a structure for the test
    dataset = DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')

    # Step 2. Add example Scans to the system
    for _ in range(50):
        ScansRepository.add_new_scan(dataset, number_of_slices=3)

    # Step 3. Fetch them with MedTagger REST API
    response = api_client.get('/api/v1/scans?dataset_key=KIDNEYS',
                              headers=get_headers(token=user_token))
    assert response.status_code == 403
    json_response = json.loads(response.data)
    assert json_response['message'] == 'Access forbidden'
    assert json_response[
        'details'] == 'You don\'t have required roles to access this method.'
def test_get_predefined_label_for_scan_in_task__predefined_label_for_given_task(
        prepare_environment: Any) -> None:
    """Test for fetching Predefined Label only for specific Task."""
    # Step 1. Prepare a structure for the test
    dataset = DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task_left = TasksRepository.add_task('MARK_LEFT', 'Mark Left',
                                         'path/to/image', ['KIDNEYS'], '', [],
                                         [])
    task_right = TasksRepository.add_task('MARK_RIGHT', 'Mark Right',
                                          'path/to/image', ['KIDNEYS'], '', [],
                                          [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.RECTANGLE], task_left.id)
    scan = ScansRepository.add_new_scan(dataset, 0)
    user_id = UsersRepository.add_new_user(
        User('user@medtagger', 'HASH', 'Admin', 'Admin'))
    user = UsersRepository.get_user_by_id(user_id)

    # Step 2. Add Labels for each Task
    label_left = LabelsRepository.add_new_label(scan.id,
                                                task_left.key,
                                                user,
                                                LabelingTime(0),
                                                is_predefined=True)
    label_right = LabelsRepository.add_new_label(scan.id,
                                                 task_right.key,
                                                 user,
                                                 LabelingTime(0),
                                                 is_predefined=True)

    # Step 3. Check if there are these Predefined Labels
    predefined_label = LabelsRepository.get_predefined_label_for_scan_in_task(
        scan, task_left)
    assert predefined_label
    assert predefined_label.id == label_left.id
    predefined_label = LabelsRepository.get_predefined_label_for_scan_in_task(
        scan, task_right)
    assert predefined_label
    assert predefined_label.id == label_right.id
Exemple #21
0
def test_add_task(prepare_environment: Any, synchronous_celery: Any) -> None:
    """Test application with basic flow."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    DatasetsRepository.add_new_dataset('LUNGS', 'Lungs')

    # Step 2. Add new Task through the REST API
    payload = {
        'key':
        'MARK_NODULES',
        'name':
        'Mark nodules',
        'description':
        'This task will focus on tagging nodules.',
        'label_examples':
        ['assets/labels/label_1.png', 'assets/labels/label_2.png'],
        'image_path':
        'assets/icon/my_icon.svg',
        'datasets_keys': ['KIDNEYS', 'LUNGS'],
        'tags': [{
            'key': 'SMALL_NODULE',
            'name': 'Small nodule',
            'tools': ['POINT'],
        }, {
            'key': 'BIG_NODULE',
            'name': 'Big nodule',
            'tools': ['RECTANGLE', 'BRUSH'],
        }],
    }
    response = api_client.post('/api/v1/tasks',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['key'] == 'MARK_NODULES'
    assert json_response['name'] == 'Mark nodules'
    assert json_response['image_path'] == 'assets/icon/my_icon.svg'
    assert json_response['number_of_available_scans'] == 0
    assert len(json_response['label_examples']) == 2
    assert json_response[
        'description'] == 'This task will focus on tagging nodules.'
    assert len(json_response['tags']) == 2
    assert len(json_response['datasets_keys']) == 2

    # Step 3. Check for available Datasets through the REST API
    response = api_client.get('/api/v1/datasets',
                              headers=get_headers(token=user_token, json=True))
    json_response = json.loads(response.data)
    datasets = [
        dataset for dataset in json_response if any(
            task for task in dataset['tasks'] if task['key'] == 'MARK_NODULES')
    ]
    assert len(datasets) == 2

    # Step 4. Add Scans to datasets
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 1}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']
    payload = {'dataset': 'LUNGS', 'number_of_slices': 1}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201

    # Step 3. Send Slices
    for file in glob.glob('tests/assets/example_scan/*.dcm'):
        with open(file, 'rb') as image:
            response = api_client.post(
                '/api/v1/scans/{}/slices'.format(scan_id),
                data={
                    'image': (image, 'slice_1.dcm'),
                },
                headers=get_headers(token=user_token, multipart=True))
            assert response.status_code == 201

    # Step 4. Check for Task metadata through the REST API
    response = api_client.get('/api/v1/tasks/MARK_NODULES',
                              headers=get_headers(token=user_token, json=True))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['key'] == 'MARK_NODULES'
    assert json_response['name'] == 'Mark nodules'
    assert json_response['number_of_available_scans'] == 1
    assert len(json_response['label_examples']) == 2
    assert json_response[
        'description'] == 'This task will focus on tagging nodules.'
def test_basic_flow_with_predefined_label(prepare_environment: Any,
                                          synchronous_celery: Any) -> None:
    """Test application with basic flow that uses Predefined Label in Scan."""
    api_client = get_api_client()
    web_socket_client = get_web_socket_client(namespace='/slices')
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.RECTANGLE, LabelTool.BRUSH],
                                    task.id)

    # Step 2. Get all datasets
    response = api_client.get('/api/v1/datasets',
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, list)
    dataset = json_response[0]
    dataset_key = dataset['key']
    task_key = dataset['tasks'][0]['key']

    # Step 3. Add Scan to the system
    payload = {'dataset': dataset_key, 'number_of_slices': 1}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    scan_id = json_response['scan_id']

    # Step 4. Send slices
    with open('tests/assets/example_scan/slice_1.dcm', 'rb') as image:
        response = api_client.post('/api/v1/scans/{}/slices'.format(scan_id),
                                   data={
                                       'image': (image, 'slice_1.dcm'),
                                   },
                                   content_type='multipart/form-data',
                                   headers=get_headers(token=user_token))
    assert response.status_code == 201

    # Step 5. Send Predefined Label
    payload = {
        'elements': [{
            'x': 0.5,
            'y': 0.5,
            'slice_index': 0,
            'width': 0.1,
            'height': 0.1,
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.RECTANGLE.value,
        }, {
            'slice_index': 0,
            'width': 128,
            'height': 128,
            'image_key': 'SLICE_1',
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.BRUSH.value,
        }],
        'labeling_time':
        None,
    }
    with open('tests/assets/example_labels/binary_mask.png', 'rb') as image:
        data = {
            'label': json.dumps(payload),
            'SLICE_1': (image, 'slice_1'),
        }
        response = api_client.post(
            '/api/v1/scans/{}/MARK_KIDNEYS/label?is_predefined=true'.format(
                scan_id),
            data=data,
            headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    predefined_label_id = json_response['label_id']
    assert type(predefined_label_id), str
    assert predefined_label_id

    # Step 6. Get random scan
    response = api_client.get('/api/v1/scans/random?task={}'.format(task_key),
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['scan_id'] == scan_id
    assert json_response['number_of_slices'] == 1
    assert json_response['width'] == 512
    assert json_response['height'] == 512
    assert json_response['predefined_label_id'] == predefined_label_id

    # Step 7. Get slices from the server
    payload = {
        'scan_id': scan_id,
        'task_key': task_key,
        'begin': 0,
        'count': 1
    }
    web_socket_client.emit('request_slices', payload, namespace='/slices')
    responses = web_socket_client.get_received(namespace='/slices')
    assert len(responses) == 2
    slice_response = next(response for response in responses
                          if response['name'] == 'slice')
    assert slice_response['args'][0]['scan_id'] == scan_id
    assert slice_response['args'][0]['index'] == 0
    assert isinstance(slice_response['args'][0]['image'], bytes)
    brush_label_response = next(response for response in responses
                                if response['name'] == 'brush_labels')
    assert brush_label_response['args'][0]['scan_id'] == scan_id
    assert brush_label_response['args'][0]['tag_key'] == 'EXAMPLE_TAG'
    assert brush_label_response['args'][0]['index'] == 0
    assert isinstance(brush_label_response['args'][0]['image'], bytes)

    # Step 8. Label it
    payload = {
        'elements': [{
            'x': 0.5,
            'y': 0.5,
            'slice_index': 0,
            'width': 0.1,
            'height': 0.1,
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.RECTANGLE.value,
        }],
        'labeling_time':
        12.34,
    }
    response = api_client.post(
        '/api/v1/scans/{}/MARK_KIDNEYS/label'.format(scan_id),
        data={'label': json.dumps(payload)},
        headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    label_id = json_response['label_id']
    assert isinstance(label_id, str)
    assert len(label_id) >= 1

    # Step 9. Get random label for validation
    response = api_client.get('/api/v1/labels/random',
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['label_id'] == label_id
def test_adding_new_survey(prepare_environment: Any) -> None:
    """Test for adding new Survey and fetching it through API."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('volunteer')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    label_tag = LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                                [LabelTool.RECTANGLE], task.id)

    # Step 2. Add an example of Survey
    survey = Survey(name='Colors Survey',
                    initial_element_key=SurveyElementKey('FIRST_QUESTION'))
    survey.elements = [
        SurveySingleChoiceQuestion(
            key=SurveyElementKey('FIRST_QUESTION'),
            title='What is your favourite color?',
            possible_answers={
                'Red': SurveyElementKey('SECOND_QUESTION'),
                'Green': None,
                'Blue': None,
            },
        ),
        SurveySingleChoiceQuestion(
            key=SurveyElementKey('SECOND_QUESTION'),
            title='Why do you like Red?',
            possible_answers={
                'It is nice': None,
                'Love it': None,
                'I do not know': None,
            },
        ),
    ]
    label_tag.actions.append(survey)
    label_tag.save()

    # Step 3.1 Check if it's available through API
    response = api_client.get('/api/v1/labels/actions/1',
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert set(json_response) == {'action_id', 'action_type', 'details'}
    assert json_response['action_id'] == 1
    assert json_response['action_type'] == 'Survey'
    assert isinstance(json_response['details'], dict)

    # Step 3.2. Make sure that Survey details have all necessary fields
    assert set(json_response['details']) == {
        'name', 'initial_element_key', 'elements'
    }
    assert json_response['details']['name'] == 'Colors Survey'
    assert json_response['details']['initial_element_key'] == 'FIRST_QUESTION'
    assert isinstance(json_response['details']['elements'], list)

    # Step 3.3. Check what elements does this Survey contain
    all_elements = json_response['details']['elements']
    assert len(all_elements) == 2
    all_element_keys = {element['key'] for element in all_elements}
    assert all_element_keys == {'FIRST_QUESTION', 'SECOND_QUESTION'}

    # Step 3.4. Check what does first question has inside
    first_question = next(element for element in all_elements
                          if element['key'] == 'FIRST_QUESTION')
    assert first_question == {
        'key': 'FIRST_QUESTION',
        'instant_next_element': None,
        'type': 'SurveySingleChoiceQuestion',
        'title': 'What is your favourite color?',
        'possible_answers': {
            'Red': 'SECOND_QUESTION',
            'Green': None,
            'Blue': None,
        },
    }

    # Step 3.5. Check what second question has inside
    first_question = next(element for element in all_elements
                          if element['key'] == 'SECOND_QUESTION')
    assert first_question == {
        'key': 'SECOND_QUESTION',
        'instant_next_element': None,
        'type': 'SurveySingleChoiceQuestion',
        'title': 'Why do you like Red?',
        'possible_answers': {
            'It is nice': None,
            'Love it': None,
            'I do not know': None,
        },
    }

    # Step 4. Check if we can fetch any unavailable Action through API
    response = api_client.get('/api/v1/labels/actions/2',
                              headers=get_headers(token=user_token))
    assert response.status_code == 404
    json_response = json.loads(response.data)
    assert json_response == {
        'message': 'Requested object does not exist.',
        'details': 'Action "2" not found.',
    }

    # Step 5. Check if above Action is available from Task endpoint
    response = api_client.get('/api/v1/tasks',
                              headers=get_headers(token=user_token))
    json_response = json.loads(response.data)
    mark_kidneys_task = next(task for task in json_response
                             if task['key'] == 'MARK_KIDNEYS')
    example_tag = next(tag for tag in mark_kidneys_task['tags']
                       if tag['key'] == 'EXAMPLE_TAG')
    assert example_tag['actions_ids'] == [1]
Exemple #24
0
def test_add_brush_label(prepare_environment: Any,
                         synchronous_celery: Any) -> None:
    """Test for adding a Label made with Brush tool."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.BRUSH], task.id)

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 3}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    scan_id = json_response['scan_id']

    # Step 3. Label it with Brush
    payload = {
        'elements': [{
            'slice_index': 0,
            'width': 128,
            'height': 128,
            'image_key': 'SLICE_1',
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.BRUSH.value,
        }],
        'labeling_time':
        12.34,
        'task_id':
        TasksRepository.get_task_by_key('MARK_KIDNEYS').id,
    }
    with open('tests/assets/example_labels/binary_mask.png', 'rb') as image:
        data = {
            'label': json.dumps(payload),
            'SLICE_1': (image, 'slice_1'),
        }
        response = api_client.post(
            '/api/v1/scans/{}/MARK_KIDNEYS/label'.format(scan_id),
            data=data,
            headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    label_id = json_response['label_id']
    assert isinstance(label_id, str)
    assert len(label_id) >= 1

    # Step 4. Fetch details about above Label and check image storage
    response = api_client.get('/api/v1/labels/' + label_id,
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    label_element_id = json_response['elements'][0]['label_element_id']
    brush_label_element = BrushLabelElement.get(id=label_element_id)
    assert brush_label_element.image
def test_delete_scan_with_slices(prepare_environment: Any,
                                 synchronous_celery: Any) -> None:
    """Test deleting scan with at least 1 slice."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag',
                                    [LabelTool.RECTANGLE], task.id)

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 1}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    scan_id: ScanID = json_response['scan_id']
    assert isinstance(scan_id, str)
    assert len(scan_id) >= 1

    # Step 3. Send slices
    with open('tests/assets/example_scan/slice_1.dcm', 'rb') as image:
        response = api_client.post('/api/v1/scans/{}/slices'.format(scan_id),
                                   data={
                                       'image': (image, 'slice_1.dcm'),
                                   },
                                   content_type='multipart/form-data',
                                   headers=get_headers(token=user_token))
        assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    slice_id: SliceID = json_response['slice_id']
    assert isinstance(slice_id, str)
    assert len(slice_id) >= 1

    # Step 4. Get scan
    response = api_client.get('/api/v1/scans/{}'.format(scan_id),
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['scan_id'] == scan_id
    assert json_response['number_of_slices'] == 1
    assert json_response['width'] == 512
    assert json_response['height'] == 512

    # Step 5. Delete scan from the system
    ScansRepository.delete_scan_by_id(scan_id)

    # Step 6. Check that scan has been deleted
    response = api_client.get('/api/v1/scans/{}'.format(scan_id),
                              headers=get_headers(token=user_token))
    assert response.status_code == 404

    # Step 7. Check that slices has been deleted
    with pytest.raises(NoResultFound):
        SliceRepository.get_slice_by_id(slice_id)
def test_delete_scan_with_labels(prepare_environment: Any,
                                 synchronous_celery: Any) -> None:
    """Test deleting scan with at least 1 slice and with labels made with all tools."""
    api_client = get_api_client()
    web_socket_client = get_web_socket_client(namespace='/slices')
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Prepare a structure for the test
    DatasetsRepository.add_new_dataset('KIDNEYS', 'Kidneys')
    task = TasksRepository.add_task('MARK_KIDNEYS', 'Mark Kidneys',
                                    'path/to/image', ['KIDNEYS'], [])
    LabelTagsRepository.add_new_tag('EXAMPLE_TAG', 'Example Tag', [
        LabelTool.RECTANGLE, LabelTool.CHAIN, LabelTool.POINT, LabelTool.BRUSH
    ], task.id)

    # Step 2. Add Scan to the system
    payload = {'dataset': 'KIDNEYS', 'number_of_slices': 1}
    response = api_client.post('/api/v1/scans',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    scan_id: ScanID = json_response['scan_id']
    assert isinstance(scan_id, str)
    assert len(scan_id) >= 1

    # Step 3. Send slices
    with open('tests/assets/example_scan/slice_1.dcm', 'rb') as image:
        response = api_client.post('/api/v1/scans/{}/slices'.format(scan_id),
                                   data={
                                       'image': (image, 'slice_1.dcm'),
                                   },
                                   content_type='multipart/form-data',
                                   headers=get_headers(token=user_token))
        assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    slice_id: SliceID = json_response['slice_id']
    assert isinstance(slice_id, str)
    assert len(slice_id) >= 1

    # Step 4. Get scan
    response = api_client.get('/api/v1/scans/{}'.format(scan_id),
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['scan_id'] == scan_id
    assert json_response['number_of_slices'] == 1
    assert json_response['width'] == 512
    assert json_response['height'] == 512

    # Step 5. Get slices from the server
    payload = {
        'scan_id': scan_id,
        'task_key': 'MARK_KIDNEYS',
        'begin': 0,
        'count': 1
    }
    web_socket_client.emit('request_slices', payload, namespace='/slices')
    responses = web_socket_client.get_received(namespace='/slices')
    assert len(responses) == 1
    response = responses[0]
    assert response['name'] == 'slice'
    assert response['args'][0]['scan_id'] == scan_id
    assert response['args'][0]['index'] == 0
    assert isinstance(response['args'][0]['image'], bytes)

    # Step 6. Label it with all available tools
    payload = {
        'elements': [{
            'x': 0.5,
            'y': 0.5,
            'slice_index': 0,
            'width': 0.1,
            'height': 0.1,
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.RECTANGLE.value,
        }, {
            'slice_index': 0,
            'width': 128,
            'height': 128,
            'image_key': 'SLICE_1',
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.BRUSH.value,
        }, {
            'slice_index': 0,
            'x': 0.25,
            'y': 0.5,
            'tag': 'EXAMPLE_TAG',
            'tool': LabelTool.POINT.value,
        }, {
            'slice_index':
            0,
            'points': [
                {
                    'x': 0.2,
                    'y': 0.3,
                },
                {
                    'x': 0.5,
                    'y': 0.8,
                },
            ],
            'tag':
            'EXAMPLE_TAG',
            'tool':
            LabelTool.CHAIN.value,
            'loop':
            False,
        }],
        'labeling_time':
        12.34,
    }
    with open('tests/assets/example_labels/binary_mask.png', 'rb') as image:
        data = {
            'label': json.dumps(payload),
            'SLICE_1': (image, 'slice_1'),
        }
        response = api_client.post(
            '/api/v1/scans/{}/MARK_KIDNEYS/label'.format(scan_id),
            data=data,
            headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    label_id = json_response['label_id']
    assert isinstance(label_id, str)
    assert len(label_id) >= 1

    # Step 7. Fetch details about above Label and check image storage
    response = api_client.get('/api/v1/labels/' + label_id,
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    label_element_id = json_response['elements'][1]['label_element_id']
    brush_label_element = BrushLabelElement.get(id=label_element_id)
    assert brush_label_element.image

    # Step 7. Delete scan from the system
    ScansRepository.delete_scan_by_id(scan_id)

    # Step 8. Check that scan has been deleted
    response = api_client.get('/api/v1/scans/{}'.format(scan_id),
                              headers=get_headers(token=user_token))
    assert response.status_code == 404

    # Step 9. Check that slices has been deleted
    with pytest.raises(NoResultFound):
        SliceRepository.get_slice_by_id(slice_id)

    # Step 10. Check that slices original image has been deleted from storage
    with pytest.raises(DoesNotExist):
        OriginalSlice.get(id=slice_id)

    # Step 11. Check that slices processed image has been deleted from storage
    with pytest.raises(DoesNotExist):
        ProcessedSlice.get(id=slice_id)

    # Step 12. Check that labels has been deleted
    response = api_client.get('/api/v1/labels/{}'.format(label_id),
                              headers=get_headers(token=user_token))
    assert response.status_code == 404

    # Step 13. Check that Brush Label was deleted from storage
    with pytest.raises(DoesNotExist):
        BrushLabelElement.get(id=label_element_id)