benchy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: