From a152b226f5d46c5997b94ea9453e55b92fb699ef Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Mon, 23 Sep 2024 11:58:03 +0100 Subject: [PATCH 1/4] Adding back the feature removals --- features/api/tag_layouts.feature | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/features/api/tag_layouts.feature b/features/api/tag_layouts.feature index e50694c94e..d095561f1a 100644 --- a/features/api/tag_layouts.feature +++ b/features/api/tag_layouts.feature @@ -55,6 +55,46 @@ Feature: Access tag layouts through the API } """ + @tag_layout @create @barcode-service + Scenario: Creating a tag layout of an entire plate using 96 tags by pools + Given the Baracoda barcode service returns "SQPD-1000001" + Given the Baracoda barcode service returns "SQPD-1000002" + Given the tag group "Example Tag Group" exists + And the UUID for the tag group "Example Tag Group" is "00000000-1111-2222-3333-444444444444" + And the tag group "Example Tag Group" has 20 tags + + Given a "Stock plate" plate called "Testing the API" exists + And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" + And all wells on the plate "Testing the API" have unique samples + + Given a "Stock plate" plate called "Testing the tagging" exists + And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" + And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 12, 8, 20, 12, 8, 20, 16 + + When I make an authorised POST with the following JSON to the API path "/tag_layouts": + """ + { + "tag_layout": { + "plate": "11111111-2222-3333-4444-000000000001", + "user": "99999999-8888-7777-6666-555555555555", + "tag_group": "00000000-1111-2222-3333-444444444444", + "direction": "column", + "walking_by": "manual by pool", + "initial_tag": 0 + } + } + """ + Then the HTTP response should be "201 Created" + + Then the tag layout on the plate "Testing the tagging" should be: + | TAG1 | TAG9 | TAG5 | TAG5 | TAG13 | TAG1 | TAG9 | TAG5 | TAG5 | TAG13 | TAG1 | TAG9 | + | TAG2 | TAG10 | TAG6 | TAG6 | TAG14 | TAG2 | TAG10 | TAG6 | TAG6 | TAG14 | TAG2 | TAG10 | + | TAG3 | TAG11 | TAG7 | TAG7 | TAG15 | TAG3 | TAG11 | TAG7 | TAG7 | TAG15 | TAG3 | TAG11 | + | TAG4 | TAG12 | TAG8 | TAG8 | TAG16 | TAG4 | TAG12 | TAG8 | TAG8 | TAG16 | TAG4 | TAG12 | + | TAG5 | TAG1 | TAG1 | TAG9 | TAG17 | TAG5 | TAG1 | TAG1 | TAG9 | TAG17 | TAG5 | TAG13 | + | TAG6 | TAG2 | TAG2 | TAG10 | TAG18 | TAG6 | TAG2 | TAG2 | TAG10 | TAG18 | TAG6 | TAG14 | + | TAG7 | TAG3 | TAG3 | TAG11 | TAG19 | TAG7 | TAG3 | TAG3 | TAG11 | TAG19 | TAG7 | TAG15 | + | TAG8 | TAG4 | TAG4 | TAG12 | TAG20 | TAG8 | TAG4 | TAG4 | TAG12 | TAG20 | TAG8 | TAG16 | @tag_layout @create @barcode-service Scenario: Creating a tag layout of an entire plate using 96 tags by pools @@ -139,6 +179,47 @@ Feature: Access tag layouts through the API | TAG8 | TAG16 | TAG24 | TAG32 | TAG40 | TAG47 | TAG55 | TAG63 | TAG71 | TAG79 | TAG87 | TAG95 | + @tag_layout @create @barcode-service + Scenario: Creating a tag layout of an entire plate using 96 tags by pools with an offset + Given the Baracoda barcode service returns "SQPD-1000001" + Given the Baracoda barcode service returns "SQPD-1000002" + Given the tag group "Example Tag Group" exists + And the UUID for the tag group "Example Tag Group" is "00000000-1111-2222-3333-444444444444" + And the tag group "Example Tag Group" has 30 tags + + Given a "Stock plate" plate called "Testing the API" exists + And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" + And all wells on the plate "Testing the API" have unique samples + + Given a "Stock plate" plate called "Testing the tagging" exists + And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" + And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 12, 8, 20, 12, 8, 20, 16 + + When I make an authorised POST with the following JSON to the API path "/tag_layouts": + """ + { + "tag_layout": { + "plate": "11111111-2222-3333-4444-000000000001", + "user": "99999999-8888-7777-6666-555555555555", + "tag_group": "00000000-1111-2222-3333-444444444444", + "direction": "column", + "walking_by": "manual by pool", + "initial_tag": 10 + } + } + """ + Then the HTTP response should be "201 Created" + + Then the tag layout on the plate "Testing the tagging" should be: + | TAG11 | TAG19 | TAG15 | TAG15 | TAG23 | TAG11 | TAG19 | TAG15 | TAG15 | TAG23 | TAG11 | TAG19 | + | TAG12 | TAG20 | TAG16 | TAG16 | TAG24 | TAG12 | TAG20 | TAG16 | TAG16 | TAG24 | TAG12 | TAG20 | + | TAG13 | TAG21 | TAG17 | TAG17 | TAG25 | TAG13 | TAG21 | TAG17 | TAG17 | TAG25 | TAG13 | TAG21 | + | TAG14 | TAG22 | TAG18 | TAG18 | TAG26 | TAG14 | TAG22 | TAG18 | TAG18 | TAG26 | TAG14 | TAG22 | + | TAG15 | TAG11 | TAG11 | TAG19 | TAG27 | TAG15 | TAG11 | TAG11 | TAG19 | TAG27 | TAG15 | TAG23 | + | TAG16 | TAG12 | TAG12 | TAG20 | TAG28 | TAG16 | TAG12 | TAG12 | TAG20 | TAG28 | TAG16 | TAG24 | + | TAG17 | TAG13 | TAG13 | TAG21 | TAG29 | TAG17 | TAG13 | TAG13 | TAG21 | TAG29 | TAG17 | TAG25 | + | TAG18 | TAG14 | TAG14 | TAG22 | TAG30 | TAG18 | TAG14 | TAG14 | TAG22 | TAG30 | TAG18 | TAG26 | + @tag_layout @create @barcode-service Scenario: Creating a tag layout of an entire plate using 96 tags by pools with an offset Given the Baracoda barcode service returns "SQPD-1000001" From db77c2cdf3ac12c2f9cb3bfae0a83c2180d116a0 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Mon, 23 Sep 2024 19:26:59 +0100 Subject: [PATCH 2/4] Fixing input plate tests - Part 1 --- features/api/tag_layout_templates.feature | 14 +++++++------- features/support/step_definitions/plate_steps.rb | 12 ++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/features/api/tag_layout_templates.feature b/features/api/tag_layout_templates.feature index b9c5a38776..e25e4846e8 100644 --- a/features/api/tag_layout_templates.feature +++ b/features/api/tag_layout_templates.feature @@ -40,7 +40,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled in columns to the plate "Testing the tagging" @@ -290,7 +290,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 96 And "F11-F12" of the plate "Testing the tagging" have been failed @@ -460,7 +460,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled in columns to the plate "Testing the tagging" @@ -550,7 +550,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 @@ -633,7 +633,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 8, 2, 10, 4, 8, 2, 10, 4, 8, 2, 10, 4, 8, 8, 8 @@ -706,7 +706,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 96 @@ -747,7 +747,7 @@ Feature: Access tag layout templates through the API And all wells on the plate "Testing the API" have unique samples And H12 on the plate "Testing the API" is empty - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 95 diff --git a/features/support/step_definitions/plate_steps.rb b/features/support/step_definitions/plate_steps.rb index ad656e1d82..60ca7b65c4 100644 --- a/features/support/step_definitions/plate_steps.rb +++ b/features/support/step_definitions/plate_steps.rb @@ -125,6 +125,18 @@ plate_purpose.create!(name: plate_name) end +Given /^a "([^"]+)" input plate called "([^"]+)" exists$/ do |name, plate_name| + plate_purpose = PlatePurpose.find_by!(name: name) + # binding.pry + plate_purpose.create!(name: plate_name) + + # Create requests for the wells of the plate + plate = Plate.find_by(name: plate_name) + plate.wells.each do |well| + FactoryBot.create(:customer_request, asset: well, sti_type: 'Request::LibraryCreation', state: 'pending') + end +end + Given(/^a plate called "([^"]*)" exists with purpose "([^"]*)"$/) do |name, purpose_name| purpose = Purpose.find_by(name: purpose_name) || FactoryBot.create(:plate_purpose, name: purpose_name) FactoryBot.create(:plate, name: name, purpose: purpose, well_count: 8) From 7de2230f8481d2a62ff5da3b6f8e3206626ca601 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 24 Sep 2024 09:25:35 +0100 Subject: [PATCH 3/4] Adding docs --- .../support/step_definitions/plate_steps.rb | 6 ------ .../step_definitions/tag_layout_steps.rb | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/features/support/step_definitions/plate_steps.rb b/features/support/step_definitions/plate_steps.rb index 60ca7b65c4..adf7bd7050 100644 --- a/features/support/step_definitions/plate_steps.rb +++ b/features/support/step_definitions/plate_steps.rb @@ -129,12 +129,6 @@ plate_purpose = PlatePurpose.find_by!(name: name) # binding.pry plate_purpose.create!(name: plate_name) - - # Create requests for the wells of the plate - plate = Plate.find_by(name: plate_name) - plate.wells.each do |well| - FactoryBot.create(:customer_request, asset: well, sti_type: 'Request::LibraryCreation', state: 'pending') - end end Given(/^a plate called "([^"]*)" exists with purpose "([^"]*)"$/) do |name, purpose_name| diff --git a/features/support/step_definitions/tag_layout_steps.rb b/features/support/step_definitions/tag_layout_steps.rb index 541ca753c3..821c5d8e9e 100644 --- a/features/support/step_definitions/tag_layout_steps.rb +++ b/features/support/step_definitions/tag_layout_steps.rb @@ -112,20 +112,33 @@ def check_tag2_layout(name, well_range, expected_wells_to_oligos) # rubocop:todo set_uuid_for(TagLayout.find(id).plate, uuid_value) end +# Pooling from source plate ("Testing the API") to destination plate ("Testing the tagging") with a specified pooling +# strategy +# # rubocop:todo Metrics/MethodLength def pool_by_strategy(source, destination, pooling_strategy) # rubocop:todo Metrics/AbcSize unless pooling_strategy.sum == source.size Rails.logger.info("Pooling strategy does not fit plate size #{source.size}: #{pooling_strategy.inspect}") end + + # Column major: reads columns from left to right, top to bottom + # Row major: reads rows from top to bottom, left to right + # For example, a 96-well plate would be read as: A1, B1, C1, D1, E1, F1, G1, H1, A2, B2, C2, D2, E2, F2, G2, H2, ... source_wells = source.wells.in_column_major_order.to_a destination_wells = destination.wells.in_column_major_order.to_a pooling_strategy.each_with_index do |pool, _old_submission_id| + # This will generate a new submission for each pool. So the number of submissions will be equal to the number of + # pools. For example, for a pooling strategy of [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8], there will be 12 submissions. submission_id = Submission.create!(user: User.first || User.create!(login: 'a')).id + # Slice operation cuts the array in place (i.e., removes the elements cut from the well array), + # so we need to assign the result to a new variable wells_for_source, wells_for_destination = source_wells.slice!(0, pool), destination_wells.slice!(0, pool) wells_for_source .zip(wells_for_destination) .each do |w| + # Because of the way we use zip w.first would be the source, w.last would be the destination + # This is the transfer request that would be created by the API TransferRequest.create!(asset: w.first, target_asset: w.last, submission_id: submission_id) FactoryBot.create :request_without_submission, asset: w.first, @@ -133,6 +146,11 @@ def pool_by_strategy(source, destination, pooling_strategy) # rubocop:todo Metri submission_id: submission_id end end + + # Create a request for each well in the destination plate + destination.wells.each do |well| + FactoryBot.create(:customer_request, asset: well, sti_type: 'Request::LibraryCreation', state: 'pending') + end end # rubocop:enable Metrics/MethodLength # This fakes out the transfers so that they look like they came from different submissions, effectively meaning From d00377aade1e514f36ea01ada0807e0a041657d7 Mon Sep 17 00:00:00 2001 From: Dasun Pubudumal Date: Tue, 24 Sep 2024 11:42:27 +0100 Subject: [PATCH 4/4] Adding docs --- .../support/step_definitions/tag_layout_steps.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/features/support/step_definitions/tag_layout_steps.rb b/features/support/step_definitions/tag_layout_steps.rb index 821c5d8e9e..e4f8512742 100644 --- a/features/support/step_definitions/tag_layout_steps.rb +++ b/features/support/step_definitions/tag_layout_steps.rb @@ -130,7 +130,8 @@ def pool_by_strategy(source, destination, pooling_strategy) # rubocop:todo Metri pooling_strategy.each_with_index do |pool, _old_submission_id| # This will generate a new submission for each pool. So the number of submissions will be equal to the number of # pools. For example, for a pooling strategy of [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8], there will be 12 submissions. - submission_id = Submission.create!(user: User.first || User.create!(login: 'a')).id + submission = Submission.create!(user: User.first || User.create!(login: 'a')) + submission_id = submission.id # Slice operation cuts the array in place (i.e., removes the elements cut from the well array), # so we need to assign the result to a new variable wells_for_source, wells_for_destination = source_wells.slice!(0, pool), destination_wells.slice!(0, pool) @@ -138,8 +139,12 @@ def pool_by_strategy(source, destination, pooling_strategy) # rubocop:todo Metri .zip(wells_for_destination) .each do |w| # Because of the way we use zip w.first would be the source, w.last would be the destination - # This is the transfer request that would be created by the API + # This is the transfer request that would be created by the API. + # Note that transfer request behavior not used for input plates. For input plates, it is overridden + # to use requests (see app/models/well.rb:120). + # Creating TransferRequests invokes a callback that transfers aliquots from source to destination wells. TransferRequest.create!(asset: w.first, target_asset: w.last, submission_id: submission_id) + # This request is for the source plate. FactoryBot.create :request_without_submission, asset: w.first, target_asset: w.last, @@ -148,8 +153,11 @@ def pool_by_strategy(source, destination, pooling_strategy) # rubocop:todo Metri end # Create a request for each well in the destination plate - destination.wells.each do |well| - FactoryBot.create(:customer_request, asset: well, sti_type: 'Request::LibraryCreation', state: 'pending') + # This is required for input plates + if destination.purpose.is_a?(PlatePurpose::Input) + destination.wells.each do |well| + FactoryBot.create(:customer_request, asset: well, sti_type: 'Request::LibraryCreation', state: 'pending') + end end end # rubocop:enable Metrics/MethodLength