front_end_loader 0.2.3
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/Gemfile +2 -0
 - data/LICENSE +22 -0
 - data/README.md +121 -0
 - data/Rakefile +52 -0
 - data/front_end_loader.gemspec +36 -0
 - data/lib/front_end_loader/experiment.rb +277 -0
 - data/lib/front_end_loader/request.rb +30 -0
 - data/lib/front_end_loader/request_manager.rb +28 -0
 - data/lib/front_end_loader/screen.rb +226 -0
 - data/lib/front_end_loader.rb +10 -0
 - metadata +77 -0
 
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2011-2012 Brewster Inc., Aubrey Holland
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            MIT License
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 6 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 7 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 8 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 9 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 10 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 11 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 14 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 17 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 18 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 19 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 20 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 21 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 22 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,121 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Front End Loader
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Front End Loader is a Ruby DSL for declaring load tests. It works in the spirit of
         
     | 
| 
      
 4 
     | 
    
         
            +
            tools like JMeter, by simulating a number of users performing a scripted set of actions
         
     | 
| 
      
 5 
     | 
    
         
            +
            and displaying metrics about response times and error rates as the requests are performed.
         
     | 
| 
      
 6 
     | 
    
         
            +
            Unlike GUI tools like JMeter, however, front_end_loader makes it very simple to declare
         
     | 
| 
      
 7 
     | 
    
         
            +
            your requests and to pass data between requests, by looking at the responses to gather data.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            ## Install
         
     | 
| 
      
 10 
     | 
    
         
            +
                gem install front_end_loader
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            ## Creating an Experiment
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            In order to create a test, just declare a FrontEndLoader::Experiment object:
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 17 
     | 
    
         
            +
            require 'front_end_loader'
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            experiment = FrontEndLoader::Experiment.new.tap do |e|
         
     | 
| 
      
 20 
     | 
    
         
            +
              e.user_count = 20
         
     | 
| 
      
 21 
     | 
    
         
            +
              e.loop_count = 5
         
     | 
| 
      
 22 
     | 
    
         
            +
              e.domain = 'https://www.google.com'
         
     | 
| 
      
 23 
     | 
    
         
            +
              e.basic_auth('unreal_login', 'unreal_password')
         
     | 
| 
      
 24 
     | 
    
         
            +
              e.default_parameters = { 'unnecessary' => 'true' }
         
     | 
| 
      
 25 
     | 
    
         
            +
              e.debug = '/tmp/front_end_loader.txt'
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              e.requests do |r|
         
     | 
| 
      
 28 
     | 
    
         
            +
                ...
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            experiment.run
         
     | 
| 
      
 33 
     | 
    
         
            +
            ```
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            This block declares an experiment that:
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            * simulates 20 users simultaneously interacting with the system
         
     | 
| 
      
 38 
     | 
    
         
            +
            * executes the request script five times per user before exiting. You can specify infinite loops by either not calling loop_count or passing -1
         
     | 
| 
      
 39 
     | 
    
         
            +
            * will operate against the google.com domain
         
     | 
| 
      
 40 
     | 
    
         
            +
            * uses http basic auth
         
     | 
| 
      
 41 
     | 
    
         
            +
            * passes a default parameter of unnecessary to each request, and
         
     | 
| 
      
 42 
     | 
    
         
            +
            * writes debugging output to /tmp/front_end_loader.txt
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            It then runs the experiment, which causes the requests to start flowing and output to be displayed
         
     | 
| 
      
 45 
     | 
    
         
            +
            on the screen. The requests method on the experiment is where you will define the script to be run
         
     | 
| 
      
 46 
     | 
    
         
            +
            loop_count times for each of the simulated users:
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 49 
     | 
    
         
            +
              e.requests do |r|
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
               word = nil
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                r.get('test_search', '/search', :q => 'test') do |response|
         
     | 
| 
      
 54 
     | 
    
         
            +
                  word = response.body.
         
     | 
| 
      
 55 
     | 
    
         
            +
                    split(/\s/).
         
     | 
| 
      
 56 
     | 
    
         
            +
                    reject { |i| i.length < 3 || i.length > 10 }.
         
     | 
| 
      
 57 
     | 
    
         
            +
                    sort_by { rand }.
         
     | 
| 
      
 58 
     | 
    
         
            +
                    first
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                e.write_debug(word)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                r.get('random_word_search', '/search', :q => word)
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                r.get('privacy_policy', '/intl/en/policies')
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                # r.post(...)
         
     | 
| 
      
 68 
     | 
    
         
            +
                # r.put(...)
         
     | 
| 
      
 69 
     | 
    
         
            +
                # r.delete(...)
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
            ```
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            For each request, arguments are:
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            * the label to use when tracking it in the display
         
     | 
| 
      
 76 
     | 
    
         
            +
            * the path
         
     | 
| 
      
 77 
     | 
    
         
            +
            * parameters, as a hash
         
     | 
| 
      
 78 
     | 
    
         
            +
            * for post and put requests, a data object to use as the request body
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            All request declarations can take a block that will be passed the response from that request. The response
         
     | 
| 
      
 81 
     | 
    
         
            +
            is a Patron::Response object and can be used to access data and pass it into further requests. Each iteration
         
     | 
| 
      
 82 
     | 
    
         
            +
            of the script will be run in order and will not affect other iterations that may be running.
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            ## Running the experiment
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            Excuting an experiment will produce output like this:
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            ```
         
     | 
| 
      
 89 
     | 
    
         
            +
            ------------------------------------------------------------------------------------------------------
         
     | 
| 
      
 90 
     | 
    
         
            +
            | call                           | count    | avg time | max time | errors   | error %  | throughput  |
         
     | 
| 
      
 91 
     | 
    
         
            +
            ------------------------------------------------------------------------------------------------------
         
     | 
| 
      
 92 
     | 
    
         
            +
            | profile                        | 40       | 0.252    | 0.731    | 0        | 0.0      | 140         |
         
     | 
| 
      
 93 
     | 
    
         
            +
            | random search                  | 40       | 0.275    | 0.491    | 0        | 0.0      | 140         |
         
     | 
| 
      
 94 
     | 
    
         
            +
            | filtered_search                | 40       | 0.28     | 0.67     | 0        | 0.0      | 140         |
         
     | 
| 
      
 95 
     | 
    
         
            +
            | suggestions                    | 40       | 0.264    | 0.624    | 0        | 0.0      | 140         |
         
     | 
| 
      
 96 
     | 
    
         
            +
            | autocomplete                   | 38       | 0.234    | 0.456    | 0        | 0.0      | 133         |
         
     | 
| 
      
 97 
     | 
    
         
            +
            | filtered autocomplete          | 37       | 0.204    | 0.323    | 0        | 0.0      | 130         |
         
     | 
| 
      
 98 
     | 
    
         
            +
            | services                       | 37       | 0.203    | 0.476    | 0        | 0.0      | 130         |
         
     | 
| 
      
 99 
     | 
    
         
            +
            | service types                  | 37       | 0.185    | 0.456    | 0        | 0.0      | 130         |
         
     | 
| 
      
 100 
     | 
    
         
            +
            | me                             | 36       | 0.25     | 0.555    | 0        | 0.0      | 126         |
         
     | 
| 
      
 101 
     | 
    
         
            +
            |                                |          |          |          |          |          |             |
         
     | 
| 
      
 102 
     | 
    
         
            +
            | TOTAL                          | 345      | 0.238    | 0.731    | 0        | 0.0      | 1209        |
         
     | 
| 
      
 103 
     | 
    
         
            +
            ------------------------------------------------------------------------------------------------------
         
     | 
| 
      
 104 
     | 
    
         
            +
            run time: 0:00:17
         
     | 
| 
      
 105 
     | 
    
         
            +
            ```
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
            Throughput is measured in requests per minute and note that because each "user" is running though the script
         
     | 
