From 7ac6ed893fbfe9b4d4ce0e0ef18c3fecfbd48ff4 Mon Sep 17 00:00:00 2001 From: Rick Olson Date: Fri, 29 Sep 2006 16:25:49 +0000 Subject: Add Basic HTTP Authentication to ActiveResource (closes #6305). [jonathan] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5208 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activeresource/test/authorization_test.rb | 82 +++++++++++++++++++++++++++++++ activeresource/test/base_errors_test.rb | 2 +- activeresource/test/base_test.rb | 46 ++++++++--------- activeresource/test/connection_test.rb | 40 +++++++++++++++ activeresource/test/http_mock.rb | 33 +++++++++---- 5 files changed, 170 insertions(+), 33 deletions(-) create mode 100644 activeresource/test/authorization_test.rb (limited to 'activeresource/test') diff --git a/activeresource/test/authorization_test.rb b/activeresource/test/authorization_test.rb new file mode 100644 index 0000000000..bfe51ce1e3 --- /dev/null +++ b/activeresource/test/authorization_test.rb @@ -0,0 +1,82 @@ +require "#{File.dirname(__FILE__)}/abstract_unit" +require 'base64' + +class AuthorizationTest < Test::Unit::TestCase + Response = Struct.new(:code) + + def setup + @conn = ActiveResource::Connection.new('http://localhost') + @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person') + @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person') + @authenticated_conn = ActiveResource::Connection.new("http://david:test123@localhost") + @authorization_request_header = { 'Authorization' => 'Basic ZGF2aWQ6dGVzdDEyMw==' } + + ActiveResource::HttpMock.respond_to do |mock| + mock.get "/people/2.xml", @authorization_request_header, @david + mock.put "/people/2.xml", @authorization_request_header, nil, 204 + mock.delete "/people/2.xml", @authorization_request_header, nil, 200 + mock.post "/people/2/addresses.xml", @authorization_request_header, nil, 201, 'Location' => '/people/1/addresses/5' + end + end + + def test_authorization_header + authorization_header = @authenticated_conn.send(:authorization_header) + assert_equal @authorization_request_header['Authorization'], authorization_header['Authorization'] + authorization = authorization_header["Authorization"].to_s.split + + assert_equal "Basic", authorization[0] + assert_equal ["david", "test123"], Base64.decode64(authorization[1]).split(":")[0..1] + end + + def test_authorization_header_with_username_but_no_password + @conn = ActiveResource::Connection.new("http://david:@localhost") + authorization_header = @conn.send(:authorization_header) + authorization = authorization_header["Authorization"].to_s.split + + assert_equal "Basic", authorization[0] + assert_equal ["david"], Base64.decode64(authorization[1]).split(":")[0..1] + end + + def test_authorization_header_with_password_but_no_username + @conn = ActiveResource::Connection.new("http://:test123@localhost") + authorization_header = @conn.send(:authorization_header) + authorization = authorization_header["Authorization"].to_s.split + + assert_equal "Basic", authorization[0] + assert_equal ["", "test123"], Base64.decode64(authorization[1]).split(":")[0..1] + end + + def test_get + david = @authenticated_conn.get("/people/2.xml") + assert_equal "David", david["person"]["name"] + end + + def test_post + response = @authenticated_conn.post("/people/2/addresses.xml") + assert_equal "/people/1/addresses/5", response["Location"] + end + + def test_put + response = @authenticated_conn.put("/people/2.xml") + assert_equal 204, response.code + end + + def test_delete + response = @authenticated_conn.delete("/people/2.xml") + assert_equal 200, response.code + end + + def test_raises_invalid_request_on_unauthorized_requests + assert_raises(ActiveResource::InvalidRequestError) { @conn.post("/people/2.xml") } + assert_raises(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.xml") } + assert_raises(ActiveResource::InvalidRequestError) { @conn.put("/people/2.xml") } + assert_raises(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.xml") } + end + + protected + def assert_response_raises(klass, code) + assert_raise(klass, "Expected response code #{code} to raise #{klass}") do + @conn.send(:handle_response, Response.new(code)) + end + end +end diff --git a/activeresource/test/base_errors_test.rb b/activeresource/test/base_errors_test.rb index 5125adf218..1aa677b1ba 100644 --- a/activeresource/test/base_errors_test.rb +++ b/activeresource/test/base_errors_test.rb @@ -4,7 +4,7 @@ require "fixtures/person" class BaseErrorsTest < Test::Unit::TestCase def setup ActiveResource::HttpMock.respond_to do |mock| - mock.post "/people.xml", "Age can't be blankName can't be blankName must start with a letterPerson quota full for today.", 400 + mock.post "/people.xml", {}, "Age can't be blankName can't be blankName must start with a letterPerson quota full for today.", 400 end @exception = nil @person = Person.new(:name => '', :age => '') diff --git a/activeresource/test/base_test.rb b/activeresource/test/base_test.rb index 2a3091ecba..f3fd3b43e2 100644 --- a/activeresource/test/base_test.rb +++ b/activeresource/test/base_test.rb @@ -7,25 +7,27 @@ class BaseTest < Test::Unit::TestCase @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person') @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person') @addy = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address') + @default_request_headers = { 'Content-Type' => 'application/xml' } + ActiveResource::HttpMock.respond_to do |mock| - mock.get "/people/1.xml", @matz - mock.get "/people/2.xml", @david - mock.put "/people/1.xml", nil, 204 - mock.delete "/people/1.xml", nil, 200 - mock.delete "/people/2.xml", nil, 400 - mock.post "/people.xml", nil, 201, 'Location' => '/people/5.xml' - mock.get "/people/99.xml", nil, 404 - mock.get "/people.xml", "#{@matz}#{@david}" - mock.get "/people/1/addresses.xml", "#{@addy}" - mock.get "/people/1/addresses/1.xml", @addy - mock.put "/people/1/addresses/1.xml", nil, 204 - mock.delete "/people/1/addresses/1.xml", nil, 200 - mock.post "/people/1/addresses.xml", nil, 201, 'Location' => '/people/1/addresses/5' - mock.get "/people//addresses.xml", nil, 404 - mock.get "/people//addresses/1.xml", nil, 404 - mock.put "/people//addresses/1.xml", nil, 404 - mock.delete "/people//addresses/1.xml", nil, 404 - mock.post "/people//addresses.xml", nil, 404 + mock.get "/people/1.xml", {}, @matz + mock.get "/people/2.xml", {}, @david + mock.put "/people/1.xml", {}, nil, 204 + mock.delete "/people/1.xml", {}, nil, 200 + mock.delete "/people/2.xml", {}, nil, 400 + mock.post "/people.xml", {}, nil, 201, 'Location' => '/people/5.xml' + mock.get "/people/99.xml", {}, nil, 404 + mock.get "/people.xml", {}, "#{@matz}#{@david}" + mock.get "/people/1/addresses.xml", {}, "#{@addy}" + mock.get "/people/1/addresses/1.xml", {}, @addy + mock.put "/people/1/addresses/1.xml", {}, nil, 204 + mock.delete "/people/1/addresses/1.xml", {}, nil, 200 + mock.post "/people/1/addresses.xml", {}, nil, 201, 'Location' => '/people/1/addresses/5' + mock.get "/people//addresses.xml", {}, nil, 404 + mock.get "/people//addresses/1.xml", {}, nil, 404 + mock.put "/people//addresses/1.xml", {}, nil, 404 + mock.delete "/people//addresses/1.xml", {}, nil, 404 + mock.post "/people//addresses.xml", {}, nil, 404 end end @@ -144,8 +146,8 @@ class BaseTest < Test::Unit::TestCase def test_update_conflict ActiveResource::HttpMock.respond_to do |mock| - mock.get "/people/2.xml", @david - mock.put "/people/2.xml", nil, 409 + mock.get "/people/2.xml", {}, @david + mock.put "/people/2.xml", @default_request_headers, nil, 409 end assert_raises(ActiveResource::ResourceConflict) { Person.find(2).save } end @@ -153,7 +155,7 @@ class BaseTest < Test::Unit::TestCase def test_destroy assert Person.find(1).destroy ActiveResource::HttpMock.respond_to do |mock| - mock.get "/people/1.xml", nil, 404 + mock.get "/people/1.xml", {}, nil, 404 end assert_raises(ActiveResource::ResourceNotFound) { Person.find(1).destroy } end @@ -161,7 +163,7 @@ class BaseTest < Test::Unit::TestCase def test_destroy_with_custom_prefix assert StreetAddress.find(1, :person_id => 1).destroy ActiveResource::HttpMock.respond_to do |mock| - mock.get "/people/1/addresses/1.xml", nil, 404 + mock.get "/people/1/addresses/1.xml", {}, nil, 404 end assert_raises(ActiveResource::ResourceNotFound) { StreetAddress.find(1, :person_id => 1).destroy } end diff --git a/activeresource/test/connection_test.rb b/activeresource/test/connection_test.rb index 0744e327e6..efde099c90 100644 --- a/activeresource/test/connection_test.rb +++ b/activeresource/test/connection_test.rb @@ -1,10 +1,20 @@ require "#{File.dirname(__FILE__)}/abstract_unit" +require 'base64' class ConnectionTest < Test::Unit::TestCase Response = Struct.new(:code) def setup @conn = ActiveResource::Connection.new('http://localhost') + @matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person') + @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person') + @default_request_headers = { 'Content-Type' => 'application/xml' } + ActiveResource::HttpMock.respond_to do |mock| + mock.get "/people/1.xml", {}, @matz + mock.put "/people/1.xml", {}, nil, 204 + mock.delete "/people/1.xml", {}, nil, 200 + mock.post "/people.xml", {}, nil, 201, 'Location' => '/people/5.xml' + end end def test_handle_response @@ -38,7 +48,37 @@ class ConnectionTest < Test::Unit::TestCase assert_response_raises ActiveResource::ConnectionError, code end end + + def test_site_accessor_accepts_uri_or_string_argument + site = URI.parse("http://localhost") + + assert_nothing_raised { @conn.site = "http://localhost" } + assert_equal site, @conn.site + assert_nothing_raised { @conn.site = site } + assert_equal site, @conn.site + end + + def test_get + matz = @conn.get("/people/1.xml") + assert_equal "Matz", matz["person"]["name"] + end + + def test_post + response = @conn.post("/people.xml") + assert_equal "/people/5.xml", response["Location"] + end + + def test_put + response = @conn.put("/people/1.xml") + assert_equal 204, response.code + end + + def test_delete + response = @conn.delete("/people/1.xml") + assert_equal 200, response.code + end + protected def assert_response_raises(klass, code) assert_raise(klass, "Expected response code #{code} to raise #{klass}") do diff --git a/activeresource/test/http_mock.rb b/activeresource/test/http_mock.rb index 40921f6b6b..66351501d9 100644 --- a/activeresource/test/http_mock.rb +++ b/activeresource/test/http_mock.rb @@ -1,6 +1,8 @@ require 'active_resource/connection' module ActiveResource + class InvalidRequestError < StandardError; end + class HttpMock class Responder def initialize(responses) @@ -9,8 +11,8 @@ module ActiveResource for method in [ :post, :put, :get, :delete ] module_eval <<-EOE - def #{method}(path, body = nil, status = 200, headers = {}) - @responses[Request.new(:#{method}, path, nil)] = Response.new(body || {}, status, headers) + def #{method}(path, request_headers = {}, body = nil, status = 200, response_headers = {}) + @responses[Request.new(:#{method}, path, nil, request_headers)] = Response.new(body || {}, status, response_headers) end EOE end @@ -39,12 +41,22 @@ module ActiveResource end end - for method in [ :post, :put, :get, :delete ] + for method in [ :post, :put ] + module_eval <<-EOE + def #{method}(path, body, headers) + request = ActiveResource::Request.new(:#{method}, path, body, headers) + self.class.requests << request + self.class.responses[request] || raise(InvalidRequestError.new("No response recorded for: \#{request}")) + end + EOE + end + + for method in [ :get, :delete ] module_eval <<-EOE - def #{method}(*arguments) - request = ActiveResource::Request.new(:#{method}, *arguments) + def #{method}(path, headers) + request = ActiveResource::Request.new(:#{method}, path, nil, headers) self.class.requests << request - self.class.responses[request] || raise("No response recorded for: \#{request}") + self.class.responses[request] || raise(InvalidRequestError.new("No response recorded for: \#{request}")) end EOE end @@ -55,10 +67,11 @@ module ActiveResource end class Request - attr_accessor :path, :method, :body + attr_accessor :path, :method, :body, :headers def initialize(method, path, body = nil, headers = nil) - @method, @path, @body = method, path, body + @method, @path, @body, @headers = method, path, body, headers + @headers.update('Content-Type' => 'application/xml') end def ==(other_request) @@ -70,11 +83,11 @@ module ActiveResource end def to_s - "<#{method.to_s.upcase}: #{path} (#{body})>" + "<#{method.to_s.upcase}: #{path} [#{headers}] (#{body})>" end def hash - "#{path}#{method}".hash + "#{path}#{method}#{headers}".hash end end -- cgit v1.2.3