5.1 KiB
title, date, draft, needs_review, canonical_url
| title | date | draft | needs_review | canonical_url |
|---|---|---|---|---|
| Testing Solr and Sunspot (locally and on CircleCI) | 2018-11-27T00:00:00+00:00 | false | true | https://www.viget.com/articles/testing-solr-and-sunspot-locally-and-on-circleci/ |
I don't usually write complex search systems, but when I do, I reach for Solr and the awesome Sunspot gem. I pulled them into a recent client project, and while Sunspot makes it a breeze to define your search indicies and queries, its testing philosophy can best be described as "figure it out yourself, smartypants."
I found a seven-year old code
snippet that
got me most of the way, but needed to make some updates to make it
compatible with modern RSpec and account for a delay on Circle between
Solr starting and being available to index documents. Here's the
resulting config, which should live in spec/support/sunspot.rb:
require 'sunspot/rails/spec_helper'
require 'net/http'
try_server = proc do |uri|
begin
response = Net::HTTP.get_response uri
response.code != "503"
rescue Errno::ECONNREFUSED
end
end
start_server = proc do |timeout|
server = Sunspot::Rails::Server.new
uri = URI.parse("http://0.0.0.0:#{server.port}/solr/default/update?wt=json")
try_server[uri] or begin
server.start
at_exit { server.stop }
timeout.times.any? do
sleep 1
try_server[uri]
end
end
end
original_session = nil # always nil between specs
sunspot_server = nil # one server shared by all specs
if defined? Spork
Spork.prefork do
sunspot_server = start_server[60] if Spork.using_spork?
end
end
RSpec.configure do |config|
config.before(:each) do |example|
if example.metadata[:solr]
sunspot_server ||= start_server[60] || raise("SOLR connection timeout")
else
original_session = Sunspot.session
Sunspot.session = Sunspot::Rails::StubSessionProxy.new(original_session)
end
end
config.after(:each) do |example|
if example.metadata[:solr]
Sunspot.remove_all!
else
Sunspot.session = original_session
end
original_session = nil
end
end
(Fork me at https://gist.github.com/dce/3a9b5d8623326214f2e510839e2cac26.)
With this code in place, pass solr: true as RSpec metadata^1^
to your describe, context, and it blocks to test against a live
Solr instance, and against a stub instance otherwise.
[]{#a-couple-other-sunspot-related-things}
A couple other Sunspot-related things #
While I've got you here, thinking about search, here are a few other neat tricks to make working with Sunspot and Solr easier.
[]{#use-foreman-to-start-all-the-things}
Use Foreman to start all the things #
Install the Foreman gem and create
a Procfile like so:
rails: bundle exec rails server -p 3000
webpack: bin/webpack-dev-server
solr: bundle exec rake sunspot:solr:run
Then you can boot up all your processes with a simple foreman start.
[]{#configure-sunspot-to-use-the-same-solr-instance-in-dev-and-test}
Configure Sunspot to use the same Solr instance in dev and test #
By
default,
Sunspot wants to run two different Solr processes, listening on two
different ports, for the development and test environments. You only
need one instance of Solr running --- it'll handle setting up a
"core" for each environment. Just set the port to the same number in
config/sunspot.yml to avoid starting up and shutting down Solr every
time you run your test suite.
[]{#sunspot-doesnt-reindex-automatically-in-test-mode}
Sunspot doesn't reindex automatically in test mode #
Just a little gotcha: typically, Sunspot updates the index after every
update to an indexed model, but not so in test mode. You'll need to run
some combo of Sunspot.commit and [ModelName].reindex after making
changes that you want to test against.
That's all I've got. Have a #blessed Tuesday and a happy holiday season.
[1.]{#f1} e.g. describe "viewing the list of speakers", solr: true do
↩