liri 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,8 +19,8 @@ module Liri
19
19
  manager_folder_path = setup_manager.manager_folder_path
20
20
  manager_tests_results_folder_path = setup_manager.manager_tests_results_folder_path
21
21
 
22
- Liri.set_logger(setup_manager.logs_folder_path, 'liri-manager.log')
23
- Liri.logger.info('Manager process started')
22
+ Liri.set_logger(setup_manager.logs_folder_path, 'lirimanager.log')
23
+ Liri.logger.info('Manager process started', true)
24
24
  Liri.logger.info("Press Ctrl + c to finish Manager process manually\n", true)
25
25
 
26
26
  user, password = get_credentials(setup_manager.setup_folder_path)
@@ -33,19 +33,68 @@ module Liri
33
33
 
34
34
  threads = []
35
35
  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]) unless stop # Esperar y enviar los test unitarios a los Agents
36
+ unless stop
37
+ # Esperar y enviar los test unitarios a los Agents
38
+ manager.start_server_socket_to_process_tests(threads[0])
39
+ end
37
40
 
38
- source_code.delete_compressed_file
41
+ Liri.init_exit(stop, threads)
42
+ rescue SignalException
43
+ # Liri.logger.info("\nManager process finished manually", true)
44
+ ensure
45
+ # Siempre se ejecutan estos comandos, haya o no excepción
46
+ Liri.kill(threads) if threads&.any?
47
+ manager&.print_results
48
+ source_code&.delete_compressed_file
49
+ Liri.logger.info("Manager process finished", true)
50
+ end
39
51
 
40
- Liri.init_exit(stop, threads, 'Manager')
41
- Liri.logger.info('Manager process finished')
42
- rescue SignalException => e
43
- Liri.logger.info("Exception(#{e}) Proceso Manager process finished manually")
44
- Liri.kill(threads)
52
+ def udp_request_delay
53
+ Liri.setup.manager.udp_request_delay
45
54
  end
46
55
 
47
56
  def test_files_by_runner
48
- Liri.setup.test_files_by_runner
57
+ Liri.setup.manager.test_files_by_runner
58
+ end
59
+
60
+ def show_share_source_code_progress_bar
61
+ Liri.setup.manager.bar.share_source_code
62
+ end
63
+
64
+ def print_summary_table
65
+ Liri.setup.manager.print.table.summary
66
+ end
67
+
68
+ def print_detailed_table
69
+ Liri.setup.manager.print.table.detailed
70
+ end
71
+
72
+ def print_summary_failures
73
+ Liri.setup.manager.print.failures.summary
74
+ end
75
+
76
+ def print_detailed_failures
77
+ Liri.setup.manager.print.failures.detailed
78
+ end
79
+
80
+ def show_failed_files_column
81
+ Liri.setup.manager.print.column.failed_files
82
+ end
83
+
84
+ def show_files_load_column
85
+ Liri.setup.manager.print.column.files_load
86
+ end
87
+
88
+ def show_finish_in_column
89
+ Liri.setup.manager.print.column.finish_in
90
+ end
91
+
92
+ def show_batch_run_column
93
+ Liri.setup.manager.print.column.batch_run
94
+ end
95
+
96
+ def show_share_source_code_column
97
+ Liri.setup.manager.print.column.share_source_code
49
98
  end
50
99
 
51
100
  private
@@ -66,14 +115,19 @@ module Liri
66
115
  end
67
116
 
68
117
  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: 'Compressing source code |%B| %a') do
118
+ source_code = Common::SourceCode.new(source_code_folder_path, manager_folder_path, Liri.ignored_folders_in_compress, Liri.compression_class, Liri.unit_test_class)
119
+ #Common::Progressbar.start(total: nil, length: 120, format: 'Compressing source code |%B| %a') do
120
+ Common::TtyProgressbar.start("Compressing source code |:bar| :percent | Time: :time", total: nil, width: 80, bar_format: :box) do
72
121
  source_code.compress_folder
73
122
  end
74
- puts "\n\n"
75
-
123
+ puts "\n"
124
+ Liri.logger.info("Batch Files: #{test_files_by_runner}", true)
125
+ puts "\n"
76
126
  source_code
127
+ rescue SignalException => e
128
+ # Se captura la excepción sólo para imprimir espacios despues de la barra de progreso
129
+ puts "\n\n"
130
+ raise e
77
131
  end
78
132
 
79
133
  def get_manager_data(user, password, tests_results_folder_path, source_code)
@@ -88,12 +142,17 @@ module Liri
88
142
  def get_all_tests(source_code)
89
143
  all_tests = {}
90
144
 
91
- Common::Progressbar.start(total: nil, length: 100, format: 'Getting unit tests |%B| %a') do
145
+ #Common::TtyProgressbar.start("Getting unit tests |:bar| Time::elapsed", total: nil, width: 100) do
146
+ #Common::Progressbar.start(total: nil, length: 120, format: 'Getting unit tests |%B| %a') do
92
147
  all_tests = source_code.all_tests
93
- end
94
- puts "\n\n"
148
+ #end
149
+ #puts "\n\n"
95
150
 
96
151
  all_tests
152
+ rescue SignalException => e
153
+ # Se captura la excepción sólo para imprimir espacios despues de la barra de progreso
154
+ puts "\n\n"
155
+ raise e
97
156
  end
98
157
  end
99
158
 
@@ -102,23 +161,33 @@ module Liri
102
161
  @udp_socket = UDPSocket.new
103
162
  @tcp_port = tcp_port
104
163
 
105
- @all_tests = all_tests
106
- @all_tests_count = all_tests.size
107
- @all_tests_results = {}
164
+ @batch_num = 0
165
+ @tests_batches = {}
166
+ @tests_files_count = 0
167
+ build_tests_batches(all_tests)
168
+
108
169
  @files_processed = 0
109
- @all_tests_processing_count = 0
110
170
  @agents = {}
111
-
112
- @agents_search_processing_enabled = true
113
- @test_processing_enabled = true
114
-
115
- @tests_batch_number = 0
116
- @processed_tests_batches = {}
171
+ @connected_agents = {}
172
+ @working_agents = {}
117
173
 
118
174
  @tests_result = tests_result
119
175
  @semaphore = Mutex.new
120
176
 
121
- @progressbar = ProgressBar.create(starting_at: 0, total: @all_tests_count, length: 100, format: 'Progress %c/%C |%b=%i| %p%% | %a')
177
+ @tests_processing_bar = TTY::ProgressBar::Multi.new("Tests Running Progress")
178
+ @tests_running_progress_bar = @tests_processing_bar.register("Tests files processed :current/:total |:bar| :percent | Time: :time", total: @tests_files_count, width: 80, bar_format: :box)
179
+ @agents_bar = @tests_processing_bar.register("Agents: Connected: :connected, Working: :working")
180
+ @tests_result_bar = @tests_processing_bar.register("Examples: :examples, Passed: :passed, Failures: :failures")
181
+
182
+ @tests_processing_bar.start # Se inicia la multi barra de progreso
183
+
184
+ # Se establece el estado inicial de las barras
185
+ @tests_running_progress_bar.use(Common::TtyProgressbar::TimeFormatter) # Se configura el uso de un nuevo token llamado time para mostrar el tiempo de ejcución
186
+ @tests_running_progress_bar.advance(0) # Esto obliga a que esta barra se muestre antes que los siguientes
187
+ @tests_running_progress_bar.pause
188
+
189
+ @agents_bar.advance(0, connected: "0", working: "0")
190
+ @tests_result_bar.advance(0, examples: "0", passed: "0", failures: "0")
122
191
  end
123
192
 
124
193
  # Inicia un cliente udp que hace un broadcast en toda la red para iniciar una conexión con los Agent que estén escuchando
@@ -127,11 +196,11 @@ module Liri
127
196
  # la red para obtener mas Agents. Una vez que los tests terminan de ejecutarse, este hilo será finalizado.
128
197
  Thread.new do
129
198
  Liri.logger.info('Searching agents... Wait')
130
- Liri.logger.info("Sending UDP broadcast each #{Liri.udp_request_delay} seconds in UDP port: #{@udp_port}")
131
- while agents_search_processing_enabled
199
+ Liri.logger.info("Sending UDP broadcast each #{Manager.udp_request_delay} seconds in UDP port: #{@udp_port}")
200
+ while processing
132
201
  @udp_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
133
202
  @udp_socket.send(manager_data.to_h.to_json, 0, '<broadcast>', @udp_port)
134
- sleep(Liri.udp_request_delay) # Se pausa un momento antes de efectuar nuevamente la petición broadcast
203
+ sleep(Manager.udp_request_delay) # Se pausa un momento antes de efectuar nuevamente la petición broadcast
135
204
  end
136
205
  end
137
206
  end
@@ -149,11 +218,13 @@ module Liri
149
218
  Liri.logger.info("Waiting Agents connection in TCP port: #{@tcp_port}")
150
219
  # El siguiente bucle permite que varios clientes es decir Agents se conecten
151
220
  # De: http://www.w3big.com/es/ruby/ruby-socket-programming.html
152
- while test_processing_enabled
221
+ while processing
153
222
  Thread.start(tcp_socket.accept) do |client|
154
223
  agent_ip_address = client.remote_address.ip_address
155
- hardware_model = nil
224
+ hardware_specs = nil
156
225
  run_tests_batch_time_start = nil
226
+ share_source_code_time_start = nil
227
+ share_source_code_progress_bar = nil
157
228
 
158
229
  while line = client.gets
159
230
  client_data = JSON.parse(line.chop)
@@ -166,23 +237,38 @@ module Liri
166
237
  break
167
238
  else
168
239
  register_agent(agent_ip_address)
169
- hardware_model = client_data['hardware_model']
170
- msg = all_tests.any? ? 'proceed_get_source_code' : 'no_exist_tests'
240
+ update_connected_agents(agent_ip_address)
241
+ hardware_specs = client_data['hardware_specs']
242
+ msg = processing ? 'proceed_get_source_code' : 'no_exist_tests'
243
+ share_source_code_time_start = Time.now
244
+
245
+ share_source_code_progress_bar = start_share_source_code_progress_bar(hardware_specs, msg)
246
+
171
247
  client.puts({ msg: msg }.to_json)
172
248
  end
173
249
  end
174
250
 
175
251
  if msg == 'get_source_code_fail'
252
+ stop_share_source_code_progress_bar(hardware_specs, share_source_code_progress_bar)
253
+
176
254
  client.puts({ msg: 'finish_agent' }.to_json)
177
255
  client.close
178
256
  break
179
257
  end
180
258
 
259
+ # Primera ejecucion de pruebas
181
260
  if msg == 'get_tests_files'
261
+ stop_share_source_code_progress_bar(hardware_specs, share_source_code_progress_bar)
262
+
263
+ share_source_code_time_end = Time.now - share_source_code_time_start
264
+
182
265
  Liri.logger.info("Running unit tests. Agent: #{agent_ip_address}. Wait... ", false)
266
+
267
+ start_tests_running_progress_bar
183
268
  run_tests_batch_time_start = Time.now
269
+ update_working_agents(agent_ip_address)
270
+ tests_batch = tests_batch(agent_ip_address, hardware_specs, share_source_code_time_end)
184
271
 
185
- tests_batch = tests_batch(agent_ip_address)
186
272
  if tests_batch.empty?
187
273
  client.puts({ msg: 'no_exist_tests' }.to_json)
188
274
  client.close
@@ -192,15 +278,15 @@ module Liri
192
278
  end
193
279
  end
194
280
 
281
+ # Segunda ejecucion de pruebas y las siguientes ejecuciones
195
282
  if msg == 'processed_tests'
196
283
  tests_result = client_data
197
284
  Liri.logger.debug("Agent response #{agent_ip_address}: #{tests_result}")
198
- batch_run = Time.now - run_tests_batch_time_start
199
- process_tests_result(agent_ip_address, hardware_model, tests_result, batch_run)
285
+ process_tests_result(agent_ip_address, hardware_specs, tests_result, run_tests_batch_time_start)
200
286
 
201
287
  run_tests_batch_time_start = Time.now
202
288
 
203
- tests_batch = tests_batch(agent_ip_address)
289
+ tests_batch = tests_batch(agent_ip_address, hardware_specs, 0)
204
290
  if tests_batch.empty?
205
291
  client.puts({ msg: 'no_exist_tests' }.to_json)
206
292
  client.close
@@ -211,161 +297,257 @@ module Liri
211
297
  end
212
298
  end
213
299
 
214
- update_processing_statuses
215
300
  Thread.kill(search_agents_thread)
216
- unregister_agent(agent_ip_address)
217
301
  rescue Errno::EPIPE => e
218
302
  # Esto al parecer se da cuando el Agent ya cerró las conexiones y el Manager intenta contactar
219
303
  Liri.logger.error("Exception(#{e}) Agent #{agent_ip_address} already finished connection")
