sunspot_rails 0.11.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,54 @@
1
+ module Sunspot
2
+ module Rails
3
+ module SolrLogging
4
+ class <<self
5
+ def included(base)
6
+ base.module_eval { alias_method_chain(:request, :rails_logging) }
7
+ end
8
+ end
9
+
10
+ def request_with_rails_logging(path, params={}, *extra)
11
+
12
+ # Set up logging text.
13
+ body = (params.nil? || params.empty?) ? extra.first : params.inspect
14
+ action = path[1..-1].capitalize
15
+ if body == "<commit/>"
16
+ action = 'Commit'
17
+ body = ''
18
+ end
19
+ body = body[0, 800] + '...' if body.length > 800
20
+
21
+ # Make request and log.
22
+ response = nil
23
+ begin
24
+ ms = Benchmark.ms do
25
+ response = request_without_rails_logging(path, params, *extra)
26
+ end
27
+ log_name = 'Solr %s (%.1fms)' % [action, ms]
28
+ ::Rails.logger.debug(format_log_entry(log_name, body))
29
+ rescue Exception => e
30
+ log_name = 'Solr %s (Error)' % [action]
31
+ ::Rails.logger.error(format_log_entry(log_name, body))
32
+ raise e
33
+ end
34
+
35
+ response
36
+ end
37
+
38
+ private
39
+
40
+ def format_log_entry(message, dump = nil)
41
+ if ActiveRecord::Base.colorize_logging
42
+ message_color, dump_color = "4;32;1", "0;1"
43
+ log_entry = " \e[#{message_color}m#{message}\e[0m "
44
+ log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
45
+ log_entry
46
+ else
47
+ "%s %s" % [message, dump]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ RSolr::Connection::Base.module_eval { include(Sunspot::Rails::SolrLogging) }
@@ -0,0 +1,19 @@
1
+ module Sunspot
2
+ module Rails
3
+ module SpecHelper
4
+ def disconnect_sunspot
5
+ before(:each) do
6
+ Sunspot.session = StubSessionProxy.new(Sunspot.session)
7
+ end
8
+
9
+ after(:each) do
10
+ Sunspot.session = Sunspot.session.original_session
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ Spec::Runner.configure do |config|
18
+ config.extend(Sunspot::Rails::SpecHelper)
19
+ end
@@ -0,0 +1,83 @@
1
+ module Sunspot
2
+ module Rails
3
+ class StubSessionProxy
4
+ attr_reader :original_session
5
+
6
+ def initialize(original_session)
7
+ @original_session = original_session
8
+ end
9
+
10
+ def index(*objects)
11
+ end
12
+
13
+ def index!(*objects)
14
+ end
15
+
16
+ def remove(*objects)
17
+ end
18
+
19
+ def remove!(*objects)
20
+ end
21
+
22
+ def remove_by_id(clazz, id)
23
+ end
24
+
25
+ def remove_by_id!(clazz, id)
26
+ end
27
+
28
+ def remove_all(clazz = nil)
29
+ end
30
+
31
+ def remove_all!(clazz = nil)
32
+ end
33
+
34
+ def dirty?
35
+ false
36
+ end
37
+
38
+ def delete_dirty?
39
+ false
40
+ end
41
+
42
+ def commit_if_dirty
43
+ end
44
+
45
+ def commit_if_delete_dirty
46
+ end
47
+
48
+ def commit
49
+ end
50
+
51
+ def search(*types)
52
+ Search.new
53
+ end
54
+
55
+ def new_search(*types)
56
+ Search.new
57
+ end
58
+
59
+ class Search
60
+ def results
61
+ []
62
+ end
63
+
64
+ def hits(options = {})
65
+ []
66
+ end
67
+
68
+ def total
69
+ 0
70
+ end
71
+
72
+ def facet(name)
73
+ end
74
+
75
+ def dynamic_facet(name)
76
+ end
77
+
78
+ def execute
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -5,12 +5,12 @@ namespace :sunspot do
5
5
  if RUBY_PLATFORM =~ /w(in)?32$/
6
6
  abort('This command does not work on Windows. Please use rake sunspot:solr:run to run Solr in the foreground.')
7
7
  end
8
- Sunspot::Rails::Server.start
8
+ Sunspot::Rails::Server.new.start
9
9
  end
10
10
 
11
11
  desc 'Run the Solr instance in the foreground'
12
12
  task :run => :environment do
13
- Sunspot::Rails::Server.run
13
+ Sunspot::Rails::Server.new.run
14
14
  end
