mu 5.7.9 → 5.7.10
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/lib/mu/command/cmd_musl.rb +4 -4
- data/lib/mu/command/cmd_runscale.rb +1 -81
- data/lib/mu/command/help.rb +0 -1
- data/lib/mu/har.rb +29 -10
- data/lib/mu/maker.rb +0 -4
- metadata +19 -22
- data/lib/mu/command/cmd_appid.rb +0 -531
- data/lib/mu/libxml.rb +0 -21
- data/lib/mu/xmlizable.rb +0 -559
data/lib/mu/command/cmd_musl.rb
CHANGED
@@ -59,7 +59,7 @@ class Mu
|
|
59
59
|
# Get har object and hosts
|
60
60
|
har_file = @options.har_files[0]
|
61
61
|
@har = Har.new har_file, @options, @ignores
|
62
|
-
msl_file
|
62
|
+
msl_file = File.open(@options.scenario,'w')
|
63
63
|
created_musl = @har.generate msl_file
|
64
64
|
msl_file.write created_musl
|
65
65
|
msl_file.close
|
@@ -131,9 +131,9 @@ class Mu
|
|
131
131
|
@options.strip_large_content = true
|
132
132
|
@options.large_content_size = size
|
133
133
|
end
|
134
|
-
|
135
|
-
|
136
|
-
end
|
134
|
+
#@opts.on( '--endpoint', 'One way communication' ) do
|
135
|
+
# @options.endpoint = true
|
136
|
+
#end
|
137
137
|
@opts.on( '-s', '--scenario [FILENAME]', 'Specify the msl filename to be created' ) do |scenario|
|
138
138
|
@options.scenario = scenario
|
139
139
|
end
|
@@ -15,79 +15,6 @@ class Mu
|
|
15
15
|
help
|
16
16
|
end
|
17
17
|
|
18
|
-
# sets up, executes, and closes a Studio Scale test
|
19
|
-
# * argv = command-line arguments , requires a scenario (-s) argument
|
20
|
-
def cmd_run_file argv
|
21
|
-
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
22
|
-
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
23
|
-
puts "Please use 'cmd_runscale:run_files'"
|
24
|
-
setup argv
|
25
|
-
|
26
|
-
if not @hash['scenario']
|
27
|
-
msg "scenario required", Logger::ERROR
|
28
|
-
return help
|
29
|
-
else
|
30
|
-
if @hash['scenario'].include?(".msl")
|
31
|
-
scenario = @hash['scenario']
|
32
|
-
else # TODO: eventually, xml and mus file may be supported by scale api
|
33
|
-
msg "only .msl files are currently supported", Logger::ERROR
|
34
|
-
return help
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
if not File.readable?(scenario)
|
39
|
-
msg "*** Error: can't read scenario file #{scenario}", Logger::ERROR
|
40
|
-
return
|
41
|
-
end
|
42
|
-
|
43
|
-
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
44
|
-
@api.configure("pattern", @cmd_line_pattern)
|
45
|
-
@params = {}
|
46
|
-
@params["dir"] = @dir
|
47
|
-
@params["msl"] = scenario
|
48
|
-
@params["hosts"] = @cmd_line_hosts
|
49
|
-
run(scenario)
|
50
|
-
@api.release
|
51
|
-
end
|
52
|
-
|
53
|
-
# sets up, executes, and closes a Studio Scale test for each scenario (.msl file) found in the specified directory
|
54
|
-
# * argv = command-line arguments, requires a directory (-d) argument
|
55
|
-
# * optional -r argument for recursive directory search (default is a flat directory)
|
56
|
-
def cmd_run_dir argv
|
57
|
-
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
58
|
-
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
59
|
-
puts "Please use 'cmd_runscale:run_files'"
|
60
|
-
setup argv
|
61
|
-
|
62
|
-
if not @hash['dir']
|
63
|
-
return help
|
64
|
-
else
|
65
|
-
@dir = @hash['dir']
|
66
|
-
end
|
67
|
-
|
68
|
-
msg "Clean up existing stats files: app_id_status.json, app_id_stats.csv", Logger::INFO
|
69
|
-
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
70
|
-
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
71
|
-
|
72
|
-
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
73
|
-
@api.configure("pattern", @cmd_line_pattern)
|
74
|
-
@params = {}
|
75
|
-
@params["dir"] = @dir
|
76
|
-
@params["hosts"] = @cmd_line_hosts
|
77
|
-
recursive = (@hash['recursive'].nil?) ? "": "**"
|
78
|
-
files = Dir.glob(File.join(@dir,recursive,"*.msl"))
|
79
|
-
if !files.empty?
|
80
|
-
files.sort.each do | f |
|
81
|
-
run(f)
|
82
|
-
output_csv(f)
|
83
|
-
sleep 2
|
84
|
-
end
|
85
|
-
else
|
86
|
-
msg "no msl files found in #{@dir}", Logger::ERROR
|
87
|
-
end
|
88
|
-
@api.release
|
89
|
-
end
|
90
|
-
|
91
18
|
# sets up, executes, and closes a Studio Scale test for one scenario or each scenario (.msl file) found in the specified directory
|
92
19
|
# * argv = command-line arguments
|
93
20
|
# * optional -s scenario file
|
@@ -606,19 +533,12 @@ class Mu
|
|
606
533
|
cmds = [
|
607
534
|
"mu cmd_runscale:help",
|
608
535
|
"mu cmd_runscale:run_files -s <scenario>|-d <scenario_directory> --recursive -i <hosts, e.g. a1,dell-9> -p <pattern, e.g. 1-1000:30>",
|
609
|
-
"mu cmd_runscale:run_file -s <scenario> -i <hosts, e.g. a1,dell-9> -p <pattern, e.g. 1-1000:30>",
|
610
|
-
"mu cmd_runscale:run_dir -d <scenario_directory>",
|
611
536
|
"mu cmd_runscale:running?"
|
612
537
|
]
|
613
538
|
|
614
539
|
max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
|
615
540
|
max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
|
616
|
-
|
617
|
-
puts "Usage: mu cmd_runscale:<command> <options>"
|
618
|
-
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
619
|
-
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
620
|
-
puts "Please use 'cmd_runscale:run_files'"
|
621
|
-
puts
|
541
|
+
|
622
542
|
helps.each do |h|
|
623
543
|
puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
|
624
544
|
end
|
data/lib/mu/command/help.rb
CHANGED
@@ -6,7 +6,6 @@ class Help < Command
|
|
6
6
|
puts "Usage: mu <command>:<option>"
|
7
7
|
helps = [
|
8
8
|
{ :cmd => 'mu help', :help => "Display this help" },
|
9
|
-
{ :cmd => 'mu cmd_appid:help', :help => 'Show help on using the appid application for running multi-host msl files at scale'},
|
10
9
|
{ :cmd => 'mu cmd_cli:help', :help => 'Show help on using the Mu CLI Api through the command-line' },
|
11
10
|
{ :cmd => 'mu cmd_ddt:help', :help => 'Show help on using the Studio Verify Api through the command-line' },
|
12
11
|
{ :cmd => 'mu cmd_homepage:help', :help => 'Show help on using the Homepage Api through the command-line' },
|
data/lib/mu/har.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# To change this template, choose Tools | Templates
|
2
2
|
# and open the template in the editor.
|
3
3
|
require 'mu/maker'
|
4
|
-
require 'mu/xmlizable'
|
5
4
|
|
6
5
|
class Har
|
7
6
|
HTTP_CONTENT_LENGTH_HEADER = 'Content-Length'
|
@@ -48,10 +47,6 @@ class Har
|
|
48
47
|
|
49
48
|
HTTP_CONTENT_SLICE_SIZE = 1024
|
50
49
|
|
51
|
-
MSL_ESCAPES = XMLizable::ESCAPES.dup
|
52
|
-
MSL_ESCAPES['"'.ord] = %q{\"}
|
53
|
-
MSL_ESCAPES["'".ord] = %q{\'}
|
54
|
-
|
55
50
|
|
56
51
|
attr_reader :har_file
|
57
52
|
attr_accessor :entries,:hosts,:har,:har_hosts
|
@@ -64,6 +59,7 @@ class Har
|
|
64
59
|
begin
|
65
60
|
@har = JSON File.read(@har_file)
|
66
61
|
rescue Exception=>e
|
62
|
+
puts "There was an error reading the JSON har file, probably a parsing problem"
|
67
63
|
raise e
|
68
64
|
end
|
69
65
|
|
@@ -186,8 +182,7 @@ class Har
|
|
186
182
|
# If this is a Cookie header, try and map the cookie
|
187
183
|
# value to a step variable preceding this step
|
188
184
|
if ('cookie' === header['name'].downcase)
|
189
|
-
|
190
|
-
value = XMLizable.escape(header['value'], MSL_ESCAPES)
|
185
|
+
value = self.escape(header['value'])
|
191
186
|
for j in 0..cookies.length
|
192
187
|
cookie = cookies[j]
|
193
188
|
|
@@ -298,7 +293,7 @@ class Har
|
|
298
293
|
end # end steps.client_send
|
299
294
|
|
300
295
|
# Skip the server side if the command line option included --endpint
|
301
|
-
unless @options.endpoint
|
296
|
+
#unless @options.endpoint
|
302
297
|
steps.server_receive("sr#{entry_count}", "cs#{entry_count}") do ||
|
303
298
|
#return nil
|
304
299
|
end
|
@@ -319,7 +314,7 @@ class Har
|
|
319
314
|
build_payload ss, entry_count, res, scenario
|
320
315
|
end unless @options.ignore_payload
|
321
316
|
end # end server_send
|
322
|
-
end
|
317
|
+
#end
|
323
318
|
|
324
319
|
# If the endpoint option is chosen only include cs 'client send' values instead of ss 'server send' values
|
325
320
|
receive_side = @options.endpoint ? 'cs' : 'ss'
|
@@ -419,7 +414,7 @@ class Har
|
|
419
414
|
end
|
420
415
|
cs_send.literal_no_format("\"");
|
421
416
|
else
|
422
|
-
cs_send.literal_no_format("\"" +
|
417
|
+
cs_send.literal_no_format("\"" + self.escape(payload) + "\"")
|
423
418
|
end
|
424
419
|
|
425
420
|
|
@@ -446,4 +441,28 @@ class Har
|
|
446
441
|
not @content_transfer_encoding.to_s == 'binary' and
|
447
442
|
not @mu_content_transfer_encoding.to_s == 'binary'
|
448
443
|
end
|
444
|
+
|
445
|
+
ESCAPES= Array.new 256 do |i|
|
446
|
+
case i
|
447
|
+
when 9; "\\t".freeze
|
448
|
+
when 13; "\\r".freeze
|
449
|
+
when 92; "\\\\".freeze
|
450
|
+
when 10; "\\n".freeze
|
451
|
+
when 32..126; i.chr.freeze
|
452
|
+
else ; ('\x%02x' % i).freeze
|
453
|
+
end
|
454
|
+
end
|
455
|
+
ESCAPES['"'.ord] = %q{\"}
|
456
|
+
ESCAPES["'".ord] = %q{\'}
|
457
|
+
ESCAPES.freeze
|
458
|
+
|
459
|
+
# Takes input and a table that maps ascii codes to their representation
|
460
|
+
def escape input, escapes=nil
|
461
|
+
escapes ||= ESCAPES
|
462
|
+
output = []
|
463
|
+
input.each_byte do |i|
|
464
|
+
output << escapes[i]
|
465
|
+
end
|
466
|
+
output.join
|
467
|
+
end
|
449
468
|
end
|
data/lib/mu/maker.rb
CHANGED
@@ -85,10 +85,6 @@ class Maker
|
|
85
85
|
def escape text
|
86
86
|
text.gsub(/\\/, '\\\\').gsub(/\r/, '\\r').gsub(/\n/, '\\n').gsub(/"/, '\\"')
|
87
87
|
end
|
88
|
-
|
89
|
-
def escape_payload text
|
90
|
-
text.gsub(/\\/, '\\\\\\').gsub(/\r/, '\\r').gsub(/\n/, '\\n').gsub(/"/, '\\"')
|
91
|
-
end
|
92
88
|
|
93
89
|
def attrs kvs = {}
|
94
90
|
return '' if kvs.empty?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.7.
|
4
|
+
version: 5.7.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-04-
|
12
|
+
date: 2011-04-12 00:00:00.000000000 -07:00
|
13
13
|
default_executable: mu
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
17
|
-
requirement: &
|
17
|
+
requirement: &18971320 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 1.0.0
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *18971320
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: jeweler
|
28
|
-
requirement: &
|
28
|
+
requirement: &18969320 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 1.5.1
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *18969320
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: rcov
|
39
|
-
requirement: &
|
39
|
+
requirement: &18968360 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *18968360
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: nokogiri
|
50
|
-
requirement: &
|
50
|
+
requirement: &18964500 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: 1.4.4
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *18964500
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: rest-client
|
61
|
-
requirement: &
|
61
|
+
requirement: &18963660 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: 1.6.1
|
67
67
|
type: :runtime
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *18963660
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: mime-types
|
72
|
-
requirement: &
|
72
|
+
requirement: &18958760 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ! '>='
|
@@ -77,10 +77,10 @@ dependencies:
|
|
77
77
|
version: '1.16'
|
78
78
|
type: :runtime
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *18958760
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: json_pure
|
83
|
-
requirement: &
|
83
|
+
requirement: &18957600 !ruby/object:Gem::Requirement
|
84
84
|
none: false
|
85
85
|
requirements:
|
86
86
|
- - ! '>='
|
@@ -88,10 +88,10 @@ dependencies:
|
|
88
88
|
version: 1.4.6
|
89
89
|
type: :runtime
|
90
90
|
prerelease: false
|
91
|
-
version_requirements: *
|
91
|
+
version_requirements: *18957600
|
92
92
|
- !ruby/object:Gem::Dependency
|
93
93
|
name: hexy
|
94
|
-
requirement: &
|
94
|
+
requirement: &18956640 !ruby/object:Gem::Requirement
|
95
95
|
none: false
|
96
96
|
requirements:
|
97
97
|
- - ! '>='
|
@@ -99,7 +99,7 @@ dependencies:
|
|
99
99
|
version: 0.1.1
|
100
100
|
type: :runtime
|
101
101
|
prerelease: false
|
102
|
-
version_requirements: *
|
102
|
+
version_requirements: *18956640
|
103
103
|
description: general purpose mu gem
|
104
104
|
email: bwilkerson@mudynamics.com
|
105
105
|
executables:
|
@@ -117,7 +117,6 @@ files:
|
|
117
117
|
- lib/mu/client.rb
|
118
118
|
- lib/mu/command.rb
|
119
119
|
- lib/mu/command/api.rb
|
120
|
-
- lib/mu/command/cmd_appid.rb
|
121
120
|
- lib/mu/command/cmd_cli.rb
|
122
121
|
- lib/mu/command/cmd_ddt.rb
|
123
122
|
- lib/mu/command/cmd_homepage.rb
|
@@ -136,9 +135,7 @@ files:
|
|
136
135
|
- lib/mu/har.rb
|
137
136
|
- lib/mu/helper.rb
|
138
137
|
- lib/mu/http_helper.rb
|
139
|
-
- lib/mu/libxml.rb
|
140
138
|
- lib/mu/maker.rb
|
141
|
-
- lib/mu/xmlizable.rb
|
142
139
|
- bin/mu
|
143
140
|
has_rdoc: true
|
144
141
|
homepage: http://www.mudynamics.com
|
@@ -156,7 +153,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
153
|
version: '0'
|
157
154
|
segments:
|
158
155
|
- 0
|
159
|
-
hash: -
|
156
|
+
hash: -973453883911657948
|
160
157
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
158
|
none: false
|
162
159
|
requirements:
|
data/lib/mu/command/cmd_appid.rb
DELETED
@@ -1,531 +0,0 @@
|
|
1
|
-
# runs Mu Studio multi-host app_id msl files in Studio Scale, in client/server passthrough
|
2
|
-
# mode, collapsing all hosts in the scenario to two. Runs either a single msl file or
|
3
|
-
# a directory of msl files, and has command-line options to specify the Mu parameters,
|
4
|
-
# the interfaces to use, and the pattern in which to run
|
5
|
-
require 'mu/api/scale'
|
6
|
-
class Mu
|
7
|
-
class Command
|
8
|
-
class Cmd_appid < Command
|
9
|
-
|
10
|
-
attr_accessor :api, :params, :hosts, :addr_indexes, :hash
|
11
|
-
|
12
|
-
# displays command-line help
|
13
|
-
def cmd_help argv
|
14
|
-
help
|
15
|
-
end
|
16
|
-
|
17
|
-
# returns a boolean indicating whether the scale test is running or not
|
18
|
-
# * argv = command-line arguments
|
19
|
-
def cmd_running? argv
|
20
|
-
if @api.nil?
|
21
|
-
msg "false"
|
22
|
-
return
|
23
|
-
end
|
24
|
-
|
25
|
-
status = @api.status
|
26
|
-
if !status.nil?
|
27
|
-
if !status["status"].nil?
|
28
|
-
msg status["status"]["running"]
|
29
|
-
end
|
30
|
-
else
|
31
|
-
msg "false"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# runs a single Studio Scale test
|
36
|
-
# * argv = command-line arguments, requires a scenario (-s) argument
|
37
|
-
def cmd_run_file argv
|
38
|
-
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
39
|
-
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
40
|
-
puts "Please use 'cmd_runscale:run_files'"
|
41
|
-
setup argv
|
42
|
-
|
43
|
-
if not @hash['scenario']
|
44
|
-
raise "*** Error: scenario required, using -s option"
|
45
|
-
else
|
46
|
-
scenario = @hash['scenario']
|
47
|
-
end
|
48
|
-
|
49
|
-
if !File.exists?(scenario)
|
50
|
-
raise "*** Error: Scenario file #{scenario} was not found"
|
51
|
-
end
|
52
|
-
|
53
|
-
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
54
|
-
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
55
|
-
|
56
|
-
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
57
|
-
@api.configure("pattern", @cmd_line_pattern)
|
58
|
-
@params = {}
|
59
|
-
@params["msl"] = scenario
|
60
|
-
@params["hosts"] = @cmd_line_hosts
|
61
|
-
run(scenario)
|
62
|
-
@api.release
|
63
|
-
end
|
64
|
-
|
65
|
-
# runs through a directory of msl files and executes a Studio Scale test for each one
|
66
|
-
# * argv = command-line arguments, require a directory (-d) argument
|
67
|
-
# * optional -r argument for recursive directory search (default is a flat directory)
|
68
|
-
def cmd_run_dir argv
|
69
|
-
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
70
|
-
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
71
|
-
puts "Please use 'cmd_runscale:run_files'"
|
72
|
-
setup argv
|
73
|
-
|
74
|
-
if not @hash['dir']
|
75
|
-
raise "*** Error: directory required, using -d option"
|
76
|
-
else
|
77
|
-
dir = @hash['dir']
|
78
|
-
end
|
79
|
-
|
80
|
-
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
81
|
-
File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
|
82
|
-
|
83
|
-
@api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
|
84
|
-
@api.configure("pattern", @cmd_line_pattern)
|
85
|
-
@params = {}
|
86
|
-
@params["dir"] = dir
|
87
|
-
@params["hosts"] = @cmd_line_hosts
|
88
|
-
Dir.chdir(@params["dir"])
|
89
|
-
File.delete("app_id_status.json") if File.exists?("app_id_status.json")
|
90
|
-
if @hash['recursive'].nil?
|
91
|
-
files = Dir.glob("*.msl")
|
92
|
-
else
|
93
|
-
files = Dir.glob("**/*.msl")
|
94
|
-
end
|
95
|
-
if !files.empty?
|
96
|
-
files.sort.each do | f |
|
97
|
-
run(f)
|
98
|
-
output_csv(f)
|
99
|
-
sleep 2
|
100
|
-
end
|
101
|
-
else
|
102
|
-
msg "no msl files found in #{dir}"
|
103
|
-
end
|
104
|
-
@api.release
|
105
|
-
end
|
106
|
-
|
107
|
-
private
|
108
|
-
|
109
|
-
def setup argv
|
110
|
-
parse_cli argv
|
111
|
-
@params = {}
|
112
|
-
@peak_throughput = 0.0
|
113
|
-
|
114
|
-
if @hash['test']
|
115
|
-
@verify_only = true
|
116
|
-
else
|
117
|
-
@verify_only = false
|
118
|
-
end
|
119
|
-
|
120
|
-
if not @hash['pattern']
|
121
|
-
@cmd_line_pattern = "{ \"iterations\": 1, \"intervals\": [ {\"iterations\":1, \"end\":100, \"start\":1, \"duration\":20 } ] }"
|
122
|
-
else
|
123
|
-
@cmd_line_pattern = @hash['pattern']
|
124
|
-
end
|
125
|
-
|
126
|
-
if not @hash['interfaces']
|
127
|
-
@cmd_line_hosts = "b1,b2"
|
128
|
-
else
|
129
|
-
@cmd_line_hosts = @hash['interfaces']
|
130
|
-
end
|
131
|
-
|
132
|
-
if not @hash['testset']
|
133
|
-
@testset = ""
|
134
|
-
else
|
135
|
-
@testset = @hash['testset']
|
136
|
-
end
|
137
|
-
|
138
|
-
if not @hash['delay']
|
139
|
-
@delay = 0
|
140
|
-
else
|
141
|
-
@delay = @hash['delay'].to_i
|
142
|
-
end
|
143
|
-
|
144
|
-
if not @hash['no_verify']
|
145
|
-
@no_verify = false
|
146
|
-
else
|
147
|
-
@no_verify = true
|
148
|
-
end
|
149
|
-
|
150
|
-
end
|
151
|
-
|
152
|
-
def run(msl)
|
153
|
-
if !File.exists?(msl)
|
154
|
-
return "file not found: #{msl}"
|
155
|
-
end
|
156
|
-
|
157
|
-
@api.configure("musl", File.read(msl))
|
158
|
-
|
159
|
-
unless @testset.empty?
|
160
|
-
if @testset.include?("/") # assume it is the full path in this case
|
161
|
-
csv_file = @testset
|
162
|
-
else
|
163
|
-
csv_file = @params["dir"] + "/" + @testset
|
164
|
-
end
|
165
|
-
@api.configure("csv", File.read(csv_file))
|
166
|
-
end
|
167
|
-
|
168
|
-
set_global_hosts
|
169
|
-
all_hosts = get_all_hosts_from_musl(msl)
|
170
|
-
@hosts_config = map_all_hosts_to_json(all_hosts)
|
171
|
-
@api.configure("hosts", @hosts_config)
|
172
|
-
@api.configure("delay", @delay)
|
173
|
-
if @no_verify == false # don't do verify if no_verify==true
|
174
|
-
msg "verifying #{msl} ..."
|
175
|
-
response = @api.verify
|
176
|
-
# sleep 3
|
177
|
-
v = parse_verify_response(response)
|
178
|
-
if v.nil?
|
179
|
-
msg "error in verify"
|
180
|
-
return
|
181
|
-
end
|
182
|
-
if @verify_only
|
183
|
-
msg v
|
184
|
-
return
|
185
|
-
end
|
186
|
-
end
|
187
|
-
msg "starting #{msl} ..."
|
188
|
-
@api.start
|
189
|
-
start_time = Time.now.to_i
|
190
|
-
while true
|
191
|
-
sleep 5
|
192
|
-
status = @api.status
|
193
|
-
if !status.nil?
|
194
|
-
if !status["status"].nil?
|
195
|
-
if status["status"]["running"] == false
|
196
|
-
msg "running = #{status["status"]["running"]}", Logger::DEBUG
|
197
|
-
r = parse_status(status)
|
198
|
-
dump_status(status, msl)
|
199
|
-
return
|
200
|
-
else
|
201
|
-
r = parse_status(status)
|
202
|
-
end
|
203
|
-
else # status['status'].nil? ... no bonafide status was returned
|
204
|
-
time_now = Time.now.to_i
|
205
|
-
if time_now - start_time > 20
|
206
|
-
# puts "\nError: timing out after 20 seconds. Test had failed to start or verify"
|
207
|
-
break
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
ensure
|
213
|
-
msg "stopping #{msl} ..."
|
214
|
-
end
|
215
|
-
|
216
|
-
def set_global_hosts
|
217
|
-
@hosts = Array.new
|
218
|
-
@addr_indexes = Array.new
|
219
|
-
hosts = @params["hosts"]
|
220
|
-
if !hosts.nil?
|
221
|
-
p = hosts.split(",")
|
222
|
-
p.each do | h |
|
223
|
-
if h.include?("-") # b1-1000,b2-1 to indicate addr_count
|
224
|
-
q = h.split("-")
|
225
|
-
@hosts << q[0]
|
226
|
-
@addr_indexes << q[1]
|
227
|
-
else # default to the 1st addr index
|
228
|
-
@hosts << h
|
229
|
-
@addr_indexes << 1
|
230
|
-
end
|
231
|
-
end
|
232
|
-
else
|
233
|
-
@hosts = ['b1','b2']
|
234
|
-
@addr_indexes = [1,1]
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
def dump_status(status, msl)
|
239
|
-
filename = "app_id_status.json"
|
240
|
-
f = File.open(filename, "a")
|
241
|
-
status["filename"] = msl
|
242
|
-
str = JSON.pretty_generate(status)
|
243
|
-
f.write(",") if !File.zero?(f) # if appending, we need to insert a comma
|
244
|
-
f.write(str)
|
245
|
-
f.close
|
246
|
-
end
|
247
|
-
|
248
|
-
def output_csv(msl_file)
|
249
|
-
filename = "app_id_stats.csv"
|
250
|
-
doc = "#{msl_file},#{@executed},#{@errors.to_i},#{@timeouts.to_i},#{@client_tx_bytes},#{@client_tx_msgs},#{@client_rx_bytes},#{@client_rx_msgs},#{@server_tx_bytes},#{@server_tx_msgs},#{@server_rx_bytes},#{@server_rx_msgs}\n"
|
251
|
-
File.open(filename, File::RDWR|File::TRUNC|File::CREAT) {|f| f.write(doc) }
|
252
|
-
end
|
253
|
-
|
254
|
-
# finds all the hosts in the musl file
|
255
|
-
def get_all_hosts_from_musl(msl)
|
256
|
-
f = IO.read(msl)
|
257
|
-
hosts = f.scan(/host_\d+/)
|
258
|
-
hosts.uniq!
|
259
|
-
return hosts
|
260
|
-
end
|
261
|
-
|
262
|
-
# maps host_0 to the client interface
|
263
|
-
# maps all other hosts to the server interface
|
264
|
-
def map_all_hosts_to_json(hosts=[])
|
265
|
-
new_hosts = Array.new
|
266
|
-
hosts.each_with_index do | h, i |
|
267
|
-
if i == 0
|
268
|
-
new_hosts << @hosts[0] + "/*,#{@addr_indexes[0]}"
|
269
|
-
else
|
270
|
-
new_hosts << @hosts[1] + "/*,#{@addr_indexes[1]}"
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
hosts_config = {}
|
275
|
-
|
276
|
-
# assign hosts to consecutive string keys, host_0, host_1, etc ...
|
277
|
-
new_hosts.each_with_index do | h, i |
|
278
|
-
hosts_config["host_#{i}"] = h # new_hosts[i]
|
279
|
-
end
|
280
|
-
|
281
|
-
# convert keys to symbols
|
282
|
-
new_hosts_config = {}
|
283
|
-
hosts_config.each_key { |k| new_hosts_config[k.to_sym] = hosts_config[k] }
|
284
|
-
|
285
|
-
return new_hosts_config
|
286
|
-
end
|
287
|
-
|
288
|
-
def parse_verify_response(response)
|
289
|
-
if response.nil? # || response.empty?
|
290
|
-
msg "*** error = no response received from /verify ***\n\n"
|
291
|
-
return nil
|
292
|
-
end
|
293
|
-
begin
|
294
|
-
msg JSON.pretty_generate(response), Logger::DEBUG
|
295
|
-
if !response["status"].nil?
|
296
|
-
if response["status"]["error"] == true
|
297
|
-
@error = response["status"]["error"]
|
298
|
-
@reason = response["status"]["reason"]
|
299
|
-
dump_status(response)
|
300
|
-
msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
|
301
|
-
return nil
|
302
|
-
end
|
303
|
-
end
|
304
|
-
msg "*** verify: okay ***", Logger::DEBUG
|
305
|
-
return "*** verify: okay ***"
|
306
|
-
rescue
|
307
|
-
# could nbe json parse error
|
308
|
-
return nil
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
def parse_status(status)
|
313
|
-
return nil if status.nil?
|
314
|
-
msg JSON.pretty_generate(status), Logger::DEBUG
|
315
|
-
@reported_volume = 0
|
316
|
-
if !status["status"]["error"].nil?
|
317
|
-
if status["status"]["error"] == true
|
318
|
-
@error = status["status"]["error"]
|
319
|
-
@reason = status["status"]["reason"]
|
320
|
-
# puts "*** Error = #{@error}, reason = #{@reason} ***\n\n"
|
321
|
-
return nil
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
@stats_summary = status["status"]["statistics"]["summary"]
|
326
|
-
@duration = @stats_summary["duration"]
|
327
|
-
@instances = @stats_summary["instances"]
|
328
|
-
@total_instances = @instances["total"]
|
329
|
-
@executed = @instances["executed"]
|
330
|
-
@timeouts = @instances["timeouts"]
|
331
|
-
@errors = @instances["errors"]
|
332
|
-
@asserts_failed = @stats_summary["asserts"]["failed"]
|
333
|
-
@server = @stats_summary["server"]
|
334
|
-
@server_tx_bytes = @server["tx"]["bytes"]
|
335
|
-
@server_tx_msgs = @server["tx"]["msgs"]
|
336
|
-
@server_rx_bytes = @server["rx"]["bytes"]
|
337
|
-
@server_rx_msgs = @server["rx"]["msgs"]
|
338
|
-
@client = @stats_summary["client"]
|
339
|
-
@client_tx_bytes = @client["tx"]["bytes"]
|
340
|
-
@client_tx_msgs = @client["tx"]["msgs"]
|
341
|
-
@client_rx_bytes = @client["rx"]["bytes"]
|
342
|
-
@client_rx_msgs = @client["rx"]["msgs"]
|
343
|
-
@scenarios = status["status"]["statistics"]["scenarios"]
|
344
|
-
@scenarios.each do | scenario |
|
345
|
-
@reported_volume = @reported_volume + scenario["volume"]
|
346
|
-
end
|
347
|
-
|
348
|
-
bits1 = (@client_tx_bytes.to_i + @client_rx_bytes.to_i) * 8
|
349
|
-
dur1 = @duration.to_f
|
350
|
-
thruput = format_float(2, bits1.to_f / dur1)
|
351
|
-
|
352
|
-
if thruput.to_f > @peak_throughput
|
353
|
-
@peak_throughput = thruput.to_f
|
354
|
-
end
|
355
|
-
|
356
|
-
msg ""
|
357
|
-
msg "duration: #{format_float(2, @duration)}"
|
358
|
-
msg "concurrency: #{@reported_volume}"
|
359
|
-
msg "tests/sec: #{format_float(2, @executed.to_f / @duration)}" if @duration.to_i > 0
|
360
|
-
msg "bits/sec: #{thruput}" if @duration.to_i > 0
|
361
|
-
msg "passed: #{@executed}"
|
362
|
-
msg "errors: #{@errors}"
|
363
|
-
msg "timeouts: #{@timeouts}"
|
364
|
-
msg "client tx bytes/sec #{format_float(2, @client_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
365
|
-
msg "client tx msgs/sec #{format_float(2, @client_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
366
|
-
msg "client rx bytes/sec #{format_float(2, @client_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
367
|
-
msg "client rx msgs/sec #{format_float(2, @client_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
368
|
-
msg "server tx bytes/sec #{format_float(2, @server_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
369
|
-
msg "server tx msgs/sec #{format_float(2, @server_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
370
|
-
msg "server rx bytes/sec #{format_float(2, @server_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
|
371
|
-
msg "server rx msgs/sec #{format_float(2, @server_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
|
372
|
-
msg ""
|
373
|
-
end
|
374
|
-
|
375
|
-
def parse_cli argv
|
376
|
-
@hash = Hash.new
|
377
|
-
while not argv.empty?
|
378
|
-
break if argv.first[0,1] != '-'
|
379
|
-
|
380
|
-
k = argv.shift
|
381
|
-
|
382
|
-
if [ '-c', '--csv' ].member? k
|
383
|
-
@hash['testset'] = shift(k, argv)
|
384
|
-
next
|
385
|
-
end
|
386
|
-
|
387
|
-
if [ '-d', '--dir' ].member? k
|
388
|
-
@hash['dir'] = shift(k, argv)
|
389
|
-
next
|
390
|
-
end
|
391
|
-
|
392
|
-
if [ '-i', '--interfaces' ].member? k
|
393
|
-
@hash['interfaces'] = shift(k, argv)
|
394
|
-
next
|
395
|
-
end
|
396
|
-
|
397
|
-
if [ '-h', '--help' ].member? k
|
398
|
-
help
|
399
|
-
exit
|
400
|
-
end
|
401
|
-
|
402
|
-
if [ '-l', '--delay' ].member? k
|
403
|
-
@hash['delay'] = shift(k, argv)
|
404
|
-
next
|
405
|
-
end
|
406
|
-
|
407
|
-
if [ '-m', '--mu_string' ].member? k
|
408
|
-
mu_string = shift(k, argv)
|
409
|
-
if mu_string =~ /(.+?):(.+?)@(.*)/
|
410
|
-
@@mu_admin_user = $1
|
411
|
-
@@mu_admin_pass = $2
|
412
|
-
@@mu_ip = $3
|
413
|
-
end
|
414
|
-
next
|
415
|
-
end
|
416
|
-
|
417
|
-
if [ '-n', '--no_verify' ].member? k
|
418
|
-
@hash['no_verify'] = true
|
419
|
-
next
|
420
|
-
end
|
421
|
-
|
422
|
-
if [ '-o', '--output'].member? k
|
423
|
-
$stdout.reopen(shift(k, argv), "w")
|
424
|
-
next
|
425
|
-
end
|
426
|
-
|
427
|
-
if [ '-p', '--pattern' ].member? k
|
428
|
-
patterns = Array.new
|
429
|
-
pattern_string = shift(k, argv)
|
430
|
-
pstrings = pattern_string.split(",")
|
431
|
-
pstrings.each do | p |
|
432
|
-
if p =~ /(.+?)-(.+?):(.*)/ # e.g. 1-10000:60
|
433
|
-
start_vol = $1
|
434
|
-
end_vol = $2
|
435
|
-
duration = $3
|
436
|
-
patterns << "{\"iterations\":1, \"end\":#{end_vol}, \"start\":#{start_vol}, \"duration\":#{duration} }"
|
437
|
-
end
|
438
|
-
end
|
439
|
-
ps = "{ \"iterations\": 1, \"intervals\": ["
|
440
|
-
patterns.each do | p |
|
441
|
-
ps = ps + p + ","
|
442
|
-
end
|
443
|
-
ps = ps[0..ps.length-2] # remove final comma
|
444
|
-
ps = ps + "] }"
|
445
|
-
@hash['pattern'] = ps
|
446
|
-
next
|
447
|
-
end
|
448
|
-
|
449
|
-
if [ '-r', '--recursive'].member? k
|
450
|
-
@hash['recursive'] = true
|
451
|
-
next
|
452
|
-
end
|
453
|
-
|
454
|
-
if [ '-s', '--scenario' ].member? k
|
455
|
-
@hash['scenario'] = shift(k, argv)
|
456
|
-
next
|
457
|
-
end
|
458
|
-
|
459
|
-
if [ '-t', '--test' ].member? k
|
460
|
-
@hash['test'] = true
|
461
|
-
next
|
462
|
-
end
|
463
|
-
|
464
|
-
if [ '-v', '--verbose' ].member? k
|
465
|
-
$log.level = Logger::DEBUG
|
466
|
-
next
|
467
|
-
end
|
468
|
-
|
469
|
-
raise ArgumentError, "Unknown option #{k}"
|
470
|
-
end
|
471
|
-
|
472
|
-
hash
|
473
|
-
end
|
474
|
-
|
475
|
-
def help
|
476
|
-
helps = [
|
477
|
-
{ :short => '-c', :long => '--csv', :value => '<string>', :help => 'name of the csv testset to run' },
|
478
|
-
{ :short => '-d', :long => '--dir', :value => '<string>', :help => 'directory containing msl files, required for run_dir' },
|
479
|
-
{ :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
|
480
|
-
{ :short => '-i', :long => '--interfaces', :value => '<string>', :help => 'comma-separated list of interfaces, e.g. b1,b2 or b1-1000:0,b2 for ip range and offset' },
|
481
|
-
{ :short => '-l', :long => '--delay', :value => '<string>', :help => 'intra-scenario delay value' },
|
482
|
-
{ :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
|
483
|
-
{ :short => '-n', :long => '--no_verify', :value => '', :help => 'do not do verify before start' },
|
484
|
-
{ :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
|
485
|
-
{ :short => '-p', :long => '--pattern', :value => '<string>', :help => 'pattern in the form of comma-separated concurrency_start-end:duration strings, e.g. 1-10000:60,10000-1:30. Duration is in seconds' },
|
486
|
-
{ :short => '-r', :long => '--recursive', :value => '', :help => 'for run_dir, recurse through sub-directories' },
|
487
|
-
{ :short => '-s', :long => '--scenario', :value => '<string>', :help => 'msl file, required for run_msl' },
|
488
|
-
{ :short => '-t', :long => '--test', :value => '', :help => 'do verify only' },
|
489
|
-
{ :short => '-v', :long => '--verbose', :value => '', :help => 'set Logger::DEBUG level' }
|
490
|
-
]
|
491
|
-
|
492
|
-
cmds = [
|
493
|
-
"mu cmd_appid:help",
|
494
|
-
"mu cmd_appid:run_file -s <file>",
|
495
|
-
"mu cmd_appid:run_dir -d <dir> [-r]",
|
496
|
-
"mu cmd_appid:running?"
|
497
|
-
]
|
498
|
-
|
499
|
-
max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
|
500
|
-
max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
|
501
|
-
puts "\n***WARNING***\nThe following commands will be deprecated in a future release:"
|
502
|
-
puts "cmd_runscale:run_file, cmd_runscale:run_dir, cmd_appid\n"
|
503
|
-
puts "Please use 'cmd_runscale:run_files'"
|
504
|
-
puts
|
505
|
-
puts "Usage: mu cmd_appid:<command> <options>"
|
506
|
-
puts
|
507
|
-
helps.each do |h|
|
508
|
-
puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
|
509
|
-
end
|
510
|
-
puts
|
511
|
-
puts "Available Commands"
|
512
|
-
puts
|
513
|
-
cmds.each do | c |
|
514
|
-
puts c
|
515
|
-
end
|
516
|
-
puts
|
517
|
-
puts "Outputs"
|
518
|
-
puts
|
519
|
-
puts "app_id_stats.csv"
|
520
|
-
puts "scenario_name , passed , errors , timeouts,"
|
521
|
-
puts "client tx bytes/sec , client tx msgs/sec , client rx bytes/sec , client rx msgs/src,"
|
522
|
-
puts "server tx bytes/sec , server tx msgs/sec , server rx bytes/sec , server rx msgs/src"
|
523
|
-
puts
|
524
|
-
puts "app_id_status.json"
|
525
|
-
puts "contains the last status json object returned from polling, per scenario"
|
526
|
-
end
|
527
|
-
|
528
|
-
end
|
529
|
-
end # Command
|
530
|
-
end # Mu
|
531
|
-
|