Sean Cribbs avatar Sean Cribbs committed 3423ddf

Control the mock server via DRb so it is less deadlock-prone.

Comments (0)

Files changed (5)

riak-client/lib/riak/client/curb_backend.rb

 module Riak
   class Client
     # An HTTP backend for Riak::Client that uses the 'curb' library/gem.
-    # If the 'curb' library is present, this backend will be preferred to
-    # the backend based on Net::HTTP.
     # Conforms to the Riak::Client::HTTPBackend interface.
     class CurbBackend < HTTPBackend
       def self.configured?
           end
         end
       end
-
-      def response_headers
-        Thread.current[:response_headers] ||= Riak::Util::Headers.new
-      end
-
-      def create_request_headers(hash)
-        h = Riak::Util::Headers.new
-        hash.each {|k,v| h.add_field(k,v) }
-        [].tap do |arr|
-          h.each_capitalized do |k,v|
-            arr << "#{k}: #{v}"
-          end
-        end
-      end
     end
   end
 end

riak-client/lib/riak/client/http_backend.rb

         resource = Array(resource).flatten
         raise ArgumentError, t("resource_path_short") unless resource.length > 1 || resource.include?(@client.mapred)
       end
-      
+
       # Checks the expected response codes against the actual response code. Use internally when
       # implementing {#perform}.
       # @param [String, Fixnum, Array<String,Fixnum>] expected the expected response code(s)
       def return_body?(method, code, has_block)
         method != :head && !valid_response?([204,205,304], code) && !has_block
       end
-      
+
       # Executes requests according to the underlying HTTP client library semantics.
       # @abstract Subclasses must implement this internal method to perform HTTP requests
       #           according to the API of their HTTP libraries.
       def perform(method, uri, headers, expect, body=nil)
         raise NotImplementedError
       end
+
+      private
+      def create_request_headers(hash)
+        h = Riak::Util::Headers.new
+        hash.each {|k,v| h.add_field(k,v) }
+        [].tap do |arr|
+          h.each_capitalized do |k,v|
+            arr << "#{k}: #{v}"
+          end
+        end
+      end
+
+      def response_headers
+        Thread.current[:response_headers] ||= Riak::Util::Headers.new
+      end
     end
   end
 end

riak-client/spec/riak/curb_backend_spec.rb

 rescue LoadError
   warn "Skipping CurbBackend specs, curb library not found."
 else
-  $server = MockServer.new
-  at_exit { $server.stop }
+  $mock_server = DrbMockServer
+  $mock_server.maybe_start
 
   describe Riak::Client::CurbBackend do
     def setup_http_mock(method, uri, options={})
       body = options[:body] || []
       headers = options[:headers] || {}
       headers['Content-Type'] ||= "text/plain"
-      $server.attach do |env|
-        env["REQUEST_METHOD"].should == method
-        env["PATH_INFO"].should == path
-        env["QUERY_STRING"].should == query
-        [status, headers, Array(body)]
-      end
+      @_mock_set = [status, headers, method, path, query, body]
+      $mock_server.expect(*@_mock_set)
     end
 
     before :each do
-      @client = Riak::Client.new(:port => $server.port) # Point to our mock
-      @backend = Riak::Client::CurbBackend.new(@client)
+      @client = Riak::Client.new(:port => $mock_server.port, :http_backend => :Curb) # Point to our mock
+      @backend = @client.http
+      @_mock_set = false
+    end
+
+    after :each do
+      if @_mock_set
+        $mock_server.satisfied.should be_true("Expected #{@_mock_set.inspect}, failed")
+      end
+      Thread.current[:curl_easy_handle] = nil
     end
 
     it_should_behave_like "HTTP backend"
         @backend.post(200, "/riak/", "foo", file, {})
       end.should_not raise_error
     end
-
-    after :each do
-      $server.detach
-      Thread.current[:curl_easy_handle] = nil
-    end
   end
 end

riak-client/spec/support/drb_mock_server.rb

+require 'drb/drb'
+DRBURI="druby://localhost:8787"
+
+module DrbMockServer
+  extend self
+  def start_server
+    server = MockServer.new
+    DRb.start_service(DRBURI, server)
+    Signal.trap("HUP") { server.stop; exit }
+    DRb.thread.join
+  end
+
+  def start_client
+    child_pid = fork do
+      start_server
+    end
+    sleep 1
+    at_exit { Process.kill("HUP", child_pid); Process.wait2 }
+    DRb.start_service
+    @server = DRbObject.new_with_uri(DRBURI)
+    true
+  end
+
+  def maybe_start
+    start_client unless @server
+  end
+
+  def method_missing(meth, *args, &block)
+    @server.send(meth, *args, &block)
+  end
+end

riak-client/spec/support/mock_server.rb

+# -*- coding: utf-8 -*-
 # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License");
 
 class MockServer
   attr_accessor :port
-  
+  attr_accessor :satisfied
+
   def initialize(pause = 1)
     self.port = 4000 + rand(61535)
     @block = nil
     Thread.kill(@thread)
   end
 
+  def expect(status, headers, method, path, query, body)
+    attach do |env|
+      @satisfied = (env["REQUEST_METHOD"] == method &&
+                    env["PATH_INFO"] == path &&
+                    env["QUERY_STRING"] == query)
+      [status, headers, Array(body)]
+    end
+  end
+
   def attach(&block)
     @block = block
   end
       raise "Specify a handler for the request using attach(block), the block should return a valid rack response and can test expectations" unless @block
       @block.call(env)
     rescue Exception => e
-      @parent_thread.raise e
-      [ 500, { 'Content-Type' => 'text/plain', 'Content-Length' => '13' }, [ 'Bad test code' ]]
+      @satisfied = false
+      # @parent_thread.raise e
+      body = "Bad test code\n#{e.inspect}\n#{e.backtrace}"
+      [ 500, { 'Content-Type' => 'text/plain', 'Content-Length' => body.length.to_s }, [ body ]]
     end
   end
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.