spec/acceptance/rest/base_spec.rb in ably-0.6.2 vs spec/acceptance/rest/base_spec.rb in ably-0.7.0

- old
+ new

@@ -1,232 +1,164 @@ +# encoding: utf-8 require 'spec_helper' -require 'securerandom' -describe 'REST' do - let(:client) do - Ably::Rest::Client.new(api_key: api_key, environment: environment) - end - - describe 'protocol' do +describe Ably::Rest do + describe 'transport protocol' do include Ably::Modules::Conversions let(:client_options) { {} } let(:client) do Ably::Rest::Client.new(client_options.merge(api_key: 'appid.keyuid:keysecret')) end - context 'transport' do - let(:now) { Time.now - 1000 } - let(:body_value) { [as_since_epoch(now)] } + let(:now) { Time.now - 1000 } + let(:body_value) { [as_since_epoch(now)] } - before do - stub_request(:get, "#{client.endpoint}/time"). - with(:headers => { 'Accept' => mime }). - to_return(:status => 200, :body => request_body, :headers => { 'Content-Type' => mime }) - end + before do + stub_request(:get, "#{client.endpoint}/time"). + with(:headers => { 'Accept' => mime }). + to_return(:status => 200, :body => request_body, :headers => { 'Content-Type' => mime }) + end - context 'when protocol is not defined it defaults to :msgpack' do - let(:client_options) { { } } - let(:mime) { 'application/x-msgpack' } - let(:request_body) { body_value.to_msgpack } + context 'when protocol is not defined it defaults to :msgpack' do + let(:client_options) { { } } + let(:mime) { 'application/x-msgpack' } + let(:request_body) { body_value.to_msgpack } - it 'uses MsgPack', webmock: true do - expect(client.protocol).to eql(:msgpack) - expect(client.time).to be_within(1).of(now) - end + it 'uses MsgPack', :webmock do + expect(client.protocol).to eql(:msgpack) + expect(client.time).to be_within(1).of(now) end + end - options = [ - { protocol: :json }, - { use_binary_protocol: false } - ].each do |client_option| + options = [ + { protocol: :json }, + { use_binary_protocol: false } + ].each do |client_option| - context "when option #{client_option} is used" do - let(:client_options) { client_option } - let(:mime) { 'application/json' } - let(:request_body) { body_value.to_json } + context "when option #{client_option} is used" do + let(:client_options) { client_option } + let(:mime) { 'application/json' } + let(:request_body) { body_value.to_json } - it 'uses JSON', webmock: true do - expect(client.protocol).to eql(:json) - expect(client.time).to be_within(1).of(now) - end + it 'uses JSON', :webmock do + expect(client.protocol).to eql(:json) + expect(client.time).to be_within(1).of(now) end end + end - options = [ - { protocol: :json }, - { use_binary_protocol: false } - ].each do |client_option| + options = [ + { protocol: :msgpack }, + { use_binary_protocol: true } + ].each do |client_option| - context "when option #{client_option} is used" do - let(:client_options) { { protocol: :msgpack } } - let(:mime) { 'application/x-msgpack' } - let(:request_body) { body_value.to_msgpack } + context "when option #{client_option} is used" do + let(:client_options) { client_option } + let(:mime) { 'application/x-msgpack' } + let(:request_body) { body_value.to_msgpack } - it 'uses MsgPack', webmock: true do - expect(client.protocol).to eql(:msgpack) - expect(client.time).to be_within(1).of(now) - end + it 'uses MsgPack', :webmock do + expect(client.protocol).to eql(:msgpack) + expect(client.time).to be_within(1).of(now) end end end end - describe 'invalid requests in middleware' do - it 'should raise an InvalidRequest exception with a valid message' do - invalid_client = Ably::Rest::Client.new(api_key: 'appid.keyuid:keysecret', environment: environment) - expect { invalid_client.channel('test').publish('foo', 'choo') }.to raise_error do |error| - expect(error).to be_a(Ably::Exceptions::InvalidToken) - expect(error.message).to match(/invalid credentials/) - expect(error.code).to eql(40100) - expect(error.status).to eql(401) - end + vary_by_protocol do + let(:client) do + Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol) end - describe 'server error with JSON response', webmock: true do - let(:error_response) { '{ "error": { "statusCode": 500, "code": 50000, "message": "Internal error" } }' } - - before do - stub_request(:get, "#{client.endpoint}/time"). - to_return(:status => 500, :body => error_response, :headers => { 'Content-Type' => 'application/json' }) + describe 'failed requests' do + context 'due to invalid Auth' do + it 'should raise an InvalidRequest exception with a valid error message and code' do + invalid_client = Ably::Rest::Client.new(api_key: 'appid.keyuid:keysecret', environment: environment) + expect { invalid_client.channel('test').publish('foo', 'choo') }.to raise_error do |error| + expect(error).to be_a(Ably::Exceptions::InvalidRequest) + expect(error.message).to match(/invalid credentials/) + expect(error.code).to eql(40100) + expect(error.status).to eql(401) + end + end end - it 'should raise a ServerError exception' do - expect { client.time }.to raise_error(Ably::Exceptions::ServerError, /Internal error/) - end - end + describe 'server error with JSON error response body', :webmock do + let(:error_response) { '{ "error": { "statusCode": 500, "code": 50000, "message": "Internal error" } }' } - describe 'server error', webmock: true do - before do - stub_request(:get, "#{client.endpoint}/time"). - to_return(:status => 500, :headers => { 'Content-Type' => 'application/json' }) - end + before do + stub_request(:get, "#{client.endpoint}/time"). + to_return(:status => 500, :body => error_response, :headers => { 'Content-Type' => 'application/json' }) + end - it 'should raise a ServerError exception' do - expect { client.time }.to raise_error(Ably::Exceptions::ServerError, /Unknown/) + it 'should raise a ServerError exception' do + expect { client.time }.to raise_error(Ably::Exceptions::ServerError, /Internal error/) + end end - end - end - describe 'authentication failure', webmock: true do - let(:token_1) { { id: SecureRandom.hex } } - let(:token_2) { { id: SecureRandom.hex } } - let(:channel) { 'channelname' } + describe '500 server error without a valid JSON response body', :webmock do + before do + stub_request(:get, "#{client.endpoint}/time"). + to_return(:status => 500, :headers => { 'Content-Type' => 'application/json' }) + end - before do - @token_requests = 0 - @publish_attempts = 0 - - stub_request(:post, "#{client.endpoint}/keys/#{key_id}/requestToken").to_return do - @token_requests += 1 - { - :body => { access_token: send("token_#{@token_requests}").merge(expires: Time.now.to_i + 3600) }.to_json, - :headers => { 'Content-Type' => 'application/json' } - } - end - - stub_request(:post, "#{client.endpoint}/channels/#{channel}/publish").to_return do - @publish_attempts += 1 - if [1, 3].include?(@publish_attempts) - { status: 201, :body => '[]', :headers => { 'Content-Type' => 'application/json' } } - else - raise Ably::Exceptions::InvalidRequest.new('Authentication failure', 401, 40140) + it 'should raise a ServerError exception' do + expect { client.time }.to raise_error(Ably::Exceptions::ServerError, /Unknown/) end end end - context 'when auth#token_renewable?' do + describe 'token authentication failures', :webmock do + let(:token_1) { { id: random_str } } + let(:token_2) { { id: random_str } } + let(:channel) { 'channelname' } + before do - client.auth.authorise - end + @token_requests = 0 + @publish_attempts = 0 - it 'should automatically reissue a token' do - client.channel(channel).publish('evt', 'msg') - expect(@publish_attempts).to eql(1) + stub_request(:post, "#{client.endpoint}/keys/#{key_id}/requestToken").to_return do + @token_requests += 1 + { + :body => { access_token: send("token_#{@token_requests}").merge(expires: Time.now.to_i + 3600) }.to_json, + :headers => { 'Content-Type' => 'application/json' } + } + end - client.channel(channel).publish('evt', 'msg') - expect(@publish_attempts).to eql(3) - expect(@token_requests).to eql(2) - end - end - - context 'when NOT auth#token_renewable?' do - let(:client) { Ably::Rest::Client.new(token_id: 'token ID cannot be used to create a new token', environment: environment) } - it 'should raise the exception' do - client.channel(channel).publish('evt', 'msg') - expect(@publish_attempts).to eql(1) - expect { client.channel(channel).publish('evt', 'msg') }.to raise_error Ably::Exceptions::InvalidToken - expect(@token_requests).to eql(0) - end - end - end - - describe Ably::Rest::Client do - context '#initialize' do - context 'with an auth block' do - let(:client) { Ably::Rest::Client.new(environment: environment) { token_request } } - let(:token_request) { client.auth.create_token_request(key_id: key_id, key_secret: key_secret, client_id: client_id) } - let(:client_id) { 'unique_client_id' } - - it 'calls the block to get a new token' do - expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token } - expect(client.auth.current_token.client_id).to eql(client_id) + stub_request(:post, "#{client.endpoint}/channels/#{channel}/publish").to_return do + @publish_attempts += 1 + if [1, 3].include?(@publish_attempts) + { status: 201, :body => '[]', :headers => { 'Content-Type' => 'application/json' } } + else + raise Ably::Exceptions::InvalidRequest.new('Authentication failure', 401, 40140) + end end end - context 'with an auth URL' do - let(:client) { Ably::Rest::Client.new(environment: environment, auth_url: token_request_url, auth_method: :get) } - let(:token_request_url) { 'http://get.token.request.com/' } - let(:token_request) { client.auth.create_token_request(key_id: key_id, key_secret: key_secret, client_id: client_id) } - let(:client_id) { 'unique_client_id' } - + context 'when auth#token_renewable?' do before do - allow(client.auth).to receive(:token_request_from_auth_url).with(token_request_url, :auth_method => :get).and_return(token_request) + client.auth.authorise end - it 'sends an HTTP request to get a new token' do - expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token } - expect(client.auth.current_token.client_id).to eql(client_id) - end - end - end + it 'should automatically reissue a token' do + client.channel(channel).publish('evt', 'msg') + expect(@publish_attempts).to eql(1) - context 'token expiry' do - let(:client) do - Ably::Rest::Client.new(environment: environment) do - @request_index ||= 0 - @request_index += 1 - send("token_request_#{@request_index}") + client.channel(channel).publish('evt', 'msg') + expect(@publish_attempts).to eql(3) + expect(@token_requests).to eql(2) end end - let(:token_request_1) { client.auth.create_token_request(token_request_options.merge(client_id: SecureRandom.hex)) } - let(:token_request_2) { client.auth.create_token_request(token_request_options.merge(client_id: SecureRandom.hex)) } - context 'when expired' do - let(:token_request_options) { { key_id: key_id, key_secret: key_secret, ttl: Ably::Models::Token::TOKEN_EXPIRY_BUFFER } } + context 'when NOT auth#token_renewable?' do + let(:client) { Ably::Rest::Client.new(token_id: 'token ID cannot be used to create a new token', environment: environment, protocol: protocol) } - it 'creates a new token automatically when the old token expires' do - expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token } - expect(client.auth.current_token.client_id).to eql(token_request_1[:client_id]) - - sleep 1 - - expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token } - expect(client.auth.current_token.client_id).to eql(token_request_2[:client_id]) - end - end - - context 'token authentication with long expiry token' do - let(:token_request_options) { { key_id: key_id, key_secret: key_secret, ttl: 3600 } } - - it 'creates a new token automatically when the old token expires' do - expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token } - expect(client.auth.current_token.client_id).to eql(token_request_1[:client_id]) - - sleep 1 - - expect { client.channel('channel_name').publish('event', 'message') }.to_not change { client.auth.current_token } - expect(client.auth.current_token.client_id).to eql(token_request_1[:client_id]) + it 'should raise an InvalidToken exception' do + client.channel(channel).publish('evt', 'msg') + expect(@publish_attempts).to eql(1) + expect { client.channel(channel).publish('evt', 'msg') }.to raise_error Ably::Exceptions::InvalidToken + expect(@token_requests).to eql(0) end end end end end