flexmls_api 0.3.6 → 0.4.5

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.
Files changed (63) hide show
  1. data/Gemfile +6 -6
  2. data/Gemfile.lock +6 -6
  3. data/README.md +5 -3
  4. data/Rakefile +2 -1
  5. data/VERSION +1 -1
  6. data/lib/flexmls_api/authentication.rb +25 -54
  7. data/lib/flexmls_api/authentication/api_auth.rb +100 -0
  8. data/lib/flexmls_api/authentication/base_auth.rb +47 -0
  9. data/lib/flexmls_api/authentication/oauth2.rb +219 -0
  10. data/lib/flexmls_api/client.rb +7 -1
  11. data/lib/flexmls_api/configuration.rb +5 -2
  12. data/lib/flexmls_api/faraday.rb +6 -2
  13. data/lib/flexmls_api/models.rb +2 -0
  14. data/lib/flexmls_api/models/base.rb +5 -1
  15. data/lib/flexmls_api/models/contact.rb +1 -0
  16. data/lib/flexmls_api/models/custom_fields.rb +2 -2
  17. data/lib/flexmls_api/models/finders.rb +2 -2
  18. data/lib/flexmls_api/models/idx_link.rb +1 -1
  19. data/lib/flexmls_api/models/listing.rb +31 -5
  20. data/lib/flexmls_api/models/market_statistics.rb +1 -1
  21. data/lib/flexmls_api/models/note.rb +43 -0
  22. data/lib/flexmls_api/models/standard_fields.rb +43 -0
  23. data/lib/flexmls_api/models/subresource.rb +5 -2
  24. data/lib/flexmls_api/models/system_info.rb +7 -0
  25. data/lib/flexmls_api/models/tour_of_home.rb +24 -0
  26. data/lib/flexmls_api/request.rb +13 -28
  27. data/spec/fixtures/add_note.json +11 -0
  28. data/spec/fixtures/agent_shared_note.json +11 -0
  29. data/spec/fixtures/agent_shared_note_empty.json +7 -0
  30. data/spec/fixtures/authentication_failure.json +7 -0
  31. data/spec/fixtures/count.json +10 -0
  32. data/spec/fixtures/errors/expired.json +7 -0
  33. data/spec/fixtures/generic_delete.json +1 -0
  34. data/spec/fixtures/generic_failure.json +5 -0
  35. data/spec/fixtures/oauth2_access.json +3 -0
  36. data/spec/fixtures/oauth2_error.json +3 -0
  37. data/spec/fixtures/session.json +1 -1
  38. data/spec/fixtures/standardfields.json +188 -0
  39. data/spec/fixtures/standardfields_city.json +1031 -0
  40. data/spec/fixtures/standardfields_nearby.json +53 -0
  41. data/spec/fixtures/standardfields_stateorprovince.json +36 -0
  42. data/spec/fixtures/tour_of_homes.json +23 -0
  43. data/spec/spec_helper.rb +22 -5
  44. data/spec/unit/flexmls_api/authentication/api_auth_spec.rb +159 -0
  45. data/spec/unit/flexmls_api/authentication/oauth2_spec.rb +183 -0
  46. data/spec/unit/flexmls_api/authentication_spec.rb +10 -2
  47. data/spec/unit/flexmls_api/configuration_spec.rb +2 -2
  48. data/spec/unit/flexmls_api/faraday_spec.rb +3 -7
  49. data/spec/unit/flexmls_api/models/base_spec.rb +1 -1
  50. data/spec/unit/flexmls_api/models/contact_spec.rb +8 -4
  51. data/spec/unit/flexmls_api/models/document_spec.rb +2 -5
  52. data/spec/unit/flexmls_api/models/listing_spec.rb +46 -9
  53. data/spec/unit/flexmls_api/models/note_spec.rb +90 -0
  54. data/spec/unit/flexmls_api/models/photo_spec.rb +2 -2
  55. data/spec/unit/flexmls_api/models/system_info_spec.rb +37 -3
  56. data/spec/unit/flexmls_api/models/tour_of_home_spec.rb +43 -0
  57. data/spec/unit/flexmls_api/models/video_spec.rb +2 -4
  58. data/spec/unit/flexmls_api/models/virtual_tour_spec.rb +2 -2
  59. data/spec/unit/flexmls_api/paginate_spec.rb +11 -8
  60. data/spec/unit/flexmls_api/request_spec.rb +31 -16
  61. data/spec/unit/flexmls_api/standard_fields_spec.rb +86 -0
  62. data/spec/unit/flexmls_api_spec.rb +6 -27
  63. metadata +119 -76
