hatetepe 0.0.4 → 0.2.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/.rspec +1 -0
- data/.travis.yml +3 -0
- data/README.md +21 -5
- data/Rakefile +3 -10
- data/bin/hatetepe +4 -0
- data/hatetepe.gemspec +10 -3
- data/lib/hatetepe.rb +5 -0
- data/lib/hatetepe/app.rb +44 -0
- data/lib/hatetepe/body.rb +79 -0
- data/lib/hatetepe/builder.rb +19 -3
- data/lib/hatetepe/cli.rb +50 -0
- data/lib/hatetepe/client.rb +95 -0
- data/lib/hatetepe/events.rb +35 -0
- data/lib/hatetepe/message.rb +13 -0
- data/lib/hatetepe/parser.rb +41 -71
- data/lib/hatetepe/prefork.rb +11 -0
- data/lib/hatetepe/proxy.rb +58 -0
- data/lib/hatetepe/request.rb +31 -0
- data/lib/hatetepe/response.rb +20 -0
- data/lib/hatetepe/server.rb +98 -0
- data/lib/hatetepe/thread_pool.rb +4 -0
- data/lib/hatetepe/version.rb +1 -1
- data/lib/rack/handler/hatetepe.rb +33 -0
- data/spec/integration/cli/start_spec.rb +169 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/unit/app_spec.rb +108 -0
- data/spec/unit/body_spec.rb +198 -0
- data/spec/unit/client_spec.rb +270 -0
- data/spec/unit/events_spec.rb +96 -0
- data/spec/unit/parser_spec.rb +215 -0
- data/spec/unit/rack_handler_spec.rb +70 -0
- data/spec/unit/server_spec.rb +255 -0
- metadata +141 -56
- data/example.rb +0 -29
- data/test/builder_test.rb +0 -7
- data/test/parser_test.rb +0 -7
- data/test/test_helper.rb +0 -7
    
        data/lib/hatetepe/parser.rb
    CHANGED
    
    | @@ -1,68 +1,51 @@ | |
| 1 1 | 
             
            require "http/parser"
         | 
| 2 2 |  | 
| 3 | 
            +
            require "hatetepe/events"
         | 
| 4 | 
            +
            require "hatetepe/request"
         | 
| 5 | 
            +
            require "hatetepe/response"
         | 
| 6 | 
            +
             | 
| 3 7 | 
             
            module Hatetepe
         | 
| 4 8 | 
             
              class ParserError < StandardError; end
         | 
| 5 9 |  | 
| 6 10 | 
             
              class Parser
         | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
                      message[:status] = args[0]
         | 
| 17 | 
            -
                      message[:http_version] = args[1]
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                    p.on_header do |name, value|
         | 
| 20 | 
            -
                      (message[:headers] ||= {})[name] = value
         | 
| 21 | 
            -
                    end
         | 
| 22 | 
            -
                    p.on_body_chunk do |chunk|
         | 
| 23 | 
            -
                      (message[:body] ||= "") << chunk
         | 
| 24 | 
            -
                    end
         | 
| 25 | 
            -
                  end
         | 
| 26 | 
            -
                  
         | 
| 27 | 
            -
                  if block
         | 
| 28 | 
            -
                    block.arity == 0 ? parser.instance_eval(&block) : block.call(parser)
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
                  
         | 
| 31 | 
            -
                  Array(data).each {|chunk| parser << chunk }
         | 
| 32 | 
            -
                  message
         | 
| 33 | 
            -
                end
         | 
| 11 | 
            +
                include Events
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                event :reset
         | 
| 14 | 
            +
                event :request, :response
         | 
| 15 | 
            +
                event :headers, :body
         | 
| 16 | 
            +
                event :trailing_header, :trailing_headers_complete
         | 
| 17 | 
            +
                event :complete
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                attr_reader :message
         | 
| 34 20 |  | 
| 35 21 | 
             
                def initialize(&block)
         | 
| 36 | 
            -
                  @ | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
                         | 
| 22 | 
            +
                  @parser = HTTP::Parser.new.tap {|p|
         | 
| 23 | 
            +
                    p.on_headers_complete = proc {
         | 
| 24 | 
            +
                      version = p.http_version.join(".")
         | 
| 25 | 
            +
                      if p.http_method
         | 
| 26 | 
            +
                        @message = Request.new(p.http_method, p.request_url, version)
         | 
| 27 | 
            +
                        event! :request, message
         | 
| 28 | 
            +
                      else
         | 
| 29 | 
            +
                        @message = Response.new(p.status_code, version)
         | 
| 30 | 
            +
                        event! :response, message
         | 
| 45 31 | 
             
                      end
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                       | 
| 48 | 
            -
             | 
| 49 | 
            -
                       | 
| 50 | 
            -
             | 
| 32 | 
            +
                      
         | 
| 33 | 
            +
                      message.headers = p.headers
         | 
| 34 | 
            +
                      event! :headers, message.headers
         | 
| 35 | 
            +
                      
         | 
| 36 | 
            +
                      event! :body, message.body
         | 
| 37 | 
            +
                      nil
         | 
| 38 | 
            +
                    }
         | 
| 51 39 |  | 
| 52 | 
            -
                     | 
| 53 | 
            -
                       | 
| 54 | 
            -
                     | 
| 40 | 
            +
                    p.on_body = proc {|chunk|
         | 
| 41 | 
            +
                      message.body << chunk unless message.body.closed_write?
         | 
| 42 | 
            +
                    }
         | 
| 55 43 |  | 
| 56 | 
            -
                     | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
                  end
         | 
| 62 | 
            -
                  
         | 
| 63 | 
            -
                  @parser.on_message_complete = proc do
         | 
| 64 | 
            -
                    on_complete.each {|f| f.call }
         | 
| 65 | 
            -
                  end
         | 
| 44 | 
            +
                    p.on_message_complete = proc {
         | 
| 45 | 
            +
                      message.body.close_write unless message.body.closed_write?
         | 
| 46 | 
            +
                      event! :complete
         | 
| 47 | 
            +
                    }
         | 
| 48 | 
            +
                  }
         | 
| 66 49 |  | 
| 67 50 | 
             
                  reset
         | 
| 68 51 |  | 
| @@ -73,27 +56,14 @@ module Hatetepe | |
| 73 56 |  | 
| 74 57 | 
             
                def reset
         | 
| 75 58 | 
             
                  @parser.reset!
         | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
                [:request, :response, :header, :headers_complete,
         | 
| 79 | 
            -
                 :body_chunk, :complete, :error].each do |hook|
         | 
| 80 | 
            -
                  define_method :"on_#{hook}" do |&block|
         | 
| 81 | 
            -
                    store = instance_variable_get(:"@on_#{hook}")
         | 
| 82 | 
            -
                    return store unless block
         | 
| 83 | 
            -
                    store << block
         | 
| 84 | 
            -
                  end
         | 
| 59 | 
            +
                  event! :reset
         | 
| 60 | 
            +
                  @message = nil
         | 
| 85 61 | 
             
                end
         | 
| 86 62 |  | 
| 87 63 | 
             
                def <<(data)
         | 
| 88 64 | 
             
                  @parser << data
         | 
| 89 | 
            -
                rescue HTTP::Parser::Error =>  | 
| 90 | 
            -
                   | 
| 91 | 
            -
                  error.set_backtrace(original_error.backtrace)
         | 
| 92 | 
            -
                  unless on_error.empty?
         | 
| 93 | 
            -
                    on_error.each {|e| e.call(error) }
         | 
| 94 | 
            -
                  else
         | 
| 95 | 
            -
                    raise(error)
         | 
| 96 | 
            -
                  end
         | 
| 65 | 
            +
                rescue HTTP::Parser::Error => e
         | 
| 66 | 
            +
                  raise Hatetepe::ParserError, e.message, e.backtrace
         | 
