kymera 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/inspectionProfiles/Project_Default.xml +7 -0
- data/.idea/inspectionProfiles/profiles_settings.xml +7 -0
- data/.idea/kymera.iml +187 -0
- data/.idea/misc.xml +5 -0
- data/.idea/modules.xml +9 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/.idea/workspace.xml +1035 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +96 -0
- data/Rakefile +1 -0
- data/bin/kymera +63 -0
- data/kymera.gemspec +31 -0
- data/lib/kymera/broker.rb +112 -0
- data/lib/kymera/client.rb +98 -0
- data/lib/kymera/config/config.rb +36 -0
- data/lib/kymera/cucumber/cucumber_html_parser.rb +80 -0
- data/lib/kymera/cucumber/cucumber_results_parser.rb +93 -0
- data/lib/kymera/cucumber/cucumber_test_runner.rb +76 -0
- data/lib/kymera/cucumber/dry_run_formatter.rb +31 -0
- data/lib/kymera/cucumber/test_parser.rb +36 -0
- data/lib/kymera/mongo_driver.rb +39 -0
- data/lib/kymera/platform_utils.rb +64 -0
- data/lib/kymera/results_bus.rb +26 -0
- data/lib/kymera/szmq/szmq.rb +252 -0
- data/lib/kymera/test_results_collector.rb +126 -0
- data/lib/kymera/version.rb +3 -0
- data/lib/kymera/worker.rb +83 -0
- data/lib/kymera.rb +88 -0
- data/lib/spec/broker_spec.rb +25 -0
- data/lib/spec/client_spec.rb +21 -0
- data/lib/spec/client_test_run_spec.rb +3 -0
- data/lib/spec/config_options.txt +51 -0
- data/lib/spec/full_run_for_linux_spec.rb +44 -0
- data/lib/spec/full_run_spec.rb +44 -0
- data/lib/spec/get_bus_data.rb +43 -0
- data/lib/spec/html_parser_spec.rb +61 -0
- data/lib/spec/html_parsing_alg.txt +31 -0
- data/lib/spec/json_message_example.txt +6 -0
- data/lib/spec/mongo_driver_spec.rb +5 -0
- data/lib/spec/plain_broker_spec.rb +44 -0
- data/lib/spec/plain_reply_socket_spec.rb +13 -0
- data/lib/spec/plain_request_socket_spec.rb +13 -0
- data/lib/spec/result_bus_spec.rb +13 -0
- data/lib/spec/results_parser_test_run_spec.rb +18 -0
- data/lib/spec/send_bus_data.rb +16 -0
- data/lib/spec/startup_broker_bus_collector_spec.rb +35 -0
- data/lib/spec/test_file_paths_spec.rb +2 -0
- data/lib/spec/worker_spec.rb +15 -0
- data/lib/spec/worker_test_run_spec.rb +21 -0
- data/lib/spec/zmq_network_test_spec.rb +13 -0
- metadata +228 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'cucumber'
|
2
|
+
module Kymera
|
3
|
+
module Cucumber
|
4
|
+
class Runner
|
5
|
+
|
6
|
+
#This is the test runner. It is responsible for the actual running of the test. It takes in 3 parameters. The first being options(Array). These are the options to be used
|
7
|
+
#for the cucumber test run. The run_id(String), this is a unique id identifying the test run that this test is for. It is used as the channel name for publishing results
|
8
|
+
#on the results bus. And lastly results_bus(SSocket), this is a socket object representing the results bus. This is what is used for publishing results to that bus
|
9
|
+
def initialize(options, run_id, result_bus = nil)
|
10
|
+
@options = options
|
11
|
+
@result_bus = result_bus
|
12
|
+
@run_id = run_id
|
13
|
+
ENV["AUTOTEST"] = "1" if $stdout.tty?
|
14
|
+
end
|
15
|
+
|
16
|
+
#This is kicking off the test. Takes in 3 parameters, test(String) is the test to be executed. options(Array) is an array of the options to be used with this test run. By default,
|
17
|
+
#it uses the options passed in with the constructor. run_id(String) is the id of test run that this test is associated with. This is also defaulted with what was passed in
|
18
|
+
#with the constructor
|
19
|
+
def run_test(test, branch, options = @options, run_id = @run_id)
|
20
|
+
_results = ''
|
21
|
+
_options = ''
|
22
|
+
options.each do |option|
|
23
|
+
_options += " #{option}"
|
24
|
+
end
|
25
|
+
|
26
|
+
switch_to_branch(branch)
|
27
|
+
|
28
|
+
puts "Running test: #{test}"
|
29
|
+
io = Object::IO.popen("bundle exec cucumber #{test} #{_options}")
|
30
|
+
until io.eof? do
|
31
|
+
result = io.gets
|
32
|
+
unless @result_bus.nil?
|
33
|
+
@result_bus.publish_message(run_id, result)
|
34
|
+
end
|
35
|
+
_results += result
|
36
|
+
end
|
37
|
+
Process.wait2(io.pid)
|
38
|
+
_results
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
#TODO - add support for git
|
44
|
+
#The worker machines have to be setup for public/private key authentication with hg. Otherwise, this will lockup the system waiting for a password
|
45
|
+
def switch_to_branch(branch)
|
46
|
+
io = Object::IO.popen('hg branch')
|
47
|
+
current_branch = io.gets.chomp
|
48
|
+
if current_branch == branch
|
49
|
+
update_current_branch
|
50
|
+
else
|
51
|
+
output = ''
|
52
|
+
io = Object::IO.popen("hg update #{branch}")
|
53
|
+
until io.eof?
|
54
|
+
output << io.gets
|
55
|
+
end
|
56
|
+
Process.wait2(io.pid)
|
57
|
+
puts output
|
58
|
+
update_current_branch
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_current_branch
|
63
|
+
output = ''
|
64
|
+
io = Object::IO.popen("hg pull -b . -u")
|
65
|
+
until io.eof?
|
66
|
+
output << io.gets
|
67
|
+
end
|
68
|
+
Process.wait2(io.pid)
|
69
|
+
puts output
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kymera
|
2
|
+
module Cucumber
|
3
|
+
class DryRunFormatter
|
4
|
+
|
5
|
+
def initialize(step_mother, io, options)
|
6
|
+
@io = io
|
7
|
+
end
|
8
|
+
|
9
|
+
def scenario_name(*args)
|
10
|
+
#if args[0].include?("Outline")
|
11
|
+
# @scenario_name = args[2].split(':')[0]
|
12
|
+
#else
|
13
|
+
$stdout << args[2]
|
14
|
+
$stdout << "\n"
|
15
|
+
#end
|
16
|
+
end
|
17
|
+
|
18
|
+
#def before_table_row(*args)
|
19
|
+
#
|
20
|
+
# args.each do |arg|
|
21
|
+
# unless arg.line < 1 || arg.send(:header?) == true
|
22
|
+
# $stdout << "#{@scenario_name + ":" + arg.line.to_s }"
|
23
|
+
# $stdout << "\n"
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# end
|
27
|
+
#end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'dry_run_formatter'
|
2
|
+
|
3
|
+
module Kymera
|
4
|
+
|
5
|
+
module Cucumber
|
6
|
+
class TestParser
|
7
|
+
|
8
|
+
def initialize(tests, options)
|
9
|
+
@tests = tests
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_tests
|
14
|
+
tests = dry_run(["cucumber", @tests, '--dry-run -f DryRunFormatter', @options].compact.join(" ")).split("\n")
|
15
|
+
refined_tests =[]
|
16
|
+
tests.delete_at(0) if tests[0].downcase.include?('using')
|
17
|
+
tests.each do |test|
|
18
|
+
refined_tests << test.gsub('\\','/')
|
19
|
+
end
|
20
|
+
$stdout << "The number of scenarios found to be executed: #{refined_tests.count}"
|
21
|
+
$stdout << "\n"
|
22
|
+
refined_tests
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def dry_run(cmd)
|
28
|
+
$stdout << "Preprocessing test files"
|
29
|
+
$stdout << "\n"
|
30
|
+
tr = Thread.new(cmd) { |c| `#{c}`}
|
31
|
+
tr.join
|
32
|
+
tr.value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'szmq/szmq'
|
2
|
+
require 'json'
|
3
|
+
require 'mongo'
|
4
|
+
|
5
|
+
module Kymera
|
6
|
+
|
7
|
+
class MongoDriver
|
8
|
+
include Mongo
|
9
|
+
|
10
|
+
|
11
|
+
def self.log_results(log, address = "localhost", port = 27017, database = 'default_db', collection = 'default_collection')
|
12
|
+
puts "Sending results to mongodb..."
|
13
|
+
MongoDriver.new(address, port, database, collection).write_log(log)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
#This can be initialized by specifying the address and the port of the mongodb server. By default, this expects that the
|
18
|
+
#mongodb server is located on the same machine as the calling code. A collection name will also be defaulted if not passed in.
|
19
|
+
#By default, this will be 'default_db'
|
20
|
+
def initialize(address = "localhost", port = 27017, database = 'default_db', collection = 'default_db')
|
21
|
+
puts "Initializing db connection.."
|
22
|
+
@db_client = MongoClient.new(address, port).db(database)
|
23
|
+
puts "Assigning collection..."
|
24
|
+
@collection = collection
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
#The @param log needs to be a JSON string.
|
29
|
+
def write_log(log)
|
30
|
+
puts "Getting collection..."
|
31
|
+
coll = @db_client["#{@collection}"]
|
32
|
+
puts "Sending insert request.."
|
33
|
+
coll.insert(JSON.parse log)
|
34
|
+
puts "Request completed"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Kymera
|
4
|
+
|
5
|
+
def self.processor_count
|
6
|
+
@processor_count ||= case RbConfig::CONFIG['host_os']
|
7
|
+
when /darwin9/
|
8
|
+
`hwprefs cpu_count`.to_i
|
9
|
+
when /darwin/
|
10
|
+
(hwprefs_available? ? `hwprefs thread_count` : `sysctl -n hw.ncpu`).to_i
|
11
|
+
when /linux|cygwin/
|
12
|
+
`grep -c ^processor /proc/cpuinfo`.to_i
|
13
|
+
when /(net|open|free)bsd/
|
14
|
+
`sysctl -n hw.ncpu`.to_i
|
15
|
+
when /mswin|mingw/
|
16
|
+
require 'win32ole'
|
17
|
+
wmi = WIN32OLE.connect("winmgmts://")
|
18
|
+
cpu = wmi.ExecQuery("select NumberOfLogicalProcessors from Win32_Processor")
|
19
|
+
cpu.to_enum.first.NumberOfLogicalProcessors
|
20
|
+
when /solaris2/
|
21
|
+
`psrinfo -p`.to_i # this is physical cpus afaik
|
22
|
+
else
|
23
|
+
$stderr.puts "Unknown architecture ( #{RbConfig::CONFIG["host_os"]} ) assuming one processor."
|
24
|
+
1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.is_linux?
|
29
|
+
case RbConfig::CONFIG['host_os']
|
30
|
+
when /linux|darwin/
|
31
|
+
true
|
32
|
+
else
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def self.ip_address
|
40
|
+
ips = Socket.ip_address_list
|
41
|
+
ip = ''
|
42
|
+
ips.each do |i|
|
43
|
+
ip = i.ip_address if i.ipv4? && i.ip_address.start_with?("10")
|
44
|
+
end
|
45
|
+
ip
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
def self.host_name
|
51
|
+
Socket.gethostname
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.wait_for(&block)
|
55
|
+
found = false
|
56
|
+
i = 0
|
57
|
+
until i == 60 || found
|
58
|
+
found = yield
|
59
|
+
sleep 1
|
60
|
+
i +=1
|
61
|
+
end
|
62
|
+
found
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative 'szmq/szmq'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Kymera
|
5
|
+
|
6
|
+
class ResultsBus
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
config = Kymera::Config.new
|
10
|
+
@zmq = Kymera::SZMQ.new
|
11
|
+
@incoming_socket = @zmq.socket("tcp://*:#{config.result_bus["pub_port"]}", 'xsub')
|
12
|
+
@outgoing_socket = @zmq.socket("tcp://*:#{config.result_bus["sub_port"]}", 'xpub')
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_bus
|
16
|
+
puts "Results bus started..."
|
17
|
+
@zmq.start_pub_sub_proxy(@incoming_socket, @outgoing_socket)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,252 @@
|
|
1
|
+
require 'ffi-rzmq'
|
2
|
+
|
3
|
+
module Kymera
|
4
|
+
class SZMQ
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
SZMQ.context
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.context
|
12
|
+
@context ||= ZMQ::Context.new
|
13
|
+
end
|
14
|
+
|
15
|
+
#returns a SSocket object
|
16
|
+
def socket(address, type)
|
17
|
+
SSocket.new(address, type)
|
18
|
+
end
|
19
|
+
|
20
|
+
#Takes two SSocket objects. One representing the client and other representing the worker. Upon receiving a INT command (ctrl + c), the proxy still be shut down
|
21
|
+
#and the frontend and backend sockets will be closed
|
22
|
+
def start_proxy(frontend_socket, backend_socket)
|
23
|
+
|
24
|
+
trap ("INT") do
|
25
|
+
puts "\nStopping proxy..."
|
26
|
+
frontend_socket.close
|
27
|
+
backend_socket.close
|
28
|
+
@close = true
|
29
|
+
end
|
30
|
+
|
31
|
+
frontend_socket.bind
|
32
|
+
backend_socket.bind
|
33
|
+
|
34
|
+
ZMQ::Device.new(frontend_socket.send(:get_socket), backend_socket.send(:get_socket))
|
35
|
+
#ZMQ::Device.new(backend_socket.send(:get_socket), frontend_socket.send(:get_socket))
|
36
|
+
|
37
|
+
#while !@close do
|
38
|
+
# text = "\r"
|
39
|
+
# text << "Online"
|
40
|
+
# space = " "
|
41
|
+
# 0.upto(2) do
|
42
|
+
# STDOUT.print text
|
43
|
+
# sleep 0.5
|
44
|
+
# STDOUT.print "\r#{space * (text.length - 1)}"
|
45
|
+
# sleep 0.5
|
46
|
+
# end
|
47
|
+
#end
|
48
|
+
end
|
49
|
+
|
50
|
+
def start_pub_sub_proxy(front_end, back_end)
|
51
|
+
trap ("INT") do
|
52
|
+
puts "\nStopping proxy..."
|
53
|
+
front_end.close
|
54
|
+
back_end.close
|
55
|
+
@close = true
|
56
|
+
end
|
57
|
+
|
58
|
+
front_end.bind
|
59
|
+
back_end.bind
|
60
|
+
|
61
|
+
ZMQ::Device.new(front_end.send(:get_socket), back_end.send(:get_socket))
|
62
|
+
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def error_check(rc)
|
70
|
+
if ZMQ::Util.resultcode_ok?(rc)
|
71
|
+
false
|
72
|
+
else
|
73
|
+
STDERR.puts "Operation failed, [#{ZMQ::Util.errno}] description [#{ZMQ::Util.error_string}]"
|
74
|
+
caller(1).each { |callstack| STDERR.puts(callstack)}
|
75
|
+
raise SystemExit
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class SSocket
|
81
|
+
|
82
|
+
def initialize(address, type)
|
83
|
+
@socket_types = %w(request reply dealer router pub sub push pull xpub xsub)
|
84
|
+
@context = SZMQ.context
|
85
|
+
@address = address
|
86
|
+
@socket_type_string = type
|
87
|
+
@socket_type = get_socket_type(type)
|
88
|
+
if @socket_types.include?(type.downcase)
|
89
|
+
@socket = @context.socket(@socket_type)
|
90
|
+
#for some reason if the socket is a push socket the linger option is causing the message not to get sent
|
91
|
+
@socket.setsockopt(ZMQ::LINGER, 0) unless @socket_type_string == 'push'
|
92
|
+
else
|
93
|
+
raise "#{type} is not a valid socket type"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def bind(address = @address)
|
98
|
+
if address.nil?
|
99
|
+
raise "An address must be set or passed"
|
100
|
+
end
|
101
|
+
error_check(@socket.bind(address))
|
102
|
+
end
|
103
|
+
|
104
|
+
def connect(address = @address)
|
105
|
+
if address.nil?
|
106
|
+
raise "An address must be set or passed"
|
107
|
+
end
|
108
|
+
error_check(@socket.connect(address))
|
109
|
+
end
|
110
|
+
|
111
|
+
def subscribe(channels, &block)
|
112
|
+
raise "This socket is not of type SUB and cannot subscribe to a channel" unless @socket_type_string == 'sub'
|
113
|
+
if channels.is_a? String
|
114
|
+
#Debug code
|
115
|
+
#puts "Subscribing to #{channels}"
|
116
|
+
error_check(@socket.setsockopt(ZMQ::SUBSCRIBE, channels))
|
117
|
+
elsif channels.is_a? Array
|
118
|
+
channels.each do |channel|
|
119
|
+
#debug code
|
120
|
+
#puts "Subscribing to #{channel}"
|
121
|
+
error_check(@socket.setsockopt(ZMQ::SUBSCRIBE, channel))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
connect
|
125
|
+
channel = ''
|
126
|
+
message = ''
|
127
|
+
loop do
|
128
|
+
@socket.recv_string(channel)
|
129
|
+
@socket.recv_string(message)
|
130
|
+
if block_given?
|
131
|
+
yield(channel, message)
|
132
|
+
else
|
133
|
+
[channel, message]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def publish_message(channel, message)
|
139
|
+
raise 'this socket is not of type PUB and cannot publish a message' unless @socket_type_string == 'pub'
|
140
|
+
@socket.send_string(channel, ZMQ::SNDMORE)
|
141
|
+
@socket.send_string(message)
|
142
|
+
end
|
143
|
+
|
144
|
+
def close
|
145
|
+
error_check(@socket.close)
|
146
|
+
end
|
147
|
+
|
148
|
+
def send_message(message)
|
149
|
+
trap ("INT") do
|
150
|
+
puts "Received interrupt..."
|
151
|
+
@socket.close
|
152
|
+
end
|
153
|
+
if @socket_type == ZMQ::REQ
|
154
|
+
@socket.send_string(message)
|
155
|
+
reply = ''
|
156
|
+
@socket.recv_string(reply)
|
157
|
+
reply
|
158
|
+
#end
|
159
|
+
else
|
160
|
+
@socket.send_string(message)
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
#This method listens for messages coming in and then processes them will the block passed into the method. If no block is passed, messages will be received but
|
166
|
+
#will then be dropped on the floor. If the socket is of type REP and no block is given, the receive method will reply with "0" indicating that the message was received
|
167
|
+
#currently, the result of the block is sent back as a reply for REP sockets. This may change later
|
168
|
+
#TODO - Currently, the send_string method is causing the interupt to be delayed until the next message is received. need to find a way to fix this
|
169
|
+
#TODO - add support for SUB sockets
|
170
|
+
def receive(&block)
|
171
|
+
|
172
|
+
trap ("INT") do
|
173
|
+
puts "Received interrupt..."
|
174
|
+
@close = true
|
175
|
+
end
|
176
|
+
received_message = ''
|
177
|
+
|
178
|
+
if @socket_type == ZMQ::PULL
|
179
|
+
loop do
|
180
|
+
break if @close
|
181
|
+
@socket.recv_string(received_message)
|
182
|
+
if block_given?
|
183
|
+
yield(received_message)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
elsif @socket_type == ZMQ::REP
|
188
|
+
reply_message = ''
|
189
|
+
loop do
|
190
|
+
break if @close
|
191
|
+
unless @socket.recv_string(received_message) == -1
|
192
|
+
@socket.recv_string(received_message)
|
193
|
+
if block_given?
|
194
|
+
reply_message = yield(received_message)
|
195
|
+
else
|
196
|
+
reply_message = "0"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
@socket.send_string(reply_message)
|
200
|
+
end
|
201
|
+
else
|
202
|
+
raise "Socket type of #{@socket_type_string} does not receive messages"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def error_check(rc)
|
210
|
+
if ZMQ::Util.resultcode_ok?(rc)
|
211
|
+
false
|
212
|
+
else
|
213
|
+
STDERR.puts "Operation failed, [#{ZMQ::Util.errno}] description [#{ZMQ::Util.error_string}]"
|
214
|
+
caller(1).each { |callstack| STDERR.puts(callstack)}
|
215
|
+
raise SystemExit
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def get_socket
|
220
|
+
@socket
|
221
|
+
end
|
222
|
+
|
223
|
+
def get_socket_type(type)
|
224
|
+
case type
|
225
|
+
when 'request'
|
226
|
+
ZMQ::REQ
|
227
|
+
when 'reply'
|
228
|
+
ZMQ::REP
|
229
|
+
when 'dealer'
|
230
|
+
ZMQ::DEALER
|
231
|
+
when 'router'
|
232
|
+
ZMQ::ROUTER
|
233
|
+
when 'pub'
|
234
|
+
ZMQ::PUB
|
235
|
+
when 'sub'
|
236
|
+
ZMQ::SUB
|
237
|
+
when 'push'
|
238
|
+
ZMQ::PUSH
|
239
|
+
when 'pull'
|
240
|
+
ZMQ::PULL
|
241
|
+
when 'xpub'
|
242
|
+
ZMQ::XPUB
|
243
|
+
when 'xsub'
|
244
|
+
ZMQ::XSUB
|
245
|
+
else
|
246
|
+
nil
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require_relative 'szmq/szmq'
|
2
|
+
require_relative 'mongo_driver'
|
3
|
+
require 'chronic'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Kymera
|
7
|
+
|
8
|
+
class TestResultsCollector
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@config = Kymera::Config.new
|
12
|
+
@zmq = Kymera::SZMQ.new
|
13
|
+
@inc_socket = @zmq.socket("tcp://*:#{@config.result_collector["inc_listening_port"]}", 'pull')
|
14
|
+
@out_socket = @zmq.socket(@config.result_collector["result_bus_address"], 'pub')
|
15
|
+
@inc_socket.bind
|
16
|
+
@out_socket.connect
|
17
|
+
end
|
18
|
+
|
19
|
+
def listen
|
20
|
+
puts "Test collector started..."
|
21
|
+
test_count = ''
|
22
|
+
start_test_count = ''
|
23
|
+
@run_id = ''
|
24
|
+
results = ''
|
25
|
+
runner = ''
|
26
|
+
start_time = ''
|
27
|
+
count = 0
|
28
|
+
@inc_socket.receive do |message|
|
29
|
+
parsed_message = JSON.parse message
|
30
|
+
if count < 1
|
31
|
+
@run_id = parsed_message["run_id"]
|
32
|
+
test_count = parsed_message["test_count"].to_i
|
33
|
+
start_test_count = parsed_message["test_count"]
|
34
|
+
runner = parsed_message["runner"]
|
35
|
+
results << parsed_message["results"]
|
36
|
+
start_time = parsed_message["start_time"]
|
37
|
+
puts 'Results run started with the following configuration:'
|
38
|
+
puts "Run ID: #{@run_id}"
|
39
|
+
puts "Test count: #{test_count}"
|
40
|
+
test_count -= 1
|
41
|
+
count +=1
|
42
|
+
elsif test_count > 0
|
43
|
+
results << parsed_message["results"]
|
44
|
+
test_count -= 1
|
45
|
+
end
|
46
|
+
|
47
|
+
if test_count <= 0
|
48
|
+
finalize_results(start_test_count, @run_id, results, runner, start_time)
|
49
|
+
test_count = ''
|
50
|
+
@run_id = ''
|
51
|
+
results = ''
|
52
|
+
runner = ''
|
53
|
+
start_time = ''
|
54
|
+
count = 0
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def finalize_results(test_count, run_id, results, runner, start_time)
|
65
|
+
if runner.downcase == 'cucumber'
|
66
|
+
|
67
|
+
begin
|
68
|
+
#r_results = Kymera::Cucumber::ResultsParser.summarize_results(results)
|
69
|
+
puts "Summarizing results.."
|
70
|
+
r_results = Kymera::Cucumber::ResultsParser.summarize_results(results)
|
71
|
+
puts "Getting pass count..."
|
72
|
+
pass_count = Kymera::Cucumber::ResultsParser.scenario_counts[:pass]
|
73
|
+
puts "Getting fail count..."
|
74
|
+
fail_count = Kymera::Cucumber::ResultsParser.scenario_counts[:fail]
|
75
|
+
# r_results = Kymera::Cucumber::ResultsParser.summarize_results(results)
|
76
|
+
puts "Converting results to html..."
|
77
|
+
html_results = Kymera::Cucumber::HTMLResultsParser.to_html(results)
|
78
|
+
puts "Converting summary to html..."
|
79
|
+
html_summary = Kymera::Cucumber::HTMLResultsParser.to_html(r_results)
|
80
|
+
puts "Setting end time"
|
81
|
+
end_time = Time.now
|
82
|
+
# puts html_results
|
83
|
+
# Kymera::MongoDriver.log_results(build_test_log(test_count, run_id, results, r_results), '10.6.49.83', 27017, 'apollo', 'test_runs')
|
84
|
+
puts "Starting database logging processes..."
|
85
|
+
Kymera::MongoDriver.log_results(build_test_log(test_count, run_id, html_results, html_summary, start_time, end_time.to_s, pass_count, fail_count), @config.result_collector["mongodb_address"],
|
86
|
+
@config.result_collector["mongodb_port"].to_i, @config.result_collector["mongodb_database_name"], @config.result_collector["mongodb_collection_name"])
|
87
|
+
puts "Setting run id..."
|
88
|
+
rescue => e
|
89
|
+
puts "There was an error in the logging process:"
|
90
|
+
puts e
|
91
|
+
ensure
|
92
|
+
run_id = "end_#{@run_id}"
|
93
|
+
puts "Sending results to client..."
|
94
|
+
@out_socket.publish_message(run_id, r_results)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_test_log(test_count, run_id, results, summary, start_time, end_time, pass_count, fail_count)
|
100
|
+
begin
|
101
|
+
log_message = {}
|
102
|
+
log_message["run_id"] = run_id
|
103
|
+
log_message["test_count"] = test_count
|
104
|
+
log_message["results"] = results
|
105
|
+
log_message["summary"] = summary
|
106
|
+
log_message["start_time"] = start_time
|
107
|
+
log_message["end_time"] = end_time
|
108
|
+
log_message["duration"] = Chronic.parse(end_time) - Chronic.parse(start_time)
|
109
|
+
log_message["pass_count"] = pass_count
|
110
|
+
log_message["fail_count"] = fail_count
|
111
|
+
|
112
|
+
JSON.generate log_message
|
113
|
+
rescue => e
|
114
|
+
puts e
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
end
|