220
304
  # Si el Agente ya no responde es mejor terminar el hilo. Aunque igual quedará colgado el Manager
221
305
  # mientras sigan pruebas pendientes
222
- unregister_agent(agent_ip_address)
223
306
  Thread.exit
224
307
  end
225
308
  end
226
-
227
- @tests_result.print_summary
228
- print_agents_summary
229
- print_agents_detailed_summary if Liri.print_agents_detailed_summary
230
- @tests_result.print_failures_list if Liri.print_failures_list
231
- @tests_result.print_failed_examples if Liri.print_failed_examples
232
309
  end
233
310
 
234
- def all_tests
311
+ def processing
235
312
  @semaphore.synchronize do
236
- @all_tests
313
+ @unfinished_tests_batches.positive?
237
314
  end
238
315
  end
239
316
 
240
- def agents_search_processing_enabled=(value)
241
- @semaphore.synchronize do
242
- @agents_search_processing_enabled = value
317
+ def build_tests_batches(all_tests)
318
+ while all_tests.any?
319
+ @batch_num += 1 # Se numera cada lote
320
+ samples = all_tests.sample!(Manager.test_files_by_runner) # Se obtiene algunos tests
321
+ samples_keys = samples.keys # Se obtiene la clave asignada a los tests
322
+ files_count = samples.size
323
+ status = "pending"
324
+ @tests_files_count += files_count
325
+ # Se construye el lote a enviar
326
+ tests_batch = {
327
+ batch_num: @batch_num,
328
+ tests_batch_keys: samples_keys,
329
+ msg: "process_tests",
330
+ files_count: files_count,
331
+ status: status,
332
+ files_status: "#{files_count} #{status}",
333
+ agent_ip_address: "",
334
+ examples: 0,
335
+ passed: 0,
336
+ failures: 0,
337
+ pending: 0,
338
+ failed_files: "",
339
+ files_load: 0,
340
+ finish_in: 0,
341
+ batch_run: 0,
342
+ share_source_code: 0,
343
+ tests_runtime: 0,
344
+ hardware_specs: ""
345
+ }
346
+ @tests_batches[@batch_num] = tests_batch
243
347
  end
244
- end
245
348
 
246
- def agents_search_processing_enabled
247
- @semaphore.synchronize do
248
- @agents_search_processing_enabled
249
- end
349
+ @unfinished_tests_batches = @batch_num
250
350
  end
251
351
 
252
- def test_processing_enabled
352
+ def tests_batch(agent_ip_address, hardware_specs, share_source_code_time_end)
353
+ # Se inicia un semáforo para evitar que varios hilos actualicen variables compartidas
253
354
  @semaphore.synchronize do
254
- @test_processing_enabled
255
- end
256
- end
355
+ return {} if @unfinished_tests_batches.zero?
356
+
357
+ tests_batch = {}
358
+ pending_tests_batch = {}
359
+ sent_tests_batch = {}
360
+
361
+ @tests_batches.each_value do |batch|
362
+ if batch[:status] == "pending"
363
+ pending_tests_batch = batch
364
+ break
365
+ elsif batch[:status] == "sent"
366
+ sent_tests_batch = batch # Es importante que este no tenga un break para guardar el ultimo enviado
367
+ # el cual tiene menos probabilidades de terminar de ejecutarse rapido
368
+ end
369
+ end
257
370
 
258
- def update_processing_statuses
259
- @semaphore.synchronize do
260
- @test_processing_enabled = false if @all_tests_count == @files_processed
261
- @agents_search_processing_enabled = false if @all_tests_count == @all_tests_processing_count
262
- end
263
- end
371
+ # Es importante setear el status y el hardware_spec solo si los hashes no estan vacios
372
+ # Porque si estan vacios significa que ya no hay tests que ejecutar, y si seteamos algun valor en el hash
373
+ # estando este vacio entonces se tratara de ejecutar algo sin los datos suficientes y fallara
374
+ if pending_tests_batch.any?
375
+ tests_batch = pending_tests_batch
376
+ tests_batch[:status] = "sent"
377
+ tests_batch[:agent_ip_address] = agent_ip_address
378
+ tests_batch[:hardware_specs] = hardware_specs
379
+ elsif sent_tests_batch.any?
380
+ tests_batch = sent_tests_batch
381
+ tests_batch[:status] = "resent"
382
+ tests_batch[:agent_ip_address] = agent_ip_address
383
+ tests_batch[:hardware_specs] = hardware_specs
384
+ end
264
385
 
265
- def tests_batch(agent_ip_address)
266
- # Se inicia un semáforo para evitar que varios hilos actualicen variables compartidas
267
- @semaphore.synchronize do
268
- return {} if @all_tests.empty?
386
+ return {} if tests_batch.empty?
269
387
 
270
- @tests_batch_number += 1 # Se numera cada lote
271
- samples = @all_tests.sample!(Manager.test_files_by_runner) # Se obtiene algunos tests
272
- samples_keys = samples.keys # Se obtiene la clave asignada a los tests
273
- @all_tests_processing_count += samples_keys.size
388
+ tests_batch[:agent_ip_address] = agent_ip_address
389
+ tests_batch[:share_source_code] = share_source_code_time_end
274
390
 
275
- tests_batch = { msg: 'process_tests', tests_batch_number: @tests_batch_number, tests_batch_keys: samples_keys } # Se construye el lote a enviar
276
391
  Liri.logger.debug("Tests batches sent to Agent #{agent_ip_address}: #{tests_batch}")
277
- tests_batch
392
+ # se devuelve el hash con los datos que se enviarán al agente, por eso, primero se remueven los datos innecesarios
393
+ tests_batch.remove(:files_count, :status, :files_status, :agent_ip_address, :examples, :passed, :failures,
394
+ :pending, :failed_files, :files_load, :finish_in, :batch_run, :share_source_code,
395
+ :tests_runtime, :hardware_specs)
278
396
  end
279
397
  end
280
398
 
281
- def process_tests_result(agent_ip_address, hardware_model, tests_result, batch_run)
399
+ def process_tests_result(agent_ip_address, hardware_specs, tests_result, run_tests_batch_time_start)
282
400
  # Se inicia un semáforo para evitar que varios hilos actualicen variables compartidas
283
401
  @semaphore.synchronize do
284
- tests_batch_number = tests_result['tests_batch_number']
402
+ batch_num = tests_result['batch_num']
285
403
  tests_result_file_name = tests_result['tests_result_file_name']
286
- files_processed = tests_result['tests_batch_keys_size']
287
-
288
- @files_processed += files_processed
289
-
290
- @progressbar.progress = @files_processed
291
-
292
- tests_result = @tests_result.process(tests_result_file_name, files_processed)
293
-
294
- @processed_tests_batches[tests_batch_number] = tests_result.clone
295
- @processed_tests_batches[tests_batch_number][:batch_run] = batch_run
296
- @processed_tests_batches[tests_batch_number][:agent_ip_address] = agent_ip_address
297
- @processed_tests_batches[tests_batch_number][:hardware_model] = hardware_model
298
- @processed_tests_batches[tests_batch_number][:tests_batch_number] = tests_batch_number
299
-
300
- Liri.logger.info("Processed unit tests by Agent: #{agent_ip_address}: #{files_processed}")
404
+ status = "processed"
405
+ # Sólo se procesan las pruebas en estado sent o resent, caso contrario no se avanza con el procesamiento
406
+ return if (["pending", status]).include?(@tests_batches[batch_num][:status])
407
+
408
+ tests_result = @tests_result.process(tests_result_file_name)
409
+ return if tests_result.empty?
410
+
411
+ @unfinished_tests_batches -= 1
412
+
413
+ files_count = @tests_batches[batch_num][:files_count]
414
+ @files_processed += files_count
415
+
416
+ batch_runtime = Time.now - run_tests_batch_time_start
417
+
418
+ @tests_running_progress_bar.advance(files_count)
419
+ @tests_result_bar.advance(1, examples: @tests_result.examples.to_s, passed: @tests_result.passed.to_s, failures: @tests_result.failures.to_s)
420
+ @tests_running_progress_bar.stop if @unfinished_tests_batches.zero?
421
+
422
+ @tests_batches[batch_num][:status] = status
423
+ @tests_batches[batch_num][:files_status] = "#{files_count} #{status}"
424
+ @tests_batches[batch_num][:agent_ip_address] = agent_ip_address
425
+ @tests_batches[batch_num][:examples] = tests_result[:examples]
426
+ @tests_batches[batch_num][:passed] = tests_result[:passed]
427
+ @tests_batches[batch_num][:failures] = tests_result[:failures]
428
+ @tests_batches[batch_num][:pending] = tests_result[:pending]
429
+ @tests_batches[batch_num][:failed_files] = tests_result[:failed_files]
430
+ @tests_batches[batch_num][:files_load] = tests_result[:files_load]
431
+ @tests_batches[batch_num][:finish_in] = tests_result[:finish_in]
432
+ @tests_batches[batch_num][:batch_run] = batch_runtime
433
+ @tests_batches[batch_num][:tests_runtime] = @tests_batches[batch_num][:batch_run] + @tests_batches[batch_num][:share_source_code]
434
+ @tests_batches[batch_num][:hardware_specs] = hardware_specs
435
+
436
+ Liri.logger.info("Processed unit tests by Agent: #{agent_ip_address}: #{files_count}")
301
437
  end
