Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 138 lines (117 sloc) 3.026 kb
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
require 'sinatra/base'
require 'rbconfig'
require 'open-uri'

module IntegrationHelper
  class Server
    extend Enumerable
    attr_accessor :server, :port, :pipe
    alias name server

    def self.all
      @all ||= []
    end

    def self.each(&block)
      all.each(&block)
    end

    def self.run(server, port)
      new(server, port).run
    end

    def app_file
      File.expand_path('../integration/app.rb', __FILE__)
    end

    def environment
      "development"
    end

    def initialize(server, port)
      @installed, @pipe, @server, @port = nil, nil, server, port
      Server.all << self
    end

    def run
      return unless installed?
      @log = ""
      @pipe = IO.popen(command)
      @started = Time.now
      warn "#{server} up and running on port #{port}" if ping
      at_exit { kill }
    end

    def expect(str)
      return if log.size < str.size or log[0, str.size] == str
      raise "Server did not start properly:\n\n#{log}"
    end

    def ping(timeout = 10)
      loop do
        return if alive?
        if Time.now - @started > timeout
          $stderr.puts command, log
          get('/ping')
        else
          expect "loading"
          sleep 0.1
        end
      end
    end

    def alive?
      3.times { get('/ping') }
      true
    rescue Errno::ECONNREFUSED => error
      false
    end

    def open(url)
      super("http://127.0.0.1:#{port}#{url}")
    end

    def get(url)
      open(url).read
    end

    def log
      @log ||= ""
      loop { @log << @pipe.read_nonblock(1) }
    rescue Exception
      @log
    end

    def installed?
      return @installed unless @installed.nil?
      require server
      @installed = true
    rescue LoadError
      warn "#{server} is not installed, skipping integration tests"
      @installed = false
    end

    def command
      @command ||= begin
        cmd = ["RACK_ENV=#{environment}", "exec"]
        if RbConfig.respond_to? :ruby
          cmd << RbConfig.ruby.inspect
        else
          file, dir = RbConfig::CONFIG.values_at('ruby_install_name', 'bindir')
          cmd << File.expand_path(file, dir).inspect
        end
        cmd << "-I" << File.expand_path('../../lib', __FILE__).inspect
        cmd << app_file.inspect << '-s' << server << '-o' << '127.0.0.1' << '-p' << port
        cmd << "-e" << environment.to_s << '2>&1'
        cmd.join " "
      end
    end

    def kill
      return unless pipe
      Process.kill("KILL", pipe.pid)
    rescue NotImplementedError
      system "kill -9 #{pipe.pid}"
    end
  end

  def it(message, &block)
    Server.each do |server|
      next unless server.installed?
      super "with #{server.name}: #{message}" do
        self.server = server
        server.run unless server.alive?
        instance_eval(&block)
      end
    end
  end

  def self.extend_object(obj)
    super

    base_port = 5000 + Process.pid % 100
    Sinatra::Base.server.each_with_index do |server, index|
      Server.run(server, 5000+index)
    end
  end
end
Something went wrong with that request. Please try again.