Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DAR-4041][External] Add multi-file E2E tests #931

Merged
merged 3 commits into from
Oct 8, 2024
Merged

[DAR-4041][External] Add multi-file E2E tests #931

merged 3 commits into from
Oct 8, 2024

Conversation

JBWilkie
Copy link
Collaborator

@JBWilkie JBWilkie commented Sep 26, 2024

Problem

No E2E tests for:

  • Pushing multi-file items
  • Importing annotations to multi-file items

Solution

Add the following E2E tests:
push:

  • test_push_multi_slotted_item: Upload a multi-slotted item via the CLI
  • test_push_multi_channel_item: Upload a multi-channel item via the CLI
  • test_push_dicom_series: Upload a multi-file DICOM series via the CLI

import:

  • test_import_annotations_to_multi_slotted_item_without_slots_defined: Upload annotations to a multi-slotted item without aligning each annotation to a slot. All annotations should end up in the item's first slot
  • test_import_annotations_to_multi_slotted_item_with_slots_defined: Upload annotations to a multi-slotted item where each annotation is aligned with a particular slot. Each annotation should end up in the correct slot
  • test_import_annotations_to_multi_channel_item_without_slots_defined: Upload annotations to a multi-channel item without aligning each annotation to a slot. All annotations should end up the base slot
  • test_import_annotations_to_multi_channel_item_with_slots_defined: Upload annotations to a multi-channel item where each annotation is aligned with the base slot. All annotations should end up in the base slot
  • test_import_annotations_to_multi_channel_item_non_base_slot: Upload annotations to a multi-channel item where each annotation is aligned with a non-base slot. The importer should throw an error

Changelog

Added E2E test coverage for uploading & importing annotations to multi-file items

Copy link

linear bot commented Sep 26, 2024

Copy link

@umbertoDifa umbertoDifa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are 🔥 , I just left minor comments

