-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4275 from sanger/y24-234-update-missing-event-his…
…tory-records Y24 234 update missing event history records
- Loading branch information
Showing
7 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# frozen_string_literal: true | ||
|
||
# Rails task to add missing asset audit records from a CSV file | ||
namespace :asset_audit do | ||
# This rake task is used to add missing asset audit records from a CSV file. | ||
# If there are any errors in the CSV file, no records will be inserted. | ||
# Usage: rails asset_audit:add_missing_records['/path/to/file.csv'] | ||
# The CSV file should have the following headers: | ||
# barcode, message, created_by, created_at | ||
# The message column should have one of the following values: | ||
# 'Destroying location', 'Destroying labware' | ||
|
||
desc 'Add missing asset audit records' | ||
task :add_missing_records, [:file_path] => :environment do |_, args| | ||
required_csv_headers = %w[barcode message created_by created_at] | ||
|
||
# Check if the file path is provided and valid | ||
file_path = args[:file_path] == 'nil' ? nil : args[:file_path] | ||
raise 'Please provide a valid file path' if file_path.nil? || !File.exist?(file_path) | ||
|
||
# Read the CSV file and validate the headers | ||
begin | ||
csv_data = CSV.read(file_path, headers: true) | ||
rescue StandardError => e | ||
raise "Failed to read CSV file: #{e.message}" | ||
end | ||
|
||
unless csv_data.headers.length == required_csv_headers.length | ||
raise 'Failed to read CSV file: Invalid number of header columns.' | ||
end | ||
|
||
# Process the CSV data and create asset audit records data array to insert | ||
asset_audit_data = [] | ||
csv_data.each do |row| | ||
missing_columns = required_csv_headers.select { |header| row[header].nil? } | ||
|
||
# Check if any of the required columns are missing | ||
raise 'Failed to read CSV file: Missing columns.' unless missing_columns.empty? | ||
|
||
# Find the asset by barcode | ||
asset = Labware.find_by_barcode(row['barcode'].strip) | ||
raise "Asset with barcode #{row['barcode']} not found." if asset.nil? | ||
|
||
# Check if the message is valid | ||
key = | ||
case row['message'] | ||
when 'Destroying location' | ||
'destroy_location' | ||
when 'Destroying labware' | ||
'destroy_labware' | ||
end | ||
|
||
raise "Invalid message for asset with barcode #{row['barcode']}." if key.nil? | ||
|
||
# Create the asset audit record data | ||
data = { | ||
asset_id: asset.id, | ||
created_by: row['created_by'], | ||
created_at: row['created_at'], | ||
message: "Process '#{row['message']}' performed on instrument Destroying instrument", | ||
key: key | ||
} | ||
asset_audit_data << data | ||
end | ||
|
||
# Insert the asset audit records | ||
ActiveRecord::Base.transaction do | ||
asset_audit_data.each do |data| | ||
AssetAudit.create!( | ||
message: data[:message], | ||
created_by: data[:created_by], | ||
created_at: data[:created_at], | ||
asset_id: data[:asset_id], | ||
key: data[:key] | ||
) | ||
end | ||
puts 'All records successfully inserted.' | ||
rescue ActiveRecord::ActiveRecordError => e | ||
puts "Failed to insert records: #{e.message}" | ||
raise ActiveRecord::Rollback | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
barcode,message,created_by,created_at | ||
SQPD-9002;"Destroying location;User1,2021-01-01 12:00:00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
barcode,message,created_by,created_at | ||
SQPD-1,Destroying test,User1,2021-01-01 12:00:00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
barcode,message,created_by,created_at | ||
SQPD-1,Destroying location,2021-01-01 12:00:00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
barcode,created_by,created_at | ||
SQPD-1,Destroying location,2021-01-01 12:00:00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
barcode,message,created_by,created_at | ||
SQPD-1,Destroying location,User1,2021-01-01 12:00:00 | ||
SQPD-2,Destroying labware,User2,2021-01-02 12:00:00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
|
||
RSpec.describe 'asset_audit:add_missing_records', type: :task do | ||
before do | ||
Rake.application.rake_require 'tasks/add_missing_asset_audit_records' | ||
Rake::Task.define_task(:environment) | ||
end | ||
|
||
context 'when an invalid file path is given' do | ||
let(:run_rake_task) do | ||
Rake::Task['asset_audit:add_missing_records'].reenable | ||
Rake.application.invoke_task('asset_audit:add_missing_records[nil]') | ||
end | ||
|
||
it 'outputs an error message and returns' do | ||
expect { run_rake_task }.to raise_error(RuntimeError, /Please provide a valid file path/) | ||
end | ||
end | ||
|
||
describe 'invalid csv file' do | ||
context 'when csv has a bad format' do | ||
let(:file_path) { 'spec/data/asset_audits/bad_format.csv' } | ||
let(:run_rake_task) do | ||
Rake::Task['asset_audit:add_missing_records'].reenable | ||
Rake.application.invoke_task("asset_audit:add_missing_records[#{file_path}]") | ||
end | ||
|
||
it 'outputs an error message and return' do | ||
expect { run_rake_task }.to raise_error(RuntimeError, /Failed to read CSV file/) | ||
end | ||
end | ||
|
||
context 'when csv columns are mising' do | ||
let(:file_path) { 'spec/data/asset_audits/missing_column.csv' } | ||
let(:run_rake_task) do | ||
Rake::Task['asset_audit:add_missing_records'].reenable | ||
Rake.application.invoke_task("asset_audit:add_missing_records[#{file_path}]") | ||
end | ||
|
||
it 'outputs an error message and return' do | ||
expect { run_rake_task }.to raise_error(RuntimeError, 'Failed to read CSV file: Missing columns.') | ||
end | ||
end | ||
|
||
context 'when csv with no header given' do | ||
let(:file_path) { 'spec/data/asset_audits/missing_header.csv' } | ||
let(:run_rake_task) do | ||
Rake::Task['asset_audit:add_missing_records'].reenable | ||
Rake.application.invoke_task("asset_audit:add_missing_records[#{file_path}]") | ||
end | ||
|
||
it 'outputs an error message and return' do | ||
expect { run_rake_task }.to raise_error(/Failed to read CSV file: Invalid number of header columns./) | ||
end | ||
end | ||
end | ||
|
||
describe 'valid csv file' do | ||
context 'when asset with barcode is not found' do | ||
let(:file_path) { 'spec/data/asset_audits/valid_data.csv' } | ||
let(:run_rake_task) do | ||
Rake::Task['asset_audit:add_missing_records'].reenable | ||
Rake.application.invoke_task("asset_audit:add_missing_records[#{file_path}]") | ||
end | ||
|
||
it 'does not add records if there is any invalid data' do | ||
create(:plate, barcode: 'SQPD-1') | ||
|
||
expect { run_rake_task }.to raise_error(RuntimeError, 'Asset with barcode SQPD-2 not found.') | ||
end | ||
end | ||
|
||
context 'when message column is invalid' do | ||
let(:file_path) { 'spec/data/asset_audits/invalid_message.csv' } | ||
let(:run_rake_task) do | ||
Rake::Task['asset_audit:add_missing_records'].reenable | ||
Rake.application.invoke_task("asset_audit:add_missing_records[#{file_path}]") | ||
end | ||
|
||
it 'does not add records if there is any invalid data' do | ||
create(:plate, barcode: 'SQPD-1') | ||
|
||
expect { run_rake_task }.to raise_error(RuntimeError, 'Invalid message for asset with barcode SQPD-1.') | ||
end | ||
end | ||
|
||
context 'when all data is good' do | ||
let(:file_path) { 'spec/data/asset_audits/valid_data.csv' } | ||
let(:run_rake_task) do | ||
Rake::Task['asset_audit:add_missing_records'].reenable | ||
Rake.application.invoke_task("asset_audit:add_missing_records[#{file_path}]") | ||
end | ||
|
||
it 'adds missing asset audit records' do | ||
plate1 = create(:plate, barcode: 'SQPD-1') | ||
plate2 = create(:plate, barcode: 'SQPD-2') | ||
|
||
expect { run_rake_task }.to output(/All records successfully inserted./).to_stdout | ||
|
||
expect( | ||
AssetAudit.where( | ||
asset_id: plate1.id, | ||
key: 'destroy_location', | ||
message: "Process 'Destroying location' performed on instrument Destroying instrument" | ||
) | ||
).to exist | ||
|
||
expect( | ||
AssetAudit.where( | ||
asset_id: plate2.id, | ||
key: 'destroy_labware', | ||
message: "Process 'Destroying labware' performed on instrument Destroying instrument" | ||
) | ||
).to exist | ||
end | ||
end | ||
|
||
context 'when there is a failed transaction' do | ||
let(:file_path) { 'spec/data/asset_audits/valid_data.csv' } | ||
let(:run_rake_task) do | ||
Rake::Task['asset_audit:add_missing_records'].reenable | ||
Rake.application.invoke_task("asset_audit:add_missing_records[#{file_path}]") | ||
end | ||
|
||
it 'rolls back transaction when there is an error in inserting records' do | ||
create(:plate, barcode: 'SQPD-1') | ||
create(:plate, barcode: 'SQPD-2') | ||
allow(AssetAudit).to receive(:create!).and_raise(ActiveRecord::ActiveRecordError, 'Test error') | ||
|
||
expect { run_rake_task }.to output(/Failed to insert records: Test error/).to_stdout | ||
end | ||
end | ||
end | ||
end |