liri 0.1.0 → 0.2.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.
@@ -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