Las pruebas de librsvg ahora están en Rust

Translations: en - Tags: gnome, librsvg, rust

Están en marcha varios cambios importantes en librsvg.

Cambios en la integración contínua

Hace unos días, Dunja Lalic re-escribió los scripts de integración contínua y ahora son mucho más rápidos. Un pipeline completo solía tardar unos 90 minutos o más, y ahora tarda en promedio unos 15 minutos.

Gráfica de tiempos para los pipelines, se reducen súbitamente

La descripción de los cambios es interesante. Se trata de que las pruebas que fallan rápido ocurran al principio. Para acelerar todo el pipeline, Dunja hizo lo siguiente:

  • Mover el paso de cargo check al principio. Esta prueba significa, "¿tiene esto siquiera la posibilidad de compilar?".

  • Hacer que las pruebas de estilo y de formateo, cargo clippy y cargo fmt, se ejecuten en paralelo con las pruebas unitarias. Estos lints pueden fallar pero son fáciles de arreglar después de que uno termina de escribir la parte importante del código.

  • Correr las pruebas unitarias y lo mínimo de integración rápidamente, en modo debug, para que compilen rápido.

  • Correr las pruebas completas, de integración y todo, en modo release. Tarda más la compilación, pero aquí sí hay pruebas lentas que se benefician de código que se ejecuta más rápido.

  • Mover las pruebas de release hasta el final, y correrlas sólo una vez por semana — o cuando sea, de forma manual. Estas sí tardan un montón, porque hay que hacer make distcheck y autotools es lento. Incluso así, ahora tardan unos 30-40 minutos en vez de los 90 de antes.

  • Entre cada estado del pipeline, no cachear lo que no ayuda al tiempo de las pruebas. Parece que mover un cache grandote, con todo el target de compilación, entre cada estado del pipeline puede ser peor que no hacerlo.

Pipeline completo con todas las fases

Pruebas en Rust

Entre Sven Neumann, Dunja Lalic, y yo hemos logrado portar la suite de pruebas a Rust: todas las pruebas de librsvg ya se ejecutan en Rust, excepto las pruebas de la API en C. Hubo que hacer varias cosas:

  • Revisar las pruebas viejas y quitar algunas obsoletas.

  • Portar cada uno de los módulos de pruebas a Rust. Son pequeños, pero cada uno tiene cosillas especiales — probar crashes durante la carga de XML, probar crashes durante el renderizado, probar los límites de seguridad de la biblioteca.

  • Arreglar las pruebas pequeñas que vienen como parte de la documentación.

  • Desmenuzar las pruebas de referencia y portarlas a Rust.

  • Mover montoncitos de código para que las pruebas unitarias y las pruebas de integración puedan compartir las utilerías para comparar imágenes, obtener rutas de archivos a los documentos de prueba, etc.

Lo más complicado de portar fueron las pruebas de referencia. Estas son las más importantes; son cada prueba carga un documento SVG, lo renderiza y compara el resultado con un PNG de referencia. Hay varias complicaciones en estas pruebas; una es que hay que crear una configuración especial de Fontconfig y Pango para tener renderizado reproducible de fonts. Los bindings de pango-rs no contemplan esta parte de Pango, entonces hay que hacer algunas cosas a mano.

Pero bien, las pruebas ya están en Rust. Una ventaja es que ahora las pruebas se ejecutan automáticamente en paralelo en todos los núcleos del CPU, entonces ahorramos tiempo total en las pruebas.

Lo que sigue: cargo-c y publicar a crates.io

Queremos poder publicar librsvg en crates.io como cualquier otro crate de Rust; esto implica poder compilar, probar y publicar librsvg sin usar nada más que Cargo. La parte de compilar y probar todo desde Cargo ya se puede hacer.

Ahora falta reorganizar el código para que se pueda publicar a crates.io. Librsvg viene en tres partes, rsvg_internals que trae la implementación de la biblioteca, librsvg que exporta el API tradicional en C, y librsvg_crate con el API en Rust. Sin embargo, para publicar el API en Rust a crates.io, sería más conveniente tener un solo crate en vez de uno con las entrañas y otro con el API.

El siguiente paso es reorganizar el código:

  • Hacer posible que el API en C se pueda implementar como una opción de compilación sobre el código normal en Rust. Queremos usar cargo-c para compilar la biblioteca compartida librsvg.so tradicional, en vez de depender de las herramientas para compilar y ligar código en C.

  • Combinar rsvg_internals y librsvg_crate en un solo crate, para publicarlo todo junto. Crates.io tiene un límite de 10 MB por crate; ahora que las pruebas viven en un crate tests separado, esto no será problema.

  • Me gustaría pulir los tipos públicos de errores antes de publicar el API en Rust; ahorita tienen algunos detalles de implementación que no le interesan a quien llame a librsvg.

¿Que falta por portar a Rust?

Sólo dos cosas que entre sí son menos de 900 líneas de código en C.

  • rsvg-convert - el programa de línea de comandos que usa todo el mundo para convertir SVG a PNG y otros formatos. Por fortuna Sven Neumann escribió unas pruebas fabulosas para rsvg-convert, pues es como una API que se tiene que mantener estable: si cambiamos las opciones de línea de comandos o la conducta del programa, romperíamos los scripts de todo el mundo y eso no debe ser.

  • El módulo de gdk-pixbuf para cargar SVG. Alberto Ruiz ya comenzó el port a Rust. La parte genérica de este código podría servir después para envolver otros codecs de imágenes en Rust y enchufarlos a gdk-pixbuf.