🕵️ Introduzione
Il Linux Test Project (LTP) è un progetto congiunto avviato anni fa da SGI, OSDL e Bull, sviluppato e oggi mantenuto da IBM, Cisco, Fujitsu, SUSE, Red Hat, Oracle e molti altri. L’obiettivo del progetto è fornire alla community open source test che convalidino l’affidabilità, la robustezza e la stabilità di Linux.
In questi giorni sto esplorando il progetto, quindi con questo articolo voglio mostrare passo dopo passo come configurarlo, come vengono effettivamente scritti i test e fornirvi una guida rapida ed essenziale per scrivere il vostro primo test.
🧰 Cominciamo
NOTA: Poiché alcuni test modificano le impostazioni del sistema operativo, se avete intenzione di eseguire l’intera suite di test è consigliabile mantenere pulita la vostra workstation e configurare un ambiente separato, come un PC di riserva o una macchina virtuale di sviluppo.
La prima cosa da fare è installare gli strumenti di sviluppo e clonare la repository:
# zypper in -t pattern devel_basis
or
# zypper install gcc git make pkg-config autoconf automake bison flex m4 linux-glibc-devel glibc-devel
$ git clone https://github.com/linux-test-project/ltp.git && cd ltp
$ make autotools
$ ./configure
[...omitted output...]
Ora potete continuare compilando ed eseguendo un singolo test oppure compilando e installando l’intera suite di test. Facciamo un piccolo passo alla volta:
⚗️ Un test di esempio
Se si desidera eseguire solo un singolo test, in realtà non è necessario compilare l’intero progetto LTP. Scegliamo un test di esempio per la syscall open(). Per trovare questo test specifico:
$ cd testcases/kernel/syscalls/open
$ cat open03.c
Cosa c’è dentro? ⁉️
| |
Questo test è piuttosto semplice, poiché il codice effettivo è inferiore a 10 righe. Ecco una breve panoramica riga per riga:
- 1-12: commenti standard, licenza e intestazione della documentazione. Questo progetto ha più di 20 anni di storia!
- 13: inclusione dell’header obbligatorio della libreria LTP
- 15: un nome di file di esempio che proveremo a creare chiamando la syscall
open() - 17-19: la funzione di test vera e propria: utilizzando le macro fornite dal framework, invia al kernel una chiamata di sistema
open()e si assicura che l’operazione vada a buon fine; se per qualsiasi motivo la syscall dovesse restituire un errore, questo viene segnalato automaticamente e il risultato del test viene contrassegnato come fallito (failed). In ogni caso, il valore restituito viene memorizzato nella variabileTST_RET - 20-22: le macro
SAFE_*ci consentono di chiudere ed eliminare il file appena aperto in modo pulito - 24-27: definizione dei metadati del test: di quali opzioni ha bisogno per essere eseguito e qual è la funzione che il framework eseguirà per noi. Il framework LTP cercherà questa struttura e utilizzerà le informazioni contenute al suo interno. Se siete curiosi di conoscere tutte le opzioni disponibili, potete trovare una buona descrizione qui, ma trattandosi di un argomento molto vasto, merita un post dedicato in futuro
Il Linux Test Project, così como lo stesso Kernel Linux, fa un uso massiccio di macro C, al fine di mantenere i test puliti, manutenibili e leggibili. Ovviamente tutte le macro e le funzioni di libreria sono documentate e spiegate nella documentazione del progetto.
Per un riferimento delle syscall, basta consultare le pagine man del sistema. Un piccolo consiglio: è raccomandabile clonare il repository man ufficiale a monte (upstream) perché a volte le pagine man distribuite con le distribuzioni possono essere un po’ vecchie.
👟 Come eseguire il test
Grazie alla configurazione del build system, possiamo semplicemente compilare con make il nostro singolo test ed eseguire l’eseguibile standalone. LTP aggiungerà molte informazioni utili al nostro piccolo programma:
$ make open03
[... compiler messages omitted...]
$ ./open03
tst_test.c:1741: TINFO: LTP version: 20240129
tst_test.c:1625: TINFO: Timeout per run is 0h 00m 30s
open03.c:19: TPASS: open(TEST_FILE, O_RDWR | O_CREAT, 0700) returned fd 3
Summary:
passed 1
failed 0
broken 0
skipped 0
warnings 0
L’eseguibile compilato accetta anche alcune opzioni, sempre grazie al framework LTP:
$ ./open03 -h
Environment Variables
---------------------
KCONFIG_PATH Specify kernel config file
KCONFIG_SKIP_CHECK Skip kernel config check if variable set (not set by default)
LTPROOT Prefix for installed LTP (default: /opt/ltp)
LTP_COLORIZE_OUTPUT Force colorized output behaviour (y/1 always, n/0: never)
LTP_DEV Path to the block device to be used (for .needs_device)
LTP_DEV_FS_TYPE Filesystem used for testing (default: ext2)
LTP_SINGLE_FS_TYPE Testing only - specifies filesystem instead all supported (for .all_filesystems)
LTP_TIMEOUT_MUL Timeout multiplier (must be a number >=1)
LTP_RUNTIME_MUL Runtime multiplier (must be a number >=1)
LTP_VIRT_OVERRIDE Overrides virtual machine detection (values: ""|kvm|microsoft|xen|zvm)
TMPDIR Base directory for template directory (for .needs_tmpdir, default: /tmp)
Timeout and runtime
-------------------
Test timeout (not including runtime) 0h 0m 30s
Options
-------
-h Prints this help
-i n Execute test n times
-I x Execute test for n seconds
-D Prints debug information
-V Prints LTP version
-C ARG Run child process with ARG arguments (used internally)
potete anche controllare il vostro codice sorgente rispetto alle best practice del progetto:
$ make check-open03
Riceverete suggerimenti ed errori sulla qualità del codice, la formattazione e le possibili deviazioni dagli standard di programmazione del progetto.
🗿 Hello, nuovo test
Quindi, se volete scrivere un nuovo test per LTP, potete semplicemente scegliere una sottocartella in testcases/kernel/ e creare un nuovo file .c usando un template come questo:
| |
In questo esempio è importante notare che le funzioni setup() e cleanup() servono a creare/disporre le risorse del test (come buffer, file, socket, processi figli e così via) e vengono eseguite una sola volta, mentre run() è il codice di test vero e proprio e può essere ripetuto molte volte.
Dopo aver salvato il codice sorgente con un nome del tipo mynewtest01.c, basta eseguire:
$ make mynewtest01
CC testcases/kernel/syscalls/open/mynewtest01
$ ls -l mynewtest*
-rwxr-xr-x 1 andrea andrea 738064 Feb 10 11:46 mynewtest01
-rw-r--r-- 1 andrea andrea 475 Feb 10 11:46 mynewtest01.c
$ ./mynewtest01
tst_test.c:1741: TINFO: LTP version: 20240129
tst_test.c:1625: TINFO: Timeout per run is 0h 00m 30s
mynewtest01.c:5: TINFO: example setup
mynewtest01.c:15: TPASS: Doing hardly anything is easy
mynewtest01.c:10: TINFO: example cleanup
Summary:
passed 1
failed 0
broken 0
skipped 0
warnings 0
Non fa ancora nulla ma sembra funzionare; ora non vi resta che implementare la logica del test vero e proprio.
Una volta terminato e testato, se volete che il nuovo test venga eseguito come parte della suite, dovete aggiungerlo in una delle sottocartelle runtest, dove ogni file di testo definisce un gruppo di test (ovvero una test suite).
✅ Conclusioni
Se siete interessati al progetto, consultate la Wiki del progetto per ulteriore documentazione e per le linee guida di scrittura (Writing Guidelines); potete anche iscrivervi alla Mailing List di LTP. Buon divertimento!