lilypad 0.2.4 → 0.3.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/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
|