config_values.team_slug,
config_values.server,
)
return items[item_idx]["slots"][0]["slot_name"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not be an issue now, but what if the BE decided to return the list of items in a different order? Wouldn't it be safer to find an item by item_id or name?

@@ -78,15 +80,55 @@ def assert_same_annotation_properties(
assert expected_property in actual_properties # type : ignore


def get_base_slot_of_item(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_base_slot_name_of_item it returns the name not the slot right?

if expected_annotation.slot_names:
assert expected_annotation.slot_names == actual_annotation.slot_names
else:
assert actual_annotation.slot_names == [base_slot]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to think when we have this case: if it's a multislot and I don't specify the slot_name of an annotation then by default it gets uploaded to the base slot?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly

assert_same_annotation_properties(expected_annotation, actual_annotation)
assert_annotation_slot_alignment(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:I'd probably expect something named assert_same_annotation_slot_name?

Comment on lines 379 to 496
assert_cli(result, 0)
base_slot = get_base_slot_of_item(config_values, local_dataset.id, item_idx=0)
with tempfile.TemporaryDirectory() as tmp_dir_str:
actual_annotations_dir = Path(tmp_dir_str)
export_and_download_annotations(
actual_annotations_dir, local_dataset, config_values
)
compare_annotations_export(
actual_annotations_dir, expected_annotations_dir, item_type, base_slot
)


def test_import_annotations_to_multi_slotted_item_with_slots_defined(
local_dataset: E2EDataset, config_values: ConfigValues
) -> None:
"""
Upload annotations to a multi-slotted item where each annotation is aligned with a
particular slot. Each annotation should end up in the correct slot
"""
item_type = "multi_slotted"
local_dataset.register_read_only_items(config_values, item_type)
expected_annotations_dir = (
Path(__file__).parents[1]
/ "data"
/ "import"
/ "multi_slotted_annotations_with_slots_defined"
)
result = run_cli_command(
f"darwin dataset import {local_dataset.name} darwin {expected_annotations_dir}"
)
assert_cli(result, 0)
base_slot = get_base_slot_of_item(config_values, local_dataset.id, item_idx=0)
with tempfile.TemporaryDirectory() as tmp_dir_str:
actual_annotations_dir = Path(tmp_dir_str)
export_and_download_annotations(
actual_annotations_dir, local_dataset, config_values
)
compare_annotations_export(
actual_annotations_dir, expected_annotations_dir, item_type, base_slot
)


def test_import_annotations_to_multi_channel_item_without_slots_defined(
local_dataset: E2EDataset, config_values: ConfigValues
) -> None:
"""
Upload annotations to a multi-channel item without aligning each annotation to a
slot. All annotations should end up the base slot
"""
item_type = "multi_channel"
local_dataset.register_read_only_items(config_values, item_type)
expected_annotations_dir = (
Path(__file__).parents[1]
/ "data"
/ "import"
/ "multi_channel_annotations_without_slots_defined"
)
result = run_cli_command(
f"darwin dataset import {local_dataset.name} darwin {expected_annotations_dir}"
)
assert_cli(result, 0)
base_slot = get_base_slot_of_item(config_values, local_dataset.id, item_idx=0)
with tempfile.TemporaryDirectory() as tmp_dir_str:
actual_annotations_dir = Path(tmp_dir_str)
export_and_download_annotations(
actual_annotations_dir, local_dataset, config_values
)
compare_annotations_export(
actual_annotations_dir, expected_annotations_dir, item_type, base_slot
)


def test_import_annotations_to_multi_channel_item_with_slots_defined(
local_dataset: E2EDataset, config_values: ConfigValues
) -> None:
"""
Upload annotations to a multi-channel item where each annotation is aligned with
the base slot. Each annotation should end up in the base slot
"""
item_type = "multi_channel"
local_dataset.register_read_only_items(config_values, item_type="multi_channel")
expected_annotations_dir = (
Path(__file__).parents[1]
/ "data"
/ "import"
/ "multi_channel_annotations_with_slots_defined"
)
result = run_cli_command(
f"darwin dataset import {local_dataset.name} darwin {expected_annotations_dir}"
)
assert_cli(result, 0)
base_slot = get_base_slot_of_item(config_values, local_dataset.id, item_idx=0)
with tempfile.TemporaryDirectory() as tmp_dir_str:
actual_annotations_dir = Path(tmp_dir_str)
export_and_download_annotations(
actual_annotations_dir, local_dataset, config_values
)
compare_annotations_export(
actual_annotations_dir, expected_annotations_dir, item_type, base_slot
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like these methods are identical and only the expected_annotations_dir changes. I wonder if it can be useful to simplify. The rule of thumb is: if you repeat it 3 times than you can DRY the code. Up to you

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DRYing the code would make it way faster to read and understand

local_dataset: E2EDataset, config_values: ConfigValues
) -> None:
"""
Upload annotations to a multi-channel item where each annotation is aligned with a

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if I have at least one annotation that is aligned to a base_slot? Would that be the only one imported?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No - If there is any annotation that is not aligned with the base slot, the importer will throw an error

Copy link
Contributor

@AndriiKlymchuk AndriiKlymchuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing critical. Just consider to address existing comments before merge.

Comment on lines 258 to 272
with tempfile.TemporaryDirectory() as tmp_dir_str:
tmp_dir = Path(tmp_dir_str)
with zipfile.ZipFile(push_dir) as z:
z.extractall(tmp_dir)
result = run_cli_command(
f"darwin dataset push {local_dataset.name} {tmp_dir}/flat_directory_of_2_dicom_files --item-merge-mode {merge_mode}"
)
assert_cli(result, 0)
wait_until_items_processed(config_values, local_dataset.id)
items = list_items(
config_values.api_key,
local_dataset.id,
config_values.team_slug,
config_values.server,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic here repeats in every test. Maybe you can de-duplicate it. At least it is easier to dot it from line 261

@JBWilkie
Copy link
Collaborator Author

JBWilkie commented Oct 8, 2024

These tests are 🔥 , I just left minor comments

Useful points, thank you! All addressed

@JBWilkie
Copy link
Collaborator Author

JBWilkie commented Oct 8, 2024

Nothing critical. Just consider to address existing comments before merge.

All addressed, thank you!

@JBWilkie JBWilkie merged commit 25aff99 into master Oct 8, 2024
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants