diff --git a/.travis.yml b/.travis.yml index 3677baad..7ee50eb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,3 @@ rvm: - 2.1.0 - 1.9.3 - jruby-19mode - - rbx diff --git a/lib/linked_in.rb b/lib/linked_in.rb new file mode 100644 index 00000000..cea67420 --- /dev/null +++ b/lib/linked_in.rb @@ -0,0 +1,36 @@ +require 'oauth' +require 'linked_in/configuration' + +module LinkedIn + extend Configuration + class << self + attr_accessor :token, :secret, :default_profile_fields + + # config/initializers/linkedin.rb (for instance) + # + # ```ruby + # LinkedIn.configure do |config| + # config.token = 'consumer_token' + # config.secret = 'consumer_secret' + # config.default_profile_fields = ['educations', 'positions'] + # end + # ``` + # elsewhere + # + # ```ruby + # client = LinkedIn::Client.new + # ``` + def configure + yield self + true + end + end + + autoload :Api, "linked_in/api" + autoload :Client, "linked_in/client" + autoload :Mash, "linked_in/mash" + autoload :Errors, "linked_in/errors" + autoload :Helpers, "linked_in/helpers" + autoload :Search, "linked_in/search" + autoload :Version, "linked_in/version" +end diff --git a/lib/linked_in/api/communications.rb b/lib/linked_in/api/communications.rb index b6ac9983..6d805658 100644 --- a/lib/linked_in/api/communications.rb +++ b/lib/linked_in/api/communications.rb @@ -24,7 +24,7 @@ module Communications # message # @return [void] def send_message(subject, body, recipient_paths) - path = "/people/~/mailbox" + path = "people/~/mailbox" message = { 'subject' => subject, diff --git a/lib/linked_in/api/companies.rb b/lib/linked_in/api/companies.rb index 1110c100..d8f1a790 100644 --- a/lib/linked_in/api/companies.rb +++ b/lib/linked_in/api/companies.rb @@ -96,7 +96,7 @@ def company_updates_likes(update_key, options={}) # @macro share_input_fields # @return [void] def add_company_share(company_id, share) - path = "/companies/#{company_id}/shares" + path = "companies/#{company_id}/shares" defaults = {:visibility => {:code => "anyone"}} post(path, MultiJson.dump(defaults.merge(share)), "Content-Type" => "application/json") end @@ -108,7 +108,7 @@ def add_company_share(company_id, share) # @param [String] company_id Company ID # @return [void] def follow_company(company_id) - path = "/people/~/following/companies" + path = "people/~/following/companies" body = {:id => company_id } post(path, MultiJson.dump(body), "Content-Type" => "application/json") end @@ -120,7 +120,7 @@ def follow_company(company_id) # @param [String] company_id Company ID # @return [void] def unfollow_company(company_id) - path = "/people/~/following/companies/id=#{company_id}" + path = "people/~/following/companies/id=#{company_id}" delete(path) end end diff --git a/lib/linked_in/api/groups.rb b/lib/linked_in/api/groups.rb index 3483bd84..a21fd3f7 100644 --- a/lib/linked_in/api/groups.rb +++ b/lib/linked_in/api/groups.rb @@ -95,7 +95,7 @@ def post_group_discussion(group_id, discussion) # @macro share_input_fields # @return [void] def add_group_share(group_id, share) - path = "/groups/#{group_id}/posts" + path = "groups/#{group_id}/posts" post(path, MultiJson.dump(share), "Content-Type" => "application/json") end @@ -106,7 +106,7 @@ def add_group_share(group_id, share) # @param [String] group_id Group ID # @return [void] def join_group(group_id) - path = "/people/~/group-memberships/#{group_id}" + path = "people/~/group-memberships/#{group_id}" body = {'membership-state' => {'code' => 'member' }} put(path, MultiJson.dump(body), "Content-Type" => "application/json") end diff --git a/lib/linked_in/api/jobs.rb b/lib/linked_in/api/jobs.rb index 3689bc28..547b08e9 100644 --- a/lib/linked_in/api/jobs.rb +++ b/lib/linked_in/api/jobs.rb @@ -55,7 +55,7 @@ def job_suggestions(options = {}) # @param [String] job_id Job ID # @return [void] def add_job_bookmark(job_id) - path = "/people/~/job-bookmarks" + path = "people/~/job-bookmarks" body = {'job' => {'id' => job_id}} post(path, MultiJson.dump(body), "Content-Type" => "application/json") end diff --git a/lib/linked_in/api/query_helpers.rb b/lib/linked_in/api/query_helpers.rb index a1be84fe..30adcdd1 100644 --- a/lib/linked_in/api/query_helpers.rb +++ b/lib/linked_in/api/query_helpers.rb @@ -5,7 +5,7 @@ module QueryHelpers private def group_path(options) - path = "/groups" + path = "groups" if id = options.delete(:id) path += "/#{id}" end @@ -21,10 +21,10 @@ def simple_query(path, options={}) end headers = options.delete(:headers) || {} - params = to_query(options) - path += "#{path.include?("?") ? "&" : "?"}#{params}" if !params.empty? + # params = to_query(options) + # path += "#{path.include?("?") ? "&" : "?"}#{params}" if !params.empty? - Mash.from_json(get(path, headers)) + get(path, options, headers) end def build_fields_params(fields) @@ -38,7 +38,7 @@ def build_fields_params(fields) end def person_path(options) - path = "/people" + path = "people" if id = options.delete(:id) path += "/id=#{id}" elsif url = options.delete(:url) @@ -51,7 +51,7 @@ def person_path(options) end def company_path(options) - path = "/companies" + path = "companies" if domain = options.delete(:domain) path += "?email-domain=#{CGI.escape(domain)}" @@ -74,7 +74,7 @@ def picture_urls_path(options) end def jobs_path(options) - path = "/jobs" + path = "jobs" if id = options.delete(:id) path += "/id=#{id}" else diff --git a/lib/linked_in/api/share_and_social_stream.rb b/lib/linked_in/api/share_and_social_stream.rb index e9f2b4d9..8d7d44dd 100644 --- a/lib/linked_in/api/share_and_social_stream.rb +++ b/lib/linked_in/api/share_and_social_stream.rb @@ -85,7 +85,7 @@ def share_likes(update_key, options={}) # @macro share_input_fields # @return [void] def add_share(share) - path = "/people/~/shares" + path = "people/~/shares" defaults = {:visibility => {:code => "anyone"}} post(path, MultiJson.dump(defaults.merge(share)), "Content-Type" => "application/json") end @@ -99,7 +99,7 @@ def add_share(share) # @param [String] comment The text of the comment # @return [void] def update_comment(update_key, comment) - path = "/people/~/network/updates/key=#{update_key}/update-comments" + path = "people/~/network/updates/key=#{update_key}/update-comments" body = {'comment' => comment} post(path, MultiJson.dump(body), "Content-Type" => "application/json") end @@ -112,7 +112,7 @@ def update_comment(update_key, comment) # particular network update # @return [void] def like_share(update_key) - path = "/people/~/network/updates/key=#{update_key}/is-liked" + path = "people/~/network/updates/key=#{update_key}/is-liked" put(path, 'true', "Content-Type" => "application/json") end @@ -125,7 +125,7 @@ def like_share(update_key) # particular network update # @return [void] def unlike_share(update_key) - path = "/people/~/network/updates/key=#{update_key}/is-liked" + path = "people/~/network/updates/key=#{update_key}/is-liked" put(path, 'false', "Content-Type" => "application/json") end end diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index 645f196d..4021eab1 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -1,4 +1,6 @@ require 'cgi' +require 'faraday' +require 'faraday_middleware' module LinkedIn @@ -21,30 +23,50 @@ def initialize(ctoken=LinkedIn.token, csecret=LinkedIn.secret, options={}) @consumer_secret = csecret @consumer_options = options end + private - # - # def current_status - # path = "/people/~/current-status" - # Crack::XML.parse(get(path))['current_status'] - # end - # - # def network_statuses(options={}) - # options[:type] = 'STAT' - # network_updates(options) - # end - # - # def network_updates(options={}) - # path = "/people/~/network" - # Network.from_xml(get(to_uri(path, options))) - # end - # - # # helpful in making authenticated calls and writing the - # # raw xml to a fixture file - # def write_fixture(path, filename) - # file = File.new("test/fixtures/#{filename}", "w") - # file.puts(access_token.get(path).body) - # file.close - # end + def authentication + { + :consumer_key => consumer_token, + :consumer_secret => consumer_secret, + :token => @auth_token, + :token_secret => @auth_secret, + } + end + + def authenticated? + authentication.values.all? + end + + def connection_options + LinkedIn.faraday_options.merge({ + :headers => { + 'Accept' => "application/#{LinkedIn.format}", + 'User-Agent' => LinkedIn.user_agent, + 'x-li-format' => 'json' + }, + :proxy => LinkedIn.proxy, + :ssl => {:verify => false}, + :url => LinkedIn.endpoint + }) + end + + def connection + raise "Please authenticate first" unless authenticated? + + @connection ||= Faraday.new(connection_options) do |builder| + builder.use ::Faraday::Request::OAuth, authentication.merge(:ignore_extra_keys => true) + builder.use ::Faraday::Request::UrlEncoded + builder.use ::FaradayMiddleware::Mashify, :mash_class => LinkedIn::Mash + builder.use ::Faraday::Response::ParseJson + + LinkedIn.middleware.each do |middle| + builder.use middle + end + + builder.adapter(LinkedIn.adapter) + end + end end diff --git a/lib/linked_in/configuration.rb b/lib/linked_in/configuration.rb new file mode 100644 index 00000000..e1efbe22 --- /dev/null +++ b/lib/linked_in/configuration.rb @@ -0,0 +1,104 @@ +require 'linked_in/version' +require 'faraday' +require 'faraday_middleware' +require 'linked_in/middleware/error_reporter' + +module LinkedIn + # Defines constants and methods related to configuration + module Configuration + # An array of valid keys in the options hash when configuring a {LinkedIn::API} + VALID_OPTIONS_KEYS = [ + :adapter, + :consumer_key, + :consumer_secret, + :default_profile_fields, + :endpoint, + :format, + :gateway, + :oauth_token, + :oauth_token_secret, + :proxy, + :user_agent, + :faraday_options, + :middleware].freeze + + # The adapter that will be used to connect if none is set + DEFAULT_ADAPTER = :net_http + + # By default, don't set an application key + DEFAULT_CONSUMER_KEY = nil + + # By default, don't set an application secret + DEFAULT_CONSUMER_SECRET = nil + + # The endpoint that will be used to connect if none is set + # + DEFAULT_ENDPOINT = 'https://api.linkedin.com/'.freeze + + # The response format appended to the path and sent in the 'Accept' header if none is set + # + # @note JSON is preferred over XML because it is more concise and faster to parse. + DEFAULT_FORMAT = :json + + # By default, don't set a user oauth token + DEFAULT_OAUTH_TOKEN = nil + + # By default, don't set a user oauth secret + DEFAULT_OAUTH_TOKEN_SECRET = nil + + # By default, don't set any profile fields + DEFAULT_PROFILE_FIELDS = nil + + # By default, don't use a proxy server + DEFAULT_PROXY = nil + + # The value sent in the 'User-Agent' header if none is set + DEFAULT_USER_AGENT = "LinkedIn Ruby Gem #{LinkedIn::VERSION}".freeze + + DEFAULT_GATEWAY = nil + + DEFAULT_FARADAY_OPTIONS = {}.freeze + + DEFAULT_MIDDLEWARE = [ + ::LinkedIn::ErrorReporter + ] + + # @private + attr_accessor *VALID_OPTIONS_KEYS + + # When this module is extended, set all configuration options to their default values + def self.extended(base) + base.reset + end + + # Convenience method to allow configuration options to be set in a block + def configure + yield self + end + + # Create a hash of options and their values + def options + options = {} + VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)} + options + end + + # Reset all configuration options to defaults + def reset + self.adapter = DEFAULT_ADAPTER + self.consumer_key = DEFAULT_CONSUMER_KEY + self.consumer_secret = DEFAULT_CONSUMER_SECRET + self.default_profile_fields = DEFAULT_PROFILE_FIELDS + self.endpoint = DEFAULT_ENDPOINT + self.format = DEFAULT_FORMAT + self.oauth_token = DEFAULT_OAUTH_TOKEN + self.oauth_token_secret = DEFAULT_OAUTH_TOKEN_SECRET + self.proxy = DEFAULT_PROXY + self.user_agent = DEFAULT_USER_AGENT + self.gateway = DEFAULT_GATEWAY + self.faraday_options = DEFAULT_FARADAY_OPTIONS + self.middleware = DEFAULT_MIDDLEWARE + self + end + end +end \ No newline at end of file diff --git a/lib/linked_in/errors.rb b/lib/linked_in/errors.rb index bded0658..59c422aa 100644 --- a/lib/linked_in/errors.rb +++ b/lib/linked_in/errors.rb @@ -1,12 +1,6 @@ module LinkedIn module Errors - class LinkedInError < StandardError - attr_reader :data - def initialize(data) - @data = data - super - end - end + class LinkedInError < StandardError; end # Raised when a 401 response status code is received class UnauthorizedError < LinkedInError; end diff --git a/lib/linked_in/helpers/request.rb b/lib/linked_in/helpers/request.rb index 94f66592..14711c2d 100644 --- a/lib/linked_in/helpers/request.rb +++ b/lib/linked_in/helpers/request.rb @@ -3,83 +3,27 @@ module Helpers module Request - DEFAULT_HEADERS = { - 'x-li-format' => 'json' - } - - API_PATH = '/v1' - protected - def get(path, options={}) - response = access_token.get("#{API_PATH}#{path}", DEFAULT_HEADERS.merge(options)) - raise_errors(response) - response.body - end - - def post(path, body='', options={}) - response = access_token.post("#{API_PATH}#{path}", body, DEFAULT_HEADERS.merge(options)) - raise_errors(response) - response - end - - def put(path, body, options={}) - response = access_token.put("#{API_PATH}#{path}", body, DEFAULT_HEADERS.merge(options)) - raise_errors(response) - response - end - - def delete(path, options={}) - response = access_token.delete("#{API_PATH}#{path}", DEFAULT_HEADERS.merge(options)) - raise_errors(response) - response - end - - private - - def raise_errors(response) - # Even if the json answer contains the HTTP status code, LinkedIn also sets this code - # in the HTTP answer (thankfully). - case response.code.to_i - when 401 - data = Mash.from_json(response.body) - raise LinkedIn::Errors::UnauthorizedError.new(data), "(#{data.status}): #{data.message}" - when 400 - data = Mash.from_json(response.body) - raise LinkedIn::Errors::GeneralError.new(data), "(#{data.status}): #{data.message}" - when 403 - data = Mash.from_json(response.body) - raise LinkedIn::Errors::AccessDeniedError.new(data), "(#{data.status}): #{data.message}" - when 404 - raise LinkedIn::Errors::NotFoundError, "(#{response.code}): #{response.message}" - when 500 - raise LinkedIn::Errors::InformLinkedInError, "LinkedIn had an internal error. Please let them know in the forum. (#{response.code}): #{response.message}" - when 502..503 - raise LinkedIn::Errors::UnavailableError, "(#{response.code}): #{response.message}" - end - end - - - # Stolen from Rack::Util.build_query - def to_query(params) - params.map { |k, v| - if v.class == Array - to_query(v.map { |x| [k, x] }) - else - v.nil? ? escape(k) : "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" - end - }.join("&") - end - - def to_uri(path, options) - uri = URI.parse(path) - - if options && options != {} - uri.query = to_query(options) - end - uri.to_s - end + def get(path, query_params, headers = {}) + response = connection.get('v1/' + path, query_params, headers) + response.body + end + + def post(path, body='', options={}) + response = connection.post('v1/' + path, body, options) + response + end + + def put(path, body, options={}) + response = connection.put('v1/' + path, body, options) + response + end + + def delete(path, options={}) + response = connection.delete('v1/' + path, options) + response + end end - end end diff --git a/lib/linked_in/mash.rb b/lib/linked_in/mash.rb index b07e8ddd..9b987850 100644 --- a/lib/linked_in/mash.rb +++ b/lib/linked_in/mash.rb @@ -6,16 +6,6 @@ module LinkedIn # The generalized pseudo-object that is returned for all query # requests. class Mash < ::Hashie::Mash - - # Convert a json string to a Mash - # - # @param [String] json_string - # @return [LinkedIn::Mash] - def self.from_json(json_string) - result_hash = ::MultiJson.decode(json_string) - new(result_hash) - end - # Returns a Date if we have year, month and day, and no conflicting key # # @return [Date] diff --git a/lib/linked_in/middleware/error_reporter.rb b/lib/linked_in/middleware/error_reporter.rb new file mode 100644 index 00000000..5c5a1106 --- /dev/null +++ b/lib/linked_in/middleware/error_reporter.rb @@ -0,0 +1,23 @@ +module LinkedIn + class ErrorReporter < Faraday::Middleware + def call(env) + @app.call(env).on_complete do + response = env[:response] + case response.status + when 401 + raise LinkedIn::Errors::UnauthorizedError.new(response), "(#{response.status}): #{response.body}" + when 400 + raise LinkedIn::Errors::GeneralError.new(response), "(#{response.status}): #{response.body}" + when 403 + raise LinkedIn::Errors::AccessDeniedError.new(response), "(#{response.status}): #{response.body}" + when 404 + raise LinkedIn::Errors::NotFoundError, "(#{response.status}): #{response.body}" + when 500 + raise LinkedIn::Errors::InformLinkedInError, "LinkedIn had an internal error. Please let them know in the forum. (#{response.status}): #{response.body}" + when 502..503 + raise LinkedIn::Errors::UnavailableError, "(#{response.status}): #{response.body}" + end + end + end + end +end \ No newline at end of file diff --git a/lib/linked_in/search.rb b/lib/linked_in/search.rb index 2cf3f821..9a2d5561 100644 --- a/lib/linked_in/search.rb +++ b/lib/linked_in/search.rb @@ -18,7 +18,7 @@ module Search # @return [LinkedIn::Mash] def search(options={}, type='people') - path = "/#{type.to_s}-search" + path = "#{type.to_s}-search" if options.is_a?(Hash) fields = options.delete(:fields) @@ -27,10 +27,7 @@ def search(options={}, type='people') options = { :keywords => options } if options.is_a?(String) options = format_options_for_query(options) - - result_json = get(to_uri(path, options)) - - Mash.from_json(result_json) + get(path, options) end private diff --git a/lib/linkedin.rb b/lib/linkedin.rb index 513f55ca..7416b677 100644 --- a/lib/linkedin.rb +++ b/lib/linkedin.rb @@ -1,35 +1 @@ -require 'oauth' - -module LinkedIn - - class << self - attr_accessor :token, :secret, :default_profile_fields - - # config/initializers/linkedin.rb (for instance) - # - # ```ruby - # LinkedIn.configure do |config| - # config.token = 'consumer_token' - # config.secret = 'consumer_secret' - # config.default_profile_fields = ['educations', 'positions'] - # end - # ``` - # elsewhere - # - # ```ruby - # client = LinkedIn::Client.new - # ``` - def configure - yield self - true - end - end - - autoload :Api, "linked_in/api" - autoload :Client, "linked_in/client" - autoload :Mash, "linked_in/mash" - autoload :Errors, "linked_in/errors" - autoload :Helpers, "linked_in/helpers" - autoload :Search, "linked_in/search" - autoload :Version, "linked_in/version" -end +require 'linked_in' diff --git a/linkedin.gemspec b/linkedin.gemspec index ac2f6d4f..6662ed85 100644 --- a/linkedin.gemspec +++ b/linkedin.gemspec @@ -3,8 +3,11 @@ require File.expand_path('../lib/linked_in/version', __FILE__) Gem::Specification.new do |gem| gem.add_dependency 'hashie', '~> 3.0' - gem.add_dependency 'multi_json', '~> 1.0' + gem.add_dependency 'multi_json', '~> 1.8' gem.add_dependency 'oauth', '~> 0.4' + gem.add_dependency 'faraday', '~> 0.8' + gem.add_dependency 'faraday_middleware' + gem.add_dependency 'simple_oauth' # gem.add_development_dependency 'json', '~> 1.6' gem.add_development_dependency 'rake', '~> 10' gem.add_development_dependency 'yard' diff --git a/spec/cases/api_spec.rb b/spec/cases/api_spec.rb index d2a528ab..8e993b63 100644 --- a/spec/cases/api_spec.rb +++ b/spec/cases/api_spec.rb @@ -71,14 +71,14 @@ stub_request(:post, "https://api.linkedin.com/v1/people/~/shares").to_return(:body => "", :status => 201) response = client.add_share(:comment => "Testing, 1, 2, 3") response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to share a new company status" do stub_request(:post, "https://api.linkedin.com/v1/companies/123456/shares").to_return(:body => "", :status => 201) response = client.add_company_share("123456", { :comment => "Testing, 1, 2, 3" }) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "returns the shares for a person" do @@ -92,7 +92,7 @@ :body => "", :status => 201) response = client.update_comment('SOMEKEY', "Testing, 1, 2, 3") response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to like a network update" do @@ -100,7 +100,7 @@ with(:body => "true").to_return(:body => "", :status => 201) response = client.like_share('SOMEKEY') response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to unlike a network update" do @@ -108,7 +108,7 @@ with(:body => "false").to_return(:body => "", :status => 201) response = client.unlike_share('SOMEKEY') response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to pass down the additional arguments to OAuth's get_request_token" do @@ -125,7 +125,7 @@ context "Company API", :vcr do it "should be able to view a company profile" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586").to_return(:body => "{}") client.company(:id => 1586).should be_an_instance_of(LinkedIn::Mash) end @@ -162,22 +162,22 @@ end it "should be able to view company_updates" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586/updates").to_return(:body => "{}") client.company_updates(:id => 1586).should be_an_instance_of(LinkedIn::Mash) end it "should be able to view company_statistic" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/company-statistics").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586/company-statistics").to_return(:body => "{}") client.company_statistics(:id => 1586).should be_an_instance_of(LinkedIn::Mash) end it "should be able to view company updates comments" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates/key=company_update_key/update-comments").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586/updates/key=company_update_key/update-comments").to_return(:body => "{}") client.company_updates_comments("company_update_key", :id => 1586).should be_an_instance_of(LinkedIn::Mash) end it "should be able to view company updates likes" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates/key=company_update_key/likes").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586/updates/key=company_update_key/likes").to_return(:body => "{}") client.company_updates_likes("company_update_key", :id => 1586).should be_an_instance_of(LinkedIn::Mash) end @@ -186,7 +186,7 @@ response = client.follow_company(1586) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to unfollow a company" do @@ -194,7 +194,7 @@ response = client.unfollow_company(1586) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end end @@ -220,7 +220,7 @@ stub_request(:post, "https://api.linkedin.com/v1/people/~/job-bookmarks").to_return(:body => "", :status => 201) response = client.add_job_bookmark(:id => 1452577) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end end @@ -247,7 +247,7 @@ response = client.join_group(123) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to list a group profile" do @@ -274,14 +274,14 @@ stub_request(:post, "https://api.linkedin.com/v1/groups/123/posts").with(:body => expected).to_return(:body => "", :status => 201) response = client.post_group_discussion(123, expected) response.body.should == nil - response.code.should == '201' + response.status.should == 201 end it "should be able to share a new group status" do stub_request(:post, "https://api.linkedin.com/v1/groups/1/posts").to_return(:body => "", :status => 201) response = client.add_group_share(1, :comment => "Testing, 1, 2, 3") response.body.should == nil - response.code.should == "201" + response.status.should == 201 end end @@ -290,7 +290,7 @@ stub_request(:post, "https://api.linkedin.com/v1/people/~/mailbox").to_return(:body => "", :status => 201) response = client.send_message("subject", "body", ["recip1", "recip2"]) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end end diff --git a/spec/cases/error_reporter_spec.rb b/spec/cases/error_reporter_spec.rb new file mode 100644 index 00000000..fb008429 --- /dev/null +++ b/spec/cases/error_reporter_spec.rb @@ -0,0 +1,42 @@ +require 'helper' + +describe LinkedIn::Client do + before do + LinkedIn.default_profile_fields = nil + client.stub(:consumer).and_return(consumer) + client.authorize_from_access('atoken', 'asecret') + end + + let(:client) { LinkedIn::Client.new('token', 'secret') } + let(:consumer) { OAuth::Consumer.new('token', 'secret', :site => 'https://api.linkedin.com') } + + it 'raises an unauthorized error when 401' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 401) + ->{ client.profile }.should raise_error(LinkedIn::Errors::UnauthorizedError) + end + + it 'raises a general error when 400' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 400) + ->{ client.profile }.should raise_error(LinkedIn::Errors::GeneralError) + end + + it 'raises a access denied error when 403' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 403) + ->{ client.profile }.should raise_error(LinkedIn::Errors::AccessDeniedError) + end + + it 'raises a notfounderror when 404' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 404) + ->{ client.profile }.should raise_error(LinkedIn::Errors::NotFoundError) + end + + it 'raises a informlinkedinerror if 500' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 500) + ->{ client.profile }.should raise_error(LinkedIn::Errors::InformLinkedInError) + end + + it 'raises an unavailable error if either 502 or 503' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 502) + ->{ client.profile }.should raise_error(LinkedIn::Errors::UnavailableError) + end +end diff --git a/spec/cases/mash_spec.rb b/spec/cases/mash_spec.rb index 08021e39..e2fcc904 100644 --- a/spec/cases/mash_spec.rb +++ b/spec/cases/mash_spec.rb @@ -2,16 +2,6 @@ describe LinkedIn::Mash do - describe ".from_json" do - it "should convert a json string to a Mash" do - json_string = "{\"name\":\"Josh Kalderimis\"}" - mash = LinkedIn::Mash.from_json(json_string) - - mash.should have_key('name') - mash.name.should == 'Josh Kalderimis' - end - end - describe "#convert_keys" do let(:mash) do LinkedIn::Mash.new({ diff --git a/spec/cases/search_spec.rb b/spec/cases/search_spec.rb index c3924c5c..01ace293 100644 --- a/spec/cases/search_spec.rb +++ b/spec/cases/search_spec.rb @@ -167,7 +167,7 @@ end describe "by multiple email address", vcr: vcr_options do - + let(:results) do fields = ['id'] client.profile(:email => 'email=yy@zz.com,email=xx@yy.com', :fields => fields) diff --git a/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml b/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml index 5e231240..3f20a7ea 100644 --- a/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml +++ b/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml @@ -2,7 +2,7 @@ http_interactions: - request: method: get - uri: https://api.linkedin.com/v1/companies/id=1586 + uri: https://api.linkedin.com/v1/companies/1586 body: encoding: US-ASCII string: '' @@ -39,7 +39,7 @@ http_interactions: recorded_at: Wed, 10 Apr 2013 22:06:51 GMT - request: method: get - uri: https://api.linkedin.com/v1/companies/id=1586:(id,name,industry,locations:(address:(city,state,country-code),is-headquarters),employee-count-range) + uri: https://api.linkedin.com/v1/companies/1586:(id,name,industry,locations:(address:(city,state,country-code),is-headquarters),employee-count-range) body: encoding: US-ASCII string: '' diff --git a/spec/helper.rb b/spec/helper.rb index b0765d65..b1dd8650 100644 --- a/spec/helper.rb +++ b/spec/helper.rb @@ -1,5 +1,6 @@ $:.unshift File.expand_path('..', __FILE__) $:.unshift File.expand_path('../../lib', __FILE__) + if ENV['COVERAGE'] == 't' require 'simplecov' SimpleCov.start