@@ -0,0 +1,53 @@
1
+ {
2
+ "D": {
3
+ "Success": true,
4
+ "Results": [{
5
+ "City": {
6
+ "ResourceUri": "/v1/standardfields/nearby/A/City",
7
+ "HasList": true,
8
+ "FieldList": [{
9
+ "Name": "Fargo",
10
+ "Value": "'Fargo'"
11
+ },
12
+ {
13
+ "Name": "Moorhead",
14
+ "Value": "'Moorhead'"
15
+ }],
16
+ "Searchable": true,
17
+ "Type": "Character"
18
+ },
19
+ "PostalCode": {
20
+ "ResourceUri": "/v1/standardfields/nearby/A/PostalCode",
21
+ "HasList": true,
22
+ "FieldList": [{
23
+ "Name": "56560",
24
+ "Value": "'56560'"
25
+ },
26
+ {
27
+ "Name": "58102",
28
+ "Value": "'58102'"
29
+ },
30
+ {
31
+ "Name": "58103",
32
+ "Value": "'58103'"
33
+ }],
34
+ "Searchable": true,
35
+ "Type": "Character"
36
+ },
37
+ "StateOrProvince": {
38
+ "ResourceUri": "/v1/standardfields/nearby/A/StateOrProvince",
39
+ "HasList": true,
40
+ "FieldList": [{
41
+ "Name": "MN",
42
+ "Value": "'MN'"
43
+ },
44
+ {
45
+ "Name": "ND",
46
+ "Value": "'ND'"
47
+ }],
48
+ "Searchable": true,
49
+ "Type": "Character"
50
+ }
51
+ }]
52
+ }
53
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "D": {
3
+ "Success": true,
4
+ "Results": [{
5
+ "StateOrProvince": {
6
+ "ResourceUri": "/v1/standardfields/StateOrProvince",
7
+ "FieldList": [{
8
+ "Name": "IA",
9
+ "Applies To": ["A", "B", "G", "I", "J", "K", "M"],
10
+ "Value": "IA"
11
+ },
12
+ {
13
+ "Name": "MN",
14
+ "Value": "MN"
15
+ },
16
+ {
17
+ "Name": "ND",
18
+ "Value": "ND"
19
+ },
20
+ {
21
+ "Name": "SD",
22
+ "Applies To": ["A", "B", "G", "I", "J", "K", "M"],
23
+ "Value": "SD"
24
+ },
25
+ {
26
+ "Name": "WI",
27
+ "Applies To": ["A", "B", "G", "I", "J", "K", "M"],
28
+ "Value": "WI"
29
+ }],
30
+ "HasList": true,
31
+ "Searchable": true,
32
+ "Type": "Character"
33
+ }
34
+ }]
35
+ }
36
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "D": {
3
+ "Results": [
4
+ {"ResourceUri":"/listings/20060725224713296297000000/tourofhomes/20101127153422574618000000",
5
+ "Id": "20101127153422574618000000",
6
+ "Date": "10/01/2010",
7
+ "StartTime": "09:00 AM",
8
+ "EndTime": "12:00 PM",
9
+ "Comments": "Wonderful home; must see!",
10
+ "AdditionalInfo": [{"Hosted By": "Joe Smith"}, {"Host Phone": "123-456-7890"}, {"Tour Area": "North-Central"}]
11
+ },
12
+ {"ResourceUri":"/listings/20060725224713296297000000/tourofhomes/20101127153422174618000000",
13
+ "Id": "20101127153422174618000000",
14
+ "Date": "10/08/2010",
15
+ "StartTime": "09:00 AM",
16
+ "EndTime": "12:00 PM",
17
+ "Comments": "Wonderful home; must see!",
18
+ "AdditionalInfo": [{"Hosted By": "Joe Smith"}, {"Host Phone": "123-456-7890"}, {"Tour Area": "North-Central"}]
19
+ }
20
+ ],
21
+ "Success": true
22
+ }
23
+ }
data/spec/spec_helper.rb CHANGED
@@ -36,9 +36,23 @@ def mock_session()
36
36
  FlexmlsApi::Authentication::Session.new("AuthToken" => "1234", "Expires" => (Time.now + 3600).to_s, "Roles" => "['idx']")
