Implementación de Step Definitions en Cucumber-JVM

Continuando con los dilemas del uso de cucumber, luego de un par de reuniones con los analistas/testers del proyecto, tomamos algunas decisiones:

  • Escribir los steps con las menor cantidad de parámetros posibles
  • Agrupar los step definitions en base a conceptos de negocio
  • Utilitzar Step definitions con estado (stateful)

A partir de esto, el flujo de trabajo es: los analistas/testers identifican los casos de tests y los expresan como escenarios usando lenguaje Gherkin. Luego usando las anotaciones de Cucumber-JVM yo genero los métodos que implementan los pasos de los escenarios. Estos métodos son los que se conocen como «Step definitions». Hasta aquí llega la herramienta. La forma en que se implementan los Step Definitions depende de cómo sea la aplicación que se pretende testear. Si quisiéramos testear una aplicación web, posiblemente usariamos el driver de Selenium. En mi caso, tengo que testear un sistema de facturación a través de una interfaz propietaria basada en mensajes XML. Más allá de la interfaz hay dos cuestiones que requieren interactuar directamente con la base de datos del sistema:

  1. Limpiar los datos luego de la ejecución de cada test
  2. Realizar ciertas verificaciones (asserts) sobre los datos generados por el sistema que no se encuentran disponibles en la interfaz

Para lidiar con todas estas cuestiones he generado un conjunto de clases (¿micro-framework?) que agrupan código común y que me permiten elevar un poco el nivel de abstracción. cucumber_domain   Scenario, no es una clase, es un caso de prueba especificado en lenguaje Gherkin en un archivo de extensión .feature (un feature suele contener varios scenarios). StepsDefinition no es una clase, sino que son métodos agrupados en clases según criterios de negocio. BusinessAction, son clases que agrupan operaciones de alto nivel con granularidad de negocio. ScenarioContext, es un singleton donde se almacena el estado a lo largo de la ejecución de los distintos steps que conforman un scenario. Este contexto es reseteado cada vez que se ejecuta un scenario. Driver, es una clase con operaciones «de bajo nivel» que permite la interacción con el sistema que se está testeando. DBHelper, es una clase con operaciones para interactuar con la base de datos, se utiliza para resetear el estado del sistema y también para realizar algunas verificaciones que no pueden hacer utilizando el driver/api. Los siguientes diagramas muestran la interacción de estos componentes. cucumber_sequence1     cucumber_sequence2

Estrategia de Continuous Delivery: git + jenkins + heroku (parte 1)

En uno de los proyectos open source en los que participo hemos montado una infraestructura de continuous delivery que nos viene dando buenos resultados por ello quiero dedicar algunas líneas a describir su estructura.

El proyecto consta de 2 aplicaciones, una webapp y un servicio de backend pero cada una es manejada de forma independiente, por ello el resto de este artículo hablaré de forma genérica como si fuera una única aplicación. La aplicación web está construida con Ruby/Padrino, mientras que el servicio es Ruby «puro».

El código de la aplicación es versionado en GitHub, donde tenemos un branch develop sobre el trabajamos y un branch master que tiene el código que está en producción. El código de develop es desplegado automáticamente por Jenkins en una instancia de prueba (que denominamos preview) mientras que el código de master es desplegado en la instancia de producción. Ambas instancia estan corriendo en Heroku.

En el proyecto somos tres programadores, que trabajamos en la aplicación en nuestros tiempos extra laborales. Cuando trabajamos en funcionalidades no tan chicas, que pueden llevarnos un par de días, creamos feature branches.

Adicionalmente al repositorio de GitHub, tenemos otro repositorio, privado, hosteado en BitBucket donde almacenamos la configuración de la aplicación. Aquí tenemos dos branches, uno por cada ambiente.

Jenkins se encarga de la correr la integración continua y los pasajes entre ambientes. Para ello tenemos los siguientas tareas:

  • CI: corre integración contínua sobre el branch develop. Básicamente corre pruebas unitarias y de aceptación.
  • CI_All: es análogo al CI, pero trabajo sobre todos los demás branches, lo que nos permite tener integración contínua incluso cuando trabajamos en feature branches.
  • Deploy_to_Preview: despliega en el ambiente de preview (test) el código proveniente del branch develop
  • Run_Preview_Pos_deploy: aplica la configuración actualizada y las correspondientes migraciones en el ambiente de preview y ejecuta un smoke test
  • Run_Pre_Production_deploy: mergea el branch develop en master
  • Deploy_to_production: despliega en el ambiente productivo el código proveniente del branch master
  • Run_Production_Pos_deploy: aplica la configuración actualizada y las correspondientes migraciones en el ambiente de preview y ejecuta un smoke test

Algunos detalles más para destacar son:

  • Todo commit a develop, se despliega automáticamente a preview.
  • No se hacen despliegues a preview y producción en forma manual, todo pasa por Jenkins
  • Ante cada build, Jenkins informa el resultado via chat (Jabber) a todos los miembros del equipo de desarrollo.
  • El monitoreo de la aplicación en el ambiente productivo lo hacemos con LogEntries y New Relic

Sin duda que este esquema no es una bala de plata, pero nos funciona muy bien en este proyecto. Algunas cuestiones a revisar en otros proyectos serían:

  • En caso de trabajar con un lenguaje compilado estáticamente (Java, C#, etc) habría que considerar utilizar un repositorio de binarios para que la aplicación se compile una única vez (algo tipo Artifactory)
  • En caso de aplicaciones con requerimientos de disponibilidad 7×24, había que considerar una estrategia de deploy distinta, tal vez algo del tipo blue-green deploy.

Si gustan conocer más detalles, no duden en consultar.

Cucumber: teoría y práctica

Teoría: Cucumber es una herramienta para hacer BDD y como tal logró su difusión. BDD una de las técnicas de la familia Test-First.

Práctica: uno puede utilizar Cucumber sin hacer BDD ni Test-First. O sea, es posible usar Cucumber para escribir pruebas sobre aplicaciones ya existentes.

Personalmente hace más de dos años que usé Cucumber por primera vez y desde entonces he leído bastante sobre al respecto y en la gran mayoría de los casos se lo trata como una herramienta de BDD. Sin embargo casi toda la gente que conozco que usa Cucumber (y que no es mucha) no lo usa para hacer BDD, sino que lo utiliza como una herramienta tradicional de automatización de tests.

*nota: al decir Cucumber, hablo de forma genérica, sin centrarme en ninguna implementación particular.

cucumber_logo

 

 

Todo un día de troubleshooting y el problema era el DNS

Resulta que conseguimos un nuevo servidor para instalar el Jenkins. La instalación como de costumbre fue muy simple, lo que llevó un poco más de trabajo fue configurarlo para que buildeara (este término me parece que no existe) nuestro proyecto.

Como parte de nuestro proceso de despliegue, era necesario que uno de los Jobs ejecutara un merge de svn.

Estuve 2 horas para hacerlo funcionar. Resulta que al correr el job obtenia un error del svn diciendo que no podia conectar al servidor. Entonces entré a probar distintas cosas para encontrar la razón del error. Me conecté al server svn, me dió ok. Revisé el plugin de conexión a svn y googleando encontré que podia haber problemas con mi versión, entonces lo actualicé. Volví a probar, el mismo error. Actualicé la versión de svn, el problema persistia. Empecé a pensar que el problema estaba en servidor svn, pero desde mi máquina conectaba OK. Pensé que habría un problema con el job, entonces cree otro. Al pepe, el error persistía.

Así seguí probando cosas, hasta que finalmente escribí al proveedor del servicio quien me confirmó que el servicio estaba funcionando bien y me preguntó que DNS estaba usando. Me fijé en el server y estabamos usando el DNS de Google, lo cual «me dejó tranquilo». Pero para mi sorpresa la gente de soporte del servicio svn me indicó que el DNS de Google no es una buena opción y que durante el año anterior habian tenido varios problemas. ¡Ja! ¿¡quien lo iba a imaginar!? Esta es la respuesta textual de la gente de soporte:

I would not recommend using Google’s DNS, it’s been very flakey the past year, so much so we no longer use it internally at all. Here are some other options: UltraDNS, Dynect, OpenDNS, Norton DNS.

Bueno, en sí, no fue todo el día, pero fue mucho más de lo que debería haber sido.

To Heroku or not to Heroku

Hace un tiempo estuve escribiendo sobre el Proyecto CMS. Actualmente continuo trabajando en dicho proyecto y en estos dias estamos analizando en que plataforma hostear la aplicación. En este momento la aplicación está corriendo en Heroku, pero hay ciertas cuestiones que están ocasionando issues de performance. Ello llevó a que hicieramos una prueba de concepto levantando la aplicación en Linode.

Personalmente creo que las cuestiones de performance de la aplicación no tienen que ver con donde está hosteada sino con ciertas cuestiones de diseño y configuración. Al mismo tiempo, el pasaje de una plataforma como Heroku a otra plataforma del estilo Linode o Amazon EC2 implica un incremento importante en el costo de operación (al menos en un principio hasta que uno logra automatizar parte del trabajo).

Estimo que en las próximas dos semanas estaremos tomando una decisión respecto a esto (en realidad yo no tomo ninguna decisión, simplemente doy mi opinión).

Continuará…

¿Alguna vez te preguntaste como está hecho Google Docs?

Yo me lo he preguntado en varias ocasiones y particularmente una de las cosas que más me cautiva en la edición en simultáneo en tiempo real. A ciencia cierta desconozco como lo hace Google, pero durante las últimas semanas un par de compañeros de Southworks liderados por MatiasW estan trabajando en una herramienta que también cuenta con esta capacidad.

Se trata de MarkdownR, un editor colaborativo en tiempo real de markdown desarrollado con share.js. En verdad vale la pena tomarse unos minutos para darle una mirada, pueden accederlo aquí: http://markdownr.cloudapp.net/.

Y para los curiosos, el código está disponible en GitHub: https://github.com/southworksinc/markdownR/.

Build Server Gratuito en la nube: TravisCI

Ayer descubrí TravisCI, un build server gratuito y open souce para proyectos open source. Si bien no tiene en principio todos los features de Jenkins (en cuanto a reportes, notificaciones, etc, etc) cumple bien su trabajo de build server.

Trabaja integrado con GitHub y para disparar los build utiliza un hook the Github. Ofrece soporte para los siguientes lenguajes: Clojure, Erlang, Groovy, Java, Node.js, Perl, PHP, Python, Ruby y Scala.

Lo probé con mi proyecto SWTFederation y la verdad que me sorprendió lo simple que fue la configuración.

Espero les resulte útil.

Recursos para el profesional independiente (freelancer)

En los últimos años me ha tentado en más de una ocasión ejercer mi profesión de manera independiente, pero por diversos motivos nunca me decidí a hacerlo. Más allá de eso quiero compartir algunos recursos que revisé en esas ocaciones y que me parecieron muy útiles particularmente para profesionales independientes.

Empiezo por el libro de Miles Burke: The Principles Of Successful Freelancing. Esta obra toca una gran diversidad de temas que van desde las consideraciones para decidirse a trabajar independiente, hasta work-life balance, pasando por consejos financieros, calidad de servicio y configuración de la oficina hogareña. Un recurso muy útil y entretenido para leer.

Otro recurso valiosísimo es la técnica del Pomodoro. Sin entrar en mayor detalle les digo que esta técnica ayuda administrar mejor el tiempo e incrementar la productuvidad.

Una lectura que también me parece apropiada y no solo para independientes es el best seller: Los 7 hábitos de la gente altamente efectiva.

Por último creo que Linkedin es una herramienta clave para promocionarse y hacer contactos, dos puntos a mi entender importantísimos para todo freelancer.

Bien, esto es todo lo que tenia por decir a pesar de nuncar abler trabajado independiente, pero bue, es lo que hay.

Se aceptan sugerencias.

GitHub quickstart

Hace un tiempo que estoy colaborando en un proyecto open source que recientemente fue migrado de SVN a GIT, particularmente a GitHub y dado que algunos miembros del equipo del proyecto no estan familiarizados con esta herramienta he decidido escribir es post orientativo. GIT a diferencia de SVN es un sistema de control de versiones NO centralizado (SVN es centralizado), este es un detalle interesante, pero en este momento no voy a profundizar al respecto, sino que voy a pasar directamente a los pasos para comenzar a trabajar con esta herramienta.

Aclaración: si bien hay más de una forma de trabajar con Github, yo voy a enfocarme en la que considero más simple.

En primer lugar vamos a github para crear

image

Dado que en este caso vamos a trabajar en un proyecto open source bastará con seleccionar la opción de cuenta gratuita. Una vez que tengamos nuestra cuenta, nos comunicaremos con el administrador del proyecto en que deseamos colaborar y pedirle que nos otorgue acceso de escritura.

image

Bien, ahora vamos a tener que instalarnos un cliente de git para poder conectarnos y trabajar. Aqui hay una lista de clientes para todos los gustos, personalmente les recomiendo un cliente de consola, a mi me ha dado más exito que los clientes de ventanas. Una vez instalado el cliente vamos a necesitar generar una clave RSA que es lo que Git utiliza para autenticar a los usuarios. Esto es muy simple (al menos con el cliente de consola, ja!) en está página de github van  encontrar las instrucción para generar su clave, pero siendo más directo, hagan esto: abren la consola Git, se posicionan en la carperta c:\users\{tuusuario}\.ssh (si no existe la crean) y tipean:

ssh-keygen -t rsa –C “{tu cuenta de mail que usaste para registrarte en github}”

Cuando les pida nombre de archivo, presionen enter y se utilizarán los nombres default. Si gustan pueden poner un passphrase, pero es opcional. Esto va a generar dos archivos: uno con la clave pública para subir a github (id_rsa.pub) y otro con la clave privada que NUNCA deberán compartir (id_rsa).

image

El siguiente paso es configurar nuestro client local indicando nuestro nombre y direccion de correo. Para ello debemos ejercutar las siguientes dos lineas:

git config —global user.name «{tu nombre de usuario}»

git config –global user.email {tu correo}

Ahora que ya tenemos nuestro par de claves, volvemos a github y subimos nuestra clave pública. Vamos a SSH Public Keys\ Add another public key y pegamos el contenido del archivo id_rsa.pub (mucho cuidado de no agregar ningún caracter adicional).

image

image

Con esto ya estamos en condiciones de dirigimos al repositorio del proyecto en que queremos trabajar. Claro, antes de esto deberiamos asegurarnos que el administrador del proyecto nos haya otorgado permiso de escritura en el repositorio. Si es asi, entonces veremos en la página del repositorio la URL de read+write.

image

Copiamos la url de read+write y vamos a la consola git. Nos dirigimos al directorio local donde crearemos nuestro repositorio local y ejecutamos la sentencia para crearlo:

git clone {url que copiamos de github}

image

Si todo salió bien, ya tenemos nuestro repositorio local y podemos empezar a trabajar. Un detalle interesante a tener en cuenta cuando trabajamos con git es que es una herramienta no centralizada de control de versiones. Esto significa que cada miembro cuenta con una copia local completa de todo el repositorio. Para trabajar sincronizadamente, uno de estos repositorios es designado como master. El master, en cierto modo puede ver como el repositorio central de un SVN, a lo interente de git es que si el master se cae, facilmente podemos designar otro y seguir trabajando.

Dicho esto, en general nuestro flujo de trabajo será:

  1. Actualizar nuestro repositorio local y nuestra copia de trabajo obteniendo la última versión desde el repositorio master. En términos concretos de git esto es ejecutar un git pull.
  2. Realizar nuestro trabajo sobre el contenido y comitearlo. En términos de git es ejecutar dos comando: git add <arcihvo modificado/agregado>  y git commit. El primero de estos comando «agrega» el archivo indicado a la lista de archivos del próximo commit. El segundo es el commit que  “copia” nuestras modificaciones desde nuestra copia de trabajo a nuestro repositorio local.
  3. Mezclar nuestros cambios con el repositorio master, esto es: ejecutar un git pull para obtener la última version desde el repositorio master. Si el pull es exitoso, entonces nuestro repositorio contendrá la última versión (lo que estaba en el repositorio master + nuestros cambios)
  4. Actualizar el repositorio master con nuestro contenido, lo cual se hace ejecutando un git push.

Creo que no olvido nada, si bien hay muchas cosas más por decir esto deberia ser suficiente para las necesidades de mi equipo de proyecto.

Le doy las gracias al groso de  Dario Seminara, evangelizador de GIT, por revisar este post y les recomiendo que si gustan aprender más de Git, no duden en visitar el blog de Dario.

Espero les resulte útil.