httping 1.0.0
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/Rakefile +26 -0
- data/VERSION +1 -0
- data/bin/httping +7 -0
- data/lib/extensions/enumerable.rb +9 -0
- data/lib/extensions/fixnum.rb +9 -0
- data/lib/extensions/float.rb +9 -0
- data/lib/httping.rb +10 -0
- data/lib/httping/ping.rb +93 -0
- data/lib/httping/runner.rb +83 -0
- data/spec/extensions_spec.rb +53 -0
- data/spec/ping_spec.rb +44 -0
- data/spec/runner_spec.rb +60 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +34 -0
- metadata +90 -0
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec/rake/spectask'
|
2
|
+
|
3
|
+
task :default => [:spec]
|
4
|
+
|
5
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
6
|
+
spec.libs << 'lib' << 'spec'
|
7
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
8
|
+
spec.spec_opts = ['--options', 'spec/spec.opts']
|
9
|
+
end
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
gem.name = "httping"
|
15
|
+
gem.date = %q{2009-09-15}
|
16
|
+
gem.default_executable = %q{httping}
|
17
|
+
gem.summary = "Measures web site response time"
|
18
|
+
gem.description = "Measures web site response time"
|
19
|
+
gem.email = "john.pignata@gmail.com"
|
20
|
+
gem.authors = ["John Pignata"]
|
21
|
+
gem.add_development_dependency "rspec", "1.2.9"
|
22
|
+
gem.add_development_dependency "fakeweb", "1.2.6"
|
23
|
+
end
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
26
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/bin/httping
ADDED
data/lib/httping.rb
ADDED
data/lib/httping/ping.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
class Ping
|
2
|
+
include Net
|
3
|
+
|
4
|
+
attr_writer :flood, :format, :audible, :user_agent, :referrer, :delay, :count, :uri
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@ping_results = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
trap("INT") { results }
|
12
|
+
loop do
|
13
|
+
ping
|
14
|
+
results if count_reached?
|
15
|
+
sleep @delay unless @flood
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def ping
|
20
|
+
start_time = Time.now
|
21
|
+
response, data = request.get(uri, http_header)
|
22
|
+
@ping_results << duration = Time.now - start_time
|
23
|
+
ping_summary(response, data, duration) if @format == :interactive
|
24
|
+
end
|
25
|
+
|
26
|
+
def request
|
27
|
+
request = Net::HTTP.new(@uri.host, @uri.port)
|
28
|
+
|
29
|
+
if @uri.scheme == "https"
|
30
|
+
request.use_ssl = true
|
31
|
+
request.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
32
|
+
end
|
33
|
+
|
34
|
+
request
|
35
|
+
end
|
36
|
+
|
37
|
+
def uri
|
38
|
+
if @uri.query
|
39
|
+
"#{@uri.path}?#{@uri.query}"
|
40
|
+
else
|
41
|
+
"#{@uri.path}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def http_header
|
46
|
+
header = {}
|
47
|
+
header['User-Agent'] = @user_agent if @user_agent
|
48
|
+
header['Referrer'] = @referrer if @referrer
|
49
|
+
header
|
50
|
+
end
|
51
|
+
|
52
|
+
def ping_summary(response, data, duration)
|
53
|
+
print beep if @audible
|
54
|
+
puts "#{data.length.to_human_size} from #{@uri}: code=#{response.code} msg=#{response.message} time=#{duration.to_human_time}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def beep
|
58
|
+
7.chr
|
59
|
+
end
|
60
|
+
|
61
|
+
def results
|
62
|
+
if @format.nil?
|
63
|
+
interactive_results
|
64
|
+
else
|
65
|
+
send("#{@format}_results")
|
66
|
+
end
|
67
|
+
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
def interactive_results
|
72
|
+
puts
|
73
|
+
puts "--- #{@uri} httping.rb statistics ---"
|
74
|
+
puts "#{@ping_results.size} GETs transmitted"
|
75
|
+
puts "round-trip min/avg/max = #{@ping_results.min.to_human_time}/#{@ping_results.mean.to_human_time}/#{@ping_results.max.to_human_time}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def json_results
|
79
|
+
results = "{\"max\": #{@ping_results.max}, \"avg\": #{@ping_results.mean}, \"min\": #{@ping_results.min}}"
|
80
|
+
sent = @ping_results.size
|
81
|
+
uri = @uri.to_s
|
82
|
+
puts "{\"results\": #{results}, \"sent\": #{sent}, \"uri\": \"#{uri}\"}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def quick_results
|
86
|
+
duration = @ping_results.first.to_human_time
|
87
|
+
puts "OK [#{duration}]"
|
88
|
+
end
|
89
|
+
|
90
|
+
def count_reached?
|
91
|
+
@ping_results.size == @count
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class Runner
|
2
|
+
BANNER = "Usage: httping [options] uri"
|
3
|
+
|
4
|
+
def run
|
5
|
+
options = parse_arguments
|
6
|
+
|
7
|
+
if options[:uri]
|
8
|
+
httping = Ping.new
|
9
|
+
options.each { |property, value| httping.send("#{property}=", value) }
|
10
|
+
httping.run
|
11
|
+
else
|
12
|
+
puts BANNER
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_arguments
|
17
|
+
options = {
|
18
|
+
:delay => 1,
|
19
|
+
:format => :interactive,
|
20
|
+
:flood => false,
|
21
|
+
:audible => false
|
22
|
+
}
|
23
|
+
|
24
|
+
begin
|
25
|
+
params = OptionParser.new do |opts|
|
26
|
+
opts.banner = BANNER
|
27
|
+
opts.on('-c', '--count NUM', 'Number of times to ping host') do |count|
|
28
|
+
options[:count] = count.to_i
|
29
|
+
end
|
30
|
+
opts.on('-d', '--delay SECS', 'Delay in seconds between pings (default: 1)') do |delay|
|
31
|
+
options[:delay] = delay.to_i
|
32
|
+
end
|
33
|
+
opts.on('-f', '--flood', 'Flood ping (no delay)') do
|
34
|
+
options[:flood] = true
|
35
|
+
end
|
36
|
+
opts.on('-j', '--json', 'Return JSON results') do
|
37
|
+
options[:format] = :json
|
38
|
+
end
|
39
|
+
opts.on('-q', '--quick', 'Ping once and return OK if up') do
|
40
|
+
options[:format] = :quick
|
41
|
+
end
|
42
|
+
opts.on('-a', '--audible', 'Beep on each ping') do
|
43
|
+
options[:audible] = true
|
44
|
+
end
|
45
|
+
opts.on('-u', '--user-agent STR', 'User agent string to send in headers') do |user_agent|
|
46
|
+
options[:user_agent] = user_agent
|
47
|
+
end
|
48
|
+
opts.on('-r', '--referrer STR', 'Referrer string to send in headers') do |referrer|
|
49
|
+
options[:referrer] = referrer
|
50
|
+
end
|
51
|
+
opts.on('-h', '--help', 'Display this screen') do
|
52
|
+
puts opts
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
opts.parse!
|
56
|
+
options[:uri] = parse_uri if ARGV.first
|
57
|
+
end
|
58
|
+
rescue OptionParser::InvalidOption => exception
|
59
|
+
puts exception
|
60
|
+
end
|
61
|
+
|
62
|
+
if options[:format] == :json && !options.include?(:count)
|
63
|
+
options[:count] = 5 # Default to 5 if no count provided for JSON format
|
64
|
+
elsif options[:format] == :quick
|
65
|
+
options[:count] = 1 # Quick format always sends only 1 ping
|
66
|
+
end
|
67
|
+
|
68
|
+
options
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_uri
|
72
|
+
uri = URI.parse(ARGV.first)
|
73
|
+
|
74
|
+
unless ["http", "https"].include?(uri.scheme)
|
75
|
+
puts "ERROR: Invalid URI #{uri}"
|
76
|
+
exit
|
77
|
+
end
|
78
|
+
|
79
|
+
uri.path = "/" unless uri.path.match /^\//
|
80
|
+
|
81
|
+
uri
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Enumerable" do
|
4
|
+
before do
|
5
|
+
@array = [1, 58, 49, 330, 2, 15, 3, 80]
|
6
|
+
end
|
7
|
+
|
8
|
+
context ".sum" do
|
9
|
+
it "returns the sum of all members of a set" do
|
10
|
+
@array.sum.should be(538)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context ".mean" do
|
15
|
+
it "returns the mean of a set" do
|
16
|
+
@array.mean.should be(67)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "Float" do
|
22
|
+
before do
|
23
|
+
@milliseconds = 0.2997921
|
24
|
+
@second = 1.1291
|
25
|
+
@seconds = 48.31292
|
26
|
+
end
|
27
|
+
|
28
|
+
context ".to_human_time" do
|
29
|
+
it "returns a human friendly string of the elapsed time represented by a float" do
|
30
|
+
@milliseconds.to_human_time.should == "299 msecs"
|
31
|
+
@second.to_human_time.should == "1 sec"
|
32
|
+
@seconds.to_human_time.should == "48 secs"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "Fixnum" do
|
38
|
+
before do
|
39
|
+
@bytes = 12
|
40
|
+
@kilobytes = 8_939
|
41
|
+
@megabytes = 4_911_219
|
42
|
+
@gigabytes = 8_289_119_584
|
43
|
+
end
|
44
|
+
|
45
|
+
context ".to_human_size" do
|
46
|
+
it "returns a human friendly string of the amount of bytes represented by a number" do
|
47
|
+
@bytes.to_human_size.should == "12 bytes"
|
48
|
+
@kilobytes.to_human_size.should == "8 kb"
|
49
|
+
@megabytes = "5 mb"
|
50
|
+
@gigabytes = "8289119489 bytes"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/ping_spec.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Ping" do
|
4
|
+
before do
|
5
|
+
@httping = Ping.new
|
6
|
+
@httping.uri = URI.parse("http://www.example.com/")
|
7
|
+
@httping.format = :interactive
|
8
|
+
@httping.count = 10
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:each) do
|
12
|
+
Output.clear
|
13
|
+
end
|
14
|
+
|
15
|
+
context ".ping" do
|
16
|
+
it "pings the configured url and outputs statistics" do
|
17
|
+
@httping.ping
|
18
|
+
Output.to_s.should match(/10 bytes from http:\/\/www.example.com\/: code=200 msg=OK time=[0-9] msecs/)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context ".count_reached?" do
|
23
|
+
it "returns false if a host has not yet been pinged the number of times requested" do
|
24
|
+
2.times { @httping.ping }
|
25
|
+
@httping.should_not be_count_reached
|
26
|
+
end
|
27
|
+
|
28
|
+
it "returns true if a host has been pinged the number of times requested" do
|
29
|
+
10.times { @httping.ping }
|
30
|
+
@httping.should be_count_reached
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context ".results" do
|
35
|
+
before do
|
36
|
+
5.times { @httping.ping }
|
37
|
+
end
|
38
|
+
|
39
|
+
it "outputs a summary of the pings" do
|
40
|
+
@httping.results
|
41
|
+
Output.to_s.should match(/-- http:\/\/www.example.com\/ httping.rb statistics ---\n5 GETs transmitted\n/)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/runner_spec.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Runner" do
|
4
|
+
before(:each) do
|
5
|
+
ARGV.clear
|
6
|
+
@runner = Runner.new
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
Output.clear
|
11
|
+
end
|
12
|
+
|
13
|
+
context ".parse_arguments" do
|
14
|
+
it "parses command-line arguments into an options hash" do
|
15
|
+
ARGV << "http://www.example.com"
|
16
|
+
ARGV << "--count"
|
17
|
+
ARGV << "3"
|
18
|
+
|
19
|
+
options = @runner.parse_arguments
|
20
|
+
options[:count].should == 3
|
21
|
+
options[:uri].to_s.should == "http://www.example.com/"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context ".run" do
|
26
|
+
it "returns the params banner if no arguments are passed" do
|
27
|
+
@runner.run
|
28
|
+
Output.to_s.should == "Usage: httping [options] uri"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns the params banner if invalid arguments are specified" do
|
32
|
+
ARGV << "-z"
|
33
|
+
@runner.run
|
34
|
+
Output.to_s.should == "invalid option: -z\nUsage: httping [options] uri"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "parse_uri" do
|
39
|
+
it "outputs an error and exists if not given an HTTP(S) URI" do
|
40
|
+
ARGV.clear
|
41
|
+
ARGV << "ftp://www.example.com"
|
42
|
+
@runner.parse_uri
|
43
|
+
Output.to_s.should == "ERROR: Invalid URI ftp://www.example.com"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "accepts HTTP URIs" do
|
47
|
+
ARGV.clear
|
48
|
+
ARGV << "http://www.example.com"
|
49
|
+
@runner.parse_uri
|
50
|
+
Output.to_s.should_not match(/ERROR/)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "accepts HTTPS URIs" do
|
54
|
+
ARGV.clear
|
55
|
+
ARGV << "https://www.example.com"
|
56
|
+
@runner.parse_uri
|
57
|
+
Output.to_s.should_not match(/ERROR/)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require File.join(File.dirname(__FILE__), '../lib/httping')
|
3
|
+
|
4
|
+
|
5
|
+
require 'fakeweb'
|
6
|
+
FakeWeb.allow_net_connect = false
|
7
|
+
FakeWeb.register_uri(:any, "http://www.example.com", :body => "hey there.")
|
8
|
+
|
9
|
+
class Object
|
10
|
+
def exit(status_code = nil)
|
11
|
+
@status = status_code
|
12
|
+
end
|
13
|
+
|
14
|
+
def puts(output_string = "\n")
|
15
|
+
Output.puts(output_string)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Output
|
20
|
+
class << self
|
21
|
+
def puts(output_string)
|
22
|
+
@output = [] if @output.nil?
|
23
|
+
@output << output_string
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
@output.join("\n") if @output
|
28
|
+
end
|
29
|
+
|
30
|
+
def clear
|
31
|
+
@output.clear if @output
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: httping
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Pignata
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-15 00:00:00 -04:00
|
13
|
+
default_executable: httping
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - "="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: fakeweb
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.2.6
|
34
|
+
version:
|
35
|
+
description: Measures web site response time
|
36
|
+
email: john.pignata@gmail.com
|
37
|
+
executables:
|
38
|
+
- httping
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- Rakefile
|
45
|
+
- VERSION
|
46
|
+
- bin/httping
|
47
|
+
- lib/extensions/enumerable.rb
|
48
|
+
- lib/extensions/fixnum.rb
|
49
|
+
- lib/extensions/float.rb
|
50
|
+
- lib/httping.rb
|
51
|
+
- lib/httping/ping.rb
|
52
|
+
- lib/httping/runner.rb
|
53
|
+
- spec/extensions_spec.rb
|
54
|
+
- spec/ping_spec.rb
|
55
|
+
- spec/runner_spec.rb
|
56
|
+
- spec/spec.opts
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage:
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.5
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: Measures web site response time
|
86
|
+
test_files:
|
87
|
+
- spec/extensions_spec.rb
|
88
|
+
- spec/ping_spec.rb
|
89
|
+
- spec/runner_spec.rb
|
90
|
+
- spec/spec_helper.rb
|