37
37
  end
38
38
 
39
+ def mock_oauth_session()
40
+ FlexmlsApi::Authentication::OAuthSession.new("access_token" => "1234", "expires_in" => 3600, "scope" => nil, "refresh_token"=> "1000refresh")
41
+ end
39
42
 
40
43
  class MockClient < FlexmlsApi::Client
41
- attr_accessor :connection, :session
44
+ attr_accessor :connection
45
+
46
+ def connection(ssl = false)
47
+ @connection
48
+ end
49
+ end
50
+
51
+ class MockApiAuthenticator < FlexmlsApi::Authentication::ApiAuth
52
+ # Sign a request
53
+ def sign(sig)
54
+ "SignedToken"
55
+ end
42
56
  end
43
57
 
44
58
  def mock_client(stubs)
@@ -60,19 +74,22 @@ def test_connection(stubs)
60
74
  end
61
75
  end
62
76
 
63
-
64
77
  def stub_auth_request()
65
78
  stub_request(:post, "https://api.flexmls.com/#{FlexmlsApi.version}/session").
66
79
  with(:query => {:ApiKey => "", :ApiSig => "806737984ab19be2fd08ba36030549ac"}).
67
80
  to_return(:body => fixture("session.json"))
68
81
  end
69
82
 
70
-
71
-
72
-
73
83
  def fixture(file)
74
84
  File.new(File.expand_path("../fixtures", __FILE__) + '/' + file)
75
85
  end
76
86
 
87
+ def reset_config()
88
+ FlexmlsApi.reset
89
+ FlexmlsApi.configure do |config|
90
+ config.api_user = "foobar"
91
+ end
92
+ end
93
+ reset_config
77
94
 
78
95
  include FlexmlsApi::Models
