mu 5.7.2.3

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.
Files changed (117) hide show
  1. data/Mu_Gem.html +1591 -0
  2. data/bin/mu +11 -0
  3. data/lib/mu.rb +65 -0
  4. data/lib/mu/api/ddt.rb +233 -0
  5. data/lib/mu/api/homepage.rb +54 -0
  6. data/lib/mu/api/muapi.rb +231 -0
  7. data/lib/mu/api/netconfig.rb +233 -0
  8. data/lib/mu/api/scale.rb +199 -0
  9. data/lib/mu/api/system.rb +40 -0
  10. data/lib/mu/client.rb +31 -0
  11. data/lib/mu/command.rb +28 -0
  12. data/lib/mu/command/api.rb +95 -0
  13. data/lib/mu/command/cmd_appid.rb +486 -0
  14. data/lib/mu/command/cmd_cli.rb +151 -0
  15. data/lib/mu/command/cmd_ddt.rb +449 -0
  16. data/lib/mu/command/cmd_homepage.rb +146 -0
  17. data/lib/mu/command/cmd_muapi.rb +361 -0
  18. data/lib/mu/command/cmd_netconfig.rb +262 -0
  19. data/lib/mu/command/cmd_runscale.rb +533 -0
  20. data/lib/mu/command/cmd_runscenario.rb +258 -0
  21. data/lib/mu/command/cmd_runverify.rb +336 -0
  22. data/lib/mu/command/cmd_scale.rb +333 -0
  23. data/lib/mu/command/cmd_system.rb +127 -0
  24. data/lib/mu/command/curl.rb +246 -0
  25. data/lib/mu/command/help.rb +29 -0
  26. data/lib/mu/curl/error.rb +54 -0
  27. data/lib/mu/curl/verify.rb +137 -0
  28. data/lib/mu/helper.rb +55 -0
  29. data/lib/mu/http_helper.rb +232 -0
  30. data/rdoc/classes/Mu.html +305 -0
  31. data/rdoc/classes/Mu/Client.html +265 -0
  32. data/rdoc/classes/Mu/Command.html +208 -0
  33. data/rdoc/classes/Mu/Command/API.html +524 -0
  34. data/rdoc/classes/Mu/Command/Cmd_appid.html +934 -0
  35. data/rdoc/classes/Mu/Command/Cmd_cli.html +515 -0
  36. data/rdoc/classes/Mu/Command/Cmd_ddt.html +1169 -0
  37. data/rdoc/classes/Mu/Command/Cmd_homepage.html +489 -0
  38. data/rdoc/classes/Mu/Command/Cmd_muapi.html +968 -0
  39. data/rdoc/classes/Mu/Command/Cmd_netconfig.html +743 -0
  40. data/rdoc/classes/Mu/Command/Cmd_runscale.html +970 -0
  41. data/rdoc/classes/Mu/Command/Cmd_runscenario.html +530 -0
  42. data/rdoc/classes/Mu/Command/Cmd_runverify.html +621 -0
  43. data/rdoc/classes/Mu/Command/Cmd_scale.html +939 -0
  44. data/rdoc/classes/Mu/Command/Cmd_system.html +426 -0
  45. data/rdoc/classes/Mu/Command/Curl.html +524 -0
  46. data/rdoc/classes/Mu/Command/Help.html +166 -0
  47. data/rdoc/classes/Mu/Curl.html +116 -0
  48. data/rdoc/classes/Mu/Curl/Error.html +157 -0
  49. data/rdoc/classes/Mu/Curl/Error/Authorize.html +178 -0
  50. data/rdoc/classes/Mu/Curl/Error/Connect.html +149 -0
  51. data/rdoc/classes/Mu/Curl/Error/DNS.html +113 -0
  52. data/rdoc/classes/Mu/Curl/Error/Region.html +160 -0
  53. data/rdoc/classes/Mu/Curl/Error/Status.html +149 -0
  54. data/rdoc/classes/Mu/Curl/Error/Timeout.html +149 -0
  55. data/rdoc/classes/Mu/Curl/Verify.html +282 -0
  56. data/rdoc/classes/Mu/Curl/Verify/Request.html +227 -0
  57. data/rdoc/classes/Mu/Curl/Verify/Response.html +187 -0
  58. data/rdoc/classes/Mu/Curl/Verify/Result.html +188 -0
  59. data/rdoc/classes/Mu/Ddt.html +914 -0
  60. data/rdoc/classes/Mu/Helper.html +308 -0
  61. data/rdoc/classes/Mu/Homepage.html +377 -0
  62. data/rdoc/classes/Mu/HttpHelper.html +639 -0
  63. data/rdoc/classes/Mu/Muapi.html +816 -0
  64. data/rdoc/classes/Mu/Netconfig.html +781 -0
  65. data/rdoc/classes/Mu/Scale.html +832 -0
  66. data/rdoc/classes/Mu/System.html +281 -0
  67. data/rdoc/classes/Object.html +148 -0
  68. data/rdoc/classes/TCTestMu.html +1793 -0
  69. data/rdoc/classes/Test.html +107 -0
  70. data/rdoc/classes/Test/Unit.html +107 -0
  71. data/rdoc/classes/Test/Unit/TestCase.html +113 -0
  72. data/rdoc/created.rid +1 -0
  73. data/rdoc/files/lib/mu/api/ddt_rb.html +101 -0
  74. data/rdoc/files/lib/mu/api/homepage_rb.html +101 -0
  75. data/rdoc/files/lib/mu/api/muapi_rb.html +101 -0
  76. data/rdoc/files/lib/mu/api/netconfig_rb.html +101 -0
  77. data/rdoc/files/lib/mu/api/scale_rb.html +101 -0
  78. data/rdoc/files/lib/mu/api/system_rb.html +101 -0
  79. data/rdoc/files/lib/mu/client_rb.html +101 -0
  80. data/rdoc/files/lib/mu/command/api_rb.html +101 -0
  81. data/rdoc/files/lib/mu/command/cmd_appid_rb.html +119 -0
  82. data/rdoc/files/lib/mu/command/cmd_cli_rb.html +108 -0
  83. data/rdoc/files/lib/mu/command/cmd_ddt_rb.html +117 -0
  84. data/rdoc/files/lib/mu/command/cmd_homepage_rb.html +115 -0
  85. data/rdoc/files/lib/mu/command/cmd_muapi_rb.html +116 -0
  86. data/rdoc/files/lib/mu/command/cmd_netconfig_rb.html +116 -0
  87. data/rdoc/files/lib/mu/command/cmd_runscale_rb.html +119 -0
  88. data/rdoc/files/lib/mu/command/cmd_runscenario_rb.html +115 -0
  89. data/rdoc/files/lib/mu/command/cmd_runverify_rb.html +117 -0
  90. data/rdoc/files/lib/mu/command/cmd_scale_rb.html +115 -0
  91. data/rdoc/files/lib/mu/command/cmd_system_rb.html +116 -0
  92. data/rdoc/files/lib/mu/command/curl_rb.html +101 -0
  93. data/rdoc/files/lib/mu/command/help_rb.html +101 -0
  94. data/rdoc/files/lib/mu/command_rb.html +107 -0
  95. data/rdoc/files/lib/mu/curl/error_rb.html +101 -0
  96. data/rdoc/files/lib/mu/curl/verify_rb.html +101 -0
  97. data/rdoc/files/lib/mu/helper_rb.html +101 -0
  98. data/rdoc/files/lib/mu/http_helper_rb.html +101 -0
  99. data/rdoc/files/lib/mu_rb.html +121 -0
  100. data/rdoc/files/test/helper_rb.html +112 -0
  101. data/rdoc/files/test/tc_test_mu_rb.html +111 -0
  102. data/rdoc/fr_class_index.html +68 -0
  103. data/rdoc/fr_file_index.html +55 -0
  104. data/rdoc/fr_method_index.html +374 -0
  105. data/rdoc/index.html +24 -0
  106. data/rdoc/rdoc-style.css +208 -0
  107. data/test/data/app_id_stats.csv +1 -0
  108. data/test/data/data_cgi.msl +94 -0
  109. data/test/data/data_cgi.xml +322 -0
  110. data/test/data/default_test.csv +3 -0
  111. data/test/data/ftp_with_channel.xml +1643 -0
  112. data/test/data/irc.xml +3837 -0
  113. data/test/data/scale_configuration.json +25 -0
  114. data/test/data/test_data_cgi_error.xml +35 -0
  115. data/test/helper.rb +18 -0
  116. data/test/tc_test_mu.rb +716 -0
  117. metadata +322 -0
