spark_api 1.0.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/History.txt +139 -0
- data/LICENSE +14 -0
- data/README.md +153 -0
- data/Rakefile +18 -0
- data/VERSION +1 -0
- data/bin/spark_api +8 -0
- data/bin/spark_api~ +8 -0
- data/lib/spark_api.rb +46 -0
- data/lib/spark_api/authentication.rb +55 -0
- data/lib/spark_api/authentication/api_auth.rb +104 -0
- data/lib/spark_api/authentication/api_auth.rb~ +104 -0
- data/lib/spark_api/authentication/base_auth.rb +47 -0
- data/lib/spark_api/authentication/base_auth.rb~ +47 -0
- data/lib/spark_api/authentication/oauth2.rb +198 -0
- data/lib/spark_api/authentication/oauth2.rb~ +199 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb +87 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb~ +87 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_code.rb +48 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_code.rb~ +49 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_password.rb +44 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_password.rb~ +45 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb +35 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb~ +36 -0
- data/lib/spark_api/authentication/oauth2_impl/middleware.rb +38 -0
- data/lib/spark_api/authentication/oauth2_impl/middleware.rb~ +39 -0
- data/lib/spark_api/authentication/oauth2_impl/password_provider.rb +24 -0
- data/lib/spark_api/authentication/oauth2_impl/password_provider.rb~ +25 -0
- data/lib/spark_api/cli.rb +158 -0
- data/lib/spark_api/cli.rb~ +158 -0
- data/lib/spark_api/cli/api_auth.rb +8 -0
- data/lib/spark_api/cli/api_auth.rb~ +8 -0
- data/lib/spark_api/cli/oauth2.rb +14 -0
- data/lib/spark_api/cli/oauth2.rb~ +14 -0
- data/lib/spark_api/cli/setup.rb +47 -0
- data/lib/spark_api/cli/setup.rb~ +47 -0
- data/lib/spark_api/client.rb +27 -0
- data/lib/spark_api/configuration.rb +54 -0
- data/lib/spark_api/configuration.rb~ +54 -0
- data/lib/spark_api/configuration/yaml.rb +101 -0
- data/lib/spark_api/configuration/yaml.rb~ +101 -0
- data/lib/spark_api/connection.rb +42 -0
- data/lib/spark_api/faraday.rb +64 -0
- data/lib/spark_api/faraday.rb~ +64 -0
- data/lib/spark_api/models.rb +33 -0
- data/lib/spark_api/models.rb~ +33 -0
- data/lib/spark_api/models/account.rb +115 -0
- data/lib/spark_api/models/account.rb~ +115 -0
- data/lib/spark_api/models/base.rb +118 -0
- data/lib/spark_api/models/base.rb~ +118 -0
- data/lib/spark_api/models/connect_prefs.rb +10 -0
- data/lib/spark_api/models/connect_prefs.rb~ +10 -0
- data/lib/spark_api/models/constraint.rb +16 -0
- data/lib/spark_api/models/constraint.rb~ +16 -0
- data/lib/spark_api/models/contact.rb +49 -0
- data/lib/spark_api/models/contact.rb~ +49 -0
- data/lib/spark_api/models/custom_fields.rb +12 -0
- data/lib/spark_api/models/custom_fields.rb~ +12 -0
- data/lib/spark_api/models/document.rb +11 -0
- data/lib/spark_api/models/document.rb~ +11 -0
- data/lib/spark_api/models/finders.rb +45 -0
- data/lib/spark_api/models/finders.rb~ +45 -0
- data/lib/spark_api/models/idx_link.rb +47 -0
- data/lib/spark_api/models/idx_link.rb~ +47 -0
- data/lib/spark_api/models/listing.rb +197 -0
- data/lib/spark_api/models/listing.rb~ +197 -0
- data/lib/spark_api/models/listing_cart.rb +72 -0
- data/lib/spark_api/models/listing_cart.rb~ +72 -0
- data/lib/spark_api/models/market_statistics.rb +33 -0
- data/lib/spark_api/models/market_statistics.rb~ +33 -0
- data/lib/spark_api/models/message.rb +21 -0
- data/lib/spark_api/models/message.rb~ +21 -0
- data/lib/spark_api/models/note.rb +41 -0
- data/lib/spark_api/models/note.rb~ +41 -0
- data/lib/spark_api/models/notification.rb +42 -0
- data/lib/spark_api/models/notification.rb~ +42 -0
- data/lib/spark_api/models/open_house.rb +24 -0
- data/lib/spark_api/models/open_house.rb~ +24 -0
- data/lib/spark_api/models/photo.rb +70 -0
- data/lib/spark_api/models/photo.rb~ +70 -0
- data/lib/spark_api/models/property_types.rb +7 -0
- data/lib/spark_api/models/property_types.rb~ +7 -0
- data/lib/spark_api/models/saved_search.rb +16 -0
- data/lib/spark_api/models/saved_search.rb~ +16 -0
- data/lib/spark_api/models/shared_listing.rb +35 -0
- data/lib/spark_api/models/shared_listing.rb~ +35 -0
- data/lib/spark_api/models/standard_fields.rb +50 -0
- data/lib/spark_api/models/standard_fields.rb~ +50 -0
- data/lib/spark_api/models/subresource.rb +19 -0
- data/lib/spark_api/models/subresource.rb~ +19 -0
- data/lib/spark_api/models/system_info.rb +14 -0
- data/lib/spark_api/models/system_info.rb~ +14 -0
- data/lib/spark_api/models/tour_of_home.rb +24 -0
- data/lib/spark_api/models/tour_of_home.rb~ +24 -0
- data/lib/spark_api/models/video.rb +16 -0
- data/lib/spark_api/models/video.rb~ +16 -0
- data/lib/spark_api/models/virtual_tour.rb +18 -0
- data/lib/spark_api/models/virtual_tour.rb~ +18 -0
- data/lib/spark_api/multi_client.rb +59 -0
- data/lib/spark_api/multi_client.rb~ +59 -0
- data/lib/spark_api/paginate.rb +109 -0
- data/lib/spark_api/paginate.rb~ +109 -0
- data/lib/spark_api/primary_array.rb +29 -0
- data/lib/spark_api/primary_array.rb~ +29 -0
- data/lib/spark_api/request.rb +96 -0
- data/lib/spark_api/request.rb~ +96 -0
- data/lib/spark_api/response.rb +70 -0
- data/lib/spark_api/response.rb~ +70 -0
- data/lib/spark_api/version.rb +4 -0
- data/lib/spark_api/version.rb~ +4 -0
- data/script/console +6 -0
- data/script/console~ +6 -0
- data/script/example.rb +27 -0
- data/script/example.rb~ +27 -0
- data/spec/fixtures/accounts/all.json +160 -0
- data/spec/fixtures/accounts/my.json +74 -0
- data/spec/fixtures/accounts/my_portal.json +20 -0
- data/spec/fixtures/accounts/my_put.json +5 -0
- data/spec/fixtures/accounts/my_save.json +5 -0
- data/spec/fixtures/accounts/office.json +142 -0
- data/spec/fixtures/accounts/password_save.json +6 -0
- data/spec/fixtures/authentication_failure.json +7 -0
- data/spec/fixtures/base.json +13 -0
- data/spec/fixtures/contacts/contacts.json +28 -0
- data/spec/fixtures/contacts/my.json +19 -0
- data/spec/fixtures/contacts/new.json +11 -0
- data/spec/fixtures/contacts/new_empty.json +8 -0
- data/spec/fixtures/contacts/new_notify.json +11 -0
- data/spec/fixtures/contacts/post.json +10 -0
- data/spec/fixtures/contacts/tags.json +11 -0
- data/spec/fixtures/count.json +10 -0
- data/spec/fixtures/empty.json +3 -0
- data/spec/fixtures/errors/expired.json +7 -0
- data/spec/fixtures/errors/failure.json +5 -0
- data/spec/fixtures/errors/failure_with_constraint.json +17 -0
- data/spec/fixtures/errors/failure_with_msg.json +7 -0
- data/spec/fixtures/generic_delete.json +1 -0
- data/spec/fixtures/generic_failure.json +5 -0
- data/spec/fixtures/listing_carts/add_listing.json +13 -0
- data/spec/fixtures/listing_carts/add_listing_post.json +5 -0
- data/spec/fixtures/listing_carts/empty.json +5 -0
- data/spec/fixtures/listing_carts/listing_cart.json +19 -0
- data/spec/fixtures/listing_carts/new.json +12 -0
- data/spec/fixtures/listing_carts/post.json +10 -0
- data/spec/fixtures/listing_carts/remove_listing.json +13 -0
- data/spec/fixtures/listings/constraints.json +18 -0
- data/spec/fixtures/listings/constraints_with_pagination.json +24 -0
- data/spec/fixtures/listings/document_index.json +19 -0
- data/spec/fixtures/listings/multiple.json +69 -0
- data/spec/fixtures/listings/no_subresources.json +38 -0
- data/spec/fixtures/listings/open_houses.json +21 -0
- data/spec/fixtures/listings/photos/index.json +469 -0
- data/spec/fixtures/listings/photos/new.json +12 -0
- data/spec/fixtures/listings/photos/post.json +20 -0
- data/spec/fixtures/listings/put.json +5 -0
- data/spec/fixtures/listings/put_expiration_date.json +5 -0
- data/spec/fixtures/listings/saved_search.json +17 -0
- data/spec/fixtures/listings/shared_listing_get.json +14 -0
- data/spec/fixtures/listings/shared_listing_new.json +9 -0
- data/spec/fixtures/listings/shared_listing_post.json +10 -0
- data/spec/fixtures/listings/tour_of_homes.json +23 -0
- data/spec/fixtures/listings/videos_index.json +18 -0
- data/spec/fixtures/listings/virtual_tours_index.json +42 -0
- data/spec/fixtures/listings/with_documents.json +52 -0
- data/spec/fixtures/listings/with_permissions.json +44 -0
- data/spec/fixtures/listings/with_photos.json +110 -0
- data/spec/fixtures/listings/with_supplement.json +39 -0
- data/spec/fixtures/listings/with_videos.json +54 -0
- data/spec/fixtures/listings/with_vtour.json +48 -0
- data/spec/fixtures/logo_fbs.png +0 -0
- data/spec/fixtures/messages/new.json +14 -0
- data/spec/fixtures/messages/new_empty.json +7 -0
- data/spec/fixtures/messages/new_with_recipients.json +15 -0
- data/spec/fixtures/messages/post.json +5 -0
- data/spec/fixtures/notes/add.json +11 -0
- data/spec/fixtures/notes/agent_shared.json +11 -0
- data/spec/fixtures/notes/agent_shared_empty.json +7 -0
- data/spec/fixtures/notes/new.json +5 -0
- data/spec/fixtures/notifications/mark_read.json +1 -0
- data/spec/fixtures/notifications/new.json +8 -0
- data/spec/fixtures/notifications/new_empty.json +7 -0
- data/spec/fixtures/notifications/notifications.json +43 -0
- data/spec/fixtures/notifications/post.json +10 -0
- data/spec/fixtures/notifications/unread.json +10 -0
- data/spec/fixtures/oauth2/access.json +3 -0
- data/spec/fixtures/oauth2/access_with_old_refresh.json +5 -0
- data/spec/fixtures/oauth2/access_with_refresh.json +5 -0
- data/spec/fixtures/oauth2/authorization_code_body.json +7 -0
- data/spec/fixtures/oauth2/error.json +3 -0
- data/spec/fixtures/oauth2/password_body.json +7 -0
- data/spec/fixtures/oauth2/refresh_body.json +7 -0
- data/spec/fixtures/oauth2_error.json +3 -0
- data/spec/fixtures/property_types/property_types.json +31 -0
- data/spec/fixtures/session.json +10 -0
- data/spec/fixtures/standardfields/city.json +1031 -0
- data/spec/fixtures/standardfields/nearby.json +53 -0
- data/spec/fixtures/standardfields/standardfields.json +188 -0
- data/spec/fixtures/standardfields/stateorprovince.json +36 -0
- data/spec/fixtures/success.json +5 -0
- data/spec/json_helper.rb +76 -0
- data/spec/mock_helper.rb +124 -0
- data/spec/oauth2_helper.rb +68 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/unit/flexmls_api_spec.rb~ +23 -0
- data/spec/unit/spark_api/authentication/api_auth_spec.rb +169 -0
- data/spec/unit/spark_api/authentication/api_auth_spec.rb~ +169 -0
- data/spec/unit/spark_api/authentication/base_auth_spec.rb +10 -0
- data/spec/unit/spark_api/authentication/base_auth_spec.rb~ +10 -0
- data/spec/unit/spark_api/authentication/oauth2_impl/grant_type_base_spec.rb +10 -0
- data/spec/unit/spark_api/authentication/oauth2_impl/grant_type_base_spec.rb~ +10 -0
- data/spec/unit/spark_api/authentication/oauth2_spec.rb +205 -0
- data/spec/unit/spark_api/authentication/oauth2_spec.rb~ +205 -0
- data/spec/unit/spark_api/authentication_spec.rb +38 -0
- data/spec/unit/spark_api/authentication_spec.rb~ +38 -0
- data/spec/unit/spark_api/configuration/yaml_spec.rb +72 -0
- data/spec/unit/spark_api/configuration/yaml_spec.rb~ +72 -0
- data/spec/unit/spark_api/configuration_spec.rb +122 -0
- data/spec/unit/spark_api/configuration_spec.rb~ +122 -0
- data/spec/unit/spark_api/faraday_spec.rb +90 -0
- data/spec/unit/spark_api/faraday_spec.rb~ +90 -0
- data/spec/unit/spark_api/models/account_spec.rb +176 -0
- data/spec/unit/spark_api/models/base_spec.rb +106 -0
- data/spec/unit/spark_api/models/connect_prefs_spec.rb +9 -0
- data/spec/unit/spark_api/models/constraint_spec.rb +19 -0
- data/spec/unit/spark_api/models/contact_spec.rb +108 -0
- data/spec/unit/spark_api/models/contact_spec.rb~ +108 -0
- data/spec/unit/spark_api/models/document_spec.rb +32 -0
- data/spec/unit/spark_api/models/listing_cart_spec.rb +127 -0
- data/spec/unit/spark_api/models/listing_cart_spec.rb~ +127 -0
- data/spec/unit/spark_api/models/listing_spec.rb +320 -0
- data/spec/unit/spark_api/models/listing_spec.rb~ +320 -0
- data/spec/unit/spark_api/models/message_spec.rb +47 -0
- data/spec/unit/spark_api/models/message_spec.rb~ +47 -0
- data/spec/unit/spark_api/models/note_spec.rb +63 -0
- data/spec/unit/spark_api/models/note_spec.rb~ +63 -0
- data/spec/unit/spark_api/models/notification_spec.rb +62 -0
- data/spec/unit/spark_api/models/notification_spec.rb~ +62 -0
- data/spec/unit/spark_api/models/open_house_spec.rb +39 -0
- data/spec/unit/spark_api/models/photo_spec.rb +92 -0
- data/spec/unit/spark_api/models/property_types_spec.rb +33 -0
- data/spec/unit/spark_api/models/saved_search_spec.rb +40 -0
- data/spec/unit/spark_api/models/shared_listing_spec.rb +45 -0
- data/spec/unit/spark_api/models/shared_listing_spec.rb~ +45 -0
- data/spec/unit/spark_api/models/standard_fields_spec.rb +60 -0
- data/spec/unit/spark_api/models/system_info_spec.rb +83 -0
- data/spec/unit/spark_api/models/tour_of_home_spec.rb +44 -0
- data/spec/unit/spark_api/models/video_spec.rb +36 -0
- data/spec/unit/spark_api/models/virtual_tour_spec.rb +44 -0
- data/spec/unit/spark_api/multi_client_spec.rb +56 -0
- data/spec/unit/spark_api/multi_client_spec.rb~ +56 -0
- data/spec/unit/spark_api/paginate_spec.rb +224 -0
- data/spec/unit/spark_api/paginate_spec.rb~ +224 -0
- data/spec/unit/spark_api/primary_array_spec.rb +41 -0
- data/spec/unit/spark_api/primary_array_spec.rb~ +41 -0
- data/spec/unit/spark_api/request_spec.rb +344 -0
- data/spec/unit/spark_api/request_spec.rb~ +344 -0
- data/spec/unit/spark_api_spec.rb +23 -0
- metadata +725 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Lightweight example of an oauth2 provider used by the ruby client.
|
|
2
|
+
class TestOAuth2Provider < SparkApi::Authentication::BaseOAuth2Provider
|
|
3
|
+
|
|
4
|
+
def initialize
|
|
5
|
+
@authorization_uri = "https://test.fbsdata.com/r/oauth2"
|
|
6
|
+
@access_uri = "https://api.test.fbsdata.com/v1/oauth2/grant"
|
|
7
|
+
@redirect_uri = "https://exampleapp.fbsdata.com/oauth-callback"
|
|
8
|
+
@client_id="example-id"
|
|
9
|
+
@client_secret="example-password"
|
|
10
|
+
@session_cache = {}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def redirect(url)
|
|
14
|
+
# User redirected to url, signs in, and gets code sent to callback
|
|
15
|
+
self.code="my_code"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def load_session()
|
|
19
|
+
@session_cache["test_user_session"]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def save_session(session)
|
|
23
|
+
@session_cache["test_user_session"] = session
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def session_timeout; 7200; end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestCLIOAuth2Provider < SparkApi::Authentication::BaseOAuth2Provider
|
|
33
|
+
def initialize
|
|
34
|
+
@authorization_uri = "https://test.fbsdata.com/r/oauth2"
|
|
35
|
+
@access_uri = "https://api.test.fbsdata.com/v1/oauth2/grant"
|
|
36
|
+
@client_id="example-id"
|
|
37
|
+
@client_secret="example-secret"
|
|
38
|
+
@username="example-user"
|
|
39
|
+
@password="example-password"
|
|
40
|
+
@session_cache = {}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def grant_type
|
|
44
|
+
:password
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def redirect(url)
|
|
48
|
+
raise "Unsupported in oauth grant_type=password mode"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def load_session()
|
|
52
|
+
@session_cache["test_user_session"]
|
|
53
|
+
end
|
|
54
|
+
def save_session(session)
|
|
55
|
+
@session_cache["test_user_session"] = session
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
def session_timeout; 60; end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class InvalidAuth2Provider < SparkApi::Authentication::BaseOAuth2Provider
|
|
63
|
+
|
|
64
|
+
def grant_type
|
|
65
|
+
:not_a_real_type
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "json"
|
|
3
|
+
require "rspec"
|
|
4
|
+
require 'rspec/autorun'
|
|
5
|
+
require 'webmock/rspec'
|
|
6
|
+
|
|
7
|
+
begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
|
|
8
|
+
path = File.expand_path(File.dirname(__FILE__) + "/../lib/")
|
|
9
|
+
$LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
|
|
10
|
+
require path + '/spark_api'
|
|
11
|
+
|
|
12
|
+
require 'spark_api'
|
|
13
|
+
require File.expand_path('../mock_helper', __FILE__)
|
|
14
|
+
require File.expand_path('../json_helper', __FILE__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
FileUtils.mkdir 'log' unless File.exists? 'log'
|
|
18
|
+
|
|
19
|
+
# TODO, really we should change the library to support configuration without overriding
|
|
20
|
+
module SparkApi
|
|
21
|
+
def self.logger
|
|
22
|
+
if @logger.nil?
|
|
23
|
+
@logger = Logger.new('log/test.log')
|
|
24
|
+
@logger.level = Logger::DEBUG
|
|
25
|
+
end
|
|
26
|
+
@logger
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
SparkApi.logger.info("Setup gem for rspec testing")
|
|
31
|
+
|
|
32
|
+
def reset_config()
|
|
33
|
+
SparkApi.reset
|
|
34
|
+
SparkApi.configure do |config|
|
|
35
|
+
config.api_user = "foobar"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
reset_config
|
|
39
|
+
|
|
40
|
+
include SparkApi::Models
|
|
41
|
+
|
|
42
|
+
RSpec.configure do |config|
|
|
43
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
44
|
+
config.alias_example_to :on_get_it, :method => 'GET'
|
|
45
|
+
config.alias_example_to :on_put_it, :method => 'PUT'
|
|
46
|
+
config.alias_example_to :on_post_it, :method => 'POST'
|
|
47
|
+
config.alias_example_to :on_delete_it, :method => 'DELETE'
|
|
48
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require './spec/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe FlexmlsApi do
|
|
4
|
+
after(:each) do
|
|
5
|
+
reset_config
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should load the version" do
|
|
9
|
+
subject::VERSION.should match(/\d+\.\d+\.\d+/)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should give me a client connection" do
|
|
13
|
+
subject.client.should be_a(FlexmlsApi::Client)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should reset my connection" do
|
|
17
|
+
c1 = subject.client
|
|
18
|
+
subject.reset
|
|
19
|
+
subject.client.should_not eq(c1)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
require './spec/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SparkApi::Authentication::ApiAuth do
|
|
4
|
+
subject {SparkApi::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) { SparkApi::Client.new({:api_key => "my_key", :api_secret => "my_secret"}) }
|
|
21
|
+
subject do
|
|
22
|
+
s = SparkApi::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.sparkapi.com/#{SparkApi.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.sparkapi.com/#{SparkApi.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(SparkApi::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 {SparkApi::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) { SparkApi::Client.new({:api_key => "my_key", :api_secret => "my_secret"}) }
|
|
80
|
+
let(:session) { mock_session }
|
|
81
|
+
subject do
|
|
82
|
+
s = SparkApi::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, "#{SparkApi.endpoint}/#{SparkApi.version}/listings").
|
|
96
|
+
with(:query => {
|
|
97
|
+
:ApiSig => "1cb789831f8f4c6925dc708c93762a2c",
|
|
98
|
+
:AuthToken => "1234"}.merge(args)).
|
|
99
|
+
to_return(:body => fixture("listings/no_subresources.json"))
|
|
100
|
+
subject.session = session
|
|
101
|
+
subject.request(:get, "/#{SparkApi.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, "#{SparkApi.endpoint}/#{SparkApi.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, "/#{SparkApi.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
|
+
describe "sign_token" do
|
|
133
|
+
let(:client) { SparkApi::Client.new({:api_key => "my_key", :api_secret => "my_secret"}) }
|
|
134
|
+
subject {SparkApi::Authentication::ApiAuth.new(client) }
|
|
135
|
+
it "should fully sign the token" do
|
|
136
|
+
parms = {:AuthToken => "1234", :ApiUser => "CoolAsIce"}
|
|
137
|
+
subject.sign_token("/test", parms).should eq("7bbe3384a8b64368357f8551cab271e3")
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context "when the server says the session is expired (even if we disagree)" do
|
|
142
|
+
it "should reset the session and reauthenticate" do
|
|
143
|
+
reset_config
|
|
144
|
+
count = 0
|
|
145
|
+
# Make sure the auth request goes out twice.
|
|
146
|
+
stub_request(:post, "https://api.sparkapi.com/#{SparkApi.version}/session").
|
|
147
|
+
with(:query => {:ApiKey => "", :ApiSig => "806737984ab19be2fd08ba36030549ac"}).
|
|
148
|
+
to_return do |r|
|
|
149
|
+
count += 1
|
|
150
|
+
{:body => fixture("session.json")}
|
|
151
|
+
end
|
|
152
|
+
# Fail the first time, but then return the correct value after reauthentication
|
|
153
|
+
stub_request(:get, "#{SparkApi.endpoint}/#{SparkApi.version}/listings/1234").
|
|
154
|
+
with(:query => {
|
|
155
|
+
:ApiSig => "554b6e2a3efec8719b782647c19d238d",
|
|
156
|
+
:AuthToken => "c401736bf3d3f754f07c04e460e09573",
|
|
157
|
+
:ApiUser => "foobar",
|
|
158
|
+
:_expand => "Documents"
|
|
159
|
+
}).
|
|
160
|
+
to_return(:body => fixture('errors/expired.json'), :status => 401).times(1).then.
|
|
161
|
+
to_return(:body => fixture('listings/with_documents.json'))
|
|
162
|
+
l = Listing.find('1234', :_expand => "Documents")
|
|
163
|
+
|
|
164
|
+
count.should eq(2)
|
|
165
|
+
SparkApi.client.session.expired?.should eq(false)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
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("listings/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
|
+
describe "sign_token" do
|
|
133
|
+
let(:client) { FlexmlsApi::Client.new({:api_key => "my_key", :api_secret => "my_secret"}) }
|
|
134
|
+
subject {FlexmlsApi::Authentication::ApiAuth.new(client) }
|
|
135
|
+
it "should fully sign the token" do
|
|
136
|
+
parms = {:AuthToken => "1234", :ApiUser => "CoolAsIce"}
|
|
137
|
+
subject.sign_token("/test", parms).should eq("7bbe3384a8b64368357f8551cab271e3")
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context "when the server says the session is expired (even if we disagree)" do
|
|
142
|
+
it "should reset the session and reauthenticate" do
|
|
143
|
+
reset_config
|
|
144
|
+
count = 0
|
|
145
|
+
# Make sure the auth request goes out twice.
|
|
146
|
+
stub_request(:post, "https://api.flexmls.com/#{FlexmlsApi.version}/session").
|
|
147
|
+
with(:query => {:ApiKey => "", :ApiSig => "806737984ab19be2fd08ba36030549ac"}).
|
|
148
|
+
to_return do |r|
|
|
149
|
+
count += 1
|
|
150
|
+
{:body => fixture("session.json")}
|
|
151
|
+
end
|
|
152
|
+
# Fail the first time, but then return the correct value after reauthentication
|
|
153
|
+
stub_request(:get, "#{FlexmlsApi.endpoint}/#{FlexmlsApi.version}/listings/1234").
|
|
154
|
+
with(:query => {
|
|
155
|
+
:ApiSig => "554b6e2a3efec8719b782647c19d238d",
|
|
156
|
+
:AuthToken => "c401736bf3d3f754f07c04e460e09573",
|
|
157
|
+
:ApiUser => "foobar",
|
|
158
|
+
:_expand => "Documents"
|
|
159
|
+
}).
|
|
160
|
+
to_return(:body => fixture('errors/expired.json'), :status => 401).times(1).then.
|
|
161
|
+
to_return(:body => fixture('listings/with_documents.json'))
|
|
162
|
+
l = Listing.find('1234', :_expand => "Documents")
|
|
163
|
+
|
|
164
|
+
count.should eq(2)
|
|
165
|
+
FlexmlsApi.client.session.expired?.should eq(false)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|