liri 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,115 @@
1
+ # = tests_result.rb
2
+ #
3
+ # @author Rodrigo Fernández
4
+ #
5
+ # == Clase TestsResult
6
+
7
+ module Liri
8
+ module Common
9
+ # Esta clase se encarga de guardar y procesar el archivo de resultados
10
+ class TestsResult
11
+ def initialize(folder_path)
12
+ @folder_path = folder_path
13
+ @example_quantity = 0
14
+ @failure_quantity = 0
15
+ @passed_quantity = 0
16
+ @failures = ''
17
+ end
18
+
19
+ def save(file_name, raw_tests_result)
20
+ file_path = File.join(@folder_path, '/', file_name)
21
+ File.write(file_path, raw_tests_result)
22
+ file_path
23
+ end
24
+
25
+ def build_file_name(agent_ip_address, tests_batch_number)
26
+ "batch_#{tests_batch_number}_agent_#{agent_ip_address}_tests_results"
27
+ end
28
+
29
+ # Procesa el resultado crudo de las pruebas unitarias y lo devuelve en formato hash manejable
30
+ # Ejemplo del hash retornado:
31
+ # {example_quantity: 2, failure_quantity: 1}
32
+ def process(tests_result_file_name)
33
+ file_path = File.join(@folder_path, '/', tests_result_file_name)
34
+ result_hash = process_tests_result_file(file_path)
35
+ update_partial_result(result_hash)
36
+ #print_partial_result(result_hash)
37
+ result_hash
38
+ end
39
+
40
+ def print_summary
41
+ puts "\n#{@example_quantity} examples, #{@failure_quantity} failures\n"
42
+ end
43
+
44
+ def print_failures
45
+ puts "\nFailures: " if !@failures.empty?
46
+ puts @failures
47
+ end
48
+
49
+ private
50
+
51
+ # Recibe el resultado crudo de las pruebas unitarias
52
+ # Procesa el archivo con los resultados crudos y lo devuelve en formato hash manejable
53
+ # Ejemplo del hash retornado:
54
+ # {result: '.F', failures: '', example_quantity: 2, failure_quantity: 1, failed_examples: ''}
55
+ def process_tests_result_file(file_path)
56
+ result_hash = {failures: '', example_quantity: 0, failure_quantity: 0, passed_quantity: 0, failed_examples: ''}
57
+ flag = ''
58
+ File.foreach(file_path) do |line|
59
+ if flag == '' && line.strip.start_with?('Randomized')
60
+ flag = 'Randomized'
61
+ next
62
+ end
63
+
64
+ if ['Randomized', ''].include?(flag) && line.strip.start_with?('Failures')
65
+ flag = 'Failures'
66
+ next
67
+ end
68
+
69
+ if ['Randomized', 'Failures', ''].include?(flag) && line.strip.start_with?('Finished')
70
+ flag = 'Finished'
71
+ next
72
+ end
73
+
74
+ if ['Finished', ''].include?(flag) && line.strip.start_with?('Failed')
75
+ flag = 'Failed'
76
+ next
77
+ end
78
+
79
+ case flag
80
+ when 'Failures'
81
+ result_hash[:failures] << line
82
+ when 'Finished'
83
+ values = line.to_s.match(/([\d]+) example.?, ([\d]+) failure.?/)
84
+ result_hash[:example_quantity] = values[1].to_i
85
+ result_hash[:failure_quantity] = values[2].to_i
86
+ result_hash[:passed_quantity] = result_hash[:example_quantity] - result_hash[:failure_quantity]
87
+ flag = ''
88
+ when 'Failed'
89
+ result_hash[:failed_examples] << line
90
+ end
91
+ end
92
+
93
+ result_hash
94
+ end
95
+
96
+ def update_partial_result(hash_result)
97
+ @example_quantity += hash_result[:example_quantity]
98
+ @failure_quantity += hash_result[:failure_quantity]
99
+ @passed_quantity += hash_result[:passed_quantity]
100
+ @failures << hash_result[:failures]
101
+ end
102
+
103
+ def print_partial_result(result_hash)
104
+ result_hash[:passed_quantity].times do
105
+ print '.'
106
+ end
107
+
108
+ result_hash[:failure_quantity].times do
109
+ print 'F'
110
+ end
111
+ end
112
+
113
+ end
114
+ end
115
+ end
@@ -16,7 +16,10 @@ module Liri
16
16
  tests_hash = {}
