Tests 👷🏽♀️
Tests unitaires et d'intégration
Des tests sont fournis avec le squelette. Ils vérifieront que les fonctions de base du buffer circulaire fonctionnent comme on l'attend, mais également que les éléments sont bien détruits au bon moment (et seulement à ce moment là).
Lancez les tests à l'aide de cargo test
(ou cargo test --release
).
On pourra remarquer dans le test
tests/drop.rs
l'utilisation du crateserial_test
. Celui-ci fournit un nouvel attribut#[serial]
qui permet de sérialiser les tests qui l'utilisent. Cela est nécessaire car nous utilisons un compteur d'instances global et si les tests tournaient en parallèle nous ne pourrions pas vérifier de manière cohérente que le nombre d'instances vivantes à un moment donné correspond bien à ce que nous prévoyons.
Miri
Miri est un outil de test pour Rust qui permet de détecter les comportements indéfinis. Par exemple, il peut détecter des accès mémoire incorrectement synchronisés (encore expérimental, mais fonctionnel).
Pour pouvoir utiliser Miri, il faut utiliser la version "nightly" de Rust (la version du jour) et ajouter le composant miri
:
$ rustup toolchain add nightly
$ rustup +nightly component add miri
On peut ensuite lancer le test qui nous intéresse (test_concurrency
dans concurrency.rs
dans le cas présent) sous le contrôle de Miri, en utilisant la version "nightly" de Rust :
$ cargo +nightly miri test --test concurrency
Si une erreur est détectée, Miri en indiquera la cause :
#![allow(unused)] fn main() { test test_concurrency ... error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `test_concurrenc` and (2) non-atomic write on thread `unnamed-2` at alloc128439. help: (2) just happened here 148 | self.buffer.as_ptr().add(i).write(e); | help: and (1) occurred earlier here 182 | mem::drop(unsafe { self.buffer.as_ptr().add(i).read() }); }
Ici par exemple, il s'agit d'un accès mal synchronisé car certaines variables ont été manipulées sans le bon mode (par exemple Acquire
ou Release
).
On ne veut pas exécuter tous les tests sous Miri, car certains tests utilisent par exemple le crate serial_test
qui fait des allocations mémoire qui seraient détectées par Miri comme des fuites mémoire et qui sont en dehors de notre contrôle. Par contre, le test test_concurrency
, dans concurrency.rs
, nous permet de tester les caractéristiques qui nous intéressent.
⚠️ L'exécution sous Miri est beaucoup plus lente que l'exécution normale, qui est non supervisée. Assurez vous que vos tests ne comportent pas de boucles trop longues (par exemple pour faire tourner un test 10 millions de fois).
💭 Miri est un outil très puissant pour détecter les bugs dûs à des comportements mal spécifiés, n'hésitez pas à l'utiliser dès que vous écrivez des programmes gérant manuellement des ressources !