302
438
  end
303
439
 
304
- def print_agents_summary
440
+ def print_results
441
+ @tests_processing_bar&.stop
442
+ print_summary_table if Manager.print_summary_table
443
+ print_detailed_table if Manager.print_detailed_table
444
+ @tests_result.print_summary_failures if Manager.print_summary_failures
445
+ @tests_result.print_detailed_failures if Manager.print_detailed_failures
446
+ end
447
+
448
+ def print_summary_table
305
449
  processed_tests_batches_by_agent = processed_tests_batches_by_agents
306
450
  rows = processed_tests_batches_by_agent.values.map do |value|
307
- value[:finish_in] = value[:finish_in].to_duration
308
- value[:files_load] = value[:files_load].to_duration
309
- value[:batch_run] = value[:batch_run].to_duration
451
+ value[:files_load] = to_duration(value[:files_load]) if value[:files_load]
452
+ value[:finish_in] = to_duration(value[:finish_in]) if value[:finish_in]
453
+ value[:batch_run] = to_duration(value[:batch_run]) if value[:batch_run]
454
+ value[:share_source_code] = to_duration(value[:share_source_code]) if value[:share_source_code]
455
+ value[:tests_runtime] = to_duration(value[:tests_runtime]) if value[:tests_runtime]
310
456
  value.values
311
457
  end
312
458
 
313
- rows << Array.new(9) # Se agrega una linea vacia antes de mostrar los totales
314
- rows << get_footer_values
459
+ rows << Array.new(rows.size) # Se agrega una linea vacia antes de mostrar los totales
460
+ rows << summary_footer.remove(:batch_num).values
315
461
  header = processed_tests_batches_by_agent.values.first.keys
316
462
 
317
463
  table = Terminal::Table.new title: 'Summary', headings: header, rows: rows
318
464
  table.style = { padding_left: 3, border_x: '=', border_i: 'x'}
319
- puts table
465
+
466
+ Liri.logger.info("\n#{table}", true)
320
467
  end
321
468
 
322
469
  def processed_tests_batches_by_agents
323
470
  tests_batches = {}
324
- @processed_tests_batches.values.each do |processed_test_batch|
471
+ files_count = {}
472
+ @tests_batches.each_value do |processed_test_batch|
325
473
  agent_ip_address = processed_test_batch[:agent_ip_address]
326
- if tests_batches[agent_ip_address]
327
- tests_batches[agent_ip_address][:examples] += processed_test_batch[:examples]
328
- tests_batches[agent_ip_address][:failures] += processed_test_batch[:failures]
329
- tests_batches[agent_ip_address][:pending] += processed_test_batch[:pending]
330
- tests_batches[agent_ip_address][:passed] += processed_test_batch[:passed]
331
- tests_batches[agent_ip_address][:finish_in] += processed_test_batch[:finish_in]
332
- tests_batches[agent_ip_address][:files_load] += processed_test_batch[:files_load]
333
- tests_batches[agent_ip_address][:files_processed] += processed_test_batch[:files_processed]
334
- tests_batches[agent_ip_address][:batch_run] += processed_test_batch[:batch_run]
474
+ status = processed_test_batch[:status]
475
+ key = "#{agent_ip_address}#{status}"
476
+ if tests_batches[key]
477
+ files_count[key] += processed_test_batch[:files_count]
478
+ tests_batches[key][:files_status] = "#{files_count[key]} #{status}"
479
+ tests_batches[key][:examples] += processed_test_batch[:examples]
480
+ tests_batches[key][:passed] += processed_test_batch[:passed]
481
+ tests_batches[key][:failures] += processed_test_batch[:failures]
482
+ tests_batches[key][:failed_files] += processed_test_batch[:failed_files] if Manager.show_failed_files_column
483
+ tests_batches[key][:files_load] += processed_test_batch[:files_load] if Manager.show_files_load_column
484
+ tests_batches[key][:finish_in] += processed_test_batch[:finish_in] if Manager.show_finish_in_column
485
+ tests_batches[key][:batch_run] += processed_test_batch[:batch_run] if Manager.show_batch_run_column
486
+ tests_batches[key][:share_source_code] += processed_test_batch[:share_source_code] if Manager.show_share_source_code_column
487
+ tests_batches[key][:tests_runtime] += processed_test_batch[:tests_runtime]
335
488
  else