15
15
 
16
16
  desc 'Stop the Solr instance'
@@ -18,18 +18,20 @@ namespace :sunspot do
18
18
  if RUBY_PLATFORM =~ /w(in)?32$/
19
19
  abort('This command does not work on Windows.')
20
20
  end
21
- Sunspot::Rails::Server.stop
21
+ Sunspot::Rails::Server.new.stop
22
22
  end
23
23
 
24
- desc 'Reindex all solr models'
25
- task :reindex => :environment do
26
- all_files = Dir.glob(File.join(RAILS_ROOT, 'app', 'models', '*.rb'))
27
- all_models = all_files.map { |path| File.basename(path, '.rb').camelize.constantize }
28
- sunspot_models = all_models.select { |m| m < ActiveRecord::Base and m.searchable? }
29
-
30
- sunspot_models.each do |model|
31
- model.reindex :batch_commit => false
32
- end
24
+ task :reindex => :"sunspot:reindex"
25
+ end
26
+
27
+ desc 'Reindex all solr models'
28
+ task :reindex => :environment do
29
+ all_files = Dir.glob(File.join(RAILS_ROOT, 'app', 'models', '*.rb'))
30
+ all_models = all_files.map { |path| File.basename(path, '.rb').camelize.constantize }
31
+ sunspot_models = all_models.select { |m| m < ActiveRecord::Base and m.searchable? }
32
+
33
+ sunspot_models.each do |model|
34
+ model.reindex :batch_commit => false
33
35
  end
34
36
  end
35
- end
37
+ end
@@ -1,5 +1,5 @@
1
1
  module Sunspot
2
2
  module Rails
3
- VERSION = '0.11.5'
3
+ VERSION = '1.0.0'
4
4
  end
5
5
  end
data/lib/sunspot/rails.rb CHANGED
@@ -1,12 +1,15 @@
1
1
  require 'sunspot'
2
- require 'sunspot/rails/configuration'
3
- require 'sunspot/rails/adapters'
4
- require 'sunspot/rails/request_lifecycle'
5
- require 'sunspot/rails/searchable'
6
- require 'sunspot/rails/util'
2
+ require File.join(File.dirname(__FILE__), 'rails', 'configuration')
3
+ require File.join(File.dirname(__FILE__), 'rails', 'adapters')
4
+ require File.join(File.dirname(__FILE__), 'rails', 'request_lifecycle')
5
+ require File.join(File.dirname(__FILE__), 'rails', 'searchable')
7
6
 
8
7
  module Sunspot #:nodoc:
9
8
  module Rails #:nodoc:
9
+ autoload :StubSessionProxy, File.join(File.dirname(__FILE__), 'rails', 'stub_session_proxy')
10
+ autoload :Server, File.join(File.dirname(__FILE__), 'rails', 'server')
11
+ autoload :VERSION, File.join(File.dirname(__FILE__), 'rails', 'version')
12
+
10
13
  class <<self
11
14
  attr_writer :configuration
12
15
 
@@ -15,7 +18,40 @@ module Sunspot #:nodoc:
15
18
  end
16
19
 
17
20
  def reset
18
- @master_session = @configuration = nil
21
+ @configuration = nil
22
+ end
23
+
24
+ def build_session(configuration = self.configuration)
25
+ if configuration.has_master?
26
+ SessionProxy::MasterSlaveSessionProxy.new(
27
+ SessionProxy::ThreadLocalSessionProxy.new(master_config(configuration)),
28
+ SessionProxy::ThreadLocalSessionProxy.new(slave_config(configuration))
29
+ )
30
+ else
31
+ SessionProxy::ThreadLocalSessionProxy.new(slave_config(configuration))
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def master_config(sunspot_rails_configuration)
38
+ config = Sunspot::Configuration.build
39
+ config.solr.url = URI::HTTP.build(
40
+ :host => sunspot_rails_configuration.master_hostname,
41
+ :port => sunspot_rails_configuration.master_port,
42
+ :path => sunspot_rails_configuration.master_path
43
+ ).to_s
44
+ config
45
+ end
46
+
47
+ def slave_config(sunspot_rails_configuration)
48
+ config = Sunspot::Configuration.build
49
+ config.solr.url = URI::HTTP.build(
50
+ :host => configuration.hostname,
51
+ :port => configuration.port,
52
+ :path => configuration.path
53
+ ).to_s
54
+ config
19
55
  end
