gridinit-jmeter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitattributes +22 -0
- data/.gitignore +20 -0
- data/.rbenv-version +1 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +18 -0
- data/LICENSE.txt +22 -0
- data/README.md +335 -0
- data/Rakefile +6 -0
- data/examples/basic_assertion.rb +13 -0
- data/examples/basic_auth.rb +11 -0
- data/examples/basic_cache.rb +11 -0
- data/examples/basic_cookies.rb +11 -0
- data/examples/basic_google.rb +8 -0
- data/examples/basic_grid.rb +11 -0
- data/examples/basic_run.rb +12 -0
- data/examples/basic_testplan.jmx +138 -0
- data/examples/basic_testplan.rb +44 -0
- data/examples/basic_think_time.rb +12 -0
- data/gridinit-jmeter.gemspec +19 -0
- data/lib/gridinit-jmeter/auth_manager.rb +28 -0
- data/lib/gridinit-jmeter/cache_manager.rb +22 -0
- data/lib/gridinit-jmeter/cookie_manager.rb +23 -0
- data/lib/gridinit-jmeter/dsl.rb +177 -0
- data/lib/gridinit-jmeter/gaussian_random_timer.rb +17 -0
- data/lib/gridinit-jmeter/http_sampler.rb +68 -0
- data/lib/gridinit-jmeter/regex_extractor.rb +25 -0
- data/lib/gridinit-jmeter/response_assertion.rb +58 -0
- data/lib/gridinit-jmeter/test_plan.rb +22 -0
- data/lib/gridinit-jmeter/thread_group.rb +31 -0
- data/lib/gridinit-jmeter/transaction.rb +20 -0
- data/lib/gridinit-jmeter/user_defined_variable.rb +27 -0
- data/lib/gridinit-jmeter/version.rb +5 -0
- data/lib/gridinit-jmeter.rb +20 -0
- data/spec/dsl_spec.rb +35 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/stub.rb +31 -0
- metadata +85 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'gridinit-jmeter'
|
3
|
+
|
4
|
+
base_url = 'http://localhost:4567'
|
5
|
+
endpoint = 'localhost:3000'
|
6
|
+
|
7
|
+
test do
|
8
|
+
|
9
|
+
cache clear_each_iteration: true
|
10
|
+
cookies
|
11
|
+
|
12
|
+
threads 100 do
|
13
|
+
|
14
|
+
random_timer 3000, 3000
|
15
|
+
|
16
|
+
transaction 'First Visit', {parent: true} do
|
17
|
+
visit 'Home Page', "#{base_url}/" do
|
18
|
+
extract 'csrf-token', "content='(.+?)' name='csrf-token'"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
transaction 'Login' do
|
23
|
+
submit 'Submit Form', "#{base_url}/login", {
|
24
|
+
fill_in: {
|
25
|
+
username: 'tim',
|
26
|
+
password: 'password',
|
27
|
+
'csrf-token' => '${csrf-token}'
|
28
|
+
}
|
29
|
+
}
|
30
|
+
think_time 1000
|
31
|
+
end
|
32
|
+
|
33
|
+
transaction 'Check Mana' do
|
34
|
+
visit 'Rails Camp' , "#{base_url}/magic" do
|
35
|
+
assert "contains", "magic"
|
36
|
+
assert "not-contains", "unicorns"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# end.jmx
|
43
|
+
# end.run(path: '/usr/share/jmeter/bin/')
|
44
|
+
end.grid '4dy-zJLEIgpYkKe6p6JhSQ', { endpoint: endpoint }
|
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'gridinit-jmeter'
|
3
|
+
|
4
|
+
test do
|
5
|
+
threads 100 do
|
6
|
+
think_time 5000,5000
|
7
|
+
transaction 'Google Search' do
|
8
|
+
visit 'Home Page', 'http://google.com/'
|
9
|
+
random_timer 3000
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end.jmx
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gridinit-jmeter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "gridinit-jmeter"
|
8
|
+
gem.version = Gridinit::Jmeter::VERSION
|
9
|
+
gem.authors = ["Tim Koopmans"]
|
10
|
+
gem.email = ["support@gridinit.com"]
|
11
|
+
gem.description = %q{This is a Ruby based DSL for writing JMeter test plans}
|
12
|
+
gem.summary = %q{This is a Ruby based DSL for writing JMeter test plans}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class AuthManager
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<AuthManager guiclass="AuthPanel" testclass="AuthManager" testname="HTTP Authorization Manager" enabled="true">
|
9
|
+
<collectionProp name="AuthManager.auth_list">
|
10
|
+
<elementProp name="" elementType="Authorization">
|
11
|
+
<stringProp name="Authorization.url">/</stringProp>
|
12
|
+
<stringProp name="Authorization.username"></stringProp>
|
13
|
+
<stringProp name="Authorization.password"></stringProp>
|
14
|
+
<stringProp name="Authorization.domain"></stringProp>
|
15
|
+
<stringProp name="Authorization.realm"></stringProp>
|
16
|
+
</elementProp>
|
17
|
+
</collectionProp>
|
18
|
+
</AuthManager>
|
19
|
+
EOF
|
20
|
+
params.each do |name, value|
|
21
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
22
|
+
node.first.content = value unless node.empty?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class CacheManager
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<CacheManager guiclass="CacheManagerGui" testclass="CacheManager" testname="HTTP Cache Manager" enabled="true">
|
9
|
+
<boolProp name="clearEachIteration">#{params[:clear_each_iteration] ? 'true' : 'false'}</boolProp>
|
10
|
+
<boolProp name="useExpires">#{params[:use_expires] ? 'true' : 'false'}</boolProp>
|
11
|
+
</CacheManager>
|
12
|
+
EOF
|
13
|
+
params.delete :clear_each_iteration
|
14
|
+
params.each do |name, value|
|
15
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
16
|
+
node.first.content = value unless node.empty?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class CookieManager
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie Manager" enabled="true">
|
9
|
+
<collectionProp name="CookieManager.cookies"/>
|
10
|
+
<boolProp name="CookieManager.clearEachIteration">#{params[:clear_each_iteration] ? 'true' : 'false'}</boolProp>
|
11
|
+
<stringProp name="CookieManager.policy">default</stringProp>
|
12
|
+
</CookieManager>
|
13
|
+
EOF
|
14
|
+
params.delete :clear_each_iteration
|
15
|
+
params.each do |name, value|
|
16
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
17
|
+
node.first.content = value unless node.empty?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class DSL
|
5
|
+
attr_accessor :root
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@root = Nokogiri::XML(<<-EOF.strip_heredoc)
|
9
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
10
|
+
<jmeterTestPlan version="1.2" properties="2.1">
|
11
|
+
<hashTree>
|
12
|
+
</hashTree>
|
13
|
+
</jmeterTestPlan>
|
14
|
+
EOF
|
15
|
+
node = Gridinit::Jmeter::TestPlan.new
|
16
|
+
@root.at_xpath("//jmeterTestPlan/hashTree") << node.doc.children << hash_tree
|
17
|
+
|
18
|
+
variables(
|
19
|
+
name: 'testguid',
|
20
|
+
value: '${__P(testguid,${__time(,)})}',
|
21
|
+
comments: 'The testguid variable is mandatory when running on the Grid.') {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def variables(params={}, &block)
|
25
|
+
node = Gridinit::Jmeter::UserDefinedVariable.new(params)
|
26
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
27
|
+
self.instance_exec(&block) if block
|
28
|
+
end
|
29
|
+
|
30
|
+
def cookies(params={}, &block)
|
31
|
+
node = Gridinit::Jmeter::CookieManager.new(params)
|
32
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
33
|
+
self.instance_exec(&block) if block
|
34
|
+
end
|
35
|
+
|
36
|
+
def cache(params={}, &block)
|
37
|
+
node = Gridinit::Jmeter::CacheManager.new(params)
|
38
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
39
|
+
self.instance_exec(&block) if block
|
40
|
+
end
|
41
|
+
|
42
|
+
def auth(params={}, &block)
|
43
|
+
node = Gridinit::Jmeter::AuthManager.new(params)
|
44
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
45
|
+
self.instance_exec(&block) if block
|
46
|
+
end
|
47
|
+
|
48
|
+
def threads(num_threads=1, params={}, &block)
|
49
|
+
node = Gridinit::Jmeter::ThreadGroup.new(num_threads, params)
|
50
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
51
|
+
self.instance_exec(&block) if block
|
52
|
+
end
|
53
|
+
|
54
|
+
def transaction(name="Transaction Contoller", params={}, &block)
|
55
|
+
node = Gridinit::Jmeter::Transaction.new(name, params)
|
56
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
57
|
+
self.instance_exec(&block) if block
|
58
|
+
end
|
59
|
+
|
60
|
+
def visit(name="HTTP Request", url="", params={}, &block)
|
61
|
+
params[:method] = 'GET'
|
62
|
+
node = Gridinit::Jmeter::HttpSampler.new(name, url, params)
|
63
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
64
|
+
self.instance_exec(&block) if block
|
65
|
+
end
|
66
|
+
|
67
|
+
def submit(name="HTTP Request", url="", params={}, &block)
|
68
|
+
params[:method] = 'POST'
|
69
|
+
node = Gridinit::Jmeter::HttpSampler.new(name, url, params)
|
70
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
71
|
+
self.instance_exec(&block) if block
|
72
|
+
end
|
73
|
+
|
74
|
+
alias_method :post, :submit
|
75
|
+
|
76
|
+
def extract(name="", regex="", params={}, &block)
|
77
|
+
node = Gridinit::Jmeter::RegexExtractor.new(name, regex, params)
|
78
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
79
|
+
self.instance_exec(&block) if block
|
80
|
+
end
|
81
|
+
|
82
|
+
alias_method :web_reg_save_param, :extract
|
83
|
+
|
84
|
+
def random_timer(delay=0, range=0, &block)
|
85
|
+
node = Gridinit::Jmeter::GaussianRandomTimer.new(delay, range)
|
86
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
87
|
+
self.instance_exec(&block) if block
|
88
|
+
end
|
89
|
+
|
90
|
+
alias_method :think_time, :random_timer
|
91
|
+
|
92
|
+
def assert(match="contains", pattern="", params={}, &block)
|
93
|
+
node = Gridinit::Jmeter::ResponseAssertion.new(match, pattern, params)
|
94
|
+
@root.at_xpath(xpath_from(caller)) << node.doc.children << hash_tree
|
95
|
+
self.instance_exec(&block) if block
|
96
|
+
end
|
97
|
+
|
98
|
+
alias_method :web_reg_find, :assert
|
99
|
+
|
100
|
+
def jmx(params={})
|
101
|
+
file(params)
|
102
|
+
puts doc.to_xml(:indent => 2)
|
103
|
+
logger.info "JMX saved to: #{params[:file]}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def run(params={})
|
107
|
+
file(params)
|
108
|
+
logger.warn "Test executing locally ..."
|
109
|
+
cmd = "#{params[:path]}jmeter -n -t #{params[:file]} -j #{params[:log] ? params[:log] : 'jmeter.log' } -l #{params[:jtl] ? params[:jtl] : 'jmeter.jtl' }"
|
110
|
+
logger.info cmd
|
111
|
+
`#{cmd}`
|
112
|
+
logger.info "Results at: #{params[:jtl] ? params[:jtl] : 'jmeter.jtl'}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def grid(token, params={})
|
116
|
+
file(params)
|
117
|
+
begin
|
118
|
+
response = RestClient.post "http://#{params[:endpoint] ? params[:endpoint] : 'gridinit.com'}/api?token=#{token}", {
|
119
|
+
:name => 'attachment',
|
120
|
+
:attachment => File.new("#{params[:file]}", 'rb'),
|
121
|
+
:multipart => true,
|
122
|
+
:content_type => 'application/octet-stream'
|
123
|
+
}
|
124
|
+
logger.info "Results at: #{JSON.parse(response)["results"]}" if response.code == 200
|
125
|
+
rescue => e
|
126
|
+
logger.fatal "There was an error: #{e.message}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def hash_tree
|
133
|
+
Nokogiri::XML::Node.new("hashTree", @root)
|
134
|
+
end
|
135
|
+
|
136
|
+
def xpath_from(calling_method)
|
137
|
+
case calling_method.grep(/dsl/)[1][/`.*'/][1..-2]
|
138
|
+
when 'threads'
|
139
|
+
'//ThreadGroup[last()]/following-sibling::hashTree'
|
140
|
+
when 'transaction'
|
141
|
+
'//TransactionController[last()]/following-sibling::hashTree'
|
142
|
+
when 'visit'
|
143
|
+
'//HTTPSamplerProxy[last()]/following-sibling::hashTree'
|
144
|
+
when 'submit'
|
145
|
+
'//HTTPSamplerProxy[last()]/following-sibling::hashTree'
|
146
|
+
when 'extract'
|
147
|
+
'//RegexExtractor[last()]/following-sibling::hashTree'
|
148
|
+
when 'random_timer'
|
149
|
+
'//GaussianRandomTimer[last()]/following-sibling::hashTree'
|
150
|
+
else
|
151
|
+
'//TestPlan/following-sibling::hashTree'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def file(params={})
|
156
|
+
params[:file] ||= 'jmeter.jmx'
|
157
|
+
File.open(params[:file], 'w') { |file| file.write(doc.to_xml(:indent => 2)) }
|
158
|
+
end
|
159
|
+
|
160
|
+
def doc
|
161
|
+
Nokogiri::XML(@root.to_s,&:noblanks)
|
162
|
+
end
|
163
|
+
|
164
|
+
def logger
|
165
|
+
@log ||= Logger.new(STDOUT)
|
166
|
+
@log.level = Logger::DEBUG
|
167
|
+
@log
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def test(&block)
|
176
|
+
Docile.dsl_eval(Gridinit::Jmeter::DSL.new, &block)
|
177
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class GaussianRandomTimer
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(delay, range)
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<GaussianRandomTimer guiclass="GaussianRandomTimerGui" testclass="GaussianRandomTimer" testname="Think Time" enabled="true">
|
9
|
+
<stringProp name="ConstantTimer.delay">#{delay}</stringProp>
|
10
|
+
<stringProp name="RandomTimer.range">#{range}</stringProp>
|
11
|
+
</GaussianRandomTimer>
|
12
|
+
EOF
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class HttpSampler
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(name, url, params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="#{name}" enabled="true">
|
9
|
+
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
10
|
+
<collectionProp name="Arguments.arguments"/>
|
11
|
+
</elementProp>
|
12
|
+
<stringProp name="HTTPSampler.domain"></stringProp>
|
13
|
+
<stringProp name="HTTPSampler.port"></stringProp>
|
14
|
+
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
|
15
|
+
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
16
|
+
<stringProp name="HTTPSampler.protocol"></stringProp>
|
17
|
+
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
18
|
+
<stringProp name="HTTPSampler.path">/</stringProp>
|
19
|
+
<stringProp name="HTTPSampler.method">GET</stringProp>
|
20
|
+
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
21
|
+
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
22
|
+
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
23
|
+
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
|
24
|
+
<boolProp name="HTTPSampler.monitor">false</boolProp>
|
25
|
+
<boolProp name="HTTPSampler.image_parser">true</boolProp>
|
26
|
+
<boolProp name="HTTPSampler.concurrentDwn">true</boolProp>
|
27
|
+
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
|
28
|
+
</HTTPSamplerProxy>
|
29
|
+
EOF
|
30
|
+
parse_url(url, params) unless url.empty?
|
31
|
+
fill_in(params) if params[:fill_in]
|
32
|
+
params.each do |name, value|
|
33
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
34
|
+
node.first.content = value unless node.empty?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_uri(url)
|
39
|
+
URI.parse(url).scheme.nil? ? URI.parse("http://#{url}") : URI.parse(url)
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_url(url, params)
|
43
|
+
uri = parse_uri(url)
|
44
|
+
params[:domain] = uri.host
|
45
|
+
params[:port] = uri.port
|
46
|
+
params[:path] = uri.path
|
47
|
+
end
|
48
|
+
|
49
|
+
def fill_in(params)
|
50
|
+
params[:fill_in].each do |name, value|
|
51
|
+
@doc.at_xpath('//collectionProp') <<
|
52
|
+
Nokogiri::XML(<<-EOF.strip_heredoc).children
|
53
|
+
<elementProp name="username" elementType="HTTPArgument">
|
54
|
+
<boolProp name="HTTPArgument.always_encode">false</boolProp>
|
55
|
+
<stringProp name="Argument.value">#{value}</stringProp>
|
56
|
+
<stringProp name="Argument.metadata">=</stringProp>
|
57
|
+
<boolProp name="HTTPArgument.use_equals">true</boolProp>
|
58
|
+
<stringProp name="Argument.name">#{name}</stringProp>
|
59
|
+
</elementProp>
|
60
|
+
EOF
|
61
|
+
end
|
62
|
+
params.delete :fill_in
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class RegexExtractor
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(name, regex, params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor" enabled="true">
|
9
|
+
<stringProp name="RegexExtractor.useHeaders">false</stringProp>
|
10
|
+
<stringProp name="RegexExtractor.refname">#{name}</stringProp>
|
11
|
+
<stringProp name="RegexExtractor.regex">#{CGI.escapeHTML regex}</stringProp>
|
12
|
+
<stringProp name="RegexExtractor.template">$1$</stringProp>
|
13
|
+
<stringProp name="RegexExtractor.default"></stringProp>
|
14
|
+
<stringProp name="RegexExtractor.match_number">0</stringProp>
|
15
|
+
</RegexExtractor>
|
16
|
+
EOF
|
17
|
+
params.each do |name, value|
|
18
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
19
|
+
node.first.content = value unless node.empty?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class ResponseAssertion
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(match, pattern, params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true">
|
9
|
+
<collectionProp name="Asserion.test_strings">
|
10
|
+
<stringProp name="#{Time.now.to_i}">#{pattern}</stringProp>
|
11
|
+
</collectionProp>
|
12
|
+
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
|
13
|
+
<boolProp name="Assertion.assume_success">false</boolProp>
|
14
|
+
<intProp name="Assertion.test_type">#{test_type(match)}</intProp>
|
15
|
+
</ResponseAssertion>
|
16
|
+
EOF
|
17
|
+
if params[:scope]
|
18
|
+
@doc.at_xpath('//ResponseAssertion') <<
|
19
|
+
Nokogiri::XML(<<-EOF.strip_heredoc).children
|
20
|
+
<stringProp name="Assertion.scope">#{params[:scope]}</stringProp>
|
21
|
+
EOF
|
22
|
+
params.delete [:scope]
|
23
|
+
end
|
24
|
+
params.each do |name, value|
|
25
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
26
|
+
node.first.content = value unless node.empty?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def test_type(match)
|
33
|
+
case match
|
34
|
+
when 'contains'
|
35
|
+
2
|
36
|
+
when 'not-contains'
|
37
|
+
6
|
38
|
+
when 'matches'
|
39
|
+
1
|
40
|
+
when 'not-matches'
|
41
|
+
5
|
42
|
+
when 'equals'
|
43
|
+
8
|
44
|
+
when 'not-equals'
|
45
|
+
12
|
46
|
+
when 'substring'
|
47
|
+
16
|
48
|
+
when 'not-substring'
|
49
|
+
20
|
50
|
+
else
|
51
|
+
2
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class TestPlan
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
|
9
|
+
<stringProp name="TestPlan.comments"></stringProp>
|
10
|
+
<boolProp name="TestPlan.functional_mode">false</boolProp>
|
11
|
+
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
|
12
|
+
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
13
|
+
<collectionProp name="Arguments.arguments"/>
|
14
|
+
</elementProp>
|
15
|
+
<stringProp name="TestPlan.user_define_classpath"></stringProp>
|
16
|
+
</TestPlan>
|
17
|
+
EOF
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class ThreadGroup
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(num_threads, params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
|
9
|
+
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
10
|
+
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
11
|
+
<boolProp name="LoopController.continue_forever">false</boolProp>
|
12
|
+
<stringProp name="LoopController.loops">1</stringProp>
|
13
|
+
</elementProp>
|
14
|
+
<stringProp name="ThreadGroup.num_threads">#{num_threads}</stringProp>
|
15
|
+
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
16
|
+
<longProp name="ThreadGroup.start_time">1352677419000</longProp>
|
17
|
+
<longProp name="ThreadGroup.end_time">1352677419000</longProp>
|
18
|
+
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
19
|
+
<stringProp name="ThreadGroup.duration"></stringProp>
|
20
|
+
<stringProp name="ThreadGroup.delay"></stringProp>
|
21
|
+
</ThreadGroup>
|
22
|
+
EOF
|
23
|
+
params.each do |name, value|
|
24
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
25
|
+
node.first.content = value unless node.empty?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class Transaction
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(name, params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<TransactionController guiclass="TransactionControllerGui" testclass="TransactionController" testname="#{name}" enabled="true">
|
9
|
+
<boolProp name="TransactionController.parent">false</boolProp>
|
10
|
+
</TransactionController>
|
11
|
+
EOF
|
12
|
+
params.each do |name, value|
|
13
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
14
|
+
node.first.content = value unless node.empty?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Gridinit
|
2
|
+
module Jmeter
|
3
|
+
|
4
|
+
class UserDefinedVariable
|
5
|
+
attr_accessor :doc
|
6
|
+
def initialize(params={})
|
7
|
+
@doc = Nokogiri::XML(<<-EOF.strip_heredoc)
|
8
|
+
<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
9
|
+
<collectionProp name="Arguments.arguments">
|
10
|
+
<elementProp name="testguid" elementType="Argument">
|
11
|
+
<stringProp name="Argument.name"></stringProp>
|
12
|
+
<stringProp name="Argument.value"></stringProp>
|
13
|
+
<stringProp name="Argument.metadata">=</stringProp>
|
14
|
+
</elementProp>
|
15
|
+
</collectionProp>
|
16
|
+
<stringProp name="TestPlan.comments"></stringProp>
|
17
|
+
</Arguments>
|
18
|
+
EOF
|
19
|
+
params.each do |name, value|
|
20
|
+
node = @doc.children.xpath("//*[contains(@name,\"#{name.to_s}\")]")
|
21
|
+
node.first.content = value unless node.empty?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'docile'
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
require 'logger/colors'
|
5
|
+
require 'rest_client'
|
6
|
+
require 'cgi'
|
7
|
+
|
8
|
+
require 'gridinit-jmeter/dsl'
|
9
|
+
require 'gridinit-jmeter/version'
|
10
|
+
require 'gridinit-jmeter/test_plan'
|
11
|
+
require 'gridinit-jmeter/auth_manager'
|
12
|
+
require 'gridinit-jmeter/cookie_manager'
|
13
|
+
require 'gridinit-jmeter/cache_manager'
|
14
|
+
require 'gridinit-jmeter/thread_group'
|
15
|
+
require 'gridinit-jmeter/transaction'
|
16
|
+
require 'gridinit-jmeter/http_sampler'
|
17
|
+
require 'gridinit-jmeter/regex_extractor'
|
18
|
+
require 'gridinit-jmeter/user_defined_variable'
|
19
|
+
require 'gridinit-jmeter/gaussian_random_timer'
|
20
|
+
require 'gridinit-jmeter/response_assertion'
|
data/spec/dsl_spec.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "DSL" do
|
4
|
+
|
5
|
+
it "test plan should respond to thread groups" do
|
6
|
+
test {}.should respond_to :threads
|
7
|
+
end
|
8
|
+
|
9
|
+
it "test plan should respond to transactions" do
|
10
|
+
test {}.should respond_to :transaction
|
11
|
+
end
|
12
|
+
|
13
|
+
it "test plan should respond to visit" do
|
14
|
+
test {}.should respond_to :visit
|
15
|
+
end
|
16
|
+
|
17
|
+
it "test plan should respond to submit" do
|
18
|
+
test {}.should respond_to :submit
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should output a test plan to stdout" do
|
22
|
+
$stdout.should_receive(:puts).with(/jmeterTestPlan/i)
|
23
|
+
test do
|
24
|
+
end.jmx
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should output a test plan to jmx file" do
|
28
|
+
file = mock('file')
|
29
|
+
File.should_receive(:open).with("/tmp/jmeter.jmx", "w").and_yield(file)
|
30
|
+
file.should_receive(:write).with(/jmeterTestPlan/i)
|
31
|
+
test do
|
32
|
+
end.jmx
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|