index.md (4112B)
1 --- 2 title: "Testing Solr and Sunspot (locally and on CircleCI)" 3 date: 2018-11-27T00:00:00+00:00 4 draft: false 5 canonical_url: https://www.viget.com/articles/testing-solr-and-sunspot-locally-and-on-circleci/ 6 --- 7 8 I don't usually write complex search systems, but when I do, I reach 9 for [Solr](http://lucene.apache.org/solr/) and the awesome 10 [Sunspot](http://sunspot.github.io/) gem. I pulled them into a recent 11 client project, and while Sunspot makes it a breeze to define your 12 search indices and queries, its testing philosophy can best be 13 described as "figure it out yourself, smartypants." 14 15 I found a [seven-year old code 16 snippet](https://dzone.com/articles/install-and-test-solrsunspot) that 17 got me most of the way, but needed to make some updates to make it 18 compatible with modern RSpec and account for a delay on Circle between 19 Solr starting and being available to index documents. Here's the 20 resulting config, which should live in `spec/support/sunspot.rb`: 21 22 ```ruby 23 require 'sunspot/rails/spec_helper' 24 require 'net/http' 25 26 try_server = proc do |uri| 27 begin 28 response = Net::HTTP.get_response uri 29 response.code != "503" 30 rescue Errno::ECONNREFUSED 31 end 32 end 33 34 start_server = proc do |timeout| 35 server = Sunspot::Rails::Server.new 36 uri = URI.parse("http://0.0.0.0:#{server.port}/solr/default/update?wt=json") 37 38 try_server[uri] or begin 39 server.start 40 at_exit { server.stop } 41 42 timeout.times.any? do 43 sleep 1 44 try_server[uri] 45 end 46 end 47 end 48 49 original_session = nil # always nil between specs 50 sunspot_server = nil # one server shared by all specs 51 52 if defined? Spork 53 Spork.prefork do 54 sunspot_server = start_server[60] if Spork.using_spork? 55 end 56 end 57 58 RSpec.configure do |config| 59 config.before(:each) do |example| 60 if example.metadata[:solr] 61 sunspot_server ||= start_server[60] || raise("SOLR connection timeout") 62 else 63 original_session = Sunspot.session 64 Sunspot.session = Sunspot::Rails::StubSessionProxy.new(original_session) 65 end 66 end 67 68 config.after(:each) do |example| 69 if example.metadata[:solr] 70 Sunspot.remove_all! 71 else 72 Sunspot.session = original_session 73 end 74 75 original_session = nil 76 end 77 end 78 ``` 79 80 *(Fork me at 81 <https://gist.github.com/dce/3a9b5d8623326214f2e510839e2cac26>.)* 82 83 With this code in place, pass `solr: true` as RSpec metadata[^1] 84 to your `describe`, `context`, and `it` blocks to test against a live 85 Solr instance, and against a stub instance otherwise. 86 87 ## A couple other Sunspot-related things 88 89 While I've got you here, thinking about search, here are a few other 90 neat tricks to make working with Sunspot and Solr easier. 91 92 ### Use Foreman to start all the things 93 94 Install the [Foreman](http://ddollar.github.io/foreman/) gem and create 95 a `Procfile` like so: 96 97 ``` 98 rails: bundle exec rails server -p 3000 99 webpack: bin/webpack-dev-server 100 solr: bundle exec rake sunspot:solr:run 101 ``` 102 103 Then you can boot up all your processes with a simple `foreman start`. 104 105 ### Configure Sunspot to use the same Solr instance in dev and test 106 107 [By 108 default](https://github.com/sunspot/sunspot/blob/3328212da79178319e98699d408f14513855d3c0/sunspot_rails/lib/generators/sunspot_rails/install/templates/config/sunspot.yml), 109 Sunspot wants to run two different Solr processes, listening on two 110 different ports, for the development and test environments. You only 111 need one instance of Solr running --- it'll handle setting up a 112 "core" for each environment. Just set the port to the same number in 113 `config/sunspot.yml` to avoid starting up and shutting down Solr every 114 time you run your test suite. 115 116 ### Sunspot doesn't reindex automatically in test mode 117 118 Just a little gotcha: typically, Sunspot updates the index after every 119 update to an indexed model, but not so in test mode. You'll need to run 120 some combo of `Sunspot.commit` and `[ModelName].reindex` after making 121 changes that you want to test against. 122 123 ------------------------------------------------------------------------ 124 125 That's all I've got. Have a #blessed Tuesday and a happy holiday 126 season. 127 128 [^1]: e.g. `describe "viewing the list of speakers", solr: true do`