489
+ files_count[key] = processed_test_batch[:files_count]
490
+
336
491
  _processed_test_batch = processed_test_batch.clone # Clone to change values in other hash
337
- _processed_test_batch.remove!(:failures_list, :failed_examples, :agent_ip_address, :tests_batch_number)
338
- tests_batches[agent_ip_address] = _processed_test_batch
492
+ _processed_test_batch.remove!(:batch_num, :tests_batch_keys, :msg, :files_count, :status, :agent_ip_address,
493
+ :pending)
494
+
495
+ _processed_test_batch.remove!(:failed_files) unless Manager.show_failed_files_column
496
+ _processed_test_batch.remove!(:files_load) unless Manager.show_files_load_column
497
+ _processed_test_batch.remove!(:finish_in) unless Manager.show_finish_in_column
498
+ _processed_test_batch.remove!(:batch_run) unless Manager.show_batch_run_column
499
+ _processed_test_batch.remove!(:share_source_code) unless Manager.show_share_source_code_column
500
+ _processed_test_batch[:files_status] = "#{files_count[key]} #{status}"
501
+
502
+ tests_batches[key] = _processed_test_batch
339
503
  end
340
504
  end
341
505
  tests_batches
342
506
  end
343
507
 
344
- def print_agents_detailed_summary
345
- puts "\n"
346
- rows = @processed_tests_batches.values.map do |value|
347
- value.remove!(:failures_list, :failed_examples, :agent_ip_address, :tests_batch_number)
348
- value[:finish_in] = value[:finish_in].to_duration
349
- value[:files_load] = value[:files_load].to_duration
350
- value[:batch_run] = value[:batch_run].to_duration
508
+ def print_detailed_table
509
+ rows = @tests_batches.values.map do |value|
510
+ value.remove!(:tests_batch_keys, :msg, :files_count, :status, :agent_ip_address, :pending)
511
+
512
+ value.remove!(:failed_files) unless Manager.show_failed_files_column
513
+ value.remove!(:files_load) unless Manager.show_files_load_column
514
+ value.remove!(:finish_in) unless Manager.show_finish_in_column
515
+ value.remove!(:batch_run) unless Manager.show_batch_run_column
516
+ value.remove!(:share_source_code) unless Manager.show_share_source_code_column
517
+
518
+ value[:files_load] = to_duration(value[:files_load]) if value[:files_load]
519
+ value[:finish_in] = to_duration(value[:finish_in]) if value[:finish_in]
520
+ value[:batch_run] = to_duration(value[:batch_run]) if value[:batch_run]
521
+ value[:share_source_code] = to_duration(value[:share_source_code]) if value[:share_source_code]
522
+ value[:tests_runtime] = to_duration(value[:tests_runtime])
351
523
  value.values
352
524
  end
353
525
 
354
- rows << Array.new(9) # Se agrega una linea vacia antes de mostrar los totales
355
- rows << get_footer_values
356
- header = @processed_tests_batches.values.first.keys
526
+ rows << Array.new(rows.size) # Se agrega una linea vacia antes de mostrar los totales
527
+ rows << summary_footer.values
528
+ header = @tests_batches.values.first.keys
357
529
 
358
530
  table = Terminal::Table.new title: 'Detailed Summary', headings: header, rows: rows
359
531
  table.style = { padding_left: 3, border_x: '=', border_i: 'x' }
360
532
 
361
- puts table
533
+ Liri.logger.info("\n#{table}", true)
362
534
  end
363
535
 
