Commits

Michael Granger  committed 070611c

Convert specs to new RSpec 'expect' syntax.

  • Participants
  • Parent commits d55e679

Comments (0)

Files changed (31)

File Manifest.txt

 lib/mongrel2/testing.rb
 lib/mongrel2/websocket.rb
 lib/mongrel2/xmlrequest.rb
-spec/lib/constants.rb
-spec/lib/helpers.rb
-spec/lib/matchers.rb
+spec/constants.rb
+spec/helpers.rb
+spec/matchers.rb
 spec/mongrel2/config/directory_spec.rb
 spec/mongrel2/config/dsl_spec.rb
 spec/mongrel2/config/filter_spec.rb

File spec/constants.rb

+#!/usr/bin/env ruby
+
+require 'uri'
+
+require 'mongrel2' unless defined?( Mongrel2 )
+
+
+### A collection of constants used in testing
+module Mongrel2::TestConstants # :nodoc:all
+
+	include Mongrel2::Constants,
+	        Mongrel2::WebSocket::Constants
+
+	unless defined?( TEST_HOST )
+
+		TEST_HOST = 'localhost'
+		TEST_PORT = 8118
+
+		# Rule 2: Every message to and from Mongrel2 has that Mongrel2 instances
+		#   UUID as the very first thing.
+		TEST_UUID = 'BD17D85C-4730-4BF2-999D-9D2B2E0FCCF9'
+
+		# 0mq socket specifications for Handlers
+		TEST_SEND_SPEC = 'tcp://127.0.0.1:9998'
+		TEST_RECV_SPEC = 'tcp://127.0.0.1:9997'
+
+		# Rule 3: Mongrel2 sends requests with one number right after the
+		#   servers UUID separated by a space. Handlers return a netstring with
+		#   a list of numbers separated by spaces. The numbers indicate the
+		#   connected browser the message is to/from.
+		TEST_ID = 8
+
+		#
+		# HTTP request constants
+		#
+
+		TEST_ROUTE = '/handler'
+		TEST_PATH  = TEST_ROUTE
+		TEST_QUERY = 'thing=foom'
+
+		TEST_HEADERS = {
+			"x-forwarded-for" => "127.0.0.1",
+			"accept-language" => "en-US,en;q=0.8",
+			"accept-encoding" => "gzip,deflate,sdch",
+			"connection"      => "keep-alive",
+			"accept-charset"  => "UTF-8,*;q=0.5",
+			"accept"          => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
+			"user-agent"      => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) " +
+			                     "AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 " +
+			                     "Safari/535.1",
+			"host"            => "localhost:3667",
+			"METHOD"          => "GET",
+			"VERSION"         => "HTTP/1.1",
+		}
+
+		TEST_BODY = ''
+
+		TEST_REQUEST_OPTS = {
+			:uuid    => TEST_UUID,
+			:id      => TEST_ID,
+			:path    => TEST_PATH,
+			:body    => TEST_BODY,
+		}
+
+
+		#
+		# JSON (JSSocket, etc.) request constants
+		#
+
+		TEST_JSON_PATH = '@directory'
+
+		TEST_JSON_HEADERS = {
+			'PATH'            => TEST_JSON_PATH,
+			'x-forwarded-for' => "127.0.0.1",
+			'METHOD'          => "JSON",
+			'PATTERN'         => TEST_JSON_PATH,
+		}
+		TEST_JSON_BODY = { 'type' => 'msg', 'msg' => 'connect' }
+
+		TEST_JSON_REQUEST_OPTS = {
+			:uuid    => TEST_UUID,
+			:id      => TEST_ID,
+			:path    => TEST_JSON_PATH,
+			:body    => TEST_JSON_BODY,
+		}
+
+
+		#
+		# XML message request constants
+		#
+
+		TEST_XML_PATH = '<directory'
+
+		TEST_XML_HEADERS = {
+			'PATH'            => TEST_XML_PATH,
+			'x-forwarded-for' => "127.0.0.1",
+			'METHOD'          => "XML",
+			'PATTERN'         => TEST_XML_PATH,
+		}
+		TEST_XML_BODY = '<directory><file name="foom.txt" /><file name="foom2.md" /></directory>'
+
+		TEST_XML_REQUEST_OPTS = {
+			:uuid    => TEST_UUID,
+			:id      => TEST_ID,
+			:path    => TEST_XML_PATH,
+			:body    => TEST_XML_BODY,
+		}
+
+
+		#
+		# WebSocket frame constants
+		#
+
+		TEST_WEBSOCKET_PATH = '/ws'
+
+		TEST_WEBSOCKET_HEADERS = {
+			 'connection'               => 'Upgrade',
+			 'FLAGS'                    => '0x8A',
+			 'host'                     => 'host.example.com:80',
+			 'METHOD'                   => 'WEBSOCKET',
+			 'origin'                   => 'http://host.example.com:80',
+			 'PATH'                     => TEST_WEBSOCKET_PATH,
+			 'PATTERN'                  => TEST_WEBSOCKET_PATH,
+			 'sec-websocket-extensions' => 'x-webkit-deflate-frame',
+			 'sec-websocket-key'        => 'SQvDVdT2SbgTg6P/lSZo7Q==',
+			 'sec-websocket-protocol'   => 'echo',
+			 'sec-websocket-version'    => '13',
+			 'upgrade'                  => 'websocket',
+			 'URI'                      => TEST_WEBSOCKET_PATH,
+			 'VERSION'                  => 'HTTP/1.1',
+			 'x-forwarded-for'          => '127.0.0.2',
+		}
+		TEST_WEBSOCKET_HANDSHAKE_HEADERS = {
+			'connection'               => 'Upgrade',
+			'host'                     => 'host.example.com:80',
+			'METHOD'                   => 'WEBSOCKET_HANDSHAKE',
+			'origin'                   => 'http://host.example.com:80',
+			'PATH'                     => TEST_WEBSOCKET_PATH,
+			'PATTERN'                  => TEST_WEBSOCKET_PATH,
+			'sec-websocket-extensions' => 'x-webkit-deflate-frame',
+			'sec-websocket-key'        => 'SQvDVdT2SbgTg6P/lSZo7Q==',
+			'sec-websocket-protocol'   => 'echo',
+			'sec-websocket-version'    => '13',
+			'upgrade'                  => 'websocket',
+			'URI'                      => TEST_WEBSOCKET_PATH,
+			'VERSION'                  => 'HTTP/1.1',
+			'x-forwarded-for'          => '127.0.0.2',
+		}
+		TEST_WEBSOCKET_BODY = 'GR7M5bFPiY2GvVc5a7CIMErQ18Q='
+		TEST_WEBSOCKET_REQUEST_OPTS = {
+			:uuid    => TEST_UUID,
+			:id      => TEST_ID,
+			:path    => TEST_WEBSOCKET_PATH,
+			:body    => '',
+		}
+
+
+		#
+		# HTTP constants
+		#
+
+		# Space
+		SP = '\\x20'
+
+		# Network EOL
+		CRLF = '\\r\\n'
+
+		# Pattern to match the contents of ETag and If-None-Match headers
+		ENTITY_TAG_PATTERN = %r{
+			(w/)?       # Weak flag
+			"           # Opaque-tag
+				([^"]+) # Quoted-string
+			"           # Closing quote
+		  }ix
+
+		# Separators    = "(" | ")" | "<" | ">" | "@"
+		#                  | "," | ";" | ":" | "\" | <">
+		#                  | "/" | "[" | "]" | "?" | "="
+		#                  | "{" | "}" | SP | HT
+		SEPARATORS = Regexp.quote("(\")<>@,;:\\/[]?={} \t")
+
+		# token         = 1*<any CHAR except CTLs or separators>
+		TOKEN = /[^#{SEPARATORS}[:cntrl:]]+/
+
+		# Borrow URI's pattern for matching absolute URIs
+		REQUEST_URI = URI::REL_URI_REF
+
+		# Canonical HTTP methods
+		REQUEST_METHOD = /OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT/
+
+		# Extension HTTP methods
+		# extension-method = token
+		EXTENSION_METHOD = TOKEN
+
+		# HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
+		HTTP_VERSION = %r{HTTP/(\d+\.\d+)}
+
+		# LWS            = [CRLF] 1*( SP | HT )
+		LWS = /#{CRLF}[ \t]+/
+
+		# TEX            = <any OCTET except CTLs, but including LWS>
+		TEXT = /[^[:cntrl:]]|#{LWS}/
+
+		# Reason-Phrase  = *<TEXT, excluding CR, LF>
+		REASON_PHRASE = %r{[^[:cntrl:]]+}
+
+		# Pattern to match HTTP response lines
+		#	Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
+		HTTP_RESPONSE_LINE = %r{
+			(?<http_version>#{HTTP_VERSION})
+			#{SP}
+			(?<status_code>\d{3})
+			#{SP}
+			(?<reason_phrase>#{REASON_PHRASE})
+			#{CRLF}
+		}x
+
+		# message-header = field-name ":" [ field-value ]
+		# field-name     = token
+		# field-value    = *( field-content | LWS )
+		# field-content  = <the OCTETs making up the field-value
+		#                  and consisting of either *TEXT or combinations
+		#                  of token, separators, and quoted-string>
+
+		# Pattern to match a single header tuple, possibly split over multiple lines
+		HEADER_LINE = %r{
+			^
+			#{TOKEN}
+			:
+			(?:#{LWS}|#{TEXT})*
+			#{CRLF}
+		}mx
+
+		# entity-body	 = *OCTET
+		MESSAGE_BODY = /.*/
+
+		# Pattern to match an entire HTTP response
+		#   Response      = Status-Line               ; Section 6.1
+		#                   *(( general-header        ; Section 4.5
+		#                    | response-header        ; Section 6.2
+		#                    | entity-header ) CRLF)  ; Section 7.1
+		#                   CRLF
+		#                   [ message-body ]          ; Section 7.2
+		HTTP_RESPONSE = %r{
+			^
+			(?<response_line>#{HTTP_RESPONSE_LINE})
+			(?<headers>#{HEADER_LINE}*)
+			#{CRLF}
+			(?<message_body>#{MESSAGE_BODY})
+		}x
+
+		# wkday        = "Mon" | "Tue" | "Wed"
+		#              | "Thu" | "Fri" | "Sat" | "Sun"
+		WKDAY =	 Regexp.union( %w[Mon Tue Wed Thu Fri Sat Sun] )
+
+		# month        = "Jan" | "Feb" | "Mar" | "Apr"
+		#              | "May" | "Jun" | "Jul" | "Aug"
+		#              | "Sep" | "Oct" | "Nov" | "Dec"
+		MONTH = Regexp.union( %w[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec] )
+
+		# Match an RFC1123 "HTTP date"
+		# rfc1123-date = wkday "," SP date1 SP time SP "GMT"
+		# date1        = 2DIGIT SP month SP 4DIGIT
+		#                ; day month year (e.g., 02 Jun 1982)
+		# time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+		#                ; 00:00:00 - 23:59:59
+		HTTP_DATE = %r{
+			#{WKDAY} , #{SP}
+			\d{2} #{SP}
+			#{MONTH} #{SP}
+			\d{4} #{SP}
+			\d{2} : \d{2} : \d{2} #{SP} GMT
+		}x
+
+
+		# Freeze all testing constants
+		constants.each do |cname|
+			const_get(cname).freeze if cname.to_s.start_with?( 'TEST' )
+		end
+	end
+
+end
+
+

File spec/helpers.rb

+#!/usr/bin/ruby
+# coding: utf-8
+
+require_relative 'constants'
+require_relative 'matchers'
+
+# SimpleCov test coverage reporting; enable this using the :coverage rake task
+if ENV['COVERAGE']
+	$stderr.puts "\n\n>>> Enabling coverage report.\n\n"
+	require 'simplecov'
+	SimpleCov.start do
+		add_filter 'spec'
+		add_group "Config Classes" do |file|
+			file.filename =~ %r{lib/mongrel2/config(\.rb|/.*)$}
+		end
+		add_group "Needing tests" do |file|
+			file.covered_percent < 90
+		end
+	end
+end
+
+begin
+	require 'configurability'
+rescue LoadError => err
+end
+
+require 'pathname'
+require 'tmpdir'
+
+require 'rspec'
+require 'mongrel2'
+require 'mongrel2/config'
+require 'mongrel2/testing'
+
+require 'loggability/spechelpers'
+
+require 'sequel'
+require 'sequel/model'
+
+
+
+### RSpec helper functions that are used to test Mongrel2 itself.
+module Mongrel2::SpecHelpers
+	include Mongrel2::TestConstants
+
+	###############
+	module_function
+	###############
+
+	### Make an easily-comparable version vector out of +ver+ and return it.
+	def vvec( ver )
+		return ver.split('.').collect {|char| char.to_i }.pack('N*')
+	end
+
+
+	### Set up a Mongrel2 configuration database in memory.
+	def setup_config_db
+		Mongrel2::Config.db ||= Mongrel2::Config.in_memory_db
+		Mongrel2::Config.init_database
+		Mongrel2::Config.db.tables.collect {|t| Mongrel2::Config.db[t] }.each( &:truncate )
+	end
+
+
+	### Normalize and fill in missing members for the given +opts+.
+	def normalize_headers( opts, defaults=TEST_HEADERS )
+		headers = defaults.merge( opts[:headers] || {} )
+
+		headers["PATH"]    = opts[:path]
+		headers["URI"]     = "#{opts[:path]}?#{opts[:query]}"
+		headers["QUERY"]   = opts[:query]
+		headers["PATTERN"] = opts[:pattern] || opts[:path]
+
+		return headers
+	end
+
+
+	### Make a raw Mongrel2 request from the specified +opts+ and return it as a String.
+	def make_request( opts={} )
+		opts = TEST_REQUEST_OPTS.merge( opts )
+		headers = normalize_headers( opts )
+
+		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
+		bodystring = TNetstring.dump( opts[:body] || '' )
+
+		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
+		data = "%s %d %s %s%s" % [
+			opts[:uuid],
+			opts[:id],
+			opts[:path],
+			headerstring,
+			bodystring,
+		]
+		return data.encode( 'binary' )
+	end
+
+
+	### Make a new-style (TNetstring headers) raw Mongrel2 request from the specified +opts+
+	### and return it as a String.
+	def make_tn_request( opts={} )
+		opts = TEST_REQUEST_OPTS.merge( opts )
+		headers = normalize_headers( opts )
+
+		headerstring = TNetstring.dump( headers )
+		bodystring = TNetstring.dump( opts[:body] || '' )
+
+		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
+		data = "%s %d %s %s%s" % [
+			opts[:uuid],
+			opts[:id],
+			opts[:path],
+			headerstring,
+			bodystring,
+		]
+		return data.encode( 'binary' )
+	end
+
+
+	### Make a Mongrel2 request for a JSON route.
+	def make_json_request( opts={} )
+		opts = TEST_JSON_REQUEST_OPTS.merge( opts )
+		headers = normalize_headers( opts, TEST_JSON_HEADERS )
+		headers.delete( 'URI' ) # JSON requests don't have one
+
+		Mongrel2.log.debug "JSON request, headers = %p, opts = %p" % [ headers, opts ]
+
+		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
+		bodystring = TNetstring.dump( Yajl::Encoder.encode(opts[:body] || []) )
+
+		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
+		data = "%s %d %s %s%s" % [
+			opts[:uuid],
+			opts[:id],
+			opts[:path],
+			headerstring,
+			bodystring,
+		]
+		return data.encode( 'binary' )
+	end
+
+
+	### Make a Mongrel2 request for an XML route.
+	def make_xml_request( opts={} )
+		opts = TEST_XML_REQUEST_OPTS.merge( opts )
+		headers = normalize_headers( opts, TEST_XML_HEADERS )
+		headers.delete( 'URI' ) # XML requests don't have one
+
+		Mongrel2.log.debug "XML request, headers = %p, opts = %p" % [ headers, opts ]
+
+		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
+		bodystring = TNetstring.dump( opts[:body] || "#{TEST_XML_PATH} />" )
+
+		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
+		data = "%s %d %s %s%s" % [
+			opts[:uuid],
+			opts[:id],
+			opts[:path],
+			headerstring,
+			bodystring,
+		]
+		return data.encode( 'binary' )
+	end
+
+	### Make a Mongrel2 handshake request for a WebSocket route.
+	def make_websocket_handshake( opts={} )
+		opts = TEST_WEBSOCKET_REQUEST_OPTS.merge( opts )
+		headers = normalize_headers( opts, TEST_WEBSOCKET_HANDSHAKE_HEADERS )
+
+		Mongrel2.log.debug "WebSocket start handshake, headers = %p, opts = %p" % [ headers, opts ]
+
+		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
+		bodystring = TNetstring.dump( opts[:body] || TEST_WEBSOCKET_BODY )
+
+		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
+		data = "%s %d %s %s%s" % [
+			opts[:uuid],
+			opts[:id],
+			opts[:path],
+			headerstring,
+			bodystring,
+		]
+		return data.encode( 'binary' )
+	end
+
+	### Make a Mongrel2 frame for a WebSocket route.
+	def make_websocket_frame( opts={} )
+		opts = TEST_WEBSOCKET_REQUEST_OPTS.merge( opts )
+		headers = normalize_headers( opts, TEST_WEBSOCKET_HEADERS )
+
+		Mongrel2.log.debug "WebSocket frame, headers = %p, opts = %p" % [ headers, opts ]
+
+		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
+		bodystring = TNetstring.dump( opts[:body] )
+
+		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
+		data = "%s %d %s %s%s" % [
+			opts[:uuid],
+			opts[:id],
+			opts[:path],
+			headerstring,
+			bodystring,
+		]
+		return data.encode( 'binary' )
+	end
+
+end
+
+
+abort "You need a version of RSpec >= 2.6.0" unless defined?( RSpec )
+
+if defined?( ::Amalgalite )
+	$stderr.puts ">>> Using Amalgalite #{Amalgalite::VERSION} for DB access."
+else
+	$stderr.puts ">>> Using SQLite3 #{SQLite3::VERSION} for DB access."
+end
+
+### Mock with RSpec
+RSpec.configure do |c|
+	include Mongrel2::TestConstants
+
+	c.treat_symbols_as_metadata_keys_with_true_values = true
+	c.run_all_when_everything_filtered = true
+	c.filter_run :focus
+	c.order = 'random'
+	c.mock_with( :rspec ) do |config|
+		config.syntax = :expect
+	end
+
+	c.extend( Mongrel2::TestConstants )
+	c.include( Mongrel2::TestConstants )
+	c.include( Mongrel2::SpecHelpers )
+	c.include( Mongrel2::Matchers )
+	c.include( Loggability::SpecHelpers )
+
+	c.include( Mongrel2::Config::DSL )
+end
+
+# vim: set nosta noet ts=4 sw=4:
+

File spec/lib/constants.rb

-#!/usr/bin/env ruby
-
-require 'uri'
-require 'yajl'
-require 'tnetstring'
-
-require 'mongrel2' unless defined?( Mongrel2 )
-
-
-### A collection of constants used in testing
-module Mongrel2::TestConstants # :nodoc:all
-
-	include Mongrel2::Constants,
-	        Mongrel2::WebSocket::Constants
-
-	unless defined?( TEST_HOST )
-
-		TEST_HOST = 'localhost'
-		TEST_PORT = 8118
-
-		# Rule 2: Every message to and from Mongrel2 has that Mongrel2 instances
-		#   UUID as the very first thing.
-		TEST_UUID = 'BD17D85C-4730-4BF2-999D-9D2B2E0FCCF9'
-
-		# 0mq socket specifications for Handlers
-		TEST_SEND_SPEC = 'tcp://127.0.0.1:9998'
-		TEST_RECV_SPEC = 'tcp://127.0.0.1:9997'
-
-		# Rule 3: Mongrel2 sends requests with one number right after the
-		#   servers UUID separated by a space. Handlers return a netstring with
-		#   a list of numbers separated by spaces. The numbers indicate the
-		#   connected browser the message is to/from.
-		TEST_ID = 8
-
-		#
-		# HTTP request constants
-		#
-
-		TEST_ROUTE = '/handler'
-		TEST_PATH  = TEST_ROUTE
-		TEST_QUERY = 'thing=foom'
-
-		TEST_HEADERS = {
-			"x-forwarded-for" => "127.0.0.1",
-			"accept-language" => "en-US,en;q=0.8",
-			"accept-encoding" => "gzip,deflate,sdch",
-			"connection"      => "keep-alive",
-			"accept-charset"  => "UTF-8,*;q=0.5",
-			"accept"          => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
-			"user-agent"      => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) " +
-			                     "AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 " +
-			                     "Safari/535.1",
-			"host"            => "localhost:3667",
-			"METHOD"          => "GET",
-			"VERSION"         => "HTTP/1.1",
-		}
-
-		TEST_BODY = ''
-
-		TEST_REQUEST_OPTS = {
-			:uuid    => TEST_UUID,
-			:id      => TEST_ID,
-			:path    => TEST_PATH,
-			:body    => TEST_BODY,
-		}
-
-
-		#
-		# JSON (JSSocket, etc.) request constants
-		#
-
-		TEST_JSON_PATH = '@directory'
-
-		TEST_JSON_HEADERS = {
-			'PATH'            => TEST_JSON_PATH,
-			'x-forwarded-for' => "127.0.0.1",
-			'METHOD'          => "JSON",
-			'PATTERN'         => TEST_JSON_PATH,
-		}
-		TEST_JSON_BODY = { 'type' => 'msg', 'msg' => 'connect' }
-
-		TEST_JSON_REQUEST_OPTS = {
-			:uuid    => TEST_UUID,
-			:id      => TEST_ID,
-			:path    => TEST_JSON_PATH,
-			:body    => TEST_JSON_BODY,
-		}
-
-
-		#
-		# XML message request constants
-		#
-
-		TEST_XML_PATH = '<directory'
-
-		TEST_XML_HEADERS = {
-			'PATH'            => TEST_XML_PATH,
-			'x-forwarded-for' => "127.0.0.1",
-			'METHOD'          => "XML",
-			'PATTERN'         => TEST_XML_PATH,
-		}
-		TEST_XML_BODY = '<directory><file name="foom.txt" /><file name="foom2.md" /></directory>'
-
-		TEST_XML_REQUEST_OPTS = {
-			:uuid    => TEST_UUID,
-			:id      => TEST_ID,
-			:path    => TEST_XML_PATH,
-			:body    => TEST_XML_BODY,
-		}
-
-
-		#
-		# WebSocket frame constants
-		#
-
-		TEST_WEBSOCKET_PATH = '/ws'
-
-		TEST_WEBSOCKET_HEADERS = {
-			 'connection'               => 'Upgrade',
-			 'FLAGS'                    => '0x8A',
-			 'host'                     => 'host.example.com:80',
-			 'METHOD'                   => 'WEBSOCKET',
-			 'origin'                   => 'http://host.example.com:80',
-			 'PATH'                     => TEST_WEBSOCKET_PATH,
-			 'PATTERN'                  => TEST_WEBSOCKET_PATH,
-			 'sec-websocket-extensions' => 'x-webkit-deflate-frame',
-			 'sec-websocket-key'        => 'SQvDVdT2SbgTg6P/lSZo7Q==',
-			 'sec-websocket-protocol'   => 'echo',
-			 'sec-websocket-version'    => '13',
-			 'upgrade'                  => 'websocket',
-			 'URI'                      => TEST_WEBSOCKET_PATH,
-			 'VERSION'                  => 'HTTP/1.1',
-			 'x-forwarded-for'          => '127.0.0.2',
-		}
-		TEST_WEBSOCKET_HANDSHAKE_HEADERS = {
-			'connection'               => 'Upgrade',
-			'host'                     => 'host.example.com:80',
-			'METHOD'                   => 'WEBSOCKET_HANDSHAKE',
-			'origin'                   => 'http://host.example.com:80',
-			'PATH'                     => TEST_WEBSOCKET_PATH,
-			'PATTERN'                  => TEST_WEBSOCKET_PATH,
-			'sec-websocket-extensions' => 'x-webkit-deflate-frame',
-			'sec-websocket-key'        => 'SQvDVdT2SbgTg6P/lSZo7Q==',
-			'sec-websocket-protocol'   => 'echo',
-			'sec-websocket-version'    => '13',
-			'upgrade'                  => 'websocket',
-			'URI'                      => TEST_WEBSOCKET_PATH,
-			'VERSION'                  => 'HTTP/1.1',
-			'x-forwarded-for'          => '127.0.0.2',
-		}
-		TEST_WEBSOCKET_BODY = 'GR7M5bFPiY2GvVc5a7CIMErQ18Q='
-		TEST_WEBSOCKET_REQUEST_OPTS = {
-			:uuid    => TEST_UUID,
-			:id      => TEST_ID,
-			:path    => TEST_WEBSOCKET_PATH,
-			:body    => '',
-		}
-
-
-		#
-		# HTTP constants
-		#
-
-		# Space
-		SP = '\\x20'
-
-		# Network EOL
-		CRLF = '\\r\\n'
-
-		# Pattern to match the contents of ETag and If-None-Match headers
-		ENTITY_TAG_PATTERN = %r{
-			(w/)?       # Weak flag
-			"           # Opaque-tag
-				([^"]+) # Quoted-string
-			"           # Closing quote
-		  }ix
-
-		# Separators    = "(" | ")" | "<" | ">" | "@"
-		#                  | "," | ";" | ":" | "\" | <">
-		#                  | "/" | "[" | "]" | "?" | "="
-		#                  | "{" | "}" | SP | HT
-		SEPARATORS = Regexp.quote("(\")<>@,;:\\/[]?={} \t")
-
-		# token         = 1*<any CHAR except CTLs or separators>
-		TOKEN = /[^#{SEPARATORS}[:cntrl:]]+/
-
-		# Borrow URI's pattern for matching absolute URIs
-		REQUEST_URI = URI::REL_URI_REF
-
-		# Canonical HTTP methods
-		REQUEST_METHOD = /OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT/
-
-		# Extension HTTP methods
-		# extension-method = token
-		EXTENSION_METHOD = TOKEN
-
-		# HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
-		HTTP_VERSION = %r{HTTP/(\d+\.\d+)}
-
-		# LWS            = [CRLF] 1*( SP | HT )
-		LWS = /#{CRLF}[ \t]+/
-
-		# TEX            = <any OCTET except CTLs, but including LWS>
-		TEXT = /[^[:cntrl:]]|#{LWS}/
-
-		# Reason-Phrase  = *<TEXT, excluding CR, LF>
-		REASON_PHRASE = %r{[^[:cntrl:]]+}
-
-		# Pattern to match HTTP response lines
-		#	Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
-		HTTP_RESPONSE_LINE = %r{
-			(?<http_version>#{HTTP_VERSION})
-			#{SP}
-			(?<status_code>\d{3})
-			#{SP}
-			(?<reason_phrase>#{REASON_PHRASE})
-			#{CRLF}
-		}x
-
-		# message-header = field-name ":" [ field-value ]
-		# field-name     = token
-		# field-value    = *( field-content | LWS )
-		# field-content  = <the OCTETs making up the field-value
-		#                  and consisting of either *TEXT or combinations
-		#                  of token, separators, and quoted-string>
-
-		# Pattern to match a single header tuple, possibly split over multiple lines
-		HEADER_LINE = %r{
-			^
-			#{TOKEN}
-			:
-			(?:#{LWS}|#{TEXT})*
-			#{CRLF}
-		}mx
-
-		# entity-body	 = *OCTET
-		MESSAGE_BODY = /.*/
-
-		# Pattern to match an entire HTTP response
-		#   Response      = Status-Line               ; Section 6.1
-		#                   *(( general-header        ; Section 4.5
-		#                    | response-header        ; Section 6.2
-		#                    | entity-header ) CRLF)  ; Section 7.1
-		#                   CRLF
-		#                   [ message-body ]          ; Section 7.2
-		HTTP_RESPONSE = %r{
-			^
-			(?<response_line>#{HTTP_RESPONSE_LINE})
-			(?<headers>#{HEADER_LINE}*)
-			#{CRLF}
-			(?<message_body>#{MESSAGE_BODY})
-		}x
-
-		# wkday        = "Mon" | "Tue" | "Wed"
-		#              | "Thu" | "Fri" | "Sat" | "Sun"
-		WKDAY =	 Regexp.union( %w[Mon Tue Wed Thu Fri Sat Sun] )
-
-		# month        = "Jan" | "Feb" | "Mar" | "Apr"
-		#              | "May" | "Jun" | "Jul" | "Aug"
-		#              | "Sep" | "Oct" | "Nov" | "Dec"
-		MONTH = Regexp.union( %w[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec] )
-
-		# Match an RFC1123 "HTTP date"
-		# rfc1123-date = wkday "," SP date1 SP time SP "GMT"
-		# date1        = 2DIGIT SP month SP 4DIGIT
-		#                ; day month year (e.g., 02 Jun 1982)
-		# time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
-		#                ; 00:00:00 - 23:59:59
-		HTTP_DATE = %r{
-			#{WKDAY} , #{SP}
-			\d{2} #{SP}
-			#{MONTH} #{SP}
-			\d{4} #{SP}
-			\d{2} : \d{2} : \d{2} #{SP} GMT
-		}x
-
-
-		# Freeze all testing constants
-		constants.each do |cname|
-			const_get(cname).freeze if cname.to_s.start_with?( 'TEST' )
-		end
-	end
-
-end
-
-

File spec/lib/helpers.rb

-#!/usr/bin/ruby
-# coding: utf-8
-
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
-	$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
-}
-
-# SimpleCov test coverage reporting; enable this using the :coverage rake task
-if ENV['COVERAGE']
-	$stderr.puts "\n\n>>> Enabling coverage report.\n\n"
-	require 'simplecov'
-	SimpleCov.start do
-		add_filter 'spec'
-		add_group "Config Classes" do |file|
-			file.filename =~ %r{lib/mongrel2/config(\.rb|/.*)$}
-		end
-		add_group "Needing tests" do |file|
-			file.covered_percent < 90
-		end
-	end
-end
-
-begin
-	require 'configurability'
-rescue LoadError => err
-end
-
-require 'pathname'
-require 'tmpdir'
-
-require 'rspec'
-require 'mongrel2'
-require 'mongrel2/config'
-require 'mongrel2/testing'
-
-require 'loggability/spechelpers'
-
-require 'sequel'
-require 'sequel/model'
-
-require 'spec/lib/constants'
-require 'spec/lib/matchers'
-
-
-### RSpec helper functions that are used to test Mongrel2 itself.
-module Mongrel2::SpecHelpers
-	include Mongrel2::TestConstants
-
-	###############
-	module_function
-	###############
-
-	### Make an easily-comparable version vector out of +ver+ and return it.
-	def vvec( ver )
-		return ver.split('.').collect {|char| char.to_i }.pack('N*')
-	end
-
-
-	### Set up a Mongrel2 configuration database in memory.
-	def setup_config_db
-		Mongrel2::Config.db ||= Mongrel2::Config.in_memory_db
-		Mongrel2::Config.init_database
-		Mongrel2::Config.db.tables.collect {|t| Mongrel2::Config.db[t] }.each( &:truncate )
-	end
-
-
-	### Normalize and fill in missing members for the given +opts+.
-	def normalize_headers( opts, defaults=TEST_HEADERS )
-		headers = defaults.merge( opts[:headers] || {} )
-
-		headers["PATH"]    = opts[:path]
-		headers["URI"]     = "#{opts[:path]}?#{opts[:query]}"
-		headers["QUERY"]   = opts[:query]
-		headers["PATTERN"] = opts[:pattern] || opts[:path]
-
-		return headers
-	end
-
-
-	### Make a raw Mongrel2 request from the specified +opts+ and return it as a String.
-	def make_request( opts={} )
-		opts = TEST_REQUEST_OPTS.merge( opts )
-		headers = normalize_headers( opts )
-
-		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
-		bodystring = TNetstring.dump( opts[:body] || '' )
-
-		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
-		data = "%s %d %s %s%s" % [
-			opts[:uuid],
-			opts[:id],
-			opts[:path],
-			headerstring,
-			bodystring,
-		]
-		return data.encode( 'binary' )
-	end
-
-
-	### Make a new-style (TNetstring headers) raw Mongrel2 request from the specified +opts+
-	### and return it as a String.
-	def make_tn_request( opts={} )
-		opts = TEST_REQUEST_OPTS.merge( opts )
-		headers = normalize_headers( opts )
-
-		headerstring = TNetstring.dump( headers )
-		bodystring = TNetstring.dump( opts[:body] || '' )
-
-		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
-		data = "%s %d %s %s%s" % [
-			opts[:uuid],
-			opts[:id],
-			opts[:path],
-			headerstring,
-			bodystring,
-		]
-		return data.encode( 'binary' )
-	end
-
-
-	### Make a Mongrel2 request for a JSON route.
-	def make_json_request( opts={} )
-		opts = TEST_JSON_REQUEST_OPTS.merge( opts )
-		headers = normalize_headers( opts, TEST_JSON_HEADERS )
-		headers.delete( 'URI' ) # JSON requests don't have one
-
-		Mongrel2.log.debug "JSON request, headers = %p, opts = %p" % [ headers, opts ]
-
-		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
-		bodystring = TNetstring.dump( Yajl::Encoder.encode(opts[:body] || []) )
-
-		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
-		data = "%s %d %s %s%s" % [
-			opts[:uuid],
-			opts[:id],
-			opts[:path],
-			headerstring,
-			bodystring,
-		]
-		return data.encode( 'binary' )
-	end
-
-
-	### Make a Mongrel2 request for an XML route.
-	def make_xml_request( opts={} )
-		opts = TEST_XML_REQUEST_OPTS.merge( opts )
-		headers = normalize_headers( opts, TEST_XML_HEADERS )
-		headers.delete( 'URI' ) # XML requests don't have one
-
-		Mongrel2.log.debug "XML request, headers = %p, opts = %p" % [ headers, opts ]
-
-		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
-		bodystring = TNetstring.dump( opts[:body] || "#{TEST_XML_PATH} />" )
-
-		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
-		data = "%s %d %s %s%s" % [
-			opts[:uuid],
-			opts[:id],
-			opts[:path],
-			headerstring,
-			bodystring,
-		]
-		return data.encode( 'binary' )
-	end
-
-	### Make a Mongrel2 handshake request for a WebSocket route.
-	def make_websocket_handshake( opts={} )
-		opts = TEST_WEBSOCKET_REQUEST_OPTS.merge( opts )
-		headers = normalize_headers( opts, TEST_WEBSOCKET_HANDSHAKE_HEADERS )
-
-		Mongrel2.log.debug "WebSocket start handshake, headers = %p, opts = %p" % [ headers, opts ]
-
-		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
-		bodystring = TNetstring.dump( opts[:body] || TEST_WEBSOCKET_BODY )
-
-		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
-		data = "%s %d %s %s%s" % [
-			opts[:uuid],
-			opts[:id],
-			opts[:path],
-			headerstring,
-			bodystring,
-		]
-		return data.encode( 'binary' )
-	end
-
-	### Make a Mongrel2 frame for a WebSocket route.
-	def make_websocket_frame( opts={} )
-		opts = TEST_WEBSOCKET_REQUEST_OPTS.merge( opts )
-		headers = normalize_headers( opts, TEST_WEBSOCKET_HEADERS )
-
-		Mongrel2.log.debug "WebSocket frame, headers = %p, opts = %p" % [ headers, opts ]
-
-		headerstring = TNetstring.dump( Yajl::Encoder.encode(headers) )
-		bodystring = TNetstring.dump( opts[:body] )
-
-		# UUID ID PATH SIZE:HEADERS,SIZE:BODY,
-		data = "%s %d %s %s%s" % [
-			opts[:uuid],
-			opts[:id],
-			opts[:path],
-			headerstring,
-			bodystring,
-		]
-		return data.encode( 'binary' )
-	end
-
-end
-
-
-abort "You need a version of RSpec >= 2.6.0" unless defined?( RSpec )
-
-if defined?( ::Amalgalite )
-	$stderr.puts ">>> Using Amalgalite #{Amalgalite::VERSION} for DB access."
-else
-	$stderr.puts ">>> Using SQLite3 #{SQLite3::VERSION} for DB access."
-end
-
-### Mock with RSpec
-RSpec.configure do |c|
-	include Mongrel2::TestConstants
-
-	c.mock_with :rspec
-
-	c.extend( Mongrel2::TestConstants )
-	c.include( Mongrel2::TestConstants )
-	c.include( Mongrel2::SpecHelpers )
-	c.include( Mongrel2::Matchers )
-	c.include( Loggability::SpecHelpers )
-
-	c.include( Mongrel2::Config::DSL )
-end
-
-# vim: set nosta noet ts=4 sw=4:
-

File spec/lib/matchers.rb

-#!/usr/bin/ruby
-# coding: utf-8
-
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
-}
-
-require 'rspec'
-require 'mongrel2'
-
-
-### RSpec matchers for Mongrel2 specs
-module Mongrel2::Matchers
-
-    ### A matcher for unordered array contents
-	class EnumerableAllBeMatcher
-
-		def initialize( expected_mod )
-			@expected_mod = expected_mod
-		end
-
-		def matches?( collection )
-			collection.all? {|obj| obj.is_a?(@expected_mod) }
-		end
-
-		def description
-			return "all be a kind of %p" % [ @expected_mod ]
-		end
-	end
-
-
-	###############
-	module_function
-	###############
-
-	### Returns true if the actual value is an Array, all of which respond truly to
-	### .is_a?( expected_mod )
-	def all_be_a( expected_mod )
-		EnumerableAllBeMatcher.new( expected_mod )
-	end
-
-
-end # module Mongrel2::Matchers
-
-

File spec/matchers.rb

+#!/usr/bin/ruby
+# coding: utf-8
+
+require 'mongrel2' unless defined?( Mongrel2 )
+
+
+### RSpec matchers for Mongrel2 specs
+module Mongrel2::Matchers # :nodoc:
+
+    ### A matcher for unordered array contents
+	class EnumerableAllBeMatcher
+
+		def initialize( expected_mod )
+			@expected_mod = expected_mod
+		end
+
+		def matches?( collection )
+			collection.all? {|obj| obj.is_a?(@expected_mod) }
+		end
+
+		def description
+			return "all be a kind of %p" % [ @expected_mod ]
+		end
+	end
+
+
+	###############
+	module_function
+	###############
+
+	### Returns true if the actual value is an Array, all of which respond truly to
+	### .is_a?( expected_mod )
+	def all_be_a( expected_mod )
+		EnumerableAllBeMatcher.new( expected_mod )
+	end
+
+
+end # module Mongrel2::Matchers
+
+

File spec/mongrel2/config/directory_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 
 describe Mongrel2::Config::Directory do
 
 	before( :all ) do
-		setup_logging( :fatal )
+		setup_logging()
 		setup_config_db()
 	end
 
 
 
 	it "is valid if its base, index_file, and default_ctype are all valid" do
-		@dir.should be_valid()
+		expect( @dir ).to be_valid()
 	end
 
 	it "isn't valid if it doesn't have a base" do
 		@dir.base = nil
-		@dir.should_not be_valid()
-		@dir.errors.full_messages.first.should =~ /missing or nil/i
+		expect( @dir ).to_not be_valid()
+		expect( @dir.errors.full_messages.first ).to match( /missing or nil/i )
 	end
 
 	it "isn't valid when its base starts with '/'" do
 		@dir.base = '/var/www/public/'
-		@dir.should_not be_valid()
-		@dir.errors.full_messages.first.should =~ %r{shouldn't start with '/'}i
+		expect( @dir ).to_not be_valid()
+		expect( @dir.errors.full_messages.first ).to match( %r{shouldn't start with '/'}i )
 	end
 
 	it "isn't valid when its base doesn't end with '/'" do
 		@dir.base = 'var/www/public'
-		@dir.should_not be_valid()
-		@dir.errors.full_messages.first.should =~ %r{must end with '/'}i
+		expect( @dir ).to_not be_valid()
+		expect( @dir.errors.full_messages.first ).to match( %r{must end with '/'}i )
 	end
 
 	it "isn't valid if it doesn't have an index file" do
 		@dir.index_file = nil
-		@dir.should_not be_valid()
-		@dir.errors.full_messages.first.should =~ /must not be nil/i
+		expect( @dir ).to_not be_valid()
+		expect( @dir.errors.full_messages.first ).to match( /must not be nil/i )
 	end
 
 	it "isn't valid if it doesn't have a default content-type" do
 		@dir.default_ctype = nil
-		@dir.should_not be_valid()
-		@dir.errors.full_messages.first.should =~ /must not be nil/i
+		expect( @dir ).to_not be_valid()
+		expect( @dir.errors.full_messages.first ).to match( /must not be nil/i )
 	end
 
 	it "isn't valid if its cache TTL is set to a negative value" do
 		@dir.cache_ttl = -5
-		@dir.should_not be_valid()
-		@dir.errors.full_messages.first.should =~ /not a positive integer/i
+		expect( @dir ).to_not be_valid()
+		expect( @dir.errors.full_messages.first ).to match( /not a positive integer/i )
 	end
 
 	it "is valid if its cache TTL is set to zero" do
 		@dir.cache_ttl = 0
-		@dir.should be_valid()
+		expect( @dir ).to be_valid()
 	end
 
 end

File spec/mongrel2/config/dsl_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 
 	include described_class
 
 	before( :all ) do
-		setup_logging( :fatal )
+		setup_logging()
 		setup_config_db()
 	end
 

File spec/mongrel2/config/filter_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 

File spec/mongrel2/config/handler_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 
 describe Mongrel2::Config::Handler do
 
 	before( :all ) do
-		setup_logging( :fatal )
+		setup_logging()
 		setup_config_db()
 	end
 
 	before( :each ) do
+		Mongrel2::Config::Handler.truncate
 		@handler = Mongrel2::Config::Handler.new(
 			:send_spec  => TEST_SEND_SPEC,
 			:send_ident => TEST_UUID,
 	end
 
 	it "is valid if its specs and identities are all valid" do
-		@handler.should be_valid()
+		expect( @handler ).to be_valid()
 	end
 
 
 	it "isn't valid if it doesn't have a send_spec" do
 		@handler.send_spec = nil
-		@handler.should_not be_valid()
-		@handler.errors.full_messages.first.should =~ /must not be nil/i
+		expect( @handler ).to_not be_valid()
+		expect( @handler.errors.full_messages.first ).to match( /must not be nil/i )
 	end
 
 	it "isn't valid if it doesn't have a recv_spec" do
 		@handler.recv_spec = nil
-		@handler.should_not be_valid()
-		@handler.errors.full_messages.first.should =~ /must not be nil/i
+		expect( @handler ).to_not be_valid()
+		expect( @handler.errors.full_messages.first ).to match( /must not be nil/i )
 	end
 
 
 	it "isn't valid if it doesn't have a valid URL in its send_spec" do
 		@handler.send_spec = 'carrier pigeon'
-		@handler.should_not be_valid()
-		@handler.errors.full_messages.first.should =~ /not a uri/i
+		expect( @handler ).to_not be_valid()
+		expect( @handler.errors.full_messages.first ).to match( /not a uri/i )
 	end
 
 	it "isn't valid if it doesn't have a valid URL in its recv_spec" do
 		@handler.recv_spec = 'smoke signals'
-		@handler.should_not be_valid()
-		@handler.errors.full_messages.first.should =~ /not a uri/i
+		expect( @handler ).to_not be_valid()
+		expect( @handler.errors.full_messages.first ).to match( /not a uri/i )
 	end
 
 
 	it "isn't valid if has an unsupported transport in its send_spec" do
 		@handler.send_spec = 'inproc://application'
-		@handler.should_not be_valid()
-		@handler.errors.full_messages.first.should =~ /invalid 0mq transport/i
+		expect( @handler ).to_not be_valid()
+		expect( @handler.errors.full_messages.first ).to match( /invalid 0mq transport/i )
 	end
 
 	it "isn't valid if has an unsupported transport in its recv_spec" do
 		@handler.recv_spec = 'inproc://application'
-		@handler.should_not be_valid()
-		@handler.errors.full_messages.first.should =~ /invalid 0mq transport/i
+		expect( @handler ).to_not be_valid()
+		expect( @handler.errors.full_messages.first ).to match( /invalid 0mq transport/i )
 	end
 
 
 	it "isn't valid if it doesn't have a send_ident" do
 		@handler.send_ident = nil
-		@handler.should_not be_valid()
-		@handler.errors.full_messages.first.should =~ /invalid sender identity/i
+		expect( @handler ).to_not be_valid()
+		expect( @handler.errors.full_messages.first ).to match( /invalid sender identity/i )
 	end
 
 	it "*is* valid if it doesn't have a recv_ident" do
 		@handler.recv_ident = nil
-		@handler.should be_valid()
+		expect( @handler ).to be_valid()
 	end
 
 
 	it "is valid if it has 'json' set as the protocol" do
 		@handler.protocol = 'json'
-		@handler.should be_valid()
+		expect( @handler ).to be_valid()
 	end
 
 	it "is valid if it has 'tnetstring' set as the protocol" do
 		@handler.protocol = 'tnetstring'
-		@handler.should be_valid()
+		expect( @handler ).to be_valid()
 	end
 
 	it "isn't valid if it has an invalid protocol" do
 		@handler.protocol = 'morsecode'
-		@handler.should_not be_valid()
-		@handler.errors.full_messages.first.should =~ /invalid/i
+		expect( @handler ).to_not be_valid()
+		expect( @handler.errors.full_messages.first ).to match( /invalid/i )
 	end
 
 	it "isn't valid if its send_spec isn't unique" do

File spec/mongrel2/config/host_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 

File spec/mongrel2/config/log_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
+require_relative '../../helpers'
 
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require 'rspec'
 
 require 'socket'
-require 'rspec'
-
-require 'spec/lib/constants'
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 
 describe Mongrel2::Config::Log do
 
 	before( :all ) do
-		setup_logging( :fatal )
+		setup_logging()
 		setup_config_db()
 	end
 
 
 		log = Mongrel2::Config::Log.log_action( what, why, where, how )
 
-		log.what.should == what
-		log.why.should == why
-		log.location.should == where
-		log.how.should == how
+		expect( log.what ).to eq( what )
+		expect( log.why ).to eq( why )
+		expect( log.location ).to eq( where )
+		expect( log.how ).to eq( how )
 	end
 
 	it "has reasonable defaults for 'where' and 'how'" do
 
 		log = Mongrel2::Config::Log.log_action( what, why )
 
-		log.location.should == Socket.gethostname
-		log.how.should == File.basename( $0 )
+		expect( log.location ).to eq( Socket.gethostname )
+		expect( log.how ).to eq( File.basename( $0 ) )
 	end
 
 	describe "an entry" do
 		it "stringifies as a readable log file line" do
 
 			# 2011-09-09 20:29:47 -0700 [mgranger] @localhost m2sh: load etc/mongrel2.conf (updating)
-			@log.to_s.should =~ %r{
+			expect( @log.to_s ).to match(%r{
 				^
 				(?-x:\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [\+\-]\d{4} )
 				\[who\] \s
 				how: \s
 				what
 				$
-			}x
+			}x)
 		end
 
 		it "stringifies with a reason if it has one" do
 			@log.why = 'Because'
 
 			# 2011-09-09 20:29:47 -0700 [mgranger] @localhost m2sh: load etc/mongrel2.conf (updating)
-			@log.to_s.should =~ %r{
+			expect( @log.to_s ).to match(%r{
 				^
 				(?-x:\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [\+\-]\d{4} )
 				\[who\] \s
 				what \s
 				\(Because\)
 				$
-			}x
+			}x)
 		end
 
 	end

File spec/mongrel2/config/proxy_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 

File spec/mongrel2/config/route_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 
 		reset_logging()
 	end
 
+
 	it "returns a Mongrel2::Config::Directory if its target_type is 'dir'" do
 		dir = Mongrel2::Config::Directory.create(
 			:base => 'var/www/',
 		@route.target_type = 'dir'
 		@route.target_id = dir.id
 
-		@route.target.should == dir
+		expect( @route.target ).to eq( dir )
 	end
 
 	it "returns a Mongrel2::Config::Proxy if its target_type is 'proxy'" do
 		@route.target_type = 'proxy'
 		@route.target_id = proxy.id
 
-		@route.target.should == proxy
+		expect( @route.target ).to eq( proxy )
 	end
 
 	it "returns a Mongrel2::Config::Handler if its target_type is 'handler'" do
 		@route.target_type = 'handler'
 		@route.target_id = handler.id
 
-		@route.target.should == handler
+		expect( @route.target ).to eq( handler )
 	end
 
 	it "raises an exception if its target_type is set to something invalid" do

File spec/mongrel2/config/server_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 
 describe Mongrel2::Config::Server do
 
 	before( :all ) do
-		setup_logging( :fatal )
+		setup_logging()
 		setup_config_db()
 	end
 
 
 
 	it "is valid if its access_log, error_log, pid_file, default_host, and port are all valid" do
-		@server.should be_valid()
+		expect( @server ).to be_valid()
 	end
 
 	it "isn't valid if it doesn't have an access_log path" do
 		@server.access_log = nil
-		@server.should_not be_valid()
-		@server.errors.full_messages.first.should =~ /missing or nil/i
+		expect( @server ).to_not be_valid()
+		expect( @server.errors.full_messages.first ).to match( /missing or nil/i )
 	end
 
 	it "isn't valid if it doesn't have an error_log path" do
 		@server.error_log = nil
-		@server.should_not be_valid()
-		@server.errors.full_messages.first.should =~ /missing or nil/i
+		expect( @server ).to_not be_valid()
+		expect( @server.errors.full_messages.first ).to match( /missing or nil/i )
 	end
 
 	it "isn't valid if it doesn't have an pid_file path" do
 		@server.pid_file = nil
-		@server.should_not be_valid()
-		@server.errors.full_messages.first.should =~ /missing or nil/i
+		expect( @server ).to_not be_valid()
+		expect( @server.errors.full_messages.first ).to match( /missing or nil/i )
 	end
 
 	it "isn't valid if it doesn't have a default_host" do
 		@server.default_host = nil
-		@server.should_not be_valid()
-		@server.errors.full_messages.first.should =~ /missing or nil/i
+		expect( @server ).to_not be_valid()
+		expect( @server.errors.full_messages.first ).to match( /missing or nil/i )
 	end
 
 	it "isn't valid if it doesn't specify a port" do
 		@server.port = nil
-		@server.should_not be_valid()
-		@server.errors.full_messages.first.should =~ /missing or nil/i
+		expect( @server ).to_not be_valid()
+		expect( @server.errors.full_messages.first ).to match( /missing or nil/i )
 	end
 
 
 	it "knows where its control socket is if there's no setting for control_port" do
 		Mongrel2::Config::Setting.dataset.truncate
-		FileTest.stub( :socket? ).with( '/usr/local/www/run/control' ).
+		allow( FileTest ).to receive( :socket? ).with( '/usr/local/www/run/control' ).
 			and_return( true )
-		@server.control_socket_uri.should == 'ipc:///usr/local/www/run/control'
+		expect( @server.control_socket_uri ).to eq( 'ipc:///usr/local/www/run/control' )
 	end
 
 	it "knows where its control socket is if there is a setting for control_port" do
 		Mongrel2::Config::Setting.dataset.truncate
-		FileTest.stub( :socket? ).with( '/usr/local/www/var/run/control.sock' ).
+		allow( FileTest ).to receive( :socket? ).with( '/usr/local/www/var/run/control.sock' ).
 			and_return( true )
 		Mongrel2::Config::Setting.create( key: 'control_port', value: 'ipc://var/run/control.sock' )
-		@server.control_socket_uri.should == 'ipc:///usr/local/www/var/run/control.sock'
+		expect( @server.control_socket_uri ).to eq( 'ipc:///usr/local/www/var/run/control.sock' )
 	end
 
 	it "raises an error if the control socket path doesn't point to a UNIX socket" do
 
 	it "can create a Mongrel2::Control for its control port" do
 		Mongrel2::Config::Setting.dataset.truncate
-		FileTest.stub( :socket? ).with( '/usr/local/www/run/control' ).
+		allow( FileTest ).to receive( :socket? ).with( '/usr/local/www/run/control' ).
 			and_return( true )
 		sock = @server.control_socket
-		sock.should be_a( Mongrel2::Control )
+		expect( sock ).to be_a( Mongrel2::Control )
 		sock.close
 	end
 
 	it "knows what the Pathname of its PID file is" do
 		pidfile = @server.pid_file_path
-		pidfile.should be_a( Pathname )
-		pidfile.to_s.should == '/run/mongrel2.pid'
+		expect( pidfile ).to be_a( Pathname )
+		expect( pidfile.to_s ).to eq( '/run/mongrel2.pid' )
 	end
 
 	it "has a predicate that understands the use_ssl value" do
-		@server.use_ssl.should be_false()
+		expect( @server.use_ssl ).to be_false()
 		@server.use_ssl = true
-		@server.use_ssl.should be_true()
+		expect( @server.use_ssl ).to be_true()
 	end
 
 end

File spec/mongrel2/config/setting_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 

File spec/mongrel2/config/statistic_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 

File spec/mongrel2/config/xrequest_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
+require_relative '../../helpers'
 
 require 'rspec'
-
-require 'spec/lib/helpers'
-
 require 'mongrel2'
 require 'mongrel2/config'
 

File spec/mongrel2/config_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
-
-require 'rspec'
-
-require 'spec/lib/helpers'
+require_relative '../helpers'
 
 require 'mongrel2'
 require 'mongrel2/config'
 describe Mongrel2::Config do
 
 	before( :all ) do
-		setup_logging( :fatal )
+		setup_logging()
 		setup_config_db()
 	end
 
 	it "has a factory method for creating derivative classes" do
 		begin
 			model_class = Mongrel2::Config( :hookers )
-			model_class.should < Mongrel2::Config
-			model_class.dataset.first_source.should == :hookers
+			expect( model_class ).to satisfy {|klass| klass < Mongrel2::Config }
+			expect( model_class.dataset.first_source ).to eq( :hookers )
 		ensure
 			# Remove the example class from the list of subclasses so it
 			# doesn't affect later tests
 	it "can reset the database handle for the config classes" do
 		db = Mongrel2::Config.in_memory_db
 		Mongrel2::Config.db = db
-		Mongrel2::Config::Directory.db.should equal( db )
+		expect( Mongrel2::Config::Directory.db ).to equal( db )
 	end
 
 	it "has a convenience method for fetching an Array of all of its configured servers" do
 			default_host: 'localhost',
 			port: 8275
 		  )
-		Mongrel2::Config.servers.should have( 1 ).member
-		Mongrel2::Config.servers.first.uuid.should == TEST_UUID
+		expect( Mongrel2::Config.servers ).to have( 1 ).member
+		expect( Mongrel2::Config.servers.first.uuid ).to eq( TEST_UUID )
 	end
 
 	it "has a convenience method for getting a setting's value" do
 		Mongrel2::Config.init_database
 		Mongrel2::Config::Setting.dataset.truncate
 		Mongrel2::Config::Setting.create( key: 'control_port', value: 'ipc://var/run/control.sock' )
-		Mongrel2::Config.settings.should respond_to( :[] )
-		Mongrel2::Config.settings.should have( 1 ).member
-		Mongrel2::Config.settings[ :control_port ].should == 'ipc://var/run/control.sock'
+		expect( Mongrel2::Config.settings ).to respond_to( :[] )
+		expect( Mongrel2::Config.settings ).to have( 1 ).member
+		expect( Mongrel2::Config.settings[ :control_port ] ).to eq( 'ipc://var/run/control.sock' )
 	end
 
 	it "can read the configuration schema from a data file" do
-		Mongrel2::Config.load_config_schema.should =~ /create table server/i
+		expect( Mongrel2::Config.load_config_schema ).to match( /create table server/i )
 	end
 
 	it "knows whether or not its database has been initialized" do
 		Mongrel2::Config.db = Mongrel2::Config.in_memory_db
-		Mongrel2::Config.database_initialized?.should be_false()
+		expect( Mongrel2::Config.database_initialized? ).to be_false()
 		Mongrel2::Config.init_database!
-		Mongrel2::Config.database_initialized?.should be_true()
+		expect( Mongrel2::Config.database_initialized? ).to be_true()
 	end
 
 	it "doesn't re-initialize the database if the non-bang version of init_database is used" do
 		Mongrel2::Config.db = Mongrel2::Config.in_memory_db
 		Mongrel2::Config.init_database
 
-		Mongrel2::Config.should_not_receive( :load_config_schema )
+		expect( Mongrel2::Config ).to_not receive( :load_config_schema )
 		Mongrel2::Config.init_database
 	end
 
 	it "can return the path to the config DB as a Pathname if it's pointing at a file" do
 		Mongrel2::Config.db = Sequel.
 			connect( adapter: Mongrel2::Config.sqlite_adapter, database: 'config-spec.sqlite' )
-		Mongrel2::Config.dbname.should == 'config-spec.sqlite'
+		expect( Mongrel2::Config.dbname ).to eq( 'config-spec.sqlite' )
 	end
 
 	it "returns nil if asked for the pathname to an in-memory database" do
 		Mongrel2::Config.db = Mongrel2::Config.in_memory_db
-		Mongrel2::Config.dbname.should be_nil()
+		expect( Mongrel2::Config.dbname ).to be_nil()
 	end
 
 	describe "Configurability support", :if => defined?( Configurability ) do
 		it_should_behave_like "an object with Configurability"
 
 		it "uses the 'mongrel2' config section" do
-			Mongrel2::Config.config_key.should == :mongrel2
+			expect( Mongrel2::Config.config_key ).to eq( :mongrel2 )
 		end
 
 	end

File spec/mongrel2/connection_spec.rb

 #!/usr/bin/env ruby
 
-BEGIN {
-	require 'pathname'
-	basedir = Pathname.new( __FILE__ ).dirname.parent.parent
-
-	libdir = basedir + "lib"
-
-	$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
-	$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
-}
-
-require 'rspec'
-
-require 'spec/lib/helpers'
+require_relative '../helpers'
 
 require 'mongrel2'
 require 'mongrel2/connection'
 
 
 	it "doesn't connect to the endpoints when it's created" do
-		@conn.instance_variable_get( :@request_sock ).should be_nil()
-		@conn.instance_variable_get( :@response_sock ).should be_nil()
+		expect( @conn.instance_variable_get( :@request_sock ) ).to be_nil()
+		expect( @conn.instance_variable_get( :@response_sock ) ).to be_nil()
 	end
 
 	it "connects to the endpoints specified on demand" do
 		request_sock = double( "request socket" )
 		response_sock = double( "response socket" )
 
-		@ctx.should_receive( :socket ).with( :PULL ).and_return( request_sock )
-		request_sock.should_receive( :linger= ).with( 0 )
-		request_sock.should_receive( :connect ).with( TEST_SEND_SPEC )
+		expect( @ctx ).to receive( :socket ).with( :PULL ).and_return( request_sock )
+		expect( request_sock ).to receive( :linger= ).with( 0 )
+		expect( request_sock ).to receive( :connect ).with( TEST_SEND_SPEC )
 
-		@ctx.should_receive( :socket ).with( :PUB ).and_return( response_sock )
-		response_sock.should_receive( :linger= ).with( 0 )
-		response_sock.should_receive( :identity= ).with( /^[[:xdigit:]]{40}$/ )
-		response_sock.should_receive( :connect ).with( TEST_RECV_SPEC )
+		expect( @ctx ).to receive( :socket ).with( :PUB ).and_return( response_sock )
+		expect( response_sock ).to receive( :linger= ).with( 0 )
+		expect( response_sock ).to receive( :identity= ).with( /^[[:xdigit:]]{40}$/ )
+		expect( response_sock ).to receive( :connect ).with( TEST_RECV_SPEC )
 
-		@conn.request_sock.should == request_sock
-		@conn.response_sock.should == response_sock
+		expect( @conn.request_sock ).to eq( request_sock )
+		expect( @conn.response_sock ).to eq( response_sock )
 	end
 
 	it "stringifies as a description of the appid and both sockets" do
-		@conn.to_s.should == "{#{TEST_UUID}} #{TEST_SEND_SPEC} <-> #{TEST_RECV_SPEC}"
+		expect( @conn.to_s ).to eq( "{#{TEST_UUID}} #{TEST_SEND_SPEC} <-> #{TEST_RECV_SPEC}" )
 	end
 
 	context "after a connection has been established" do
 			@request_sock = double( "request socket", :linger= => nil, :connect => nil )
 			@response_sock = double( "response socket", :linger= => nil, :identity= => nil, :connect => nil )
 
-			@ctx.stub( :socket ).with( :PULL ).and_return( @request_sock )
-			@ctx.stub( :socket ).with( :PUB ).and_return( @response_sock )
+			allow( @ctx ).to receive( :socket ).with( :PULL ).and_return( @request_sock )
+			allow( @ctx ).to receive( :socket ).with( :PUB ).and_return( @response_sock )
 
 			@conn.connect
 		end
 
 
 		it "closes both of its sockets when closed" do
-			@request_sock.should_receive( :close )
-			@response_sock.should_receive( :close )
+			expect( @request_sock ).to receive( :close )
+			expect( @response_sock ).to receive( :close )
 
 			@conn.close
 		end
 
 		it "raises an exception if asked to fetch data after being closed" do
-			@request_sock.stub( :close )
-			@response_sock.stub( :close )
+			allow( @request_sock ).to receive( :close )
+			allow( @response_sock ).to receive( :close )
 
 			@conn.close
 
 		it "doesn't keep its request and response sockets when duped" do
 			request_sock2 = double( "request socket", :linger= => nil, :connect => nil )