17
17
  test_files.each do |test_file|
18
18
  File.open(test_file) do |file|
19
+ @inside_comment = false
19
20
  file.each_with_index do |line, index|
21
+ next if line_inside_comment_block(line)
22
+
20
23
  if line.strip.start_with?('it')
21
24
  absolute_file_path = file.to_path
22
25
  relative_file_path = absolute_file_path.sub(@source_code_folder_path + '/', '')
@@ -50,40 +53,29 @@ module Liri
50
53
  raw_tests_result = %x|bash -lc 'rvm use #{Liri.current_folder_ruby_and_gemset}; rspec #{tests.join(' ')} --format progress'|
51
54
  end
52
55
 
53
- hash_tests_result = process_tests_result(raw_tests_result)
54
- hash_tests_result
56
+ return raw_tests_result
55
57
  end
56
58
  end
57
59
 
58
60
  private
61
+
59
62
  def test_files
60
63
  Dir[@tests_folder_path + "/**/*spec.rb"]
61
64
  end
62
65
 
63
- # Recibe el resultado crudo de las pruebas unitarias
64
- # Procesa el resultado y lo devuelve en formato hash manejable
65
- # Ejemplo del hash retornado:
66
- # {example_quantity: 2, failure_quantity: 1}
67
- def process_tests_result(raw_test_results)
68
- result_hash = {example_quantity: 0, failure_quantity: 0}
69
- flag = ''
70
- raw_test_results.each_line do |line|
71
- if line.strip.start_with?('Finished')
72
- flag = 'Finished'
73
- next
74
- end
66
+ # Revisa si la línea se encuentra dentro de un bloque comentado
67
+ def line_inside_comment_block(line)
68
+ if line.strip.start_with?('=begin')
69
+ @inside_comment = true
70
+ return true
71
+ end
75
72
 
76
- if flag == 'Finished'
77
- puts ''
78
- Liri.logger.info(line)
79
- values = line.to_s.match(/([\d]+) example.?, ([\d]+) failure.?/)
80
- result_hash[:example_quantity] = values[1].to_i
81
- result_hash[:failure_quantity] = values[2].to_i
82
- flag = ''
83
- end
73
+ if line.strip.start_with?('=end')
74
+ @inside_comment = false
75
+ return false
84
76
  end
85
77
 
86
- result_hash
78
+ return true if @inside_comment
87
79
  end
88
80
  end
89
81
  end
data/lib/liri.rb CHANGED
@@ -3,20 +3,16 @@
3
3
  # Este modulo contiene datos del programa que son reutilizados en otras partes de la aplicacion
4
4
  module Liri
5
5
  NAME = 'liri' # El gemspec requiere que el nombre este en minusculas
6
- VERSION = '0.1.0'
7
- SETUP_FOLDER_NAME = 'liri'
8
- SETUP_FOLDER_PATH = File.join(Dir.pwd, '/', SETUP_FOLDER_NAME)
9
- LOGS_FOLDER_NAME = 'logs'
10
- MANAGER_LOGS_FOLDER_PATH = File.join(SETUP_FOLDER_PATH, '/', LOGS_FOLDER_NAME)
11
- AGENT_LOGS_FOLDER_PATH = MANAGER_LOGS_FOLDER_PATH
12
- AGENT_FOLDER_NAME = 'agent'
13
- AGENT_FOLDER_PATH = File.join(SETUP_FOLDER_PATH, '/', AGENT_FOLDER_NAME)
14
- MANAGER_FOLDER_NAME = 'manager'
15
- MANAGER_FOLDER_PATH = File.join(SETUP_FOLDER_PATH, '/', MANAGER_FOLDER_NAME)
6
+ VERSION = '0.2.0'
16
7
 
17
8
  class << self
9
+ def set_setup(destination_folder_path)
10
+ load_setup_manager(destination_folder_path)
11
+ end
12
+
13
+ # Carga las configuraciones en memoria desde un archivo de configuracion
18
14
  def setup
19
- @setup ||= load_setup
15
+ @setup
20
16
  end
21
17
 
22
18
  def logger
@@ -36,30 +32,16 @@ module Liri
36
32
  end
37
33
  end
38
34
 
39
- def create_folders(program)
40
- Dir.mkdir(SETUP_FOLDER_PATH) unless Dir.exist?(SETUP_FOLDER_PATH)
41
-
42
- case program
43
- when 'manager'
44
- Dir.mkdir(MANAGER_LOGS_FOLDER_PATH) unless Dir.exist?(MANAGER_LOGS_FOLDER_PATH)
45
- Dir.mkdir(MANAGER_FOLDER_PATH) unless Dir.exist?(MANAGER_FOLDER_PATH)
46
- when 'agent'
47
- Dir.mkdir(AGENT_FOLDER_PATH) unless Dir.exist?(AGENT_FOLDER_PATH)
48
- Dir.mkdir(AGENT_LOGS_FOLDER_PATH) unless Dir.exist?(AGENT_LOGS_FOLDER_PATH)
49
- end
50
- end
51
-
52
- def clean_folder(folder_path)
35
+ def clean_folder_content(folder_path)
53
36
  FileUtils.rm_rf(Dir.glob(folder_path + '/*')) if Dir.exist?(folder_path)
54
37
  end
55
38
 
56
39
  def reload_setup
57
- @setup = load_setup
40
+ @setup = (@setup_manager ? @setup_manager.load : nil)
58
41
  end
59
42
 
60
43
  def delete_setup
61
- liri_setup = Liri::Manager::Setup.new(SETUP_FOLDER_PATH)
62
- liri_setup.delete
44
+ @setup_manager ? @setup_manager.delete_setup_folder : false
63
45
  end
64
46
 
65
47
  def init_exit(stop, threads, program)
@@ -75,7 +57,7 @@ module Liri
75
57
  end
76
58
 
77
59
  def kill(threads)
78
- threads.each{|thread| Thread.kill(thread)}
60
+ threads.each{ |thread| Thread.kill(thread) }
79
61
  end
80
62
 
81
63
  def current_host_ip_address
@@ -99,22 +81,27 @@ module Liri
99
81
  setup.ports.tcp
100
82
  end
101
83
 
84
+ def print_failures
85
+ setup.print_failures
86
+ end
87
+
102
88
  def current_folder_ruby_and_gemset
103
89
  "#{File.read('.ruby-version').strip}@#{File.read('.ruby-gemset').strip}"
104
90
  end
105
91
 
106
92
  private
107
93
 
108
- # Carga las configuraciones en memoria desde un archivo de configuracion
109
- def load_setup
110
- liri_setup = Liri::Manager::Setup.new(SETUP_FOLDER_PATH)
111
- liri_setup.create unless File.exist?(liri_setup.path)
112
- liri_setup.load
94
+ # Inicializa el objeto que gestiona las configuraciones
95
+ def load_setup_manager(destination_folder_path)
96
+ @setup_manager = Liri::Common::Setup.new(destination_folder_path)
97
+ @setup_manager.init
98
+ @setup = @setup_manager.load
99
+ @setup_manager
113
100
  end
114
101
 
115
102
  # Inicializa y configura la librería encargada de loguear
116
103
  def load_logger(folder_path = nil, file_name = nil)
117
- log = Liri::Common::Log.new('daily', folder_path: folder_path, file_name: file_name, stdout: Liri.setup.log.stdout.show)
104
+ log = Liri::Common::Log.new('daily', folder_path: folder_path, file_name: file_name, stdout: setup.log.stdout.show)
118
105
  log
119
106
  end
120
107
  end
@@ -1,7 +1,11 @@
1
1
  =begin
2
2
  Este modulo es el punto de entrada del programa principal
3
3
  =end
4
+
5
+ # TODO Para trabajar con hilos y concurrencia recomiendan usar parallel, workers, concurrent-ruby. Fuente: https://www.rubyguides.com/2015/07/ruby-threads/
6
+
4
7
  require 'all_libraries'
8
+ require 'terminal-table'
5
9
 
6
10
  module Liri
7
11
  class Manager
@@ -11,29 +15,27 @@ module Liri
11
15
  class << self
12
16
  # Inicia la ejecución del Manager
13
17
  # @param stop [Boolean] el valor true es para que no se ejecute infinitamente el método en el test unitario.
14
- def run(stop = false)
18
+ def run(source_code_folder_path, stop = false)
15
19
  return unless valid_project
16
- Liri.create_folders('manager')
17
-
18
- Liri.set_logger(Liri::MANAGER_LOGS_FOLDER_PATH, 'liri-manager.log')
19
- Liri.logger.info("Proceso Manager iniciado")
20
- puts "Presione Ctrl + c para terminar el proceso Manager manualmente\n\n"
21
20
 
22
- user, password = get_credentials
21
+ setup_manager = Liri.set_setup(source_code_folder_path)
22
+ manager_folder_path = setup_manager.manager_folder_path
23
23
 
24
- source_code = compress_source_code
25
-
26
- manager_data = manager_data(user, password, source_code)
24
+ Liri.set_logger(setup_manager.logs_folder_path, 'liri-manager.log')
25
+ Liri.logger.info("Proceso Manager iniciado")
26
+ Liri.logger.info("Presione Ctrl + c para terminar el proceso Manager manualmente\n", true)
27
27
 
28
+ user, password = get_credentials(setup_manager.setup_folder_path)
29
+ source_code = compress_source_code(source_code_folder_path, manager_folder_path)
30
+ manager_data = get_manager_data(user, password, manager_folder_path, source_code)
28
31
  all_tests = get_all_tests(source_code)
32
+ tests_result = Common::TestsResult.new(manager_folder_path)
29
33
 
30
- test_result = Liri::Manager::TestResult.new
31
-
32
- manager = Manager.new(Liri.udp_port, Liri.tcp_port, all_tests, test_result)
34
+ manager = Manager.new(Liri.udp_port, Liri.tcp_port, all_tests, tests_result, manager_folder_path)
33
35
 
34
36
  threads = []
35
37
  threads << manager.start_client_socket_to_search_agents(manager_data) # Enviar peticiones broadcast a toda la red para encontrar Agents
36
- manager.start_server_socket_to_process_tests(threads[0]) # Esperar y enviar los test unitarios a los Agents
38
+ manager.start_server_socket_to_process_tests(threads[0]) unless stop # Esperar y enviar los test unitarios a los Agents
37
39
 
38
40
  Liri.init_exit(stop, threads, 'Manager')
39
41
  Liri.logger.info("Proceso Manager terminado")
@@ -58,44 +60,44 @@ module Liri
58
60
  end
59
61
  end
60
62
 
61
- def compressed_file_folder_path
62
- File.join(Liri::Common.setup_folder_path, '/manager')
63
- end
64
-
65
- def decompressed_file_folder_path
66
- compressed_file_folder_path
67
- end
68
-
69
- def get_credentials
70
- credential = Liri::Manager::Credential.new(Liri::SETUP_FOLDER_PATH)
63
+ def get_credentials(setup_folder_path)
64
+ credential = Liri::Manager::Credential.new(setup_folder_path)
71
65
  credential.get
72
66
  end
73
67
 
74
- def compress_source_code
75
- source_code = Liri::Common::SourceCode.new(Liri::MANAGER_FOLDER_PATH, Liri.compression_class, Liri.unit_test_class)
76
- Liri::Common::Benchmarking.start(start_msg: "Comprimiendo código fuente. Espere... ") do
68
+ def compress_source_code(source_code_folder_path, manager_folder_path)
69
+ source_code = Common::SourceCode.new(source_code_folder_path, manager_folder_path, Liri.compression_class, Liri.unit_test_class)
70
+
71
+ Common::Progressbar.start(total: nil, length: 100, format: 'Comprimiendo Código Fuente |%B| %a') do
77
72
  source_code.compress_folder
78
73
  end
79
- puts ''
74
+ puts "\n\n"
75
+
80
76
  source_code
81
77
  end
82
78
 
83
- def manager_data(user, password, source_code)
84
- # puts "User: #{user} Password: #{password}"
85
- [user, password, source_code.compressed_file_path].join(';')
79
+ def get_manager_data(user, password, manager_folder_path, source_code)
80
+ Common::ManagerData.new(
81
+ folder_path: manager_folder_path,
82
+ compressed_file_path: source_code.compressed_file_path,
83
+ user: user,
84
+ password: password
85
+ )
86
86
  end
87
87
 
88
88
  def get_all_tests(source_code)
89
89
  all_tests = {}
90
- Liri::Common::Benchmarking.start(start_msg: "Obteniendo conjunto de pruebas. Espere... ") do
90
+
91
+ Common::Progressbar.start(total: nil, length: 100, format: 'Extrayendo Pruebas Unitarias |%B| %a') do
91
92
  all_tests = source_code.all_tests
92
93
  end
93
- puts ''
94
+ puts "\n\n"
95
+
94
96
  all_tests
95
97
  end
96
98
  end
97
99
 
98
- def initialize(udp_port, tcp_port, all_tests, test_result)
100
+ def initialize(udp_port, tcp_port, all_tests, tests_result, manager_folder_path)
99
101
  @udp_port = udp_port
100
102
  @udp_socket = UDPSocket.new
101
103
  @tcp_port = tcp_port
@@ -110,22 +112,29 @@ module Liri
110
112
  @agents_search_processing_enabled = true
111
113
  @test_processing_enabled = true
112
114
 
113
- @test_result = test_result
115
+ @tests_batch_number = 0
116
+ @tests_batches = {}
117
+
118
+ @tests_result = tests_result
114
119
  @semaphore = Mutex.new
120
+
121
+ @manager_folder_path = manager_folder_path
122
+
123
+ @progressbar = ProgressBar.create(starting_at: 0, total: @all_tests_count, length: 100, format: 'Progress %c/%C |%b=%i| %p%% | %a')
115
124
  end
116
125
 
117
126
  # Inicia un cliente udp que hace un broadcast en toda la red para iniciar una conexión con los Agent que estén escuchando
118
- def start_client_socket_to_search_agents(user_data)
127
+ def start_client_socket_to_search_agents(manager_data)
119
128
  # El cliente udp se ejecuta en bucle dentro de un hilo, esto permite realizar otras tareas mientras este hilo sigue sondeando
120
129
  # la red para obtener mas Agents. Una vez que los tests terminan de ejecutarse, este hilo será finalizado.
121
130
  Thread.new do
