fail_fast 0.1.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.
- 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
|