liri 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rakeTasks +7 -0
- data/.rspec +8 -0
- data/.rubocop.yml +15 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +32 -0
- data/Gemfile.lock +76 -0
- data/LICENSE.txt +21 -0
- data/README.md +161 -0
- data/Rakefile +61 -0
- data/bin/bundle +114 -0
- data/bin/coderay +29 -0
- data/bin/commander +29 -0
- data/bin/htmldiff +29 -0
- data/bin/ldiff +29 -0
- data/bin/liri +29 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bin/ruby-parse +29 -0
- data/bin/ruby-rewrite +29 -0
- data/bin/yard +29 -0
- data/bin/yardoc +29 -0
- data/bin/yri +29 -0
- data/config/locales/to_duration_es.yml +25 -0
- data/exe/liri +73 -0
- data/lib/agent/agent.rb +235 -0
- data/lib/agent/runner.rb +19 -0
- data/lib/all_libraries.rb +30 -0
- data/lib/common/benchmarking.rb +36 -0
- data/lib/common/compressor/zip.rb +70 -0
- data/lib/common/log.rb +121 -0
- data/lib/common/source_code.rb +53 -0
- data/lib/common/unit_test/rspec.rb +91 -0
- data/lib/exe/agent.rb +5 -0
- data/lib/exe/manager.rb +5 -0
- data/lib/hash_extend.rb +57 -0
- data/lib/liri.rb +129 -0
- data/lib/manager/credential.rb +47 -0
- data/lib/manager/manager.rb +258 -0
- data/lib/manager/setup.rb +70 -0
- data/lib/manager/test_result.rb +38 -0
- data/lib/task.rb +15 -0
- data/liri.gemspec +58 -0
- data/template/liri-config.yml +28 -0
- metadata +182 -0
data/bin/htmldiff
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'htmldiff' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("diff-lcs", "htmldiff")
|
data/bin/ldiff
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'ldiff' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("diff-lcs", "ldiff")
|
data/bin/liri
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'liri' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("liri", "liri")
|
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/rubocop
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rubocop", "rubocop")
|
data/bin/ruby-parse
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'ruby-parse' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("parser", "ruby-parse")
|
data/bin/ruby-rewrite
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'ruby-rewrite' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("parser", "ruby-rewrite")
|
data/bin/yard
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'yard' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("yard", "yard")
|
data/bin/yardoc
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'yardoc' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("yard", "yardoc")
|
data/bin/yri
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'yri' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("yard", "yri")
|
@@ -0,0 +1,25 @@
|
|
1
|
+
es:
|
2
|
+
to_duration:
|
3
|
+
and: y
|
4
|
+
less_than_one_second: Menos de un segundo
|
5
|
+
year:
|
6
|
+
one: año
|
7
|
+
other: años
|
8
|
+
month:
|
9
|
+
one: mes
|
10
|
+
other: meses
|
11
|
+
week:
|
12
|
+
one: semana
|
13
|
+
other: semanas
|
14
|
+
day:
|
15
|
+
one: día
|
16
|
+
other: dias
|
17
|
+
hour:
|
18
|
+
one: hora
|
19
|
+
other: horas
|
20
|
+
minute:
|
21
|
+
one: minuto
|
22
|
+
other: minutos
|
23
|
+
second:
|
24
|
+
one: segundo
|
25
|
+
other: segundos
|
data/exe/liri
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Este script de ruby permite ejecutar el comando liri en CLI (interface de línea de comandos)
|
3
|
+
# From:
|
4
|
+
# - https://robdodson.me/how-to-write-a-command-line-ruby-gem/
|
5
|
+
# - https://medium.com/@stephenagrice/making-a-command-line-ruby-gem-write-build-and-push-aec24c6c49eb
|
6
|
+
# - https://www.sitepoint.com/ruby-command-line-interface-gems/
|
7
|
+
require 'rubygems'
|
8
|
+
require 'commander/import'
|
9
|
+
require 'liri'
|
10
|
+
require 'manager/manager'
|
11
|
+
require 'agent/agent'
|
12
|
+
|
13
|
+
program :name, Liri::NAME
|
14
|
+
program :version, Liri::VERSION
|
15
|
+
program :description, 'Ejecuta pruebas unitarias usando un sistema distribuido'
|
16
|
+
|
17
|
+
# Define el comando y los parámetros para el programa principal
|
18
|
+
command :manager do |c|
|
19
|
+
c.syntax = 'liri manager [options]'
|
20
|
+
c.summary = 'Ejecuta pruebas unitarias'
|
21
|
+
c.description = 'Ejecuta el programa principal que se conecta con uno o más programas agentes para organizar la ejecución de pruebas unitarias'
|
22
|
+
c.example 'Ejecuta el programa principal mostrando el resultado en línea de comandos', 'liri'
|
23
|
+
c.example 'Ejecuta el programa principal mostrando el resultado en línea de comandos', 'liri m'
|
24
|
+
c.example 'Ejecuta el programa principal mostrando el resultado en línea de comandos', 'liri manager'
|
25
|
+
c.example 'Ejecuta el programa principal guardando los resultados en un archivo .html', 'liri -o result.html'
|
26
|
+
c.option '-o', '--output [filename]', String, 'Especifica donde guardar los resultados de la ejecución de pruebas unitarias'
|
27
|
+
c.action do |args, options|
|
28
|
+
Liri::Common::Benchmarking.start(end_msg: "\nFinalizado en: ") do
|
29
|
+
# Metodo que se ejecuta al llamar al comando manager
|
30
|
+
Liri::Manager.run
|
31
|
+
end
|
32
|
+
puts ''
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Define el alias m para el comando manager
|
37
|
+
alias_command :m, :manager
|
38
|
+
# Define un texto vacío como alias lo que permite ejecutar el programa principal solamente usando el comando liri
|
39
|
+
#alias_command '', :manager
|
40
|
+
|
41
|
+
# Define el comando y los parámetros para el programa agente
|
42
|
+
command :agent do |c|
|
43
|
+
c.syntax = 'Liri agent [options]'
|
44
|
+
c.summary = 'Ejecuta el programa agente'
|
45
|
+
c.description = 'Espera las ordenes del programa principal para ejecutar pruebas unitarias'
|
46
|
+
c.example 'Ejecuta el programa agente', 'liri a'
|
47
|
+
c.example 'Ejecuta el programa agente', 'liri agent'
|
48
|
+
c.action do |args, options|
|
49
|
+
# Método que se ejecuta al llamar al comando agent
|
50
|
+
Liri::Agent.run
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Define el alias m para el comando agent
|
55
|
+
alias_command :a, :agent
|
56
|
+
|
57
|
+
# Define el comando y los parámetros para obtener la cantidad de tests
|
58
|
+
command :tests do |c|
|
59
|
+
c.syntax = 'Liri tests [options]'
|
60
|
+
c.summary = 'Retorna la cantidad total de tests'
|
61
|
+
c.description = 'Ejecuta el comando para obtener la cantidad total de tests del proyecto'
|
62
|
+
c.example 'Ejecuta el comando tests', 'liri t'
|
63
|
+
c.example 'Ejecuta el comando tests', 'liri tests'
|
64
|
+
c.action do |args, options|
|
65
|
+
# Método que se ejecuta al llamar al comando tests
|
66
|
+
tests_count = Liri::Task.tests_count
|
67
|
+
puts tests_count
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Define el alias t para el comando tests
|
72
|
+
alias_command :t, :tests
|
73
|
+
|
data/lib/agent/agent.rb
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
=begin
|
2
|
+
Este módulo es el punto de entrada del programa agente
|
3
|
+
=end
|
4
|
+
require 'net/scp'
|
5
|
+
require 'all_libraries'
|
6
|
+
|
7
|
+
module Liri
|
8
|
+
class Agent
|
9
|
+
attr_reader :managers
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Inicia la ejecución del Agent
|
13
|
+
# @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)
|
15
|
+
Liri.create_folders('agent')
|
16
|
+
|
17
|
+
Liri.set_logger(Liri::AGENT_LOGS_FOLDER_PATH, 'liri-agent.log')
|
18
|
+
Liri.logger.info("Proceso Agent iniciado")
|
19
|
+
puts "Presione Ctrl + c para terminar el proceso Agent manualmente\n\n"
|
20
|
+
|
21
|
+
source_code = Liri::Common::SourceCode.new(Liri::AGENT_FOLDER_PATH, Liri.compression_class, Liri.unit_test_class)
|
22
|
+
runner = Liri::Agent::Runner.new(Liri.unit_test_class, source_code.decompressed_file_folder_path)
|
23
|
+
agent = Agent.new(Liri.udp_port, Liri.tcp_port, source_code, runner)
|
24
|
+
threads = []
|
25
|
+
threads << agent.start_server_socket_to_process_manager_connection_request # Esperar y procesar la petición de conexión del Manager
|
26
|
+
|
27
|
+
Liri.init_exit(stop, threads, 'Agent')
|
28
|
+
Liri.logger.info("Proceso Agent terminado")
|
29
|
+
rescue SignalException => e
|
30
|
+
Liri.logger.info("Exception(#{e}) Proceso Agent terminado manualmente")
|
31
|
+
Liri.kill(threads)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(udp_port, tcp_port, source_code, runner)
|
36
|
+
@udp_port = udp_port
|
37
|
+
@udp_socket = UDPSocket.new
|
38
|
+
@tcp_port = tcp_port
|
39
|
+
|
40
|
+
@source_code = source_code
|
41
|
+
@runner = runner
|
42
|
+
|
43
|
+
@managers = {}
|
44
|
+
end
|
45
|
+
|
46
|
+
# Inicia un servidor udp que se mantiene en espera de la primera petición de conexión del Manager
|
47
|
+
def start_server_socket_to_process_manager_connection_request
|
48
|
+
# El servidor udp se ejecuta en bucle dentro de un hilo, esto permite realizar otras tareas mientras este hilo sigue esperando
|
49
|
+
# que un Manager se conecte, cuando se conecta un Manager, se guarda la ip de este manager y se vuelve a esperar otra petición
|
50
|
+
Thread.new do
|
51
|
+
BasicSocket.do_not_reverse_lookup = true
|
52
|
+
begin
|
53
|
+
@udp_socket.bind('0.0.0.0', @udp_port)
|
54
|
+
rescue Errno::EADDRINUSE => e
|
55
|
+
Liri.logger.error("Exception(#{e}) Puerto UDP #{@udp_port} ocupado")
|
56
|
+
Thread.exit
|
57
|
+
end
|
58
|
+
Liri.logger.info("En espera de peticiones de Managers en el puerto UDP #{@udp_port}
|
59
|
+
(Se espera que algún Manager se contacte por primera vez para establecer una conexión TCP)
|
60
|
+
")
|
61
|
+
|
62
|
+
loop do
|
63
|
+
@manager_request = @udp_socket.recvfrom(1024)
|
64
|
+
manager_ip_address = @manager_request.last.last
|
65
|
+
user, pass, dir = @manager_request.first.split(";")
|
66
|
+
process_manager_connection_request(manager_ip_address, user, pass, dir)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Inicia un cliente tcp para responder a la petición broadcast del Manager para que éste sepa donde enviar las pruebas
|
72
|
+
def start_client_socket_to_process_tests(manager_ip_address)
|
73
|
+
tcp_socket = TCPSocket.open(manager_ip_address, @tcp_port)
|
74
|
+
|
75
|
+
Liri.logger.info("Se inicia una conexión con el Manager: #{manager_ip_address} en el puerto TCP: #{@tcp_port}
|
76
|
+
(Se establece una conexión para procesar la ejecución de las pruebas)
|
77
|
+
")
|
78
|
+
|
79
|
+
tcp_socket.print("Listo para ejecutar pruebas") # Se envía un mensaje inicial al Manager
|
80
|
+
puts "\nConexión iniciada con el Manager: #{manager_ip_address}"
|
81
|
+
|
82
|
+
# Se procesan las pruebas enviadds por el Manager
|
83
|
+
while line = tcp_socket.gets
|
84
|
+
response = line.chop
|
85
|
+
break if response == 'exit'
|
86
|
+
|
87
|
+
tests = JSON.parse(response)
|
88
|
+
Liri.logger.debug("Pruebas recibidas del Manager #{manager_ip_address}:")
|
89
|
+
Liri.logger.debug(tests)
|
90
|
+
|
91
|
+
tests_result = @runner.run_tests(tests)
|
92
|
+
|
93
|
+
json_tests_result = tests_result.to_json
|
94
|
+
Liri.logger.debug("Resultados de la ejecución de las pruebas recibidas del Manager #{manager_ip_address}:")
|
95
|
+
Liri.logger.debug(json_tests_result)
|
96
|
+
|
97
|
+
Liri.logger.info("
|
98
|
+
#{tests.size} pruebas recibidas, #{tests_result[:example_quantity]} pruebas ejecutadas
|
99
|
+
")
|
100
|
+
tcp_socket.print(json_tests_result) # Este no logra enviar toda la información, porque? en cambio el cliente recibe un json grande sin problemas
|
101
|
+
end
|
102
|
+
|
103
|
+
tcp_socket.close
|
104
|
+
Liri.logger.info("Se termina la conexión con el Manager #{manager_ip_address}")
|
105
|
+
|
106
|
+
Liri.clean_folder(Liri::AGENT_FOLDER_PATH)
|
107
|
+
|
108
|
+
start_client_to_close_manager_server(manager_ip_address, 'Conexión Terminada')
|
109
|
+
unregister_manager(manager_ip_address)
|
110
|
+
rescue Errno::EADDRINUSE => e
|
111
|
+
Liri.logger.error("Exception(#{e}) Puerto TCP #{@tcp_port} ocupado")
|
112
|
+
rescue Errno::ECONNRESET => e
|
113
|
+
tcp_socket.close
|
114
|
+
Liri.logger.error("Exception(#{e}) Conexión cerrada en el puerto TCP #{@tcp_port}")
|
115
|
+
Liri.logger.info("Se termina la conexión con el Manager #{manager_ip_address}")
|
116
|
+
unregister_manager(manager_ip_address)
|
117
|
+
rescue Errno::ECONNREFUSED => e
|
118
|
+
Liri.logger.error("Exception(#{e}) Conexión rechazada en el puerto TCP #{@tcp_port}")
|
119
|
+
Liri.logger.info("Se termina la conexión con el Manager #{manager_ip_address}")
|
120
|
+
unregister_manager(manager_ip_address)
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# Inserta el ip recibido dentro del hash si es que ya no existe en el hash
|
126
|
+
# Nota: Se requieren imprimir datos para saber el estado de la aplicación, sería muy útil usar algo para logear
|
127
|
+
# estas cosas en los diferentes niveles, debug, info, etc.
|
128
|
+
def process_manager_connection_request(manager_ip_address, user, pass, dir)
|
129
|
+
unless registered_manager?(manager_ip_address)
|
130
|
+
register_manager(manager_ip_address)
|
131
|
+
Liri.logger.info("Petición broadcast UDP recibida del Manager: #{manager_ip_address} en el puerto UDP: #{@udp_port}")
|
132
|
+
if process_manager_connection_scp(manager_ip_address, user, pass, dir)
|
133
|
+
start_client_socket_to_process_tests(manager_ip_address)
|
134
|
+
else
|
135
|
+
unregister_manager(manager_ip_address)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Se establece una nueva comunicación con el servidor TCP del Manager con el único objetivo de cerrar el servidor
|
141
|
+
# Esta conexión permitirá al Manager cerrar sus hilos pendientes con servidores TCP en espera y terminar el proceso
|
142
|
+
def start_client_to_close_manager_server(manager_ip_address, msg)
|
143
|
+
tcp_socket = TCPSocket.open(manager_ip_address, @tcp_port)
|
144
|
+
Liri.logger.info("Se termina cualquier proceso pendiente con el Manager #{manager_ip_address}")
|
145
|
+
tcp_socket.print({msg: msg}.to_json)
|
146
|
+
tcp_socket.close
|
147
|
+
end
|
148
|
+
|
149
|
+
def process_manager_connection_scp(manager_ip_address, user, password, dir)
|
150
|
+
# puts "User: #{user} Password: #{password}"
|
151
|
+
puts ''
|
152
|
+
Liri::Common::Benchmarking.start(start_msg: "Obteniendo código fuente. Espere... ") do
|
153
|
+
puts ''
|
154
|
+
Net::SCP.start(manager_ip_address, user, :password => password) do |scp|
|
155
|
+
scp.download!(dir, @source_code.compressed_file_folder_path)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
puts ''
|
159
|
+
|
160
|
+
downloaded_file_name = dir.split('/').last
|
161
|
+
downloaded_file_path = File.join(@source_code.compressed_file_folder_path, '/', downloaded_file_name)
|
162
|
+
|
163
|
+
Liri::Common::Benchmarking.start(start_msg: "Descomprimiendo código fuente. Espere... ") do
|
164
|
+
@source_code.decompress_file(downloaded_file_path)
|
165
|
+
end
|
166
|
+
puts ''
|
167
|
+
|
168
|
+
# Se cambia temporalmente la carpeta de trabajo a la carpeta de código fuente descomprimida
|
169
|
+
Dir.chdir(@source_code.decompressed_file_folder_path) do
|
170
|
+
# Se borra el directorio .git para evitar el siguiente error al ejecutar las pruebas: fatal: not a git repository (or any of the parent directories): .git
|
171
|
+
# Una mejor alternativa es no traer siquiera esa carpeta junto al código fuente excluyendo la carpeta .git al comprimir el código fuente.
|
172
|
+
# Por cuestiones de tiempo se procede a borrar la carpeta .git por ahora, aunque al parecer el error mostrado no afecta la ejecución del Agent
|
173
|
+
# Al realizar pruebas, el error mencionado se sigue viendo en producción así que no es seguro que este borrado de la carpeta .git solucione el problema
|
174
|
+
git_folder_path = File.join(Dir.pwd, '/.git')
|
175
|
+
FileUtils.rm_rf(git_folder_path) if Dir.exist?(git_folder_path)
|
176
|
+
|
177
|
+
# Descomentar para la depuración en entorno de desarrollo (Creo que aún así no se puede depurar)
|
178
|
+
# system("bundle install")
|
179
|
+
# Descomentar para el entorno de producción
|
180
|
+
# Se setea la versión de ruby y el gemset para el código fuente descomprimido
|
181
|
+
# Se especifica el Gemfile del cual se van a instalar los requerimientos
|
182
|
+
# Esto se hace porque por defecto se usa la versión de Ruby de Liri y su Gemset y por ello hay que cambiarlos explicitamente aquí
|
183
|
+
Liri::Common::Benchmarking.start(start_msg: "Ejecutando bundle install. Espere... ", end_msg: "Ejecución de bundle install. Duración: ") do
|
184
|
+
puts ''
|
185
|
+
system("bash -lc 'rvm use #{Liri.current_folder_ruby_and_gemset}; BUNDLE_GEMFILE=Gemfile bundle install'")
|
186
|
+
end
|
187
|
+
puts ''
|
188
|
+
|
189
|
+
Liri::Common::Benchmarking.start(start_msg: "Ejecutando rake db:migrate RAILS_ENV=test. Espere... ", end_msg: "Ejecución de rake db:migrate RAILS_ENV=test. Duración: ") do
|
190
|
+
puts ''
|
191
|
+
system("bash -lc 'rvm use #{Liri.current_folder_ruby_and_gemset}; rake db:migrate RAILS_ENV=test'")
|
192
|
+
end
|
193
|
+
puts ''
|
194
|
+
|
195
|
+
#Liri::Common::Benchmarking.start(start_msg: "Ejecutando rake db:migrate:reset RAILS_ENV=test. Espere... ", end_msg: "Ejecución de rake db:migrate:reset RAILS_ENV=test. Duración: ") do
|
196
|
+
# puts ''
|
197
|
+
# system("bash -lc 'rvm use #{Liri.current_folder_ruby_and_gemset}; rake db:migrate:reset RAILS_ENV=test'")
|
198
|
+
#end
|
199
|
+
#puts ''
|
200
|
+
end
|
201
|
+
true
|
202
|
+
rescue Errno::ECONNREFUSED => e
|
203
|
+
Liri.logger.error("Exception(#{e}) Conexión rechazada por #{manager_ip_address}. Posiblemente ssh no esté ejecutandose en #{manager_ip_address}")
|
204
|
+
false
|
205
|
+
rescue Errno::ENOTTY => e
|
206
|
+
# Este rescue es temporal, hay que ver una mejor manera de detectar si la contraseña es incorrecta
|
207
|
+
Liri.logger.error("Exception(#{e}) Contraseña incorrecta recibida de #{manager_ip_address} para la conexión ssh")
|
208
|
+
start_client_to_close_manager_server(manager_ip_address, "No se puede obtener el archivo de código fuente. Posiblemente se envío una contraseña incorrencta desde #{manager_ip_address}")
|
209
|
+
false
|
210
|
+
rescue Net::SSH::AuthenticationFailed => e
|
211
|
+
# Este rescue es temporal, hay que ver una mejor manera de detectar si la contraseña es incorrecta
|
212
|
+
Liri.logger.error("Exception(#{e}) Contraseña incorrecta recibida de #{manager_ip_address} para la conexión ssh")
|
213
|
+
start_client_to_close_manager_server(manager_ip_address, "No se puede obtener el archivo de código fuente. Posiblemente se envío una contraseña incorrencta desde #{manager_ip_address}")
|
214
|
+
false
|
215
|
+
rescue Net::SCP::Error => e
|
216
|
+
Liri.logger.warn("Exception(#{e}) Archivo no encontrado en #{manager_ip_address} a través de scp")
|
217
|
+
false
|
218
|
+
rescue TypeError => e
|
219
|
+
Liri.logger.warn("Exception(#{e}) Error indeterminado")
|
220
|
+
false
|
221
|
+
end
|
222
|
+
|
223
|
+
def registered_manager?(manager_ip_address)
|
224
|
+
@managers[manager_ip_address]
|
225
|
+
end
|
226
|
+
|
227
|
+
def register_manager(manager_ip_address)
|
228
|
+
@managers[manager_ip_address] = manager_ip_address
|
229
|
+
end
|
230
|
+
|
231
|
+
def unregister_manager(manager_ip_address)
|
232
|
+
@managers.remove!(manager_ip_address)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|