Remove all works and then run the import again from a clean slate. This will remove all files and associations and any edits made since the last import will be lost.
+ <%= form.button :submit,
+ value: 'Remove and Rerun',
+ class: 'btn btn-primary',
+ data: {confirm: "Are you sure? This will delete all the works and any associated files and relationships before re running."} %>
+
<% end %>
diff --git a/app/views/bulkrax/importers/_edit_item_buttons.html.erb b/app/views/bulkrax/importers/_edit_item_buttons.html.erb
new file mode 100644
index 000000000..4a7987abc
--- /dev/null
+++ b/app/views/bulkrax/importers/_edit_item_buttons.html.erb
@@ -0,0 +1,18 @@
+
- <%# @todo improve on this implementation.
- As it stands, it's a hostage to namespaces,
- eg. dc:title
+ <%# @todo improve on this implementation.
+ As it stands, it's a hostage to namespaces,
+ eg. dc:title
if namespaces aren't in the xml, we would have to specify dc:title
but if the namespaces ARE present, we remove them so we would need title
%>
- <%= fi.input :record_element,
- hint: 'Provide the xml element name to use to identify the record, or records, eg. ROW - each record in the attached XML is wrapped in a tag.',
+ <%= fi.input :record_element,
+ hint: 'Provide the xml element name to use to identify the record, or records, eg. ROW - each record in the attached XML is wrapped in a tag.',
input_html: { value: importer.parser_fields['record_element'] }
%>
- <%= fi.input :import_type,
+ <%= fi.input :import_type,
collection: [
['Single Work per Metadata File', 'single'],
- ['Multiple Works per Metadata File', 'multiple']
- ],
+ ['Multiple Works per Metadata File', 'multiple']
+ ],
selected: importer.parser_fields['import_type'],
input_html: { class: 'form-control' }
%>
-
+
+ <%= link_to raw(''), item_entry_path(item, e) %>
+ <% if an_importer?(item) %>
+
+ <% end %>
+ <%= link_to raw(''), item_entry_path(item, e), method: :delete, data: { confirm: 'This will delete the entry and any work associated with it. Are you sure?' } %>
+
diff --git a/app/views/hyrax/dashboard/sidebar/_bulkrax_sidebar_additions.html.erb b/app/views/hyrax/dashboard/sidebar/_bulkrax_sidebar_additions.html.erb
index e92a8c47b..16560afec 100644
--- a/app/views/hyrax/dashboard/sidebar/_bulkrax_sidebar_additions.html.erb
+++ b/app/views/hyrax/dashboard/sidebar/_bulkrax_sidebar_additions.html.erb
@@ -1,12 +1,20 @@
<% if current_ability.can_import_works? %>
- <%= menu.nav_link(bulkrax.importers_path,
- title: t('bulkrax.admin.sidebar.importers')) do %>
+ <%= menu.nav_link(
+ bulkrax.importers_path,
+ title: t('bulkrax.admin.sidebar.importers'),
+ class: "nav-link",
+ onclick: "dontChangeAccordion(event);"
+ ) do %>
<%= t('bulkrax.admin.sidebar.importers') %>
<% end %>
<% end %>
<% if current_ability.can_export_works? %>
- <%= menu.nav_link(bulkrax.exporters_path,
- title: t('bulkrax.admin.sidebar.exporters')) do %>
+ <%= menu.nav_link(
+ bulkrax.exporters_path,
+ title: t('bulkrax.admin.sidebar.exporters'),
+ class: "nav-link",
+ onclick: "dontChangeAccordion(event);"
+ ) do %>
<%= t('bulkrax.admin.sidebar.exporters') %>
<% end %>
<% end %>
diff --git a/bulkrax.gemspec b/bulkrax.gemspec
index 2abbd52a3..141330dec 100644
--- a/bulkrax.gemspec
+++ b/bulkrax.gemspec
@@ -21,7 +21,6 @@ Gem::Specification.new do |s|
s.add_dependency 'rails', '>= 5.1.6'
s.add_dependency 'bagit', '~> 0.4.6'
s.add_dependency 'coderay'
- s.add_dependency 'dry-monads', '~> 1.5'
s.add_dependency 'iso8601', '~> 0.9.0'
s.add_dependency 'kaminari'
s.add_dependency 'language_list', '~> 1.2', '>= 1.2.1'
diff --git a/config/locales/bulkrax.en.yml b/config/locales/bulkrax.en.yml
index e73d3c18a..573cc78be 100644
--- a/config/locales/bulkrax.en.yml
+++ b/config/locales/bulkrax.en.yml
@@ -46,18 +46,23 @@ en:
generated_metadata: "These exported fields currently cannot be imported."
importer:
labels:
- name: Name
- user: User
admin_set: Admin set
+ collection_entries: Collection Entries
+ entry_id: Entry ID
+ exporter: Exporter
+ file_set_entries: File Set Entries
frequency: Frequency
- parser_klass: Parser klass
+ identifier: Identifier
+ importer: Importer
limit: Limit
- total_work_entries: Total Works
+ name: Name
+ parser_klass: Parser klass
total_collections: Total Collections
total_file_sets: Total File Sets
+ total_work_entries: Total Works
+ type: Type
+ user: User
work_entries: Work Entries
- collection_entries: Collection Entries
- file_set_entries: File Set Entries
table_header:
labels:
identifier: Identifier
diff --git a/config/routes.rb b/config/routes.rb
index 31f416b3f..e4a709e27 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -3,7 +3,7 @@
Bulkrax::Engine.routes.draw do
resources :exporters do
get :download
- resources :entries, only: %i[show]
+ resources :entries, only: %i[show update destroy]
end
resources :importers do
put :continue
@@ -11,7 +11,7 @@
collection do
post :external_sets
end
- resources :entries, only: %i[show]
+ resources :entries, only: %i[show update destroy]
get :upload_corrected_entries
post :upload_corrected_entries_file
end
diff --git a/db/migrate/20190731114016_change_importer_and_exporter_to_polymorphic.rb b/db/migrate/20190731114016_change_importer_and_exporter_to_polymorphic.rb
index 5e90688ff..c541788f2 100644
--- a/db/migrate/20190731114016_change_importer_and_exporter_to_polymorphic.rb
+++ b/db/migrate/20190731114016_change_importer_and_exporter_to_polymorphic.rb
@@ -6,11 +6,13 @@ class Entry < ApplicationRecord
class ChangeImporterAndExporterToPolymorphic < ActiveRecord::Migration[5.1]
def change
- if column_exists?(:bulkrax_entries, :importer_id)
- remove_foreign_key :bulkrax_entries, column: :importer_id
- remove_index :bulkrax_entries, :importer_id
- rename_column :bulkrax_entries, :importer_id, :importerexporter_id
+ begin # deal with odd bug around foreign keys in ci
+ remove_foreign_key :bulkrax_entries, column: :importer_id if foreign_key_exists?(:bulkrax_entries, column: :importer_id)
+ rescue ArgumentError
+ # do nothing
end
+ remove_index :bulkrax_entries, :importer_id if index_exists?(:bulkrax_entries, :importer_id)
+ rename_column :bulkrax_entries, :importer_id, :importerexporter_id if column_exists?(:bulkrax_entries, :importer_id)
add_column :bulkrax_entries, :importerexporter_type, :string, after: :id, default: 'Bulkrax::Importer' unless column_exists?(:bulkrax_entries, :importerexporter_type)
end
end
diff --git a/db/migrate/20230608153601_add_indices_to_bulkrax.rb b/db/migrate/20230608153601_add_indices_to_bulkrax.rb
index 3c76368a1..d6415aa67 100644
--- a/db/migrate/20230608153601_add_indices_to_bulkrax.rb
+++ b/db/migrate/20230608153601_add_indices_to_bulkrax.rb
@@ -4,11 +4,11 @@ def change
check_and_add_index :bulkrax_entries, :identifier
check_and_add_index :bulkrax_entries, :type
check_and_add_index :bulkrax_entries, [:importerexporter_id, :importerexporter_type], name: 'bulkrax_entries_importerexporter_idx'
- check_and_add_index :bulkrax_pending_relationships, :child_id
check_and_add_index :bulkrax_pending_relationships, :parent_id
- check_and_add_index :bulkrax_statuses, :error_class
- check_and_add_index :bulkrax_statuses, [:runnable_id, :runnable_type], name: 'bulkrax_statuses_runnable_idx'
+ check_and_add_index :bulkrax_pending_relationships, :child_id
check_and_add_index :bulkrax_statuses, [:statusable_id, :statusable_type], name: 'bulkrax_statuses_statusable_idx'
+ check_and_add_index :bulkrax_statuses, [:runnable_id, :runnable_type], name: 'bulkrax_statuses_runnable_idx'
+ check_and_add_index :bulkrax_statuses, :error_class
end
if RUBY_VERSION =~ /^2/
diff --git a/lib/bulkrax.rb b/lib/bulkrax.rb
index 486a92292..3ca099995 100644
--- a/lib/bulkrax.rb
+++ b/lib/bulkrax.rb
@@ -35,6 +35,36 @@ class Configuration
:reserved_properties,
:server_name
+ attr_writer :persistence_adapter
+
+ ##
+ # Configure the persistence adapter used for persisting imported data.
+ #
+ # @return [Bulkrax::PersistenceLayer::AbstractAdapter]
+ # @see Bulkrax::PersistenceLayer
+ def persistence_adapter
+ @persistence_adapter || derived_persistence_adapter
+ end
+
+ def derived_persistence_adapter
+ if defined?(Hyrax)
+ # There's probably some configuration of Hyrax we could use to better refine this; but it's
+ # likely a reasonable guess. The main goal is to not break existing implementations and
+ # maintain an upgrade path.
+ if Gem::Version.new(Hyrax::VERSION) >= Gem::Version.new('6.0.0')
+ Bulkrax::PersistenceLayer::ValkyrieAdapter
+ else
+ Bulkrax::PersistenceLayer::ActiveFedoraAdapter
+ end
+ elsif defined?(ActiveFedora)
+ Bulkrax::PersistenceLayer::ActiveFedoraAdapter
+ elsif defined?(Valkyrie)
+ Bulkrax::PersistenceLayer::ValkyrieAdapter
+ else
+ raise "Unable to derive a persistence adapter"
+ end
+ end
+
attr_writer :use_locking
def use_locking
@@ -81,6 +111,8 @@ def config
:object_factory=,
:parsers,
:parsers=,
+ :persistence_adapter,
+ :persistence_adapter=,
:qa_controlled_properties,
:qa_controlled_properties=,
:related_children_field_mapping,
diff --git a/lib/bulkrax/engine.rb b/lib/bulkrax/engine.rb
index c48313c5b..063afddb5 100644
--- a/lib/bulkrax/engine.rb
+++ b/lib/bulkrax/engine.rb
@@ -13,6 +13,12 @@ class Engine < ::Rails::Engine
end
end
+ initializer 'requires' do
+ require 'bulkrax/persistence_layer'
+ require 'bulkrax/persistence_layer/active_fedora_adapter' if defined?(ActiveFedora)
+ require 'bulkrax/persistence_layer/valkyrie_adapter' if defined?(Valkyrie)
+ end
+
config.generators do |g|
g.test_framework :rspec
begin
diff --git a/lib/bulkrax/entry_spec_helper.rb b/lib/bulkrax/entry_spec_helper.rb
index 3a40325ec..7e0da64e6 100644
--- a/lib/bulkrax/entry_spec_helper.rb
+++ b/lib/bulkrax/entry_spec_helper.rb
@@ -10,13 +10,17 @@ module Bulkrax
#
# This module came about through a desire to expose a quick means of vetting the accuracy of the
# different parsers.
+ #
+ # @see .entry_for
module EntrySpecHelper
##
# @api public
# @since v5.0.1
#
- # The purpose of this method is encapsulate the logic of creating the appropriate Bulkrax::Entry
- # object based on the given data, identifier, and parser_class_name.
+ # The purpose of this method is encapsulate the logic of creating the appropriate
+ # {Bulkrax::Entry} object based on the given data, identifier, and parser_class_name. Due to
+ # the different means of instantiation of {Bulkrax::Entry} subclasses, there are several
+ # optional parameters.
#
# From that entry, you should be able to test how {Bulkrax::Entry#build_metadata} populates the
# {Bulkrax::Entry#parsed_metadata} variable. Other uses may emerge.
@@ -29,9 +33,47 @@ module EntrySpecHelper
# @param parser_class_name [String] The name of the parser class you're wanting to test.
# @param type [Sybmol] The type of entry (e.g. :entry, :collection, :file_set) for testing.
# @param options [Hash] these are to be passed along into the instantiation of
- # the various classes. See implementation details.
+ # the various classes.
+ # @option options [String] importer_name (Optional) The name of the test importer. One will be
+ # auto-assigned if unprovided.
+ # @option options [String] importer_admin_set_id (Optional) The ID of an admin set to deposit
+ # into. One will be auto-assigned if unprovided. And this admin set does not need to
+ # be persisted nor exist. It is simply a required parameter for instantiating an
+ # importer.
+ # @option options [User] user (Optional) The user who is performing the import. One will be
+ # auto-assigned if unprovided. The user does not need to be persisted. It is simply a
+ # required parameter for instantiating an importer
+ # @option options [Integer] limit (Optional) You really shouldn't need to set this, but for
+ # completeness it is provided.
+ # @option options [Hash] importer_field_mappings Each parser class may require
+ # different field mappings. See the given examples for more details.
+ #
+ # @return [Bulkrax::Entry] a subclass of {Bulkrax::Entry} based on the application's
+ # configuration. It would behoove you to write a spec regarding the returned entry's
+ # class.
+ #
+ # @example
+ # entry = Bulkrax::EntrySpecHelper.entry_for(
+ # data: { source_identifier: "123", title: "Hello World" },
+ # parser_class_name: "Bulkrax::CsvParser",
+ # importer_field_mappings: { 'import_file_path' => "path/to/file.csv" }
+ # )
+ #
+ # @note In the case of the Bulkrax::CsvParser, the :data keyword is a Hash, where the keys are
+ # the column name of the CSV you're importing. The 'import_file_path' is a path to a CSV
+ # file. That CSV's columns does not need to match the :data's keys, though there may be
+ # required headers on that CSV based on the parser implementation.
#
- # @return [Bulkrax::Entry]
+ # @example
+ # entry = Bulkrax::EntrySpecHelper.entry_for(
+ # identifier: identifier,
+ # data: File.read("/path/to/some/file.xml"),
+ # parser_class_name: "Bulkrax::OaiDcParser",
+ # parser_fields: { "base_url" => "http://oai.adventistdigitallibrary.org/OAI-script" }
+ # )
+ #
+ # @note In the case of an OaiParser, the :data keyword should be a String. And you'll need to
+ # provide a :parser_fields with a "base_url".
def self.entry_for(data:, identifier:, parser_class_name:, type: :entry, **options)
importer = importer_for(parser_class_name: parser_class_name, **options)
entry_type_method_name = ENTRY_TYPE_TO_METHOD_NAME_MAP.fetch(type)
@@ -58,6 +100,7 @@ def self.entry_for(data:, identifier:, parser_class_name:, type: :entry, **optio
**options)
end
+ ##
# @api public
#
# @param parser_class_name [String]
@@ -121,16 +164,6 @@ def self.importer_for(parser_class_name:, parser_fields: {}, **options)
end
private_class_method :importer_for
- ##
- # @api private
- #
- # @param data [Hash] we're expecting a hash with keys that are symbols and then
- # values that are strings.
- #
- # @return [Bulkrax::CsvEntry]
- #
- # @note As a foible of this implementation, you'll need to include along a CSV to establish the
- # columns that you'll parse (e.g. the first row
def self.build_csv_entry_for(importer:, data:, identifier:, entry_class:, **_options)
entry_class.new(
importerexporter: importer,
@@ -138,13 +171,8 @@ def self.build_csv_entry_for(importer:, data:, identifier:, entry_class:, **_opt
raw_metadata: data
)
end
+ private_class_method :build_csv_entry_for
- ##
- # @api private
- #
- # @param data [String] we're expecting a string that is well-formed XML for OAI parsing.
- #
- # @return [Bulkrax::OaiEntry]
def self.build_oai_entry_for(importer:, data:, identifier:, entry_class:, **options)
# The raw record assumes we take the XML data, parse it and then send that to the
# OAI::GetRecordResponse object.
@@ -165,13 +193,8 @@ def self.build_oai_entry_for(importer:, data:, identifier:, entry_class:, **opti
raw_metadata: raw_metadata
)
end
+ private_class_method :build_oai_entry_for
- ##
- # @api private
- #
- # @param data [String] we're expecting a string that is well-formed XML.
- #
- # @return [Bulkrax::XmlEntry]
def self.build_xml_entry_for(importer:, data:, identifier:, entry_class:, **options)
raw_metadata = {
importer.parser.source_identifier.to_s => identifier,
@@ -186,5 +209,6 @@ def self.build_xml_entry_for(importer:, data:, identifier:, entry_class:, **opti
raw_metadata: raw_metadata
)
end
+ private_class_method :build_xml_entry_for
end
end
diff --git a/lib/bulkrax/persistence_layer.rb b/lib/bulkrax/persistence_layer.rb
new file mode 100644
index 000000000..361e72e42
--- /dev/null
+++ b/lib/bulkrax/persistence_layer.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Bulkrax
+ ##
+ # The target data layer where we write and read our imported {Bulkrax::Entry} objects.
+ module PersistenceLayer
+ # We're inheriting from an ActiveRecord exception as that is something we know will be here; and
+ # something that the main_app will be expect to be able to handle.
+ class ObjectNotFoundError < ActiveRecord::RecordNotFound
+ end
+
+ # We're inheriting from an ActiveRecord exception as that is something we know will be here; and
+ # something that the main_app will be expect to be able to handle.
+ class RecordInvalid < ActiveRecord::RecordInvalid
+ end
+
+ class AbstractAdapter
+ # @see ActiveFedora::Base.find
+ def self.find(id)
+ raise NotImplementedError, "#{self}.#{__method__}"
+ end
+
+ def self.solr_name(field_name)
+ raise NotImplementedError, "#{self}.#{__method__}"
+ end
+
+ # @yield when Rails application is running in test environment.
+ def self.clean!
+ return true unless Rails.env.test?
+ yield
+ end
+
+ def self.query(q, **kwargs)
+ raise NotImplementedError, "#{self}.#{__method__}"
+ end
+ end
+ end
+end
diff --git a/lib/bulkrax/persistence_layer/active_fedora_adapter.rb b/lib/bulkrax/persistence_layer/active_fedora_adapter.rb
new file mode 100644
index 000000000..1aad45031
--- /dev/null
+++ b/lib/bulkrax/persistence_layer/active_fedora_adapter.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Bulkrax
+ module PersistenceLayer
+ class ActiveFedoraAdapter < AbstractAdapter
+ def self.find(id)
+ ActiveFedora::Base.find(id)
+ rescue ActiveFedora::ObjectNotFoundError => e
+ raise PersistenceLayer::RecordNotFound, e.message
+ end
+
+ def self.query(q, **kwargs)
+ ActiveFedora::SolrService.query(q, **kwargs)
+ end
+
+ def self.clean!
+ super do
+ ActiveFedora::Cleaner.clean!
+ end
+ end
+
+ def self.solr_name(field_name)
+ ActiveFedora.index_field_mapper.solr_name(field_name)
+ end
+ end
+ end
+end
diff --git a/lib/bulkrax/persistence_layer/valkyrie_adapter.rb b/lib/bulkrax/persistence_layer/valkyrie_adapter.rb
new file mode 100644
index 000000000..cfa334bbd
--- /dev/null
+++ b/lib/bulkrax/persistence_layer/valkyrie_adapter.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module Bulkrax
+ module PersistenceLayer
+ class ValkyrieAdapter < AbstractAdapter
+ end
+ end
+end
diff --git a/lib/bulkrax/version.rb b/lib/bulkrax/version.rb
index ac10a184b..ea78a8e7b 100644
--- a/lib/bulkrax/version.rb
+++ b/lib/bulkrax/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Bulkrax
- VERSION = '5.3.0'
+ VERSION = '6.0.1'
end
diff --git a/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb b/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb
index 2e887e655..7cf496a10 100644
--- a/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb
+++ b/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb
@@ -49,7 +49,7 @@
# (For more info on importing relationships, see Bulkrax Wiki: https://github.com/samvera-labs/bulkrax/wiki/Configuring-Bulkrax#parent-child-relationship-field-mappings)
#
# # e.g. to add the required source_identifier field
- # # config.field_mappings["Bulkrax::CsvParser"]["source_id"] = { from: ["old_source_id"], source_identifier: true }
+ # # config.field_mappings["Bulkrax::CsvParser"]["source_id"] = { from: ["old_source_id"], source_identifier: true, search_field: 'source_id_sim' }
# If you want Bulkrax to fill in source_identifiers for you, see below
# To duplicate a set of mappings from one parser to another
@@ -82,6 +82,7 @@
end
# Sidebar for hyrax 3+ support
+# rubocop:disable Style/IfUnlessModifier
if Object.const_defined?(:Hyrax) && ::Hyrax::DashboardController&.respond_to?(:sidebar_partials)
Hyrax::DashboardController.sidebar_partials[:repository_content] << "hyrax/dashboard/sidebar/bulkrax_sidebar_additions"
end
diff --git a/lib/tasks/bulkrax_tasks.rake b/lib/tasks/bulkrax_tasks.rake
index b465aef3c..f0a741cb7 100644
--- a/lib/tasks/bulkrax_tasks.rake
+++ b/lib/tasks/bulkrax_tasks.rake
@@ -124,7 +124,7 @@ namespace :bulkrax do
end
def make_new_exports
- Bulkrax::Exporter.all.each { |e| Bulkrax::ExporterJob.perform_later(e.id) }
+ Bulkrax::Exporter.find_each { |e| Bulkrax::ExporterJob.perform_later(e.id) }
rescue => e
puts "(#{e.message})"
end
diff --git a/spec/factories/bulkrax/object_factory_spec.rb b/spec/factories/bulkrax/object_factory_spec.rb
index ce807ac73..5a46ddb8e 100644
--- a/spec/factories/bulkrax/object_factory_spec.rb
+++ b/spec/factories/bulkrax/object_factory_spec.rb
@@ -1,29 +1,4 @@
# frozen_string_literal: true
-require 'rails_helper'
-
-RSpec.describe Bulkrax::ObjectFactory do
- # Why aren't there more tests? In part because so much of the ObjectFactory require that we boot
- # up Fedora and SOLR; something that remains non-desirous due to speed.
- describe "#transform_attributes" do
- context 'default behavior' do
- it "does not empty arrays that only have empty values" do
- attributes = { empty_array: ["", ""], empty_string: "", filled_array: ["A", "B"], filled_string: "A" }
- factory = described_class.new(attributes: attributes, source_identifier_value: 123, work_identifier: "filled_string")
- factory.base_permitted_attributes = %i[empty_array empty_string filled_array filled_string]
- expect(factory.send(:transform_attributes)).to eq(attributes.stringify_keys)
- end
- end
-
- context 'when :transformation_removes_blank_hash_values = true' do
- it "empties arrays that only have empty values" do
- attributes = { empty_array: ["", ""], empty_string: "", filled_array: ["A", "B"], filled_string: "A" }
- factory = described_class.new(attributes: attributes, source_identifier_value: 123, work_identifier: "filled_string")
- factory.base_permitted_attributes = %i[empty_array empty_string filled_array filled_string]
- factory.transformation_removes_blank_hash_values = true
- expect(factory.send(:transform_attributes))
- .to eq({ empty_array: [], empty_string: nil, filled_array: ["A", "B"], filled_string: "A" }.stringify_keys)
- end
- end
- end
-end
+# NOTE: do not put any specs here. FactoryBot autoloads every ruby file in spec/factories so even through it better
+# mirrors the app/ path, we put the ObjectFactory specs in spec/models/bulkrax/object_factory_spec.rb
diff --git a/spec/factories/bulkrax_exporter_runs.rb b/spec/factories/bulkrax_exporter_runs.rb
index 92a748c2d..e7088a4c4 100644
--- a/spec/factories/bulkrax_exporter_runs.rb
+++ b/spec/factories/bulkrax_exporter_runs.rb
@@ -2,11 +2,11 @@
FactoryBot.define do
factory :bulkrax_exporter_run, class: 'Bulkrax::ExporterRun' do
- exporter { nil }
+ exporter { FactoryBot.build(:bulkrax_exporter) }
total_work_entries { 1 }
enqueued_records { 1 }
- processed_records { 1 }
- deleted_records { 1 }
- failed_records { 1 }
+ processed_records { 0 }
+ deleted_records { 0 }
+ failed_records { 0 }
end
end
diff --git a/spec/factories/bulkrax_importer_runs.rb b/spec/factories/bulkrax_importer_runs.rb
index f51f2d93f..f3cf45140 100644
--- a/spec/factories/bulkrax_importer_runs.rb
+++ b/spec/factories/bulkrax_importer_runs.rb
@@ -5,8 +5,8 @@
importer { FactoryBot.build(:bulkrax_importer) }
total_work_entries { 1 }
enqueued_records { 1 }
- processed_records { 1 }
- deleted_records { 1 }
- failed_records { 1 }
+ processed_records { 0 }
+ deleted_records { 0 }
+ failed_records { 0 }
end
end
diff --git a/spec/factories/bulkrax_object_factories.rb b/spec/factories/bulkrax_object_factories.rb
index 0e49a0e42..59e116351 100644
--- a/spec/factories/bulkrax_object_factories.rb
+++ b/spec/factories/bulkrax_object_factories.rb
@@ -6,7 +6,8 @@
new(
attributes: {},
source_identifier_value: :source_identifier,
- work_identifier: :source
+ work_identifier: :source,
+ work_identifier_search_field: 'source_sim'
)
end
end
diff --git a/spec/jobs/bulkrax/delete_work_job_spec.rb b/spec/jobs/bulkrax/delete_work_job_spec.rb
index 73599ae16..a40c0ba47 100644
--- a/spec/jobs/bulkrax/delete_work_job_spec.rb
+++ b/spec/jobs/bulkrax/delete_work_job_spec.rb
@@ -5,8 +5,8 @@
module Bulkrax
RSpec.describe DeleteWorkJob, type: :job do
subject(:delete_work_job) { described_class.new }
- let(:entry) { FactoryBot.build(:bulkrax_entry) }
- let(:importer_run) { FactoryBot.build(:bulkrax_importer_run) }
+ let(:entry) { create(:bulkrax_entry) }
+ let(:importer_run) { create(:bulkrax_importer_run) }
describe 'successful job object removed' do
before do
@@ -18,12 +18,14 @@ module Bulkrax
end
it 'increments :deleted_records' do
- entry.save
- importer_run.save
+ expect(importer_run.enqueued_records).to eq(1)
+ expect(importer_run.deleted_records).to eq(0)
+
delete_work_job.perform(entry, importer_run)
importer_run.reload
- expect(importer_run.enqueued_records).to equal(0)
- expect(importer_run.deleted_records).to equal(2)
+
+ expect(importer_run.enqueued_records).to eq(0)
+ expect(importer_run.deleted_records).to eq(1)
end
end
@@ -35,12 +37,14 @@ module Bulkrax
end
it 'increments :deleted_records' do
- entry.save
- importer_run.save
+ expect(importer_run.enqueued_records).to eq(1)
+ expect(importer_run.deleted_records).to eq(0)
+
delete_work_job.perform(entry, importer_run)
importer_run.reload
- expect(importer_run.enqueued_records).to equal(0)
- expect(importer_run.deleted_records).to equal(2)
+
+ expect(importer_run.enqueued_records).to eq(0)
+ expect(importer_run.deleted_records).to eq(1)
end
end
end
diff --git a/spec/jobs/bulkrax/export_work_job_spec.rb b/spec/jobs/bulkrax/export_work_job_spec.rb
index 183bda396..c4d3176b4 100644
--- a/spec/jobs/bulkrax/export_work_job_spec.rb
+++ b/spec/jobs/bulkrax/export_work_job_spec.rb
@@ -5,23 +5,43 @@
module Bulkrax
RSpec.describe ExportWorkJob, type: :job do
subject(:export_work_job) { described_class.new }
- let(:entry) { FactoryBot.build(:bulkrax_entry) }
- let(:exporter_run) { FactoryBot.build(:bulkrax_exporter_run) }
+ let(:exporter) { create(:bulkrax_exporter, :all) }
+ let(:entry) { create(:bulkrax_entry, importerexporter: exporter) }
+ let(:exporter_run) { create(:bulkrax_exporter_run, exporter: exporter) }
before do
allow(Bulkrax::Entry).to receive(:find).with(1).and_return(entry)
- allow(Bulkrax::ExporterRun).to receive(:find).with(1).and_return(exporter_run)
allow(entry).to receive(:build)
end
describe 'successful job' do
- before do
- allow(entry).to receive(:save).and_return(true)
+ it 'increments :processed_records' do
+ expect(exporter_run.processed_records).to eq(0)
+
+ export_work_job.perform(entry.id, exporter_run.id)
+ exporter_run.reload
+
+ expect(exporter_run.processed_records).to eq(1)
end
- it 'increments :processed_records and decrements enqueued record' do
- expect(exporter_run).to receive(:increment!).with(:processed_records)
- expect(exporter_run).to receive(:decrement!).with(:enqueued_records)
- export_work_job.perform(1, 1)
+
+ it 'decrements :enqueued_records' do
+ expect(exporter_run.enqueued_records).to eq(1)
+
+ export_work_job.perform(entry.id, exporter_run.id)
+ exporter_run.reload
+
+ expect(exporter_run.enqueued_records).to eq(0)
+ end
+
+ it "doesn't change unrelated counters" do
+ expect(exporter_run.failed_records).to eq(0)
+ expect(exporter_run.deleted_records).to eq(0)
+
+ export_work_job.perform(1, exporter_run.id)
+ exporter_run.reload
+
+ expect(exporter_run.failed_records).to eq(0)
+ expect(exporter_run.deleted_records).to eq(0)
end
end
end
diff --git a/spec/jobs/bulkrax/import_file_set_job_spec.rb b/spec/jobs/bulkrax/import_file_set_job_spec.rb
index 092baa81d..962c7c0af 100644
--- a/spec/jobs/bulkrax/import_file_set_job_spec.rb
+++ b/spec/jobs/bulkrax/import_file_set_job_spec.rb
@@ -5,8 +5,8 @@
module Bulkrax
RSpec.describe ImportFileSetJob, type: :job do
subject(:import_file_set_job) { described_class.new }
- let(:importer) { FactoryBot.create(:bulkrax_importer_csv_complex) }
- let(:importer_run) { importer.current_run }
+ let(:importer) { create(:bulkrax_importer_csv_complex) }
+ let(:importer_run) { create(:bulkrax_importer_run, importer: importer) }
let(:entry) { create(:bulkrax_csv_entry_file_set, :with_file_set_metadata, importerexporter: importer) }
let(:factory) { instance_double(ObjectFactory) }
@@ -16,7 +16,6 @@ module Bulkrax
before do
allow(Entry).to receive(:find).with(entry.id).and_return(entry)
- allow(ImporterRun).to receive(:find).with(importer_run.id).and_return(importer_run)
allow(::Hyrax.config).to receive(:curation_concerns).and_return([Work])
allow(::Work).to receive(:where).and_return([])
allow(importer.parser).to receive(:path_to_files).with(filename: 'removed.png').and_return('spec/fixtures/removed.png')
@@ -51,15 +50,49 @@ module Bulkrax
import_file_set_job.perform(entry.id, importer_run.id)
end
- it "updates the importer run's counters" do
- expect(importer_run).to receive(:increment!).with(:processed_records).once
- expect(importer_run).to receive(:increment!).with(:processed_file_sets).once
+ it 'increments :processed_records and :processed_file_sets' do
+ expect(importer_run.processed_records).to eq(0)
+ expect(importer_run.processed_file_sets).to eq(0)
- expect(importer_run).not_to receive(:decrement!).with(:enqueued_records)
- expect(importer_run).not_to receive(:increment!).with(:failed_records)
- expect(importer_run).not_to receive(:increment!).with(:failed_file_sets)
+ import_file_set_job.perform(entry.id, importer_run.id)
+ importer_run.reload
+
+ expect(importer_run.processed_records).to eq(1)
+ expect(importer_run.processed_file_sets).to eq(1)
+ end
+
+ it 'decrements :enqueued_records' do
+ expect(importer_run.enqueued_records).to eq(1)
+
+ import_file_set_job.perform(entry.id, importer_run.id)
+ importer_run.reload
+
+ expect(importer_run.enqueued_records).to eq(0)
+ end
+
+ it "doesn't change unrelated counters" do
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.deleted_records).to eq(0)
+ expect(importer_run.processed_collections).to eq(0)
+ expect(importer_run.failed_collections).to eq(0)
+ expect(importer_run.processed_relationships).to eq(0)
+ expect(importer_run.failed_relationships).to eq(0)
+ expect(importer_run.failed_file_sets).to eq(0)
+ expect(importer_run.processed_works).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
import_file_set_job.perform(entry.id, importer_run.id)
+ importer_run.reload
+
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.deleted_records).to eq(0)
+ expect(importer_run.processed_collections).to eq(0)
+ expect(importer_run.failed_collections).to eq(0)
+ expect(importer_run.processed_relationships).to eq(0)
+ expect(importer_run.failed_relationships).to eq(0)
+ expect(importer_run.failed_file_sets).to eq(0)
+ expect(importer_run.processed_works).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
end
end
@@ -79,8 +112,8 @@ module Bulkrax
end
it "does not update any of importer run's counters" do
- expect(importer_run).not_to receive(:increment!)
- expect(importer_run).not_to receive(:decrement!)
+ expect(ImporterRun).not_to receive(:increment_counter)
+ expect(ImporterRun).not_to receive(:decrement_counter)
end
it 'reschedules the job to try again after a couple minutes' do
@@ -111,8 +144,11 @@ module Bulkrax
end
it "only decrements the importer run's :enqueued_records counter" do
- expect(importer_run).not_to receive(:increment!)
- expect(importer_run).to receive(:decrement!).with(:enqueued_records).once
+ expect(ImporterRun).not_to receive(:increment_counter)
+ expect(ImporterRun)
+ .to receive(:decrement_counter)
+ .with(:enqueued_records, importer_run.id)
+ .once
import_file_set_job.perform(entry.id, importer_run.id)
end
@@ -165,15 +201,49 @@ module Bulkrax
import_file_set_job.perform(entry.id, importer_run.id)
end
- it "updates the importer run's counters" do
- expect(importer_run).to receive(:increment!).with(:failed_records).once
- expect(importer_run).to receive(:increment!).with(:failed_file_sets).once
+ it 'increments :failed_records and :failed_file_sets' do
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.failed_file_sets).to eq(0)
+
+ import_file_set_job.perform(entry.id, importer_run.id)
+ importer_run.reload
+
+ expect(importer_run.failed_records).to eq(1)
+ expect(importer_run.failed_file_sets).to eq(1)
+ end
+
+ it 'decrements :enqueued_records' do
+ expect(importer_run.enqueued_records).to eq(1)
+
+ import_file_set_job.perform(entry.id, importer_run.id)
+ importer_run.reload
+
+ expect(importer_run.enqueued_records).to eq(0)
+ end
- expect(importer_run).not_to receive(:decrement!).with(:enqueued_records)
- expect(importer_run).not_to receive(:increment!).with(:processed_records)
- expect(importer_run).not_to receive(:increment!).with(:processed_file_sets)
+ it "doesn't change unrelated counters" do
+ expect(importer_run.processed_records).to eq(0)
+ expect(importer_run.deleted_records).to eq(0)
+ expect(importer_run.processed_collections).to eq(0)
+ expect(importer_run.failed_collections).to eq(0)
+ expect(importer_run.processed_relationships).to eq(0)
+ expect(importer_run.failed_relationships).to eq(0)
+ expect(importer_run.processed_file_sets).to eq(0)
+ expect(importer_run.processed_works).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
import_file_set_job.perform(entry.id, importer_run.id)
+ importer_run.reload
+
+ expect(importer_run.processed_records).to eq(0)
+ expect(importer_run.deleted_records).to eq(0)
+ expect(importer_run.processed_collections).to eq(0)
+ expect(importer_run.failed_collections).to eq(0)
+ expect(importer_run.processed_relationships).to eq(0)
+ expect(importer_run.failed_relationships).to eq(0)
+ expect(importer_run.processed_file_sets).to eq(0)
+ expect(importer_run.processed_works).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
end
end
end
diff --git a/spec/jobs/bulkrax/import_work_job_spec.rb b/spec/jobs/bulkrax/import_work_job_spec.rb
index 14652c4c6..f55eb50a4 100644
--- a/spec/jobs/bulkrax/import_work_job_spec.rb
+++ b/spec/jobs/bulkrax/import_work_job_spec.rb
@@ -11,7 +11,6 @@ module Bulkrax
before do
allow(Bulkrax::Entry).to receive(:find).with(1).and_return(entry)
- allow(Bulkrax::ImporterRun).to receive(:find).with(importer_run_id).and_return(importer_run)
end
describe 'successful job' do
@@ -20,11 +19,57 @@ module Bulkrax
allow(entry).to receive(:build).and_return(instance_of(Work))
allow(entry).to receive(:status).and_return('Complete')
end
+
it 'increments :processed_records' do
- expect(importer_run).to receive(:increment!).with(:processed_records)
- expect(importer_run).to receive(:increment!).with(:processed_works)
- expect(importer_run).to receive(:decrement!).with(:enqueued_records)
+ expect(importer_run.processed_records).to eq(0)
+
+ import_work_job.perform(1, importer_run_id)
+ importer_run.reload
+
+ expect(importer_run.processed_records).to eq(1)
+ end
+
+ it 'increments :processed_works' do
+ expect(importer_run.processed_works).to eq(0)
+
import_work_job.perform(1, importer_run_id)
+ importer_run.reload
+
+ expect(importer_run.processed_works).to eq(1)
+ end
+
+ it 'decrements :enqueued_records' do
+ expect(importer_run.enqueued_records).to eq(1)
+
+ import_work_job.perform(1, importer_run_id)
+ importer_run.reload
+
+ expect(importer_run.enqueued_records).to eq(0)
+ end
+
+ it "doesn't change unrelated counters" do
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.deleted_records).to eq(0)
+ expect(importer_run.processed_collections).to eq(0)
+ expect(importer_run.failed_collections).to eq(0)
+ expect(importer_run.processed_relationships).to eq(0)
+ expect(importer_run.failed_relationships).to eq(0)
+ expect(importer_run.processed_file_sets).to eq(0)
+ expect(importer_run.failed_file_sets).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
+
+ import_work_job.perform(1, importer_run_id)
+ importer_run.reload
+
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.deleted_records).to eq(0)
+ expect(importer_run.processed_collections).to eq(0)
+ expect(importer_run.failed_collections).to eq(0)
+ expect(importer_run.processed_relationships).to eq(0)
+ expect(importer_run.failed_relationships).to eq(0)
+ expect(importer_run.processed_file_sets).to eq(0)
+ expect(importer_run.failed_file_sets).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
end
end
@@ -32,11 +77,22 @@ module Bulkrax
before do
allow(entry).to receive(:build_for_importer).and_raise(CollectionsCreatedError)
end
- it 'does not call increment' do
- expect(importer_run).not_to receive(:increment!)
- expect(importer_run).not_to receive(:decrement!)
+
+ it 'does not change counters' do
+ expect(importer_run.processed_records).to eq(0)
+ expect(importer_run.processed_works).to eq(0)
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
+
import_work_job.perform(1, importer_run_id)
+ importer_run.reload
+
+ expect(importer_run.processed_records).to eq(0)
+ expect(importer_run.processed_works).to eq(0)
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
end
+
it 'reschedules the job' do
expect(import_work_job).to receive(:reschedule) # rubocop:disable RSpec/SubjectStub
import_work_job.perform(1, importer_run_id)
@@ -47,11 +103,25 @@ module Bulkrax
before do
allow(entry).to receive(:build).and_return(nil)
end
- it 'increments :failed_records' do
- expect(importer_run).to receive(:increment!).with(:failed_records)
- expect(importer_run).to receive(:increment!).with(:failed_works)
- expect(importer_run).to receive(:decrement!).with(:enqueued_records)
+
+ it 'increments :failed_records and :failed_works' do
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
+
import_work_job.perform(1, importer_run_id)
+ importer_run.reload
+
+ expect(importer_run.failed_records).to eq(1)
+ expect(importer_run.failed_works).to eq(1)
+ end
+
+ it 'decrements :enqueued_records' do
+ expect(importer_run.enqueued_records).to eq(1)
+
+ import_work_job.perform(1, importer_run_id)
+ importer_run.reload
+
+ expect(importer_run.enqueued_records).to eq(0)
end
end
@@ -59,10 +129,25 @@ module Bulkrax
before do
allow(entry).to receive(:build).and_raise(OAIError)
end
- it 'increments :failed_records' do
+
+ it 'does not increment :failed_records or :failed_works' do
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
+
expect { import_work_job.perform(1, importer_run_id) }.to raise_error(OAIError)
- expect(importer_run).not_to receive(:increment!).with(:failed_records)
- expect(importer_run).not_to receive(:decrement!).with(:enqueued_records)
+ importer_run.reload
+
+ expect(importer_run.failed_records).to eq(0)
+ expect(importer_run.failed_works).to eq(0)
+ end
+
+ it 'does not decrement :enqueued_records' do
+ expect(importer_run.enqueued_records).to eq(1)
+
+ expect { import_work_job.perform(1, importer_run_id) }.to raise_error(OAIError)
+ importer_run.reload
+
+ expect(importer_run.enqueued_records).to eq(1)
end
end
end
diff --git a/spec/lib/bulkrax_spec.rb b/spec/lib/bulkrax_spec.rb
index d914ee9be..4701b004a 100644
--- a/spec/lib/bulkrax_spec.rb
+++ b/spec/lib/bulkrax_spec.rb
@@ -197,4 +197,12 @@
expect(returned_value).to eq("file")
end
end
+
+ context '.persistence_adapter' do
+ subject { described_class.persistence_adapter }
+ it { is_expected.to respond_to(:find) }
+ it { is_expected.to respond_to(:query) }
+ it { is_expected.to respond_to(:solr_name) }
+ it { is_expected.to respond_to(:clean!) }
+ end
end
diff --git a/spec/models/bulkrax/object_factory_spec.rb b/spec/models/bulkrax/object_factory_spec.rb
index efe191aa0..2c888feab 100644
--- a/spec/models/bulkrax/object_factory_spec.rb
+++ b/spec/models/bulkrax/object_factory_spec.rb
@@ -5,11 +5,42 @@
module Bulkrax
# NOTE: Unable to put this file in spec/factories/bulkrax (where it would mirror the path in app/) because
# (presumably) FactoryBot autoloads all files in spec/factories, which would always run this spec.
+ # Why aren't there more tests? In part because so much of the ObjectFactory require that we boot
+ # up Fedora and SOLR; something that remains non-desirous due to speed.
+
RSpec.describe ObjectFactory do
subject(:object_factory) { build(:object_factory) }
describe 'is capable of looking up records dynamically' do
include_examples 'dynamic record lookup'
end
+
+ describe "#transform_attributes" do
+ context 'default behavior' do
+ it "does not empty arrays that only have empty values" do
+ attributes = { empty_array: ["", ""], empty_string: "", filled_array: ["A", "B"], filled_string: "A" }
+ factory = described_class.new(attributes: attributes,
+ source_identifier_value: 123,
+ work_identifier: "filled_string",
+ work_identifier_search_field: 'filled_string_sim')
+ factory.base_permitted_attributes = %i[empty_array empty_string filled_array filled_string]
+ expect(factory.send(:transform_attributes)).to eq(attributes.stringify_keys)
+ end
+ end
+
+ context 'when :transformation_removes_blank_hash_values = true' do
+ it "empties arrays that only have empty values" do
+ attributes = { empty_array: ["", ""], empty_string: "", filled_array: ["A", "B"], filled_string: "A" }
+ factory = described_class.new(attributes: attributes,
+ source_identifier_value: 123,
+ work_identifier: "filled_string",
+ work_identifier_search_field: 'filled_string_sim')
+ factory.base_permitted_attributes = %i[empty_array empty_string filled_array filled_string]
+ factory.transformation_removes_blank_hash_values = true
+ expect(factory.send(:transform_attributes))
+ .to eq({ empty_array: [], empty_string: nil, filled_array: ["A", "B"], filled_string: "A" }.stringify_keys)
+ end
+ end
+ end
end
end
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index 386ec8ec2..d0d48acd3 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -69,7 +69,7 @@
end
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
- config.fixture_path = "#{::Rails.root}/spec/fixtures"
+ config.fixture_path = Rails.root.join('spec', 'fixtures')
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
diff --git a/spec/test_app/app/controllers/application_controller.rb b/spec/test_app/app/controllers/application_controller.rb
index 354ff36df..62e308956 100644
--- a/spec/test_app/app/controllers/application_controller.rb
+++ b/spec/test_app/app/controllers/application_controller.rb
@@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
include Blacklight::Controller
include Hyrax::ThemedLayoutController
with_themed_layout '1_column'
- skip_after_action :discard_flash_if_xhr
+ skip_after_action :discard_flash_if_xhr if
+ Rails.version.split('.').first.to_i < 6
protect_from_forgery with: :exception
-
end
diff --git a/spec/test_app/app/helpers/application_helper.rb b/spec/test_app/app/helpers/application_helper.rb
index 15b06f0f6..e6fbe7222 100644
--- a/spec/test_app/app/helpers/application_helper.rb
+++ b/spec/test_app/app/helpers/application_helper.rb
@@ -1,4 +1,6 @@
# frozen_string_literal: true
module ApplicationHelper
+ include ::Hyrax::HyraxHelperBehavior if defined?(::Hyrax)
+
end
diff --git a/spec/test_app/config/application.rb b/spec/test_app/config/application.rb
index 16c5c5d6b..af0ed0959 100644
--- a/spec/test_app/config/application.rb
+++ b/spec/test_app/config/application.rb
@@ -19,7 +19,6 @@ module TestApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.1
- config.active_record.sqlite3.represent_boolean_as_integer = true
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
diff --git a/spec/test_app/db/schema.rb b/spec/test_app/db/schema.rb
index 054b476fc..70580d6ec 100644
--- a/spec/test_app/db/schema.rb
+++ b/spec/test_app/db/schema.rb
@@ -99,8 +99,6 @@
t.integer "total_file_set_entries", default: 0
t.integer "processed_works", default: 0
t.integer "failed_works", default: 0
- t.integer "processed_children", default: 0
- t.integer "failed_children", default: 0
t.index ["importer_id"], name: "index_bulkrax_importer_runs_on_importer_id"
end