From 779903530186622f493a06f7fd7020c45c76e458 Mon Sep 17 00:00:00 2001 From: Justin Coyne Date: Fri, 12 Apr 2019 15:03:03 -0500 Subject: [PATCH 1/2] Remove ShelvingService It was moved into CommonAccessioning --- .rubocop_todo.yml | 68 ++++------ lib/dor-services.rb | 1 - lib/dor/services/shelving_service.rb | 69 ---------- spec/services/shelving_service_spec.rb | 179 ------------------------- 4 files changed, 27 insertions(+), 290 deletions(-) delete mode 100644 lib/dor/services/shelving_service.rb delete mode 100644 spec/services/shelving_service_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 0dd385a8..54010644 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2019-04-11 09:11:29 -0500 using RuboCop version 0.65.0. +# on 2019-04-12 15:02:20 -0500 using RuboCop version 0.65.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -54,7 +54,7 @@ Lint/Void: Exclude: - 'lib/dor/models/concerns/identifiable.rb' -# Offense count: 69 +# Offense count: 63 Metrics/AbcSize: Max: 106 @@ -63,11 +63,11 @@ Metrics/AbcSize: Metrics/ClassLength: Max: 253 -# Offense count: 15 +# Offense count: 13 Metrics/CyclomaticComplexity: Max: 25 -# Offense count: 62 +# Offense count: 61 # Configuration parameters: CountComments, ExcludedMethods. Metrics/MethodLength: Max: 52 @@ -75,14 +75,14 @@ Metrics/MethodLength: # Offense count: 1 # Configuration parameters: CountComments. Metrics/ModuleLength: - Max: 128 + Max: 121 # Offense count: 1 # Configuration parameters: CountKeywordArgs. Metrics/ParameterLists: Max: 6 -# Offense count: 15 +# Offense count: 13 Metrics/PerceivedComplexity: Max: 25 @@ -161,25 +161,21 @@ Naming/VariableName: - 'spec/datastreams/content_metadata_ds_spec.rb' - 'spec/indexers/processable_indexer_spec.rb' -# Offense count: 11 +# Offense count: 1 # Configuration parameters: EnforcedStyle. # SupportedStyles: snake_case, normalcase, non_integer Naming/VariableNumber: Exclude: - - 'spec/services/cleanup_reset_service_spec.rb' - 'spec/services/cleanup_service_filesystem_spec.rb' -# Offense count: 24 +# Offense count: 6 RSpec/AnyInstance: Exclude: - 'spec/indexers/indexer_spec.rb' - 'spec/indexers/processable_indexer_spec.rb' - 'spec/models/concerns/embargoable_spec.rb' - - 'spec/models/concerns/versionable_spec.rb' - 'spec/models/workflow_object_spec.rb' - - 'spec/services/datastream_builder_spec.rb' - 'spec/services/public_xml_service_spec.rb' - - 'spec/services/publish_metadata_service_spec.rb' # Offense count: 22 RSpec/Be: @@ -187,20 +183,19 @@ RSpec/Be: - 'spec/datastreams/embargo_metadata_spec.rb' - 'spec/services/public_xml_service_spec.rb' -# Offense count: 9 +# Offense count: 8 RSpec/BeforeAfterAll: Exclude: - 'spec/spec_helper.rb' - 'spec/rails_helper.rb' - 'spec/support/**/*.rb' - - 'spec/services/cleanup_reset_service_spec.rb' - 'spec/services/cleanup_service_spec.rb' - 'spec/services/digital_stacks_service_spec.rb' - 'spec/services/metadata_service_spec.rb' - 'spec/services/suri_service_spec.rb' - 'spec/services/technical_metadata_service_spec.rb' -# Offense count: 43 +# Offense count: 33 # Configuration parameters: Prefixes. # Prefixes: when, with, without RSpec/ContextWording: @@ -222,29 +217,27 @@ RSpec/DescribedClass: Exclude: - 'spec/utils/sdr_client_spec.rb' -# Offense count: 178 +# Offense count: 159 # Configuration parameters: Max. RSpec/ExampleLength: Enabled: false -# Offense count: 28 +# Offense count: 11 RSpec/ExpectInHook: Exclude: - 'spec/datastreams/content_metadata_ds_spec.rb' - 'spec/services/metadata_service_spec.rb' - 'spec/services/public_desc_metadata_service_spec.rb' - 'spec/services/public_xml_service_spec.rb' - - 'spec/services/publish_metadata_service_spec.rb' - 'spec/services/sdr_ingest_service_spec.rb' - - 'spec/services/shelving_service_spec.rb' - 'spec/services/status_service_spec.rb' -# Offense count: 64 +# Offense count: 58 # Configuration parameters: CustomTransform, IgnoreMethods. RSpec/FilePath: Enabled: false -# Offense count: 709 +# Offense count: 539 # Configuration parameters: AssignmentOnly. RSpec/InstanceVariable: Enabled: false @@ -254,35 +247,34 @@ RSpec/MessageChain: Exclude: - 'spec/services/suri_service_spec.rb' -# Offense count: 134 -# Configuration parameters: EnforcedStyle. +# Offense count: 100 +# Configuration parameters: . # SupportedStyles: have_received, receive RSpec/MessageSpies: - Enabled: false + EnforcedStyle: receive # Offense count: 1 RSpec/MultipleDescribes: Exclude: - 'spec/services/digital_stacks_service_spec.rb' -# Offense count: 247 +# Offense count: 210 # Configuration parameters: AggregateFailuresByDefault. RSpec/MultipleExpectations: Max: 14 -# Offense count: 54 +# Offense count: 53 # Configuration parameters: IgnoreSharedExamples. RSpec/NamedSubject: Exclude: - 'spec/datastreams/default_object_rights_ds_spec.rb' - 'spec/models/admin_policy_object_spec.rb' - 'spec/models/collection_spec.rb' - - 'spec/services/shelving_service_spec.rb' - 'spec/services/thumbnail_service_spec.rb' -# Offense count: 26 +# Offense count: 17 RSpec/NestedGroups: - Max: 5 + Max: 4 # Offense count: 22 RSpec/RepeatedDescription: @@ -291,7 +283,7 @@ RSpec/RepeatedDescription: - 'spec/services/abiltiy_spec.rb' - 'spec/services/release_tag_service_spec.rb' -# Offense count: 21 +# Offense count: 19 RSpec/ScatteredLet: Exclude: - 'spec/indexers/describable_indexer_spec.rb' @@ -304,9 +296,8 @@ RSpec/ScatteredLet: - 'spec/models/workflow_document_spec.rb' - 'spec/services/public_desc_metadata_service_spec.rb' - 'spec/services/public_xml_service_spec.rb' - - 'spec/services/shelving_service_spec.rb' -# Offense count: 20 +# Offense count: 16 RSpec/ScatteredSetup: Exclude: - 'spec/datastreams/content_metadata_ds_spec.rb' @@ -315,12 +306,10 @@ RSpec/ScatteredSetup: - 'spec/models/concerns/governable_spec.rb' - 'spec/models/workflow_object_spec.rb' - 'spec/services/public_desc_metadata_service_spec.rb' - - 'spec/services/publish_metadata_service_spec.rb' - - 'spec/services/reset_workspace_service_spec.rb' - 'spec/services/search_service_spec.rb' - 'spec/services/suri_service_spec.rb' -# Offense count: 39 +# Offense count: 36 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: Enabled: false @@ -352,12 +341,11 @@ Style/ClassVars: - 'lib/dor/services/search_service.rb' - 'lib/dor/workflow/document.rb' -# Offense count: 3 +# Offense count: 2 Style/CommentedKeyword: Exclude: - 'lib/dor/datastreams/identity_metadata_ds.rb' - 'lib/dor/datastreams/rights_metadata_ds.rb' - - 'lib/dor/services/reset_workspace_service.rb' # Offense count: 1 # Cop supports --auto-correct. @@ -371,14 +359,13 @@ Style/ConditionalAssignment: Style/Documentation: Enabled: false -# Offense count: 9 +# Offense count: 8 # Configuration parameters: MinBodyLength. Style/GuardClause: Exclude: - 'lib/dor/datastreams/geo_metadata_ds.rb' - 'lib/dor/datastreams/version_metadata_ds.rb' - 'lib/dor/models/concerns/governable.rb' - - 'lib/dor/services/reset_workspace_service.rb' - 'lib/dor/services/sdr_ingest_service.rb' - 'lib/dor/services/technical_metadata_service.rb' - 'lib/dor/utils/predicate_patch.rb' @@ -400,7 +387,7 @@ Style/MultilineBlockChain: Style/NumericPredicate: Enabled: false -# Offense count: 28 +# Offense count: 27 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: @@ -410,7 +397,6 @@ Style/PercentLiteralDelimiters: - 'lib/dor/indexers/describable_indexer.rb' - 'lib/dor/services/cleanup_service.rb' - 'lib/dor/services/metadata_handlers/catalog_handler.rb' - - 'lib/dor/services/publish_metadata_service.rb' - 'spec/datastreams/events_ds_spec.rb' - 'spec/datastreams/geo_metadata_spec.rb' - 'spec/indexers/indexer_spec.rb' diff --git a/lib/dor-services.rb b/lib/dor-services.rb index 438cbde9..5391f852 100644 --- a/lib/dor-services.rb +++ b/lib/dor-services.rb @@ -139,7 +139,6 @@ def logger autoload :SdrIngestService autoload :SearchService autoload :SecondaryFileNameService - autoload :ShelvingService autoload :StatusService autoload :SuriService autoload :TagService diff --git a/lib/dor/services/shelving_service.rb b/lib/dor/services/shelving_service.rb deleted file mode 100644 index 596a14a7..00000000 --- a/lib/dor/services/shelving_service.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -module Dor - # Push file changes for shelve-able files into the stacks - class ShelvingService - def self.shelve(work) - new(work).shelve - end - - def initialize(work) - @work = work - end - - def shelve - # retrieve the differences between the current contentMetadata and the previously ingested version - diff = shelve_diff - stacks_object_pathname = stacks_location - # determine the location of the object's files in the stacks area - stacks_druid = DruidTools::StacksDruid.new work.id, stacks_object_pathname - stacks_object_pathname = Pathname(stacks_druid.path) - # determine the location of the object's content files in the workspace area - workspace_druid = DruidTools::Druid.new(work.id, Config.stacks.local_workspace_root) - workspace_content_pathname = workspace_content_dir(diff, workspace_druid) - # delete, rename, or copy files to the stacks area - DigitalStacksService.remove_from_stacks(stacks_object_pathname, diff) - DigitalStacksService.rename_in_stacks(stacks_object_pathname, diff) - DigitalStacksService.shelve_to_stacks(workspace_content_pathname, stacks_object_pathname, diff) - end - - private - - attr_reader :work - - # retrieve the differences between the current contentMetadata and the previously ingested version - # (filtering to select only the files that should be shelved to stacks) - def shelve_diff - raise Dor::ParameterError, 'Missing Dor::Config.stacks.local_workspace_root' if Config.stacks.local_workspace_root.nil? - raise Dor::Exception, 'Missing contentMetadata datastream' if work.contentMetadata.nil? - - client = Dor::Services::Client.object(work.pid).sdr - current_content = work.contentMetadata.content - inventory_diff = client.content_diff(current_content: current_content, subset: 'shelve') - inventory_diff.group_difference('content') - end - - # Find the location of the object's content files in the workspace area - # @param [Moab::FileGroupDifference] content_diff The differences between the current contentMetadata and the previously ingested version - # @param [DruidTools::Druid] workspace_druid the location of the object's files in the workspace area - # @return [Pathname] The location of the object's content files in the workspace area - def workspace_content_dir(content_diff, workspace_druid) - deltas = content_diff.file_deltas - filelist = deltas[:modified] + deltas[:added] + deltas[:copyadded].collect { |_old, new| new } - return nil if filelist.empty? - - Pathname(workspace_druid.find_filelist_parent('content', filelist)) - end - - # get the stack location based on the contentMetadata stacks attribute - # or using the default value from the config file if it doesn't exist - def stacks_location - return Config.stacks.local_stacks_root unless work.contentMetadata&.stacks.present? - - location = work.contentMetadata.stacks[0] - return location if location.start_with? '/' # Absolute stacks path - - raise "stacks attribute for item: #{work.id} contentMetadata should start with /. The current value is #{location}" - end - end -end diff --git a/spec/services/shelving_service_spec.rb b/spec/services/shelving_service_spec.rb deleted file mode 100644 index 247052dd..00000000 --- a/spec/services/shelving_service_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Dor::ShelvingService do - let(:shelvable_item) do - Class.new(ActiveFedora::Base) { include Dor::Itemizable } - end - - let!(:stacks_root) { Dir.mktmpdir } - let!(:workspace_root) { Dir.mktmpdir } - - before do - Dor::Config.push! { |c| c.stacks.local_stacks_root stacks_root } - Dor::Config.push! { |c| c.stacks.local_workspace_root workspace_root } - end - - after do - FileUtils.remove_entry stacks_root - FileUtils.remove_entry workspace_root - Dor::Config.pop! - end - - let(:work) { shelvable_item.new(pid: druid) } - let(:service) { described_class.new work } - - describe '.shelve' do - let(:druid) { 'druid:ng782rw8378' } - let(:mock_diff) { double(Moab::FileGroupDifference) } - let(:mock_workspace_path) { double(Pathname) } - - before do - allow(described_class).to receive(:new).and_return(service) - # stub the shelve_diff method which is unit tested below - expect(service).to receive(:shelve_diff).and_return(mock_diff) - # stub the workspace_content_dir method which is unit tested below - expect(service).to receive(:workspace_content_dir).with(mock_diff, an_instance_of(DruidTools::Druid)).and_return(mock_workspace_path) - end - - it 'pushes file changes for shelve-able files into the stacks' do - stacks_object_pathname = Pathname(DruidTools::StacksDruid.new(druid, stacks_root).path) - # make sure the DigitalStacksService is getting the correct delete, rename, and shelve requests - # (These methods are unit tested in digital_stacks_service_spec.rb) - expect(Dor::DigitalStacksService).to receive(:remove_from_stacks).with(stacks_object_pathname, mock_diff) - expect(Dor::DigitalStacksService).to receive(:rename_in_stacks).with(stacks_object_pathname, mock_diff) - expect(Dor::DigitalStacksService).to receive(:shelve_to_stacks).with(mock_workspace_path, stacks_object_pathname, mock_diff) - described_class.shelve(work) - end - end - - describe '#shelve_diff' do - subject(:result) { service.send(:shelve_diff) } - - let(:druid) { 'druid:jq937jp0017' } - - context 'when contentMetadata exists' do - before do - allow(Dor::Services::Client).to receive(:object).with(druid).and_return(object_client) - end - - let(:object_client) { instance_double(Dor::Services::Client::Object, sdr: sdr_client) } - let(:sdr_client) { instance_double(Dor::Services::Client::SDR, content_diff: inventory_diff) } - # read in a FileInventoryDifference manifest from the fixtures area - let(:xml_pathname) { Pathname('spec').join('fixtures', 'content_diff_reports', 'jq937jp0017-v1-v2.xml') } - let(:inventory_diff) { Moab::FileInventoryDifference.parse(xml_pathname.read) } - - it 'retrieves the differences between the current contentMetadata and the previously ingested version' do - expect(result.to_xml).to be_equivalent_to(<<-XML - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - XML - ) - end - end - - context 'when contentMetadata does not exist' do - it 'raises an error' do - work.datastreams.delete 'contentMetadata' - expect { result }.to raise_error(Dor::Exception) - end - end - end - - describe '#workspace_content_dir' do - subject { service.send(:workspace_content_dir, content_diff, workspace_druid) } - - let(:druid) { 'druid:jq937jp0017' } - let(:workspace_druid) { DruidTools::Druid.new(druid, Dor::Config.stacks.local_workspace_root) } - - # create an empty workspace location for object content files - let(:content_dir) { workspace_druid.path('content', true) } - - # read in a FileInventoryDifference manifest from the fixtures area - let(:content_diff_reports) { Pathname('spec').join('fixtures', 'content_diff_reports') } - let(:inventory_diff_xml) { content_diff_reports.join('ng782rw8378-v3-v4.xml') } - let(:inventory_diff) { Moab::FileInventoryDifference.parse(inventory_diff_xml.read) } - let(:content_diff) { inventory_diff.group_difference('content') } - - context 'when the manifest files are not in the workspace' do - it 'raises an error' do - expect { subject }.to raise_error(RuntimeError, /content dir not found/) - end - end - - context 'when the content files are in the workspace area' do - before do - # put the content files in the content_pathname location .../ng/782/rw/8378/ng782rw8378/content - deltas = content_diff.file_deltas - filelist = deltas[:modified] + deltas[:added] + deltas[:copyadded].collect { |_old, new| new } - expect(filelist).to eq(['SUB2_b2000_2.bvecs', 'SUB2_b2000_2.nii.gz', 'SUB2_b2000_1.bvals']) - filelist.each { |file| FileUtils.touch(File.join(content_dir, file)) } - end - - it { is_expected.to eq Pathname(content_dir) } - - context 'when the content files are up a directory to .../ng/782/rw/8378/ng782rw8378' do - let(:content_dir) { workspace_druid.path(nil, true) } - - it { is_expected.to eq Pathname(content_dir) } - end - - context 'when the content files are up a dreictory to .../ng/782/rw/8378' do - let(:content_dir) { Pathname(workspace_druid.path(nil, true)).parent } - - it { is_expected.to eq Pathname(content_dir) } - end - end - end - - describe '#stacks_location' do - subject(:location) { service.send(:stacks_location) } - - let(:druid) { 'druid:xy123xy1234' } - - it 'returns the default stack' do - work.contentMetadata.content = '' - expect(location).to eq stacks_root - end - - it 'returns the absolute stack' do - work.contentMetadata.content = '' - expect(location).to eq '/specialstacks' - end - - it 'returns a relative stack' do - work.contentMetadata.content = '' - expect { location }.to raise_error(RuntimeError) - end - end -end From b2091bce99c93bde79fc1056a270b1a171a47255 Mon Sep 17 00:00:00 2001 From: Justin Coyne Date: Fri, 12 Apr 2019 15:16:11 -0500 Subject: [PATCH 2/2] Remove DigitalStacksService it moved to common-accessioning --- lib/dor-services.rb | 1 - lib/dor/services/digital_stacks_service.rb | 122 -------- .../gj643zf5650-v3-v4.xml | 32 --- .../jq937jp0017-v1-v2.xml | 59 ---- .../ng782rw8378-v3-v4.xml | 152 ---------- spec/services/digital_stacks_service_spec.rb | 268 ------------------ 6 files changed, 634 deletions(-) delete mode 100644 lib/dor/services/digital_stacks_service.rb delete mode 100644 spec/fixtures/content_diff_reports/gj643zf5650-v3-v4.xml delete mode 100644 spec/fixtures/content_diff_reports/jq937jp0017-v1-v2.xml delete mode 100644 spec/fixtures/content_diff_reports/ng782rw8378-v3-v4.xml delete mode 100644 spec/services/digital_stacks_service_spec.rb diff --git a/lib/dor-services.rb b/lib/dor-services.rb index 5391f852..662677e5 100644 --- a/lib/dor-services.rb +++ b/lib/dor-services.rb @@ -127,7 +127,6 @@ def logger autoload :CreateWorkflowService autoload :CreativeCommonsLicenseService autoload :DecommissionService - autoload :DigitalStacksService autoload :DublinCoreService autoload :IndexingService autoload :MetadataService diff --git a/lib/dor/services/digital_stacks_service.rb b/lib/dor/services/digital_stacks_service.rb deleted file mode 100644 index 0c2084e9..00000000 --- a/lib/dor/services/digital_stacks_service.rb +++ /dev/null @@ -1,122 +0,0 @@ -# frozen_string_literal: true - -module Dor - class DigitalStacksService - # Delete files from stacks that have change type 'deleted', 'copydeleted', or 'modified' - # @param [Pathname] stacks_object_pathname the stacks location of the digital object - # @param [Moab::FileGroupDifference] content_diff the content file version differences report - def self.remove_from_stacks(stacks_object_pathname, content_diff) - %i[deleted copydeleted modified].each do |change_type| - subset = content_diff.subset(change_type) # {Moab::FileGroupDifferenceSubset} - subset.files.each do |moab_file| # {Moab::FileInstanceDifference} - moab_signature = moab_file.signatures.first # {Moab::FileSignature} - file_pathname = stacks_object_pathname.join(moab_file.basis_path) - delete_file(file_pathname, moab_signature) - end - end - end - - # Delete a file, but only if it exists and matches the expected signature - # @param [Pathname] file_pathname The location of the file to be deleted - # @param [Moab::FileSignature] moab_signature The fixity values of the file - # @return [Boolean] true if file deleted, false otherwise - def self.delete_file(file_pathname, moab_signature) - if file_pathname.exist? && (file_pathname.size == moab_signature.size) - file_signature = Moab::FileSignature.new.signature_from_file(file_pathname) - if file_signature == moab_signature - file_pathname.delete - return true - end - end - false - end - - # Rename files from stacks that have change type 'renamed' using an intermediate temp filename. - # The 2-step renaming allows chained or cyclic renames to occur without file collisions. - # @param [Pathname] stacks_object_pathname the stacks location of the digital object - # @param [Moab::FileGroupDifference] content_diff the content file version differences report - def self.rename_in_stacks(stacks_object_pathname, content_diff) - subset = content_diff.subset(:renamed) # {Moab::FileGroupDifferenceSubset - - # 1st Pass - rename files from original name to checksum-based name - subset.files.each do |moab_file| # {Moab::FileInstanceDifference} - moab_signature = moab_file.signatures.first # {Moab::FileSignature} - original_pathname = stacks_object_pathname.join(moab_file.basis_path) - temp_pathname = stacks_object_pathname.join(moab_signature.checksums.values.last) - rename_file(original_pathname, temp_pathname, moab_signature) - end - - # 2nd Pass - rename files from checksum-based name to new name - subset.files.each do |moab_file| # {Moab::FileInstanceDifference} - moab_signature = moab_file.signatures.first # {Moab::FileSignature} - temp_pathname = stacks_object_pathname.join(moab_signature.checksums.values.last) - new_pathname = stacks_object_pathname.join(moab_file.other_path) - rename_file(temp_pathname, new_pathname, moab_signature) - end - end - - # Rename a file, but only if it exists and has the expected signature - # @param [Pathname] old_pathname The original location/name of the file being renamed - # @param [Pathname] new_pathname The new location/name of the file - # @param [Moab::FileSignature] moab_signature The fixity values of the file - # @return [Boolean] true if file renamed, false otherwise - def self.rename_file(old_pathname, new_pathname, moab_signature) - if old_pathname.exist? && (old_pathname.size == moab_signature.size) - file_signature = Moab::FileSignature.new.signature_from_file(old_pathname) - if file_signature == moab_signature - new_pathname.parent.mkpath - old_pathname.rename(new_pathname) - return true - end - end - false - end - - # Add files to stacks that have change type 'added', 'copyadded' or 'modified'. - # @param [Pathname] workspace_content_pathname The dor workspace location of the digital object's content fies - # @param [Pathname] stacks_object_pathname the stacks location of the digital object's shelved files - # @param [Moab::FileGroupDifference] content_diff the content file version differences report - def self.shelve_to_stacks(workspace_content_pathname, stacks_object_pathname, content_diff) - return false if workspace_content_pathname.nil? - - %i[added copyadded modified].each do |change_type| - subset = content_diff.subset(change_type) # {Moab::FileGroupDifferenceSubset - subset.files.each do |moab_file| # {Moab::FileInstanceDifference} - moab_signature = moab_file.signatures.last # {Moab::FileSignature} - filename = change_type == :modified ? moab_file.basis_path : moab_file.other_path - workspace_pathname = workspace_content_pathname.join(filename) - stacks_pathname = stacks_object_pathname.join(filename) - copy_file(workspace_pathname, stacks_pathname, moab_signature) - end - end - true - end - - # Copy a file to stacks, but only if it does not yet exist with the expected signature - # @param [Pathname] workspace_pathname The location of the file in the DOR workspace - # @param [Pathname] stacks_pathname The location of the file in the stacks - # @param [Moab::FileSignature] moab_signature The fixity values of the file - # @return [Boolean] true if file copied, false otherwise - def self.copy_file(workspace_pathname, stacks_pathname, moab_signature) - if stacks_pathname.exist? - file_signature = Moab::FileSignature.new.signature_from_file(stacks_pathname) - stacks_pathname.delete if file_signature != moab_signature - end - unless stacks_pathname.exist? - stacks_pathname.parent.mkpath - FileUtils.cp workspace_pathname.to_s, stacks_pathname.to_s - # Change permissions - FileUtils.chmod 'u=rw,go=r', stacks_pathname.to_s - return true - end - false - end - - # Assumes the digital stacks storage root is mounted to the local file system - # TODO: since this is delegating to the Druid, this method may not be necessary - def self.prune_stacks_dir(id) - stacks_druid_tree = DruidTools::StacksDruid.new(id, Config.stacks.local_stacks_root) - stacks_druid_tree.prune! - end - end -end diff --git a/spec/fixtures/content_diff_reports/gj643zf5650-v3-v4.xml b/spec/fixtures/content_diff_reports/gj643zf5650-v3-v4.xml deleted file mode 100644 index 6b7f157d..00000000 --- a/spec/fixtures/content_diff_reports/gj643zf5650-v3-v4.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/spec/fixtures/content_diff_reports/jq937jp0017-v1-v2.xml b/spec/fixtures/content_diff_reports/jq937jp0017-v1-v2.xml deleted file mode 100644 index 95a99538..00000000 --- a/spec/fixtures/content_diff_reports/jq937jp0017-v1-v2.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/spec/fixtures/content_diff_reports/ng782rw8378-v3-v4.xml b/spec/fixtures/content_diff_reports/ng782rw8378-v3-v4.xml deleted file mode 100644 index a7340c2c..00000000 --- a/spec/fixtures/content_diff_reports/ng782rw8378-v3-v4.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spec/services/digital_stacks_service_spec.rb b/spec/services/digital_stacks_service_spec.rb deleted file mode 100644 index e0c2698e..00000000 --- a/spec/services/digital_stacks_service_spec.rb +++ /dev/null @@ -1,268 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require 'moab/stanford' - -describe Dor::DigitalStacksService do - before do - @content_diff_reports = Pathname('spec').join('fixtures', 'content_diff_reports') - - inventory_diff_xml = @content_diff_reports.join('gj643zf5650-v3-v4.xml') - inventory_diff = Moab::FileInventoryDifference.parse(inventory_diff_xml.read) - @gj643zf5650_content_diff = inventory_diff.group_difference('content') - - inventory_diff_xml = @content_diff_reports.join('jq937jp0017-v1-v2.xml') - inventory_diff = Moab::FileInventoryDifference.parse(inventory_diff_xml.read) - @jq937jp0017_content_diff = inventory_diff.group_difference('content') - - inventory_diff_xml = @content_diff_reports.join('ng782rw8378-v3-v4.xml') - inventory_diff = Moab::FileInventoryDifference.parse(inventory_diff_xml.read) - @ng782rw8378_content_diff = inventory_diff.group_difference('content') - end - - describe '.remove_from_stacks' do - it 'deletes content from the digital stacks by druid and file names' do - s = Pathname('/s') - - content_diff = @gj643zf5650_content_diff - delete_list = get_delete_list(content_diff) - expect(delete_list.map { |file| file[0, 2] }).to eq([[:deleted, 'page-3.jpg']]) - delete_list.each do |_change_type, filename, signature| - expect(described_class).to receive(:delete_file).with(s.join(filename), signature) - end - described_class.remove_from_stacks(s, content_diff) - - content_diff = @jq937jp0017_content_diff - delete_list = get_delete_list(content_diff) - expect(delete_list.map { |file| file[0, 2] }).to eq([ - [:deleted, 'intro-1.jpg'], - [:deleted, 'intro-2.jpg'], - [:modified, 'page-1.jpg'] - ]) - delete_list.each do |_change_type, filename, signature| - expect(described_class).to receive(:delete_file).with(s.join(filename), signature) - end - described_class.remove_from_stacks(s, content_diff) - - content_diff = @ng782rw8378_content_diff - delete_list = get_delete_list(content_diff) - expect(delete_list.map { |file| file[0, 2] }).to eq([ - [:deleted, 'SUB2_b2000_1.bvecs'], - [:deleted, 'SUB2_b2000_1.bvals'], - [:deleted, 'SUB2_b2000_1.nii.gz'] - ]) - delete_list.each do |_change_type, filename, signature| - expect(described_class).to receive(:delete_file).with(s.join(filename), signature) - end - described_class.remove_from_stacks(s, content_diff) - end - end - - def get_delete_list(content_diff) - delete_list = [] - %i[deleted copydeleted modified].each do |change_type| - subset = content_diff.subset(change_type) # {Moab::FileGroupDifferenceSubset} - subset.files.each do |moab_file| # {Moab::FileInstanceDifference} - moab_signature = moab_file.signatures.first # {Moab::FileSignature} - delete_list << [change_type, moab_file.basis_path, moab_signature] - end - end - delete_list - end - - describe '.rename_in_stacks' do - it 'renames content in the digital stacks' do - s = Pathname('/s') - - content_diff = @gj643zf5650_content_diff - rename_list = get_rename_list(content_diff) - expect(rename_list.map { |file| file[0, 3] }).to eq([ - [:renamed, 'page-2.jpg', 'page-2a.jpg'], - [:renamed, 'page-4.jpg', 'page-3.jpg'] - ]) - rename_list.each do |_change_type, oldname, newname, signature| - tempname = signature.checksums.values.last - expect(described_class).to receive(:rename_file).with(s.join(oldname), s.join(tempname), signature) - expect(described_class).to receive(:rename_file).with(s.join(tempname), s.join(newname), signature) - end - described_class.rename_in_stacks(s, content_diff) - - content_diff = @jq937jp0017_content_diff - rename_list = get_rename_list(content_diff) - expect(rename_list.map { |file| file[0, 3] }).to eq([]) - expect{ described_class.rename_in_stacks(s, content_diff) }.not_to raise_error - - content_diff = @ng782rw8378_content_diff - rename_list = get_rename_list(content_diff) - expect(rename_list.map { |file| file[0, 3] }).to eq([ - [:renamed, 'SUB2_b2000_2.nii.gz', 'SUB2_b2000_1.nii.gz'], - [:renamed, 'SUB2_b2000_2.bvecs', 'SUB2_b2000_1.bvecs'] - ]) - rename_list.each do |_change_type, oldname, newname, signature| - tempname = signature.checksums.values.last - expect(described_class).to receive(:rename_file).with(s.join(oldname), s.join(tempname), signature) - expect(described_class).to receive(:rename_file).with(s.join(tempname), s.join(newname), signature) - end - described_class.rename_in_stacks(s, content_diff) - end - end - - def get_rename_list(content_diff) - rename_list = [] - subset = content_diff.subset(:renamed) # {Moab::FileGroupDifferenceSubset - subset.files.each do |moab_file| # {Moab::FileInstanceDifference} - moab_signature = moab_file.signatures.last # {Moab::FileSignature} - rename_list << [:renamed, moab_file.basis_path, moab_file.other_path, moab_signature] - end - rename_list - end - - describe '.shelve_to_stacks' do - it 'copies the content to the digital stacks' do - w = Pathname('/w') - s = Pathname('/s') - - content_diff = @gj643zf5650_content_diff - shelve_list = get_shelve_list(content_diff) - expect(shelve_list.map { |file| file[0, 2] }).to eq([[:added, 'page-4.jpg']]) - shelve_list.each do |_change_type, filename, signature| - expect(described_class).to receive(:copy_file).with(w.join(filename), s.join(filename), signature) - end - described_class.shelve_to_stacks(w, s, content_diff) - - content_diff = @jq937jp0017_content_diff - shelve_list = get_shelve_list(content_diff) - expect(shelve_list.map { |file| file[0, 2] }).to eq([[:modified, 'page-1.jpg']]) - shelve_list.each do |_change_type, filename, signature| - expect(described_class).to receive(:copy_file).with(w.join(filename), s.join(filename), signature) - end - described_class.shelve_to_stacks(w, s, content_diff) - - content_diff = @ng782rw8378_content_diff - shelve_list = get_shelve_list(content_diff) - expect(shelve_list.map { |file| file[0, 2] }).to eq([ - [:added, 'SUB2_b2000_2.bvecs'], - [:added, 'SUB2_b2000_2.nii.gz'], - [:copyadded, 'SUB2_b2000_1.bvals'] - ]) - shelve_list.each do |_change_type, filename, signature| - expect(described_class).to receive(:copy_file).with(w.join(filename), s.join(filename), signature) - end - described_class.shelve_to_stacks(w, s, content_diff) - end - end - - def get_shelve_list(content_diff) - shelve_list = [] - %i[added copyadded modified].each do |change_type| - subset = content_diff.subset(change_type) # {Moab::FileGroupDifferenceSubset - subset.files.each do |moab_file| # {Moab::FileInstanceDifference} - moab_signature = moab_file.signatures.last # {Moab::FileSignature} - filename = change_type == :modified ? moab_file.basis_path : moab_file.other_path - shelve_list << [change_type, filename, moab_signature] - end - end - shelve_list - end -end - -describe 'file operations' do - before(:all) do - @tmpdir = Pathname(Dir.mktmpdir('stacks')) - end - - after(:all) do - @tmpdir.rmtree if @tmpdir.exist? - end - - describe '.delete_file' do - it 'deletes a file, but only if it exists and matches the expected signature' do - # if file does not exist - file_pathname = @tmpdir.join('delete-me.txt') - moab_signature = Moab::FileSignature.new - expect(file_pathname).not_to exist - expect(Dor::DigitalStacksService.delete_file(file_pathname, moab_signature)).to be_falsey - # if file exists, but has unexpected signature - FileUtils.touch(file_pathname.to_s) - expect(file_pathname).to exist - expect(Dor::DigitalStacksService.delete_file(file_pathname, moab_signature)).to be_falsey - expect(file_pathname).to exist - # if file exists, and has expected signature - moab_signature = Moab::FileSignature.new.signature_from_file(file_pathname) - expect(Dor::DigitalStacksService.delete_file(file_pathname, moab_signature)).to be_truthy - expect(file_pathname).not_to exist - end - end - - describe '.rename_file' do - it 'renames a file, but only if it exists and has the expected signature' do - # if file does not exist - old_pathname = @tmpdir.join('rename-me.txt') - new_pathname = @tmpdir.join('new-name.txt') - moab_signature = Moab::FileSignature.new - expect(old_pathname).not_to exist - expect(new_pathname).not_to exist - expect(Dor::DigitalStacksService.rename_file(old_pathname, new_pathname, moab_signature)).to be_falsey - # if file exists, but has unexpected signature - FileUtils.touch(old_pathname.to_s) - expect(old_pathname).to exist - expect(Dor::DigitalStacksService.rename_file(old_pathname, new_pathname, moab_signature)).to be_falsey - expect(old_pathname).to exist - expect(new_pathname).not_to exist - # if file exists, and has expected signature - moab_signature = Moab::FileSignature.new.signature_from_file(old_pathname) - expect(Dor::DigitalStacksService.rename_file(old_pathname, new_pathname, moab_signature)).to be_truthy - expect(old_pathname).not_to exist - expect(new_pathname).to exist - end - end - - describe '.copy_file' do - it 'copies a file to stacks, but only if it does not yet exist with the expected signature' do - # if file does not exist in stacks - workspace_pathname = @tmpdir.join('copy-me.txt') - stacks_pathname = @tmpdir.join('stacks-name.txt') - FileUtils.touch(workspace_pathname.to_s) - FileUtils.chmod 0o640, workspace_pathname.to_s - expect(File::Stat.new(workspace_pathname.to_s).mode.to_s(8)).to eq('100640') - moab_signature = Moab::FileSignature.new.signature_from_file(workspace_pathname) - expect(workspace_pathname).to exist - expect(stacks_pathname).not_to exist - expect(Dor::DigitalStacksService.copy_file(workspace_pathname, stacks_pathname, moab_signature)).to be_truthy - # if file exists, and has expected signature - expect(workspace_pathname).to exist - expect(stacks_pathname).to exist - expect(File::Stat.new(stacks_pathname.to_s).mode.to_s(8)).to eq('100644') - moab_signature = Moab::FileSignature.new.signature_from_file(stacks_pathname) - expect(Dor::DigitalStacksService.copy_file(workspace_pathname, stacks_pathname, moab_signature)).to be_falsey - # if file exists, but has unexpected signature - moab_signature = Moab::FileSignature.new - expect(workspace_pathname).to exist - expect(stacks_pathname).to exist - expect(Dor::DigitalStacksService.copy_file(workspace_pathname, stacks_pathname, moab_signature)).to be_truthy - end - end -end - -describe '.prune_stacks_dir' do - let(:stacks_root) { Dir.mktmpdir } - - before do - Dor::Config.push! { |c| c.stacks.local_stacks_root stacks_root } - end - - after do - FileUtils.remove_entry stacks_root - Dor::Config.pop! - end - - it 'prunes the stacks directory' do - dr = DruidTools::StacksDruid.new 'druid:aa123bb4567', stacks_root - item_root = dr.path(nil, true) - File.open(File.join(item_root, 'somefile'), 'w') { |f| f.write 'junk' } - Dor::DigitalStacksService.prune_stacks_dir 'druid:aa123bb4567' - item_pathname = Pathname item_root - expect(File).not_to exist(item_pathname) - expect(File).not_to exist(item_pathname.parent) - end -end