nethttp_ab 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.
data/Manifest ADDED
@@ -0,0 +1,12 @@
1
+ README
2
+ Rakefile
3
+ bin/nethttp_ab
4
+ lib/net.rb
5
+ lib/requester.rb
6
+ lib/requests_queue.rb
7
+ lib/simple_requests_queue.rb
8
+ test/nethttp_ab_test.rb
9
+ test/requests_queue_test.rb
10
+ test/resources/index.html
11
+ test/simple_requests_queue_test.rb
12
+ Manifest
data/README ADDED
@@ -0,0 +1,8 @@
1
+ Simple tool to benchmark sites (rpm, response time, etc)
2
+
3
+ SIMPLE USAGE
4
+ 3 concurrent threads and 100 total requests:
5
+ nethttp_ab -n 100 -c 3 http://www.yoursite.com
6
+
7
+ OR simulate user and follow all local links on the page:
8
+ nethttp_ab -f http://localhost:3000
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('nethttp_ab', '0.0.1') do |p|
6
+ p.description = "Simple tool to benchmark sites"
7
+ p.url = "http://github.com/german/nethttp_ab"
8
+ p.author = "Dmitrii Samoilov"
9
+ p.email = "germaninthetown@gmail.com"
10
+ p.development_dependencies = []
11
+ end
data/bin/nethttp_ab ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'trollop'
4
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/requester.rb'
5
+
6
+ # SIMPLE USAGE:
7
+ # 3 concurrent threads and 100 total requests
8
+ # nethttp_ab -n 100 -c 3 http://www.yoursite.com
9
+ #
10
+ # OR simulate user and follow all local links on the page
11
+ # nethttp_ab -f http://localhost:3000
12
+
13
+ opts = Trollop::options do
14
+ opt :concurrent_threads, "Number of concurrent threads", :default => 3, :short => 'c'
15
+ opt :requests, "Total number of requests", :default => 10, :short => 'n'
16
+ opt :follow_links, "Whether to follow links from received pages (emulating real user)", :default => false, :short => 'f'
17
+ end
18
+
19
+ url_to_benchmark = "http://localhost:3000/"
20
+ # search for the url to perform benchmarking on
21
+ # we don't use trollop here since I don't like to specify --url=http://mysite.com to get the url
22
+ ARGV.each do |arg|
23
+ url_to_benchmark = arg if arg =~ /https?:\/\/|www\./
24
+ end
25
+
26
+ requester = NethttpAb::Requester.new
27
+ requester.concurrent_users = opts[:concurrent_threads]
28
+ requester.num_of_requests = opts[:requests]
29
+ requester.follow_links = opts[:follow_links]
30
+ requester.url = url_to_benchmark
31
+
32
+ requester.proceed
33
+ requester.print_stats
data/lib/net.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ module NethttpAb
5
+ module Utility
6
+ def get_http_session(url)
7
+ http = Net::HTTP.new(url.host, url.port)
8
+ if url.scheme == "https"
9
+ http.use_ssl = true
10
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
11
+ end
12
+
13
+ http.read_timeout = 10
14
+ http.open_timeout = 10
15
+
16
+ http_opened_session = http.start
17
+
18
+ http_opened_session
19
+ end
20
+ end
21
+ end
data/lib/requester.rb ADDED
@@ -0,0 +1,144 @@
1
+ require 'benchmark'
2
+ require 'thread'
3
+ require 'nokogiri' # we could follow links on the pages if there's --follow-links=2 option
4
+
5
+ require File.dirname(File.expand_path(__FILE__)) + '/requests_queue'
6
+ require File.dirname(File.expand_path(__FILE__)) + '/simple_requests_queue'
7
+ require File.dirname(File.expand_path(__FILE__)) + '/net'
8
+
9
+ module NethttpAb
10
+ class Requester
11
+ include NethttpAb::Utility
12
+
13
+ attr_accessor :successfull_requests
14
+ attr_accessor :failed_requests
15
+
16
+ def initialize
17
+ @response_length = 0
18
+ @total_time = 0.0
19
+ @threads = []
20
+ @mutex = Mutex.new
21
+ @failed_requests = 0
22
+ @successfull_requests = 0
23
+ @follow_links = false
24
+ end
25
+
26
+ def concurrent_users=(num)
27
+ @concurrent_users = num
28
+ end
29
+
30
+ def num_of_requests=(num)
31
+ @num_of_requests = num
32
+ end
33
+
34
+ def follow_links=(flag)
35
+ @follow_links = flag
36
+ end
37
+
38
+ def url=(link)
39
+ @url = URI.parse(link)
40
+ @url.path = '/' if @url.path == "" # ensure we requesting main page (if url is like http://google.com)
41
+ end
42
+
43
+ def print_stats
44
+ print "Failed requests: #{@failed_requests}\n"
45
+ print "Succeeded requests: #{@successfull_requests}\n\n"
46
+
47
+ print "Total response length: #{@response_length} bytes\n"
48
+ if @successfull_requests > 0
49
+ print "Recieved characters per one page: #{@response_length / @successfull_requests} bytes\n\n"
50
+ end
51
+
52
+ printf "Total time: %.03f s\n", @total_time
53
+ printf "Average time per request: %.03f s\n", @total_time / @successfull_requests.to_f
54
+ printf "Requests per second: %.01f rps\n", 1.0 / (@total_time / @successfull_requests.to_f)
55
+ end
56
+
57
+ def proceed
58
+ prepare_queue
59
+ start_threads
60
+ end
61
+
62
+ private
63
+
64
+ def prepare_queue
65
+ @requests_queue = if @follow_links
66
+ # get all links to benchmark as user behavior
67
+ begin
68
+ http_opened_session = get_http_session(@url)
69
+ rescue OpenSSL::SSL::SSLError => e
70
+ puts("The url you provided is wrong, please check is it really ssl encrypted")
71
+ exit
72
+ rescue Errno::ECONNREFUSED => e
73
+ puts("Connection error, please check your internet connection or make sure the server is running (it's local)")
74
+ exit
75
+ end
76
+
77
+ req = Net::HTTP::Get.new(@url.path)
78
+ response = http_opened_session.request(req)
79
+ doc = Nokogiri::HTML(response.body)
80
+ #puts doc.css('a').map{|el| el.attr('href')}.inspect
81
+ local_links = doc.css('a').reject{|el| el.attr('rel') == 'nofollow'}.select{|el| el.attr('href').match(Regexp.escape(@url.host)) || (el.attr('href') !~ /^(http|www|javascript)/) }
82
+ local_links.map!{|el| el.attr('href')}
83
+ local_links.uniq!
84
+ print "Found #{local_links.inspect} local links\n"
85
+ NethttpAb::RequestsQueue.new(local_links)
86
+ else
87
+ NethttpAb::SimpleRequestsQueue.new(@num_of_requests)
88
+ end
89
+ end
90
+
91
+ def start_threads
92
+ @concurrent_users.times do
93
+ begin
94
+ http_opened_session = get_http_session(@url)
95
+ rescue OpenSSL::SSL::SSLError => e
96
+ puts("The url you provided is wrong, please check is it really ssl encrypted")
97
+ exit
98
+ rescue Errno::ECONNREFUSED => e
99
+ puts("Connection error, please check your internet connection or make sure the server is running (it's local)")
100
+ exit
101
+ end
102
+
103
+ @threads << Thread.new do
104
+ while !@requests_queue.empty? do
105
+ # lock request in order to avoid sharing same request by two threads and making more requests then specified
106
+ if next_url = @requests_queue.lock_next_request
107
+ req = if @follow_links
108
+ next_url_parsed = URI.parse(next_url)
109
+ Net::HTTP::Get.new(next_url_parsed.path)
110
+ else
111
+ Net::HTTP::Get.new(@url.path)
112
+ end
113
+
114
+ @total_time += Benchmark.realtime do
115
+ begin
116
+ response = http_opened_session.request(req)
117
+ @mutex.synchronize do
118
+ @response_length += response.body.length
119
+ @successfull_requests += 1
120
+ @requests_queue.release_locked_request(next_url)
121
+ end
122
+ rescue Net::HTTPBadResponse => e
123
+ print "An error occured: #{e.message}\n"
124
+ @failed_requests += 1
125
+ rescue Timeout::Error => e
126
+ print "Timeout error for #{next_url}\n"
127
+ @failed_requests += 1
128
+ rescue => e
129
+ print "An error occured: #{e.message}\n"
130
+ @failed_requests += 1
131
+ end
132
+ end
133
+ else
134
+ # exit current thread since there's no available requests in requests_queue
135
+ Thread.exit
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ @threads.each{|thread| thread.join}
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,32 @@
1
+ module NethttpAb
2
+ class RequestsQueue
3
+ def initialize(url_array)
4
+ @urls_queue = url_array
5
+ @locked_urls = []
6
+
7
+ @num_of_requests = url_array.size
8
+ @num_of_locked = 0
9
+ end
10
+
11
+ def lock_next_request
12
+ if @num_of_requests > @num_of_locked
13
+ @num_of_locked += 1
14
+ @locked_urls << @urls_queue.shift
15
+ @locked_urls.last
16
+ end
17
+ end
18
+
19
+ def release_locked_request(url)
20
+ if @num_of_locked > 0
21
+ @num_of_locked -= 1
22
+ @locked_urls.delete_if{|u| u == url}
23
+ end
24
+
25
+ @num_of_requests -= 1 if @num_of_requests > 0
26
+ end
27
+
28
+ def empty?
29
+ @num_of_requests == 0
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ module NethttpAb
2
+ class SimpleRequestsQueue
3
+ def initialize(num_of_requests)
4
+ @num_of_requests = num_of_requests
5
+ @num_of_locked = 0
6
+ end
7
+
8
+ def lock_next_request
9
+ if @num_of_requests > @num_of_locked
10
+ @num_of_locked += 1
11
+ true
12
+ else
13
+ false
14
+ end
15
+ end
16
+
17
+ def release_locked_request(url = nil)
18
+ @num_of_locked -= 1 if @num_of_locked > 0
19
+ @num_of_requests -= 1 if @num_of_requests > 0
20
+ end
21
+
22
+ def empty?
23
+ @num_of_requests == 0
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{nethttp_ab}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Dmitrii Samoilov"]
9
+ s.cert_chain = ["/home/german/.ssh/gem-public_cert.pem"]
10
+ s.date = %q{2011-04-05}
11
+ s.default_executable = %q{nethttp_ab}
12
+ s.description = %q{Simple tool to benchmark sites}
13
+ s.email = %q{germaninthetown@gmail.com}
14
+ s.executables = ["nethttp_ab"]
15
+ s.extra_rdoc_files = ["README", "bin/nethttp_ab", "lib/net.rb", "lib/requester.rb", "lib/requests_queue.rb", "lib/simple_requests_queue.rb"]
16
+ s.files = ["README", "Rakefile", "bin/nethttp_ab", "lib/net.rb", "lib/requester.rb", "lib/requests_queue.rb", "lib/simple_requests_queue.rb", "test/nethttp_ab_test.rb", "test/requests_queue_test.rb", "test/resources/index.html", "test/simple_requests_queue_test.rb", "Manifest", "nethttp_ab.gemspec"]
17
+ s.homepage = %q{http://github.com/german/nethttp_ab}
18
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Nethttp_ab", "--main", "README"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{nethttp_ab}
21
+ s.rubygems_version = %q{1.6.2}
22
+ s.signing_key = %q{/home/german/.ssh/gem-private_key.pem}
23
+ s.summary = %q{Simple tool to benchmark sites}
24
+ s.test_files = ["test/simple_requests_queue_test.rb", "test/requests_queue_test.rb", "test/nethttp_ab_test.rb"]
25
+
26
+ if s.respond_to? :specification_version then
27
+ s.specification_version = 3
28
+
29
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
30
+ else
31
+ end
32
+ else
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ require 'test/unit'
2
+ require 'net/http'
3
+ require 'mocha'
4
+
5
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/requester.rb'
6
+
7
+ class TestResponse < Struct.new(:head, :body, :response_code)
8
+ end
9
+
10
+ class OpenSession
11
+ def request(url)
12
+ body = File.read(File.join(File.dirname(File.expand_path(__FILE__)), 'resources', url.path))
13
+ TestResponse.new("head", body, 200)
14
+ end
15
+ end
16
+
17
+ class NetHttpAbTest < Test::Unit::TestCase
18
+ def test_simple
19
+ Net::HTTP.any_instance.stubs(:start).returns(OpenSession.new)
20
+
21
+ requester = NethttpAb::Requester.new
22
+
23
+ requester.url = "http://localhost/index.html"
24
+ requester.concurrent_users = 3
25
+ requester.num_of_requests = 10
26
+ requester.follow_links = false
27
+
28
+ requester.proceed
29
+
30
+ assert_equal 10, requester.successfull_requests
31
+ assert_equal 0, requester.failed_requests
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/requests_queue.rb'
3
+
4
+ class RequestQueueTest < Test::Unit::TestCase
5
+ def test_initial
6
+ urls = ["http://www.google.com", "http://www.ruby-lang.com", "http://www.github.com", "http://www.def-end.com"]
7
+
8
+ queue = NethttpAb::RequestsQueue.new urls
9
+ assert !queue.empty?
10
+
11
+ 4.times { assert queue.lock_next_request }
12
+
13
+ 3.times { |i| queue.release_locked_request(urls[i]) }
14
+
15
+ assert !queue.empty?
16
+
17
+ queue.release_locked_request(urls[3])
18
+
19
+ assert queue.empty?
20
+
21
+ assert !queue.lock_next_request
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ <html>
2
+ <body>test</body>
3
+ </html>
@@ -0,0 +1,21 @@
1
+ require 'test/unit'
2
+ require File.dirname(File.expand_path(__FILE__)) + '/../lib/simple_requests_queue.rb'
3
+
4
+ class SimpleRequestQueueTest < Test::Unit::TestCase
5
+ def test_initial
6
+ queue = NethttpAb::SimpleRequestsQueue.new(3)
7
+ assert !queue.empty?
8
+
9
+ 3.times { assert queue.lock_next_request }
10
+
11
+ 2.times { queue.release_locked_request }
12
+
13
+ assert !queue.empty?
14
+
15
+ queue.release_locked_request
16
+
17
+ assert queue.empty?
18
+
19
+ assert !queue.lock_next_request
20
+ end
21
+ end
data.tar.gz.sig ADDED
@@ -0,0 +1 @@
1
+ ��5�\',�-�Oº� �ۓ���s�*��HKȴH��!�o��>:�=�h�|C�'�\��Ws��s���)���bâΘ U�>���o_�uT�Sm/�;��9S�����^�)��P����KO‰�v�o�g���^ը����L��wU������<cHb��u�*�t0M�u��\�
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nethttp_ab
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Dmitrii Samoilov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain:
12
+ - |
13
+ -----BEGIN CERTIFICATE-----
14
+ MIIDQDCCAiigAwIBAgIBADANBgkqhkiG9w0BAQUFADBGMRgwFgYDVQQDDA9nZXJt
15
+ YW5pbnRoZXRvd24xFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixk
16
+ ARkWA2NvbTAeFw0xMTA0MDUwOTM4NTRaFw0xMjA0MDQwOTM4NTRaMEYxGDAWBgNV
17
+ BAMMD2dlcm1hbmludGhldG93bjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYK
18
+ CZImiZPyLGQBGRYDY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
19
+ wgFgELrtM2WGMHb0Tbd0mHzzd1O7begCVLUVqTfULTWxRyfa1xlPYGOkprxwfQE0
20
+ e1TLzhgtzrwPtKm0+IWlz0yiDdcP+/vORNYGJn0hlVMIyoh/Gjvy9tg+lAZHHzyW
21
+ P08b83YCvTAsfmYwj1gCVERJcTNYoqerpTX711+qYYAm4KMEXOlk3w6vOSXSgioH
22
+ qT3hlHivuRnLO8ASv2dC0Xpej0wUqtFx+h6FkYzrs5PFp5r9Ccste/vTonP5sWX3
23
+ FlXZaqawuFqlYbkVEjIZyE5smYeBR3NJsNjIpcdpInWaYul631yIEy5UiPucGlnQ
24
+ LSqxi4knbIeA0S58KgRvtQIDAQABozkwNzAJBgNVHRMEAjAAMB0GA1UdDgQWBBQR
25
+ MgXYASGhr6Z27DY6DTOu66QfKjALBgNVHQ8EBAMCBLAwDQYJKoZIhvcNAQEFBQAD
26
+ ggEBADkXRjtNXe+PCTkBpODetl9Mgrw3vxmQbpaQFeV0IPMiav+6m48/ai0p9zxF
27
+ JpjN7GPHzy8LJQGmwOOrpDwU7JsX6hlXtXToKM/RcStUqm1v+8GLE/K777Foq4T+
28
+ 6QmqCPwYdpN1hijiEM4miV9osuZYTAnR9IKBakY3tRE1Q7aTTyT4tMmS/GrwY+IB
29
+ qih6K+1QUvvm0euQNIlHfM0RQ+cgISMezNJRmDtldZTLI5NbSnbO6mW+QoFcKmXz
30
+ +Zut89O9LtR+kOHx2W1p7eHudOUB4L6lCafXA1O54piyMbYsde8oHmAjW39hKaUo
31
+ r061XXjdbf9qKeUjTZ6lmWaQMjM=
32
+ -----END CERTIFICATE-----
33
+
34
+ date: 2011-04-05 00:00:00 +03:00
35
+ default_executable:
36
+ dependencies: []
37
+
38
+ description: Simple tool to benchmark sites
39
+ email: germaninthetown@gmail.com
40
+ executables:
41
+ - nethttp_ab
42
+ extensions: []
43
+
44
+ extra_rdoc_files:
45
+ - README
46
+ - bin/nethttp_ab
47
+ - lib/net.rb
48
+ - lib/requester.rb
49
+ - lib/requests_queue.rb
50
+ - lib/simple_requests_queue.rb
51
+ files:
52
+ - README
53
+ - Rakefile
54
+ - bin/nethttp_ab
55
+ - lib/net.rb
56
+ - lib/requester.rb
57
+ - lib/requests_queue.rb
58
+ - lib/simple_requests_queue.rb
59
+ - test/nethttp_ab_test.rb
60
+ - test/requests_queue_test.rb
61
+ - test/resources/index.html
62
+ - test/simple_requests_queue_test.rb
63
+ - Manifest
64
+ - nethttp_ab.gemspec
65
+ has_rdoc: true
66
+ homepage: http://github.com/german/nethttp_ab
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --line-numbers
72
+ - --inline-source
73
+ - --title
74
+ - Nethttp_ab
75
+ - --main
76
+ - README
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "1.2"
91
+ requirements: []
92
+
93
+ rubyforge_project: nethttp_ab
94
+ rubygems_version: 1.6.2
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Simple tool to benchmark sites
98
+ test_files:
99
+ - test/simple_requests_queue_test.rb
100
+ - test/requests_queue_test.rb
101
+ - test/nethttp_ab_test.rb
metadata.gz.sig ADDED
Binary file