Class: Liri::Agent

Inherits:
Object
  • Object
show all
Defined in:
lib/agent/agent.rb,
lib/agent/runner.rb

Defined Under Namespace

Classes: Runner

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(udp_port, tcp_port, source_code, runner, tests_result, agent_folder_path) ⇒ Agent

Returns a new instance of Agent.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/agent/agent.rb', line 38

def initialize(udp_port, tcp_port, source_code, runner, tests_result, agent_folder_path)
  @udp_port = udp_port
  @udp_socket = UDPSocket.new
  @tcp_port = tcp_port

  @source_code = source_code
  @runner = runner
  @tests_result = tests_result

  @all_tests = {}

  @managers = {}

  @agent_folder_path = agent_folder_path
end

Instance Attribute Details

#managersObject (readonly)

Returns the value of attribute managers.



9
10
11
# File 'lib/agent/agent.rb', line 9

def managers
  @managers
end

Class Method Details

.run(work_folder_path, stop = false) ⇒ Object

Inicia la ejecución del Agent

Parameters:

  • stop (Boolean) (defaults to: false)

    el valor true es para que no se ejecute infinitamente el método en el test unitario.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/agent/agent.rb', line 14

def run(work_folder_path, stop = false)
  setup_manager = Liri.set_setup(work_folder_path)
  agent_folder_path = setup_manager.agent_folder_path

  Liri.set_logger(setup_manager.logs_folder_path, 'liri-agent.log')
  Liri.logger.info("Proceso Agent iniciado")
  Liri.logger.info("Presione Ctrl + c para terminar el proceso Agent manualmente\n", true)

  decompressed_source_code_path = File.join(agent_folder_path, '/', Common::SourceCode::DECOMPRESSED_FOLDER_NAME)
  source_code = Common::SourceCode.new(decompressed_source_code_path, agent_folder_path, Liri.compression_class, Liri.unit_test_class)
  runner = Agent::Runner.new(Liri.unit_test_class, source_code.decompressed_file_folder_path)
  tests_result = Common::TestsResult.new(agent_folder_path)
  agent = Agent.new(Liri.udp_port, Liri.tcp_port, source_code, runner, tests_result, agent_folder_path)
  threads = []
  threads << agent.start_server_socket_to_process_manager_connection_request # Esperar y procesar la petición de conexión del Manager

  Liri.init_exit(stop, threads, 'Agent')
  Liri.logger.info("Proceso Agent terminado")
rescue SignalException => e
  Liri.logger.info("Exception(#{e}) Proceso Agent terminado manualmente")
  Liri.kill(threads)
end

Instance Method Details

#start_client_socket_to_process_tests(manager_ip_address, manager_data) ⇒ Object

Inicia un cliente tcp para responder a la petición broadcast del Manager para que éste sepa donde enviar las pruebas



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/agent/agent.rb', line 80

def start_client_socket_to_process_tests(manager_ip_address, manager_data)
  tcp_socket = TCPSocket.open(manager_ip_address, @tcp_port)

  agent_ip_address = tcp_socket.addr[2]

  tcp_socket.puts({ msg: 'Listo' }) # Se envía un mensaje inicial al Manager

  Liri.logger.info("Se inicia una conexión para procesar pruebas con el Manager: #{manager_ip_address} en el puerto TCP: #{@tcp_port}")
  Liri.logger.info("\nConexión iniciada con el Manager: #{manager_ip_address}", true)

  # En la siguiente línea se espera un puts desde el Manager, pero el Manager no lo hace
  response = JSON.parse(tcp_socket.gets)
  return unless response['exist_tests']

  get_source_code(manager_ip_address, manager_data)

  # Se procesan las pruebas enviadas por el Manager
  while line = tcp_socket.gets
    response = line.chop
    break if response == 'exit'

    tests_batch = JSON.parse(response)
    tests = get_tests(tests_batch, manager_ip_address)

    raw_tests_result = @runner.run_tests(tests)

    tests_batch_number = tests_batch['tests_batch_number']
    tests_result_file_name = @tests_result.build_file_name(agent_ip_address, tests_batch_number)
    tests_result_file_path = @tests_result.save(tests_result_file_name, raw_tests_result)

    send_tests_results_file(manager_ip_address, manager_data, tests_result_file_path)
    result = { tests_batch_number: tests_batch_number, tests_result_file_name: tests_result_file_name, tests_batch_keys_size: tests_batch['tests_batch_keys'].size}
    tcp_socket.puts(result.to_json) # Envía el número de lote y el nombre del archivo de resultados.
  end

  tcp_socket.close
  Liri.logger.info("Se termina la conexión con el Manager #{manager_ip_address} en el puerto TCP: #{@tcp_port}")

  Liri.clean_folder_content(@agent_folder_path)

  start_client_to_close_manager_server(manager_ip_address, 'Conexión Terminada')
  unregister_manager(manager_ip_address)
rescue Errno::EADDRINUSE => e
  Liri.logger.error("Exception(#{e}) Puerto TCP #{@tcp_port} ocupado")
rescue Errno::ECONNRESET => e
  tcp_socket.close
  Liri.logger.error("Exception(#{e}) Conexión cerrada en el puerto TCP #{@tcp_port}")
  Liri.logger.info("Se termina la conexión con el Manager #{manager_ip_address} en el puerto TCP: #{@tcp_port}")
  unregister_manager(manager_ip_address)
rescue Errno::ECONNREFUSED => e
  Liri.logger.error("Exception(#{e}) Conexión rechazada en el puerto TCP #{@tcp_port}")
  Liri.logger.info("Se termina la conexión con el Manager #{manager_ip_address} en el puerto TCP: #{@tcp_port}")
  unregister_manager(manager_ip_address)
end

#start_server_socket_to_process_manager_connection_requestObject

Inicia un servidor udp que se mantiene en espera de la primera petición de conexión del Manager



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/agent/agent.rb', line 55

def start_server_socket_to_process_manager_connection_request
  # El servidor udp se ejecuta en bucle dentro de un hilo, esto permite realizar otras tareas mientras este hilo sigue esperando
  # 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
  Thread.new do
    BasicSocket.do_not_reverse_lookup = true
    begin
      @udp_socket.bind('0.0.0.0', @udp_port)
    rescue Errno::EADDRINUSE => e
      Liri.logger.error("Exception(#{e}) Puerto UDP #{@udp_port} ocupado")
      Thread.exit
    end
    Liri.logger.info("En espera de peticiones de Managers en el puerto UDP #{@udp_port}
                                 (Se espera que algún Manager se contacte por primera vez para establecer una conexión TCP)
    ")

    loop do
      @manager_request = @udp_socket.recvfrom(1024)
      manager_ip_address = @manager_request.last.last
      manager_data = get_manager_data(JSON.parse(@manager_request.first))
      process_manager_connection_request(manager_ip_address, manager_data)
    end
  end
end