20
56
  end
21
57
  end
data/rails/init.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'sunspot'
2
2
 
3
- Sunspot.session = Sunspot::Rails::SessionProxy.instance
3
+ Sunspot.session = Sunspot::Rails.build_session
4
4
  Sunspot::Adapters::InstanceAdapter.register(Sunspot::Rails::Adapters::ActiveRecordInstanceAdapter, ActiveRecord::Base)
5
5
  Sunspot::Adapters::DataAccessor.register(Sunspot::Rails::Adapters::ActiveRecordDataAccessor, ActiveRecord::Base)
6
6
  ActiveRecord::Base.module_eval { include(Sunspot::Rails::Searchable) }
@@ -0,0 +1,2 @@
1
+ class PhotoPost < PostWithAuto
2
+ end
@@ -1,6 +1,7 @@
1
1
  ActiveRecord::Schema.define(:version => 0) do
2
2
  create_table :posts, :force => true do |t|
3
3
  t.string :title
4
+ t.string :type
4
5
  t.text :body
5
6
  t.references :blog
6
7
  t.timestamps
@@ -1 +0,0 @@
1
- S
@@ -1,8 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
3
  describe 'searchable with lifecycle' do
4
- integrate_sunspot
5
-
6
4
  describe 'on create' do
7
5
  before :each do
8
6
  @post = PostWithAuto.create
@@ -24,6 +22,20 @@ describe 'searchable with lifecycle' do
24
22
  it 'should automatically update index' do
25
23
  PostWithAuto.search { with :title, 'Test 1' }.results.should == [@post]
26
24
  end
25
+
26
+ it "should index model if relevant attribute changed" do
27
+ @post = PostWithAuto.create!
28
+ @post.title = 'new title'
29
+ @post.should_receive :index
30
+ @post.save!
31
+ end
32
+
33
+ it "should not index model if relevant attribute not changed" do
34
+ @post = PostWithAuto.create!
35
+ @post.updated_at = Date.tomorrow
36
+ @post.should_not_receive :index
37
+ @post.save!
38
+ end
27
39
  end
28
40
 
29
41
  describe 'on destroy' do
@@ -40,8 +52,6 @@ describe 'searchable with lifecycle' do
40
52
  end
41
53
 
42
54
  describe 'searchable with lifecycle - ignoring specific attributes' do
43
- integrate_sunspot
44
-
45
55
  before(:each) do
46
56
  @post = PostWithAuto.create
47
57
  end
data/spec/model_spec.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
3
  describe 'ActiveRecord mixin' do
4
- integrate_sunspot
5
-
6
4
  describe 'index()' do
7
5
  before :each do
8
6
  @post = Post.create!
@@ -19,6 +17,17 @@ describe 'ActiveRecord mixin' do
19
17
  end
20
18
  end
21
19
 
20
+ describe 'single table inheritence' do
21
+ before :each do
22
+ @post = PhotoPost.create!
23
+ end
24
+
25
+ it 'should not break auto-indexing' do
26
+ @post.title = 'Title'
27
+ lambda { @post.save! }.should_not raise_error
28
+ end
29
+ end
30
+
22
31
  describe 'index!()' do
23
32
  before :each do
24
33
  @post = Post.create!
@@ -107,7 +116,7 @@ describe 'ActiveRecord mixin' do
107
116
  end
108
117
 
109
118
  it 'should find ActiveRecord objects with an integer, not a string' do
110
- Post.should_receive(:find).with([@post.id.to_i], anything()).and_return([@post])
119
+ Post.should_receive(:find_all_by_id).with([@post.id.to_i], anything).and_return([@post])
111
120
  Post.search do
112
121
  with :title, 'Test Post'
113
122
  end.results.should == [@post]
@@ -135,6 +144,16 @@ describe 'ActiveRecord mixin' do
135
144
  with :title, 'Test Post'
136
145
  end.results.should == [@post]
137
146
  end
147
+
148
+ it 'should gracefully handle nonexistent records' do
149
+ post2 = Post.create!(:title => 'Test Post')
150
+ post2.index!
151
+ post2.destroy
152
+ Post.search do
153
+ with :title, 'Test Post'
154
+ end.results.should == [@post]
155
+ end
156
+
138
157
  end
139
158
 
140
159
  describe 'search_ids()' do
@@ -233,8 +252,9 @@ describe 'ActiveRecord mixin' do
233
252
  Post.search.results.to_set.should == @posts.to_set
234
253
  end
235
254
  end
236
-
237
255
  end
256
+
257
+
238
258
 
239
259
  describe "reindex()" do
240
260
 
data/spec/schema.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  ActiveRecord::Schema.define(:version => 0) do
2
2
  create_table :posts, :force => true do |t|
3
3
  t.string :title
4
+ t.string :type
4
5
  t.text :body
5
6
  t.references :blog
6
7
  t.timestamps
data/spec/server_spec.rb CHANGED
@@ -1,124 +1,36 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
3
  describe Sunspot::Rails::Server do
4
- before(:each) do
5
- @sunspot_configuration = Sunspot::Rails::Configuration.new
4
+ before :each do
5
+ @server = Sunspot::Rails::Server.new
6
+ @solr_home = File.expand_path(File.join(Rails.root, 'solr'))
6
7
  end
7
8
 
8
- describe "rake task commands" do
9
- before(:each) do
10
- Sunspot::Rails::Server.should_receive(:pid_path).and_return('/tmp')
11
- end
12
-
13
- it "should generate and execute the start command" do
14
- Sunspot::Rails::Server.should_receive(:start_command).and_return('sunspot-start')
15
- Sunspot::Rails::Server.should_respond_to_and_receive(:bootstrap_neccessary?).and_return(false)
16
- Kernel.should_receive(:system).with('sunspot-start').and_return(true)
17
- Sunspot::Rails::Server.start.should == true
18
- end
19
-
20
- it "should generate and execute the stop command" do
21
- Sunspot::Rails::Server.should_receive(:stop_command).and_return('sunspot-stop')
22
- Sunspot::Rails::Server.should_not_receive(:bootstrap_neccessary?)
23
- Kernel.should_receive(:system).with('sunspot-stop').and_return(true)
24
- Sunspot::Rails::Server.stop.should == true
25
- end
26
-
27
- it "should generate and execute the run command" do
28
- Sunspot::Rails::Server.should_receive(:run_command).and_return('sunspot-run')
29
- Sunspot::Rails::Server.should_respond_to_and_receive(:bootstrap_neccessary?).and_return(false)
30
- Kernel.should_receive(:system).with('sunspot-run').and_return(true)
31
- Sunspot::Rails::Server.run.should == true
32
- end
9
+ it "sets the correct Solr home" do
10
+ @server.solr_home.should == @solr_home
33
11
  end
34
12
 
35
- describe "bootstraping" do
36
- before(:each) do
37
- @temp_dir = File.join( Dir.tmpdir, 'solr_rspec', Time.now.to_i.to_s, rand(1000).to_s )
38
- Sunspot::Rails::Server.should_receive(:solr_home).at_least(1).and_return( @temp_dir )
39
- end
40
-
41
- it "should require bootstraping" do
42
- Sunspot::Rails::Server.bootstrap_neccessary?.should == true
43
- end
44
-
45
- it "should not require bootstrapping again" do
46
- Sunspot::Rails::Server.bootstrap_neccessary?.should == true
47
- Sunspot::Rails::Server.bootstrap
48
- Sunspot::Rails::Server.bootstrap_neccessary?.should == false
49
- end
13
+ it "sets the correct Solr library path" do
14
+ @server.lib_path.should == File.join(@solr_home, 'lib')
50
15
  end
51
16
 
52
- describe "delegate methods" do
53
- before(:each) do
54
- Sunspot::Rails::Server.should_receive(:configuration).at_least(1).and_return(@sunspot_configuration)
55
- end
56
-
57
- it "should delegate the port method to the configuration" do
58
- @sunspot_configuration.should_respond_to_and_receive(:port).and_return(1234)
59
- Sunspot::Rails::Server.port.should == 1234
60
- end
61
-
62
- it "should delegate the solr_home method to the configuration" do
63
- @sunspot_configuration.should_respond_to_and_receive(:solr_home).and_return('/some/path')
64
- Sunspot::Rails::Server.solr_home.should == '/some/path'
65
- end
66
-
67
- it "should delegate the log_level method to the configuration" do
68
- @sunspot_configuration.should_respond_to_and_receive(:log_level).and_return('LOG_LEVEL')
69
- Sunspot::Rails::Server.log_level.should == 'LOG_LEVEL'
70
- end
71
-
72
- it "should delegate the log_dir method to the configuration" do
73
- @sunspot_configuration.should_respond_to_and_receive(:log_file).and_return('log_file')
74
- Sunspot::Rails::Server.log_file.should =~ /log_file/
75
- end
17
+ it "sets the correct Solr PID path" do
18
+ @server.pid_path.should == File.join(Rails.root, 'tmp', 'pids', 'sunspot-solr-test.pid')
19
+ end
76
20
 
