package com.rzg.zombieland.server.comunicacion;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.UUID;
import java.util.concurrent.BrokenBarrierException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.google.gson.Gson;
import com.rzg.zombieland.comunes.comunicacion.Enviable;
import com.rzg.zombieland.comunes.comunicacion.HiloEscucha;
import com.rzg.zombieland.comunes.comunicacion.pojo.POJOPartida;
import com.rzg.zombieland.comunes.comunicacion.pojo.POJOUnirsePartida;
import com.rzg.zombieland.comunes.comunicacion.respuesta.RespuestaGenerica;
import com.rzg.zombieland.comunes.comunicacion.respuesta.RespuestaUnirsePartida;
import com.rzg.zombieland.comunes.controlador.ControladorTest;
import com.rzg.zombieland.comunes.misc.ZombielandException;
import com.rzg.zombieland.server.comunicacion.controlador.ControladorServidorFactory;
import com.rzg.zombieland.server.controlador.AbstractPartidasTest;
import com.rzg.zombieland.server.meta.Partida;
import com.rzg.zombieland.server.persistencia.HibernateSingleton;
import com.rzg.zombieland.server.sesion.Jugador;
import com.rzg.zombieland.server.sesion.ServicioSesion;
import com.rzg.zombieland.server.sesion.Sesion;
/**
* Prueba la recepci�n completa de una petici�n.
* @author nicolas
*
*/
public class RecepecionPeticionTest extends AbstractPartidasTest {
// El servicio de escucha que se prueba.
private static ServicioEscucha servicioEscucha;
private Socket socket;
// Salida y entrada conectada al servicio de escucha.
private PrintWriter salida;
private BufferedReader entrada;
private InputStreamReader reader;
private final String host = "localhost";
private final int puerto = 2048;
private final static String LINEA_ENVIO = "Chau socket :)";
private int TIEMPO_SLEEP = 5;
private int MAX_TIEMPO = 5000;
private int CANTIDAD_INTENTOS = 100;
/**
* Levanta al servidor y al cliente para el test.
* @throws UnknownHostException
* @throws IOException
* @throws ZombielandException
* @throws InterruptedException
*/
@Before
public void prepararCliente() throws UnknownHostException, IOException, ZombielandException, InterruptedException {
HibernateSingleton.setTest();
servicioEscucha = new ServicioEscucha();
servicioEscucha.start();
socket = new Socket(host, puerto);
salida = new PrintWriter(socket.getOutputStream());
reader = new InputStreamReader(socket.getInputStream());
entrada = new BufferedReader(reader);
int vueltas = 0;
while (servicioEscucha.getHilos().size() != 1) {
Thread.sleep(TIEMPO_SLEEP);
vueltas++;
assertFalse(vueltas * TIEMPO_SLEEP > MAX_TIEMPO);
}
}
/**
* Mata al cliente y al servidor.
* @throws IOException
* @throws InterruptedException
*/
@After
public void cerrarCliente() throws IOException, InterruptedException {
entrada.close();
salida.close();
reader.close();
socket.close();
servicioEscucha.cerrar();
servicioEscucha.join();
}
/**
* Intenta recibir una petici�n de pruebas, que solo devuelve un eco.
* @throws IOException
* @throws InterruptedException
* @throws BrokenBarrierException
*/
@Test
public void testRecepcionPeticion() throws IOException, InterruptedException, BrokenBarrierException {
salida.write(Enviable.TEST);
UUID uuid = UUID.randomUUID();
salida.println(uuid);
salida.println(LINEA_ENVIO);
salida.flush();
int codigoRespuesta = entrada.read();
String uuidRecibido = entrada.readLine();
String lineaEntrada = entrada.readLine();
assertEquals(codigoRespuesta, Enviable.RESPUESTA);
assertEquals(lineaEntrada, LINEA_ENVIO);
assertEquals(uuid.toString(), uuidRecibido);
assertTrue(ControladorTest.proceso(LINEA_ENVIO));
}
/**
* Env�a una petici�n desconocida y esperar un error por respuesta.
* @throws IOException
* @throws InterruptedException
* @throws BrokenBarrierException
*/
@Test
public void testRecepcionPeticionNoConocida() throws IOException, InterruptedException, BrokenBarrierException {
final String LINEA_ENVIO = "testRecepcionPeticionNoConocida";
salida.write(0xFF);
UUID uuid = UUID.randomUUID();
salida.println(uuid);
salida.println(LINEA_ENVIO);
salida.flush();
int codigoRespuesta = entrada.read();
String uuidRecibido = entrada.readLine();
String lineaEntrada = entrada.readLine();
assertEquals(Enviable.RESPUESTA, codigoRespuesta);
assertEquals(lineaEntrada, Enviable.LINEA_ERROR);
assertEquals(uuid.toString(), uuidRecibido);
assertFalse(ControladorTest.proceso(LINEA_ENVIO));
}
/**
* Crea una partida, hace que se una un jugador, y verifica que se notifique al jugador que la
* cre�.
* TODO mover a otro lado?
* TODO extraer l�gica de env�o / recepci�n en funciones.
* @throws IOException
* @throws InterruptedException
* @throws ZombielandException
*/
@Test
public void testIntegracionNotificacionPartida() throws IOException, InterruptedException, ZombielandException {
for (int i = 0; i < CANTIDAD_INTENTOS; i++) {
Gson gson = new Gson();
// Creo una partida y obtengo los datos del jugador que crea la partida.
Partida partida = crearPartida();
Jugador primerJugador = getUltimoAdmin();
Sesion sesionPrimerJugador = new Sesion(primerJugador, servicioEscucha.getHilos().get(0));
sesionPrimerJugador.setPartida(partida);
ServicioSesion.getInstancia().addSesion(sesionPrimerJugador);
// Otro jugador se conecta.
try (Socket socketOtroJugador = new Socket(host, puerto);
PrintWriter salidaOtroJugador = new PrintWriter(socketOtroJugador.getOutputStream());
InputStreamReader readerOtroJugador = new InputStreamReader(socketOtroJugador.getInputStream());
BufferedReader entradaOtroJugador = new BufferedReader(readerOtroJugador)) {
// Esperamos a que el servidor acepta la conexi�n.
int vueltas = 0;
while (servicioEscucha.getHilos().size() != 2) {
Thread.sleep(TIEMPO_SLEEP);
vueltas++;
assertFalse(vueltas * TIEMPO_SLEEP > MAX_TIEMPO);
}
// El segundo jugador inicia sesi�n.
HiloEscucha hiloOtroJugador = servicioEscucha.getHilos().get(1);
Jugador otroJugador = crearJugador();
Sesion sesionOtroJugador = new Sesion(otroJugador, hiloOtroJugador);
ServicioSesion.getInstancia().addSesion(sesionOtroJugador);
ControladorServidorFactory factory =
(ControladorServidorFactory) hiloOtroJugador.getFactory();
factory.setSesion(sesionOtroJugador);
// El segundo jugador pide unirse a la partida.
salidaOtroJugador.write(Enviable.UNIRSE_PARTIDA);
UUID uuid = UUID.randomUUID();
salidaOtroJugador.println(uuid);
POJOUnirsePartida pojo = new POJOUnirsePartida(partida.getId().toString(), false);
salidaOtroJugador.println(gson.toJson(pojo));
salidaOtroJugador.flush();
// El segundo jugador recibe la respuesta exitosa.
int codigoRespuesta = entradaOtroJugador.read();
entradaOtroJugador.readLine(); // Leemos el UUID.
String lineaEntrada = entradaOtroJugador.readLine();
assertEquals(Enviable.RESPUESTA, codigoRespuesta);
RespuestaUnirsePartida respuesta = gson.fromJson(lineaEntrada, RespuestaUnirsePartida.class);
assertTrue(respuesta.fuePeticionExitosa());
assertEquals(partida.getPOJO(otroJugador), respuesta.getPartida());
// El primer jugador recibe la actualizaci�n de lobby.
codigoRespuesta = entrada.read();
String id = entrada.readLine();
lineaEntrada = entrada.readLine();
assertEquals(Enviable.ACTUALIZACION_LOBBY, codigoRespuesta);
POJOPartida pojoRecibido = gson.fromJson(lineaEntrada, POJOPartida.class);
assertEquals(partida.getPOJO(primerJugador), pojoRecibido);
salida.write(Enviable.RESPUESTA);
salida.println(id);
salida.println(gson.toJson(new RespuestaGenerica()));
salida.flush();
// El segundo jugador se desconecta.
socketOtroJugador.close();
// El primer jugador recibe la nueva actualizaci�n de lobby.
codigoRespuesta = entrada.read();
id = entrada.readLine();
lineaEntrada = entrada.readLine();
assertEquals(Enviable.ACTUALIZACION_LOBBY, codigoRespuesta);
pojoRecibido = gson.fromJson(lineaEntrada, POJOPartida.class);
assertEquals(partida.getPOJO(primerJugador), pojoRecibido);
}
// Esperamos a que desconecte el primer jugador.
int vueltas = 0;
while (servicioEscucha.getHilos().size() != 1) {
Thread.sleep(TIEMPO_SLEEP);
vueltas++;
assertFalse(vueltas * TIEMPO_SLEEP > MAX_TIEMPO);
}
}
System.out.println("fin :)");
}
}