| 97 67 | 
             
                end
         | 
| 98 68 | 
             
              end
         | 
| 99 69 | 
             
            end
         | 
| @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            require "eventmachine"
         | 
| 2 | 
            +
            require "uri"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require "hatetepe/client"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Hatetepe
         | 
| 7 | 
            +
              class Proxy
         | 
| 8 | 
            +
                attr_reader :app, :env
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
                def initialize(app)
         | 
| 11 | 
            +
                  @app = app
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                def call(env)
         | 
| 15 | 
            +
                  @env = env
         | 
| 16 | 
            +
                  env["proxy.start"] = method(:start)
         | 
| 17 | 
            +
                  
         | 
| 18 | 
            +
                  app.call env
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                def start(target)
         | 
| 22 | 
            +
                  uri = build_uri(target)
         | 
| 23 | 
            +
                  
         | 
| 24 | 
            +
                  env.delete "proxy.start"
         | 
| 25 | 
            +
                  env["proxy.callback"] ||= method(:callback)
         | 
| 26 | 
            +
                  
         | 
| 27 | 
            +
                  response = Client.request(verb, uri, headers)
         | 
| 28 | 
            +
                  env["proxy.callback"].call @response, env
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                def callback(response, env)
         | 
| 32 | 
            +
                  response
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            module Hatetepe
         | 
| 38 | 
            +
              class OldProxy
         | 
| 39 | 
            +
                attr_reader :env, :target
         | 
| 40 | 
            +
                
         | 
| 41 | 
            +
                def initialize(env, target)
         | 
| 42 | 
            +
                  client = EM.connect target.host, target.port, Client
         | 
| 43 | 
            +
                  client.request env["rity.request"].verb, env["rity.request"].uri
         | 
| 44 | 
            +
                  
         | 
| 45 | 
            +
                  env["proxy.callback"] ||= proc {|response|
         | 
| 46 | 
            +
                    env["proxy.start_reverse"].call response
         | 
| 47 | 
            +
                  }
         | 
| 48 | 
            +
                  env["proxy.start_reverse"] = proc {|response|
         | 
| 49 | 
            +
                    env["stream.start"].call *response[0..1]
         | 
| 50 | 
            +
                    env["stream.send_raw"].call client.requests
         | 
| 51 | 
            +
                  }
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
                
         | 
| 54 | 
            +
                def initialize(env, target)
         | 
| 55 | 
            +
                  response = Client.request(env["rity.request"])
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            require "hatetepe/message"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Hatetepe
         | 
| 4 | 
            +
              class Request < Message
         | 
| 5 | 
            +
                include EM::Deferrable
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                attr_accessor :verb, :uri, :response
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                def initialize(verb, uri, http_version = "1.1")
         | 
| 10 | 
            +
                  @verb, @uri = verb, uri
         | 
| 11 | 
            +
                  super http_version
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                def to_hash
         | 
| 15 | 
            +
                  {
         | 
| 16 | 
            +
                    "rack.version" => [1, 0],
         | 
| 17 | 
            +
                    "hatetepe.request" => self,
         | 
| 18 | 
            +
                    "rack.input" => body,
         | 
| 19 | 
            +
                    "REQUEST_METHOD" => verb.dup,
         | 
| 20 | 
            +
                    "REQUEST_URI" => uri.dup
         | 
| 21 | 
            +
                  }.tap {|h|
         | 
| 22 | 
            +
                    headers.each {|key, value|
         | 
| 23 | 
            +
                      h["HTTP_#{key.upcase.gsub(/[^A-Z_]/, "_")}"] = value
         | 
| 24 | 
            +
                    }
         | 
| 25 | 
            +
                    
         | 
| 26 | 
            +
                    h["REQUEST_PATH"], qm, h["QUERY_STRING"] = uri.partition("?")
         | 
| 27 | 
            +
                    h["PATH_INFO"], h["SCRIPT_NAME"] = h["REQUEST_PATH"].dup, ""
         | 
| 28 | 
            +
                  }
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require "hatetepe/message"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Hatetepe
         | 
| 4 | 
            +
              class Response < Message
         | 
| 5 | 
            +
                attr_accessor :status
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                def initialize(status, http_version = "1.1")
         | 
| 8 | 
            +
                  @status = status
         | 
| 9 | 
            +
                  super http_version
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                def to_a
         | 
| 13 | 
            +
                  [status, headers, body]
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                def [](i)
         | 
| 17 | 
            +
                  to_a[i]
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,98 @@ | |
| 1 | 
            +
            require "eventmachine"
         | 
| 2 | 
            +
            require "em-synchrony"
         | 
| 3 | 
            +
            require "rack"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require "hatetepe/app"
         | 
| 6 | 
            +
            require "hatetepe/builder"
         | 
| 7 | 
            +
            require "hatetepe/parser"
         | 
| 8 | 
            +
            require "hatetepe/request"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            module Hatetepe
         | 
| 11 | 
            +
              class Server < EM::Connection
         | 
| 12 | 
            +
                def self.start(config)
         | 
| 13 | 
            +
                  server = EM.start_server(config[:host], config[:port], self, config)
         | 
| 14 | 
            +
                  #Prefork.run server if config[:prefork]
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                
         | 
| 17 | 
            +
                attr_reader :app, :config, :errors
         | 
| 18 | 
            +
                attr_reader :requests, :parser, :builder
         | 
| 19 | 
            +
                
         | 
| 20 | 
            +
                def initialize(config)
         | 
| 21 | 
            +
                  @config = config
         | 
| 22 | 
            +
                  @errors = config[:errors] || $stderr
         | 
| 23 | 
            +
                  
         | 
| 24 | 
            +
                  @app = Rack::Builder.new.tap {|b|
         | 
| 25 | 
            +
                    b.use Hatetepe::App
         | 
| 26 | 
            +
                    #b.use Hatetepe::Proxy
         | 
| 27 | 
            +
                    b.run config[:app]
         | 
| 28 | 
            +
                  }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  super
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                def post_init
         | 
| 34 | 
            +
                  @requests = []
         | 
| 35 | 
            +
                  @parser, @builder = Parser.new, Builder.new
         | 
| 36 | 
            +
                  
         | 
| 37 | 
            +
                  parser.on_request << requests.method(:<<)
         | 
| 38 | 
            +
                  parser.on_headers << method(:process)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  builder.on_write << method(:send_data)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
                
         | 
| 43 | 
            +
                def receive_data(data)
         | 
| 44 | 
            +
                  parser << data
         | 
| 45 | 
            +
                rescue ParserError
         | 
| 46 | 
            +
                  close_connection
         | 
| 47 | 
            +
                rescue Exception => ex
         | 
| 48 | 
            +
                  close_connection_after_writing
         | 
| 49 | 
            +
                  backtrace = ex.backtrace.map {|line| "\t#{line}" }.join("\n")
         | 
| 50 | 
            +
                  errors << "#{ex.class}: #{ex.message}\n#{backtrace}\n"
         | 
| 51 | 
            +
                  errors.flush
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
                
         | 
| 54 | 
            +
                def process(*)
         | 
| 55 | 
            +
                  previous, request = requests.values_at(-2, -1)
         | 
| 56 | 
            +
                  
         | 
