appsignal 0.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.
- data/.gitignore +19 -0
- data/.rvmrc +1 -0
- data/.travis.yml +30 -0
- data/Gemfile +3 -0
- data/LICENCE +20 -0
- data/README.md +48 -0
- data/Rakefile +52 -0
- data/appsignal.gemspec +33 -0
- data/bin/appsignal +13 -0
- data/config/appsignal.yml +8 -0
- data/gemfiles/3.0.gemfile +16 -0
- data/gemfiles/3.1.gemfile +16 -0
- data/gemfiles/3.2.gemfile +16 -0
- data/gemfiles/edge.gemfile +16 -0
- data/lib/appsignal.rb +45 -0
- data/lib/appsignal/agent.rb +104 -0
- data/lib/appsignal/auth_check.rb +19 -0
- data/lib/appsignal/capistrano.rb +41 -0
- data/lib/appsignal/cli.rb +118 -0
- data/lib/appsignal/config.rb +30 -0
- data/lib/appsignal/exception_notification.rb +25 -0
- data/lib/appsignal/marker.rb +35 -0
- data/lib/appsignal/middleware.rb +30 -0
- data/lib/appsignal/railtie.rb +19 -0
- data/lib/appsignal/transaction.rb +77 -0
- data/lib/appsignal/transaction/faulty_request_formatter.rb +30 -0
- data/lib/appsignal/transaction/params_sanitizer.rb +36 -0
- data/lib/appsignal/transaction/regular_request_formatter.rb +11 -0
- data/lib/appsignal/transaction/slow_request_formatter.rb +34 -0
- data/lib/appsignal/transaction/transaction_formatter.rb +93 -0
- data/lib/appsignal/transmitter.rb +53 -0
- data/lib/appsignal/version.rb +3 -0
- data/lib/generators/appsignal/USAGE +8 -0
- data/lib/generators/appsignal/appsignal_generator.rb +70 -0
- data/lib/generators/appsignal/templates/appsignal.yml +4 -0
- data/log/.gitkeep +0 -0
- data/resources/cacert.pem +3849 -0
- data/spec/appsignal/agent_spec.rb +259 -0
- data/spec/appsignal/auth_check_spec.rb +36 -0
- data/spec/appsignal/capistrano_spec.rb +81 -0
- data/spec/appsignal/cli_spec.rb +124 -0
- data/spec/appsignal/config_spec.rb +40 -0
- data/spec/appsignal/exception_notification_spec.rb +12 -0
- data/spec/appsignal/inactive_railtie_spec.rb +30 -0
- data/spec/appsignal/marker_spec.rb +83 -0
- data/spec/appsignal/middleware_spec.rb +73 -0
- data/spec/appsignal/railtie_spec.rb +54 -0
- data/spec/appsignal/transaction/faulty_request_formatter_spec.rb +49 -0
- data/spec/appsignal/transaction/params_sanitizer_spec.rb +68 -0
- data/spec/appsignal/transaction/regular_request_formatter_spec.rb +14 -0
- data/spec/appsignal/transaction/slow_request_formatter_spec.rb +76 -0
- data/spec/appsignal/transaction/transaction_formatter_spec.rb +178 -0
- data/spec/appsignal/transaction_spec.rb +191 -0
- data/spec/appsignal/transmitter_spec.rb +64 -0
- data/spec/appsignal_spec.rb +66 -0
- data/spec/generators/appsignal/appsignal_generator_spec.rb +222 -0
- data/spec/spec_helper.rb +85 -0
- data/spec/support/delegate_matcher.rb +39 -0
- metadata +247 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Appsignal::Config do
|
4
|
+
subject { Appsignal::Config.new(Dir.pwd, 'test').load }
|
5
|
+
|
6
|
+
it {
|
7
|
+
should == {
|
8
|
+
:ignore_exceptions => [],
|
9
|
+
:endpoint => 'http://localhost:3000/1',
|
10
|
+
:slow_request_threshold => 200,
|
11
|
+
:api_key => 'abc',
|
12
|
+
:active => true
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
context 'when there is no config file' do
|
17
|
+
before { Dir.stub(:pwd => '/not/existing') }
|
18
|
+
|
19
|
+
it "should log error" do
|
20
|
+
Appsignal.logger.should_receive(:error).with(
|
21
|
+
"config not found at:"\
|
22
|
+
" /not/existing/config/appsignal.yml"
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
after { subject }
|
27
|
+
end
|
28
|
+
|
29
|
+
context "the env is not in the config" do
|
30
|
+
subject { Appsignal::Config.new(Dir.pwd, 'staging').load }
|
31
|
+
|
32
|
+
it "should generate error" do
|
33
|
+
Appsignal.logger.should_receive(:error).with(
|
34
|
+
"config for 'staging' not found"
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
after { subject }
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Appsignal::ExceptionNotification do
|
4
|
+
let(:error) { StandardError.new('moo') }
|
5
|
+
let(:notification) { Appsignal::ExceptionNotification.new({}, error) }
|
6
|
+
subject { notification }
|
7
|
+
before { Rails.stub(:respond_to? => false) }
|
8
|
+
|
9
|
+
its(:exception) { should == error }
|
10
|
+
its(:name) { should == 'StandardError' }
|
11
|
+
its(:message) { should == 'moo' }
|
12
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Inactive Appsignal::Railtie" do
|
4
|
+
it "should not insert itself into the middleware stack" do
|
5
|
+
# This uses a hack because Rails really dislikes you trying to
|
6
|
+
# start multiple applications in one process. This works decently
|
7
|
+
# on every platform except JRuby, so we're disabling this test on
|
8
|
+
# JRuby for now.
|
9
|
+
if RUBY_PLATFORM == "java"
|
10
|
+
pending "This spec cannot run on JRuby currently"
|
11
|
+
else
|
12
|
+
pid = fork do
|
13
|
+
Appsignal.stub(:active? => false)
|
14
|
+
Rails.application = nil
|
15
|
+
instance_eval do
|
16
|
+
module MyTempApp
|
17
|
+
class Application < Rails::Application
|
18
|
+
config.active_support.deprecation = proc { |message, stack| }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
MyTempApp::Application.initialize!
|
23
|
+
|
24
|
+
MyTempApp::Application.middleware.to_a.should_not include Appsignal::Middleware
|
25
|
+
end
|
26
|
+
Process.wait(pid)
|
27
|
+
raise 'Example failed' unless $?.exitstatus == 0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Appsignal::Marker do
|
4
|
+
let(:marker) {
|
5
|
+
Appsignal::Marker.new({
|
6
|
+
:revision => '503ce0923ed177a3ce000005',
|
7
|
+
:repository => 'master',
|
8
|
+
:user => 'batman',
|
9
|
+
:rails_env => 'development'
|
10
|
+
},
|
11
|
+
Dir.pwd,
|
12
|
+
'development',
|
13
|
+
logger
|
14
|
+
)
|
15
|
+
}
|
16
|
+
let(:log) { StringIO.new }
|
17
|
+
let(:logger) { Logger.new(log) }
|
18
|
+
|
19
|
+
context "transmit" do
|
20
|
+
before do
|
21
|
+
@transmitter = mock()
|
22
|
+
Appsignal::Transmitter.should_receive(:new).
|
23
|
+
with('http://localhost:3000/1', 'markers', 'abc').
|
24
|
+
and_return(@transmitter)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should transmit data" do
|
28
|
+
@transmitter.should_receive(:transmit).
|
29
|
+
with(
|
30
|
+
{
|
31
|
+
:revision => "503ce0923ed177a3ce000005",
|
32
|
+
:repository => "master",
|
33
|
+
:user => "batman",
|
34
|
+
:rails_env => "development"
|
35
|
+
}
|
36
|
+
)
|
37
|
+
|
38
|
+
marker.transmit
|
39
|
+
end
|
40
|
+
|
41
|
+
context "logs" do
|
42
|
+
shared_examples_for "logging info and errors" do
|
43
|
+
it "should log status 200" do
|
44
|
+
@transmitter.should_receive(:transmit).and_return('200')
|
45
|
+
|
46
|
+
marker.transmit
|
47
|
+
|
48
|
+
log.string.should include('Notifying Appsignal of deploy...')
|
49
|
+
log.string.should include(
|
50
|
+
'Appsignal has been notified of this deploy!'
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should log other status" do
|
55
|
+
@transmitter.should_receive(:transmit).and_return('500')
|
56
|
+
@transmitter.should_receive(:uri).and_return('http://localhost:3000/1/markers')
|
57
|
+
|
58
|
+
marker.transmit
|
59
|
+
|
60
|
+
log.string.should include('Notifying Appsignal of deploy...')
|
61
|
+
log.string.should include(
|
62
|
+
'Something went wrong while trying to notify Appsignal: 500 at http://localhost:3000/1/markers'
|
63
|
+
)
|
64
|
+
log.string.should_not include(
|
65
|
+
'Appsignal has been notified of this deploy!'
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it_should_behave_like "logging info and errors"
|
71
|
+
|
72
|
+
context "with a Capistrano logger" do
|
73
|
+
let(:logger) {
|
74
|
+
Capistrano::Logger.new(:output => log).tap do |logger|
|
75
|
+
logger.level = Capistrano::Logger::MAX_LEVEL
|
76
|
+
end
|
77
|
+
}
|
78
|
+
|
79
|
+
it_should_behave_like "logging info and errors"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
IgnoreMeError = Class.new(StandardError)
|
5
|
+
end
|
6
|
+
|
7
|
+
class AppWithError
|
8
|
+
def self.call(env)
|
9
|
+
raise Appsignal::IgnoreMeError, 'the roof'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Appsignal::Middleware do
|
14
|
+
describe '#call' do
|
15
|
+
let(:app) { stub(:call => true) }
|
16
|
+
let(:env) { {'action_dispatch.request_id' => '1'} }
|
17
|
+
let(:middleware) { Appsignal::Middleware.new(app, {})}
|
18
|
+
let(:current) { stub(:complete! => true, :add_exception => true) }
|
19
|
+
before { Appsignal::Transaction.stub(:current => current) }
|
20
|
+
|
21
|
+
describe 'around call' do
|
22
|
+
it 'should call appsignal transaction' do
|
23
|
+
Appsignal::Transaction.should_receive(:create).with('1', env)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should call complete! after the call' do
|
27
|
+
current.should_receive(:complete!)
|
28
|
+
end
|
29
|
+
|
30
|
+
after { middleware.call(env) }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'with exception' do
|
34
|
+
let(:app) { AppWithError }
|
35
|
+
|
36
|
+
it 'should re-raise the exception' do
|
37
|
+
expect {
|
38
|
+
middleware.call(env)
|
39
|
+
}.to raise_error
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should catch the exception and notify the transaction of it' do
|
43
|
+
Appsignal::ExceptionNotification.should_receive(:new)
|
44
|
+
current.should_receive(:add_exception)
|
45
|
+
middleware.call(env) rescue nil
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when ignoring exception' do
|
49
|
+
before { Appsignal.stub(:config => {:ignore_exceptions => 'Appsignal::IgnoreMeError'})}
|
50
|
+
|
51
|
+
it 'should re-raise the exception' do
|
52
|
+
expect {
|
53
|
+
middleware.call(env)
|
54
|
+
}.to raise_error
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should ignore the error' do
|
58
|
+
Appsignal::ExceptionNotification.should_not_receive(:new)
|
59
|
+
current.should_not_receive(:add_exception)
|
60
|
+
middleware.call(env) rescue nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'after an error' do
|
65
|
+
it 'should call complete! after the call' do
|
66
|
+
current.should_receive(:complete!)
|
67
|
+
end
|
68
|
+
|
69
|
+
after { middleware.call(env) rescue nil }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'action_controller/railtie'
|
3
|
+
require 'appsignal/railtie'
|
4
|
+
|
5
|
+
describe Appsignal::Railtie do
|
6
|
+
|
7
|
+
before(:all) { MyApp::Application.initialize! }
|
8
|
+
|
9
|
+
it "should have set the appsignal subscriber" do
|
10
|
+
Appsignal.subscriber.
|
11
|
+
should be_a ActiveSupport::Notifications::Fanout::Subscriber
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have added the middleware for exceptions" do
|
15
|
+
MyApp::Application.middleware.to_a.should include Appsignal::Middleware
|
16
|
+
end
|
17
|
+
|
18
|
+
context "non action_controller event" do
|
19
|
+
it "should call add_event for non action_controller event" do
|
20
|
+
current = stub
|
21
|
+
current.should_receive(:add_event)
|
22
|
+
Appsignal::Transaction.should_receive(:current).twice.
|
23
|
+
and_return(current)
|
24
|
+
end
|
25
|
+
|
26
|
+
after { ActiveSupport::Notifications.instrument 'query.mongoid' }
|
27
|
+
end
|
28
|
+
|
29
|
+
context "action_controller event" do
|
30
|
+
it "should call set_process_action_event for action_controller event" do
|
31
|
+
current = stub
|
32
|
+
current.should_receive(:set_process_action_event)
|
33
|
+
current.should_receive(:add_event)
|
34
|
+
Appsignal::Transaction.should_receive(:current).exactly(3).times.
|
35
|
+
and_return(current)
|
36
|
+
end
|
37
|
+
|
38
|
+
after do
|
39
|
+
ActiveSupport::Notifications.
|
40
|
+
instrument 'process_action.action_controller'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "event that starts with a bang" do
|
45
|
+
it "should not be processed" do
|
46
|
+
Appsignal::Transaction.should_not_receive(:current)
|
47
|
+
end
|
48
|
+
|
49
|
+
after do
|
50
|
+
ActiveSupport::Notifications.
|
51
|
+
instrument '!render_template'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Appsignal::TransactionFormatter::FaultyRequestFormatter do
|
4
|
+
let(:parent) { Appsignal::TransactionFormatter }
|
5
|
+
let(:transaction) { transaction_with_exception }
|
6
|
+
let(:faulty) { parent::FaultyRequestFormatter.new(transaction) }
|
7
|
+
subject { faulty }
|
8
|
+
|
9
|
+
describe "#to_hash" do
|
10
|
+
it "can call #to_hash on its superclass" do
|
11
|
+
parent.new(transaction).respond_to?(:to_hash).should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
context "return value" do
|
15
|
+
subject { faulty.to_hash }
|
16
|
+
before { faulty.stub(:formatted_exception => :faulty_request) }
|
17
|
+
|
18
|
+
it "includes the exception" do
|
19
|
+
subject[:exception].should == :faulty_request
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# protected
|
25
|
+
|
26
|
+
it { should delegate(:backtrace).to(:exception) }
|
27
|
+
it { should delegate(:name).to(:exception) }
|
28
|
+
it { should delegate(:message).to(:exception) }
|
29
|
+
|
30
|
+
describe "#formatted_exception" do
|
31
|
+
subject { faulty.send(:formatted_exception) }
|
32
|
+
|
33
|
+
its(:keys) { should include :backtrace }
|
34
|
+
its(:keys) { should include :exception }
|
35
|
+
its(:keys) { should include :message }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#basic_process_action_event" do
|
39
|
+
subject { faulty.send(:basic_process_action_event) }
|
40
|
+
|
41
|
+
it "should return a hash with extra keys" do
|
42
|
+
subject[:environment].should == {
|
43
|
+
"HTTP_USER_AGENT" => "IE6",
|
44
|
+
"SERVER_NAME" => "localhost"
|
45
|
+
}
|
46
|
+
subject[:session_data].should == {}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Appsignal::ParamsSanitizer do
|
4
|
+
describe ".sanitize" do
|
5
|
+
let(:file) { ActionDispatch::Http::UploadedFile.new(:tempfile => '/tmp') }
|
6
|
+
let(:params) do
|
7
|
+
{
|
8
|
+
:text => 'string',
|
9
|
+
:file => file,
|
10
|
+
:hash => {
|
11
|
+
:nested_text => 'string',
|
12
|
+
:nested_array => [
|
13
|
+
'something',
|
14
|
+
'else',
|
15
|
+
file,
|
16
|
+
{
|
17
|
+
:key => 'value',
|
18
|
+
:nested_array_hash_file => file,
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
let(:sanitized_params) { Appsignal::ParamsSanitizer.sanitize(params) }
|
25
|
+
|
26
|
+
subject { sanitized_params }
|
27
|
+
|
28
|
+
it { should be_instance_of Hash }
|
29
|
+
it('should have a text') { subject[:text].should == 'string' }
|
30
|
+
it('should have a file') do
|
31
|
+
subject[:file].should be_instance_of String
|
32
|
+
subject[:file].should include '#<ActionDispatch::Http::UploadedFile:'
|
33
|
+
end
|
34
|
+
|
35
|
+
context "hash" do
|
36
|
+
subject { sanitized_params[:hash] }
|
37
|
+
|
38
|
+
it { should be_instance_of Hash }
|
39
|
+
it('should have a nested text') { subject[:nested_text].should == 'string' }
|
40
|
+
|
41
|
+
context "nested_array" do
|
42
|
+
subject { sanitized_params[:hash][:nested_array] }
|
43
|
+
|
44
|
+
it { should be_instance_of Array }
|
45
|
+
|
46
|
+
it("should have two string items") do
|
47
|
+
subject.first.should == 'something'
|
48
|
+
subject.second.should == 'else'
|
49
|
+
end
|
50
|
+
it "should have a file" do
|
51
|
+
subject.third.should be_instance_of String
|
52
|
+
subject.third.should include '#<ActionDispatch::Http::UploadedFile:'
|
53
|
+
end
|
54
|
+
|
55
|
+
context "nested hash" do
|
56
|
+
subject { sanitized_params[:hash][:nested_array].fourth }
|
57
|
+
|
58
|
+
it { should be_instance_of Hash }
|
59
|
+
it('should have a text') { subject[:key].should == 'value' }
|
60
|
+
it('should have a file') do
|
61
|
+
subject[:nested_array_hash_file].should be_instance_of String
|
62
|
+
subject[:nested_array_hash_file].should include '#<ActionDispatch::Http::UploadedFile:'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Appsignal::TransactionFormatter::RegularRequestFormatter do
|
4
|
+
let(:parent) { Appsignal::TransactionFormatter }
|
5
|
+
let(:transaction) { appsignal_transaction }
|
6
|
+
let(:klass) { parent::RegularRequestFormatter }
|
7
|
+
let(:regular) { klass.new(transaction) }
|
8
|
+
|
9
|
+
describe "#sanitized_event_payload" do
|
10
|
+
subject { regular.sanitized_event_payload(:whatever, :arguments) }
|
11
|
+
|
12
|
+
it { should == {} }
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe Appsignal::TransactionFormatter::SlowRequestFormatter do
|
5
|
+
let(:parent) { Appsignal::TransactionFormatter }
|
6
|
+
let(:transaction) { slow_transaction }
|
7
|
+
let(:klass) { parent::SlowRequestFormatter }
|
8
|
+
let(:slow) { klass.new(transaction) }
|
9
|
+
|
10
|
+
describe "#to_hash" do
|
11
|
+
subject { slow.to_hash }
|
12
|
+
before { slow.stub(:detailed_events => :startled) }
|
13
|
+
|
14
|
+
it "includes events" do
|
15
|
+
subject[:events].should == :startled
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# protected
|
20
|
+
|
21
|
+
context "with an event" do
|
22
|
+
let(:start_time) { Time.at(2.71828182) }
|
23
|
+
let(:end_time) { Time.at(3.141592654) }
|
24
|
+
let(:event) do
|
25
|
+
mock(
|
26
|
+
:event,
|
27
|
+
:name => 'Startled',
|
28
|
+
:duration => 2,
|
29
|
+
:time => start_time,
|
30
|
+
:end => end_time,
|
31
|
+
:payload => {
|
32
|
+
:controller => 'controller',
|
33
|
+
:action => 'action',
|
34
|
+
:sensitive => 'data'
|
35
|
+
}
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#detailed_events" do
|
40
|
+
subject { slow.send(:detailed_events) }
|
41
|
+
before do
|
42
|
+
slow.stub(
|
43
|
+
:events => [event],
|
44
|
+
:format => :foo
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
it { should == [:foo] }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#format" do
|
52
|
+
subject { slow.send(:format, event) }
|
53
|
+
before { slow.stub(:sanitized_event_payload => :sanitized) }
|
54
|
+
|
55
|
+
it { should == {
|
56
|
+
:name => 'Startled',
|
57
|
+
:duration => 2,
|
58
|
+
:time => start_time.to_f,
|
59
|
+
:end => end_time.to_f,
|
60
|
+
:payload => :sanitized
|
61
|
+
} }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#basic_process_action_event" do
|
66
|
+
subject { slow.send(:basic_process_action_event) }
|
67
|
+
|
68
|
+
it "should return a hash with extra keys" do
|
69
|
+
subject[:environment].should == {
|
70
|
+
"HTTP_USER_AGENT" => "IE6",
|
71
|
+
"SERVER_NAME" => "localhost"
|
72
|
+
}
|
73
|
+
subject[:session_data].should == {}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|