rainbows 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +12 -6
- data/README +3 -2
- data/Rakefile +3 -3
- data/TODO +2 -9
- data/lib/rainbows.rb +1 -0
- data/lib/rainbows/app_pool.rb +10 -6
- data/lib/rainbows/base.rb +1 -1
- data/lib/rainbows/const.rb +1 -1
- data/lib/rainbows/ev_core.rb +88 -0
- data/lib/rainbows/event_machine.rb +218 -0
- data/lib/rainbows/http_server.rb +4 -1
- data/lib/rainbows/rev.rb +21 -89
- data/lib/rainbows/revactor.rb +4 -10
- data/local.mk.sample +13 -7
- data/rainbows.gemspec +17 -2
- data/t/.gitignore +1 -0
- data/t/GNUmakefile +63 -40
- data/t/README +6 -2
- data/t/async_sinatra.ru +13 -0
- data/t/bin/unused_listen +1 -1
- data/t/large-file-response.ru +1 -0
- data/t/my-tap-lib.sh +200 -0
- data/t/simple-http_Base.ru +3 -0
- data/t/simple-http_EventMachine.ru +9 -0
- data/t/simple-http_Rev.ru +9 -0
- data/t/simple-http_Revactor.ru +10 -0
- data/t/simple-http_ThreadPool.ru +10 -0
- data/t/simple-http_ThreadSpawn.ru +10 -0
- data/t/t0000-simple-http.sh +142 -0
- data/t/t0001-unix-http.sh +103 -0
- data/t/t0002-graceful.sh +32 -0
- data/t/t0002-parser-error.sh +31 -0
- data/t/t0003-reopen-logs.sh +97 -0
- data/t/t0005-large-file-response.sh +83 -0
- data/t/t0100-rack-input-hammer.sh +45 -0
- data/t/t0101-rack-input-trailer.sh +68 -0
- data/t/t0200-async-response.sh +66 -0
- data/t/t0201-async-response-no-autochunk.sh +3 -0
- data/t/t0300-async_sinatra.sh +65 -0
- data/t/t9000-rack-app-pool.sh +45 -33
- data/t/test-lib.sh +67 -56
- metadata +26 -56
- data/t/lib-async-response-no-autochunk.sh +0 -6
- data/t/lib-async-response.sh +0 -45
- data/t/lib-graceful.sh +0 -40
- data/t/lib-input-trailer.sh +0 -63
- data/t/lib-large-file-response.sh +0 -45
- data/t/lib-parser-error.sh +0 -29
- data/t/lib-rack-input-hammer.sh +0 -38
- data/t/lib-reopen-logs.sh +0 -60
- data/t/lib-simple-http.sh +0 -92
- data/t/t0000-basic.sh +0 -2
- data/t/t1000-thread-pool-basic.sh +0 -2
- data/t/t1002-thread-pool-graceful.sh +0 -2
- data/t/t1003-thread-pool-reopen-logs.sh +0 -2
- data/t/t1004-thread-pool-async-response.sh +0 -45
- data/t/t1005-thread-pool-large-file-response.sh +0 -45
- data/t/t1006-thread-pool-async-response-no-autochunk.sh +0 -6
- data/t/t1100-thread-pool-rack-input.sh +0 -2
- data/t/t1101-thread-pool-input-trailer.sh +0 -2
- data/t/t2000-thread-spawn-basic.sh +0 -2
- data/t/t2002-thread-spawn-graceful.sh +0 -2
- data/t/t2003-thread-spawn-reopen-logs.sh +0 -2
- data/t/t2004-thread-spawn-async-response.sh +0 -45
- data/t/t2005-thread-spawn-large-file-response.sh +0 -45
- data/t/t2006-thread-spawn-async-response-no-autochunk.sh +0 -6
- data/t/t2100-thread-spawn-rack-input.sh +0 -2
- data/t/t2101-thread-spawn-input-trailer.sh +0 -2
- data/t/t3000-revactor-basic.sh +0 -2
- data/t/t3002-revactor-graceful.sh +0 -2
- data/t/t3003-revactor-reopen-logs.sh +0 -2
- data/t/t3004-revactor-async-response.sh +0 -45
- data/t/t3005-revactor-large-file-response.sh +0 -2
- data/t/t3006-revactor-async-response-no-autochunk.sh +0 -6
- data/t/t3100-revactor-rack-input.sh +0 -2
- data/t/t3101-revactor-rack-input-trailer.sh +0 -2
- data/t/t4000-rev-basic.sh +0 -2
- data/t/t4002-rev-graceful.sh +0 -2
- data/t/t4003-rev-parser-error.sh +0 -2
- data/t/t4003-rev-reopen-logs.sh +0 -2
- data/t/t4004-rev-async-response.sh +0 -45
- data/t/t4005-rev-large-file-response.sh +0 -2
- data/t/t4006-rev-async-response-no-autochunk.sh +0 -6
- data/t/t4100-rev-rack-input.sh +0 -2
- data/t/t4101-rev-rack-input-trailer.sh +0 -2
    
        data/lib/rainbows/http_server.rb
    CHANGED
    
    | @@ -33,7 +33,10 @@ module Rainbows | |
| 33 33 | 
             
                  extend(mod)
         | 
| 34 34 | 
             
                  Const::RACK_DEFAULTS['rainbows.model'] = @use = model
         | 
| 35 35 | 
             
                  Const::RACK_DEFAULTS['rack.multithread'] = !!(/Thread/ =~ model.to_s)
         | 
| 36 | 
            -
                   | 
| 36 | 
            +
                  case model
         | 
| 37 | 
            +
                  when :Rev, :EventMachine
         | 
| 38 | 
            +
                    Const::RACK_DEFAULTS['rainbows.autochunk'] = true
         | 
| 39 | 
            +
                  end
         | 
| 37 40 | 
             
                end
         | 
| 38 41 |  | 
| 39 42 | 
             
                def worker_connections(*args)
         | 
    
        data/lib/rainbows/rev.rb
    CHANGED
    
    | @@ -1,9 +1,7 @@ | |
| 1 1 | 
             
            # -*- encoding: binary -*-
         | 
| 2 2 | 
             
            require 'rev'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
            # ref: http://rubyforge.org/pipermail/revactor-talk/2009-October/000034.html
         | 
| 6 | 
            -
            defined?(Rev::Buffer) or Rev::Buffer = IO::Buffer
         | 
| 3 | 
            +
            Rev::VERSION >= '0.3.0' or abort 'rev >= 0.3.0 is required'
         | 
| 4 | 
            +
            require 'rainbows/ev_core'
         | 
| 7 5 |  | 
| 8 6 | 
             
            module Rainbows
         | 
| 9 7 |  | 
| @@ -30,46 +28,22 @@ module Rainbows | |
| 30 28 | 
             
                include Base
         | 
| 31 29 |  | 
| 32 30 | 
             
                class Client < ::Rev::IO
         | 
| 33 | 
            -
                  include  | 
| 34 | 
            -
                  include Rainbows::Const
         | 
| 31 | 
            +
                  include Rainbows::EvCore
         | 
| 35 32 | 
             
                  G = Rainbows::G
         | 
| 36 33 |  | 
| 37 | 
            -
                  # queued, optional response bodies, it should only be unpollable "fast"
         | 
| 38 | 
            -
                  # devices where read(2) is uninterruptable.  Unfortunately, NFS and ilk
         | 
| 39 | 
            -
                  # are also part of this.  We'll also stick DeferredResponse bodies in
         | 
| 40 | 
            -
                  # here to prevent connections from being closed on us.
         | 
| 41 | 
            -
                  attr_reader :deferred_bodies
         | 
| 42 | 
            -
             | 
| 43 34 | 
             
                  def initialize(io)
         | 
| 44 35 | 
             
                    G.cur += 1
         | 
| 45 36 | 
             
                    super(io)
         | 
| 46 | 
            -
                     | 
| 47 | 
            -
                    @env = {}
         | 
| 48 | 
            -
                    @hp = HttpParser.new
         | 
| 49 | 
            -
                    @state = :headers # [ :body [ :trailers ] ] :app_call :close
         | 
| 50 | 
            -
                    @buf = ""
         | 
| 51 | 
            -
                    @deferred_bodies = [] # for (fast) regular files only
         | 
| 52 | 
            -
                  end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                  # graceful exit, like SIGQUIT
         | 
| 55 | 
            -
                  def quit
         | 
| 56 | 
            -
                    @deferred_bodies.clear
         | 
| 57 | 
            -
                    @state = :close
         | 
| 37 | 
            +
                    post_init
         | 
| 58 38 | 
             
                  end
         | 
| 59 39 |  | 
| 60 | 
            -
                   | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
                     | 
| 66 | 
            -
             | 
| 67 | 
            -
                    else
         | 
| 68 | 
            -
                      G.logger.error "Read error: #{e.inspect}"
         | 
| 69 | 
            -
                      G.logger.error e.backtrace.join("\n")
         | 
| 70 | 
            -
                      ERROR_500_RESPONSE
         | 
| 71 | 
            -
                    end
         | 
| 72 | 
            -
                    write(msg)
         | 
| 40 | 
            +
                  # queued, optional response bodies, it should only be unpollable "fast"
         | 
| 41 | 
            +
                  # devices where read(2) is uninterruptable.  Unfortunately, NFS and ilk
         | 
| 42 | 
            +
                  # are also part of this.  We'll also stick DeferredResponse bodies in
         | 
| 43 | 
            +
                  # here to prevent connections from being closed on us.
         | 
| 44 | 
            +
                  def defer_body(io)
         | 
| 45 | 
            +
                    @deferred_bodies << io
         | 
| 46 | 
            +
                    on_write_complete unless @hp.headers? # triggers a write
         | 
| 73 47 | 
             
                  end
         | 
| 74 48 |  | 
| 75 49 | 
             
                  def app_call
         | 
| @@ -89,7 +63,7 @@ module Rainbows | |
| 89 63 | 
             
                        # keepalive requests are always body-less, so @input is unchanged
         | 
| 90 64 | 
             
                        @hp.headers(@env, @buf) and next
         | 
| 91 65 | 
             
                      else
         | 
| 92 | 
            -
                         | 
| 66 | 
            +
                        quit
         | 
| 93 67 | 
             
                      end
         | 
| 94 68 | 
             
                      return
         | 
| 95 69 | 
             
                    end while true
         | 
| @@ -104,6 +78,7 @@ module Rainbows | |
| 104 78 | 
             
                        rescue EOFError # expected at file EOF
         | 
| 105 79 | 
             
                          @deferred_bodies.shift
         | 
| 106 80 | 
             
                          body.close
         | 
| 81 | 
            +
                          close if :close == @state && @deferred_bodies.empty?
         | 
| 107 82 | 
             
                        end
         | 
| 108 83 | 
             
                      rescue Object => e
         | 
| 109 84 | 
             
                        handle_error(e)
         | 
| @@ -116,53 +91,6 @@ module Rainbows | |
| 116 91 | 
             
                  def on_close
         | 
| 117 92 | 
             
                    G.cur -= 1
         | 
| 118 93 | 
             
                  end
         | 
| 119 | 
            -
             | 
| 120 | 
            -
                  def tmpio
         | 
| 121 | 
            -
                    io = Util.tmpio
         | 
| 122 | 
            -
                    def io.size
         | 
| 123 | 
            -
                      # already sync=true at creation, so no need to flush before stat
         | 
| 124 | 
            -
                      stat.size
         | 
| 125 | 
            -
                    end
         | 
| 126 | 
            -
                    io
         | 
| 127 | 
            -
                  end
         | 
| 128 | 
            -
             | 
| 129 | 
            -
                  # TeeInput doesn't map too well to this right now...
         | 
| 130 | 
            -
                  def on_read(data)
         | 
| 131 | 
            -
                    case @state
         | 
| 132 | 
            -
                    when :headers
         | 
| 133 | 
            -
                      @hp.headers(@env, @buf << data) or return
         | 
| 134 | 
            -
                      @state = :body
         | 
| 135 | 
            -
                      len = @hp.content_length
         | 
| 136 | 
            -
                      if len == 0
         | 
| 137 | 
            -
                        @input = HttpRequest::NULL_IO
         | 
| 138 | 
            -
                        app_call # common case
         | 
| 139 | 
            -
                      else # nil or len > 0
         | 
| 140 | 
            -
                        # since we don't do streaming input, we have no choice but
         | 
| 141 | 
            -
                        # to take over 100-continue handling from the Rack application
         | 
| 142 | 
            -
                        if @env[HTTP_EXPECT] =~ /\A100-continue\z/i
         | 
| 143 | 
            -
                          write(EXPECT_100_RESPONSE)
         | 
| 144 | 
            -
                          @env.delete(HTTP_EXPECT)
         | 
| 145 | 
            -
                        end
         | 
| 146 | 
            -
                        @input = len && len <= MAX_BODY ? StringIO.new("") : tmpio
         | 
| 147 | 
            -
                        @hp.filter_body(@buf2 = @buf.dup, @buf)
         | 
| 148 | 
            -
                        @input << @buf2
         | 
| 149 | 
            -
                        on_read("")
         | 
| 150 | 
            -
                      end
         | 
| 151 | 
            -
                    when :body
         | 
| 152 | 
            -
                      if @hp.body_eof?
         | 
| 153 | 
            -
                        @state = :trailers
         | 
| 154 | 
            -
                        on_read(data)
         | 
| 155 | 
            -
                      elsif data.size > 0
         | 
| 156 | 
            -
                        @hp.filter_body(@buf2, @buf << data)
         | 
| 157 | 
            -
                        @input << @buf2
         | 
| 158 | 
            -
                        on_read("")
         | 
| 159 | 
            -
                      end
         | 
| 160 | 
            -
                    when :trailers
         | 
| 161 | 
            -
                      @hp.trailers(@env, @buf << data) and app_call
         | 
| 162 | 
            -
                    end
         | 
| 163 | 
            -
                    rescue Object => e
         | 
| 164 | 
            -
                      handle_error(e)
         | 
| 165 | 
            -
                  end
         | 
| 166 94 | 
             
                end
         | 
| 167 95 |  | 
| 168 96 | 
             
                class Server < ::Rev::IO
         | 
| @@ -172,7 +100,7 @@ module Rainbows | |
| 172 100 | 
             
                    return if G.cur >= G.max
         | 
| 173 101 | 
             
                    begin
         | 
| 174 102 | 
             
                      Client.new(@_io.accept_nonblock).attach(::Rev::Loop.default)
         | 
| 175 | 
            -
                    rescue Errno::EAGAIN, Errno:: | 
| 103 | 
            +
                    rescue Errno::EAGAIN, Errno::ECONNABORTED
         | 
| 176 104 | 
             
                    end
         | 
| 177 105 | 
             
                  end
         | 
| 178 106 |  | 
| @@ -191,7 +119,7 @@ module Rainbows | |
| 191 119 | 
             
                    # here since we can't get here without checking to_path first
         | 
| 192 120 | 
             
                    io = body.to_io if body.respond_to?(:to_io)
         | 
| 193 121 | 
             
                    io ||= ::IO.new($1.to_i) if body.to_path =~ %r{\A/dev/fd/(\d+)\z}
         | 
