lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb in ably-rest-0.8.3 vs lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb in ably-rest-0.8.5

- old
+ new

@@ -25,11 +25,11 @@ ) end vary_by_protocol do let(:default_options) { { environment: environment, protocol: protocol } } - let(:client_options) { default_options.merge(key: api_key) } + let(:client_options) { default_options.merge(key: api_key) } let(:client) do Ably::Rest::Client.new(client_options) end let(:auth) { client.auth } let(:content_type) do @@ -64,14 +64,14 @@ describe '#request_token' do let(:ttl) { 30 * 60 } let(:capability) { { :foo => ['publish'] } } let(:token_details) do - auth.request_token(token_params: { + auth.request_token( ttl: ttl, capability: capability - }) + ) end it 'creates a TokenRequest automatically and sends it to Ably to obtain a token', webmock: true do token_request_stub = stub_request(:post, "#{client.endpoint}/keys/#{key_name}/requestToken"). to_return(status: 201, body: serialize({}, protocol), headers: { 'Content-Type' => content_type }) @@ -110,11 +110,11 @@ :body => serialize(token_response, protocol), :headers => { 'Content-Type' => content_type } ) end - before { auth.request_token token_params: token_params } + before { auth.request_token token_params } it "overrides default and uses camelCase notation for attributes" do expect(request_token_stub).to have_been_requested end end @@ -124,11 +124,11 @@ let(:key_name) { "app.#{random_str}" } let(:key_secret) { random_str } let(:nonce) { random_str } let(:auth_options) { { key: "#{key_name}:#{key_secret}" } } let(:token_params) { { nonce: nonce, timestamp: Time.now } } - let(:token_request) { auth.create_token_request(auth_options, token_params) } + let(:token_request) { auth.create_token_request(token_params, auth_options) } let(:mac) do hmac_for(token_request, key_secret) end let(:token_response) { {} } @@ -140,11 +140,11 @@ :status => 201, :body => serialize(token_response, protocol), :headers => { 'Content-Type' => content_type }) end - let!(:token) { auth.request_token(auth_options, token_params) } + let!(:token) { auth.request_token(token_params, auth_options) } specify 'key_name is used in request and signing uses key_secret' do expect(request_token_stub).to have_been_requested end end @@ -154,11 +154,11 @@ let(:key_secret) { random_str } let(:nonce) { random_str } let(:auth_options) { { key_name: key_name, key_secret: key_secret } } let(:token_params) { { nonce: nonce, timestamp: Time.now } } - let(:token_request) { auth.create_token_request(auth_options, token_params) } + let(:token_request) { auth.create_token_request(token_params, auth_options) } let(:mac) do hmac_for(token_request, key_secret) end let(:token_response) { {} } @@ -170,11 +170,11 @@ :status => 201, :body => serialize(token_response, protocol), :headers => { 'Content-Type' => content_type }) end - let!(:token) { auth.request_token(auth_options, token_params) } + let!(:token) { auth.request_token(token_params, auth_options) } specify 'key_name is used in request and signing uses key_secret' do expect(request_token_stub).to have_been_requested end end @@ -182,20 +182,20 @@ context 'with :query_time option' do let(:options) { { query_time: true } } it 'queries the server for the time' do expect(client).to receive(:time).and_call_original - auth.request_token(options) + auth.request_token({}, options) end end context 'without :query_time option' do let(:options) { { query_time: false } } it 'does not query the server for the time' do expect(client).to_not receive(:time) - auth.request_token(options) + auth.request_token({}, options) end end context 'with :auth_url option', :webmock do let(:auth_url) { 'https://www.fictitious.com/get_token' } @@ -235,11 +235,11 @@ :headers => { 'Content-Type' => content_type } ) end context 'when response from :auth_url is a valid token request' do - let!(:token) { auth.request_token(auth_options) } + let!(:token) { auth.request_token({}, auth_options) } it 'requests a token from :auth_url using an HTTP GET request' do expect(request_token_stub).to have_been_requested expect(auth_url_request_stub).to have_been_requested end @@ -288,11 +288,11 @@ 'expires' => expires.to_i * 1000, 'capability'=> capability_str }.to_json end - let!(:token_details) { auth.request_token(auth_options) } + let!(:token_details) { auth.request_token({}, auth_options) } it 'returns TokenDetails created from the token JSON' do expect(auth_url_request_stub).to have_been_requested expect(request_token_stub).to_not have_been_requested expect(token_details).to be_a(Ably::Models::TokenDetails) @@ -306,11 +306,11 @@ context 'when response from :auth_url is text/plain content type and a token string' do let(:token) { 'J_0Tlg.D7AVZkdOZW-PqNNGvCSp38' } let(:auth_url_content_type) { 'text/plain' } let(:auth_url_response) { token } - let!(:token_details) { auth.request_token(auth_options) } + let!(:token_details) { auth.request_token({}, auth_options) } it 'returns TokenDetails created from the token JSON' do expect(auth_url_request_stub).to have_been_requested expect(request_token_stub).to_not have_been_requested expect(token_details).to be_a(Ably::Models::TokenDetails) @@ -323,22 +323,22 @@ let!(:auth_url_request_stub) do stub_request(auth_method, auth_url).to_return(:status => 500) end it 'raises ServerError' do - expect { auth.request_token auth_options }.to raise_error(Ably::Exceptions::ServerError) + expect { auth.request_token({}, auth_options) }.to raise_error(Ably::Exceptions::ServerError) end end context 'XML' do let!(:auth_url_request_stub) do stub_request(auth_method, auth_url). to_return(:status => 201, :body => '<xml></xml>', :headers => { 'Content-Type' => 'application/xml' }) end it 'raises InvalidResponseBody' do - expect { auth.request_token auth_options }.to raise_error(Ably::Exceptions::InvalidResponseBody) + expect { auth.request_token({}, auth_options) }.to raise_error(Ably::Exceptions::InvalidResponseBody) end end end end @@ -348,16 +348,16 @@ let(:ttl) { 8888 } let(:auth_callback) do Proc.new do |token_params_arg| @block_called = true expect(token_params_arg).to eq(token_params) - auth.create_token_request(token_params: { client_id: client_id }) + auth.create_token_request(client_id: client_id) end end let(:token_params) { { ttl: ttl } } let!(:request_token) do - auth.request_token(auth_callback: auth_callback, token_params: token_params) + auth.request_token(token_params, auth_callback: auth_callback) end it 'calls the Proc with token_params when authenticating to obtain the request token' do expect(@block_called).to eql(true) end @@ -367,35 +367,35 @@ end end context 'that returns a TokenDetails JSON object' do let(:client_id) { random_str } - let(:options) { { client_id: client_id } } + let(:token_params){ { client_id: client_id } } let(:token) { 'J_0Tlg.D7AVZkdOZW-PqNNGvCSp38' } let(:issued) { Time.now } let(:expires) { Time.now + 60} let(:capability) { {'foo'=>['publish']} } let(:capability_str) { JSON.dump(capability) } let!(:token_details) do - auth.request_token(auth_callback: Proc.new do |token_params_arg| + auth.request_token(token_params, auth_callback: Proc.new do |token_params_arg| @block_called = true @block_params = token_params_arg { 'token' => token, 'keyName' => 'J_0Tlg.NxCRig', 'clientId' => client_id, 'issued' => issued.to_i * 1000, 'expires' => expires.to_i * 1000, 'capability'=> capability_str } - end, token_params: options) + end) end it 'calls the Proc when authenticating to obtain the request token' do expect(@block_called).to eql(true) - expect(@block_params).to include(options) + expect(@block_params).to include(token_params) end it 'uses the token request returned from the callback when requesting a new token' do expect(token_details).to be_a(Ably::Models::TokenDetails) expect(token_details.token).to eql(token) @@ -408,14 +408,12 @@ context 'that returns a TokenDetails object' do let(:client_id) { random_str } let!(:token_details) do - auth.request_token(auth_callback: Proc.new do |block_options| - auth.create_token_request(token_params: { - client_id: client_id - }) + auth.request_token({}, auth_callback: Proc.new do |block_options| + auth.create_token_request(client_id: client_id) end) end it 'uses the token request returned from the callback when requesting a new token' do expect(token_details).to be_a(Ably::Models::TokenDetails) @@ -426,11 +424,11 @@ context 'that returns a Token string' do let(:second_client) { Ably::Rest::Client.new(key: api_key, environment: environment, protocol: protocol) } let(:token) { second_client.auth.request_token.token } let!(:token_details) do - auth.request_token(auth_callback: Proc.new do |block_options| + auth.request_token({}, auth_callback: Proc.new do |block_options| token end) end it 'uses the token request returned from the callback when requesting a new token' do @@ -438,14 +436,13 @@ expect(token_details.token).to eql(token) end end end - context 'persisted option', api_private: true do + context 'persisted option of token params', api_private: true do context 'when set to true', api_private: true do - let(:options) { { persisted: true } } - let(:token_details) { auth.request_token(token_params: options) } + let(:token_details) { auth.request_token(persisted: true) } it 'returns a token with a short token ID that is used to look up the token details' do expect(token_details.token.length).to be < 64 expect(token_details.token).to match(/^#{app_id}\.A/) end @@ -460,20 +457,20 @@ end end context 'with auth_option :client_id' do let(:client_id) { random_str } - let(:token_details) { auth.request_token(client_id: client_id) } + let(:token_details) { auth.request_token({}, client_id: client_id) } it 'returns a token with the client_id' do expect(token_details.client_id).to eql(client_id) end end context 'with token_param :client_id' do let(:client_id) { random_str } - let(:token_details) { auth.request_token(token_params: { client_id: client_id }) } + let(:token_details) { auth.request_token(client_id: client_id) } it 'returns a token with the client_id' do expect(token_details.client_id).to eql(client_id) end end @@ -493,12 +490,12 @@ let(:token_params) do { ttl: 55 } end it 'passes all auth_options and token_params to #request_token' do - expect(auth).to receive(:request_token).with(auth_options, token_params) - auth.authorise auth_options, token_params + expect(auth).to receive(:request_token).with(token_params, auth_options) + auth.authorise token_params, auth_options end it 'returns a valid token' do expect(auth.authorise).to be_a(Ably::Models::TokenDetails) end @@ -524,24 +521,30 @@ expect(auth).to receive(:request_token) expect { auth.authorise }.to change { auth.current_token_details } end it 'issues a new token if option :force => true' do - expect { auth.authorise(force: true) }.to change { auth.current_token_details } + expect { auth.authorise({}, force: true) }.to change { auth.current_token_details } end end - it 'updates the persisted auth options that are then used for subsequent authorise requests' do - expect(auth.options[:ttl]).to_not eql(26) + it 'updates the persisted token params that are then used for subsequent authorise requests' do + expect(auth.token_params[:ttl]).to_not eql(26) auth.authorise(ttl: 26) - expect(auth.options[:ttl]).to eql(26) + expect(auth.token_params[:ttl]).to eql(26) end + it 'updates the persisted token params that are then used for subsequent authorise requests' do + expect(auth.options[:query_time]).to_not eql(true) + auth.authorise({}, query_time: true) + expect(auth.options[:query_time]).to eql(true) + end + context 'with a Proc for the :auth_callback option' do let(:client_id) { random_str } let!(:token) do - auth.authorise(auth_callback: Proc.new do + auth.authorise({}, auth_callback: Proc.new do @block_called ||= 0 @block_called += 1 auth.create_token_request(client_id: client_id) end) end @@ -562,25 +565,53 @@ end end context 'with a provided block' do it 'does not call the originally provided Proc and calls the new #request_token :auth_callback Proc' do - auth.request_token(auth_callback: Proc.new { @request_block_called = true; auth.create_token_request }) + auth.request_token({}, auth_callback: Proc.new { @request_block_called = true; auth.create_token_request }) expect(@block_called).to eql(1) expect(@request_block_called).to eql(true) end end end end + + context 'with an explicit token string that expires' do + context 'and a Proc for the :auth_callback option to provide a means to renew the token' do + before do + # Ensure a soon to expire token is not treated as expired + stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0 + old_token_defaults = Ably::Auth::TOKEN_DEFAULTS + stub_const 'Ably::Auth::TOKEN_DEFAULTS', old_token_defaults.merge(renew_token_buffer: 0) + end + + let(:token_client) { Ably::Rest::Client.new(default_options.merge(key: api_key, token_params: { ttl: 3 })) } + let(:client_options) { + default_options.merge(token: token_client.auth.request_token.token, auth_callback: Proc.new do + @block_called ||= 0 + @block_called += 1 + token_client.auth.create_token_request + end) + } + + it 'calls the Proc once the token has expired and the new token is used' do + client.stats + expect(@block_called).to be_nil + sleep 3.5 + expect { client.stats }.to change { client.auth.current_token_details } + expect(@block_called).to eql(1) + end + end + end end describe '#create_token_request' do let(:ttl) { 60 * 60 } let(:capability) { { "foo" => ["publish"] } } let(:token_params) { Hash.new } - subject { auth.create_token_request(token_params: token_params) } + subject { auth.create_token_request(token_params) } it 'returns a TokenRequest object' do expect(subject).to be_a(Ably::Models::TokenRequest) end @@ -664,24 +695,24 @@ context 'when required fields are missing' do let(:client) { Ably::Rest::Client.new(auth_url: 'http://example.com', protocol: protocol) } it 'should raise an exception if key secret is missing' do - expect { auth.create_token_request(key_name: 'name') }.to raise_error Ably::Exceptions::TokenRequestFailed + expect { auth.create_token_request({}, key_name: 'name') }.to raise_error Ably::Exceptions::TokenRequestFailed end it 'should raise an exception if key name is missing' do - expect { auth.create_token_request(key_secret: 'secret') }.to raise_error Ably::Exceptions::TokenRequestFailed + expect { auth.create_token_request({}, key_secret: 'secret') }.to raise_error Ably::Exceptions::TokenRequestFailed end end context 'timestamp attribute' do context 'with :query_time auth_option' do let(:time) { Time.now - 30 } let(:auth_options) { { query_time: true } } - subject { auth.create_token_request(auth_options) } + subject { auth.create_token_request({}, auth_options) } it 'queries the server for the timestamp' do expect(client).to receive(:time).and_return(time) expect(subject['timestamp']).to be_within(1).of(time.to_f * 1000) end @@ -731,14 +762,14 @@ let(:capability) { { :foo => ["publish"] } } describe 'with :token option' do let(:ttl) { 60 * 60 } let(:token_details) do - auth.request_token(token_params: { + auth.request_token( ttl: ttl, capability: capability - }) + ) end let(:token) { token_details.token } let(:token_auth_client) do Ably::Rest::Client.new(token: token, environment: environment, protocol: protocol) end @@ -754,10 +785,10 @@ expect(error.code).to eql(40160) end end it 'fails if timestamp is invalid' do - expect { auth.request_token(token_params: { timestamp: Time.now - 180 }) }.to raise_error do |error| + expect { auth.request_token(timestamp: Time.now - 180) }.to raise_error do |error| expect(error).to be_a(Ably::Exceptions::InvalidRequest) expect(error.status).to eql(401) expect(error.code).to eql(40101) end end