122
- puts "\nBuscando Agentes... Espere"
131
+ Liri.logger.info("Buscando Agentes... Espere")
123
132
  Liri.logger.info("Se emite un broadcast cada #{UDP_REQUEST_DELAY} segundos en el puerto UDP: #{@udp_port}
124
133
  (Se mantiene escaneando la red para encontrar Agents)
125
134
  ")
126
- while @agents_search_processing_enabled
135
+ while agents_search_processing_enabled
127
136
  @udp_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
128
- @udp_socket.send(user_data, 0, '<broadcast>', @udp_port)
137
+ @udp_socket.send(manager_data.to_h.to_json, 0, '<broadcast>', @udp_port)
129
138
  sleep(UDP_REQUEST_DELAY) # Se pausa un momento antes de efectuar nuevamente la petición broadcast
130
139
  end
131
140
  end
@@ -146,12 +155,18 @@ module Liri
146
155
  ")
147
156
  # El siguiente bucle permite que varios clientes es decir Agents se conecten
148
157
  # De: http://www.w3big.com/es/ruby/ruby-socket-programming.html
149
- while @test_processing_enabled
158
+ while test_processing_enabled
150
159
  Thread.start(tcp_socket.accept) do |client|
151
160
  agent_ip_address = client.remote_address.ip_address
152
161
  response = client.recvfrom(1000).first
153
162
 
154
- if @all_tests.empty?
163
+ Liri.logger.info("\nConexión iniciada con el Agente: #{agent_ip_address}")
164
+ Liri.logger.info("Respuesta al broadcast recibida del Agent: #{agent_ip_address} en el puerto TCP: #{@tcp_port}: #{response}")
165
+
166
+ # Se le indica al agente que proceda
167
+ client.puts({ msg: 'Recibido', exist_tests: all_tests.any? }.to_json)
168
+
169
+ if all_tests.empty?
155
170
  # No importa lo que le haga, el broadcast udp no se muere al instante y el agente sigue respondiendo
156
171
  # Las siguientes dos lineas son para que se deje de hacer el broadcast pero aun asi se llegan a hacer
157
172
  # 3 a 4 broadcast antes de que se finalize el proceso, al parecer el broadcast va a tener que quedar asi
@@ -159,49 +174,42 @@ module Liri
159
174
  # tests enviados sin resultados, tests finalizados, si se recibe respuesta al broadcast se trata de enviar primero test pendientes
160
175
  # luego test enviados sin resultados o sino ignorar
161
176
  Thread.kill(search_agents_thread)
162
- @agents_search_processing_enabled = false
163
- Liri.logger.info("Se termina cualquier proceso pendiente con el Agent #{agent_ip_address}")
164
- Liri.logger.info(response)
177
+ agents_search_processing_enabled = false
178
+ Liri.logger.info("Se termina cualquier proceso pendiente con el Agent #{agent_ip_address} en el puerto TCP: #{@tcp_port}: #{response}")
165
179
  client.close
166
180
  Thread.exit
167
181
  end
168
182
 
169
- puts "\nConexión iniciada con el Agente: #{agent_ip_address}"
170
- Liri.logger.info("Respuesta al broadcast recibida del Agent: #{agent_ip_address} en el puerto TCP: #{@tcp_port}
171
- => Agent #{agent_ip_address}: #{response}
172
- ")
173
-
174
- while @all_tests.any?
175
- tests = samples
176
- break if tests.empty?
177
- begin
178
- client.puts(tests.to_json) # Este envía un hash bastante grande al cliente y siempre llega, pero la respuesta del cliente a veces no llega todo, porque?
179
- response = client.recvfrom(1000).first
180
- rescue Errno::EPIPE => e
181
- # Esto al parecer se da cuando el Agent ya cerró las conexiones y el Manager intenta contactar
182
- Liri.logger.error("Exception(#{e}) El Agent #{agent_ip_address} ya terminó la conexión")
183
- # Si el Agente ya no responde es mejor romper el bucle para que no quede colgado
184
- break
183
+ while all_tests.any?
184
+ time_in_seconds = Liri::Common::Benchmarking.start(start_msg: "Proceso de Ejecución de pruebas. Agent: #{agent_ip_address}. Espere... ", end_msg: "Proceso de Ejecución de pruebas. Agent: #{agent_ip_address}. Duración: ", stdout: false) do
185
+ tests_batch = tests_batch(agent_ip_address)
186
+ break unless tests_batch
187
+
188
+ begin
189
+ Liri.logger.debug("Conjunto de pruebas enviadas al Agent #{agent_ip_address}: #{tests_batch}")
190
+
191
+ client.puts(tests_batch.to_json) # Se envia el lote de tests
192
+ response = client.recvfrom(1000).first # Se recibe la respuesta. Cuando mas alto es el parámetro de recvfrom, mas datos se reciben osino se truncan.
193
+ rescue Errno::EPIPE => e
194
+ # Esto al parecer se da cuando el Agent ya cerró las conexiones y el Manager intenta contactar
195
+ Liri.logger.error("Exception(#{e}) El Agent #{agent_ip_address} ya terminó la conexión")
196
+ # Si el Agente ya no responde es mejor romper el bucle para que no quede colgado
197
+ break
198
+ end
185
199
  end
186
- # TODO A veces se tiene un error de parseo JSON, de ser asi los resultados no pueden procesarse,
187
- # hay que arreglar esto, mientras, se captura el error para que no falle
200
+
201
+ # Se captura por si acaso los errores de parseo JSON
188
202
  begin
189
- tests_result = response
190
- Liri.logger.debug("Resultados de la ejecución de las pruebas recibidas del Agent #{agent_ip_address}:")
191
- Liri.logger.debug("RAW:")
192
- Liri.logger.debug(tests_result)
193
- json_tests_result = JSON.parse(tests_result)
194
- Liri.logger.debug("JSON:")
195
- Liri.logger.debug(json_tests_result)
196
- process_tests_result(tests, json_tests_result)
203
+ tests_result = JSON.parse(response)
204
+ Liri.logger.debug("Respuesta del Agent #{agent_ip_address}: #{tests_result}")
205
+ process_tests_result(agent_ip_address, tests_result, time_in_seconds)
197
206
  rescue JSON::ParserError => e
198
207
  Liri.logger.error("Exception(#{e}) Error de parseo JSON")
199
208
  end
200
209
  end
201
210
 
202
211
  update_processing_statuses
203
- puts ''
204
- Liri.logger.info("Se termina la conexión con el Agent #{agent_ip_address}")
212
+ Liri.logger.info("Se termina la conexión con el Agent #{agent_ip_address} en el puerto TCP: #{@tcp_port}")
205
213
  begin
206
214
  client.puts('exit') # Se envía el string exit para que el Agent sepa que el proceso terminó
207
215
  client.close # se desconecta el cliente
@@ -215,44 +223,101 @@ module Liri
215
223
  end
216
224
  end
217
225
 
218
- Liri.clean_folder(Liri::MANAGER_FOLDER_PATH)
219
- @test_result.print_summary
226
+ Liri.clean_folder_content(@manager_folder_path)
227
+ @tests_result.print_summary
228
+ print_agents_summary
229
+ @tests_result.print_failures if Liri.print_failures
230
+ end
231
+
232
+ def all_tests
233
+ @semaphore.synchronize do
234
+ @all_tests
235
+ end
236
+ end
237
+
238
+ def agents_search_processing_enabled=(value)
239
+ @semaphore.synchronize do
240
+ @agents_search_processing_enabled = value
241
+ end
242
+ end
243
+
244
+ def agents_search_processing_enabled
245
+ @semaphore.synchronize do
246
+ @agents_search_processing_enabled
247
+ end
248
+ end
249
+
250
+ def test_processing_enabled
251
+ @semaphore.synchronize do
252
+ @test_processing_enabled
253
+ end
220
254
  end
221
255
 
222
256
  def update_processing_statuses
223
- @semaphore.synchronize {
257
+ @semaphore.synchronize do
224
258
  @test_processing_enabled = false if @all_tests_count == @all_tests_results_count
225
259
  @agents_search_processing_enabled = false if @all_tests_count == @all_tests_processing_count
226
- }
260
+ end
227
261
  end
228
262
 
229
- def update_all_tests_results_count(new_count)
230
- @all_tests_results_count += new_count
231
- end
263
+ def tests_batch(agent_ip_address)
264
+ # Se inicia un semáforo para evitar que varios hilos actualicen variables compartidas
265
+ @semaphore.synchronize do
266
+ return nil if @all_tests.empty?
232
267
 
233
- def update_all_tests_processing_count(new_count)
234
- @all_tests_processing_count += new_count
268
+ @tests_batch_number += 1 # Se numera cada lote
269
+ samples = @all_tests.sample!(Manager.test_samples_by_runner) # Se obtiene algunos tests
270
+ samples_keys = samples.keys # Se obtiene la clave asignada a los tests
271
+ @all_tests_processing_count += samples_keys.size
272
+
273
+ @agents[agent_ip_address] = { agent_ip_address: agent_ip_address, tests_processed_count: 0, examples: 0, failures: 0, time_in_seconds: 0, duration: '' } unless @agents[agent_ip_address]
274
+
275
+ #@tests_batches[@tests_batch_number] = { agent_ip_address: agent_ip_address, tests_batch_keys: samples_keys } # Se guarda el lote a enviar
276
+ tests_batch = { tests_batch_number: @tests_batch_number, tests_batch_keys: samples_keys } # Se construye el lote a enviar
277
+ tests_batch
278
+ end
235
279
  end
236
280
 
237
- def samples
238
- _samples = nil
239
- # Varios hilos no deben acceder simultaneamente al siguiente bloque porque actualiza variables compartidas
240
- @semaphore.synchronize {
241
- _samples = @all_tests.sample!(Manager.test_samples_by_runner)
242
- puts ''
243
- Liri.logger.info("Cantidad de pruebas pendientes: #{@all_tests.size}")
244
- update_all_tests_processing_count(_samples.size)
245
- }
246
- _samples
281
+ def process_tests_result(agent_ip_address, tests_result, time_in_seconds)
282
+ # Se inicia un semáforo para evitar que varios hilos actualicen variables compartidas
283
+ @semaphore.synchronize do
284
+ tests_batch_number = tests_result['tests_batch_number']
285
+ tests_result_file_name = tests_result['tests_result_file_name']
286
+ tests_batch_keys_size = tests_result['tests_batch_keys_size']
287
+
288
+ #tests_batch_keys = @tests_batches[tests_batch_number][:tests_batch_keys]
289
+ tests_processed_count = tests_batch_keys_size
290
+ @all_tests_results_count += tests_processed_count
291
+
292
+ @progressbar.progress = @all_tests_results_count
293
+
294
+ #@tests_batches[tests_batch_number][:tests_result_file_name] = tests_result_file_name
295
+
296
+ tests_result = @tests_result.process(tests_result_file_name)
297
+
298
+ @agents[agent_ip_address][:tests_processed_count] += tests_processed_count
299
+ @agents[agent_ip_address][:examples] += tests_result[:example_quantity]
300
+ @agents[agent_ip_address][:failures] += tests_result[:failure_quantity]
301
+ @agents[agent_ip_address][:time_in_seconds] += time_in_seconds
302
+ @agents[agent_ip_address][:duration] = @agents[agent_ip_address][:time_in_seconds].to_duration
303
+
304
+ Liri.logger.info("Pruebas procesadas por Agente: #{agent_ip_address}: #{@agents[agent_ip_address][:tests_processed_count]}")
305
+ end
247
306
  end
248
307
 
249
- def process_tests_result(tests, tests_result)
250
- # Varios hilos no deben acceder simultaneamente al siguiente bloque porque actualiza variables compartidas
251
- @semaphore.synchronize {
252
- update_all_tests_results_count(tests.size)
253
- @test_result.print_process(tests_result)
254
- @test_result.update(tests_result)
255
- }
308
+ def print_agents_summary
309
+ rows = @agents.values.map { |line| line.values }
310
+ headings = @agents.values.first.keys
311
+
312
+ table = Terminal::Table.new title: "Resúmen", headings: headings, rows: rows
313
+ table.style = {padding_left: 3, border_x: "=", border_i: "x" }
314
+ table.align_column(1, :right)
315
+ table.align_column(2, :right)
316
+ table.align_column(3, :right)
317
+ table.align_column(4, :right)
318
+ table.align_column(5, :right)
319
+
320
+ puts table
256
321
  end
257
322
  end
258
323
  end
data/lib/task.rb CHANGED
@@ -5,8 +5,8 @@
5
5
  module Liri
6
6
  module Task
7
7
  class << self
8
- def tests_count
9
- source_code = Liri::Common::SourceCode.new('', Liri.compression_class, Liri.unit_test_class)
8
+ def tests_count(source_code_folder_path)
9
+ source_code = Liri::Common::SourceCode.new(source_code_folder_path,'', Liri.compression_class, Liri.unit_test_class)
10
10
  source_code.all_tests.size
11
11
  end
12
12
  end