jstd-runner 0.0.2
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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +13 -0
- data/README.rdoc +25 -0
- data/Rakefile +7 -0
- data/autotest/discover.rb +1 -0
- data/bin/jstd-runner +5 -0
- data/jstd-runner.gemspec +25 -0
- data/lib/jstd-runner.rb +27 -0
- data/lib/jstd-runner/JsTestDriver-1.2.2.jar +0 -0
- data/lib/jstd-runner/browser.rb +62 -0
- data/lib/jstd-runner/cli.rb +50 -0
- data/lib/jstd-runner/monitorable.rb +15 -0
- data/lib/jstd-runner/runner.rb +167 -0
- data/lib/jstd-runner/server.rb +79 -0
- data/lib/jstd-runner/version.rb +3 -0
- data/lib/jstd-runner/vnc_control.rb +54 -0
- data/spec/jstd-runner/browser_spec.rb +57 -0
- data/spec/jstd-runner/cli_spec.rb +47 -0
- data/spec/jstd-runner/monitorable_spec.rb +56 -0
- data/spec/jstd-runner/runner_spec.rb +40 -0
- data/spec/jstd-runner/server_spec.rb +94 -0
- data/spec/jstd-runner/vnc_control_spec.rb +7 -0
- data/spec/spec_helper.rb +3 -0
- metadata +162 -0
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            Copyright 2010 FINN.no AS
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 4 | 
            +
            you may not use this file except in compliance with the License.
         | 
| 5 | 
            +
            You may obtain a copy of the License at
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                http://www.apache.org/licenses/LICENSE-2.0
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Unless required by applicable law or agreed to in writing, software
         | 
| 10 | 
            +
            distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 11 | 
            +
            WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 12 | 
            +
            See the License for the specific language governing permissions and
         | 
| 13 | 
            +
            limitations under the License.
         | 
    
        data/README.rdoc
    ADDED
    
    | @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            = jstd-runner
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            A gem that provides a tool to launch a JsTestDriver server, capture browser(s) and monitor the involved processes.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            = TODO
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            * Config file
         | 
| 8 | 
            +
            * Support launching multiple browsers
         | 
| 9 | 
            +
            * Support launching browser through a remote WebDriver server
         | 
| 10 | 
            +
            * Configurable logging
         | 
| 11 | 
            +
            * Prettier logging
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            == Note on Patches/Pull Requests
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            * Fork the project.
         | 
| 16 | 
            +
            * Make your feature addition or bug fix.
         | 
| 17 | 
            +
            * Add tests for it. This is important so I don't break it in a
         | 
| 18 | 
            +
              future version unintentionally.
         | 
| 19 | 
            +
            * Commit, do not mess with rakefile, version, or history.
         | 
