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
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.', }
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
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)
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'
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.'
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
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'
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_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
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
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.'
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
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
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
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
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_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
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
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
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
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]
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_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)