Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Phase B2 — Conventions opérationnelles

Document de setup phase 0 — Version 1.0

Vue d’ensemble

La Phase B2 couvre les conventions qu’un contributeur rencontre à chaque PR : comment tester, comment gérer les erreurs en couches supérieures, comment formater les commits et les pull requests.

Section 1 : Conventions de tests

Organisation physique

Trois types de tests coexistent dans Air :

Tests unitaires : dans le même fichier que le code testé, dans un module #[cfg(test)] mod tests. Testent les fonctions privées et les détails d’implémentation.

Tests d’intégration de crate : dans le dossier tests/ à côté de src/. Testent l’API publique.

Tests cross-crate : dans le dossier tests/ à la racine du workspace. Testent les interactions entre plusieurs crates Air.

Nommage des tests

Convention subject_action_expectation.

#![allow(unused)]
fn main() {
#[test]
fn open_existing_file_returns_owned_fd() { /* ... */ }

#[test]
fn open_nonexistent_file_returns_enoent() { /* ... */ }
}

Catégories de tests à couvrir

Pour les couches 0 et 1 (Principe 1 : test exhaustif), chaque fonction publique a au minimum :

  1. Test du cas nominal.
  2. Tests des chemins d’erreur (un par variant documenté).
  3. Tests des limites.
  4. Tests des invariants.

Pour les fonctions complexes, s’ajoutent :

  1. Property-based tests (via proptest ou quickcheck).
  2. Tests adversariaux.
  3. Tests de concurrence (via loom si nécessaire).
  4. Fuzzing via cargo-fuzz.

Harnais spécifiques

Harnais subprocess : pour les tests qui modifient l’état du processus (seccomp, prctl, etc.). Fork un sous-processus, exécute la fonction, propage le résultat.

Harnais tempdir : pour les tests filesystem. Chaque test obtient son propre dossier temporaire.

Harnais io_uring_test_ring : pour les tests io_uring. Crée un ring de test, gère le cleanup.

Harnais signal_isolation : pour les tests qui manipulent les signaux. Restaure le state après.

Tests qui demandent des privilèges

#![allow(unused)]
fn main() {
#[test]
#[cfg_attr(not(privileged_test), ignore = "requires CAP_SYS_ADMIN")]
fn unshare_creates_new_namespace() { /* ... */ }
}

Le CI exécute ces tests dans un environnement privilégié séparé.

Tests bench-comme

Outillage : criterion. Les benchmarks vivent dans benches/. Le CI les exécute sur les machines de référence (ADR-014) et détecte les régressions :

  • Augmentation > 10% : alerte.
  • Augmentation > 25% : échec CI.

Couverture de tests

100% sur les couches 0 et 1. Outillage : cargo-tarpaulin ou cargo-llvm-cov.

Une baisse de couverture sur les couches 0 et 1 fait échouer le CI.

Section 2 : Conventions de gestion des erreurs en couches supérieures

Application de l’ADR-019

Couche 0 : Errno minimal. Couches 1+ : type Error enrichi par crate, via thiserror.

Définition d’un type Error par crate

#![allow(unused)]
fn main() {
use thiserror::Error;
use air_sys_types::Errno;

#[derive(Debug, Error)]
pub enum IoError {
    #[error("syscall failed: {source}")]
    Syscall {
        #[from]
        source: Errno,
    },
    
    #[error("io_uring submission failed: queue full")]
    SubmissionQueueFull,
    
    #[error("invalid operation parameters: {reason}")]
    InvalidParameters { reason: &'static str },
    
    #[error("operation not supported on this kernel: {0:?}")]
    OperationNotSupported(IoUringOpcode),
    
    #[error("internal runtime error: {0}")]
    Internal(InternalError),
}
}

Conventions :

  • Un variant par catégorie d’erreur logique.
  • #[from] pour les conversions automatiques.
  • Messages d’erreur informatifs.
  • Pas de String dans les messages sauf nécessité (préférer &'static str).

Attachement de contexte

Le contexte est attaché au moment de la propagation :

#![allow(unused)]
fn main() {
fn open_config(path: &Path) -> Result<Config, ConfigError> {
    let fd = openat2(DirFd::Cwd, path.as_cstr(), OpenHow::read_only())
        .map_err(|errno| ConfigError::OpenFailed {
            path: path.to_path_buf(),
            source: errno,
        })?;
    // ...
}
}

Hiérarchie des erreurs

Les erreurs se propagent en chaîne via source() :

#![allow(unused)]
fn main() {
#[derive(Debug, Error)]
pub enum TransportError {
    #[error("io error: {0}")]
    Io(#[from] air_runtime_io::IoError),
    
    #[error("connection refused by peer")]
    ConnectionRefused,
    
    #[error("invalid wire format: {reason}")]
    ProtocolViolation { reason: &'static str },
}
}

Politique sur les panic

Panic acceptable : violations d’invariants internes (bugs Air).

Panic inacceptable : input utilisateur invalide, condition normale d’erreur, erreur kernel.

Documentation des erreurs

La section # Errors de chaque fonction publique liste les variants d’erreur possibles avec leur contexte.

Section 3 : Templates de PR et de commits

Format des messages de commit

Variation simplifiée de Conventional Commits :

<type>(<scope>): <short description>

<optional body>

<optional footer>

Types reconnus : feat, fix, docs, style, refactor, perf, test, chore, adr.

Scope : nom de la crate ou du module touché.

Description courte : mode impératif, présent, sans point final, minuscule.

Exemple :

feat(air-sys-syscall): add pidfd_open wrapper

Implements the pidfd_open syscall as part of the process management
family. Includes RAII handle (PidFd), error mapping, and full test
coverage including post-mortem usage.

Resolves: AIR-127

Pas de commits “wip” ou “fix typo”

Les commits sont des unités logiques cohérentes. Squashés ou réordonnés avant le merge.

Template de PR

## Summary

<!-- One or two sentences describing what this PR does. -->

## Motivation

<!-- Why is this change needed? Link to issues or RFCs. -->

## Changes

-

## Testing

-

## Documentation

-

## Dependencies

<!-- Did this PR add, remove, or modify dependencies?
Link to DEPENDENCIES.md changes per ADR-024. -->

## Breaking changes

<!-- Note that breaking changes on air-stable symbols
require a major version bump per ADR-012. -->

## Engineering Principles checklist

- [ ] Test coverage maintained (100% for layers 0 and 1, > 90% elsewhere)
- [ ] Defensive arithmetic conventions followed
- [ ] String/buffer/encoding handling explicit
- [ ] Inputs validated upfront, invariants documented
- [ ] No unsafe code added without SAFETY comments and review
- [ ] If new dependency added: DEPENDENCIES.md updated per ADR-024
- [ ] If new public API: rustdoc complete
- [ ] ABI stability respected on `air-stable` symbols

## Related ADRs

<!-- List any ADRs that motivated or relate to this change. -->

Workflow de revue

  1. Auto-vérification par le contributeur (checklist).
  2. Revue par CI automatique.
  3. Revue humaine par un mainteneur.
  4. Revue spécialisée si nécessaire :
    • unsafe modifié : revue par mainteneur senior systèmes.
    • ADR ajouté : revue par BDFL/TC.
    • ABI publique modifiée : revue ABI dédiée.
  5. Approbation et merge.

Pas de merge sans approbation explicite. Pas d’auto-merge.

Préférer squash-and-merge pour PR avec plusieurs commits intermédiaires.

Branches

Trunk-based development.

  • Une seule branche stable : main.
  • Les PRs sont mergées dans main directement.
  • Pas de branches develop, release, ou autres.
  • Les releases sont des tags Git sur des commits de main.
  • Les backports vers les versions majeures supportées (cf. ADR-012) se font sur des branches release/N.0.

Section 4 : Documents de référence à créer

  • CONTRIBUTING.md : guide général.
  • STYLE_GUIDE.md : conventions de code (Phase B1).
  • TESTING_GUIDE.md : conventions de tests (Phase B2 section 1).
  • ERROR_HANDLING.md : conventions d’erreurs (Phase B2 section 2).
  • COMMIT_CONVENTIONS.md : format des messages de commit.
  • PR_REVIEW_GUIDE.md : workflow de revue.

Récapitulatif Phase B2

DomaineConvention principale
Tests unitairesDans src/, #[cfg(test)] mod tests
Tests intégrationDans tests/ au niveau crate
Tests cross-crateDans tests/ au niveau workspace
Harnais spéciauxsubprocess, tempdir, io_uring_test_ring, etc.
Erreurs couches supType par crate via thiserror, contexte au point d’attachement
Format commitsVariation Conventional Commits, scope par crate
Template PRChecklist Principes d’ingénierie obligatoire
BranchesTrunk-based, main unique
DocumentsPlusieurs guides à la racine

Licence du document : MPL 2.0 Statut : Document de setup phase 0.