hansel 0.1.7 → 0.2.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/README.md +103 -0
- data/Rakefile +9 -1
- data/VERSION +1 -1
- data/bin/hansel +2 -5
- data/hansel.gemspec +23 -11
- data/lib/hansel/arg_parser.rb +84 -0
- data/lib/{csv_formatter.rb → hansel/formatting/csv_formatter.rb} +8 -13
- data/lib/hansel/formatting/formatting.rb +51 -0
- data/lib/{octave_formatter.rb → hansel/formatting/octave_formatter.rb} +1 -1
- data/lib/hansel/formatting/yaml_formatter.rb +10 -0
- data/lib/hansel/hansel.rb +77 -0
- data/lib/hansel/httperf/httperf.rb +36 -0
- data/lib/{httperf_result.rb → hansel/httperf_result.rb} +1 -1
- data/lib/{httperf_result_parser.rb → hansel/httperf_result_parser.rb} +1 -1
- data/lib/hansel/job_queue/job_queue.rb +27 -0
- data/lib/hansel.rb +9 -124
- data/spec/arg_parser_spec.rb +91 -34
- data/spec/hansel_spec.rb +134 -0
- data/spec/httperf_result_parser_spec.rb +3 -3
- data/spec/jobs.yml +8 -0
- data/spec/spec_helper.rb +1 -2
- metadata +44 -15
- data/README.rdoc +0 -22
- data/lib/arg_parser.rb +0 -143
- data/lib/config.rb +0 -60
- data/lib/yaml_formatter.rb +0 -14
data/lib/hansel.rb
CHANGED
@@ -1,127 +1,12 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require '
|
3
|
-
require 'lib/httperf_result'
|
2
|
+
require 'yaml'
|
4
3
|
|
5
|
-
|
6
|
-
#
|
7
|
-
# Class wrapper over httperf.
|
8
|
-
#
|
9
|
-
class Hansel
|
10
|
-
def initialize(options = {})
|
11
|
-
@options = options
|
12
|
-
@results = []
|
13
|
-
@current_rate = nil
|
14
|
-
end
|
4
|
+
$:.unshift File.dirname(__FILE__) + "/../lib/hansel"
|
15
5
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
"--num-conns=#{@options.num_conns}",
|
24
|
-
"--rate=#{@current_rate}",
|
25
|
-
cookie && "--add-header='Cookie: #{cookie}\\n'"
|
26
|
-
].compact.join ' '
|
27
|
-
end
|
28
|
-
|
29
|
-
#
|
30
|
-
# Runs httperf with a given request rate. Parses the output and returns
|
31
|
-
# a hash with the results.
|
32
|
-
#
|
33
|
-
def httperf
|
34
|
-
httperf_cmd = build_httperf_cmd
|
35
|
-
IO.popen("#{httperf_cmd} 2>&1") do |pipe|
|
36
|
-
puts "\n#{httperf_cmd}"
|
37
|
-
@results << (httperf_result = HttperfResult.new({
|
38
|
-
:rate => @current_rate,
|
39
|
-
:server => @options.server,
|
40
|
-
:port => @options.port,
|
41
|
-
:uri => @options.uri,
|
42
|
-
:num_conns => @options.num_conns
|
43
|
-
}))
|
44
|
-
HttperfResultParser.new(pipe).parse(httperf_result)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def yaml_formatter
|
49
|
-
load File.here '/../lib/yaml_formatter.rb'
|
50
|
-
YamlFormatter.new(@results)
|
51
|
-
end
|
52
|
-
|
53
|
-
def csv_formatter
|
54
|
-
load File.here '/../lib/csv_formatter.rb'
|
55
|
-
CsvFormatter.new(@results)
|
56
|
-
end
|
57
|
-
|
58
|
-
def octave_formatter
|
59
|
-
load File.here '/../lib/octave_formatter.rb'
|
60
|
-
puts @output_file_name
|
61
|
-
OctaveFormatter.new(@results, {
|
62
|
-
:output_file_name => @output_file_name,
|
63
|
-
:template => File.join([@options.template_path,
|
64
|
-
@options.template || 'octave.m.erb']),
|
65
|
-
}
|
66
|
-
)
|
67
|
-
end
|
68
|
-
|
69
|
-
def format format
|
70
|
-
formatter = "#{format}_formatter".to_sym
|
71
|
-
unless self.respond_to? formatter
|
72
|
-
puts "Using default octave_formatter"
|
73
|
-
octave_formatter
|
74
|
-
else
|
75
|
-
puts "Using #{formatter}"
|
76
|
-
self.send formatter
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def formatted_output
|
81
|
-
@output_file_name = [@options.server, @options.num_conns.to_s].join('.')
|
82
|
-
output_file = File.join @options.output_dir, @output_file_name
|
83
|
-
output_format = @options.output_format
|
84
|
-
type = { :yaml => 'yml', :csv => 'csv', :octave => 'm' }[output_format]
|
85
|
-
File.open([output_file, type].join('.'), "w+") do |file|
|
86
|
-
file.puts format(output_format).format
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
#
|
91
|
-
# Output the results based on the requested output format
|
92
|
-
#
|
93
|
-
def output
|
94
|
-
if @options.output
|
95
|
-
FileUtils.mkdir_p @options.output_dir
|
96
|
-
formatted_output
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def status text
|
101
|
-
puts text if @options.verbose
|
102
|
-
end
|
103
|
-
|
104
|
-
def run_all
|
105
|
-
(@options.low_rate.to_i..@options.high_rate.to_i).step(@options.rate_step.to_i) do |rate|
|
106
|
-
status "running httperf at rate: #{rate}"
|
107
|
-
@current_rate = rate
|
108
|
-
httperf
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
#
|
113
|
-
# Run httperf from low_rate to high_rate, stepping by rate_step
|
114
|
-
#
|
115
|
-
def run
|
116
|
-
status "starting run..."
|
117
|
-
run_all
|
118
|
-
output
|
119
|
-
status "ending run..."
|
120
|
-
end
|
121
|
-
|
122
|
-
trap("INT") {
|
123
|
-
puts "Terminating."
|
124
|
-
Process.exit
|
125
|
-
}
|
126
|
-
end
|
127
|
-
end
|
6
|
+
require 'arg_parser'
|
7
|
+
require 'formatting/formatting'
|
8
|
+
require 'httperf/httperf'
|
9
|
+
require 'httperf_result'
|
10
|
+
require 'httperf_result_parser'
|
11
|
+
require 'job_queue/job_queue'
|
12
|
+
require 'hansel'
|
data/spec/arg_parser_spec.rb
CHANGED
@@ -1,57 +1,114 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
-
require 'arg_parser'
|
3
2
|
|
4
|
-
describe
|
3
|
+
describe HanselCore::ArgParser, "#parse" do
|
5
4
|
before :each do
|
6
|
-
@argv = [
|
7
|
-
'--server=frunobulax.local',
|
8
|
-
'--port=4000',
|
9
|
-
'--uri=/',
|
10
|
-
'--num_conns=1',
|
11
|
-
'--low_rate=1',
|
12
|
-
'--high_rate=5',
|
13
|
-
'--rate_step=1',
|
14
|
-
'--format=octave',
|
15
|
-
'--output=true'
|
16
|
-
]
|
17
|
-
@options = Hansel::ArgParser.new(@argv).parse
|
18
5
|
end
|
19
6
|
|
20
|
-
describe "
|
21
|
-
|
22
|
-
|
23
|
-
|
7
|
+
describe "when the option" do
|
8
|
+
describe "master is set to 'localhost:4000'" do
|
9
|
+
it "should set master" do
|
10
|
+
@argv = [ '--master=localhost:4000' ]
|
11
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
12
|
+
@options.master.should == 'localhost:4000'
|
13
|
+
end
|
24
14
|
|
25
|
-
|
26
|
-
|
15
|
+
it "should set master" do
|
16
|
+
@argv = [ '-mlocalhost:4000' ]
|
17
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
18
|
+
@options.master.should == 'localhost:4000'
|
19
|
+
end
|
27
20
|
end
|
28
21
|
|
29
|
-
|
30
|
-
|
22
|
+
describe "dir is set to '/tmp/hansel_output'" do
|
23
|
+
it "should set output_dir" do
|
24
|
+
@argv = [ '--dir=/tmp/hansel_output' ]
|
25
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
26
|
+
@options.output_dir.should == '/tmp/hansel_output'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set output_dir" do
|
30
|
+
@argv = [ '-d/tmp/hansel_output' ]
|
31
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
32
|
+
@options.output_dir.should == '/tmp/hansel_output'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set template" do
|
36
|
+
@argv = [ '--template=/home/templates' ]
|
37
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
38
|
+
@options.template.should == '/home/templates'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should set template" do
|
42
|
+
@argv = [ '-t/home/templates' ]
|
43
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
44
|
+
@options.template.should == '/home/templates'
|
45
|
+
end
|
31
46
|
end
|
32
47
|
|
33
|
-
|
34
|
-
|
48
|
+
%w(yaml csv octave).each do |format|
|
49
|
+
describe "output --format is set to #{format}" do
|
50
|
+
it "should set format #{format}" do
|
51
|
+
@argv = [ "--format=#{format}" ]
|
52
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
53
|
+
@options.format.should == format
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should set format to #{format}" do
|
57
|
+
@argv = [ "-f#{format}" ]
|
58
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
59
|
+
@options.format.should == format
|
60
|
+
end
|
61
|
+
end
|
35
62
|
end
|
36
63
|
|
37
|
-
|
38
|
-
|
64
|
+
describe "verbose is set" do
|
65
|
+
it "should set verbose to true" do
|
66
|
+
@argv = [ '--verbose' ]
|
67
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
68
|
+
@options.verbose.should == true
|
69
|
+
end
|
70
|
+
it "should set verbose to true" do
|
71
|
+
@argv = [ '-v' ]
|
72
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
73
|
+
@options.verbose.should == true
|
74
|
+
end
|
39
75
|
end
|
40
76
|
|
41
|
-
|
42
|
-
|
77
|
+
describe "no-verbose is set" do
|
78
|
+
it "should set verbose to false" do
|
79
|
+
@argv = [ '--verbose', '--no-verbose' ]
|
80
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
81
|
+
@options.verbose.should == false
|
82
|
+
end
|
43
83
|
end
|
44
84
|
|
45
|
-
|
46
|
-
|
85
|
+
describe "verbose is not set" do
|
86
|
+
it "verbose defaults to false" do
|
87
|
+
@argv = [ ]
|
88
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
89
|
+
@options.verbose.should == false
|
90
|
+
end
|
47
91
|
end
|
48
92
|
|
49
|
-
|
50
|
-
|
93
|
+
describe "help is set" do
|
94
|
+
it "should set exit to true" do
|
95
|
+
@argv = [ '--help' ]
|
96
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
97
|
+
@options.exit.should == true
|
98
|
+
end
|
99
|
+
it "should set exit to true" do
|
100
|
+
@argv = [ '-h' ]
|
101
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
102
|
+
@options.exit.should == true
|
103
|
+
end
|
51
104
|
end
|
52
105
|
|
53
|
-
|
54
|
-
|
106
|
+
describe "version is set" do
|
107
|
+
it "should set exit to true" do
|
108
|
+
@argv = [ '--version' ]
|
109
|
+
@options = HanselCore::ArgParser.new(@argv).parse
|
110
|
+
@options.exit.should == true
|
111
|
+
end
|
55
112
|
end
|
56
113
|
end
|
57
114
|
end
|
data/spec/hansel_spec.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
require 'typhoeus'
|
4
|
+
require 'json'
|
5
|
+
require 'yaml'
|
6
|
+
require 'ostruct'
|
7
|
+
|
8
|
+
describe HanselCore, "in general" do
|
9
|
+
before :each do
|
10
|
+
@hansel = HanselCore::Hansel.new
|
11
|
+
@hansel.stub(:config_path).and_return 'spec'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have an empty job queue" do
|
15
|
+
@hansel.should respond_to :push_job
|
16
|
+
@hansel.should respond_to :jobs
|
17
|
+
@hansel.jobs.length.should == 0
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "adding to the job queue" do
|
21
|
+
before :each do
|
22
|
+
jobs = YAML.load_file(File.join ['spec', 'jobs.yml']).map{ |job| OpenStruct.new job }
|
23
|
+
jobs.each{ |job| @hansel.push_job job }
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have some jobs" do
|
27
|
+
@hansel.jobs.length.should > 0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "when calling run" do
|
32
|
+
before :each do
|
33
|
+
@hansel.stub( :httperf ).and_return @hansel
|
34
|
+
@hansel.load_job_queue
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "initially" do
|
38
|
+
it "should have some jobs" do
|
39
|
+
@hansel.jobs.length.should > 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "on completion" do
|
44
|
+
before :each do
|
45
|
+
@hansel.run
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have an empty job queue" do
|
49
|
+
@hansel.jobs.length.should == 0
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should have results to output" do
|
53
|
+
@hansel.should respond_to :results
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "after a run" do
|
59
|
+
before :each do
|
60
|
+
result = HanselCore::HttperfResult.new :server => "localhost",
|
61
|
+
:port => 80,
|
62
|
+
:rate => 1,
|
63
|
+
:uri => "/",
|
64
|
+
:num_conns => 1
|
65
|
+
|
66
|
+
result.reply_time = 0.0
|
67
|
+
result.status = 0
|
68
|
+
result.reply_rate_avg = 0.0
|
69
|
+
result.request_rate = 0.0
|
70
|
+
result.reply_rate_min = 0.0
|
71
|
+
result.connection_rate = 6754.1
|
72
|
+
result.errors = 1
|
73
|
+
result.reply_rate_stddev = 0.0
|
74
|
+
result.net_io = 0.0
|
75
|
+
result.replies = 0
|
76
|
+
result.reply_rate_max = 0.0
|
77
|
+
|
78
|
+
@hansel.stub( :results ).and_return [ result ]
|
79
|
+
@hansel.stub( :options ).and_return HanselCore::ArgParser.
|
80
|
+
new( [ '--format=yaml', '--dir=/tmp/hansel_output' ] ).parse
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "calling output" do
|
84
|
+
before :each do
|
85
|
+
@default_name = File.join [ @hansel.options.output_dir, 'localhost:80.yml' ]
|
86
|
+
FileUtils.rm @default_name if File.exists? @default_name
|
87
|
+
@hansel.output
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should have stubbed results" do
|
91
|
+
@hansel.results.size.should > 0
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "should put the output into a file in the specified format" do
|
95
|
+
it "should be in a file with the default file name" do
|
96
|
+
@default_name.should == @hansel.output_filename
|
97
|
+
File.exists?( @default_name ).should be_true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe HanselCore, "in distributed mode" do
|
105
|
+
before :each do
|
106
|
+
@options = HanselCore::ArgParser.new( [ '--master=localhost:4000' ] ).parse
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "should register with the master" do
|
110
|
+
before :each do
|
111
|
+
response = Typhoeus::Response.new(
|
112
|
+
:code => 200,
|
113
|
+
:headers => "",
|
114
|
+
:body => { :token => '0123456789' }.to_json,
|
115
|
+
:time => 0.3)
|
116
|
+
Typhoeus::Request.stub(:get, @options.master).and_return response
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "when initialized" do
|
120
|
+
before :each do
|
121
|
+
@hansel = HanselCore::Hansel.new @options
|
122
|
+
@hansel.stub(:config_path).and_return 'spec'
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should be able to register with the master server" do
|
126
|
+
@hansel.should respond_to :register
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should return the access token when registring with the master server" do
|
130
|
+
@hansel.register.should == '0123456789'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -28,14 +28,14 @@ Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
|
|
28
28
|
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
|
29
29
|
EOS
|
30
30
|
|
31
|
-
describe
|
31
|
+
describe HanselCore::HttperfResultParser, "#score" do
|
32
32
|
before(:each) do
|
33
|
-
@parser =
|
33
|
+
@parser = HanselCore::HttperfResultParser.new SAMPLE_HTTPERF_OUTPUT
|
34
34
|
end
|
35
35
|
|
36
36
|
describe "when calling parse" do
|
37
37
|
before(:each) do
|
38
|
-
@httperf_result =
|
38
|
+
@httperf_result = HanselCore::HttperfResult.new(
|
39
39
|
:rate => 10,
|
40
40
|
:server => 'www.example.com',
|
41
41
|
:port => 80,
|
data/spec/jobs.yml
ADDED
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Paul Mylchreest
|
@@ -14,10 +14,33 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-06-13 00:00:00 -04:00
|
18
18
|
default_executable: hansel
|
19
|
-
dependencies:
|
20
|
-
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: typhoeus
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
version: "0"
|
42
|
+
type: :runtime
|
43
|
+
version_requirements: *id002
|
21
44
|
description: Ruby driver for httperf - automated load and performance testing
|
22
45
|
email: paul.mylchreest@mac.com
|
23
46
|
executables:
|
@@ -26,26 +49,31 @@ extensions: []
|
|
26
49
|
|
27
50
|
extra_rdoc_files:
|
28
51
|
- LICENSE
|
29
|
-
- README.
|
52
|
+
- README.md
|
30
53
|
files:
|
31
54
|
- .document
|
32
55
|
- .gitignore
|
33
56
|
- LICENSE
|
34
|
-
- README.
|
57
|
+
- README.md
|
35
58
|
- Rakefile
|
36
59
|
- VERSION
|
37
60
|
- bin/hansel
|
38
61
|
- hansel.gemspec
|
39
|
-
- lib/arg_parser.rb
|
40
|
-
- lib/config.rb
|
41
|
-
- lib/csv_formatter.rb
|
42
62
|
- lib/hansel.rb
|
43
|
-
- lib/
|
44
|
-
- lib/
|
45
|
-
- lib/
|
46
|
-
- lib/
|
63
|
+
- lib/hansel/arg_parser.rb
|
64
|
+
- lib/hansel/formatting/csv_formatter.rb
|
65
|
+
- lib/hansel/formatting/formatting.rb
|
66
|
+
- lib/hansel/formatting/octave_formatter.rb
|
67
|
+
- lib/hansel/formatting/yaml_formatter.rb
|
68
|
+
- lib/hansel/hansel.rb
|
69
|
+
- lib/hansel/httperf/httperf.rb
|
70
|
+
- lib/hansel/httperf_result.rb
|
71
|
+
- lib/hansel/httperf_result_parser.rb
|
72
|
+
- lib/hansel/job_queue/job_queue.rb
|
47
73
|
- spec/arg_parser_spec.rb
|
74
|
+
- spec/hansel_spec.rb
|
48
75
|
- spec/httperf_result_parser_spec.rb
|
76
|
+
- spec/jobs.yml
|
49
77
|
- spec/spec_helper.rb
|
50
78
|
- templates/octave.m.erb
|
51
79
|
has_rdoc: true
|
@@ -80,5 +108,6 @@ specification_version: 3
|
|
80
108
|
summary: Ruby driver for httperf - automated load and performance testing
|
81
109
|
test_files:
|
82
110
|
- spec/arg_parser_spec.rb
|
111
|
+
- spec/hansel_spec.rb
|
83
112
|
- spec/httperf_result_parser_spec.rb
|
84
113
|
- spec/spec_helper.rb
|
data/README.rdoc
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
= hansel
|
2
|
-
|
3
|
-
Description goes here.
|
4
|
-
|
5
|
-
== Note on Patches/Pull Requests
|
6
|
-
|
7
|
-
* Fork the project.
|
8
|
-
* Make your feature addition or bug fix.
|
9
|
-
* Add tests for it. This is important so I don't break it in a
|
10
|
-
future version unintentionally.
|
11
|
-
* Commit, do not mess with rakefile, version, or history.
|
12
|
-
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
-
* Send me a pull request. Bonus points for topic branches.
|
14
|
-
|
15
|
-
== References
|
16
|
-
|
17
|
-
"HTTP Perforance Testing with httperf":http://agiletesting.blogspot.com/2005/04/http-performance-testing-with-httperf.html
|
18
|
-
"Perforance vs Load Testing":http://agiletesting.blogspot.com/2005/04/more-on-performance-vs-load-testing.html
|
19
|
-
|
20
|
-
== Copyright
|
21
|
-
|
22
|
-
Copyright (c) 2010 Paul Mylchreest. See LICENSE for details.
|