| 57 | 
            +
                  env = request.to_hash.tap {|e|
         | 
| 58 | 
            +
                    e["hatetepe.connection"] = self
         | 
| 59 | 
            +
                    e["rack.url_scheme"] = "http"
         | 
| 60 | 
            +
                    e["rack.input"].source = self
         | 
| 61 | 
            +
                    e["rack.errors"] = errors
         | 
| 62 | 
            +
                    
         | 
| 63 | 
            +
                    e["rack.multithread"] = false
         | 
| 64 | 
            +
                    e["rack.multiprocess"] = false
         | 
| 65 | 
            +
                    e["rack.run_once"] = false
         | 
| 66 | 
            +
                    
         | 
| 67 | 
            +
                    e["SERVER_NAME"] = config[:host].dup
         | 
| 68 | 
            +
                    e["SERVER_PORT"] = String(config[:port])
         | 
| 69 | 
            +
                    
         | 
| 70 | 
            +
                    host = e["HTTP_HOST"] || config[:host].dup
         | 
| 71 | 
            +
                    host += ":#{config[:port]}" unless host.include? ":"
         | 
| 72 | 
            +
                    e["HTTP_HOST"] = host
         | 
| 73 | 
            +
                    
         | 
| 74 | 
            +
                    e["stream.start"] = proc {|response|
         | 
| 75 | 
            +
                      e.delete "stream.start"
         | 
| 76 | 
            +
                      EM::Synchrony.sync previous if previous
         | 
| 77 | 
            +
                      response[1]["Server"] = "hatetepe/#{VERSION}"
         | 
| 78 | 
            +
                      builder.response response[0..1]
         | 
| 79 | 
            +
                    }
         | 
| 80 | 
            +
                    
         | 
| 81 | 
            +
                    e["stream.send"] = builder.method(:body)
         | 
| 82 | 
            +
                    
         | 
| 83 | 
            +
                    e["stream.close"] = proc {
         | 
| 84 | 
            +
                      e.delete "stream.send"
         | 
| 85 | 
            +
                      e.delete "stream.close"
         | 
| 86 | 
            +
                      
         | 
| 87 | 
            +
                      builder.complete
         | 
| 88 | 
            +
                      requests.delete request
         | 
| 89 | 
            +
                      request.succeed
         | 
| 90 | 
            +
                      
         | 
| 91 | 
            +
                      close_connection_after_writing if requests.empty?
         | 
| 92 | 
            +
                    }
         | 
| 93 | 
            +
                  }
         | 
| 94 | 
            +
                  
         | 
| 95 | 
            +
                  Fiber.new { app.call env }.resume
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
            end
         | 
    
        data/lib/hatetepe/version.rb
    CHANGED
    
    
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            require "eventmachine"
         | 
| 2 | 
            +
            require "hatetepe/server"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Rack
         | 
| 5 | 
            +
              module Handler
         | 
| 6 | 
            +
                class Hatetepe
         | 
| 7 | 
            +
                  def self.run(app, options = {})
         | 
| 8 | 
            +
                    options = {
         | 
| 9 | 
            +
                      :host => options[:Host] || "0.0.0.0",
         | 
| 10 | 
            +
                      :port => options[:Port] || 8080,
         | 
| 11 | 
            +
                      :app => app
         | 
| 12 | 
            +
                    }
         | 
| 13 | 
            +
                    
         | 
| 14 | 
            +
                    Signal.trap("INT") { EM.stop }
         | 
| 15 | 
            +
                    Signal.trap("TERM") { EM.stop }
         | 
| 16 | 
            +
                    
         | 
| 17 | 
            +
                    EM.run {
         | 
| 18 | 
            +
                      EM.epoll
         | 
| 19 | 
            +
                      
         | 
| 20 | 
            +
                      server = ::Hatetepe::Server.start options
         | 
| 21 | 
            +
                      yield server if block_given?
         | 
| 22 | 
            +
                    }
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def self.valid_options
         | 
| 26 | 
            +
                    {
         | 
| 27 | 
            +
                      "Host=HOST" => "Hostname to listen on (default: 0.0.0.0 / all interfaces)",
         | 
| 28 | 
            +
                      "Port=PORT" => "Port to listen on (default: 8080)",
         | 
| 29 | 
            +
                    }
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -0,0 +1,169 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
            require "hatetepe/cli"
         | 
| 3 | 
            +
            require "socket"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            describe "start command" do
         | 
| 6 | 
            +
              def hook_event_loop(&block)
         | 
| 7 | 
            +
                EM.spec_hooks << block
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              def add_stop_timer(timeout)
         | 
| 11 | 
            +
                hook_event_loop do
         | 
| 12 | 
            +
                  EM.add_timer(timeout) { EM.stop }
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
              
         | 
| 16 | 
            +
              before do
         | 
| 17 | 
            +
                $stderr = StringIO.new ""
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                FakeFS.activate!
         | 
| 20 | 
            +
                File.open("config.ru", "w") do |f|
         | 
| 21 | 
            +
                  f.write %q{run proc {|e| [200, {"Content-Type" => "text/plain"}, [e["REQUEST_URI"]]] }}
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                File.open("config2.ru", "w") do |f|
         | 
| 24 | 
            +
                  f.write %q{run proc {|e| [200, {"Content-Type" => "text/plain"}, ["config2.ru loaded"]] }}
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
              
         | 
| 28 | 
            +
              after do
         | 
| 29 | 
            +
                $stderr = STDERR
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                FakeFS.deactivate!
         | 
| 32 | 
            +
                FakeFS::FileSystem.clear
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
              it "starts an instance of Rity" do
         | 
| 36 | 
            +
                add_stop_timer 0.05
         | 
| 37 | 
            +
                hook_event_loop do
         | 
| 38 | 
            +
                  Socket.tcp("127.0.0.1", 3000) {|*| }
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
                Hatetepe::CLI.start %w{}
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                $stderr.string.should include("127.0.0.1:3000")
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
              
         | 
| 45 | 
            +
              it "answers HTTP requests" do
         | 
| 46 | 
            +
                add_stop_timer 0.02
         | 
| 47 | 
            +
                hook_event_loop do
         | 
| 48 | 
            +
                  request = EM::HttpRequest.new("http://127.0.0.1:3000").aget
         | 
| 49 | 
            +
                  response = EM::Synchrony.sync(request)
         | 
| 50 | 
            +
                  
         | 
| 51 | 
            +
                  response.response_header.status.should == 200
         | 
| 52 | 
            +
                  response.response_header["CONTENT_TYPE"].should == "text/plain"
         | 
| 53 | 
            +
                  response.response.should == "/"
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
                Hatetepe::CLI.start %w{}
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
              
         | 
| 58 | 
            +
              describe "--port option" do
         | 
| 59 | 
            +
                it "changes the listen port" do
         | 
| 60 | 
            +
                  add_stop_timer 0.05
         | 
| 61 | 
            +
                  hook_event_loop do
         | 
| 62 | 
            +
                    Socket.tcp("127.0.0.1", 3001) {|*| }
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                  Hatetepe::CLI.start %w{--port=3001}
         | 
| 65 | 
            +
                  
         | 
| 66 | 
            +
                  $stderr.string.should include(":3001")
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
                it "has an alias: -p" do
         | 
| 70 | 
            +
                  add_stop_timer 0.05
         | 
| 71 | 
            +
                  hook_event_loop do
         | 
| 72 | 
            +
                    Socket.tcp("127.0.0.1", 3002) {|*| }
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                  Hatetepe::CLI.start %w{-p 3002}
         | 
| 75 | 
            +
                  
         | 
| 76 | 
            +
                  $stderr.string.should include(":3002")
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
              
         | 
| 80 | 
            +
              describe "--bind option" do
         | 
| 81 | 
            +
                it "changes the listen interface" do
         | 
| 82 | 
            +
                  add_stop_timer 0.05
         | 
| 83 | 
            +
                  hook_event_loop do
         | 
| 84 | 
            +
                    Socket.tcp("127.0.0.2", 3000) {|*| }
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
                  Hatetepe::CLI.start %w{--bind=127.0.0.2}
         | 
| 87 | 
            +
                  
         | 
| 88 | 
            +
                  $stderr.string.should include("127.0.0.2:")
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
                
         | 
| 91 | 
            +
                it "has an alias: -b" do
         | 
| 92 | 
            +
                  add_stop_timer 0.05
         | 
| 93 | 
            +
                  hook_event_loop do
         | 