@@ -0,0 +1,31 @@
1
+ class Mu
2
+ class Client
3
+ attr_reader :mu
4
+
5
+ def initialize user, apik, host=''
6
+ scheme = host.index('localhost') ? 'http' : 'https'
7
+ @mu = RestClient::Resource.new "#{scheme}://#{host}", \
8
+ :headers => {
9
+ :x_api_user => user,
10
+ :x_api_key => apik,
11
+ :x_api_version => ::Mu::Version
12
+ }
13
+ end
14
+
15
+ def curl data
16
+ JSON.parse mu['/api/1/curl'].post(data.to_json)
17
+ end
18
+
19
+ def login
20
+ JSON.parse mu['/account/login/api'].get
21
+ end
22
+
23
+ def job_status job_id
24
+ JSON.parse mu["/api/1/jobs/#{job_id}/status"].get
25
+ end
26
+
27
+ def abort_job job_id
28
+ JSON.parse mu["/api/1/jobs/#{job_id}/abort"].put('')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ #require 'test/unit/assertions'
2
+
3
+ # The default template string contains what was sent and received. Strip
4
+ # these out since we don't need them
5
+ =begin
6
+ class Test::Unit::Assertions::AssertionMessage
7
+ alias :old_template :template
8
+
9
+ def template
10
+ @template_string = ''
11
+ @parameters = []
12
+ old_template
13
+ end
14
+ end
15
+ =end
16
+
17
+ class Mu
18
+ class Command
19
+ #include Test::Unit::Assertions
20
+ include Helper
21
+
22
+ @@mu_ip = ENV['MU_IP']
23
+ @@mu_admin_user = ENV['MU_ADMIN_USER']
24
+ @@mu_admin_pass = ENV['MU_ADMIN_PASS']
25
+ end
26
+ end # Mu
27
+
28
+ Dir["#{File.dirname(__FILE__)}/command/*.rb"].each { |c| require c }
@@ -0,0 +1,95 @@
1
+ class Mu
2
+ class Command
3
+ class API < Command
4
+ attr_accessor :credentials
5
+
6
+ def cmd_init argv
7
+ FileUtils.rm credentials_file rescue nil
8
+ API.client
9
+
10
+ msg "You are now ready to use mu!"
11
+ msg "Try mu help to learn more about the commands."
12
+ end
13
+
14
+ def client
15
+ get_credentials
16
+ Mu::Client.new(user, password, host)
17
+ end
18
+
19
+ def user
20
+ get_credentials
21
+ @credentials[0]
22
+ end
23
+
24
+ def password
25
+ get_credentials
26
+ @credentials[1]
27
+ end
28
+
29
+ def host
30
+ ENV['MU_IP'] || ''
31
+ end
32
+
33
+ def credentials_file
34
+ end
35
+
36
+ def get_credentials
37
+ return if @credentials
38
+ unless @credentials = read_credentials
39
+ @credentials = ask_for_credentials
40
+ save_credentials
41
+ end
42
+ @credentials
43
+ end
44
+
45
+ def read_credentials
46
+ File.exists?(credentials_file) and File.read(credentials_file).split("\n")
47
+ end
48
+
49
+ def ask_for_credentials
50
+ msg "Enter your credentials."
51
+ print "User-ID: "
52
+ user = ask
53
+ print "API-Key: "
54
+ apik = ask
55
+ apik2 = Mu::Client.new(user, apik, host).login['api_key']
56
+ if not apik2
57
+ error "Authentication failed"
58
+ exit 1
59
+ end
60
+
61
+ [ user, apik2 ]
62
+ end
63
+
64
+ def save_credentials
65
+ write_credentials
66
+ end
67
+
68
+ def write_credentials
69
+ FileUtils.mkdir_p(File.dirname(credentials_file))
70
+ File.open(credentials_file, 'w') do |f|
71
+ f.puts self.credentials
72
+ end
73
+ set_credentials_permissions
74
+ end
75
+
76
+ def set_credentials_permissions
77
+ FileUtils.chmod 0700, File.dirname(credentials_file)
78
+ FileUtils.chmod 0600, credentials_file
79
+ end
80
+
81
+ def self.instance
82
+ @instance ||= API.new
83
+ end
84
+
85
+ def self.client
86
+ self.instance.client
87
+ end
88
+
89
+ private
90
+ def initialize
91
+ end
92
+ end
93
+ Api = API
94
+ end # Command
95
+ end # Mu
@@ -0,0 +1,486 @@
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
+ setup argv
39
+
40
+ if not @hash['scenario']
41
+ raise "*** Error: scenario required, using -s option"
42
+ else
43
+ scenario = @hash['scenario']
44
+ end
45
+
46
+ if !File.exists?(scenario)
47
+ raise "*** Error: Scenario file #{scenario} was not found"
48
+ end
49
+
50
+ File.delete("app_id_status.json") if File.exists?("app_id_status.json")
51
+ File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
52
+
53
+ @api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
54
+ @api.configure("pattern", @cmd_line_pattern)
55
+ @params = {}
56
+ @params["msl"] = scenario
57
+ @params["hosts"] = @cmd_line_hosts
58
+ run(scenario)
59
+ @api.release
60
+ end
61
+
62
+ # runs through a directory of msl files and executes a Studio Scale test for each one
63
+ # * argv = command-line arguments, require a directory (-d) argument
64
+ # * optional -r argument for recursive directory search (default is a flat directory)
65
+ def cmd_run_dir argv
66
+ setup argv
67
+
68
+ if not @hash['dir']
69
+ raise "*** Error: directory required, using -d option"
70
+ else
71
+ dir = @hash['dir']
72
+ end
73
+
74
+ File.delete("app_id_status.json") if File.exists?("app_id_status.json")
75
+ File.delete("app_id_stats.csv") if File.exists?("app_id_stats.csv")
76
+
77
+ @api = Scale.new(@@mu_ip, @@mu_admin_user, @@mu_admin_pass)
78
+ @api.configure("pattern", @cmd_line_pattern)
79
+ @params = {}
80
+ @params["dir"] = dir
81
+ @params["hosts"] = @cmd_line_hosts
82
+ Dir.chdir(@params["dir"])
83
+ File.delete("app_id_status.json") if File.exists?("app_id_status.json")
84
+ if @hash['recursive'].nil?
85
+ files = Dir.glob("*.msl")
86
+ else
87
+ files = Dir.glob("**/*.msl")
88
+ end
89
+ if !files.empty?
90
+ files.sort.each do | f |
91
+ run(f)
92
+ output_csv(f)
93
+ sleep 2
94
+ end
95
+ else
96
+ msg "no msl files found in #{dir}"
97
+ end
98
+ @api.release
99
+ end
100
+
101
+ private
102
+
103
+ def setup argv
104
+ parse_cli argv
105
+ @params = {}
106
+
107
+ if @hash['test']
108
+ @verify_only = true
109
+ else
110
+ @verify_only = false
111
+ end
112
+
113
+ if not @hash['pattern']
114
+ @cmd_line_pattern = "{ \"iterations\": 1, \"intervals\": [ {\"iterations\":1, \"end\":100, \"start\":1, \"duration\":20 } ] }"
115
+ else
116
+ @cmd_line_pattern = @hash['pattern']
117
+ end
118
+
119
+ if not @hash['interfaces']
120
+ @cmd_line_hosts = "b1,b2"
121
+ else
122
+ @cmd_line_hosts = @hash['interfaces']
123
+ end
124
+
125
+ if not @hash['testset']
126
+ @testset = ""
127
+ else
128
+ @testset = @hash['testset']
129
+ end
130
+
131
+ end
132
+
133
+ def run(msl)
134
+ if !File.exists?(msl)
135
+ return "file not found: #{msl}"
136
+ end
137
+
138
+ @api.configure("musl", File.read(msl))
139
+
140
+ unless @testset.empty?
141
+ if @testset.include?("/") # assume it is the full path in this case
142
+ csv_file = @testset
143
+ else
144
+ csv_file = @params["dir"] + "/" + @testset
145
+ end
146
+ @api.configure("csv", File.read(csv_file))
147
+ end
148
+
149
+ set_global_hosts
150
+ all_hosts = get_all_hosts_from_musl(msl)
151
+ @hosts_config = map_all_hosts_to_json(all_hosts)
152
+ @api.configure("hosts", @hosts_config)
153
+ msg "verifying #{msl} ..."
154
+ response = @api.verify
155
+ # sleep 3
156
+ v = parse_verify_response(response)
157
+ if v.nil?
158
+ msg "error in verify"
159
+ return
160
+ end
161
+ if @verify_only
162
+ msg v
163
+ return
164
+ end
165
+ msg "starting #{msl} ..."
166
+ @api.start
167
+ start_time = Time.now.to_i
168
+ while true
169
+ sleep 5
170
+ status = @api.status
171
+ if !status.nil?
172
+ if !status["status"].nil?
173
+ if status["status"]["running"] == false
174
+ msg "running = #{status["status"]["running"]}", Logger::DEBUG
175
+ r = parse_status(status)
176
+ dump_status(status, msl)
177
+ return
178
+ else
179
+ r = parse_status(status)
180
+ end
181
+ else # status['status'].nil? ... no bonafide status was returned
182
+ time_now = Time.now.to_i
183
+ if time_now - start_time > 20
184
+ # puts "\nError: timing out after 20 seconds. Test had failed to start or verify"
185
+ break
186
+ end
187
+ end
188
+ end
189
+ end
190
+ ensure
191
+ msg "stopping #{msl} ..."
192
+ end
193
+
194
+ def set_global_hosts
195
+ @hosts = Array.new
196
+ @addr_indexes = Array.new
197
+ hosts = @params["hosts"]
198
+ if !hosts.nil?
199
+ p = hosts.split(",")
200
+ p.each do | h |
201
+ if h.include?("-") # b1-1000,b2-1 to indicate addr_count
202
+ q = h.split("-")
203
+ @hosts << q[0]
204
+ @addr_indexes << q[1]
205
+ else # default to the 1st addr index
206
+ @hosts << h
207
+ @addr_indexes << 1
208
+ end
209
+ end
210
+ else
211
+ @hosts = ['b1','b2']
212
+ @addr_indexes = [1,1]
213
+ end
214
+ end
215
+
216
+ def dump_status(status, msl)
217
+ filename = "app_id_status.json"
218
+ f = File.open(filename, "a")
219
+ status["filename"] = msl
220
+ str = JSON.pretty_generate(status)
221
+ f.write(",") if !File.zero?(f) # if appending, we need to insert a comma
222
+ f.write(str)
223
+ f.close
224
+ end
225
+
226
+ def output_csv(msl_file)
227
+ filename = "app_id_stats.csv"
228
+ f = File.open(filename, "a")
229
+ 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"
230
+ File.open(filename, 'a') {|f| f.write(doc) }
231
+ end
232
+
233
+ # finds all the hosts in the musl file
234
+ def get_all_hosts_from_musl(msl)
235
+ f = IO.read(msl)
236
+ hosts = f.scan(/host_\d+/)
237
+ hosts.uniq!
238
+ return hosts
239
+ end
240
+
241
+ # maps host_0 to the client interface
242
+ # maps all other hosts to the server interface
243
+ def map_all_hosts_to_json(hosts=[])
244
+ new_hosts = Array.new
245
+ hosts.each_with_index do | h, i |
246
+ if i == 0
247
+ new_hosts << @hosts[0] + "/*,#{@addr_indexes[0]}"
248
+ else
249
+ new_hosts << @hosts[1] + "/*,#{@addr_indexes[1]}"
250
+ end
251
+ end
252
+
253
+ hosts_config = {}
254
+
255
+ # assign hosts to consecutive string keys, host_0, host_1, etc ...
256
+ new_hosts.each_with_index do | h, i |
257
+ hosts_config["host_#{i}"] = h # new_hosts[i]
258
+ end
259
+
260
+ # convert keys to symbols
261
+ new_hosts_config = {}
262
+ hosts_config.each_key { |k| new_hosts_config[k.to_sym] = hosts_config[k] }
263
+
264
+ return new_hosts_config
265
+ end
266
+
267
+ def parse_verify_response(response)
268
+ if response.nil? # || response.empty?
269
+ msg "*** error = no response received from /verify ***\n\n"
270
+ return nil
271
+ end
272
+ begin
273
+ msg JSON.pretty_generate(response), Logger::DEBUG
274
+ if !response["status"].nil?
275
+ if response["status"]["error"] == true
276
+ @error = response["status"]["error"]
277
+ @reason = response["status"]["reason"]
278
+ dump_status(response)
279
+ msg "*** Error = #{@error}, reason = #{@reason} ***\n\n"
280
+ return nil
281
+ end
282
+ end
283
+ msg "*** verify: okay ***", Logger::DEBUG
284
+ return "*** verify: okay ***"
285
+ rescue
286
+ # could nbe json parse error
287
+ return nil
288
+ end
289
+ end
290
+
291
+ def parse_status(status)
292
+ return nil if status.nil?
293
+ msg JSON.pretty_generate(status), Logger::DEBUG
294
+ @reported_volume = 0
295
+ if !status["status"]["error"].nil?
296
+ if status["status"]["error"] == true
297
+ @error = status["status"]["error"]
298
+ @reason = status["status"]["reason"]
299
+ # puts "*** Error = #{@error}, reason = #{@reason} ***\n\n"
300
+ return nil
301
+ end
302
+ end
303
+
304
+ @stats_summary = status["status"]["statistics"]["summary"]
305
+ @duration = @stats_summary["duration"]
306
+ @instances = @stats_summary["instances"]
307
+ @total_instances = @instances["total"]
308
+ @executed = @instances["executed"]
309
+ @timeouts = @instances["timeouts"]
310
+ @errors = @instances["errors"]
311
+ @asserts_failed = @stats_summary["asserts"]["failed"]
312
+ @server = @stats_summary["server"]
313
+ @server_tx_bytes = @server["tx"]["bytes"]
314
+ @server_tx_msgs = @server["tx"]["msgs"]
315
+ @server_rx_bytes = @server["rx"]["bytes"]
316
+ @server_rx_msgs = @server["rx"]["msgs"]
317
+ @client = @stats_summary["client"]
318
+ @client_tx_bytes = @client["tx"]["bytes"]
319
+ @client_tx_msgs = @client["tx"]["msgs"]
320
+ @client_rx_bytes = @client["rx"]["bytes"]
321
+ @client_rx_msgs = @client["rx"]["msgs"]
322
+ @scenarios = status["status"]["statistics"]["scenarios"]
323
+ @scenarios.each do | scenario |
324
+ @reported_volume = @reported_volume + scenario["volume"]
325
+ end
326
+
327
+ msg ""
328
+ msg "duration: #{format_float(2, @duration)}"
329
+ msg "concurrency: #{@reported_volume}"
330
+ msg "tests/sec: #{format_float(2, @executed.to_f / @duration)}" if @duration.to_i > 0
331
+ msg "passed: #{@executed}"
332
+ msg "errors: #{@errors}"
333
+ msg "timeouts: #{@timeouts}"
334
+ msg "client tx bytes/sec #{format_float(2, @client_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
335
+ msg "client tx msgs/sec #{format_float(2, @client_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
336
+ msg "client rx bytes/sec #{format_float(2, @client_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
337
+ msg "client rx msgs/sec #{format_float(2, @client_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
338
+ msg "server tx bytes/sec #{format_float(2, @server_tx_bytes.to_f / @duration)}" if @duration.to_i > 0
339
+ msg "server tx msgs/sec #{format_float(2, @server_tx_msgs.to_f / @duration)}" if @duration.to_i > 0
340
+ msg "server rx bytes/sec #{format_float(2, @server_rx_bytes.to_f / @duration)}" if @duration.to_i > 0
341
+ msg "server rx msgs/sec #{format_float(2, @server_rx_msgs.to_f / @duration)}" if @duration.to_i > 0
342
+ msg ""
343
+ end
344
+
345
+ def parse_cli argv
346
+ @hash = Hash.new
347
+ while not argv.empty?
348
+ break if argv.first[0,1] != '-'
349
+
350
+ k = argv.shift
351
+
352
+ if [ '-c', '--csv' ].member? k
353
+ @hash['testset'] = shift(k, argv)
354
+ next
355
+ end
356
+
357
+ if [ '-d', '--dir' ].member? k
358
+ @hash['dir'] = shift(k, argv)
359
+ next
360
+ end
361
+
362
+ if [ '-i', '--interfaces' ].member? k
363
+ @hash['interfaces'] = shift(k, argv)
364
+ next
365
+ end
366
+
367
+ if [ '-h', '--help' ].member? k
368
+ help
369
+ exit
370
+ end
371
+
372
+ if [ '-m', '--mu_string' ].member? k
373
+ mu_string = shift(k, argv)
374
+ if mu_string =~ /(.+?):(.+?)@(.*)/
375
+ @@mu_admin_user = $1
376
+ @@mu_admin_pass = $2
377
+ @@mu_ip = $3
378
+ end
379
+ next
380
+ end
381
+
382
+ if [ '-o', '--output'].member? k
383
+ $stdout.reopen(shift(k, argv), "w")
384
+ next
385
+ end
386
+
387
+ if [ '-p', '--pattern' ].member? k
388
+ patterns = Array.new
389
+ pattern_string = shift(k, argv)
390
+ pstrings = pattern_string.split(",")
391
+ pstrings.each do | p |
392
+ if p =~ /(.+?)-(.+?):(.*)/ # e.g. 1-10000:60
393
+ start_vol = $1
394
+ end_vol = $2
395
+ duration = $3
396
+ patterns << "{\"iterations\":1, \"end\":#{end_vol}, \"start\":#{start_vol}, \"duration\":#{duration} }"
397
+ end
398
+ end
399
+ ps = "{ \"iterations\": 1, \"intervals\": ["
400
+ patterns.each do | p |
401
+ ps = ps + p + ","
402
+ end
403
+ ps = ps[0..ps.length-2] # remove final comma
404
+ ps = ps + "] }"
405
+ @hash['pattern'] = ps
406
+ next
407
+ end
408
+
409
+ if [ '-r', '--recursive'].member? k
410
+ @hash['recursive'] = true
411
+ next
412
+ end
413
+
414
+ if [ '-s', '--scenario' ].member? k
415
+ @hash['scenario'] = shift(k, argv)
416
+ next
417
+ end
418
+
419
+ if [ '-t', '--test' ].member? k
420
+ @hash['test'] = true
421
+ next
422
+ end
423
+
424
+ if [ '-v', '--verbose' ].member? k
425
+ $log.level = Logger::DEBUG
426
+ next
427
+ end
428
+
429
+ raise ArgumentError, "Unknown option #{k}"
430
+ end
431
+
432
+ hash
433
+ end
434
+
435
+ def help
436
+ helps = [
437
+ { :short => '-c', :long => '--csv', :value => '<string>', :help => 'name of the csv testset to run' },
438
+ { :short => '-d', :long => '--dir', :value => '<string>', :help => 'directory containing msl files, required for run_dir' },
439
+ { :short => '-h', :long => '--help', :value => '', :help => 'help on command line options' },
440
+ { :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' },
441
+ { :short => '-m', :long => '--mu_string', :value => '<string>', :help => 'user, password, mu_ip in the form of admin:admin@10.9.8.7' },
442
+ { :short => '-o', :long => '--output', :value => '<string>', :help => 'output logging to this file' },
443
+ { :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' },
444
+ { :short => '-r', :long => '--recursive', :value => '', :help => 'for run_dir, recurse through sub-directories' },
445
+ { :short => '-s', :long => '--scenario', :value => '<string>', :help => 'msl file, required for run_msl' },
446
+ { :short => '-t', :long => '--test', :value => '', :help => 'do verify only' },
447
+ { :short => '-v', :long => '--verbose', :value => '', :help => 'set Logger::DEBUG level' }
448
+ ]
449
+
450
+ cmds = [
451
+ "mu cmd_appid:help",
452
+ "mu cmd_appid:run_file -s <file>",
453
+ "mu cmd_appid:run_dir -d <dir> [-r]",
454
+ "mu cmd_appid:running?"
455
+ ]
456
+
457
+ max_long_size = helps.inject(0) { |memo, obj| [ obj[:long].size, memo ].max }
458
+ max_value_size = helps.inject(0) { |memo, obj| [ obj[:value].size, memo ].max }
459
+ puts
460
+ puts "Usage: mu cmd_appid:<command> <options>"
461
+ puts
462
+ helps.each do |h|
463
+ puts "%-*s %*s %-*s %s" % [max_long_size, h[:long], 2, h[:short], max_value_size, h[:value], h[:help]]
464
+ end
465
+ puts
466
+ puts "Available Commands"
467
+ puts
468
+ cmds.each do | c |
469
+ puts c
470
+ end
471
+ puts
472
+ puts "Outputs"
473
+ puts
474
+ puts "app_id_stats.csv"
475
+ puts "scenario_name , passed , errors , timeouts,"
476
+ puts "client tx bytes/sec , client tx msgs/sec , client rx bytes/sec , client rx msgs/src,"
477
+ puts "server tx bytes/sec , server tx msgs/sec , server rx bytes/sec , server rx msgs/src"
478
+ puts
479
+ puts "app_id_status.json"
480
+ puts "contains the last status json object returned from polling, per scenario"
481
+ end
482
+
483
+ end
484
+ end # Command
485
+ end # Mu
486
+