| 
      
 108 
     | 
    
         
            +
            in series, the throughput for an individual request is not as high as you would expect by running only that request
         
     | 
| 
      
 109 
     | 
    
         
            +
            over and over again.
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
            This display accepts the following keyboard controls:
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
            * c - reset the data
         
     | 
| 
      
 114 
     | 
    
         
            +
            * d - write the contents of the screen to the debug file
         
     | 
| 
      
 115 
     | 
    
         
            +
            * p - pause the scripts, so the data will remain static and no requests will be made
         
     | 
| 
      
 116 
     | 
    
         
            +
            * q - quit
         
     | 
| 
      
 117 
     | 
    
         
            +
            * s - start the scripts again when paused
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
            ## <a name="copyright"></a>Copyright
         
     | 
| 
      
 120 
     | 
    
         
            +
            Copyright (c) 2011-2012 Brewster Inc., Aubrey Holland
         
     | 
| 
      
 121 
     | 
    
         
            +
            See [LICENSE](https://github.com/brewster/front_end_loader/blob/master/LICENSE) for details.
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rspec/core/rake_task'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            task :default => :test
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## helper functions
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            def name
         
     | 
| 
      
 8 
     | 
    
         
            +
              @name ||= Dir['*.gemspec'].first.split('.').first
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            def version
         
     | 
| 
      
 12 
     | 
    
         
            +
              line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
         
     | 
| 
      
 13 
     | 
    
         
            +
              line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            def gemspec_file
         
     | 
| 
      
 17 
     | 
    
         
            +
              "#{name}.gemspec"
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            def replace_header(head, header_name)
         
     | 
| 
      
 21 
     | 
    
         
            +
              head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            ## standard tasks
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            RSpec::Core::RakeTask.new(:test)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            desc "Generate #{gemspec_file}"
         
     | 
| 
      
 29 
     | 
    
         
            +
            task :gemspec do
         
     | 
| 
      
 30 
     | 
    
         
            +
              # read spec file and split out manifest section
         
     | 
| 
      
 31 
     | 
    
         
            +
              spec = File.read(gemspec_file)
         
     | 
| 
      
 32 
     | 
    
         
            +
              head, manifest, tail = spec.split("  # = MANIFEST =\n")
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              # replace name version and date
         
     | 
| 
      
 35 
     | 
    
         
            +
              replace_header(head, :name)
         
     | 
| 
      
 36 
     | 
    
         
            +
              replace_header(head, :version)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              # determine file list from git ls-files
         
     | 
| 
      
 39 
     | 
    
         
            +
              files = `git ls-files`.
         
     | 
| 
      
 40 
     | 
    
         
            +
                split("\n").
         
     | 
| 
      
 41 
     | 
    
         
            +
                sort.
         
     | 
| 
      
 42 
     | 
    
         
            +
                reject { |file| file =~ /^\./ }.
         
     | 
| 
      
 43 
     | 
    
         
            +
                reject { |file| file =~ /^(rdoc|pkg)/ }.
         
     | 
| 
      
 44 
     | 
    
         
            +
                map { |file| "    #{file}" }.
         
     | 
| 
      
 45 
     | 
    
         
            +
                join("\n")
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              # piece file back together and write
         
     | 
| 
      
 48 
     | 
    
         
            +
              manifest = "  s.files = %w[\n#{files}\n  ]\n"
         
     | 
| 
      
 49 
     | 
    
         
            +
              spec = [head, manifest, tail].join("  # = MANIFEST =\n")
         
     | 
| 
      
 50 
     | 
    
         
            +
              File.open(gemspec_file, 'w') { |io| io.write(spec) }
         
     | 
| 
      
 51 
     | 
    
         
            +
              puts "Updated #{gemspec_file}"
         
     | 
| 
      
 52 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 2 
     | 
    
         
            +
              s.specification_version = 2 if s.respond_to? :specification_version=
         
     | 
| 
      
 3 
     | 
    
         
            +
              s.required_rubygems_version = Gem::Requirement.new(">= 1.3.5") if s.respond_to? :required_rubygems_version=
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              s.name    = 'front_end_loader'
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.version = '0.2.3'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              s.summary     = 'A framework for doing declarative load testing in ruby'
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.description = <<-EOF
         
     | 
| 
      
 10 
     | 
    
         
            +
            Front End Loader allows clients to declare load tests using a pure-Ruby DSL.
         
     | 
| 
      
 11 
     | 
    
         
            +
            This means that it is very simple to pass data between requests or to interact
         
     | 
| 
      
 12 
     | 
    
         
            +
            with your systems in dynamic, complex ways.
         
     | 
| 
      
 13 
     | 
    
         
            +
            EOF
         
     | 
| 
      
 14 
     | 
    
         
            +
              s.authors  = ['Aubrey Holland']
         
     | 
| 
      
 15 
     | 
    
         
            +
              s.email    = 'aubreyholland@gmail.com'
         
     | 
| 
      
 16 
     | 
    
         
            +
              s.homepage = 'https://github.com/brewster/front_end_loader'
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              s.add_dependency 'patron'
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              # = MANIFEST =
         
     | 
| 
      
 21 
     | 
    
         
            +
              s.files = %w[
         
     | 
| 
      
 22 
     | 
    
         
            +
                Gemfile
         
     | 
| 
      
 23 
     | 
    
         
            +
                LICENSE
         
     | 
| 
      
 24 
     | 
    
         
            +
                README.md
         
     | 
| 
      
 25 
     | 
    
         
            +
                Rakefile
         
     | 
| 
      
 26 
     | 
    
         
            +
                front_end_loader.gemspec
         
     | 
| 
      
 27 
     | 
    
         
            +
                lib/front_end_loader.rb
         
     | 
| 
      
 28 
     | 
    
         
            +
                lib/front_end_loader/experiment.rb
         
     | 
| 
      
 29 
     | 
    
         
            +
                lib/front_end_loader/request.rb
         
     | 
| 
      
 30 
     | 
    
         
            +
                lib/front_end_loader/request_manager.rb
         
     | 
| 
      
 31 
     | 
    
         
            +
                lib/front_end_loader/screen.rb
         
     | 
| 
      
 32 
     | 
    
         
            +
              ]
         
     | 
| 
      
 33 
     | 
    
         
            +
              # = MANIFEST =
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              s.test_files = s.files.select { |path| path =~ %r{^spec/*/.+\.rb} }
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,277 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module FrontEndLoader
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Experiment
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_accessor :domain
         
     | 
| 
      
 4 
     | 
    
         
            +
                attr_accessor :user_count
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_accessor :loop_count
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :default_parameters
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :basic_auth_enabled
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_reader :basic_auth_user
         
     | 
| 
      
 9 
     | 
    
         
            +
                attr_reader :basic_auth_password
         
     | 
| 
      
 10 
     | 
    
         
            +
                attr_reader :screen
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                attr_reader :run_start_time
         
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :run_completed_time
         
     | 
| 
      
 14 
     | 
    
         
            +
                attr_reader :running
         
     | 
| 
      
 15 
     | 
    
         
            +
                attr_reader :call_times
         
     | 
| 
      
 16 
     | 
    
         
            +
                attr_reader :call_error_counts
         
     | 
| 
      
 17 
     | 
    
         
            +
                attr_reader :call_max_times
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @screen = Screen.new(self)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @running = false
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @mutex = Mutex.new
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @debug_mutex = Mutex.new
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @loop_count = -1
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @paused = false
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @run_completed_time = nil
         
     | 
| 
      
 27 
     | 
    
         
            +
                  clear_data
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def synchronize(&block)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    block.call
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def debug=(file)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @debug_file = File.open(file, 'a')
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def write_debug(data)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  if @debug_file
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @debug_mutex.synchronize do
         
     | 
| 
      
 43 
     | 
    
         
            +
                      @debug_file.puts(data)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      @debug_file.flush
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def write_screen_to_debug
         
     | 
| 
      
 50 
     | 
    
         
            +
                  if @debug_file
         
     | 
| 
      
 51 
     | 
    
         
            +
                    @debug_mutex.synchronize do
         
     | 
| 
      
 52 
     | 
    
         
            +
                      @screen.write_debug(@debug_file)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def clear_data
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 59 
     | 
    
         
            +
                    @call_counts ||= Hash.new { |h,k| h[k] = 0 }
         
     | 
| 
      
 60 
     | 
    
         
            +
                    @call_counts.keys.each { |k| @call_counts[k] = 0 }
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    @call_times ||= Hash.new { |h,k| h[k] = 0.0 }
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @call_times.keys.each { |k| @call_times[k] = 0.0 }
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    @call_max_times ||= Hash.new { |h,k| h[k] = 0.0 }
         
     | 
| 
      
 66 
     | 
    
         
            +
                    @call_max_times.keys.each { |k| @call_max_times[k] = 0.0 }
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    @call_error_counts ||= Hash.new { |h,k| h[k] = 0 }
         
     | 
| 
      
 69 
     | 
    
         
            +
                    @call_error_counts .keys.each { |k| @call_error_counts[k] = 0 }
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    @call_times_last_25 ||= Hash.new { |h,k| h[k] = [] }
         
     | 
| 
      
 72 
     | 
    
         
            +
                    @call_times_last_25.keys.each { |k| @call_times_last_25[k] = [] }
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    @error_counts_by_type ||= Hash.new { |h,k| h[k] = 0 }
         
     | 
| 
      
 75 
     | 
    
         
            +
                    @error_counts_by_type.keys.each { |k| @error_counts_by_type[k] = 0 }
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    if @run_start_time
         
     | 
| 
      
 78 
     | 
    
         
            +
                      @run_start_time = Time.now
         
     | 
| 
      
 79 
     | 
    
         
            +
                    else
         
     | 
| 
      
 80 
     | 
    
         
            +
                      @run_start_time = nil
         
     | 
| 
      
 81 
     | 
    
         
            +
                    end
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def basic_auth(user, password)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @basic_auth_enabled = true
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @basic_auth_user = user
         
     | 
| 
      
 88 
     | 
    
         
            +
                  @basic_auth_password = password
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                def requests(&block)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  @request_block = block
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                def run_completed!
         
     | 
| 
      
 96 
     | 
    
         
            +
                  @run_completed_time = Time.now
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                def run
         
     | 
| 
      
 100 
     | 
    
         
            +
                  @running = true
         
     | 
| 
      
 101 
     | 
    
         
            +
                  @run_start_time = Time.now
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                  threads = (1..user_count).to_a.map do
         
     | 
| 
      
 104 
     | 
    
         
            +
                    Thread.new(self, @request_block) do |experiment, request_block|
         
     | 
| 
      
 105 
     | 
    
         
            +
                      loops_left = experiment.loop_count
         
     | 
| 
      
 106 
     | 
    
         
            +
                      while(loops_left != 0)
         
     | 
| 
      
 107 
     | 
    
         
            +
                        if experiment.paused?
         
     | 
| 
      
 108 
     | 
    
         
            +
                          sleep(0.25)
         
     | 
| 
      
 109 
     | 
    
         
            +
                        elsif experiment.quitting?
         
     | 
| 
      
 110 
     | 
    
         
            +
                          loops_left = 0
         
     | 
| 
      
 111 
     | 
    
         
            +
                        else
         
     | 
| 
      
 112 
     | 
    
         
            +
                          request_manager = RequestManager.new(experiment, experiment.http_session)
         
     | 
| 
      
 113 
     | 
    
         
            +
                          request_block.call(request_manager)
         
     | 
| 
      
 114 
     | 
    
         
            +
                          loops_left -= 1
         
     | 
| 
      
 115 
     | 
    
         
            +
                        end
         
     | 
| 
      
 116 
     | 
    
         
            +
                      end
         
     | 
| 
      
 117 
     | 
    
         
            +
                      experiment.run_completed!
         
     | 
| 
      
 118 
     | 
    
         
            +
                    end
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                  threads << Thread.new(self) do |experiment|
         
     | 
| 
      
 122 
     | 
    
         
            +
                    while (!experiment.quitting?)
         
     | 
| 
      
 123 
     | 
    
         
            +
                      if experiment.paused?
         
     | 
| 
      
 124 
     | 
    
         
            +
                        sleep(0.25)
         
     | 
| 
      
 125 
     | 
    
         
            +
                      else
         
     | 
| 
      
 126 
     | 
    
         
            +
                        experiment.screen.refresh
         
     | 
| 
      
 127 
     | 
    
         
            +
                        sleep(0.1)
         
     | 
| 
      
 128 
     | 
    
         
            +
                      end
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  threads << Thread.new(self) do |experiment|
         
     | 
| 
      
 133 
     | 
    
         
            +
                    while (!experiment.quitting?)
         
     | 
| 
      
 134 
     | 
    
         
            +
                      ch = Curses.getch
         
     | 
| 
      
 135 
     | 
    
         
            +
                      if ch == 'c'
         
     | 
| 
      
 136 
     | 
    
         
            +
                        experiment.clear_data
         
     | 
| 
      
 137 
     | 
    
         
            +
                      elsif ch == 'd'
         
     | 
| 
      
 138 
     | 
    
         
            +
                        experiment.write_screen_to_debug
         
     | 
| 
      
 139 
     | 
    
         
            +
                      elsif ch == 'p'
         
     | 
| 
      
 140 
     | 
    
         
            +
                        experiment.pause
         
     | 
| 
      
 141 
     | 
    
         
            +
                      elsif ch == 'q'
         
     | 
| 
      
 142 
     | 
    
         
            +
                        experiment.quit
         
     | 
| 
      
 143 
     | 
    
         
            +
                      elsif ch == 's'
         
     | 
| 
      
 144 
     | 
    
         
            +
                        experiment.clear_data
         
     | 
| 
      
 145 
     | 
    
         
            +
                        experiment.go
         
     | 
| 
      
 146 
     | 
    
         
            +
                      end
         
     | 
| 
      
 147 
     | 
    
         
            +
                    end
         
     | 
| 
      
 148 
     | 
    
         
            +
                  end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 151 
     | 
    
         
            +
                    threads.each(&:run)
         
     | 
| 
      
 152 
     | 
    
         
            +
                    threads.each(&:join)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  rescue Interrupt
         
     | 
| 
      
 154 
     | 
    
         
            +
                    @screen.close
         
     | 
| 
      
 155 
     | 
    
         
            +
                  end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                  @screen.close
         
     | 
| 
      
 158 
     | 
    
         
            +
                end
         
     | 
| 
      
 159 
     | 
    
         
            +
                
         
     | 
| 
      
 160 
     | 
    
         
            +
                def http_session
         
     | 
| 
      
 161 
     | 
    
         
            +
                  Patron::Session.new.tap do |session|
         
     | 
| 
      
 162 
     | 
    
         
            +
                    session.base_url = domain
         
     | 
| 
      
 163 
     | 
    
         
            +
                    session.insecure = true
         
     | 
| 
      
 164 
     | 
    
         
            +
                    session.max_redirects = 0
         
     | 
| 
      
 165 
     | 
    
         
            +
                    if basic_auth_enabled
         
     | 
| 
      
 166 
     | 
    
         
            +
                      session.auth_type = :basic
         
     | 
| 
      
 167 
     | 
    
         
            +
                      session.username = basic_auth_user
         
     | 
| 
      
 168 
     | 
    
         
            +
                      session.password = basic_auth_password
         
     | 
| 
      
 169 
     | 
    
         
            +
                      session.connect_timeout = 10
         
     | 
| 
      
 170 
     | 
    
         
            +
                      session.timeout = 500
         
     | 
| 
      
 171 
     | 
    
         
            +
                    end
         
     | 
| 
      
 172 
     | 
    
         
            +
                  end
         
     | 
| 
      
 173 
     | 
    
         
            +
                end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                def paused?
         
     | 
| 
      
 176 
     | 
    
         
            +
                  @paused
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                def pause
         
     | 
| 
      
 180 
     | 
    
         
            +
                  @paused = true
         
     | 
| 
      
 181 
     | 
    
         
            +
                end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                def go
         
     | 
| 
      
 184 
     | 
    
         
            +
                  @paused = false
         
     | 
| 
      
 185 
     | 
    
         
            +
                end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                def quitting?
         
     | 
| 
      
 188 
     | 
    
         
            +
                  @quitting
         
     | 
| 
      
 189 
     | 
    
         
            +
                end
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                def quit
         
     | 
| 
      
 192 
     | 
    
         
            +
                  @quitting = true
         
     | 
| 
      
 193 
     | 
    
         
            +
                end
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
                def time_call(name, &block)
         
     | 
| 
      
 196 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 197 
     | 
    
         
            +
                    start = Time.now
         
     | 
| 
      
 198 
     | 
    
         
            +
                    response = block.call
         
     | 
| 
      
 199 
     | 
    
         
            +
                    time = Time.now - start
         
     | 
| 
      
 200 
     | 
    
         
            +
                    @mutex.synchronize do
         
     | 
| 
      
 201 
     | 
    
         
            +
                      @call_times[name] += time
         
     | 
| 
      
 202 
     | 
    
         
            +
                      @call_max_times[name] = time if time > @call_max_times[name]
         
     | 
| 
      
 203 
     | 
    
         
            +
                      unless response.status >= 200 && response.status < 400
         
     | 
| 
      
 204 
     | 
    
         
            +
                        write_debug(response.body)
         
     | 
| 
      
 205 
     | 
    
         
            +
                        @call_error_counts[name] += 1
         
     | 
| 
      
 206 
     | 
    
         
            +
                        @error_counts_by_type[response.status] += 1
         
     | 
| 
      
 207 
     | 
    
         
            +
                      end
         
     | 
| 
      
 208 
     | 
    
         
            +
                      @call_counts[name] += 1
         
     | 
| 
      
 209 
     | 
    
         
            +
                      @call_times_last_25[name].unshift(time)
         
     | 
| 
      
 210 
     | 
    
         
            +
                      @call_times_last_25[name] = @call_times_last_25[name].slice(0, 25)
         
     | 
| 
      
 211 
     | 
    
         
            +
                    end
         
     | 
| 
      
 212 
     | 
    
         
            +
                    response
         
     | 
| 
      
 213 
     | 
    
         
            +
                  rescue Patron::TimeoutError
         
     | 
| 
      
 214 
     | 
    
         
            +
                    add_timeout(name)
         
     | 
| 
      
 215 
     | 
    
         
            +
                  end
         
     | 
| 
      
 216 
     | 
    
         
            +
                end
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                def add_timeout(name)
         
     | 
| 
      
 219 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 220 
     | 
    
         
            +
                    @call_counts[name] += 1
         
     | 
| 
      
 221 
     | 
    
         
            +
                    @call_times[name] += 0
         
     | 
| 
      
 222 
     | 
    
         
            +
                    @call_error_counts[name] += 1
         
     | 
| 
      
 223 
     | 
    
         
            +
                    @error_counts_by_type['Timeout'] += 1
         
     | 
| 
      
 224 
     | 
    
         
            +
                  end
         
     | 
| 
      
 225 
     | 
    
         
            +
                end
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
                def call_counts
         
     | 
| 
      
 228 
     | 
    
         
            +
                  @call_counts.dup
         
     | 
| 
      
 229 
     | 
    
         
            +
                end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                def total_times
         
     | 
| 
      
 232 
     | 
    
         
            +
                  @call_times.dup
         
     | 
| 
      
 233 
     | 
    
         
            +
                end
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                def average_times
         
     | 
| 
      
 236 
     | 
    
         
            +
                  @call_times.keys.inject({}) do |hash, name|
         
     | 
| 
      
 237 
     | 
    
         
            +
                    if @call_counts[name] == 0
         
     | 
| 
      
 238 
     | 
    
         
            +
                      hash[name] = 0.0
         
     | 
| 
      
 239 
     | 
    
         
            +
                    else
         
     | 
| 
      
 240 
     | 
    
         
            +
                      hash[name] = @call_times[name] / @call_counts[name].to_f
         
     | 
| 
      
 241 
     | 
    
         
            +
                    end
         
     | 
| 
      
 242 
     | 
    
         
            +
                    hash
         
     | 
| 
      
 243 
     | 
    
         
            +
                  end
         
     | 
| 
      
 244 
     | 
    
         
            +
                end
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
                def max_times
         
     | 
| 
      
 247 
     | 
    
         
            +
                  @call_max_times.dup
         
     | 
| 
      
 248 
     | 
    
         
            +
                end
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
                def error_counts
         
     | 
| 
      
 251 
     | 
    
         
            +
                  @call_error_counts.dup
         
     | 
| 
      
 252 
     | 
    
         
            +
                end
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
                def error_types
         
     | 
| 
      
 255 
     | 
    
         
            +
                  @error_counts_by_type.dup
         
     | 
| 
      
 256 
     | 
    
         
            +
                end
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
                def error_percents
         
     | 
| 
      
 259 
     | 
    
         
            +
                  @call_counts.keys.inject({}) do |hash, name|
         
     | 
| 
      
 260 
     | 
    
         
            +
                    if @call_counts[name] && @call_counts[name] > 0 && @call_error_counts[name] && @call_error_counts[name] > 0
         
     | 
| 
      
 261 
     | 
    
         
            +
                      hash[name] = (@call_error_counts[name].to_f / @call_counts[name].to_f) * 100.0
         
     | 
| 
      
 262 
     | 
    
         
            +
                    else
         
     | 
| 
      
 263 
     | 
    
         
            +
                      hash[name] = 0.0
         
     | 
| 
      
 264 
     | 
    
         
            +
                    end
         
     | 
| 
      
 265 
     | 
    
         
            +
                    hash
         
     | 
| 
      
 266 
     | 
    
         
            +
                  end
         
     | 
| 
      
 267 
     | 
    
         
            +
                end
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
                def throughput
         
     | 
| 
      
 270 
     | 
    
         
            +
                  delta = ((@run_completed_time || Time.now) - @run_start_time) / 60.0
         
     | 
| 
      
 271 
     | 
    
         
            +
                  @call_counts.keys.inject({}) do |hash, name|
         
     | 
| 
      
 272 
     | 
    
         
            +
                    hash[name] = @call_counts[name].to_f / delta
         
     | 
| 
      
 273 
     | 
    
         
            +
                    hash
         
     | 
| 
      
 274 
     | 
    
         
            +
                  end
         
     | 
| 
      
 275 
     | 
    
         
            +
                end
         
     | 
| 
      
 276 
     | 
    
         
            +
              end
         
     | 
| 
      
 277 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module FrontEndLoader
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Request
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize(experiment, session, method, name, path, params, data, response_block)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @experiment = experiment
         
     | 
| 
      
 5 
     | 
    
         
            +
                  @session = session
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @method = method
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @name = name
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @path = path
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @params = URI.encode(@experiment.default_parameters.merge(params).map { |k,v| "#{k}=#{v}" }.join('&'))
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @data = data
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @response_block = response_block
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def run
         
     | 
| 
      
 15 
     | 
    
         
            +
                  response = nil
         
     | 
| 
      
 16 
     | 
    
         
            +
                  if [:get, :delete].include?(@method)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    response = @experiment.time_call(@name) do
         
     | 
| 
      
 18 
     | 
    
         
            +
                      @session.__send__(@method, "#{@path}?#{@params}")
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  else
         
     | 
| 
      
 21 
     | 
    
         
            +
                    response = @experiment.time_call(@name) do
         
     | 
| 
      
 22 
     | 
    
         
            +
                      @session.__send__(@method, "#{@path}?#{@params}", @data, {'Content-Type' => 'application/json'})
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  if @response_block && response.is_a?(Patron::Response)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @response_block.call(response)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module FrontEndLoader
         
     | 
| 
      
 2 
     | 
    
         
            +
              class RequestManager
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize(experiment, session)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @experiment = experiment
         
     | 
| 
      
 5 
     | 
    
         
            +
                  @session = session
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def get(name, path, params={}, &block)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  Request.new(@experiment, @session, :get, name, path, params, nil, block).run
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def post(name, path, params={}, data="{}", &block)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  Request.new(@experiment, @session, :post, name, path, params, data, block).run
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def put(name, path, params={}, data="{}", &block)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  Request.new(@experiment, @session, :put, name, path, params, data, block).run
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def delete(name, path, params={}, &block)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  Request.new(@experiment, @session, :delete, name, path, params, nil, block).run
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def debug(data)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @experiment.write_debug(data)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,226 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'curses'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module FrontEndLoader
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Screen
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                POSITIONS = {
         
     | 
| 
      
 7 
     | 
    
         
            +
                  :count => 0,
         
     | 
| 
      
 8 
     | 
    
         
            +
                  :average_time => 11,
         
     | 
| 
      
 9 
     | 
    
         
            +
                  :max_time => 22,
         
     | 
| 
      
 10 
     | 
    
         
            +
                  :errors => 33,
         
     | 
| 
      
 11 
     | 
    
         
            +
                  :error_percent => 44,
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :throughput => 55
         
     | 
| 
      
 13 
     | 
    
         
            +
                }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                LENGTHS = {
         
     | 
| 
      
 16 
     | 
    
         
            +
                  :count => 9,
         
     | 
| 
      
 17 
     | 
    
         
            +
                  :average_time => 9,
         
     | 
| 
      
 18 
     | 
    
         
            +
                  :max_time => 9,
         
     | 
| 
      
 19 
     | 
    
         
            +
                  :errors => 9,
         
     | 
| 
      
 20 
     | 
    
         
            +
                  :error_percent => 9,
         
     | 
| 
      
 21 
     | 
    
         
            +
                  :throughput => 12
         
     | 
| 
      
 22 
     | 
    
         
            +
                }
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                TOTAL_LENGTH = 66
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def initialize(experiment)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @experiment = experiment
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @entry_count = nil
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @longest_name = 0
         
     | 
| 
      
 30 
     | 
    
         
            +
                  Curses.init_screen
         
     | 
| 
      
 31 
     | 
    
         
            +
                  Curses.nonl
         
     | 
| 
      
 32 
     | 
    
         
            +
                  Curses.cbreak
         
     | 
| 
      
 33 
     | 
    
         
            +
                  Curses.noecho
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def refresh
         
     | 
| 
      
 37 
     | 
    
         
            +
                  run_start_time = nil
         
     | 
| 
      
 38 
     | 
    
         
            +
                  names = nil
         
     | 
| 
      
 39 
     | 
    
         
            +
                  counts_by_name = {}
         
     | 
| 
      
 40 
     | 
    
         
            +
                  times_by_name = {}
         
     | 
| 
      
 41 
     | 
    
         
            +
                  average_times_by_name = {}
         
     | 
| 
      
 42 
     | 
    
         
            +
                  max_times_by_name = {}
         
     | 
| 
      
 43 
     | 
    
         
            +
                  error_counts_by_name = {}
         
     | 
| 
      
 44 
     | 
    
         
            +
                  error_counts_by_type = {}
         
     | 
| 
      
 45 
     | 
    
         
            +
                  error_percents_by_name = {}
         
     | 
| 
      
 46 
     | 
    
         
            +
                  throughput_by_name = {}
         
     | 
| 
      
 47 
     | 
    
         
            +
                  total_calls = nil
         
     | 
| 
      
 48 
     | 
    
         
            +
                  total_time = nil
         
     | 
| 
      
 49 
     | 
    
         
            +
                  total_errors = nil
         
     | 
| 
      
 50 
     | 
    
         
            +
                  delta = nil
         
     | 
| 
      
 51 
     | 
    
         
            +
                  max_max_time = nil
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  @experiment.synchronize do
         
     | 
| 
      
 54 
     | 
    
         
            +
                    return if !@experiment.running || @experiment.call_counts.empty?
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    run_start_time = @experiment.run_start_time.dup
         
     | 
| 
      
 57 
     | 
    
         
            +
                    names = @experiment.call_counts.keys.dup
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    counts_by_name = @experiment.call_counts
         
     | 
| 
      
 60 
     | 
    
         
            +
                    times_by_name = @experiment.total_times
         
     | 
| 
      
 61 
     | 
    
         
            +
                    average_times_by_name = @experiment.average_times
         
     | 
| 
      
 62 
     | 
    
         
            +
                    max_times_by_name = @experiment.max_times
         
     | 
| 
      
 63 
     | 
    
         
            +
                    error_counts_by_name = @experiment.error_counts
         
     | 
| 
      
 64 
     | 
    
         
            +
                    error_counts_by_type = @experiment.error_types
         
     | 
| 
      
 65 
     | 
    
         
            +
                    error_percents_by_name = @experiment.error_percents
         
     | 
| 
      
 66 
     | 
    
         
            +
                    throughput_by_name = @experiment.throughput
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    total_calls = @experiment.call_counts.values.inject(0) { |s,i| s + i }
         
     | 
| 
      
 69 
     | 
    
         
            +
                    total_time = @experiment.call_times.values.inject(0) { |s,i| s + i }
         
     | 
| 
      
 70 
     | 
    
         
            +
                    total_errors = @experiment.call_error_counts.values.inject(0) { |s,i| s + i }
         
     | 
| 
      
 71 
     | 
    
         
            +
                    max_max_time = @experiment.call_max_times.values.max.round(3).to_s
         
     | 
| 
      
 72 
     | 
    
         
            +
                    delta = ((@experiment.run_completed_time || Time.now) - @experiment.run_start_time) / 60.0
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  if names.count != @entry_count
         
     | 
| 
      
 76 
     | 
    
         
            +
                    @entry_count = names.length
         
     | 
| 
      
 77 
     | 
    
         
            +
                    @longest_name = names.map(&:length).max
         
     | 
| 
      
 78 
     | 
    
         
            +
                    draw_outlines(names)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  first_position = @longest_name + 6
         
     | 
| 
      
 82 
     | 
    
         
            +
                  line = 3
         
     | 
| 
      
 83 
     | 
    
         
            +
                  names.each do |name|
         
     | 
| 
      
 84 
     | 
    
         
            +
                    clear_line(line, first_position)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    Curses.setpos(line, first_position + POSITIONS[:count])
         
     | 
| 
      
 86 
     | 
    
         
            +
                    Curses.addstr(counts_by_name[name].to_s)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    Curses.setpos(line, first_position + POSITIONS[:average_time])
         
     | 
| 
      
 88 
     | 
    
         
            +
                    Curses.addstr(average_times_by_name[name].round(3).to_s)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    Curses.setpos(line, first_position + POSITIONS[:max_time])
         
     | 
| 
      
 90 
     | 
    
         
            +
                    Curses.addstr(max_times_by_name[name].round(3).to_s)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    Curses.setpos(line, first_position + POSITIONS[:errors])
         
     | 
| 
      
 92 
     | 
    
         
            +
                    Curses.addstr(error_counts_by_name[name].to_s)
         
     | 
| 
      
 93 
     | 
    
         
            +
                    Curses.setpos(line, first_position + POSITIONS[:error_percent])
         
     | 
| 
      
 94 
     | 
    
         
            +
                    Curses.addstr(error_percents_by_name[name].round(3).to_s)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    Curses.setpos(line, first_position + POSITIONS[:throughput])
         
     | 
| 
      
 96 
     | 
    
         
            +
                    Curses.addstr(throughput_by_name[name].to_i.to_s)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    line += 1
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
                  line += 1
         
     | 
| 
      
 100 
     | 
    
         
            +
                  clear_line(line, first_position)
         
     | 
| 
      
 101 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:count])
         
     | 
| 
      
 102 
     | 
    
         
            +
                  Curses.addstr(total_calls.to_s)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:average_time])
         
     | 
| 
      
 104 
     | 
    
         
            +
                  Curses.addstr((total_time / total_calls.to_f).round(3).to_s)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:max_time])
         
     | 
| 
      
 106 
     | 
    
         
            +
                  Curses.addstr(max_max_time.to_s)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:errors])
         
     | 
| 
      
 108 
     | 
    
         
            +
                  Curses.addstr(total_errors.to_s)
         
     | 
| 
      
 109 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:error_percent])
         
     | 
| 
      
 110 
     | 
    
         
            +
                  Curses.addstr(((total_errors.to_f / total_calls.to_f) * 100.0).round(1).to_s)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:throughput])
         
     | 
| 
      
 112 
     | 
    
         
            +
                  Curses.addstr((total_calls.to_f / delta).to_i.to_s)
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  line += 3
         
     | 
| 
      
 115 
     | 
    
         
            +
                  time = Time.now - run_start_time
         
     | 
| 
      
 116 
     | 
    
         
            +
                  hours = (time / 3600).to_i
         
     | 
| 
      
 117 
     | 
    
         
            +
                  minutes = (time / 60 - (hours * 60)).to_i
         
     | 
| 
      
 118 
     | 
    
         
            +
                  seconds = (time - (minutes * 60 + hours * 3600)).to_i
         
     | 
| 
      
 119 
     | 
    
         
            +
                  Curses.setpos(line, 3)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  Curses.addstr("run time: #{hours}:#{'%02d' % minutes}:#{'%02d' % seconds}")
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                  line += 2
         
     | 
| 
      
 123 
     | 
    
         
            +
                  error_counts_by_type.each do |type, count|
         
     | 
| 
      
 124 
     | 
    
         
            +
                    erase_line(line)
         
     | 
| 
      
 125 
     | 
    
         
            +
                    Curses.setpos(line, 3)
         
     | 
| 
      
 126 
     | 
    
         
            +
                    Curses.addstr("#{type}: #{count}") 
         
     | 
| 
      
 127 
     | 
    
         
            +
                    line += 1
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                  Curses.curs_set(0)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  Curses.refresh
         
     | 
| 
      
 132 
     | 
    
         
            +
                rescue StandardError => e
         
     | 
| 
      
 133 
     | 
    
         
            +
                  puts e.message
         
     | 
| 
      
 134 
     | 
    
         
            +
                  puts e.backtrace.first
         
     | 
| 
      
 135 
     | 
    
         
            +
                end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                def clear_line(line, first_position)
         
     | 
| 
      
 138 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:count])
         
     | 
| 
      
 139 
     | 
    
         
            +
                  Curses.addstr(' ' * LENGTHS[:count])
         
     | 
| 
      
 140 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:average_time])
         
     | 
| 
      
 141 
     | 
    
         
            +
                  Curses.addstr(' ' * LENGTHS[:average_time])
         
     | 
| 
      
 142 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:max_time])
         
     | 
| 
      
 143 
     | 
    
         
            +
                  Curses.addstr(' ' * LENGTHS[:max_time])
         
     | 
| 
      
 144 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:errors])
         
     | 
| 
      
 145 
     | 
    
         
            +
                  Curses.addstr(' ' * LENGTHS[:error_percent])
         
     | 
| 
      
 146 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:error_percent])
         
     | 
| 
      
 147 
     | 
    
         
            +
                  Curses.addstr(' ' * LENGTHS[:error_percent])
         
     | 
| 
      
 148 
     | 
    
         
            +
                  Curses.setpos(line, first_position + POSITIONS[:throughput])
         
     | 
| 
      
 149 
     | 
    
         
            +
                  Curses.addstr(' ' * LENGTHS[:throughput])
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                def erase_line(line)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  Curses.setpos(line, 0)
         
     | 
| 
      
 154 
     | 
    
         
            +
                  Curses.addstr(' ' * TOTAL_LENGTH)
         
     | 
| 
      
 155 
     | 
    
         
            +
                end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                def draw_outlines(names)
         
     | 
| 
      
 158 
     | 
    
         
            +
                  first_position = @longest_name + 6
         
     | 
| 
      
 159 
     | 
    
         
            +
                  Curses.clear
         
     | 
| 
      
 160 
     | 
    
         
            +
                  Curses.setpos(0, 2)
         
     | 
| 
      
 161 
     | 
    
         
            +
                  Curses.addstr('-' * (first_position + TOTAL_LENGTH))
         
     | 
| 
      
 162 
     | 
    
         
            +
                  Curses.setpos(1, 1)
         
     | 
| 
      
 163 
     | 
    
         
            +
                  Curses.addstr(divider_string)
         
     | 
| 
      
 164 
     | 
    
         
            +
                  Curses.setpos(1, 3)
         
     | 
| 
      
 165 
     | 
    
         
            +
                  Curses.addstr('call')
         
     | 
| 
      
 166 
     | 
    
         
            +
                  Curses.setpos(1, first_position + POSITIONS[:count])
         
     | 
| 
      
 167 
     | 
    
         
            +
                  Curses.addstr('count')
         
     | 
| 
      
 168 
     | 
    
         
            +
                  Curses.setpos(1, first_position + POSITIONS[:average_time])
         
     | 
| 
      
 169 
     | 
    
         
            +
                  Curses.addstr('avg time')
         
     | 
| 
      
 170 
     | 
    
         
            +
                  Curses.setpos(1, first_position + POSITIONS[:max_time])
         
     | 
| 
      
 171 
     | 
    
         
            +
                  Curses.addstr('max time')
         
     | 
| 
      
 172 
     | 
    
         
            +
                  Curses.setpos(1, first_position + POSITIONS[:errors])
         
     | 
| 
      
 173 
     | 
    
         
            +
                  Curses.addstr('errors')
         
     | 
| 
      
 174 
     | 
    
         
            +
                  Curses.setpos(1, first_position + POSITIONS[:error_percent])
         
     | 
| 
      
 175 
     | 
    
         
            +
                  Curses.addstr('error %')
         
     | 
| 
      
 176 
     | 
    
         
            +
                  Curses.setpos(1, first_position + POSITIONS[:throughput])
         
     | 
| 
      
 177 
     | 
    
         
            +
                  Curses.addstr('throughput')
         
     | 
| 
      
 178 
     | 
    
         
            +
                  Curses.setpos(2, 2)
         
     | 
| 
      
 179 
     | 
    
         
            +
                  Curses.addstr('-' * (first_position + TOTAL_LENGTH))
         
     | 
| 
      
 180 
     | 
    
         
            +
                  line = 3
         
     | 
| 
      
 181 
     | 
    
         
            +
                  names.each do |name|
         
     | 
| 
      
 182 
     | 
    
         
            +
                    Curses.setpos(line, 1)
         
     | 
| 
      
 183 
     | 
    
         
            +
                    Curses.addstr(divider_string)
         
     | 
| 
      
 184 
     | 
    
         
            +
                    Curses.setpos(line, 3)
         
     | 
| 
      
 185 
     | 
    
         
            +
                    Curses.addstr(name)
         
     | 
| 
      
 186 
     | 
    
         
            +
                    line += 1
         
     | 
| 
      
 187 
     | 
    
         
            +
                  end
         
     | 
| 
      
 188 
     | 
    
         
            +
                  Curses.setpos(line, 1)
         
     | 
| 
      
 189 
     | 
    
         
            +
                  Curses.addstr(divider_string)
         
     | 
| 
      
 190 
     | 
    
         
            +
                  line += 1
         
     | 
| 
      
 191 
     | 
    
         
            +
                  Curses.setpos(line, 1)
         
     | 
| 
      
 192 
     | 
    
         
            +
                  Curses.addstr(divider_string)
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                  Curses.setpos(line, 3)
         
     | 
| 
      
 195 
     | 
    
         
            +
                  Curses.addstr('TOTAL')
         
     | 
| 
      
 196 
     | 
    
         
            +
                  line += 1
         
     | 
| 
      
 197 
     | 
    
         
            +
                  Curses.setpos(line, 2)
         
     | 
| 
      
 198 
     | 
    
         
            +
                  Curses.addstr('-' * (first_position + TOTAL_LENGTH))
         
     | 
| 
      
 199 
     | 
    
         
            +
                end
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
                def divider_string
         
     | 
| 
      
 202 
     | 
    
         
            +
                  first_position = '|' + (' ' * (@longest_name + 2))
         
     | 
| 
      
 203 
     | 
    
         
            +
                  first_position + '|          |          |          |          |          |             |'
         
     | 
| 
      
 204 
     | 
    
         
            +
                end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                def close
         
     | 
| 
      
 207 
     | 
    
         
            +
                  Curses.curs_set(1)
         
     | 
| 
      
 208 
     | 
    
         
            +
                  Curses::close_screen
         
     | 
| 
      
 209 
     | 
    
         
            +
                end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                def write_debug(file)
         
     | 
| 
      
 212 
     | 
    
         
            +
                  (0..Curses.lines).each do |line|
         
     | 
| 
      
 213 
     | 
    
         
            +
                    line_string = ''
         
     | 
| 
      
 214 
     | 
    
         
            +
                    (0..Curses.cols).each do |col|
         
     | 
| 
      
 215 
     | 
    
         
            +
                      Curses.setpos(line, col)
         
     | 
| 
      
 216 
     | 
    
         
            +
                      line_string << Curses.inch.chr
         
     | 
| 
      
 217 
     | 
    
         
            +
                    end
         
     | 
| 
      
 218 
     | 
    
         
            +
                    line_string.strip!
         
     | 
| 
      
 219 
     | 
    
         
            +
                    unless line_string.empty?
         
     | 
| 
      
 220 
     | 
    
         
            +
                      file.puts(line_string)
         
     | 
| 
      
 221 
     | 
    
         
            +
                    end
         
     | 
| 
      
 222 
     | 
    
         
            +
                  end
         
     | 
| 
      
 223 
     | 
    
         
            +
                  file.flush
         
     | 
| 
      
 224 
     | 
    
         
            +
                end
         
     | 
| 
      
 225 
     | 
    
         
            +
              end
         
     | 
| 
      
 226 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,77 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: front_end_loader
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.3
         
     | 
| 
      
 5 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 6 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 7 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Aubrey Holland
         
     | 
| 
      
 9 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 10 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 11 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2012-10-08 00:00:00.000000000 Z
         
     | 
| 
      
 13 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 14 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 15 
     | 
    
         
            +
              name: patron
         
     | 
| 
      
 16 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 17 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 18 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 19 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 20 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 21 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 22 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 23 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 24 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 25 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 26 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 27 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 28 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 29 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 30 
     | 
    
         
            +
            description: ! 'Front End Loader allows clients to declare load tests using a pure-Ruby
         
     | 
| 
      
 31 
     | 
    
         
            +
              DSL.
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              This means that it is very simple to pass data between requests or to interact
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              with your systems in dynamic, complex ways.
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            '
         
     | 
| 
      
 38 
     | 
    
         
            +
            email: aubreyholland@gmail.com
         
     | 
| 
      
 39 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 40 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 41 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 42 
     | 
    
         
            +
            files:
         
     | 
| 
      
 43 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 44 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 45 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 46 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 47 
     | 
    
         
            +
            - front_end_loader.gemspec
         
     | 
| 
      
 48 
     | 
    
         
            +
            - lib/front_end_loader.rb
         
     | 
| 
      
 49 
     | 
    
         
            +
            - lib/front_end_loader/experiment.rb
         
     | 
| 
      
 50 
     | 
    
         
            +
            - lib/front_end_loader/request.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            - lib/front_end_loader/request_manager.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            - lib/front_end_loader/screen.rb
         
     | 
| 
      
 53 
     | 
    
         
            +
            homepage: https://github.com/brewster/front_end_loader
         
     | 
| 
      
 54 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 55 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 56 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 57 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 58 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 59 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 60 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 61 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 62 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 63 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 64 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 65 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 66 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 67 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 68 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 69 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 70 
     | 
    
         
            +
                  version: 1.3.5
         
     | 
| 
      
 71 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 72 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 73 
     | 
    
         
            +
            rubygems_version: 1.8.24
         
     | 
| 
      
 74 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 75 
     | 
    
         
            +
            specification_version: 2
         
     | 
| 
      
 76 
     | 
    
         
            +
            summary: A framework for doing declarative load testing in ruby
         
     | 
| 
      
 77 
     | 
    
         
            +
            test_files: []
         
     |