flying-sphinx 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,11 @@ unless Rails.env.development? || Rails.env.test?
6
6
 
7
7
  ThinkingSphinx::Configuration.instance.address = config.host
8
8
  ThinkingSphinx::Configuration.instance.port = config.port
9
+ ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =
10
+ config.client_key
9
11
  end
10
12
 
11
- ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
13
+ if ENV['DATABASE_URL'][/^mysql/].nil?
14
+ ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
15
+ end
12
16
  end
@@ -8,7 +8,11 @@ class FlyingSphinx::Railtie < Rails::Railtie
8
8
 
9
9
  ThinkingSphinx::Configuration.instance.address = config.host
10
10
  ThinkingSphinx::Configuration.instance.port = config.port
11
+ ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =
12
+ config.client_key
11
13
 
12
- ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
14
+ if ENV['DATABASE_URL'][/^mysql/].nil?
15
+ ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
16
+ end
13
17
  end unless Rails.env.development? || Rails.env.test?
14
18
  end
@@ -2,8 +2,10 @@ namespace :fs do
2
2
  task :index => :environment do
3
3
  puts "Starting Index Request"
4
4
  FlyingSphinx::IndexRequest.cancel_jobs
5
- FlyingSphinx::IndexRequest.new.update_and_index
6
- puts "Index Request has completed"
5
+ request = FlyingSphinx::IndexRequest.new
6
+ request.update_and_index
7
+ puts request.status_message
8
+
7
9
  end
8
10
 
9
11
  task :start => :environment do
@@ -20,4 +22,12 @@ namespace :fs do
20
22
 
21
23
  task :restart => [:environment, :stop, :start]
22
24
  task :rebuild => [:environment, :stop, :index, :start]
25
+
26
+ task :index_log => :environment do
27
+ FlyingSphinx::IndexRequest.output_last_index
28
+ end
29
+
30
+ task :actions => :environment do
31
+ FlyingSphinx::Configuration.new.output_recent_actions
32
+ end
23
33
  end
@@ -2,45 +2,54 @@ class FlyingSphinx::Tunnel
2
2
  def self.connect(configuration, &block)
3
3
  tunnel = new configuration
4
4
  tunnel.open do |session|
5
- session.loop &block
5
+ session.loop do
6
+ block.call
7
+ end
6
8
  end
7
9
  end
8
10
 
11
+ def self.required?
12
+ ThinkingSphinx.database_adapter == FlyingSphinx::HerokuSharedAdapter
13
+ end
14
+
9
15
  def initialize(configuration)
10
16
  @configuration = configuration
11
17
  end
12
-
18
+
13
19
  def open(&block)
14
- Net::SSH.start(@configuration.host, 'sphinx', ssh_options) do |session|
15
- session.forward.remote(
16
- db_port, db_host, @configuration.database_port, '0.0.0.0'
17
- )
18
- session.loop { !remote_exists?(session) }
19
-
20
- yield session
21
- end
22
- end
20
+ session = Net::SSH.start(@configuration.host, 'sphinx', ssh_options)
21
+ session.forward.remote(
22
+ db_port, db_host, @configuration.database_port, '0.0.0.0'
23
+ )
24
+
25
+ session.loop { !remote_exists?(session) }
23
26
 
24
- private
27
+ yield session
28
+ rescue IOError
29
+ # Server closed the connection on us. That's (hopefully) expected, nothing
30
+ # to worry about.
31
+ end
25
32
 
33
+ private
34
+
26
35
  def db_host
27
36
  db_config[:host]
28
37
  end
29
-
38
+
30
39
  def db_port
31
40
  db_config[:port]
32
41
  end
33
-
42
+
34
43
  def db_config
35
44
  @db_config ||= ActiveRecord::Base.connection.instance_variable_get(:@config)
36
45
  end
37
-
46
+
38
47
  def ssh_options
39
48
  {:keys => [
40
49
  File.expand_path('../../../keys/key', __FILE__)
41
50
  ]}
42
51
  end
43
-
52
+
44
53
  def remote_exists?(session)
45
54
  session.forward.active_remotes.include?(
46
55
  [@configuration.database_port, '0.0.0.0']
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ begin
3
+ require 'bundler'
4
+ rescue LoadError
5
+ puts "although not required, it's recommended you use bundler during development"
6
+ end
7
+
8
+ require 'timeout'
9
+
10
+ require 'thinking-sphinx'
11
+ require 'flying_sphinx'
12
+ require 'delayed_job'
13
+
14
+ require 'fakeweb'
15
+ require 'fakeweb_matcher'
16
+
17
+ FakeWeb.allow_net_connect = false
18
+
19
+ Delayed::Worker.backend = :active_record
20
+
21
+ # we don't want a checking of interval in testing
22
+ FlyingSphinx::IndexRequest.send(:remove_const, :INDEX_COMPLETE_CHECKING_INTERVAL)
23
+ FlyingSphinx::IndexRequest::INDEX_COMPLETE_CHECKING_INTERVAL = 0
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'multi_json'
3
+
4
+ describe FlyingSphinx::Configuration do
5
+ describe '#initialize' do
6
+ let(:api_server) { 'https://flying-sphinx.com/api/my' }
7
+ let(:api_key) { 'foo-bar-baz' }
8
+ let(:identifier) { 'app@heroku.com' }
9
+ let(:config) { FlyingSphinx::Configuration.new identifier, api_key }
10
+
11
+ before :each do
12
+ FakeWeb.register_uri(:get, "#{api_server}/app",
13
+ :body => MultiJson.encode(
14
+ :server => 'foo.bar.com',
15
+ :port => 9319,
16
+ :database_port => 10001
17
+ )
18
+ )
19
+ end
20
+
21
+ it "requests details from the server with the given API key" do
22
+ config
23
+ FakeWeb.should have_requested :get, "#{api_server}/app"
24
+ end
25
+
26
+ it "sets the host from the server information" do
27
+ config.host.should == 'foo.bar.com'
28
+ end
29
+
30
+ it "sets the port from the server information" do
31
+ config.port.should == 9319
32
+ end
33
+
34
+ it "sets the port from the server information" do
35
+ config.database_port.should == 10001
36
+ end
37
+ end
38
+ end
File without changes
@@ -0,0 +1,176 @@
1
+ require 'spec_helper'
2
+
3
+ describe FlyingSphinx::IndexRequest do
4
+ let(:api) { FlyingSphinx::API.new 'foo', 'bar' }
5
+ let(:configuration) {
6
+ stub(:configuration, :api => api, :sphinx_configuration => 'foo {}')
7
+ }
8
+
9
+ let(:index_response) {
10
+ stub(:response, :body => stub(:body, :id => 42, :status => 'OK'))
11
+ }
12
+ let(:blocked_response) {
13
+ stub(:response, :body => stub(:body, :id => nil, :status => 'BLOCKED'))
14
+ }
15
+
16
+ before :each do
17
+ ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
18
+
19
+ FlyingSphinx::Configuration.stub!(:new => configuration)
20
+ FlyingSphinx::Tunnel.stub(:connect) { |config, block| block.call }
21
+ end
22
+
23
+ describe '.cancel_jobs' do
24
+ before :each do
25
+ Delayed::Job.stub!(:delete_all => true)
26
+ end
27
+
28
+ it "should not delete any rows if the delayed_jobs table does not exist" do
29
+ Delayed::Job.stub!(:table_exists? => false)
30
+ Delayed::Job.should_not_receive(:delete_all)
31
+
32
+ FlyingSphinx::IndexRequest.cancel_jobs
33
+ end
34
+
35
+ it "should delete rows if the delayed_jobs table does exist" do
36
+ Delayed::Job.stub!(:table_exists? => true)
37
+ Delayed::Job.should_receive(:delete_all)
38
+
39
+ FlyingSphinx::IndexRequest.cancel_jobs
40
+ end
41
+
42
+ it "should delete only Thinking Sphinx jobs" do
43
+ Delayed::Job.stub!(:table_exists? => true)
44
+ Delayed::Job.should_receive(:delete_all) do |sql|
45
+ sql.should match(/handler LIKE '--- !ruby\/object:FlyingSphinx::\%'/)
46
+ end
47
+
48
+ FlyingSphinx::IndexRequest.cancel_jobs
49
+ end
50
+ end
51
+
52
+ describe '#update_and_index' do
53
+ let(:index_request) { FlyingSphinx::IndexRequest.new }
54
+ let(:conf_params) { { :configuration => 'foo {}' } }
55
+ let(:index_params) { { :indices => '' } }
56
+
57
+ it "makes a new request" do
58
+ api.should_receive(:put).with('/', conf_params).and_return('ok')
59
+ api.should_receive(:post).
60
+ with('indices', index_params).and_return(index_response)
61
+
62
+ begin
63
+ Timeout::timeout(0.2) {
64
+ index_request.update_and_index
65
+ }
66
+ rescue Timeout::Error
67
+ end
68
+ end
69
+
70
+ context 'delta request without delta support' do
71
+ it "should explain why the request failed" do
72
+ api.should_receive(:put).
73
+ with('/', conf_params).and_return('ok')
74
+ api.should_receive(:post).
75
+ with('indices', index_params).and_return(blocked_response)
76
+ index_request.should_receive(:puts).
77
+ with('Your account does not support delta indexing. Upgrading plans is probably the best way around this.')
78
+
79
+ index_request.update_and_index
80
+ end
81
+ end
82
+
83
+ context 'request for a MySQL database' do
84
+ before :each do
85
+ ThinkingSphinx.database_adapter = nil
86
+ end
87
+
88
+ after :each do
89
+ ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
90
+ end
91
+
92
+ it "should not establish an SSH connection" do
93
+ FlyingSphinx::Tunnel.should_not_receive(:connect)
94
+
95
+ api.should_receive(:put).with('/', conf_params).and_return('ok')
96
+ api.should_receive(:post).
97
+ with('indices', index_params).and_return(index_response)
98
+ api.should_receive(:get).with('indices/42').
99
+ and_return(stub(:response, :body => stub(:body, :status => 'FINISHED')))
100
+
101
+ index_request.update_and_index
102
+ end
103
+ end
104
+ end
105
+
106
+ describe '#perform' do
107
+ let(:index_request) { FlyingSphinx::IndexRequest.new ['foo_delta'] }
108
+ let(:index_params) { { :indices => 'foo_delta' } }
109
+
110
+ it "makes a new request" do
111
+ api.should_receive(:post).
112
+ with('indices', index_params).and_return(index_response)
113
+
114
+ begin
115
+ Timeout::timeout(0.2) {
116
+ index_request.perform
117
+ }
118
+ rescue Timeout::Error
119
+ end
120
+ end
121
+ end
122
+
123
+ describe '#status_message' do
124
+ let(:index_request) { FlyingSphinx::IndexRequest.new }
125
+ let(:finished_response) {
126
+ stub(:response, :body => stub(:body, :status => 'FINISHED'))
127
+ }
128
+ let(:failure_response) {
129
+ stub(:response, :body => stub(:body, :status => 'FAILED'))
130
+ }
131
+ let(:pending_response) {
132
+ stub(:response, :body => stub(:body, :status => 'PENDING'))
133
+ }
134
+ let(:unknown_response) {
135
+ stub(:response, :body => stub(:body, :status => 'UNKNOWN'))
136
+ }
137
+
138
+ before :each do
139
+ api.stub(:post => index_response)
140
+ end
141
+
142
+ it "returns with a positive message on success" do
143
+ api.stub(:get => finished_response)
144
+
145
+ index_request.status_message.should == 'Index Request has completed.'
146
+ end
147
+
148
+ it "returns with a failure message on failure" do
149
+ api.stub(:get => failure_response)
150
+
151
+ index_request.status_message.should == 'Index Request failed.'
152
+ end
153
+
154
+ it "warns the user if the request is still pending" do
155
+ api.stub(:get => pending_response)
156
+
157
+ index_request.status_message.should == 'Index Request is still pending - something has gone wrong.'
158
+ end
159
+
160
+ it "treats all other statuses as unknown" do
161
+ api.stub(:get => unknown_response)
162
+
163
+ index_request.status_message.should == "Unknown index response: 'UNKNOWN'."
164
+ end
165
+ end
166
+
167
+ describe "#display_name" do
168
+ let(:index_request) {
169
+ FlyingSphinx::IndexRequest.new ['foo_core', 'bar_core']
170
+ }
171
+
172
+ it "should display class name with all indexes" do
173
+ index_request.display_name.should == "FlyingSphinx::IndexRequest for foo_core, bar_core"
174
+ end
175
+ end
176
+ end
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flying-sphinx
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 4
9
- - 4
10
- version: 0.4.4
4
+ prerelease:
5
+ version: 0.5.0
11
6
  platform: ruby
12
7
  authors:
13
8
  - Pat Allan
@@ -15,167 +10,141 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-02-07 00:00:00 +11:00
13
+ date: 2011-05-12 00:00:00 +10:00
19
14
  default_executable:
20
15
  dependencies:
21
16
  - !ruby/object:Gem::Dependency
22
- type: :runtime
23
- prerelease: false
24
17
  name: thinking-sphinx
25
- version_requirements: &id001 !ruby/object:Gem::Requirement
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
26
20
  none: false
27
21
  requirements:
28
22
  - - ">="
29
23
  - !ruby/object:Gem::Version
30
- hash: 3
31
- segments:
32
- - 0
33
24
  version: "0"
34
- requirement: *id001
35
- - !ruby/object:Gem::Dependency
36
25
  type: :runtime
37
- prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
38
28
  name: net-ssh
39
- version_requirements: &id002 !ruby/object:Gem::Requirement
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
40
31
  none: false
41
32
  requirements:
42
33
  - - ~>
43
34
  - !ruby/object:Gem::Version
44
- hash: 33
45
- segments:
46
- - 2
47
- - 0
48
- - 23
49
35
  version: 2.0.23
50
- requirement: *id002
51
- - !ruby/object:Gem::Dependency
52
36
  type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: multi_json
53
40
  prerelease: false
54
- name: json
55
- version_requirements: &id003 !ruby/object:Gem::Requirement
41
+ requirement: &id003 !ruby/object:Gem::Requirement
56
42
  none: false
57
43
  requirements:
58
44
  - - ~>
59
45
  - !ruby/object:Gem::Version
60
- hash: 11
61
- segments:
62
- - 1
63
- - 4
64
- - 6
65
- version: 1.4.6
66
- requirement: *id003
67
- - !ruby/object:Gem::Dependency
46
+ version: 1.0.1
68
47
  type: :runtime
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: faraday
69
51
  prerelease: false
70
- name: httparty
71
- version_requirements: &id004 !ruby/object:Gem::Requirement
52
+ requirement: &id004 !ruby/object:Gem::Requirement
72
53
  none: false
73
54
  requirements:
74
55
  - - ~>
75
56
  - !ruby/object:Gem::Version
76
- hash: 5
77
- segments:
78
- - 0
79
- - 6
80
- - 1
81
57
  version: 0.6.1
82
- requirement: *id004
58
+ type: :runtime
59
+ version_requirements: *id004
83
60
  - !ruby/object:Gem::Dependency
84
- type: :development
61
+ name: faraday_middleware
85
62
  prerelease: false
86
- name: jeweler
87
- version_requirements: &id005 !ruby/object:Gem::Requirement
63
+ requirement: &id005 !ruby/object:Gem::Requirement
88
64
  none: false
89
65
  requirements:
90
- - - "="
66
+ - - ~>
91
67
  - !ruby/object:Gem::Version
92
- hash: 1
93
- segments:
94
- - 1
95
- - 5
96
- - 1
97
- version: 1.5.1
98
- requirement: *id005
68
+ version: 0.6.3
69
+ type: :runtime
70
+ version_requirements: *id005
99
71
  - !ruby/object:Gem::Dependency
100
- type: :development
72
+ name: rash
101
73
  prerelease: false
102
- name: rspec
103
- version_requirements: &id006 !ruby/object:Gem::Requirement
74
+ requirement: &id006 !ruby/object:Gem::Requirement
104
75
  none: false
105
76
  requirements:
106
- - - "="
77
+ - - ~>
107
78
  - !ruby/object:Gem::Version
108
- hash: 11
109
- segments:
110
- - 2
111
- - 1
112
- - 0
113
- version: 2.1.0
114
- requirement: *id006
79
+ version: 0.3.0
80
+ type: :runtime
81
+ version_requirements: *id006
115
82
  - !ruby/object:Gem::Dependency
116
- type: :development
83
+ name: yajl-ruby
117
84
  prerelease: false
118
- name: rcov
119
- version_requirements: &id007 !ruby/object:Gem::Requirement
85
+ requirement: &id007 !ruby/object:Gem::Requirement
120
86
  none: false
121
87
  requirements:
122
- - - "="
88
+ - - ~>
123
89
  - !ruby/object:Gem::Version
124
- hash: 43
125
- segments:
126
- - 0
127
- - 9
128
- - 8
129
- version: 0.9.8
130
- requirement: *id007
90
+ version: 0.8.2
91
+ type: :development
92
+ version_requirements: *id007
131
93
  - !ruby/object:Gem::Dependency
94
+ name: rspec
95
+ prerelease: false
96
+ requirement: &id008 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 2.5.0
132
102
  type: :development
103
+ version_requirements: *id008
104
+ - !ruby/object:Gem::Dependency
105
+ name: rcov
133
106
  prerelease: false
107
+ requirement: &id009 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ~>
111
+ - !ruby/object:Gem::Version
112
+ version: 0.9.9
113
+ type: :development
114
+ version_requirements: *id009
115
+ - !ruby/object:Gem::Dependency
134
116
  name: fakeweb
135
- version_requirements: &id008 !ruby/object:Gem::Requirement
117
+ prerelease: false
118
+ requirement: &id010 !ruby/object:Gem::Requirement
136
119
  none: false
137
120
  requirements:
138
- - - "="
121
+ - - ~>
139
122
  - !ruby/object:Gem::Version
140
- hash: 27
141
- segments:
142
- - 1
143
- - 3
144
- - 0
145
123
  version: 1.3.0
146
- requirement: *id008
147
- - !ruby/object:Gem::Dependency
148
124
  type: :development
149
- prerelease: false
125
+ version_requirements: *id010
126
+ - !ruby/object:Gem::Dependency
150
127
  name: fakeweb-matcher
151
- version_requirements: &id009 !ruby/object:Gem::Requirement
128
+ prerelease: false
129
+ requirement: &id011 !ruby/object:Gem::Requirement
152
130
  none: false
153
131
  requirements:
154
- - - "="
132
+ - - ~>
155
133
  - !ruby/object:Gem::Version
156
- hash: 27
157
- segments:
158
- - 1
159
- - 2
160
- - 2
161
134
  version: 1.2.2
162
- requirement: *id009
163
- - !ruby/object:Gem::Dependency
164
135
  type: :development
165
- prerelease: false
136
+ version_requirements: *id011
137
+ - !ruby/object:Gem::Dependency
166
138
  name: delayed_job
167
- version_requirements: &id010 !ruby/object:Gem::Requirement
139
+ prerelease: false
140
+ requirement: &id012 !ruby/object:Gem::Requirement
168
141
  none: false
169
142
  requirements:
170
- - - "="
143
+ - - ~>
171
144
  - !ruby/object:Gem::Version
172
- hash: 15
173
- segments:
174
- - 2
175
- - 1
176
- - 2
177
- version: 2.1.2
178
- requirement: *id010
145
+ version: 2.1.4
146
+ type: :development
147
+ version_requirements: *id012
179
148
  description: Hooks Thinking Sphinx into the Flying Sphinx service
180
149
  email: pat@freelancing-gods.com
181
150
  executables: []
@@ -185,9 +154,13 @@ extensions: []
185
154
  extra_rdoc_files:
186
155
  - README.textile
187
156
  files:
157
+ - .gitignore
158
+ - Gemfile
188
159
  - LICENCE
189
160
  - README.textile
161
+ - Rakefile
190
162
  - VERSION
163
+ - flying-sphinx.gemspec
191
164
  - keys/key
192
165
  - lib/flying-sphinx.rb
193
166
  - lib/flying_sphinx.rb
@@ -201,15 +174,20 @@ files:
201
174
  - lib/flying_sphinx/railtie.rb
202
175
  - lib/flying_sphinx/tasks.rb
203
176
  - lib/flying_sphinx/tunnel.rb
204
- - spec/flying_sphinx/configuration_spec.rb
205
- - spec/flying_sphinx/delayed_delta_spec.rb
206
- - spec/flying_sphinx/flag_as_deleted_job_spec.rb
207
- - spec/flying_sphinx/index_request_spec.rb
177
+ - spec/spec_helper.rb
178
+ - spec/specs/configuration_spec.rb
179
+ - spec/specs/delayed_delta_spec.rb
180
+ - spec/specs/flag_as_deleted_job_spec.rb
181
+ - spec/specs/index_request_spec.rb
208
182
  has_rdoc: true
209
183
  homepage: https://flying-sphinx.com
210
184
  licenses: []
211
185
 
212
- post_install_message:
186
+ post_install_message: |
187
+ If you're upgrading, you should rebuild your Sphinx setup when deploying:
188
+
189
+ $ heroku rake fs:rebuild
190
+
213
191
  rdoc_options: []
214
192
 
215
193
  require_paths:
@@ -219,28 +197,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
219
197
  requirements:
220
198
  - - ">="
221
199
  - !ruby/object:Gem::Version
222
- hash: 3
223
- segments:
224
- - 0
225
200
  version: "0"
226
201
  required_rubygems_version: !ruby/object:Gem::Requirement
227
202
  none: false
228
203
  requirements:
229
204
  - - ">="
230
205
  - !ruby/object:Gem::Version
231
- hash: 3
232
- segments:
233
- - 0
234
206
  version: "0"
235
207
  requirements: []
236
208
 
237
209
  rubyforge_project:
238
- rubygems_version: 1.3.7
210
+ rubygems_version: 1.6.2
239
211
  signing_key:
240
212
  specification_version: 3
241
213
  summary: Sphinx in the Cloud
242
214
  test_files:
243
- - spec/flying_sphinx/configuration_spec.rb
244
- - spec/flying_sphinx/delayed_delta_spec.rb
245
- - spec/flying_sphinx/flag_as_deleted_job_spec.rb
246
- - spec/flying_sphinx/index_request_spec.rb
215
+ - spec/spec_helper.rb
216
+ - spec/specs/configuration_spec.rb
217
+ - spec/specs/delayed_delta_spec.rb
218
+ - spec/specs/flag_as_deleted_job_spec.rb
219
+ - spec/specs/index_request_spec.rb