benchy 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in benchy.gemspec
4
+ gemspec
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "benchy/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "benchy"
7
+ s.version = Benchy::VERSION
8
+ s.authors = ["Brad Gessler"]
9
+ s.email = ["brad@bradgessler.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Benchmark HTTP applications}
12
+ s.description = %q{A dirty-simple HTTP benchmarking application}
13
+
14
+ s.rubyforge_project = "benchy"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ s.add_runtime_dependency "em-http-request"
24
+ s.add_runtime_dependency "thor"
25
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'rubygems'
5
+ require 'benchy'
6
+
7
+ Benchy::CLI.start
@@ -0,0 +1,125 @@
1
+ require "benchy/version"
2
+ require 'logger'
3
+ require "thor"
4
+
5
+ module Benchy
6
+ def self.logger
7
+ @logger ||= Logger.new($stdout)
8
+ end
9
+
10
+ class Dispatcher
11
+ attr_accessor :concurrency, :request
12
+
13
+ def initialize(request, concurrency=1)
14
+ @request, @concurrency = request, concurrency
15
+ end
16
+
17
+ def run
18
+ workers.each(&:run)
19
+ end
20
+
21
+ def halt
22
+ workers.each(&:halt)
23
+ end
24
+
25
+ def workers
26
+ @workers ||= (0...concurrency).map{|n| Worker.new(request, "worker.#{n}") }
27
+ end
28
+ end
29
+
30
+ class Worker
31
+ attr_accessor :request, :name
32
+
33
+ def initialize(request, name)
34
+ @request, @name = request, name
35
+ end
36
+
37
+ # Run, and keep running!
38
+ def run
39
+ return if halted?
40
+
41
+ http = request.em
42
+ http.callback {
43
+ Benchy.logger.info "#{name}\t| #{request.method.upcase} #{request.url} - HTTP #{http.response_header.status}"
44
+ run
45
+ }
46
+ http.errback {
47
+ Benchy.logger.debug "Connection error!"
48
+ halt # TODO - Make this fail the ping and try again, not halt
49
+ }
50
+ end
51
+
52
+ def halt
53
+ @halted = false
54
+ end
55
+
56
+ def halted?
57
+ !!@halted
58
+ end
59
+ end
60
+
61
+ # Represents an HTTP Request, but can't actually be executed
62
+ class Request
63
+ attr_accessor :url, :method, :headers, :body
64
+
65
+ def initialize(url, method, headers, body=nil)
66
+ @url, @method, @headers, @body = url, method, (headers || {}), body
67
+ end
68
+
69
+ # Grab an instance of an Em::Http request so we can run it somewhere.
70
+ def em
71
+ EventMachine::HttpRequest.new(url).send(method.downcase,
72
+ :head => default_headers.merge(headers),
73
+ :body => body,
74
+ :connect_timeout => 9000, # Disable
75
+ :inactivity_timeout => 9000 # Disable
76
+ )
77
+ end
78
+
79
+ # Setup smart default headers to minimize the chances that a request gets rejected.
80
+ def default_headers
81
+ default_headers = {}
82
+ default_headers['Content-Type'] = 'application/binary-octet' if body
83
+ default_headers['Accepts'] = '*/*'
84
+ default_headers
85
+ end
86
+ end
87
+
88
+ # Parse out some command line goodness
89
+ class CLI < Thor
90
+ desc "benchmark URL", "Run benchmarks against server"
91
+ method_option :body,
92
+ :type => :string,
93
+ :aliases => '-b',
94
+ :desc => "Request body"
95
+ method_option :file,
96
+ :type => :string,
97
+ :aliases => '-f',
98
+ :desc => "File for request body"
99
+ method_option :headers,
100
+ :type => :hash,
101
+ :aliases => '-h',
102
+ :desc => 'HTTP headers'
103
+ method_option :method,
104
+ :type => :string,
105
+ :desc => "Request method",
106
+ :aliases => '-m',
107
+ :default => 'GET'
108
+ method_option :concurrency,
109
+ :type => :numeric,
110
+ :desc => "Concurrent requests",
111
+ :aliases => '-c',
112
+ :default => 1
113
+
114
+ def benchmark(url)
115
+ req = Request.new(url, options[:method], options[:headers], self.class.body(options))
116
+ EM.run { Dispatcher.new(req, options[:concurrency]).run }
117
+ end
118
+
119
+ private
120
+ # Normalize the request body if its a file or a text string.
121
+ def self.body(options)
122
+ options[:file] ? File.read(options[:file]) : options[:body]
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,5 @@
1
+ require 'em-http-request'
2
+
3
+ module Benchy
4
+ VERSION = "0.0.1"
5
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: benchy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Brad Gessler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: em-http-request
16
+ requirement: &70165834461960 !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: *70165834461960
25
+ - !ruby/object:Gem::Dependency
26
+ name: thor
27
+ requirement: &70165834461540 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70165834461540
36
+ description: A dirty-simple HTTP benchmarking application
37
+ email:
38
+ - brad@bradgessler.com
39
+ executables:
40
+ - benchy
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - Rakefile
47
+ - benchy.gemspec
48
+ - bin/benchy
49
+ - lib/benchy.rb
50
+ - lib/benchy/version.rb
51
+ homepage: ''
52
+ licenses: []
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project: benchy
71
+ rubygems_version: 1.8.11
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Benchmark HTTP applications
75
+ test_files: []
76
+ has_rdoc: