lib/manager/manager.rb in liri-0.3.1 vs lib/manager/manager.rb in liri-0.4.0

- old
+ new

@@ -17,12 +17,12 @@ setup_manager = Liri.set_setup(source_code_folder_path, :manager, manager_tests_results_folder_time: DateTime.now.strftime("%d_%m_%y_%H_%M_%S")) manager_folder_path = setup_manager.manager_folder_path manager_tests_results_folder_path = setup_manager.manager_tests_results_folder_path - Liri.set_logger(setup_manager.logs_folder_path, 'liri-manager.log') - Liri.logger.info('Manager process started') + Liri.set_logger(setup_manager.logs_folder_path, 'lirimanager.log') + Liri.logger.info('Manager process started', true) Liri.logger.info("Press Ctrl + c to finish Manager process manually\n", true) user, password = get_credentials(setup_manager.setup_folder_path) source_code = compress_source_code(source_code_folder_path, manager_folder_path) manager_data = get_manager_data(user, password, manager_tests_results_folder_path, source_code) @@ -31,25 +31,74 @@ manager = Manager.new(Liri.udp_port, Liri.tcp_port, all_tests, tests_result) threads = [] threads << manager.start_client_socket_to_search_agents(manager_data) # Enviar peticiones broadcast a toda la red para encontrar Agents - manager.start_server_socket_to_process_tests(threads[0]) unless stop # Esperar y enviar los test unitarios a los Agents + unless stop + # Esperar y enviar los test unitarios a los Agents + manager.start_server_socket_to_process_tests(threads[0]) + end - source_code.delete_compressed_file + Liri.init_exit(stop, threads) + rescue SignalException + # Liri.logger.info("\nManager process finished manually", true) + ensure + # Siempre se ejecutan estos comandos, haya o no excepción + Liri.kill(threads) if threads&.any? + manager&.print_results + source_code&.delete_compressed_file + Liri.logger.info("Manager process finished", true) + end - Liri.init_exit(stop, threads, 'Manager') - Liri.logger.info('Manager process finished') - rescue SignalException => e - Liri.logger.info("Exception(#{e}) Proceso Manager process finished manually") - Liri.kill(threads) + def udp_request_delay + Liri.setup.manager.udp_request_delay end def test_files_by_runner - Liri.setup.test_files_by_runner + Liri.setup.manager.test_files_by_runner end + def show_share_source_code_progress_bar + Liri.setup.manager.bar.share_source_code + end + + def print_summary_table + Liri.setup.manager.print.table.summary + end + + def print_detailed_table + Liri.setup.manager.print.table.detailed + end + + def print_summary_failures + Liri.setup.manager.print.failures.summary + end + + def print_detailed_failures + Liri.setup.manager.print.failures.detailed + end + + def show_failed_files_column + Liri.setup.manager.print.column.failed_files + end + + def show_files_load_column + Liri.setup.manager.print.column.files_load + end + + def show_finish_in_column + Liri.setup.manager.print.column.finish_in + end + + def show_batch_run_column + Liri.setup.manager.print.column.batch_run + end + + def show_share_source_code_column + Liri.setup.manager.print.column.share_source_code + end + private def valid_project if File.exist?(File.join(Dir.pwd, 'Gemfile')) true else @@ -64,18 +113,23 @@ credential = Liri::Manager::Credential.new(setup_folder_path) credential.get end def compress_source_code(source_code_folder_path, manager_folder_path) - source_code = Common::SourceCode.new(source_code_folder_path, manager_folder_path, Liri.compression_class, Liri.unit_test_class) - - Common::Progressbar.start(total: nil, length: 100, format: 'Compressing source code |%B| %a') do + source_code = Common::SourceCode.new(source_code_folder_path, manager_folder_path, Liri.ignored_folders_in_compress, Liri.compression_class, Liri.unit_test_class) + #Common::Progressbar.start(total: nil, length: 120, format: 'Compressing source code |%B| %a') do + Common::TtyProgressbar.start("Compressing source code |:bar| :percent | Time: :time", total: nil, width: 80, bar_format: :box) do source_code.compress_folder end - puts "\n\n" - + puts "\n" + Liri.logger.info("Batch Files: #{test_files_by_runner}", true) + puts "\n" source_code + rescue SignalException => e + # Se captura la excepción sólo para imprimir espacios despues de la barra de progreso + puts "\n\n" + raise e end def get_manager_data(user, password, tests_results_folder_path, source_code) Common::ManagerData.new( tests_results_folder_path: tests_results_folder_path, @@ -86,54 +140,69 @@ end def get_all_tests(source_code) all_tests = {} - Common::Progressbar.start(total: nil, length: 100, format: 'Getting unit tests |%B| %a') do + #Common::TtyProgressbar.start("Getting unit tests |:bar| Time::elapsed", total: nil, width: 100) do + #Common::Progressbar.start(total: nil, length: 120, format: 'Getting unit tests |%B| %a') do all_tests = source_code.all_tests - end - puts "\n\n" + #end + #puts "\n\n" all_tests + rescue SignalException => e + # Se captura la excepción sólo para imprimir espacios despues de la barra de progreso + puts "\n\n" + raise e end end def initialize(udp_port, tcp_port, all_tests, tests_result) @udp_port = udp_port @udp_socket = UDPSocket.new @tcp_port = tcp_port - @all_tests = all_tests - @all_tests_count = all_tests.size - @all_tests_results = {} + @batch_num = 0 + @tests_batches = {} + @tests_files_count = 0 + build_tests_batches(all_tests) + @files_processed = 0 - @all_tests_processing_count = 0 @agents = {} + @connected_agents = {} + @working_agents = {} - @agents_search_processing_enabled = true - @test_processing_enabled = true - - @tests_batch_number = 0 - @processed_tests_batches = {} - @tests_result = tests_result @semaphore = Mutex.new - @progressbar = ProgressBar.create(starting_at: 0, total: @all_tests_count, length: 100, format: 'Progress %c/%C |%b=%i| %p%% | %a') + @tests_processing_bar = TTY::ProgressBar::Multi.new("Tests Running Progress") + @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) + @agents_bar = @tests_processing_bar.register("Agents: Connected: :connected, Working: :working") + @tests_result_bar = @tests_processing_bar.register("Examples: :examples, Passed: :passed, Failures: :failures") + + @tests_processing_bar.start # Se inicia la multi barra de progreso + + # Se establece el estado inicial de las barras + @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 + @tests_running_progress_bar.advance(0) # Esto obliga a que esta barra se muestre antes que los siguientes + @tests_running_progress_bar.pause + + @agents_bar.advance(0, connected: "0", working: "0") + @tests_result_bar.advance(0, examples: "0", passed: "0", failures: "0") end # Inicia un cliente udp que hace un broadcast en toda la red para iniciar una conexión con los Agent que estén escuchando def start_client_socket_to_search_agents(manager_data) # El cliente udp se ejecuta en bucle dentro de un hilo, esto permite realizar otras tareas mientras este hilo sigue sondeando # la red para obtener mas Agents. Una vez que los tests terminan de ejecutarse, este hilo será finalizado. Thread.new do Liri.logger.info('Searching agents... Wait') - Liri.logger.info("Sending UDP broadcast each #{Liri.udp_request_delay} seconds in UDP port: #{@udp_port}") - while agents_search_processing_enabled + Liri.logger.info("Sending UDP broadcast each #{Manager.udp_request_delay} seconds in UDP port: #{@udp_port}") + while processing @udp_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true) @udp_socket.send(manager_data.to_h.to_json, 0, '<broadcast>', @udp_port) - sleep(Liri.udp_request_delay) # Se pausa un momento antes de efectuar nuevamente la petición broadcast + sleep(Manager.udp_request_delay) # Se pausa un momento antes de efectuar nuevamente la petición broadcast end end end # Inicia un servidor tcp para procesar los pruebas después de haberse iniciado la conexión a través de udp @@ -147,15 +216,17 @@ end Liri.logger.info("Waiting Agents connection in TCP port: #{@tcp_port}") # El siguiente bucle permite que varios clientes es decir Agents se conecten # De: http://www.w3big.com/es/ruby/ruby-socket-programming.html - while test_processing_enabled + while processing Thread.start(tcp_socket.accept) do |client| agent_ip_address = client.remote_address.ip_address - hardware_model = nil + hardware_specs = nil run_tests_batch_time_start = nil + share_source_code_time_start = nil + share_source_code_progress_bar = nil while line = client.gets client_data = JSON.parse(line.chop) msg = client_data['msg'] @@ -164,210 +235,321 @@ client.puts({ msg: 'already_connected' }.to_json) client.close break else register_agent(agent_ip_address) - hardware_model = client_data['hardware_model'] - msg = all_tests.any? ? 'proceed_get_source_code' : 'no_exist_tests' + update_connected_agents(agent_ip_address) + hardware_specs = client_data['hardware_specs'] + msg = processing ? 'proceed_get_source_code' : 'no_exist_tests' + share_source_code_time_start = Time.now + + share_source_code_progress_bar = start_share_source_code_progress_bar(hardware_specs, msg) + client.puts({ msg: msg }.to_json) end end if msg == 'get_source_code_fail' + stop_share_source_code_progress_bar(hardware_specs, share_source_code_progress_bar) + client.puts({ msg: 'finish_agent' }.to_json) client.close break end + # Primera ejecucion de pruebas if msg == 'get_tests_files' + stop_share_source_code_progress_bar(hardware_specs, share_source_code_progress_bar) + + share_source_code_time_end = Time.now - share_source_code_time_start + Liri.logger.info("Running unit tests. Agent: #{agent_ip_address}. Wait... ", false) + + start_tests_running_progress_bar run_tests_batch_time_start = Time.now + update_working_agents(agent_ip_address) + tests_batch = tests_batch(agent_ip_address, hardware_specs, share_source_code_time_end) - tests_batch = tests_batch(agent_ip_address) if tests_batch.empty? client.puts({ msg: 'no_exist_tests' }.to_json) client.close break else client.puts(tests_batch.to_json) # Se envia el lote de tests end end + # Segunda ejecucion de pruebas y las siguientes ejecuciones if msg == 'processed_tests' tests_result = client_data Liri.logger.debug("Agent response #{agent_ip_address}: #{tests_result}") - batch_run = Time.now - run_tests_batch_time_start - process_tests_result(agent_ip_address, hardware_model, tests_result, batch_run) + process_tests_result(agent_ip_address, hardware_specs, tests_result, run_tests_batch_time_start) run_tests_batch_time_start = Time.now - tests_batch = tests_batch(agent_ip_address) + tests_batch = tests_batch(agent_ip_address, hardware_specs, 0) if tests_batch.empty? client.puts({ msg: 'no_exist_tests' }.to_json) client.close break else client.puts(tests_batch.to_json) # Se envia el lote de tests end end end - update_processing_statuses Thread.kill(search_agents_thread) - unregister_agent(agent_ip_address) rescue Errno::EPIPE => e # Esto al parecer se da cuando el Agent ya cerró las conexiones y el Manager intenta contactar Liri.logger.error("Exception(#{e}) Agent #{agent_ip_address} already finished connection") # Si el Agente ya no responde es mejor terminar el hilo. Aunque igual quedará colgado el Manager # mientras sigan pruebas pendientes - unregister_agent(agent_ip_address) Thread.exit end end - - @tests_result.print_summary - print_agents_summary - print_agents_detailed_summary if Liri.print_agents_detailed_summary - @tests_result.print_failures_list if Liri.print_failures_list - @tests_result.print_failed_examples if Liri.print_failed_examples end - def all_tests + def processing @semaphore.synchronize do - @all_tests + @unfinished_tests_batches.positive? end end - def agents_search_processing_enabled=(value) - @semaphore.synchronize do - @agents_search_processing_enabled = value + def build_tests_batches(all_tests) + while all_tests.any? + @batch_num += 1 # Se numera cada lote + samples = all_tests.sample!(Manager.test_files_by_runner) # Se obtiene algunos tests + samples_keys = samples.keys # Se obtiene la clave asignada a los tests + files_count = samples.size + status = "pending" + @tests_files_count += files_count + # Se construye el lote a enviar + tests_batch = { + batch_num: @batch_num, + tests_batch_keys: samples_keys, + msg: "process_tests", + files_count: files_count, + status: status, + files_status: "#{files_count} #{status}", + agent_ip_address: "", + examples: 0, + passed: 0, + failures: 0, + pending: 0, + failed_files: "", + files_load: 0, + finish_in: 0, + batch_run: 0, + share_source_code: 0, + tests_runtime: 0, + hardware_specs: "" + } + @tests_batches[@batch_num] = tests_batch end - end - def agents_search_processing_enabled - @semaphore.synchronize do - @agents_search_processing_enabled - end + @unfinished_tests_batches = @batch_num end - def test_processing_enabled + def tests_batch(agent_ip_address, hardware_specs, share_source_code_time_end) + # Se inicia un semáforo para evitar que varios hilos actualicen variables compartidas @semaphore.synchronize do - @test_processing_enabled - end - end + return {} if @unfinished_tests_batches.zero? - def update_processing_statuses - @semaphore.synchronize do - @test_processing_enabled = false if @all_tests_count == @files_processed - @agents_search_processing_enabled = false if @all_tests_count == @all_tests_processing_count - end - end + tests_batch = {} + pending_tests_batch = {} + sent_tests_batch = {} - def tests_batch(agent_ip_address) - # Se inicia un semáforo para evitar que varios hilos actualicen variables compartidas - @semaphore.synchronize do - return {} if @all_tests.empty? + @tests_batches.each_value do |batch| + if batch[:status] == "pending" + pending_tests_batch = batch + break + elsif batch[:status] == "sent" + sent_tests_batch = batch # Es importante que este no tenga un break para guardar el ultimo enviado + # el cual tiene menos probabilidades de terminar de ejecutarse rapido + end + end - @tests_batch_number += 1 # Se numera cada lote - samples = @all_tests.sample!(Manager.test_files_by_runner) # Se obtiene algunos tests - samples_keys = samples.keys # Se obtiene la clave asignada a los tests - @all_tests_processing_count += samples_keys.size + # Es importante setear el status y el hardware_spec solo si los hashes no estan vacios + # Porque si estan vacios significa que ya no hay tests que ejecutar, y si seteamos algun valor en el hash + # estando este vacio entonces se tratara de ejecutar algo sin los datos suficientes y fallara + if pending_tests_batch.any? + tests_batch = pending_tests_batch + tests_batch[:status] = "sent" + tests_batch[:agent_ip_address] = agent_ip_address + tests_batch[:hardware_specs] = hardware_specs + elsif sent_tests_batch.any? + tests_batch = sent_tests_batch + tests_batch[:status] = "resent" + tests_batch[:agent_ip_address] = agent_ip_address + tests_batch[:hardware_specs] = hardware_specs + end - tests_batch = { msg: 'process_tests', tests_batch_number: @tests_batch_number, tests_batch_keys: samples_keys } # Se construye el lote a enviar + return {} if tests_batch.empty? + + tests_batch[:agent_ip_address] = agent_ip_address + tests_batch[:share_source_code] = share_source_code_time_end + Liri.logger.debug("Tests batches sent to Agent #{agent_ip_address}: #{tests_batch}") - tests_batch + # se devuelve el hash con los datos que se enviarán al agente, por eso, primero se remueven los datos innecesarios + tests_batch.remove(:files_count, :status, :files_status, :agent_ip_address, :examples, :passed, :failures, + :pending, :failed_files, :files_load, :finish_in, :batch_run, :share_source_code, + :tests_runtime, :hardware_specs) end end - def process_tests_result(agent_ip_address, hardware_model, tests_result, batch_run) + def process_tests_result(agent_ip_address, hardware_specs, tests_result, run_tests_batch_time_start) # Se inicia un semáforo para evitar que varios hilos actualicen variables compartidas @semaphore.synchronize do - tests_batch_number = tests_result['tests_batch_number'] + batch_num = tests_result['batch_num'] tests_result_file_name = tests_result['tests_result_file_name'] - files_processed = tests_result['tests_batch_keys_size'] + status = "processed" + # Sólo se procesan las pruebas en estado sent o resent, caso contrario no se avanza con el procesamiento + return if (["pending", status]).include?(@tests_batches[batch_num][:status]) - @files_processed += files_processed + tests_result = @tests_result.process(tests_result_file_name) + return if tests_result.empty? - @progressbar.progress = @files_processed + @unfinished_tests_batches -= 1 - tests_result = @tests_result.process(tests_result_file_name, files_processed) + files_count = @tests_batches[batch_num][:files_count] + @files_processed += files_count - @processed_tests_batches[tests_batch_number] = tests_result.clone - @processed_tests_batches[tests_batch_number][:batch_run] = batch_run - @processed_tests_batches[tests_batch_number][:agent_ip_address] = agent_ip_address - @processed_tests_batches[tests_batch_number][:hardware_model] = hardware_model - @processed_tests_batches[tests_batch_number][:tests_batch_number] = tests_batch_number + batch_runtime = Time.now - run_tests_batch_time_start - Liri.logger.info("Processed unit tests by Agent: #{agent_ip_address}: #{files_processed}") + @tests_running_progress_bar.advance(files_count) + @tests_result_bar.advance(1, examples: @tests_result.examples.to_s, passed: @tests_result.passed.to_s, failures: @tests_result.failures.to_s) + @tests_running_progress_bar.stop if @unfinished_tests_batches.zero? + + @tests_batches[batch_num][:status] = status + @tests_batches[batch_num][:files_status] = "#{files_count} #{status}" + @tests_batches[batch_num][:agent_ip_address] = agent_ip_address + @tests_batches[batch_num][:examples] = tests_result[:examples] + @tests_batches[batch_num][:passed] = tests_result[:passed] + @tests_batches[batch_num][:failures] = tests_result[:failures] + @tests_batches[batch_num][:pending] = tests_result[:pending] + @tests_batches[batch_num][:failed_files] = tests_result[:failed_files] + @tests_batches[batch_num][:files_load] = tests_result[:files_load] + @tests_batches[batch_num][:finish_in] = tests_result[:finish_in] + @tests_batches[batch_num][:batch_run] = batch_runtime + @tests_batches[batch_num][:tests_runtime] = @tests_batches[batch_num][:batch_run] + @tests_batches[batch_num][:share_source_code] + @tests_batches[batch_num][:hardware_specs] = hardware_specs + + Liri.logger.info("Processed unit tests by Agent: #{agent_ip_address}: #{files_count}") end end - def print_agents_summary + def print_results + @tests_processing_bar&.stop + print_summary_table if Manager.print_summary_table + print_detailed_table if Manager.print_detailed_table + @tests_result.print_summary_failures if Manager.print_summary_failures + @tests_result.print_detailed_failures if Manager.print_detailed_failures + end + + def print_summary_table processed_tests_batches_by_agent = processed_tests_batches_by_agents rows = processed_tests_batches_by_agent.values.map do |value| - value[:finish_in] = value[:finish_in].to_duration - value[:files_load] = value[:files_load].to_duration - value[:batch_run] = value[:batch_run].to_duration + value[:files_load] = to_duration(value[:files_load]) if value[:files_load] + value[:finish_in] = to_duration(value[:finish_in]) if value[:finish_in] + value[:batch_run] = to_duration(value[:batch_run]) if value[:batch_run] + value[:share_source_code] = to_duration(value[:share_source_code]) if value[:share_source_code] + value[:tests_runtime] = to_duration(value[:tests_runtime]) if value[:tests_runtime] value.values end - rows << Array.new(9) # Se agrega una linea vacia antes de mostrar los totales - rows << get_footer_values + rows << Array.new(rows.size) # Se agrega una linea vacia antes de mostrar los totales + rows << summary_footer.remove(:batch_num).values header = processed_tests_batches_by_agent.values.first.keys table = Terminal::Table.new title: 'Summary', headings: header, rows: rows table.style = { padding_left: 3, border_x: '=', border_i: 'x'} - puts table + + Liri.logger.info("\n#{table}", true) end def processed_tests_batches_by_agents tests_batches = {} - @processed_tests_batches.values.each do |processed_test_batch| + files_count = {} + @tests_batches.each_value do |processed_test_batch| agent_ip_address = processed_test_batch[:agent_ip_address] - if tests_batches[agent_ip_address] - tests_batches[agent_ip_address][:examples] += processed_test_batch[:examples] - tests_batches[agent_ip_address][:failures] += processed_test_batch[:failures] - tests_batches[agent_ip_address][:pending] += processed_test_batch[:pending] - tests_batches[agent_ip_address][:passed] += processed_test_batch[:passed] - tests_batches[agent_ip_address][:finish_in] += processed_test_batch[:finish_in] - tests_batches[agent_ip_address][:files_load] += processed_test_batch[:files_load] - tests_batches[agent_ip_address][:files_processed] += processed_test_batch[:files_processed] - tests_batches[agent_ip_address][:batch_run] += processed_test_batch[:batch_run] + status = processed_test_batch[:status] + key = "#{agent_ip_address}#{status}" + if tests_batches[key] + files_count[key] += processed_test_batch[:files_count] + tests_batches[key][:files_status] = "#{files_count[key]} #{status}" + tests_batches[key][:examples] += processed_test_batch[:examples] + tests_batches[key][:passed] += processed_test_batch[:passed] + tests_batches[key][:failures] += processed_test_batch[:failures] + tests_batches[key][:failed_files] += processed_test_batch[:failed_files] if Manager.show_failed_files_column + tests_batches[key][:files_load] += processed_test_batch[:files_load] if Manager.show_files_load_column + tests_batches[key][:finish_in] += processed_test_batch[:finish_in] if Manager.show_finish_in_column + tests_batches[key][:batch_run] += processed_test_batch[:batch_run] if Manager.show_batch_run_column + tests_batches[key][:share_source_code] += processed_test_batch[:share_source_code] if Manager.show_share_source_code_column + tests_batches[key][:tests_runtime] += processed_test_batch[:tests_runtime] else + files_count[key] = processed_test_batch[:files_count] + _processed_test_batch = processed_test_batch.clone # Clone to change values in other hash - _processed_test_batch.remove!(:failures_list, :failed_examples, :agent_ip_address, :tests_batch_number) - tests_batches[agent_ip_address] = _processed_test_batch + _processed_test_batch.remove!(:batch_num, :tests_batch_keys, :msg, :files_count, :status, :agent_ip_address, + :pending) + + _processed_test_batch.remove!(:failed_files) unless Manager.show_failed_files_column + _processed_test_batch.remove!(:files_load) unless Manager.show_files_load_column + _processed_test_batch.remove!(:finish_in) unless Manager.show_finish_in_column + _processed_test_batch.remove!(:batch_run) unless Manager.show_batch_run_column + _processed_test_batch.remove!(:share_source_code) unless Manager.show_share_source_code_column + _processed_test_batch[:files_status] = "#{files_count[key]} #{status}" + + tests_batches[key] = _processed_test_batch end end tests_batches end - def print_agents_detailed_summary - puts "\n" - rows = @processed_tests_batches.values.map do |value| - value.remove!(:failures_list, :failed_examples, :agent_ip_address, :tests_batch_number) - value[:finish_in] = value[:finish_in].to_duration - value[:files_load] = value[:files_load].to_duration - value[:batch_run] = value[:batch_run].to_duration + def print_detailed_table + rows = @tests_batches.values.map do |value| + value.remove!(:tests_batch_keys, :msg, :files_count, :status, :agent_ip_address, :pending) + + value.remove!(:failed_files) unless Manager.show_failed_files_column + value.remove!(:files_load) unless Manager.show_files_load_column + value.remove!(:finish_in) unless Manager.show_finish_in_column + value.remove!(:batch_run) unless Manager.show_batch_run_column + value.remove!(:share_source_code) unless Manager.show_share_source_code_column + + value[:files_load] = to_duration(value[:files_load]) if value[:files_load] + value[:finish_in] = to_duration(value[:finish_in]) if value[:finish_in] + value[:batch_run] = to_duration(value[:batch_run]) if value[:batch_run] + value[:share_source_code] = to_duration(value[:share_source_code]) if value[:share_source_code] + value[:tests_runtime] = to_duration(value[:tests_runtime]) value.values end - rows << Array.new(9) # Se agrega una linea vacia antes de mostrar los totales - rows << get_footer_values - header = @processed_tests_batches.values.first.keys + rows << Array.new(rows.size) # Se agrega una linea vacia antes de mostrar los totales + rows << summary_footer.values + header = @tests_batches.values.first.keys table = Terminal::Table.new title: 'Detailed Summary', headings: header, rows: rows table.style = { padding_left: 3, border_x: '=', border_i: 'x' } - puts table + Liri.logger.info("\n#{table}", true) end - def get_footer_values - footer = { examples: @tests_result.examples, failures: @tests_result.failures, pending: @tests_result.pending, - passed: @tests_result.passed, finish_in: "", files_load: "", - files_processed: @tests_result.files_processed, batch_run: "", hardware_model: "" } - footer.values + def summary_footer + hash = {} + hash[:batch_num] = "" + hash[:files_status] = "#{@tests_files_count} in total" + hash[:examples] = @tests_result.examples + hash[:passed] = @tests_result.passed + hash[:failures] = @tests_result.failures + hash[:failed_files] = "" if Manager.show_failed_files_column + hash[:files_load] = "" if Manager.show_files_load_column + hash[:finish_in] = "" if Manager.show_finish_in_column + hash[:batch_run] = "" if Manager.show_batch_run_column + hash[:share_source_code] = "" if Manager.show_share_source_code_column + hash[:tests_runtime] = "" + hash[:hardware_specs] = "" + hash end def registered_agent?(agent_ip_address) @agents[agent_ip_address] end @@ -375,10 +557,70 @@ def register_agent(agent_ip_address) @agents[agent_ip_address] = agent_ip_address Liri.logger.info("\nStarted connection with Agent: #{agent_ip_address} in TCP port: #{@tcp_port}") end - def unregister_agent(agent_ip_address) - @agents.remove!(agent_ip_address) + def update_connected_agents(agent_ip_address) + unless @connected_agents[agent_ip_address] + @connected_agents[agent_ip_address] = agent_ip_address + update_agents_bar + end + end + + def update_working_agents(agent_ip_address) + unless @working_agents[agent_ip_address] + @working_agents[agent_ip_address] = agent_ip_address + update_agents_bar + end + end + + def update_agents_bar + @agents_bar.advance(1, connected: @connected_agents.size.to_s, working: @working_agents.size.to_s) + end + + def start_share_source_code_progress_bar(hardware_specs, msg) + if msg == 'proceed_get_source_code' && Manager.show_share_source_code_progress_bar + 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) + share_source_code_progress_bar.start + share_source_code_progress_bar.use(Common::TtyProgressbar::TimeFormatter) + Thread.new do + animation_count = 0 + while !share_source_code_progress_bar.stopped? + share_source_code_progress_bar.advance(1, agent: hardware_specs) + + share_source_code_progress_bar.update(unknown: Common::TtyProgressbar::ANIMATION2[animation_count]) + animation_count += 1 + animation_count = 0 if animation_count == 3 + + sleep(0.1) + end + end + end + share_source_code_progress_bar + end + + def stop_share_source_code_progress_bar(hardware_specs, share_source_code_progress_bar) + if Manager.show_share_source_code_progress_bar + share_source_code_progress_bar.update(total: 1, agent: hardware_specs) + share_source_code_progress_bar.stop + end + end + + def start_tests_running_progress_bar + @semaphore.synchronize do + # Es importante hacer un reset acá osino va a contar desde que se instancia y no desde que se inicia la ejecución + # del primer test. Solo se resetea si esta paused para evitar que al conectarse con cada Agent se vuelva a resetear + @tests_running_progress_bar.reset if @tests_running_progress_bar.paused? + Thread.new do + while !@tests_running_progress_bar.stopped? + @tests_running_progress_bar.advance(0) + sleep(0.1) # Es importante que las otras barras tambien tengan el mismo sleep para que sean mas consistentes en sus resultados + end + end + end + end + + def to_duration(value) + Common::Duration.humanize(value, times_round: Liri.times_round, times_round_type: Liri.times_round_type) end end end \ No newline at end of file