spec/supernova/solr_indexer_spec.rb in supernova-0.2.2 vs spec/supernova/solr_indexer_spec.rb in supernova-0.3.0
- old
+ new
@@ -1,22 +1,31 @@
require "spec_helper"
describe Supernova::SolrIndexer do
-
+ let(:indexer_clazz) { Class.new(Supernova::SolrIndexer) }
let(:db) { double("db", :query => [to_index]) }
let(:to_index) { { :id => 1, :title => "Some Title"} }
let(:file_stub) { double("file").as_null_object }
- let(:indexer) {
+ let(:indexer) do
indexer = Supernova::SolrIndexer.new
indexer.db = db
Supernova::Solr.url = "http://solr.xx:9333/solr"
indexer.stub!(:system).and_return true
indexer
- }
+ end
+ let(:custom_indexer) { indexer_clazz.new }
+
before(:each) do
+ indexer_clazz.has(:title, :type => :text)
+ indexer_clazz.has(:artist_id, :type => :integer)
+ indexer_clazz.has(:description, :type => :text)
+ indexer_clazz.has(:created_at, :type => :date)
+ end
+
+ before(:each) do
File.stub!(:open).and_return file_stub
end
describe "initialize" do
it "sets all options" do
@@ -27,12 +36,88 @@
it "sets all known attributes" do
indexer = Supernova::SolrIndexer.new(:db => db)
indexer.db.should == db
end
+
+ it "can be initialized with ids" do
+ Supernova::SolrIndexer.new(:ids => [1, 2]).ids.should == [1, 2]
+ end
+
+ it "sets ids to all when nil" do
+ Supernova::SolrIndexer.new.ids.should == :all
+ end
end
+ describe "index!" do
+ it "calls query_to_index" do
+ indexer.should_receive(:query_to_index).and_return "some query"
+ indexer.index!
+ end
+
+ it "calls index_query on query_to_index" do
+ query = "some query"
+ indexer.stub!(:query_to_index).and_return query
+ indexer.should_receive(:index_query).with(query)
+ indexer.index!
+ end
+
+ it "calls row_to_solr with all returned rows from sql" do
+ row1 = double("row1")
+ row2 = double("row2")
+ indexer.stub!(:query).and_return [row1, row2]
+ indexer.stub!(:query_to_index).and_return "some query"
+ indexer.should_receive(:row_to_solr).with(row1)
+ indexer.stub!(:index_query).and_yield(row1)
+ indexer.index!
+ end
+ end
+
+ describe "validate_lat" do
+ { nil => nil, 10 => 10.0, 90.1 => nil, 90 => 90, -90.1 => nil, -90 => -90 }.each do |from, to|
+ it "converts #{from} to #{to}" do
+ indexer.validate_lat(from).should == to
+ end
+ end
+ end
+
+ describe "validate_lng" do
+ { nil => nil, 10 => 10.0, 180.1 => nil, 180 => 180, -180.1 => nil, -180 => -180 }.each do |from, to|
+ it "converts #{from} to #{to}" do
+ indexer.validate_lng(from).should == to
+ end
+ end
+ end
+
+ describe "#sql_column_from_field_and_type" do
+ {
+ [:title, :string] => "title AS title_s",
+ [:count, :int] => "count AS count_i",
+ [:test, :sint] => "test AS test_si",
+ [:lat, :float] => "lat AS lat_f",
+ [:text, :boolean] => "text AS text_b",
+ [:loc, :location] => "loc AS loc_p",
+ [:deleted_at, :date] => %(IF(deleted_at IS NULL, NULL, CONCAT(REPLACE(deleted_at, " ", "T"), "Z")) AS deleted_at_dt),
+ }.each do |(field, type), name|
+ it "maps #{field} with #{type} to #{name}" do
+ indexer.sql_column_from_field_and_type(field, type).should == name
+ end
+ end
+
+ it "raises an error when no mapping defined" do
+ lambda {
+ indexer.sql_column_from_field_and_type(:text, :rgne)
+ }.should raise_error
+ end
+ end
+
+ describe "#row_to_solr" do
+ it "returns the db row by default" do
+ indexer.row_to_solr("id" => 1).should == { "id" => 1 }
+ end
+ end
+
describe "#query_db" do
it "executes the query" do
db.should_receive(:query).with("query").and_return [to_index]
indexer.query_db("query")
end
@@ -160,8 +245,197 @@
it "executes the correct curl call when not local" do
# curl 'http://localhost:8983/solr/update/json?commit=true' --data-binary @books.json -H 'Content-type:application/json'
indexer.index_file_path = "/tmp/some_path.json"
indexer.should_receive(:system).with("cd /tmp && curl -s 'http://solr.xx:9333/solr/update/json?commit=true' --data-binary @some_path.json -H 'Content-type:application/json'")
indexer.do_index_file
+ end
+ end
+
+ describe "define mappings" do
+ let(:blank_indexer_clazz) { Class.new(Supernova::SolrIndexer) }
+
+ it "has an empty array of field_definitions by default" do
+ blank_indexer_clazz.field_definitions.should == {}
+ end
+
+ it "has adds filters to the field_definitions" do
+ blank_indexer_clazz.has(:artist_id, :type => :integer, :sortable => true)
+ blank_indexer_clazz.field_definitions.should == { :artist_id => { :type => :integer, :sortable => true } }
+ end
+
+ it "clazz sets indexed class" do
+ blank_indexer_clazz.clazz(Integer)
+ blank_indexer_clazz.instance_variable_get("@clazz").should == Integer
+ end
+
+ it "does not change but return the clazz when nil" do
+ blank_indexer_clazz.clazz(Integer)
+ blank_indexer_clazz.clazz.should == Integer
+ end
+
+ it "allows setting the clazz to nil" do
+ blank_indexer_clazz.clazz(Integer)
+ blank_indexer_clazz.clazz(nil)
+ blank_indexer_clazz.clazz.should be_nil
+ end
+
+ it "table_name sets the table name" do
+ blank_indexer_clazz.table_name(:people)
+ blank_indexer_clazz.instance_variable_get("@table_name").should == :people
+ end
+
+ it "table_name does not overwrite but return table_name when nil given" do
+ blank_indexer_clazz.table_name(:people)
+ blank_indexer_clazz.table_name.should == :people
+ end
+
+ it "allows setting the table_name to nil" do
+ blank_indexer_clazz.table_name(:people)
+ blank_indexer_clazz.table_name(nil).should be_nil
+ end
+ end
+
+ describe "#default_mappings" do
+ it "returns id when no class defined" do
+ indexer_clazz.new.default_fields.should == ["id"]
+ end
+
+ it "adds type when class defined" do
+ indexer_clazz.clazz Integer
+ indexer_clazz.new.default_fields.should == ["id", %("Integer" AS type_s)]
+ end
+ end
+
+ describe "#defined_fields" do
+ let(:field_definitions) { { :title => { :type => :string } } }
+
+ it "calls field_definitions" do
+ indexer_clazz.should_receive(:field_definitions).and_return field_definitions
+ custom_indexer.defined_fields
+ end
+
+ ["title AS title_t", "artist_id AS artist_id_i", "description AS description_t",
+ %(IF(created_at IS NULL, NULL, CONCAT(REPLACE(created_at, " ", "T"), "Z")) AS created_at_dt)
+ ].each do |field|
+ it "includes field #{field.inspect}" do
+ custom_indexer.defined_fields.should include(field)
+ end
+ end
+
+ it "does not include virtual fields" do
+ clazz = Class.new(Supernova::SolrIndexer)
+ clazz.has :location, :type => :location, :virtual => true
+ clazz.has :title, :type => :string
+ clazz.new.defined_fields.should == ["title AS title_s"]
+ end
+ end
+
+ describe "#table_name" do
+ it "returns nil when no table_name defined on indexer class and no class defined" do
+ Class.new(Supernova::SolrIndexer).new.table_name.should be_nil
+ end
+
+ it "returns nil when no table_name defined on indexer class and class does not respond to table name" do
+ clazz = Class.new(Supernova::SolrIndexer)
+ clazz.clazz(Integer)
+ clazz.new.table_name.should be_nil
+ end
+
+ it "returns the table name defined in indexer class" do
+ clazz = Class.new(Supernova::SolrIndexer)
+ clazz.table_name(:some_table)
+ clazz.new.table_name.should == :some_table
+ end
+
+ it "returns the table name ob class when responding to table_name" do
+ model_clazz = double("clazz", :table_name => "model_table")
+ clazz = Class.new(Supernova::SolrIndexer)
+ clazz.clazz(model_clazz)
+ clazz.new.table_name.should == "model_table"
+ end
+ end
+
+ describe "#query_to_index" do
+ before(:each) do
+ @indexer_clazz = Class.new(Supernova::SolrIndexer)
+ @indexer_clazz.clazz Integer
+ @indexer_clazz.table_name "integers"
+ @indexer = @indexer_clazz.new
+ end
+
+ it "raises an error when table_name returns nil" do
+ @indexer_clazz.clazz(nil)
+ @indexer_clazz.table_name(nil)
+ @indexer.should_receive(:table_name).and_return nil
+ lambda {
+ @indexer.query_to_index
+ }.should raise_error("no table_name defined")
+ end
+
+ it "returns a string" do
+ @indexer.query_to_index.should be_an_instance_of(String)
+ end
+
+ it "does not include a where when ids is nil" do
+ @indexer.query_to_index.should_not include("WHERE")
+ end
+
+ it "does include a where when ids are present" do
+ @indexer_clazz.new(:ids => %w(1 2)).query_to_index.should include("WHERE id IN (1, 2)")
+ end
+
+ it "calls and includes select_fields" do
+ @indexer.should_receive(:select_fields).and_return %w(a c)
+ @indexer.query_to_index.should include("SELECT a, c FROM integers")
+ end
+ end
+
+ describe "#select_fields" do
+ it "joins default_fields with defined_fields" do
+ default = double("default fields")
+ defined = double("defined fields")
+ indexer.should_receive(:default_fields).and_return [default]
+ indexer.should_receive(:defined_fields).and_return [defined]
+ indexer.select_fields.should == [default, defined]
+ end
+ end
+
+ describe "#method_missing" do
+ it "returns a new supernova criteria" do
+ indexer_clazz.where(:a => 1).should be_an_instance_of(Supernova::SolrCriteria)
+ end
+
+ it "sets the correct clazz" do
+ indexer_clazz = Class.new(Supernova::SolrIndexer)
+ indexer_clazz.clazz(String)
+ indexer_clazz.where(:a => 1).clazz.should == String
+ end
+
+ it "adds the attribute_mapping" do
+ indexer_clazz.where(:a => 1).search_options[:attribute_mapping].should == {
+ :artist_id=>{:type=>:integer}, :title=>{:type=>:text}, :created_at=>{:type=>:date}, :description=>{:type=>:text}
+ }
+ end
+ end
+
+ describe "#solr_field_for_field_name_and_mapping" do
+ let(:mapping) do
+ {
+ :artist_name => { :type => :string },
+ :artist_id => { :type => :integer },
+ }
+ end
+
+ {
+ :artist_name => "artist_name_s", "artist_name" => "artist_name_s",
+ :artist_id => "artist_id_i", :popularity => "popularity"
+ }.each do |from, to|
+ it "maps #{from} to #{to}" do
+ Supernova::SolrIndexer.solr_field_for_field_name_and_mapping(from, mapping).should == to
+ end
+ end
+
+ it "returns the original field when mapping is nil" do
+ Supernova::SolrIndexer.solr_field_for_field_name_and_mapping(:artist, nil).should == "artist"
end
end
end