Skip to content

Commit

Permalink
Merge branch 'master' into 2i-test-backend
Browse files Browse the repository at this point in the history
  • Loading branch information
seancribbs committed Apr 12, 2012
2 parents 7ee184a + 5cd7751 commit 799d00b
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 37 deletions.
47 changes: 40 additions & 7 deletions lib/riak/client/excon_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ def self.configured?
begin
require 'excon'
Client::NETWORK_ERRORS << Excon::Errors::SocketError
Client::NETWORK_ERRORS << Excon::Errors::TimeoutError if defined? Excon::Errors::TimeoutError
Client::NETWORK_ERRORS.uniq!
Gem::Version.new(Excon::VERSION) >= Gem::Version.new("0.5.7") && patch_excon
minimum_version?("0.5.7") && handle_deprecations && patch_excon
rescue LoadError
false
end
Expand All @@ -34,6 +35,43 @@ def sockets
@@patched = true
end

# Defines instance methods that handle changes in the Excon API
# across different versions.
def self.handle_deprecations
# Define #make_request
if minimum_version?("0.10.2")
def make_request(params, block)
params[:response_block] = block if block
connection.request(params)
end
else
def make_request(params, block)
response = connection.request(params, &block)
end
end

# Define #configure_ssl
if minimum_version?("0.9.6")
def configure_ssl
Excon.defaults[:ssl_verify_peer] = (@node.ssl_options[:verify_mode].to_s === "peer")
Excon.defaults[:ssl_ca_path] = @node.ssl_options[:ca_path] if @node.ssl_options[:ca_path]
end
else
def configure_ssl
Excon.ssl_verify_peer = (@node.ssl_options[:verify_mode].to_s === "peer")
Excon.ssl_ca_path = @node.ssl_options[:ca_path] if @node.ssl_options[:ca_path]
end
end
private :make_request, :configure_ssl
end

# Returns true if the Excon library is at least the given
# version. This is used inside the backend to check how to
# provide certain request and configuration options.
def self.minimum_version?(version)
Gem::Version.new(Excon::VERSION) >= Gem::Version.new(version)
end

def teardown
connection.reset
end
Expand All @@ -54,7 +92,7 @@ def perform(method, uri, headers, expect, data=nil, &block)
# Later versions of Excon pass multiple arguments to the block
block = lambda {|*args| yield args.first } if block_given?

response = connection.request(params, &block)
response = make_request(params, block)
response_headers.initialize_http_header(response.headers)

if valid_response?(expect, response.status)
Expand All @@ -71,11 +109,6 @@ def perform(method, uri, headers, expect, data=nil, &block)
def connection
@connection ||= Excon::Connection.new(root_uri.to_s)
end

def configure_ssl
Excon.ssl_verify_peer = @node.ssl_options[:verify_mode].to_s === "peer"
Excon.ssl_ca_path = @node.ssl_options[:ca_path] if @node.ssl_options[:ca_path]
end
end
end
end
5 changes: 2 additions & 3 deletions lib/riak/client/net_http_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ def perform(method, uri, headers, expect, data=nil) #:nodoc:
configure_ssl(http) if @node.ssl_enabled?

request = Net::HTTP.const_get(method.to_s.capitalize).new(uri.request_uri, headers)
case data
when String
if String === data
request.body = data
when data.respond_to?(:read)
elsif data.respond_to?(:read)
case
when data.respond_to?(:stat) # IO#stat
request.content_length = data.stat.size
Expand Down
22 changes: 12 additions & 10 deletions lib/riak/robject.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,17 @@ def self.load_from_mapreduce(client, response)
def initialize(bucket, key=nil)
@bucket, @key = bucket, key
@links, @meta = Set.new, {}
@indexes = Hash.new {|h,k| h[k] = Set.new }
@indexes = new_index_hash
yield self if block_given?
end

def indexes=(hash)
@indexes = hash.inject(new_index_hash) do |h, (k,v)|
h[k].merge([*v])
h
end
end

# Load object data from a map/reduce response item.
# This method is used by RObject::load_from_mapreduce to instantiate the necessary
# objects.
Expand Down Expand Up @@ -270,15 +277,6 @@ def to_link(tag)
Link.new(@bucket.name, @key, tag)
end

# Generates a URL representing the object according to the client, bucket and key.
# If the key is blank, the bucket URL will be returned (where the object will be
# submitted to when stored).
def url
segments = [ @bucket.client.http_paths[:prefix], escape(@bucket.name)]
segments << escape(@key) if @key
@bucket.client.http.path(*segments).to_s
end

alias :vector_clock :vclock
alias :vector_clock= :vclock=

Expand Down Expand Up @@ -312,5 +310,9 @@ def extract_if_present(hash, key, attribute=nil)
send("#{attribute}=", value)
end
end

def new_index_hash
Hash.new {|h,k| h[k] = Set.new }
end
end
end
2 changes: 1 addition & 1 deletion riak-client.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
gem.add_development_dependency "rspec", "~>2.8.0"
gem.add_development_dependency "fakeweb", ">=1.2"
gem.add_development_dependency "rack", ">=1.0"
gem.add_development_dependency "excon", "~>0.6.1"
gem.add_development_dependency "excon", ">=0.6.1"
gem.add_development_dependency 'rake'
gem.add_runtime_dependency "i18n", ">=0.4.0"
gem.add_runtime_dependency "builder", ">= 2.1.2"
Expand Down
51 changes: 51 additions & 0 deletions spec/integration/riak/http_backends_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,57 @@
end

