Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test ElasticSearch in a Rails application (Rspec)

I was wondering how you were testing the search in your application when using ElasticSearch and Tire.

  • How do you setup a new ElasticSearch test instance? Is there a way to mock it?

  • Any gems you know of that might help with that?


Some stuff I found helpful:

I found a great article answering pretty much all my questions :)

http://bitsandbit.es/post/11295134047/unit-testing-with-tire-and-elastic-search#disqus_thread

Plus, there is an answer from Karmi, Tire author.

This is useful as well: https://github.com/karmi/tire/wiki/Integration-Testing-Rails-Models-with-Tire

I can't believe I did not find these before asking...

like image 869
Robin Avatar asked Mar 12 '12 23:03

Robin


People also ask

How does Elasticsearch integrate with rails?

To get it running: install all gems, create the database (SQLite 3), run an elasticsearch instance in the background and seed the Application with the provided Wikipedia articles within the /db/seed/ directory. After you've got it running go to localhost:3000 and try searching for ruby or language.

How do I run a RSpec test on a file?

Running tests by their file or directory names is the most familiar way to run tests with RSpec. RSpec can take a file name or directory name and run the file or the contents of the directory. So you can do: rspec spec/jobs to run the tests found in the jobs directory.


2 Answers

Prefixing your index-names for the current environment

You could set a different index-name for each environment (in your case: the test environment).

For example, you could create an initializer in

config/initializers/tire.rb 

with the following line:

Tire::Model::Search.index_prefix "#{Rails.application.class.parent_name.downcase}_#{Rails.env.to_s.downcase}" 

A conceivable approach for deleting the indexes

Assuming that you have models named Customer, Order and Product, put the following code somewhere at your test-startup/before-block/each-run-block.

# iterate over the model types # there are also ways to fetch all model classes of the rails app automaticly, e.g.: #   http://stackoverflow.com/questions/516579/is-there-a-way-to-get-a-collection-of-all-the-models-in-your-rails-app [Customer, Order, Product].each do |klass|    # make sure that the current model is using tire   if klass.respond_to? :tire     # delete the index for the current model     klass.tire.index.delete      # the mapping definition must get executed again. for that, we reload the model class.     load File.expand_path("../../app/models/#{klass.name.downcase}.rb", __FILE__)    end end 

Alternative

An alternative could be to set up a different ElasticSearch instance for testing on another port, let's say 1234. In your enviornment/test.rb you could then set

Tire::Configuration.url "http://localhost:1234" 

And at a suitable location (e.g. your testing startup) you can then delete all indexes on the ElasticSearch testing-instance with:

Tire::Configuration.client.delete(Tire::Configuration.url) 

Maybe you must still make sure that your Tire-Mapping definitions for you model classes are still getting called.

like image 130
spaudanjo Avatar answered Oct 01 '22 12:10

spaudanjo


I ran into a quirky bug when deleting my elasticsearch index via tire in my rspec suite. In my Rspec configuration, similar to the Bits and Bytes blog, I have an after_each call which cleans the database and wipes out the index.

I found I needed to call Tire's create_elasticsearch_index method which is responsible for reading the mapping in the ActiveRecord class to set up the appropriate analyzers, etc. The issue I was seeing was I had some :not_analyzed fields in my model which were actually getting analyzed (this broke how I wanted faceting to work).

Everything was fine on dev, but the test suite was failing as facets were being broken down by individual words and not the entire multi word string. It seems that the mapping configuration was not being created appropriately in rspec after the index was deleted. Adding the create_elasticsearch_index call fixed the problem:

config.after(:each) do
  DatabaseCleaner.clean
  Media.tire.index.delete
  Media.tire.create_elasticsearch_index
end

Media is my model class.

like image 21
mhamrah Avatar answered Oct 01 '22 10:10

mhamrah