fail_fast 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/CHANGELOG.txt +2 -0
- data/LICENSE +20 -0
- data/README.markdown +91 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/fail_fast.gemspec +86 -0
- data/lib/fail_fast/check_active_record_db.rb +107 -0
- data/lib/fail_fast/check_email.rb +34 -0
- data/lib/fail_fast/check_file_system.rb +65 -0
- data/lib/fail_fast/check_mongo_db.rb +61 -0
- data/lib/fail_fast/check_url.rb +73 -0
- data/lib/fail_fast/check_value.rb +38 -0
- data/lib/fail_fast/main.rb +89 -0
- data/lib/fail_fast/report.txt.erb +8 -0
- data/lib/fail_fast.rb +14 -0
- data/show_all_errors.rb +63 -0
- data/spec/file_is_empty_spec.rb +8 -0
- data/spec/file_is_missing_spec.rb +17 -0
- data/spec/file_system_spec.rb +40 -0
- data/spec/fixtures/empty.yml +0 -0
- data/spec/fixtures/simple.yml +32 -0
- data/spec/has_active_record_db_spec.rb +39 -0
- data/spec/has_email_for_spec.rb +13 -0
- data/spec/has_mongoDB_for_spec.rb +60 -0
- data/spec/has_url_for_spec.rb +22 -0
- data/spec/has_value_for_spec.rb +69 -0
- data/spec/how_to_use_spec.rb +45 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +86 -0
- metadata +136 -0
data/.document
ADDED
data/.gitignore
ADDED
data/CHANGELOG.txt
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Alain Ravet
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# fail_fast : don't start your application if some preconditions are not met.
|
2
|
+
|
3
|
+
## How to use :
|
4
|
+
|
5
|
+
Early in your project boot sequence insert code like
|
6
|
+
|
7
|
+
require 'fail_fast'
|
8
|
+
FailFast('database.yml').check do
|
9
|
+
has_active_record_db_for Rails.env
|
10
|
+
end
|
11
|
+
|
12
|
+
FailFast('database.mongo.yml').check do
|
13
|
+
has_mongoDB_for Rails.env
|
14
|
+
end
|
15
|
+
|
16
|
+
FailFast('path_to/config.yml', prefix=Rails.env).check do
|
17
|
+
has\_values_for 'author/fname', 'author/lname'
|
18
|
+
has\_url_for 'bug_tracker/url', :reachable => true
|
19
|
+
has\_email_for 'newsletter/to_address'
|
20
|
+
|
21
|
+
directory_exists_for '/tmp'
|
22
|
+
file_exists_for 'public/nda.pdf'
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
## Info :
|
27
|
+
|
28
|
+
Failing fast is important.
|
29
|
+
This gem DSL lets you write tests scripts that run early in the boot sequence of an application.
|
30
|
+
An exception is raised if one or more tests fail, and you get a detailled report of all the problems encountered.
|
31
|
+
|
32
|
+
Some rules are based on the contents of configuration files (database.yml, config.yml, etc...) :
|
33
|
+
|
34
|
+
- can a database connnection be established?
|
35
|
+
- is the mongoDB server active?
|
36
|
+
- is there an _:application\_name_ value in _config.yml_, and does it match a regexp pattern?
|
37
|
+
- is the value of _:info\_email__ a valid email?
|
38
|
+
- is the value of _:sponspor\_link_ a valid url, and is the site up?
|
39
|
+
|
40
|
+
You can also add custom rules, not related to any config files :
|
41
|
+
|
42
|
+
- is there a _/tmp_, or an _public/upload_ directory on the server?
|
43
|
+
- can the server access _http://google.com_?
|
44
|
+
- is there a _public/nda\_pdf_ file?
|
45
|
+
- etc..
|
46
|
+
|
47
|
+
|
48
|
+
## Features :
|
49
|
+
|
50
|
+
### _free/direct_ commands (not linked to the yaml file contents) :
|
51
|
+
|
52
|
+
directory_exists '/tmp'
|
53
|
+
file_exists '/Users/me/.bash_profile'
|
54
|
+
has_mongoDB 'localhost', 'db_app_1'
|
55
|
+
has_active_record_db :host => 'dbserv', :adapter => 'mysql', :database => 'db'
|
56
|
+
|
57
|
+
|
58
|
+
### _keyed_ commands (linked to a value found in a yaml file) :
|
59
|
+
|
60
|
+
####Test values linked to a key :
|
61
|
+
|
62
|
+
*presence :*
|
63
|
+
|
64
|
+
has_value_for :application_name
|
65
|
+
has_values_for 'author/fname', 'author/lname'
|
66
|
+
|
67
|
+
*contents <-> a regexp or pattern :*
|
68
|
+
|
69
|
+
has_value_for 'level', /(alpha|beta|production)/
|
70
|
+
has_url_for 'bug_tracker/url'
|
71
|
+
has_email_for 'newsletter/to_address'
|
72
|
+
|
73
|
+
Test the file system :
|
74
|
+
|
75
|
+
directory_exists_for 'public/assets'
|
76
|
+
file_exists_for 'public/500_custom.html'
|
77
|
+
|
78
|
+
Test external services :
|
79
|
+
|
80
|
+
# is a webserver up ?
|
81
|
+
has_url_for 'bug_tracker/url', :reachable => true
|
82
|
+
has_url_for 'bug_tracker/url', :reachable => true, :may_add_trailing_slash => true
|
83
|
+
|
84
|
+
|
85
|
+
# can we connect to a mongoDB db/server :
|
86
|
+
has_mongoDB_for 'test/mongoDB'
|
87
|
+
has_mongoDB_for 'test/unknown_mongoDB_db', :check_database => false
|
88
|
+
|
89
|
+
# can we connect to a SQL db :
|
90
|
+
has_active_record_db_for 'production/db_connection'
|
91
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "fail_fast"
|
8
|
+
gem.summary = %Q{raises an error if the yaml contents of a config file does pass a test script.}
|
9
|
+
gem.description = %Q{raises an error if the yaml contents of a config file does not pass a test script.}
|
10
|
+
gem.email = "alainravet@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/alainravet/fail_fast"
|
12
|
+
gem.authors = ["Alain Ravet"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.add_development_dependency "mongo"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "config_file_check #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/fail_fast.gemspec
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{fail_fast}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Alain Ravet"]
|
12
|
+
s.date = %q{2010-06-20}
|
13
|
+
s.description = %q{raises an error if the yaml contents of a config file does not pass a test script.}
|
14
|
+
s.email = %q{alainravet@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"CHANGELOG.txt",
|
23
|
+
"LICENSE",
|
24
|
+
"README.markdown",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"fail_fast.gemspec",
|
28
|
+
"lib/fail_fast.rb",
|
29
|
+
"lib/fail_fast/check_active_record_db.rb",
|
30
|
+
"lib/fail_fast/check_email.rb",
|
31
|
+
"lib/fail_fast/check_file_system.rb",
|
32
|
+
"lib/fail_fast/check_mongo_db.rb",
|
33
|
+
"lib/fail_fast/check_url.rb",
|
34
|
+
"lib/fail_fast/check_value.rb",
|
35
|
+
"lib/fail_fast/main.rb",
|
36
|
+
"lib/fail_fast/report.txt.erb",
|
37
|
+
"show_all_errors.rb",
|
38
|
+
"spec/file_is_empty_spec.rb",
|
39
|
+
"spec/file_is_missing_spec.rb",
|
40
|
+
"spec/file_system_spec.rb",
|
41
|
+
"spec/fixtures/empty.yml",
|
42
|
+
"spec/fixtures/simple.yml",
|
43
|
+
"spec/has_active_record_db_spec.rb",
|
44
|
+
"spec/has_email_for_spec.rb",
|
45
|
+
"spec/has_mongoDB_for_spec.rb",
|
46
|
+
"spec/has_url_for_spec.rb",
|
47
|
+
"spec/has_value_for_spec.rb",
|
48
|
+
"spec/how_to_use_spec.rb",
|
49
|
+
"spec/spec.opts",
|
50
|
+
"spec/spec_helper.rb"
|
51
|
+
]
|
52
|
+
s.homepage = %q{http://github.com/alainravet/fail_fast}
|
53
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
54
|
+
s.require_paths = ["lib"]
|
55
|
+
s.rubygems_version = %q{1.3.7}
|
56
|
+
s.summary = %q{raises an error if the yaml contents of a config file does pass a test script.}
|
57
|
+
s.test_files = [
|
58
|
+
"spec/file_is_empty_spec.rb",
|
59
|
+
"spec/file_is_missing_spec.rb",
|
60
|
+
"spec/file_system_spec.rb",
|
61
|
+
"spec/has_active_record_db_spec.rb",
|
62
|
+
"spec/has_email_for_spec.rb",
|
63
|
+
"spec/has_mongoDB_for_spec.rb",
|
64
|
+
"spec/has_url_for_spec.rb",
|
65
|
+
"spec/has_value_for_spec.rb",
|
66
|
+
"spec/how_to_use_spec.rb",
|
67
|
+
"spec/spec_helper.rb"
|
68
|
+
]
|
69
|
+
|
70
|
+
if s.respond_to? :specification_version then
|
71
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
72
|
+
s.specification_version = 3
|
73
|
+
|
74
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
75
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
76
|
+
s.add_development_dependency(%q<mongo>, [">= 0"])
|
77
|
+
else
|
78
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
79
|
+
s.add_dependency(%q<mongo>, [">= 0"])
|
80
|
+
end
|
81
|
+
else
|
82
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
83
|
+
s.add_dependency(%q<mongo>, [">= 0"])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
# ActiveRecord::Base.establish_connection(
|
3
|
+
# :adapter => "mysql",
|
4
|
+
# :host => "localhost",
|
5
|
+
# :username => "myuser",
|
6
|
+
# :password => "mypass",
|
7
|
+
# :database => "somedatabase"
|
8
|
+
# )
|
9
|
+
# ActiveRecord::Base.establish_connection(
|
10
|
+
# :adapter => "sqlite",
|
11
|
+
# :database => "path/to/dbfile"
|
12
|
+
# )
|
13
|
+
# ActiveRecord::Base.establish_connection(
|
14
|
+
# :adapter => "sqlite3",
|
15
|
+
# :dbfile => ":memory:"
|
16
|
+
#)
|
17
|
+
|
18
|
+
class FailFast
|
19
|
+
module CheckActiveRecordDB
|
20
|
+
|
21
|
+
# Ensure the ActiveRecord connection can be established :
|
22
|
+
#
|
23
|
+
# Usage :
|
24
|
+
# has_active_record_db :host => 'localhost', :adapter => 'sqlite3', :database=> 'prod_db'
|
25
|
+
#
|
26
|
+
def has_active_record_db(*params)
|
27
|
+
options = params.last.is_a?(Hash) ? params.pop : {}
|
28
|
+
begin
|
29
|
+
ActiveRecord::Base.establish_connection(options)
|
30
|
+
@connection = ActiveRecord::Base.connection
|
31
|
+
@success = @connection && @connection.active?
|
32
|
+
rescue => e
|
33
|
+
@success = false
|
34
|
+
@error_message = e.message
|
35
|
+
end
|
36
|
+
unless @success
|
37
|
+
FailFast.errors << ErrorDetails.new(nil, :active_record_db_connection_error, @error_message)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Ensure the ActiveRecord connection can be established :
|
42
|
+
#
|
43
|
+
# Usage :
|
44
|
+
# has_active_record_db_for 'production/database'
|
45
|
+
#
|
46
|
+
def has_active_record_db_for(key, *params)
|
47
|
+
return unless has_value_for key
|
48
|
+
return unless has_value_for "#{key}/adapter"
|
49
|
+
return unless has_value_for "#{key}/database"
|
50
|
+
|
51
|
+
p = key_value_regexp_options(key, params)
|
52
|
+
key, options = p.key, p.options
|
53
|
+
|
54
|
+
begin
|
55
|
+
connection_options = p.value
|
56
|
+
ActiveRecord::Base.establish_connection(connection_options)
|
57
|
+
@connection = ActiveRecord::Base.connection
|
58
|
+
@success = @connection && @connection.active?
|
59
|
+
rescue => e
|
60
|
+
@success = false
|
61
|
+
@error_message = e.message
|
62
|
+
end
|
63
|
+
unless @success
|
64
|
+
FailFast.errors << ErrorDetails.new(key, :active_record_db_connection_error, @error_message)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
FailFast.send :include, FailFast::CheckActiveRecordDB
|
72
|
+
|
73
|
+
__END__
|
74
|
+
# Ensure the mongoDB server can be reached, and the db could be opened :
|
75
|
+
#
|
76
|
+
# Usage :
|
77
|
+
# has_mongoDB_for 'test/mongoDB'
|
78
|
+
# has_mongoDB_for 'test/unknown_mongoDB_db', :check_database => false
|
79
|
+
#
|
80
|
+
def has_mongoDB_for(key, *params)
|
81
|
+
return unless has_value_for key
|
82
|
+
return unless has_value_for "#{key}/host"
|
83
|
+
return unless has_value_for "#{key}/database"
|
84
|
+
|
85
|
+
p = key_value_regexp_options(key, params)
|
86
|
+
key, options = p.key, p.options
|
87
|
+
|
88
|
+
value = value_for_deep_key(key)
|
89
|
+
host, port, db = value['host'], value['port'], value['database']
|
90
|
+
|
91
|
+
begin
|
92
|
+
@conn = Mongo::Connection.new(host, port)
|
93
|
+
rescue Mongo::ConnectionFailure
|
94
|
+
FailFast.errors << ErrorDetails.new(key, :mongoDB_server_not_found, host)
|
95
|
+
return
|
96
|
+
end
|
97
|
+
|
98
|
+
must_check_db = !(false == options[:check_database])
|
99
|
+
if must_check_db && !@conn.database_names.include?(db)
|
100
|
+
FailFast.errors << ErrorDetails.new(key, :mongoDB_db_not_found, db)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class FailFast
|
2
|
+
|
3
|
+
module CheckEmail
|
4
|
+
# Usage
|
5
|
+
# has_email_for 'test/admin_email'
|
6
|
+
#
|
7
|
+
def has_email_for(key, *params)
|
8
|
+
return unless has_value_for key
|
9
|
+
|
10
|
+
p = key_value_regexp_options(key, params)
|
11
|
+
key, options = p.key, p.options
|
12
|
+
|
13
|
+
value = value_for_deep_key(key)
|
14
|
+
if EmailValidator.invalid_email_address?(value)
|
15
|
+
FailFast.errors << ErrorDetails.new(key, :not_an_email, value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module EmailValidator
|
21
|
+
VALID_EMAIL_ADDRESS_REGEXP = /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/
|
22
|
+
|
23
|
+
def self.valid_email_address?(email)
|
24
|
+
email.strip!
|
25
|
+
!!(email =~ VALID_EMAIL_ADDRESS_REGEXP)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.invalid_email_address?(email)
|
29
|
+
!valid_email_address?(email)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
FailFast.send :include, FailFast::CheckEmail
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class FailFast
|
2
|
+
module CheckFileSystem
|
3
|
+
|
4
|
+
# Ensure the value is an existing directory
|
5
|
+
#
|
6
|
+
# Usage
|
7
|
+
# directory_exists '/tmp'
|
8
|
+
#
|
9
|
+
def directory_exists(path, *params)
|
10
|
+
unless File.exists?(path) && File.directory?(path)
|
11
|
+
FailFast.errors << ErrorDetails.new(nil, :directory_not_found, path)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Ensure the value is an existing file
|
16
|
+
#
|
17
|
+
# Usage
|
18
|
+
# file_exists '~/.bash_profile'
|
19
|
+
#
|
20
|
+
def file_exists(path, *params)
|
21
|
+
unless File.exists?(path) && File.file?(path)
|
22
|
+
FailFast.errors << ErrorDetails.new(nil, :file_not_found, path)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Ensure the key value is an existing directory
|
27
|
+
#
|
28
|
+
# Usage
|
29
|
+
# directory_exists_for 'foo/config'
|
30
|
+
#
|
31
|
+
def directory_exists_for(key, *params)
|
32
|
+
return unless has_value_for key
|
33
|
+
|
34
|
+
p = key_value_regexp_options(key, params)
|
35
|
+
key, options = p.key, p.options
|
36
|
+
|
37
|
+
path = value_for_deep_key(key)
|
38
|
+
|
39
|
+
unless File.exists?(path) && File.directory?(path)
|
40
|
+
FailFast.errors << ErrorDetails.new(key, :directory_not_found, p.value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Ensure the key value is an existing file exists
|
45
|
+
#
|
46
|
+
# Usage
|
47
|
+
# file_exists_for 'foo/config/app.yml'
|
48
|
+
#
|
49
|
+
def file_exists_for(key, *params)
|
50
|
+
return unless has_value_for key
|
51
|
+
|
52
|
+
p = key_value_regexp_options(key, params)
|
53
|
+
key, options = p.key, p.options
|
54
|
+
|
55
|
+
path = value_for_deep_key(key)
|
56
|
+
|
57
|
+
unless File.exists?(path) && File.file?(path)
|
58
|
+
FailFast.errors << ErrorDetails.new(key, :file_not_found, p.value)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
FailFast.send :include, FailFast::CheckFileSystem
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class FailFast
|
2
|
+
module CheckMongoDB
|
3
|
+
|
4
|
+
# Ensure the mongoDB server can be reached, and the db could be opened :
|
5
|
+
#
|
6
|
+
# Usage :
|
7
|
+
# has_mongoDB 'localhost'
|
8
|
+
# has_mongoDB 'localhost', 'my_db', :port => 1234, :timeout => 2
|
9
|
+
# has_mongoDB 'localhost', :port => 1234, :timeout => 2
|
10
|
+
#
|
11
|
+
def has_mongoDB(host, *params)
|
12
|
+
options = params.last.is_a?(Hash) ? params.pop : {}
|
13
|
+
db = params.first
|
14
|
+
|
15
|
+
begin
|
16
|
+
port = options.delete(:port)
|
17
|
+
@conn = Mongo::Connection.new(host, port, options)
|
18
|
+
rescue Mongo::ConnectionFailure
|
19
|
+
FailFast.errors << ErrorDetails.new(nil, :mongoDB_server_not_found, host)
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
if db && !@conn.database_names.include?(db)
|
24
|
+
FailFast.errors << ErrorDetails.new(nil, :mongoDB_db_not_found, db)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Ensure the mongoDB server can be reached, and the db could be opened :
|
29
|
+
#
|
30
|
+
# Usage :
|
31
|
+
# has_mongoDB_for 'test/mongoDB'
|
32
|
+
# has_mongoDB_for 'test/unknown_mongoDB_db', :check_database => false
|
33
|
+
#
|
34
|
+
def has_mongoDB_for(key, *params)
|
35
|
+
return unless has_value_for key
|
36
|
+
return unless has_value_for "#{key}/host"
|
37
|
+
return unless has_value_for "#{key}/database"
|
38
|
+
|
39
|
+
p = key_value_regexp_options(key, params)
|
40
|
+
key, options = p.key, p.options
|
41
|
+
|
42
|
+
value = value_for_deep_key(key)
|
43
|
+
host, port, db = value['host'], value['port'], value['database']
|
44
|
+
|
45
|
+
begin
|
46
|
+
@conn = Mongo::Connection.new(host, port)
|
47
|
+
rescue Mongo::ConnectionFailure
|
48
|
+
FailFast.errors << ErrorDetails.new(key, :mongoDB_server_not_found, host)
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
must_check_db = !(false == options[:check_database])
|
53
|
+
if must_check_db && !@conn.database_names.include?(db)
|
54
|
+
FailFast.errors << ErrorDetails.new(key, :mongoDB_db_not_found, db)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
FailFast.send :include, FailFast::CheckMongoDB
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class FailFast
|
2
|
+
|
3
|
+
module CheckUrl
|
4
|
+
# Usage
|
5
|
+
# test if the url is valid :
|
6
|
+
# has_url_for 'test/server_url'
|
7
|
+
# test if the url is reachable :
|
8
|
+
# has_url_for 'test/server_url', :reachable => true
|
9
|
+
# test if the url is reachable, possibly after adding a trailing slash.
|
10
|
+
# (ex: http://example.com + http://example.com/)
|
11
|
+
# has_url_for 'test/server_url', :reachable => true, :may_add_trailing_slash => true
|
12
|
+
#
|
13
|
+
def has_url_for(key, *params)
|
14
|
+
return unless has_value_for key
|
15
|
+
|
16
|
+
p = key_value_regexp_options(key, params)
|
17
|
+
key, options = p.key, p.options
|
18
|
+
|
19
|
+
value = value_for_deep_key(key)
|
20
|
+
if UrlValidator.invalid_url?(value)
|
21
|
+
FailFast.errors << ErrorDetails.new(key, :not_a_url, value)
|
22
|
+
return
|
23
|
+
end
|
24
|
+
if true==options.delete(:reachable) && UrlValidator.unreachable_url?(value, options)
|
25
|
+
FailFast.errors << ErrorDetails.new(key, :url_not_reachable, value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module UrlValidator
|
31
|
+
IPv4_PART = /\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]/ # 0-255
|
32
|
+
VALID_URL_REGEXP = %r{
|
33
|
+
\A
|
34
|
+
https?:// # http:// or https://
|
35
|
+
([^\s:@]+:[^\s:@]*@)? # optional username:pw@
|
36
|
+
( (([^\W_]+\.)*xn--)?[^\W_]+([-.][^\W_]+)*\.[a-z]{2,6}\.? | # domain (including Punycode/IDN)...
|
37
|
+
#{IPv4_PART}(\.#{IPv4_PART}){3} | # or IPv4
|
38
|
+
localhost ) # or localhost
|
39
|
+
(:\d{1,5})? # optional port
|
40
|
+
([/?]\S*)? # optional /whatever or ?whatever
|
41
|
+
\Z
|
42
|
+
}iux
|
43
|
+
|
44
|
+
def self.valid_url?(url)
|
45
|
+
url.strip!
|
46
|
+
!!(url =~ VALID_URL_REGEXP)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.invalid_url?(url)
|
50
|
+
!valid_url?(url)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.reachable_url?(url_s, options = {:may_add_trailing_slash => false})
|
54
|
+
url_s = "http://#{url_s}" unless url_s =~ /http/
|
55
|
+
url = URI.parse(url_s)
|
56
|
+
http = Net::HTTP.new(url.host, url.port)
|
57
|
+
http.open_timeout = http.read_timeout = 5 #seconds
|
58
|
+
http.get(url.path)
|
59
|
+
true
|
60
|
+
rescue Exception
|
61
|
+
can_retry_after_appending_a_fwd_slash = (true == options[:may_add_trailing_slash]) && !(url_s =~ /\/$/)
|
62
|
+
can_retry_after_appending_a_fwd_slash ?
|
63
|
+
reachable_url?(url_s + '/', options) :
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.unreachable_url?(url_s, options = {:may_add_trailing_slash => false})
|
68
|
+
!reachable_url?(url_s, options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
FailFast.send :include, FailFast::CheckUrl
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class FailFast
|
2
|
+
module CheckValue
|
3
|
+
|
4
|
+
# Usage
|
5
|
+
# has_value_for 'str_key'
|
6
|
+
# has_value_for :sym_key, /localhost/
|
7
|
+
# returns
|
8
|
+
# true if succesful, false otherwise
|
9
|
+
def has_value_for(key, *params)
|
10
|
+
p = key_value_regexp_options(key, params)
|
11
|
+
key, options = p.key, p.options
|
12
|
+
|
13
|
+
nof_errors = FailFast.errors.size
|
14
|
+
if blank?(p.value)
|
15
|
+
FailFast.errors << ErrorDetails.new(key, :missing_value, nil)
|
16
|
+
|
17
|
+
elsif p.regexp
|
18
|
+
FailFast.errors << ErrorDetails.new(key, :value_does_not_match, p.value) unless p.value =~ p.regexp
|
19
|
+
|
20
|
+
elsif hash?(options) && range?(options[:in])
|
21
|
+
FailFast.errors << ErrorDetails.new(key, :value_not_in_range, p.value) unless options[:in].include?(p.value)
|
22
|
+
|
23
|
+
elsif hash?(options) && array?(options[:in])
|
24
|
+
FailFast.errors << ErrorDetails.new(key, :value_not_in_array, p.value) unless options[:in].include?(p.value)
|
25
|
+
end
|
26
|
+
no_new_error = nof_errors == FailFast.errors.size
|
27
|
+
end
|
28
|
+
|
29
|
+
# Usage
|
30
|
+
# has_values_for :sym_key, 'str_key'
|
31
|
+
#
|
32
|
+
def has_values_for(*keys)
|
33
|
+
keys.each{|key| has_value_for(key)}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
FailFast.send :include, FailFast::CheckValue
|