From f18dded3462ece080c4a9a1dcfaa16cbc3ee8c99 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 23 Jul 2024 18:31:16 +0100 Subject: [PATCH 01/70] Use SS API v2 for getting BarcodePrinters --- app/controllers/labware_controller.rb | 2 +- app/controllers/print_jobs_controller.rb | 2 +- app/helpers/barcode_labels_helper.rb | 2 +- .../sequencescape/api/v2/barcode_printer.rb | 5 +++++ spec/controllers/plates_controller_spec.rb | 2 +- .../controllers/print_jobs_controller_spec.rb | 2 +- spec/controllers/searches_controller_spec.rb | 2 +- spec/controllers/tubes_controller_spec.rb | 2 +- spec/factories/barcode_printer_factories.rb | 19 +++++++++++++++++ .../features/cancelling_a_whole_plate_spec.rb | 2 +- .../charge_and_pass_libraries_spec.rb | 2 +- spec/features/creating_a_plate_spec.rb | 2 +- ..._quadrant_stamp_primer_panel_plate_spec.rb | 2 +- spec/features/creating_a_tag_plate_spec.rb | 2 +- .../features/creating_plate_with_bait_spec.rb | 2 +- spec/features/failing_a_whole_plate_spec.rb | 2 +- spec/features/failing_quadrants_spec.rb | 2 +- spec/features/failing_thresholds_spec.rb | 2 +- spec/features/failing_wells_spec.rb | 2 +- .../pool_tubes_at_end_of_pipeline_spec.rb | 2 +- ...ling_multiple_plates_into_one_tube_spec.rb | 2 +- spec/features/pooling_multiple_plates_spec.rb | 2 +- ...oling_multiple_tubes_into_one_tube_spec.rb | 2 +- spec/features/viewing_a_minimal_plate_spec.rb | 7 ++++--- spec/features/viewing_a_plate_spec.rb | 7 ++++--- spec/helpers/barcode_labels_helper_spec.rb | 6 +++--- spec/support/api_url_helper.rb | 21 ++++++++++++------- 27 files changed, 69 insertions(+), 38 deletions(-) create mode 100644 app/sequencescape/sequencescape/api/v2/barcode_printer.rb diff --git a/app/controllers/labware_controller.rb b/app/controllers/labware_controller.rb index e889473f6..b5d189cd3 100644 --- a/app/controllers/labware_controller.rb +++ b/app/controllers/labware_controller.rb @@ -81,7 +81,7 @@ def locate_labware end def find_printers - @printers = api.barcode_printer.all + @printers = Sequencescape::Api::V2::BarcodePrinter.all end def state_changer_for(purpose_uuid, labware_uuid) diff --git a/app/controllers/print_jobs_controller.rb b/app/controllers/print_jobs_controller.rb index 67a72069e..29a7cb4d2 100644 --- a/app/controllers/print_jobs_controller.rb +++ b/app/controllers/print_jobs_controller.rb @@ -35,7 +35,7 @@ def print_job_params def find_printer_from_name # there's bound to be a better way of doing this, so we don't have to # requery all the printers here to find the right one - printers = api.barcode_printer.all + printers = Sequencescape::Api::V2::BarcodePrinter.all printers.find { |p| p.name == print_job_params[:printer_name] } end end diff --git a/app/helpers/barcode_labels_helper.rb b/app/helpers/barcode_labels_helper.rb index 1f1278305..1d620dcd6 100644 --- a/app/helpers/barcode_labels_helper.rb +++ b/app/helpers/barcode_labels_helper.rb @@ -24,7 +24,7 @@ def barcode_printing_form( end def printers_of_type(printer_types) - @printers.select { |printer| printer_types.include?(printer.type.name) } # rubocop:todo Rails/HelperInstanceVariable + @printers.select { |printer| printer_types.include?(printer.type_name) } # rubocop:todo Rails/HelperInstanceVariable end def useful_barcode(barcode) diff --git a/app/sequencescape/sequencescape/api/v2/barcode_printer.rb b/app/sequencescape/sequencescape/api/v2/barcode_printer.rb new file mode 100644 index 000000000..2827dad46 --- /dev/null +++ b/app/sequencescape/sequencescape/api/v2/barcode_printer.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +# barcode printer resource +class Sequencescape::Api::V2::BarcodePrinter < Sequencescape::Api::V2::Base +end diff --git a/spec/controllers/plates_controller_spec.rb b/spec/controllers/plates_controller_spec.rb index c54444ce1..ba8bfdb49 100644 --- a/spec/controllers/plates_controller_spec.rb +++ b/spec/controllers/plates_controller_spec.rb @@ -10,7 +10,7 @@ let(:v2_plate) { create :v2_plate, uuid: plate_uuid, purpose_uuid: 'stock-plate-purpose-uuid' } let(:wells_json) { json :well_collection } let(:plate_wells_request) { stub_api_get plate_uuid, 'wells', body: wells_json } - let(:barcode_printers_request) { stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) } + let(:barcode_printers_request) { stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) } let(:user_uuid) { SecureRandom.uuid } describe '#show' do diff --git a/spec/controllers/print_jobs_controller_spec.rb b/spec/controllers/print_jobs_controller_spec.rb index 613fa327f..f295256f7 100644 --- a/spec/controllers/print_jobs_controller_spec.rb +++ b/spec/controllers/print_jobs_controller_spec.rb @@ -8,7 +8,7 @@ has_a_working_api it 'creates print_job is successful' do - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) params = { print_job: { diff --git a/spec/controllers/searches_controller_spec.rb b/spec/controllers/searches_controller_spec.rb index 2c6d65f58..d02015525 100644 --- a/spec/controllers/searches_controller_spec.rb +++ b/spec/controllers/searches_controller_spec.rb @@ -12,7 +12,7 @@ let(:wells_json) { json :well_collection } let(:plate_request) { stub_api_get plate_uuid, body: plate_json } let(:plate_wells_request) { stub_api_get plate_uuid, 'wells', body: wells_json } - let(:barcode_printers_request) { stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) } + let(:barcode_printers_request) { stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) } let(:user_uuid) { SecureRandom.uuid } let(:uuid) { SecureRandom.uuid } diff --git a/spec/controllers/tubes_controller_spec.rb b/spec/controllers/tubes_controller_spec.rb index 433545489..ff23ce32f 100644 --- a/spec/controllers/tubes_controller_spec.rb +++ b/spec/controllers/tubes_controller_spec.rb @@ -10,7 +10,7 @@ let(:tube_json) { json :tube, uuid: tube_uuid, purpose_uuid: 'stock-tube-purpose-uuid', state: 'passed' } let(:v2_tube) { create :v2_tube, uuid: tube_uuid, purpose_uuid: 'stock-tube-purpose-uuid', state: 'passed' } let(:tube_request) { stub_api_get tube_uuid, body: tube_json } - let(:barcode_printers_request) { stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) } + let(:barcode_printers_request) { stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) } let(:user_uuid) { SecureRandom.uuid } describe '#show' do diff --git a/spec/factories/barcode_printer_factories.rb b/spec/factories/barcode_printer_factories.rb index e0e2adbae..429a6d176 100644 --- a/spec/factories/barcode_printer_factories.rb +++ b/spec/factories/barcode_printer_factories.rb @@ -60,4 +60,23 @@ Array.new(plate_printer_size) { |i| associated(:tube_barcode_printer, name: "tube printer #{i}") } end end + + # Build an API v2 JSONAPI barcode printer. + factory :v2_barcode_printer, class: Sequencescape::Api::V2::BarcodePrinter do + skip_create + type { 'barcode_printers' } + uuid + sequence(:id, &:to_s) + sequence(:name) { |n| "Barcode Printer #{n}" } + print_service { 'PMB' } + type_name { nil } + + factory :v2_plate_barcode_printer do + type_name { '96 Well Plate' } + end + + factory :v2_tube_barcode_printer do + type_name { '1D Tube' } + end + end end diff --git a/spec/features/cancelling_a_whole_plate_spec.rb b/spec/features/cancelling_a_whole_plate_spec.rb index e2a2e9aa7..b3ccbb7d4 100644 --- a/spec/features/cancelling_a_whole_plate_spec.rb +++ b/spec/features/cancelling_a_whole_plate_spec.rb @@ -160,7 +160,7 @@ ) # We get the printers - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) end scenario 'from the interface' do diff --git a/spec/features/charge_and_pass_libraries_spec.rb b/spec/features/charge_and_pass_libraries_spec.rb index 860456611..e1fa03e35 100644 --- a/spec/features/charge_and_pass_libraries_spec.rb +++ b/spec/features/charge_and_pass_libraries_spec.rb @@ -21,7 +21,7 @@ background do # We look up the user stub_swipecard_search(user_swipecard, user) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) stub_api_post('work_completions', payload: work_completion_request, body: work_completion) end diff --git a/spec/features/creating_a_plate_spec.rb b/spec/features/creating_a_plate_spec.rb index 8ef258f2a..45676b4f7 100644 --- a/spec/features/creating_a_plate_spec.rb +++ b/spec/features/creating_a_plate_spec.rb @@ -105,7 +105,7 @@ # We get the actual plate 2.times { stub_v2_plate(example_plate) } stub_v2_plate(child_plate, stub_search: false) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) end scenario 'basic plate creation' do diff --git a/spec/features/creating_a_quadrant_stamp_primer_panel_plate_spec.rb b/spec/features/creating_a_quadrant_stamp_primer_panel_plate_spec.rb index 5f5d9a56d..51ee784bd 100644 --- a/spec/features/creating_a_quadrant_stamp_primer_panel_plate_spec.rb +++ b/spec/features/creating_a_quadrant_stamp_primer_panel_plate_spec.rb @@ -96,7 +96,7 @@ let(:parent1_plate_old_api) { json(:plate, barcode_number: '2', state: 'passed', uuid: parent_uuid) } background do - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) create :purpose_config, name: 'Primer Panel example', uuid: parent_purpose_uuid create :purpose_config, creator_class: 'LabwareCreators::QuadrantStampPrimerPanel', diff --git a/spec/features/creating_a_tag_plate_spec.rb b/spec/features/creating_a_tag_plate_spec.rb index 296edd295..b9a6f4a5f 100644 --- a/spec/features/creating_a_tag_plate_spec.rb +++ b/spec/features/creating_a_tag_plate_spec.rb @@ -65,7 +65,7 @@ stub_api_get(plate_uuid, body: old_api_example_plate) stub_api_get(plate_uuid, 'wells', body: json(:well_collection)) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) stub_api_get('tag_layout_templates', body: templates) stub_api_get(plate_uuid, 'submission_pools', body: submission_pools) diff --git a/spec/features/creating_plate_with_bait_spec.rb b/spec/features/creating_plate_with_bait_spec.rb index 5cd74b37d..d7625dd66 100644 --- a/spec/features/creating_plate_with_bait_spec.rb +++ b/spec/features/creating_plate_with_bait_spec.rb @@ -39,7 +39,7 @@ stub_v2_plate(example_plate) stub_v2_plate(child_plate) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) # end of stubs for plate show page diff --git a/spec/features/failing_a_whole_plate_spec.rb b/spec/features/failing_a_whole_plate_spec.rb index 5e49bcba4..a5a243f17 100644 --- a/spec/features/failing_a_whole_plate_spec.rb +++ b/spec/features/failing_a_whole_plate_spec.rb @@ -158,7 +158,7 @@ ) # We get the printers - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) end scenario 'failing a plate' do diff --git a/spec/features/failing_quadrants_spec.rb b/spec/features/failing_quadrants_spec.rb index c4fbba73b..d9f43ce13 100644 --- a/spec/features/failing_quadrants_spec.rb +++ b/spec/features/failing_quadrants_spec.rb @@ -65,7 +65,7 @@ 'wells', body: json(:well_collection, default_state: 'passed', custom_state: { 'B2' => 'failed' }) ) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) end scenario 'failing wells' do diff --git a/spec/features/failing_thresholds_spec.rb b/spec/features/failing_thresholds_spec.rb index ad67ff5d9..910422407 100644 --- a/spec/features/failing_thresholds_spec.rb +++ b/spec/features/failing_thresholds_spec.rb @@ -62,7 +62,7 @@ 'wells', body: json(:well_collection, default_state: 'passed', custom_state: { 'B2' => 'failed' }) ) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) end scenario 'failing wells' do diff --git a/spec/features/failing_wells_spec.rb b/spec/features/failing_wells_spec.rb index d6a72e696..ec476c638 100644 --- a/spec/features/failing_wells_spec.rb +++ b/spec/features/failing_wells_spec.rb @@ -61,7 +61,7 @@ 'wells', body: json(:well_collection, default_state: 'passed', custom_state: { 'B2' => 'failed' }) ) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) end scenario 'failing wells' do diff --git a/spec/features/pool_tubes_at_end_of_pipeline_spec.rb b/spec/features/pool_tubes_at_end_of_pipeline_spec.rb index 601420eb5..dd6d96f6f 100644 --- a/spec/features/pool_tubes_at_end_of_pipeline_spec.rb +++ b/spec/features/pool_tubes_at_end_of_pipeline_spec.rb @@ -68,8 +68,8 @@ # Creator uses the old tube stub_api_get(tube_uuid, body: example_tube) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) stub_api_get('transfer-template-uuid', body: json(:transfer_template, uuid: 'transfer-template-uuid')) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) stub_v2_tube(create(:v2_tube, uuid: multiplexed_library_tube_uuid)) transfer_request transfer_request_b diff --git a/spec/features/pooling_multiple_plates_into_one_tube_spec.rb b/spec/features/pooling_multiple_plates_into_one_tube_spec.rb index bb7d56bfb..13e3124dd 100644 --- a/spec/features/pooling_multiple_plates_into_one_tube_spec.rb +++ b/spec/features/pooling_multiple_plates_into_one_tube_spec.rb @@ -143,7 +143,7 @@ stub_v2_tube(child_tube) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) end scenario 'creates multiple plates' do diff --git a/spec/features/pooling_multiple_plates_spec.rb b/spec/features/pooling_multiple_plates_spec.rb index 288b08896..b7a49849f 100644 --- a/spec/features/pooling_multiple_plates_spec.rb +++ b/spec/features/pooling_multiple_plates_spec.rb @@ -104,7 +104,7 @@ stub_v2_plate(example_plate_2) stub_v2_plate(child_plate) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) end scenario 'creates multiple plates' do diff --git a/spec/features/pooling_multiple_tubes_into_one_tube_spec.rb b/spec/features/pooling_multiple_tubes_into_one_tube_spec.rb index 8e755fad2..52c9a50cd 100644 --- a/spec/features/pooling_multiple_tubes_into_one_tube_spec.rb +++ b/spec/features/pooling_multiple_tubes_into_one_tube_spec.rb @@ -205,7 +205,7 @@ # Used in the redirect. This is call is probably unnecessary stub_api_get(child_uuid, body: child_tube) stub_v2_tube(child_tube_v2) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) allow(SearchHelper).to receive(:stock_plate_names).and_return([stock_plate_purpose_name]) stub_get_labware_metadata(parent_1.barcode.machine, parent_1_v1) diff --git a/spec/features/viewing_a_minimal_plate_spec.rb b/spec/features/viewing_a_minimal_plate_spec.rb index d2f4b6d40..383a86d8b 100644 --- a/spec/features/viewing_a_minimal_plate_spec.rb +++ b/spec/features/viewing_a_minimal_plate_spec.rb @@ -11,7 +11,8 @@ let(:plate_uuid) { SecureRandom.uuid } let(:plate_state) { 'pending' } let(:example_plate) { create :v2_stock_plate, uuid: plate_uuid, size: 384, state: plate_state, pool_sizes: [3] } - let(:default_tube_printer) { 'tube printer 1' } + let(:printer_list) { create_list(:v2_tube_barcode_printer, 2) + create_list(:v2_plate_barcode_printer, 2) } + let(:default_tube_printer) { printer_list.first.name } # Setup stubs background do @@ -26,7 +27,7 @@ # We get the actual plate stub_v2_plate(example_plate) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(printer_list) end scenario 'of a recognised type' do @@ -119,7 +120,7 @@ }, purpose_uuid: 'child-purpose-0' end - let(:barcode_printer) { 'tube printer 0' } + let(:barcode_printer) { printer_list[1].name } let(:print_copies) { 2 } let(:label_a) do diff --git a/spec/features/viewing_a_plate_spec.rb b/spec/features/viewing_a_plate_spec.rb index b747e8ce7..253f643a1 100644 --- a/spec/features/viewing_a_plate_spec.rb +++ b/spec/features/viewing_a_plate_spec.rb @@ -20,7 +20,8 @@ purpose_uuid: purpose_uuid end let(:wells_collection) { %w[A1 B1].map { |loc| create(:v2_well, state: state, position: { 'name' => loc }) } } - let(:default_tube_printer) { 'tube printer 1' } + let(:printer_list) { create_list(:v2_tube_barcode_printer, 2) + create_list(:v2_plate_barcode_printer, 2) } + let(:default_tube_printer) { printer_list.first.name } let(:purpose_config) { create :purpose_config, uuid: purpose_uuid } # Setup stubs @@ -36,7 +37,7 @@ # We get the actual plate stub_v2_plate(example_plate) - stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) + stub_v2_barcode_printers(printer_list) end scenario 'of a recognised type' do @@ -132,7 +133,7 @@ }, purpose_uuid: 'child-purpose-0' end - let(:barcode_printer) { 'tube printer 0' } + let(:barcode_printer) { printer_list[1].name } let(:print_copies) { 2 } let(:label_a) do diff --git a/spec/helpers/barcode_labels_helper_spec.rb b/spec/helpers/barcode_labels_helper_spec.rb index 49e8b261d..1599e2a42 100644 --- a/spec/helpers/barcode_labels_helper_spec.rb +++ b/spec/helpers/barcode_labels_helper_spec.rb @@ -12,12 +12,12 @@ let(:labels) { [Labels::PlateLabel.new(plate, {})] } let(:redirection_url) { 'example_plate_url' } let(:default_printer_name) { 'example_printer_name' } - let(:barcode_printers_request) { stub_api_get('barcode_printers', body: json(:barcode_printer_collection)) } + let(:barcode_printers_request) { stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) } let(:presenter) { Presenters::StockPlatePresenter.new } before do barcode_printers_request - @printers = api.barcode_printer.all + @printers = Sequencescape::Api::V2::BarcodePrinter.all @presenter = presenter end @@ -38,7 +38,7 @@ ) printer_types = labels.map(&:printer_type) - printers = @printers.select { |printer| printer_types.include?(printer.type.name) } + printers = @printers.select { |printer| printer_types.include?(printer.type_name) } expect(rendered).to include(printers[0].name) expect(rendered).to include(printers[1].name) diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index 64575b898..aac0e4a7e 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -90,6 +90,11 @@ def stub_barcode_search(barcode, labware) allow(Sequencescape::Api::V2).to receive(:minimal_labware_by_barcode).with(barcode).and_return(labware_result) end + # Stubs a request for all barcode printers + def stub_v2_barcode_printers(printers) + allow(Sequencescape::Api::V2::BarcodePrinter).to receive(:all).and_return(printers) + end + # Builds the basic v2 plate finding query. def stub_v2_plate(plate, stub_search: true, custom_query: nil, custom_includes: nil) # rubocop:todo Metrics/AbcSize stub_barcode_search(plate.barcode.machine, plate) if stub_search @@ -105,11 +110,9 @@ def stub_v2_plate(plate, stub_search: true, custom_query: nil, custom_includes: end end - # Builds the basic v2 tube finding query. - def stub_v2_tube(tube, stub_search: true, custom_includes: false) - stub_barcode_search(tube.barcode.machine, tube) if stub_search - arguments = custom_includes ? [{ uuid: tube.uuid }, { includes: custom_includes }] : [{ uuid: tube.uuid }] - allow(Sequencescape::Api::V2::Tube).to receive(:find_by).with(*arguments).and_return(tube) + def stub_v2_polymetadata(polymetadata, metadatable_id) + arguments = [{ key: polymetadata.key, metadatable_id: metadatable_id }] + allow(Sequencescape::Api::V2::PolyMetadatum).to receive(:find).with(*arguments).and_return([polymetadata]) end def stub_v2_project(project) @@ -122,9 +125,11 @@ def stub_v2_study(study) allow(Sequencescape::Api::V2::Study).to receive(:find).with(*arguments).and_return([study]) end - def stub_v2_polymetadata(polymetadata, metadatable_id) - arguments = [{ key: polymetadata.key, metadatable_id: metadatable_id }] - allow(Sequencescape::Api::V2::PolyMetadatum).to receive(:find).with(*arguments).and_return([polymetadata]) + # Builds the basic v2 tube finding query. + def stub_v2_tube(tube, stub_search: true, custom_includes: false) + stub_barcode_search(tube.barcode.machine, tube) if stub_search + arguments = custom_includes ? [{ uuid: tube.uuid }, { includes: custom_includes }] : [{ uuid: tube.uuid }] + allow(Sequencescape::Api::V2::Tube).to receive(:find_by).with(*arguments).and_return(tube) end end extend ClassMethods From 095cc2f3a6f61ec1904c3b97648cf0d676c6c43b Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 23 Jul 2024 18:46:10 +0100 Subject: [PATCH 02/70] Remove v1 barcode printer factories --- spec/factories/barcode_printer_factories.rb | 60 ------------------- .../barcode_printer_factory_spec.rb | 32 ---------- spec/models/print_job_spec.rb | 6 +- 3 files changed, 3 insertions(+), 95 deletions(-) delete mode 100644 spec/factory_outputs/barcode_printer_factory_spec.rb diff --git a/spec/factories/barcode_printer_factories.rb b/spec/factories/barcode_printer_factories.rb index 429a6d176..8591b723a 100644 --- a/spec/factories/barcode_printer_factories.rb +++ b/spec/factories/barcode_printer_factories.rb @@ -1,66 +1,6 @@ # frozen_string_literal: true FactoryBot.define do - # Build an API v1 barcode printer. You probably want to use: plate_barcode_printer or - # tube_barcode_printer instead - factory :barcode_printer, class: Sequencescape::BarcodePrinter, traits: [:api_object] do - json_root { 'barcode_printer' } - - active { true } # Whether Sequencescape reports the printer as active or not - service { { 'url' => 'DEPRECATED' } } # Previously the URL of the SOAP barcode printing service. Now deprecated. - print_service { 'PMB' } - - transient do - # The type of printer, either 'plate' or 'tube'. Use this to set the layout and name to something - # appropriate - printer_type { 'plate' } - - # Sets the type.name attribute. Use printer_type to set this automatically - printer_type_name { { 'plate' => '96 Well Plate', 'tube' => '1D Tube' }.fetch(printer_type) } - - # Sets the type.layout attribute. Use printer_type to set this automatically. - layout { { 'plate' => 1, 'tube' => 2 }.fetch(printer_type) } - end - - # Type is a hash provided by the Sequencescape API which describes the label type - # loaded into the printer. - type { { 'name' => printer_type_name, 'layout' => layout } } - - name { "#{printer_type} printer" } - - after(:build) do |barcode_printer, evaluator| - RSpec::Mocks.allow_message(barcode_printer, :type).and_return(evaluator.type) - end - - # Build an API V1 plate barcode printer - factory :plate_barcode_printer do - transient { printer_type { 'plate' } } - end - - # Build an API V1 tube barcode printer - factory :tube_barcode_printer do - transient { printer_type { 'tube' } } - end - end - - factory :barcode_printer_collection, class: Sequencescape::Api::PageOfResults, traits: [:api_object] do - size { tube_printer_size + plate_printer_size } - - transient do - tube_printer_size { 2 } - plate_printer_size { 2 } - json_root { nil } - resource_actions { %w[read first last] } - resource_url { "#{api_root}/barcode_printers/1" } - uuid { nil } - end - - barcode_printers do - Array.new(tube_printer_size) { |i| associated(:plate_barcode_printer, name: "plate printer #{i}") } + - Array.new(plate_printer_size) { |i| associated(:tube_barcode_printer, name: "tube printer #{i}") } - end - end - # Build an API v2 JSONAPI barcode printer. factory :v2_barcode_printer, class: Sequencescape::Api::V2::BarcodePrinter do skip_create diff --git a/spec/factory_outputs/barcode_printer_factory_spec.rb b/spec/factory_outputs/barcode_printer_factory_spec.rb deleted file mode 100644 index c7422b805..000000000 --- a/spec/factory_outputs/barcode_printer_factory_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'barcode printer factory' do - subject { json(:barcode_printer, uuid: 'example-barcode-printer-uuid', printer_type: 'tube') } - - let(:json_content) do - '{ - "barcode_printer": { - "actions": { - "read": "http://example.com:3000/example-barcode-printer-uuid" - }, - "uuid": "example-barcode-printer-uuid", - "name": "tube printer", - "print_service": "PMB", - "active": true, - "service": { - "url": "DEPRECATED" - }, - "type": { - "name": "1D Tube", - "layout": 2 - } - } - }' - end - - it 'should match the expected json' do - expect(JSON.parse(subject)['barcode_printer']).to eq JSON.parse(json_content)['barcode_printer'] - end -end diff --git a/spec/models/print_job_spec.rb b/spec/models/print_job_spec.rb index d4b4ff089..7a0ffbf07 100644 --- a/spec/models/print_job_spec.rb +++ b/spec/models/print_job_spec.rb @@ -5,9 +5,9 @@ RSpec.describe PrintJob do has_a_working_api - let(:printer_pmb) { build :barcode_printer } - let(:printer_sprint) { build :barcode_printer, print_service: 'SPrint' } - let(:printer_unknown) { build :barcode_printer, print_service: 'UNKNOWN' } + let(:printer_pmb) { build :v2_barcode_printer } + let(:printer_sprint) { build :v2_barcode_printer, print_service: 'SPrint' } + let(:printer_unknown) { build :v2_barcode_printer, print_service: 'UNKNOWN' } let(:label_template_id) { 1 } let(:label_template_name_pmb) { 'sqsc_96plate_label_template' } From 58625fadd232549177a00ce31b05cd52c9580a42 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 23 Jul 2024 18:46:29 +0100 Subject: [PATCH 03/70] Rename type_name to barcode_type --- app/helpers/barcode_labels_helper.rb | 2 +- spec/factories/barcode_printer_factories.rb | 6 +++--- spec/helpers/barcode_labels_helper_spec.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/helpers/barcode_labels_helper.rb b/app/helpers/barcode_labels_helper.rb index 1d620dcd6..069a4851d 100644 --- a/app/helpers/barcode_labels_helper.rb +++ b/app/helpers/barcode_labels_helper.rb @@ -24,7 +24,7 @@ def barcode_printing_form( end def printers_of_type(printer_types) - @printers.select { |printer| printer_types.include?(printer.type_name) } # rubocop:todo Rails/HelperInstanceVariable + @printers.select { |printer| printer_types.include?(printer.barcode_type) } # rubocop:todo Rails/HelperInstanceVariable end def useful_barcode(barcode) diff --git a/spec/factories/barcode_printer_factories.rb b/spec/factories/barcode_printer_factories.rb index 8591b723a..28dec7b43 100644 --- a/spec/factories/barcode_printer_factories.rb +++ b/spec/factories/barcode_printer_factories.rb @@ -9,14 +9,14 @@ sequence(:id, &:to_s) sequence(:name) { |n| "Barcode Printer #{n}" } print_service { 'PMB' } - type_name { nil } + barcode_type { nil } factory :v2_plate_barcode_printer do - type_name { '96 Well Plate' } + barcode_type { '96 Well Plate' } end factory :v2_tube_barcode_printer do - type_name { '1D Tube' } + barcode_type { '1D Tube' } end end end diff --git a/spec/helpers/barcode_labels_helper_spec.rb b/spec/helpers/barcode_labels_helper_spec.rb index 1599e2a42..8f86888b4 100644 --- a/spec/helpers/barcode_labels_helper_spec.rb +++ b/spec/helpers/barcode_labels_helper_spec.rb @@ -38,7 +38,7 @@ ) printer_types = labels.map(&:printer_type) - printers = @printers.select { |printer| printer_types.include?(printer.type_name) } + printers = @printers.select { |printer| printer_types.include?(printer.barcode_type) } expect(rendered).to include(printers[0].name) expect(rendered).to include(printers[1].name) From 4004e22408a3e63ce6d09ff35497e9eca0f0e4d2 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Wed, 24 Jul 2024 15:33:03 +0100 Subject: [PATCH 04/70] Remove unused test variable --- spec/features/charge_and_pass_libraries_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/features/charge_and_pass_libraries_spec.rb b/spec/features/charge_and_pass_libraries_spec.rb index e1fa03e35..26518e966 100644 --- a/spec/features/charge_and_pass_libraries_spec.rb +++ b/spec/features/charge_and_pass_libraries_spec.rb @@ -10,7 +10,6 @@ let(:user_swipecard) { 'abcdef' } let(:labware_barcode) { SBCF::SangerBarcode.new(prefix: 'DN', number: 1).machine_barcode.to_s } let(:labware_uuid) { SecureRandom.uuid } - let(:default_tube_printer) { 'tube printer 1' } let(:work_completion_request) do { 'work_completion' => { target: labware_uuid, submissions: submissions, user: user_uuid } } end From bc41bfcfcfe7e5d65c2297f4903f687d81535c81 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 25 Jul 2024 15:18:09 +0100 Subject: [PATCH 05/70] Update the devour config file Only just found out about it and it looks like it hasn't been done by anyone in recent times. --- app/javascript/shared/resources.js | 1661 ++++++++++++++++------------ 1 file changed, 945 insertions(+), 716 deletions(-) diff --git a/app/javascript/shared/resources.js b/app/javascript/shared/resources.js index 122a55e94..453b9c851 100644 --- a/app/javascript/shared/resources.js +++ b/app/javascript/shared/resources.js @@ -1,6 +1,6 @@ /* - * Auto-generated by Sequencescape on 2022-01-21 11:24:03 +0000" - * Using dpl098_lca_dna_rna_setup@807ca72 + * Auto-generated by Sequencescape on 2024-07-25 15:16:51 +0100" + * Using Y24-190-2-support-limber-labware-metadata-in-api-v2@6466af5 * bundle exec rake devour:create_config" * */ @@ -9,836 +9,1065 @@ /* eslint quotes: ["error", "double"] */ const resources = [ { - resource: "aliquot", - attributes: { - tag_oligo: "", - tag_index: "", - tag2_oligo: "", - tag2_index: "", - suboptimal: "", - library_type: "", - study: { - jsonApi: "hasOne", - type: "study", - }, - project: { - jsonApi: "hasOne", - type: "project", - }, - sample: { - jsonApi: "hasOne", - type: "sample", - }, - request: { - jsonApi: "hasOne", - type: "request", - }, + "resource": "aliquot", + "attributes": { + "tag_oligo": "", + "tag_index": "", + "tag2_oligo": "", + "tag2_index": "", + "suboptimal": "", + "library_type": "", + "insert_size_to": "", + "study": { + "jsonApi": "hasOne", + "type": "study" + }, + "project": { + "jsonApi": "hasOne", + "type": "project" + }, + "sample": { + "jsonApi": "hasOne", + "type": "sample" + }, + "request": { + "jsonApi": "hasOne", + "type": "request" + }, + "receptacle": { + "jsonApi": "hasOne", + "type": "receptacle" + }, + "tag": { + "jsonApi": "hasOne", + "type": "tag" + }, + "tag2": { + "jsonApi": "hasOne", + "type": "tag" + }, + "library": { + "jsonApi": "hasOne", + "type": "receptacle" + } }, - options: {}, + "options": { + } }, { - resource: "asset", - attributes: { - uuid: "", - custom_metadatum_collection: { - jsonApi: "hasOne", - type: "custom_metadatum_collection", - }, - comments: { - jsonApi: "hasMany", - type: "comment", - }, + "resource": "asset_audit", + "attributes": { + "key": "", + "message": "", + "created_by": "", + "asset_uuid": "", + "witnessed_by": "", + "metadata": "" }, - options: {}, + "options": { + } }, { - resource: "comment", - attributes: { - title: "", - description: "", - created_at: "", - updated_at: "", - user: { - jsonApi: "hasOne", - type: "user", - }, - commentable: { - jsonApi: "hasOne", - }, + "resource": "asset", + "attributes": { + "uuid": "", + "custom_metadatum_collection": { + "jsonApi": "hasOne", + "type": "custom_metadatum_collection" + }, + "comments": { + "jsonApi": "hasMany", + "type": "comment" + } }, - options: {}, + "options": { + } }, { - resource: "custom_metadatum_collection", - attributes: { - uuid: "", - user_id: "", - asset_id: "", - metadata: {}, + "resource": "barcode_printer", + "attributes": { + "name": "", + "uuid": "", + "print_service": "", + "barcode_type": "" }, - options: {}, + "options": { + } }, { - resource: "labware", - attributes: { - uuid: "", - created_at: "", - purpose: { - jsonApi: "hasOne", - type: "purpose", - }, - custom_metadatum_collection: { - jsonApi: "hasOne", - type: "custom_metadatum_collection", - }, - comments: { - jsonApi: "hasMany", - type: "comment", - }, - direct_submissions: { - jsonApi: "hasMany", - type: "submission", - }, - state_changes: { - jsonApi: "hasMany", - type: "state_change", - }, - ancestors: { - jsonApi: "hasMany", - }, - descendants: { - jsonApi: "hasMany", - }, - parents: { - jsonApi: "hasMany", - }, - children: { - jsonApi: "hasMany", - }, + "resource": "comment", + "attributes": { + "title": "", + "description": "", + "created_at": "", + "updated_at": "", + "user": { + "jsonApi": "hasOne", + "type": "user" + }, + "commentable": { + "jsonApi": "hasOne" + } }, - options: {}, + "options": { + } }, { - resource: "lane", - attributes: { - uuid: "", - name: "", - samples: { - jsonApi: "hasMany", - type: "sample", - }, - studies: { - jsonApi: "hasMany", - type: "study", - }, - projects: { - jsonApi: "hasMany", - type: "project", - }, + "resource": "custom_metadatum_collection", + "attributes": { + "uuid": "", + "user_id": "", + "asset_id": "", + "metadata": "" }, - options: {}, + "options": { + } }, { - resource: "lot", - attributes: { - uuid: "", - lot_number: "", - lot_type: { - jsonApi: "hasOne", - type: "lot_type", - }, - user: { - jsonApi: "hasOne", - type: "user", - }, - template: { - jsonApi: "hasOne", - }, - tag_layout_template: { - jsonApi: "hasOne", - type: "tag_layout_template", - }, + "resource": "labware", + "attributes": { + "uuid": "", + "name": "", + "labware_barcode": "", + "state": "", + "created_at": "", + "updated_at": "", + "purpose": { + "jsonApi": "hasOne", + "type": "purpose" + }, + "custom_metadatum_collection": { + "jsonApi": "hasOne", + "type": "custom_metadatum_collection" + }, + "samples": { + "jsonApi": "hasMany", + "type": "sample" + }, + "studies": { + "jsonApi": "hasMany", + "type": "study" + }, + "projects": { + "jsonApi": "hasMany", + "type": "project" + }, + "comments": { + "jsonApi": "hasMany", + "type": "comment" + }, + "receptacles": { + "jsonApi": "hasMany" + }, + "ancestors": { + "jsonApi": "hasMany" + }, + "descendants": { + "jsonApi": "hasMany" + }, + "parents": { + "jsonApi": "hasMany" + }, + "children": { + "jsonApi": "hasMany" + }, + "child_plates": { + "jsonApi": "hasMany", + "type": "plate" + }, + "child_tubes": { + "jsonApi": "hasMany", + "type": "tube" + }, + "direct_submissions": { + "jsonApi": "hasMany", + "type": "submission" + }, + "state_changes": { + "jsonApi": "hasMany", + "type": "state_change" + } }, - options: {}, + "options": { + } }, { - resource: "lot_type", - attributes: { - uuid: "", - name: "", - template_type: "", - target_purpose: { - jsonApi: "hasOne", - type: "purpose", - }, + "resource": "lane", + "attributes": { + "uuid": "", + "name": "", + "samples": { + "jsonApi": "hasMany", + "type": "sample" + }, + "studies": { + "jsonApi": "hasMany", + "type": "study" + }, + "projects": { + "jsonApi": "hasMany", + "type": "project" + } }, - options: {}, + "options": { + } }, { - resource: "order", - attributes: { - uuid: "", + "resource": "lot", + "attributes": { + "uuid": "", + "lot_number": "", + "lot_type": { + "jsonApi": "hasOne", + "type": "lot_type" + }, + "user": { + "jsonApi": "hasOne", + "type": "user" + }, + "template": { + "jsonApi": "hasOne" + }, + "tag_layout_template": { + "jsonApi": "hasOne", + "type": "tag_layout_template" + } }, - options: {}, + "options": { + } }, { - resource: "pick_list", - attributes: { - created_at: "", - updated_at: "", - state: "", - links: "", - pick_attributes: "", - labware_pick_attributes: "", - asynchronous: "", + "resource": "lot_type", + "attributes": { + "uuid": "", + "name": "", + "template_type": "", + "target_purpose": { + "jsonApi": "hasOne", + "type": "purpose" + } }, - options: {}, + "options": { + } }, { - resource: "plate", - attributes: { - uuid: "", - name: "", - labware_barcode: "", - state: "", - number_of_rows: "", - number_of_columns: "", - size: "", - created_at: "", - updated_at: "", - purpose: { - jsonApi: "hasOne", - type: "purpose", - }, - custom_metadatum_collection: { - jsonApi: "hasOne", - type: "custom_metadatum_collection", - }, - samples: { - jsonApi: "hasMany", - type: "sample", - }, - studies: { - jsonApi: "hasMany", - type: "study", - }, - projects: { - jsonApi: "hasMany", - type: "project", - }, - wells: { - jsonApi: "hasMany", - type: "well", - }, - comments: { - jsonApi: "hasMany", - type: "comment", - }, - ancestors: { - jsonApi: "hasMany", - }, - descendants: { - jsonApi: "hasMany", - }, - parents: { - jsonApi: "hasMany", - }, - children: { - jsonApi: "hasMany", - }, - child_plates: { - jsonApi: "hasMany", - type: "plate", - }, - child_tubes: { - jsonApi: "hasMany", - type: "tube", - }, - direct_submissions: { - jsonApi: "hasMany", - type: "submission", - }, - state_changes: { - jsonApi: "hasMany", - type: "state_change", - }, + "resource": "order", + "attributes": { + "uuid": "", + "request_options": "" }, - options: {}, + "options": { + } }, { - resource: "plate_template", - attributes: { - uuid: "", + "resource": "pick_list", + "attributes": { + "created_at": "", + "updated_at": "", + "state": "", + "links": "", + "pick_attributes": "", + "labware_pick_attributes": "", + "asynchronous": "" }, - options: {}, + "options": { + } }, { - resource: "pre_capture_pool", - attributes: { - uuid: "", + "resource": "plate_purpose", + "attributes": { + "name": "", + "stock_plate": "", + "cherrypickable_target": "", + "input_plate": "", + "size": "", + "asset_shape": "", + "uuid": "" }, - options: {}, + "options": { + } }, { - resource: "primer_panel", - attributes: { - name: "", - programs: "", + "resource": "plate", + "attributes": { + "uuid": "", + "name": "", + "labware_barcode": "", + "state": "", + "created_at": "", + "updated_at": "", + "number_of_rows": "", + "number_of_columns": "", + "size": "", + "purpose": { + "jsonApi": "hasOne", + "type": "purpose" + }, + "custom_metadatum_collection": { + "jsonApi": "hasOne", + "type": "custom_metadatum_collection" + }, + "samples": { + "jsonApi": "hasMany", + "type": "sample" + }, + "studies": { + "jsonApi": "hasMany", + "type": "study" + }, + "projects": { + "jsonApi": "hasMany", + "type": "project" + }, + "comments": { + "jsonApi": "hasMany", + "type": "comment" + }, + "receptacles": { + "jsonApi": "hasMany" + }, + "ancestors": { + "jsonApi": "hasMany" + }, + "descendants": { + "jsonApi": "hasMany" + }, + "parents": { + "jsonApi": "hasMany" + }, + "children": { + "jsonApi": "hasMany" + }, + "child_plates": { + "jsonApi": "hasMany", + "type": "plate" + }, + "child_tubes": { + "jsonApi": "hasMany", + "type": "tube" + }, + "direct_submissions": { + "jsonApi": "hasMany", + "type": "submission" + }, + "state_changes": { + "jsonApi": "hasMany", + "type": "state_change" + }, + "wells": { + "jsonApi": "hasMany", + "type": "well" + } }, - options: {}, + "options": { + } }, { - resource: "project", - attributes: { - name: "", - cost_code: "", - uuid: "", + "resource": "plate_template", + "attributes": { + "uuid": "" }, - options: {}, + "options": { + } }, { - resource: "purpose", - attributes: { - uuid: "", - name: "", - size: "", + "resource": "poly_metadatum", + "attributes": { + "key": "", + "value": "", + "created_at": "", + "updated_at": "", + "metadatable": { + "jsonApi": "hasOne" + } }, - options: {}, + "options": { + } }, { - resource: "qc_assay", - attributes: { - lot_number: "", - qc_results: { - jsonApi: "hasMany", - type: "qc_result", - }, + "resource": "pre_capture_pool", + "attributes": { + "uuid": "" }, - options: {}, + "options": { + } }, { - resource: "qc_result", - attributes: { - key: "", - value: "", - units: "", - cv: "", - assay_type: "", - assay_version: "", - created_at: "", - asset: { - jsonApi: "hasOne", - type: "receptacle", - }, + "resource": "primer_panel", + "attributes": { + "name": "", + "programs": "" }, - options: {}, + "options": { + } }, { - resource: "qcable", - attributes: { - uuid: "", - state: "", - labware_barcode: "", - lot: { - jsonApi: "hasOne", - type: "lot", - }, - asset: { - jsonApi: "hasOne", - }, + "resource": "project", + "attributes": { + "name": "", + "cost_code": "", + "uuid": "" }, - options: {}, + "options": { + } }, { - resource: "racked_tube", - attributes: { - coordinate: "", - tube: { - jsonApi: "hasOne", - type: "tube", - }, - tube_rack: { - jsonApi: "hasOne", - type: "tube_rack", - }, + "resource": "purpose", + "attributes": { + "uuid": "", + "name": "", + "size": "", + "lifespan": "" }, - options: {}, + "options": { + } }, { - resource: "receptacle", - attributes: { - uuid: "", - name: "", - pcr_cycles: "", - submit_for_sequencing: "", - sub_pool: "", - coverage: "", - diluent_volume: "", - samples: { - jsonApi: "hasMany", - type: "sample", - }, - studies: { - jsonApi: "hasMany", - type: "study", - }, - projects: { - jsonApi: "hasMany", - type: "project", - }, - requests_as_source: { - jsonApi: "hasMany", - type: "request", - }, - requests_as_target: { - jsonApi: "hasMany", - type: "request", - }, - qc_results: { - jsonApi: "hasMany", - type: "qc_result", - }, - aliquots: { - jsonApi: "hasMany", - type: "aliquot", - }, - downstream_assets: { - jsonApi: "hasMany", - }, - downstream_wells: { - jsonApi: "hasMany", - type: "well", - }, - downstream_plates: { - jsonApi: "hasMany", - type: "plate", - }, - downstream_tubes: { - jsonApi: "hasMany", - type: "tube", - }, - upstream_assets: { - jsonApi: "hasMany", - }, - upstream_wells: { - jsonApi: "hasMany", - type: "well", - }, - upstream_plates: { - jsonApi: "hasMany", - type: "plate", - }, - upstream_tubes: { - jsonApi: "hasMany", - type: "tube", - }, + "resource": "qc_assay", + "attributes": { + "lot_number": "", + "qc_results": { + "jsonApi": "hasMany", + "type": "qc_result" + } }, - options: {}, + "options": { + } }, { - resource: "request", - attributes: { - uuid: "", - role: "", - state: "", - priority: "", - options: "", - library_type: "", - submission: { - jsonApi: "hasOne", - type: "submission", - }, - order: { - jsonApi: "hasOne", - type: "order", - }, - request_type: { - jsonApi: "hasOne", - type: "request_type", - }, - primer_panel: { - jsonApi: "hasOne", - type: "primer_panel", - }, - pre_capture_pool: { - jsonApi: "hasOne", - type: "pre_capture_pool", - }, + "resource": "qc_result", + "attributes": { + "key": "", + "value": "", + "units": "", + "cv": "", + "assay_type": "", + "assay_version": "", + "created_at": "", + "asset": { + "jsonApi": "hasOne", + "type": "receptacle" + } }, - options: {}, + "options": { + } }, { - resource: "request_type", - attributes: { - uuid: "", - name: "", - key: "", - for_multiplexing: "", + "resource": "qcable", + "attributes": { + "uuid": "", + "state": "", + "labware_barcode": "", + "lot": { + "jsonApi": "hasOne", + "type": "lot" + }, + "asset": { + "jsonApi": "hasOne" + } }, - options: {}, + "options": { + } }, { - resource: "sample_manifest", - attributes: { - supplier_name: "", + "resource": "racked_tube", + "attributes": { + "coordinate": "", + "tube": { + "jsonApi": "hasOne", + "type": "tube" + }, + "tube_rack": { + "jsonApi": "hasOne", + "type": "tube_rack" + } }, - options: {}, + "options": { + } }, { - resource: "sample_metadata", - attributes: { - sample_common_name: "", - supplier_name: "", - collected_by: "" + "resource": "receptacle", + "attributes": { + "uuid": "", + "name": "", + "pcr_cycles": "", + "submit_for_sequencing": "", + "sub_pool": "", + "coverage": "", + "diluent_volume": "", + "state": "", + "samples": { + "jsonApi": "hasMany", + "type": "sample" + }, + "studies": { + "jsonApi": "hasMany", + "type": "study" + }, + "projects": { + "jsonApi": "hasMany", + "type": "project" + }, + "requests_as_source": { + "jsonApi": "hasMany", + "type": "request" + }, + "requests_as_target": { + "jsonApi": "hasMany", + "type": "request" + }, + "qc_results": { + "jsonApi": "hasMany", + "type": "qc_result" + }, + "aliquots": { + "jsonApi": "hasMany", + "type": "aliquot" + }, + "downstream_assets": { + "jsonApi": "hasMany" + }, + "downstream_wells": { + "jsonApi": "hasMany", + "type": "well" + }, + "downstream_plates": { + "jsonApi": "hasMany", + "type": "plate" + }, + "downstream_tubes": { + "jsonApi": "hasMany", + "type": "tube" + }, + "upstream_assets": { + "jsonApi": "hasMany" + }, + "upstream_wells": { + "jsonApi": "hasMany", + "type": "well" + }, + "upstream_plates": { + "jsonApi": "hasMany", + "type": "plate" + }, + "upstream_tubes": { + "jsonApi": "hasMany", + "type": "tube" + }, + "transfer_requests_as_source": { + "jsonApi": "hasMany", + "type": "transfer_request" + }, + "transfer_requests_as_target": { + "jsonApi": "hasMany", + "type": "transfer_request" + }, + "labware": { + "jsonApi": "hasOne", + "type": "labware" + } }, - options: {}, + "options": { + } }, { - resource: "sample", - attributes: { - name: "", - sanger_sample_id: "", - uuid: "", - control: "", - control_type: "", - sample_metadata: { - jsonApi: "hasOne", - type: "sample_metadata", - }, - sample_manifest: { - jsonApi: "hasOne", - type: "sample_manifest", - }, - component_samples: { - jsonApi: "hasMany", - type: "sample", - }, + "resource": "request", + "attributes": { + "uuid": "", + "role": "", + "state": "", + "priority": "", + "options": "", + "library_type": "", + "submission": { + "jsonApi": "hasOne", + "type": "submission" + }, + "order": { + "jsonApi": "hasOne", + "type": "order" + }, + "request_type": { + "jsonApi": "hasOne", + "type": "request_type" + }, + "primer_panel": { + "jsonApi": "hasOne", + "type": "primer_panel" + }, + "pre_capture_pool": { + "jsonApi": "hasOne", + "type": "pre_capture_pool" + }, + "poly_metadata": { + "jsonApi": "hasMany", + "type": "poly_metadatum" + } }, - options: {}, + "options": { + } }, { - resource: "state_change", - attributes: { - previous_state: "", - target_state: "", - created_at: "", - updated_at: "", - labware: { - jsonApi: "hasOne", - type: "labware", - }, + "resource": "request_type", + "attributes": { + "uuid": "", + "name": "", + "key": "", + "for_multiplexing": "" }, - options: {}, + "options": { + } }, { - resource: "study", - attributes: { - name: "", - uuid: "", + "resource": "sample_manifest", + "attributes": { + "supplier_name": "" }, - options: {}, + "options": { + } }, { - resource: "submission", - attributes: { - uuid: "", - name: "", - state: "", - created_at: "", - updated_at: "", - used_tags: "", + "resource": "sample_metadata", + "attributes": { + "sample_common_name": "", + "supplier_name": "", + "collected_by": "", + "cohort": "", + "sample_description": "", + "donor_id": "", + "concentration": "", + "volume": "" }, - options: {}, + "options": { + } }, { - resource: "tag_group_adapter_type", - attributes: { - name: "", - tag_groups: { - jsonApi: "hasMany", - type: "tag_group", - }, + "resource": "sample", + "attributes": { + "name": "", + "sanger_sample_id": "", + "uuid": "", + "control": "", + "control_type": "", + "sample_metadata": { + "jsonApi": "hasOne", + "type": "sample_metadata" + }, + "sample_manifest": { + "jsonApi": "hasOne", + "type": "sample_manifest" + }, + "studies": { + "jsonApi": "hasMany", + "type": "study" + }, + "component_samples": { + "jsonApi": "hasMany", + "type": "sample" + } }, - options: {}, + "options": { + } }, { - resource: "tag_group", - attributes: { - uuid: "", - name: "", - tags: "", - tag_group_adapter_type: { - jsonApi: "hasOne", - type: "tag_group_adapter_type", - }, + "resource": "state_change", + "attributes": { + "previous_state": "", + "target_state": "", + "created_at": "", + "updated_at": "", + "labware": { + "jsonApi": "hasOne", + "type": "labware" + } }, - options: {}, + "options": { + } }, { - resource: "tag_layout_template", - attributes: { - uuid: "", - direction: "", - walking_by: "", - tag_group: { - jsonApi: "hasOne", - type: "tag_group", - }, - tag2_group: { - jsonApi: "hasOne", - type: "tag_group", - }, + "resource": "study", + "attributes": { + "name": "", + "uuid": "", + "poly_metadata": { + "jsonApi": "hasMany", + "type": "poly_metadatum" + } }, - options: {}, + "options": { + } }, { - resource: "transfer_request", - attributes: { - uuid: "", - state: "", - volume: "", - target_asset: { - jsonApi: "hasOne", - type: "receptacle", - }, - source_asset: { - jsonApi: "hasOne", - type: "receptacle", - }, - submission: { - jsonApi: "hasOne", - type: "submission", - }, + "resource": "submission", + "attributes": { + "uuid": "", + "name": "", + "state": "", + "created_at": "", + "updated_at": "", + "used_tags": "", + "lanes_of_sequencing": "" }, - options: {}, + "options": { + } }, { - resource: "tube_rack", - attributes: { - uuid: "", - created_at: "", - updated_at: "", - labware_barcode: "", - size: "", - number_of_rows: "", - number_of_columns: "", - name: "", - tube_locations: "", - racked_tubes: { - jsonApi: "hasMany", - type: "racked_tube", - }, - comments: { - jsonApi: "hasMany", - type: "comment", - }, - purpose: { - jsonApi: "hasOne", - type: "purpose", - }, + "resource": "submission_template", + "attributes": { + "name": "", + "uuid": "" }, - options: {}, + "options": { + } }, { - resource: "tube_rack_status", - attributes: { - uuid: "", + "resource": "tag_group_adapter_type", + "attributes": { + "name": "", + "tag_groups": { + "jsonApi": "hasMany", + "type": "tag_group" + } }, - options: {}, + "options": { + } }, { - resource: "tube", - attributes: { - uuid: "", - name: "", - labware_barcode: "", - state: "", - created_at: "", - updated_at: "", - purpose: { - jsonApi: "hasOne", - type: "purpose", - }, - custom_metadatum_collection: { - jsonApi: "hasOne", - type: "custom_metadatum_collection", - }, - samples: { - jsonApi: "hasMany", - type: "sample", - }, - studies: { - jsonApi: "hasMany", - type: "study", - }, - projects: { - jsonApi: "hasMany", - type: "project", - }, - aliquots: { - jsonApi: "hasMany", - type: "aliquot", - }, - direct_submissions: { - jsonApi: "hasMany", - type: "submission", - }, - ancestors: { - jsonApi: "hasMany", - }, - descendants: { - jsonApi: "hasMany", - }, - parents: { - jsonApi: "hasMany", - }, - children: { - jsonApi: "hasMany", - }, - child_plates: { - jsonApi: "hasMany", - type: "plate", - }, - child_tubes: { - jsonApi: "hasMany", - type: "tube", - }, - comments: { - jsonApi: "hasMany", - type: "comment", - }, - state_changes: { - jsonApi: "hasMany", - type: "state_change", - }, - transfer_requests_as_target: { - jsonApi: "hasMany", - type: "transfer_request", - }, - receptacle: { - jsonApi: "hasOne", - type: "receptacle", - }, + "resource": "tag_group", + "attributes": { + "uuid": "", + "name": "", + "tags": "", + "tag_group_adapter_type": { + "jsonApi": "hasOne", + "type": "tag_group_adapter_type" + } }, - options: {}, + "options": { + } }, { - resource: "user", - attributes: { - uuid: "", - login: "", - first_name: "", - last_name: "", + "resource": "tag_layout_template", + "attributes": { + "uuid": "", + "direction": "", + "walking_by": "", + "tag_group": { + "jsonApi": "hasOne", + "type": "tag_group" + }, + "tag2_group": { + "jsonApi": "hasOne", + "type": "tag_group" + } }, - options: {}, + "options": { + } }, { - resource: "well", - attributes: { - uuid: "", - name: "", - position: "", - state: "", - pcr_cycles: "", - submit_for_sequencing: "", - sub_pool: "", - coverage: "", - diluent_volume: "", - samples: { - jsonApi: "hasMany", - type: "sample", - }, - studies: { - jsonApi: "hasMany", - type: "study", - }, - projects: { - jsonApi: "hasMany", - type: "project", - }, - qc_results: { - jsonApi: "hasMany", - type: "qc_result", - }, - requests_as_source: { - jsonApi: "hasMany", - type: "request", - }, - requests_as_target: { - jsonApi: "hasMany", - type: "request", - }, - aliquots: { - jsonApi: "hasMany", - type: "aliquot", - }, - downstream_assets: { - jsonApi: "hasMany", - }, - downstream_wells: { - jsonApi: "hasMany", - type: "well", - }, - downstream_plates: { - jsonApi: "hasMany", - type: "plate", - }, - downstream_tubes: { - jsonApi: "hasMany", - type: "tube", - }, - upstream_assets: { - jsonApi: "hasMany", - }, - upstream_wells: { - jsonApi: "hasMany", - type: "well", - }, - upstream_plates: { - jsonApi: "hasMany", - type: "plate", - }, - upstream_tubes: { - jsonApi: "hasMany", - type: "tube", - }, - transfer_requests_as_source: { - jsonApi: "hasMany", - type: "transfer_request", - }, - transfer_requests_as_target: { - jsonApi: "hasMany", - type: "transfer_request", - }, + "resource": "tag", + "attributes": { + "oligo": "", + "map_id": "", + "tag_group": { + "jsonApi": "hasOne", + "type": "tag_group" + } }, - options: {}, + "options": { + } }, { - resource: "work_order", - attributes: { - order_type: "", - quantity: "", - state: "", - options: "", - at_risk: "", - study: { - jsonApi: "hasOne", - type: "study", - }, - project: { - jsonApi: "hasOne", - type: "project", - }, - source_receptacle: { - jsonApi: "hasOne", - }, - samples: { - jsonApi: "hasMany", - type: "sample", - }, + "resource": "transfer_request", + "attributes": { + "uuid": "", + "state": "", + "volume": "", + "target_asset": { + "jsonApi": "hasOne", + "type": "receptacle" + }, + "source_asset": { + "jsonApi": "hasOne", + "type": "receptacle" + }, + "submission": { + "jsonApi": "hasOne", + "type": "submission" + } + }, + "options": { + } + }, + { + "resource": "transfer_template", + "attributes": { + "name": "", + "uuid": "" + }, + "options": { + } + }, + { + "resource": "tube_purpose", + "attributes": { + "name": "", + "purpose_type": "", + "target_type": "" + }, + "options": { + } + }, + { + "resource": "tube_rack", + "attributes": { + "uuid": "", + "created_at": "", + "updated_at": "", + "labware_barcode": "", + "size": "", + "number_of_rows": "", + "number_of_columns": "", + "name": "", + "tube_locations": "", + "racked_tubes": { + "jsonApi": "hasMany", + "type": "racked_tube" + }, + "comments": { + "jsonApi": "hasMany", + "type": "comment" + }, + "purpose": { + "jsonApi": "hasOne", + "type": "purpose" + } + }, + "options": { + } + }, + { + "resource": "tube_rack_status", + "attributes": { + "uuid": "" + }, + "options": { + } + }, + { + "resource": "tube", + "attributes": { + "uuid": "", + "name": "", + "labware_barcode": "", + "state": "", + "created_at": "", + "updated_at": "", + "purpose": { + "jsonApi": "hasOne", + "type": "purpose" + }, + "custom_metadatum_collection": { + "jsonApi": "hasOne", + "type": "custom_metadatum_collection" + }, + "samples": { + "jsonApi": "hasMany", + "type": "sample" + }, + "studies": { + "jsonApi": "hasMany", + "type": "study" + }, + "projects": { + "jsonApi": "hasMany", + "type": "project" + }, + "comments": { + "jsonApi": "hasMany", + "type": "comment" + }, + "receptacles": { + "jsonApi": "hasMany" + }, + "ancestors": { + "jsonApi": "hasMany" + }, + "descendants": { + "jsonApi": "hasMany" + }, + "parents": { + "jsonApi": "hasMany" + }, + "children": { + "jsonApi": "hasMany" + }, + "child_plates": { + "jsonApi": "hasMany", + "type": "plate" + }, + "child_tubes": { + "jsonApi": "hasMany", + "type": "tube" + }, + "direct_submissions": { + "jsonApi": "hasMany", + "type": "submission" + }, + "state_changes": { + "jsonApi": "hasMany", + "type": "state_change" + }, + "aliquots": { + "jsonApi": "hasMany", + "type": "aliquot" + }, + "transfer_requests_as_target": { + "jsonApi": "hasMany", + "type": "transfer_request" + }, + "receptacle": { + "jsonApi": "hasOne", + "type": "receptacle" + } + }, + "options": { + } + }, + { + "resource": "user", + "attributes": { + "uuid": "", + "login": "", + "first_name": "", + "last_name": "" }, - options: {}, + "options": { + } }, + { + "resource": "volume_update", + "attributes": { + "created_by": "", + "target_uuid": "", + "volume_change": "" + }, + "options": { + } + }, + { + "resource": "well", + "attributes": { + "uuid": "", + "name": "", + "pcr_cycles": "", + "submit_for_sequencing": "", + "sub_pool": "", + "coverage": "", + "diluent_volume": "", + "state": "", + "position": "", + "samples": { + "jsonApi": "hasMany", + "type": "sample" + }, + "studies": { + "jsonApi": "hasMany", + "type": "study" + }, + "projects": { + "jsonApi": "hasMany", + "type": "project" + }, + "requests_as_source": { + "jsonApi": "hasMany", + "type": "request" + }, + "requests_as_target": { + "jsonApi": "hasMany", + "type": "request" + }, + "qc_results": { + "jsonApi": "hasMany", + "type": "qc_result" + }, + "aliquots": { + "jsonApi": "hasMany", + "type": "aliquot" + }, + "downstream_assets": { + "jsonApi": "hasMany" + }, + "downstream_wells": { + "jsonApi": "hasMany", + "type": "well" + }, + "downstream_plates": { + "jsonApi": "hasMany", + "type": "plate" + }, + "downstream_tubes": { + "jsonApi": "hasMany", + "type": "tube" + }, + "upstream_assets": { + "jsonApi": "hasMany" + }, + "upstream_wells": { + "jsonApi": "hasMany", + "type": "well" + }, + "upstream_plates": { + "jsonApi": "hasMany", + "type": "plate" + }, + "upstream_tubes": { + "jsonApi": "hasMany", + "type": "tube" + }, + "transfer_requests_as_source": { + "jsonApi": "hasMany", + "type": "transfer_request" + }, + "transfer_requests_as_target": { + "jsonApi": "hasMany", + "type": "transfer_request" + }, + "labware": { + "jsonApi": "hasOne", + "type": "labware" + } + }, + "options": { + } + }, + { + "resource": "work_order", + "attributes": { + "order_type": "", + "quantity": "", + "state": "", + "options": "", + "at_risk": "", + "study": { + "jsonApi": "hasOne", + "type": "study" + }, + "project": { + "jsonApi": "hasOne", + "type": "project" + }, + "source_receptacle": { + "jsonApi": "hasOne" + }, + "samples": { + "jsonApi": "hasMany", + "type": "sample" + } + }, + "options": { + } + } ] export default resources From 6440fb319bae6ac377d490d2908d780690d9b1f6 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 26 Jul 2024 09:02:47 +0100 Subject: [PATCH 06/70] Remove v1 API from LabwareController --- app/controllers/labware_controller.rb | 2 +- app/models/labels/plate_split.rb | 2 +- .../plate_split_to_tube_racks.rb | 2 +- .../labware_creators/pooled_tubes_base.rb | 4 +-- .../labware_creators/quadrant_split_plate.rb | 6 ++--- .../labware_creators/quadrant_stamp_base.rb | 2 +- app/models/labware_metadata.rb | 27 ++++++++----------- app/models/presenters/presenter.rb | 4 +-- .../robots/bed/plate_to_tube_racks_bed.rb | 4 +-- 9 files changed, 22 insertions(+), 31 deletions(-) diff --git a/app/controllers/labware_controller.rb b/app/controllers/labware_controller.rb index b5d189cd3..baede85e0 100644 --- a/app/controllers/labware_controller.rb +++ b/app/controllers/labware_controller.rb @@ -89,6 +89,6 @@ def state_changer_for(purpose_uuid, labware_uuid) end def presenter_for(labware) - Presenters.lookup_for(labware).new(api: api, labware: labware) + Presenters.lookup_for(labware).new(labware: labware) end end diff --git a/app/models/labels/plate_split.rb b/app/models/labels/plate_split.rb index cc8882f30..dacc1a7b4 100644 --- a/app/models/labels/plate_split.rb +++ b/app/models/labels/plate_split.rb @@ -19,7 +19,7 @@ def stock_plate_barcode def stock_plate_barcode_getter api = Sequencescape::Api.new(Limber::Application.config.api.v1.connection_options.dup) - metadata = LabwareMetadata.new(api: api, barcode: labware.barcode.machine).metadata + metadata = LabwareMetadata.new(barcode: labware.barcode.machine).metadata barcode = 'N/A' barcode = metadata.fetch('stock_barcode', barcode) unless metadata.nil? barcode diff --git a/app/models/labware_creators/plate_split_to_tube_racks.rb b/app/models/labware_creators/plate_split_to_tube_racks.rb index 8dcbd7186..87e7e5dd3 100644 --- a/app/models/labware_creators/plate_split_to_tube_racks.rb +++ b/app/models/labware_creators/plate_split_to_tube_racks.rb @@ -652,7 +652,7 @@ def add_contingency_tube_metadata # @return [void] def add_tube_metadata(child_tube, tube_posn, tube_details) LabwareMetadata - .new(api: api, user: user_uuid, barcode: child_tube.barcode.machine) + .new(user: user_uuid, barcode: child_tube.barcode.machine) .update!(tube_rack_barcode: tube_details['tube_rack_barcode'], tube_rack_position: tube_posn) end diff --git a/app/models/labware_creators/pooled_tubes_base.rb b/app/models/labware_creators/pooled_tubes_base.rb index 7dae13389..4d071645d 100644 --- a/app/models/labware_creators/pooled_tubes_base.rb +++ b/app/models/labware_creators/pooled_tubes_base.rb @@ -94,9 +94,9 @@ def metadata_stock_barcode def parent_metadata if parent.is_a? Limber::Plate - LabwareMetadata.new(api: api, labware: parent).metadata + LabwareMetadata.new(labware: parent).metadata else - LabwareMetadata.new(api: api, barcode: parent.barcode.machine).metadata + LabwareMetadata.new(barcode: parent.barcode.machine).metadata end || {} end diff --git a/app/models/labware_creators/quadrant_split_plate.rb b/app/models/labware_creators/quadrant_split_plate.rb index b13352824..257013290 100644 --- a/app/models/labware_creators/quadrant_split_plate.rb +++ b/app/models/labware_creators/quadrant_split_plate.rb @@ -42,12 +42,10 @@ def transfer_request_attributes(child_plates) def add_stock_barcode_metadata(plates) # rubocop:todo Metrics/AbcSize merger_plate = parent.ancestors.where(purpose_name: SearchHelper.merger_plate_names).first - metadata = LabwareMetadata.new(api: api, barcode: merger_plate.barcode.machine).metadata + metadata = LabwareMetadata.new(barcode: merger_plate.barcode.machine).metadata plates.each_with_index do |plate, index| stock_barcode = stock_barcode_from_quadrant(index, metadata) || "* #{plate.barcode.human}" - LabwareMetadata - .new(api: api, user: user_uuid, barcode: plate.barcode.machine) - .update!(stock_barcode: stock_barcode) + LabwareMetadata.new(user: user_uuid, barcode: plate.barcode.machine).update!(stock_barcode: stock_barcode) end end diff --git a/app/models/labware_creators/quadrant_stamp_base.rb b/app/models/labware_creators/quadrant_stamp_base.rb index bb1ddbed6..071498c7a 100644 --- a/app/models/labware_creators/quadrant_stamp_base.rb +++ b/app/models/labware_creators/quadrant_stamp_base.rb @@ -36,7 +36,7 @@ class QuadrantStampBase < MultiStamp def create_labware! super do |child| - LabwareMetadata.new(api: api, user: user_uuid, labware: child).update!(stock_barcodes_by_quadrant) + LabwareMetadata.new(user: user_uuid, labware: child).update!(stock_barcodes_by_quadrant) yield(child) if block_given? end end diff --git a/app/models/labware_metadata.rb b/app/models/labware_metadata.rb index 619985d8e..6923b0f8e 100644 --- a/app/models/labware_metadata.rb +++ b/app/models/labware_metadata.rb @@ -1,39 +1,34 @@ # frozen_string_literal: true class LabwareMetadata # rubocop:todo Style/Documentation - attr_accessor :api, :user, :labware, :barcode + attr_accessor :user, :labware, :barcode def initialize(params = {}) - @api = params.fetch(:api, nil) @user = params.fetch(:user, nil) @barcode = params.fetch(:barcode, nil) if barcode.present? - @labware = find_labware(barcode, api) + @labware = Sequencescape::Api::V2::Labware.where(barcode: barcode).first else @labware = params.fetch(:labware, nil) raise ArgumentError, 'Parameters labware or barcode missing' if labware.nil? end - raise ArgumentError, 'Parameter api missing' if api.nil? end def update!(metadata) # rubocop:todo Metrics/AbcSize - if labware.custom_metadatum_collection.uuid.present? - current_metadata = labware.custom_metadatum_collection.metadata.symbolize_keys + if @labware.custom_metadatum_collection.uuid.present? + current_metadata = @labware.custom_metadatum_collection.metadata.symbolize_keys labware.custom_metadatum_collection.update!(metadata: current_metadata.merge(metadata.symbolize_keys)) else - api.custom_metadatum_collection.create!(user: user, asset: labware.uuid, metadata: metadata.symbolize_keys) + Sequencescape::Api::V2::CustomMetadatumCollection.create!( + user_id: @user.id, + asset_id: @labware.id, + metadata: metadata.symbolize_keys + ) end end def metadata - @labware.custom_metadatum_collection.metadata - rescue URI::InvalidURIError - nil - end - - private - - def find_labware(labware_barcode, api) - api.search.find(Settings.searches['Find assets by barcode']).first(barcode: labware_barcode) + # Note that not all labware has custom metadata, hence the null-coalescing operator for the metadata method + @labware.custom_metadatum_collection&.metadata end end diff --git a/app/models/presenters/presenter.rb b/app/models/presenters/presenter.rb index 3ac211f0f..fa4207008 100644 --- a/app/models/presenters/presenter.rb +++ b/app/models/presenters/presenter.rb @@ -12,7 +12,7 @@ module Presenters::Presenter # rubocop:todo Style/Documentation class_attribute :summary_items, :sidebar_partial, :summary_partial, :pooling_tab - attr_accessor :api, :labware + attr_accessor :labware self.page = 'show' self.sidebar_partial = 'default' @@ -92,7 +92,7 @@ def purpose_config def stock_plate_barcode_from_metadata(plate_machine_barcode) begin - metadata = LabwareMetadata.new(api: api, barcode: plate_machine_barcode).metadata + metadata = LabwareMetadata.new(barcode: plate_machine_barcode).metadata rescue Sequencescape::Api::ResourceNotFound metadata = nil end diff --git a/app/models/robots/bed/plate_to_tube_racks_bed.rb b/app/models/robots/bed/plate_to_tube_racks_bed.rb index 01617e757..4f57418c7 100644 --- a/app/models/robots/bed/plate_to_tube_racks_bed.rb +++ b/app/models/robots/bed/plate_to_tube_racks_bed.rb @@ -17,9 +17,7 @@ class PlateToTubeRacksBed < Robots::Bed::Base def labware_created_with_robot(robot_barcode) # RobotController uses machine barcode for initialising LabwareMetadata labware.tubes.each do |tube| - LabwareMetadata - .new(api: api, user: user_uuid, barcode: tube.barcode.machine) - .update!(created_with_robot: robot_barcode) + LabwareMetadata.new(user: user_uuid, barcode: tube.barcode.machine).update!(created_with_robot: robot_barcode) end end From 8feebba8c57b854e6570352337cfcc11e941d1bd Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 26 Jul 2024 09:13:28 +0100 Subject: [PATCH 07/70] Put the api attribute back on Presenter for now It's used by sub-classes so they need to be fixed first --- app/models/presenters/presenter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/presenters/presenter.rb b/app/models/presenters/presenter.rb index fa4207008..9b23da05f 100644 --- a/app/models/presenters/presenter.rb +++ b/app/models/presenters/presenter.rb @@ -12,7 +12,7 @@ module Presenters::Presenter # rubocop:todo Style/Documentation class_attribute :summary_items, :sidebar_partial, :summary_partial, :pooling_tab - attr_accessor :labware + attr_accessor :api, :labware self.page = 'show' self.sidebar_partial = 'default' From e49c4b2c7d857ed3b8256e6e4f35c1a9fc9b6199 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 29 Jul 2024 17:03:52 +0100 Subject: [PATCH 08/70] Move the LabwareMetadata class over to using the V2 API --- app/controllers/labware_controller.rb | 2 +- app/models/labware_creators/quadrant_split_plate.rb | 2 +- app/models/labware_creators/quadrant_stamp_base.rb | 2 +- app/models/labware_metadata.rb | 13 +++++++------ app/models/robots/bed/plate_to_tube_racks_bed.rb | 4 +++- app/sequencescape/sequencescape/api/v2/tube.rb | 1 + 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/app/controllers/labware_controller.rb b/app/controllers/labware_controller.rb index baede85e0..ea801bd13 100644 --- a/app/controllers/labware_controller.rb +++ b/app/controllers/labware_controller.rb @@ -85,7 +85,7 @@ def find_printers end def state_changer_for(purpose_uuid, labware_uuid) - StateChangers.lookup_for(purpose_uuid).new(api, labware_uuid, current_user_uuid) + StateChangers.lookup_for(purpose_uuid).new(labware_uuid, current_user_uuid) end def presenter_for(labware) diff --git a/app/models/labware_creators/quadrant_split_plate.rb b/app/models/labware_creators/quadrant_split_plate.rb index 257013290..0ff80ed8a 100644 --- a/app/models/labware_creators/quadrant_split_plate.rb +++ b/app/models/labware_creators/quadrant_split_plate.rb @@ -45,7 +45,7 @@ def add_stock_barcode_metadata(plates) # rubocop:todo Metrics/AbcSize metadata = LabwareMetadata.new(barcode: merger_plate.barcode.machine).metadata plates.each_with_index do |plate, index| stock_barcode = stock_barcode_from_quadrant(index, metadata) || "* #{plate.barcode.human}" - LabwareMetadata.new(user: user_uuid, barcode: plate.barcode.machine).update!(stock_barcode: stock_barcode) + LabwareMetadata.new(user_uuid: user_uuid, barcode: plate.barcode.machine).update!(stock_barcode: stock_barcode) end end diff --git a/app/models/labware_creators/quadrant_stamp_base.rb b/app/models/labware_creators/quadrant_stamp_base.rb index 071498c7a..60ced9c7c 100644 --- a/app/models/labware_creators/quadrant_stamp_base.rb +++ b/app/models/labware_creators/quadrant_stamp_base.rb @@ -36,7 +36,7 @@ class QuadrantStampBase < MultiStamp def create_labware! super do |child| - LabwareMetadata.new(user: user_uuid, labware: child).update!(stock_barcodes_by_quadrant) + LabwareMetadata.new(user_uuid: user_uuid, labware: child).update!(stock_barcodes_by_quadrant) yield(child) if block_given? end end diff --git a/app/models/labware_metadata.rb b/app/models/labware_metadata.rb index 6923b0f8e..6af48f815 100644 --- a/app/models/labware_metadata.rb +++ b/app/models/labware_metadata.rb @@ -1,13 +1,14 @@ # frozen_string_literal: true class LabwareMetadata # rubocop:todo Style/Documentation - attr_accessor :user, :labware, :barcode + attr_accessor :user_uuid, :labware, :barcode def initialize(params = {}) - @user = params.fetch(:user, nil) + @user_uuid = params.fetch(:user, nil) + @user = Sequencescape::Api::V2::User.find(uuid: @user_uuid).first unless @user_uuid.nil? @barcode = params.fetch(:barcode, nil) if barcode.present? - @labware = Sequencescape::Api::V2::Labware.where(barcode: barcode).first + @labware = Sequencescape::Api::V2::Labware.find(barcode: barcode).first else @labware = params.fetch(:labware, nil) raise ArgumentError, 'Parameters labware or barcode missing' if labware.nil? @@ -15,12 +16,12 @@ def initialize(params = {}) end def update!(metadata) # rubocop:todo Metrics/AbcSize - if @labware.custom_metadatum_collection.uuid.present? - current_metadata = @labware.custom_metadatum_collection.metadata.symbolize_keys + if @labware.custom_metadatum_collection&.uuid.present? + current_metadata = self.metadata.symbolize_keys labware.custom_metadatum_collection.update!(metadata: current_metadata.merge(metadata.symbolize_keys)) else Sequencescape::Api::V2::CustomMetadatumCollection.create!( - user_id: @user.id, + user_id: @user&.id, asset_id: @labware.id, metadata: metadata.symbolize_keys ) diff --git a/app/models/robots/bed/plate_to_tube_racks_bed.rb b/app/models/robots/bed/plate_to_tube_racks_bed.rb index 4f57418c7..6e013c6ad 100644 --- a/app/models/robots/bed/plate_to_tube_racks_bed.rb +++ b/app/models/robots/bed/plate_to_tube_racks_bed.rb @@ -17,7 +17,9 @@ class PlateToTubeRacksBed < Robots::Bed::Base def labware_created_with_robot(robot_barcode) # RobotController uses machine barcode for initialising LabwareMetadata labware.tubes.each do |tube| - LabwareMetadata.new(user: user_uuid, barcode: tube.barcode.machine).update!(created_with_robot: robot_barcode) + LabwareMetadata + .new(user_uuid: user_uuid, barcode: tube.barcode.machine) + .update!(created_with_robot: robot_barcode) end end diff --git a/app/sequencescape/sequencescape/api/v2/tube.rb b/app/sequencescape/sequencescape/api/v2/tube.rb index a5f0dfb57..d76b06d52 100644 --- a/app/sequencescape/sequencescape/api/v2/tube.rb +++ b/app/sequencescape/sequencescape/api/v2/tube.rb @@ -22,6 +22,7 @@ class Sequencescape::Api::V2::Tube < Sequencescape::Api::V2::Base has_many :child_plates, class_name: 'Sequencescape::Api::V2::Plate' has_many :child_tubes, class_name: 'Sequencescape::Api::V2::Tube' has_one :receptacle, class_name: 'Sequencescape::Api::V2::Receptacle' + has_one :custom_metadatum_collection has_many :direct_submissions has_many :state_changes From 8655a67b861e1be65c5ccef405b11e0d69af6911 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 29 Jul 2024 17:04:22 +0100 Subject: [PATCH 09/70] Update some tests with new API v2 helper methods --- .../tube_creation_controller_spec.rb | 56 +++--- ...cycles_binned_plate_for_duplex_seq_spec.rb | 4 +- ...cycles_binned_plate_for_t_nano_seq_spec.rb | 13 +- .../plate_split_to_tube_racks_spec.rb | 172 +++++------------- ...d_plate_adding_randomised_controls_spec.rb | 12 +- spec/support/api_url_helper.rb | 26 ++- 6 files changed, 106 insertions(+), 177 deletions(-) diff --git a/spec/controllers/tube_creation_controller_spec.rb b/spec/controllers/tube_creation_controller_spec.rb index 2849bc885..09531ebf7 100644 --- a/spec/controllers/tube_creation_controller_spec.rb +++ b/spec/controllers/tube_creation_controller_spec.rb @@ -22,38 +22,34 @@ end describe '#new' do - context 'from a tube parent' do - it 'creates a tube' do - get :new, - params: { - limber_tube_id: parent_uuid, - purpose_uuid: child_purpose_uuid - }, - session: { - user_uuid: user_uuid - } - expect(response).to render_template('new') - expect(assigns(:labware_creator).parent_uuid).to eq(parent_uuid) - expect(assigns(:labware_creator).user_uuid).to eq(user_uuid) - expect(assigns(:labware_creator).purpose_uuid).to eq(child_purpose_uuid) - end + it 'creates a tube from a tube parent' do + get :new, + params: { + limber_tube_id: parent_uuid, + purpose_uuid: child_purpose_uuid + }, + session: { + user_uuid: user_uuid + } + expect(response).to render_template('new') + expect(assigns(:labware_creator).parent_uuid).to eq(parent_uuid) + expect(assigns(:labware_creator).user_uuid).to eq(user_uuid) + expect(assigns(:labware_creator).purpose_uuid).to eq(child_purpose_uuid) end - context 'from a plate parent' do - it 'creates a tube' do - get :new, - params: { - limber_plate_id: parent_uuid, - purpose_uuid: child_purpose_uuid - }, - session: { - user_uuid: user_uuid - } - expect(response).to render_template('new') - expect(assigns(:labware_creator).parent_uuid).to eq(parent_uuid) - expect(assigns(:labware_creator).user_uuid).to eq(user_uuid) - expect(assigns(:labware_creator).purpose_uuid).to eq(child_purpose_uuid) - end + it 'creates a tube from a plate parent' do + get :new, + params: { + limber_plate_id: parent_uuid, + purpose_uuid: child_purpose_uuid + }, + session: { + user_uuid: user_uuid + } + expect(response).to render_template('new') + expect(assigns(:labware_creator).parent_uuid).to eq(parent_uuid) + expect(assigns(:labware_creator).user_uuid).to eq(user_uuid) + expect(assigns(:labware_creator).purpose_uuid).to eq(child_purpose_uuid) end end diff --git a/spec/models/labware_creators/pcr_cycles_binned_plate_for_duplex_seq_spec.rb b/spec/models/labware_creators/pcr_cycles_binned_plate_for_duplex_seq_spec.rb index 93054cb08..641b0964f 100644 --- a/spec/models/labware_creators/pcr_cycles_binned_plate_for_duplex_seq_spec.rb +++ b/spec/models/labware_creators/pcr_cycles_binned_plate_for_duplex_seq_spec.rb @@ -345,8 +345,6 @@ ) end - let!(:api_v2_post) { stub_api_v2_post('Well') } - let(:transfer_requests) do [ { @@ -449,6 +447,8 @@ ) end + before { stub_api_v2_patch('Well') } + it 'makes the expected transfer requests to bin the wells' do expect(subject.save!).to eq true expect(plate_creation_request).to have_been_made diff --git a/spec/models/labware_creators/pcr_cycles_binned_plate_for_t_nano_seq_spec.rb b/spec/models/labware_creators/pcr_cycles_binned_plate_for_t_nano_seq_spec.rb index c447ef748..8f91ec429 100644 --- a/spec/models/labware_creators/pcr_cycles_binned_plate_for_t_nano_seq_spec.rb +++ b/spec/models/labware_creators/pcr_cycles_binned_plate_for_t_nano_seq_spec.rb @@ -361,10 +361,6 @@ ) end - let!(:api_v2_post) { stub_api_v2_post('Well') } - - let!(:api_v2_post) { stub_api_v2_save('PolyMetadatum') } - let(:transfer_requests) do [ { @@ -467,6 +463,11 @@ ) end + before do + stub_api_v2_patch('Well') + stub_api_v2_save('PolyMetadatum') + end + it 'makes the expected method calls when creating the child plate' do # NB. because we're mocking the API call for the save of the request metadata we cannot # check the metadata values on the requests, only that the method was triggered. @@ -584,9 +585,9 @@ ) end - let!(:api_v2_post) { allow(pm_pcr_cycles).to receive(:update).and_return(true) } - before do + allow(pm_pcr_cycles).to receive(:update).and_return(true) + stub_v2_polymetadata(pm_original_plate_barcode, loop_request.id) stub_v2_polymetadata(pm_original_well_id, loop_request.id) stub_v2_polymetadata(pm_concentration_nm, loop_request.id) diff --git a/spec/models/labware_creators/plate_split_to_tube_racks_spec.rb b/spec/models/labware_creators/plate_split_to_tube_racks_spec.rb index f5dddc115..4ab8c6154 100644 --- a/spec/models/labware_creators/plate_split_to_tube_racks_spec.rb +++ b/spec/models/labware_creators/plate_split_to_tube_racks_spec.rb @@ -17,7 +17,8 @@ expect(described_class.page).to eq 'plate_split_to_tube_racks' end - let(:user_uuid) { SecureRandom.uuid } + let(:user) { create :user } + let(:user_uuid) { user.uuid } let(:child_sequencing_tube_purpose_uuid) { SecureRandom.uuid } let(:child_sequencing_tube_purpose_name) { 'Seq Child Purpose' } let(:child_contingency_tube_purpose_uuid) { SecureRandom.uuid } @@ -825,61 +826,21 @@ let(:child_tube_4_v1) { json :tube, uuid: child_tube_4_uuid, barcode_prefix: 'FX', barcode_number: 12 } let(:child_tube_5_v1) { json :tube, uuid: child_tube_5_uuid, barcode_prefix: 'FX', barcode_number: 13 } - # need to stub the creation of the tube metadata + # Metadata expected to be sent in POST requests let!(:metadata_for_tube_1) { { tube_rack_barcode: 'TR00000001', tube_rack_position: 'A1' } } - let!(:stub_create_metadata_for_tube_1) do - stub_create_labware_metadata( - child_tube_1_v2.barcode.machine, - child_tube_1_v1, - child_tube_1_uuid, - user_uuid, - metadata_for_tube_1 - ) - end + let(:tube_1_create_args) { { user_id: user.id, asset_id: child_tube_1_v2.id, metadata: metadata_for_tube_1 } } let!(:metadata_for_tube_2) { { tube_rack_barcode: 'TR00000001', tube_rack_position: 'B1' } } - let!(:stub_create_metadata_for_tube_2) do - stub_create_labware_metadata( - child_tube_2_v2.barcode.machine, - child_tube_2_v1, - child_tube_2_uuid, - user_uuid, - metadata_for_tube_2 - ) - end + let(:tube_2_create_args) { { user_id: user.id, asset_id: child_tube_2_v2.id, metadata: metadata_for_tube_2 } } let!(:metadata_for_tube_3) { { tube_rack_barcode: 'TR00000002', tube_rack_position: 'A1' } } - let!(:stub_create_metadata_for_tube_3) do - stub_create_labware_metadata( - child_tube_3_v2.barcode.machine, - child_tube_3_v1, - child_tube_3_uuid, - user_uuid, - metadata_for_tube_3 - ) - end + let(:tube_3_create_args) { { user_id: user.id, asset_id: child_tube_3_v2.id, metadata: metadata_for_tube_3 } } let!(:metadata_for_tube_4) { { tube_rack_barcode: 'TR00000002', tube_rack_position: 'B1' } } - let!(:stub_create_metadata_for_tube_4) do - stub_create_labware_metadata( - child_tube_4_v2.barcode.machine, - child_tube_4_v1, - child_tube_4_uuid, - user_uuid, - metadata_for_tube_4 - ) - end + let(:tube_4_create_args) { { user_id: user.id, asset_id: child_tube_4_v2.id, metadata: metadata_for_tube_4 } } let!(:metadata_for_tube_5) { { tube_rack_barcode: 'TR00000002', tube_rack_position: 'C1' } } - let!(:stub_create_metadata_for_tube_5) do - stub_create_labware_metadata( - child_tube_5_v2.barcode.machine, - child_tube_5_v1, - child_tube_5_uuid, - user_uuid, - metadata_for_tube_5 - ) - end + let(:tube_5_create_args) { { user_id: user.id, asset_id: child_tube_5_v2.id, metadata: metadata_for_tube_5 } } let(:contingency_file) do fixture_file_upload( @@ -889,20 +850,21 @@ end before do - stub_get_labware_metadata(child_tube_1_v2.barcode.machine, child_tube_1_v1) - stub_get_labware_metadata(child_tube_2_v2.barcode.machine, child_tube_2_v1) - stub_get_labware_metadata(child_tube_3_v2.barcode.machine, child_tube_3_v1) - stub_get_labware_metadata(child_tube_4_v2.barcode.machine, child_tube_4_v1) - stub_get_labware_metadata(child_tube_5_v2.barcode.machine, child_tube_5_v1) - - stub_asset_search(child_tube_1_v2.barcode.machine, child_tube_1_v1) - stub_asset_search(child_tube_2_v2.barcode.machine, child_tube_2_v1) - stub_asset_search(child_tube_3_v2.barcode.machine, child_tube_3_v1) - stub_asset_search(child_tube_4_v2.barcode.machine, child_tube_4_v1) - stub_asset_search(child_tube_5_v2.barcode.machine, child_tube_5_v1) + stub_v2_user(user) + + stub_v2_labware(child_tube_1_v2) + stub_v2_labware(child_tube_2_v2) + stub_v2_labware(child_tube_3_v2) + stub_v2_labware(child_tube_4_v2) + stub_v2_labware(child_tube_5_v2) end it 'creates the child tubes' do + expect_api_v2_posts( + 'CustomMetadatumCollection', + [tube_1_create_args, tube_2_create_args, tube_3_create_args, tube_4_create_args, tube_5_create_args] + ) + expect(subject.valid?).to be_truthy expect(subject.save).to be_truthy expect(stub_sequencing_file_upload).to have_been_made.once @@ -910,11 +872,6 @@ expect(stub_contingency_file_upload).to have_been_made.once expect(stub_contingency_tube_creation_request).to have_been_made.once expect(stub_transfer_creation_request).to have_been_made.once - expect(stub_create_metadata_for_tube_1).to have_been_requested - expect(stub_create_metadata_for_tube_2).to have_been_requested - expect(stub_create_metadata_for_tube_3).to have_been_requested - expect(stub_create_metadata_for_tube_4).to have_been_requested - expect(stub_create_metadata_for_tube_5).to have_been_requested end context 'when a well has been failed' do @@ -1037,6 +994,11 @@ end it 'does not create a tube for the failed well' do + expect_api_v2_posts( + 'CustomMetadatumCollection', + [tube_1_create_args, tube_2_create_args, tube_3_create_args, tube_4_create_args] # no tube 5 + ) + expect(subject.valid?).to be_truthy expect(subject.save).to be_truthy expect(stub_sequencing_file_upload).to have_been_made.once @@ -1044,12 +1006,6 @@ expect(stub_contingency_file_upload).to have_been_made.once expect(stub_contingency_tube_creation_request).to have_been_made.once expect(stub_transfer_creation_request).to have_been_made.once - expect(stub_create_metadata_for_tube_1).to have_been_requested - expect(stub_create_metadata_for_tube_2).to have_been_requested - expect(stub_create_metadata_for_tube_3).to have_been_requested - expect(stub_create_metadata_for_tube_4).to have_been_requested - - expect(stub_create_metadata_for_tube_5).to_not have_been_requested end end end @@ -1212,85 +1168,41 @@ # need to stub the creation of the tube metadata let!(:metadata_for_tube_1) { { tube_rack_barcode: 'TR00000002', tube_rack_position: 'A1' } } - let!(:stub_create_metadata_for_tube_1) do - stub_create_labware_metadata( - child_tube_1_v2.barcode.machine, - child_tube_1_v1, - child_tube_1_uuid, - user_uuid, - metadata_for_tube_1 - ) - end + let(:tube_1_create_args) { { user_id: user.id, asset_id: child_tube_1_v2.id, metadata: metadata_for_tube_1 } } let!(:metadata_for_tube_2) { { tube_rack_barcode: 'TR00000002', tube_rack_position: 'B1' } } - let!(:stub_create_metadata_for_tube_2) do - stub_create_labware_metadata( - child_tube_2_v2.barcode.machine, - child_tube_2_v1, - child_tube_2_uuid, - user_uuid, - metadata_for_tube_2 - ) - end + let(:tube_2_create_args) { { user_id: user.id, asset_id: child_tube_2_v2.id, metadata: metadata_for_tube_2 } } let!(:metadata_for_tube_3) { { tube_rack_barcode: 'TR00000002', tube_rack_position: 'C1' } } - let!(:stub_create_metadata_for_tube_3) do - stub_create_labware_metadata( - child_tube_3_v2.barcode.machine, - child_tube_3_v1, - child_tube_3_uuid, - user_uuid, - metadata_for_tube_3 - ) - end + let(:tube_3_create_args) { { user_id: user.id, asset_id: child_tube_3_v2.id, metadata: metadata_for_tube_3 } } let!(:metadata_for_tube_4) { { tube_rack_barcode: 'TR00000002', tube_rack_position: 'E1' } } - let!(:stub_create_metadata_for_tube_4) do - stub_create_labware_metadata( - child_tube_4_v2.barcode.machine, - child_tube_4_v1, - child_tube_4_uuid, - user_uuid, - metadata_for_tube_4 - ) - end + let(:tube_4_create_args) { { user_id: user.id, asset_id: child_tube_4_v2.id, metadata: metadata_for_tube_4 } } let!(:metadata_for_tube_5) { { tube_rack_barcode: 'TR00000002', tube_rack_position: 'F1' } } - let!(:stub_create_metadata_for_tube_5) do - stub_create_labware_metadata( - child_tube_5_v2.barcode.machine, - child_tube_5_v1, - child_tube_5_uuid, - user_uuid, - metadata_for_tube_5 - ) - end + let(:tube_5_create_args) { { user_id: user.id, asset_id: child_tube_5_v2.id, metadata: metadata_for_tube_5 } } before do - stub_get_labware_metadata(child_tube_1_v2.barcode.machine, child_tube_1_v1) - stub_get_labware_metadata(child_tube_2_v2.barcode.machine, child_tube_2_v1) - stub_get_labware_metadata(child_tube_3_v2.barcode.machine, child_tube_3_v1) - stub_get_labware_metadata(child_tube_4_v2.barcode.machine, child_tube_4_v1) - stub_get_labware_metadata(child_tube_5_v2.barcode.machine, child_tube_5_v1) - - stub_asset_search(child_tube_1_v2.barcode.machine, child_tube_1_v1) - stub_asset_search(child_tube_2_v2.barcode.machine, child_tube_2_v1) - stub_asset_search(child_tube_3_v2.barcode.machine, child_tube_3_v1) - stub_asset_search(child_tube_4_v2.barcode.machine, child_tube_4_v1) - stub_asset_search(child_tube_5_v2.barcode.machine, child_tube_5_v1) + stub_v2_user(user) + + stub_v2_labware(child_tube_1_v2) + stub_v2_labware(child_tube_2_v2) + stub_v2_labware(child_tube_3_v2) + stub_v2_labware(child_tube_4_v2) + stub_v2_labware(child_tube_5_v2) end it 'creates the child tubes' do + expect_api_v2_posts( + 'CustomMetadatumCollection', + [tube_1_create_args, tube_2_create_args, tube_3_create_args, tube_4_create_args, tube_5_create_args] + ) + expect(subject.valid?).to be_truthy expect(subject.save).to be_truthy expect(stub_contingency_file_upload).to have_been_made.once expect(stub_contingency_tube_creation_request).to have_been_made.once expect(stub_transfer_creation_request).to have_been_made.once - expect(stub_create_metadata_for_tube_1).to have_been_requested - expect(stub_create_metadata_for_tube_2).to have_been_requested - expect(stub_create_metadata_for_tube_3).to have_been_requested - expect(stub_create_metadata_for_tube_4).to have_been_requested - expect(stub_create_metadata_for_tube_5).to have_been_requested end end end diff --git a/spec/models/labware_creators/stamped_plate_adding_randomised_controls_spec.rb b/spec/models/labware_creators/stamped_plate_adding_randomised_controls_spec.rb index 5a2d92a67..5356b3b8f 100644 --- a/spec/models/labware_creators/stamped_plate_adding_randomised_controls_spec.rb +++ b/spec/models/labware_creators/stamped_plate_adding_randomised_controls_spec.rb @@ -134,12 +134,6 @@ ) end - let!(:api_v2_post) { stub_api_v2_post('Sample') } - - let!(:api_v2_update_sample_metadata) { stub_api_v2_post('SampleMetadata') } - - let!(:api_v2_save_aliquot) { stub_api_v2_save('Aliquot') } - let!(:transfer_creation_request) do stub_api_post( 'transfer_request_collections', @@ -153,6 +147,12 @@ ) end + before do + stub_api_v2_patch('Sample') + stub_api_v2_patch('SampleMetadata') + stub_api_v2_save('Aliquot') + end + it 'makes the expected requests' do expect(subject.save!).to eq true expect(plate_creation_request).to have_been_made diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index aac0e4a7e..0396587fc 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -71,20 +71,30 @@ def stub_api_put(*components, body:, payload:) stub_api_modify(*components, action: :put, status: 200, body: body, payload: payload) end - def stub_api_v2_post(klass) - # intercepts the 'update' method for any class beginning with + def stub_api_v2_patch(klass) + # intercepts the 'update' and 'update!' method for any instance of the class beginning with # 'Sequencescape::Api::V2::' and returns true receiving_class = "Sequencescape::Api::V2::#{klass}".constantize allow_any_instance_of(receiving_class).to receive(:update).and_return(true) + allow_any_instance_of(receiving_class).to receive(:update!).and_return(true) end def stub_api_v2_save(klass) - # intercepts the 'save' method for any class beginning with + # intercepts the 'save' method for any instance of the class beginning with # 'Sequencescape::Api::V2::' and returns true receiving_class = "Sequencescape::Api::V2::#{klass}".constantize allow_any_instance_of(receiving_class).to receive(:save).and_return(true) end + def expect_api_v2_posts(klass, args_list) + # Expects the 'create!' method for any class beginning with + # 'Sequencescape::Api::V2::' to be called with given arguments, in sequence, and returns true + receiving_class = "Sequencescape::Api::V2::#{klass}".constantize + expect(receiving_class).to receive(:create!).exactly(args_list.count).times do |args| + expect(args).to eq(args_list.shift) + end.and_return(true) + end + def stub_barcode_search(barcode, labware) labware_result = create :labware, type: labware.type, uuid: labware.uuid, id: labware.id allow(Sequencescape::Api::V2).to receive(:minimal_labware_by_barcode).with(barcode).and_return(labware_result) @@ -95,6 +105,11 @@ def stub_v2_barcode_printers(printers) allow(Sequencescape::Api::V2::BarcodePrinter).to receive(:all).and_return(printers) end + def stub_v2_labware(labware) + arguments = [{ barcode: labware.barcode.machine }] + allow(Sequencescape::Api::V2::Labware).to receive(:find).with(*arguments).and_return([labware]) + end + # Builds the basic v2 plate finding query. def stub_v2_plate(plate, stub_search: true, custom_query: nil, custom_includes: nil) # rubocop:todo Metrics/AbcSize stub_barcode_search(plate.barcode.machine, plate) if stub_search @@ -131,6 +146,11 @@ def stub_v2_tube(tube, stub_search: true, custom_includes: false) arguments = custom_includes ? [{ uuid: tube.uuid }, { includes: custom_includes }] : [{ uuid: tube.uuid }] allow(Sequencescape::Api::V2::Tube).to receive(:find_by).with(*arguments).and_return(tube) end + + def stub_v2_user(user) + arguments = [{ uuid: user.uuid }] + allow(Sequencescape::Api::V2::User).to receive(:find).with(*arguments).and_return([user]) + end end extend ClassMethods end From 4772f7a966fd46f36d6ff08d796b201c5c5a2de5 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 29 Jul 2024 17:06:06 +0100 Subject: [PATCH 10/70] Fix Rubocop concerns --- app/models/labels/plate_split.rb | 1 - app/models/labware_metadata.rb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/models/labels/plate_split.rb b/app/models/labels/plate_split.rb index dacc1a7b4..0ec7eebcb 100644 --- a/app/models/labels/plate_split.rb +++ b/app/models/labels/plate_split.rb @@ -18,7 +18,6 @@ def stock_plate_barcode private def stock_plate_barcode_getter - api = Sequencescape::Api.new(Limber::Application.config.api.v1.connection_options.dup) metadata = LabwareMetadata.new(barcode: labware.barcode.machine).metadata barcode = 'N/A' barcode = metadata.fetch('stock_barcode', barcode) unless metadata.nil? diff --git a/app/models/labware_metadata.rb b/app/models/labware_metadata.rb index 6af48f815..d14fd7e6c 100644 --- a/app/models/labware_metadata.rb +++ b/app/models/labware_metadata.rb @@ -15,7 +15,7 @@ def initialize(params = {}) end end - def update!(metadata) # rubocop:todo Metrics/AbcSize + def update!(metadata) if @labware.custom_metadatum_collection&.uuid.present? current_metadata = self.metadata.symbolize_keys labware.custom_metadatum_collection.update!(metadata: current_metadata.merge(metadata.symbolize_keys)) From 38f0809d1fb79c868b344a32e248c4aff58182d5 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 30 Jul 2024 11:25:14 +0100 Subject: [PATCH 11/70] Fix tests for quadrant split plate --- .../plate_split_to_tube_racks.rb | 2 +- app/models/labware_metadata.rb | 2 +- .../quadrant_split_plate_spec.rb | 80 ++++++++----------- 3 files changed, 37 insertions(+), 47 deletions(-) diff --git a/app/models/labware_creators/plate_split_to_tube_racks.rb b/app/models/labware_creators/plate_split_to_tube_racks.rb index 87e7e5dd3..d5434ef8e 100644 --- a/app/models/labware_creators/plate_split_to_tube_racks.rb +++ b/app/models/labware_creators/plate_split_to_tube_racks.rb @@ -652,7 +652,7 @@ def add_contingency_tube_metadata # @return [void] def add_tube_metadata(child_tube, tube_posn, tube_details) LabwareMetadata - .new(user: user_uuid, barcode: child_tube.barcode.machine) + .new(user_uuid: user_uuid, barcode: child_tube.barcode.machine) .update!(tube_rack_barcode: tube_details['tube_rack_barcode'], tube_rack_position: tube_posn) end diff --git a/app/models/labware_metadata.rb b/app/models/labware_metadata.rb index d14fd7e6c..8734ea90e 100644 --- a/app/models/labware_metadata.rb +++ b/app/models/labware_metadata.rb @@ -4,7 +4,7 @@ class LabwareMetadata # rubocop:todo Style/Documentation attr_accessor :user_uuid, :labware, :barcode def initialize(params = {}) - @user_uuid = params.fetch(:user, nil) + @user_uuid = params.fetch(:user_uuid, nil) @user = Sequencescape::Api::V2::User.find(uuid: @user_uuid).first unless @user_uuid.nil? @barcode = params.fetch(:barcode, nil) if barcode.present? diff --git a/spec/models/labware_creators/quadrant_split_plate_spec.rb b/spec/models/labware_creators/quadrant_split_plate_spec.rb index 6329c99e5..353e79369 100644 --- a/spec/models/labware_creators/quadrant_split_plate_spec.rb +++ b/spec/models/labware_creators/quadrant_split_plate_spec.rb @@ -13,8 +13,8 @@ it_behaves_like 'it has no custom page' has_a_working_api - let(:user_uuid) { 'user-uuid' } - let(:user) { json :v1_user, uuid: user_uuid } + let(:user) { create :user } + let(:user_uuid) { user.uuid } let(:parent_uuid) { 'example-plate-uuid' } let(:parent_plate_size) { 384 } @@ -80,6 +80,10 @@ outer_requests: quad_a_requests ) end + let(:child_plate_a_create_args) do + { user_id: user.id, asset_id: child_plate_a.id, metadata: { stock_barcode: "* #{child_plate_a.barcode.machine}" } } + end + let(:child_plate_b) do create( :v2_plate, @@ -89,6 +93,10 @@ outer_requests: quad_b_requests ) end + let(:child_plate_b_create_args) do + { user_id: user.id, asset_id: child_plate_b.id, metadata: { stock_barcode: "* #{child_plate_b.barcode.machine}" } } + end + let(:child_plate_c) do create( :v2_plate, @@ -98,6 +106,10 @@ outer_requests: quad_c_requests ) end + let(:child_plate_c_create_args) do + { user_id: user.id, asset_id: child_plate_c.id, metadata: { stock_barcode: "* #{child_plate_c.barcode.machine}" } } + end + let(:child_plate_d) do create( :v2_plate, @@ -107,6 +119,10 @@ outer_requests: quad_d_requests ) end + let(:child_plate_d_create_args) do + { user_id: user.id, asset_id: child_plate_d.id, metadata: { stock_barcode: "* #{child_plate_d.barcode.machine}" } } + end + let(:child_plate_a_v1) { json(:plate_with_metadata, uuid: 'child-a-uuid', barcode_number: '3') } let(:child_plate_b_v1) { json(:plate_with_metadata, uuid: 'child-b-uuid', barcode_number: '4') } let(:child_plate_c_v1) { json(:plate_with_metadata, uuid: 'child-c-uuid', barcode_number: '5') } @@ -132,49 +148,6 @@ shared_examples 'a quad-split plate creator' do describe '#save!' do - setup do - allow(SearchHelper).to receive(:merger_plate_names).and_return(stock_purpose_name) - - stub_api_get('user-uuid', body: user) - - # This is a hack, but since I couldn't find a way to stub - # `custom_metadatum_collection` for a particular uuid that doesn't - # involve modifying the stubbing methods, I had to merge all the keys - # in one hash and use one single value. - merger_plate_metadata = { - stock_barcode_q0: 'STOCK-BARCODE-0', - stock_barcode_q1: 'STOCK-BARCODE-0', - stock_barcode_q2: 'STOCK-BARCODE-0', - stock_barcode_q3: 'STOCK-BARCODE-0', - stock_barcode: 'STOCK-BARCODE-0' - } - stub_get_labware_metadata(stock_plate_v2.barcode.machine, stock_plate_v1, metadata: merger_plate_metadata) - stub_asset_search(child_plate_a.barcode.machine, child_plate_a_v1) - stub_asset_search(child_plate_b.barcode.machine, child_plate_b_v1) - stub_asset_search(child_plate_c.barcode.machine, child_plate_c_v1) - stub_asset_search(child_plate_d.barcode.machine, child_plate_d_v1) - - stub_api_get('asset-uuid', body: child_plate_a_v1) - stub_api_get('asset-uuid', body: child_plate_b_v1) - stub_api_get('asset-uuid', body: child_plate_c_v1) - stub_api_get('asset-uuid', body: child_plate_d_v1) - - stub_api_put( - 'custom_metadatum_collection-uuid', - payload: { - custom_metadatum_collection: { - metadata: merger_plate_metadata - } - }, - body: - json( - :v1_custom_metadatum_collection, - uuid: 'custom_metadatum_collection-uuid', - metadata: merger_plate_metadata - ) - ) - end - let!(:plate_creation_request) do stub_api_post( 'plate_creations', @@ -207,7 +180,24 @@ ) end + before do + allow(SearchHelper).to receive(:merger_plate_names).and_return(stock_purpose_name) + + stub_v2_user(user) + + stub_v2_labware(stock_plate_v2) + stub_v2_labware(child_plate_a) + stub_v2_labware(child_plate_b) + stub_v2_labware(child_plate_c) + stub_v2_labware(child_plate_d) + end + it 'makes the expected requests' do + expect_api_v2_posts( + 'CustomMetadatumCollection', + [child_plate_a_create_args, child_plate_b_create_args, child_plate_c_create_args, child_plate_d_create_args] + ) + expect(subject.save!).to eq true expect(plate_creation_request).to have_been_made.times(4) expect(transfer_creation_request).to have_been_made From 12dea359ceda3dcafd6ef8f694857e5afa26674e Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 30 Jul 2024 14:08:39 +0100 Subject: [PATCH 12/70] Remove reference to custom_metadatum_collection from tube --- app/sequencescape/sequencescape/api/v2/tube.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/sequencescape/sequencescape/api/v2/tube.rb b/app/sequencescape/sequencescape/api/v2/tube.rb index d76b06d52..a5f0dfb57 100644 --- a/app/sequencescape/sequencescape/api/v2/tube.rb +++ b/app/sequencescape/sequencescape/api/v2/tube.rb @@ -22,7 +22,6 @@ class Sequencescape::Api::V2::Tube < Sequencescape::Api::V2::Base has_many :child_plates, class_name: 'Sequencescape::Api::V2::Plate' has_many :child_tubes, class_name: 'Sequencescape::Api::V2::Tube' has_one :receptacle, class_name: 'Sequencescape::Api::V2::Receptacle' - has_one :custom_metadatum_collection has_many :direct_submissions has_many :state_changes From 86d593430289bce5adb8bdea2a0e0f067fb4502d Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Wed, 31 Jul 2024 10:21:38 +0100 Subject: [PATCH 13/70] Add classes for using v2 API TagLayoutTemplate --- .../tagged_plate_behaviour.rb | 2 +- .../tagging/tag_collection.rb | 6 +-- .../api/v2/tag_layout_template.rb | 42 +++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 app/sequencescape/sequencescape/api/v2/tag_layout_template.rb diff --git a/app/models/concerns/labware_creators/tagged_plate_behaviour.rb b/app/models/concerns/labware_creators/tagged_plate_behaviour.rb index be3205dee..36822ba10 100644 --- a/app/models/concerns/labware_creators/tagged_plate_behaviour.rb +++ b/app/models/concerns/labware_creators/tagged_plate_behaviour.rb @@ -30,7 +30,7 @@ def transfer_hash end def tag_plates - @tag_plates ||= LabwareCreators::Tagging::TagCollection.new(api, labware, purpose_uuid) + @tag_plates ||= LabwareCreators::Tagging::TagCollection.new(labware, purpose_uuid) end # diff --git a/app/models/labware_creators/tagging/tag_collection.rb b/app/models/labware_creators/tagging/tag_collection.rb index 9f1284b37..4d159f0b1 100644 --- a/app/models/labware_creators/tagging/tag_collection.rb +++ b/app/models/labware_creators/tagging/tag_collection.rb @@ -5,12 +5,10 @@ class TagCollection # rubocop:todo Style/Documentation # # Create a tag collection # - # @param [Sequencescape::Client::Api] api an api object used to retrieve tag templates # @param [Limber::Plate] plate The plate from which the tag layout will be generated # @param [String] purpose_uuid The uuid of the purpose which is about to be created # - def initialize(api, plate, purpose_uuid) - @api = api + def initialize(plate, purpose_uuid) @plate = plate @purpose_uuid = purpose_uuid end @@ -105,7 +103,7 @@ def tags_by_column(layout) end def tag_layout_templates - @api.tag_layout_template.all.map(&:coerce) + Sequencescape::Api::V2::TagLayoutTemplate.all.map(&:coerce) end end end diff --git a/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb b/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb new file mode 100644 index 000000000..57cc5d050 --- /dev/null +++ b/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# tag layout template resource +class Sequencescape::Api::V2::TagLayoutTemplate < Sequencescape::Api::V2::Base + has_one :tag_group + has_one :tag2_group + + # Performs the coercion of this instance so that it behaves appropriately given the direction + # and walking algorithm information. + def coerce + extend("limber/tag_layout_template/in_#{direction.gsub(/\s+/, '_')}s".camelize.constantize) + extend("limber/tag_layout_template/walk_#{walking_by.gsub(/\s+/, '_')}".camelize.constantize) + rescue NameError => e + Rails.logger.warn("Unrecognised layout options: #{e.message}") + extend Unsupported + ensure + self + end + + # This returns an array of well location to pool pairs. The 'walker' is responsible for actually doing the walking + # of the wells that are acceptable, and it calls back with the location of the well being processed. + def group_wells(plate) + well_to_pool = plate.wells.each_with_object({}) { |well, store| store[well.location] = well.pool_id } + + # We assume that if a well is unpooled then it is in the same pool as the previous pool. + prior_pool = nil + callback = + lambda do |row_column| + prior_pool = pool = well_to_pool[row_column] || prior_pool # or next + well_empty = well_to_pool[row_column].nil? + well = pool.nil? ? nil : row_column + [well, pool, well_empty] # Triplet: [ A1, pool_id, well_empty ] + end + yield(callback) + end + private :group_wells + + def tag_ids + tag_group.tags.map { |t| t['index'].to_i }.sort + end + private :tag_ids +end From b73aa7b930f3aa6f30733a4ee0ee780500f6c7d2 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Wed, 31 Jul 2024 12:17:10 +0100 Subject: [PATCH 14/70] Start putting V2 tag layout template stubs/factories in place --- spec/factories/tag_factories.rb | 14 ++++++++++++-- spec/factories/tag_layout_template_factories.rb | 10 ++++++++++ .../labware_creators/custom_tagged_plate_spec.rb | 5 ++++- spec/support/api_url_helper.rb | 4 ++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/spec/factories/tag_factories.rb b/spec/factories/tag_factories.rb index 42c7354f5..16e19a688 100644 --- a/spec/factories/tag_factories.rb +++ b/spec/factories/tag_factories.rb @@ -12,13 +12,23 @@ def generate_oligo factory :v2_tag, class: Sequencescape::Api::V2::Tag do skip_create + sequence(:map_id) { |i| i } sequence(:oligo) { |_index| generate_oligo } - tag_group { create :v2_tag_group } + tag_group { create :v2_tag_group, v2_tags: [instance] } end - factory :v2_tag_group, class: Sequencescape::Api::V2::Tag do + factory :v2_tag_group, class: Sequencescape::Api::V2::TagGroup do skip_create + transient { v2_tags { [] } } sequence(:name) { |index| "TagGroup#{index}" } + tags { v2_tags.map { |t| { index: t.map_id, oligo: t.oligo } } } + + factory :v2_tag_group_with_tags do + transient do + size { 96 } + v2_tags { (1..size).map { |i| create(:v2_tag, map_id: i) } } + end + end end end diff --git a/spec/factories/tag_layout_template_factories.rb b/spec/factories/tag_layout_template_factories.rb index 027e9cd0f..466e65d9b 100644 --- a/spec/factories/tag_layout_template_factories.rb +++ b/spec/factories/tag_layout_template_factories.rb @@ -1,6 +1,16 @@ # frozen_string_literal: true FactoryBot.define do + factory :v2_tag_layout_template, class: Sequencescape::Api::V2::TagLayoutTemplate do + skip_create + + uuid + name { 'Test tag layout' } + direction { 'column' } + walking_by { 'wells of plate' } + tag_group { create :v2_tag_group_with_tags } + end + # API V1 tag layout template. The inheriting factories set up the patterns # commonly seen by Limber factory :tag_layout_template, class: Limber::TagLayoutTemplate, traits: [:api_object] do diff --git a/spec/models/labware_creators/custom_tagged_plate_spec.rb b/spec/models/labware_creators/custom_tagged_plate_spec.rb index 78b497839..bf9929d03 100644 --- a/spec/models/labware_creators/custom_tagged_plate_spec.rb +++ b/spec/models/labware_creators/custom_tagged_plate_spec.rb @@ -44,8 +44,11 @@ let(:maximum_tag_offset) { largest_tag_group - occupied_wells } let(:maximum_well_offset) { plate_size - occupied_wells + 1 } + let(:tag_group) { create :v2_tag_group_with_tags } + let(:tlts) { create_list :v2_tag_layout_template, 2 } it 'can be created' do + binding.pry expect(subject).to be_a LabwareCreators::CustomTaggedPlate end @@ -58,7 +61,7 @@ end context 'fetching layout templates' do - before { stub_api_get('tag_layout_templates', body: json(:tag_layout_template_collection, size: 2)) } + before { stub_v2_tag_layout_templates(create_list :v2_tag_layout_template, 2) } let(:layout_hash) do WellHelpers.column_order.each_with_index.map do |w, i| diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index aac0e4a7e..20f489a2c 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -125,6 +125,10 @@ def stub_v2_study(study) allow(Sequencescape::Api::V2::Study).to receive(:find).with(*arguments).and_return([study]) end + def stub_v2_tag_layout_templates(templates) + allow(Sequencescape::Api::V2::TagLayoutTemplate).to receive(:all).and_return(templates) + end + # Builds the basic v2 tube finding query. def stub_v2_tube(tube, stub_search: true, custom_includes: false) stub_barcode_search(tube.barcode.machine, tube) if stub_search From dff8746d2bf5a77360aebd17e2a5436e6cb4f4fc Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 1 Aug 2024 11:59:59 +0100 Subject: [PATCH 15/70] Document the approach to stubbing relationships in V2 resources --- README.md | 58 +++++++++++++++++++++++++- spec/factories/asset_factories.rb | 2 +- spec/factories/labware_factories.rb | 3 +- spec/factories/plate_factories.rb | 12 +----- spec/factories/receptacle_factories.rb | 1 + spec/factories/request_factories.rb | 1 + spec/factories/sample_factories.rb | 1 + spec/factories/tube_factories.rb | 2 +- spec/factories/tube_rack_factories.rb | 1 + spec/factories/well_factories.rb | 3 +- 10 files changed, 67 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 25ff4bcda..d39d44ccc 100644 --- a/README.md +++ b/README.md @@ -200,12 +200,68 @@ There are a few tools available to assist with writing specs: - Helpers: `with_has_many_associations` and `with_belongs_to_associations` can be used in factories to set up the relevant json. They won't actually mock up the relevant requests, but ensure that things like actions are defined so that the api knows where to find them. -#### Request stubbing +#### Request stubbing for the Sequencescape v1 API Request stubs are provided by webmock. Two helper methods will assist with the majority of mocking requests to the api, `stub_api_get` and `stub_api_post`. See `spec/support/api_url_helper.rb` for details. **Note**: Due to the way the api functions, the factories don't yet support nested associations. +#### Request stubbing for the Sequencescape v2 API + +The V2 API uses `JsonApiClient::Resource` sub-classes to represent the records in memory. +Generally these are quite dynamic so you don't need to explicitly specify every property the API will respond with. +The base class also provides us with methods that are familiar to Rails for finding one or more records that match criteria. +So to stub the API, the easiest thing to do is to get FactoryBot to make up resources using the specific resource sub-class for the V2 API, and then mock the calls to those lookup methods. +Many of these have already been done for you in `spec/support/api_url_helper.rb` such as `stub_v2_study` and `stub_v2_tag_layout_templates` which sets up the `find` method for studies by name and the `all` method for tag layout templates, respectively. +However there's also `stub_api_v2_post`, `stub_api_v2_patch` and `stub_api_v2_save` which ensures that any calls to the `create`, `update` and the `save` method for resources of a particular type are expected and give a return value. +If none of the existing method suit your needs, you should add new ones. + +##### FactoryBot is not mocking my related resources correctly + +Nested relationships, such as Wells inside a Plate, the resource should indicate this with keywords like `has_one`, `has_many`, `belongs_to`, etc. +See the [json_api_client repository](https://github.com/JsonApiClient/json_api_client) for this topic and more. +However, FactoryBot does not get on well with some of these relationship methods and will not mock them properly using standard FactoryBot definitions. + +If you find that FactoryBot is not giving you the expected resource for a related record, you can inject the related resource directly into the `JsonApiClient::Resource`'s cache of relationships. +To do that, define the related resource as a `transient` variable and use an `after(:build)` block to assign the resource to the `_cached_relationship` method. +For example, where the Resource might be defined as the following class: + +```ruby +class Sequencescape::Api::V2::RootRecord < JsonApiClient::Resource + has_one :related_thing +end +``` + +You might expect to be able to use FactoryBot in the following way: + +```ruby +FactoryBot.define do + factory :root_record, class: Sequencescape::Api::V2::RootRecord do + skip_create + + related_thing { create :related_thing } + end +end +``` + +But the related thing will not be the one you defined to be generated by another factory. +It appears the `has_one` method in the resource over-rides the mocked value and you get an empty record back instead. +So, instead, you should create the `related_thing` record as a transient and assign it to the `root_record` in an `after(:build)` block as shown here. + +```ruby +FactoryBot.define do + factory :root_record, class: Sequencescape::Api::V2::RootRecord do + skip_create + + transient { related_thing { create :v2_tag_group_with_tags } } + + after(:build) do |record, factory| + record._cached_relationship(:related_thing) { factory.related_thing } if evaluator.related_thing + end + end +end +``` + ### Lefthook [Lefthook](https://github.com/Arkweid/lefthook) is a git-hook manager that will diff --git a/spec/factories/asset_factories.rb b/spec/factories/asset_factories.rb index 84fe83e0b..3d6c38f38 100644 --- a/spec/factories/asset_factories.rb +++ b/spec/factories/asset_factories.rb @@ -18,7 +18,7 @@ purpose_uuid { 'example-purpose-uuid' } purpose { create :v2_purpose, name: purpose_name, uuid: purpose_uuid } - # Mock the relationships. Should probably handle this all a bit differently + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) { |asset, evaluator| asset._cached_relationship(:purpose) { evaluator.purpose } } end end diff --git a/spec/factories/labware_factories.rb b/spec/factories/labware_factories.rb index 087777dfc..04b51a260 100644 --- a/spec/factories/labware_factories.rb +++ b/spec/factories/labware_factories.rb @@ -22,9 +22,8 @@ factory(:labware_tube) { type { 'tubes' } } factory(:labware_tube_rack) { type { 'tube_racks' } } + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |labware, evaluator| - # see plate_factories -> v2_plate factory -> after(:build) for an explanation of _cached_relationship - # basically, it allows you to call .purpose on the labware and get a Sequencescape::Api::V2::Purpose labware._cached_relationship(:purpose) { evaluator.purpose } if evaluator.purpose labware._cached_relationship(:ancestors) { evaluator.ancestors } if evaluator.ancestors end diff --git a/spec/factories/plate_factories.rb b/spec/factories/plate_factories.rb index b87624d85..f51f799d1 100644 --- a/spec/factories/plate_factories.rb +++ b/spec/factories/plate_factories.rb @@ -134,17 +134,7 @@ updated_at { '2017-06-29T09:31:59.000+01:00' } custom_metadatum_collection { nil } - # Set up the relationships. - # json_client_api handles assigning of relationship information in a frustrating manner - # which isn't amenable to setting up objects for testing. Instead it tends to strip - # the attributes off the associated records, leaving just a type and an id. This is not - # useful if you want to use this data later. - # Even more frustratingly is that if you attempt to bypass this and set the attribute directly - # the getter attempts to fetch the object via a cache instead. - # Here we populate the cache directly with the objects we want. This is *MUCH* faster - # than achieving the same through mocks. - # We could probably avoid needing to do anything sneaky at all if we instead generated - # json-api data and generated the objects from that. + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |plate, evaluator| Sequencescape::Api::V2::Plate.associations.each do |association| plate._cached_relationship(association.attr_name) { evaluator.send(association.attr_name) } diff --git a/spec/factories/receptacle_factories.rb b/spec/factories/receptacle_factories.rb index ac2c4016f..3f899a17b 100644 --- a/spec/factories/receptacle_factories.rb +++ b/spec/factories/receptacle_factories.rb @@ -12,6 +12,7 @@ transient { qc_results { [] } } + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |receptacle, evaluator| receptacle._cached_relationship(:qc_results) { evaluator.qc_results || [] } receptacle._cached_relationship(:requests_as_source) { evaluator.requests_as_source || [] } diff --git a/spec/factories/request_factories.rb b/spec/factories/request_factories.rb index 445adac03..ae20ad075 100644 --- a/spec/factories/request_factories.rb +++ b/spec/factories/request_factories.rb @@ -70,6 +70,7 @@ factory :library_request do request_type { create :library_request_type } + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) { |request, evaluator| request._cached_relationship(:request_type) { evaluator.request_type } } # Library request with primer panel information diff --git a/spec/factories/sample_factories.rb b/spec/factories/sample_factories.rb index 53b836312..8fa27b6d9 100644 --- a/spec/factories/sample_factories.rb +++ b/spec/factories/sample_factories.rb @@ -15,6 +15,7 @@ sample_manifest { create(:v2_sample_manifest) } uuid { SecureRandom.uuid } + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) { |sample, evaluator| sample._cached_relationship(:sample_metadata) { evaluator.sample_metadata } } end diff --git a/spec/factories/tube_factories.rb b/spec/factories/tube_factories.rb index c487968e6..d2b98b46e 100644 --- a/spec/factories/tube_factories.rb +++ b/spec/factories/tube_factories.rb @@ -119,7 +119,7 @@ purpose { create :v2_purpose, name: purpose_name, uuid: purpose_uuid } end - # Mock the relationships. Should probably handle this all a bit differently + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |asset, evaluator| asset._cached_relationship(:purpose) { evaluator.purpose } ancestors_scope = JsonApiClient::Query::Builder.new(Sequencescape::Api::V2::Asset) diff --git a/spec/factories/tube_rack_factories.rb b/spec/factories/tube_rack_factories.rb index 66adfe094..807f3a847 100644 --- a/spec/factories/tube_rack_factories.rb +++ b/spec/factories/tube_rack_factories.rb @@ -34,6 +34,7 @@ created_at { '2017-06-29T09:31:59.000+01:00' } updated_at { '2017-06-29T09:31:59.000+01:00' } + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |tube_rack, evaluator| Sequencescape::Api::V2::TubeRack.associations.each do |association| tube_rack._cached_relationship(association.attr_name) { evaluator.send(association.attr_name) } diff --git a/spec/factories/well_factories.rb b/spec/factories/well_factories.rb index 2da1c844f..60e5059b8 100644 --- a/spec/factories/well_factories.rb +++ b/spec/factories/well_factories.rb @@ -105,6 +105,7 @@ sub_pool { nil } coverage { nil } + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |well, evaluator| well._cached_relationship(:qc_results) { evaluator.qc_results || [] } well._cached_relationship(:aliquots) { evaluator.aliquots || [] } @@ -273,8 +274,8 @@ sample { create :v2_sample, sample_attributes } request { outer_request } + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |aliquot, evaluator| - # Set up relationships downstream Sequencescape::Api::V2::Aliquot.associations.each do |association| aliquot._cached_relationship(association.attr_name) { evaluator.send(association.attr_name) } end From 4fd7757dc37b5697087223912fb8cc5cabad3d7e Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 1 Aug 2024 12:00:26 +0100 Subject: [PATCH 16/70] Remove the accidentally committed test debugging objects --- spec/models/labware_creators/custom_tagged_plate_spec.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/spec/models/labware_creators/custom_tagged_plate_spec.rb b/spec/models/labware_creators/custom_tagged_plate_spec.rb index bf9929d03..38c5fd689 100644 --- a/spec/models/labware_creators/custom_tagged_plate_spec.rb +++ b/spec/models/labware_creators/custom_tagged_plate_spec.rb @@ -44,11 +44,8 @@ let(:maximum_tag_offset) { largest_tag_group - occupied_wells } let(:maximum_well_offset) { plate_size - occupied_wells + 1 } - let(:tag_group) { create :v2_tag_group_with_tags } - let(:tlts) { create_list :v2_tag_layout_template, 2 } it 'can be created' do - binding.pry expect(subject).to be_a LabwareCreators::CustomTaggedPlate end From 1d89cf78cacb1df3c9bfa52417750144c01e107a Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 1 Aug 2024 12:00:53 +0100 Subject: [PATCH 17/70] Ensure tags generated for a tag_group point to the correct group --- spec/factories/tag_factories.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/factories/tag_factories.rb b/spec/factories/tag_factories.rb index 16e19a688..36787d8ea 100644 --- a/spec/factories/tag_factories.rb +++ b/spec/factories/tag_factories.rb @@ -27,7 +27,7 @@ def generate_oligo factory :v2_tag_group_with_tags do transient do size { 96 } - v2_tags { (1..size).map { |i| create(:v2_tag, map_id: i) } } + v2_tags { (1..size).map { |i| create(:v2_tag, map_id: i, tag_group: instance) } } end end end From 4b82bbbc78e4d93118f2b6b12199524f3b809dc9 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 1 Aug 2024 12:01:14 +0100 Subject: [PATCH 18/70] Fix relationships for tag layout templates in FactoryBot --- spec/factories/tag_layout_template_factories.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spec/factories/tag_layout_template_factories.rb b/spec/factories/tag_layout_template_factories.rb index 466e65d9b..126a2e41d 100644 --- a/spec/factories/tag_layout_template_factories.rb +++ b/spec/factories/tag_layout_template_factories.rb @@ -5,10 +5,15 @@ skip_create uuid - name { 'Test tag layout' } + sequence(:name) { |index| "TagLayoutTemplate#{index}" } direction { 'column' } walking_by { 'wells of plate' } - tag_group { create :v2_tag_group_with_tags } + transient { tag_group { create :v2_tag_group_with_tags } } + + # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" + after(:build) do |tag_layout_template, evaluator| + tag_layout_template._cached_relationship(:tag_group) { evaluator.tag_group } if evaluator.tag_group + end end # API V1 tag layout template. The inheriting factories set up the patterns From 3306e6dead06ce2d4ede898b27aa995777786ea1 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 1 Aug 2024 17:27:10 +0100 Subject: [PATCH 19/70] Fix tests for custom tagged plate spec --- .../sequencescape/api/v2/tag_layout_template.rb | 4 ++++ spec/factories/tag_layout_template_factories.rb | 6 +++++- .../labware_creators/custom_tagged_plate_spec.rb | 15 ++++++++------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb b/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb index 57cc5d050..2dcd88147 100644 --- a/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb +++ b/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb @@ -5,6 +5,10 @@ class Sequencescape::Api::V2::TagLayoutTemplate < Sequencescape::Api::V2::Base has_one :tag_group has_one :tag2_group + def dual_index? + tag2_group.present? + end + # Performs the coercion of this instance so that it behaves appropriately given the direction # and walking algorithm information. def coerce diff --git a/spec/factories/tag_layout_template_factories.rb b/spec/factories/tag_layout_template_factories.rb index 126a2e41d..5720c6877 100644 --- a/spec/factories/tag_layout_template_factories.rb +++ b/spec/factories/tag_layout_template_factories.rb @@ -8,11 +8,15 @@ sequence(:name) { |index| "TagLayoutTemplate#{index}" } direction { 'column' } walking_by { 'wells of plate' } - transient { tag_group { create :v2_tag_group_with_tags } } + transient do + tag_group { create :v2_tag_group_with_tags } + tag2_group { nil } + end # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |tag_layout_template, evaluator| tag_layout_template._cached_relationship(:tag_group) { evaluator.tag_group } if evaluator.tag_group + tag_layout_template._cached_relationship(:tag2_group) { evaluator.tag2_group } if evaluator.tag2_group end end diff --git a/spec/models/labware_creators/custom_tagged_plate_spec.rb b/spec/models/labware_creators/custom_tagged_plate_spec.rb index 38c5fd689..d4ba93ded 100644 --- a/spec/models/labware_creators/custom_tagged_plate_spec.rb +++ b/spec/models/labware_creators/custom_tagged_plate_spec.rb @@ -58,8 +58,6 @@ end context 'fetching layout templates' do - before { stub_v2_tag_layout_templates(create_list :v2_tag_layout_template, 2) } - let(:layout_hash) do WellHelpers.column_order.each_with_index.map do |w, i| pool = i < 8 ? 1 : 2 @@ -67,19 +65,22 @@ end end - # rubocop:todo Layout/LineLength - # Recording existing behaviour here before refactoring, but this looks like it might be just for pool tagging. Which is noe unused. - # rubocop:enable Layout/LineLength + let(:tag_layout_templates) { create_list :v2_tag_layout_template, 2 } + + before { stub_v2_tag_layout_templates(tag_layout_templates) } + + # Recording existing behaviour here before refactoring, but this looks like it might be just for pool tagging. + # Which is now unused. it 'lists tag groups' do expect(subject.tag_plates_list).to eq( - 'tag-layout-template-0' => { + tag_layout_templates[0].uuid => { tags: layout_hash, used: false, dual_index: false, approved: true, matches_templates_in_pool: true }, - 'tag-layout-template-1' => { + tag_layout_templates[1].uuid => { tags: layout_hash, used: false, dual_index: false, From b751825f8a2f3dfed63f255bc5f0fdde909b4332 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 1 Aug 2024 18:02:45 +0100 Subject: [PATCH 20/70] Fix tests for tagged_plate_spec --- .../labware_creators/tagged_plate_spec.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/spec/models/labware_creators/tagged_plate_spec.rb b/spec/models/labware_creators/tagged_plate_spec.rb index 166450efe..a9253a587 100644 --- a/spec/models/labware_creators/tagged_plate_spec.rb +++ b/spec/models/labware_creators/tagged_plate_spec.rb @@ -70,8 +70,6 @@ end context 'fetching layout templates' do - before { stub_api_get('tag_layout_templates', body: json(:tag_layout_template_collection, size: 2)) } - let(:layout_hash) do WellHelpers.column_order.each_with_index.map do |w, i| pool = i < 8 ? 1 : 2 @@ -79,22 +77,23 @@ end end - # rubocop:todo Layout/LineLength - # Recording existing behaviour here before refactoring, but this looks like it might be just for pool tagging. Which is not unused. - # rubocop:enable Layout/LineLength - # rubocop:todo Layout/LineLength - # No method explicitly called `tag_plates_list` - comes from `delegate :used?, :list, :names, to: :tag_plates, prefix: true` - # rubocop:enable Layout/LineLength + let(:tag_layout_templates) { create_list :tag_layout_template, 2 } + + before { stub_v2_tag_layout_templates(tag_layout_templates) } + + # Recording existing behaviour here before refactoring, but this looks like it might be just for pool tagging. + # Which is now unused. No method explicitly called `tag_plates_list` comes from + # `delegate :used?, :list, :names, to: :tag_plates, prefix: true` it 'lists tag groups' do expect(subject.tag_plates_list).to eq( - 'tag-layout-template-0' => { + tag_layout_templates[0].uuid => { tags: layout_hash, used: false, dual_index: false, approved: true, matches_templates_in_pool: true }, - 'tag-layout-template-1' => { + tag_layout_templates[1].uuid => { tags: layout_hash, used: false, dual_index: false, From c4940a1b1643a0e3d5724d89dd5ab60e22abff40 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 2 Aug 2024 16:41:36 +0100 Subject: [PATCH 21/70] Remove unneeded stub --- spec/support/shared_tagging_examples.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/support/shared_tagging_examples.rb b/spec/support/shared_tagging_examples.rb index 1d6d45a36..b718f8dc0 100644 --- a/spec/support/shared_tagging_examples.rb +++ b/spec/support/shared_tagging_examples.rb @@ -50,11 +50,9 @@ ) end - let(:tag_layout_template) { json(:tag_layout_template, uuid: tag_template_uuid) } let(:enforce_uniqueness) { true } let!(:tag_layout_creation_request) do - stub_api_get(tag_template_uuid, body: tag_layout_template) stub_api_post( tag_template_uuid, payload: { From cc2593be8ec6de04cc73a105bdfda31a56c3851f Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 2 Aug 2024 16:41:53 +0100 Subject: [PATCH 22/70] Add a factory for a dual indexed tag layout template --- spec/factories/tag_layout_template_factories.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/factories/tag_layout_template_factories.rb b/spec/factories/tag_layout_template_factories.rb index 5720c6877..678ec581e 100644 --- a/spec/factories/tag_layout_template_factories.rb +++ b/spec/factories/tag_layout_template_factories.rb @@ -18,6 +18,10 @@ tag_layout_template._cached_relationship(:tag_group) { evaluator.tag_group } if evaluator.tag_group tag_layout_template._cached_relationship(:tag2_group) { evaluator.tag2_group } if evaluator.tag2_group end + + factory :v2_dual_index_tag_layout_template do + transient { tag2_group { create :v2_tag_group_with_tags } } + end end # API V1 tag layout template. The inheriting factories set up the patterns From cbb3f58224c5b22ebef177368d6dc23acf90aae2 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 2 Aug 2024 16:43:15 +0100 Subject: [PATCH 23/70] Clean up the naming in shared examples --- spec/features/creating_a_tag_plate_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/features/creating_a_tag_plate_spec.rb b/spec/features/creating_a_tag_plate_spec.rb index b9a6f4a5f..312f566b6 100644 --- a/spec/features/creating_a_tag_plate_spec.rb +++ b/spec/features/creating_a_tag_plate_spec.rb @@ -74,7 +74,7 @@ stub_api_get('tag-lot-type-uuid', body: json(:tag_lot_type)) end - shared_examples 'supports the plate' do + shared_examples 'it supports the plate' do let(:help_text) { "Click 'Create plate'" } before { stub_v2_plate(create(:v2_plate, uuid: tag_plate_uuid, purpose_uuid: 'stock-plate-purpose-uuid')) } @@ -132,7 +132,7 @@ let(:submission_pools) { json(:submission_pool_collection) } let(:help_text) { 'This plate does not appear to be part of a larger pool. Dual indexing is optional.' } let(:enforce_uniqueness) { false } - it_behaves_like 'supports the plate' + it_behaves_like 'it supports the plate' end context 'when the pool has been tagged by plates' do @@ -154,7 +154,7 @@ context 'when nothing has been done' do let(:submission_pools) { json(:dual_submission_pool_collection) } let(:help_text) { 'This plate is part of a larger pool and must be indexed with UDI plates.' } - it_behaves_like 'supports the plate' + it_behaves_like 'it supports the plate' end context 'when the pool has been tagged by plates' do @@ -165,7 +165,7 @@ ) end let(:help_text) { 'This plate is part of a larger pool which has been indexed with UDI plates.' } - it_behaves_like 'supports the plate' + it_behaves_like 'it supports the plate' end context 'when the template has been used' do @@ -197,7 +197,7 @@ context 'when the template has been used' do let(:used_template_uuid) { 'tag-layout-template-0' } - it_behaves_like 'supports the plate' + it_behaves_like 'it supports the plate' end context 'when the pool has been tagged by plates' do From 3da27a2163ae34a8b2f775771863771878c95dcd Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 5 Aug 2024 10:25:08 +0100 Subject: [PATCH 24/70] Correctly name context blocks --- spec/features/creating_a_tag_plate_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/creating_a_tag_plate_spec.rb b/spec/features/creating_a_tag_plate_spec.rb index 312f566b6..b291ce5b5 100644 --- a/spec/features/creating_a_tag_plate_spec.rb +++ b/spec/features/creating_a_tag_plate_spec.rb @@ -118,8 +118,8 @@ end shared_examples 'a recognised template' do - context 'a single indexed tag plate' do let(:template_factory) { :tag_layout_template } + context 'with a single indexed tag plate' do context 'when nothing has been done on a cross plate pool' do let(:submission_pools) { json(:dual_submission_pool_collection) } @@ -148,8 +148,8 @@ end end - context 'a dual indexed tag plate' do let(:template_factory) { :dual_index_tag_layout_template } + context 'with a dual indexed tag plate' do context 'when nothing has been done' do let(:submission_pools) { json(:dual_submission_pool_collection) } From 7b0759f93f6d74cd906d05d7e748d11dac222b41 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 5 Aug 2024 15:25:52 +0100 Subject: [PATCH 25/70] Assign correct class for tag2_group on tag_layout_template --- app/sequencescape/sequencescape/api/v2/tag_layout_template.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb b/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb index 2dcd88147..b62e8dc8c 100644 --- a/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb +++ b/app/sequencescape/sequencescape/api/v2/tag_layout_template.rb @@ -3,7 +3,7 @@ # tag layout template resource class Sequencescape::Api::V2::TagLayoutTemplate < Sequencescape::Api::V2::Base has_one :tag_group - has_one :tag2_group + has_one :tag2_group, class_name: 'TagGroup' def dual_index? tag2_group.present? From 201fb5b0735428c98e5573f09576e7fc47781019 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 5 Aug 2024 15:52:00 +0100 Subject: [PATCH 26/70] Merge page results when getting tag layout templates --- app/models/labware_creators/tagging/tag_collection.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/labware_creators/tagging/tag_collection.rb b/app/models/labware_creators/tagging/tag_collection.rb index 4d159f0b1..e5fdb984b 100644 --- a/app/models/labware_creators/tagging/tag_collection.rb +++ b/app/models/labware_creators/tagging/tag_collection.rb @@ -103,7 +103,8 @@ def tags_by_column(layout) end def tag_layout_templates - Sequencescape::Api::V2::TagLayoutTemplate.all.map(&:coerce) + query = Sequencescape::Api::V2::TagLayoutTemplate.paginate(per_page: 100) + Sequencescape::Api::V2.merge_page_results(query).map(&:coerce) end end end From 7e895d308e64bc33657a443201771db74f81c189 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 6 Aug 2024 09:19:35 +0100 Subject: [PATCH 27/70] Add TODO about calling methods on resources --- app/models/labware_creators/tagged_plate.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/labware_creators/tagged_plate.rb b/app/models/labware_creators/tagged_plate.rb index 0ff3b4b63..088a8f10c 100644 --- a/app/models/labware_creators/tagged_plate.rb +++ b/app/models/labware_creators/tagged_plate.rb @@ -79,6 +79,10 @@ def convert_tag_plate_to_new_purpose def create_labware! create_plate! do |plate_uuid| + # TODO: {Y24-190} Work out a way to call the `create!` method on TagLayoutTemplate model in Sequencescape + # using the V2 API. I think either we need to misuse the PATCH method with some kind of + # attributes telling Sequencescape to run the `create!` method, or we need to create a new + # endpoint associated with a TagLayoutTemplate that will run the `create!` method. api .tag_layout_template .find(tag_plate.template_uuid) From d92ff39dd8611fdd61a327e2fa093f07649e82ab Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 6 Aug 2024 10:31:08 +0100 Subject: [PATCH 28/70] Stub v2 TagLayoutTemplates with paging --- spec/support/api_url_helper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index 20f489a2c..00db054d7 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -126,7 +126,9 @@ def stub_v2_study(study) end def stub_v2_tag_layout_templates(templates) - allow(Sequencescape::Api::V2::TagLayoutTemplate).to receive(:all).and_return(templates) + query = double('tag_layout_template_query') + allow(Sequencescape::Api::V2::TagLayoutTemplate).to receive(:paginate).and_return(query) + allow(Sequencescape::Api::V2).to receive(:merge_page_results).with(query).and_return(templates) end # Builds the basic v2 tube finding query. From ef03d4b9cfaf4e43bb050b3800a1e715b3c75a28 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 6 Aug 2024 10:45:36 +0100 Subject: [PATCH 29/70] Fix tests for creating_a_tag_plate_spec using V2 --- spec/features/creating_a_tag_plate_spec.rb | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/spec/features/creating_a_tag_plate_spec.rb b/spec/features/creating_a_tag_plate_spec.rb index b291ce5b5..c14ac46ca 100644 --- a/spec/features/creating_a_tag_plate_spec.rb +++ b/spec/features/creating_a_tag_plate_spec.rb @@ -66,12 +66,15 @@ stub_api_get(plate_uuid, 'wells', body: json(:well_collection)) stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) - stub_api_get('tag_layout_templates', body: templates) + stub_v2_tag_layout_templates(templates) stub_api_get(plate_uuid, 'submission_pools', body: submission_pools) stub_api_get(tag_plate_qcable_uuid, body: tag_plate_qcable) stub_api_get('lot-uuid', body: json(:tag_lot, lot_number: tag_lot_number, template_uuid: tag_template_uuid)) stub_api_get('tag-lot-type-uuid', body: json(:tag_lot_type)) + + # TODO: {Y24-190} Drop this stub when we no longer need to use V1 in #create_labware! in tagged_plate.rb + stub_api_get(tag_template_uuid, body: json(:tag_layout_template, uuid: tag_template_uuid)) end shared_examples 'it supports the plate' do @@ -118,8 +121,8 @@ end shared_examples 'a recognised template' do - let(:template_factory) { :tag_layout_template } context 'with a single indexed tag plate' do + let(:template_factory) { :v2_tag_layout_template } context 'when nothing has been done on a cross plate pool' do let(:submission_pools) { json(:dual_submission_pool_collection) } @@ -148,8 +151,8 @@ end end - let(:template_factory) { :dual_index_tag_layout_template } context 'with a dual indexed tag plate' do + let(:template_factory) { :v2_dual_index_tag_layout_template } context 'when nothing has been done' do let(:submission_pools) { json(:dual_submission_pool_collection) } @@ -211,11 +214,14 @@ feature 'with no configured templates' do let(:acceptable_templates) { nil } + let(:direction) { 'column' } + let(:templates) do - json(:tag_layout_template_collection, size: 2, direction: direction, template_factory: template_factory) + create_list(template_factory, 2, direction: direction) do |template, i| + template.uuid = "tag-layout-template-#{i}" + template.name = "Tag2 layout #{i}" + end end - let(:tag_layout_template) { json(template_factory, uuid: tag_template_uuid) } - let(:direction) { 'column' } let(:a2_tag) { '9' } it_behaves_like 'a recognised template' @@ -224,8 +230,12 @@ feature 'with configured templates' do let(:acceptable_templates) { ['Tag2 layout 0'] } let(:direction) { 'row' } + let(:templates) do - json(:tag_layout_template_collection, size: 2, direction: direction, template_factory: template_factory) + create_list(template_factory, 2, direction: direction) do |template, i| + template.uuid = "tag-layout-template-#{i}" + template.name = "Tag2 layout #{i}" + end end let(:a2_tag) { '2' } @@ -234,7 +244,7 @@ end feature 'and non matching scanned template' do - let(:template_factory) { :dual_index_tag_layout_template } + let(:template_factory) { :v2_dual_index_tag_layout_template } let(:tag_template_uuid) { 'unrecognised template' } let(:tag_error) { 'It is not approved for use with this pipeline.' } it_behaves_like 'it rejects the candidate plate' From 98fa7a115b20f9e43320609ed87abe53c4dde075 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 6 Aug 2024 13:44:13 +0100 Subject: [PATCH 30/70] Fix final tests for tag_layout_templates move to V2 --- spec/features/creating_a_tag_plate_spec.rb | 3 --- spec/support/shared_tagging_examples.rb | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/features/creating_a_tag_plate_spec.rb b/spec/features/creating_a_tag_plate_spec.rb index c14ac46ca..8f70f27b1 100644 --- a/spec/features/creating_a_tag_plate_spec.rb +++ b/spec/features/creating_a_tag_plate_spec.rb @@ -72,9 +72,6 @@ stub_api_get(tag_plate_qcable_uuid, body: tag_plate_qcable) stub_api_get('lot-uuid', body: json(:tag_lot, lot_number: tag_lot_number, template_uuid: tag_template_uuid)) stub_api_get('tag-lot-type-uuid', body: json(:tag_lot_type)) - - # TODO: {Y24-190} Drop this stub when we no longer need to use V1 in #create_labware! in tagged_plate.rb - stub_api_get(tag_template_uuid, body: json(:tag_layout_template, uuid: tag_template_uuid)) end shared_examples 'it supports the plate' do diff --git a/spec/support/shared_tagging_examples.rb b/spec/support/shared_tagging_examples.rb index b718f8dc0..6a1a0881f 100644 --- a/spec/support/shared_tagging_examples.rb +++ b/spec/support/shared_tagging_examples.rb @@ -50,9 +50,13 @@ ) end + let(:tag_layout_template) { json(:tag_layout_template, uuid: tag_template_uuid) } let(:enforce_uniqueness) { true } let!(:tag_layout_creation_request) do + # TODO: {Y24-190} Drop this stub when we no longer need to use V1 in #create_labware! in tagged_plate.rb + stub_api_get(tag_template_uuid, body: tag_layout_template) + stub_api_post( tag_template_uuid, payload: { From fcceab76f1f86ccd46fb65e977d0355b40f78f7a Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 9 Aug 2024 15:36:07 +0100 Subject: [PATCH 31/70] Resolve remaining use of V1 API during Chromium pipeline This includes creating a new module which lets LabwareCreators lookup a V2 plate as a `source_plate` when they usually only deal with v1 plates as `parent`. --- app/controllers/labware_controller.rb | 2 +- app/controllers/robots_controller.rb | 2 +- .../support_v2_source_plate.rb | 23 +++++++++++++++++++ .../labware_creators/cardinal_pools_plate.rb | 7 +----- .../labware_creators/pooled_tubes_base.rb | 5 +++- app/models/presenters/presenter.rb | 2 +- 6 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 app/models/concerns/labware_creators/support_v2_source_plate.rb diff --git a/app/controllers/labware_controller.rb b/app/controllers/labware_controller.rb index ea801bd13..baede85e0 100644 --- a/app/controllers/labware_controller.rb +++ b/app/controllers/labware_controller.rb @@ -85,7 +85,7 @@ def find_printers end def state_changer_for(purpose_uuid, labware_uuid) - StateChangers.lookup_for(purpose_uuid).new(labware_uuid, current_user_uuid) + StateChangers.lookup_for(purpose_uuid).new(api, labware_uuid, current_user_uuid) end def presenter_for(labware) diff --git a/app/controllers/robots_controller.rb b/app/controllers/robots_controller.rb index 634cc1eef..0d2733d01 100644 --- a/app/controllers/robots_controller.rb +++ b/app/controllers/robots_controller.rb @@ -74,7 +74,7 @@ def update_bed_labware_metadata(bed, robot_barcode) # def labware_created_with_robot(labware_barcode, robot_barcode) LabwareMetadata - .new(api: api, user: current_user_uuid, barcode: labware_barcode) + .new(user_uuid: current_user_uuid, barcode: labware_barcode) .update!(created_with_robot: robot_barcode) end diff --git a/app/models/concerns/labware_creators/support_v2_source_plate.rb b/app/models/concerns/labware_creators/support_v2_source_plate.rb new file mode 100644 index 000000000..451ba4291 --- /dev/null +++ b/app/models/concerns/labware_creators/support_v2_source_plate.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# TODO: {Y24-190} Remove this module once the V1 API is no longer used. + +# Can be included in labware creators which require access to a V2 source plate when passing a V1 parent plate +# to methods/classes requiring V2 resources. +module LabwareCreators::SupportV2SourcePlate + extend ActiveSupport::Concern + + included do + # parent is using SS v1 API + # so this method is used to access the plate via SS v2 API + def source_plate + if parent.is_a? Limber::Plate + @source_plate ||= Sequencescape::Api::V2::Plate.find_by(uuid: parent.uuid) if @source_plate&.uuid != parent.uuid + else + @source_plate = nil + end + + @source_plate + end + end +end diff --git a/app/models/labware_creators/cardinal_pools_plate.rb b/app/models/labware_creators/cardinal_pools_plate.rb index ece69eeb7..cfe4241e3 100644 --- a/app/models/labware_creators/cardinal_pools_plate.rb +++ b/app/models/labware_creators/cardinal_pools_plate.rb @@ -18,6 +18,7 @@ class CardinalPoolsPlate < Base include SupportParent::PlateOnly include LabwareCreators::RequireWellsWithCollectedBy + include LabwareCreators::SupportV2SourcePlate validate :wells_with_aliquots_must_have_collected_by @@ -29,12 +30,6 @@ def filters=(filter_parameters) well_filter.assign_attributes(filter_parameters) end - # parent is using SS v1 API - # so this method is used to access the plate via SS v2 API - def source_plate - @source_plate ||= Sequencescape::Api::V2::Plate.find_by(uuid: parent.uuid) - end - # Returns: a list of passed wells passed_parent_wells def passed_parent_wells source_plate.wells.select { |well| well.state == 'passed' } diff --git a/app/models/labware_creators/pooled_tubes_base.rb b/app/models/labware_creators/pooled_tubes_base.rb index 4d071645d..2cc5e2098 100644 --- a/app/models/labware_creators/pooled_tubes_base.rb +++ b/app/models/labware_creators/pooled_tubes_base.rb @@ -7,6 +7,9 @@ module LabwareCreators # the submission uuid - this should be changed class PooledTubesBase < Base include SupportParent::TaggedPlateOnly + + include LabwareCreators::SupportV2SourcePlate + attr_reader :tube_transfer, :child_stock_tubes attr_writer :metadata_stock_barcode @@ -94,7 +97,7 @@ def metadata_stock_barcode def parent_metadata if parent.is_a? Limber::Plate - LabwareMetadata.new(labware: parent).metadata + LabwareMetadata.new(labware: source_plate).metadata else LabwareMetadata.new(barcode: parent.barcode.machine).metadata end || {} diff --git a/app/models/presenters/presenter.rb b/app/models/presenters/presenter.rb index 9b23da05f..fa4207008 100644 --- a/app/models/presenters/presenter.rb +++ b/app/models/presenters/presenter.rb @@ -12,7 +12,7 @@ module Presenters::Presenter # rubocop:todo Style/Documentation class_attribute :summary_items, :sidebar_partial, :summary_partial, :pooling_tab - attr_accessor :api, :labware + attr_accessor :labware self.page = 'show' self.sidebar_partial = 'default' From 9ef1a335b4ac48405d9b95af29439076655d9ea3 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 9 Aug 2024 16:47:36 +0100 Subject: [PATCH 32/70] Fix tests for Presenters They no longer use the api V1 and the tests were passing them the api variable when they no longer accept one. --- spec/models/presenters/banking_plate_presenter_spec.rb | 4 +--- .../presenters/concentration_binned_plate_presenter_spec.rb | 4 +--- .../models/presenters/donor_pooling_plate_presenter_spec.rb | 4 +--- spec/models/presenters/final_tube_presenter_spec.rb | 6 +----- spec/models/presenters/minimal_pcr_plate_presenter_spec.rb | 4 +--- spec/models/presenters/minimal_plate_presenter_spec.rb | 4 +--- .../models/presenters/minimal_stock_plate_presenter_spec.rb | 4 +--- .../presenters/normalised_binned_plate_presenter_spec.rb | 4 +--- ...es_binned_plate_using_request_metadata_presenter_spec.rb | 4 +--- ...ycles_binned_plate_using_well_metadata_presenter_spec.rb | 4 +--- spec/models/presenters/permissive_presenter_spec.rb | 4 +--- spec/models/presenters/plate_presenter_spec.rb | 4 +--- spec/models/presenters/rvi_cnda_xp_presenter_spec.rb | 4 +--- .../presenters/single_child_permissive_presenter_spec.rb | 4 +--- spec/models/presenters/standard_presenter_spec.rb | 4 +--- spec/models/presenters/stock_plate_presenter_spec.rb | 4 +--- spec/models/presenters/submission_plate_presenter_spec.rb | 4 +--- spec/models/presenters/tag_plate_384_presenter_spec.rb | 4 +--- spec/models/presenters/tube_presenter_spec.rb | 4 +--- spec/models/presenters/tube_rack_presenter_spec.rb | 4 +--- spec/models/presenters/unknown_plate_presenter_spec.rb | 4 +--- 21 files changed, 21 insertions(+), 65 deletions(-) diff --git a/spec/models/presenters/banking_plate_presenter_spec.rb b/spec/models/presenters/banking_plate_presenter_spec.rb index 44f09f058..090011616 100644 --- a/spec/models/presenters/banking_plate_presenter_spec.rb +++ b/spec/models/presenters/banking_plate_presenter_spec.rb @@ -6,14 +6,12 @@ # state. We use StandardPresenter to test this because it is the default # presenter for plates and it includes a state machine to handle the state. RSpec.describe Presenters::StandardPresenter do - has_a_working_api - before { create :banking_plate_purpose_config } let(:purpose_name) { 'banking-plate-purpose' } let(:purpose) { create :v2_purpose, name: purpose_name } let(:labware) { create :v2_plate, purpose: purpose } - let(:presenter) { described_class.new(api: api, labware: labware) } + let(:presenter) { described_class.new(labware: labware) } describe '#csv_file_links' do let(:download_in_passed_state_name) { 'Download PBMC Bank Tubes Content Report' } diff --git a/spec/models/presenters/concentration_binned_plate_presenter_spec.rb b/spec/models/presenters/concentration_binned_plate_presenter_spec.rb index 7639508c0..53d1adf42 100644 --- a/spec/models/presenters/concentration_binned_plate_presenter_spec.rb +++ b/spec/models/presenters/concentration_binned_plate_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::ConcentrationBinnedPlatePresenter do - has_a_working_api - let(:purpose_name) { 'Limber example purpose' } let(:title) { purpose_name } let(:state) { 'pending' } @@ -58,7 +56,7 @@ before { stub_v2_plate(labware, stub_search: false, custom_includes: 'wells.aliquots,wells.qc_results') } - subject(:presenter) { Presenters::ConcentrationBinnedPlatePresenter.new(api: api, labware: labware) } + subject(:presenter) { Presenters::ConcentrationBinnedPlatePresenter.new(labware: labware) } context 'when binning configuration is missing' do it 'throws an exception' do diff --git a/spec/models/presenters/donor_pooling_plate_presenter_spec.rb b/spec/models/presenters/donor_pooling_plate_presenter_spec.rb index b3e58d30d..077bbdaff 100644 --- a/spec/models/presenters/donor_pooling_plate_presenter_spec.rb +++ b/spec/models/presenters/donor_pooling_plate_presenter_spec.rb @@ -3,8 +3,6 @@ require 'spec_helper' RSpec.describe Presenters::DonorPoolingPlatePresenter do - has_a_working_api - # First set of source wells let(:source_well_a1) { create(:v2_well, location: 'A1') } @@ -76,7 +74,7 @@ let(:option_key) { 'scrna_core_pbmc_donor_pooling_required_number_of_cells' } let(:default_cell_count) { 5000 } - subject { Presenters::DonorPoolingPlatePresenter.new(api: api, labware: labware) } + subject { Presenters::DonorPoolingPlatePresenter.new(labware: labware) } before do Settings.purposes = { diff --git a/spec/models/presenters/final_tube_presenter_spec.rb b/spec/models/presenters/final_tube_presenter_spec.rb index c3ffd33d6..712c258f6 100644 --- a/spec/models/presenters/final_tube_presenter_spec.rb +++ b/spec/models/presenters/final_tube_presenter_spec.rb @@ -5,10 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::FinalTubePresenter do - # Not sure why this is getting executed twice. - # Want to get the basics working first though - has_a_working_api - let(:labware) do build :v2_tube, purpose_name: purpose_name, state: state, barcode_number: 6, created_at: '2016-10-19 12:00:00 +0100' end @@ -29,7 +25,7 @@ end let(:sidebar_partial) { 'default' } - subject { Presenters::FinalTubePresenter.new(api: api, labware: labware) } + subject { Presenters::FinalTubePresenter.new(labware: labware) } it_behaves_like 'a labware presenter' end diff --git a/spec/models/presenters/minimal_pcr_plate_presenter_spec.rb b/spec/models/presenters/minimal_pcr_plate_presenter_spec.rb index f46312ce1..08a177ae0 100644 --- a/spec/models/presenters/minimal_pcr_plate_presenter_spec.rb +++ b/spec/models/presenters/minimal_pcr_plate_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::MinimalPcrPlatePresenter do - has_a_working_api - let(:labware) do create :v2_plate_with_primer_panels, purpose_name: purpose_name, @@ -33,7 +31,7 @@ end let(:sidebar_partial) { 'default' } - subject(:presenter) { Presenters::MinimalPcrPlatePresenter.new(api: api, labware: labware) } + subject(:presenter) { Presenters::MinimalPcrPlatePresenter.new(labware: labware) } before do create(:purpose_config, uuid: labware.purpose.uuid) diff --git a/spec/models/presenters/minimal_plate_presenter_spec.rb b/spec/models/presenters/minimal_plate_presenter_spec.rb index 93fbb1b7c..eba217064 100644 --- a/spec/models/presenters/minimal_plate_presenter_spec.rb +++ b/spec/models/presenters/minimal_plate_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::MinimalPlatePresenter do - has_a_working_api - let(:labware) do create :v2_plate, purpose_name: purpose_name, @@ -37,7 +35,7 @@ create :stock_plate_config, uuid: 'stock-plate-purpose-uuid' end - subject(:presenter) { Presenters::MinimalPlatePresenter.new(api: api, labware: labware) } + subject(:presenter) { Presenters::MinimalPlatePresenter.new(labware: labware) } it 'returns label attributes' do expected_label = { diff --git a/spec/models/presenters/minimal_stock_plate_presenter_spec.rb b/spec/models/presenters/minimal_stock_plate_presenter_spec.rb index 860928a2f..ce55c0b28 100644 --- a/spec/models/presenters/minimal_stock_plate_presenter_spec.rb +++ b/spec/models/presenters/minimal_stock_plate_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::MinimalStockPlatePresenter do - has_a_working_api - let(:labware) do create :v2_stock_plate, purpose_name: purpose_name, @@ -35,7 +33,7 @@ before { create :stock_plate_config, uuid: labware.purpose.uuid, name: purpose_name } - subject(:presenter) { Presenters::MinimalStockPlatePresenter.new(api: api, labware: labware) } + subject(:presenter) { Presenters::MinimalStockPlatePresenter.new(labware: labware) } it 'returns label attributes' do expected_label = { diff --git a/spec/models/presenters/normalised_binned_plate_presenter_spec.rb b/spec/models/presenters/normalised_binned_plate_presenter_spec.rb index aaf539ae4..3388763cb 100644 --- a/spec/models/presenters/normalised_binned_plate_presenter_spec.rb +++ b/spec/models/presenters/normalised_binned_plate_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::NormalisedBinnedPlatePresenter do - has_a_working_api - let(:purpose_name) { 'Limber example purpose' } let(:title) { purpose_name } let(:state) { 'pending' } @@ -59,7 +57,7 @@ before { stub_v2_plate(labware, stub_search: false, custom_includes: 'wells.aliquots,wells.qc_results') } - subject(:presenter) { Presenters::NormalisedBinnedPlatePresenter.new(api: api, labware: labware) } + subject(:presenter) { Presenters::NormalisedBinnedPlatePresenter.new(labware: labware) } context 'when configuration is missing' do it 'throws an exception' do diff --git a/spec/models/presenters/pcr_cycles_binned_plate_using_request_metadata_presenter_spec.rb b/spec/models/presenters/pcr_cycles_binned_plate_using_request_metadata_presenter_spec.rb index 09757b85f..fb20d6127 100644 --- a/spec/models/presenters/pcr_cycles_binned_plate_using_request_metadata_presenter_spec.rb +++ b/spec/models/presenters/pcr_cycles_binned_plate_using_request_metadata_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::PcrCyclesBinnedPlateUsingRequestMetadataPresenter do - has_a_working_api - let(:purpose_name) { 'Limber example purpose' } let(:title) { purpose_name } let(:state) { 'pending' } @@ -112,7 +110,7 @@ ) end - subject(:presenter) { Presenters::PcrCyclesBinnedPlateUsingRequestMetadataPresenter.new(api: api, labware: labware) } + subject(:presenter) { Presenters::PcrCyclesBinnedPlateUsingRequestMetadataPresenter.new(labware: labware) } context 'when binning' do it_behaves_like 'a labware presenter' diff --git a/spec/models/presenters/pcr_cycles_binned_plate_using_well_metadata_presenter_spec.rb b/spec/models/presenters/pcr_cycles_binned_plate_using_well_metadata_presenter_spec.rb index b6e5554bb..1c8d9ac3f 100644 --- a/spec/models/presenters/pcr_cycles_binned_plate_using_well_metadata_presenter_spec.rb +++ b/spec/models/presenters/pcr_cycles_binned_plate_using_well_metadata_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::PcrCyclesBinnedPlateUsingWellMetadataPresenter do - has_a_working_api - let(:purpose_name) { 'Limber example purpose' } let(:title) { purpose_name } let(:state) { 'pending' } @@ -86,7 +84,7 @@ before { stub_v2_plate(labware, stub_search: false, custom_includes: 'wells.aliquots,wells.qc_results') } - subject(:presenter) { Presenters::PcrCyclesBinnedPlateUsingWellMetadataPresenter.new(api: api, labware: labware) } + subject(:presenter) { Presenters::PcrCyclesBinnedPlateUsingWellMetadataPresenter.new(labware: labware) } context 'when binning' do it_behaves_like 'a labware presenter' diff --git a/spec/models/presenters/permissive_presenter_spec.rb b/spec/models/presenters/permissive_presenter_spec.rb index 91d0273fa..9eb4cb12a 100644 --- a/spec/models/presenters/permissive_presenter_spec.rb +++ b/spec/models/presenters/permissive_presenter_spec.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true RSpec.describe Presenters::PermissivePresenter do - has_a_working_api - let(:purpose_name) { 'Example purpose' } let(:labware) { create :v2_plate, state: state, purpose_name: purpose_name, pool_sizes: [1] } - subject { Presenters::PermissivePresenter.new(api: api, labware: labware) } + subject { Presenters::PermissivePresenter.new(labware: labware) } before(:each) do create :purpose_config, uuid: 'child-purpose', name: 'Child purpose' diff --git a/spec/models/presenters/plate_presenter_spec.rb b/spec/models/presenters/plate_presenter_spec.rb index 779f0afca..3a4e90622 100644 --- a/spec/models/presenters/plate_presenter_spec.rb +++ b/spec/models/presenters/plate_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::PlatePresenter do - has_a_working_api - let(:purpose_name) { 'Limber example purpose' } let(:title) { purpose_name } let(:state) { 'pending' } @@ -40,7 +38,7 @@ create(:stock_plate_config, uuid: 'stock-plate-purpose-uuid') end - subject(:presenter) { Presenters::PlatePresenter.new(api: api, labware: labware) } + subject(:presenter) { Presenters::PlatePresenter.new(labware: labware) } describe '#custom_metadata_fields' do context 'with custom_metadata_fields' do diff --git a/spec/models/presenters/rvi_cnda_xp_presenter_spec.rb b/spec/models/presenters/rvi_cnda_xp_presenter_spec.rb index 7da6b2eb4..96d9aa76f 100644 --- a/spec/models/presenters/rvi_cnda_xp_presenter_spec.rb +++ b/spec/models/presenters/rvi_cnda_xp_presenter_spec.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true RSpec.describe Presenters::RviCdnaXpPresenter do - has_a_working_api - let(:purpose_name) { 'Example purpose' } let(:labware) { create :v2_plate, state: state, purpose_name: purpose_name, pool_sizes: [1] } - subject { Presenters::RviCdnaXpPresenter.new(api: api, labware: labware) } + subject { Presenters::RviCdnaXpPresenter.new(labware: labware) } before(:each) do create :purpose_config, uuid: 'child-purpose', name: 'Child purpose' diff --git a/spec/models/presenters/single_child_permissive_presenter_spec.rb b/spec/models/presenters/single_child_permissive_presenter_spec.rb index 24af5885b..3fc336f4f 100644 --- a/spec/models/presenters/single_child_permissive_presenter_spec.rb +++ b/spec/models/presenters/single_child_permissive_presenter_spec.rb @@ -1,14 +1,12 @@ # frozen_string_literal: true RSpec.describe Presenters::SingleChildPermissivePresenter do - has_a_working_api - let(:purpose_name) { 'Example purpose' } let(:labware) { create :v2_plate, state: state, purpose_name: purpose_name, pool_sizes: [1] } let(:child_purpose) { 'Child purpose' } let(:child_plate) { create :v2_plate, purpose_name: child_purpose } - subject { Presenters::SingleChildPermissivePresenter.new(api: api, labware: labware) } + subject { Presenters::SingleChildPermissivePresenter.new(labware: labware) } before(:each) do create :purpose_config, uuid: 'child-purpose', name: child_purpose diff --git a/spec/models/presenters/standard_presenter_spec.rb b/spec/models/presenters/standard_presenter_spec.rb index 314f54f43..09a36dff6 100644 --- a/spec/models/presenters/standard_presenter_spec.rb +++ b/spec/models/presenters/standard_presenter_spec.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true RSpec.describe Presenters::StandardPresenter do - has_a_working_api - let(:purpose_name) { 'Example purpose' } let(:aliquot_type) { :v2_aliquot } let(:state) { 'pending' } @@ -41,7 +39,7 @@ end let(:suggest_passes) { nil } - subject { Presenters::StandardPresenter.new(api: api, labware: labware) } + subject { Presenters::StandardPresenter.new(labware: labware) } it 'returns the priority' do expect(subject.priority).to eq(2) diff --git a/spec/models/presenters/stock_plate_presenter_spec.rb b/spec/models/presenters/stock_plate_presenter_spec.rb index 6619998aa..d015d999d 100644 --- a/spec/models/presenters/stock_plate_presenter_spec.rb +++ b/spec/models/presenters/stock_plate_presenter_spec.rb @@ -4,11 +4,9 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::StockPlatePresenter do - has_a_working_api - let(:labware) { create :v2_stock_plate } - subject { Presenters::StockPlatePresenter.new(api: api, labware: labware) } + subject { Presenters::StockPlatePresenter.new(labware: labware) } let(:barcode_string) { 'DN2T' } diff --git a/spec/models/presenters/submission_plate_presenter_spec.rb b/spec/models/presenters/submission_plate_presenter_spec.rb index 07b31d1df..c24588e46 100644 --- a/spec/models/presenters/submission_plate_presenter_spec.rb +++ b/spec/models/presenters/submission_plate_presenter_spec.rb @@ -4,9 +4,7 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::SubmissionPlatePresenter do - has_a_working_api - - subject(:presenter) { described_class.new(api: api, labware: labware) } + subject(:presenter) { described_class.new(labware: labware) } let(:submission_options) do { diff --git a/spec/models/presenters/tag_plate_384_presenter_spec.rb b/spec/models/presenters/tag_plate_384_presenter_spec.rb index 8d77544fd..6b6c3d823 100644 --- a/spec/models/presenters/tag_plate_384_presenter_spec.rb +++ b/spec/models/presenters/tag_plate_384_presenter_spec.rb @@ -5,15 +5,13 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::TagPlate384Presenter do - has_a_working_api - before { create :tag_plate_384_purpose_config } let(:date_format) { /\A\s?\d{1,2}-[A-Z]{3}-\d{4}\z/ } # e.g., ' 4 JUL 2023' or '24 JUL 2023' let(:purpose_name) { 'Tag Plate - 384' } let(:purpose) { create :v2_purpose, name: purpose_name } let(:labware) { create :v2_plate, purpose: purpose, size: 384, stock_plate: nil } - let(:presenter) { described_class.new(api: api, labware: labware) } + let(:presenter) { described_class.new(labware: labware) } it 'can be looked up for labware' do expect(Presenters.lookup_for(labware)).to be(described_class) diff --git a/spec/models/presenters/tube_presenter_spec.rb b/spec/models/presenters/tube_presenter_spec.rb index aa103ec79..e5de9e233 100644 --- a/spec/models/presenters/tube_presenter_spec.rb +++ b/spec/models/presenters/tube_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::TubePresenter do - has_a_working_api - let(:labware) do build :v2_tube, receptacle: receptacle, @@ -41,7 +39,7 @@ end let(:sidebar_partial) { 'default' } - subject { Presenters::TubePresenter.new(api: api, labware: labware) } + subject { Presenters::TubePresenter.new(labware: labware) } it_behaves_like 'a labware presenter' diff --git a/spec/models/presenters/tube_rack_presenter_spec.rb b/spec/models/presenters/tube_rack_presenter_spec.rb index d49a67b8b..676527bba 100644 --- a/spec/models/presenters/tube_rack_presenter_spec.rb +++ b/spec/models/presenters/tube_rack_presenter_spec.rb @@ -5,8 +5,6 @@ require_relative 'shared_labware_presenter_examples' RSpec.describe Presenters::TubeRackPresenter do - has_a_working_api - let(:purpose_name) { 'TR96' } let(:tube_purpose_name) { 'Tube purpose' } let(:title) { "#{purpose_name} : #{tube_purpose_name}" } @@ -49,7 +47,7 @@ create(:stock_plate_config, uuid: 'stock-plate-purpose-uuid') end - subject(:presenter) { described_class.new(api: api, labware: labware) } + subject(:presenter) { described_class.new(labware: labware) } it_behaves_like 'a labware presenter' diff --git a/spec/models/presenters/unknown_plate_presenter_spec.rb b/spec/models/presenters/unknown_plate_presenter_spec.rb index 5b63846a1..53f7dbd74 100644 --- a/spec/models/presenters/unknown_plate_presenter_spec.rb +++ b/spec/models/presenters/unknown_plate_presenter_spec.rb @@ -1,11 +1,9 @@ # frozen_string_literal: true RSpec.describe Presenters::UnknownPlatePresenter do - has_a_working_api - let(:labware) { create :v2_plate, purpose_name: 'Other plate' } - subject { described_class.new(api: api, labware: labware) } + subject { described_class.new(labware: labware) } it 'prevents state change' do expect { |b| subject.default_state_change(&b) }.not_to yield_control From fee8b56cce5b3bbe97ec04ef23c56832f84b2a11 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 9 Aug 2024 16:52:43 +0100 Subject: [PATCH 33/70] Pass a V2 tube to SimpleTubePresenter --- spec/models/presenters/simple_tube_spec.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/models/presenters/simple_tube_spec.rb b/spec/models/presenters/simple_tube_spec.rb index 7fff611f2..cd4e60834 100644 --- a/spec/models/presenters/simple_tube_spec.rb +++ b/spec/models/presenters/simple_tube_spec.rb @@ -1,11 +1,9 @@ # frozen_string_literal: true RSpec.describe Presenters::SimpleTubePresenter do - has_a_working_api + let(:labware) { build :v2_tube, state: state } - let(:labware) { build :tube, state: state } - - subject { Presenters::SimpleTubePresenter.new(api: api, labware: labware) } + subject { Presenters::SimpleTubePresenter.new(labware: labware) } before do create(:purpose_config, name: 'Example Plate Purpose', uuid: 'example-purpose-uuid-1') From fbdafbc99489aa31076b1616681f2be3b1ef768e Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 9 Aug 2024 17:17:49 +0100 Subject: [PATCH 34/70] Apply more fixes to tests --- .../support_v2_source_plate.rb | 20 ++++++++--------- .../labware_creators/pooled_tubes_base.rb | 2 +- .../cardinal_pools_plate_spec.rb | 4 +++- .../custom_pooled_tubes_spec.rb | 22 ++++++++++++++----- .../pooled_tubes_by_submission_spec.rb | 2 +- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/app/models/concerns/labware_creators/support_v2_source_plate.rb b/app/models/concerns/labware_creators/support_v2_source_plate.rb index 451ba4291..4b1eec4ec 100644 --- a/app/models/concerns/labware_creators/support_v2_source_plate.rb +++ b/app/models/concerns/labware_creators/support_v2_source_plate.rb @@ -7,17 +7,15 @@ module LabwareCreators::SupportV2SourcePlate extend ActiveSupport::Concern - included do - # parent is using SS v1 API - # so this method is used to access the plate via SS v2 API - def source_plate - if parent.is_a? Limber::Plate - @source_plate ||= Sequencescape::Api::V2::Plate.find_by(uuid: parent.uuid) if @source_plate&.uuid != parent.uuid - else - @source_plate = nil - end - - @source_plate + # parent is using SS v1 API + # so this method is used to access the plate via SS v2 API + def source_plate + if parent.is_a? Limber::Plate + @source_plate ||= Sequencescape::Api::V2::Plate.find_by(uuid: parent.uuid) if @source_plate&.uuid != parent.uuid + else + @source_plate = nil end + + @source_plate end end diff --git a/app/models/labware_creators/pooled_tubes_base.rb b/app/models/labware_creators/pooled_tubes_base.rb index 2cc5e2098..00eba0bfa 100644 --- a/app/models/labware_creators/pooled_tubes_base.rb +++ b/app/models/labware_creators/pooled_tubes_base.rb @@ -96,7 +96,7 @@ def metadata_stock_barcode end def parent_metadata - if parent.is_a? Limber::Plate + if source_plate.is_a? Sequencescape::Api::V2::Plate LabwareMetadata.new(labware: source_plate).metadata else LabwareMetadata.new(barcode: parent.barcode.machine).metadata diff --git a/spec/models/labware_creators/cardinal_pools_plate_spec.rb b/spec/models/labware_creators/cardinal_pools_plate_spec.rb index 0e8bc20d8..20704658f 100644 --- a/spec/models/labware_creators/cardinal_pools_plate_spec.rb +++ b/spec/models/labware_creators/cardinal_pools_plate_spec.rb @@ -18,6 +18,8 @@ let(:form_attributes) { { purpose_uuid: dest_purpose_uuid, parent_uuid: parent_uuid, user_uuid: user_uuid } } + let(:dummy_v1_plate) { create(:plate, uuid: parent_uuid) } + # TODO: rename throughout to source and dest # SS V2 API Plate let(:plate) do @@ -38,7 +40,7 @@ plate1 end - before { allow(subject).to receive(:parent).and_return(plate) } + before { allow(subject).to receive(:parent).and_return(dummy_v1_plate) } subject { LabwareCreators::CardinalPoolsPlate.new(api, form_attributes) } diff --git a/spec/models/labware_creators/custom_pooled_tubes_spec.rb b/spec/models/labware_creators/custom_pooled_tubes_spec.rb index 25a99be65..c9ed9f2e9 100644 --- a/spec/models/labware_creators/custom_pooled_tubes_spec.rb +++ b/spec/models/labware_creators/custom_pooled_tubes_spec.rb @@ -9,6 +9,8 @@ # Each well on the plate gets transferred into a tube # transfer targets are determined by pool RSpec.describe LabwareCreators::CustomPooledTubes, with: :uploader do + has_a_working_api + it_behaves_like 'it only allows creation from charged and passed plates' subject { described_class.new(api, form_attributes) } @@ -22,22 +24,29 @@ let(:purpose) { json :purpose, uuid: purpose_uuid } let(:parent_uuid) { SecureRandom.uuid } let(:parent) { json :plate, uuid: parent_uuid, stock_plate_barcode: 5, qc_files_actions: %w[read create] } + let(:v2_plate) { create(:v2_plate, uuid: parent_uuid) } + let(:form_attributes) { { purpose_uuid: purpose_uuid, parent_uuid: parent_uuid } } let(:wells_json) { json :well_collection, size: 16, default_state: 'passed' } context 'on new' do - has_a_working_api - - let(:form_attributes) { { purpose_uuid: purpose_uuid, parent_uuid: parent_uuid } } - it 'can be created' do expect(subject).to be_a LabwareCreators::CustomPooledTubes end end - context '#save' do - has_a_working_api + context '#source_plate' do + before do + stub_api_get(parent_uuid, body: parent) + stub_v2_plate(v2_plate, stub_search: false) + end + it 'returns V2 plate' do + expect(subject.source_plate).to eq(v2_plate) + end + end + + context '#save' do let(:file_content) do content = file.read file.rewind @@ -92,6 +101,7 @@ # Used to fetch the pools. This is the kind of thing we could pass through from a custom form let(:stub_parent_request) do + stub_v2_plate(v2_plate, stub_search: false) stub_api_get(parent_uuid, body: parent) stub_api_get(parent_uuid, 'wells', body: wells_json) end diff --git a/spec/models/labware_creators/pooled_tubes_by_submission_spec.rb b/spec/models/labware_creators/pooled_tubes_by_submission_spec.rb index 956623258..80c5e3d78 100644 --- a/spec/models/labware_creators/pooled_tubes_by_submission_spec.rb +++ b/spec/models/labware_creators/pooled_tubes_by_submission_spec.rb @@ -13,7 +13,7 @@ it_behaves_like 'it only allows creation from charged and passed plates with defined downstream pools' - subject { LabwareCreators::PooledTubesBySubmission.new(api, form_attributes) } + subject { LabwareCreators::PooledTubesBySubmission.new(form_attributes) } let(:user_uuid) { SecureRandom.uuid } From b06fd07456de550ff87b960b4cec8dd243d009db Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 9 Aug 2024 17:32:08 +0100 Subject: [PATCH 35/70] Fix tests for PooledTubesBySubmission --- .../labware_creators/pooled_tubes_by_submission_spec.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/models/labware_creators/pooled_tubes_by_submission_spec.rb b/spec/models/labware_creators/pooled_tubes_by_submission_spec.rb index 80c5e3d78..f358503a5 100644 --- a/spec/models/labware_creators/pooled_tubes_by_submission_spec.rb +++ b/spec/models/labware_creators/pooled_tubes_by_submission_spec.rb @@ -13,7 +13,7 @@ it_behaves_like 'it only allows creation from charged and passed plates with defined downstream pools' - subject { LabwareCreators::PooledTubesBySubmission.new(form_attributes) } + subject { LabwareCreators::PooledTubesBySubmission.new(api, form_attributes) } let(:user_uuid) { SecureRandom.uuid } @@ -22,11 +22,14 @@ let(:parent_uuid) { SecureRandom.uuid } let(:parent) { json :plate, uuid: parent_uuid, pool_sizes: [3, 6], stock_plate_barcode: 5, for_multiplexing: true } + let(:source_plate) { create :v2_plate, uuid: parent_uuid } let(:form_attributes) { { user_uuid: user_uuid, purpose_uuid: purpose_uuid, parent_uuid: parent_uuid } } let(:wells_json) { json :well_collection, size: 9, default_state: 'passed' } + before { stub_v2_plate(source_plate, stub_search: false) } + context '#save!' do has_a_working_api @@ -118,8 +121,8 @@ end context 'with parent metadata' do - let(:child_1_name) { 'DN6 A1:C1' } - let(:child_2_name) { 'DN6 D1:A2' } + let(:child_1_name) { 'DN8 A1:C1' } + let(:child_2_name) { 'DN8 D1:A2' } let(:parent) do json :plate_with_metadata, From 4b9cb28cbd559b6e1a5e6208b131d134e11fd43e Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 9 Aug 2024 17:36:40 +0100 Subject: [PATCH 36/70] Fix tests on QuadrantStampPrimerPanel --- .../labware_creators/quadrant_stamp_primer_panel_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/models/labware_creators/quadrant_stamp_primer_panel_spec.rb b/spec/models/labware_creators/quadrant_stamp_primer_panel_spec.rb index 8a16aa38d..3e56ef4dc 100644 --- a/spec/models/labware_creators/quadrant_stamp_primer_panel_spec.rb +++ b/spec/models/labware_creators/quadrant_stamp_primer_panel_spec.rb @@ -46,7 +46,8 @@ let(:child_purpose_name) { 'Child Purpose' } let(:user_uuid) { 'user-uuid' } - let(:user) { json :v1_user, uuid: user_uuid } + let(:v1_user) { json :v1_user, uuid: user_uuid } + let(:user) { create :user, uuid: user_uuid } before do create :purpose_config, name: child_purpose_name @@ -304,7 +305,8 @@ 'custom_metadatum_collection-uuid', body: json(:v1_custom_metadatum_collection, uuid: 'custom_metadatum_collection-uuid') ) - stub_api_get('user-uuid', body: user) + stub_api_get('user-uuid', body: v1_user) + stub_v2_user(user) stub_api_get('asset-uuid', body: child_plate_v1) metadata = From ea5f99044c57fb2c8c1af597ef389db5a5a8516e Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 9 Aug 2024 18:15:12 +0100 Subject: [PATCH 37/70] Fix tests for plate transfer --- spec/features/plate_transfer_spec.rb | 26 +++++++------------------- spec/support/api_url_helper.rb | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/spec/features/plate_transfer_spec.rb b/spec/features/plate_transfer_spec.rb index 78a7807ea..f8aad570a 100644 --- a/spec/features/plate_transfer_spec.rb +++ b/spec/features/plate_transfer_spec.rb @@ -45,28 +45,12 @@ Settings.robots['bravo-lb-post-shear-to-lb-end-prep'] = settings[:robots]['bravo-lb-post-shear-to-lb-end-prep'] Settings.robots['bravo-lb-end-prep'] = settings[:robots]['bravo-lb-end-prep'] - # # We look up the user - stub_swipecard_search(swipecard, user) + # We look up the user + stub_v2_user(user, swipecard) - stub_custom_metdatum_collections_post stub_state_changes_post end - let(:payload) do - { - custom_metadatum_collection: { - user: user_uuid, - asset: plate_uuid, - metadata: { - created_with_robot: 'robot_barcode' - } - } - } - end - - let(:stub_custom_metdatum_collections_post) do - stub_api_post('custom_metadatum_collections', payload: payload, body: json(:custom_metadatum_collection)) - end let(:stub_state_changes_post) do stub_api_post( 'state_changes', @@ -85,6 +69,11 @@ end scenario 'starts the robot and saves the robot barcode' do + expect_api_v2_posts( + 'CustomMetadatumCollection', + [{ user_id: user.id, asset_id: example_plate.id, metadata: { created_with_robot: 'robot_barcode' } }] + ) + allow_any_instance_of(Robots::Robot).to receive(:verify).and_return( beds: { '580000004838' => true, @@ -146,7 +135,6 @@ end click_button('Start the bravo LB Post Shear => LB End Prep') expect(page).to have_content('Robot bravo LB Post Shear => LB End Prep has been started.') - expect(stub_custom_metdatum_collections_post).to have_been_requested expect(stub_state_changes_post).to have_been_requested end diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index f3ae6fc69..c5a80c80a 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -123,6 +123,8 @@ def stub_v2_plate(plate, stub_search: true, custom_query: nil, custom_includes: else allow(Sequencescape::Api::V2).to receive(:plate_for_presenter).with(uuid: plate.uuid).and_return(plate) end + + stub_v2_labware(plate) end def stub_v2_polymetadata(polymetadata, metadatable_id) @@ -153,9 +155,16 @@ def stub_v2_tube(tube, stub_search: true, custom_includes: false) allow(Sequencescape::Api::V2::Tube).to receive(:find_by).with(*arguments).and_return(tube) end - def stub_v2_user(user) - arguments = [{ uuid: user.uuid }] - allow(Sequencescape::Api::V2::User).to receive(:find).with(*arguments).and_return([user]) + def stub_v2_user(user, swipecard = nil) + # Find by UUID + uuid_args = [{ uuid: user.uuid }] + allow(Sequencescape::Api::V2::User).to receive(:find).with(*uuid_args).and_return([user]) + + if swipecard + # Find by swipecard + swipecard_args = [{ user_code: swipecard }] + allow(Sequencescape::Api::V2::User).to receive(:find).with(*swipecard_args).and_return([user]) + end end end extend ClassMethods From 7bb36c98c2a4b615d15b1702bf44553400bf30bb Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 9 Aug 2024 18:23:56 +0100 Subject: [PATCH 38/70] Make Rubocop happy --- spec/support/api_url_helper.rb | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index c5a80c80a..d2db2cb02 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -4,10 +4,11 @@ module ApiUrlHelper API_ROOT = 'http://example.com:3000' def self.included(base) - base.extend(ClassMethods) + base.extend(V1Helpers) + base.extend(V2Helpers) end - module ClassMethods + module V1Helpers def api_root API_ROOT end @@ -70,7 +71,9 @@ def stub_api_modify(*components, body:, payload:, action: :post, status: 201) def stub_api_put(*components, body:, payload:) stub_api_modify(*components, action: :put, status: 200, body: body, payload: payload) end + end + module V2Helpers def stub_api_v2_patch(klass) # intercepts the 'update' and 'update!' method for any instance of the class beginning with # 'Sequencescape::Api::V2::' and returns true @@ -160,17 +163,17 @@ def stub_v2_user(user, swipecard = nil) uuid_args = [{ uuid: user.uuid }] allow(Sequencescape::Api::V2::User).to receive(:find).with(*uuid_args).and_return([user]) - if swipecard - # Find by swipecard - swipecard_args = [{ user_code: swipecard }] - allow(Sequencescape::Api::V2::User).to receive(:find).with(*swipecard_args).and_return([user]) - end + return unless swipecard + + # Find by swipecard + swipecard_args = [{ user_code: swipecard }] + allow(Sequencescape::Api::V2::User).to receive(:find).with(*swipecard_args).and_return([user]) end end - extend ClassMethods end RSpec.configure do |config| config.include ApiUrlHelper - config.include ApiUrlHelper::ClassMethods + config.include ApiUrlHelper::V1Helpers + config.include ApiUrlHelper::V2Helpers end From b3e4e1a4f4edc0d3a39b18fe599b5efe50677cfa Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 12 Aug 2024 11:33:58 +0100 Subject: [PATCH 39/70] Fix tests for RobotsController and when pooling_multiple_tubes_into_one_tube --- spec/controllers/robots_controller_spec.rb | 54 ++++++------------- ...oling_multiple_tubes_into_one_tube_spec.rb | 4 ++ 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/spec/controllers/robots_controller_spec.rb b/spec/controllers/robots_controller_spec.rb index 91f8377ea..e0adc0aa8 100644 --- a/spec/controllers/robots_controller_spec.rb +++ b/spec/controllers/robots_controller_spec.rb @@ -12,14 +12,8 @@ describe '#start' do has_a_working_api - let(:user_uuid) { SecureRandom.uuid } - let(:plate_uuid) { 'plate_uuid' } - let!(:plate) do - create :v2_plate, - uuid: plate_uuid, - purpose_name: 'target_plate_purpose', - purpose_uuid: 'target_plate_purpose_uuid' - end + let(:user) { create :user } + let(:plate) { create :v2_plate, purpose_name: 'target_plate_purpose', purpose_uuid: 'target_plate_purpose_uuid' } let!(:state_chage) do stub_api_post( @@ -29,8 +23,8 @@ 'target_state' => 'passed', 'reason' => 'Robot robot_name started', 'customer_accepts_responsibility' => false, - 'target' => 'plate_uuid', - 'user' => user_uuid, + 'target' => plate.uuid, + 'user' => user.uuid, 'contents' => nil } }, @@ -38,20 +32,8 @@ ) end - let!(:metadata_request) do - stub_api_post( - 'custom_metadatum_collections', - payload: { - custom_metadatum_collection: { - user: user_uuid, - asset: plate_uuid, - metadata: { - created_with_robot: 'robot_barcode' - } - } - }, - body: json(:custom_metadatum_collection) - ) + let(:metadata_payload) do + { user_id: user.id, asset_id: plate.id, metadata: { created_with_robot: 'robot_barcode' } } end setup do @@ -59,6 +41,7 @@ create :purpose_config, uuid: 'target_plate_purpose_uuid', state_changer_class: 'StateChangers::DefaultStateChanger' + stub_v2_user(user) stub_v2_plate(plate) bed_labware_lookup(plate) @@ -70,6 +53,8 @@ end it 'adds robot barcode to plate metadata' do + expect_api_v2_posts('CustomMetadatumCollection', [metadata_payload]) + post :start, params: { bed_labwares: { @@ -80,9 +65,9 @@ id: 'robot_id' }, session: { - user_uuid: user_uuid + user_uuid: user.uuid } - expect(metadata_request).to have_been_requested + expect(flash[:notice]).to match 'Robot robot_name has been started.' end end @@ -90,22 +75,15 @@ describe '#verify' do has_a_working_api - let(:user_uuid) { SecureRandom.uuid } - let(:target_plate_uuid) { 'plate_uuid' } - let!(:target_plate) do + let(:user) { create :user } + let(:target_plate) do create :v2_plate, - uuid: target_plate_uuid, purpose_name: 'target_plate_purpose', purpose_uuid: 'target_plate_purpose_uuid', parents: [source_plate] end - - let(:source_plate_uuid) { 'plate_uuid' } - let!(:source_plate) do - create :v2_plate, - uuid: source_plate_uuid, - purpose_name: 'source_plate_purpose', - purpose_uuid: 'source_plate_purpose_uuid' + let(:source_plate) do + create :v2_plate, purpose_name: 'source_plate_purpose', purpose_uuid: 'source_plate_purpose_uuid' end it 'verifies robot and beds' do @@ -129,7 +107,7 @@ id: 'robot_id' }, session: { - user_uuid: user_uuid + user_uuid: user.uuid }, format: :json end diff --git a/spec/features/pooling_multiple_tubes_into_one_tube_spec.rb b/spec/features/pooling_multiple_tubes_into_one_tube_spec.rb index 52c9a50cd..a877b28cb 100644 --- a/spec/features/pooling_multiple_tubes_into_one_tube_spec.rb +++ b/spec/features/pooling_multiple_tubes_into_one_tube_spec.rb @@ -161,6 +161,10 @@ allow(Sequencescape::Api::V2::Tube).to receive(:find_all) .with(barcode: [tube_barcode_1, tube_barcode_2], includes: []) .and_return([example_v2_tube, example_v2_tube2]) + + # Allow parent plates to be found in API v2 + stub_v2_plate(parent_1, stub_search: false) + stub_v2_plate(parent_2, stub_search: false) end background do From ab1c8dd1d42f593987a357a8392a704dd6f1f28f Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 12 Aug 2024 12:14:14 +0100 Subject: [PATCH 40/70] Add the relationship to custom_metadatum_collection on tubes --- .../sequencescape/api/v2/tube.rb | 9 +++---- spec/factories/tube_factories.rb | 7 +++++- .../robots/plate_to_tube_racks_robot_spec.rb | 24 +++++++++---------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/app/sequencescape/sequencescape/api/v2/tube.rb b/app/sequencescape/sequencescape/api/v2/tube.rb index a5f0dfb57..0f763ea39 100644 --- a/app/sequencescape/sequencescape/api/v2/tube.rb +++ b/app/sequencescape/sequencescape/api/v2/tube.rb @@ -16,17 +16,18 @@ class Sequencescape::Api::V2::Tube < Sequencescape::Api::V2::Base self.tube = true has_many :ancestors, class_name: 'Sequencescape::Api::V2::Asset' # Having issues with polymorphism, temporary class - has_many :descendants, class_name: 'Sequencescape::Api::V2::Asset' # Having issues with polymorphism, temporary class - has_many :parents, class_name: 'Sequencescape::Api::V2::Asset' # Having issues with polymorphism, temporary class has_many :children, class_name: 'Sequencescape::Api::V2::Asset' # Having issues with polymorphism, temporary class has_many :child_plates, class_name: 'Sequencescape::Api::V2::Plate' has_many :child_tubes, class_name: 'Sequencescape::Api::V2::Tube' - has_one :receptacle, class_name: 'Sequencescape::Api::V2::Receptacle' - + has_many :descendants, class_name: 'Sequencescape::Api::V2::Asset' # Having issues with polymorphism, temporary class has_many :direct_submissions + has_many :parents, class_name: 'Sequencescape::Api::V2::Asset' # Having issues with polymorphism, temporary class has_many :state_changes has_many :transfer_requests_as_target, class_name: 'Sequencescape::Api::V2::TransferRequest' + has_one :custom_metadatum_collection + has_one :receptacle, class_name: 'Sequencescape::Api::V2::Receptacle' + property :created_at, type: :time property :updated_at, type: :time diff --git a/spec/factories/tube_factories.rb b/spec/factories/tube_factories.rb index d2b98b46e..5842988f5 100644 --- a/spec/factories/tube_factories.rb +++ b/spec/factories/tube_factories.rb @@ -117,6 +117,7 @@ end parents { [] } purpose { create :v2_purpose, name: purpose_name, uuid: purpose_uuid } + custom_metadatum_collection { nil } end # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" @@ -133,10 +134,14 @@ asset._cached_relationship(:aliquots) { evaluator.aliquots || [] } asset._cached_relationship(:parents) { evaluator.parents } asset._cached_relationship(:receptacle) { evaluator.receptacle } + + if evaluator.custom_metadatum_collection + asset._cached_relationship(:custom_metadatum_collection) { evaluator.custom_metadatum_collection } + end end factory :v2_tube_with_metadata do - with_belongs_to_associations 'custom_metadatum_collection' + transient { custom_metadatum_collection { create :custom_metadatum_collection } } end factory :v2_stock_tube do diff --git a/spec/models/robots/plate_to_tube_racks_robot_spec.rb b/spec/models/robots/plate_to_tube_racks_robot_spec.rb index a86d3603a..fe4e77b9a 100644 --- a/spec/models/robots/plate_to_tube_racks_robot_spec.rb +++ b/spec/models/robots/plate_to_tube_racks_robot_spec.rb @@ -23,12 +23,12 @@ let(:tube6_metadata) { { 'tube_rack_barcode' => tube_rack2_barcode, 'tube_rack_position' => 'C1' } } # tube custom metadata collections - let(:tube1_custom_metadata) { create(:custom_metadatum_collection, metadata: tube1_metadata) } - let(:tube2_custom_metadata) { create(:custom_metadatum_collection, metadata: tube2_metadata) } - let(:tube3_custom_metadata) { create(:custom_metadatum_collection, metadata: tube3_metadata) } - let(:tube4_custom_metadata) { create(:custom_metadatum_collection, metadata: tube4_metadata) } - let(:tube5_custom_metadata) { create(:custom_metadatum_collection, metadata: tube5_metadata) } - let(:tube6_custom_metadata) { create(:custom_metadatum_collection, metadata: tube6_metadata) } + let(:tube1_custom_metadatum_collection) { create(:custom_metadatum_collection, metadata: tube1_metadata) } + let(:tube2_custom_metadatum_collection) { create(:custom_metadatum_collection, metadata: tube2_metadata) } + let(:tube3_custom_metadatum_collection) { create(:custom_metadatum_collection, metadata: tube3_metadata) } + let(:tube4_custom_metadatum_collection) { create(:custom_metadatum_collection, metadata: tube4_metadata) } + let(:tube5_custom_metadatum_collection) { create(:custom_metadatum_collection, metadata: tube5_metadata) } + let(:tube6_custom_metadatum_collection) { create(:custom_metadatum_collection, metadata: tube6_metadata) } # tube uuids let(:tube1_uuid) { 'tube1_uuid' } @@ -67,7 +67,7 @@ uuid: tube1_uuid, barcode_prefix: 'FX', barcode_number: 4, - custom_metadatum_collection: tube1_custom_metadata, + custom_metadatum_collection: tube1_custom_metadatum_collection, purpose: tube_purpose1, state: tube1_state ) @@ -78,7 +78,7 @@ uuid: tube2_uuid, barcode_prefix: 'FX', barcode_number: 5, - custom_metadatum_collection: tube2_custom_metadata, + custom_metadatum_collection: tube2_custom_metadatum_collection, purpose: tube_purpose1, state: tube2_state ) @@ -89,7 +89,7 @@ uuid: tube3_uuid, barcode_prefix: 'FX', barcode_number: 6, - custom_metadatum_collection: tube3_custom_metadata, + custom_metadatum_collection: tube3_custom_metadatum_collection, purpose: tube_purpose1, state: tube3_state ) @@ -100,7 +100,7 @@ uuid: tube4_uuid, barcode_prefix: 'FX', barcode_number: 7, - custom_metadatum_collection: tube4_custom_metadata, + custom_metadatum_collection: tube4_custom_metadatum_collection, purpose: tube_purpose2, state: tube4_state ) @@ -111,7 +111,7 @@ uuid: tube5_uuid, barcode_prefix: 'FX', barcode_number: 8, - custom_metadatum_collection: tube5_custom_metadata, + custom_metadatum_collection: tube5_custom_metadatum_collection, purpose: tube_purpose2, state: tube5_state ) @@ -122,7 +122,7 @@ uuid: tube6_uuid, barcode_prefix: 'FX', barcode_number: 9, - custom_metadatum_collection: tube6_custom_metadata, + custom_metadatum_collection: tube6_custom_metadatum_collection, purpose: tube_purpose2, state: tube6_state ) From e93e79c688577cd859f94472a75d7e1c5abf23e3 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 12 Aug 2024 14:10:05 +0100 Subject: [PATCH 41/70] Add uuids to factory build custom_metadatum_collections --- spec/factories/custom_metadatum_collection_factories.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/factories/custom_metadatum_collection_factories.rb b/spec/factories/custom_metadatum_collection_factories.rb index ab8927935..72dbf0927 100644 --- a/spec/factories/custom_metadatum_collection_factories.rb +++ b/spec/factories/custom_metadatum_collection_factories.rb @@ -13,6 +13,7 @@ factory :custom_metadatum_collection, class: Sequencescape::Api::V2::CustomMetadatumCollection do initialize_with { Sequencescape::Api::V2::CustomMetadatumCollection.load(attributes) } skip_create + uuid metadata { { metadata_1: 'metadata_1', metadata_2: 'metadata_2' } } end end From 999e3c1c420c73f4927d79e67fe896b6ff2c1f2d Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 12 Aug 2024 14:10:23 +0100 Subject: [PATCH 42/70] Reference labware with an @ in CustomMetadatumCollection --- app/models/labware_metadata.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/labware_metadata.rb b/app/models/labware_metadata.rb index 8734ea90e..90df6af17 100644 --- a/app/models/labware_metadata.rb +++ b/app/models/labware_metadata.rb @@ -18,7 +18,7 @@ def initialize(params = {}) def update!(metadata) if @labware.custom_metadatum_collection&.uuid.present? current_metadata = self.metadata.symbolize_keys - labware.custom_metadatum_collection.update!(metadata: current_metadata.merge(metadata.symbolize_keys)) + @labware.custom_metadatum_collection.update!(metadata: current_metadata.merge(metadata.symbolize_keys)) else Sequencescape::Api::V2::CustomMetadatumCollection.create!( user_id: @user&.id, From b5e751e562c936a698ca179ff7c3345d0c557999 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 12 Aug 2024 14:10:49 +0100 Subject: [PATCH 43/70] Associate custom_metadatum_collections correctly on V2 tube and plate factories --- spec/factories/plate_factories.rb | 18 ++++++++++++++++-- spec/factories/tube_factories.rb | 6 ++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/spec/factories/plate_factories.rb b/spec/factories/plate_factories.rb index f51f799d1..4a0a421a7 100644 --- a/spec/factories/plate_factories.rb +++ b/spec/factories/plate_factories.rb @@ -116,6 +116,9 @@ # Array of states for individual wells, used to overide plate state for, eg. failed wells well_states { [state] * size } is_stock { false } + + # The CustomMetadatumCollection will be cached as a relationship in the after(:build) block. + custom_metadatum_collection { nil } end sequence(:id) { |i| i } @@ -132,7 +135,6 @@ state { 'pending' } created_at { '2017-06-29T09:31:59.000+01:00' } updated_at { '2017-06-29T09:31:59.000+01:00' } - custom_metadatum_collection { nil } # See the README.md for an explanation under "FactoryBot is not mocking my related resources correctly" after(:build) do |plate, evaluator| @@ -150,6 +152,15 @@ end RSpec::Mocks.allow_message(plate, :ancestors).and_return(ancestors_scope) plate._cached_relationship(:parents) { evaluator.parents } + + if evaluator.custom_metadatum_collection + plate._cached_relationship(:custom_metadatum_collection) { evaluator.custom_metadatum_collection } + end + end + + # Set up a plate with a default custom_metadatum_collection. + factory :v2_plate_with_metadata do + transient { custom_metadatum_collection { create :custom_metadatum_collection } } end # Set up a stock plate. Changed behaviour relative to standard plate: @@ -159,7 +170,6 @@ # - Sets is_stock to true, which ensures the stock_plate matches itself factory :v2_stock_plate do transient do - barcode_number { 2 } well_factory { :v2_stock_well } purpose_name { 'Limber Cherrypicked' } purpose_uuid { 'stock-plate-purpose-uuid' } @@ -168,6 +178,10 @@ end state { 'passed' } + + factory :v2_stock_plate_with_metadata do + transient { custom_metadatum_collection { create :custom_metadatum_collection } } + end end # Sets up a plate of GBS requests with configured primer panels diff --git a/spec/factories/tube_factories.rb b/spec/factories/tube_factories.rb index 5842988f5..02a1c909a 100644 --- a/spec/factories/tube_factories.rb +++ b/spec/factories/tube_factories.rb @@ -117,6 +117,8 @@ end parents { [] } purpose { create :v2_purpose, name: purpose_name, uuid: purpose_uuid } + + # The CustomMetadatumCollection will be cached as a relationship in the after(:build) block. custom_metadatum_collection { nil } end @@ -147,6 +149,10 @@ factory :v2_stock_tube do ancestors { nil } outer_request { nil } + + factory :v2_stock_tube_with_metadata do + transient { custom_metadatum_collection { create :custom_metadatum_collection } } + end end end From 85020f914f89c8fc0b992f7ab380dec52a254345 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 12 Aug 2024 14:29:44 +0100 Subject: [PATCH 44/70] Fix issues generated by not having a static barcode for stock plates --- spec/models/presenters/final_tube_presenter_spec.rb | 2 +- spec/models/presenters/stock_plate_presenter_spec.rb | 2 +- spec/models/presenters/tube_presenter_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/models/presenters/final_tube_presenter_spec.rb b/spec/models/presenters/final_tube_presenter_spec.rb index 712c258f6..68297a9ba 100644 --- a/spec/models/presenters/final_tube_presenter_spec.rb +++ b/spec/models/presenters/final_tube_presenter_spec.rb @@ -19,7 +19,7 @@ ['Barcode', 'NT6T 3980000006844'], ['Tube type', purpose_name], ['Current tube state', state], - ['Input plate barcode', 'DN2T'], + ['Input plate barcode', labware.stock_plate.human_barcode], ['Created on', '2016-10-19'] ] end diff --git a/spec/models/presenters/stock_plate_presenter_spec.rb b/spec/models/presenters/stock_plate_presenter_spec.rb index d015d999d..57641d1b3 100644 --- a/spec/models/presenters/stock_plate_presenter_spec.rb +++ b/spec/models/presenters/stock_plate_presenter_spec.rb @@ -8,7 +8,7 @@ subject { Presenters::StockPlatePresenter.new(labware: labware) } - let(:barcode_string) { 'DN2T' } + let(:barcode_string) { labware.human_barcode } it_behaves_like 'a stock presenter' end diff --git a/spec/models/presenters/tube_presenter_spec.rb b/spec/models/presenters/tube_presenter_spec.rb index e5de9e233..a7e8260ff 100644 --- a/spec/models/presenters/tube_presenter_spec.rb +++ b/spec/models/presenters/tube_presenter_spec.rb @@ -33,7 +33,7 @@ ['Barcode', 'NT6T 3980000006844'], ['Tube type', purpose_name], ['Current tube state', state], - ['Input plate barcode', 'DN2T'], + ['Input plate barcode', labware.stock_plate.human_barcode], ['Created on', '2016-10-19'] ] end From cbd14336385c6e77cef62d047fdd88d743e88a2d Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 12 Aug 2024 14:56:32 +0100 Subject: [PATCH 45/70] Fix LabwareMetadata tests --- spec/models/labware_metadata_spec.rb | 144 +++++++++++++++++---------- spec/support/api_url_helper.rb | 2 + 2 files changed, 94 insertions(+), 52 deletions(-) diff --git a/spec/models/labware_metadata_spec.rb b/spec/models/labware_metadata_spec.rb index 58430906d..a1efc0d81 100644 --- a/spec/models/labware_metadata_spec.rb +++ b/spec/models/labware_metadata_spec.rb @@ -5,81 +5,121 @@ RSpec.describe LabwareMetadata do include FeatureHelpers - describe 'with api' do - let(:user_uuid) { SecureRandom.uuid } - let(:user) { json :v1_user, uuid: user_uuid } - let(:plate_uuid) { SecureRandom.uuid } - let(:plate) { json :stock_plate, uuid: plate_uuid } - let(:plate_with_metadata) { json :stock_plate_with_metadata, uuid: plate_uuid } - - let(:tube_uuid) { SecureRandom.uuid } - let(:tube) { json :stock_tube, uuid: tube_uuid } - let(:tube_with_metadata) { json :stock_tube_with_metadata, uuid: tube_uuid } - - has_a_working_api - - it 'raises an exception if the barcode is invalid' do - stub_asset_search(456, nil) - expect { LabwareMetadata.new(api: api, barcode: 456, user: user_uuid) }.to raise_error( - Sequencescape::Api::ResourceNotFound - ) + let(:user) { create :user } + let(:updated_metadata) { { created_with_robot: 'robot_barcode' } } + + before { stub_v2_user(user) } + + it 'raises an exception if the barcode is invalid' do + error = Sequencescape::Api::ResourceNotFound.new('Not found') + invalid_barcode = 'not_a_barcode' + allow(Sequencescape::Api::V2::Labware).to receive(:find).with(barcode: invalid_barcode).and_raise(error) + + expect { LabwareMetadata.new(barcode: invalid_barcode, user_uuid: user.uuid) }.to raise_error(error) + end + + it 'raises an exception if both labware and barcode are nil' do + expect { LabwareMetadata.new }.to raise_error(ArgumentError) + end + + context 'plates' do + let(:plate) { create :v2_stock_plate } + let(:plate_with_metadata) { create :v2_stock_plate_with_metadata } + + before do + stub_v2_plate(plate) + stub_v2_plate(plate_with_metadata) end - context 'plates' do - it 'raises an exception if both plate and barcode are nil' do - expect { LabwareMetadata.new(api: api) }.to raise_error(ArgumentError) + context 'by labware' do + it 'creates metadata' do + expect_api_v2_posts( + 'CustomMetadatumCollection', + [user_id: user.id, asset_id: plate.id, metadata: updated_metadata] + ) + + LabwareMetadata.new(labware: plate, user_uuid: user.uuid).update!(updated_metadata) end - it 'raises an exception if api is nil' do - expect { LabwareMetadata.new(labware: plate) }.to raise_error(ArgumentError) + it 'updates metadata' do + metadata = attributes_for(:custom_metadatum_collection).fetch(:metadata, {}).merge(updated_metadata) + expect(plate_with_metadata.custom_metadatum_collection).to receive(:update!) + .with(metadata: metadata) + .and_return(true) + + LabwareMetadata.new(labware: plate_with_metadata, user_uuid: user.uuid).update!(updated_metadata) end + end + context 'by barcode' do it 'creates metadata' do - metadata = { created_with_robot: 'robot_barcode' } - stub = stub_create_labware_metadata(123, plate, plate_uuid, user_uuid, metadata) + expect_api_v2_posts( + 'CustomMetadatumCollection', + [user_id: user.id, asset_id: plate.id, metadata: updated_metadata] + ) - LabwareMetadata.new(api: api, barcode: 123, user: user_uuid).update!(created_with_robot: 'robot_barcode') - expect(stub).to have_been_requested + LabwareMetadata.new(barcode: plate.barcode.machine, user_uuid: user.uuid).update!(updated_metadata) end it 'updates metadata' do - metadata = - attributes_for(:v1_custom_metadatum_collection) - .fetch(:metadata, {}) - .merge(created_with_robot: 'robot_barcode') - stub = stub_update_labware_metadata(123, plate_with_metadata, user, metadata) - - LabwareMetadata.new(api: api, barcode: 123, user: user_uuid).update!(created_with_robot: 'robot_barcode') - expect(stub).to have_been_requested + metadata = attributes_for(:custom_metadatum_collection).fetch(:metadata, {}).merge(updated_metadata) + expect(plate_with_metadata.custom_metadatum_collection).to receive(:update!) + .with(metadata: metadata) + .and_return(true) + + LabwareMetadata + .new(barcode: plate_with_metadata.barcode.machine, user_uuid: user.uuid) + .update!(updated_metadata) end end + end + + context 'tubes' do + let(:tube) { create :v2_stock_tube } + let(:tube_with_metadata) { create :v2_stock_tube_with_metadata } + + before do + stub_v2_tube(tube) + stub_v2_tube(tube_with_metadata) + end - context 'tubes' do - it 'raises an exception if both tube and barcode are nil' do - expect { LabwareMetadata.new(api: api) }.to raise_error(ArgumentError) + context 'by labware' do + it 'creates metadata' do + expect_api_v2_posts( + 'CustomMetadatumCollection', + [user_id: user.id, asset_id: tube.id, metadata: updated_metadata] + ) + + LabwareMetadata.new(labware: tube, user_uuid: user.uuid).update!(updated_metadata) end - it 'raises an exception if api is nil' do - expect { LabwareMetadata.new(labware: tube) }.to raise_error(ArgumentError) + it 'updates metadata' do + metadata = attributes_for(:custom_metadatum_collection).fetch(:metadata, {}).merge(updated_metadata) + expect(tube_with_metadata.custom_metadatum_collection).to receive(:update!) + .with(metadata: metadata) + .and_return(true) + + LabwareMetadata.new(labware: tube_with_metadata, user_uuid: user.uuid).update!(updated_metadata) end + end + context 'by barcode' do it 'creates metadata' do - metadata = { created_with_robot: 'robot_barcode' } - stub = stub_create_labware_metadata(123, tube, tube_uuid, user_uuid, metadata) + expect_api_v2_posts( + 'CustomMetadatumCollection', + [user_id: user.id, asset_id: tube.id, metadata: updated_metadata] + ) - LabwareMetadata.new(api: api, barcode: 123, user: user_uuid).update!(created_with_robot: 'robot_barcode') - expect(stub).to have_been_requested + LabwareMetadata.new(barcode: tube.barcode.machine, user_uuid: user.uuid).update!(updated_metadata) end it 'updates metadata' do - metadata = - attributes_for(:v1_custom_metadatum_collection) - .fetch(:metadata, {}) - .merge(created_with_robot: 'robot_barcode') - stub = stub_update_labware_metadata(123, plate_with_metadata, user, metadata) - - LabwareMetadata.new(api: api, barcode: 123, user: user_uuid).update!(created_with_robot: 'robot_barcode') - expect(stub).to have_been_requested + metadata = attributes_for(:custom_metadatum_collection).fetch(:metadata, {}).merge(updated_metadata) + expect(tube_with_metadata.custom_metadatum_collection).to receive(:update!) + .with(metadata: metadata) + .and_return(true) + + LabwareMetadata.new(barcode: tube_with_metadata.barcode.machine, user_uuid: user.uuid).update!(updated_metadata) end end end diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index d2db2cb02..3a7e305de 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -156,6 +156,8 @@ def stub_v2_tube(tube, stub_search: true, custom_includes: false) stub_barcode_search(tube.barcode.machine, tube) if stub_search arguments = custom_includes ? [{ uuid: tube.uuid }, { includes: custom_includes }] : [{ uuid: tube.uuid }] allow(Sequencescape::Api::V2::Tube).to receive(:find_by).with(*arguments).and_return(tube) + + stub_v2_labware(tube) end def stub_v2_user(user, swipecard = nil) From 680776d9588f80d354ddffd35b42014a8ede8ba5 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Mon, 12 Aug 2024 16:39:31 +0100 Subject: [PATCH 46/70] Fix naming of memoized variable for transfer_template --- app/models/labware_creators/base.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/models/labware_creators/base.rb b/app/models/labware_creators/base.rb index 8129ccdcc..94d9c7939 100644 --- a/app/models/labware_creators/base.rb +++ b/app/models/labware_creators/base.rb @@ -103,13 +103,10 @@ def purpose_name private - # rubocop:todo Naming/MemoizedInstanceVariableName def transfer_template - @template ||= api.transfer_template.find(transfer_template_uuid) + @transfer_template ||= api.transfer_template.find(transfer_template_uuid) end - # rubocop:enable Naming/MemoizedInstanceVariableName - def create_plate_with_standard_transfer! plate_creation = create_plate_from_parent! @child = plate_creation.child From 1e1a0766ff3c346b2234f506df2453c33946fa8e Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Wed, 14 Aug 2024 09:22:48 +0100 Subject: [PATCH 47/70] Don't check the type of source_plate Either it's the correct type, or it's nil, which is when we would fall back to the barcode instead for LabwareMetadata --- app/models/labware_creators/pooled_tubes_base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/labware_creators/pooled_tubes_base.rb b/app/models/labware_creators/pooled_tubes_base.rb index 00eba0bfa..d0187839a 100644 --- a/app/models/labware_creators/pooled_tubes_base.rb +++ b/app/models/labware_creators/pooled_tubes_base.rb @@ -96,7 +96,7 @@ def metadata_stock_barcode end def parent_metadata - if source_plate.is_a? Sequencescape::Api::V2::Plate + if source_plate LabwareMetadata.new(labware: source_plate).metadata else LabwareMetadata.new(barcode: parent.barcode.machine).metadata From 7b694bab6870d8af587e96eb29229a17f4a266f3 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 20 Aug 2024 12:12:55 +0100 Subject: [PATCH 48/70] Replace creation of Transfers via v1 with v2 --- app/models/labware_creators/base.rb | 14 ++++++++------ app/models/labware_creators/final_tube.rb | 3 +-- .../labware_creators/final_tube_from_plate.rb | 13 +++++-------- app/models/labware_creators/plate_with_template.rb | 2 +- .../pooled_tubes_from_whole_plates.rb | 6 ++---- app/models/labware_creators/tube_from_tube.rb | 3 ++- app/sequencescape/sequencescape/api/v2/transfer.rb | 5 +++++ 7 files changed, 24 insertions(+), 22 deletions(-) create mode 100644 app/sequencescape/sequencescape/api/v2/transfer.rb diff --git a/app/models/labware_creators/base.rb b/app/models/labware_creators/base.rb index 94d9c7939..436a2fc04 100644 --- a/app/models/labware_creators/base.rb +++ b/app/models/labware_creators/base.rb @@ -70,7 +70,7 @@ def transfer_template_name # # The uuid of the transfer template to be used. - # Extracted from the transfer template cache base on the name + # Extracted from the transfer template cache based on the name # # @return [String] UUID # @@ -103,10 +103,6 @@ def purpose_name private - def transfer_template - @transfer_template ||= api.transfer_template.find(transfer_template_uuid) - end - def create_plate_with_standard_transfer! plate_creation = create_plate_from_parent! @child = plate_creation.child @@ -120,8 +116,14 @@ def create_plate_from_parent! api.plate_creation.create!(parent: parent_uuid, child_purpose: purpose_uuid, user: user_uuid) end + def transfer!(attributes) + Sequencescape::Api::V2::Template.create!( + attributes.merge(transfer_template_uuid: transfer_template_uuid, user_uuid: user_uuid) + ) + end + def transfer_material_from_parent!(child_uuid) - transfer_template.create!(source: parent_uuid, destination: child_uuid, user: user_uuid, transfers: transfer_hash) + transfer!(source_uuid: parent_uuid, destination_uuid: child_uuid, transfer: transfer_hash) end # Override in classes with custom transfers diff --git a/app/models/labware_creators/final_tube.rb b/app/models/labware_creators/final_tube.rb index 50054d15e..1ba61cc63 100644 --- a/app/models/labware_creators/final_tube.rb +++ b/app/models/labware_creators/final_tube.rb @@ -28,8 +28,7 @@ def all_ready? end def create_labware! - @all_tube_transfers = - parents.map { |this_parent_uuid| transfer_template.create!(user: user_uuid, source: this_parent_uuid) } + @all_tube_transfers = parents.map { |this_parent_uuid| transfer!(source_uuid: this_parent_uuid) } true end diff --git a/app/models/labware_creators/final_tube_from_plate.rb b/app/models/labware_creators/final_tube_from_plate.rb index b8bc5dd22..e0ecefb13 100644 --- a/app/models/labware_creators/final_tube_from_plate.rb +++ b/app/models/labware_creators/final_tube_from_plate.rb @@ -21,7 +21,7 @@ class FinalTubeFromPlate < Base self.default_transfer_template_name = 'Transfer wells to MX library tubes by submission' def create_labware! - transfer_into_existing_tubes! + create_transfer! pass_tubes! end @@ -40,15 +40,12 @@ def anchor private - # rubocop:todo Naming/MemoizedInstanceVariableName - def transfer_into_existing_tubes! - @transfer ||= transfer_template.create!(user: user_uuid, source: parent_uuid) + def create_transfer! + @create_transfer ||= transfer!(source_uuid: parent_uuid) end - # rubocop:enable Naming/MemoizedInstanceVariableName - def pass_tubes! - raise StandardError, 'Tubes cannot be passed before transfer' if @transfer.nil? + raise StandardError, 'Tubes cannot be passed before transfer' if @create_transfer.nil? tubes_from_transfer.each do |tube_uuid| api.state_change.create!(user: user_uuid, target: tube_uuid, target_state: 'passed') @@ -56,7 +53,7 @@ def pass_tubes! end def tubes_from_transfer - @transfer + create_transfer! .transfers .values .each_with_object(Set.new) { |tube_details, tube_uuids| tube_uuids << tube_details.fetch('uuid') } diff --git a/app/models/labware_creators/plate_with_template.rb b/app/models/labware_creators/plate_with_template.rb index 4f0e026d6..1cb7e790d 100644 --- a/app/models/labware_creators/plate_with_template.rb +++ b/app/models/labware_creators/plate_with_template.rb @@ -8,7 +8,7 @@ class PlateWithTemplate < Base # rubocop:todo Style/Documentation include SupportParent::PlateOnly def transfer_material_from_parent!(child_uuid) - transfer_template.create!(source: parent_uuid, destination: child_uuid, user: user_uuid) + transfer!(source_uuid: parent_uuid, child_uuid: child_uuid) end end end diff --git a/app/models/labware_creators/pooled_tubes_from_whole_plates.rb b/app/models/labware_creators/pooled_tubes_from_whole_plates.rb index bf3ead908..49556305d 100644 --- a/app/models/labware_creators/pooled_tubes_from_whole_plates.rb +++ b/app/models/labware_creators/pooled_tubes_from_whole_plates.rb @@ -13,7 +13,7 @@ class PooledTubesFromWholePlates < Base validate :parents_suitable - def create_labware! # rubocop:todo Metrics/AbcSize + def create_labware! # Create a single tube # TODO: This should link to multiple parents in production @child = @@ -29,9 +29,7 @@ def create_labware! # rubocop:todo Metrics/AbcSize .first # Transfer EVERYTHING into it - parents.each do |parent_plate| - transfer_template.create!(user: user_uuid, source: parent_plate.uuid, destination: @child.uuid) - end + parents.each { |parent_plate| transfer!(source_uuid: parent_plate.uuid, child_uuid: @child.uuid) } end def barcodes=(input) diff --git a/app/models/labware_creators/tube_from_tube.rb b/app/models/labware_creators/tube_from_tube.rb index 0322f919d..4e264406b 100644 --- a/app/models/labware_creators/tube_from_tube.rb +++ b/app/models/labware_creators/tube_from_tube.rb @@ -13,7 +13,8 @@ def create_labware! @child_tube = api.tube_from_tube_creation.create!(parent: parent_uuid, child_purpose: purpose_uuid, user: user_uuid).child - @tube_transfer = transfer_template.create!(user: user_uuid, source: parent_uuid, destination: @child_tube.uuid) + @tube_transfer = transfer!(source_uuid: parent_uuid, child_uuid: @child_tube.uuid) + true end diff --git a/app/sequencescape/sequencescape/api/v2/transfer.rb b/app/sequencescape/sequencescape/api/v2/transfer.rb new file mode 100644 index 000000000..69851a9ba --- /dev/null +++ b/app/sequencescape/sequencescape/api/v2/transfer.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +# transfer resource +class Sequencescape::Api::V2::Transfer < Sequencescape::Api::V2::Base +end From 2356a355e6a381a74f0284f52def4df3294f6452 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 20 Aug 2024 16:12:36 +0100 Subject: [PATCH 49/70] Use correct name for the API v2 endpoint --- app/models/labware_creators/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/labware_creators/base.rb b/app/models/labware_creators/base.rb index 436a2fc04..baa4c50e6 100644 --- a/app/models/labware_creators/base.rb +++ b/app/models/labware_creators/base.rb @@ -117,7 +117,7 @@ def create_plate_from_parent! end def transfer!(attributes) - Sequencescape::Api::V2::Template.create!( + Sequencescape::Api::V2::Transfer.create!( attributes.merge(transfer_template_uuid: transfer_template_uuid, user_uuid: user_uuid) ) end From 85d34cd1dce72fbf011e96dc6e429589a02cbacf Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 20 Aug 2024 16:12:50 +0100 Subject: [PATCH 50/70] Pluralise the transfers attribute --- app/models/labware_creators/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/labware_creators/base.rb b/app/models/labware_creators/base.rb index baa4c50e6..86a6557e4 100644 --- a/app/models/labware_creators/base.rb +++ b/app/models/labware_creators/base.rb @@ -123,7 +123,7 @@ def transfer!(attributes) end def transfer_material_from_parent!(child_uuid) - transfer!(source_uuid: parent_uuid, destination_uuid: child_uuid, transfer: transfer_hash) + transfer!(source_uuid: parent_uuid, destination_uuid: child_uuid, transfers: transfer_hash) end # Override in classes with custom transfers From dd89b64484fc6312448f6bd527d2834231a5e4f9 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 20 Aug 2024 16:13:17 +0100 Subject: [PATCH 51/70] Indicate that Transfers are nested one layer deeper than other resources --- app/sequencescape/sequencescape/api/v2/transfer.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/sequencescape/sequencescape/api/v2/transfer.rb b/app/sequencescape/sequencescape/api/v2/transfer.rb index 69851a9ba..924ab694a 100644 --- a/app/sequencescape/sequencescape/api/v2/transfer.rb +++ b/app/sequencescape/sequencescape/api/v2/transfer.rb @@ -2,4 +2,7 @@ # transfer resource class Sequencescape::Api::V2::Transfer < Sequencescape::Api::V2::Base + def self.resource_path + 'transfers/transfers' # Transfers are nested beneath a transfers path. + end end From 8df2472e1e5917d4804ab7ea592eb9439e4933f6 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 20 Aug 2024 16:13:58 +0100 Subject: [PATCH 52/70] Fix attribute reference when getting destination UUIDs via API v2 --- app/models/labware_creators/final_tube.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/labware_creators/final_tube.rb b/app/models/labware_creators/final_tube.rb index 1ba61cc63..949a5a0ad 100644 --- a/app/models/labware_creators/final_tube.rb +++ b/app/models/labware_creators/final_tube.rb @@ -41,7 +41,7 @@ def custom_input_expected def redirection_target return :contents_not_transfered_to_mx_tube if all_tube_transfers.nil? - destination_uuids = all_tube_transfers.map { |tt| tt.destination.uuid }.uniq + destination_uuids = all_tube_transfers.map { |tt| tt.destination_uuid }.uniq # The client_api returns a 'barcoded asset' here, rather than a tube. # We know that its a tube though, so wrap it in this useful tool From 24a1378dd346797fd71ba166906f414e4f45e628 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 20 Aug 2024 16:17:35 +0100 Subject: [PATCH 53/70] Use method mapping for destination_uuid --- app/models/labware_creators/final_tube.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/labware_creators/final_tube.rb b/app/models/labware_creators/final_tube.rb index 949a5a0ad..afa8fa9ff 100644 --- a/app/models/labware_creators/final_tube.rb +++ b/app/models/labware_creators/final_tube.rb @@ -41,7 +41,7 @@ def custom_input_expected def redirection_target return :contents_not_transfered_to_mx_tube if all_tube_transfers.nil? - destination_uuids = all_tube_transfers.map { |tt| tt.destination_uuid }.uniq + destination_uuids = all_tube_transfers.map(&:destination_uuid).uniq # The client_api returns a 'barcoded asset' here, rather than a tube. # We know that its a tube though, so wrap it in this useful tool From a3e97ebd692cf8926507b86d0d386b3601f0471f Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Tue, 20 Aug 2024 17:01:32 +0100 Subject: [PATCH 54/70] Use correct key when setting the destination of a transfer --- app/models/labware_creators/plate_with_template.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/labware_creators/plate_with_template.rb b/app/models/labware_creators/plate_with_template.rb index 1cb7e790d..389b17bb4 100644 --- a/app/models/labware_creators/plate_with_template.rb +++ b/app/models/labware_creators/plate_with_template.rb @@ -8,7 +8,7 @@ class PlateWithTemplate < Base # rubocop:todo Style/Documentation include SupportParent::PlateOnly def transfer_material_from_parent!(child_uuid) - transfer!(source_uuid: parent_uuid, child_uuid: child_uuid) + transfer!(source_uuid: parent_uuid, destination_uuid: child_uuid) end end end From b900cfccba035636447578c2d1912c012a1bf052 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Wed, 21 Aug 2024 14:52:53 +0100 Subject: [PATCH 55/70] Fix further instances of child_uuid instead of destination_uuid --- app/models/labware_creators/pooled_tubes_from_whole_plates.rb | 2 +- app/models/labware_creators/tube_from_tube.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/labware_creators/pooled_tubes_from_whole_plates.rb b/app/models/labware_creators/pooled_tubes_from_whole_plates.rb index 49556305d..41a09f490 100644 --- a/app/models/labware_creators/pooled_tubes_from_whole_plates.rb +++ b/app/models/labware_creators/pooled_tubes_from_whole_plates.rb @@ -29,7 +29,7 @@ def create_labware! .first # Transfer EVERYTHING into it - parents.each { |parent_plate| transfer!(source_uuid: parent_plate.uuid, child_uuid: @child.uuid) } + parents.each { |parent_plate| transfer!(source_uuid: parent_plate.uuid, destination_uuid: @child.uuid) } end def barcodes=(input) diff --git a/app/models/labware_creators/tube_from_tube.rb b/app/models/labware_creators/tube_from_tube.rb index 4e264406b..f8daa931c 100644 --- a/app/models/labware_creators/tube_from_tube.rb +++ b/app/models/labware_creators/tube_from_tube.rb @@ -13,7 +13,7 @@ def create_labware! @child_tube = api.tube_from_tube_creation.create!(parent: parent_uuid, child_purpose: purpose_uuid, user: user_uuid).child - @tube_transfer = transfer!(source_uuid: parent_uuid, child_uuid: @child_tube.uuid) + @tube_transfer = transfer!(source_uuid: parent_uuid, destination_uuid: @child_tube.uuid) true end From 775407c72bf07f3a81259cd53fc8c45b180879c7 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Wed, 21 Aug 2024 18:26:31 +0100 Subject: [PATCH 56/70] Fix tests in three spec files --- spec/factories/transfer_factories.rb | 17 +++++ .../custom_tagged_plate_spec.rb | 39 ++++++----- .../labware_creators/final_tube_spec.rb | 66 +++++-------------- .../pooled_tubes_from_whole_plates_spec.rb | 34 ++++------ spec/support/api_url_helper.rb | 21 ++++-- 5 files changed, 89 insertions(+), 88 deletions(-) diff --git a/spec/factories/transfer_factories.rb b/spec/factories/transfer_factories.rb index 2453ddadd..7f996188a 100644 --- a/spec/factories/transfer_factories.rb +++ b/spec/factories/transfer_factories.rb @@ -1,6 +1,23 @@ # frozen_string_literal: true FactoryBot.define do + # API V2 Transfer + factory :v2_transfer, class: Sequencescape::Api::V2::Transfer do + skip_create + + transient do + user + source { create :v2_plate } + destination { create :v2_plate } + end + + uuid { SecureRandom.uuid } + user_uuid { user.uuid } + source_uuid { source.uuid } + destination_uuid { destination.uuid } + transfers { { 'A1' => 'A1', 'B1' => 'B1', 'C1' => 'C1' } } + end + # API V1 Transfer factory :transfer, class: Sequencescape::Transfer, traits: [:api_object] do json_root { 'transfer' } diff --git a/spec/models/labware_creators/custom_tagged_plate_spec.rb b/spec/models/labware_creators/custom_tagged_plate_spec.rb index d4ba93ded..c831d4c58 100644 --- a/spec/models/labware_creators/custom_tagged_plate_spec.rb +++ b/spec/models/labware_creators/custom_tagged_plate_spec.rb @@ -114,19 +114,18 @@ let(:expected_transfers) { WellHelpers.stamp_hash(96) } - let!(:transfer_creation_request) do - stub_api_get(transfer_template_uuid, body: transfer_template) - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - source: plate_uuid, - destination: child_plate_uuid, - user: user_uuid, + def expect_transfer_creation + expect_api_v2_posts( + 'Transfer', + [ + { + user_uuid: user_uuid, + source_uuid: plate_uuid, + destination_uuid: child_plate_uuid, + transfer_template_uuid: transfer_template_uuid, transfers: expected_transfers } - }, - body: '{}' + ] ) end @@ -200,14 +199,17 @@ let(:tag_plate_state) { 'available' } it 'creates a tag plate' do + expect_transfer_creation + expect(subject.save).to be true expect(plate_creation_request).to have_been_made.once - expect(transfer_creation_request).to have_been_made.once expect(state_change_tag_plate_request).to have_been_made.once expect(custom_tag_layout_creation_request).to have_been_made.once end it 'has the correct child (and uuid)' do + stub_api_v2_post('Transfer') + expect(subject.save).to be true # This will be our new plate @@ -232,9 +234,10 @@ end it 'creates a tag plate' do + expect_transfer_creation + expect(subject.save).to be true expect(plate_creation_request).to have_been_made.once - expect(transfer_creation_request).to have_been_made.once expect(state_change_tag_plate_request).to have_been_made expect(custom_tag_layout_creation_request).to have_been_made.once end @@ -245,9 +248,10 @@ let(:tag_plate_state) { 'exhausted' } it 'creates a tagged plate' do + expect_transfer_creation + expect(subject.save).to be true expect(plate_creation_request).to have_been_made.once - expect(transfer_creation_request).to have_been_made.once expect(state_change_tag_plate_request).not_to have_been_made # This one will be VERY different @@ -255,6 +259,8 @@ end it 'has the correct child (and uuid)' do + stub_api_v2_post('Transfer') + expect(subject.save).to be true # This will be our new plate @@ -268,14 +274,17 @@ let(:parents) { [plate_uuid] } it 'creates a tag plate' do + expect_transfer_creation + expect(subject.save).to be true expect(plate_creation_request).to have_been_made.once - expect(transfer_creation_request).to have_been_made.once expect(state_change_tag_plate_request).not_to have_been_made expect(custom_tag_layout_creation_request).to have_been_made.once end it 'has the correct child (and uuid)' do + stub_api_v2_post('Transfer') + expect(subject.save).to be true expect(subject.child.uuid).to eq(child_plate_uuid) end diff --git a/spec/models/labware_creators/final_tube_spec.rb b/spec/models/labware_creators/final_tube_spec.rb index ecb7117ae..bbff446d6 100644 --- a/spec/models/labware_creators/final_tube_spec.rb +++ b/spec/models/labware_creators/final_tube_spec.rb @@ -25,32 +25,23 @@ let(:user_uuid) { 'user-uuid' } let(:multiplexed_library_tube_uuid) { 'multiplexed-library-tube--uuid' } let(:transfer_template_uuid) { 'transfer-template-uuid' } + let(:transfer) { create :v2_transfer } let(:form_attributes) { { purpose_uuid: child_purpose_uuid, parent_uuid: parent_uuid, user_uuid: user_uuid } } context 'with a sibling-less parent tube' do - let(:transfer_request) do - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - user: user_uuid, - source: parent_uuid - } - }, - body: json(:transfer_between_tubes_by_submission, destination: multiplexed_library_tube_uuid) - ) - end - let(:tube_json) { json(:tube_without_siblings, uuid: parent_uuid) } - before { transfer_request } - describe '#save' do it 'should be vaild' do + expect_api_v2_posts( + 'Transfer', + [{ user_uuid: user_uuid, source_uuid: parent_uuid, transfer_template_uuid: transfer_template_uuid }], + [transfer] + ) + expect(subject.save).to be true - expect(subject.redirection_target.to_param).to eq('multiplexed-library-tube--uuid') - expect(transfer_request).to have_been_made.once + expect(subject.redirection_target.to_param).to eq(transfer.destination_uuid) end end end @@ -88,41 +79,20 @@ end let(:sibling_uuid) { 'sibling-tube-0' } - let(:transfer_request) do - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - user: user_uuid, - source: parent_uuid - } - }, - body: json(:transfer_between_tubes_by_submission, destination: multiplexed_library_tube_uuid) - ) - end - let(:transfer_request_b) do - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - user: user_uuid, - source: sibling_uuid - } - }, - body: json(:transfer_between_tubes_by_submission, destination: multiplexed_library_tube_uuid) - ) - end - - before do - transfer_request - transfer_request_b - end + let(:transfer_b) { create :v2_transfer } it 'should create transfers per sibling' do + expect_api_v2_posts( + 'Transfer', + [ + { user_uuid: user_uuid, source_uuid: parent_uuid, transfer_template_uuid: transfer_template_uuid }, + { user_uuid: user_uuid, source_uuid: sibling_uuid, transfer_template_uuid: transfer_template_uuid } + ], + [transfer, transfer_b] + ) + expect(subject).to be_valid expect(subject.save).to be true - expect(transfer_request).to have_been_made.once - expect(transfer_request_b).to have_been_made.once end end end diff --git a/spec/models/labware_creators/pooled_tubes_from_whole_plates_spec.rb b/spec/models/labware_creators/pooled_tubes_from_whole_plates_spec.rb index 0284c0adc..6b4244691 100644 --- a/spec/models/labware_creators/pooled_tubes_from_whole_plates_spec.rb +++ b/spec/models/labware_creators/pooled_tubes_from_whole_plates_spec.rb @@ -21,6 +21,7 @@ let(:user_uuid) { SecureRandom.uuid } let(:purpose_uuid) { SecureRandom.uuid } let(:purpose) { json :purpose, uuid: purpose_uuid } + let(:transfer_template_uuid) { SecureRandom.uuid } let(:parent_uuid) { SecureRandom.uuid } let(:parent2_uuid) { SecureRandom.uuid } let(:parent3_uuid) { SecureRandom.uuid } @@ -39,7 +40,7 @@ ] end - before { Settings.transfer_templates['Whole plate to tube'] = 'whole-plate-to-tube' } + before { Settings.transfer_templates['Whole plate to tube'] = transfer_template_uuid } describe '#new' do it_behaves_like 'it has a custom page', 'pooled_tubes_from_whole_plates' @@ -81,35 +82,28 @@ # Used to fetch the pools. This is the kind of thing we could pass through from a custom form let(:stub_barcode_searches) { stub_asset_search(barcodes, [parent, parent2, parent3, parent4]) } - let(:transfer_creation_request) do - stub_api_get('whole-plate-to-tube', body: json(:whole_plate_to_tube)) - [parent_uuid, parent2_uuid, parent3_uuid, parent4_uuid].map do |uuid| - stub_api_post( - 'whole-plate-to-tube', - payload: { - transfer: { - user: user_uuid, - source: uuid, - destination: 'tube-0' - } - }, - body: '{}' - ) - end - end - before do stub_barcode_searches tube_creation_children_request tube_creation_request - transfer_creation_request end context 'with compatible plates' do it 'pools from all the plates' do + expect_api_v2_posts( + 'Transfer', + [parent_uuid, parent2_uuid, parent3_uuid, parent4_uuid].map do |source_uuid| + { + user_uuid: user_uuid, + source_uuid: source_uuid, + destination_uuid: 'tube-0', + transfer_template_uuid: transfer_template_uuid + } + end + ) + expect(subject.save!).to be_truthy expect(tube_creation_request).to have_been_made.once - transfer_creation_request.each { |transfer| expect(transfer).to have_been_made.once } end end end diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index 3a7e305de..54d162f9c 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -89,13 +89,24 @@ def stub_api_v2_save(klass) allow_any_instance_of(receiving_class).to receive(:save).and_return(true) end - def expect_api_v2_posts(klass, args_list) + def stub_api_v2_post(klass) + # intercepts the 'create!' method for any class beginning with + # 'Sequencescape::Api::V2::' and returns true + receiving_class = "Sequencescape::Api::V2::#{klass}".constantize + allow(receiving_class).to receive(:create!).and_return(true) + end + + def expect_api_v2_posts(klass, args_list, return_values = []) # Expects the 'create!' method for any class beginning with - # 'Sequencescape::Api::V2::' to be called with given arguments, in sequence, and returns true + # 'Sequencescape::Api::V2::' to be called with given arguments, in sequence, and returns the given values. + # If return_values is empty, it will return true. receiving_class = "Sequencescape::Api::V2::#{klass}".constantize - expect(receiving_class).to receive(:create!).exactly(args_list.count).times do |args| - expect(args).to eq(args_list.shift) - end.and_return(true) + args_list + .zip(return_values) + .each do |args, ret| + ret ||= true + expect(receiving_class).to receive(:create!).with(args).and_return(ret) + end end def stub_barcode_search(barcode, labware) From 4b9ca0debdca468be49b69c3ec1f955f23ef2a3b Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 22 Aug 2024 12:17:35 +0100 Subject: [PATCH 57/70] Fix more tests --- spec/factories/transfer_factories.rb | 13 +++++++ ...ling_multiple_plates_into_one_tube_spec.rb | 33 +++++++--------- .../final_tube_from_plate_spec.rb | 39 +++++++++---------- spec/support/api_url_helper.rb | 4 +- 4 files changed, 48 insertions(+), 41 deletions(-) diff --git a/spec/factories/transfer_factories.rb b/spec/factories/transfer_factories.rb index 7f996188a..9caad07b8 100644 --- a/spec/factories/transfer_factories.rb +++ b/spec/factories/transfer_factories.rb @@ -16,6 +16,19 @@ source_uuid { source.uuid } destination_uuid { destination.uuid } transfers { { 'A1' => 'A1', 'B1' => 'B1', 'C1' => 'C1' } } + + factory :v2_transfer_to_tubes_by_submission do + transient do + tube_count { 2 } + tubes { create_list(:v2_tube, tube_count) } + well_coordinates { WellHelpers.column_order[0, tube_count] } + end + + destination_uuid { nil } + + # Transfers will be a hash with column names as keys and tube-like objects for the values. + transfers { (0..tube_count - 1).map { |i| [well_coordinates[i], { uuid: tubes[i].uuid }] }.to_h } + end end # API V1 Transfer diff --git a/spec/features/pooling_multiple_plates_into_one_tube_spec.rb b/spec/features/pooling_multiple_plates_into_one_tube_spec.rb index 13e3124dd..73937a3d7 100644 --- a/spec/features/pooling_multiple_plates_into_one_tube_spec.rb +++ b/spec/features/pooling_multiple_plates_into_one_tube_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.feature 'Poling multiple plates into a tube', js: true do +RSpec.feature 'Pooling multiple plates into a tube', js: true do has_a_working_api let(:user_uuid) { SecureRandom.uuid } @@ -90,23 +90,6 @@ stub_asset_search([plate_barcode_1, plate_barcode_2], [example_plate_listed, example_plate_2_listed]) end - let!(:transfer_creation_request) do - stub_api_get('whole-plate-to-tube', body: json(:whole_plate_to_tube)) - [plate_uuid, plate_uuid_2].map do |uuid| - stub_api_post( - 'whole-plate-to-tube', - payload: { - transfer: { - user: user_uuid, - source: uuid, - destination: 'tube-0' - } - }, - body: '{}' - ) - end - end - let(:well_set_a) { json(:well_collection, aliquot_factory: :tagged_aliquot) } background do @@ -148,6 +131,19 @@ scenario 'creates multiple plates' do stub_v2_plate(example_plate_2) + + expect_api_v2_posts( + 'Transfer', + [plate_uuid, plate_uuid_2].map do |source_uuid| + { + user_uuid: user_uuid, + source_uuid: source_uuid, + destination_uuid: 'tube-0', + transfer_template_uuid: 'whole-plate-to-tube' + } + end + ) + fill_in_swipecard_and_barcode(user_swipecard, plate_barcode_1) plate_title = find('#plate-title') expect(plate_title).to have_text('example-purpose') @@ -165,7 +161,6 @@ # of confirming that the right information got passed to the back end otherwise. # (Although you expect it to fail on an incorrect request) expect(tube_creation_request).to have_been_made - transfer_creation_request.map { |r| expect(r).to have_been_made } end scenario 'detects tag clash' do diff --git a/spec/models/labware_creators/final_tube_from_plate_spec.rb b/spec/models/labware_creators/final_tube_from_plate_spec.rb index 4aea29873..c8bc20d97 100644 --- a/spec/models/labware_creators/final_tube_from_plate_spec.rb +++ b/spec/models/labware_creators/final_tube_from_plate_spec.rb @@ -24,23 +24,8 @@ # Used to fetch the pools. This is the kind of thing we could pass through from a custom form let!(:parent_request) { stub_api_get(parent_uuid, body: parent) } - # The API needs to pull back the transfer template to know what actions it can perform - let!(:transfer_template_request) do - stub_api_get('transfer-to-mx-tubes-on-submission', body: json(:transfer_wells_to_mx_library_tubes_by_submission)) - end - - let!(:transfer_creation_request) do - stub_api_post( - 'transfer-to-mx-tubes-on-submission', - payload: { - transfer: { - source: parent_uuid, - user: user_uuid - } - }, - body: json(:transfer_to_mx_tubes_by_submission) - ) - end + let(:destination_tubes) { create_list :v2_tube, 2 } + let(:transfer) { create :v2_transfer_to_tubes_by_submission, tubes: destination_tubes } let!(:tube_state_change_request_0) do stub_api_post( @@ -48,20 +33,21 @@ payload: { 'state_change' => { user: user_uuid, - target: 'child-tube-0', + target: destination_tubes[0].uuid, target_state: 'passed' } }, body: '{}' # We don't care about the response ) end + let!(:tube_state_change_request_1) do stub_api_post( 'state_changes', payload: { 'state_change' => { user: user_uuid, - target: 'child-tube-1', + target: destination_tubes[1].uuid, target_state: 'passed' } }, @@ -69,9 +55,22 @@ ) end + before { stub_api_v2_post('Transfer', transfer) } + it 'pools by submission' do + expect_api_v2_posts( + 'Transfer', + [ + { + user_uuid: user_uuid, + source_uuid: parent_uuid, + transfer_template_uuid: 'transfer-to-mx-tubes-on-submission' + } + ], + [transfer] + ) + expect(subject.save!).to be_truthy - expect(transfer_creation_request).to have_been_made.once end it 'passes the tubes automatically' do diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index 54d162f9c..13e9f24dd 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -89,11 +89,11 @@ def stub_api_v2_save(klass) allow_any_instance_of(receiving_class).to receive(:save).and_return(true) end - def stub_api_v2_post(klass) + def stub_api_v2_post(klass, return_value = true) # intercepts the 'create!' method for any class beginning with # 'Sequencescape::Api::V2::' and returns true receiving_class = "Sequencescape::Api::V2::#{klass}".constantize - allow(receiving_class).to receive(:create!).and_return(true) + allow(receiving_class).to receive(:create!).and_return(return_value) end def expect_api_v2_posts(klass, args_list, return_values = []) From ac6dfbe237a84e1d49b7bb1d767ad51aa3e7ef7b Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 22 Aug 2024 15:37:43 +0100 Subject: [PATCH 58/70] Finish fixing tests in Limber --- spec/factories/transfer_factories.rb | 17 ++++++-- spec/features/creating_a_tag_plate_spec.rb | 19 ++++++++- .../pool_tubes_at_end_of_pipeline_spec.rb | 42 ++++--------------- .../plate_with_template_spec.rb | 26 +++++------- .../pooled_tubes_from_whole_plates_spec.rb | 5 +-- .../labware_creators/tagged_plate_spec.rb | 18 +++++++- .../labware_creators/tube_from_tube_spec.rb | 29 ++++++------- spec/support/api_url_helper.rb | 9 ++-- spec/support/shared_tagging_examples.rb | 18 -------- 9 files changed, 84 insertions(+), 99 deletions(-) diff --git a/spec/factories/transfer_factories.rb b/spec/factories/transfer_factories.rb index 9caad07b8..2e7770308 100644 --- a/spec/factories/transfer_factories.rb +++ b/spec/factories/transfer_factories.rb @@ -19,15 +19,24 @@ factory :v2_transfer_to_tubes_by_submission do transient do - tube_count { 2 } - tubes { create_list(:v2_tube, tube_count) } - well_coordinates { WellHelpers.column_order[0, tube_count] } + destination_tube_count { 2 } + tubes { create_list(:v2_tube, destination_tube_count) } + well_coordinates { WellHelpers.column_order[0, destination_tube_count] } end destination_uuid { nil } # Transfers will be a hash with column names as keys and tube-like objects for the values. - transfers { (0..tube_count - 1).map { |i| [well_coordinates[i], { uuid: tubes[i].uuid }] }.to_h } + transfers { (0..tube_count - 1).to_h { |i| [well_coordinates[i], { uuid: tubes[i].uuid }] } } + end + + factory :v2_transfer_between_tubes do + transient do + source { create :v2_tube } + destination { create :v2_tube } + end + + transfers { nil } end end diff --git a/spec/features/creating_a_tag_plate_spec.rb b/spec/features/creating_a_tag_plate_spec.rb index 8f70f27b1..3d23f4e44 100644 --- a/spec/features/creating_a_tag_plate_spec.rb +++ b/spec/features/creating_a_tag_plate_spec.rb @@ -33,7 +33,7 @@ let(:tag_plate_uuid) { 'tag-plate-uuid' } let(:tag_plate_qcable) { json :tag_plate_qcable, uuid: tag_plate_qcable_uuid, lot_uuid: 'lot-uuid' } let(:transfer_template_uuid) { 'custom-pooling' } - let(:transfer_template) { json :transfer_template, uuid: transfer_template_uuid } + let(:expected_transfers) { WellHelpers.stamp_hash(96) } let(:tag_template_uuid) { 'tag-layout-template-0' } let(:submission_pools) { json(:submission_pool_collection) } @@ -77,7 +77,22 @@ shared_examples 'it supports the plate' do let(:help_text) { "Click 'Create plate'" } - before { stub_v2_plate(create(:v2_plate, uuid: tag_plate_uuid, purpose_uuid: 'stock-plate-purpose-uuid')) } + before do + stub_v2_plate(create(:v2_plate, uuid: tag_plate_uuid, purpose_uuid: 'stock-plate-purpose-uuid')) + + expect_api_v2_posts( + 'Transfer', + [ + { + user_uuid: user_uuid, + source_uuid: plate_uuid, + destination_uuid: tag_plate_uuid, + transfer_template_uuid: transfer_template_uuid, + transfers: expected_transfers + } + ] + ) + end scenario 'creation with the plate' do fill_in_swipecard_and_barcode user_swipecard, plate_barcode diff --git a/spec/features/pool_tubes_at_end_of_pipeline_spec.rb b/spec/features/pool_tubes_at_end_of_pipeline_spec.rb index dd6d96f6f..01f71b4f6 100644 --- a/spec/features/pool_tubes_at_end_of_pipeline_spec.rb +++ b/spec/features/pool_tubes_at_end_of_pipeline_spec.rb @@ -18,39 +18,10 @@ let(:example_tube) do json(:tube_with_siblings, uuid: tube_uuid, siblings_count: 1, state: 'passed', barcode_number: 1) end - let(:transfer_template_uuid) { 'transfer-template-uuid' } - let(:transfer_template) { json :transfer_template, uuid: transfer_template_uuid } let(:multiplexed_library_tube_uuid) { 'multiplexed-library-tube-uuid' } - let(:transfer_request) do - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - user: user_uuid, - source: tube_uuid - } - }, - body: json(:transfer_between_tubes_by_submission, destination: multiplexed_library_tube_uuid) - ) - end - let(:transfer_request_b) do - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - user: user_uuid, - source: sibling_uuid - } - }, - body: json(:transfer_between_tubes_by_submission, destination: multiplexed_library_tube_uuid) - ) - end - # Setup stubs background do - Settings.transfer_templates['Transfer from tube to tube by submission'] = transfer_template_uuid - # Set-up the tube config create :tube_config, name: 'Example Purpose', uuid: 'example-purpose-uuid' create :tube_config, @@ -71,8 +42,15 @@ stub_api_get('transfer-template-uuid', body: json(:transfer_template, uuid: 'transfer-template-uuid')) stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) stub_v2_tube(create(:v2_tube, uuid: multiplexed_library_tube_uuid)) - transfer_request - transfer_request_b + + expect_api_v2_posts( + 'Transfer', + [ + { user_uuid: user_uuid, source_uuid: tube_uuid, transfer_template_uuid: 'tube-to-tube-by-sub' }, + { user_uuid: user_uuid, source_uuid: sibling_uuid, transfer_template_uuid: 'tube-to-tube-by-sub' } + ], + create_list(:v2_transfer_between_tubes, 2, destination_uuid: multiplexed_library_tube_uuid) + ) end shared_examples 'a tube validation form' do @@ -89,8 +67,6 @@ find_field('Tube barcode').send_keys barcode_reader_key click_on('Make Tube') expect(page).to have_content('New empty labware added to the system.') - expect(transfer_request).to have_been_made.once - expect(transfer_request_b).to have_been_made.once end end diff --git a/spec/models/labware_creators/plate_with_template_spec.rb b/spec/models/labware_creators/plate_with_template_spec.rb index 21f4987ba..75e58544c 100644 --- a/spec/models/labware_creators/plate_with_template_spec.rb +++ b/spec/models/labware_creators/plate_with_template_spec.rb @@ -60,25 +60,21 @@ let!(:plate_request) { stub_api_get(parent_uuid, body: plate) } - let!(:transfer_template_request) { stub_api_get('custom-transfer-template', body: transfer_template) } - - let!(:transfer_creation_request) do - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - destination: 'child-uuid', - source: parent_uuid, - user: user_uuid + it 'makes the expected requests' do + expect_api_v2_posts( + 'Transfer', + [ + { + user_uuid: user_uuid, + source_uuid: parent_uuid, + destination_uuid: 'child-uuid', + transfer_template_uuid: transfer_template_uuid } - }, - body: '{}' + ] ) - end - it 'makes the expected requests' do + expect(subject.save!).to eq true expect(plate_creation_request).to have_been_made - expect(transfer_creation_request).to have_been_made end end end diff --git a/spec/models/labware_creators/pooled_tubes_from_whole_plates_spec.rb b/spec/models/labware_creators/pooled_tubes_from_whole_plates_spec.rb index 6b4244691..e5ce80273 100644 --- a/spec/models/labware_creators/pooled_tubes_from_whole_plates_spec.rb +++ b/spec/models/labware_creators/pooled_tubes_from_whole_plates_spec.rb @@ -21,7 +21,6 @@ let(:user_uuid) { SecureRandom.uuid } let(:purpose_uuid) { SecureRandom.uuid } let(:purpose) { json :purpose, uuid: purpose_uuid } - let(:transfer_template_uuid) { SecureRandom.uuid } let(:parent_uuid) { SecureRandom.uuid } let(:parent2_uuid) { SecureRandom.uuid } let(:parent3_uuid) { SecureRandom.uuid } @@ -40,8 +39,6 @@ ] end - before { Settings.transfer_templates['Whole plate to tube'] = transfer_template_uuid } - describe '#new' do it_behaves_like 'it has a custom page', 'pooled_tubes_from_whole_plates' has_a_working_api @@ -97,7 +94,7 @@ user_uuid: user_uuid, source_uuid: source_uuid, destination_uuid: 'tube-0', - transfer_template_uuid: transfer_template_uuid + transfer_template_uuid: 'whole-plate-to-tube' } end ) diff --git a/spec/models/labware_creators/tagged_plate_spec.rb b/spec/models/labware_creators/tagged_plate_spec.rb index a9253a587..38a8e3f1c 100644 --- a/spec/models/labware_creators/tagged_plate_spec.rb +++ b/spec/models/labware_creators/tagged_plate_spec.rb @@ -18,7 +18,7 @@ let(:wells) { json :well_collection, size: 16 } let(:wells_in_column_order) { WellHelpers.column_order } let(:transfer_template_uuid) { 'custom-pooling' } - let(:transfer_template) { json :transfer_template, uuid: transfer_template_uuid } + let(:expected_transfers) { WellHelpers.stamp_hash(96) } let(:child_purpose_uuid) { 'child-purpose' } let(:child_purpose_name) { 'Child Purpose' } @@ -210,14 +210,28 @@ Settings.transfer_templates['Custom pooling'] = 'custom-plate-transfer-template-uuid' it 'creates a tag plate' do + expect_api_v2_posts( + 'Transfer', + [ + { + user_uuid: user_uuid, + source_uuid: plate_uuid, + destination_uuid: tag_plate_uuid, + transfer_template_uuid: transfer_template_uuid, + transfers: expected_transfers + } + ] + ) + expect(subject.save).to be true expect(state_change_tag_plate_request).to have_been_made.once expect(plate_conversion_request).to have_been_made.once - expect(transfer_creation_request).to have_been_made.once expect(tag_layout_creation_request).to have_been_made.once end it 'has the correct child (and uuid)' do + stub_api_v2_post('Transfer') + expect(subject.save).to be true expect(subject.child.uuid).to eq(tag_plate_uuid) end diff --git a/spec/models/labware_creators/tube_from_tube_spec.rb b/spec/models/labware_creators/tube_from_tube_spec.rb index eec36ea22..f5ebd68f6 100644 --- a/spec/models/labware_creators/tube_from_tube_spec.rb +++ b/spec/models/labware_creators/tube_from_tube_spec.rb @@ -33,9 +33,7 @@ before do Settings.transfer_templates['Transfer between specific tubes'] = transfer_template_uuid - stub_api_get(transfer_template_uuid, body: json(:transfer_template, uuid: transfer_template_uuid)) creation_request - transfer_request end let(:controller) { TubeCreationController.new } @@ -61,26 +59,23 @@ ) end - let(:transfer_request) do - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - user: user_uuid, - source: parent_uuid, - destination: child_uuid - } - }, - body: json(:transfer_between_specific_tubes, destination_uuid: child_uuid) - ) - end - describe '#save!' do it 'creates the child' do + expect_api_v2_posts( + 'Transfer', + [ + { + user_uuid: user_uuid, + source_uuid: parent_uuid, + destination_uuid: child_uuid, + transfer_template_uuid: transfer_template_uuid + } + ] + ) + subject.save! expect(subject.redirection_target.uuid).to eq(child_uuid) expect(creation_request).to have_been_made.once - expect(transfer_request).to have_been_made.once end end end diff --git a/spec/support/api_url_helper.rb b/spec/support/api_url_helper.rb index 13e9f24dd..4894b46af 100644 --- a/spec/support/api_url_helper.rb +++ b/spec/support/api_url_helper.rb @@ -76,7 +76,7 @@ def stub_api_put(*components, body:, payload:) module V2Helpers def stub_api_v2_patch(klass) # intercepts the 'update' and 'update!' method for any instance of the class beginning with - # 'Sequencescape::Api::V2::' and returns true + # 'Sequencescape::Api::V2::' and returns true. receiving_class = "Sequencescape::Api::V2::#{klass}".constantize allow_any_instance_of(receiving_class).to receive(:update).and_return(true) allow_any_instance_of(receiving_class).to receive(:update!).and_return(true) @@ -84,15 +84,16 @@ def stub_api_v2_patch(klass) def stub_api_v2_save(klass) # intercepts the 'save' method for any instance of the class beginning with - # 'Sequencescape::Api::V2::' and returns true + # 'Sequencescape::Api::V2::' and returns true. receiving_class = "Sequencescape::Api::V2::#{klass}".constantize allow_any_instance_of(receiving_class).to receive(:save).and_return(true) end - def stub_api_v2_post(klass, return_value = true) + def stub_api_v2_post(klass, return_value = nil) # intercepts the 'create!' method for any class beginning with - # 'Sequencescape::Api::V2::' and returns true + # 'Sequencescape::Api::V2::' and returns the given value or else true. receiving_class = "Sequencescape::Api::V2::#{klass}".constantize + return_value ||= true allow(receiving_class).to receive(:create!).and_return(return_value) end diff --git a/spec/support/shared_tagging_examples.rb b/spec/support/shared_tagging_examples.rb index 6a1a0881f..84893b202 100644 --- a/spec/support/shared_tagging_examples.rb +++ b/spec/support/shared_tagging_examples.rb @@ -32,24 +32,6 @@ ) end - let(:expected_transfers) { WellHelpers.stamp_hash(96) } - - let!(:transfer_creation_request) do - stub_api_get(transfer_template_uuid, body: transfer_template) - stub_api_post( - transfer_template_uuid, - payload: { - transfer: { - source: plate_uuid, - destination: tag_plate_uuid, - user: user_uuid, - transfers: expected_transfers - } - }, - body: '{}' - ) - end - let(:tag_layout_template) { json(:tag_layout_template, uuid: tag_template_uuid) } let(:enforce_uniqueness) { true } From 30b85c095644760d3bcd4bd32a34d8c91af1f631 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 22 Aug 2024 15:41:19 +0100 Subject: [PATCH 59/70] Fix misnamed variable reference --- spec/factories/transfer_factories.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/factories/transfer_factories.rb b/spec/factories/transfer_factories.rb index 2e7770308..20f369f21 100644 --- a/spec/factories/transfer_factories.rb +++ b/spec/factories/transfer_factories.rb @@ -27,7 +27,7 @@ destination_uuid { nil } # Transfers will be a hash with column names as keys and tube-like objects for the values. - transfers { (0..tube_count - 1).to_h { |i| [well_coordinates[i], { uuid: tubes[i].uuid }] } } + transfers { (0..destination_tube_count - 1).to_h { |i| [well_coordinates[i], { uuid: tubes[i].uuid }] } } end factory :v2_transfer_between_tubes do From 305a65771cbe6063ec511e210df2e1e3f29678b0 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Thu, 22 Aug 2024 15:54:26 +0100 Subject: [PATCH 60/70] Fix remaining instances of changing persisted transfer template IDs across tests --- spec/factories/transfer_factories.rb | 2 +- spec/models/labware_creators/base_spec.rb | 2 ++ spec/models/labware_creators/final_tube_spec.rb | 8 ++------ spec/models/labware_creators/plate_with_template_spec.rb | 5 +---- spec/models/labware_creators/tagged_plate_spec.rb | 2 -- spec/models/labware_creators/tube_from_tube_spec.rb | 7 ++----- spec/spec_helper.rb | 6 ++++-- 7 files changed, 12 insertions(+), 20 deletions(-) diff --git a/spec/factories/transfer_factories.rb b/spec/factories/transfer_factories.rb index 20f369f21..af3f09536 100644 --- a/spec/factories/transfer_factories.rb +++ b/spec/factories/transfer_factories.rb @@ -27,7 +27,7 @@ destination_uuid { nil } # Transfers will be a hash with column names as keys and tube-like objects for the values. - transfers { (0..destination_tube_count - 1).to_h { |i| [well_coordinates[i], { uuid: tubes[i].uuid }] } } + transfers { (0...destination_tube_count).to_h { |i| [well_coordinates[i], { uuid: tubes[i].uuid }] } } end factory :v2_transfer_between_tubes do diff --git a/spec/models/labware_creators/base_spec.rb b/spec/models/labware_creators/base_spec.rb index 5f10043b8..a2a717f48 100644 --- a/spec/models/labware_creators/base_spec.rb +++ b/spec/models/labware_creators/base_spec.rb @@ -19,6 +19,8 @@ context 'with a custom transfer-template' do before do create :purpose_config, transfer_template: 'Custom transfer template', uuid: 'test-purpose' + + # Note this next change is persisted across the whole test run Settings.transfer_templates['Custom transfer template'] = 'custom-template-uuid' end diff --git a/spec/models/labware_creators/final_tube_spec.rb b/spec/models/labware_creators/final_tube_spec.rb index bbff446d6..b2264a865 100644 --- a/spec/models/labware_creators/final_tube_spec.rb +++ b/spec/models/labware_creators/final_tube_spec.rb @@ -13,18 +13,14 @@ context 'on creation' do subject { LabwareCreators::FinalTube.new(api, form_attributes) } - before do - Settings.transfer_templates['Transfer from tube to tube by submission'] = transfer_template_uuid - stub_api_get(parent_uuid, body: tube_json) - stub_api_get(transfer_template_uuid, body: json(:transfer_template, uuid: transfer_template_uuid)) - end + before { stub_api_get(parent_uuid, body: tube_json) } let(:controller) { TubeCreationController.new } let(:child_purpose_uuid) { 'child-purpose-uuid' } let(:parent_uuid) { 'parent-uuid' } let(:user_uuid) { 'user-uuid' } let(:multiplexed_library_tube_uuid) { 'multiplexed-library-tube--uuid' } - let(:transfer_template_uuid) { 'transfer-template-uuid' } + let(:transfer_template_uuid) { 'tube-to-tube-by-sub' } # Defined in spec_helper.rb let(:transfer) { create :v2_transfer } let(:form_attributes) { { purpose_uuid: child_purpose_uuid, parent_uuid: parent_uuid, user_uuid: user_uuid } } diff --git a/spec/models/labware_creators/plate_with_template_spec.rb b/spec/models/labware_creators/plate_with_template_spec.rb index 75e58544c..3a19bd859 100644 --- a/spec/models/labware_creators/plate_with_template_spec.rb +++ b/spec/models/labware_creators/plate_with_template_spec.rb @@ -17,9 +17,7 @@ let(:plate) { json :plate, uuid: parent_uuid, barcode_number: '2', pool_sizes: [8, 8] } let(:wells) { json :well_collection, size: 16 } let(:wells_in_column_order) { WellHelpers.column_order } - let(:transfer_template_name) { 'Pool wells based on submission' } - let(:transfer_template_uuid) { 'custom-transfer-template' } - let(:transfer_template) { json :transfer_template, uuid: transfer_template_uuid, name: transfer_template_name } + let(:transfer_template_uuid) { 'custom-transfer-template' } # Defined in spec_helper.rb let(:child_purpose_uuid) { 'child-purpose' } let(:child_purpose_name) { 'Child Purpose' } @@ -28,7 +26,6 @@ before do create(:templated_transfer_config, name: child_purpose_name, uuid: child_purpose_uuid) - Settings.transfer_templates[transfer_template_name] = transfer_template_uuid stub_api_get(parent_uuid, body: plate) stub_api_get(parent_uuid, 'wells', body: wells) end diff --git a/spec/models/labware_creators/tagged_plate_spec.rb b/spec/models/labware_creators/tagged_plate_spec.rb index 38a8e3f1c..90f20b9e2 100644 --- a/spec/models/labware_creators/tagged_plate_spec.rb +++ b/spec/models/labware_creators/tagged_plate_spec.rb @@ -207,8 +207,6 @@ it_behaves_like 'it has a custom page', 'tagged_plate' context 'on save' do - Settings.transfer_templates['Custom pooling'] = 'custom-plate-transfer-template-uuid' - it 'creates a tag plate' do expect_api_v2_posts( 'Transfer', diff --git a/spec/models/labware_creators/tube_from_tube_spec.rb b/spec/models/labware_creators/tube_from_tube_spec.rb index f5ebd68f6..144cdd1ff 100644 --- a/spec/models/labware_creators/tube_from_tube_spec.rb +++ b/spec/models/labware_creators/tube_from_tube_spec.rb @@ -31,17 +31,14 @@ it_behaves_like 'it has no custom page' - before do - Settings.transfer_templates['Transfer between specific tubes'] = transfer_template_uuid - creation_request - end + before { creation_request } let(:controller) { TubeCreationController.new } let(:child_purpose_uuid) { 'child-purpose-uuid' } let(:parent_uuid) { 'parent-uuid' } let(:child_uuid) { 'child-uuid' } let(:user_uuid) { 'user-uuid' } - let(:transfer_template_uuid) { 'transfer-between-specific-tubes' } + let(:transfer_template_uuid) { 'transfer-between-specific-tubes' } # Defined in spec_helper.rb let(:form_attributes) { { purpose_uuid: child_purpose_uuid, parent_uuid: parent_uuid, user_uuid: user_uuid } } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1da732cb8..c32370bac 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -160,10 +160,12 @@ FactoryBot.find_definitions Settings.robots = {} Settings.transfer_templates = { - 'Transfer columns 1-12' => 'transfer-1-12', - 'Transfer wells to MX library tubes by submission' => 'transfer-to-mx-tubes-on-submission', 'Custom pooling' => 'custom-pooling', + 'Pool wells based on submission' => 'custom-transfer-template', + 'Transfer between specific tubes' => 'transfer-between-specific-tubes', + 'Transfer columns 1-12' => 'transfer-1-12', 'Transfer from tube to tube by submission' => 'tube-to-tube-by-sub', + 'Transfer wells to MX library tubes by submission' => 'transfer-to-mx-tubes-on-submission', 'Whole plate to tube' => 'whole-plate-to-tube' } YAML From 1dce9e9a1747e414dc1fbd76e1a31837e0e35f4d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:17:23 +0000 Subject: [PATCH 61/70] build(deps): bump micromatch from 4.0.5 to 4.0.8 Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8. - [Release notes](https://github.com/micromatch/micromatch/releases) - [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8) --- updated-dependencies: - dependency-name: micromatch dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index af14498b1..92d38e5b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1015,7 +1015,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -2178,11 +2178,11 @@ microee@0.0.6: integrity sha512-/LdL3jiBWDJ3oQIRLgRhfeCZNE3patM1LiwCC124+/HHn10sI/G2OAyiMfTNzH5oYWoZBk0tRZADAUOv+0Wt0A== micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: From 99d5394d5fb31652431c9d8cb8cfea3b7c7ba054 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 30 Aug 2024 14:20:03 +0100 Subject: [PATCH 62/70] Switch to using API v2 for StateChange creations --- app/controllers/plates_controller.rb | 10 +++++----- .../labware_creators/tagged_plate_behaviour.rb | 8 ++++---- .../labware_creators/final_tube_from_plate.rb | 6 +++++- app/models/state_changers.rb | 15 +++++++-------- .../sequencescape/api/v2/state_change.rb | 3 ++- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/app/controllers/plates_controller.rb b/app/controllers/plates_controller.rb index 257a024c1..7d6338bec 100644 --- a/app/controllers/plates_controller.rb +++ b/app/controllers/plates_controller.rb @@ -14,13 +14,13 @@ def fail_wells # rubocop:todo Metrics/AbcSize notice: 'No wells were selected to fail' # rubocop:todo Rails/I18nLocaleTexts ) else - api.state_change.create!( - user: current_user_uuid, - target: params[:id], + Sequencescape::Api::V2::StateChange.create!( contents: wells_to_fail, - target_state: 'failed', + customer_accepts_responsibility: params[:customer_accepts_responsibility], reason: 'Individual Well Failure', - customer_accepts_responsibility: params[:customer_accepts_responsibility] + target_state: 'failed', + target_uuid: params[:id], + user_uuid: current_user_uuid ) redirect_to( limber_plate_path(params[:id]), diff --git a/app/models/concerns/labware_creators/tagged_plate_behaviour.rb b/app/models/concerns/labware_creators/tagged_plate_behaviour.rb index 36822ba10..0356e6c58 100644 --- a/app/models/concerns/labware_creators/tagged_plate_behaviour.rb +++ b/app/models/concerns/labware_creators/tagged_plate_behaviour.rb @@ -17,11 +17,11 @@ module LabwareCreators::TaggedPlateBehaviour # @return [Sequencescape::Api::StateChange] The created state change # def flag_tag_plate_as_exhausted - api.state_change.create!( - user: user_uuid, - target: tag_plate.asset_uuid, + Sequencescape::Api::V2::StateChange.create!( reason: 'Used in Library creation', - target_state: 'exhausted' + target_state: 'exhausted', + target_uuid: tag_plate.asset_uuid, + user_uuid: user_uuid ) end diff --git a/app/models/labware_creators/final_tube_from_plate.rb b/app/models/labware_creators/final_tube_from_plate.rb index e0ecefb13..f8b9f56ad 100644 --- a/app/models/labware_creators/final_tube_from_plate.rb +++ b/app/models/labware_creators/final_tube_from_plate.rb @@ -48,7 +48,11 @@ def pass_tubes! raise StandardError, 'Tubes cannot be passed before transfer' if @create_transfer.nil? tubes_from_transfer.each do |tube_uuid| - api.state_change.create!(user: user_uuid, target: tube_uuid, target_state: 'passed') + Sequencescape::Api::V2::StateChange.create!( + target_state: 'passed', + target_uuid: tube_uuid, + user_uuid: user_uuid + ) end end diff --git a/app/models/state_changers.rb b/app/models/state_changers.rb index acb0f468f..b0e33c72e 100644 --- a/app/models/state_changers.rb +++ b/app/models/state_changers.rb @@ -24,15 +24,14 @@ def initialize(api, labware_uuid, user_uuid) # rubocop:todo Style/OptionalBooleanParameter def move_to!(state, reason = nil, customer_accepts_responsibility = false) - state_details = { - target: labware_uuid, - user: user_uuid, - target_state: state, - reason: reason, + Sequencescape::Api::V2::StateChange.create!( + contents: contents_for(state), customer_accepts_responsibility: customer_accepts_responsibility, - contents: contents_for(state) - } - api.state_change.create!(state_details) + reason: reason, + target_state: state, + target_uuid: labware_uuid, + user_uuid: user_uuid + ) end # rubocop:enable Style/OptionalBooleanParameter diff --git a/app/sequencescape/sequencescape/api/v2/state_change.rb b/app/sequencescape/sequencescape/api/v2/state_change.rb index 73de8b819..76d078078 100644 --- a/app/sequencescape/sequencescape/api/v2/state_change.rb +++ b/app/sequencescape/sequencescape/api/v2/state_change.rb @@ -2,5 +2,6 @@ # Represents a state change in Limber via the Sequencescape API class Sequencescape::Api::V2::StateChange < Sequencescape::Api::V2::Base - has_one :labware, class_name: 'Sequencescape::Api::V2::Labware' + has_one :target, class_name: 'Sequencescape::Api::V2::Labware' + has_one :user, class_name: 'Sequencescape::Api::V2::User' end From 863651a3d2d5aa586dee00e1352cd294b5766ec3 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Fri, 30 Aug 2024 16:00:08 +0100 Subject: [PATCH 63/70] Update tests to expect API v2 StateChange creation --- spec/controllers/plates_controller_spec.rb | 52 +++++---------- spec/controllers/robots_controller_spec.rb | 37 +++++------ spec/controllers/tubes_controller_spec.rb | 29 ++++----- .../features/cancelling_a_whole_plate_spec.rb | 24 +++---- spec/features/creating_a_tag_plate_spec.rb | 3 + spec/features/failing_a_whole_plate_spec.rb | 24 +++---- spec/features/failing_quadrants_spec.rb | 27 ++++---- spec/features/failing_thresholds_spec.rb | 36 +++++------ spec/features/failing_wells_spec.rb | 32 +++++----- spec/features/plate_transfer_spec.rb | 28 +++------ .../custom_tagged_plate_spec.rb | 44 +++++-------- .../final_tube_from_plate_spec.rb | 42 ++++--------- .../labware_creators/tagged_plate_spec.rb | 14 ++++- .../robots/plate_to_tube_racks_robot_spec.rb | 39 +++++------- .../pooling_and_splitting_robot_spec.rb | 63 +++++++------------ spec/models/robots/pooling_robot_spec.rb | 28 ++++----- spec/models/robots/quadrant_robot_spec.rb | 28 ++++----- spec/models/robots/robot_spec.rb | 33 +++++----- spec/models/robots/splitting_robot_spec.rb | 33 +++++----- spec/models/state_changers_spec.rb | 33 ++++------ spec/support/shared_tagging_examples.rb | 16 ----- 21 files changed, 260 insertions(+), 405 deletions(-) diff --git a/spec/controllers/plates_controller_spec.rb b/spec/controllers/plates_controller_spec.rb index ba8bfdb49..5c4cb9303 100644 --- a/spec/controllers/plates_controller_spec.rb +++ b/spec/controllers/plates_controller_spec.rb @@ -13,6 +13,13 @@ let(:barcode_printers_request) { stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3)) } let(:user_uuid) { SecureRandom.uuid } + def expect_state_change_create(attributes) + expect_api_v2_posts( + 'StateChange', + [{ target_state: 'failed', target_uuid: plate_uuid, user_uuid: user_uuid }.merge(attributes)] + ) + end + describe '#show' do before do create :stock_plate_config, uuid: 'stock-plate-purpose-uuid' @@ -46,24 +53,10 @@ let(:old_api_example_plate) do json :plate, barcode_number: v2_plate.labware_barcode.number, uuid: plate_uuid, state: 'passed' end - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: plate_uuid, - target_state: 'failed', - reason: 'Because testing', - customer_accepts_responsibility: true, - contents: nil - } - }, - body: '{}' - ) # We don't care about the response - end it 'transitions the plate' do + expect_state_change_create(contents: nil, customer_accepts_responsibility: true, reason: 'Because testing') + put :update, params: { id: plate_uuid, @@ -77,30 +70,19 @@ session: { user_uuid: user_uuid } - expect(state_change_request).to have_been_made + expect(response).to redirect_to(search_path) end end describe '#fail_wells' do - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: plate_uuid, - contents: ['A1'], - target_state: 'failed', - reason: 'Individual Well Failure', - customer_accepts_responsibility: nil - } - }, - body: '{}' - ) # We don't care about the response - end - it 'fails the selected wells' do + expect_state_change_create( + contents: ['A1'], + customer_accepts_responsibility: nil, + reason: 'Individual Well Failure' + ) + post :fail_wells, params: { id: plate_uuid, @@ -114,7 +96,7 @@ session: { user_uuid: user_uuid } - expect(state_change_request).to have_been_made + expect(response).to redirect_to(limber_plate_path(plate_uuid)) end end diff --git a/spec/controllers/robots_controller_spec.rb b/spec/controllers/robots_controller_spec.rb index e0adc0aa8..268396e29 100644 --- a/spec/controllers/robots_controller_spec.rb +++ b/spec/controllers/robots_controller_spec.rb @@ -4,36 +4,30 @@ require './app/controllers/robots_controller' RSpec.describe RobotsController, type: :controller, robots: true do + has_a_working_api + include FeatureHelpers include RobotHelpers let(:settings) { YAML.load_file(Rails.root.join('spec/data/settings.yml')).with_indifferent_access } describe '#start' do - has_a_working_api - let(:user) { create :user } let(:plate) { create :v2_plate, purpose_name: 'target_plate_purpose', purpose_uuid: 'target_plate_purpose_uuid' } - let!(:state_chage) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - 'target_state' => 'passed', - 'reason' => 'Robot robot_name started', - 'customer_accepts_responsibility' => false, - 'target' => plate.uuid, - 'user' => user.uuid, - 'contents' => nil - } - }, - body: json(:state_change) - ) + let(:metadata_attributes) do + { user_id: user.id, asset_id: plate.id, metadata: { created_with_robot: 'robot_barcode' } } end - let(:metadata_payload) do - { user_id: user.id, asset_id: plate.id, metadata: { created_with_robot: 'robot_barcode' } } + let(:state_change_attributes) do + { + contents: nil, + customer_accepts_responsibility: false, + reason: 'Robot robot_name started', + target_state: 'passed', + target_uuid: plate.uuid, + user_uuid: user.uuid + } end setup do @@ -53,7 +47,8 @@ end it 'adds robot barcode to plate metadata' do - expect_api_v2_posts('CustomMetadatumCollection', [metadata_payload]) + expect_api_v2_posts('CustomMetadatumCollection', [metadata_attributes]) + expect_api_v2_posts('StateChange', [state_change_attributes]) post :start, params: { @@ -73,8 +68,6 @@ end describe '#verify' do - has_a_working_api - let(:user) { create :user } let(:target_plate) do create :v2_plate, diff --git a/spec/controllers/tubes_controller_spec.rb b/spec/controllers/tubes_controller_spec.rb index ff23ce32f..7d75da7ef 100644 --- a/spec/controllers/tubes_controller_spec.rb +++ b/spec/controllers/tubes_controller_spec.rb @@ -34,24 +34,21 @@ tube_request end - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: tube_uuid, - target_state: 'cancelled', - reason: 'Because testing', + it 'transitions the tube' do + expect_api_v2_posts( + 'StateChange', + [ + { + contents: nil, customer_accepts_responsibility: true, - contents: nil + reason: 'Because testing', + target_state: 'cancelled', + target_uuid: tube_uuid, + user_uuid: user_uuid } - }, - body: '{}' - ) # We don't care about the response - end + ] + ) - it 'transitions the tube' do put :update, params: { id: tube_uuid, @@ -65,7 +62,7 @@ session: { user_uuid: user_uuid } - expect(state_change_request).to have_been_made + expect(response).to redirect_to(search_path) end end diff --git a/spec/features/cancelling_a_whole_plate_spec.rb b/spec/features/cancelling_a_whole_plate_spec.rb index b3ccbb7d4..b5907df0a 100644 --- a/spec/features/cancelling_a_whole_plate_spec.rb +++ b/spec/features/cancelling_a_whole_plate_spec.rb @@ -26,13 +26,11 @@ json :plate, barcode_number: example_plate.labware_barcode.number, uuid: plate_uuid, state: 'passed' end - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: plate_uuid, + def expect_state_change_create + expect_api_v2_posts( + 'StateChange', + [ + { contents: %w[ A1 B1 @@ -130,12 +128,13 @@ G12 H12 ], - target_state: 'cancelled', + customer_accepts_responsibility: nil, reason: 'Not required', - customer_accepts_responsibility: nil + target_state: 'cancelled', + target_uuid: plate_uuid, + user_uuid: user_uuid } - }, - body: '{}' # We don't care about the response + ] ) end @@ -164,6 +163,8 @@ end scenario 'from the interface' do + expect_state_change_create + fill_in_swipecard_and_barcode user_swipecard, plate_barcode # Spotted a potential bug where we could accidentally persist details @@ -180,6 +181,5 @@ click_on('Cancel Labware') expect(find('#flashes')).to have_content("Labware: #{plate_barcode} has been changed to a state of Cancelled.") - expect(state_change_request).to have_been_made end end diff --git a/spec/features/creating_a_tag_plate_spec.rb b/spec/features/creating_a_tag_plate_spec.rb index 3d23f4e44..b319045bc 100644 --- a/spec/features/creating_a_tag_plate_spec.rb +++ b/spec/features/creating_a_tag_plate_spec.rb @@ -5,6 +5,7 @@ RSpec.feature 'Creating a tag plate', js: true, tag_plate: true do has_a_working_api + let(:user_uuid) { 'user-uuid' } let(:user) { create :user, uuid: user_uuid } let(:user_swipecard) { 'abcdef' } @@ -92,6 +93,8 @@ } ] ) + + stub_api_v2_post('StateChange') end scenario 'creation with the plate' do diff --git a/spec/features/failing_a_whole_plate_spec.rb b/spec/features/failing_a_whole_plate_spec.rb index a5a243f17..22f2c8cf1 100644 --- a/spec/features/failing_a_whole_plate_spec.rb +++ b/spec/features/failing_a_whole_plate_spec.rb @@ -26,13 +26,11 @@ json :plate, barcode_number: example_plate.labware_barcode.number, uuid: plate_uuid, state: 'passed' end - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: plate_uuid, + def expect_state_change_create + expect_api_v2_posts( + 'StateChange', + [ + { contents: %w[ A1 B1 @@ -130,12 +128,13 @@ G12 H12 ], - target_state: 'failed', + customer_accepts_responsibility: true, reason: 'Power failure', - customer_accepts_responsibility: true + target_state: 'failed', + target_uuid: plate_uuid, + user_uuid: user_uuid } - }, - body: '{}' # We don't care about the response + ] ) end @@ -162,6 +161,8 @@ end scenario 'failing a plate' do + expect_state_change_create + fill_in_swipecard_and_barcode user_swipecard, plate_barcode within_fieldset('Change state to') { choose('failed', allow_label_click: true) } @@ -175,6 +176,5 @@ expect(find('#flashes')).to have_content( "Labware: #{plate_barcode} has been changed to a state of Failed. The customer will still be charged." ) - expect(state_change_request).to have_been_made end end diff --git a/spec/features/failing_quadrants_spec.rb b/spec/features/failing_quadrants_spec.rb index d9f43ce13..35765001a 100644 --- a/spec/features/failing_quadrants_spec.rb +++ b/spec/features/failing_quadrants_spec.rb @@ -28,21 +28,15 @@ size: 384 end - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: plate_uuid, - contents: %w[A1 A3], - target_state: 'failed', - reason: 'Individual Well Failure', - customer_accepts_responsibility: nil - } - }, - body: '{}' # We don't care about the response - ) + let(:state_change_attributes) do + { + contents: %w[A1 A3], + customer_accepts_responsibility: nil, + reason: 'Individual Well Failure', + target_state: 'failed', + target_uuid: plate_uuid, + user_uuid: user_uuid + } end # Setup stubs @@ -69,6 +63,8 @@ end scenario 'failing wells' do + expect_api_v2_posts('StateChange', [state_change_attributes]) + fill_in_swipecard_and_barcode user_swipecard, plate_barcode click_on('Fail Wells') @@ -77,6 +73,5 @@ click_on('Fail selected wells') expect(find('#flashes')).to have_content('Selected wells have been failed') - expect(state_change_request).to have_been_made end end diff --git a/spec/features/failing_thresholds_spec.rb b/spec/features/failing_thresholds_spec.rb index 910422407..bfc838692 100644 --- a/spec/features/failing_thresholds_spec.rb +++ b/spec/features/failing_thresholds_spec.rb @@ -25,23 +25,6 @@ create :v2_plate, uuid: plate_uuid, purpose_uuid: 'stock-plate-purpose-uuid', state: 'passed', wells: wells end - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: plate_uuid, - contents: %w[A1 A3], - target_state: 'failed', - reason: 'Individual Well Failure', - customer_accepts_responsibility: nil - } - }, - body: '{}' # We don't care about the response - ) - end - # Setup stubs background do # Set-up the plate config @@ -66,14 +49,25 @@ end scenario 'failing wells' do - fill_in_swipecard_and_barcode user_swipecard, plate_barcode + expect_api_v2_posts( + 'StateChange', + [ + { + contents: %w[A1 A3], + customer_accepts_responsibility: nil, + reason: 'Individual Well Failure', + target_state: 'failed', + target_uuid: plate_uuid, + user_uuid: user_uuid + } + ] + ) + fill_in_swipecard_and_barcode user_swipecard, plate_barcode click_on('Fail Wells') - fill_in 'Molarity', with: 15 - click_on('Fail selected wells') + expect(find('#flashes')).to have_content('Selected wells have been failed') - expect(state_change_request).to have_been_made end end diff --git a/spec/features/failing_wells_spec.rb b/spec/features/failing_wells_spec.rb index ec476c638..f7072b5c4 100644 --- a/spec/features/failing_wells_spec.rb +++ b/spec/features/failing_wells_spec.rb @@ -23,23 +23,6 @@ create :v2_plate, uuid: plate_uuid, purpose_uuid: 'stock-plate-purpose-uuid', state: 'passed', wells: wells end - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: plate_uuid, - contents: %w[A2 A3], - target_state: 'failed', - reason: 'Individual Well Failure', - customer_accepts_responsibility: nil - } - }, - body: '{}' # We don't care about the response - ) - end - # Setup stubs background do # Set-up the plate config @@ -65,6 +48,20 @@ end scenario 'failing wells' do + expect_api_v2_posts( + 'StateChange', + [ + { + contents: %w[A2 A3], + customer_accepts_responsibility: nil, + reason: 'Individual Well Failure', + target_state: 'failed', + target_uuid: plate_uuid, + user_uuid: user_uuid + } + ] + ) + fill_in_swipecard_and_barcode user_swipecard, plate_barcode click_on('Fail Wells') within_fieldset('Select wells to fail') do @@ -76,6 +73,5 @@ click_on('Fail selected wells') expect(find('#flashes')).to have_content('Selected wells have been failed') - expect(state_change_request).to have_been_made end end diff --git a/spec/features/plate_transfer_spec.rb b/spec/features/plate_transfer_spec.rb index f8aad570a..5aac74c18 100644 --- a/spec/features/plate_transfer_spec.rb +++ b/spec/features/plate_transfer_spec.rb @@ -47,25 +47,17 @@ # We look up the user stub_v2_user(user, swipecard) - - stub_state_changes_post end - let(:stub_state_changes_post) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - target_state: 'started', - reason: 'Robot bravo LB Post Shear => LB End Prep started', - customer_accepts_responsibility: false, - target: plate_uuid, - user: user_uuid, - contents: nil - } - }, - body: json(:state_change, target_state: 'started') - ) + let(:state_change_attributes) do + { + contents: nil, + customer_accepts_responsibility: false, + reason: 'Robot bravo LB Post Shear => LB End Prep started', + target_state: 'started', + target_uuid: plate_uuid, + user_uuid: user_uuid + } end scenario 'starts the robot and saves the robot barcode' do @@ -73,6 +65,7 @@ 'CustomMetadatumCollection', [{ user_id: user.id, asset_id: example_plate.id, metadata: { created_with_robot: 'robot_barcode' } }] ) + expect_api_v2_posts('StateChange', [state_change_attributes]) allow_any_instance_of(Robots::Robot).to receive(:verify).and_return( beds: { @@ -135,7 +128,6 @@ end click_button('Start the bravo LB Post Shear => LB End Prep') expect(page).to have_content('Robot bravo LB Post Shear => LB End Prep has been started.') - expect(stub_state_changes_post).to have_been_requested end scenario 'informs if the robot barcode is wrong' do diff --git a/spec/models/labware_creators/custom_tagged_plate_spec.rb b/spec/models/labware_creators/custom_tagged_plate_spec.rb index c831d4c58..4c605f864 100644 --- a/spec/models/labware_creators/custom_tagged_plate_spec.rb +++ b/spec/models/labware_creators/custom_tagged_plate_spec.rb @@ -129,18 +129,17 @@ def expect_transfer_creation ) end - let!(:state_change_tag_plate_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - user: user_uuid, - target: tag_plate_uuid, + def expect_state_change_creation + expect_api_v2_posts( + 'StateChange', + [ + { reason: 'Used in Library creation', - target_state: 'exhausted' + target_uuid: tag_plate_uuid, + target_state: 'exhausted', + user_uuid: user_uuid } - }, - body: json(:state_change) + ] ) end @@ -200,15 +199,16 @@ def expect_transfer_creation it 'creates a tag plate' do expect_transfer_creation + expect_state_change_creation expect(subject.save).to be true expect(plate_creation_request).to have_been_made.once - expect(state_change_tag_plate_request).to have_been_made.once expect(custom_tag_layout_creation_request).to have_been_made.once end it 'has the correct child (and uuid)' do stub_api_v2_post('Transfer') + stub_api_v2_post('StateChange') expect(subject.save).to be true @@ -217,28 +217,12 @@ def expect_transfer_creation end context 'when a user has exhausted the plate in another tab' do - let!(:state_change_tag_plate_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - user: user_uuid, - target: tag_plate_uuid, - reason: 'Used in Library creation', - target_state: 'exhausted' - } - }, - status: 500, - body: '{"general":["No obvious transition from \"passed\" to \"passed\""]}' - ) - end - it 'creates a tag plate' do expect_transfer_creation + expect_state_change_creation expect(subject.save).to be true expect(plate_creation_request).to have_been_made.once - expect(state_change_tag_plate_request).to have_been_made expect(custom_tag_layout_creation_request).to have_been_made.once end end @@ -249,10 +233,10 @@ def expect_transfer_creation it 'creates a tagged plate' do expect_transfer_creation + expect(Sequencescape::Api::V2::StateChange).not_to receive(:create!) expect(subject.save).to be true expect(plate_creation_request).to have_been_made.once - expect(state_change_tag_plate_request).not_to have_been_made # This one will be VERY different expect(custom_tag_layout_creation_request).to have_been_made.once @@ -275,10 +259,10 @@ def expect_transfer_creation it 'creates a tag plate' do expect_transfer_creation + expect(Sequencescape::Api::V2::StateChange).not_to receive(:create!) expect(subject.save).to be true expect(plate_creation_request).to have_been_made.once - expect(state_change_tag_plate_request).not_to have_been_made expect(custom_tag_layout_creation_request).to have_been_made.once end diff --git a/spec/models/labware_creators/final_tube_from_plate_spec.rb b/spec/models/labware_creators/final_tube_from_plate_spec.rb index c8bc20d97..371189bcb 100644 --- a/spec/models/labware_creators/final_tube_from_plate_spec.rb +++ b/spec/models/labware_creators/final_tube_from_plate_spec.rb @@ -27,36 +27,11 @@ let(:destination_tubes) { create_list :v2_tube, 2 } let(:transfer) { create :v2_transfer_to_tubes_by_submission, tubes: destination_tubes } - let!(:tube_state_change_request_0) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: destination_tubes[0].uuid, - target_state: 'passed' - } - }, - body: '{}' # We don't care about the response - ) - end - - let!(:tube_state_change_request_1) do - stub_api_post( - 'state_changes', - payload: { - 'state_change' => { - user: user_uuid, - target: destination_tubes[1].uuid, - target_state: 'passed' - } - }, - body: '{}' # We don't care about the response - ) + before do + stub_api_v2_post('Transfer', transfer) + stub_api_v2_post('StateChange') end - before { stub_api_v2_post('Transfer', transfer) } - it 'pools by submission' do expect_api_v2_posts( 'Transfer', @@ -74,13 +49,20 @@ end it 'passes the tubes automatically' do + expect_api_v2_posts( + 'StateChange', + [ + { target_state: 'passed', target_uuid: destination_tubes[0].uuid, user_uuid: user_uuid }, + { target_state: 'passed', target_uuid: destination_tubes[1].uuid, user_uuid: user_uuid } + ] + ) + subject.save! - expect(tube_state_change_request_0).to have_been_made.once - expect(tube_state_change_request_1).to have_been_made.once end it 'redirects to the parent plate' do subject.save! + expect(subject.redirection_target.uuid).to eq(parent_uuid) end end diff --git a/spec/models/labware_creators/tagged_plate_spec.rb b/spec/models/labware_creators/tagged_plate_spec.rb index 90f20b9e2..2926c706d 100644 --- a/spec/models/labware_creators/tagged_plate_spec.rb +++ b/spec/models/labware_creators/tagged_plate_spec.rb @@ -221,14 +221,26 @@ ] ) + expect_api_v2_posts( + 'StateChange', + [ + { + reason: 'Used in Library creation', + target_state: 'exhausted', + target_uuid: tag_plate_uuid, + user_uuid: user_uuid + } + ] + ) + expect(subject.save).to be true - expect(state_change_tag_plate_request).to have_been_made.once expect(plate_conversion_request).to have_been_made.once expect(tag_layout_creation_request).to have_been_made.once end it 'has the correct child (and uuid)' do stub_api_v2_post('Transfer') + stub_api_v2_post('StateChange') expect(subject.save).to be true expect(subject.child.uuid).to eq(tag_plate_uuid) diff --git a/spec/models/robots/plate_to_tube_racks_robot_spec.rb b/spec/models/robots/plate_to_tube_racks_robot_spec.rb index fe4e77b9a..0955e4dd9 100644 --- a/spec/models/robots/plate_to_tube_racks_robot_spec.rb +++ b/spec/models/robots/plate_to_tube_racks_robot_spec.rb @@ -355,40 +355,29 @@ end describe '#perform_transfer' do - let(:state_change_requests) do - tube_uuids.map do |tube_uuid| - stub_api_post( - 'state_changes', - payload: { - state_change: { - target_state: 'passed', - reason: "Robot #{robot_name} started", - customer_accepts_responsibility: false, - target: tube_uuid, - user: user_uuid, - contents: nil - } - }, - body: json(:state_change, target_state: 'passed') - ) - end - end - before do # Create purpose configs in Settings for state changers. create(:purpose_config, uuid: plate_purpose_uuid, name: plate_purpose_name) create(:purpose_config, uuid: tube_purpose1_uuid, name: tube_purpose1_name) create(:purpose_config, uuid: tube_purpose2_uuid, name: tube_purpose2_name) - - # Stub state change requests to the Sequencescape API; one for each tube on tube-racks. - state_change_requests end it 'performs transfers for all tubes on the tube-racks' do - robot.perform_transfer(scanned_layout) + expect_api_v2_posts( + 'StateChange', + tube_uuids.map do |tube_uuid| + { + contents: nil, + customer_accepts_responsibility: false, + reason: "Robot #{robot_name} started", + target_state: 'passed', + target_uuid: tube_uuid, + user_uuid: user_uuid + } + end + ) - expect(state_change_requests[0]).to have_been_requested - tube_uuids.each_with_index { |_tube_uuid, index| expect(state_change_requests[index]).to have_been_requested } + robot.perform_transfer(scanned_layout) end end end diff --git a/spec/models/robots/pooling_and_splitting_robot_spec.rb b/spec/models/robots/pooling_and_splitting_robot_spec.rb index 0d5559a99..355883d39 100644 --- a/spec/models/robots/pooling_and_splitting_robot_spec.rb +++ b/spec/models/robots/pooling_and_splitting_robot_spec.rb @@ -354,40 +354,6 @@ end describe '#perform_transfer' do - let(:state_change_target_1_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - target_state: 'passed', - reason: 'Robot Pooling And Splitting Robot started', - customer_accepts_responsibility: false, - target: target_plate_1_uuid, - user: user_uuid, - contents: nil - } - }, - body: json(:state_change, target_state: 'passed') - ) - end - - let(:state_change_target_2_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - target_state: 'passed', - reason: 'Robot Pooling And Splitting Robot started', - customer_accepts_responsibility: false, - target: target_plate_2_uuid, - user: user_uuid, - contents: nil - } - }, - body: json(:state_change, target_state: 'passed') - ) - end - let(:scanned_layout) do { 'bed1_barcode' => [source_1_barcode], @@ -396,15 +362,30 @@ } end - before do - state_change_target_1_request - state_change_target_2_request - end - it 'performs transfers from started to passed for all destination plates' do + expect_api_v2_posts( + 'StateChange', + [ + { + contents: nil, + customer_accepts_responsibility: false, + reason: 'Robot Pooling And Splitting Robot started', + target_state: 'passed', + target_uuid: target_plate_1_uuid, + user_uuid: user_uuid + }, + { + contents: nil, + customer_accepts_responsibility: false, + reason: 'Robot Pooling And Splitting Robot started', + target_state: 'passed', + target_uuid: target_plate_2_uuid, + user_uuid: user_uuid + } + ] + ) + robot.perform_transfer(scanned_layout) - expect(state_change_target_1_request).to have_been_requested - expect(state_change_target_2_request).to have_been_requested end end end diff --git a/spec/models/robots/pooling_robot_spec.rb b/spec/models/robots/pooling_robot_spec.rb index d5270464d..ae8fa0854 100644 --- a/spec/models/robots/pooling_robot_spec.rb +++ b/spec/models/robots/pooling_robot_spec.rb @@ -212,28 +212,22 @@ end describe '#perform_transfer' do - let(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - target_state: 'passed', - reason: 'Robot Pooling Robot started', + it 'performs transfer from started to passed' do + expect_api_v2_posts( + 'StateChange', + [ + { + contents: nil, customer_accepts_responsibility: false, - target: target_plate_uuid, - user: user_uuid, - contents: nil + reason: 'Robot Pooling Robot started', + target_state: 'passed', + target_uuid: target_plate_uuid, + user_uuid: user_uuid } - }, - body: json(:state_change, target_state: 'passed') + ] ) - end - before { state_change_request } - - it 'performs transfer from started to passed' do robot.perform_transfer('bed1_barcode' => [source_barcode], 'bed5_barcode' => [target_barcode]) - expect(state_change_request).to have_been_requested end context 'if the bed is unexpectedly invalid' do diff --git a/spec/models/robots/quadrant_robot_spec.rb b/spec/models/robots/quadrant_robot_spec.rb index 058182b05..8badd8386 100644 --- a/spec/models/robots/quadrant_robot_spec.rb +++ b/spec/models/robots/quadrant_robot_spec.rb @@ -262,28 +262,22 @@ end describe '#perform_transfer' do - let(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - target_state: 'passed', - reason: 'Robot Pooling Robot started', + it 'performs transfer from started to passed' do + expect_api_v2_posts( + 'StateChange', + [ + { + contents: nil, customer_accepts_responsibility: false, - target: target_plate_uuid, - user: user_uuid, - contents: nil + reason: 'Robot Pooling Robot started', + target_state: 'passed', + target_uuid: target_plate_uuid, + user_uuid: user_uuid } - }, - body: json(:state_change, target_state: 'passed') + ] ) - end - before { state_change_request } - - it 'performs transfer from started to passed' do robot.perform_transfer('bed1_barcode' => [source_barcode], 'bed5_barcode' => [target_barcode]) - expect(state_change_request).to have_been_requested end end end diff --git a/spec/models/robots/robot_spec.rb b/spec/models/robots/robot_spec.rb index e59b78aa9..5d3fe1c43 100644 --- a/spec/models/robots/robot_spec.rb +++ b/spec/models/robots/robot_spec.rb @@ -714,23 +714,6 @@ end let(:target_plate_state) { 'started' } - let(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - target_state: 'passed', - reason: 'Robot bravo LB End Prep started', - customer_accepts_responsibility: false, - target: plate.uuid, - user: user_uuid, - contents: nil - } - }, - body: json(:state_change, target_state: 'passed') - ) - end - let(:plate) do create :v2_plate, barcode_number: '123', @@ -741,13 +724,25 @@ before do create :purpose_config, uuid: 'lb_end_prep_uuid', state_changer_class: 'StateChangers::DefaultStateChanger' - state_change_request bed_labware_lookup(plate) end it 'performs transfer from started to passed' do + expect_api_v2_posts( + 'StateChange', + [ + { + contents: nil, + customer_accepts_responsibility: false, + reason: 'Robot bravo LB End Prep started', + target_state: 'passed', + target_uuid: plate.uuid, + user_uuid: user_uuid + } + ] + ) + robot.perform_transfer('580000014851' => [plate.human_barcode]) - expect(state_change_request).to have_been_requested end context 'if the bed is unexpectedly invalid' do diff --git a/spec/models/robots/splitting_robot_spec.rb b/spec/models/robots/splitting_robot_spec.rb index cd7c381b3..7f8e5995f 100644 --- a/spec/models/robots/splitting_robot_spec.rb +++ b/spec/models/robots/splitting_robot_spec.rb @@ -143,23 +143,6 @@ } end - let(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - target_state: 'passed', - reason: 'Robot bravo LB End Prep started', - customer_accepts_responsibility: false, - target: plate.uuid, - user: user_uuid, - contents: nil - } - }, - body: json(:state_change, target_state: 'passed') - ) - end - let(:plate) do create :v2_plate, barcode_number: '123', @@ -170,13 +153,25 @@ before do create :purpose_config, uuid: 'lb_end_prep_uuid', state_changer_class: 'StateChangers::DefaultStateChanger' - state_change_request bed_plate_lookup(plate, [:purpose, { wells: :downstream_plates }]) end it 'performs transfer from started to passed' do + expect_api_v2_posts( + 'StateChange', + [ + { + contents: nil, + customer_accepts_responsibility: false, + reason: 'Robot bravo LB End Prep started', + target_state: 'passed', + target_uuid: plate.uuid, + user_uuid: user_uuid + } + ] + ) + robot.perform_transfer('580000014851' => [plate.human_barcode]) - expect(state_change_request).to have_been_requested end end end diff --git a/spec/models/state_changers_spec.rb b/spec/models/state_changers_spec.rb index 918986438..702c30543 100644 --- a/spec/models/state_changers_spec.rb +++ b/spec/models/state_changers_spec.rb @@ -15,13 +15,19 @@ subject { StateChangers::DefaultStateChanger.new(api, plate_uuid, user_uuid) } describe '#move_to!' do - let!(:state_change_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: expected_parameters - }, - body: '{}' # We don't care + before do + expect_api_v2_posts( + 'StateChange', + [ + { + contents: wells_to_pass, + customer_accepts_responsibility: customer_accepts_responsibility, + reason: reason, + target_state: target_state, + target_uuid: plate_uuid, + user_uuid: user_uuid + } + ] ) end @@ -31,17 +37,6 @@ end end - let(:expected_parameters) do - { - target: plate_uuid, - user: user_uuid, - target_state: target_state, - reason: reason, - customer_accepts_responsibility: customer_accepts_responsibility, - contents: wells_to_pass - } - end - context 'on a fully pending plate' do let(:plate_state) { 'pending' } let(:target_state) { 'passed' } @@ -144,7 +139,5 @@ end end end - - after { expect(state_change_request).to have_been_made.once } end end diff --git a/spec/support/shared_tagging_examples.rb b/spec/support/shared_tagging_examples.rb index 84893b202..44037b2b0 100644 --- a/spec/support/shared_tagging_examples.rb +++ b/spec/support/shared_tagging_examples.rb @@ -1,22 +1,6 @@ # frozen_string_literal: true RSpec.shared_context 'a tag plate creator' do - # Requests that might get made - let!(:state_change_tag_plate_request) do - stub_api_post( - 'state_changes', - payload: { - state_change: { - user: user_uuid, - target: tag_plate_uuid, - reason: 'Used in Library creation', - target_state: 'exhausted' - } - }, - body: json(:state_change) - ) - end - let!(:plate_conversion_request) do stub_api_post( 'plate_conversions', From 130099e09921ce5e2b2e0812bbbf3c73fe0d80e7 Mon Sep 17 00:00:00 2001 From: Stuart McHattie Date: Wed, 4 Sep 2024 17:11:27 +0100 Subject: [PATCH 64/70] Add new API v2 endpoints to resources.js --- app/frontend/javascript/shared/resources.js | 289 +++++++++++++++----- 1 file changed, 223 insertions(+), 66 deletions(-) diff --git a/app/frontend/javascript/shared/resources.js b/app/frontend/javascript/shared/resources.js index 5f73dc2ff..0803f7082 100644 --- a/app/frontend/javascript/shared/resources.js +++ b/app/frontend/javascript/shared/resources.js @@ -1,6 +1,6 @@ /* - * Auto-generated by Sequencescape on 2024-07-25 15:16:51 +0100" - * Using Y24-190-2-support-limber-labware-metadata-in-api-v2@6466af5 + * Auto-generated by Sequencescape on 2024-09-04 17:09:09 +0100" + * Using develop-Y24-190@8b0e5a6 * bundle exec rake devour:create_config" * */ @@ -94,6 +94,71 @@ const resources = [ "options": { } }, + { + "resource": "between_plate_and_tube", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, + { + "resource": "between_plate", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, + { + "resource": "between_plates_by_submission", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, + { + "resource": "between_specific_tube", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, + { + "resource": "between_tubes_by_submission", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, { "resource": "comment", "attributes": { @@ -123,6 +188,71 @@ const resources = [ "options": { } }, + { + "resource": "from_plate_to_specific_tube", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, + { + "resource": "from_plate_to_specific_tubes_by_pool", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, + { + "resource": "from_plate_to_tube_by_multiplex", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, + { + "resource": "from_plate_to_tube_by_submission", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, + { + "resource": "from_plate_to_tube", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, { "resource": "labware", "attributes": { @@ -212,6 +342,20 @@ const resources = [ "options": { } }, + { + "resource": "lot_type", + "attributes": { + "uuid": "", + "name": "", + "template_type": "", + "target_purpose": { + "jsonApi": "hasOne", + "type": "purpose" + } + }, + "options": { + } + }, { "resource": "lot", "attributes": { @@ -236,20 +380,6 @@ const resources = [ "options": { } }, - { - "resource": "lot_type", - "attributes": { - "uuid": "", - "name": "", - "template_type": "", - "target_purpose": { - "jsonApi": "hasOne", - "type": "purpose" - } - }, - "options": { - } - }, { "resource": "order", "attributes": { @@ -287,6 +417,14 @@ const resources = [ "options": { } }, + { + "resource": "plate_template", + "attributes": { + "uuid": "" + }, + "options": { + } + }, { "resource": "plate", "attributes": { @@ -363,20 +501,15 @@ const resources = [ } }, { - "resource": "plate_template", + "resource": "poly_metadatum", "attributes": { - "uuid": "" - }, - "options": { - } - }, - { - resource: "purpose", - attributes: { - uuid: "", - name: "", - size: "", - lifespan: "" + "key": "", + "value": "", + "created_at": "", + "updated_at": "", + "metadatable": { + "jsonApi": "hasOne" + } }, "options": { } @@ -567,6 +700,17 @@ const resources = [ "options": { } }, + { + "resource": "request_type", + "attributes": { + "uuid": "", + "name": "", + "key": "", + "for_multiplexing": "" + }, + "options": { + } + }, { "resource": "request", "attributes": { @@ -604,17 +748,6 @@ const resources = [ "options": { } }, - { - "resource": "request_type", - "attributes": { - "uuid": "", - "name": "", - "key": "", - "for_multiplexing": "" - }, - "options": { - } - }, { "resource": "sample_manifest", "attributes": { @@ -626,13 +759,14 @@ const resources = [ { "resource": "sample_metadata", "attributes": { - "sample_common_name": "", - "supplier_name": "", - "collected_by": "", "cohort": "", - "sample_description": "", - "donor_id": "", + "collected_by": "", "concentration": "", + "donor_id": "", + "gender": "", + "sample_common_name": "", + "sample_description": "", + "supplier_name": "", "volume": "" }, "options": { @@ -669,11 +803,19 @@ const resources = [ { "resource": "state_change", "attributes": { + "contents": "", + "customer_accepts_responsibility": "", "previous_state": "", + "reason": "", "target_state": "", - "created_at": "", - "updated_at": "", - "labware": { + "target_uuid": "", + "user_uuid": "", + "uuid": "", + "user": { + "jsonApi": "hasOne", + "type": "user" + }, + "target": { "jsonApi": "hasOne", "type": "labware" } @@ -695,24 +837,24 @@ const resources = [ } }, { - "resource": "submission", + "resource": "submission_template", "attributes": { - "uuid": "", "name": "", - "state": "", - "created_at": "", - "updated_at": "", - "used_tags": "", - "lanes_of_sequencing": "" + "uuid": "" }, "options": { } }, { - "resource": "submission_template", + "resource": "submission", "attributes": { + "uuid": "", "name": "", - "uuid": "" + "state": "", + "created_at": "", + "updated_at": "", + "used_tags": "", + "lanes_of_sequencing": "" }, "options": { } @@ -747,6 +889,7 @@ const resources = [ "resource": "tag_layout_template", "attributes": { "uuid": "", + "name": "", "direction": "", "walking_by": "", "tag_group": { @@ -805,12 +948,34 @@ const resources = [ "options": { } }, + { + "resource": "transfer", + "attributes": { + "uuid": "", + "source_uuid": "", + "destination_uuid": "", + "user_uuid": "", + "transfers": "", + "transfer_template_uuid": "" + }, + "options": { + } + }, { "resource": "tube_purpose", "attributes": { "name": "", "purpose_type": "", - "target_type": "" + "target_type": "", + "uuid": "" + }, + "options": { + } + }, + { + "resource": "tube_rack_status", + "attributes": { + "uuid": "" }, "options": { } @@ -843,14 +1008,6 @@ const resources = [ "options": { } }, - { - "resource": "tube_rack_status", - "attributes": { - "uuid": "" - }, - "options": { - } - }, { "resource": "tube", "attributes": { From 9cdcba411a8d7787925756d6083b748427a2a32c Mon Sep 17 00:00:00 2001 From: sabrine33 Date: Mon, 9 Sep 2024 14:10:39 +0100 Subject: [PATCH 65/70] set qc threshold of LRC PBMC Pools to 70% --- config/purposes/scrna_core_cdna_prep.wip.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/purposes/scrna_core_cdna_prep.wip.yml b/config/purposes/scrna_core_cdna_prep.wip.yml index 6cf16fa7c..b2d762791 100644 --- a/config/purposes/scrna_core_cdna_prep.wip.yml +++ b/config/purposes/scrna_core_cdna_prep.wip.yml @@ -45,6 +45,10 @@ LRC PBMC Defrost PBS: LRC PBMC Pools: :asset_type: plate :label_template: plate_quad_qc # creates QC4 barcodes + :qc_thresholds: + viability: + units: '%' + default_threshold: 70 :presenter_class: name: Presenters::DonorPoolingPlatePresenter args: From ef2802e38cbe446dba776e2ea2dc263db0327a0b Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 19:00:16 +0000 Subject: [PATCH 66/70] Update postcss to version 8.4.47 --- package.json | 2 +- yarn.lock | 39 +++++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index f11d1bd0d..492cfe5da 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "eslint-plugin-vitest": "^0.5.4", "eslint-plugin-vue": "^9.0.0", "jsdom": "^24.1.1", - "postcss": "^8.4.39", + "postcss": "^8.4.47", "postcss-flexbugs-fixes": "^5.0.2", "postcss-import": "16.1.0", "postcss-nested": "^6.0.1", diff --git a/yarn.lock b/yarn.lock index 96d041cfd..a5ce32da1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2440,6 +2440,11 @@ picocolors@^1.0.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -2787,6 +2792,15 @@ postcss@^8.4.39: picocolors "^1.0.1" source-map-js "^1.2.0" +postcss@^8.4.47: + version "8.4.47" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" + integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.0" + source-map-js "^1.2.1" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -3025,6 +3039,11 @@ source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -3040,16 +3059,7 @@ std-env@^3.7.0: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3067,14 +3077,7 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== From ccdab1b33fe55757d4d11ffc82ea45263f8def0f Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 18 Sep 2024 10:46:11 +0100 Subject: [PATCH 67/70] fix: restore removed data-plate-views --- app/frontend/javascript/legacy_scripts_a.js | 4 ++++ app/views/labware/_tube.html.erb | 6 +++--- app/views/labware/plates/_binned_summary.html.erb | 4 ++-- app/views/labware/plates/_standard_summary.html.erb | 2 +- app/views/plates/_common_tabbed_pages.html.erb | 8 ++++---- app/views/tube_racks/summaries/_default.html.erb | 4 ++-- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/frontend/javascript/legacy_scripts_a.js b/app/frontend/javascript/legacy_scripts_a.js index 0ae1c6cd2..392a1766b 100644 --- a/app/frontend/javascript/legacy_scripts_a.js +++ b/app/frontend/javascript/legacy_scripts_a.js @@ -1,6 +1,10 @@ import $ from 'jquery' import { ENTER_KEYCODE, TAB_KEYCODE } from '@/javascript/lib/keycodes.js' +// The majority of the code below is for the data-plate-view data attribute used to +// show differing colours based on the view selected, eg: pools, binning, etc. +// The pattern is to have a data-plate-view attribute on all tab links, but only have the +// required views defined below. This allows for easy extension of the views in the future. let PlateViewModel = function (plateElement) { this['pools-view'] = { activate: function () { diff --git a/app/views/labware/_tube.html.erb b/app/views/labware/_tube.html.erb index 7737f0037..0761895ce 100644 --- a/app/views/labware/_tube.html.erb +++ b/app/views/labware/_tube.html.erb @@ -5,13 +5,13 @@ diff --git a/app/views/labware/plates/_binned_summary.html.erb b/app/views/labware/plates/_binned_summary.html.erb index 3a3aa44c1..5cc9dc0b5 100644 --- a/app/views/labware/plates/_binned_summary.html.erb +++ b/app/views/labware/plates/_binned_summary.html.erb @@ -4,10 +4,10 @@ <%= content_for :additional_tabs do %> <% end %> diff --git a/app/views/labware/plates/_standard_summary.html.erb b/app/views/labware/plates/_standard_summary.html.erb index 476273c3d..c40cde900 100644 --- a/app/views/labware/plates/_standard_summary.html.erb +++ b/app/views/labware/plates/_standard_summary.html.erb @@ -4,7 +4,7 @@ <%= content_for :additional_tabs do %> <% end %> diff --git a/app/views/plates/_common_tabbed_pages.html.erb b/app/views/plates/_common_tabbed_pages.html.erb index 9c2a83a3e..da3e694b6 100644 --- a/app/views/plates/_common_tabbed_pages.html.erb +++ b/app/views/plates/_common_tabbed_pages.html.erb @@ -1,10 +1,10 @@ diff --git a/app/views/tube_racks/summaries/_default.html.erb b/app/views/tube_racks/summaries/_default.html.erb index b3af981ae..d8d8b7107 100644 --- a/app/views/tube_racks/summaries/_default.html.erb +++ b/app/views/tube_racks/summaries/_default.html.erb @@ -5,10 +5,10 @@ From c957c0d4f245ffe7bb86c3721cc2b95b787335b4 Mon Sep 17 00:00:00 2001 From: yoldas Date: Wed, 18 Sep 2024 13:18:20 +0100 Subject: [PATCH 68/70] Add TSISC_UDI96 and TSRNAhWGS_UDI96 to LCMT EM Lib PCR config --- config/purposes/lcm_triomics.wip.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/purposes/lcm_triomics.wip.yml b/config/purposes/lcm_triomics.wip.yml index 2f2eaad3f..289e8a979 100644 --- a/config/purposes/lcm_triomics.wip.yml +++ b/config/purposes/lcm_triomics.wip.yml @@ -67,6 +67,8 @@ LCMT EM Lib PCR: - TS_pWGSC_UDI96 - TS_pWGSC_UDI_tag60_61_swap - TS_pWGSD_UDI96 + - TSISC_UDI96 + - TSRNAhWGS_UDI96 :size: 96 LCMT EM PCR XP: :asset_type: plate From c51a3fabbcfbae88202a242e522d13efe9c578bc Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Thu, 19 Sep 2024 10:14:33 +0100 Subject: [PATCH 69/70] build: change eslint formatter to not use the buggy stylish https://github.com/eslint/eslint/discussions/17215#discussioncomment-7884848 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 492cfe5da..2806eed4f 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "name": "limber", "scripts": { "dev": "vite dev", - "lint": "eslint --ext .js --ext .vue app/frontend", + "lint": "eslint --ext .js --ext .vue app/frontend --format compact", "test": "vitest run", "coverage": "vitest run --coverage", "lintOnly": "eslint --ext .js --ext .vue" From ea5e7420514dda58d12f8aaf730d5a5aeb3ae236 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Fri, 20 Sep 2024 12:15:09 +0100 Subject: [PATCH 70/70] release: bump patch version --- .release-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.release-version b/.release-version index 85fb8434f..80477f926 100644 --- a/.release-version +++ b/.release-version @@ -1 +1 @@ -3.59.2 +3.59.3