File: spec_helper.rb

package info (click to toggle)
thin 1.3.1-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 1,084 kB
  • sloc: ruby: 4,138; ansic: 1,537; sh: 82; makefile: 8
file content (234 lines) | stat: -rw-r--r-- 5,482 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
require 'rubygems'
require 'thin'
gem "rspec", "~> 1.2.9"
require 'spec'
require 'benchmark'
require 'timeout'
require 'fileutils'
require 'net/http'
require 'socket'

include Thin

FileUtils.mkdir_p File.dirname(__FILE__) + '/../log'
Command.script = File.dirname(__FILE__) + '/../bin/thin'
Logging.silent = true

unless Object.const_defined?(:SWIFTIPLY_PATH)
  SWIFTIPLY_PATH       = `which swiftiply`.chomp
  DEFAULT_TEST_ADDRESS = '0.0.0.0'
  DEFAULT_TEST_PORT    = 3333
end

module Matchers
  class BeFasterThen
    def initialize(max_time)
      require 'benchmark_unit'
      @max_time = max_time
    end

    # Base on benchmark_unit/assertions#compare_benchmarks
    def matches?(proc)
      @time, multiplier = 0, 1
      
      while (@time < 0.01) do
        @time = Benchmark::Unit.measure do 
          multiplier.times &proc
        end
        multiplier *= 10
      end
      
      multiplier /= 10
      
      iterations = (Benchmark::Unit::CLOCK_TARGET / @time).to_i * multiplier
      iterations = 1 if iterations < 1
      
      total = Benchmark::Unit.measure do 
        iterations.times &proc
      end
      
      @time = total / iterations
      
      @time < @max_time
    end
    
    def failure_message(less_more=:less)
      "took <#{@time.inspect} RubySeconds>, should take #{less_more} than #{@max_time} RubySeconds."
    end

    def negative_failure_message
      failure_message :more
    end
  end
  
  class ValidateWithLint
    def matches?(request)
      @request = request
      Rack::Lint.new(proc{[200, {'Content-Type' => 'text/html', 'Content-Length' => '0'}, []]}).call(@request.env)
      true
    rescue Rack::Lint::LintError => e
      @message = e.message
      false
    end
    
    def failure_message(negation=nil)
      "should#{negation} validate with Rack Lint: #{@message}"
    end

    def negative_failure_message
      failure_message ' not'
    end
  end

  class TakeLessThen
    def initialize(time)
      @time = time
    end
    
    def matches?(proc)
      Timeout.timeout(@time) { proc.call }
      true
    rescue Timeout::Error
      false 
    end
    
    def failure_message(negation=nil)
      "should#{negation} take less then #{@time} sec to run"
    end

    def negative_failure_message
      failure_message ' not'
    end
  end

  # Actual matchers that are exposed.

  def be_faster_then(time)
    BeFasterThen.new(time)
  end
  
  def validate_with_lint
    ValidateWithLint.new
  end

  def take_less_then(time)
    TakeLessThen.new(time)
  end  
end

module Helpers
  # Silences any stream for the duration of the block.
  #
  #   silence_stream(STDOUT) do
  #     puts 'This will never be seen'
  #   end
  #
  #   puts 'But this will'
  #
  # (Taken from ActiveSupport)
  def silence_stream(stream)
    old_stream = stream.dup
    stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
    stream.sync = true
    yield
  ensure
    stream.reopen(old_stream)
  end
  
  def silence_warnings
    old_verbose, $VERBOSE = $VERBOSE, nil
    yield
  ensure
    $VERBOSE = old_verbose
  end
  
  # Create and parse a request
  def R(raw, convert_line_feed=false)
    raw.gsub!("\n", "\r\n") if convert_line_feed
    request = Thin::Request.new
    request.parse(raw)
    request
  end
  
  def start_server(address=DEFAULT_TEST_ADDRESS, port=DEFAULT_TEST_PORT, options={}, &app)
    @server = Thin::Server.new(address, port, options, app)
    @server.ssl = options[:ssl]
    @server.threaded = options[:threaded]
    @server.timeout = 3
    
    @thread = Thread.new { @server.start }
    if options[:wait_for_socket]
      wait_for_socket(address, port)
    else
      # If we can't ping the address fallback to just wait for the server to run
      sleep 0.01 until @server.running?
    end
  end
  
  def stop_server
    @server.stop!
    @thread.kill
    
    100.times do
      break unless EM.reactor_running?
      sleep 0.01
    end

    raise "Reactor still running, wtf?" if EventMachine.reactor_running?
  end
  
  def wait_for_socket(address=DEFAULT_TEST_ADDRESS, port=DEFAULT_TEST_PORT, timeout=5)
    Timeout.timeout(timeout) do
      loop do
        begin
          if address.include?('/')
            UNIXSocket.new(address).close
          else
            TCPSocket.new(address, port).close
          end
          return true
        rescue
        end
      end
    end
  end
    
  def send_data(data)
    if @server.backend.class == Backends::UnixServer
      socket = UNIXSocket.new(@server.socket)
    else
      socket = TCPSocket.new(@server.host, @server.port)
    end
    socket.write data
    out = socket.read
    socket.close
    out
  end
  
  def parse_response(response)
    raw_headers, body = response.split("\r\n\r\n", 2)
    raw_status, raw_headers = raw_headers.split("\r\n", 2)

    status  = raw_status.match(%r{\AHTTP/1.1\s+(\d+)\b}).captures.first.to_i
    headers = Hash[ *raw_headers.split("\r\n").map { |h| h.split(/:\s+/, 2) }.flatten ]

    [ status, headers, body ]
  end
  
  def get(url)
    if @server.backend.class == Backends::UnixServer
      send_data("GET #{url} HTTP/1.1\r\nConnection: close\r\n\r\n")
    else
      Net::HTTP.get(URI.parse("http://#{@server.host}:#{@server.port}" + url))
    end
  end
  
  def post(url, params={})
    Net::HTTP.post_form(URI.parse("http://#{@server.host}:#{@server.port}" + url), params).body
  end
end

Spec::Runner.configure do |config|
  config.include Matchers
  config.include Helpers
end