diff --git a/app/actors/hyrax/actors/file_set_actor.rb b/app/actors/hyrax/actors/file_set_actor.rb index d1542e74..6880dc3c 100644 --- a/app/actors/hyrax/actors/file_set_actor.rb +++ b/app/actors/hyrax/actors/file_set_actor.rb @@ -182,7 +182,7 @@ def revert_content( revision_id, relation = :original_file ) Hyrax.config.callback.run(:after_revert_content, file_set, user, revision_id) true rescue Exception => e # rubocop:disable Lint/RescueException - Rails.logger.error "#{e.class} work.id=#{work.id} -- #{e.message} at #{e.backtrace[0]}" + Rails.logger.error "#{e.class} -- #{e.message} at #{e.backtrace[0]}" Deepblue::LoggingHelper.bold_debug [ Deepblue::LoggingHelper.here, Deepblue::LoggingHelper.called_from, "ERROR", diff --git a/app/services/deepblue/yaml_populate_service.rb b/app/services/deepblue/yaml_populate_service.rb index b4e4845c..1b239b40 100644 --- a/app/services/deepblue/yaml_populate_service.rb +++ b/app/services/deepblue/yaml_populate_service.rb @@ -640,17 +640,6 @@ def log_provenance_migrate( curation_concern:, parent: nil, migrate_direction: ' end end - def metadata_filename_collection( pathname_dir, collection ) - pathname_dir.join "w_#{collection.id}_metadata_report.txt" - end - - def metadata_filename_collection_work( pathname_dir, collection, work ) - pathname_dir.join "c_#{collection.id}_w_#{work.id}_metadata_report.txt" - end - - def metadata_filename_work( pathname_dir, work ) - pathname_dir.join "w_#{work.id}_metadata_report.txt" - end def metadata_multi_valued?( attribute_value ) return false if attribute_value.blank? diff --git a/spec/actors/hyrax/actors/file_actor_spec.rb b/spec/actors/hyrax/actors/file_actor_spec.rb new file mode 100644 index 00000000..55eecb89 --- /dev/null +++ b/spec/actors/hyrax/actors/file_actor_spec.rb @@ -0,0 +1,259 @@ +require 'rails_helper' + +class MockFile + def initialize(path) + @filepath = OpenStruct.new(path: path) + end + + def uploader + @filepath + end +end + +class MockIO + def initialize(path) + @file = MockFile.new(path) + end + + def uploaded_file + @file + end +end + +class MockRepo + def initialize(id) + @id = id + end + + def id + @id + end + + def restore_version(revision_id) + end +end + +class MockFileSet + def initialize(id, save, label, created) + @id = id + @save = save + @label = label + @created = created + end + + def id + @id + end + + def save + @save + end + + def latest_version + OpenStruct.new(label:@label, created: @created) + end + + def provenance_update_version(current_user:, event_note:, new_create_date:, new_revision_id:, prior_create_date:, prior_revision_id:, revision_id:) + end +end + +class MockPublicSend + + def initialize(sent) + @sent = sent + end + + def public_send(relation) + @sent + end + + def id () + "FileSet ID" + end +end + + + + +RSpec.describe Hyrax::Actors::FileActor do + + describe "#initialize" do + it "creates instance variables" do + actor_file = Hyrax::Actors::FileActor.new("file set", "relation", "user") + + actor_file.instance_variable_get(:@file_set) == "file set" + actor_file.instance_variable_get(:@relation) == :relation + actor_file.instance_variable_get(:@user) == "user" + end + end + + + describe "#ingest_file" do + before { + allow(::Deepblue::LoggingHelper).to receive(:here).and_return "here" + allow(::Deepblue::LoggingHelper).to receive(:called_from).and_return "called from" + } + + context "when bypass_fedora and file_set.save is negative" do + fileset = OpenStruct.new(save: false) + subject { described_class.new(fileset, "relational", "the user") } + + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with(["here", "called from", "io=io)", "user=the user", "continue_job_chain=true", "continue_job_chain_later=true", + "delete_input_file=true", "uploaded_file_ids=[11, 22, 33]", "bypass_fedora=true", ""]) + allow(Hydra::Works::AddExternalFileToFileSet).to receive(:call).with(fileset, true, :relational, versioning: false) + } + it "logs arguments and calls AddExternalFileToFileSet" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with(["here", "called from", "io=io)", "user=the user", "continue_job_chain=true", "continue_job_chain_later=true", + "delete_input_file=true", "uploaded_file_ids=[11, 22, 33]", "bypass_fedora=true", ""]) + expect(Hydra::Works::AddExternalFileToFileSet).to receive(:call).with(fileset, true, :relational, versioning: false) + + expect(subject.ingest_file("io", current_user: "the user", uploaded_file_ids: [11,22,33], bypass_fedora: true)).to eq false + end + end + + + context "when not bypass_fedora" do + fileset = OpenStruct.new(save: true) + mockRepo = MockRepo.new(id: "repo") + + subject { described_class.new(fileset, "relational", "the user") } + + before { + allow(subject).to receive(:related_file).and_return mockRepo + allow(Hyrax::VersioningService).to receive(:create).with(mockRepo, "user") + } + + context "when continue_job_chain_later is true" do + io = MockIO.new("one true path") + + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with(["here", "called from", "io=#{io})", "user=the user", "continue_job_chain=true", "continue_job_chain_later=true", + "delete_input_file=true", "uploaded_file_ids=[11, 22, 33]", "bypass_fedora=false", ""]) + allow(Hydra::Works::AddFileToFileSet).to receive(:call).with(fileset, "one true path", :relational, versioning: false) + + allow(CharacterizeJob).to receive(:perform_later).with(fileset, {:id=>"repo"}, "one true path", current_user: "the user", uploaded_file_ids: [11,22,33]) + } + it "logs arguments and calls AddFileToFileSet" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with(["here", "called from", "io=#{io})", "user=the user", "continue_job_chain=true", "continue_job_chain_later=true", + "delete_input_file=true", "uploaded_file_ids=[11, 22, 33]", "bypass_fedora=false", ""]) + expect(Hydra::Works::AddFileToFileSet).to receive(:call).with(fileset, io, :relational, versioning: false) + expect(Hyrax::VersioningService).to receive(:create).with(mockRepo, "the user") + expect(CharacterizeJob).to receive(:perform_later).with(fileset, {:id=>"repo"}, "one true path", current_user: "the user", uploaded_file_ids: [11,22,33]) + subject.ingest_file(io, current_user: "the user", uploaded_file_ids: [11,22,33]) + end + end + + + context "when continue_job_chain_later is false" do + io = OpenStruct.new(uploaded_file: false, path: "path finder") + + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with(["here", "called from", "io=#{io})", "user=the user", "continue_job_chain=true", "continue_job_chain_later=false", + "delete_input_file=true", "uploaded_file_ids=[11, 22, 33]", "bypass_fedora=false", ""]) + allow(Hydra::Works::AddFileToFileSet).to receive(:call).with(fileset, io, :relational, versioning: false) + allow(CharacterizeJob).to receive(:perform_now).with(fileset, {:id=>"repo"}, "path finder", continue_job_chain: true, continue_job_chain_later:false, current_user: "user", + delete_input_file: true, uploaded_file_ids: [11,22,33]) + } + it "logs arguments and calls AddFileToFileSet" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with(["here", "called from", "io=#{io})", "user=the user", "continue_job_chain=true", "continue_job_chain_later=false", + "delete_input_file=true", "uploaded_file_ids=[11, 22, 33]", "bypass_fedora=false", ""]) + expect(Hydra::Works::AddFileToFileSet).to receive(:call).with(fileset, io, :relational, versioning: false) + expect(Hyrax::VersioningService).to receive(:create).with(mockRepo, "the user") + expect(CharacterizeJob).to receive(:perform_now).with(fileset, {:id=>"repo"}, "path finder", continue_job_chain: true, continue_job_chain_later:false, + current_user: "the user", delete_input_file: true, uploaded_file_ids: [11,22,33]) + subject.ingest_file(io, continue_job_chain_later: false, current_user: "the user", uploaded_file_ids: [11,22,33]) + end + end + end + end + + + describe "#revert_to" do + before { + allow(Deepblue::LoggingHelper).to receive(:here).and_return "here" + allow(Deepblue::LoggingHelper).to receive(:called_from).and_return "called from" + } + + context "when file_set.save is negative" do + repo = MockRepo.new(id: "repo") + fileset = MockFileSet.new("a great file", false, "brand new release", "hot off the presses") + subject { described_class.new(fileset, "relational", "the user") } + + before { + allow(subject).to receive(:related_file).and_return repo + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with(["here", "called from", "user=the user", "file_set.id=a great file", "relation=relational", + "revision_id=revise revise revise" ]) + } + it "returns false" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with(["here", "called from", "user=the user", "file_set.id=a great file", "relation=relational", + "revision_id=revise revise revise" ]) + expect(repo).to receive(:restore_version).with("revise revise revise") + expect(subject.revert_to("revise revise revise")).to eq false + end + end + + context "when file_set.save is positive" do + it "returns blank" do + skip "Add a test here" + end + end + end + + + describe "#==" do + context "when argument is not a self.class" do + subject { described_class.new(double, "relativity", double) } + + it "returns false" do + expect(subject.== "plot twist").to eq false + end + end + + context "when argument is a self.class" do + context "when values are equal" do + subject { described_class.new(OpenStruct.new(id: "111"), "relativity", "just a guy") } + + it "returns true" do + expect(subject.== Hyrax::Actors::FileActor.new(OpenStruct.new(id: "111"), "relativity", "just a guy")).to eq true + end + end + + context "when values are not equal" do + subject { described_class.new(OpenStruct.new(id: "22"), "distant", "someone else") } + + it "returns false" do + expect(subject.== Hyrax::Actors::FileActor.new(OpenStruct.new(id: "111"), "relativity", "just a guy")).to eq false + end + end + end + + end + + + describe "#related_file" do + + context "sends file successfully" do + subject { described_class.new(MockPublicSend.new(true), "relational", "user dude" ) } + + it "returns true" do + expect(subject.send(:related_file)).to eq true + end + end + + context "fails to send file" do + subject { described_class.new(MockPublicSend.new(false), "relational", "user dude" ) } + + it "raises error" do + + begin + subject.send(:related_file) + rescue RuntimeError => e + expect(e.message).to eq "No relational returned for FileSet FileSet ID" + end + + end + end + end + +end diff --git a/spec/actors/hyrax/actors/file_set_actor_spec.rb b/spec/actors/hyrax/actors/file_set_actor_spec.rb new file mode 100644 index 00000000..d64450ba --- /dev/null +++ b/spec/actors/hyrax/actors/file_set_actor_spec.rb @@ -0,0 +1,799 @@ +require 'rails_helper' + +class MockFileActor + + def ingest_file(io_wrapper, continue_job_chain_later:, bypass_fedora:) + end +end + +class MockFileSet + def initialize (id, label, created) + @id = id + @label = label + @created = created + end + + def id + @id + end + + def parent + OpenStruct.new(id: @id) + end + + def creator=(creator) + end + + def depositor=(depositor_id) + end + + def label + @label + end + + def label=(label) + @label = label + end + + def latest_version + OpenStruct.new(label: @label, created: @created) + end + + def date_uploaded=(date_uploaded) + end + + def date_modified=(date_modified) + end + + def save + end + + def reload + end + + def destroy + end + + def provenance_update_version(current_user:, event_note:, new_create_date:, new_revision_id:, prior_create_date:, prior_revision_id:, revision_id:) + end +end + +class MockWork + + def initialize(id, new_record = false) + @id = id + @new_record = new_record + end + + def id + @id + end + + def reload + end + + def new_record? + @new_record + end + + def visibility + true + end + + def ordered_members + @ordered_members ||= [] + end + + def representative=(file_set) + end + + def thumbnail=(file_set) + end + + def save + end +end + +class MockLinkWork + + def initialize() + @thumbnail = "thumbnail" + @rep = "representative" + @rendering_ids = ["rendering id", "thumbnail id", "representative id"] + end + + def total_file_size_subtract_file_set!(file_set) + end + + def thumbnail_id + "thumbnail id" + end + + def representative_id + "representative id" + end + + def rendering_ids + @rendering_ids + end + + def thumbnail + @thumbnail + end + + def thumbnail=(thumbnail) + @thumbnail = thumbnail + end + + def representative + @rep + end + def representative=(representative) + @rep = representative + end + + def rendering_ids=(rendering_ids) + @rendering_ids = rendering_ids + end + + def save! + end +end + +class MockDepositor + + def initialize(user_key) + @user_key = user_key + end + + def user_key + @user_key + end +end + +class MockFileUpload + + def original_name + "original name" + end +end + +class MockBuildFileActor + + def initialize(answer) + @answer = answer + end + def revert_to (id) + @answer + end +end + +class MockUploadedFile < Hyrax::UploadedFile + + def initialize(filename) + @filename = filename + end + def uploader + OpenStruct.new(filename: @filename) + end + + def file_url + "http://www.example.com/index.html" + end +end + + + + +RSpec.describe Hyrax::Actors::FileSetActor do + + subject { described_class.new("file set", "active user") } + + + describe "#initialize" do + it "creates instance variables" do + actor_file = Hyrax::Actors::FileSetActor.new("file set", "user") + + actor_file.instance_variable_get(:@file_set) == "file set" + actor_file.instance_variable_get(:@user) == "user" + end + end + + + describe "#create_content" do + before { + allow(Deepblue::LoggingHelper).to receive(:here).and_return "here" + allow(Deepblue::LoggingHelper).to receive(:called_from).and_return "called from" + allow(Deepblue::LoggingHelper).to receive(:obj_to_json).with("file", "a file").and_return "json string" + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with ["here", "called from", "file=a file", "json string", "relation=original", "from_url=false", + "continue_job_chain_later=true", "uploaded_file_ids=[101, 202]", "bypass_fedora=false", ""] + } + + context "when file_set.save evaluates to false and file_set.title is blank" do + fileset = OpenStruct.new(label: "the fileset", title: "", save: false) + subject { described_class.new(fileset, "the user") } + + before { + allow(subject).to receive(:remove_work_id_from_label).with(fileset) + } + it "file set label and title are the same" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with ["here", "called from", "file=a file", "json string", "relation=original", "from_url=false", + "continue_job_chain_later=true", "uploaded_file_ids=[101, 202]", "bypass_fedora=false", ""] + expect(subject).not_to receive(:label_for) + expect(subject).to receive(:remove_work_id_from_label).with(fileset) + + expect(subject.create_content("a file", "original", uploaded_file_ids: [101, 202])).to eq false + expect(subject.file_set.label).to eq "the fileset" + expect(subject.file_set.title).to eq ["the fileset"] + end + end + + + context "when file_set.save is true and from_url is false and file_set.label is nil and file_set.title is not blank" do + file_set = OpenStruct.new(label: nil, title: "Grand Title", save: true) + subject { described_class.new(file_set, "the user") } + + before { + allow(subject).to receive(:label_for).with("a file", bypass_fedora: false).and_return "Fabulous Label" + allow(subject).to receive(:remove_work_id_from_label).with(file_set) + allow(subject).to receive(:wrapper!).with( file: "a file", relation: "original" ).and_return "io wrapper" + allow(IngestJob).to receive(:perform_now).with("io wrapper", continue_job_chain_later: true, uploaded_file_ids: [101, 202], bypass_fedora: false ) + } + it "file set label and title are different" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with ["here", "called from", "file=a file", "json string", "relation=original", "from_url=false", + "continue_job_chain_later=true", "uploaded_file_ids=[101, 202]", "bypass_fedora=false", ""] + expect(subject).to receive(:label_for).with("a file", bypass_fedora: false) + expect(subject).to receive(:remove_work_id_from_label).with(file_set) + expect(subject).to receive(:wrapper!).with( file: "a file", relation: "original" ) + expect(IngestJob).to receive(:perform_now).with("io wrapper", continue_job_chain_later: true, uploaded_file_ids: [101, 202], bypass_fedora: false ) + + subject.create_content("a file", "original", uploaded_file_ids: [101, 202]) + expect(subject.file_set.label).to eq "Fabulous Label" + expect(subject.file_set.title).to eq "Grand Title" + end + end + + + context "when file_set.save is true and from_url is true" do + + context "when continue_job_chain_later is true" do + fileSet = OpenStruct.new(label: "Good Label", title: "Acceptable Title", parent: "Parental", save: true) + builtFile = MockFileActor.new + + subject { described_class.new(fileSet, "the user") } + + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with ["here", "called from", "file=a file", "json string", "relation=original", "from_url=true", + "continue_job_chain_later=true", "uploaded_file_ids=[101, 202]", "bypass_fedora=false", ""] + allow(subject).to receive(:remove_work_id_from_label).with(fileSet) + allow(subject).to receive(:wrapper!).with( file: "a file", relation: "original" ).and_return "io wrapper" + + allow(subject).to receive(:build_file_actor).with("original").and_return builtFile + + allow(VisibilityCopyJob).to receive(:perform_later).with("Parental") + allow(InheritPermissionsJob).to receive(:perform_later).with("Parental") + } + it "calls perform later functions" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with ["here", "called from", "file=a file", "json string", "relation=original", "from_url=true", + "continue_job_chain_later=true", "uploaded_file_ids=[101, 202]", "bypass_fedora=false", ""] + expect(subject).not_to receive(:label_for) + expect(subject).to receive(:remove_work_id_from_label).with(fileSet) + expect(subject).to receive(:wrapper!).with( file: "a file", relation: "original" ) + expect(subject).to receive(:build_file_actor).with("original") + expect(builtFile).to receive(:ingest_file).with("io wrapper", continue_job_chain_later: true, bypass_fedora: false) + expect(VisibilityCopyJob).to receive(:perform_later).with("Parental") + expect(InheritPermissionsJob).to receive(:perform_later).with("Parental") + + expect(VisibilityCopyJob).not_to receive(:perform_now) + expect(InheritPermissionsJob).not_to receive(:perform_now) + + subject.create_content("a file", "original", from_url: true, uploaded_file_ids: [101, 202]) + expect(subject.file_set.label).to eq "Good Label" + expect(subject.file_set.title).to eq "Acceptable Title" + end + end + + context "when continue_job_chain_later is false" do + doc_set = OpenStruct.new(label: "OK Label", title: "Absent Title", parent: "Parental", save: true) + built_file = MockFileActor.new + + subject { described_class.new(doc_set, "the user") } + + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with ["here", "called from", "file=a file", "json string", "relation=original", "from_url=true", + "continue_job_chain_later=false", "uploaded_file_ids=[101, 202]", "bypass_fedora=false", ""] + allow(subject).to receive(:remove_work_id_from_label).with(doc_set) + allow(subject).to receive(:wrapper!).with( file: "a file", relation: "original" ).and_return "io wrapper" + + allow(subject).to receive(:build_file_actor).with("original").and_return built_file + + allow(VisibilityCopyJob).to receive(:perform_now).with("Parental") + allow(InheritPermissionsJob).to receive(:perform_now).with("Parental") + } + it "calls perform now functions" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with ["here", "called from", "file=a file", "json string", "relation=original", "from_url=true", + "continue_job_chain_later=false", "uploaded_file_ids=[101, 202]", "bypass_fedora=false", ""] + expect(subject).not_to receive(:label_for) + expect(subject).to receive(:remove_work_id_from_label).with(doc_set) + expect(subject).to receive(:wrapper!).with( file: "a file", relation: "original" ) + expect(subject).to receive(:build_file_actor).with("original") + expect(built_file).to receive(:ingest_file).with("io wrapper", continue_job_chain_later: false, bypass_fedora: false) + expect(VisibilityCopyJob).to receive(:perform_now).with("Parental") + expect(InheritPermissionsJob).to receive(:perform_now).with("Parental") + + expect(VisibilityCopyJob).not_to receive(:perform_later) + expect(InheritPermissionsJob).not_to receive(:perform_later) + + subject.create_content("a file", "original", from_url: true, continue_job_chain_later: false, uploaded_file_ids: [101, 202]) + expect(subject.file_set.label).to eq "OK Label" + expect(subject.file_set.title).to eq "Absent Title" + end + end + end + end + + + describe "#update_content" do + fileset = MockFileSet.new("working file set", "controversial publication", "recently") + subject { described_class.new(fileset,"admin user") } + + before { + allow(Deepblue::LoggingHelper).to receive(:here).and_return "here" + allow(Deepblue::LoggingHelper).to receive(:called_from).and_return "called from" + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "user=admin user", "file_set.id=working file set", "file=large file", + "relation=distant" ] + + allow(Hyrax::TimeService).to receive(:time_in_utc).and_return "it's utc time" + + allow(subject).to receive(:wrapper!).with(file: "large file", relation: "distant").and_return "wrapped!" + allow(IngestJob).to receive(:perform_later).with("wrapped!", notification: true) + } + + it "sets current version to latest version" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "user=admin user", "file_set.id=working file set", "file=large file", + "relation=distant" ] + expect(fileset).to receive(:provenance_update_version).with(current_user: "admin user", + event_note: "update_content", + new_create_date: '', + new_revision_id: '', + prior_create_date: "recently", + prior_revision_id: "controversial publication", + revision_id: '') + expect(fileset).to receive(:date_modified=).with("it's utc time") + expect(fileset).to receive(:save) + expect(fileset).to receive(:reload) + + expect(subject).to receive(:wrapper!).with(file: "large file", relation: "distant") + expect(IngestJob).to receive(:perform_later).with("wrapped!", notification: true) + + subject.update_content("large file", "distant") + end + end + + + describe "#create_metadata" do + fileset = MockFileSet.new("set of files", "popular article", "sometime") + user = OpenStruct.new(user_key: 'top user') + subject { described_class.new(fileset, user) } + + before { + allow(Deepblue::LoggingHelper).to receive(:here).and_return "here" + allow(Deepblue::LoggingHelper).to receive(:called_from).and_return "called from" + allow(subject).to receive(:depositor_id).with(user).and_return "depositor id" + allow(Hyrax::TimeService).to receive(:time_in_utc).and_return "it's that time again" + } + + context "when argument given is not a block and assign_visibility returns false" do + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "file_set_params={\"params\"=>\"file set\"}" ] + allow(subject).to receive(:assign_visibility?).with({"params" => "file set"}).and_return false + } + it "returns nil" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "file_set_params={\"params\"=>\"file set\"}" ] + expect(fileset).to receive(:depositor=).with("depositor id") + expect(fileset).to receive(:date_uploaded=).with("it's that time again") + expect(fileset).to receive(:date_modified=).with("it's that time again") + expect(fileset).to receive(:creator=).with(["top user"]) + expect(subject).to receive(:assign_visibility?).with({"params" => "file set"}) + + expect(Hyrax::Actors::Environment).not_to receive(:new) + expect(Hyrax::CurationConcern.file_set_create_actor).not_to receive(:create) + + expect(subject.create_metadata({"params" => "file set"})).to be_blank + end + end + + context "when argument given is a block and assign_visibility returns true" do + before { + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "file_set_params={}" ] + allow(subject).to receive(:ability).and_return 'ability' + allow(subject).to receive(:assign_visibility?).and_return true + allow(subject).to receive(:ability).and_return 'ability' + allow(Hyrax::Actors::Environment).to receive(:new).with(fileset, "ability", {}).and_return "test environment" + allow(Hyrax::CurationConcern.file_set_create_actor).to receive(:create).with("test environment") + } + it "calls CurationConcern.file_set_create_actor.create and yields block with file_set" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "file_set_params={}" ] + expect(fileset).to receive(:depositor=).with("depositor id") + expect(fileset).to receive(:date_uploaded=).with("it's that time again") + expect(fileset).to receive(:date_modified=).with("it's that time again") + expect(fileset).to receive(:creator=).with(["top user"]) + + expect(subject).to receive(:assign_visibility?) + expect(Hyrax::CurationConcern.file_set_create_actor).to receive(:create).with("test environment") + expect(subject.create_metadata do |param| "#{param.id} for #{param.label}" end).to eq "set of files for popular article" + end + end + end + + + describe "#attach_to_work" do + fileset = MockFileSet.new("boxed set", "published thesis", "in the distant past") + user = OpenStruct.new(user_key: 'this user') + work = MockWork.new("work id") + + subject { described_class.new(fileset, user) } + + before { + allow(Deepblue::LoggingHelper).to receive(:here).and_return "here" + allow(Deepblue::LoggingHelper).to receive(:called_from).and_return "called from" + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "work.id=work id", "file_set_params={\"params\"=>\"file set\"}" ] + } + context "when Exception does not occur" do + before { + allow(subject).to receive(:acquire_lock_for).with "work id" + } + it "calls bold_debug and acquires lock" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "work.id=work id", "file_set_params={\"params\"=>\"file set\"}" ] + expect(subject).to receive(:acquire_lock_for).with "work id" + subject.attach_file_to_work(work, {"params" => "file set"}, uploaded_file_id: "uploaded file id") + end + + it "updates and saves work and calls UploadHelper.log inside lock" do + skip "Add a test" + end + end + + context "when Exception occurs" do + before { + allow(subject).to receive(:acquire_lock_for).with("work id").and_raise(Exception, "Exception Message") + allow(Rails.logger).to receive(:error) + allow(Deepblue::LoggingHelper).to receive(:bold_debug) + allow(Deepblue::UploadHelper).to receive(:log) + } + + it "catches an exception and logs it" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "work.id=work id", "file_set_params={\"params\"=>\"file set\"}" ] + expect(Rails.logger).to receive(:error) + expect(Deepblue::LoggingHelper).to receive(:bold_debug) + expect(Deepblue::UploadHelper).to receive(:log) + + subject.attach_file_to_work(work, {"params" => "file set"}, uploaded_file_id: "uploaded file id") + end + end + end + + + describe "#revert_content" do + before { + allow(Deepblue::LoggingHelper).to receive(:here).and_return "here" + allow(Deepblue::LoggingHelper).to receive(:called_from).and_return "called from" + allow(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "revision_id=X555", "relation=original_file" ] + } + + context "when revert_to with revision_id returns false" do + before{ + allow(subject).to receive(:build_file_actor).with(:original_file).and_return MockBuildFileActor.new(false) + } + + it "returns false" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "revision_id=X555", "relation=original_file" ] + expect(Hyrax.config.callback).not_to receive(:run) + + expect(subject.revert_content("X555")).to eq false + end + end + + context "when revert_to with revision_id returns true" do + before{ + allow(subject).to receive(:build_file_actor).with(:original_file).and_return MockBuildFileActor.new(true) + allow(Hyrax.config.callback).to receive(:run).with(:after_revert_content, "file set", "active user", "X555") + } + + it "calls Hyrax.config.callback.run and returns true" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "revision_id=X555", "relation=original_file" ] + expect(subject).to receive(:build_file_actor).with(:original_file) + expect(Hyrax.config.callback).to receive(:run).with(:after_revert_content, "file set", "active user", "X555") + + expect(subject.revert_content("X555")).to eq true + end + end + + context "when an Exception occurs" do + before { + allow(subject).to receive(:build_file_actor).with(:original_file).and_return raise_exception + } + + it "logs the error" do + expect(Deepblue::LoggingHelper).to receive(:bold_debug).with [ "here", "called from", "revision_id=Z666", "relation=original_file" ] + expect(Rails.logger).to receive(:error) + expect(Deepblue::LoggingHelper).to receive(:bold_debug) + + expect(subject.revert_content("Z666")).to eq false + end + + skip "Add a test that includes error and bold_debug parameters checks" + end + end + + + describe "#update_metadata" do + filesetmock = MockFileSet.new("library", "entertaining review", "on a summer\'s day") + usermock = OpenStruct.new(user_key: 'responsible user') + subject { described_class.new(filesetmock, usermock) } + + before { + allow(subject).to receive(:ability).and_return 'ability' + allow(Hyrax::Actors::Environment).to receive(:new).with(filesetmock, "ability", "attributes").and_return "testing 123" + allow(Hyrax::CurationConcern.file_set_update_actor).to receive(:update).with("testing 123") + } + it "calls CurationConcern.file_set_update_actor.update" do + expect(Hyrax::Actors::Environment).to receive(:new).with(filesetmock, "ability", "attributes") + expect(Hyrax::CurationConcern.file_set_update_actor).to receive(:update).with("testing 123") + + subject.update_metadata("attributes") + end + end + + + describe "#destroy" do + file_set_mock = MockFileSet.new("zeppelin library", "over the rainbow", "in a dream") + + subject { described_class.new(file_set_mock, "responsible user") } + + before { + allow(subject).to receive(:unlink_from_work) + allow(Hyrax.config.callback).to receive(:run).with(:after_destroy, "zeppelin library", 'responsible user') + } + + it do + expect(subject).to receive(:unlink_from_work) + expect(file_set_mock).to receive(:destroy) + expect(Hyrax.config.callback).to receive(:run).with(:after_destroy, "zeppelin library", 'responsible user') + subject.destroy + end + end + + + describe "#file_actor_class" do + it "file_actor_class is an instance of Hyrax::Actors::FileActor" do + Hyrax::Actors::FileSetActor.new("file set", "user").file_actor_class.instance_of? Hyrax::Actors::FileActor + end + end + + + describe "#ability" do + context "when instance variable has a value" do + before { + subject.instance_variable_set(:@ability, "very able") + } + it "returns value of instance variable" do + expect(::Ability).not_to receive(:new) + expect(subject.send(:ability)).to eq "very able" + end + end + + context "when instance variable does not have a value" do + before { + allow(::Ability).to receive(:new).with("active user").and_return "activity level high" + } + it "sets instance variable and returns value" do + expect(subject.send(:ability)).to eq "activity level high" + + subject.instance_variable_get(:@ability) == "activity level high" + end + end + end + + + describe "#build_file_actor" do + before { + allow(subject.file_actor_class).to receive(:new).with("file set", "relation", "active user") + } + it "calls file_actor_class.new" do + expect(subject.file_actor_class).to receive(:new).with("file set", "relation", "active user") + subject.send(:build_file_actor, "relation") + end + end + + + describe "#wrapper!" do + before { + allow(JobIoWrapper).to receive(:create_with_varied_file_handling!).with(user: "active user", + file: "file", + relation: "relation", + file_set: "file set") + } + it "calls JobIoWrapper.create_with_varied_file_handling!" do + expect(JobIoWrapper).to receive(:create_with_varied_file_handling!).with(user: "active user", + file: "file", + relation: "relation", + file_set: "file set") + subject.send(:wrapper!, file:"file", relation:"relation") + end + end + + + describe "#label_for" do + context "when bypass_fedora contains external_filename" do + it "returns external_filename" do + expect(subject.send(:label_for, "file", bypass_fedora: "bypass/fedora")).to eq "fedora" + end + end + + context "when file is an UploadedFile" do + + context "when file uploader has a filename" do + it "returns filename" do + expect(subject.send(:label_for, MockUploadedFile.new("Uploader File"))).to eq "Uploader File" + end + end + + context "when file uploader does not have a filename" do + it "returns file url path" do + expect(subject.send(:label_for, MockUploadedFile.new(""))).to eq "index.html" + end + end + end + + context "when file responds to function original_name" do + it "returns original name" do + expect(subject.send(:label_for, MockFileUpload.new)).to eq "original name" + end + end + + context "when import_url present" do + file_set = OpenStruct.new(import_url: "http://example.com/main.htm") + subject { described_class.new(file_set, "newish user") } + + it "returns import url path" do + expect(subject.send(:label_for, "file")).to eq "main.htm" + end + end + + context "when import_url is not present" do + file_set = OpenStruct.new(import_url: nil) + subject { described_class.new(file_set, "ancient user") } + + before { + allow(File).to receive(:basename).with("file").and_return "file basename" + } + it "returns file basename" do + expect(subject.send(:label_for, "file")).to eq "file basename" + end + end + end + + + describe "#remove_work_id_from_label" do + context "when file_set.parent.id is present" do + it "assigns label with file_set.parent.id removed" do + file_set_mock = MockFileSet.new("opale", "opale_scent", "under the sea") + expect(subject.send(:remove_work_id_from_label, file_set_mock)).to eq "scent" + end + end + + context "when file_set.parent.id is blank" do + it "returns nil" do + file_set_mock = MockFileSet.new(nil, "opalescent", "under the sea") + expect(subject.send(:remove_work_id_from_label, file_set_mock)).to be_blank + end + end + end + + + describe "#assign_visibility?" do + visibility_keys = %w[visibility embargo_release_date lease_expiration_date] + + visibility_keys.each do |key| + context "when argument has relevant key #{key}" do #loop it + it "returns true" do + expect(subject.send(:assign_visibility?, { "#{key}" => "yes" })).to eq true + end + end + end + + context "when argument does not have relevant keys" do + it "returns false" do + expect(subject.send(:assign_visibility?, Hash.new(create_date: "yesterday", update_date: "today"))).to eq false + end + end + + context "when argument does not have keys" do + it "returns false" do + expect(subject.send(:assign_visibility?)).to eq false + end + end + end + + + describe "#depositor_id" do + context "when argument has a user_key method" do + it "returns result of user_key method" do + expect(subject.send(:depositor_id, MockDepositor.new("user key"))).to eq "user key" + end + end + + context "when argument does not have method named user_key" do + it "returns argument" do + expect(subject.send(:depositor_id, "depositor")).to eq "depositor" + end + end + end + + + describe "#unlink_from_work" do + + context "when file_set.parent is not nil but file_set.id is not relevant" do + parent = MockLinkWork.new + file_set = OpenStruct.new(parent: parent, id: "parent id") + subject { described_class.new(file_set, "frequent user") } + + it "returns nil" do + expect(parent).to receive(:total_file_size_subtract_file_set!).with file_set + expect(parent).not_to receive(:save!) + + expect(subject.send(:unlink_from_work)).to be_blank + end + end + + context "when file_set.id is equal to thumbnail_id" do + parent = MockLinkWork.new + file_set = OpenStruct.new(parent: parent, id: "thumbnail id") + subject { described_class.new(file_set, "recent user") } + + it "sets thumbnail to nil, removes file_set.id from rendering_ids, and calls save! on work" do + expect(parent).to receive(:total_file_size_subtract_file_set!).with file_set + expect(parent).to receive(:save!) + + subject.send(:unlink_from_work) + expect(parent.thumbnail).to be_blank + expect(parent.representative).to eq "representative" + expect(parent.rendering_ids).to eq ["rendering id", "representative id"] + end + end + + context "when file_set.id is equal to representative_id" do + parent = MockLinkWork.new + file_set = OpenStruct.new(parent: parent, id: "representative id") + subject { described_class.new(file_set, "popular user") } + + it "sets representative to nil, removes file_set.id from rendering_ids, and calls save! on work" do + expect(parent).to receive(:total_file_size_subtract_file_set!).with file_set + expect(parent).to receive(:save!) + + subject.send(:unlink_from_work) + expect(parent.thumbnail).to eq "thumbnail" + expect(parent.representative).to be_blank + expect(parent.rendering_ids).to eq ["rendering id", "thumbnail id"] + end + end + + context "when file_set.id is in rendering_ids" do + parent = MockLinkWork.new + file_set = OpenStruct.new(parent: parent, id: "rendering id") + subject { described_class.new(file_set, "absent user") } + + it "removes file_set.id from rendering_ids, and calls save! on work" do + expect(parent).to receive(:total_file_size_subtract_file_set!).with file_set + expect(parent).to receive(:save!) + + subject.send(:unlink_from_work) + expect(parent.thumbnail).to eq "thumbnail" + expect(parent.representative).to eq "representative" + expect(parent.rendering_ids).to eq ["thumbnail id", "representative id"] + end + end + end + +end diff --git a/spec/services/deepblue/yaml_populate_service_spec.rb b/spec/services/deepblue/yaml_populate_service_spec.rb index 446a6c4e..efc5c4c7 100644 --- a/spec/services/deepblue/yaml_populate_service_spec.rb +++ b/spec/services/deepblue/yaml_populate_service_spec.rb @@ -6,7 +6,7 @@ def puts text end end -class MockFileSet +class MockMetaData def original_name "original name" end @@ -16,6 +16,34 @@ def to_s end end +class MockFileSetFile + def initialize(original_name) + @original_name = original_name + end + + def original_name + @original_name || "" + end +end + +class ConcernedCuration + + def class + OpenStruct.new(name: "Concerned Curation") + end + + def id + "L-2002" + end + + def provenance_migrate(current_user:, parent_id:, migrate_direction:) + end +end + + + + + RSpec.describe Deepblue::YamlPopulateService do subject { described_class.new } @@ -35,6 +63,50 @@ def expected_attribute_names_user_ignore reset_password_sent_at ] end + def expected_attribute_names_always_include_cc + %w[ admin_set_id + authoremail + creator + creator_ordered + curation_notes_admin + curation_notes_admin_ordered + curation_notes_user + curation_notes_user_ordered + date_coverage + date_created + date_modified + date_published + date_uploaded + depositor + description + description_ordered + doi + fundedby + fundedby_other + grantnumber + isReferencedBy + isReferencedBy_ordered + keyword + keyword_ordered + language + language_ordered + methodology + owner + prior_identifier + referenced_by + referenced_by_ordered + rights_license_other + source + subject_discipline + title + title_ordered + tombstone + access_deepblue + access_deepblue_ordered + total_file_size ] + end + + describe 'constants' do it do expect( Deepblue::YamlPopulateService::DEFAULT_CREATE_ZERO_LENGTH_FILES ).to eq true @@ -42,6 +114,7 @@ def expected_attribute_names_user_ignore end end + describe "#initialize" do it "sets instance variables" do instance_variable_get(:@create_zero_length_files) == true @@ -57,11 +130,11 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_body_collections" do context do concern = OpenStruct.new(id: "XYZ-1000", edit_users: "editors", collection_type: OpenStruct.new(machine_id: "HAL"), work_ids: [101,202,303,404], total_file_size: 203, visibility: "public") - before { allow(subject).to receive(:yaml_item).with "out", "concave", ":id:", "XYZ-1000" allow(subject).to receive(:source).and_return 'DBDv2' @@ -103,6 +176,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_file_size" do context "when file_set.file_size is blank and file_set.original_file is nil" do it "returns 0" do @@ -126,6 +200,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_body_files" do before { allow(subject).to receive(:yaml_line).with("out", "indent", ":file_set_ids:") @@ -205,6 +280,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_body_user_body" do user = OpenStruct.new(email: 'email z') before { @@ -228,6 +304,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_body_users" do before { allow(subject).to receive(:yaml_line).with( "out", "indent", ':user_emails:' ) @@ -257,6 +334,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_body_works" do context "when result of attribute_names_work is in skip array" do concern = OpenStruct.new(id: "id", admin_set_id: "admin set id", edit_users: "edit users", file_set_ids: ["id1", "id2"], @@ -312,6 +390,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_escape_value" do context "when value argument is nil" do it "returns blank" do @@ -344,6 +423,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_export_file_path" do file_set = OpenStruct.new(id: 'file set id') before { @@ -355,6 +435,7 @@ def expected_attribute_names_user_ignore end end + # NOTE: if/else in function doesn't make a difference describe "#yaml_export_file_name" do fileset_arg = OpenStruct.new(title: ["*file^", "set"]) @@ -369,7 +450,7 @@ def expected_attribute_names_user_ignore context "when file is not nil" do before { - allow(Deepblue::MetadataHelper).to receive(:file_from_file_set).with(fileset_arg).and_return MockFileSet.new + allow(Deepblue::MetadataHelper).to receive(:file_from_file_set).with(fileset_arg).and_return MockMetaData.new } it "returns filename appropriate string" do expect(subject.yaml_export_file_name file_set: fileset_arg).to eq "_file_" @@ -377,6 +458,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_file_set_checksum" do context "when file present" do before { @@ -397,8 +479,10 @@ def expected_attribute_names_user_ignore end end + pending "#yaml_filename" + describe "#yaml_filename_collection" do before { allow(subject).to receive(:yaml_filename).with pathname_dir: "pathname", id: "ID", prefix: 'c_', task: "populate" @@ -410,6 +494,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_filename_users" do before { allow(subject).to receive(:yaml_filename).with pathname_dir: "pathname", id: "", prefix: 'users', task: "populate" @@ -421,6 +506,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_filename_work" do before { allow(subject).to receive(:yaml_filename).with pathname_dir: "pathname", id: "identify", prefix: 'w_', task: "populate" @@ -432,6 +518,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_header" do before { allow(DateTime).to receive(:now).and_return DateTime.new(2025, 6, 6, 9, 10, 35) @@ -462,6 +549,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_header_populate" do before { allow(subject).to receive(:yaml_line).with "out", "indent", 'target', comment: true @@ -479,6 +567,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_header_users" do before { allow(subject).to receive(:source).and_return "DBDv3" @@ -502,6 +591,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_is_a_work?" do context "when source is 'DBDv2'" do before { @@ -558,6 +648,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_item_file_set" do context "when ATTRIBUTE_NAMES_IGNORE includes name argument" do it "returns blank" do @@ -581,6 +672,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_item_prior_identifier" do context "when source is 'DBDv1'" do before { @@ -603,6 +695,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_item_referenced_by" do context "when source is 'DBDv1'" do before { @@ -625,6 +718,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_item_rights" do context "when source is 'DBDv1'" do before { @@ -647,6 +741,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_item_subject" do context "when source is 'DBDv1'" do before { @@ -669,6 +764,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_item_user" do context "when ATTRIBUTE_NAMES_USER_IGNORE includes name argument" do it "returns blank" do @@ -692,6 +788,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_item_work" do context "when ATTRIBUTE_NAMES_IGNORE includes name argument" do it "returns blank" do @@ -715,6 +812,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_line" do context "when comment is false" do before { @@ -739,6 +837,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_populate_collection" do object1 = OpenStruct.new(id: 111) object2 = OpenStruct.new(id: 222) @@ -835,6 +934,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_populate_stats" do before { allow(subject).to receive(:human_readable_size).with(0).and_return 100 @@ -850,6 +950,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_populate_users" do context "when out argument is not nil" do before { @@ -887,6 +988,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_populate_work" do context "when out argument is not nil" do before { @@ -954,6 +1056,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_targetdir" do context "when called with an object that is not a Pathname" do it "creates a new Pathname and returns text" do @@ -968,6 +1071,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_targetdir_collection" do before { allow(subject).to receive(:yaml_targetdir).with(pathname_dir: "pathname dir", id: "collection id", prefix: "c_", task: "populate") @@ -978,6 +1082,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_targetdir_users" do before { allow(subject).to receive(:yaml_targetdir).with(pathname_dir: "pathname dir", id: "", prefix: "users", task: "populate") @@ -988,6 +1093,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_targetdir_work" do before { allow(subject).to receive(:yaml_targetdir).with(pathname_dir: "pathname dir", id: "work id", prefix: "w_", task: "populate") @@ -998,12 +1104,14 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_user_email" do it "returns string" do expect(subject.yaml_user_email OpenStruct.new(email: "bpotter@example.com")).to eq "user_bpotter@example.com" end end + describe "#yaml_work_export_files" do exception = StandardError.new("error message") exception.set_backtrace("backtrace") @@ -1026,6 +1134,7 @@ def expected_attribute_names_user_ignore end end + describe "#yaml_work_find" do context "when source is 'DBDv2'" do before { @@ -1047,5 +1156,274 @@ def expected_attribute_names_user_ignore end end - pending "#self.init_attribute_names_always_include_cc" + + describe "#self.init_attribute_names_always_include_cc" do + it "returns hash of ATTRIBUTE_NAMES_ALWAYS_INCLUDE_CC items as keys with values of true" do + expected_result = {} + expected_attribute_names_always_include_cc.each { |name| expected_result[name] = true } + + expect(Deepblue::YamlPopulateService.init_attribute_names_always_include_cc) + .to eq expected_result + end + end + + + # protected methods + + # describe "#attribute_names_always_include_cc" do + # context "when class variable has a value" do + # before { + # Deepblue::YamlPopulateService.class_variable_set :@@attribute_names_always_include_cc, true + # } + # it "returns value of class variable" do + # #expect(subject).not_to receive(:init_attribute_names_always_include_cc) + # expect(subject.send(:attribute_names_always_include_cc)).to eq true + # end + # end + # + # context "when class variable does NOT have a value" do + # before { + # Deepblue::YamlPopulateService.class_variable_set :@@attribute_names_always_include_cc, nil + # allow(subject).to receive(:init_attribute_names_always_include_cc).and_return "always" + # } + # it "returns result of init_attribute_names_always_include_cc method" do + # #expect(subject).to receive(:init_attribute_names_always_include_cc) + # expect(subject.send(:attribute_names_always_include_cc)).to eq "always" + # end + # end + # end + + + describe "#attribute_names_collection" do + context "when class variable has a value" do + before { + Deepblue::YamlPopulateService.class_variable_set :@@attribute_names_collection, "hello" + } + it "returns value of class variable" do + expect(Collection).not_to receive(:attribute_names) + expect(subject.send(:attribute_names_collection)).to eq "hello" + end + end + + context "when class variable has NO value" do + before { + Deepblue::YamlPopulateService.class_variable_set :@@attribute_names_collection, nil + allow(Collection).to receive(:attribute_names).and_return [3,2,1] + } + it "sorts attribute_names from Collection class" do + expect(Collection).to receive(:attribute_names) + expect(subject.send(:attribute_names_collection)).to eq [1,2,3] + end + end + end + + + describe "#attribute_names_file_set" do + context "when class variable has a value" do + before { + Deepblue::YamlPopulateService.class_variable_set :@@attribute_names_file_set, "hey there" + } + it "returns value of class variable" do + expect(FileSet).not_to receive(:attribute_names) + expect(subject.send(:attribute_names_file_set)).to eq "hey there" + end + end + + context "when class variable has NO value" do + before { + Deepblue::YamlPopulateService.class_variable_set :@@attribute_names_file_set, nil + allow(FileSet).to receive(:attribute_names).and_return ["c", "b", "a"] + } + it "sorts attribute_names from FileSet class" do + expect(FileSet).to receive(:attribute_names) + expect(subject.send(:attribute_names_file_set)).to eq ["a", "b", "c"] + end + end + end + + + describe "#attribute_names_user" do + context "when class variable has a value" do + before { + Deepblue::YamlPopulateService.class_variable_set :@@attribute_names_user, "howdy" + } + it "returns value of class variable" do + expect(User).not_to receive(:attribute_names) + expect(subject.send(:attribute_names_user)).to eq "howdy" + end + end + + context "when class variable has NO value" do + before { + Deepblue::YamlPopulateService.class_variable_set :@@attribute_names_user, nil + allow(User).to receive(:attribute_names).and_return [DateTime.new(2025, 10, 1), DateTime.new(2025, 1, 10)] + } + it "sorts attribute_names from User class" do + expect(User).to receive(:attribute_names) + expect(subject.send(:attribute_names_user)).to eq [DateTime.new(2025, 1, 10), DateTime.new(2025, 10, 1)] + end + end + end + + + describe "#attribute_names_work" do + context "when source is 'DBDv2'" do + before { + subject.instance_variable_set(:@source, "DBDv2") + allow(DataSet).to receive(:attribute_names).and_return [1.0, 10, 1.1, 11] + } + it "sorts attribute_names from DataSet class" do + expect(subject.send(:attribute_names_work)).to eq [1, 1.1, 10, 11] + end + end + + context "when source is NOT 'DBDv2'" do + before { + subject.instance_variable_set(:@source, "DBDv1") + allow(GenericWork).to receive(:attribute_names).and_return ["alpha", "zeta", "omega", "beta"] + } + it "sorts attribute_names from GenericWork class" do + expect(subject.send(:attribute_names_work)).to eq ["alpha", "beta", "omega", "zeta"] + end + end + end + + + describe "#file_from_file_set" do + context "when files are nil" do + it "returns nil" do + expect(subject.send(:file_from_file_set, OpenStruct.new(files: nil))).to be_blank + end + end + + context "when files are empty" do + it "returns nil" do + expect(subject.send(:file_from_file_set, OpenStruct.new(files: []))).to be_blank + end + end + + context "when files are present and at least one has an original_name" do + it "returns the last file with an original_name" do + file1 = MockFileSetFile.new("wildly original") + file2 = MockFileSetFile.new("somewhat derivative") + file3 = MockFileSetFile.new("") + file_set_files = OpenStruct.new(files: [file1, file2, file3]) + expect(subject.send(:file_from_file_set, file_set_files)).to eq file2 + end + end + + context "when files are present but all have an empty original_name" do + it "returns the first file" do + file1 = MockFileSetFile.new("") + file2 = MockFileSetFile.new("") + file3 = MockFileSetFile.new("") + file_set_files = OpenStruct.new(files: [file1, file2, file3]) + expect(subject.send(:file_from_file_set, file_set_files)).to eq file1 + end + end + end + + + describe "#human_readable_size" do + before { + allow(ActiveSupport::NumberHelper::NumberToHumanSizeConverter).to receive(:convert).with(1500, precision: 3).and_return "1.5 KB" + } + it "returns result of NumberToHumanSizeConverter.convert" do + expect(subject.send(:human_readable_size, "1500")).to eq "1.5 KB" + end + end + + + describe "#log_lines" do + it "writes lines to file" do + subject.send(:log_lines, "temp_file.txt", ["line1", "line2", "line3"]) + expect(File.read("temp_file.txt")).to eq("line1\nline2\nline3\n") + File.delete("temp_file.txt") # Cleaning up + end + end + + + describe "#log_provenance_migrate" do + context "when source is DBDv1" do + before { + allow(subject).to receive(:source).and_return 'DBDv1' + } + + context "when parent is present" do + msg = "Migrate export Concerned Curation L-2002 parent_id: P-3003" + before { + allow( PROV_LOGGER ).to receive( :info ).with msg + } + it "ProvenanceLogger logs parameters including parent id" do + expect( PROV_LOGGER ).to receive( :info ).with msg + subject.send(:log_provenance_migrate, curation_concern: ConcernedCuration.new, parent: OpenStruct.new(id: "P-3003")) + end + end + + context "when parent is NOT present" do + parent_msg = "Migrate export Concerned Curation L-2002" + before { + allow( PROV_LOGGER ).to receive( :info ).with parent_msg + } + it "ProvenanceLogger logs parameters excluding parent id" do + expect( PROV_LOGGER ).to receive( :info ).with parent_msg + subject.send(:log_provenance_migrate, curation_concern: ConcernedCuration.new) + end + end + end + + context "when source is NOT DBDv1" do + before { + allow(subject).to receive(:source).and_return 'DBDv2' + } + + context "when curation_concern does NOT respond to provenance_migrate" do + it "returns nil" do + expect(subject.send(:log_provenance_migrate, curation_concern: "curation concern")).to be_blank + end + end + + context "when curation_concern responds to provenance_migrate" do + + context "when parent is present" do + it "calls provenance_migrate on curation_concern with parent id" do + cc = ConcernedCuration.new + expect(cc).to receive(:provenance_migrate).with(current_user: nil, parent_id: "P-3003", migrate_direction: "export") + subject.send(:log_provenance_migrate, curation_concern: cc, parent: OpenStruct.new(id: "P-3003")) + end + end + + context "when parent is NOT present" do + it "calls provenance_migrate on curation_concern withOUT parent id" do + cc = ConcernedCuration.new + expect(cc).to receive(:provenance_migrate).with(current_user: nil, parent_id: nil, migrate_direction: "export") + subject.send(:log_provenance_migrate, curation_concern: cc) + end + end + end + end + end + + + describe "#metadata_multi_valued?" do + context "when attribute_value is blank" do + it "returns false" do + expect(subject.send(:metadata_multi_valued?, '')).to eq false + end + end + + context "when attribute_value has multiple values" do + it "returns true" do + expect(subject.send(:metadata_multi_valued?, ["hi", "hello"])).to eq true + end + end + + context "when attribute_value is hash or array with single value" do + it "returns false" do + expect(subject.send(:metadata_multi_valued?, { "goodbye" => "exit"})).to eq false + end + end + end + end +