| 94 | 
            +
                    Socket.tcp("127.0.0.3", 3000) {|*| }
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                  Hatetepe::CLI.start %w{-b 127.0.0.3}
         | 
| 97 | 
            +
                  
         | 
| 98 | 
            +
                  $stderr.string.should include("127.0.0.3:")
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
              
         | 
| 102 | 
            +
              describe "--rackup option" do
         | 
| 103 | 
            +
                it "changes the rackup file that'll be loaded" do
         | 
| 104 | 
            +
                  add_stop_timer 0.05
         | 
| 105 | 
            +
                  hook_event_loop do
         | 
| 106 | 
            +
                    request = EM::HttpRequest.new("http://127.0.0.1:3000").aget
         | 
| 107 | 
            +
                    response = EM::Synchrony.sync(request)
         | 
| 108 | 
            +
                    response.response.should include("config2.ru")
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                  Hatetepe::CLI.start %w{--rackup=config2.ru}
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
                
         | 
| 113 | 
            +
                it "has an alias: -r" do
         | 
| 114 | 
            +
                  add_stop_timer 0.05
         | 
| 115 | 
            +
                  hook_event_loop do
         | 
| 116 | 
            +
                    request = EM::HttpRequest.new("http://127.0.0.1:3000").aget
         | 
| 117 | 
            +
                    response = EM::Synchrony.sync(request)
         | 
| 118 | 
            +
                    response.response.should include("config2.ru")
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
                  Hatetepe::CLI.start %w{-r config2.ru}
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
              end
         | 
| 123 | 
            +
              
         | 
| 124 | 
            +
              describe "--quiet option" do
         | 
| 125 | 
            +
                it "discards all output" do
         | 
| 126 | 
            +
                  pending
         | 
| 127 | 
            +
                  
         | 
| 128 | 
            +
                  add_stop_timer 0.05
         | 
| 129 | 
            +
                  Hatetepe::CLI.start %w{--quiet}
         | 
| 130 | 
            +
                  
         | 
| 131 | 
            +
                  $stderr.string.should be_empty
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
                
         | 
| 134 | 
            +
                it "has an alias: -q" do
         | 
| 135 | 
            +
                  pending
         | 
| 136 | 
            +
                  
         | 
| 137 | 
            +
                  add_stop_timer 0.05
         | 
| 138 | 
            +
                  Hatetepe::CLI.start %w{-q}
         | 
| 139 | 
            +
                  
         | 
| 140 | 
            +
                  $stderr.string.should be_empty
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
              end
         | 
| 143 | 
            +
              
         | 
| 144 | 
            +
              describe "--verbose option" do
         | 
| 145 | 
            +
                it "prints debugging data" do
         | 
| 146 | 
            +
                  pending
         | 
| 147 | 
            +
                  
         | 
| 148 | 
            +
                  add_stop_timer 0.05
         | 
| 149 | 
            +
                  hook_event_loop do
         | 
| 150 | 
            +
                    request = EM::HttpRequest.new("http://127.0.0.1:3000").aget
         | 
| 151 | 
            +
                  end
         | 
| 152 | 
            +
                  Hatetepe::CLI.start %w{--verbose}
         | 
| 153 | 
            +
                  
         | 
| 154 | 
            +
                  $stderr.string.split("\n").size.should > 10
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                it "has an alias: -V" do
         | 
| 158 | 
            +
                  pending
         | 
| 159 | 
            +
                  
         | 
| 160 | 
            +
                  add_stop_timer 0.05
         | 
| 161 | 
            +
                  hook_event_loop do
         | 
| 162 | 
            +
                    request = EM::HttpRequest.new("http://127.0.0.1:3000").aget
         | 
| 163 | 
            +
                  end
         | 
| 164 | 
            +
                  Hatetepe::CLI.start %w{-V}
         | 
| 165 | 
            +
                  
         | 
| 166 | 
            +
                  $stderr.string.split("\n").size.should > 10
         | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
              end
         | 
| 169 | 
            +
            end
         |