lilypad 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +70 -19
- data/gemspec.rb +1 -1
- data/lib/capistrano/lilypad.rb +21 -0
- data/lib/lilypad.rb +52 -0
- data/lib/lilypad/adapters/rails.rb +41 -0
- data/lib/lilypad/adapters/sinatra.rb +16 -0
- data/lib/lilypad/config.rb +57 -0
- data/lib/lilypad/config/request.rb +23 -0
- data/lib/lilypad/hoptoad/deploy.rb +48 -0
- data/lib/lilypad/hoptoad/notify.rb +87 -0
- data/lib/lilypad/hoptoad/xml.rb +61 -0
- data/lib/lilypad/log.rb +51 -0
- data/lib/rack/lilypad.rb +9 -143
- data/spec/fixtures/rails/config/environment.rb +2 -2
- data/spec/fixtures/rails/log/production.log +15987 -620
- data/spec/fixtures/sinatra.rb +5 -1
- data/spec/lilypad/adapters/rails_spec.rb +67 -0
- data/spec/lilypad/adapters/sinatra_spec.rb +49 -0
- data/spec/lilypad/config/request_spec.rb +27 -0
- data/spec/lilypad/config_spec.rb +59 -0
- data/spec/lilypad/hoptoad/deploy_spec.rb +85 -0
- data/spec/lilypad/hoptoad/notify_spec.rb +138 -0
- data/spec/lilypad_spec.rb +76 -0
- data/spec/spec_helper.rb +12 -2
- metadata +19 -6
- data/lib/rack/lilypad/rails.rb +0 -27
- data/spec/fixtures/rails/log/development.log +0 -4871
- data/spec/fixtures/rails/log/staging.log +0 -196
- data/spec/rack/lilypad_spec.rb +0 -128
data/spec/fixtures/sinatra.rb
CHANGED
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.expand_path("#{File.dirname __FILE__}/../../spec_helper")
|
2
|
+
|
3
|
+
describe Lilypad::Rails do
|
4
|
+
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
def app
|
8
|
+
ActionController::Dispatcher.new
|
9
|
+
end
|
10
|
+
|
11
|
+
describe :post do
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
ENV['RACK_ENV'] = 'production'
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
stub_net_http
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should post an error to Hoptoad" do
|
22
|
+
@http.should_receive(:post)
|
23
|
+
get "/test" rescue nil
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should post middleware exceptions" do
|
27
|
+
@http.should_receive(:post)
|
28
|
+
get "/nothing?test_exception=1" rescue nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should not post anything if non-production environment" do
|
32
|
+
ENV['RACK_ENV'] = 'development'
|
33
|
+
@http.should_not_receive(:post)
|
34
|
+
get "/test" rescue nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe :RACK_ENV do
|
39
|
+
|
40
|
+
before(:each) do
|
41
|
+
ENV['RACK_ENV'] = nil
|
42
|
+
ENV['RAILS_ENV'] = 'production'
|
43
|
+
ActionController::Base.send :include, Lilypad::Rails
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should set ENV['RACK_ENV']" do
|
47
|
+
ENV['RACK_ENV'].should == 'production'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe :rescue_action_without_handler do
|
52
|
+
|
53
|
+
it "should set Config::Request.action" do
|
54
|
+
Lilypad::Config::Request.should_receive(:action).with('test')
|
55
|
+
get "/test" rescue nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should set Config::Request.component" do
|
59
|
+
Lilypad::Config::Request.should_receive(:component).with('application')
|
60
|
+
get "/test" rescue nil
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should re-raise the exception (ActionController::Failsafe disabled)" do
|
64
|
+
lambda { get "/test" }.should raise_error(TestError)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path("#{File.dirname __FILE__}/../../spec_helper")
|
2
|
+
|
3
|
+
describe Lilypad::Sinatra do
|
4
|
+
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
def app
|
8
|
+
SinatraApp.new
|
9
|
+
end
|
10
|
+
|
11
|
+
describe :post do
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
ENV['RACK_ENV'] = 'production'
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
stub_net_http
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should post an error to Hoptoad" do
|
22
|
+
@http.should_receive(:post)
|
23
|
+
get "/test" rescue nil
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should post middleware exceptions" do
|
27
|
+
@http.should_receive(:post)
|
28
|
+
get "/nothing?test_exception=1" rescue nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should not post anything if non-production environment" do
|
32
|
+
ENV['RACK_ENV'] = 'development'
|
33
|
+
@http.should_not_receive(:post)
|
34
|
+
get "/test" rescue nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe :raise_errors do
|
39
|
+
|
40
|
+
it "should set raise_errors to true" do
|
41
|
+
get "/nothing"
|
42
|
+
Sinatra::Base.raise_errors?.should == true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should re-raise the exception" do
|
46
|
+
lambda { get "/test" }.should raise_error(TestError)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path("#{File.dirname __FILE__}/../../spec_helper")
|
2
|
+
|
3
|
+
describe Lilypad::Config::Request do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
Lilypad::Config::Request.action 'action'
|
7
|
+
Lilypad::Config::Request.component 'component'
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
Lilypad::Config::Request.class_eval do
|
12
|
+
@action = nil
|
13
|
+
@component = nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should set options" do
|
18
|
+
Lilypad::Config::Request.action.should == 'action'
|
19
|
+
Lilypad::Config::Request.component.should == 'component'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should provide a method to reset all options" do
|
23
|
+
Lilypad::Config::Request.reset!
|
24
|
+
Lilypad::Config::Request.action.should == nil
|
25
|
+
Lilypad::Config::Request.component.should == nil
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.expand_path("#{File.dirname __FILE__}/../spec_helper")
|
2
|
+
|
3
|
+
describe Lilypad::Config do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
Lilypad::Config.api_key 'api_key'
|
7
|
+
Lilypad::Config.deploy_url 'deploy_url'
|
8
|
+
Lilypad::Config.environments 'environments'
|
9
|
+
Lilypad::Config.filters 'filters'
|
10
|
+
Lilypad::Config.log 'log'
|
11
|
+
Lilypad::Config.notify_url 'notify_url'
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:each) do
|
15
|
+
Lilypad::Config.class_eval do
|
16
|
+
@api_key = nil
|
17
|
+
@deploy_url = nil
|
18
|
+
@environments = nil
|
19
|
+
@filters = nil
|
20
|
+
@log = nil
|
21
|
+
@notify_url = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should set options" do
|
26
|
+
Lilypad::Config.api_key.should == 'api_key'
|
27
|
+
Lilypad::Config.deploy_url.should == 'deploy_url'
|
28
|
+
Lilypad::Config.environments.should == 'environments'
|
29
|
+
Lilypad::Config.filters.should == 'filters'
|
30
|
+
Lilypad::Config.log.should == 'log'
|
31
|
+
Lilypad::Config.notify_url.should == 'notify_url'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should require the rails adapter when the rails method is called" do
|
35
|
+
adapter = File.expand_path "#{SPEC}/../lib/lilypad/adapters/rails"
|
36
|
+
Lilypad::Config.should_receive(:require).with(adapter)
|
37
|
+
Lilypad::Config.rails
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should require the rails adapter when the sinatra method is called" do
|
41
|
+
adapter = File.expand_path "#{SPEC}/../lib/lilypad/adapters/sinatra"
|
42
|
+
Lilypad::Config.should_receive(:require).with(adapter)
|
43
|
+
Lilypad::Config.sinatra
|
44
|
+
end
|
45
|
+
|
46
|
+
describe :Methods do
|
47
|
+
|
48
|
+
include Lilypad::Config::Methods
|
49
|
+
|
50
|
+
it "should provide an api_key method" do
|
51
|
+
Lilypad::Config.api_key 'api_key'
|
52
|
+
api_key.should == 'api_key'
|
53
|
+
Lilypad::Config.api_key { |env, e| [ env, e ].join '_' }
|
54
|
+
api_key.should == 'api_key' # api string takes precedence even when block configured
|
55
|
+
Lilypad::Config.class_eval { @api_key = nil }
|
56
|
+
api_key('api_key', 'block').should == 'api_key_block' # string is nil, now use the block
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path("#{File.dirname __FILE__}/../../spec_helper")
|
2
|
+
|
3
|
+
describe Lilypad::Hoptoad::Deploy do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
stub_net_http
|
7
|
+
@options = {
|
8
|
+
:username => 'username',
|
9
|
+
:environment => 'environment',
|
10
|
+
:revision => 'revision',
|
11
|
+
:repository => 'repository'
|
12
|
+
}
|
13
|
+
@instance = Lilypad::Hoptoad::Deploy.new(@options)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :initialize do
|
17
|
+
|
18
|
+
after(:each) do
|
19
|
+
@instance.send(:initialize, @options)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should call the post method" do
|
23
|
+
@instance.should_receive(:post)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should log the event" do
|
27
|
+
@instance.should_receive(:log).with(:deploy, @http_ok)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return the success status" do
|
31
|
+
@instance.should_receive(:success?)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe :params do
|
36
|
+
|
37
|
+
before(:each) do
|
38
|
+
Lilypad { api_key '' }
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return parameters for the Hoptoad request" do
|
42
|
+
@instance.send(:params).should == {
|
43
|
+
'api_key' => '',
|
44
|
+
'deploy[local_username]' => @options[:username],
|
45
|
+
'deploy[rails_env]' => @options[:environment],
|
46
|
+
'deploy[scm_revision]' => @options[:revision],
|
47
|
+
'deploy[scm_repository]' => @options[:repository]
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe :post do
|
53
|
+
|
54
|
+
before(:each) do
|
55
|
+
URI.stub!(:parse).and_return('uri')
|
56
|
+
@instance.stub!(:params).and_return('params')
|
57
|
+
end
|
58
|
+
|
59
|
+
after(:each) do
|
60
|
+
@instance.send(:post)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should parse the URI" do
|
64
|
+
URI.should_receive(:parse).with(Lilypad::Config.deploy_url)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should post the form using the URI and params method" do
|
68
|
+
@instance.should_receive(:params)
|
69
|
+
Net::HTTP.should_receive(:post_form).with('uri', 'params')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe :success? do
|
74
|
+
|
75
|
+
it "should make sure the response's superclass equals Net::HTTPSuccess" do
|
76
|
+
Net::HTTP.stub!(:post_form).and_return(nil)
|
77
|
+
@instance.send(:initialize, @options)
|
78
|
+
@instance.send(:success?).should == false
|
79
|
+
|
80
|
+
Net::HTTP.stub!(:post_form).and_return(@http_ok)
|
81
|
+
@instance.send(:initialize, @options)
|
82
|
+
@instance.send(:success?).should == true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require File.expand_path("#{File.dirname __FILE__}/../../spec_helper")
|
2
|
+
|
3
|
+
describe Lilypad::Hoptoad::Notify do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
uri = mock(:uri)
|
7
|
+
uri.stub!(:host)
|
8
|
+
uri.stub!(:port)
|
9
|
+
uri.stub!(:path).and_return('uri')
|
10
|
+
URI.stub!(:parse).and_return(uri)
|
11
|
+
stub_net_http
|
12
|
+
begin; raise 'Test'; rescue Exception => e; @e = e; end
|
13
|
+
@instance = Lilypad::Hoptoad::Notify.new(nil, @e)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :initialize do
|
17
|
+
|
18
|
+
before(:each) do
|
19
|
+
Lilypad::Hoptoad::XML.stub!(:build).and_return('xml')
|
20
|
+
@instance.stub!(:headers).and_return 'headers'
|
21
|
+
@instance.stub!(:parse).and_return ['parse']
|
22
|
+
end
|
23
|
+
|
24
|
+
after(:each) do
|
25
|
+
@instance.send(:initialize, nil, @e)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should build XML from parse method" do
|
29
|
+
Lilypad::Hoptoad::XML.should_receive(:build).with('parse')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should post the XML" do
|
33
|
+
@http.should_receive(:post).with('uri', 'xml', 'headers')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should log the event" do
|
37
|
+
@instance.should_receive(:log).with(:notify, @http_ok)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should reset the request config" do
|
41
|
+
Lilypad::Config::Request.should_receive(:reset!)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return the success status" do
|
45
|
+
@instance.should_receive(:success?)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe :backtrace do
|
50
|
+
|
51
|
+
it "should return an array of backtrace information" do
|
52
|
+
backtrace = @instance.send(:backtrace)
|
53
|
+
backtrace.first.file.should =~ /notify_spec/
|
54
|
+
backtrace.first.respond_to?(:number).should == true
|
55
|
+
backtrace.first.respond_to?(:method).should == true
|
56
|
+
backtrace.length.should > 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe :filter do
|
61
|
+
|
62
|
+
after(:each) do
|
63
|
+
Lilypad { filters [] }
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should remove elements of a hash for keys that match an element Config.filters" do
|
67
|
+
Lilypad { filters [ 't1' ] }
|
68
|
+
filtered = @instance.send(:filter, { :t1 => 't1', :t2 => 't2' })
|
69
|
+
filtered.should == { :t1 => '[FILTERED]', :t2 => 't2' }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe :http_start do
|
74
|
+
|
75
|
+
after(:each) do
|
76
|
+
@instance.send(:http_start) {}
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should get a URI instance for the notify URL" do
|
80
|
+
URI.should_receive(:parse).with(Lilypad::Config.notify_url)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should call start on Net::HTTP" do
|
84
|
+
Net::HTTP.should_receive(:start)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should yield to the block" do
|
88
|
+
yielded = false
|
89
|
+
@instance.send(:http_start) { yielded = true }
|
90
|
+
yielded.should == true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe :parse do
|
95
|
+
|
96
|
+
before(:each) do
|
97
|
+
@env = mock(:env)
|
98
|
+
@env.stub!(:merge).and_return('env')
|
99
|
+
ENV.stub!(:to_hash).and_return(@env)
|
100
|
+
@instance.stub!(:filter).and_return('env')
|
101
|
+
@instance.stub!(:backtrace).and_return('backtrace')
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should filter the environment" do
|
105
|
+
@instance.should_receive(:filter).with('env')
|
106
|
+
ENV.should_receive(:to_hash)
|
107
|
+
@env.should_receive(:merge)
|
108
|
+
@instance.send(:parse)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return the correct parameters without an environment" do
|
112
|
+
@instance.send(:parse).should == [ "backtrace", "env", @e, {}, "Internal" ]
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should return the correct parameters with an environment" do
|
116
|
+
request = mock(:request)
|
117
|
+
request.stub!(:params)
|
118
|
+
request.stub!(:script_name).and_return 'request_'
|
119
|
+
request.stub!(:path_info).and_return 'path'
|
120
|
+
Rack::Request.stub!(:new).and_return(request)
|
121
|
+
@instance.send(:initialize, {}, @e)
|
122
|
+
@instance.send(:parse).should == ["backtrace", "env", @e, "env", "request_path"]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe :success? do
|
127
|
+
|
128
|
+
it "should make sure the response's superclass equals Net::HTTPSuccess" do
|
129
|
+
@http.stub!(:post).and_return(nil)
|
130
|
+
@instance.send(:initialize, nil, @e)
|
131
|
+
@instance.send(:success?).should == false
|
132
|
+
|
133
|
+
@http.stub!(:post).and_return(@http_ok)
|
134
|
+
@instance.send(:initialize, nil, @e)
|
135
|
+
@instance.send(:success?).should == true
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/spec_helper"
|
2
|
+
|
3
|
+
describe Rack::Lilypad do
|
4
|
+
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@app = lambda { |env| raise TestError, 'Test' }
|
9
|
+
@env = Rack::MockRequest.env_for("/test")
|
10
|
+
stub_net_http
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should yield a configuration object to the block when created" do
|
14
|
+
Rack::Lilypad.new(@app, '') do
|
15
|
+
filters %w(T1 T2)
|
16
|
+
log 'T3'
|
17
|
+
end
|
18
|
+
Lilypad::Config.filters.include?('T1').should == true
|
19
|
+
Lilypad::Config.filters.include?('T2').should == true
|
20
|
+
Lilypad::Config.log.should == 'T3'
|
21
|
+
|
22
|
+
Lilypad::Config.filters []
|
23
|
+
Lilypad::Config.log false
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should write to a log file on success and failure" do
|
27
|
+
log_path = "#{SPEC}/fixtures/hoptoad.log"
|
28
|
+
notifier = Rack::Lilypad.new(@app, '') do |app|
|
29
|
+
log log_path
|
30
|
+
end
|
31
|
+
|
32
|
+
notifier.call(@env) rescue nil
|
33
|
+
|
34
|
+
File.exists?(log_path).should == true
|
35
|
+
File.read(log_path).should =~ /Notify Success/
|
36
|
+
File.delete(log_path)
|
37
|
+
|
38
|
+
@http.stub!(:post).and_return false
|
39
|
+
notifier.call(@env) rescue nil
|
40
|
+
|
41
|
+
File.exists?(log_path).should == true
|
42
|
+
File.read(log_path).should =~ /Notify Failure/
|
43
|
+
File.delete(log_path)
|
44
|
+
|
45
|
+
Lilypad::Config.log false
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should transfer valid XML to Hoptoad" do
|
49
|
+
# Test complex environment variables
|
50
|
+
@env['rack.hash_test'] = { :test => true }
|
51
|
+
@env['rack.object_test'] = Object.new
|
52
|
+
|
53
|
+
notifier = Rack::Lilypad.new(@app, '')
|
54
|
+
notifier.call(@env) rescue nil
|
55
|
+
validate_xml
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should provide a notify method" do
|
59
|
+
@http.should_receive(:post)
|
60
|
+
begin
|
61
|
+
raise TestError, 'Test'
|
62
|
+
rescue Exception => e
|
63
|
+
Lilypad.notify(e)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should provide a deploy method" do
|
68
|
+
Net::HTTP.should_receive(:post_form)
|
69
|
+
Lilypad.deploy(
|
70
|
+
:username => 't1',
|
71
|
+
:environment => 't2',
|
72
|
+
:revision => 't3',
|
73
|
+
:repository => 't4'
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|