Feb 24

OutOfMemoryError con test de maven

 

El otro día me salto un OutOfMemoryError al ejecutarse un test automático desde maven. Teóricamente, para evitar problemas de memoria con maven basta con poner la variable de entorno MAVEN_OPTS con los parámetros que le queremos pasar a la máquina virtual de java, en concreto, los de aumento de memoria

set MAVEN_OPTS=-Xmx512m

De hecho, tengo esa variable puesta por defecto en el entorno y estaba correctamente inicializada. Pero el OutOfMemoryException persiste. Así que a buscar en google.

Al final encuentro que maven arranca una máquina virtual java separada para ejecutar los test y que el parámetro MAVEN_OPTS sólo afecta a la máquina virtual en la que corre maven y no a la máquina virtual en la que se ejecutan los test. El plugin de maven que se encarga de ejecutar los test automáticos se llama maven-surefire-plugin y tiene su propia configuración. La variable argLine permite indicar, entre otras cosas, la cantidad de memoria que queremos que se asigne a la máquina virtual java en la que se ejecutan los test. Para ello, debemos ejecutar así

mvn -DargLine=-Xmx512m test

o bien, configurarlo en el mismo pom.xml del proyecto

<project>
<build>
<plugins>
   …
   <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>               
      <configuration>
         <argLine>-Xmx512m</argLine>
      </configuration>
   </plugin>
 

Feb 22

Más sobre los test automáticos

 

Comenté ayer que estaba jugando con fest-swing y otras herramientas para test automáticos de pruebas de las interfaces gráficas de usuario. Pues bien, hoy he seguido un poco y he conseguido resolver la mayor parte de los problemas que se me presentaron. Eran, por supuesto, culpa mía, de no conocer la herramienta y de la mala costumbre de jugar el ensayo y error en vez de leerse la documentación.

Por un lado, en vez de bajarme fest-swing de la página de fest-swing, usé el repositorio maven que hay para ello, dejando que fuera maven el que se bajara el jar de fest-swing y todas sus dependencias. Entiendo que esto no tiene mucho que ver (más bien nada) con los problemas que se me presentaron.

El segundo punto, y este sí es importante, es que si hacemos el ejemplo tonto de test que viene con fest-swing no hay ningún problema, sale bien a la primera. Pero si ejecutamos una batería de test con fest-swing, es muy importante reiniciar los recursos que usa fest-swing. Esto se traduce que en el método tearDown() (que JUnit ejecuta después de cada test), debemos hacer la llamada correspondiente

private FrameFixture window; // Clase de Fest-Swing con la ventana principal.

public void tearDown() {
   window.cleanUp();  // reiniciar recursos
}

Y esto ha solucionado gran parte de los problemas que tenía. Ahora las ventanas de test sí salen cuando se ejecutan desde maven y no hacen tantas cosas raras cuando se ejecutan desde eclipse.

Otro tema importante es que aunque Fest-Swing se encarga de acceder a los componentes en el hilo de tratamiento de eventos de swing, es posible que el orden de estos eventos no sea el que esperamos. Si nuestro test manda visualizar una ventana, he encontrado útil esperar a que dicha ventana esté realmente visible antes de proseguir con el test. Esto se puede conseguir con la llamada a window.requireVisible() de fest-swing. Esta llamada hace fallar el test si la ventana no está visible, pero espera un tiempo prudencial antes de cantar el fallo. De esta forma, la llamada se queda bloqueada hasta que la ventana realmente está visible, o hasta que pasa un tiempo excesivo de espera (configurable, por supuesto).

Lo que no he conseguido es que desde eclipse los test se ejecuten dando resultados siempre. Sí es cierto que con todo esto parece que falla menos, pero siguen saliéndome barras grises o negras (en vez de verdes o rojas) de vez en cuando.

Una vez conseguido que todo funcione más o menos correctamente, lo he metido en Subversion y he esperado a que el sistema de integración continua (Hudson) compilara y ejecutara los test. A pesar de las advertencias en la documentación de fest-swing de que puede haber problemas con la integración continua, todo ha ido sobre ruedas y sin problemas.