| 20 | 
            +
              (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
         | 
| 21 | 
            +
            * Send me a pull request. Bonus points for topic branches.
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            == Copyright
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            Copyright (c) 2010 FINN.no. See LICENSE for details.
         | 
    
        data/Rakefile
    ADDED
    
    
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            Autotest.add_discovery { "rspec2" }
         | 
    
        data/bin/jstd-runner
    ADDED
    
    
    
        data/jstd-runner.gemspec
    ADDED
    
    | @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            $:.push File.expand_path("../lib", __FILE__)
         | 
| 3 | 
            +
            require "jstd-runner/version"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Gem::Specification.new do |s|
         | 
| 6 | 
            +
              s.name        = "jstd-runner"
         | 
| 7 | 
            +
              s.version     = JstdRunner::VERSION
         | 
| 8 | 
            +
              s.platform    = Gem::Platform::RUBY
         | 
| 9 | 
            +
              s.authors     = ["Jari Bakken"]
         | 
| 10 | 
            +
              s.email       = ["jari.bakken@gmail.com"]
         | 
| 11 | 
            +
              s.homepage    = "http://github.com/jarib/jstd-runner"
         | 
| 12 | 
            +
              s.summary     = %q{JsTestDriver wrapper}
         | 
| 13 | 
            +
              s.description = %q{Runs a JsTestDriver server + browsers with some built-in monitoring}
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              s.files        = `git ls-files`.split("\n")
         | 
| 16 | 
            +
              s.executables  = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
         | 
| 17 | 
            +
              s.require_path = 'lib'
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              s.add_dependency "selenium-webdriver", "0.1.0"
         | 
| 20 | 
            +
              s.add_dependency "eventmachine", "0.12.10"
         | 
| 21 | 
            +
              s.add_dependency "mail", "2.2.10"
         | 
| 22 | 
            +
              s.add_dependency "daemons", "1.1.0"
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              s.add_development_dependency "rspec", ">= 2.0.0"
         | 
| 25 | 
            +
            end
         | 
    
        data/lib/jstd-runner.rb
    ADDED
    
    | @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            require "logger"
         | 
| 2 | 
            +
            require "optparse"
         | 
| 3 | 
            +
            require "etc"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module JstdRunner
         | 
| 6 | 
            +
              Log = Logger.new(STDOUT)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              class << self
         | 
| 9 | 
            +
                attr_accessor :shutting_down
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require "selenium-webdriver"
         | 
| 14 | 
            +
            require "eventmachine"
         | 
| 15 | 
            +
            require "daemons"
         | 
| 16 | 
            +
            require "socket"
         | 
| 17 | 
            +
            require "mail"
         | 
| 18 | 
            +
            require "fileutils"
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            require "jstd-runner/cli"
         | 
| 21 | 
            +
            require "jstd-runner/monitorable"
         | 
| 22 | 
            +
            require "jstd-runner/browser"
         | 
| 23 | 
            +
            require "jstd-runner/vnc_control"
         | 
| 24 | 
            +
            require "jstd-runner/server"
         | 
| 25 | 
            +
            require "jstd-runner/runner"
         | 
| 26 | 
            +
             | 
| 27 | 
            +
             | 
| Binary file | 
| @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            module JstdRunner
         | 
| 2 | 
            +
              class Browser
         | 
| 3 | 
            +
                include Monitorable
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(type = :firefox)
         | 
| 6 | 
            +
                  @type     = type
         | 
| 7 | 
            +
                  @switched = @restarting = false
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def start
         | 
| 11 | 
            +
                  Log.info "starting browser - #{@type}"
         | 
| 12 | 
            +
                  @browser = Selenium::WebDriver.for @type
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def capture(host, port)
         | 
| 16 | 
            +
                  @restarting = true
         | 
| 17 | 
            +
                  @switched = false
         | 
| 18 | 
            +
                  start unless @browser
         | 
| 19 | 
            +
                  @browser.get "http://#{host}:#{port}/capture"
         | 
| 20 | 
            +
                  @restarting = false
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def restart
         | 
| 24 | 
            +
                  @restarting = true
         | 
| 25 | 
            +
                  Log.info "restarting browser - #{@type}"
         | 
| 26 | 
            +
                  stop rescue nil
         | 
| 27 | 
            +
                  @switched = false
         | 
| 28 | 
            +
                  start
         | 
| 29 | 
            +
                  @restarting = false
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def stop
         | 
| 33 | 
            +
                  Log.info "stopping browser - #{@type}"
         | 
| 34 | 
            +
                  @browser.quit if @browser
         | 
| 35 | 
            +
                rescue Errno::ECONNREFUSED
         | 
| 36 | 
            +
                  # looks like we're not running
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def running?
         | 
| 40 | 
            +
                  Log.info "browser state: #{status}"
         | 
| 41 | 
            +
                  true
         | 
| 42 | 
            +
                rescue
         | 
| 43 | 
            +
                  false
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def status
         | 
| 47 | 
            +
                  status_span.text
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                private
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def status_span
         | 
| 53 | 
            +
                  unless @switched
         | 
| 54 | 
            +
                    @browser.switch_to.frame("0")
         | 
| 55 | 
            +
                    @switched = true
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  @browser.find_element(:tag_name => "span")
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            module JstdRunner
         | 
| 2 | 
            +
              class CLI
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                def initialize(args)
         | 
| 5 | 
            +
                  parse args
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def run
         | 
| 9 | 
            +
                  runner.run
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                private
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def parse(args)
         | 
| 15 | 
            +
                  OptionParser.new { |op|
         | 
| 16 | 
            +
                    op.banner = "Usage: #{File.basename $PROGRAM_NAME} [options]"
         | 
| 17 | 
            +
                    op.separator ""
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    op.on("-p", "--port PORT", Integer) do |port|
         | 
| 20 | 
            +
                      runner.options[:port] = port
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    op.on("-x", "--vnc") do
         | 
| 24 | 
            +
                      runner.options[:vnc] = true
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    op.on("-m", "--monitor INTERVAL", Integer) do |int|
         | 
| 28 | 
            +
                      runner.options[:monitor_interval] = int
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    op.on("-b", "--browser BROWSER", String) do |browser|
         | 
| 32 | 
            +
                      runner.options[:browser] = browser.to_sym
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    op.on("-d", "--daemonize LOGFILE", String) do |log|
         | 
| 36 | 
            +
                      runner.options[:daemonize] = log
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    op.on("-n", "--notify email1,email2,email3", Array) do |emails|
         | 
| 40 | 
            +
                      runner.options[:emails] = emails
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  }.parse!(args)
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def runner
         | 
| 46 | 
            +
                  @runner ||= Runner.new
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            module JstdRunner
         | 
| 2 | 
            +
              module Monitorable
         | 
| 3 | 
            +
                def monitor(interval, &failure_callback)
         | 
| 4 | 
            +
                  EM.add_periodic_timer(interval) {
         | 
| 5 | 
            +
                    next if JstdRunner.shutting_down || @restarting
         | 
| 6 | 
            +
                    if running?
         | 
| 7 | 
            +
                      Log.info "ok: #{self}"
         | 
| 8 | 
            +
                    else
         | 
| 9 | 
            +
                      Log.info "dead: #{self}"
         | 
| 10 | 
            +
                      failure_callback.call
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  }
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,167 @@ | |
| 1 | 
            +
            module JstdRunner
         | 
| 2 | 
            +
              class Runner
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                DEFAULT_OPTIONS = {
         | 
| 5 | 
            +
                  :port             => 4224,
         | 
| 6 | 
            +
                  :vnc              => false,
         | 
| 7 | 
            +
                  :monitor_interval => 10,
         | 
| 8 | 
            +
                  :browser          => :firefox,
         | 
| 9 | 
            +
                  :daemonize        => false
         | 
| 10 | 
            +
                }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                attr_reader :options
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def initialize
         | 
| 15 | 
            +
                  @options = DEFAULT_OPTIONS.dup
         | 
| 16 | 
            +
                  @shutting_down = @clean_shutdown = false
         | 
| 17 | 
            +
                  @server_restarting = @browser_restarting = false
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def run
         | 
| 21 | 
            +
                  EM.run {
         | 
| 22 | 
            +
                    configure_mailer
         | 
| 23 | 
            +
                    trap_signals
         | 
| 24 | 
            +
                    daemonize if options[:daemonize]
         | 
| 25 | 
            +
                    shutdown_hook
         | 
| 26 | 
            +
                    start_server
         | 
| 27 | 
            +
                    start_browser
         | 
| 28 | 
            +
                    capture_browser
         | 
| 29 | 
            +
                  }
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                private
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def trap_signals
         | 
| 35 | 
            +
                  trap_signal "INT"
         | 
| 36 | 
            +
                  trap_signal "TERM"
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def trap_signal(sig)
         | 
| 40 | 
            +
                  trap(sig) {
         | 
| 41 | 
            +
                    trap sig, "DEFAULT"
         | 
| 42 | 
            +
                    Log.info "received #{sig}, shutting down"
         | 
| 43 | 
            +
                    stop
         | 
| 44 | 
            +
                  }
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def shutting_down?
         | 
| 48 | 
            +
                  @shutting_down
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def server_restarting?
         | 
| 52 | 
            +
                  @server_restarting
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def browser_restarting?
         | 
| 56 | 
            +
                  @browser_restarting
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def clean_shutdown?
         | 
| 60 | 
            +
                  @clean_shutdown
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def shutdown_hook
         | 
| 64 | 
            +
                  at_exit {
         | 
| 65 | 
            +
                    unless clean_shutdown?
         | 
| 66 | 
            +
                      body = $! ? [$!.message, $!.backtrace].flatten.join("\n") : '(empty)'
         | 
| 67 | 
            +
                      notify "exiting @ #{Time.now}", body
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
                  }
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                def stop
         | 
| 73 | 
            +
                  JstdRunner.shutting_down = true
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  stop_browser
         | 
| 76 | 
            +
                  stop_server
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  EM.stop
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  @clean_shutdown = true
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def start_server
         | 
| 84 | 
            +
                  server.start
         | 
| 85 | 
            +
                  server.monitor(options[:monitor_interval]) {
         | 
| 86 | 
            +
                    server.restart
         | 
| 87 | 
            +
                    capture_browser
         | 
| 88 | 
            +
                  }
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                def stop_server
         | 
| 92 | 
            +
                  server.stop
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                def start_browser
         | 
| 96 | 
            +
                  start_vnc if options[:vnc]
         | 
| 97 | 
            +
                  browser.start
         | 
| 98 | 
            +
                  browser.monitor(options[:monitor_interval]) {
         | 
| 99 | 
            +
                    browser.restart
         | 
| 100 | 
            +
                    capture_browser
         | 
| 101 | 
            +
                  }
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                def capture_browser
         | 
| 105 | 
            +
                  Log.info "capturing #{browser.inspect}"
         | 
| 106 | 
            +
                  browser.capture(server.host, server.port)
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                def stop_browser
         | 
| 110 | 
            +
                  stop_vnc if options[:vnc]
         | 
| 111 | 
            +
                  browser.stop
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                def start_vnc
         | 
| 115 | 
            +
                  vnc.start
         | 
| 116 | 
            +
                  ENV['DISPLAY'] = vnc.display
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                def stop_vnc
         | 
| 120 | 
            +
                  vnc.stop
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                def daemonize
         | 
| 124 | 
            +
                  log_file = options[:daemonize]
         | 
| 125 | 
            +
                  FileUtils.touch log_file
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                  Daemonize.daemonize(log_file, "#{$PROGRAM_NAME}-daemonized")
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                def server
         | 
| 131 | 
            +
                  @server ||= Server.new(options[:port])
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                def browser
         | 
| 135 | 
            +
                  @browser ||= Browser.new(options[:browser])
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                def vnc
         | 
| 139 | 
            +
                  @vnc ||= VncControl.new
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                def configure_mailer
         | 
| 143 | 
            +
                  return unless options[:smtp]
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                  uri = URI.parse(options[:smtp])
         | 
| 146 | 
            +
                  Mail.defaults {
         | 
| 147 | 
            +
                    delivery_method(uri.scheme.to_sym, :address => uri.host, :port => uri.port)
         | 
| 148 | 
            +
                  }
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                def notify(subject, body)
         | 
| 152 | 
            +
                  return unless recipients = options[:emails]
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                  Mail.deliver {
         | 
| 155 | 
            +
                    from    [Etc.getlogin, Socket.gethostname].join("@")
         | 
| 156 | 
            +
                    to      recipients
         | 
| 157 | 
            +
                    subject "JstdRunner @ #{Socket.gethostname}: #{subject}"
         | 
| 158 | 
            +
                    body    body
         | 
| 159 | 
            +
                  }
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                def monitor(&blk)
         | 
| 163 | 
            +
                  EM.add_periodic_timer(@options[:monitor_interval], &blk)
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
              end # Runner
         | 
| 167 | 
            +
            end # JstdRunner
         | 
| @@ -0,0 +1,79 @@ | |
| 1 | 
            +
            module JstdRunner
         | 
| 2 | 
            +
              class Server
         | 
| 3 | 
            +
                include Monitorable
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class StartupError < StandardError
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class StopError < StandardError
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                JAR            = File.expand_path("../JsTestDriver-1.2.2.jar", __FILE__)
         | 
| 12 | 
            +
                LAUNCH_TIMEOUT = 120 # this is huge, but I've seen it happen
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                attr_reader :host, :port
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def initialize(port)
         | 
| 17 | 
            +
                  @host       = "127.0.0.1"
         | 
| 18 | 
            +
                  @port       = Integer(port)
         | 
| 19 | 
            +
                  @restarting = false
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def start
         | 
| 23 | 
            +
                  Log.info "starting JsTestDriver"
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  if immediate_poller.connected?
         | 
| 26 | 
            +
                    raise StartupError, "JsTestDriver already running on #{@host}:#{@port}"
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  process.start
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  unless long_poller.connected?
         | 
| 32 | 
            +
                    process.stop rescue nil
         | 
| 33 | 
            +
                    raise StartupError, "could not launch JsTestDriver server on #{@host}:#{@port} within #{LAUNCH_TIMEOUT} seconds"
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def restart
         | 
| 38 | 
            +
                  @restarting = true
         | 
| 39 | 
            +
                  Log.info "restaring server"
         | 
| 40 | 
            +
                  stop rescue nil
         | 
| 41 | 
            +
                  @process = nil
         | 
| 42 | 
            +
                  start
         | 
| 43 | 
            +
                  @restarting = false
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def stop
         | 
| 47 | 
            +
                  Log.info "stopping JsTestDriver"
         | 
| 48 | 
            +
                  process.stop
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  unless long_poller.closed?
         | 
| 51 | 
            +
                    raise StopError, "could not stop JsTestDriver server on port #{@host}:#{@port} witin #{LAUNCH_TIMEOUT} seconds"
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def running?
         | 
| 56 | 
            +
                  process.alive? && immediate_poller.connected?
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                private
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def process
         | 
| 62 | 
            +
                  @process ||= (
         | 
| 63 | 
            +
                    proc = ChildProcess.new("java", "-jar", JAR, "--port", @port.to_s)
         | 
| 64 | 
            +
                    proc.io.inherit! if $DEBUG
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    proc
         | 
| 67 | 
            +
                  )
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def long_poller
         | 
| 71 | 
            +
                  @long_poller ||= Selenium::WebDriver::SocketPoller.new(@host, @port, LAUNCH_TIMEOUT)
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def immediate_poller
         | 
| 75 | 
            +
                  @immediate_poller ||= Selenium::WebDriver::SocketPoller.new(@host, @port, 5)
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
            end
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            module JstdRunner
         | 
| 2 | 
            +
              class VncControl
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                class Error < StandardError
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                class << self
         | 
| 8 | 
            +
                  def displays
         | 
| 9 | 
            +
                    Dir[File.expand_path("~/.vnc/*.pid")].map { |e| e[/(\d+)\.pid/, 1] }.compact
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def all
         | 
| 13 | 
            +
                    displays.map { |display| new(":#{display}") }
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                attr_reader :display
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def initialize(display = nil)
         | 
| 20 | 
            +
                  @display = display
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def start
         | 
| 24 | 
            +
                  if @display
         | 
| 25 | 
            +
                    server @display
         | 
| 26 | 
            +
                    Log.info "vnc server launched on #{@display.inspect}"
         | 
| 27 | 
            +
                  else
         | 
| 28 | 
            +
                    output = server
         | 
| 29 | 
            +
                    @display = output[/desktop is #{host}(\S+)/, 1]
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def stop
         | 
| 34 | 
            +
                  server "-kill", @display.to_s
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                private
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def server(*args)
         | 
| 40 | 
            +
                  out = `tightvncserver #{args.join ' '} 2>&1`
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  unless $?.success?
         | 
| 43 | 
            +
                    raise Error, "could not run tightvncserver: #{out.inspect}"
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  out
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def host
         | 
| 50 | 
            +
                  @host ||= Socket.gethostname
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module JstdRunner
         | 
| 4 | 
            +
              describe Browser do
         | 
| 5 | 
            +
                let(:browser) { Browser.new }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                it "launches the the browser" do
         | 
| 8 | 
            +
                  Selenium::WebDriver.should_receive(:for).once
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  browser.start
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                it "captures the browser" do
         | 
| 14 | 
            +
                  mock_driver = mock(Selenium::WebDriver::Driver)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  Selenium::WebDriver.should_receive(:for).and_return(mock_driver)
         | 
| 17 | 
            +
                  mock_driver.should_receive(:get).with("http://localhost:4224/capture")
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  browser.capture "localhost", 4224
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                it "stops the browser" do
         | 
| 23 | 
            +
                  mock_driver = mock(Selenium::WebDriver::Driver)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  Selenium::WebDriver.should_receive(:for).and_return(mock_driver)
         | 
| 26 | 
            +
                  mock_driver.should_receive(:quit)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  browser.start
         | 
| 29 | 
            +
                  browser.stop
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                it "restarts the browser" do
         | 
| 33 | 
            +
                  browser.should_receive(:stop).once
         | 
| 34 | 
            +
                  browser.should_receive(:start).once
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  browser.restart
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                it "restarts the browser if it was already stopped" do
         | 
| 40 | 
            +
                  browser.should_receive(:stop).once.and_raise("foo")
         | 
| 41 | 
            +
                  browser.should_receive(:start).once
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  browser.restart
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                it "knows if the browser is running" do
         | 
| 47 | 
            +
                  browser.stub!(:status_span).and_return(mock(:text => "Waiting..."))
         | 
| 48 | 
            +
                  browser.should be_running
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                it "knows if the browser is not running" do
         | 
| 52 | 
            +
                  # if we can't get the span, we assume it's dead
         | 
| 53 | 
            +
                  browser.stub!(:status_span).and_raise(Errno::ECONNREFUSED)
         | 
| 54 | 
            +
                  browser.should_not be_running
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,47 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module JstdRunner
         | 
| 4 | 
            +
              describe CLI do
         | 
| 5 | 
            +
                let(:runner) { mock(Runner, :options => {}) }
         | 
| 6 | 
            +
                before { Runner.stub!(:new).and_return(runner) }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def cli(str = '')
         | 
| 9 | 
            +
                  CLI.new(str.split(" "))
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                it "configures the port" do
         | 
| 13 | 
            +
                  cli "--port 1234"
         | 
| 14 | 
            +
                  runner.options[:port].should == 1234
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                it "configures VNC" do
         | 
| 18 | 
            +
                  cli "--vnc"
         | 
| 19 | 
            +
                  runner.options[:vnc].should be_true
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                it "configures the monitoring interval" do
         | 
| 23 | 
            +
                  cli "--monitor 10"
         | 
| 24 | 
            +
                  runner.options[:monitor_interval].should == 10
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                it "configures the browser type" do
         | 
| 28 | 
            +
                  cli "--browser chrome"
         | 
| 29 | 
            +
                  runner.options[:browser].should == :chrome
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                it "configures daemonization" do
         | 
| 33 | 
            +
                  cli "--daemonize /foo/bar"
         | 
| 34 | 
            +
                  runner.options[:daemonize].should == "/foo/bar"
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                it "configures email notifications" do
         | 
| 38 | 
            +
                  cli "--notify a@b.com,x@y.com"
         | 
| 39 | 
            +
                  runner.options[:emails].should == %w[a@b.com x@y.com]
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                it "delegates to the runner when run" do
         | 
| 43 | 
            +
                  runner.should_receive(:run)
         | 
| 44 | 
            +
                  cli.run
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module JstdRunner
         | 
| 4 | 
            +
              describe Monitorable do
         | 
| 5 | 
            +
                let(:object) {
         | 
| 6 | 
            +
                  obj = Object.new
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  class << obj
         | 
| 9 | 
            +
                    attr_accessor :restarting, :running
         | 
| 10 | 
            +
                    include Monitorable
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    def running?
         | 
| 13 | 
            +
                      @running
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  obj
         | 
| 18 | 
            +
                }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                before { EM.should_receive(:add_periodic_timer).and_yield }
         | 
| 21 | 
            +
                after { JstdRunner.shutting_down = false }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                it "yields if self is not running" do
         | 
| 24 | 
            +
                  did_yield = false
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  object.running = false
         | 
| 27 | 
            +
                  object.monitor(1) { did_yield = true }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  did_yield.should be_true
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                it "does not yield when self is running" do
         | 
| 33 | 
            +
                  did_yield = false
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  object.running = true
         | 
| 36 | 
            +
                  object.monitor(1) { did_yield = true }
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  did_yield.should be_false
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it "does not check when we're shutting down" do
         | 
| 42 | 
            +
                  JstdRunner.shutting_down = true
         | 
| 43 | 
            +
                  object.should_not_receive :running?
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  object.monitor(1) {}
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                it "does not check when self is restarting" do
         | 
| 49 | 
            +
                  object.restarting = true
         | 
| 50 | 
            +
                  object.should_not_receive :running?
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  object.monitor(1) {}
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module JstdRunner
         | 
| 4 | 
            +
              describe Runner do
         | 
| 5 | 
            +
                let(:runner) { Runner.new }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                before {
         | 
| 8 | 
            +
                  EM.stub!(:run).and_yield
         | 
| 9 | 
            +
                  runner.stub!(:at_exit)
         | 
| 10 | 
            +
                  runner.stub!(:trap)
         | 
| 11 | 
            +
                }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                it "runs and watches the server" do
         | 
| 14 | 
            +
                  browser = mock(Browser).as_null_object
         | 
| 15 | 
            +
                  runner.stub!(:browser).and_return(browser)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  server = mock(Server, :host => "localhost", :port => 4224)
         | 
| 18 | 
            +
                  Server.should_receive(:new).with(4224).and_return(server)
         | 
| 19 | 
            +
                  server.should_receive(:start)
         | 
| 20 | 
            +
                  server.should_receive(:monitor).with(10)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  runner.run
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                it "runs, captures and watches the browser" do
         | 
| 26 | 
            +
                  server = mock(Server, :host => "localhost", :port => 1234).as_null_object
         | 
| 27 | 
            +
                  runner.stub!(:server).and_return(server)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  browser = mock(Browser)
         | 
| 30 | 
            +
                  Browser.should_receive(:new).with(:firefox).and_return(browser)
         | 
| 31 | 
            +
                  browser.should_receive(:start)
         | 
| 32 | 
            +
                  browser.should_receive(:capture).with("localhost", 1234)
         | 
| 33 | 
            +
                  browser.should_receive(:monitor).with(10)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  runner.run
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                # TODO: more specs here
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,94 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module JstdRunner
         | 
| 4 | 
            +
              describe Server do
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                let(:server) { Server.new(4224) }
         | 
| 7 | 
            +
                let(:mock_process) { mock(ChildProcess, :start => true) }
         | 
| 8 | 
            +
                let(:connected_poller) { mock(:connected? => true, :closed? => false) }
         | 
| 9 | 
            +
                let(:closed_poller) {  mock(:connected? => false, :closed? => true) }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                it "launches the server on the given port" do
         | 
| 12 | 
            +
                  server.stub!(:immediate_poller => closed_poller)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  ChildProcess.should_receive(:new).with(
         | 
| 15 | 
            +
                    "java", "-jar", /JsTestDriver.+\.jar/, "--port", "4224"
         | 
| 16 | 
            +
                  ).and_return(mock_process)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  server.stub!(:long_poller).and_return(connected_poller)
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  server.start
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                it "raises a StartupError if the server is already running" do
         | 
| 24 | 
            +
                  server.stub!(:immediate_poller => connected_poller)
         | 
| 25 | 
            +
                  server.stub!(:process => mock_process)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  lambda { server.start }.should raise_error(Server::StartupError)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                it "raises a StartupError if the server doesn't start" do
         | 
| 31 | 
            +
                  server.stub!(:immediate_poller => closed_poller)
         | 
| 32 | 
            +
                  server.stub!(:long_poller => closed_poller)
         | 
| 33 | 
            +
                  server.stub!(:process => mock_process)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  # in case it's alive but not launched properly
         | 
| 36 | 
            +
                  mock_process.should_receive(:stop)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  lambda { server.start }.should raise_error(Server::StartupError)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it "restarts the server" do
         | 
| 42 | 
            +
                  server.should_receive(:stop).once
         | 
| 43 | 
            +
                  server.should_receive(:start).once
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  server.restart
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                it "restarts the server even if stop fails" do
         | 
| 49 | 
            +
                  server.should_receive(:stop).and_raise("argh")
         | 
| 50 | 
            +
                  server.should_receive(:start).once
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  server.restart
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                it "stops the server" do
         | 
| 56 | 
            +
                  server.stub!(:process => mock_process)
         | 
| 57 | 
            +
                  server.stub!(:long_poller => mock(:closed? => true))
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  mock_process.should_receive(:stop)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  server.stop
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                it "raises a StopError if the server could not be stopped" do
         | 
| 65 | 
            +
                  server.stub!(:process => mock_process)
         | 
| 66 | 
            +
                  server.stub!(:long_poller => connected_poller)
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  mock_process.should_receive(:stop)
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  lambda { server.stop }.should raise_error(Server::StopError)
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                it "knows if the server is alive" do
         | 
| 74 | 
            +
                  server.stub!(:process => mock(:alive? => true))
         | 
| 75 | 
            +
                  server.stub!(:immediate_poller => connected_poller)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  server.should be_running
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                it "considers the server dead if it does not respond to connections" do
         | 
| 81 | 
            +
                  server.stub!(:process => mock(:alive? => true))
         | 
| 82 | 
            +
                  server.stub!(:immediate_poller => closed_poller)
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  server.should_not be_running
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                it "considers the server dead if the process died" do
         | 
| 88 | 
            +
                  server.stub!(:process => mock(:alive? => false))
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  server.should_not be_running
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | @@ -0,0 +1,162 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: jstd-runner
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              prerelease: false
         | 
| 5 | 
            +
              segments: 
         | 
| 6 | 
            +
              - 0
         | 
| 7 | 
            +
              - 0
         | 
| 8 | 
            +
              - 2
         | 
| 9 | 
            +
              version: 0.0.2
         | 
| 10 | 
            +
            platform: ruby
         | 
| 11 | 
            +
            authors: 
         | 
| 12 | 
            +
            - Jari Bakken
         | 
| 13 | 
            +
            autorequire: 
         | 
| 14 | 
            +
            bindir: bin
         | 
| 15 | 
            +
            cert_chain: []
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            date: 2010-11-26 00:00:00 +01:00
         | 
| 18 | 
            +
            default_executable: 
         | 
| 19 | 
            +
            dependencies: 
         | 
| 20 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 21 | 
            +
              name: selenium-webdriver
         | 
| 22 | 
            +
              prerelease: false
         | 
| 23 | 
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 24 | 
            +
                none: false
         | 
| 25 | 
            +
                requirements: 
         | 
| 26 | 
            +
                - - "="
         | 
| 27 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 28 | 
            +
                    segments: 
         | 
| 29 | 
            +
                    - 0
         | 
| 30 | 
            +
                    - 1
         | 
| 31 | 
            +
                    - 0
         | 
| 32 | 
            +
                    version: 0.1.0
         | 
| 33 | 
            +
              type: :runtime
         | 
| 34 | 
            +
              version_requirements: *id001
         | 
| 35 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 36 | 
            +
              name: eventmachine
         | 
| 37 | 
            +
              prerelease: false
         | 
| 38 | 
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 39 | 
            +
                none: false
         | 
| 40 | 
            +
                requirements: 
         | 
| 41 | 
            +
                - - "="
         | 
| 42 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 43 | 
            +
                    segments: 
         | 
| 44 | 
            +
                    - 0
         | 
| 45 | 
            +
                    - 12
         | 
| 46 | 
            +
                    - 10
         | 
| 47 | 
            +
                    version: 0.12.10
         | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              version_requirements: *id002
         | 
| 50 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 51 | 
            +
              name: mail
         | 
| 52 | 
            +
              prerelease: false
         | 
| 53 | 
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 54 | 
            +
                none: false
         | 
| 55 | 
            +
                requirements: 
         | 
| 56 | 
            +
                - - "="
         | 
| 57 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 58 | 
            +
                    segments: 
         | 
| 59 | 
            +
                    - 2
         | 
| 60 | 
            +
                    - 2
         | 
| 61 | 
            +
                    - 10
         | 
| 62 | 
            +
                    version: 2.2.10
         | 
| 63 | 
            +
              type: :runtime
         | 
| 64 | 
            +
              version_requirements: *id003
         | 
| 65 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 66 | 
            +
              name: daemons
         | 
| 67 | 
            +
              prerelease: false
         | 
| 68 | 
            +
              requirement: &id004 !ruby/object:Gem::Requirement 
         | 
| 69 | 
            +
                none: false
         | 
| 70 | 
            +
                requirements: 
         | 
| 71 | 
            +
                - - "="
         | 
| 72 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 73 | 
            +
                    segments: 
         | 
| 74 | 
            +
                    - 1
         | 
| 75 | 
            +
                    - 1
         | 
| 76 | 
            +
                    - 0
         | 
| 77 | 
            +
                    version: 1.1.0
         | 
| 78 | 
            +
              type: :runtime
         | 
| 79 | 
            +
              version_requirements: *id004
         | 
| 80 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 81 | 
            +
              name: rspec
         | 
| 82 | 
            +
              prerelease: false
         | 
| 83 | 
            +
              requirement: &id005 !ruby/object:Gem::Requirement 
         | 
| 84 | 
            +
                none: false
         | 
| 85 | 
            +
                requirements: 
         | 
| 86 | 
            +
                - - ">="
         | 
| 87 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 88 | 
            +
                    segments: 
         | 
| 89 | 
            +
                    - 2
         | 
| 90 | 
            +
                    - 0
         | 
| 91 | 
            +
                    - 0
         | 
| 92 | 
            +
                    version: 2.0.0
         | 
| 93 | 
            +
              type: :development
         | 
| 94 | 
            +
              version_requirements: *id005
         | 
| 95 | 
            +
            description: Runs a JsTestDriver server + browsers with some built-in monitoring
         | 
| 96 | 
            +
            email: 
         | 
| 97 | 
            +
            - jari.bakken@gmail.com
         | 
| 98 | 
            +
            executables: 
         | 
| 99 | 
            +
            - jstd-runner
         | 
| 100 | 
            +
            extensions: []
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            extra_rdoc_files: []
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            files: 
         | 
| 105 | 
            +
            - .gitignore
         | 
| 106 | 
            +
            - Gemfile
         | 
| 107 | 
            +
            - LICENSE
         | 
| 108 | 
            +
            - README.rdoc
         | 
| 109 | 
            +
            - Rakefile
         | 
| 110 | 
            +
            - autotest/discover.rb
         | 
| 111 | 
            +
            - bin/jstd-runner
         | 
| 112 | 
            +
            - jstd-runner.gemspec
         | 
| 113 | 
            +
            - lib/jstd-runner.rb
         | 
| 114 | 
            +
            - lib/jstd-runner/JsTestDriver-1.2.2.jar
         | 
| 115 | 
            +
            - lib/jstd-runner/browser.rb
         | 
| 116 | 
            +
            - lib/jstd-runner/cli.rb
         | 
| 117 | 
            +
            - lib/jstd-runner/monitorable.rb
         | 
| 118 | 
            +
            - lib/jstd-runner/runner.rb
         | 
| 119 | 
            +
            - lib/jstd-runner/server.rb
         | 
| 120 | 
            +
            - lib/jstd-runner/version.rb
         | 
| 121 | 
            +
            - lib/jstd-runner/vnc_control.rb
         | 
| 122 | 
            +
            - spec/jstd-runner/browser_spec.rb
         | 
| 123 | 
            +
            - spec/jstd-runner/cli_spec.rb
         | 
| 124 | 
            +
            - spec/jstd-runner/monitorable_spec.rb
         | 
| 125 | 
            +
            - spec/jstd-runner/runner_spec.rb
         | 
| 126 | 
            +
            - spec/jstd-runner/server_spec.rb
         | 
| 127 | 
            +
            - spec/jstd-runner/vnc_control_spec.rb
         | 
| 128 | 
            +
            - spec/spec_helper.rb
         | 
| 129 | 
            +
            has_rdoc: true
         | 
| 130 | 
            +
            homepage: http://github.com/jarib/jstd-runner
         | 
| 131 | 
            +
            licenses: []
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            post_install_message: 
         | 
| 134 | 
            +
            rdoc_options: []
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            require_paths: 
         | 
| 137 | 
            +
            - lib
         | 
| 138 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 139 | 
            +
              none: false
         | 
| 140 | 
            +
              requirements: 
         | 
| 141 | 
            +
              - - ">="
         | 
| 142 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 143 | 
            +
                  segments: 
         | 
| 144 | 
            +
                  - 0
         | 
| 145 | 
            +
                  version: "0"
         | 
| 146 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 147 | 
            +
              none: false
         | 
| 148 | 
            +
              requirements: 
         | 
| 149 | 
            +
              - - ">="
         | 
| 150 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 151 | 
            +
                  segments: 
         | 
| 152 | 
            +
                  - 0
         | 
| 153 | 
            +
                  version: "0"
         | 
| 154 | 
            +
            requirements: []
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            rubyforge_project: 
         | 
| 157 | 
            +
            rubygems_version: 1.3.7
         | 
| 158 | 
            +
            signing_key: 
         | 
| 159 | 
            +
            specification_version: 3
         | 
| 160 | 
            +
            summary: JsTestDriver wrapper
         | 
| 161 | 
            +
            test_files: []
         | 
| 162 | 
            +
             |