it_should_behave_like "Unified backend API"

describe "using Luwak", :version => "0.14.0".."1.0.3" do
let(:file) { File.open(__FILE__) }
let(:key) { "spec.rb" }
let(:string) { file.read }

def retry_400
begin
yield
rescue Riak::HTTPFailedRequest => e
# Riak 1.0.x (and possibly earlier) has a bug in
# mochiweb that will sometimes leave dangling 400
# responses on the wire between requests when the
# connection is left open. This will happen sometimes
# immediately after a store_file request.
if e.code == 400
retry
else
raise
end
end
end

it "should store an IO with a given key" do
@backend.store_file(key, 'text/plain', file)
stored_file = retry_400 { @backend.get_file(key) }
stored_file.content_type.should == 'text/plain'
stored_file.size.should == file.size
end

it "should store a String with a given key" do
@backend.store_file(key, 'text/plain', string)
stored_file = retry_400 { @backend.get_file(key) }
stored_file.content_type.should == 'text/plain'
stored_file.size.should == string.bytesize
end

it "should store an IO with a server-defined key" do
key = @backend.store_file('text/plain', file)
stored_file = retry_400 { @backend.get_file(key) }
stored_file.content_type.should == 'text/plain'
stored_file.size.should == file.size
end

it "should store a String with a server-defined key" do
key = @backend.store_file('text/plain', string)
stored_file = retry_400 { @backend.get_file(key) }
stored_file.content_type.should == 'text/plain'
stored_file.size.should == string.bytesize
end
end
end
end
end
Expand Down
31 changes: 18 additions & 13 deletions spec/riak/excon_backend_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,24 @@ def setup_http_mock(method, uri, options={})
end.should_not raise_error
end

it "should support IO objects as the request body" do
file = File.open(File.expand_path("../../fixtures/cat.jpg", __FILE__), 'rb')
lambda do
setup_http_mock(:put, @backend.path("/riak/","foo").to_s, :body => "ok")
@backend.put(200, @backend.path("/riak/","foo"), file)
$mock_server.satisfied.should be_true
end.should_not raise_error
file.rewind # Have to rewind the file or we hang
lambda do
setup_http_mock(:post, @backend.path("/riak/","foo").to_s, :body => "ok")
@backend.post(200, @backend.path("/riak/", "foo"), file)
$mock_server.satisfied.should be_true
end.should_not raise_error
it "should support IO objects as the request body on PUT" do
File.open(File.expand_path("../../fixtures/cat.jpg", __FILE__), 'rb') do |file|
lambda do
setup_http_mock(:put, @backend.path("/riak/","foo").to_s, :body => "ok")
@backend.put(200, @backend.path("/riak/","foo"), file)
$mock_server.satisfied.should be_true
end.should_not raise_error
end
end

it "should support IO objects as the request body on POST" do
File.open(File.expand_path("../../fixtures/cat.jpg", __FILE__), 'rb') do |file|
lambda do
setup_http_mock(:post, @backend.path("/riak/","foo").to_s, :body => "ok")
@backend.post(200, @backend.path("/riak/", "foo"), file)
$mock_server.satisfied.should be_true
end.should_not raise_error
end
end

context "checking the Excon Gem version" do
Expand Down
8 changes: 8 additions & 0 deletions spec/riak/robject_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@
@object.links.length.should == 1
end

it "should allow mass-overwriting indexes while preserving default behavior" do
@object = described_class.new(@bucket, 'foo')
@object.indexes = {"ts_int" => [12345], "foo_bin" => "bar"}
@object.indexes['ts_int'].should == Set.new([12345])
@object.indexes['foo_bin'].should == Set.new(["bar"])
@object.indexes['unset_bin'].should == Set.new
end

describe "when storing the object normally" do
before :each do
@backend = mock("Backend")
Expand Down
7 changes: 7 additions & 0 deletions spec/support/unified_backend_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@
end
end

it "should store an object with indexes", :version => "1.0.0" do
@robject.indexes['foo_bin'] << 'bar'
@backend.store_object(@robject, :returnbody => true)
@robject.indexes.should include('foo_bin')
@robject.indexes['foo_bin'].should include('bar')
end

after do
expect { @backend.fetch_object("test", "store") }.should_not raise_error(Riak::FailedRequest)
end
Expand Down
9 changes: 6 additions & 3 deletions spec/support/version_filter.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
require 'rubygems'

RSpec.configure do |config|
config.before(:each, :integration => true,
:version => lambda {|v| !!v },
:test_server => lambda {|ts| ts != false }) do
required = example.metadata[:version]
actual = test_server.version
actual = Gem::Version.new(test_server.version)
case required
when String
pending("SKIP: Tests feature for Riak #{required}, but testing against #{actual}") if actual < required
required = Gem::Requirement.create(">= #{required}")
when Range
pending("SKIP: Tests feature for Riak versions #{required.begin} through #{required.end}, but testing against #{actual}") unless required.include?(actual)
required = Gem::Requirement.create([">= #{required.begin}", "<= #{required.end}"])
end
pending("SKIP: Tests feature for Riak #{required.to_s}, but testing against #{actual.to_s}") unless required.satisfied_by?(actual)
end
end

0 comments on commit 799d00b

Please sign in to comment.