appsignal 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|