erchef-solr 11.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,386 @@
1
+ #
2
+ # Author:: Daniel DeLeo (<dan@opscode.com)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'pp'
19
+ require 'optparse'
20
+ require 'chef/solr/version'
21
+ require 'chef/shell_out'
22
+ require 'chef/mixin/shell_out'
23
+
24
+ class Chef
25
+ class SolrInstaller
26
+
27
+ class Config
28
+ class CompatConfig
29
+ def initialize
30
+ @config_settings = {}
31
+ end
32
+
33
+ def from_file(file)
34
+ file = File.expand_path(file)
35
+ if File.readable?(file)
36
+ instance_eval(IO.read(file), file, 1)
37
+ else
38
+ STDERR.puts "Cannot open config file #{file} default settings will be used"
39
+ end
40
+ self
41
+ end
42
+
43
+ def method_missing(method_name, *args, &block)
44
+ if args.size == 1
45
+ @config_settings[method_name] = args.first
46
+ elsif args.empty?
47
+ @config_settings[method_name] or super
48
+ else
49
+ super
50
+ end
51
+ end
52
+
53
+ def to_hash
54
+ @config_settings
55
+ end
56
+ end
57
+
58
+
59
+ def self.default_values
60
+ @default_values ||= {}
61
+ end
62
+
63
+ def self.configurables
64
+ @configurables ||= []
65
+ end
66
+
67
+ def self.configurable(value, default=nil)
68
+ configurables << value
69
+ attr_accessor value
70
+ default_values[value] = default if default
71
+ end
72
+
73
+ def each_configurable
74
+ self.class.configurables.each do |config_param|
75
+ yield [config_param, send(config_param)]
76
+ end
77
+ end
78
+
79
+ configurable :config_file, '/etc/chef/solr.rb'
80
+
81
+ # Defaults to /var/chef
82
+ configurable :solr_base_path, nil
83
+
84
+ def solr_base_path
85
+ @solr_base_path || '/var/chef'
86
+ end
87
+
88
+ # Sets the solr_base_path. Also resets solr_home_path, solr_jetty_path,
89
+ # and solr_data_path.
90
+ def solr_base_path=(base_path)
91
+ @solr_home_path, @solr_jetty_path, @solr_data_path = nil,nil,nil
92
+ @solr_base_path = base_path
93
+ end
94
+
95
+
96
+ # Computed from base path, defaults to /var/chef/solr
97
+ configurable :solr_home_path, nil
98
+
99
+ def solr_home_path
100
+ @solr_home_path || File.join(solr_base_path, 'solr')
101
+ end
102
+
103
+ # Computed from base path, defaults to /var/chef/solr-jetty
104
+ configurable :solr_jetty_path, nil
105
+
106
+ def solr_jetty_path
107
+ @solr_jetty_path || File.join(solr_base_path, 'solr-jetty')
108
+ end
109
+
110
+ # Computed from base path, defaults to /var/chef/solr/data
111
+ configurable :solr_data_path, nil
112
+
113
+ def solr_data_path
114
+ @solr_data_path || File.join(solr_base_path, 'solr', 'data')
115
+ end
116
+
117
+
118
+ configurable :user, nil
119
+
120
+ configurable :group, nil
121
+
122
+ configurable :force, false
123
+
124
+ alias :force? :force
125
+
126
+ configurable :noop, false
127
+
128
+ alias :noop? :noop
129
+
130
+ def initialize
131
+ apply_hash(self.class.default_values)
132
+ end
133
+
134
+ def configure_from(argv)
135
+ cli_config = CLI.parse_options(argv)
136
+ #pp :cli_config => cli_config.to_hash
137
+ config_file_config = CompatConfig.new.from_file(cli_config.config_file).to_hash
138
+ #pp :config_file_config => config_file_config
139
+ apply_hash(config_file_config)
140
+ apply_hash(cli_config.to_hash)
141
+ #pp :combined_config => self.to_hash
142
+ self
143
+ end
144
+
145
+ def to_hash
146
+ self.class.configurables.inject({}) do |hash, config_option|
147
+ value = instance_variable_get("@#{config_option}".to_sym)
148
+ hash[config_option] = value if value
149
+ hash
150
+ end
151
+ end
152
+
153
+ def apply_hash(hash)
154
+ hash.each do |key, value|
155
+ method_for_key = "#{key}=".to_sym
156
+ if respond_to?(method_for_key)
157
+ send(method_for_key, value)
158
+ else
159
+ STDERR.puts("Configuration setting #{key} is unknown and will be ignored")
160
+ end
161
+ end
162
+ end
163
+
164
+ module CLI
165
+ @config = Config.new
166
+
167
+ @option_parser = OptionParser.new do |o|
168
+ o.banner = "Usage: chef-solr-installer [options]"
169
+
170
+ o.on('-c', '--config CONFIG_FILE', 'The configuration file to use') do |conf|
171
+ @config.config_file = File.expand_path(conf)
172
+ end
173
+
174
+ o.on('-u', '--user USER', "User who will own Solr's data directory") do |u|
175
+ @config.user = u
176
+ end
177
+
178
+ o.on('-g', '--group GROUP', "Group that will own Solr's data directory") do |g|
179
+ @config.group = g
180
+ end
181
+
182
+ o.on('-p', '--base-path PATH', "The base path for the installation. Must be given before any -H -W or -D options") do |path|
183
+ @config.solr_base_path = path
184
+ end
185
+
186
+ o.on('-H', '--solr-home-dir PATH', 'Where to create the Solr home directory. Defaults to BASE_PATH/solr') do |path|
187
+ @config.solr_home_path = path
188
+ end
189
+
190
+ o.on('-W', '--solr-jetty-path PATH', 'Where to install Jetty for Solr. Defaults to BASE_PATH/solr-jetty ') do |path|
191
+ @config.solr_jetty_path = path
192
+ end
193
+
194
+ o.on('-D', '--solr-data-path PATH', 'Where to create the Solr data directory. Defaults to BASE_PATH/solr/data') do |path|
195
+ @config.solr_data_path = path
196
+ end
197
+
198
+ o.on('-n', '--noop', "Don't actually install, just show what would be done by the install") do
199
+ @config.noop = true
200
+ end
201
+
202
+ o.on('-f', '--force', 'Overwrite any existing installation without asking for confirmation') do
203
+ @config.force = true
204
+ end
205
+
206
+ o.on_tail('-h', '--help', 'show this message') do
207
+ puts "chef-solr-installer #{Chef::Solr::VERSION}"
208
+ puts ''
209
+ puts o
210
+ puts ''
211
+ puts 'Default Settings:'
212
+ @config.each_configurable do |param, value|
213
+ value_for_display = value || "none/false"
214
+ puts " #{param}:".ljust(20) + " #{value_for_display}"
215
+ end
216
+ exit 1
217
+ end
218
+
219
+ o.on_tail('-v', '--version', 'show the version and exit') do
220
+ puts "chef-solr-installer #{Chef::Solr::VERSION}"
221
+ exit 0
222
+ end
223
+
224
+ end
225
+
226
+ def self.parse_options(argv)
227
+ @option_parser.parse!(argv.dup)
228
+ @config
229
+ end
230
+
231
+ def self.config
232
+ @config
233
+ end
234
+
235
+ end
236
+
237
+ end
238
+
239
+ include Chef::Mixin::ShellOut
240
+
241
+ PACKAGED_SOLR_DIR = File.expand_path( "../../../../solr", __FILE__)
242
+
243
+ attr_reader :config
244
+
245
+ def initialize(argv)
246
+ @indent = 0
247
+ @config = Config.new.configure_from(argv.dup)
248
+ @overwriting = false
249
+ end
250
+
251
+ def overwriting?
252
+ @overwriting
253
+ end
254
+
255
+ def chef_solr_installed?
256
+ File.exist?(config.solr_home_path)
257
+ end
258
+
259
+ def run
260
+ say ''
261
+ say "*** DRY RUN ***" if config.noop?
262
+
263
+ if chef_solr_installed?
264
+ @overwriting = true
265
+ confirm_overwrite unless config.force? || config.noop?
266
+ scorch_the_earth
267
+ end
268
+
269
+ create_solr_home
270
+ create_solr_data_dir
271
+ unpack_solr_jetty
272
+
273
+ say ""
274
+ say "Successfully installed Chef Solr."
275
+
276
+ if overwriting?
277
+ say "You can restore your search index using `knife index rebuild`"
278
+ end
279
+ end
280
+
281
+ def confirm_overwrite
282
+ if STDIN.tty? && STDOUT.tty?
283
+ say "Chef Solr is already installed in #{config.solr_home_path}"
284
+ print "Do you want to overwrite the current install? All existing Solr data will be lost. [y/n] "
285
+ unless STDIN.gets =~ /^y/
286
+ say "Quitting. Try running this with --noop to see what it will change."
287
+ exit 1
288
+ end
289
+ else
290
+ say(<<-FAIL)
291
+ ERROR: Chef Solr is already installed in #{config.solr_home_path} and you did not use the
292
+ --force option. Use --force to overwrite an existing installation in a non-
293
+ interactive terminal.
294
+ FAIL
295
+ exit 1
296
+ end
297
+ end
298
+
299
+ def scorch_the_earth
300
+ group("Removing the existing Chef Solr installation") do
301
+ rm_rf(config.solr_home_path)
302
+ rm_rf(config.solr_jetty_path)
303
+ rm_rf(config.solr_data_path)
304
+ end
305
+ end
306
+
307
+ def create_solr_home
308
+ group("Creating Solr Home Directory") do
309
+ mkdir_p(config.solr_home_path)
310
+ chdir(config.solr_home_path) do
311
+ sh("tar zxvf #{File.join(PACKAGED_SOLR_DIR, 'solr-home.tar.gz')}")
312
+ end
313
+ end
314
+ end
315
+
316
+ def create_solr_data_dir
317
+ group("Creating Solr Data Directory") do
318
+ mkdir_p(config.solr_data_path)
319
+ chown(config.solr_data_path)
320
+ end
321
+ end
322
+
323
+ def unpack_solr_jetty
324
+ group("Unpacking Solr Jetty") do
325
+ mkdir_p(config.solr_jetty_path)
326
+ chdir(config.solr_jetty_path) do
327
+ sh("tar zxvf #{File.join(PACKAGED_SOLR_DIR, 'solr-jetty.tar.gz')}")
328
+ end
329
+ chown(config.solr_jetty_path)
330
+ end
331
+ end
332
+
333
+ def mkdir_p(directory)
334
+ say "mkdir -p #{directory}"
335
+ FileUtils.mkdir_p(directory, :mode => 0755) unless config.noop?
336
+ end
337
+
338
+ def chdir(dir, &block)
339
+ say "entering #{dir}"
340
+ if config.noop?
341
+ yield if block_given? # still call the block so we get the noop output.
342
+ else
343
+ Dir.chdir(dir) { yield if block_given? }
344
+ end
345
+ end
346
+
347
+ def sh(*args)
348
+ opts = args[1, args.size - 1]
349
+ opts_msg = opts.empty? ? '' : " #{opts.to_s}"
350
+ say "#{args.first}#{opts_msg}"
351
+ shell_out!(*(args << {:cwd => false})) unless config.noop?
352
+ end
353
+
354
+ def chown(file)
355
+ if config.user
356
+ msg = "chown -R #{config.user}"
357
+ msg << ":#{config.group}" if config.group
358
+ msg << " #{file}"
359
+ say msg
360
+ FileUtils.chown_R(config.user, config.group, file) unless config.noop?
361
+ end
362
+ end
363
+
364
+ def rm_rf(path)
365
+ say "rm -rf #{path}"
366
+ FileUtils.rm_rf(path) unless config.noop?
367
+ end
368
+
369
+ def indent
370
+ @indent += 1
371
+ yield
372
+ @indent -= 1
373
+ end
374
+
375
+ def group(message, &block)
376
+ say(message)
377
+ indent(&block)
378
+ end
379
+
380
+ def say(message)
381
+ puts "#{' ' * (2 * @indent)}#{message}"
382
+ end
383
+
384
+ end
385
+ end
386
+
@@ -0,0 +1,11 @@
1
+ class Chef
2
+ class Solr
3
+ VERSION = '11.0.0.alpha.1'
4
+
5
+ # Solr Schema. Used to detect incompatibilities between installed solr and
6
+ # chef-solr versions.
7
+ SCHEMA_NAME = "chef"
8
+ SCHEMA_VERSION = '1.2'
9
+
10
+ end
11
+ end
Binary file
Binary file
@@ -0,0 +1 @@
1
+ -cbfs
@@ -0,0 +1,24 @@
1
+ #
2
+ # Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
3
+ # Copyright:: Copyright (c) 2012 Thomas Bishop
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'rspec'
20
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
21
+ $:.unshift(File.expand_path('../../lib/', __FILE__))
22
+ $:.unshift(File.expand_path('../../../chef/lib', __FILE__))
23
+
24
+ require 'chef/solr'
@@ -0,0 +1,569 @@
1
+ #
2
+ # Author:: Thomas Bishop (<bishop.thomas@gmail.com>)
3
+ # Copyright:: Copyright (c) 2012 Thomas Bishop
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+
19
+ require 'spec_helper'
20
+ require 'chef/solr/application/solr'
21
+
22
+ describe Chef::Solr::Application::Solr do
23
+
24
+ describe 'initialize' do
25
+ it 'should have a default config_file option' do
26
+ subject.config[:config_file].should == '/etc/chef/solr.rb'
27
+ end
28
+ end
29
+
30
+ describe 'schema_file_path' do
31
+ it 'should return the default schema file path' do
32
+ subject.schema_file_path.should == '/var/chef/solr/conf/schema.xml'
33
+ end
34
+
35
+ context 'with a custom solr home path' do
36
+ it 'should return the schema path' do
37
+ Chef::Config.stub(:[]).with(:solr_home_path).
38
+ and_return('/opt/chef/solr')
39
+ subject.schema_file_path.should == '/opt/chef/solr/conf/schema.xml'
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ describe 'solr_config_file_path' do
46
+ it 'should return the default solr config path' do
47
+ subject.solr_config_file_path.should == '/var/chef/solr/conf/solrconfig.xml'
48
+ end
49
+
50
+ context 'with a custom solr home path' do
51
+ it 'should return the solr config path' do
52
+ Chef::Config.stub(:[]).with(:solr_home_path).
53
+ and_return('/opt/chef/solr')
54
+ subject.solr_config_file_path.should == '/opt/chef/solr/conf/solrconfig.xml'
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ describe 'schema_document' do
61
+ before do
62
+ @schema_path = '/opt/chef/solr/conf/schema.xml'
63
+ subject.stub :schema_file_path => @schema_path
64
+ @doc_contents = '<?xml version="1.0" encoding="UTF-8" ?><foo>bar</foo>'
65
+ end
66
+
67
+ it 'should read the schema file at the correct path' do
68
+ REXML::Document.stub(:new)
69
+ File.should_receive(:open).with(@schema_path, 'r').
70
+ and_yield(@doc_contents)
71
+ subject.schema_document
72
+ end
73
+
74
+ it 'should return the schema' do
75
+ File.stub(:open).and_yield(@doc_contents)
76
+ subject.schema_document.should be_a REXML::Document
77
+ end
78
+ end
79
+
80
+ describe 'config_document' do
81
+ before do
82
+ @solr_config_path = '/opt/chef/solr/conf/solrconfig.xml'
83
+ subject.stub :solr_config_file_path => @solr_config_path
84
+ @doc_contents = '<?xml version="1.0" encoding="UTF-8" ?><foo>bar</foo>'
85
+ end
86
+
87
+ it 'should read the config file at the correct path' do
88
+ REXML::Document.stub(:new)
89
+ File.should_receive(:open).with(@solr_config_path, 'r').
90
+ and_yield(@doc_contents)
91
+ subject.config_document
92
+ end
93
+
94
+ it 'should return an REXML document' do
95
+ File.stub(:open).and_yield(@doc_contents)
96
+ subject.config_document.should be_a REXML::Document
97
+ end
98
+ end
99
+
100
+ describe 'schema_attributes' do
101
+ it 'should return the attributes of the schema element' do
102
+ schema_doc_contents = '<?xml version="1.0" encoding="UTF-8" ?>'
103
+ schema_doc_contents << '<schema name="chef" version="1.2"></schema>'
104
+ subject.stub(:schema_document).
105
+ and_return(REXML::Document.new(schema_doc_contents))
106
+
107
+ subject.schema_attributes["name"].should == 'chef'
108
+ subject.schema_attributes["version"].should == '1.2'
109
+ end
110
+ end
111
+
112
+ describe 'solr_main_index_elements' do
113
+ before do
114
+ doc_contents = '<?xml version="1.0" encoding="UTF-8" ?>'
115
+ doc_contents << '<config><mainIndex>'
116
+ doc_contents << '<maxFieldLength>10000</maxFieldLength>'
117
+ doc_contents << '</mainIndex></config>'
118
+ subject.stub(:config_document).
119
+ and_return(REXML::Document.new(doc_contents))
120
+ end
121
+
122
+ it 'should return a collection of the REXML elements' do
123
+ subject.solr_main_index_elements.each { |e| e.should be_a REXML::Element }
124
+ end
125
+
126
+ it 'should return the correct elements' do
127
+ subject.solr_main_index_elements.first.name.should == 'maxFieldLength'
128
+ subject.solr_main_index_elements.first.text.should == '10000'
129
+ end
130
+ end
131
+
132
+ describe 'solr_schema_name' do
133
+ it 'should return the schema name' do
134
+ subject.stub :schema_attributes => { 'name' => 'chef' }
135
+ subject.solr_schema_name.should == 'chef'
136
+ end
137
+ end
138
+
139
+ describe 'solr_schema_version' do
140
+ it 'should return the schema version' do
141
+ subject.stub :schema_attributes => { 'version' => '1.2' }
142
+ subject.solr_schema_version.should == '1.2'
143
+ end
144
+ end
145
+
146
+ describe 'solr_main_index_max_field_length' do
147
+ before do
148
+ @elements = [ REXML::Element.new('useCompoundFile').add_text('false'),
149
+ REXML::Element.new('ramBufferSizeMB').add_text('32'),
150
+ REXML::Element.new('maxFieldLength').add_text('10000') ]
151
+ subject.stub :solr_main_index_elements => @elements
152
+ end
153
+
154
+ it 'should return the value of maxFieldLimit as an integer' do
155
+ subject.solr_main_index_max_field_length.should == 10000
156
+ end
157
+
158
+ context 'if unable to find the maxFieldLimit' do
159
+ before do
160
+ elements = @elements.select { |e| e.name != 'maxFieldLength' }
161
+ subject.stub :solr_main_index_elements => elements
162
+ end
163
+
164
+ it 'should return nil' do
165
+ subject.solr_main_index_max_field_length.should be_nil
166
+ end
167
+ end
168
+
169
+ end
170
+
171
+ describe 'valid_schema_name?' do
172
+ it 'should return true if the schema name matches' do
173
+ subject.stub :solr_schema_name => Chef::Solr::SCHEMA_NAME
174
+ subject.valid_schema_name?.should be_true
175
+ end
176
+
177
+ it 'should return false if the schema name does not match' do
178
+ subject.stub :solr_schema_name => 'foo'
179
+ subject.valid_schema_name?.should be_false
180
+ end
181
+ end
182
+
183
+ describe 'valid_schema_version?' do
184
+ it 'should return true if the version name matches' do
185
+ subject.stub :solr_schema_version => Chef::Solr::SCHEMA_VERSION
186
+ subject.valid_schema_version?.should be_true
187
+ end
188
+
189
+ it 'should return false if the version name does not match' do
190
+ subject.stub :solr_schema_version => '-1.0'
191
+ subject.valid_schema_version?.should be_false
192
+ end
193
+ end
194
+
195
+ describe 'check_value_of_main_index_max_field_length' do
196
+ it 'should log a warning if it is set to <= 10000' do
197
+ subject.stub :solr_main_index_max_field_length => 10000
198
+ pattern = /maxFieldLimit.+set to.+recommended to increase this value/
199
+ Chef::Log.should_receive(:warn).with(pattern)
200
+ subject.check_value_of_main_index_max_field_length
201
+ end
202
+
203
+ it 'should not log a warning if it is set to > 10000' do
204
+ subject.stub :solr_main_index_max_field_length => 10001
205
+ Chef::Log.should_not_receive(:warn)
206
+ subject.check_value_of_main_index_max_field_length
207
+ end
208
+
209
+ context 'if it is not set' do
210
+ it 'should log a warning if it is not set' do
211
+ subject.stub :solr_main_index_max_field_length => nil
212
+ Chef::Log.should_receive(:warn).
213
+ with(/Unable to determine the maxFieldLimit for the mainIndex/)
214
+ subject.check_value_of_main_index_max_field_length
215
+ end
216
+ end
217
+
218
+ end
219
+
220
+ describe 'solr_home_exists?' do
221
+ before do
222
+ Chef::Config.stub(:[]).with(:solr_home_path).
223
+ and_return('/opt/chef/solr')
224
+ end
225
+
226
+ it 'should return true if the solr home exists' do
227
+ File.stub(:directory?).with('/opt/chef/solr').
228
+ and_return(true)
229
+ subject.solr_home_exist?.should be_true
230
+ end
231
+
232
+ it 'should return false if the solr home does not exist' do
233
+ File.stub(:directory?).with('/opt/chef/solr').
234
+ and_return(false)
235
+ subject.solr_home_exist?.should be_false
236
+ end
237
+ end
238
+
239
+ describe 'solr_data_dir_exists?' do
240
+ before do
241
+ Chef::Config.stub(:[]).with(:solr_data_path).
242
+ and_return('/opt/chef/solr')
243
+ end
244
+
245
+ it 'should return true if the solr data dir exists' do
246
+ File.stub(:directory?).with('/opt/chef/solr').
247
+ and_return(true)
248
+ subject.solr_data_dir_exist?.should be_true
249
+ end
250
+
251
+ it 'should return false if the solr data dir does not exist' do
252
+ File.stub(:directory?).with('/opt/chef/solr').
253
+ and_return(false)
254
+ subject.solr_data_dir_exist?.should be_false
255
+ end
256
+ end
257
+
258
+ describe 'solr_jetty_home_exists?' do
259
+ before do
260
+ Chef::Config.stub(:[]).with(:solr_jetty_path).
261
+ and_return('/opt/chef/solr')
262
+ end
263
+
264
+ it 'should return true if the solr jetty dir exists' do
265
+ File.stub(:directory?).with('/opt/chef/solr').
266
+ and_return(true)
267
+ subject.solr_jetty_home_exist?.should be_true
268
+ end
269
+
270
+ it 'should return false if the solr jetty dir does not exist' do
271
+ File.stub(:directory?).with('/opt/chef/solr').
272
+ and_return(false)
273
+ subject.solr_jetty_home_exist?.should be_false
274
+ end
275
+ end
276
+
277
+ describe 'assert_solr_installed!' do
278
+
279
+ context 'when unsuccessful' do
280
+ before do
281
+ message = /chef solr is not installed.+home.+data.+jetty.+misconfigured/i
282
+ Chef::Log.should_receive(:fatal).with(message).and_return(true)
283
+ Chef::Log.stub(:fatal)
284
+ end
285
+
286
+ context 'because the solr home does not exist' do
287
+ before do
288
+ subject.stub :solr_home_exist? => false
289
+ subject.stub :solr_data_dir_exist => true
290
+ subject.stub :solr_jetty_home_exist => true
291
+ end
292
+
293
+ it 'should log messages and exit' do
294
+ lambda {
295
+ subject.assert_solr_installed!
296
+ }.should raise_error SystemExit
297
+ end
298
+ end
299
+
300
+ context 'because the solr data dir does not exist' do
301
+ before do
302
+ subject.stub :solr_home_exist? => true
303
+ subject.stub :solr_data_dir_exist => false
304
+ subject.stub :solr_jetty_home_exist => true
305
+ end
306
+
307
+ it 'should log messages and exit' do
308
+ lambda {
309
+ subject.assert_solr_installed!
310
+ }.should raise_error SystemExit
311
+ end
312
+ end
313
+
314
+ context 'because the solr jetty home does not exist' do
315
+ before do
316
+ subject.stub :solr_home_exist? => true
317
+ subject.stub :solr_data_dir_exist => true
318
+ subject.stub :solr_jetty_home_exist => false
319
+ end
320
+
321
+ it 'should log messages and exit' do
322
+ lambda {
323
+ subject.assert_solr_installed!
324
+ }.should raise_error SystemExit
325
+ end
326
+ end
327
+
328
+ end
329
+
330
+ context 'when solr home, data dir, and jetty home exist' do
331
+ before do
332
+ ['home', 'data_dir', 'jetty_home'].each do |item|
333
+ subject.stub "solr_#{item}_exist?".to_sym => true
334
+ end
335
+ end
336
+
337
+ it 'should not exit' do
338
+ subject.assert_solr_installed!.should_not raise_error SystemExit
339
+ end
340
+ end
341
+
342
+ end
343
+
344
+ describe 'assert_valid_schema!' do
345
+ context 'when unsuccessful' do
346
+ before do
347
+ message = /chef solr installation.+upgraded.+/i
348
+ Chef::Log.should_receive(:fatal).with(message).and_return(true)
349
+ Chef::Log.stub(:fatal)
350
+ subject.stub :solr_schema_version => ''
351
+ end
352
+
353
+ context 'because the schema name is not valid' do
354
+ before do
355
+ subject.stub :valid_schema_name? => false
356
+ subject.stub :valid_schema_version => true
357
+ end
358
+
359
+ it 'should log messages and exit' do
360
+ lambda {
361
+ subject.assert_valid_schema!
362
+ }.should raise_error SystemExit
363
+ end
364
+ end
365
+
366
+ context 'because the schema version is not valid' do
367
+ before do
368
+ subject.stub :valid_schema_name? => true
369
+ subject.stub :valid_schema_version => false
370
+ end
371
+
372
+ it 'should log messages and exit' do
373
+ lambda {
374
+ subject.assert_valid_schema!
375
+ }.should raise_error SystemExit
376
+ end
377
+ end
378
+
379
+ end
380
+
381
+ context 'when the schema name and version are valid' do
382
+ before do
383
+ ['name', 'version'].each do |item|
384
+ subject.stub "valid_schema_#{item}?".to_sym => true
385
+ end
386
+ end
387
+
388
+ it 'should not exit' do
389
+ subject.assert_valid_schema!.should_not raise_error SystemExit
390
+ end
391
+ end
392
+
393
+ end
394
+
395
+ describe 'setup_application' do
396
+ before do
397
+ Chef::Daemon.should_receive :change_privilege
398
+ end
399
+
400
+ it 'should see if solr is installed' do
401
+ subject.stub :assert_valid_schema!
402
+ subject.stub :check_value_of_main_index_max_field_length
403
+ subject.should_receive :assert_solr_installed!
404
+ subject.setup_application
405
+ end
406
+
407
+ it 'should see if the schema is valid' do
408
+ subject.stub :assert_solr_installed!
409
+ subject.stub :check_value_of_main_index_max_field_length
410
+ subject.should_receive :assert_valid_schema!
411
+ subject.setup_application
412
+ end
413
+
414
+ it 'should check the maxFieldLimit setting' do
415
+ subject.stub :assert_solr_installed!
416
+ subject.stub :assert_valid_schema!
417
+ subject.should_receive :check_value_of_main_index_max_field_length
418
+ subject.setup_application
419
+ end
420
+
421
+ context 'with solr installed and a valid schema' do
422
+ before do
423
+ subject.stub :assert_solr_installed!
424
+ subject.stub :assert_valid_schema!
425
+ subject.stub :check_value_of_main_index_max_field_length
426
+ end
427
+
428
+ context 'with -L or --logfile' do
429
+ before do
430
+ @log_location = '/var/log/chef_solr.log'
431
+ Chef::Config.stub(:[]).with(:log_location).and_return(@log_location)
432
+ Chef::Config.stub(:[]).with(:log_level).and_return(:info)
433
+ end
434
+
435
+ it 'should open the log file for appending' do
436
+ File.should_receive(:new).with(@log_location, 'a')
437
+ subject.setup_application
438
+ end
439
+ end
440
+
441
+ it 'should set the log level' do
442
+ Chef::Config.stub(:[]).with(:log_location).and_return(nil)
443
+ Chef::Config.stub(:[]).with(:log_level).and_return(:info)
444
+ Chef::Log.should_receive(:level=).with(:info)
445
+ subject.setup_application
446
+ end
447
+ end
448
+
449
+ end
450
+
451
+ describe 'run_application' do
452
+ context 'with -d or --daemonize' do
453
+ before do
454
+ Chef::Config[:daemonize] = true
455
+ Kernel.stub :exec
456
+ Dir.stub :chdir
457
+ end
458
+
459
+ it 'should daemonize' do
460
+ Chef::Daemon.should_receive(:daemonize).with('chef-solr')
461
+ subject.run_application
462
+ end
463
+ end
464
+
465
+ it 'should change to the jetty home dir' do
466
+ Kernel.stub :exec
467
+ Dir.should_receive(:chdir).with(Chef::Config[:solr_jetty_path])
468
+ subject.run_application
469
+ end
470
+
471
+ context 'after changing to the jetty home dir' do
472
+ before do
473
+ Dir.should_receive(:chdir).and_yield
474
+ Chef::Daemon.stub :daemonize
475
+ Chef::Log.stub :info
476
+ end
477
+
478
+ it 'should start the process with the default settings' do
479
+ cmd = "java -Xmx#{Chef::Config[:solr_heap_size]} "
480
+ cmd << "-Xms#{Chef::Config[:solr_heap_size]} "
481
+ cmd << "-Dsolr.data.dir=#{Chef::Config[:solr_data_path]} "
482
+ cmd << "-Dsolr.solr.home=#{Chef::Config[:solr_home_path]} "
483
+ cmd << "-jar #{File.join(Chef::Config[:solr_jetty_path], 'start.jar')}"
484
+
485
+ Kernel.should_receive(:exec).with(cmd)
486
+ subject.run_application
487
+ end
488
+
489
+ it 'should log the command that solr is started with' do
490
+ cmd = /java.+solr.+jar.+start\.jar/
491
+ Chef::Log.should_receive(:info).with(cmd)
492
+ Kernel.stub :exec
493
+ subject.run_application
494
+ end
495
+
496
+ context 'with custom heap' do
497
+ it 'should start the process with the custom setting' do
498
+ Chef::Config[:solr_heap_size] = '2048M'
499
+ cmd_fragment = /-Xmx2048M -Xms2048M/
500
+ Kernel.should_receive(:exec).with(cmd_fragment)
501
+ subject.run_application
502
+ end
503
+ end
504
+
505
+ context 'with custom data path' do
506
+ it 'should start the process with the custom setting' do
507
+ Chef::Config[:solr_data_path] = '/opt/chef/solr_data'
508
+ cmd_fragment = /-Dsolr\.data\.dir=\/opt\/chef\/solr_data/
509
+ Kernel.should_receive(:exec).with(cmd_fragment)
510
+ subject.run_application
511
+ end
512
+ end
513
+
514
+ context 'with custom home path' do
515
+ it 'should start the process with the custom setting' do
516
+ Chef::Config[:solr_home_path] = '/opt/chef/solr/'
517
+ cmd_fragment = /-Dsolr\.solr\.home=\/opt\/chef\/solr/
518
+ Kernel.should_receive(:exec).with(cmd_fragment)
519
+ subject.run_application
520
+ end
521
+ end
522
+
523
+ context 'with custom jetty path' do
524
+ it 'should start the process with the custom setting' do
525
+ Chef::Config[:solr_jetty_path] = '/opt/chef/solr_jetty/'
526
+ cmd_fragment = /-jar \/opt\/chef\/solr_jetty\/start.jar/
527
+ Kernel.should_receive(:exec).with(cmd_fragment)
528
+ subject.run_application
529
+ end
530
+ end
531
+
532
+ context 'with custom java opts' do
533
+ it 'should start the java process with the custom setting' do
534
+ Chef::Config[:solr_java_opts] = '-XX:UseLargePages'
535
+ cmd_fragment = /-XX:UseLargePages/
536
+ Kernel.should_receive(:exec).with(cmd_fragment)
537
+ subject.run_application
538
+ end
539
+ end
540
+
541
+ context 'with -L or --logfile' do
542
+ it 'should close the previously opened log file and reopen it' do
543
+ Kernel.stub :exec
544
+ subject.logfile = StringIO.new
545
+ subject.should_receive(:close_and_reopen_log_file)
546
+ subject.run_application
547
+ end
548
+ end
549
+
550
+ end
551
+
552
+ end
553
+
554
+ describe 'close_and_reopen_log_file' do
555
+ it 'should close the log and reopen it' do
556
+ log = StringIO.new
557
+ Chef::Log.should_receive :close
558
+ STDOUT.should_receive(:reopen).with log
559
+ STDERR.should_receive(:reopen).with log
560
+ subject.logfile = log
561
+ subject.close_and_reopen_log_file
562
+ end
563
+ end
564
+
565
+ describe 'run' do
566
+ it { should respond_to :run}
567
+ end
568
+
569
+ end