@@ -0,0 +1,159 @@
1
+ require './spec/spec_helper'
2
+
3
+ describe FlexmlsApi::Authentication::ApiAuth do
4
+ subject {FlexmlsApi::Authentication::ApiAuth.new(nil) }
5
+ describe "build_param_hash" do
6
+ it "should return a blank string when passed nil" do
7
+ subject.build_param_string(nil).should be_empty
8
+ end
9
+ it "should return a correct param string for one item" do
10
+ subject.build_param_string({:foo => "bar"}).should match("foobar")
11
+ end
12
+ it "should alphabatize the param names by key first, then by value" do
13
+ subject.build_param_string({:zoo => "zar", :ooo => "car"}).should match("ooocarzoozar")
14
+ subject.build_param_string({:Akey => "aValue", :aNotherkey => "AnotherValue"}).should
15
+ match "AkeyaValueaNotherkeyAnotherValue"
16
+ end
17
+ end
18
+
19
+ describe "authenticate" do
20
+ let(:client) { FlexmlsApi::Client.new({:api_key => "my_key", :api_secret => "my_secret"}) }
21
+ subject do
22
+ s = FlexmlsApi::Authentication::ApiAuth.new(client)
23
+ client.authenticator = s
24
+ s
25
+ end
26
+ it "should authenticate the api credentials" do
27
+ stub_request(:post, "https://api.flexmls.com/#{FlexmlsApi.version}/session").
28
+ with(:query => {:ApiKey => "my_key", :ApiSig => "c731cf2455fbc7a4ef937b2301108d7a"}).
29
+ to_return(:body => fixture("session.json"))
30
+ subject.authenticate()
31
+ end
32
+ it "should raise an error when api credentials are invalid" do
33
+ stub_request(:post, "https://api.flexmls.com/#{FlexmlsApi.version}/session").
34
+ with(:query => {:ApiKey => "my_key", :ApiSig => "c731cf2455fbc7a4ef937b2301108d7a"}).
35
+ to_return(:body => fixture("authentication_failure.json"), :status=>401)
36
+ expect {subject.authenticate()}.to raise_error(FlexmlsApi::ClientError){ |e| e.status.should == 401 }
37
+ end
38
+ end
39
+
40
+ describe "authenticated?" do
41
+ let(:session) { Object.new }
42
+ it "should return true when session is active" do
43
+ subject.session = session
44
+ session.stub(:expired?) { false }
45
+ subject.authenticated?.should eq(true)
46
+ end
47
+ it "should return false when session is expired" do
48
+ subject.session = session
49
+ session.stub(:expired?) { true }
50
+ subject.authenticated?.should eq(false)
51
+ end
52
+ it "should return false when session is uninitialized" do
53
+ subject.authenticated?.should eq(false)
54
+ end
55
+ end
56
+
57
+ describe "logout" do
58
+ let(:session) { mock_session }
59
+ let(:client) { Object.new }
60
+ subject {FlexmlsApi::Authentication::ApiAuth.new(client) }
61
+ it "should logout when there is an active session" do
62
+ logged_out = false
63
+ subject.session = session
64
+ client.stub(:delete).with("/session/1234") { logged_out = true }
65
+ subject.logout
66
+ subject.session.should eq(nil)
67
+ logged_out.should eq(true)
68
+ end
69
+ it "should skip logging out when there is no active session information" do
70
+ client.stub(:delete) { raise "Should not be called" }
71
+ subject.logout.should eq(nil)
72
+ end
73
+ end
74
+
75
+ # Since the request method is overly complex, the following tests just go through the whole stack
76
+ # with some semi realistic requests. Performing this type of test here should allow us to safely
77
+ # mock out authentication for the rest of our unit tests and still have some decent coverage.
78
+ describe "request" do
79
+ let(:client) { FlexmlsApi::Client.new({:api_key => "my_key", :api_secret => "my_secret"}) }
80
+ let(:session) { mock_session }
81
+ subject do
82
+ s = FlexmlsApi::Authentication::ApiAuth.new(client)
83
+ client.authenticator = s
84
+ s.session = session
85
+ s
86
+ end
87
+ it "should handle a get request" do
88
+ stub_auth_request
89
+ args = {
90
+ :ApiUser => "foobar",
91
+ :_limit => '10',
92
+ :_page => '1',
93
+ :_pagination => '1'
94
+ }
95
+ stub_request(:get, "#{FlexmlsApi.endpoint}/#{FlexmlsApi.version}/listings").
96
+ with(:query => {
97
+ :ApiSig => "1cb789831f8f4c6925dc708c93762a2c",
98
+ :AuthToken => "1234"}.merge(args)).
99
+ to_return(:body => fixture("listing_no_subresources.json"))
100
+ subject.session = session
101
+ subject.request(:get, "/#{FlexmlsApi.version}/listings", nil, args).status.should eq(200)
102
+ end
103
+ it "should handle a post request" do
104
+ stub_auth_request
105
+ args = {:ApiUser => "foobar"}
106
+ contact = '{"D":{"Contacts":[{"DisplayName":"Contact Four","PrimaryEmail":"contact4@fbsdata.com"}]}}'
107
+ stub_request(:post, "#{FlexmlsApi.endpoint}/#{FlexmlsApi.version}/contacts").
108
+ with(:query => {
109
+ :ApiSig => "82898ef88d22e1b31bd2e2ea6bb8efe7",
110
+ :AuthToken => "1234"}.merge(args),
111
+ :body => contact
112
+ ).
113
+ to_return(:body => '{"D": {
114
+ "Success": true,
115
+ "Results": [
116
+ {
117
+ "ResourceUri":"/v1/contacts/20101230223226074204000000"
118
+ }]}
119
+ }',
120
+ :status=>201)
121
+ subject.request(:post, "/#{FlexmlsApi.version}/contacts", contact, args).status.should eq(201)
122
+ end
123
+ end
124
+
125
+ describe "sign" do
126
+ it "should sign the auth parameters correctly" do
127
+ sign_token = "my_secretApiKeymy_key"
128
+ subject.sign(sign_token).should eq("c731cf2455fbc7a4ef937b2301108d7a")
129
+ end
130
+ end
131
+
132
+ context "when the server says the session is expired (even if we disagree)" do
133
+ it "should reset the session and reauthenticate" do
134
+ count = 0
135
+ # Make sure the auth request goes out twice.
136
+ stub_request(:post, "https://api.flexmls.com/#{FlexmlsApi.version}/session").
137
+ with(:query => {:ApiKey => "", :ApiSig => "806737984ab19be2fd08ba36030549ac"}).
138
+ to_return do |r|
139
+ count += 1
140
+ {:body => fixture("session.json")}
141
+ end
142
+ # Fail the first time, but then return the correct value after reauthentication
143
+ stub_request(:get, "#{FlexmlsApi.endpoint}/#{FlexmlsApi.version}/listings/1234").
144
+ with(:query => {
145
+ :ApiSig => "554b6e2a3efec8719b782647c19d238d",
146
+ :AuthToken => "c401736bf3d3f754f07c04e460e09573",
147
+ :ApiUser => "foobar",
148
+ :_expand => "Documents"
149
+ }).
150
+ to_return(:body => fixture('errors/expired.json'), :status => 401).times(1).then.
151
+ to_return(:body => fixture('listing_with_documents.json'))
152
+ l = Listing.find('1234', :_expand => "Documents")
153
+
154
+ count.should eq(2)
155
+ FlexmlsApi.client.session.expired?.should eq(false)
156
+ end
157
+ end
158
+
159
+ end
@@ -0,0 +1,183 @@
1
+ require './spec/spec_helper'
2
+
3
+ # Lightweight example of an oauth2 provider used by the ruby client.
4
+ class TestOAuth2Provider < FlexmlsApi::Authentication::BaseOAuth2Provider
5
+
6
+ def initialize
7
+ @authorization_uri = "https://test.fbsdata.com/r/oauth2"
8
+ @access_uri = "https://api.test.fbsdata.com/v1/oauth2/grant"
9
+ @redirect_uri = "https://exampleapp.fbsdata.com/oauth-callback"
10
+ @client_id="example-id"
11
+ @client_secret="example-password"
12
+ @session_cache = {}
13
+ end
14
+
15
+ def redirect(url)
16
+ # User redirected to url, signs in, and gets code sent to callback
17
+ self.code="my_code"
18
+ end
19
+
20
+ def load_session()
21
+ @session_cache["test_user_session"]
22
+ end
23
+
24
+ def save_session(session)
25
+ @session_cache["test_user_session"] = session
26
+ nil
27
+ end
28
+
29
+ def session_timeout; 7200; end
30
+
31
+ end
32
+
33
+ describe FlexmlsApi::Authentication::OAuth2 do
34
+ let(:provider) { TestOAuth2Provider.new() }
35
+ let(:client) { FlexmlsApi::Client.new({:authentication_mode => FlexmlsApi::Authentication::OAuth2,:oauth2_provider => provider}) }
36
+ subject {client.authenticator }
37
+ # Make sure the client boostraps the right plugin based on configuration.
38
+ describe "plugin" do
39
+ it "should load the oauth2 authenticator" do
40
+ client.authenticator.class.should eq(FlexmlsApi::Authentication::OAuth2)
41
+ end
42
+ end
43
+ describe "authenticate" do
44
+ it "should authenticate the api credentials" do
45
+ stub_request(:post, provider.access_uri).
46
+ with(:query => {
47
+ :client_id => provider.client_id,
48
+ :client_secret => provider.client_secret,
49
+ :grant_type => "authorization_code",
50
+ :redirect_uri => provider.redirect_uri,
51
+ :code => "my_code"
52
+ }
53
+ ).
54
+ to_return(:body => fixture("oauth2_access.json"), :status=>200)
55
+ subject.authenticate.access_token.should eq("04u7h-4cc355-70k3n")
56
+ subject.authenticate.expires_in.should eq(7200)
57
+ end
58
+
59
+ it "should raise an error when api credentials are invalid" do
60
+ stub_request(:post, provider.access_uri).
61
+ with(:query => {
62
+ :client_id => provider.client_id,
63
+ :client_secret => provider.client_secret,
64
+ :grant_type => "authorization_code",
65
+ :redirect_uri => provider.redirect_uri,
66
+ :code => "my_code"
67
+ }
68
+ ).
69
+ to_return(:body => fixture("oauth2_error.json"), :status=>400)
70
+ expect {subject.authenticate()}.to raise_error(FlexmlsApi::ClientError){ |e| e.status.should == 400 }
71
+ end
72
+
73
+ end
74
+
75
+ describe "authenticated?" do
76
+ let(:session) { Object.new }
77
+ it "should return true when session is active" do
78
+ subject.session = session
79
+ session.stub(:expired?) { false }
80
+ subject.authenticated?.should eq(true)
81
+ end
82
+ it "should return false when session is expired" do
83
+ subject.session = session
84
+ session.stub(:expired?) { true }
85
+ subject.authenticated?.should eq(false)
86
+ end
87
+ it "should return false when session is uninitialized" do
88
+ subject.authenticated?.should eq(false)
89
+ end
90
+ end
91
+
92
+ describe "logout" do
93
+ let(:session) { mock_oauth_session }
94
+ it "should logout when there is an active session" do
95
+ subject.session = session
96
+ subject.logout
97
+ subject.session.should eq(nil)
98
+ end
99
+ it "should skip logging out when there is no active session information" do
100
+ client.stub(:delete) { raise "Should not be called" }
101
+ subject.logout.should eq(nil)
102
+ end
103
+ end
104
+
105
+ describe "request" do
106
+ let(:session) { mock_oauth_session }
107
+ it "should handle a get request" do
108
+ subject.session = session
109
+ args = {
110
+ :_limit => '10',
111
+ :_page => '1',
112
+ :_pagination => '1'
113
+ }
114
+ c = stub_request(:get, "https://api.flexmls.com/#{FlexmlsApi.version}/listings").
115
+ with(:query => {:access_token => "1234"}.merge(args)).
116
+ to_return(:body => fixture("listing_no_subresources.json"))
117
+ subject.session = session
118
+ subject.request(:get, "/#{FlexmlsApi.version}/listings", nil, args).status.should eq(200)
119
+ end
120
+ it "should handle a post request" do
121
+ subject.session = session
122
+ args = {}
123
+ contact = '{"D":{"Contacts":[{"DisplayName":"Contact Four","PrimaryEmail":"contact4@fbsdata.com"}]}}'
124
+ stub_request(:post, "https://api.flexmls.com/#{FlexmlsApi.version}/contacts").
125
+ with(:query => {:access_token => "1234"}.merge(args),
126
+ :body => contact
127
+ ).
128
+ to_return(:body => '{"D": {
129
+ "Success": true,
130
+ "Results": [
131
+ {
132
+ "ResourceUri":"/v1/contacts/20101230223226074204000000"
133
+ }]}
134
+ }',
135
+ :status=>201)
136
+ subject.request(:post, "/#{FlexmlsApi.version}/contacts", contact, args).status.should eq(201)
137
+ end
138
+ end
139
+
140
+ context "when the server says the session is expired (even if we disagree)" do
141
+ it "should reset the session and reauthenticate" do
142
+ count = 0
143
+ stub_request(:post, provider.access_uri).
144
+ with(:query => {
145
+ :client_id => provider.client_id,
146
+ :client_secret => provider.client_secret,
147
+ :grant_type => "authorization_code",
148
+ :redirect_uri => provider.redirect_uri,
149
+ :code => "my_code"
150
+ }
151
+ ).
152
+ to_return do
153
+ count += 1
154
+ {:body => fixture("oauth2_access.json"), :status=>200}
155
+ end
156
+ # Make sure the auth request goes out twice.
157
+ # Fail the first time, but then return the correct value after reauthentication
158
+ stub_request(:get, "https://api.flexmls.com/#{FlexmlsApi.version}/listings/1234").
159
+ with(:query => {:access_token => "04u7h-4cc355-70k3n"}).
160
+ to_return(:body => fixture('errors/expired.json'), :status => 401).times(1).then.
161
+ to_return(:body => fixture('listing_with_documents.json'))
162
+
163
+ client.get("/listings/1234")
164
+ count.should eq(2)
165
+ client.session.expired?.should eq(false)
166
+ end
167
+ end
168
+
169
+ end
170
+
171
+ describe FlexmlsApi::Authentication::BaseOAuth2Provider do
172
+ context "session_timeout" do
173
+ it "should provide a default" do
174
+ subject.session_timeout.should eq(3600)
175
+ end
176
+ describe TestOAuth2Provider do
177
+ subject { TestOAuth2Provider.new }
178
+ it "should be able to override the session timeout" do
179
+ subject.session_timeout.should eq(7200)
180
+ end
181
+ end
182
+ end
183
+ end