Metodologie e strumenti per il testing del software di

Transcript

Metodologie e strumenti per il testing del software di
Università degli studi di RomaTre
Dipartimento di Ingegneria
Laurea triennale in Ingegneria Informatica
Tesi di laurea
Metodologie e strumenti per il testing del software di controllo di
integrità dei dati su strutture dati autenticate
Candidato
Alessio Treglia
Matr. 240930
Relatore
Maurizio Pizzonia
Anno accademico
2012/2013
The beginning is always today
(Mary Shelley)
Ho imparato un sacco di cose
in mezzo agli altri, vestiti uguali
Ma non quale é il crimine giusto
per non passare da criminali
(Fabrizio De André)
Indice
Introduzione
2
1 Contesto e stato dell’arte
3
1.1
1.2
1.3
1.4
FileRock: un servizio di sincronizzazione e backup . . . . . . . . . .
3
1.1.1
FileRock client . . . . . . . . . . . . . . . . . . . . . . . . . .
4
Strutture dati autenticate . . . . . . . . . . . . . . . . . . . . . . . .
6
1.2.1
Basis e proof . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.2.2
Merkle hash tree . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.2.3
Merkle hash tree: calcolo della proof . . . . . . . . . . . . . .
7
1.2.4
Skip list autenticate . . . . . . . . . . . . . . . . . . . . . . .
9
1.2.5
Authenticated skip list: calcolo della proof . . . . . . . . . . .
10
Implementazione: linguaggi e tecnologie . . . . . . . . . . . . . . . .
10
1.3.1
Python: caratteristiche e breve storia . . . . . . . . . . . . .
11
1.3.2
Testing: Python unittest . . . . . . . . . . . . . . . . . . . . .
12
Obiettivi previsti . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
2 Analisi e progettazione
15
2.1
Software testing come garanzia di qualità . . . . . . . . . . . . . . .
15
2.2
Obiettivi e limitazioni del collaudo . . . . . . . . . . . . . . . . . . .
16
2.2.1
Limiti del testing . . . . . . . . . . . . . . . . . . . . . . . . .
16
Verifica e validazione . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.3.1
Tecniche di verifica . . . . . . . . . . . . . . . . . . . . . . . .
18
2.3.2
Test fixture e oggetti fittizi . . . . . . . . . . . . . . . . . . .
19
2.3.3
Tecniche di validazione . . . . . . . . . . . . . . . . . . . . . .
20
2.3.4
Verifica e validazione in FileRock . . . . . . . . . . . . . . . .
20
Garanzia di qualità . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.4.1
Definizioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.4.2
Indicatori di qualità e obiettivi . . . . . . . . . . . . . . . . .
22
2.3
2.4
I
II
INDICE
2.4.3
2.5
2.6
Garanzia di qualità in FileRock . . . . . . . . . . . . . . . . .
23
Analisi: scenario iniziale . . . . . . . . . . . . . . . . . . . . . . . . .
24
2.5.1
Struttura . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
2.5.2
Analisi delle criticità e piano di lavoro . . . . . . . . . . . . .
25
Debian packaging e integrazione in Ubuntu . . . . . . . . . . . . . .
26
3 Realizzazione del software
3.1
3.2
3.3
3.4
27
Casistiche e tipologie di test . . . . . . . . . . . . . . . . . . . . . . .
27
3.1.1
Test unitario . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.1.2
Test funzionale . . . . . . . . . . . . . . . . . . . . . . . . . .
29
3.1.3
Test di integrazione . . . . . . . . . . . . . . . . . . . . . . .
31
Modello e generazione dati di input . . . . . . . . . . . . . . . . . . .
33
3.2.1
Oggetti Dataset per l’incapsulamento del filesystem . . . . .
33
3.2.2
Generazione dati casuali . . . . . . . . . . . . . . . . . . . . .
34
Supporto all’automazione . . . . . . . . . . . . . . . . . . . . . . . .
34
3.3.1
Caricamento dei dati di input da file di configurazione . . . .
34
3.3.2
Script di esecuzione automatica . . . . . . . . . . . . . . . . .
35
Integrazione in Debian e Ubuntu . . . . . . . . . . . . . . . . . . . .
36
3.4.1
Integrazione in Unity . . . . . . . . . . . . . . . . . . . . . . .
36
3.4.2
Debian packaging . . . . . . . . . . . . . . . . . . . . . . . . .
37
4 Conclusioni
39
4.1
Sviluppi futuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
4.2
Conclusioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
A Licenza
Glossario
Bibliografia
Ringraziamenti
i
iii
v
ix
Elenco delle figure
1.1
Calcolo del fingerprint dello stato iniziale . . . . . . . . . . . . . . .
5
1.2
Aggiornamento del fingerprint e caricamento dei file . . . . . . . . .
5
1.3
Verifica di integrità e download dei file . . . . . . . . . . . . . . . . .
5
1.4
Caricamento di file contenuti protetti . . . . . . . . . . . . . . . . . .
6
1.5
Struttura Merkle hash tree . . . . . . . . . . . . . . . . . . . . . . .
8
1.6
Merkle hash tree, proof per l’elemento e2 . . . . . . . . . . . . . . . .
8
1.7
Skip list autenticata. È indicato il verso di percorrenza del flusso delle
informazioni in un cammino. . . . . . . . . . . . . . . . . . . . . . .
9
1.8
Ricalcolo del basis. In grigio i nodi appartenenti al cammino scelto. .
10
1.9
Analisi prestazionale . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
2.1
Sulla sinistra gli attributi oggetti delle misurazioni, a destra le caratteristiche di qualità . . . . . . . . . . . . . . . . . . . . . . . . . . . .
III
23
IV
ELENCO DELLE FIGURE
Elenco delle tabelle
1.1
Prestazioni: Python si dimostra estremamente veloce con il calcolo
su interi long . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1
12
Analisi della distribuzione degli errori in un progetto software di medie
dimensioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
V
16
VI
ELENCO DELLE TABELLE
Introduzione
Le metodologie e le tecniche di collaudo da sempre rappresentano voci importanti
nelle valutazioni di allocazione di tempo e risorse per lo sviluppo di software. Benché
la relazione fra le strategie di assicurazione di qualità e il successo o il fallimento
di un progetto trovasse già sicuri riscontri nell’industria del periodo antecedente all’introduzione delle più recenti metodologie agili, queste ultime hanno sicuramente
contribuito all’elaborazione di nuove pratiche e strumenti: se fare del buon testing era importante quando l’ingegneria ancora si basava su processi sequenziali di
analisi e progettazione, alcune delle nuove tecniche agili, aventi come principio fondante la riduzione del rischio di insuccesso e basate sulla suddivisione dei processi
di produzione in ridotte finestre temporali, accompagnano lo studio dei requisiti di
sviluppo del software all’analisi dei requisiti di collaudo.
Il progetto FileRock é un software di condivisione di contenuti su Internet prodotto dalla Heyware s.r.l. È progettato per l’utenza desktop privata e aziendale e si
propone di fornire agli utenti le maggiori garanzie possibili in termini di confidenzialità e integrità dei dati. Per raggiungere tale obiettivo FileRock incapsula un’implementazione proprietaria di un protocollo di comunicazione client-server basato su
algoritmi di controllo di integrità dei dati su strutture dati autenticate ADS, acrònimo di Authenticated Data Structures, le quali verranno descritte in seguito.
Questa tesi ha come scopo principale quello di illustrare le strategie e i processi decisionali seguı̀ti nella progettazione dei componenti software di ausilio ai test,
nonché le metodologie e gli strumenti utilizzati dal candidato durante la sua esperienza lavorativa maturata nell’ambito di FileRock, impiegato dalla azienda produttrice
del software nel ruolo di Quality Engineer. Il fine ultimo è stato quello di fornire
agli sviluppatori degli strumenti open, affidabili e di facile utilizzo che fossero in grado di velocizzare la stesura di test case e di automatizzarne l’esecuzione. In primo
1
2
CAPITOLO 0. INTRODUZIONE
luogo sono stati esaminati diversi aspetti e casi d’uso dei componenti sottoposti a
collaudo. Una volta individuate le priorità, si è proceduto alla scrittura dei casi di
test. Durante l’avanzamento dei lavori è stato possibile generalizzare le soluzioni
alle problematiche riscontrate e estenderle a scenari più ampi. Ciò ha permesso la
scrittura di codice riutilizzabile per il collaudo di parti del software non incluse nel
progetto iniziale.
Il Capitolo 1 fornisce una rappresentazione dello scenario iniziale e lo stato dei lavori al momento dell’introduzione del candidato al processo di sviluppo del prodotto.
Sono inoltre introdotte le tecnologie, i linguaggi e gli strumenti open source utilizzate nella scrittura del codice.
Il Capitolo 2 illustra il processo decisionale, le strategie attuate e le tipologie di
problemi risolti per il raggiungimento degli scopi prefissati.
Il Capitolo 3 descrive la scelte progettuali e i dettagli implementativi delle soluzioni
ai problemi individuati duranti le fasi di analisi e comprende una selezione di esempi
di codice estratti dalla ricca codebase del progetto stesso.
Tutto il codice é rilasciato nei termini di una licenza libera, la Berkeley Software
Distribution (variante a 3 clausole) ed è liberamente riutilizzabile, modificabile e
redistribuibile secondo i termini della licenza stessa.
Capitolo 1
Contesto e stato dell’arte
In questo capitolo viene fornita una dettagliata descrizione dello scenario iniziale
dei lavori. Verranno quindi introdotte le strutture dati autenticate, componente
centrale dell’intera architettura di verifica dell’integrità nonchè target principale delle
operazioni di collaudo, le tecnologie e i linguaggi di programmazione utilizzati nello
sviluppo del software, nonché il risultato delle prime fasi di analisi del progetto.
1.1
FileRock: un servizio di sincronizzazione e backup
FileRock [fila] é un servizio di sincronizzazione e backup di dati sul web che consente la memorizzazione e la gestione di file grazie all’utilizzo di risorse software e
hardware coordinate all’interno di un’architettura remota distribuita.
Le caratteristiche del servizio sono accomunabili a quelle del classico servizio
di cloud computing, gli obiettivi prefissati (come descritto in [Nar12]) si possono
riassumere nei tre pilastri [Per11] della sicurezza dei dati:
• confidenzialità
• integrità
• disponibilità
Il termine confidenzialità si riferisce alle misure di protezione dei dati che garantiscono all’utente un controllo totale e esclusivo sulle politiche di accesso agli stessi.
Il servizio si offre di garantire all’utente che financo i membri dello staff tecnico e
amministrativo saranno impossibilitati ad accedere in lettura ai dati memorizzati.
3
4
CAPITOLO 1. CONTESTO E STATO DELL’ARTE
Il principio di integrità si può riassumere nell’impossibilità per soggetti non au-
torizzati di effettuare modifiche o cancellazioni. Qualora si verificassero modifiche
non autorizzate, l’utente sarà sempre in grado di accorgersene.
La disponibilità é il principio secondo il quale l’utente deve poter accedere ai
propri dati in qualsiasi momento. I canali di accesso, i sistemi e gli automatismi di
autenticazione devono sempre funzionare correttamente al fine di fornire un servizio
continuativo per la fruizione dei dati.
FileRock si prefigge perciò di fornire un servizio all’utente con lo scopo di soddisfare i seguenti requisiti:
• i dati si troveranno sempre nell’ultimo stato noto all’utente proprietario degli
stessi;
• in caso di guasti e di modifiche malevoli ai dati, l’utente verrà tempestivamente
avvisato;
• l’utente é libero di non fidarsi dei servizi di sincronizzazione, backup e memorizzazione fisica dei propri dati.
1.1.1
FileRock client
L’applicazione client (ovvero il programma in formato eseguibile fornito all’utente),
oltre a fornire una interfaccia gradevole e di semplice utilizzo, si occupa principalmente di verificare l’integrità del patrimonio di dati dell’utente e di gestire le
operazioni di cifratura, qualora richieste, in fase di upload dei dati sul server.
Allo stato iniziale viene calcolato una rappresentazione numerica dei contenuti
di una cartella privata dell’utente, nota come fingerprint. A un set di contenuti può
corrispondere una sola rappresentazione digitale, per evitare collisioni viene utilizzato l’algoritmo MD5 [Riv92] per produrre codici hash di lunghezza pari a 128 bit
(16-byte).
Quando vengono apportate una o più modifiche ai file presenti nella cartella privata dell’utente, l’applicazione sincronizza i dati con il server e aggiorna il fingerprint.
1.1. FILEROCK: UN SERVIZIO DI SINCRONIZZAZIONE E BACKUP
5
Figura 1.1: Calcolo del fingerprint dello stato iniziale
Figura 1.2: Aggiornamento del fingerprint e caricamento dei file
In fase di download dei dati, il servizio remoto fornisce una prova di integrità che
verrà successivamente utilizzata dall’applicazione client per verificare la correttezza dell’operazione richiesta. Se la verifica dell’integrità ha successo, il client inizia
a scaricare i dati in locale; in caso contrario informa immediatamente l’utente del
problema riscontrato.
Figura 1.3: Verifica di integrità e download dei file
6
CAPITOLO 1. CONTESTO E STATO DELL’ARTE
Fra le caratteristiche avanzate aggiuntive offerte da FileRock c’è la sopra citata
cifratura in locale. L’applicazione applica a una cartella residente sul filesystem a
scelta dell’utente un algoritmo di cifratura e provvede al suo caricamento in forma
già cifrata, impedendo in questo modo ogni eventuale accesso lato server.
Figura 1.4: Caricamento di file contenuti protetti
1.2
Strutture dati autenticate
Le prime apparizioni in ambito crittografico delle strutture dati autenticate si devono
a [Mer80], [Koc98] e [NN98], una sintetica descrizione generale viene fornita da
[Nar12]: “una struttura dati si dice autenticata se da essa è possibile trarre sempre
una prova di integrità, o proof relativa al suo stato corrente.”
L’utilizzo avviene in uno scenario in cui una fonte non fidata ha la responsabilità di soddisfare una richiesta, garantendo la veridicità della risposta fornita. Nel
caso specifico di una implementazione di una struttura dati, le richieste si possono
classificare in una ristretta selezione:
• inserimenti
• cancellazioni
• ricerca
Le entità fondamentali dell’implementazione hanno i nomi di basis e proof. La
prima é un hash crittografico di un determinato stato della struttura dati, la seconda è una coppia formata da un’operazione e un codice hash che permette la verifica
1.2. STRUTTURE DATI AUTENTICATE
7
dell’integrità di uno stato della struttura oggetto della richiesta.
1.2.1
Basis e proof
Il basis é lo strumento principale necessario per dimostrare l’integrità della struttura dati e del suo contenuto. Trattandosi di un fingerprint di un determinato stato
del dataset, una proprietà fondamentale é che a due stati diversi corrispondono due
basis diversi.
Un agente interessato a verificare l’integrità della struttura deve perciò conoscere
il valore corrente del basis. La prova di integrità é fornita dalla proof: applicando
un algoritmo a tale insieme di informazioni, è possibile ricalcolare il valore hash dei
dati e verificarne l’uguaglianza con un basis fidato. Quest’ultimo può essergli stato
comunicato da una fonte fidata (o inoltrato da una fonte non fidata fintanto che
firmato dalla fonte fidata) [Nar12].
1.2.2
Merkle hash tree
Una implementazione possibile é la Merkle hash tree, proposta in [Mer80]. Tale
struttura é una particolare istanza di albero di ricerca composta da una funzione di
hash H e un insieme di dati ordinati S e caratterizzata come segue:
• i nodi foglia corrispondo agli elementi e di S; sono anch’essi dotati di un’etichetta, la quale corrisponde al valore hash H(e) dell’elemento che rappresentano;
• i nodi intermedi sono dotati di etichetta, risultato della funzione di hash
applicata sulla concatenazione delle etichette dei nodi figli.
Ne deriva che anche il nodo radice root é provvisto di etichetta, la quale rappresenta il basis, ovvero il fingerprint dell’intera collezione di dati [Nar12].
1.2.3
Merkle hash tree: calcolo della proof
Per verificare la presenza di un dato nodo e nella struttura dati autenticate, si prenda
in considerazione un cammino T dal nodo root al nodo e. Ogni nodo p appartenente a
8
CAPITOLO 1. CONTESTO E STATO DELL’ARTE
Figura 1.5: Struttura Merkle hash tree
tale cammino possiede un nodo figlio q, non incluso nel cammino T, che contribuisce
al calcolo dell’etichetta del genitore.
Figura 1.6: Merkle hash tree, proof per l’elemento e2
La proof é composta dall’insieme di tali contributi. Nota la funziona di hash, la
proof sopra definita permette di ricalcolare il basis dell’intero insieme dei dati [Nar12].
1.2. STRUTTURE DATI AUTENTICATE
1.2.4
9
Skip list autenticate
Un’altra possibile implementazione é rappresentata dalle authenticated skip list,
ampiamente analizzate e discusse in [GTS01], [GT01] e [Nar12].
La struttura dati in questione é una variante della tradizionale skiplist, introdotte
da [Pug90], i cui elementi sono arricchiti delle informazioni di autenticazione.
Una skip list é composta da un insieme di liste ordinate. Una di queste liste
contiene l’intero insieme di dati, le altre costituiscono una parte di ridondanza: ogni
elemento ha probabilità 1/2 di essere presente in una lista se presente nella lista
precedente; l’ultima lista contiene esclusivamente gli elementi +∞ e −∞, necessari
ai fini della ricerca di elementi all’interno della struttura.
Sfruttando una logica simile a quella utilizzata dai Merkle hash tree, viene composto un grafico diretto aciclico a partire dai nodi della skip list. Tale struttura
supporta efficienti operazioni di ricerca di un elemento e all’interno di un insieme S.
Figura 1.7: Skip list autenticata. È indicato il verso di percorrenza del flusso delle
informazioni in un cammino.
In Figura 1.7 é mostrata una skip list autenticata, dove ogni elemento in ogni
lista é un nodo del grafo ed é caratterizzato da un’etichetta. Ogni etichetta è calcolata come composizione delle etichette dei nodi figli, il valore del basis é rappresentato
dall’etichetta del nodo root ((−∞, L3 )).
10
CAPITOLO 1. CONTESTO E STATO DELL’ARTE
1.2.5
Authenticated skip list: calcolo della proof
Le proof per la verifica della presenza di un elemento e nella struttura si costruiscono
con un processo del tutto simile a quello utilizzato nei Merkle hash tree. Dato
un cammino T dal nodo (e, L0 ) alla radice (−∞, L3 ), si collezionano tutti i nodi
che contribuiscono a tale cammino. Nota la funzione di hash, é sempre possibile
ricalcolare tutte le etichette dal nodo di partenza fino al basis.
In 1.8 viene mostrato il cammino di computazione per l’elemento 19; i nodi che
compongono la proof sono marcati con linee oblique. Per ottenere il fingerprint, é
necessario ricalcolare le etichette dei nodi grigi fino al nodo radice.
Figura 1.8: Ricalcolo del basis. In grigio i nodi appartenenti al cammino scelto.
Come evidenziato in Figura 1.8, per il computo del basis non é necessario conoscere
le etichette dei nodi appartenenti al cammino scelto.
1.3
Implementazione: linguaggi e tecnologie
L’implementazione scelta per le strutture dati autenticate si basa sulle authenticated
skip list descritte in 4.2. L’implementazione si basa dunque su:
• la stessa struttura dati, che supporta interrogazioni e operazioni di inserimento,
cancellazione e modifica;
• un algoritmo per il calcolo del basis;
• una proof e un algoritmo per la generazione della stessa quando associata a
un’operazione;
1.3. IMPLEMENTAZIONE: LINGUAGGI E TECNOLOGIE
11
• un algoritmo per la verifica della validità dell’operazione combinata alla proof
da parte dell’applicazione client.
Il codice dell’architettura software e dei testcases per il testing dei componenti
responsabili della verifica di integrità dei dati é interamente scritto in linguaggio
Python.
1.3.1
Python: caratteristiche e breve storia
Python é stato inventato e reso pubblico da Guido Van Rossum, un matematico olandese, nel febbraio del 1991, con un messaggio pubblicato sul newsgroup
alt.sources [Pyt91]. Sulla scelta di Python come linguaggio e dunque strumento
principale di sviluppo hanno pesato alcune delle sue più importanti caratteristiche:
• orientabilità agli oggetti: Python supporta ereditarietà, polimorfismo e
incapsulamento in modo semplice e intuitivo;
• semplcità d’uso: opera a un alto livello di astrazione e la sua sintassi è basata
su poche semplici regole;
• potenza e velocità: l’implementazione prevede che il codice venga bytecompilato prima della sua esecuzione; in molte situazioni, specialmente quelle
che coinvolgono operazioni matematiche con tipi di dati numerici si é dimostrata più veloce di Java e leggermente più lenta di C (i risultati dei test
prestazionali sono mostrati in 1.1 e 1.9);
• portabilità: scritto in linguaggio ANSI C, l’interprete CPython può essere
compilato su tutte le architetture fornite di un compilatore in grado di supportare lo standard C-89. È installato in modo predefinito sulle maggiori distribuzioni GNU/Linux (e.g. Debian, Ubuntu, Fedora) e sulle più importanti
incarnazioni moderne di UNIX come Oracle Solaris e Mac OS X, nonchè sulle
diverse varianti della famiglia BSD.
Più approfondite analisi su comparazioni prestazionali del linguaggio prestazionale
si consulti [pyt09].
12
CAPITOLO 1. CONTESTO E STATO DELL’ARTE
Factorial computatation Java
.NET
Python
Squeak 4 Mono
10.000!
343 ms
137 ms
91 ms
1.200 ms
169 ms
1.480 ms
569 ms
372 ms
1.457 ms
701 ms
20.000!
30.000!
3.424 ms
1.243 ms 836 ms
3.360 ms
1.675 ms
40.000!
6.340 ms
2.101 ms 1.975 ms 6.738 ms
3.042 ms
50.000!
10.493 ms 3.763 ms 3.658 ms 10.019 ms 5.242 ms
60.000!
15.586 ms 7.683 ms 5.788 ms 14.241 ms 10.000 ms
Tabella 1.1: Prestazioni: Python si dimostra estremamente veloce con il calcolo su
interi long
Figura 1.9: Analisi prestazionale
1.3.2
Testing: Python unittest
Il framework di testing sviluppato dal candidato si basa sul framework fornito di
default dal linguaggio: unittest. Tale framework, conosciuto anche come PyUnit
deriva dalla popolare suite di testing per Java JUnit, che a sua volta affondava le
sue radici nella libreria di testing fornita con il linguaggio Smalltalk.
Insieme a PyUnit, per motivi di praticità nella scrittura dei test é stato inoltre
utilizzato il framework Nose [nos].
Nose facilita la scrittura di test cases grazie a un intelligente sistema di discovering dei metodi di test. Nose consente inoltre una gestione trasparente delle
fixtures e dei scenari di test, agevolando la selezione di quest’ultimi in base a criteri
di raggruppamento secondo criteri prestabiliti.
1.4
Obiettivi previsti
Gli obiettivi del progetto erano:
• fornire agli sviluppatori di FileRock un framework per il testing del codice
Python di facile utilizzo specifico per le problematiche più comuni;
1.4. OBIETTIVI PREVISTI
13
• collaudare i componenti software responsabili della verifica di integrità dei dati.
Entrambi gli obiettivi sono stati raggiunti nei limiti di tempo e risorse prestabilite.
14
CAPITOLO 1. CONTESTO E STATO DELL’ARTE
Capitolo 2
Analisi e progettazione
In questo capitolo vengono illustrati il processo decisionale e le strategie applicate
durante le fasi di analisi e progettazione del componente software di ausilio ai test.
Verrà inoltre esposto il risultato dello studio effettuato sugli argomenti riguardanti la teoria e le tecniche di validazione, verifica e garanzia di qualità sulla base dei
quali il candidato ha affrontato l’ampia casistica e le diverse tipologie di problemi
durante lo sviluppo dei test cases.
2.1
Software testing come garanzia di qualità
In modo del tutto simile alla maggior parte dei processi fisici, un componente software riceve un insieme di dati di ingresso per elaborarli e produrre un insieme di
dati di uscita. Qualsiasi attività finalizzata alla valutazione delle caratteristiche di
un programma o un sistema e alla verifica che i comportamenti degli stessi diano i
risultati previsti rientra nella definizione di software testing [HH88].
¯
Ciò in cui un software differisce dagli altri sistemi fisici é l’insieme solitamente
molto ampio di modi in cui é possibile che esso fallisca; benché un software non risenta di difetti di fabbrica (molto spesso i difetti derivano da errori introdotti in fase di
progettazione e non dalla scrittura del codice sorgente) né di altri fattori ambientali
e di usura, cercare di prevedere tutti i possibili errori é di fatto impossibile [Pan99].
15
16
CAPITOLO 2. ANALISI E PROGETTAZIONE
2.2
Obiettivi e limitazioni del collaudo
Le attività di testing sono considerate parti integranti dello sviluppo di un software:
metà delle risorse impiegate nello sviluppo vengono solitamente allocate a a procedure di collaudo [Har00], le quali sono dunque generalmente riconducibili a due
importanti scopi finali:
• verifica e validazione: in altre parole, validare che il software soddisfi i
requisiti e le specifiche e verificare che lo faccia nel modo atteso;
• migliorare la qualità: la presenza di difetti rappresenta solo uno degli indici
di qualità del software (correttezza), il collaudo si propone come obiettivo quello
di valutare il software secondo un insieme di parametri.
2.2.1
Limiti del testing
La presenza di difetti nel software è strettamente correlata alla sua complessità, la
tabella 2.1 mostra l’ottima rappresentazione fornita da [BP84] dell’andamento del
rapporto che intercorre fra le dimensioni (misurate in linee di codice) di un programma e la presenza di difetti.
N. di linee sorgenti totali binari totali
0-50
53
258
51-100
107
70
101-150
80
26
151-200
56
13
201-250
34
1
251-300
14
1
301-350
7
1
351-400
9
0
>400
10
0
Total
370
370
Tabella 2.1: Analisi della distribuzione degli
dimensioni
sorgenti con errori
3
16
20
19
12
9
4
7
6
binari con errori
49
25
13
7
1
0
1
0
0
96
96
errori in un progetto software di medie
La presenza di bug in un software deriva dunque dalla complessità stessa e non é
direttamente correlata alle capacità tecniche dei programmatori che ne hanno curato
progettazione e implementazione. Per lo stesso motivo, scoprire i difetti é altrettanto difficile. Collaudare un sistema coprendo tutto l’insieme di dati accettabile dallo
2.3. VERIFICA E VALIDAZIONE
17
stesso é impraticabile; si può averne la dimostrazione prendendo in considerazione
un semplice programma sommatore a due operandi di numeri interi a 32 bit come
oggetto del collaudo: significherebbe testare il funzionamento del sistema con 264
combinazioni, con grande dispendio di tempo e risorse [Pan99].
Un’ulteriore complicazione deriva dalla frequenza di aggiornamento del software:
un test case scritto ed eseguito con successo durante le prime fasi di sviluppo potrebbe
fallire in una successiva occasione a causa di modifiche introdotte nel codice sorgente.
È evidente che l’improvviso fallimento di un test case richiede un’indagine approfondita sia del codice del programma che dello stesso test: potrebbe essere necessario
aggiornare il meccanismo di collaudo per renderlo conforme al nuovo comportamento del software. In alternativa, nel caso in cui l’errore non fosse né nel codice né
nei dati di input del test, bisognerà riparare il difetto all’interno del programma.
Infine, sarà necessario eseguire nuovamente il test. È evidente come tutte queste operazioni abbiano dei costi. Senza una strategia e degli strumenti di ausilio all’analisi
dei requisiti e alla scrittura dei componenti di collaudo, tali costi possono diventare
insostenibili.
2.3
Verifica e validazione
Verifica e validazione sono elementi fondamentali nel ciclo di vita di qualsiasi software. Lo sviluppo di un programma, un sistema complesso o anche un solo singolo
componente unitario non può mai perdere di vista il suo obiettivo: soddisfare correttamente un insieme definito di requisiti.
I concetti di validazione e verifica vengono talvolta confusi, per comprendere le
sottili ma fondamentali differenze fra questi concetti é possibile ricorrere a diverse
fonti in letteratura. Le definizioni formali più largamente diffuse e accettate sono
fornite da [PCCW93]:
• la validazione é “il processo di valutazione del software, messo in atto parallelamente o alla fine del processo di sviluppo, allo scopo di determinare se lo
stesso rispetti o meno i requisiti stabiliti”;
• la verifica é “il processo di valutazione del software atto a determinare se i
prodotti di una certa fase di sviluppo soddisfino le condizioni iniziali”.
18
CAPITOLO 2. ANALISI E PROGETTAZIONE
Secondo [Boe89], verifica e validazione devono rispondere alle seguenti domande:
• validazione: “stiamo sviluppando il prodotto corretto?”;
• verifica: “il prodotto che stiamo sviluppando è corretto?”.
2.3.1
Tecniche di verifica
Esiste una vasta letteratura sui numerosi approcci e le tecniche di verifica. La prima
macro suddivisione si basa sulla natura stessa del tipo di collaudo, che può essere
statico o dinamico [Tra99]:
• lo static testing é l’insieme di analisi e valutazioni compiute senza la necessità
di eseguire il software oggetto di collaudo. Esempi di attività statiche sono la
verifica formale e l’analisi metrica del codice sorgente;
• per dynamic testing si intendono tutte le procedure eseguite a sistema già
avviato; tipicamente tali attività coinvolgono la comparazione di risultati attesi
con quelli ottenuti a partire da un certo insieme di dati di input introdotti nel
sistema.
Le metodologie statiche possono essere suddivise in due categorie [Tra99]:
• verifiche di coerenza: alcuni esempi sono le verifiche di sintassi, tipizzazione
e corrispondenza dei parametri fra procedure diverse;
• tecniche di misurazione: includono verifiche di leggibilità del codice e livelli
di struttura [And86].
Gli approcci dinamici al collaudo vengono tipicamente suddivisi in tre grandi
categorie [Tra99]:
• testing funzionale: vengono identificate e collaudate le funzionalità previste
dalle specifiche; il classico esempio di test funzionale é noto come collaudo a
scatola nera;
• testing strutturale: viene collaudato il funzionamento interno del software;
questo prevede una conoscenza totale della sua architettura e delle scelte implementative e di design; il tipico esempio di test strutturale é il collaudo a
scatola bianca;
2.3. VERIFICA E VALIDAZIONE
19
• testing casuale: prevede l’esecuzione di un numero di casi di test selezionati,
con l’ausilio di un algoritmo pseudocasuale, tra quelli facenti parte di una
determinata collezione.
È da notare che la strategia in grado di coprire tutte le possibili combinazioni dei
dati di input, nome come collaudo esaustivo, non é altro che un caso particolare
di collaudo casuale. Benché tale strategia consenta di verificare in modo completo il
corretto funzionamento di un sistema, nella grande maggioranza dei casi tale scopo
è impossibile da raggiungere [And86].
2.3.2
Test fixture e oggetti fittizi
Tipicamente, prima di avviare una sessione di collaudo, si rende necessario configurare un contesto all’interno del quale verranno eseguiti i test: tale contesto prende
il nome di test fixture.
Una test fixture rappresenta dunque un insieme di dati e operazioni da eseguire
per portare il sistema sottoposto a collaudo a un determinato stato iniziale. Alcuni
esempi di test fixture seguono:
• inizializzazione del file system, con creazione, copia o spostamento di file o
cartelle all’interno di percorsi predefiniti;
• inizializzazione di database con predefiniti valori iniziali;
• cancellazione di file, cartelle o interi filesystem;
• inizializzazione di componenti software esterni, necessari al corretto svolgimento dei test; il comportamento di alcuni di questi possono essere emulati
attraverso l’utilizzo di oggetti fittizi.
Gli oggetti fittizi, altresı̀ noti come mock, sono utilizzati per simulare il funzionamento di singoli componenti o intere architetture software che non fanno parte degli
obiettivi del collaudo; tali oggetti sono frequentemente utilizzati nel test unitario,
dove le operazioni di collaudo si concentrano su singole unità pseudo-atomiche, allo
scopo di ridurre al minimo le interferenze esterne.
20
CAPITOLO 2. ANALISI E PROGETTAZIONE
2.3.3
Tecniche di validazione
Tipicamente la validazione avviene una volta completata una fase di sviluppo al fine
proprio di determinare se il prodotto rispetta le specifiche iniziali. Esiste una vasta
letteratura anche sulle metodologie e le tecniche di validazione [Tra99], alcune di
queste vengono discusse di seguito:
• analisi formale: utilizzo di espressioni logico-matematiche per formalizzare,
analizzare e indagare le specifiche, il progetto, la documentazione e il comportamento del sistema;
• induzione di guasti: introduzione intenzionale di errori al fine di analizzare il
comportamento del sistema; possono essere guasti di tipo fisico o software;
• analisi di affidabilità: contempla metodi per l’identificazione e la ricerca di
criticità e rischi all’interno del sistema [Kop11].
2.3.4
Verifica e validazione in FileRock
Nell’ambito del progetto FileRock il candidato si è avvalso di una serie di tecniche
di V&V allo scopo di verificare il corretto funzionamento del sistema.
Le attività principali sono state finalizzate al testing dinamico: scrittura di test
cases, generazione dati di input, collezione e raggruppamento dei risultati per casi
d’uso. Il software in oggetto è stato sottoposto a collaudo con entrambi gli approcci
di testing white box e black box. Si è voluto inoltre adottare l’approccio di fault injection che, insieme a delle procedure di random testing per la generazione di dati di
input pseudo casuali, ha permesso di valutare e correggere la gestione delle eccezioni
da parte del sistema.
Come strumento di analisi formale é stato utilizzato pylint [pyl]. Tale software
esegue controlli di coerenza sintattica e conformità del codice allo standard PEP8 [pep] del linguaggio Python e supporta la generazione di diagrammi nel linguaggio
UML.
2.4. GARANZIA DI QUALITÀ
2.4
21
Garanzia di qualità
Innumerevoli soggetti pubblici e privati affidano le proprie funzioni a complesse architetture software. Numerosi di questi soggetti si occupano delle persone e dei loro
interessi, della loro salute o risorse, molti altri si occupano di telecomunicazioni o
trasporti, altri ancora di questioni di difesa nazionale. Le attività lavorative e i
risultati di numerosi enti, società e persone dipendono dalle caratteristiche di correttezza e predicibilità del software che essi utilizzano [GW08]. Un software difettoso
può perciò avere conseguenze estremamente gravi per i propri utenti. Le tecniche di
verifica e validazione analizzate in 3.3 vengono solitamente affiancate a procedure
mirate ad assicurare che il prodotto software finale risponda a criteri di qualità.
2.4.1
Definizioni
Dopo circa settanta anni la prima storica formalizzazione del concetto di qualità
fornita da [She31], l’Organizzazione Internazionale per la Normazione ha applicato
quest’ultimo all’ingegneria del software, ridefinendolo come un misura della “conformità del prodotto software ai requisiti” [iso99, iso10]. Tale definizione non rappresenta per tutti la descrizione più appropriata, poiché a seconda della prospettiva e
dei parametri presi in considerazione la sola conformità stretta alle specifiche iniziali
può non essere sufficiente a garantire un funzionamento del software soddisfacente.
In [KP96, Gar88] vengono proposte cinque diversi approcci alla definizione formale di software quality, ognuno di questi prende in considerazione una prospettiva
diversa:
• l’utente finale è interessato che il prodotto funzioni correttamente in un dato
numero di contesti. Si tratta di una prospettiva più pragmatica, il prodotto
è stato progettato e prodotto per soddisfare una particolare necessità dei suoi
utilizzatori;
• il produttore si occupa di verificare che il prodotto finale rispetti dei requisiti
di qualità; standard internazionali come [iso99] mettono in risalto tali requisiti;
• la qualità del prodotto può essere considerata e valutata attraverso la misurazione delle caratteristiche intrinseche del prodotto stesso;
22
CAPITOLO 2. ANALISI E PROGETTAZIONE
• il valore trascendentale della qualità riguarda gli aspetti utopici del concetto stesso, come un obiettivo ideale a cui si deve sempre tendere, sempre
consapevoli della reale impossibilità di raggiungerlo [KP96];
• con una prospettiva mirata al profitto si realizza come i diversi approcci alla
assicurazione di qualità possano assumere un’importanza diversa a seconda dei
contesti.
Un’interessante definizione viene fornita da [JG88]: “La parola qualità ha diver-
si significati. Due di questi predominano sugli altri: 1. la qualità consiste in quelle
caratteristiche dei prodotti che soddisfano le necessità dei clienti, producendo dunque
soddisfazione verso il prodotto stesso 2. la qualità consiste nell’assenza di deficienze. Tuttavia, in un libro tascabile come questo, è comodo ricorrere a una definizione
abbreviata della parola qualità: idoneità all’uso”.
In [DeM99] la qualità di un prodotto viene definita in funzione di “quanto il
prodotto contribuisce a rendere il mondo un posto migliore”.
2.4.2
Indicatori di qualità e obiettivi
L’obiettivo principale della software quality assurance è dunque garantire che il
prodotto finale soddisfi i requisiti e rispetti le specifiche.
Struttura, classificazione e terminologia degli indicatori di qualità e delle tecniche applicate alla valutazione degli stessi derivano da [iso03, iso05]. Di seguito
verranno brevemente illustrate le cinque caratteristiche fondamentali, indici di qualità del software, prese in considerazione dal candidato durante le fasi di analisi e
progettazione degli strumenti di collaudo automatici:
• efficienza: meno risorse vengono utilizzate e maggiore è l’efficienza; le risorse
vengono tipicamente espresse in termini di tempo di utilizzo della CPU e spazio
di memoria necessari al software per operare;
• affidabilità: minore è la frequenza di guasti, maggiore è l’affidabilità di un
software; talvolta si basa sulla misura del mean time between failures, ovvero il
valore atteso ti tempo che intercorre fra due guasti correlati successivi [Jon87]
altro fattore importante è rappresentato dalla capacità di reazione ai guasti di
un sistema;
2.4. GARANZIA DI QUALITÀ
23
• sicurezza: si riferisce alle politiche di controllo degli accessi messe in atto dal
sistema al fine di evitare intrusioni indesiderate;
• manutenibilità: un codice ben strutturato e un’architettura modulare formata da entità logiche coerentemente raggruppate si dimostra tipicamente facile
da mantenere, estendere e correggere.
In 2.1 [qua] viene mostrato l’albero delle dipendenze che intercorrono fra i principali indicatori di qualità e le rispettive caratteristiche misurabili.
Figura 2.1: Sulla sinistra gli attributi oggetti delle misurazioni, a destra le
caratteristiche di qualità
2.4.3
Garanzia di qualità in FileRock
L’attività principale atta a garantire la conformità del software alle specifiche è stata
l’analisi di copertura del codice.
24
CAPITOLO 2. ANALISI E PROGETTAZIONE
L’analisi di copertura è una misurazione effettuata sul codice sorgente a collaudo
terminato al fine di quantificare la porzione di codice effettivamente controllata dai
test. I criteri generali più comuni per verificare la copertura dei test sono elencati
di seguito:
• statement coverage: per ogni linea, indica il numero di volte che è stata
effettivamente eseguita;
• function coverage: indica la frequenza di esecuzione di ogni routine o funzione;
• branch coverage: per ogni istruzione di controllo if...else indica se tutte le
possibilità sono state esplorate o meno;
• condition coverage: per ogni istruzione if...else indica se l’istruzione booleana
di entrata del controllo è stata valutata per entrambi i casi vero e falso
• multiple condition coverage: per ogni istruzione if...else indica se la tavola
di verità della condizione di entrata del blocco è stata completamente valutata.
Per valutare la copertura dei test in FileRock il candidato ha adottato Nose [nos]
e il modulo coverage [cov]. L’adozione di Nose ha inoltre facilitato l’adozione di
strategie di esecuzione automatica dei test; il supporto all’automazione verrà discusso nei successivi capitoli.
2.5
Analisi: scenario iniziale
La prima operazione svolta all’inizio dei lavori è stata effettuare un’approfondita
analisi del codice sorgente del componente software responsabile della gestione delle
strutture dati autenticate utilizzate all’interno del progetto per la memorizzazione
dei dati dell’utente.
2.5.1
Struttura
Il progetto è suddiviso in diversi moduli principali, vengono elencati di seguito solo
quelli oggetto del presente lavoro:
2.5. ANALISI: SCENARIO INIZIALE
25
• server: componente lato server del servizio; incapsula la parte dell’implementazione dell’algoritmo di integrità che gestisce la persistenza delle strutture
dati autenticate;
• client: codice relativo all’applicazione client; contiene il componente lato client
del meccanismo di verifica dell’integrità necessario all’utente per sincronizzare
i dati in locale con la controparte remota, gestita dal server;
• librerie condivise: codice condiviso da entrambi i sopra elencati componenti,
gestito in modo indipendente al fine di evitare fenomeni di duplicazione del
codice.
Dopo un primo studio del funzionamento del sistema, il candidato ha testato il
meccanismo di integrità manualmente al fine di aumentare il livello di confidenza
con il codice. Durante questa prima fase, le caratteristiche di introspezione e la
semplicità di sintassi del linguaggio Python si sono rivelate estremamente utili ai
fini della comprensione.
2.5.2
Analisi delle criticità e piano di lavoro
Fin dalle primissime fasi del lavoro, si è rivelata evidente la necessità di avere a disposizione un collezione di metodi e oggetti per la generazione dei dati di ingresso a
partire da un insieme di file e directory, appositamente selezionati dall’utente prima
dell’esecuzione dei test. A tal fine è stato progettato l’oggetto Dataset il quale,
a partire da una porzione di filesystem, genera un insieme di richieste e operazioni
da effettuare sulle strutture dati autenticate. I dettagli implementativi e le scelte
progettuali verranno dettagliatamente descritte nel capitolo successivo.
Insieme al componente di generazione dei dati di input, è stato progettato e
implementato un meccanismo di caricamento dinamico di fixture da file di configurazione; ciò ha consentito di personalizzare l’esecuzione automatica dei test grazie
all’ausilio di profili che potevano essere generati manualmente o via script. Inizialmente si era pensato di utilizzare il linguaggio JavaScript Object Notation [Cro06]
come formato per i file di configurazione; il candidato ha optato per il formato INIstyle per ragioni di convenienza e semplicità [kis].
26
CAPITOLO 2. ANALISI E PROGETTAZIONE
Per monitorare l’avanzamento dei lavori e consentire agli sviluppatori del proget-
to di eseguire regolarmente le sessioni di collaudo è stato progettato un test runner
per il lancio sequenziale delle suite di test e le successive fasi di raccolta e presentazione dei risultati. L’analisi dei requisiti ha evidenziato la necessità di caratteristiche di interoperabilità con il software Nose, scelto come pilota nei processi di
esecuzione automatica grazie alla presenza di un meccanismo di autodiscovering dei
casi e delle suite di test.
Parallelamente allo sviluppo degli strumenti di automazione del collaudo, si è
proceduto alla scrittura dei primi test unitari, aventi come obiettivo principale quello di garantire la correttezza delle operazioni svolte dai singoli oggetti e metodi
presenti nelle librerie condivise del progetto. Una prima struttura gerarchica del
filesystem prevedeva la suddivisione in cartelle dei casi di test secondo le tipologie
di approccio dinamico. In una successiva fase di analisi, per ragioni di convenienza
e coerenza, si è preferito classificare i test case secondo i componenti sottoposti a
collaudo, fatta eccezione per quelle particolari tipologie di collaudo che prevedevano
l’interazione fra molteplici componenti (test di interazione e smoke test).
2.6
Debian packaging e integrazione in Ubuntu
Il candidato si è occupato di risolvere un’incompatibilità fra wxWdigets [wxw], le
librerie grafiche utilizzate per lo sviluppo dell’applicazione client di FileRock, e Unity [uni], l’interfaccia grafica del sistema operativo Ubuntu [ubua], la quale causava
alcuni problemi nell’integrazione del client nell’esperienza utente globale fornita dal
sistema sponsorizzato dalla nota derivata di Debian [debb].
Infine, grazie all’esperienza maturata negli anni come Debian Developer [deba] e
Ubuntu Core Developer [ubub], il candidato ha potuto curato con successo la pacchettizzazione dell’applicazione client di FileRock per Debian e derivate.
Capitolo 3
Realizzazione del software
In questo capitolo sono illustrate le fasi di progettazione e realizzazione del software
di ausilio ai test del meccanismo di verifica dell’integrità dei dati.
Vengono accuratamente descritti lo sviluppo e il funzionamento degli oggetti e
delle funzioni che compongono l’architettura di quality assurance prodotta dal candidato durante l’esperienza come ingegnere software per FileRock.
Inoltre, alla fine del presente capitolo, sono state inseriti riferimenti ed alcune
nozioni relative al lavoro di pacchettizzazione dell’applicazione client per distribuzioni
Debian e derivate.
3.1
Casistiche e tipologie di test
A differenti problematiche corrispondono differenti approcci e tipologie di test, alcuni
dei più comuni livelli e tipi di collaudo vengono elencati di seguito:
• unit test o test unitario: metodo di collaudo che si focalizza su singoli componenti o sottosistemi di ridotte dimensioni dell’architettura software;
• functional testing o test funzionale: si concentra sulla verifica e validazione di
una specifica funzionalità del codice;
• integration testing o test di integrazione: metodologie di collaudo atte a verificare che le interfacce utilizzate dai vari componenti di un sistema e l’interazione
fra le stesse soddisfino i requisiti delle specifiche;
27
28
CAPITOLO 3. REALIZZAZIONE DEL SOFTWARE
• performance testing o collaudo prestazionale: comprende misurazioni e tecniche atte a valutare le prestazioni del software;
• regression testing o collaudo di regressione: lo scopo principale è quello di verificare il corretto funzionamento di molteplici aree di un sistema successivamente
all’introduzione di cambiamenti rilevanti.
Le tecniche e gli strumenti per l’automazione delle sessioni di collaudo verranno
affrontate nei paragrafi successivi. I dettagli delle tipologie di test affrontate dal
candidato vengono descritte di seguito.
3.1.1
Test unitario
Il test unitario è stata un’attività che ha richiesto notevole cura, da parte del candidato, nelle diverse fasi di sviluppo; la risoluzione di problemi quali la duplicazione
del codice, il disaccoppiamento della logica dai dati e la progettazione dei dati di
input ha richiesto numerose ore di analisi e scrittura di codice.
Il testing modulare comprende funzioni, casi d’uso, procedure e dati di input con
l’unico fine di verificare il corretto funzionamento di una o più parti atomiche del
software [KH07]. Mentre nella programmazione modulare tali unità sono associate
a funzioni o moduli, nella programmazione orientata agli oggetti si fa solitamente
riferimento a classi, oggetti e interfacce.
In FileRock, il candidato ha sottoposto a collaudo ogni singola funzionalità offerta dalle classi che compongono il sotto sistema di verifica dell’integrità, organizzando
e suddividendo i moduli di test seguendo la stessa convenzione dei nomi utilizzati
dagli stessi moduli in sottoposti a collaudo. Un esempio di codice estratto dalla test
suite è mostrato di seguito:
3.1. CASISTICHE E TIPOLOGIE DI TEST
29
def test_CorruptedLeaf(self):
hashset = [(u’nonexistant_file0000’, ’8eec5e665c8b14757cec6d1a7460c00e’)]
self.empty_skiplist.updateSkipList(hashlist=hashset,
recomputeBasis=False)
leaf = self.empty_skiplist.leaves[u’nonexistant_file0000’]
assert_is_not_none(leaf)
leaf.filehash = None
with assert_raises(UnexpectedBasisException):
self.empty_skiplist.getBasis()
Il codice del listato mostra un tipico esempio di fault injection. In una struttura
dati inizializzata vuota, si inserisce un nuovo dato tra gli elementi foglia del grafo al
fine di verificare il lancio di un’eccezione: il test ha successo se l’errore viene correttamente rilevato.
Il test unitario comporta diversi vantaggi:
• i test unitari consentono di scoprire difetti in anticipo;
• semplifica le modifiche e, insieme alle tecniche di collaudo di regressione, consente agli sviluppatori di eseguire il refactoring del codice con la certezza che
i singoli moduli continueranno a funzionare;
• verificando che i singoli componenti funzionano correttamente, rende semplice
l’integrazione fra gli stessi.
Tutti i componenti unitari del meccanismo di verifica di integrità dei dati sono
stati sottoposti a testing unitario.
3.1.2
Test funzionale
Il classico esempio di test funzionale è il collaudo a scatola nera che, basandosi
sulle specifiche del software, ha lo scopo di verificare le funzionalità previste dalle
stesse specifiche, tralasciando i meccanismi interni di funzionamento.Le funzionalità
vengono collaudate con l’inserimento di un determinato insieme di dati di input, i
risultati ottenuti vengono infine confrontati con i valori attesi.
La procedura seguita dal candidato durante la progettazione e lo sviluppo dei
test case funzionali si può suddividere principalmente in cinque fasi [Bor06]:
30
CAPITOLO 3. REALIZZAZIONE DEL SOFTWARE
• ricerca e identificazione delle funzionalità all’interno delle specifiche;
• progettazione dei dati di input a partire dalle specifiche;
• determinazione dei risultati attesi;
• esecuzione di codice di test;
• comparazione dei risultati con i valori attesi.
L’inserimento di un nuovo elemento in una struttura dati autenticata rientra nei
casi d’uso più frequenti considerati durante il collaudo. La seguente funzione di test,
estratta dal codice prodotto dal candidato, mostra un esempio di test funzionale; si
noti che si occupa di collaudare entrambi i componenti lato server e client, senza
necessariamente stabilire una connessione di rete fra gli stessi al fine di trascurare
eventuali problemi di rete che potrebbero inficiare i risultati dei test:
def test_RandomInsertPathnames(self):
basis_zero = self.server.adsmanager.getCurrentBasis()
assert_not_equals(basis_zero, EMPTY_BASIS)
assert_true(self.client.intmanager.isCurrent(basis_zero))
for i in xrange(int(self.dataset_random_insert_nitems)):
pathname, filehash = self.dataset_random.random_insert_pathname()
pathname = pathname.decode(’utf-8’)
# The client asks the server for the proof
proof = self.server.adsmanager.getUpdateProof(pathname, ’INSERT’)
# The client adds the operation
self.client.intmanager.addOperation(’UPLOAD’,
pathname=pathname,
proof=proof,
filehash=filehash)
# Update server’s skiplist
new_basis = self.server.adsmanager.update([(pathname, filehash)])
assert_equals(new_basis, self.server.skiplist.getBasis())
# Commit on client
self.client.intmanager.checkCommitResult(new_basis)
# Check everything’s gone fine
assert_true(self.client.intmanager.isCurrent(new_basis))
new_basis = self.server.adsmanager.getCurrentBasis()
3.1. CASISTICHE E TIPOLOGIE DI TEST
31
assert_not_equals(new_basis, EMPTY_BASIS)
assert_true(self.client.intmanager.isCurrent(new_basis))
Inizializzata una struttura dati con un determinato insieme di input, il test inserisce un numero pseudo-casuale di nuovi elementi e verifica il nuovo valore del basis
alla fine di ogni operazione. Prima di terminare verifica l’uguaglianza tra i valori
finali dei basis memorizzati dal client e dal server.
3.1.3
Test di integrazione
L’accentuata modularità dell’intero meccanismo di verifica dell’integrità ha reso necessaria l’adozione di tecniche e metodologie atte a verificare la correttezza delle
interazioni fra i singoli componenti; la natura distribuita dell’architettura ha reso
prioritaria la garanzia del corretto comportamento delle entità costituenti il sistema
di gestione delle strutture dati autenticate.
I test di integrazione sono una logica continuazione dei test unitari e si possono
individuare diversi approcci alla loro progettazione [Bin99], i più comuni sono top
down, bottom up, sandwich e big bang:
• l’approccio top down prevede che i componenti ad alto livello vengano sottoposti a collaudo prima di quelli ai livelli più bassi. Tale approccio permette
di ignorare gli aspetti implementativi di basso livello ma richiede un diffuso
utilizzo di oggetti fittizi;
• con le tecniche bottom up sono i moduli a basso livello a venire collaudati per
primi. Ne consegue la necessità di priorizzare l’esecuzione dei test unitari, che
vanno eseguiti prima dei test di integrazione;
• la tecnica sandwich è una combinazione dei due precedenti approcci;
• se la copertura del codice dei test unitari è pressoché totale, si può ricorrere
anche all’approccio big bang, il quale prevede il collaudo di tutte le interazioni del sistema. Tale soluzione richiede un massiccio collaudo unitario e può
aumentare la complessità di gestione dei piani di test.
Considerato l’alto rapporto fra il tasso di copertura del codice da parte dei test
unitari e il numero di interazioni fra i moduli del componente di verifica dell’integrità
32
CAPITOLO 3. REALIZZAZIONE DEL SOFTWARE
dei dati, il candidato ha optato per l’approccio bottom up. Quello che segue è un
esempio di test di integrazione estratto dal codice del progetto:
def test_RenamePathname(self):
old_basis = self.server.adsmanager.getCurrentBasis()
assert_not_equals(EMPTY_BASIS, old_basis)
# Rename a pathname in the Dataset object
oldp, newp, filehash = self.dataset_random.random_rename_pathname()
oldp = oldp.decode(’utf-8’)
newp = newp.decode(’utf-8’)
# The new hashset needs to be filled with the couple
# containing the information about the path removed
hashset = self.dataset_random.tohashset()
hashset.append((oldp, None))
# Check if oldpathname exists
proof_rm = self.server.adsmanager.getIntegrityProof(oldp,
’DELETE’)
# Check the newpathname does not exists
proof_new = self.server.adsmanager.getIntegrityProof(newp,
’INSERT’)
assert_not_equals(proof_rm, proof_new)
# Append delete-and-insert operations
self.client.intmanager.addOperation(’DELETE’,
pathname=oldp,
proof=proof_rm,
filehash=None)
self.client.intmanager.addOperation(’INSERT’,
pathname=newp,
proof=proof_new,
filehash=filehash)
# Update the ADS hold by the server
new_basis = self.server.adsmanager.update(hashset)
assert_not_equals(old_basis, new_basis)
# Commit on client (and do checks, of course)
self.client.intmanager.checkCommitResult(new_basis)
3.2. MODELLO E GENERAZIONE DATI DI INPUT
33
# Check whether the basis match
assert_true(self.client.intmanager.isCurrent(new_basis))
Il codice di test esegue un’operazione di rinomina su un elemento presente nella
struttura dati: il client richiede una serie di operazioni che, in ordine, prevedono la
cancellazione dell’elemento e il nuovo inserimento. Alla fine delle operazioni viene
verificata la coerenza della struttura dati.
3.2
Modello e generazione dati di input
Alcuni dei casi di test definiti in fase di progettazione richiedevano che la struttura
dati in fase di collaudo si trovasse in un particolare stato prima dell’avvio delle procedure di collaudo. Vi era perciò l’esigenza di progettare una nuova entità capace
di incapsulare un insieme di elementi da caricare nelle strutture ADS prima dell’esecuzione del codice di test; tale nuova entità sarebbe dovuta essere di facilmente
riutilizzabile dagli altri sviluppatori nella scrittura dei test.
3.2.1
Oggetti Dataset per l’incapsulamento del filesystem
Il candidato ha affrontato e risolto tale problematica con lo sviluppo della classe
Dataset, dotata di caratteristiche di incapsulamento delle più comuni operazioni
primitive su file e directory e gestione della loro rappresentazione nel formato richiesto
dalle specifiche delle strutture dati autenticate. Scendendo a un maggior livello di
dettaglio, Dataset consente di agire sul file system con le seguenti operazioni:
• creazione, rinomina e cancellazione di file e directory;
• interrogazioni in lettura (i.e. lettura dei contenuti delle directory);
• aggiornamenti in scrittura (i.e. modifiche dei contenuti dei file).
Gli oggetti di tale tipo sono in grado di fornire una rappresentazione dei propri
contenuti nel formato <pathname,hash> (supportato in modo nativo dal componenti di verifica dell’integrità); tale caratteristica è stata progettata al fine di facilitare
l’inserimento dei dati nelle strutture vuote operata dal codice di inizializzazione dei
casi di test.
34
CAPITOLO 3. REALIZZAZIONE DEL SOFTWARE
3.2.2
Generazione dati casuali
La generazione di dati pseudo casuali si è rivelata utile in alcuni scenari di collaudo:
la classe DatasetRandom estende la classe Dataset e fornisce delle utili funzionalità aggiuntive di interrogazione e generazione di dati successivamente utilizzati nelle
procedure di inizializzazione dei test.
Entrambi le classi Dataset e DatasetRandom sono state ampiamente utilizzate
durante lo sviluppo della maggior parte dei casi di test e il relativo codice è stato
anch’esso sottoposto a collaudo: gli stessi approcci di verifica, validazione e collaudo utilizzati per il codice di FileRock sono stati applicati anche a queste entità di
appoggio.
3.3
Supporto all’automazione
Uno degli obiettivi previsti era la semplificazione delle procedure di lancio dei moduli
di test. Un’altra esigenza riguardava l’utilizzo di dati di input custom e la possibilità
di eseguire più volte e in momenti diversi gli stessi test partendo da configurazioni
fornite manualmente dallo sviluppatore o da uno script automatico.
3.3.1
Caricamento dei dati di input da file di configurazione
Il candidato ha prodotto una procedura automatica per il caricamento di valori
predefiniti (preset) a tempo di esecuzione dei casi di test sfruttando la libreria e
le caratteristiche di introspezione fornite dal linguaggio Python. Durante l’avvio
e l’inizializzazione di un modulo di test, grazie a tale procedura, è stato possibile
personalizzare il codice con il caricamento di configurazioni personalizzate da file di
configurazione conformi al formato INI.
Un file di configurazione INI è solitamente composto da coppie chiave-valore raggruppate in sezioni. Un contenuto di esempio è mostrato di seguito:
[globals]
random_iter_n = 30
3.3. SUPPORTO ALL’AUTOMAZIONE
35
[test_OpsOnEmptyADS]
dataset_root = .
dataset_random_root = .
dataset_random_seed = 1239782
[test_OpsOnNonEmptyADS]
dataset_root = .
dataset_random_root = .
dataset_random_seed = 1239782
dataset_random_insert_nitems = 10
Prima della dichiarazione di classi e oggetti globali i moduli di test contengono
una chiamata alla funzione init config(), la quale accetta come unico parametro
una stringa rappresentativa del nome del modulo e inizializza automaticamente i
valori delle variabili globali elencate nella sezione speciale globals del rispettivo file
di configurazione.
Ogni classe di test contiene nel proprio inizializzatore una chiamata al metodo
load testcase config() e passa come unico parametro il riferimento all’istanza corrente. Fatta eccezione per globals, ogni sezione nel file di configurazione rappresenta
i valori iniziali delle variabili utilizzate dalle fixture dei rispettivi metodi di test; é
possibile non specificare nessun valore per i metodi, in tal caso non viene impostato
alcun valore predefinito.
Tale meccanismo ha consentito agli sviluppatori di rieseguire gli stessi metodi di
collaudo con valori di input diversi, senza dover necessariamente introdurre modifiche al codice.
3.3.2
Script di esecuzione automatica
Tra le responsabilità del candidato vi era anche lo sviluppo di un test runner, ovvero
di un componente software per il controllo dell’esecuzione automatica del codice
di test. Per soddisfare i requisiti, il candidato ha progettato e implementato un
controllore Python di esecuzione dei test fornito delle seguenti caratteristiche:
• selezione e raggruppamento dei casi di test in suite attraverso il pilotaggio di
Nose;
36
CAPITOLO 3. REALIZZAZIONE DEL SOFTWARE
• gestione del contesto attraverso l’inizializzazione dei dati di input e il caricamento delle procedure di avvio dei casi di test;
• raccolta e presentazione dei risultati delle operazioni di collaudo e statistiche sulla copertura del codice.
L’ultima caratteristica è stata sviluppata grazie all’utilizzo di coverage, un plugin
facilmente integrabile con Nose. Il prodotto finale è inoltre fornito di un’interfaccia
a riga di comando conforme all’estensione GNU [FSF] dello standard POSIX.12008 [pos08].
3.4
Integrazione in Debian e Ubuntu
Una volta raggiunto l’obiettivo previsto dal piano originale di lavoro, il candidato
ha curato l’integrazione dell’applicazione client di FileRock con Unity, l’interfaccia
grafica predefinita del sistema operativo Ubuntu. Infine, il candidato ha curato il lavoro di pacchettizzazione della medesima applicazione per sistemi Debian e derivate.
3.4.1
Integrazione in Unity
L’interfaccia dell’applicazione client di FileRock è sviluppata con le librerie grafiche
multi piattaforma wxWidgets e consiste principalmente in un’icona visibile nella
barra delle applicazioni, la quale consente all’utente di accedere alle diverse opzioni
di configurazione del proprio account e dell’applicazione stessa. Durante le fasi di
collaudo del client grafico su diversi sistemi operativi, gli sviluppatori del progetto
si accorsero di un comportamento inatteso da parte del programma quando eseguito
su sistemi Ubuntu.
Ubuntu è un sistema operativo free e open basato su Debian e sul kernel
GNU/Linux, sviluppato dalla Comunità di Ubuntu con il sostegno strategico e economico di Canonical, una società britannica con sede nell’Isola di Man e la sua interfaccia predefinita, Unity, è basata sulla versione più recente delle librerie grafiche
GTK+.
Fin dalle prime fasi di analisi del problema, il candidato ha identificato la causa
del difetto nell’incompatibilità dell’applicazione con il protocollo Application indi-
3.4. INTEGRAZIONE IN DEBIAN E UBUNTU
37
cator [app]. Grazie all’esperienza maturata negli anni precedenti nell’ambito dello
stesso progetto Ubuntu, in qualità di Ubuntu Core Developer [ubub], il candidato
ha risolto il difetto introducendo alcune modifiche nel codice atte ad aggirare le limitazioni imposte dall’interfaccia Unity.
3.4.2
Debian packaging
Per agevolare la distribuzione del software e aumentare la sua visibilità gli sviluppatori del software si sono avvalsi della consulenza del candidato, già sviluppatore [ale]
e membro ufficiale del progetto Debian [debb].
L’introduzione di un nuovo pacchetto all’interno del parco software di Debian
avviene attraverso una rigorosa procedura di revisione approfonditamente descritta
nella policy del progetto [JS]. Il software deve risponde a delle specifiche di sicurezza
e di licenza che possono essere riassunte nei seguenti punti chiave:
• deve essere funzionante;
• non deve contenere codice malevole ed essere rispettoso dei dati degli utenti e
della loro riservatezza;
• deve essere liberamente redistribuibile in qualsiasi forma e conforme a le Linee
Guida Debian per il Software Libero [Debc];
Il candidato ha proceduto seguendo la procedura prevista dalla policy:
• segnalazione del bug di tipo Intent To Package [filb];
• scrittura del codice e dei meta dati per la compilazione e l’installazione del
software.
Terminata la fase iniziale del lavoro, il pacchetto sorgente è stato caricato e mantenuto aggiornato con il codice del progetto upstream su un archivio remoto [Tre]
attraverso l’ausilio del sistema di controllo di versione distribuito Git.
Il candidato ha migliorato l’integrazione dell’applicazione client di FileRock con
il resto dei programmi e delle librerie fornite da Debian con la produzione di un’insieme di patch presenti anch’esse sull’archivio remoto contenente il pacchetto. Tali
patch vengono applicate automaticamente a tempo di compilazione del software dal
38
CAPITOLO 3. REALIZZAZIONE DEL SOFTWARE
gestore Quilt, che ne semplifica la gestione e consente il tracciamento delle modifiche
apportate a ogni nuova revisione [qui].
Capitolo 4
Conclusioni
Questo capitolo aggiunge le considerazioni finali del candidato sul lavoro svolto e dei
possibili scenari futuri di sviluppo.
4.1
Sviluppi futuri
Oltre alle caratteristiche implementate dal candidato nel corso della realizzazione
del progetto, alcuni possibili sviluppi sono desiderabili:
• estendere il piano di collaudo al maggior numero di casi d’uso possibili al
fine di migliorare la qualità generale del prodotto; ciò renderebbe necessaria
l’esecuzione di molteplici iterazioni del processo di sviluppo, in modo tale da
consentire un’ancora più tempestiva rilevazione degli errori di programma;
• implementazione di strategie di continuous integration allo scopo di permettere
al singolo sviluppatore di integrare frequentemente il proprio lavoro con quello
del resto del team, eseguendo sessioni di collaudo automatizzate a ogni nuova
iterazione.
4.2
Conclusioni
Tutti gli obiettivi del piano di lavoro iniziale sono stati raggiunti nei tempi previsti.
Durante l’esperienza lavorativa presso la Heyware s.r.l. il candidato ha avuto l’occasione di apprendere numerosi aspetti teorici ai quali fanno riferimento le diverse
tecniche e metodologie di collaudo del software e di mettere al servizio degli altri
sviluppatori, impegnati nello sviluppo del progetto FileRock, le proprie conoscenze
39
40
CAPITOLO 4. CONCLUSIONI
pregresse del linguaggio Python e dei protocolli di garanzia di qualità, ottenendo
risultati molto più che soddisfacenti in termini di crescita professionale.
Appendice A
Licenza
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
• Redistributions of works must retain the original copyright notice, this list of
conditions and the following disclaimer.
• Redistributions in binary form must reproduce the original copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
• Neither the name of the W3C nor the names of its contributors may be used
to endorse or promote products derived from this work without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
i
ii
APPENDICE A. LICENZA
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Glossario
test case
Un test case é un insieme di dati, condizioni e operazioni attraverso le quali
è possibile determinare la correttezza del comportamento di un componente
software in fase di collaudo.
test fixture
Una fixture é un insieme di attributi, operazioni e dati di input necessari
all’inizializzazione di casi di test.
test suite
Una test suite é una collezione di test case correlati, solitamente eseguiti in
modo sequenziale all’interno della stessa sessione di collaudo.
iii
iv
Glossario
Bibliografia
[ale]
Nm report for week ending 06 jun 2010. Online: http://lists.debian.org/debiannewmaint/2010/06/msg00006.html.
[And86]
Stephen J. Andriole. Software Validation, Verification, Testing, and Documentation.
Petrocelli Books, 1986. Princeton, NJ.
[app]
Ubuntu application indicators.
Online:
https://unity.ubuntu.com/projects/
appindicators/.
[Bin99]
Robert V. Binder. Testing Object-Oriented Systems: Models, Patterns, and Tools.
Addison Wesley, 1999.
[Boe89]
Barry W. Boehm. Software Risk Management. IEEE Computer Society Press, 1989.
[Bor06]
Borland Software Corporation. How to successfully automate the functional testing
process. 2006. Online: http://www.computerworld.com/pdfs/functional_testing_
process2_pdf.pdf.
[BP84]
Victor R. Basili and Barry T. Perricone. Software error and complexity: An empirical
investigation. Communications of the ACM, 27:42–52, January 1984. Online: http:
//www.lsmod.de/~bernhard/cvs/text/dipl/papers/p42-basili.pdf.
[cov]
coverage: Code coverage measurement for python. Online: https://pypi.python.org/
pypi/coverage.
[Cro06]
Douglas Crockford. The application/json Media Type for JavaScript Object Notation
(JSON). July 2006. Online: http://tools.ietf.org/html/rfc4627.
[deba]
Becoming a debian developer. Online: https://wiki.debian.org/DebianDeveloper.
[debb]
Debian - the universal operating system. Online: http://www.debian.org/intro/
about.
[Debc]
Il Progetto Debian. Il Contratto Sociale e le Linee Guida Debian per il Software Libero.
Online: http://www.debian.org/social_contract.it.html.
[DeM99]
Tom DeMarco. Management can make quality (im)possible. In Cutter IT Summit,
Boston, April 1999.
[fila]
Online: http://www.filerock.com/.
[filb]
ITP: filerock-client – client for FileRock Secure Cloud Storage. Online: http://bugs.
debian.org/cgi-bin/bugreport.cgi?bug=696541.
[FSF]
Inc. Free Software Foundation. Standards for command line interfaces. Online: http:
//www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html.
v
vi
[Gar88]
BIBLIOGRAFIA
David A. Garvin. Managing Quality: The Strategic and Competitive Edge. Free Press,
February 1988.
[GT01]
Michael T. Goodrich, , and Roberto Tamassia. Efficient authenticated dictionaries with
skip lists and commutative hashing. January 2001. Online: http://www.cs.jhu.edu/
~goodrich/cgc/pubs/hashskip.pdf.
[GTS01]
Michael T. Goodrich, Roberto Tamassia, and Andrew Schwerin. Implementation of
an authenticated dictionary with skip lists and commutative hashing.
In DARPA
INFORMATION SURVIVABILITY CONFERENCE AND EXPOSITION, pages 68–
82. IEEE Computer Society Press, 2001. Online: http://cs.brown.edu/cgc/stms/
papers/discex2001.pdf.
[GW08]
Karen Mercedes Goertzel and Theodore Winograd. Enhancing the development life
cycle to produce secure software. Technical Report DAN 358844, DACS Data and
Analysis Center for Software, October 2008. Online: http://www.seas.upenn.edu/
~lee/09cis480/papers/DACS-358844.pdf.
[Har00]
M. J. Harrold. Testing: a roadmap. In Proceedings of the Conference on the Future of
Software Engineering, ICSE ’00. ACM, June 2000.
[HH88]
[iso99]
W.C. Hetzel and B. Hetzel. The Complete Guide to Software Testing. Wiley, 1988.
Iso/iec 9001:
Quality management systems - requirements.
Technical report,
International Standards Organization, 1999.
[iso03]
Iso/iec 9126-3: Software engineering – product quality – part 3: Internal metrics. Technical report, International Standards Organization, 2003. Online: http://www.iso.
org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=22891.
[iso05]
Software engineering – software product quality requirements and evaluation (square)
– guide to square. Technical report, International Standards Organization, 2005.
[iso10]
Iso/iec 24765: Systems and software engineering - vocabulary.
Technical report,
International Standards Organization, 2010.
[JG88]
Joseph M. Juran and Frank M. Gryna. Juran’s quality control handbook. McGraw-Hill,
1988.
[Jon87]
James V. Jones. Integrated Logistics Support Handbook. McGraw Hill Professional, June
1987.
[JS]
Ian Jackson and Christian Schwarz. Debian policy manual. Online: http://www.
debian.org/doc/debian-policy/.
[KH07]
Adam Kolawa and Dorota Huizinga. Automated Defect Prevention: Best Practices in
Software Management. Wiley-IEEE Computer Society Press, 2007.
[kis]
Keep It Simple, Stupid principle. Online: http://people.apache.org/~fhanik/kiss.
html.
[Koc98]
Paul C. Kocher. On certificate revocation and validation. 1998.
[Kop11]
H. Kopetz.
Real-Time Systems:
Design Principles for Distributed Embedded
Applications. Real-Time Systems Series. Springer, 2011.
BIBLIOGRAFIA
[KP96]
vii
B. Kitchenham and S.L. Pfleeger. Software quality: the elusive target. In Software,
IEEE, volume 13, pages 12–21. IEEE Computer Society Press, January 1996.
[Mer80]
Ralph C. Merkle. Protocols for public key cryptosystems. 1980.
[Nar12]
Massimo Nardelli. Strutture dati autenticate applicate in un servizio di sincronizzazione
e backup, 2012.
[NN98]
Moni Naor and Kobbi Nissim. Certificate revocation and certificate update. In USENIX
SECURITY SYMPOSIUM. USENIX Association, 1998.
[nos]
Online: http://nose.readthedocs.org/.
[Pan99]
Jiantao Pan. Software testing. Topics in Dependable Embedded Systems, 1999. Carnegie
Mellon University.
[PCCW93] Mark C. Paulk, Bill Curtis, Mary Beth Chrissis, and Charles V. Weber. Capability
maturity model for software, version 1.1. Technical Report CMU/SEI-93-TR-024, ESCTR-93-177, Carnegie Mellon University, Feb 1993. Online: http://www.sei.cmu.edu/
reports/93tr024.pdf.
[pep]
Pep-8: Style guide for python code. Online: http://www.python.org/dev/peps/pep0008/.
[Per11]
Chad Perrin. The CIA Triad. 2011. Online: http://www.techrepublic.com/blog/
security/the-cia-triad/.
[pos08]
Posix.1-2008 - the open group base specifications issue 7, 2008. Online: http://pubs.
opengroup.org/onlinepubs/9699919799/.
[Pug90]
William Pugh. Skip lists: A probabilistic alternative to balanced trees. Communications
of the ACM, 33:668–676, January 1990. Online: http://www.cs.jhu.edu/~goodrich/
cgc/pubs/hashskip.pdf.
[pyl]
Online: http://www.pylint.org/.
[Pyt91]
Python Software Foundation. HISTORY file. 1991. Online: http://svn.python.org/
view/*checkout*/python/trunk/Misc/HISTORY.
[pyt09]
Is python slower than Java. 2009. Online: http://stackoverflow.com/a/1177553.
[qua]
Online: http://en.wikipedia.org/wiki/File:SoftwareQualityCharacteristicAttributeRelationship.
png.
[qui]
Quilt. Online: http://savannah.nongnu.org/projects/quilt.
[Riv92]
Ronald L. Rivest. The MD5 Message-Digest Algorithm. April 1992. Online: http:
//tools.ietf.org/html/rfc1321.
[She31]
Walter A. Shewhart. Economic control of quality of manufactured product. 1931.
[Tra99]
Eushiuan Tran. Verification/validation/certification. Topics in Dependable Embedded
Systems, 1999. Carnegie Mellon University.
[Tre]
Alessio Treglia. FileRock client packaging. Online: http://anonscm.debian.org/
gitweb/?p=collab-maint/filerock-client.git.
[ubua]
Ubuntu. Online: http://www.ubuntu.com.
viii
[ubub]
BIBLIOGRAFIA
Ubuntu Core Developers.
Online: https://wiki.ubuntu.com/UbuntuDevelopers#
Ubuntu_Core_Developers.
[uni]
Unity. Online: https://unity.ubuntu.com/.
[wxw]
wxWidgets. Online: http://www.wxwidgets.org/.
Ringraziamenti
Questa opera è dedicata a Valentina, senza la quale mi sarei perso nell’oscurità della mia follia, e a
Gianna e Gianni, i miei genitori, senza i quali non sarei mai arrivato a questo punto.
Seguo un elenco pressochè esaustivo di persone, organizzazioni, progetti, animali e cose che
hanno contribuito, direttamente o indirettamente, al suo compimento e il supporto di ognuno di
loro è stato assolutamente indispensabile durante una o più fasi della sua realizzazione:
Maurizio Pizzonia, Ludovica Adacher, il Programma Erasmus e l’Unione Europea, the City
of Aberdeen, the University of Aberdeen, Francesco Giovanni Malcangi, Susanna Cocco, Alex
Turner-Moore, Alberto Lazzarin, Karoly Albert Szabo, Reinhard Schillberg, Niccolò C. M. Bianchi,
Christoph Oberlack, Amandine Fouquault, Stefanie Gerdes, Andy Braescu, David Bowitz, Martha
Riva, Daniele La Cecilia, Margherita Di Leo, Martina Loleo, Matteo Cesaro, Pietro Zanta, Sotirios
Longinos, l’inverno scozzese, Andrea Grandi, Andrea Cimitan, Fabio Marzocca, Flavia Weisghizzi,
Luca Ferretti, Dennis Ritchie, Guido Van Rossum, The Debian Project, The Ubuntu Community, KDE, The LaTeX project, Sublime Text, Stefano Zacchiroli, Luca Falavigna, Enrico Zini, Leo
Iannacone, Matteo F. Vescovi, The Debian Multimedia Maintainers Team, Agostino Russo, Mauro
Sbarigia, Marco Trevisan, Elia Silvia, Simone Martinelli, Marella Santilli, Alessio il barbiere, l’intero
albero genealogico della Famiglia Severin, l’intero albero genealogico della Famiglia Treglia, Nello
Martinelli, Stefania Silvagni, Martina Martinelli, Assuntina, Pizzeria On The Green, Zia Assunta, Zio Dario, Eugenio Sbardella, Anna Eugenia Morini, Gianluca Palmieri, Francesco Benedetto,
Thangavel Thevar, Heyware s.r.l., Glow Digital Ltd, Google Inc., Facebook Inc., Canonical Ltd,
Sourcefabric o.p.s., Toshiba Corporation, Acer Inc., Dropbox Inc., AS Roma, Francesco Totti, Federico Balzaretti, Dario Fo, Boris la Serie (e il Film), Corrado Guzzanti, Caterina Guzzanti, Francesco
Pannofino, Pietro Sermonti, Alessandro Tiberi, Paolo Calabresi, Ninni Bruschetta, Antonio Catania, Karin Proia, Carolina Crescentini, Valerio Mastandrea, Giorgio Tirabassi, Gli Sceneggiatori,
Antonio Albanese, Daniele Luttazzi, Fabrizio De Andrè, Giorgio Gaber, Georges Brassens, Ennio
Morricone, Luis Bacalov, Vangelis, Miles Davis, Paolo Conte, Frank Zappa, Giorgio Moroder, Donna Summer, Aretha Franklin, Bee Gees, Franco Micalizzi, Raphael Gualazzi, Mario Biondi, Daft
Punk, Justice, Air, Röyksopp, Stuart Price, Guns N Roses, John Legend, Madonna, Scissor Sisters,
Phoenix, Mirwais, Cassius, Benjamin Diamond, Franz Ferdinand, Depeche Mode, Chicken Lips,
Stardust, Chicks on Speed, Peaches, Parov Stellar, David Bowie, Iggy Pop, Kraftwerk, Solomon
Burke, Elvis Costello, Arctic Monkeys, The Presets, Digitalism, Soulwax, LCD Soundystem, The
Rolling Stones, Elton John, The Queen, The Doors, Bob Marley, Tom Jones, The Who, Three
Dog Night, Joe Cocker, John Cleary and the Absolute Monster Gentlemen, Annibale e I Cantori
x
BIBLIOGRAFIA
Moderni, Prophilax, Ceppaflex, Marino Sumo, Sergio Leone, Carlo Verdone, Paolo Sorrentino, Ridley Scott, Quentin Tarantino, Eli Roth, Samuel L. Jackson, Leonardo Di Caprio, Christoph Waltz,
Jamie Foxx, Tim Roth, Sacha Baron Cohen, Rupert Everett, Hugh Laurie, Clint Eastwood, Gian
Maria Volontè, Lee Van Cliff, Eli Wallach, Franco Nero, Tomás Milián, Franco Lechner, Alberto
Sordi, Nino Manfredi, Ugo Tognazzi, Bud Spencer, Terence Hill, Paolo Villaggio, Friedrich Wilhelm
Nietzsche, Johann Gottlieb Fichte, Gorgia, Lucius Annaeus Seneca, Marcus Annaeus Lucanus, Lucretius Carus, Quintus Horatius Flaccus, Gaius Lucilius, Gaius Petronius Arbiter, Marcus Valerius
Martialis, Decimus Iunius Iuvenalis, il Fatto Quotidiano, Laphroaig, Oban, Glenfiddich, Old Putney,
Union Bar, The Archibald Simpson, Sir Duncan Rice Library, il Comune e la Biblioteca comunale
di Aprilia, Bar Rossi, Liceo Statale A. Meucci, Scuola Media A. Gramsci, il Comune e la Biblioteca
comunale di Anzio, the City of Edinburgh, Tiki Cafe, Student Residents’ Assistants at Hillhead
Halls, Grosvenor Casino, Espionage, the City of London, the Lambeth Council, Clapham Park,
Abode Clapham, Her Majesty The Queen In Right Of England Elizabeth II, United Kingdom, Federico Gasparro, Peter Ilinov, Valeria Galli, Cosmo Di Nitto, Daniele Palladino, Manuel Ottaviani,
Issam, Alessio Guzzon, Vincenzo Luongo, Davide Albarello, Paolo Segreto, Roberto Grigatti, Marco
Ferrazza, Alessandro Faiella, Simone Sartori, Mauro Rasera, il gruppo del poker, Clay (Armanda)
e Baccaro.