Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add some Indexing and search behavior integration tests #4343

Merged
merged 4 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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