| 194 | 
            -
                    io ||= File.open( | 
| 122 | 
            +
                    io ||= File.open(body.to_path, 'rb')
         | 
| 195 123 | 
             
                    st = io.stat
         | 
| 196 124 |  | 
| 197 125 | 
             
                    if st.socket? || st.pipe?
         | 
| @@ -199,7 +127,11 @@ module Rainbows | |
| 199 127 | 
             
                      do_chunk = false if headers.delete('X-Rainbows-Autochunk') == 'no'
         | 
| 200 128 | 
             
                      # too tricky to support keepalive/pipelining when a response can
         | 
| 201 129 | 
             
                      # take an indeterminate amount of time here.
         | 
| 202 | 
            -
                      out | 
| 130 | 
            +
                      if out.nil?
         | 
| 131 | 
            +
                        do_chunk = false
         | 
| 132 | 
            +
                      else
         | 
| 133 | 
            +
                        out[0] = CONN_CLOSE
         | 
| 134 | 
            +
                      end
         | 
| 203 135 |  | 
| 204 136 | 
             
                      io = new(io, client, do_chunk, body).attach(::Rev::Loop.default)
         | 
| 205 137 | 
             
                    elsif st.file?
         | 
| @@ -208,7 +140,7 @@ module Rainbows | |
| 208 140 | 
             
                    else # char/block device, directory, whatever... nobody cares
         | 
| 209 141 | 
             
                      return response
         | 
| 210 142 | 
             
                    end
         | 
| 211 | 
            -
                    client. | 
| 143 | 
            +
                    client.defer_body(io)
         | 
| 212 144 | 
             
                    [ response.first, headers.to_hash, [] ]
         | 
| 213 145 | 
             
                  end
         | 
| 214 146 |  | 
    
        data/lib/rainbows/revactor.rb
    CHANGED
    
    | @@ -1,9 +1,6 @@ | |
| 1 1 | 
             
            # -*- encoding: binary -*-
         | 
| 2 2 | 
             
            require 'revactor'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            # workaround revactor 0.1.4 still using the old Rev::Buffer
         | 
| 5 | 
            -
            # ref: http://rubyforge.org/pipermail/revactor-talk/2009-October/000034.html
         | 
| 6 | 
            -
            defined?(Rev::Buffer) or Rev::Buffer = IO::Buffer
         | 
| 3 | 
            +
            Revactor::VERSION >= '0.1.5' or abort 'revactor 0.1.5 is required'
         | 
| 7 4 |  | 
| 8 5 | 
             
            module Rainbows
         | 
| 9 6 |  | 
| @@ -137,16 +134,13 @@ module Rainbows | |
| 137 134 |  | 
| 138 135 | 
             
                def revactorize_listeners!
         | 
| 139 136 | 
             
                  LISTENERS.map! do |s|
         | 
| 140 | 
            -
                     | 
| 137 | 
            +
                    case s
         | 
| 138 | 
            +
                    when TCPServer
         | 
| 141 139 | 
             
                      ::Revactor::TCP.listen(s, nil)
         | 
| 142 | 
            -
                     | 
| 140 | 
            +
                    when UNIXServer
         | 
| 143 141 | 
             
                      ::Revactor::UNIX.listen(s)
         | 
| 144 | 
            -
                    else
         | 
| 145 | 
            -
                      logger.error "your version of Revactor can't handle #{s.inspect}"
         | 
| 146 | 
            -
                      nil
         | 
| 147 142 | 
             
                    end
         | 
| 148 143 | 
             
                  end
         | 
| 149 | 
            -
                  LISTENERS.compact!
         | 
| 150 144 | 
             
                end
         | 
| 151 145 |  | 
| 152 146 | 
             
              end
         | 
    
        data/local.mk.sample
    CHANGED
    
    | @@ -5,18 +5,24 @@ | |
| 5 5 | 
             
            # This is depends on a bunch of GNU-isms from bash, sed, touch.
         | 
| 6 6 |  | 
| 7 7 | 
             
            DLEXT := so
         | 
| 8 | 
            -
            gems :=  | 
| 8 | 
            +
            gems := rack-1.0.1
         | 
| 9 | 
            +
            # gems += unicorn-0.93.3 # installed via setup.rb
         | 
| 10 | 
            +
            gems += rev-0.3.1 iobuffer-0.1.1
         | 
| 11 | 
            +
            gems += eventmachine-0.12.10
         | 
| 12 | 
            +
            gems += async_sinatra-0.1.5 sinatra-0.9.4
         | 
| 9 13 |  | 
| 10 14 | 
             
            # Avoid loading rubygems to speed up tests because gmake is
         | 
| 11 15 | 
             
            # fork+exec heavy with Ruby.
         | 
| 16 | 
            +
            prefix = $(HOME)
         | 
| 12 17 | 
             
            ifeq ($(r19),)
         | 
| 13 | 
            -
               | 
| 14 | 
            -
              gem_paths := $(addprefix $( | 
| 18 | 
            +
              RUBY := $(prefix)/bin/ruby
         | 
| 19 | 
            +
              gem_paths := $(addprefix $(prefix)/lib/ruby/gems/1.8/gems/,$(gems))
         | 
| 15 20 | 
             
            else
         | 
| 16 | 
            -
               | 
| 17 | 
            -
               | 
| 18 | 
            -
               | 
| 19 | 
            -
               | 
| 21 | 
            +
              prefix := $(prefix)/ruby-1.9
         | 
| 22 | 
            +
              export PATH := $(prefix)/bin:$(PATH)
         | 
| 23 | 
            +
              RUBY := $(prefix)/bin/ruby --disable-gems
         | 
| 24 | 
            +
              gems += case-0.5 revactor-0.1.5
         | 
| 25 | 
            +
              gem_paths := $(addprefix $(prefix)/lib/ruby/gems/1.9.1/gems/,$(gems))
         | 
| 20 26 | 
             
            endif
         | 
| 21 27 |  | 
| 22 28 | 
             
            ifdef gem_paths
         | 
    
        data/rainbows.gemspec
    CHANGED
    
    | @@ -40,8 +40,23 @@ Gem::Specification.new do |s| | |
| 40 40 |  | 
| 41 41 | 
             
              s.test_files = test_files
         | 
| 42 42 |  | 
| 43 | 
            -
               | 
| 44 | 
            -
              s.add_dependency(%q<unicorn>, ["~> 0.93. | 
| 43 | 
            +
              # we need Unicorn for the HTTP parser and process management
         | 
| 44 | 
            +
              s.add_dependency(%q<unicorn>, ["~> 0.93.4"])
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              # Unicorn already depends on Rack
         | 
| 47 | 
            +
              # s.add_dependency(%q<rack>)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              # optional runtime dependencies depending on configuration
         | 
| 50 | 
            +
              # see local.mk.sample for the exact versions we've tested with
         | 
| 51 | 
            +
              #
         | 
| 52 | 
            +
              # Revactor >= 0.1.5 includes UNIX domain socket support
         | 
| 53 | 
            +
              # s.add_dependency(%q<revactor>, [">= 0.1.5"])
         | 
| 54 | 
            +
              #
         | 
| 55 | 
            +
              # Revactor depends on Rev, too, 0.3.0 got the ability to attach IOs
         | 
| 56 | 
            +
              # s.add_dependency(%q<rev>, [">= 0.3.0"])
         | 
| 57 | 
            +
              #
         | 
| 58 | 
            +
              # We use the new EM::attach/watch API in 0.12.10
         | 
| 59 | 
            +
              # s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
         | 
| 45 60 |  | 
| 46 61 | 
             
              # s.licenses = %w(GPLv2 Ruby) # accessor not compatible with older Rubygems
         | 
| 47 62 | 
             
            end
         | 
    
        data/t/.gitignore
    CHANGED
    
    
    
        data/t/GNUmakefile
    CHANGED
    
    | @@ -2,11 +2,13 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            all::
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 5 | 
            +
            pid := $(shell echo $$PPID)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            RUBY = $(ruby)
         | 
| 6 8 | 
             
            rainbows_lib := $(shell cd ../lib && pwd)
         | 
| 7 9 | 
             
            -include ../local.mk
         | 
| 8 10 | 
             
            ifeq ($(RUBY_VERSION),)
         | 
| 9 | 
            -
              RUBY_VERSION := $(shell $( | 
| 11 | 
            +
              RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
         | 
| 10 12 | 
             
            endif
         | 
| 11 13 |  | 
| 12 14 | 
             
            ifeq ($(RUBYLIB),)
         | 
| @@ -16,60 +18,81 @@ else | |
| 16 18 | 
             
            endif
         | 
| 17 19 | 
             
            export RUBYLIB RUBY_VERSION
         | 
| 18 20 |  | 
| 21 | 
            +
            models := ThreadPool ThreadSpawn Rev EventMachine
         | 
| 22 | 
            +
            ifeq ($(RUBY_VERSION),1.9.1) # 1.9.2-preview1 was broken
         | 
| 23 | 
            +
              models += Revactor
         | 
| 24 | 
            +
            endif
         | 
| 25 | 
            +
            all_models := $(models) Base
         | 
| 26 | 
            +
             | 
| 19 27 | 
             
            T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
         | 
| 20 28 |  | 
| 29 | 
            +
            MODEL_T := $(foreach m,$(all_models),$(addprefix $(m).,$(T)))
         | 
| 30 | 
            +
            $(T): MODELS = $(models)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            # some tests can be run with all models
         | 
| 33 | 
            +
            t0000-simple-http.sh: MODELS = $(all_models)
         | 
| 34 | 
            +
            t0001-unix-http.sh: MODELS = $(all_models)
         | 
| 35 | 
            +
            t0002-graceful.sh: MODELS = $(all_models)
         | 
| 36 | 
            +
            t0002-parser-error.sh: MODELS = $(all_models)
         | 
| 37 | 
            +
            t0003-reopen-logs.sh: MODELS = $(all_models)
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            # this test is not compatible with non-Thread models yet
         | 
| 40 | 
            +
            t9000-rack-app-pool.sh: MODELS = ThreadPool ThreadSpawn
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            # recursively run per-model tests
         | 
| 43 | 
            +
            # haven't figured out a good way to make make non-recursive here, yet...
         | 
| 44 | 
            +
            $(T):
         | 
| 45 | 
            +
            	$(MAKE) $(foreach m,$(MODELS),$(addprefix $(m).,$@))
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            $(all_models):
         | 
| 48 | 
            +
            	$(MAKE) $(filter $@.%,$(MODEL_T))
         | 
| 49 | 
            +
             | 
| 21 50 | 
             
            all:: $(T)
         | 
| 22 51 |  | 
| 23 52 | 
             
            # can't rely on "set -o pipefail" since we don't require bash or ksh93 :<
         | 
| 24 53 | 
             
            t_pfx = trash/$@-$(RUBY_VERSION)
         | 
| 25 | 
            -
             | 
| 26 | 
            -
            t_log = $(t_pfx).log
         | 
| 54 | 
            +
            TEST_OPTS =
         | 
| 27 55 | 
             
            # TRACER = strace -f -o $(t_pfx).strace -s 100000
         | 
| 28 56 | 
             
            # TRACER = /usr/bin/time -o $(t_pfx).time
         | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
            # prefix stdout messages with ':', and stderr messages with '!'
         | 
| 32 | 
            -
            t_wrap = ( ( ( echo 42 > $(t_code); \
         | 
| 33 | 
            -
              $(t_run); \
         | 
| 34 | 
            -
              echo $$? > $(t_code) ) \
         | 
| 35 | 
            -
              | sed 's/^/$(pfx):/' 1>&3 ) 2>&1 \
         | 
| 36 | 
            -
              | sed 's/^/$(pfx)!/' 1>&2 ) 3>&1
         | 
| 37 | 
            -
             | 
| 38 | 
            -
            ifndef V
         | 
| 39 | 
            -
              quiet_pre = @echo '* $@';
         | 
| 40 | 
            -
              quiet_post = > $(t_log) 2>&1; exit $$(cat $(t_code))
         | 
| 41 | 
            -
              pfx =
         | 
| 42 | 
            -
            else
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            ifdef V
         | 
| 43 59 | 
             
              ifeq ($(V),2)
         | 
| 44 | 
            -
                 | 
| 60 | 
            +
                TEST_OPTS += --trace
         | 
| 61 | 
            +
              else
         | 
| 62 | 
            +
                TEST_OPTS += --verbose
         | 
| 45 63 | 
             
              endif
         | 
| 46 | 
            -
              quiet_pre = @echo '* $@';
         | 
| 47 | 
            -
              quiet_post = 2>&1 | ./bin/utee $(t_log); exit $$(cat $(t_code))
         | 
| 48 | 
            -
              pfx = $@
         | 
| 49 64 | 
             
            endif
         | 
| 50 65 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
            test-bin-$(RUBY_VERSION)/rainbows: ruby_bin = $(shell which $(ruby))
         | 
| 66 | 
            +
            test-bin-$(RUBY_VERSION)/rainbows: ruby_bin = $(shell which $(RUBY))
         | 
| 54 67 | 
             
            test-bin-$(RUBY_VERSION)/rainbows: ../bin/rainbows
         | 
| 55 68 | 
             
            	mkdir -p $(@D)
         | 
| 56 | 
            -
            	install -m 755 $^  | 
| 57 | 
            -
            	$( | 
| 58 | 
            -
            	 | 
| 59 | 
            -
            	$(RM) $@+
         | 
| 69 | 
            +
            	install -m 755 $^ $@.$(pid)
         | 
| 70 | 
            +
            	$(RUBY) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $@.$(pid)
         | 
| 71 | 
            +
            	mv $@.$(pid) $@
         | 
| 60 72 |  | 
| 61 | 
            -
            req_random_blob := $(wildcard t?1??-*.sh)
         | 
| 62 73 | 
             
            random_blob:
         | 
| 63 | 
            -
            	dd if=/dev/urandom bs=1M count= | 
| 64 | 
            -
            	mv  | 
| 65 | 
            -
             | 
| 66 | 
            -
            $( | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
            $( | 
| 71 | 
            -
            $( | 
| 72 | 
            -
            	$( | 
| 74 | 
            +
            	dd if=/dev/urandom bs=1M count=30 of=$@.$(pid)
         | 
| 75 | 
            +
            	mv $@.$(pid) $@
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            $(T): random_blob
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            dependencies := socat curl
         | 
| 80 | 
            +
            deps := $(addprefix .dep+,$(dependencies))
         | 
| 81 | 
            +
            $(deps): dep_bin = $(lastword $(subst +, ,$@))
         | 
| 82 | 
            +
            $(deps):
         | 
| 83 | 
            +
            	@which $(dep_bin) > $@.$(pid) 2>/dev/null || :
         | 
| 84 | 
            +
            	@test -s $@.$(pid) || \
         | 
| 85 | 
            +
            	  { echo >&2 "E `$(dep_bin)' not found in PATH=$(PATH)"; exit 1; }
         | 
| 86 | 
            +
            	@mv $@.$(pid) $@
         | 
| 87 | 
            +
            dep: $(deps)
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            $(MODEL_T): export model = $(firstword $(subst ., ,$@))
         | 
| 90 | 
            +
            $(MODEL_T): script = $(subst $(model).,,$@)
         | 
| 91 | 
            +
            $(MODEL_T): trash/.gitignore
         | 
| 92 | 
            +
            $(MODEL_T): export RUBY := $(RUBY)
         | 
| 93 | 
            +
            $(MODEL_T): export PATH := $(CURDIR)/test-bin-$(RUBY_VERSION):$(PATH)
         | 
| 94 | 
            +
            $(MODEL_T): test-bin-$(RUBY_VERSION)/rainbows dep
         | 
| 95 | 
            +
            	$(TRACER) $(SHELL) $(SH_TEST_OPTS) $(script) $(TEST_OPTS)
         | 
| 73 96 |  | 
| 74 97 | 
             
            trash/.gitignore:
         | 
| 75 98 | 
             
            	mkdir -p $(@D)
         | 
    
        data/t/README
    CHANGED
    
    | @@ -28,9 +28,13 @@ To run the entire test suite with 8 tests running at once: | |
| 28 28 |  | 
| 29 29 | 
             
              make -j8
         | 
| 30 30 |  | 
| 31 | 
            -
            To run one individual test:
         | 
| 31 | 
            +
            To run one individual test for all concurrency models:
         | 
| 32 32 |  | 
| 33 | 
            -
              make t0000- | 
| 33 | 
            +
              make t0000-simple-http.sh
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            To run one individual test for one concurrency model:
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              make Revactor.t0000-simple-http.sh
         | 
| 34 38 |  | 
| 35 39 | 
             
            You may also increase verbosity by setting the "V" variable for
         | 
| 36 40 | 
             
            GNU make.  To disable trapping of stdout/stderr:
         | 
    
        data/t/async_sinatra.ru
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            # See http://github.com/raggi/async_sinatra
         | 
| 2 | 
            +
            # gem install async_sinatra -v0.1.5
         | 
| 3 | 
            +
            require 'sinatra/async'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class AsyncTest < Sinatra::Base
         | 
| 6 | 
            +
              register Sinatra::Async
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              aget '/:n' do |n|
         | 
| 9 | 
            +
                EM.add_timer(n.to_i) { body { "delayed for #{n} seconds\n" } }
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            run AsyncTest.new
         |