liri 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,7 +8,7 @@ module Liri
8
8
  module Common
9
9
  # Esta clase se encarga de guardar y procesar el archivo de resultados
10
10
  class TestsResult
11
- attr_reader :examples, :failures, :pending, :passed, :files_processed
11
+ attr_reader :examples, :failures, :pending, :passed
12
12
 
13
13
  def initialize(folder_path)
14
14
  @folder_path = folder_path
@@ -18,9 +18,9 @@ module Liri
18
18
  @passed = 0
19
19
  @finish_in = 0
20
20
  @files_load = 0
21
- @files_processed = 0
22
21
  @failures_list = ''
23
22
  @failed_examples = ''
23
+ @failed_files = ''
24
24
  end
25
25
 
26
26
  def save(file_name, raw_tests_result)
@@ -29,34 +29,36 @@ module Liri
29
29
  file_path
30
30
  end
31
31
 
32
- def build_file_name(agent_ip_address, tests_batch_number)
33
- "batch_#{tests_batch_number}_agent_#{agent_ip_address}_tests_results"
32
+ def build_file_name(agent_ip_address, batch_num)
33
+ "batch_#{batch_num}_agent_#{agent_ip_address}_tests_results"
34
34
  end
35
35
 
36
36
  # Procesa el resultado crudo de las pruebas unitarias y lo devuelve en formato hash manejable
37
37
  # Ejemplo del hash retornado:
38
38
  # { examples: 0, failures: 0, pending: 0, passed: 0, finish_in: 0, files_load: 0,
39
39
  # failures_list: '', failed_examples: '' }
40
- def process(tests_result_file_name, files_processed)
40
+ def process(tests_result_file_name)
41
41
  file_path = File.join(@folder_path, '/', tests_result_file_name)
42
+ # A veces no se encuentra el archivo de resultados, la siguiente condicional es para evitar errores relativos a esto
43
+ return {} unless File.exist?(file_path)
44
+
42
45
  result_hash = process_tests_result_file(file_path)
43
- result_hash[:files_processed] = files_processed
44
46
  update_partial_result(result_hash)
45
47
  result_hash
46
48
  end
47
49
 
48
50
  def print_summary
49
- puts "\n#{@examples} examples, #{@failures} failures, #{@pending} pending\n\n"
51
+ Liri.logger.info("\n#{@examples} examples, #{@passed} passed, #{@failures} failures\n", true)
50
52
  end
51
53
 
52
- def print_failures_list
53
- puts "\nFailures: " unless @failures_list.empty?
54
- puts @failures_list
54
+ def print_detailed_failures
55
+ Liri.logger.info("\nFailures: ", true) unless @failures_list.empty?
56
+ Liri.logger.info(@failures_list, true)
55
57
  end
56
58
 
57
- def print_failed_examples
58
- puts "\nFailed examples: " unless @failed_examples.empty?
59
- puts @failed_examples
59
+ def print_summary_failures
60
+ Liri.logger.info("\nFailed examples: ", true) unless @failed_examples.empty?
61
+ Liri.logger.info(@failed_examples, true)
60
62
  end
61
63
 
62
64
  private
@@ -67,7 +69,7 @@ module Liri
67
69
  # {result: '.F', failures: '', examples: 2, failures: 1, failed_examples: ''}
68
70
  def process_tests_result_file(file_path)
69
71
  result_hash = { examples: 0, failures: 0, pending: 0, passed: 0, finish_in: 0, files_load: 0,
70
- failures_list: '', failed_examples: '' }
72
+ failures_list: '', failed_examples: '', failed_files: '' }
71
73
  flag = ''
72
74
  @failures_lists_count = @failures
73
75
  File.foreach(file_path) do |line|
@@ -106,7 +108,10 @@ module Liri
106
108
  result_hash[:pending] = values[:pending]
107
109
  flag = ''
108
110
  when 'Failed'
109
- result_hash[:failed_examples] << line if line.strip.start_with?('rspec')
111
+ if line.strip.start_with?('rspec')
112
+ result_hash[:failed_examples] << line
113
+ result_hash[:failed_files] << "#{failed_example(line)}\n"
114
+ end
110
115
  end
111
116
  end
112
117
 
@@ -118,9 +123,9 @@ module Liri
118
123
  @failures += hash_result[:failures]
119
124
  @pending += hash_result[:pending]
120
125
  @passed += hash_result[:passed]
121
- @files_processed += hash_result[:files_processed]
122
126
  @failures_list << hash_result[:failures_list]
123
127
  @failed_examples << hash_result[:failed_examples]
128
+ @failed_files << hash_result[:failed_files]
124
129
  end
125
130
 
126
131
  def finish_in_values(line)
@@ -131,6 +136,13 @@ module Liri
131
136
  UnitTest::RspecResultParser.finished_summary_values(line)
132
137
  end
133
138
 