21
+ it "sets the correct Solr data dir" do
22
+ @server.solr_data_dir.should == File.join(@solr_home, 'data', 'test')
77
23
  end
78
24
 
79
- describe "protected methods" do
80
- it "should generate the start command" do
81
- Sunspot::Rails::Server.should_respond_to_and_receive(:port).and_return('1')
82
- Sunspot::Rails::Server.should_respond_to_and_receive(:solr_home).and_return('home')
83
- Sunspot::Rails::Server.should_respond_to_and_receive(:data_path).and_return('data')
84
- Sunspot::Rails::Server.should_respond_to_and_receive(:log_level).and_return('LOG')
85
- Sunspot::Rails::Server.should_respond_to_and_receive(:log_file).and_return('log_file')
86
- Sunspot::Rails::Server.send(:start_command).should == \
87
- [ 'sunspot-solr', 'start', '-p', '1', '-d', 'data', '-s', 'home', '-l', 'LOG', '--log-file', 'log_file' ]
88
- end
89
-
90
- it "should generate the stop command" do
91
- Sunspot::Rails::Server.send(:stop_command).should == [ 'sunspot-solr', 'stop' ]
92
- end
93
-
94
- it "should generate the run command" do
95
- Sunspot::Rails::Server.should_respond_to_and_receive(:port).and_return('1')
96
- Sunspot::Rails::Server.should_respond_to_and_receive(:solr_home).and_return('home')
97
- Sunspot::Rails::Server.should_respond_to_and_receive(:data_path).and_return('data')
98
- Sunspot::Rails::Server.should_respond_to_and_receive(:log_level).and_return('LOG')
99
- Sunspot::Rails::Server.should_respond_to_and_receive(:log_file).and_return('log_file')
100
- Sunspot::Rails::Server.send(:run_command).should == \
101
- [ 'sunspot-solr', 'run', '-p', '1', '-d', 'data', '-s', 'home', '-l', 'LOG', '-lf', 'log_file' ]
102
- end
25
+ it "sets the correct port" do
26
+ @server.port.should == 8980
27
+ end
103
28
 
104
- it "should generate the path for config files" do
105
- Sunspot::Rails::Server.should_receive(:solr_home).and_return('/solr/home')
106
- Sunspot::Rails::Server.config_path.should == '/solr/home/conf'
107
- end
108
-
109
- it "should generate the path for custom libraries" do
110
- Sunspot::Rails::Server.should_receive(:solr_home).and_return('/solr/home')
111
- Sunspot::Rails::Server.lib_path.should == '/solr/home/lib'
112
- end
113
-
114
- it "should generate the path for the index data" do
115
- Sunspot::Rails::Server.should_receive(:solr_home).and_return('/solr/home')
116
- Sunspot::Rails::Server.data_path.should == '/solr/home/data/test'
117
- end
29
+ it "sets the correct log level" do
30
+ @server.log_level.should == "FINE"
31
+ end
118
32
 
119
- it "should generate the path for pid files" do
120
- Sunspot::Rails::Server.should_receive(:solr_home).and_return('/solr/home')
121
- Sunspot::Rails::Server.pid_path.should == '/solr/home/pids/test'
122
- end
33
+ it "sets the correct log file" do
34
+ @server.log_file.should == File.join(Rails.root, 'log', 'sunspot-solr-test.log')
123
35
  end
124
- end
36
+ end
data/spec/spec_helper.rb CHANGED
@@ -12,8 +12,7 @@ require 'spec'
12
12
  require 'spec/rails'
13
13
  require 'rake'
14
14
  require 'ruby-debug' unless RUBY_VERSION > '1.9'
15
- require 'sunspot/rails/tasks'
16
- require 'sunspot/spec/extension'
15
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'sunspot', 'rails', 'solr_logging')
17
16
 
18
17
  def load_schema
19
18
  stdout = $stdout
@@ -31,11 +30,8 @@ end
31
30
 
32
31
  Spec::Runner.configure do |config|
33
32
  config.before(:each) do
34
- if integrate_sunspot?
35
- Sunspot.remove_all
36
- Sunspot.commit
37
- end
38
33
  load_schema
34
+ Sunspot.remove_all!
39
35
  end
40
36
  end
41
37