Otra característica que me ha parecido interesante de fest-swing, aunque no la he probado, es que si un test falla, fest-swing puede capturar y almacenar la pantalla en el momento que se produce el fallo. De esta forma, viendo la foto de nuestra interfaz gráfica de usuario con el fallo, podemos ver si realmente hay algo incorrecto o el fallo se ha producido por otra circunstancia. Por ejemplo, que la ventana de que "windows se ha actualizado" haya salido justo encima de nuestra interfaz justo cuando la estamos testeando.

Así que de momento fest-swing queda incorporado en mi trabajo como herramienta para hacer test de interfaces gráficas de usuario. Sólo me falta ir convenciendo a mis "compis" para que también la usen.

Comenté también en el post anterior que quería probar Abbott. Bien, después del éxito con fest-swing, no lo he hecho. Pero leyendo la documentación de Abbott, he visto una característica también interesante. Abbott, ¿cómo no?, viene con Costello, una aplicación que permite ejecutar nuestra interfaz de usuario de forma normal (a través de su método main()) y actuar manualmente sobre ella. Costello se encargará de capturar toda nuestra interacción con ella (a modo de grabación), de forma que luego Costello puede reproducirla una y otra vez sobre nuestra aplicación, testeando que los resultados son los mismos. Es una forma interesante de hacer los test, sin necesidad de programar demasiado. A pesar de que usaremos fest-swing, probaré Abbott y Costello en algún momento, para ver si se puede testear el sistema completo en el entorno de pruebas.

Feb 20

Test automáticos de interfaces gráficas de usuario

 

Por fin, después de una larga temporada adaptando una y otra vez el mismo software ya hecho a distintos proyectos, ha llegado el momento de empezar a hacer algo nuevo. Vamos a pasar a java unas viejas interfaces gráficas de usuario que teníamos en C++. Por supuesto y con mis ganas de aplicar (y aprender) las buenas costumbres de programación, voy a intentar hacer la parte que me toca siguiendo TDD. Pero, amigo Sancho, con la iglesia hemos topado. Una de las cosas que tradicionalmente se reconoce que son difíciles de probar automáticamente son, precisamente, las interfaces gráficas de usuario.

En una aplicación java SWING, los test básicamente consisten en coger la ventana e ir buscando en los componentes que contienen, recursivamente, hasta que se encuentra el que se busca. Una vez encontrado, actuamos sobre él, haciendo click, metiendo un texto, leyendo su contenido o lo que sea que necesitemos hacer para realizar el test automáticamente. También la clase java.awt.Robot nos permite simular eventos de ratón y teclado sobre los componentes. Pero ni buscar componentes por las ventanas, ni usar la clase Robot es precisamente una tarea cómoda. Por fortuna, hay librerías que nos ayudan a hacer estas tareas y en definitiva, a realizar los test automáticos. Así que a probar esas librerías toca.

La primera que he probado ha sido FEST-Swing, quizás la más conocida para aplicaciones de escritorio con java. La librería está muy bien y contiene características muy interesantes. Las que más me han llamado la atención:

  • Según recomendación de java, todos los accesos a ventanas deben hacerse en el hilo de refresco de ventanas y tratamiento de eventos que nos proporciona java (EDT Event dispatch Thread). Pues bien, una simple configuración de FEST en el test hace que salte si accedemos a los componentes SWING fuera de ese hilo.
  • Precisamente ese hilo es un poco rollo. Nuestro test no se ejecuta en ese thread EDT y si el código que testeamos mete algo en un componente SWING usando el thread EDT (como se recomienda), nuestro test debe esperar a que el thread EDT termine antes de verificar el contenido del componente. Pues bien, FEST nos hace esto totalmente transparente. Cuando con FEST accedemos a un componente para ver su contenido, FEST espera que terminen los hilos EDT.
  • Aunque al principio parece raro, es realmente sencillo de usar. Podemos buscar en general cualquier componente con un método simple, indicando qué tipo de componente buscamos (JTextFiel, JLabel, etc), por su nombre (si hemos tenido la precaución de ponérselo con setName()) o haciéndonos un filtro a medida (un Matcher)

Pero no es oro todo lo que reluce. Me he encontrado con dos problemas que me van a dificultar seriamente su uso, más un pequeño problemilla.

  • El pequeño problemilla es que si ejecuto un test desde eclipse, a veces parece que no se ejecuta el test. Cuando ejecutamos un test en eclipse, al final sale una barra verde o roja, indicando si el test pasa o no. Pues resulta que, de forma aleatoria, el test termina y dicha barrita queda en negro o en gris, como si eclipse no detectara que el test ha terminado. Bueno, no es grave, puesto que no voy a ejecutar habitualmente los test con eclipse y lo peor que puede pasar es que tenga que darle dos o tres veces hasta obtener la barra verde o roja.
  • Un problema más serio lo he tenido con maven. Cuando ejecuto el test en eclipse, FEST visualiza las ventanas bajo test, se hace el test y pasa el test o falla (o se queda en gris/negro). Ejecutando el mismo test desde maven, ni siquiera sale la ventana y el test falla sistemáticamente. Investigaré en este tema, pero si no consigo solucionarlo, descartaré el uso de FEST en el entorno que trabajo.
  • Y un segundo posible problema es la integración continua. Hudson se encarga de compilar y pasar los test de nuestros proyectos todas las noches. FEST requiere que la ventana se visualice y por tanto, requiere que Hudson corra en un terminal abierto en sesión, sin salvapantallas ni nada que impida la correcta visualización de la ventana. En la documentación de FEST indican varias formas para solucionar problemas con la integración continua. Me pondré con ellas si consigo pasar el punto anterior, lo de ejecutar los test con maven, ya que si hudson ejecuta maven y maven no muestra las ventanas, me da igual que haya o no pantalla disponible.

Después de esto, fui a buscar otra herramienta y me topé con uispec4j. Mucho más simple que FEST de uso (aunque menos potente) y puede cumplir para test no excesivamente ambiciosos. A diferencia de FEST, no requiere que las ventanas se hagan visibles. Esto seguramente dé menos problemas a la hora de integración continua, pero posiblemente haga que los test sean menos reales. Tampoco controla el acceso a los componentes a través del thread EDT, por lo que las esperas por dicho thread debemos codificarlas en nuestro test. Así que nada, me puse a probarla y ¿cómo no?, me encontré con un par de problemillas.

  • Al igual que FEST, al ejecutar los test con eclipse, a veces la barra no queda ni verde ni roja, sino gris claro o negro. Esto ya hace pensar que no es problema ni de FEST ni de uispect4j, sino quizás un test mal hecho por mi parte o a algún problema con mi eclipse. Tengo que probar en casa.
  • Al ejecutar los test, me salta una fea excepción. Buscando en google, veo que hay un problema cuando juntas wndows xp, java 6 y uispec4j. ¡¡ qué casualidad !! ¡¡ justo mi configuración !!.

En fin, sigo peleándome a ver si consigo que alguna de estas herramientas me funcione correctamente. También me gustaría echar un ojo a abbott, herramienta similar aunque quizás menos conocida.

Por cierto, quiero dejar claro que no estoy diciendo que FEST o uispec4j estén mal o no funcionen correctamente. Simplemente estoy contando lo que me ha pasado trabajando dos o tres días con ellas mientras hacía el código real de mi aplicación. Pueden ser fallos de las librerías, de mi configuración concreta, de mi código que haga cosas raras o de que estoy pagando la novatada haciendo mis primeros test de este tipo con este tipo de herramientas.

 

Feb 12

Gestores de documentos

 

Cuando en un proyecto entre varias personas empieza a haber montones de documentos word, excel, pdf y demás con cosas de diseño, requisitos, notas de cliente, actas de reuniones, etc, suele ser un lío organizarlos, compartirlos, encontrar justamente el que queremos, mantener distintas versiones de ellos, etc.

Para ayudarnos en este tema tenemos los gestores de documentos (creo que su nombre oficial es gestores documentales). Normalmente con una interfaz web podemos subir nuestros documentos, tenerlos organizados, mantener distintas versiones y buscar en ellos. Al ser con interfaz web, el acceso es fácil para todos los miembros del proyecto.

Rebuscando con google, el primero que me encontré gratuito es alfresco. pero no me ha hecho ninguna gracia. Me bajo el ejecutable windows, lo instalo, me pide cosas normalitas como si quiero instalación típica o personalizada, una password de administrador … y me acaba sacando esta ventana

Bueno, eso da la impresión de no estar muy cuidado. Le dí a "Cancelar" con lo que se abortó la instalación, volví a instalar y obtuve la misma pantalla. Esta vez decidí dejarlo en marcha e irme a tomar un café. Efectivamente, a pesar de la pantalla, se instaló. Arranco el servidor, intento acceder desde el navegador … y sólo tengo errores. No sé si hay que configurar algo o no, pero desde luego, no parece que esta herramienta sea demasiado robusta, ni cuidada.

Así que me pongo a buscar otra y doy con openKM. Esta sí, me la bajo, la instalo, se instala sola, la arranco y funciona. Me da algún error al abrir la página web por primera vez, pero se recupera bien y parece que funciona bien. A jugar con ella. Es la primera vez que manejo una herramienta de estas, pero voy a poner aquí las cosillas que he probado y lo que me ha llamado la atención.

En la interfaz web organizas una estructura de directorios y subes documentos de todo tipo. Una cosa que me ha llamado la atención es que una vez subido el documento, si queremos cambiarlo de directorio, basta con arrastrarlo con el ratón.

A cada documento puedes ponerle unas etiquetas (tags) para luego buscarlos fácilmente y añadirle notas. Puedes subir versiones nuevas de los mismos documentos y el guarda (y muestra todo el histórico). Es más, una vez subido y para los formatos más estándar (.doc, .pdf, .xls, .txt, .html, etc, etc) revisa el contenido y lo almacena para posteriores búsquedas. Más adelante podemos buscar documentos que contengan "estas palabras". La búsqueda, además de palabras, permite filtrar por fecha de documentos, por el usuario que lo ha subido, por las etiquetas, etc, etc.

Otra característica que me ha parecido muy interesante es que podemos importar de golpe un directorio al que tenga acceso el servidor. De esta forma, si antes de instalar la herramienta teníamos un directorio con dos mil documentos, no es necesario subirlos uno a uno. Basta indicarle a la herramienta cual es ese directorio, esperar un tiempo que puede ser grande, y ya tenemos todo importado e indexado. Ya podemos empezar a buscar. Obviamente, los documentos importados así no tienen etiquetas ni notas, que tendremos que poner a mano si queremos hacerlo.

Otra gratuita de este estilo es Nuxeo, que probaré el lunes posiblemente. De todas formas, aunque a mí no me afecta directamente el problema, si veo que una herramienta de este estilo puede ayudar mucho a los jefes de proyecto. Así que por hacerles un poco "la pelota", pondré una marcha y se la enseñaré funcionando, con uno de sus gigantescos directorios de documentos importantes de proyecto.

Feb 11

Quitar linux

 

Una vez instalado linux, quizás nos dé por quitarlo, pero hay un pequeño problema. Cuando se instala linux, este pone un gestor de arranque (LILO o GRUB) en el sector de arranque del disco duro (MBR). Este gestor de arranque busca su configuración en la partición en la que tenemos linux. Si únicamente formateamos esa partición de linux, nuestro ordenador no arrancará más. El gestor de arranque va a buscar su fichero de configuración a la partición de linux y como esta ya no existe, no funciona.

Por ello, una de las primeras cosas que tenemos que hacer antes de quitar linux es restaurar el sector de arranque original. Hay varias opciones, según nuestra versión de windows y si tenemos o no a mano el CD de instalación de windows.

Los Windows antiguos vienen con el comando fdisk, por lo que algo tan sencillo como

C:\> fdisk /mbr

debería restaurar nuestro sector de arranque. Pero los windows más modernos (de XP en adelante), no vienen con ese comando. Por ello, tenemos que arrancar desde el CD de instalación en modo de "restaurar sistema" y ejecutar una serie de extraños comandos.

Tenemos sin embargo una solución sencilla. Basta con bajarse algo como MBRFix, un pequeño ejecutable, y con un comando como

C:\> MbrFix /drive 0 /fixmbr

nos restaura el sector de arranque. Tiene opciones para restaurar el MBR en windows vista o windows 7, además de más posibles utilidades, como obtener información de los discos, manejo de particiones, etc.

Una vez restaurado y comprobado que nuestro sistema ya arranca sin pasar por el gestor de arranque LILO o GRUB, ya podemos formatear nuestras particiones de linux.

Feb 04

Simplemente, las cosas no funcionan

 

Por la mañana me caí de la cama, como siempre, sobre las cinco de la madrugada y, como siempre, lo primero que hice fue encender el ordenador. Internet no me iba. Las lucecillas del cable-modem de ONO daban que no había red. Duró la avería menos de un minuto, pero volvió a repetirse a los diez minutos y así tres o cuatro veces.

Por otro lado, mi ordenador, todavía en garantía, tiene estropeado el grabador de DVD. A veces lee, a veces no, pero nunca graba. Como tengo otro instalado y me da pereza ir a la tienda a que lo cambien (como digo, todavía está en garantía), así sigue, estropeado. Seguro que el que me funciona se estropea cuando se acabe la garantía y no me quedará más remedio que echar pestes de mi pereza y comprar otro.

Luego fuí al curro y allí, cada vez que abro eclipse, lo cierro, abro el correo, lo cierro, compilo, me eternizo esperando. Mi ordenador no es especialmente viejo, pero se ha ido degradando y va muy lento. A veces, hasta diez minutos de espera a que eclipse acabe de cerrar. Así que en una de esas esperas, decido ir a llenar mi botellita de agua a una de las fuentes que hay por la empresa. Dicha fuente tiene la palanquita de sacar agua rota, pero funciona. Eso sí, en vez de chorro de agua, sale un chorrito fino, porque algo hay mal.

De vuelta al ordenador y como no ha terminado de cerrar eclipse (y no responde nada mientras tanto) decido irme a tomar un café a una de las máquinas de café. Una "fuera de servicio", la otra se traga la moneda y no da nada, y de la tercera consigo sacar un café.

Por cierto, la tele recién comprada hace cosas raras con el TDT integrado. De vez en cuando la pantalla se queda negra durante un segundo. Como pasa más con unas cadenas que con otras y la señal que tengo no es muy allá (la tele analógica se veía con algo de nieve), pienso que no es que la tele esté mal, sino símplemente que el decodificador integrado es un asquito.

Y viendo el percal de cómo son las cosas hoy en día, donde prima más sacar beneficio rápido sacando productos malos y baratos pronto, de usar y tirar, con piezas de "plasticucho" que se rompen a la más mínima y calidad sobre todo deficiente…. ¿por qué iba a ser menos el software que hacemos? Proyectos sobre dimensionados con plazos escasos y escasez de gente,  principalmente novatos recién salidos que son más baratos y tira pa’lante.

En fin, hay días que es mejor no levantarse de la cama (y menos a esas horas), y hay días en que realmente me apetece cambiar de profesión y dedicarme a algo que no tenga nada que ver. No sé, pastor de ovejas quizás.

Feb 03

Jugando con Openmap

 

A principios de semana me salió la necesidad de hacer un algoritmo que sobre la tierra me dijera lo siguiente: Supongamos que sobre un punto de la tierra trazamos un rumbo siguiendo un azimuth determinado (ángulo respecto al Norte, en sentido horario). Se trata de saber si ese rumbo pasa o no pasa por una determinada zona geográfica, definida como un polígono cerrado sobre la superficie de la tierra.

Si suponemos tierra plana, el tema es relativamente sencillo sabiendo un poco de matemáticas y de geometría. Pero si las distancias son algo grandes, no vale suponer tierra plana. Debemos meternos con trigonometría esférica, vectores o cualquier otro artilugio de matemáticas. Como me daba pereza desempolvar los apuntes de matemáticas, me dediqué a buscar por ahí y me encontré con Openmap.

Openmap es una librería java pensada para dibujar mapas y sobre ellos, dibujar lo que queramos. Podríamos, por ejemplo, dibujar nuestro polígono y el rumbo desde el punto en cuestión. La librería viene muy completita, de forma que con un simple new OpenMap(), sin parámetros, se lanza una aplicación con el mapa mundo por defecto, opciones de zoom, de dibujar día y noche, etc, etc. Pero por supuesto, también tiene todo el conjunto de clases necesario para que nosotros podamos hacer nuestro mapa a medida. Cargamos un mapa en formato shapefile, definimos nuestros menús y barras de herramientas, etc.

Pero eso no es lo que a mí me venía bien, puesto que no quiero pintar un mapa. Lo que a mí me venía bien es que tiene clases de sobra para el cálculo de "cosas" sobre la superficie de la tierra. Hay clases capaces de decirte la distancia en km de dos puntos sobre la tierra, de decirte si dos segmentos sobre la superficie de la tierra se cortan, hay clases de zonas geográficas poligonales … y clases para saber si un segmento corta a una zona poligonal.

Total, que lo que yo imaginaba iban a ser un par de días de echar cuentas arriba y abajo, probar, volver a probar y echar humo por la cabeza, al final ha sido una mañana de jugar con Openmap y aproximádamente diez líneas de código java para mi algoritmo, usando las clases de Openmap. La única "pega" que le veo es cargar con un Openmap.jar sólo para echar unas cuentas….

 

Feb 02

Cosillas con la clase File de Java

 

El otro día, tratando de hacer un test automático, me encontré con una cosa de la clase File de java que no sé si está bien o soy yo que soy demasiado enrevesado haciendo las cosas.

Supongamos que hay un fichero.txt que está en un directorio que existe, tanto el fichero como el directorio. Pero tenemos la mala suerte de que nuestro programa se está ejecutando en otro directorio que no es en el que está el fichero. Posiblemente no es la forma correcta de hacerlo, pero se me ocurrió que mi programa podía cambiarse de directorio usando la propiedad "user.dir" de la clase System.

System.setProperty("user.dir", "/directorio");

y ahora, para ver si el fichero existe, sólo tengo que hacer esto

File fichero = new File("fichero.txt");
if (fichero.exist()) {
    ….

Pues bien, resulta que NO existe. Bueno, será que File no lee la propiedad "user.dir" para ver el directorio de ejecución, o bien la lee muy al principio y luego no la cambia. No me gusta, pero puede ser así y tendría su razón de ser. Sin embargo, no es del todo así. Si en el código anterior hacemos esto

System.out.println(fichero.getCanonicalPath());
System.out.println(fichero.getAbsolutePath());

pues resulta que sale

/directorio/fichero.txt

o sea, que para los métodos getCanonicalPath() y getAbsolutePath() sí recarga la propiedad "user.dir".

Bueno, seguramente soy un poco enrevesado, pero esto me parece una pequeña incongruencia de File. O lee "user.dir" siempre, o no lo lee nunca. No parece lógico que el constructor o el método exist() no lo lea, pero los getCanonicalPath() y getAbsolutePath() sí.

Lo del enrevesamiento tiene una pequeña explicación. La aplicación en ejecución se ejecuta en un determinado directorio y busca los ficheros con path relativos, leídos de una propiedad (aplicacion.path.fichero=path/relativo/fichero.txt). Pero cuando desde maven compilo, los test se ejecutan en el directorio raíz del proyecto maven. Mi idea era hacer un test que leyera la propiedad y comprobara que el fichero existe. Para ello, tenía que llevar el directorio de ejecución del test al equivalente de la aplicación debajo de la estructura de directorios de maven (/proyecto_maven/src/main/config) y a partir de ahí usar la propiedad con el path relativo (directorio/fichero.txt)

Al final lo he solucionado con un new File("/proyecto_maven/src/main/config", "directorio/fichero"), que posiblemente sea una opción más correcta que andar jugando con el "user.dir"