364
- def get_footer_values
365
- footer = { examples: @tests_result.examples, failures: @tests_result.failures, pending: @tests_result.pending,
366
- passed: @tests_result.passed, finish_in: "", files_load: "",
367
- files_processed: @tests_result.files_processed, batch_run: "", hardware_model: "" }
368
- footer.values
536
+ def summary_footer
537
+ hash = {}
538
+ hash[:batch_num] = ""
539
+ hash[:files_status] = "#{@tests_files_count} in total"
540
+ hash[:examples] = @tests_result.examples
541
+ hash[:passed] = @tests_result.passed
542
+ hash[:failures] = @tests_result.failures
543
+ hash[:failed_files] = "" if Manager.show_failed_files_column
544
+ hash[:files_load] = "" if Manager.show_files_load_column
545
+ hash[:finish_in] = "" if Manager.show_finish_in_column
546
+ hash[:batch_run] = "" if Manager.show_batch_run_column
547
+ hash[:share_source_code] = "" if Manager.show_share_source_code_column
548
+ hash[:tests_runtime] = ""
549
+ hash[:hardware_specs] = ""
550
+ hash
369
551
  end
370
552
 
371
553
  def registered_agent?(agent_ip_address)
@@ -377,8 +559,68 @@ module Liri
377
559
  Liri.logger.info("\nStarted connection with Agent: #{agent_ip_address} in TCP port: #{@tcp_port}")
378
560
  end
379
561
 
380
- def unregister_agent(agent_ip_address)
381
- @agents.remove!(agent_ip_address)
562
+ def update_connected_agents(agent_ip_address)
563
+ unless @connected_agents[agent_ip_address]
564
+ @connected_agents[agent_ip_address] = agent_ip_address
565
+ update_agents_bar
566
+ end
567
+ end
568
+
569
+ def update_working_agents(agent_ip_address)
570
+ unless @working_agents[agent_ip_address]
571
+ @working_agents[agent_ip_address] = agent_ip_address
572
+ update_agents_bar
573
+ end
574
+ end
575
+
576
+ def update_agents_bar
577
+ @agents_bar.advance(1, connected: @connected_agents.size.to_s, working: @working_agents.size.to_s)
578
+ end
579
+
580
+ def start_share_source_code_progress_bar(hardware_specs, msg)
581
+ if msg == 'proceed_get_source_code' && Manager.show_share_source_code_progress_bar
582
+ share_source_code_progress_bar = @tests_processing_bar.register("Sharing source code |:bar| :percent | Time: :time | Agent: [:agent ]", total: nil, width: 20, bar_format: :box)
583
+ share_source_code_progress_bar.start
584
+ share_source_code_progress_bar.use(Common::TtyProgressbar::TimeFormatter)
585
+ Thread.new do
586
+ animation_count = 0
587
+ while !share_source_code_progress_bar.stopped?
588
+ share_source_code_progress_bar.advance(1, agent: hardware_specs)
589
+
590
+ share_source_code_progress_bar.update(unknown: Common::TtyProgressbar::ANIMATION2[animation_count])
591
+ animation_count += 1
592
+ animation_count = 0 if animation_count == 3
593
+
594
+ sleep(0.1)
595
+ end
596
+ end
597
+ end
598
+ share_source_code_progress_bar
599
+ end
600
+
601
+ def stop_share_source_code_progress_bar(hardware_specs, share_source_code_progress_bar)
602
+ if Manager.show_share_source_code_progress_bar
603
+ share_source_code_progress_bar.update(total: 1, agent: hardware_specs)
604
+ share_source_code_progress_bar.stop
605
+ end
606
+ end
607
+
608
+ def start_tests_running_progress_bar
609
+ @semaphore.synchronize do
610
+ # Es importante hacer un reset acá osino va a contar desde que se instancia y no desde que se inicia la ejecución
611
+ # del primer test. Solo se resetea si esta paused para evitar que al conectarse con cada Agent se vuelva a resetear
612
+ @tests_running_progress_bar.reset if @tests_running_progress_bar.paused?
613
+ Thread.new do
614
+ while !@tests_running_progress_bar.stopped?
615
+ @tests_running_progress_bar.advance(0)
616
+ sleep(0.1) # Es importante que las otras barras tambien tengan el mismo sleep para que sean mas consistentes en sus resultados
617
+ end
618
+ end
619
+ end
620
+ end
621
+
622
+ def to_duration(value)
623
+ Common::Duration.humanize(value, times_round: Liri.times_round, times_round_type: Liri.times_round_type)
382
624
  end
383
625
  end
384
626
  end