ruby-wasp 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/wasp.rb +1 -0
- data/lib/wasp/client_command_line.rb +131 -0
- data/lib/wasp/http_report.rb +132 -0
- data/lib/wasp/load_manager.rb +78 -0
- data/lib/wasp/load_node.rb +217 -0
- data/lib/wasp/load_ramp_up.rb +159 -0
- data/lib/wasp/load_reporter.rb +48 -0
- data/lib/wasp/load_test.rb +196 -0
- data/lib/wasp/load_test_schedule.rb +79 -0
- data/lib/wasp/meter/meter.rb +2 -0
- data/lib/wasp/monitors/cpu_monitor.rb +30 -0
- data/lib/wasp/monitors/file_io_monitor.rb +42 -0
- data/lib/wasp/monitors/network_monitor.rb +48 -0
- data/lib/wasp/monitors/ram_monitor.rb +25 -0
- data/lib/wasp/test_factory.rb +20 -0
- data/lib/wasp/timing_test.rb +76 -0
- metadata +60 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b5a2860305f53ac78b7c1f349c8a290f1ce94ae9
|
4
|
+
data.tar.gz: d8305a835d8a6cb4602790bd484c187e222b9c38
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5356a57f001d93811a1c2706a2108e3276ea99007f97cb43ff3a2ce22d814b59ecca9213252bfca22d7cfdc0b9cfc1166457e47799f66ed5ed4a3ae6f1e06a48
|
7
|
+
data.tar.gz: a72d5779712f508661f4e73c8e64e3fed53e9a6b1ad1b3e49aa0d52c3d1ae2a6edf00a7ca465d486472085c7a176a2e575737eb784f05f4c284efd34783bd975
|
data/lib/wasp.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Dir["#{File.dirname(__FILE__)}/wasp/**/*.rb"].each {|f| require f}
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require_relative "./load_node.rb"
|
2
|
+
require_relative "./http_report.rb"
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
class ClientCommandLine
|
6
|
+
attr_reader :run_id, :node_info_json
|
7
|
+
|
8
|
+
def require_directory(directory_name)
|
9
|
+
project_root = File.dirname(File.absolute_path(__FILE__))
|
10
|
+
parent_directory = project_root + "/#{directory_name}"
|
11
|
+
puts "Parent root: #{parent_directory}"
|
12
|
+
Dir.glob("#{parent_directory}/*") do |file|
|
13
|
+
require file
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def launch(args)
|
18
|
+
require_directory("custom")
|
19
|
+
puts "Wasp!"
|
20
|
+
index = 0
|
21
|
+
main_command = args[0]
|
22
|
+
puts "Command: #{main_command}"
|
23
|
+
index = 1
|
24
|
+
if (main_command == "run")
|
25
|
+
node_count = 1
|
26
|
+
configuration_file_name = nil
|
27
|
+
server_address = nil
|
28
|
+
@target_server = nil
|
29
|
+
while (index < args.length)
|
30
|
+
arg = args[index]
|
31
|
+
|
32
|
+
if (arg == "-n")
|
33
|
+
index += 1
|
34
|
+
node_count = args[index].to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
if (arg == "-s")
|
38
|
+
index += 1
|
39
|
+
server_address = args[index]
|
40
|
+
end
|
41
|
+
|
42
|
+
if (arg == "-t")
|
43
|
+
index += 1
|
44
|
+
@target_server = args[index]
|
45
|
+
end
|
46
|
+
|
47
|
+
if (arg == "-c")
|
48
|
+
index += 1
|
49
|
+
configuration_file_name = args[index]
|
50
|
+
end
|
51
|
+
index += 1
|
52
|
+
#puts "Looking at command line param: #{index}"
|
53
|
+
end
|
54
|
+
if (configuration_file_name == nil)
|
55
|
+
raise "Failed to pass a -c parameter for config file"
|
56
|
+
end
|
57
|
+
|
58
|
+
if (@target_server == nil)
|
59
|
+
raise "Must specify: -t 'target_server' on the command line"
|
60
|
+
end
|
61
|
+
|
62
|
+
uri = "http://#{server_address}/client"
|
63
|
+
puts "Wasp server: #{uri}"
|
64
|
+
create_run(node_count, configuration_file_name, server_address, @target_server)
|
65
|
+
|
66
|
+
launch_node_command = "\nTo Start Nodes:\n"
|
67
|
+
@node_info_json.each do |node_config|
|
68
|
+
code = node_config["code"]
|
69
|
+
launch_node_command += " ruby wasp.rb node -c #{code} -s #{server_address} -r #{@run_id}\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
puts "
|
73
|
+
Run established.
|
74
|
+
Run ID: #{@run_id}
|
75
|
+
Waiting for #{node_count} nodes.
|
76
|
+
Run details page: http://#{server_address}/reports/run_details?run=#{@run_id}
|
77
|
+
#{launch_node_command}
|
78
|
+
"
|
79
|
+
|
80
|
+
elsif (main_command == "node")
|
81
|
+
@run_id = nil
|
82
|
+
load_node = process_node_command(args)
|
83
|
+
else
|
84
|
+
help_text =
|
85
|
+
"Usage:
|
86
|
+
wasp run -n /node_count/ -d /definition code/ {start with this process being the only node}
|
87
|
+
wasp node m {m is number of nodes, returns the run id for the node start up}
|
88
|
+
wasp node -r /run_id/ {starts one of the nodes for a run}
|
89
|
+
"
|
90
|
+
puts help_text
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def create_run(node_count, configuration_file_name, wasp_server_address, target_server)
|
95
|
+
messenger = HttpReport.new(wasp_server_address)
|
96
|
+
@run_id = messenger.run_create({ node_count: node_count, config_file_name: configuration_file_name, target_server: target_server})
|
97
|
+
@node_info_json = messenger.run_node_info({run_id: @run_id})
|
98
|
+
end
|
99
|
+
|
100
|
+
def process_node_command(args)
|
101
|
+
while (index < args.length)
|
102
|
+
arg = args[index]
|
103
|
+
if (arg == "-r")
|
104
|
+
index += 1
|
105
|
+
@run_id = args[index].to_i
|
106
|
+
elsif (arg == "-s")
|
107
|
+
index += 1
|
108
|
+
server_address = args[index]
|
109
|
+
elsif (arg == "-c")
|
110
|
+
index += 1
|
111
|
+
node_code = args[index]
|
112
|
+
end
|
113
|
+
index += 1
|
114
|
+
end
|
115
|
+
|
116
|
+
if (@run_id == nil)
|
117
|
+
raise "Failed to pass the run_id with -r for the node to run against."
|
118
|
+
end
|
119
|
+
if (server_address == nil)
|
120
|
+
raise "Failed to pass the server address with -s for the node to run against."
|
121
|
+
end
|
122
|
+
|
123
|
+
load_node = launch_node(@run_id, server_address, node_code)
|
124
|
+
return load_node
|
125
|
+
end
|
126
|
+
|
127
|
+
def launch_node(run_id, wasp_server_address, node_code)
|
128
|
+
load_node = LoadNode.new(run_id, wasp_server_address, node_code)
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require "json"
|
2
|
+
require "net/http"
|
3
|
+
|
4
|
+
class HttpReport
|
5
|
+
|
6
|
+
def initialize(server_address)
|
7
|
+
@server = server_address
|
8
|
+
end
|
9
|
+
|
10
|
+
def server_address
|
11
|
+
return "http://#{@server}/client"
|
12
|
+
end
|
13
|
+
|
14
|
+
def post(action, params)
|
15
|
+
address = server_address + action
|
16
|
+
puts "Posting to: #{address}, Params: #{params}"
|
17
|
+
uri = URI.parse(server_address + action)
|
18
|
+
begin
|
19
|
+
response = Net::HTTP.post_form(uri, params)
|
20
|
+
rescue Errno::ETIMEDOUT => error
|
21
|
+
raise "Communication with server error: #{error} Address: #{uri}"
|
22
|
+
end
|
23
|
+
|
24
|
+
if (response.code != "200")
|
25
|
+
puts "Action: #{action} Response: #{response.code} Response body: #{response.body}"
|
26
|
+
raise "Bad response from load http: #{response.code} Response: #{response.body}"
|
27
|
+
end
|
28
|
+
return response.body
|
29
|
+
end
|
30
|
+
|
31
|
+
def node_finished(params)
|
32
|
+
post "/node_finished", params
|
33
|
+
end
|
34
|
+
|
35
|
+
def report_result(run_id, node_id, test_code, wasp_id, run_at_millis, time, result)
|
36
|
+
response = nil
|
37
|
+
begin
|
38
|
+
millis = nil
|
39
|
+
if (time != nil)
|
40
|
+
millis = time * 1000
|
41
|
+
end
|
42
|
+
response = post "/timing", {"run_at_millis" => run_at_millis, "time" => "#{millis}", "run_id" => run_id, "node_id" => node_id,"test_code" => test_code, "wasp_id" => wasp_id.to_s, "result" => result}
|
43
|
+
rescue Exception => e
|
44
|
+
puts "Error sending results (#{result} in #{millis}) to server(#{server_address}): #{e.message}"
|
45
|
+
end
|
46
|
+
return response
|
47
|
+
end
|
48
|
+
|
49
|
+
def status_for_test(run_id, wasp_id)
|
50
|
+
# Checking for kill or finished run.
|
51
|
+
response = post("/status_for_test", {"run_id" => run_id, 'wasp_id' => wasp_id})
|
52
|
+
return JSON.parse(response)
|
53
|
+
end
|
54
|
+
|
55
|
+
def report_load_to_server(run_id, time, load_count)
|
56
|
+
response = post "/load", {"run_id" => run_id, "time" => time, "load" => load_count}
|
57
|
+
end
|
58
|
+
|
59
|
+
def node_register(params)
|
60
|
+
response = post("/node_register", params)
|
61
|
+
data = JSON.parse(response)
|
62
|
+
return data
|
63
|
+
end
|
64
|
+
|
65
|
+
def node_monitors(params)
|
66
|
+
response = post("/node_monitors", params)
|
67
|
+
data = JSON.parse(response)
|
68
|
+
return data
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def node_start?(params)
|
73
|
+
response = post("/node_ask_to_start", params)
|
74
|
+
data = JSON.parse(response)
|
75
|
+
#puts "Node start response: #{data}"
|
76
|
+
return data["start"]
|
77
|
+
end
|
78
|
+
|
79
|
+
def node_schedule(params)
|
80
|
+
response = post("/node_schedule", params)
|
81
|
+
data = JSON.parse(response)
|
82
|
+
return data
|
83
|
+
end
|
84
|
+
|
85
|
+
def node_ready(params)
|
86
|
+
response = post("/node_ready", params)
|
87
|
+
return response
|
88
|
+
end
|
89
|
+
|
90
|
+
def run_create(params)
|
91
|
+
node_count = params[:node_count]
|
92
|
+
if (node_count == nil)
|
93
|
+
node_count = 1
|
94
|
+
params[:node_count] = node_count
|
95
|
+
end
|
96
|
+
|
97
|
+
if (params[:config_file_name] != nil)
|
98
|
+
file_name = params[:config_file_name]
|
99
|
+
config_from_file = ""
|
100
|
+
begin
|
101
|
+
File.open(file_name, "r") do |f|
|
102
|
+
config_from_file = f.read()
|
103
|
+
end
|
104
|
+
params[:config_file_name] = file_name
|
105
|
+
# params[:configuration] = config_from_file
|
106
|
+
configuration = eval(config_from_file)
|
107
|
+
server_list = configuration[:servers]
|
108
|
+
raise "Configuration lacks 'servers' list" unless (server_list != nil)
|
109
|
+
target_server_address = server_list[params[:target_server].to_sym]
|
110
|
+
raise "Configuration lacks entry in 'servers' list for ':#{params[:target_server]}'\n #{server_list}" unless target_server_address != nil
|
111
|
+
params[:configuration] = configuration.to_s
|
112
|
+
params[:config_code] = configuration[:code]
|
113
|
+
raise "'duration' not specified for run." unless configuration[:duration] != nil
|
114
|
+
params[:duration] = configuration[:duration]
|
115
|
+
params[:name] = configuration[:name]
|
116
|
+
rescue Exception => e
|
117
|
+
raise "Exception reading config from file(#{File::absolute_path(file_name)}): #{e.message}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
response = post("/run_create", params)
|
122
|
+
data = JSON.parse(response)
|
123
|
+
return data["run_id"].to_i
|
124
|
+
end
|
125
|
+
|
126
|
+
def run_node_info(params)
|
127
|
+
response = post("/run_node_info", params)
|
128
|
+
data = JSON.parse(response)
|
129
|
+
return data
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative "./load_ramp_up"
|
2
|
+
require_relative "./load_reporter"
|
3
|
+
require_relative "./test_factory"
|
4
|
+
require_relative "./http_report"
|
5
|
+
|
6
|
+
|
7
|
+
class LoadManager
|
8
|
+
attr_reader :run_id, :configuration
|
9
|
+
|
10
|
+
def initialize(configuration, target_code)
|
11
|
+
@configuration = configuration
|
12
|
+
end
|
13
|
+
|
14
|
+
def ramp_up
|
15
|
+
puts "Load Manager - ramp_up"
|
16
|
+
#command = "ruby load_test.rb"
|
17
|
+
puts "Load Manager: #{Process.pid}"
|
18
|
+
pids = []
|
19
|
+
|
20
|
+
definition_code = configuration[:code]
|
21
|
+
@server_address = ENV["SERVER"] || "localhost:2233"
|
22
|
+
puts "Server address: #{@server_address}"
|
23
|
+
ENV[""]
|
24
|
+
|
25
|
+
|
26
|
+
if (ENV['SERVER'] == nil)
|
27
|
+
puts "No 'SERVER' env specified, creating local/minimal server to store results"
|
28
|
+
pids << fork {
|
29
|
+
@reporter = LoadReporter.new({server: @server_address})
|
30
|
+
while (@reporter.started == false)
|
31
|
+
puts "Cannot find Wasp server"
|
32
|
+
sleep 1
|
33
|
+
end
|
34
|
+
}
|
35
|
+
else
|
36
|
+
puts "Using existent 'SERVER': #{@server_address}"
|
37
|
+
end
|
38
|
+
|
39
|
+
@run_id = create_run({definition_code: definition_code})
|
40
|
+
ramp_up = LoadRampUp.new(@run_id, @target_code, @configuration)
|
41
|
+
|
42
|
+
pids << fork {
|
43
|
+
ramp_up.run
|
44
|
+
}
|
45
|
+
|
46
|
+
quit = false
|
47
|
+
while !quit
|
48
|
+
begin
|
49
|
+
system("stty raw -echo")
|
50
|
+
str = STDIN.getc
|
51
|
+
ensure
|
52
|
+
system("stty -raw echo")
|
53
|
+
end
|
54
|
+
input = str.chr
|
55
|
+
puts "You pressed: #{input} ##{str.to_i}"
|
56
|
+
if (input == "q")
|
57
|
+
quit = true
|
58
|
+
puts "=================================================================================="
|
59
|
+
puts "DONE WITH RAMP UP"
|
60
|
+
puts " PID's: #{pids}"
|
61
|
+
puts "=================================================================================="
|
62
|
+
end
|
63
|
+
end
|
64
|
+
kill_pids(pids)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def kill_pids(pids)
|
69
|
+
puts "Killing child processes"
|
70
|
+
pids.each do |pid|
|
71
|
+
Process.kill("INT", pid)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
# load_manager = LoadManager.new
|
78
|
+
# load_manager.ramp_up
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require_relative "./http_report"
|
2
|
+
require_relative "./load_test"
|
3
|
+
require_relative "./monitors/cpu_monitor.rb"
|
4
|
+
require_relative "./monitors/ram_monitor.rb"
|
5
|
+
require_relative "./monitors/file_io_monitor.rb"
|
6
|
+
require_relative "./monitors/network_monitor.rb"
|
7
|
+
require_relative "./test_factory.rb"
|
8
|
+
|
9
|
+
@@load_node_instance = nil
|
10
|
+
|
11
|
+
class LoadNode
|
12
|
+
attr_reader :node_id, :schedule, :duration_millis
|
13
|
+
attr_accessor :target_server, :target_code
|
14
|
+
|
15
|
+
def self.instance
|
16
|
+
return @@load_node_instance
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(run_id, server_address, node_code = nil)
|
20
|
+
if (@@load_node_instance != nil)
|
21
|
+
raise "LoadNode instance initialized a second time"
|
22
|
+
end
|
23
|
+
@target_code = target_code
|
24
|
+
@test_index = 1
|
25
|
+
@messenger = nil
|
26
|
+
@@load_node_instance = self
|
27
|
+
@factory = TestFactory.new
|
28
|
+
if (server_address == nil)
|
29
|
+
# Perf tests don't require server
|
30
|
+
else
|
31
|
+
begin
|
32
|
+
puts "Registering node"
|
33
|
+
@run_id = run_id
|
34
|
+
@child_pids = []
|
35
|
+
@messenger = HttpReport.new(server_address)
|
36
|
+
node_info = @messenger.node_register({run_id: @run_id, address: "#{Socket.gethostname}", code: node_code})
|
37
|
+
if (node_info['configuration'] == nil)
|
38
|
+
puts "Error starting node. Did run already complete?"
|
39
|
+
else
|
40
|
+
@configuration = eval(node_info['configuration'])
|
41
|
+
@node_id = node_info["id"].to_i
|
42
|
+
@node_code = node_info["code"]
|
43
|
+
@target_code = node_info["target_server"]
|
44
|
+
@target_server = @configuration[:servers][@target_code.to_sym]
|
45
|
+
puts "Node registered: #{@node_id} Code: #{@node_code} Target server: #{@target_server}"
|
46
|
+
@schedule = @messenger.node_schedule({node_id: @node_id})
|
47
|
+
@load_tests = create_node_tests(@node_id, @schedule)
|
48
|
+
@duration_millis = node_info["duration"]
|
49
|
+
@messenger.node_ready({node_id: @node_id})
|
50
|
+
wait_for_node_start_ok
|
51
|
+
launch_node_tests
|
52
|
+
wait_for_finish
|
53
|
+
@messenger.node_finished({node_id: @node_id})
|
54
|
+
end
|
55
|
+
rescue Interrupt => e
|
56
|
+
puts "NODE (#{@node_id}) - Interrupt signal received, quitting. [#{self.class}]"
|
57
|
+
rescue Exception => exc
|
58
|
+
puts "Exception in node: #{exc.message} \n" + exc.backtrace.join("\n")
|
59
|
+
ensure
|
60
|
+
kill_child_processes
|
61
|
+
end
|
62
|
+
#exit 0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def report_block_result(test_code, wasp_id, time_ellapsed, benchmark_time, result)
|
67
|
+
@messenger.report_result(@run_id, @node_id, test_code, wasp_id, time_ellapsed, benchmark_time, result)
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def write_pid_to_file(pid)
|
72
|
+
open('node_pids_#{@node_id}.pid', 'a') { |f|
|
73
|
+
f.puts "#{pid}\n"
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def launch_node_tests
|
78
|
+
@load_tests.each do |test|
|
79
|
+
pid = fork {
|
80
|
+
test.run
|
81
|
+
}
|
82
|
+
@child_pids << pid
|
83
|
+
write_pid_to_file(pid)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def wait_for_node_start_ok
|
89
|
+
ok_to_start = false
|
90
|
+
last_message_at = 0
|
91
|
+
while (!ok_to_start)
|
92
|
+
ok_to_start = @messenger.node_start?({node_id: @node_id})
|
93
|
+
sleep 0.2
|
94
|
+
if (Time.new.to_i - last_message_at > 5)
|
95
|
+
puts "Node waiting for other nodes to start (#{@node_code})"
|
96
|
+
last_message_at = Time.new.to_i
|
97
|
+
end
|
98
|
+
end
|
99
|
+
puts "All Nodes Launched. Node (#{@node_code}) can start now "
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def wait_for_finish
|
104
|
+
@start_time = Time.now.to_i
|
105
|
+
quit = false
|
106
|
+
while !quit
|
107
|
+
sleep 10
|
108
|
+
ellapsed_time = Time.now.to_i - @start_time
|
109
|
+
if (ellapsed_time > (@duration_millis / 1000))
|
110
|
+
quit = true
|
111
|
+
puts "Node duration reached: #{@duration_millis} seconds. Node quitting"
|
112
|
+
else
|
113
|
+
#puts "Node duration (#{ellapsed_time} secs) NOT reached: #{@duration_millis/1000} seconds."
|
114
|
+
end
|
115
|
+
@messenger.node_schedule({node_id: @node_id})
|
116
|
+
|
117
|
+
status = @messenger.status_for_test(@run_id, nil)
|
118
|
+
if (status['run_status'] == "killed")
|
119
|
+
puts "XXXXX RUN HAS BEEN KILLED - KILLING NODE: #{@wasp_id} XXXXXXX"
|
120
|
+
quit = true
|
121
|
+
elsif (status['run_status'] == "finished")
|
122
|
+
puts "XXXXX RUN IS FINISHED - KILLING NODE: #{@wasp_id} XXXXXXX"
|
123
|
+
quit = true
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
puts "Node finished. ##{@node_code}"
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def create_node_tests(node_id, node_schedule)
|
132
|
+
wasp_id = 1
|
133
|
+
load_tests = []
|
134
|
+
|
135
|
+
puts "Node Schedule:"
|
136
|
+
node_schedule.each do |test_schedule|
|
137
|
+
test_name = test_schedule["test_name"]
|
138
|
+
events = test_schedule["events"]
|
139
|
+
sched_text = "Test: #{test_name} Events: "
|
140
|
+
events.each do |event|
|
141
|
+
sched_text += "#{event['action'].capitalize} at #{event['time']} sec "
|
142
|
+
end
|
143
|
+
test_config = find_config_for_test(test_name)
|
144
|
+
test = @factory.create_test(test_name, @target_code, test_config)
|
145
|
+
test.index = @test_index
|
146
|
+
@test_index += 1
|
147
|
+
|
148
|
+
load_test = LoadTest.new(self, @run_id, node_id, wasp_id, test, events, @messenger)
|
149
|
+
load_tests << load_test
|
150
|
+
wasp_id += 1
|
151
|
+
end
|
152
|
+
|
153
|
+
node_monitors = @messenger.node_monitors( {node_id: @node_id} )
|
154
|
+
node_monitors.each do |monitor_config|
|
155
|
+
type = monitor_config["type"]
|
156
|
+
name = monitor_config["name"]
|
157
|
+
duration = monitor_config["duration"].to_i / 1000
|
158
|
+
if (name == nil)
|
159
|
+
name = "#{type.capitalize} Monitor"
|
160
|
+
end
|
161
|
+
|
162
|
+
if (type == "network")
|
163
|
+
puts "Config: #{monitor_config}"
|
164
|
+
address = monitor_config["address"]
|
165
|
+
monitor = NetworkMonitor.new(address)
|
166
|
+
elsif (type == "cpu")
|
167
|
+
monitor = CpuMonitor.new()
|
168
|
+
elsif (type == "file.io")
|
169
|
+
monitor = FileIoMonitor.new()
|
170
|
+
elsif (type == "ram")
|
171
|
+
monitor = RamMonitor.new()
|
172
|
+
else
|
173
|
+
raise "Do no know how to handle monitor type: #{type} Name: #{name}"
|
174
|
+
end
|
175
|
+
|
176
|
+
events = [{"time" => "0", "action" => "run"}, {"time" => "#{duration}", "action" => "pause"}]
|
177
|
+
load_test = LoadTest.new(self, @run_id, node_id, wasp_id, monitor, events, @messenger)
|
178
|
+
load_tests << load_test
|
179
|
+
wasp_id += 1
|
180
|
+
end
|
181
|
+
|
182
|
+
return load_tests
|
183
|
+
end
|
184
|
+
|
185
|
+
def find_config_for_test(test_name)
|
186
|
+
test_configs = @configuration[:tests]
|
187
|
+
test_configs.each do |test_config|
|
188
|
+
if (test_config[:test] == test_name)
|
189
|
+
return test_config
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
def kill_child_processes
|
196
|
+
# puts "=================================================================================="
|
197
|
+
# puts "Node Finished: #{@node_id}"
|
198
|
+
# puts " Killing child PID's: #{@child_pids}"
|
199
|
+
# puts "=================================================================================="
|
200
|
+
|
201
|
+
# trap("INT") do
|
202
|
+
# exit
|
203
|
+
# end
|
204
|
+
Process.kill('INT', -Process.getpgrp)
|
205
|
+
#
|
206
|
+
# @child_pids.each do |pid|
|
207
|
+
# begin
|
208
|
+
# puts "Killing: #{pid}"
|
209
|
+
# Process.kill("INT", pid)
|
210
|
+
# rescue Exception => e
|
211
|
+
# puts "Exception killing pid #{pid}. #{e.message}"
|
212
|
+
# end
|
213
|
+
# end
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require_relative "./load_test"
|
2
|
+
require_relative "./http_report"
|
3
|
+
require_relative "./test_factory"
|
4
|
+
|
5
|
+
|
6
|
+
class LoadRampUp
|
7
|
+
attr_reader :tests
|
8
|
+
|
9
|
+
|
10
|
+
def initialize(run_id, target_code, configuration)
|
11
|
+
puts "Load Ramp Up created"
|
12
|
+
if (run_id == nil)
|
13
|
+
end
|
14
|
+
@pids = []
|
15
|
+
@run_id = run_id
|
16
|
+
@target_code = target_code
|
17
|
+
@factory = TestFactory.new
|
18
|
+
@tests = {}
|
19
|
+
@all_tests = []
|
20
|
+
@configuration = configuration
|
21
|
+
wasp_id = 0
|
22
|
+
|
23
|
+
@configuration[:tests].each do |test_config|
|
24
|
+
test_class = test_config[:test]
|
25
|
+
|
26
|
+
initial_count = test_config[:initial]
|
27
|
+
ramp_up_config = test_config[:ramp_up]
|
28
|
+
final_count = ramp_up_config[:final]
|
29
|
+
@tests[test_class] = []
|
30
|
+
while (@tests[test_class].length < final_count)
|
31
|
+
# (run_id, node_id, wasp_id, test, schedule_events, messenger)
|
32
|
+
test = @factory.create_test(test_class, @target_code, test_config)
|
33
|
+
load_test = LoadTest.new(self, run_id, nil, wasp_id, test, test_config, messenger)
|
34
|
+
wasp_id += 1
|
35
|
+
@tests[test_class] << load_test
|
36
|
+
@all_tests << load_test
|
37
|
+
end
|
38
|
+
assign_schedules_to_tests(test_config, @tests[test_class])
|
39
|
+
end
|
40
|
+
send_schedule_to_server(@configuration)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def send_schedule_to_server(configuration)
|
45
|
+
(0..duration).each do |time|
|
46
|
+
total_load = 0
|
47
|
+
@all_tests.each do |test|
|
48
|
+
action = test.schedule.current_action(time)
|
49
|
+
if (action == :run)
|
50
|
+
total_load += 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
report_load_to_server(@run_id, time, total_load)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def duration
|
59
|
+
last_time = 0
|
60
|
+
@all_tests.each do |test|
|
61
|
+
test_last_time = test.duration
|
62
|
+
if (test_last_time > last_time)
|
63
|
+
last_time = test_last_time
|
64
|
+
end
|
65
|
+
end
|
66
|
+
return last_time
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def find_total_loads
|
71
|
+
load_at_times
|
72
|
+
time = 0
|
73
|
+
while (!done) do
|
74
|
+
count = 0
|
75
|
+
@all_tests.each do |test|
|
76
|
+
if (test.current_action(time) == :run)
|
77
|
+
count += 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
time += 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def assign_schedules_to_tests(test_config, load_tests)
|
86
|
+
ramp_up = test_config[:ramp_up]
|
87
|
+
initial_count = test_config[:initial]
|
88
|
+
|
89
|
+
load_tests.each do |test|
|
90
|
+
test.schedule.add(0, :pause)
|
91
|
+
end
|
92
|
+
|
93
|
+
(0..initial_count - 1).each do |index|
|
94
|
+
test = load_tests[index]
|
95
|
+
test.schedule.add(0, :run)
|
96
|
+
end
|
97
|
+
|
98
|
+
rate = ramp_up[:rate]
|
99
|
+
current_time = 0
|
100
|
+
tests_started = initial_count
|
101
|
+
while (tests_started < ramp_up[:final]) do
|
102
|
+
current_time += rate
|
103
|
+
load_tests[tests_started].schedule.add(current_time, :run)
|
104
|
+
tests_started += 1
|
105
|
+
end
|
106
|
+
|
107
|
+
sustain_time = test_config[:sustain]
|
108
|
+
current_time += sustain_time
|
109
|
+
|
110
|
+
ramp_down = test_config[:ramp_down]
|
111
|
+
final_count = ramp_down[:final]
|
112
|
+
rate = ramp_down[:rate]
|
113
|
+
while (tests_started > final_count) do
|
114
|
+
load_tests[tests_started - 1].schedule.add(current_time, :pause)
|
115
|
+
tests_started -= 1
|
116
|
+
current_time += rate
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
def run
|
123
|
+
begin
|
124
|
+
puts "Running Load test"
|
125
|
+
@configuration[:tests].each do |test_config|
|
126
|
+
test_name = test_config[:name]
|
127
|
+
puts "Starting test: #{test_name}"
|
128
|
+
@tests[test_name].each do |load_test|
|
129
|
+
@pids << fork {
|
130
|
+
#puts "Launching test: #{test_name} : #{load_test.wasp_id}"
|
131
|
+
load_test.run
|
132
|
+
}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
wait_for_kill_signal()
|
136
|
+
rescue Interrupt => e
|
137
|
+
puts "Interrupt signal received, quitting. [#{e.class.name}] #{e.message}"
|
138
|
+
ensure
|
139
|
+
kill_pids(@pids)
|
140
|
+
end
|
141
|
+
exit 0
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
def wait_for_kill_signal()
|
146
|
+
while (true) do
|
147
|
+
sleep 2000
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
def kill_pids(pids)
|
153
|
+
puts "Killing child processes"
|
154
|
+
pids.each do |pid|
|
155
|
+
Process.kill("INT", pid)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
|
3
|
+
class LoadReporter
|
4
|
+
attr_reader :started
|
5
|
+
include WEBrick
|
6
|
+
|
7
|
+
def initialize(params)
|
8
|
+
puts "Initializing Load Reporter"
|
9
|
+
@started = false
|
10
|
+
@server_address = params[:server]
|
11
|
+
@current_load = 0
|
12
|
+
file_name = "data_#{Time.now.to_i}.txt"
|
13
|
+
@out_file = File.new("out.txt", "w")
|
14
|
+
port = params[:port] || 2233
|
15
|
+
puts "Starting server: http://#{Socket.gethostname}:#{port}"
|
16
|
+
server = HTTPServer.new(:Port=>2233,:DocumentRoot=>Dir::pwd )
|
17
|
+
trap("INT") {
|
18
|
+
puts "Server going down"
|
19
|
+
server.shutdown
|
20
|
+
}
|
21
|
+
|
22
|
+
server.mount_proc '/' do |request, response|
|
23
|
+
response.body = process_request(request)
|
24
|
+
end
|
25
|
+
server.start
|
26
|
+
@started = true
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def process_request(request)
|
31
|
+
response = "
|
32
|
+
Current Load: #{@current_load}
|
33
|
+
Query String: #{request.query_string}
|
34
|
+
"
|
35
|
+
|
36
|
+
request.query.collect { | key, value |
|
37
|
+
#f.write("#{key}: #{value}\n")
|
38
|
+
if (key == "load")
|
39
|
+
@current_load = value.to_i
|
40
|
+
response += "Current load changed to: #{@current_load}"
|
41
|
+
end
|
42
|
+
response += "#{key}: #{value}\n"
|
43
|
+
}
|
44
|
+
puts "RESPONSE: #{response}"
|
45
|
+
return response
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "uri"
|
3
|
+
require "benchmark"
|
4
|
+
require_relative "http_report"
|
5
|
+
require_relative "load_test_schedule"
|
6
|
+
require 'logger'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
class LoadTest
|
10
|
+
PASSED = "passed"
|
11
|
+
FAILED = "failed"
|
12
|
+
|
13
|
+
attr_reader :wasp_id, :start_time, :test
|
14
|
+
attr_accessor :schedule
|
15
|
+
|
16
|
+
def initialize(owner, run_id, node_id, wasp_id, test, schedule_events, messenger = nil)
|
17
|
+
@owner = owner
|
18
|
+
test.owner = self
|
19
|
+
@schedule = LoadTestSchedule.new
|
20
|
+
@schedule.load_json(schedule_events)
|
21
|
+
@messenger = messenger
|
22
|
+
@node_id = node_id
|
23
|
+
@wasp_id = wasp_id
|
24
|
+
@time_of_last_status_check = 0
|
25
|
+
|
26
|
+
@test = test
|
27
|
+
if (run_id == nil) || (run_id == 0)
|
28
|
+
raise "No run_id specified for load test"
|
29
|
+
end
|
30
|
+
test_code = self.class.name
|
31
|
+
@run_id = run_id
|
32
|
+
@name = "Test for #{test.test_code}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def log
|
36
|
+
return @logger
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_logger
|
40
|
+
FileUtils.mkdir_p('./log/load') unless File.directory?('./log/load')
|
41
|
+
FileUtils.mkdir_p("./log/load/run_#{@run_id}") unless File.directory?("./log/load/run_#{@run_id}")
|
42
|
+
log_file = "./log/load/run_#{@run_id}/#{@test.class.name}_#{@wasp_id}.log"
|
43
|
+
@logger = Logger.new(log_file)
|
44
|
+
@logger.level = Logger::DEBUG
|
45
|
+
@test.logger = @logger
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
49
|
+
create_logger()
|
50
|
+
trap('INT') do
|
51
|
+
puts "Wasp asked to die: #{test_code}:#{@wasp_id} Pid: #{Process.pid}"
|
52
|
+
#log.info "Wasp asked to die: #{test_code}:#{@wasp_id} Pid: #{Process.pid}"
|
53
|
+
exit 0
|
54
|
+
end
|
55
|
+
|
56
|
+
begin
|
57
|
+
@start_time = Time.now
|
58
|
+
@exit = false
|
59
|
+
while (!@exit)
|
60
|
+
result = FAILED
|
61
|
+
run_if_time_right(time_ellapsed_millis)
|
62
|
+
end
|
63
|
+
puts "End of run for wasp: #{@wasp_id}. Duration: #{duration_millis}"
|
64
|
+
log.info "End of run. Duration: #{duration_millis}"
|
65
|
+
rescue Interrupt => e
|
66
|
+
log.warn "WASP KILL: #{test_code}:#{@wasp_id} Interrupt signal received, quitting. [#{e.class.name}] #{e.message}"
|
67
|
+
puts "WASP KILL: #{test_code}:#{@wasp_id} Interrupt signal received, quitting. [#{e.class.name}] #{e.message}"
|
68
|
+
@exit = true
|
69
|
+
rescue Exception => exc
|
70
|
+
log.warn "Exception in wasp: #{@wasp_id} . [#{exc.class.name}] #{exc.message}"
|
71
|
+
puts "Exception in wasp: #{@wasp_id} . [#{exc.class.name}] #{exc.message}"
|
72
|
+
ensure
|
73
|
+
log.info "Wasp process exiting: #{test_code}:#{@wasp_id} Pid: #{Process.pid}"
|
74
|
+
puts "Wasp process exiting: #{test_code}:#{@wasp_id} Pid: #{Process.pid}"
|
75
|
+
exit 0
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def run_if_time_right(current_time_millis)
|
81
|
+
benchmark_time = 0
|
82
|
+
if (current_time_millis >= duration_millis)
|
83
|
+
@exit = true
|
84
|
+
puts "Time for LoadTest instance to die. Ellapsed: #{current_time_millis} Test duration: #{duration_millis}"
|
85
|
+
else
|
86
|
+
current_action = current_action_for_time(current_time_millis)
|
87
|
+
if (current_action == :run)
|
88
|
+
#puts "Time is right. Test being performed"
|
89
|
+
result = PASSED
|
90
|
+
begin
|
91
|
+
benchmark_time = Benchmark.realtime {
|
92
|
+
perform_test
|
93
|
+
}
|
94
|
+
log.info "Test completed normally in #{benchmark_time} seconds"
|
95
|
+
rescue SystemExit => se
|
96
|
+
log.warn "Caught system exit signal. Exiting..."
|
97
|
+
@exit = true
|
98
|
+
rescue Exception => e
|
99
|
+
result = FAILED
|
100
|
+
log.error("Test (#{@test.class}) produced exception: #{e.class} #{e.message}")
|
101
|
+
e.backtrace.each do |back|
|
102
|
+
log.error(back)
|
103
|
+
end
|
104
|
+
puts "Test (#{@test.class}) produced exception: #{e.class} #{e.message} #{e.backtrace}"
|
105
|
+
end
|
106
|
+
|
107
|
+
custom_timing = @test.timing
|
108
|
+
if (custom_timing != nil)
|
109
|
+
benchmark_time = custom_timing
|
110
|
+
end
|
111
|
+
@messenger.report_result(@run_id, @node_id, @test.test_code, @wasp_id, current_time_millis, benchmark_time, result)
|
112
|
+
else
|
113
|
+
#puts "Not running test. current_action = #{current_action}"
|
114
|
+
sleep 0.2
|
115
|
+
end
|
116
|
+
|
117
|
+
if (@exit == false)
|
118
|
+
time_since_last_status_check = current_time_millis - @time_of_last_status_check
|
119
|
+
if (time_since_last_status_check > 20*1000)
|
120
|
+
@time_of_last_status_check = current_time_millis
|
121
|
+
status = @messenger.status_for_test(@run_id, @wasp_id)
|
122
|
+
if (status['run_status'] == "killed")
|
123
|
+
log.warn "XXXXX RUN HAS BEEN KILLED - KILLING WASP: #{@wasp_id} XXXXXXX"
|
124
|
+
@exit = true
|
125
|
+
elsif (status['run_status'] == "finished")
|
126
|
+
log.warn "XXXXX RUN IS FINISHED - KILLING WASP: #{@wasp_id} XXXXXXX"
|
127
|
+
@exit = true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
|
136
|
+
def duration_millis
|
137
|
+
last_run_time = nil
|
138
|
+
@schedule.events.each do |event|
|
139
|
+
if (event[:action] == :run)
|
140
|
+
last_run_time = nil
|
141
|
+
else
|
142
|
+
last_run_time = event[:time]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
if (last_run_time == nil)
|
147
|
+
raise "This test never finishes on it's own"
|
148
|
+
end
|
149
|
+
return (last_run_time * 1000)
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def time_ellapsed_millis
|
154
|
+
time_ellapsed = (Time.now - @start_time) * 1000.0
|
155
|
+
return time_ellapsed
|
156
|
+
end
|
157
|
+
|
158
|
+
def report_block_result(test_code, wasp_id, ellapsed_millis, benchmark_time, result, target_code = "unknown")
|
159
|
+
@owner.report_block_result(test_code, wasp_id, ellapsed_millis, benchmark_time, result)
|
160
|
+
end
|
161
|
+
|
162
|
+
def current_action
|
163
|
+
return current_action_for_time(time_ellapsed_millis)
|
164
|
+
end
|
165
|
+
|
166
|
+
def current_action_for_time(millis)
|
167
|
+
current_action = schedule.current_action(millis / 1000)
|
168
|
+
return current_action
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_code
|
172
|
+
return @test.test_code
|
173
|
+
end
|
174
|
+
|
175
|
+
def to_s
|
176
|
+
return "I am only one wasp of a swarm. ##{@wasp_id}"
|
177
|
+
end
|
178
|
+
|
179
|
+
def assert(value)
|
180
|
+
if (value == false)
|
181
|
+
raise "Assertion failed"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def perform_test
|
186
|
+
@test.owner = self
|
187
|
+
@test.set_up
|
188
|
+
@test.run
|
189
|
+
@test.pause_after_run
|
190
|
+
@test.tear_down
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class LoadTestSchedule
|
2
|
+
attr_accessor :events
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@events = []
|
6
|
+
@previous_action = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(time, action)
|
10
|
+
if (action != @previous_action)
|
11
|
+
remove_action_at_time(time)
|
12
|
+
@events << {time: time, action: action}
|
13
|
+
else
|
14
|
+
warn "Attempt to add same action consecutively, ignoring the later one. Time: #{time} Action: #{action}"
|
15
|
+
end
|
16
|
+
@previous_action = action
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_json(schedule_events)
|
20
|
+
schedule_events.each do |event|
|
21
|
+
time = event["time"].to_i
|
22
|
+
action = event["action"].to_sym
|
23
|
+
add(time, action)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def remove_action_at_time(time)
|
28
|
+
(0..@events.length - 1).each do |i|
|
29
|
+
if (@events[i][:time] == time)
|
30
|
+
@events.delete_at(i)
|
31
|
+
return
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def current_action(time)
|
38
|
+
event = current_event(time)
|
39
|
+
if (event == nil)
|
40
|
+
return :pause
|
41
|
+
else
|
42
|
+
return event[:action]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def next_action(time)
|
48
|
+
event = next_event(time)
|
49
|
+
if (event == nil)
|
50
|
+
return nil
|
51
|
+
else
|
52
|
+
return event[:action]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def current_event(time)
|
58
|
+
current_event = nil
|
59
|
+
@events.each do |event|
|
60
|
+
if (event[:time] <= time.to_i)
|
61
|
+
current_event = event
|
62
|
+
end
|
63
|
+
end
|
64
|
+
return current_event
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def next_event(time)
|
69
|
+
current_event = nil
|
70
|
+
@events.each do |event|
|
71
|
+
if (event[:time] > time.to_i)
|
72
|
+
return event
|
73
|
+
end
|
74
|
+
end
|
75
|
+
return @events.last
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "benchmark"
|
3
|
+
require_relative "../timing_test"
|
4
|
+
|
5
|
+
|
6
|
+
class CpuMonitor < TimingTest
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@sleep_seconds = 4
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
a = 5000
|
14
|
+
(0..1000).each do |i|
|
15
|
+
a /= 2.0
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def pause_after_run
|
20
|
+
sleep @sleep_seconds
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def test_code
|
25
|
+
return ("monitor.cpu")
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "benchmark"
|
3
|
+
require_relative "../timing_test"
|
4
|
+
|
5
|
+
|
6
|
+
class FileIoMonitor < TimingTest
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@sleep_seconds = 4
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
file_name = "./log/file_io_bench_#{Time.now.to_i}.dat"
|
14
|
+
(1..200).each do |i|
|
15
|
+
File.open(file_name, 'w') { |file|
|
16
|
+
(1..1000).each do |i|
|
17
|
+
file.write("Test text #{i} aohoasihdf oiahsdf pohiasdfha oisdhf aiousdfgho iausgdf oaia aiusdhfia hdfihdsfi ahsdfi ahudf \n")
|
18
|
+
file.flush
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
File.readlines(file_name).each do |line|
|
23
|
+
if (!line.start_with? "Test text")
|
24
|
+
raise "Error reading back file"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
File.delete(file_name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def pause_after_run
|
32
|
+
sleep @sleep_seconds
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def test_code
|
37
|
+
return ("monitor.file")
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative "../timing_test"
|
2
|
+
require 'net/ping'
|
3
|
+
|
4
|
+
|
5
|
+
class NetworkMonitor < TimingTest
|
6
|
+
attr_accessor :address
|
7
|
+
|
8
|
+
def initialize(address)
|
9
|
+
@sleep_seconds = 4
|
10
|
+
@address = address
|
11
|
+
end
|
12
|
+
|
13
|
+
def timing
|
14
|
+
return @timing
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
output = ""
|
19
|
+
begin
|
20
|
+
timing = 0
|
21
|
+
pinger = Net::Ping::External.new
|
22
|
+
(1..10).each do
|
23
|
+
pinger.ping(@address)
|
24
|
+
timing += (pinger.duration * 1000.0)
|
25
|
+
end
|
26
|
+
puts "Ping timing for 10 pings: #{timing}"
|
27
|
+
@timing = timing
|
28
|
+
rescue Exception => e
|
29
|
+
@timing = nil
|
30
|
+
puts "Error pinging address: #{@address} => #{output}"
|
31
|
+
raise "Error pinging address: #{@address} => #{output}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#64 bytes from localhost (127.0.0.1): icmp_req=4 ttl=64 time=0.015 ms
|
36
|
+
#64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.018 ms
|
37
|
+
|
38
|
+
def pause_after_run
|
39
|
+
sleep @sleep_seconds
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_code
|
43
|
+
return ("monitor.network")
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative "../timing_test"
|
2
|
+
|
3
|
+
|
4
|
+
class RamMonitor < TimingTest
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@sleep_seconds = 4
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
def pause_after_run
|
15
|
+
sleep @sleep_seconds
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def test_code
|
20
|
+
return ("monitor.ram")
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Require all files in custom test directory
|
2
|
+
this_dir_name = File.dirname(File.absolute_path(__FILE__))
|
3
|
+
Dir.glob(this_dir_name + '/custom/*') {|file| require file}
|
4
|
+
|
5
|
+
class TestFactory
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_test(test_code, target_code, config)
|
11
|
+
test_class = test_code.split(".").first
|
12
|
+
test_object = Object::const_get(test_class).new
|
13
|
+
test_object.test_code = test_code
|
14
|
+
test_object.target_code = target_code
|
15
|
+
raise "No parameters for target: :#{target_code} Test: #{test_code}" unless (config[:params] != nil) && config[:params][target_code.to_sym]
|
16
|
+
test_object.params = config[:params][target_code.to_sym]
|
17
|
+
return test_object
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "benchmark"
|
3
|
+
|
4
|
+
|
5
|
+
class TimingTest
|
6
|
+
attr_accessor :params, :index, :owner, :test_code, :logger, :target_code
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@params = {}
|
10
|
+
@index = 0
|
11
|
+
@owner = nil
|
12
|
+
@test_code = nil
|
13
|
+
@target_code = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_up
|
17
|
+
end
|
18
|
+
|
19
|
+
def tear_down
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
raise "Not Implemented"
|
24
|
+
end
|
25
|
+
|
26
|
+
def server_url
|
27
|
+
url = LoadNode.instance.target_server
|
28
|
+
if (url == nil)
|
29
|
+
raise "target_server not specified when starting main process"
|
30
|
+
end
|
31
|
+
return url
|
32
|
+
end
|
33
|
+
|
34
|
+
def ellaped_millis
|
35
|
+
@owner.time_ellapsed_millis
|
36
|
+
end
|
37
|
+
|
38
|
+
def log
|
39
|
+
return @logger
|
40
|
+
end
|
41
|
+
|
42
|
+
def time_block(code)
|
43
|
+
start_time = Time.now
|
44
|
+
begin
|
45
|
+
yield
|
46
|
+
end_time = Time.now
|
47
|
+
block_time = (end_time.to_f - start_time.to_f) * 1000
|
48
|
+
@owner.report_block_result(code, @index, @owner.time_ellapsed_millis, block_time, LoadTest::PASSED, target_code)
|
49
|
+
rescue Exception => e
|
50
|
+
log.error("Exception running timing block (#{code}) test: #{e.message}")
|
51
|
+
end_time = Time.now
|
52
|
+
block_time = (end_time.to_f - start_time.to_f) * 1000
|
53
|
+
@owner.report_block_result(code, @index, @owner.time_ellapsed_millis, block_time, LoadTest::FAILED, target_code)
|
54
|
+
raise e
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def assert(value)
|
60
|
+
if (value == false)
|
61
|
+
puts "Assertion failed"
|
62
|
+
raise "Assertion failed"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def pause_after_run
|
67
|
+
# Default is no pause
|
68
|
+
end
|
69
|
+
|
70
|
+
def timing
|
71
|
+
# LoadTest times the run method and uses that timing unless the instance of TimingTest timing method returns a non-nil time.
|
72
|
+
return nil
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-wasp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.8
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Moore
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-29 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Ruby Load Tester
|
14
|
+
email: m.moore.denver@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/wasp.rb
|
20
|
+
- lib/wasp/client_command_line.rb
|
21
|
+
- lib/wasp/http_report.rb
|
22
|
+
- lib/wasp/load_manager.rb
|
23
|
+
- lib/wasp/load_node.rb
|
24
|
+
- lib/wasp/load_ramp_up.rb
|
25
|
+
- lib/wasp/load_reporter.rb
|
26
|
+
- lib/wasp/load_test.rb
|
27
|
+
- lib/wasp/load_test_schedule.rb
|
28
|
+
- lib/wasp/meter/meter.rb
|
29
|
+
- lib/wasp/monitors/cpu_monitor.rb
|
30
|
+
- lib/wasp/monitors/file_io_monitor.rb
|
31
|
+
- lib/wasp/monitors/network_monitor.rb
|
32
|
+
- lib/wasp/monitors/ram_monitor.rb
|
33
|
+
- lib/wasp/test_factory.rb
|
34
|
+
- lib/wasp/timing_test.rb
|
35
|
+
homepage: ''
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
- lib/wasp
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 2.6.10
|
57
|
+
signing_key:
|
58
|
+
specification_version: 4
|
59
|
+
summary: Ruby Load Tester
|
60
|
+
test_files: []
|