Skip to content

Commit

Permalink
Merge pull request #4343 from sul-dlss/indexing-integration-tests
Browse files Browse the repository at this point in the history
add some Indexing and search behavior integration tests
  • Loading branch information
justinlittman authored Mar 13, 2024
2 parents 48a3b62 + 90c9320 commit e0e9929
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 5 deletions.
2 changes: 2 additions & 0 deletions app/helpers/blacklight_config_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

# Used in CatalogController. This module is split out because catalog_controller.rb
# contains all the required blacklight configurations and is plenty large enough.
#
# See spec/features/indexing_xxx_spec.rb for relevancy tests of Solr search results
module BlacklightConfigHelper
# sending these values to Solr as arguments with search requests will override
# the default params configured for Solr searching via solrconfig.xml
Expand Down
4 changes: 2 additions & 2 deletions solr_conf/conf/solrconfig.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
<str name="dir">${solr.core1.data.dir:}</str>
</updateLog>
<autoCommit>
<maxTime>${solr.autoCommit.maxTime:600000}</maxTime><!-- 10 minutes -->
<maxTime>${solr.autoCommit.maxTime:500}</maxTime><!-- 0.5 seconds (for local tests) -->
<openSearcher>false</openSearcher>
</autoCommit>
<autoSoftCommit>
<maxTime>${solr.autoSoftCommit.maxTime:5000}</maxTime><!-- 5 seconds -->
<maxTime>${solr.autoSoftCommit.maxTime:100}</maxTime><!-- 0.1 seconds (for local tests) -->
</autoSoftCommit>
</updateHandler>

Expand Down
13 changes: 10 additions & 3 deletions spec/factories/items.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# frozen_string_literal: true

# Because we are instantiating an immutable cocina-model rather than a database record,
# nested hash structure values (e.g. a title value in a description)
# may require a setter method in ItemMethodSender before they can be passed in
FactoryBot.define do
factory :persisted_item, class: 'Cocina::Models::RequestDRO' do
initialize_with do
Expand All @@ -8,9 +11,7 @@
'type' => type,
'label' => label,
'version' => 1,
'identification' => {
'sourceId' => "sul:#{SecureRandom.uuid}"
},
'identification' => identification,
'administrative' => {
'hasAdminPolicy' => admin_policy_id
},
Expand All @@ -30,6 +31,12 @@
admin_policy_id { 'druid:hv992ry2431' }
label { 'test object' }
type { Cocina::Models::ObjectType.object }
source_id { "sul:#{SecureRandom.uuid}" }
identification do
{
'sourceId' => source_id
}
end

factory :agreement do
type { Cocina::Models::ObjectType.agreement }
Expand Down
170 changes: 170 additions & 0 deletions spec/features/indexing_identifiers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# frozen_string_literal: true

require 'rails_helper'

# Integration tests for expected behaviors of our Solr indexing choices, through
# our whole stack: tests create cocina objects with factories, write them
# to dor-services-app, index the new objects via dor-indexing-app and then use
# the Argo UI to test Solr behavior such as search results and facet values.
RSpec.describe 'Indexing and search results for identifiers' do
let(:item) { FactoryBot.create_for_repository(:persisted_item) }
let(:blacklight_config) { CatalogController.blacklight_config }
let(:solr_conn) { blacklight_config.repository_class.new(blacklight_config).connection }
let(:solr_id) { item.externalIdentifier }

before do
sign_in create(:user), groups: ['sdr:administrator-role']
solr_conn.commit # ensure no deletes are pending
visit '/'
end

after do
solr_conn.delete_by_id(solr_id)
solr_conn.commit
end

describe 'identifier searching' do
context 'for druids' do
let(:prefixed_druid) { item.externalIdentifier }

it 'matches query with bare and prefixed druid' do
[prefixed_druid, prefixed_druid.split(':').last].each do |query|
fill_in 'q', with: query
click_button 'search'
expect(page).to have_content('1 entry found')
expect(page).to have_css('dd.blacklight-id', text: solr_id)
end
end
end

context 'for sourceids' do
# SPEC: Source ID: M2549_2022-259_stertzer, where M2549 is the collection number and 2022-259 is the accession number
# sul:M0997_S1_B473_021_0001 (S is for series, B is for box, F is for folder ...)
let(:source_id) { "sul:M2549_2022-259_stertzer_#{SecureRandom.alphanumeric(12)}" }
let(:item) { FactoryBot.create_for_repository(:persisted_item, source_id:) }

before do
item.identification.sourceId # ensure item is created before searching
end

it 'matches whole string, including prefix before first colon' do
fill_in 'q', with: source_id
click_button 'search'
# expect a single result, but Solr may not finish commit for previous test delete in time
# expect(page).to have_content('1 entry found')
expect(page).to have_css('dd.blacklight-id', text: solr_id)
end

it 'matches without prefix before the first colon' do
fill_in 'q', with: source_id.split(':').last
click_button 'search'
# expect a single result, but Solr may not finish commit for previous test delete in time
# expect(page).to have_content('1 entry found')
expect(page).to have_css('dd.blacklight-id', text: solr_id)
end

it 'matches source_id fragments' do
fragments = [
'M2549',
'2022-259', # accession number
'M2549_2022-259',
'M2549 2022 259',
'stertzer',
'259_stertzer',
'259-stertzer',
'259 stertzer'
]
fragments.each do |fragment|
fill_in 'q', with: fragment
click_button 'search'
# expect a single result, but Solr may not finish commit for previous test delete in time
# expect(page).to have_content('1 entry found')
expect(page).to have_css('dd.blacklight-id', text: solr_id)
end
end

it 'is not case sensitive' do
fill_in 'q', with: 'm2549 STERTZER'
click_button 'search'
# expect a single result, but Solr may not finish commit for previous test delete in time
# expect(page).to have_content('1 entry found')
expect(page).to have_css('dd.blacklight-id', text: solr_id)
end

punctuation_source_ids = [
'sulcons:8552-RB_Miscellanies_agabory,Before treatment photos',
'Archiginnasio:Bassi_Box10_Folder2_Item3.14',
'Revs:2012-015GHEW-CO-1980-b1_1.16_0007'
]
punctuation_source_ids.each do |punctuation_source_id|
context "when punctuation in #{punctuation_source_id}" do
let(:source_id) { "#{punctuation_source_id}.#{SecureRandom.alphanumeric(4)}" }

it 'matches without punctuation' do
fill_in 'q', with: source_id.gsub(/[_\-:.,]/, ' ')
click_button 'search'
expect(page).to have_css('dd.blacklight-id', text: solr_id)
end
end
end
end

context 'for barcodes' do
let(:barcode) { '20503740296' }
let(:item) do
FactoryBot.create_for_repository(:persisted_item, identification: {
sourceId: "sul:#{SecureRandom.uuid}",
barcode:
})
end

before do
item.identification.barcode # ensure item is created before searching
end

it 'matches query with bare and prefixed barcode' do
[barcode, "barcode:#{barcode}"].each do |query|
fill_in 'q', with: query
click_button 'search'
expect(page).to have_content('1 entry found')
expect(page).to have_css('dd.blacklight-id', text: solr_id)
end
end
end

context 'for ILS (folio) identifiers' do
let(:catalog_id) { 'a11403803' }
let(:item) do
FactoryBot.create_for_repository(:persisted_item, identification: {
sourceId: "sul:#{SecureRandom.uuid}",
catalogLinks: [{
catalog: 'folio',
refresh: false,
catalogRecordId: catalog_id
}]
})
end

before do
item.identification.catalogLinks # ensure item is created before searching
end

it 'matches catalog identifier with and without folio prefix' do
[catalog_id, "folio:#{catalog_id}"].each do |query|
fill_in 'q', with: query
click_button 'search'
expect(page).to have_content('1 entry found')
expect(page).to have_css('dd.blacklight-id', text: solr_id)
end
end
end

context 'for DOIs' do
# is there a reason to tokenize DOIs?

it 'matches bare and "doi:" prefixed DOIs' do
skip('write this test')
end
end
end
end
15 changes: 15 additions & 0 deletions spec/support/item_method_sender.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
# frozen_string_literal: true

# Used in conjunction with factories/items.rb to create a Cocina::Models::RequestDRO,
# allowing for customization of fields/values in the immutable cocina-model.
class ItemMethodSender
def initialize(cocina_request)
@cocina_model = cocina_request
end

attr_reader :cocina_model

# @example
# item = create(:persisted_item, title: 'simple title value')
def title=(title)
@cocina_model = @cocina_model.new(description: { title: [{ value: title }] })
end

# @param [Array<Hash>] title_values - an array of arbitrarily complex cocina title values
# @example
# item = create(:persisted_item, title_values: [{ value: 'simple title value' }, { value: 'another title' }])
def title_values=(title_values)
@cocina_model = @cocina_model.new(description: { title: title_values })
end

# @example
# item = create(:persisted_item, source_id: 'sul:M932_1623_B1_F1_001')
def source_id=(source_id)
@cocina_model = @cocina_model.new(identification: @cocina_model.identification.new(sourceId: source_id))
end

# @example
# item = create(:persisted_item, collection_id: 'druid:rt923rd3423')
def collection_id=(collection_id)
@cocina_model = @cocina_model.new(structural: Cocina::Models::DROStructural.new(isMemberOf: [collection_id]))
end
Expand Down

0 comments on commit e0e9929

Please sign in to comment.