Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
Rspec with Elasticsearch::Ruby and Elasticsearch::Model
We recently started using Elasticsearch::Ruby on our project and wanted to add some rspec integration tests. The documentation skips over rspec integration but by adapting their sample tests:
# Gemfile
group :test do
  gem 'elasticsearch-extensions'
end
# spec_helper.rb
# Add after other requires. Rake needs to be loaded.
require 'rake'
require 'elasticsearch/extensions/test/cluster/tasks'

RSpec.configure do |config|
  # Snipped other config.
  config.before :each, elasticsearch: true do
    Elasticsearch::Extensions::Test::Cluster.start(port: 9200) unless Elasticsearch::Extensions::Test::Cluster.running?
  end

  config.after :suite do
    Elasticsearch::Extensions::Test::Cluster.stop(port: 9200) if Elasticsearch::Extensions::Test::Cluster.running?
  end
end
It’s important to namespace the index somehow so that your environments don’t clash. We used this.
class User < ActiveRecord::Base
  include Elasticsearch::Model
  include Elasticsearch::Model::Callbacks
  index_name [Rails.env, model_name.collection.gsub(///, '-')].join('_')
end
Then you can add the elasticsearch tag to your rspec blocks:
describe 'Searching for a user', elasticsearch: true do
  before do
    # Create and destroy Elasticsearch indexes
    # between tests to eliminate test pollution
    User.__elasticsearch__.create_index! index: User.index_name

    # There are two options for how you create your objects
    # 1. Create your objects here and they should be synchronised
    # through the Elasticsearch::Model callbacks
    User.create!
    # 2. Call import on the model which should reindex
    # anything you've "let!"
    User.import

    # Sleeping here to allow Elasticsearch test cluster
    # to index the objects we created
    sleep 1
  end

  after do
    User.__elasticsearch__.client.indices.delete index: User.index_name
  end
end

Comments
  1. Very glad to see the `Elasticsearch::Extensions::Test::Cluster`, it’s one of my favourite parts of the gem :)

    Though, shouldn’t you use `before :all` in RSpec? It doesn’t make sense to wait for the cluster to start before _each_ test, does it? You can always wipe all the data with `client.indices.delete index: “all”`.

    Also, notice that by default 2 nodes are launched (https://github.com/elasticsearch/elasticsearch-ruby/blob/master/elasticsearch-extensions/lib/elasticsearch/extensions/test/cluster.rb#L33), you might very well be OK with just one.

  2. James Robert Somers says:

    It was one of my favourite parts too! It shouldn’t start the cluster each test – there is still that check in there to see if it’s already running or not. But yes, you could definitely change that to before :all for less unnecessary checking.

    I didn’t know about delete index all! Super useful; thank you. Keep up the amazing work on Elasticsearch :)

  3. Karel Minarik says:

    Ah, right, true! Haven’t realized that the shutdown runs only after the suite. Still would probably do it in `before :all`, so it’s more “intention revealing” :)

    (Also, there’s support for Rake tasks, so you can use a command like `TEST_CLUSTER_COMMAND=/path/to/elasticsearch-1.2.0-SNAPSHOT/bin/elasticsearch bundle exec rake test:cluster:start` to fire up a testing cluster for fooling around easily)

    (Finally, somehow the command for deleting all indices was mangled, the index value should be `_all`, with an underscore — see the docs http://rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Indices/Actions#delete-instance_method)

  4. Karel Minarik says:

    Just a hopefully final remark :), you can just replace most of the complicated logic in the test setup and just call:

    `User.import force: true, refresh: true`

  5. jed schneider says:

    what is the purpose of including rake in the spec_helper?

  6. Brian Knoles says:

    Thanks for putting this together… it helped me a lot as I set up some es tests in my current project.

    I had some trouble with the startup/shutdown of the cluster. If you check the docs here:

    http://rubydoc.info/gems/elasticsearch-extensions/Elasticsearch/Extensions/Test/Cluster#running%3F-instance_method

    you can see that the running? method defaults to port 9250, so my suite was never shutting down the cluster and trying to start it before every test.

    All I had to do was feed the port into the running? method like so:

    Elasticsearch::Extensions::Test::Cluster.running?(on: 9200)

    and everything in business.

    Also, in case anyone else runs into a timeout error, I had to up the timeout in the start method call on my local machine

    Elasticsearch::Extensions::Test::Cluster.start(port: 9200, timeout: 120)

  7. benj says:

    Interesting article, tough I could not start Elasticsearch::Extensions::Test::Cluster, there is apparently a bug in the last version.

    Anyhow I wanted to suggest: instead of `sleep 1` that may slow down your tests you can force a synchronous index update with `User.__elasticsearch__.client.indices.flush`

  8. dani vale says:

    is not better to use tire gem??

  9. Michael Chinigo says:

    Minor correction that we just ran into: to clear out all indices, you must use “_all” or “*”, not “all”. i.e.

    User.__elasticsearch__.client.indices.delete index: ‘_all’

    (See http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-delete-index.html)

    Otherwise, great tip.

  10. Eli Duke says:

    Thank you so much for this information. I was kind of surprised how little this was documented elsewhere.

    Maybe I’m missing something here, but when add the “include Elasticsearch” stuff to the User model I keep getting “uninitialized constant Elasticsearch::Model (NameError)”. I’m pretty sure I’ve added all the necessary gems and bundled and I can’t figure out how to get past that error.

    Thanks!!

  11. Keith Beckman says:

    Thanks for the post. This really helped me out a LOT.

    I have a quick question though… When I setup the Elasticsearch::Extensions::Test::Cluster and tried to let the elasticsearch index get populated by the Elasticsearch::Model::Callbacks, I couldn’t get it working. I could only get this working if I forced the Model to import all the DB records (via Model.import :refresh => true). Did you guys run into that issue? If so, was there any additional configuration required for that (or was there some setup missing)?

    Thanks.!

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *