Back to Repositories

Testing Partial Reindex Operations in Searchkick

This test suite verifies partial reindexing functionality in Searchkick, focusing on both inline and async reindexing operations for individual records and relations. The tests ensure proper index updates when specific fields are modified while maintaining data integrity.

Test Coverage Overview

The test suite provides comprehensive coverage of Searchkick’s partial reindexing capabilities. Key functionality tested includes inline relation reindexing, single record reindexing, async reindexing operations, and error handling for missing documents. Integration points between the application models and search index are thoroughly verified.

  • Relation-level partial reindexing
  • Record-level partial reindexing
  • Async reindexing operations
  • Missing document scenarios

Implementation Analysis

The testing approach employs a systematic verification of search index updates, using both relation-based and record-based partial reindexing methods. The implementation utilizes Searchkick’s callback management and refresh mechanisms to ensure accurate test state. Test patterns include setup-action-verification sequences with explicit index refreshes.

  • Callback management with Searchkick.callbacks
  • Index refresh control
  • Field-specific search assertions

Technical Details

  • Testing Framework: Minitest
  • Search Engine: Elasticsearch (via Searchkick)
  • Test Helpers: Custom assert_search method
  • Setup: Product model with searchable attributes
  • Index Management: Direct index manipulation

Best Practices Demonstrated

The test suite exemplifies strong testing practices through isolated test cases, clear setup and verification steps, and comprehensive error scenario coverage. Each test focuses on a specific aspect of partial reindexing, with explicit state management and verification of both positive and negative cases.

  • Isolated test scenarios
  • Explicit index state management
  • Comprehensive error handling
  • Clear test case organization

ankane/searchkick

test/partial_reindex_test.rb

            
require_relative "test_helper"

class PartialReindexTest < Minitest::Test
  def test_relation_inline
    store [{name: "Hi", color: "Blue"}]

    # normal search
    assert_search "hi", ["Hi"], fields: [:name], load: false
    assert_search "blue", ["Hi"], fields: [:color], load: false

    # update
    product = Product.first
    product.name = "Bye"
    product.color = "Red"
    Searchkick.callbacks(false) do
      product.save!
    end
    Product.searchkick_index.refresh

    # index not updated
    assert_search "hi", ["Hi"], fields: [:name], load: false
    assert_search "blue", ["Hi"], fields: [:color], load: false

    # partial reindex
    Product.reindex(:search_name)

    # name updated, but not color
    assert_search "bye", ["Bye"], fields: [:name], load: false
    assert_search "blue", ["Bye"], fields: [:color], load: false
  end

  def test_record_inline
    store [{name: "Hi", color: "Blue"}]

    # normal search
    assert_search "hi", ["Hi"], fields: [:name], load: false
    assert_search "blue", ["Hi"], fields: [:color], load: false

    # update
    product = Product.first
    product.name = "Bye"
    product.color = "Red"
    Searchkick.callbacks(false) do
      product.save!
    end
    Product.searchkick_index.refresh

    # index not updated
    assert_search "hi", ["Hi"], fields: [:name], load: false
    assert_search "blue", ["Hi"], fields: [:color], load: false

    product.reindex(:search_name, refresh: true)

    # name updated, but not color
    assert_search "bye", ["Bye"], fields: [:name], load: false
    assert_search "blue", ["Bye"], fields: [:color], load: false
  end

  def test_record_async
    product = Product.create!(name: "Hi")
    product.reindex(:search_data, mode: :async)
  end

  def test_relation_missing
    store [{name: "Hi", color: "Blue"}]

    product = Product.first
    Product.searchkick_index.remove(product)

    error = assert_raises(Searchkick::ImportError) do
      Product.reindex(:search_name)
    end
    assert_match "document missing", error.message
  end

  def test_record_missing
    store [{name: "Hi", color: "Blue"}]

    product = Product.first
    Product.searchkick_index.remove(product)

    error = assert_raises(Searchkick::ImportError) do
      product.reindex(:search_name)
    end
    assert_match "document missing", error.message
  end
end