예제 #1
0
def test_add_label_missing_tag(prepare_environment: Any) -> None:
    """Test application for situation when users does not provide tag."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')

    # Step 1. Add Scan to the system
    payload = {'category': '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 2. Create label
    payload = {
        'elements': [{
            'x': 0.5,
            'y': 0.5,
            'slice_index': 0,
            'width': 0.1,
            'height': 0.1,
            'tool': LabelTool.RECTANGLE.value,
        }],
        'labeling_time': 12.34,
    }
    response = api_client.post('/api/v1/scans/{}/label'.format(scan_id), data={'label': json.dumps(payload)},
                               headers=get_headers(token=user_token, multipart=True))
    assert response.status_code == 400
예제 #2
0
def test_adding_new_response_for_survey(prepare_environment: Any) -> None:
    """Test for adding new Response for Survey."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('volunteer')

    # Step 1. 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,
            },
        ),
    ]
    survey.save()

    # Step 2. Check if user can post a Response through API
    payload = {'FIRST_QUESTION': 'Red', 'SECOND_QUESTION': 'Love it'}
    response = api_client.post('/api/v1/labels/actions/1',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert json_response == {
        'action_id': 1,
        'action_type': 'Survey',
        'response_id': 1,
        'details': {
            'FIRST_QUESTION': 'Red',
            'SECOND_QUESTION': 'Love it',
        },
    }

    # Step 3. Check if user can post invalid Response (keys that were not in Survey)
    payload = {'FIRST_QUESTION': 'Red', 'THIRD_QUESTION': 'I am a hacker!'}
    response = api_client.post('/api/v1/labels/actions/1',
                               data=json.dumps(payload),
                               headers=get_headers(token=user_token,
                                                   json=True))
    assert response.status_code == 400
    json_response = json.loads(response.data)
    assert json_response == {
        'message': 'Invalid arguments.',
        'details': 'Your answers does not match keys in Survey.',
    }
예제 #3
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
예제 #4
0
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)
예제 #5
0
def test_basic_user_flow(prepare_environment: Any) -> None:
    """Test for basic user flow."""
    api_client = get_api_client()

    # Step 1. User creates an account
    payload = {
        'email': EXAMPLE_USER_EMAIL,
        'password': EXAMPLE_USER_PASSWORD,
        'firstName': EXAMPLE_USER_FIRST_NAME,
        'lastName': EXAMPLE_USER_LAST_NAME
    }
    response = api_client.post('/api/v1/auth/register',
                               data=json.dumps(payload),
                               headers=get_headers(json=True))
    assert response.status_code == 201
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    user_token = json_response['token']
    assert isinstance(user_token, str)
    assert len(user_token) > 100

    # Step 3. Get user account information
    response = api_client.get('/api/v1/users/info',
                              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['id'] > 0
    assert json_response['email'] == EXAMPLE_USER_EMAIL
    assert json_response['firstName'] == EXAMPLE_USER_FIRST_NAME
    assert json_response['lastName'] == EXAMPLE_USER_LAST_NAME
    assert json_response['role'] == 'volunteer'
예제 #6
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.'
예제 #7
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
예제 #8
0
def test_upgrade_to_doctor_role(prepare_environment: Any) -> None:
    """Test for upgrading volunteer's to doctor's role."""
    api_client = get_api_client()

    admin_id, _ = create_user(ADMIN_EMAIL, ADMIN_PASSWORD, ADMIN_FIRST_NAME,
                              ADMIN_LAST_NAME)
    volunteer_id, _ = create_user(EXAMPLE_USER_EMAIL, EXAMPLE_USER_PASSWORD,
                                  EXAMPLE_USER_FIRST_NAME,
                                  EXAMPLE_USER_LAST_NAME)

    set_user_role(admin_id, 'admin')
    set_user_role(volunteer_id, 'volunteer')

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

    # Step 2. Admin gets all users
    response = api_client.get('/api/v1/users',
                              headers=get_headers(token=admin_user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    users = json_response['users']
    assert len(users) == 2

    # Step 3. Admin changes role for user
    payload = {'role': 'doctor'}
    response = api_client.put('/api/v1/users/{}/role'.format(volunteer_id),
                              data=json.dumps(payload),
                              headers=get_headers(token=admin_user_token,
                                                  json=True))
    assert response.status_code == 200

    # Step 4. User logs in
    payload = {'email': EXAMPLE_USER_EMAIL, 'password': EXAMPLE_USER_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)
    user_token = json_response['token']
    assert response.status_code == 200

    # Step 5. Check if user role was changed
    response = api_client.get('/api/v1/users/info',
                              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['role'] == 'doctor'
예제 #9
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
예제 #10
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. Add Scan to the system
    payload = {'category': '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 2. Label it with Brush
    create_tag_and_assign_to_category('EXAMPLE_TAG', 'Example tag', 'KIDNEYS')
    payload = {
        'elements': [{
            'slice_index': 0,
            'width': 128,
            'height': 128,
            'image_key': 'SLICE_1',
            'tag': 'EXAMPLE_TAG',
            'tool': 'BRUSH',
        }],
        '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/{}/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 3. 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
예제 #11
0
def test_skipping_a_scan_that_doesnt_exist(prepare_environment: Any,
                                           synchronous_celery: Any) -> None:
    """Test for trying to skip a scan that doesn't exist."""
    api_client = get_api_client()
    user_token = get_token_for_logged_in_user('admin')
    scan_id = 'EXAMPLE_SCAN_ID'

    # Step 1. Try to skip Scan.
    response = api_client.post('/api/v1/scans/' + scan_id + '/skip',
                               headers=get_headers(token=user_token))
    assert response.status_code == 404
예제 #12
0
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.'
예제 #13
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
예제 #14
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
예제 #15
0
def test_do_not_show_tutorial_again(prepare_environment: Any) -> None:
    """If user ends tutorial with "Do not show this tutorial again" checked, the user should not see tutorial again."""
    api_client = get_api_client()

    # Step 1. User creates an account
    payload: Dict[str, Any] = {
        'email': EXAMPLE_USER_EMAIL,
        'password': EXAMPLE_USER_PASSWORD,
        'firstName': EXAMPLE_USER_FIRST_NAME,
        'lastName': EXAMPLE_USER_LAST_NAME
    }
    api_client.post('/api/v1/auth/register',
                    data=json.dumps(payload),
                    headers=get_headers(json=True))

    # Step 2. User logs in
    payload = {'email': EXAMPLE_USER_EMAIL, 'password': EXAMPLE_USER_PASSWORD}
    response = api_client.post('/api/v1/auth/sign-in',
                               data=json.dumps(payload),
                               headers=get_headers(json=True))
    user_token = json.loads(response.data)['token']

    # Step 3. Assure that parameter 'skipTutorial' in user's settings is False
    response = api_client.get('/api/v1/users/info',
                              headers=get_headers(token=user_token))
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    user_id = json_response['id']
    assert json_response['settings']['skipTutorial'] is False

    # Step 4. Set 'skipTutorial' parameter to True
    payload = {'skipTutorial': True}
    response = api_client.post('/api/v1/users/' + str(user_id) + '/settings',
                               data=json.dumps(payload),
                               headers=get_headers(json=True,
                                                   token=user_token))
    assert response.status_code == 200

    # Step 5. Assure that parameter 'skipTutorial' in user's settings is True
    response = api_client.get('/api/v1/users/info',
                              headers=get_headers(token=user_token))
    json_response = json.loads(response.data)
    assert isinstance(json_response, dict)
    assert json_response['settings']['skipTutorial'] is True
예제 #16
0
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.'
예제 #17
0
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
예제 #18
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.'
예제 #19
0
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
예제 #20
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
예제 #21
0
def test_basic_flow(prepare_environment: Any, synchronous_celery: Any) -> None:
    """Test application with basic flow."""
    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. Get all categories
    response = api_client.get('/api/v1/scans/categories',
                              headers=get_headers(token=user_token))
    assert response.status_code == 200
    json_response = json.loads(response.data)
    assert isinstance(json_response, list)
    category = json_response[0]
    category_key = category['key']
    assert isinstance(category_key, str)
    assert len(category_key) > 1

    # Step 2. Add Scan to the system
    payload = {'category': category_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']
    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 = json_response['slice_id']
    assert isinstance(slice_id, str)
    assert len(slice_id) >= 1

    # Step 4. Get random scan
    response = api_client.get(
        '/api/v1/scans/random?category={}'.format(category_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

    # Step 5. Get slices from the server
    web_socket_client.emit('request_slices', {
        'scan_id': scan_id,
        'begin': 0,
        'count': 1
    },
                           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
    tag_key = 'EXAMPLE_TAG'
    create_tag_and_assign_to_category(tag_key, 'Example tag', category_key)
    payload = {
        'elements': [{
            'x': 0.5,
            'y': 0.5,
            'slice_index': 0,
            'width': 0.1,
            'height': 0.1,
            'tag': tag_key,
            'tool': LabelTool.RECTANGLE.value,
        }],
        'labeling_time':
        12.34,
    }
    response = api_client.post('/api/v1/scans/{}/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 7. 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
    assert json_response['labeling_time'] == 12.34
    assert json_response[
        'status'] == LabelVerificationStatus.NOT_VERIFIED.value
    assert json_response['scan_id'] == scan_id
    assert len(json_response['elements'][0]['label_element_id']) >= 1
    assert json_response['elements'][0]['x'] == 0.5
    assert json_response['elements'][0]['y'] == 0.5
    assert json_response['elements'][0]['slice_index'] == 0
    assert json_response['elements'][0]['width'] == 0.1
    assert json_response['elements'][0]['height'] == 0.1
    assert json_response['elements'][0]['tag'] == tag_key
    assert json_response['elements'][0]['tool'] == LabelTool.RECTANGLE.value
    assert json_response['elements'][0][
        'status'] == LabelElementStatus.NOT_VERIFIED.value
예제 #22
0
def test_ownership(prepare_environment: Any, synchronous_celery: Any) -> None:
    """Test for checking scan and label ownership."""
    api_client = get_api_client()

    admin_id = create_user(ADMIN_EMAIL, ADMIN_PASSWORD, ADMIN_FIRST_NAME,
                           ADMIN_LAST_NAME)
    set_user_role(admin_id, 'admin')
    tag_key = 'EXAMPLE_TAG'
    create_tag_and_assign_to_category(tag_key, 'Example tag', 'LUNGS')

    # Step 1. 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 2. Add Scan to the system
    payload = {'category': '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 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=admin_user_token))
    assert response.status_code == 201

    # Step 4. Label
    payload = {
        'elements': [{
            'x': 0.5,
            'y': 0.5,
            'slice_index': 0,
            'width': 0.1,
            'height': 0.1,
            'tag': tag_key,
            'tool': LabelTool.RECTANGLE.value,
        }],
        'labeling_time':
        12.34,
    }
    response = api_client.post('/api/v1/scans/{}/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
예제 #23
0
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
예제 #24
0
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]
예제 #25
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.'
예제 #26
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
예제 #27
0
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)
예제 #28
0
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)