139
+ def failed_example(line)
140
+ # get string like this "/spec/failed_spec.rb:4"
141
+ failed_example = UnitTest::RspecResultParser.failed_example(line)
142
+ # return "failed_spec.rb:4"
143
+ failed_example.split("/").last
144
+ end
145
+
134
146
  def fix_failure_number(line)
135
147
  line_number_regex = /(\d+\))/
136
148
  if line.strip.start_with?(line_number_regex)
@@ -38,8 +38,12 @@ module Liri
38
38
  when 'minute', 'minutes' then time * 60
39
39
  when 'hour', 'hours' then time * 3600
40
40
  when 'day', 'days' then time * 86_400
41
- end
42
- time_in_seconds.to_f
41
+ end
42
+
43
+ # time in seconds puede contener valores BigDecimal como este 0.744e2 que al hacerle to_f devuelve 74.4
44
+ # Aún así conviene mantener el valor en BigDecimal para las operaciones matematicas y solo cuando se va a mostrar
45
+ # los datos en pantalla se debe hacer el to_f
46
+ time_in_seconds
43
47
  end
44
48
  end
45
49
  end
@@ -0,0 +1,70 @@
1
+ # = tty_progressbar.rb
2
+ #
3
+ # @author Rodrigo Fernández
4
+ #
5
+ # == Módulo TtyProgressbar
6
+ require "tty-progressbar"
7
+
8
+ module Liri
9
+ module Common
10
+ # Este módulo se encarga de mostrar una barra de progreso
11
+ module TtyProgressbar
12
+ ANIMATION = [
13
+ "■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□",
14
+ "□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■",
15
+ "□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□",
16
+ "□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□□■□□",
17
+ ]
18
+
19
+ ANIMATION2 = [
20
+ "■□□□■□□□■□□□■□□□■□□",
21
+ "□■□□□■□□□■□□□■□□□■□",
22
+ "□□■□□□■□□□■□□□■□□□■",
23
+ "□□□■□□□■□□□■□□□■□□□",
24
+ ]
25
+ class << self
26
+ # Example:
27
+ # Common::TtyProgressbar.start("Compressing source code |:bar| Time: :elapsed", total: nil, width: 80) do
28
+ # ...code
29
+ # end
30
+ def start(format, params = {})
31
+ params[:unknown] = ANIMATION[0]
32
+ progressbar = TTY::ProgressBar.new(format, params)
33
+ # Es importante iniciar la barra porque TimeFormatter.call accede a su start_time y si no se inició la barra
34
+ # entonces ocurre un error
35
+ progressbar.start
36
+ progressbar.use(Common::TtyProgressbar::TimeFormatter)
37
+
38
+ Thread.new do
39
+ animation_count = 0
40
+ while !progressbar.stopped?
41
+ progressbar.advance
42
+
43
+ progressbar.update(unknown: ANIMATION[animation_count])
44
+ animation_count += 1
45
+ animation_count = 0 if animation_count == 3
46
+
47
+ sleep(0.1)
48
+ end
49
+ end
50
+ yield
51
+ progressbar.update(total: 1) # Esto hace que la barra cambie a al estilo completado con un porcentaje del 100%
52
+ progressbar.stop
53
+ rescue TypeError
54
+ # Se captura la excepción solo para evitar un error en start_time mas abajo
55
+ end
56
+ end
57
+
58
+ # From
59
+ class TimeFormatter
60
+ include TTY::ProgressBar::Formatter[/:time/i]
61
+
62
+ def call(value) # specify how display string is formatted
63
+ # access current progress bar instance to read start time
64
+ elapsed = Duration.humanize(Time.now - progress.start_time, times_round: Liri.times_round, times_round_type: Liri.times_round_type)
65
+ value.gsub(matcher, elapsed) # replace :time token with a value
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -25,6 +25,16 @@ module Liri
25
25
  { examples: examples.to_i, failures: failures.to_i, pending: pending.to_i }
26
26
  end
27
27
 
28
+ # Received string like this "rspec ./spec/failed_spec.rb:4 # Liri debería fallar a propósito" and
29
+ # return string like this "/spec/failed_spec.rb:4"
30
+ # or for "rspec ./spec/system/management/budget_investments_spec.rb[1:3:1:3] # Budget Investments behaves like mappable At new_management_budget_investment_path Should create budget_investment with map"
31
+ # return "/spec/system/management/budget_investments_spec.rb[1:3:1:3]"
32
+ def failed_example(failed_example_line)
33
+ values = failed_example_line.to_s.match(/(\/.+.rb:\d+)/)
34
+ values ||= failed_example_line.to_s.match(/(\/.+.rb.*\])/)
35
+ values[1] # failed_example
36
+ end
37
+
28
38
  private
29
39
 
30
40
  def text_value_to_seconds(text)
data/lib/hash_extend.rb CHANGED
@@ -56,4 +56,11 @@ class Hash
56
56
  keys.flatten.each { |key| delete(key) }
57
57
  self
58
58
  end
59
+
60
+ # Retorna un nuevo hash con los elementos borrados según las claves indicadas
61
+ def remove(*keys)
62
+ cloned_hash = self.clone
63
+ keys.flatten.each { |key| cloned_hash.delete(key) }
64
+ cloned_hash
65
+ end
59
66
  end
data/lib/liri.rb CHANGED
@@ -3,7 +3,7 @@
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.3.1'
6
+ VERSION = '0.4.0'
7
7
 
8
8
  class << self
9
9
  def set_setup(destination_folder_path, program, manager_tests_results_folder_time: nil)
@@ -44,16 +44,13 @@ module Liri
44
44
  @setup_manager ? @setup_manager.delete_setup_folder : false
45
45
  end
46
46
 
47
- def init_exit(stop, threads, program)
47
+ def init_exit(stop, threads)
48
48
  threads = threads.compact
49
49
  kill(threads) if stop
50
50
 
51
51
  # Con la siguiente línea se asegura que los hilos no mueran antes de que finalize el programa principal
52
52
  # Fuente: https://underc0de.org/foro/ruby/hilos-en-ruby/
53
53
  threads.each{|thread| thread.join}
54
- #rescue SignalException => e
55
- #puts "\nEjecución del #{program} terminada manualmente\n"
56
- #kill(threads)
57
54
  end
58
55
 
59
56
  def kill(threads)
@@ -66,39 +63,35 @@ module Liri
66
63
  end
67
64
 
68
65
  def compression_class
69
- "Liri::Common::Compressor::#{setup.library.compression}"
66
+ "Liri::Common::Compressor::#{setup.general.library.compression}"
70
67
  end
71
68
 
72
69
  def unit_test_class
73
- "Liri::Common::UnitTest::#{setup.library.unit_test}"
70
+ "Liri::Common::UnitTest::#{setup.general.library.unit_test}"
74
71
  end
75
72
 
76
73
  def udp_port
77
- setup.ports.udp
74
+ setup.general.ports.udp
78
75
  end
79
76
 
80
77
  def tcp_port
81
- setup.ports.tcp
78
+ setup.general.ports.tcp
82
79
  end
83
80
 
84
- def print_failures_list
85
- setup.print_failures_list
86
- end
87
-
88
- def print_failed_examples
89
- setup.print_failed_examples
81
+ def current_folder_ruby_and_gemset
82
+ "#{File.read('.ruby-version').strip}@#{File.read('.ruby-gemset').strip}"
90
83
  end
91
84
 
92
- def print_agents_detailed_summary
93
- setup.print_agents_detailed_summary
85
+ def ignored_folders_in_compress
86
+ setup.general.ignored_folders_in_compress
94
87
  end
95
88
 
96
- def udp_request_delay
97
- setup.udp_request_delay
89
+ def times_round
90
+ setup.general.times_round
98
91
  end
99
92
 
100
- def current_folder_ruby_and_gemset
101
- "#{File.read('.ruby-version').strip}@#{File.read('.ruby-gemset').strip}"
93
+ def times_round_type
94
+ setup.general.times_round_type.to_sym
102
95
  end
103
96
 
104
97
  private
@@ -113,7 +106,7 @@ module Liri
113
106
 
114
107
  # Inicializa y configura la librería encargada de loguear
115
108
  def load_logger(folder_path = nil, file_name = nil)
116
- log = Liri::Common::Log.new('daily', folder_path: folder_path, file_name: file_name, stdout: setup.log.stdout.show)
109
+ log = Liri::Common::Log.new('daily', folder_path: folder_path, file_name: file_name, stdout: setup.general.log.stdout.show)
117
110
  log
118
111
  end
119
112
  end
@@ -121,7 +114,14 @@ module Liri
121
114
  # EXCEPTIONS
122
115
  class FileNotFoundError < StandardError
123
116
  def initialize(file_path)
124
- msg = "No se encuentra el archivo #{file_path}"
117
+ msg = "File not found #{file_path}"
118
+ super(msg)
119
+ end
120
+ end
121
+
122
+ class InxiCommandNotFoundError < StandardError
123
+ def initialize
124
+ msg = "Inxi command not found"
125
125
  super(msg)
126
126
  end
127
127
  end
@@ -31,6 +31,11 @@ module Liri
31
31
  else
32
32
  return nil, nil
33
33
  end
34
+ rescue Psych::SyntaxError
35
+ # Este error ocurre cuando se guardan caracteres raros en el archivo liri-credentials.yml
36
+ # en este caso se borra el archivo y se pide de nuevo la contraseña
37
+ delete_credentials
38
+ return nil, nil
34
39
  end
35
40
 
36
41
  def ask_credentials
@@ -42,6 +47,15 @@ module Liri
42
47
  def save_credentials(user, password)
43
48
  File.write(@file_path, "user: #{user}\npassword: #{password}")
44
49
  end
50
+
51
+ def delete_credentials
52
+ if File.exist?(@file_path)
53
+ File.delete(@file_path)
54
+ File.exist?(@file_path) ? false : true
55
+ else
56
+ false
57
+ end
58
+ end
45
59
  end
46
60
  end
47
61
  end