Metodi di specifica e verifica di software embedded per applicazioni
Transcript
Metodi di specifica e verifica di software embedded per applicazioni
Iniziativa Software Finmeccanica - Linea di Ricerca N°2 Metodi di specifica e verifica di software embedded per applicazioni safety-critical Alessandro Lapadula Dipartimento di Sistemi e Informatica, Univ. Firenze (DSI) Selex-Galileo - A Finmeccanica Company Sommario Introduzione Specifica di un caso di studio Definizione di metriche per valutare test Generazione automatica di test Conclusioni Software embedded: motivazioni Aree di sviluppo software in Selex-Galileo: – Spesso i sw sono classificati safety-critical – radar, sistemi elettro-ottici e sonar avionici per il ruolo svolto (es. controllo del dispositivo) e per il campo di applicazione (es. avionico) Testare sw safety-critical è sproporzionalmente costoso (es. 50%-70% sul totale delle risorse) – tecniche (formali) che permettono di ridurre il costo del testing sono estremamente benvenute Software embedded: motivazioni Aree di sviluppo software in Selex-Galileo: – Spesso i sw sono classificati safety-critical – radar, sistemi elettro-ottici e sonar avionici per il ruolo svolto (es. controllo del dispositivo) e per il campo di applicazione (es. avionico) Testare sw safety-critical è sproporzionalmente costoso (es. 50%-70% sul totale delle risorse) – tecniche (formali) che permettono di ridurre il costo del testing sono estremamente benvenute Caso di studio Consideriamo il sistema sw di un dispositivo elettro-ottico per l'osservazione (sorveglianza) di zone o cose sensibili (es. confini, veicoli, etc.) Caratteristiche principali: – visione diurna e notturna – misurazione distanze Funzionalità esaminata: – Built In Test (o “bite”) è una funzione di controllo automatico dello stato dei sensori Caso di studio Consideriamo il sistema sw di un dispositivo elettro-ottico per l'osservazione (sorveglianza) di zone o cose sensibili (es. confini, veicoli, etc.) Camera Tv Caratteristiche principali: – visione diurna e notturna – misurazione distanze Laser Infrarosso Funzionalità esaminata: – Built In Test (o “bite”) è una funzione di controllo automatico dello stato dei sensori Caso di studio Consideriamo il sistema sw di un dispositivo elettro-ottico per l'osservazione (sorveglianza) di zone o cose sensibili (es. confini, veicoli, etc.) Camera Tv Caratteristiche principali: – visione diurna e notturna – misurazione distanze Laser Infrarosso Funzionalità esaminata: – Built In Test (o “bite”) è una funzione di controllo automatico dello stato dei sensori Formalizzazione del problema “bite” Elementi usati nella descrizione formale – sid : {NONE, TVC, IR} (dati di input) – timer : {0..MAX} (timeout bite) – turn : {TVC, IR} (turno di bite) – btvc, bir : {ON, OFF} (dati di output) Un esempio di funzione di output: btvc = ON se timer ≥ MAX con turn==TVC bir==OFF e sid==NONE btvc = OFF altrimenti Formalizzazione del problema “bite” Elementi usati nella descrizione formale – sid : {NONE, TVC, IR} (dati di input) – timer : {0..MAX} (timeout bite) – turn : {TVC, IR} (turno di bite) – btvc, bir : {ON, OFF} (dati di output) Un esempio di funzione di output: btvc = ON se timer ≥ MAX con turn==TVC bir==OFF e sid==NONE btvc = OFF altrimenti Alcune nozioni generali Un sistema di transizione etichettato (LTS) è una quadrupla ⟨Q, A , →, q0⟩ dove: – Q è un insieme di stati o configurazioni – A è un insieme finito di azioni – → ⊆ (Q ⅹ A) ⅹ Q è una relazione di transizione – q0 ∊ Q è la configurazione iniziale Sia ⟨Q, A , →, q0⟩ un LTS. Una computazione è una sequenza finita o infinita del tipo (q0,a0,q1), (q1,a1,q2), ..., (qi,ai,qi+1) con (qi,ai,qi+1) ∊ → ...altre nozioni generali Data la sequenza s ∊ (A ∪ {τ})* con – τ detta azione invisibile o interna s si definisce la relazione ⇒ nel seguente modo – ⇒ = IdQ se s=ε – a τ *a τ * ⇒ = (→) → (→) se s=a – s a0 a1 a2 ⇒ = ⇒ ⇒ ⇒... se s=a0a1a2... per ogni i≥0 TAPAs (Tool for the Analysis of Process AlgebraS) Utilizza algebre di processo (CCS+CSP) per la specifica e la verifica di sistemi concorrenti – interfaccia grafica (descrive sistemi come LTS) – equivalence checker (bisimulation, branching, trace) – model checker (µ-calcolo per descrivere proprietà) TAPAs (V0.5.7) è scaricabile all'indirizzo http://rap.dsi.unifi.it/tapas Specifica LTS del problema “bite” LTS delle variabili (up to some renaming): – turn : {TVC, IR} – btvc, bir : {OFF, ON} – – – – MAX=2 ● ● ● timer : {0..MAX} sid : {NONE, TVC, IR} Definizione della funzione “next” (in forma di LTS) Definizione della funzione “next” (in forma di pseudo-code) def next(): next(btvc) := case sid==NONE & turn==TVC & timer==MAX : ON 1 : OFF esac next(bir) := case sid==NONE & turn==IR & timer==MAX : ON 1 : OFF esac next(turn) := case btvc==ON : IR bir==ON : TVC 1 : turn esac next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ 1 : 0 esac Un dettaglio della funzione “next” next(turn) := case btvc==ON : IR bir==ON : TVC 1 : turn esac da pseudo-code a CCSP S30-> is_btvc_on?.next[S38] + is_btvc_off?.next[S31] S31-> is_bir_off?.next[S40] + is_bir_on?.next[S39] da CCSP a LTS S38-> set_turnp_ir!.next[S40] S39-> set_turnp_tvc!.next[S40] S40-> ... Verifica della specifica formale Immaginiamo di avere un documento di Specifica dei Requisiti del Software (SRS) dove sono definiti i seguenti tre requisiti: R1. “In assenza prolungata di comandi (es. 5 sec) dovrà essere interrogato lo stato dei sensori” R2. “Un bite per un sensore potrà essere chiamato solo se il bite sull'altro sensore è disabilitato” R3. “Il turno-di-bite sarà assegnato in modo alterno fra i sensori” Validazione dei requisiti Esempio di test manuale del requisito R1 “In assenza prolungata di comandi dovrà essere interrogato lo stato dei sensori” 1. Si disattivano tutti comandi per i sensori 2. Si attende l'attivazione della procedura “bite” 3. Si verifica che la procedura “bite” è attiva Validazione dei requisiti Esempio di test manuale del requisito R1 “In assenza prolungata di comandi dovrà essere interrogato lo stato dei sensori” 1. Si disattivano tutti comandi per i sensori 2. Si attende l'attivazione della procedura “bite” 3. Si verifica che la procedura “bite” è attiva Come possiamo formalmente generare il test ed adattarlo alla specifica formale? Come possiamo stabilire formalmente se il test è adeguato rispetto al requisito? Requisito R1 come formula logica “In assenza prolungata di comandi dovrà essere interrogato lo stato dei sensori” Come formula logica (espressa in μ-calculus) sulle variabili btvc, bir, sid e timer: max X.([none!]ff | [*]i[elapsed!]ff | [*](max Y. (min Z.<btvc_on!>tt | <bir_on!>tt | <-step!>Z) & [-step!]Y) & [*]X) Requisito R1 come formula logica “In assenza prolungata di comandi dovrà essere interrogato lo stato dei sensori” Come formula logica (espressa in μ-calculus) sulle variabili btvc, bir, sid e timer: max X.([none!]ff | [*]i[elapsed!]ff | [*](max Y. (min Z.<btvc_on!>tt | <bir_on!>tt | <-step!>Z) & [-step!]Y) & [*]X) Formula in Computation Tree Logic (CTL): AG(sid==NONE & timer≥MAX)→ AX(btvc==ON | bir==ON) Alcuni possibili vantaggi Formalizzare i requisiti permette di: – verificarli e “tracciarli” in modo automatico – individuare anticipatamente gli errori – sperimentare nuove tecniche di testing – definire nuove misure di copertura In RTCA-DO-178B (linee-guida al processo di sviluppo software avionico) si può leggere – “Test coverage of high-level requirements is achieved” [Test objectives, Table A-7, Items 3] Alcuni possibili vantaggi Formalizzare i requisiti permette di: – verificarli e “tracciarli” in modo automatico – individuare anticipatamente gli errori – sperimentare nuove tecniche di testing – definire nuove misure di copertura In RTCA-DO-178B (linee-guida al processo di sviluppo software avionico) si può leggere “Test coverage of high-level requirements is achieved” [Test objectives, Table A-7, Items 3] Verifiche formali vs testing “Program testing can be used to show the presence of bugs, never their absence” (Dijkstra, 1972) Verifiche formali vs testing “Program testing can be used to show the presence of bugs, never their absence” (Dijkstra, 1972) Testing come qualcosa di “poco accettabile” Verifiche formali “esaustive” (anche per sw di piccole dimensioni) sono raramente efficaci Inoltre richiedono complesse tecniche di supporto (es. abstraction o assume-guarantee proofs) Verifiche formali vs testing “Program testing can be used to show the presence of bugs, never their absence” (Dijkstra, 1972) Testing come qualcosa di “poco accettabile” Verifiche formali “esaustive” (anche per sw di piccole dimensioni) sono raramente efficaci Inoltre richiedono complesse tecniche di supporto (es. abstraction o assume-guarantee proofs) “In molti casi il testing è il solo strumento utilizzabile per confermare la qualità di un programma” “Il testing non preclude l'utilizzo di tecniche formali” Cos'è per noi un test case Sia S = ⟨Q, A ∪ {τ}, →, q0⟩ una specifica LTS – un test case t ∊ A* è una sequenza di azioni e di t passaggi di stato tale che q0 ⇒ q – un test set T è un insieme finito e non vuoto di test case Rispetto ad un test case tradizionale: – un test case non descrive necessariamente sequenze di coppie input/output – da un test case formale è sempre possibile derivare test case tradizionale Un semplice esempio di test case R1. “In assenza prolungata di comandi dovrà essere interrogato lo stato dei sensori” Un semplice esempio di test case R1. “In assenza prolungata di comandi dovrà essere interrogato lo stato dei sensori” Test case manuale: 1. Si disattivano tutti comandi per i sensori 2. Si attende l'attivazione della procedura “bite” 3. Si verifica che la procedura “bite” è attiva Un semplice esempio di test case R1. “In assenza prolungata di comandi dovrà essere interrogato lo stato dei sensori” Test case manuale: 1. Si disattivano tutti comandi per i sensori 2. Si attende l'attivazione della procedura “bite” 3. Si verifica che la procedura “bite” è attiva Test case formale: Test case in forma di specifica LTS da test case a CCSP q00-> none!.test[q01] ... q05-> step!.test[q10] q10->none!.test[q11] ... q15-> step!.test[q20] q20-> tvc!.test[q21] q21-> btvc_on!.test[q22] ... Il test è adeguato? Tipicamente la scelta di un test set avviene in base ad un ben determinato criterio – random, analisi frequenze d'uso, casi limite, ... Alcuni criteri, detti di copertura, permettono di definire interessanti misure di adeguatezza Il test è adeguato? Tipicamente la scelta di un test set avviene in base ad un ben determinato criterio – random, analisi frequenze d'uso, casi limite, ... Alcuni criteri, detti di copertura, permettono di definire interessanti misure di adeguatezza Un esempio è il criterio di statement coverage Program P: y = 7 z = y - x if :: (x > y) -> z = x - y fi Il test è adeguato? Tipicamente la scelta di un test set avviene in base ad un ben determinato criterio – random, analisi frequenze d'uso, casi limite, ... Alcuni criteri, detti di copertura, permettono di definire interessanti misure di adeguatezza Un esempio è il criterio di statement coverage Program P: y = 7 z = y - x if :: (x > y) -> z = x - y fi TestSet1:{x=8} Cov=1 TestSet2:{x=6} Cov=2/3 Model checking come strumento per misurare test adequacy Test set Specifica LTS + Criterio di test LTSs LTSs LTSs 1 2 Formule logiche 3 3 Model checker 4 Misura di copertura = # formule soddisfatte #totale formule Input: S=specifica, T=test set, C=criterio di copertura Output: misura di copertura 1. ogni test case t ∊ T viene tradotto in LTS 2. da S e C si ricava un insieme R di requisti (formule logiche) 3. si verifica se ogni formula logica è vera su almeno un t ∊ T 4. T soddisfa C se la misura di copertura è adeguata Esempio di requisiti di copertura Dato il criterio di state coverage: – Esempio di requisiti per le variabili btvc e bir – durante il test ogni variabile deve assumere tutti i possibili valori del proprio domino btvc e bir devono assumere i valori ON e OFF Requisiti espressi in formule logiche (CTL): {EF(btvc==ON), EF(btvc==OFF), EF(bir==ON), ...} Espressi in forma di never claim {AG!(btvc==OFF), AG!(btvc==ON), AG!(bir==ON),...} Elenco completo delle formule generate in TAPAs (state coverage) Requisiti (formule) di state coverage per il problema “bite” Esempio di valutazione di un test set in TAPAs Sia T il test set costituito dal solo test case Nota: il test case “copre” i requisiti di alto livello R1, R2 e R3 del problema “bite” Purtroppo il test set T non risulta adeguato rispetto al criterio di state coverage Copertura dei requisiti in TAPAs Il test soddisfa i requisiti R1, R2 e R3 Risultato di non-adeguatezza La variabile “bir” non è coperta dal test Il test non è adeguato per il criterio di state coverage Risultato di non-adeguatezza (never claim) La variabile “bir” non è coperta dal test Il test non è adeguato per il criterio di state coverage Esempio di test set adeguato Sia T' il test set costituito dal solo test case Nota: T' è il prolungamento di T e risulta adeguato rispetto al criterio di state coverage Risultato di test set adeguato Ok! Il test è adeguato per il criterio di state coverage Risultato di test set adeguato Ok! Il test è adeguato per il criterio di state coverage Model checking come strumento per generare test set 2 Specifica LTS + Criterio di test 1 Never claims 4 2 Model checker 3 contro-esempi contro-esempi contro-esempi = == testset set test test set Input: S=specifica, C= criterio di test Output: T=test set 1. da S e C si ricava un insieme R di requisti come never claim 2. si verifica che ogni never claim è soddisfatto da S 3. se S soddisfa il never claim, si genera un contro-esempio che sarà un test case contenuto nel test set T 4. si minimizza il test set Generazione di test case in TAPAs* Dati i requisiti (never claim) di state coverage { max X.([bir_on!]false & [-bir_on!] X) max X.([bif_off!]false & [-bir_off!] X), ...} si verifica la soddisfacibilità sulla specifica S Generazione di test case in TAPAs* Dati i requisiti (never claim) di state coverage { max X.([bir_on!]false & [-bir_on!] X) max X.([bif_off!]false & [-bir_off!] X), ...} si verifica la soddisfacibilità sulla specifica S Formula max X.([bir_on!]false & [-bir_on!] X) is false because S satisfies: «none!»«btvc_off!»«bir_off!»«turn_tvc!»«inc!»«step!» «none!»«btvc_off!»«bir_off!»«turn_tvc!»«elapsed!»«step!» «tvc!»«btvc_on!»«bir_off!»«turn_tvc!»«elapsed!»«step!» «none!»«btvc_off!»«bir_off!»«turn_ir!»«reset!»«step!» «none!»«btvc_off!»«bir_off!»«turn_ir!»«inc!»«step!» «none!»«btvc_off!»«bir_off!»«turn_ir!»«elapsed!»«step!» «none!»«btvc_off!»«bir_on!»true Criterio di mutation adequacy Misura l'adeguatezza di un test set rispetto ad un codice sorgente [DeMillo et. al. 1978] – il criterio richiede che i test case siano sensibili a piccole variazioni della struttura del programma Criterio di mutation adequacy Misura l'adeguatezza di un test set rispetto ad un codice sorgente [DeMillo et. al. 1978] – il criterio richiede che i test case siano sensibili a piccole variazioni della struttura del programma Breve descrizione del metodo: – si genera un set M di programmi alternativi (mutanti) al programma originale P – su ogni P'∊ M si esegue il test set T finché ● ● si trova un test case per il quale P e P' si comportano diversamente (in tal caso si dice che P' viene ucciso) oppure si esaurisce il test set T (si dice P' sopravvive) Problema dei mutanti equivalenti Un mutante può sopravvivere per due motivi: – – test case inadeguati ● non esercitano la porzione di P che è mutata ● il metodo è ok - rivelano una debolezza del test set il mutante P' è equivalente all'originale P ● ● situazione classificata come caso raro il metodo è ko: stabilire se due programmi sono equivalenti in generale è un problema indecidibile Per specifiche formali stabilire l'equivalenza di un mutante è un problema meno critico Specification-based mutation analysis [Ammann et al. 2002] definisce SM' killable se e solo se SM ha una traccia che SM' non possiede (←preordine basato sulle tracce) L'adeguatezza di un test set T rispetto ad un set M di specifiche mutanti è misurata da #mutanti uccisi totale mutanti - #mutanti equivalenti Specification-based mutation analysis [Ammann et al. 2002] definisce SM' killable se e solo se SM ha una traccia che SM' non possiede (←preordine basato sulle tracce) L'adeguatezza di un test set T rispetto ad un set M di specifiche mutanti è misurata da #mutanti uccisi totale mutanti - #mutanti equivalenti T(S), T(S') (a) T(S) T(S') (b) T(S) T(S') (c) T(S) (d) T(S') T(S) (e) T(S') Specification-based mutation analysis [Ammann et al. 2002] definisce SM' killable se e solo se SM ha una traccia che SM' non possiede (←preordine basato sulle tracce) L'adeguatezza di un test set T rispetto ad un set M di specifiche mutanti è misurata da #mutanti uccisi totale mutanti - #mutanti equivalenti Nota: definizioni di equivalenza più fini permettono maggiori uccisioni e quindi misure più accurate TAPAs come strumento per mutation analysis Operatori di mutazione 1 LTSs mutanti 1 Specifica LTS 2 2 Equivalence checker 3 Formule logiche 4 Input: S=specifica, Op=set di operatori di mutazione Output: misure di copertura o generazione di test 1. da S e Op si genera un insieme dei mutanti M 2. dal Equivalent Checker di TAPAs si seleziona una equivalenza (fra quelle disponibili) per confrontare S con ogni mutante 3. dal confronto si ottengono le formule logiche che distinguono (possibilmente) S da ogni mutante 4. le formule logiche possono essere utilizzate sia per valutare altri test case che per generare nuovi test case Misure di copertura o generazione di test Operatore di mutazione Var next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ 1 : 0 esac S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4] S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4] S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4] S3-> inc_timer!.next[...] S4-> reset_timer!.next[...] Operatore Var: sostituisce una variabile con un'altra dello stesso tipo Operatore di mutazione Var next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ 1 : 0 esac S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4] S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4] S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4] S3-> inc_timer!.next[...] S4-> reset_timer!.next[...] Operatore Var: sostituisce una variabile con un'altra dello stesso tipo, per esempio sid==NONE & bir==OFF & bir==OFF : timer++ S1-> is_bir_off?.next[S2]+is_bir_on?.next[S4] Un caso di mutazione hard-to-kill Pseudo-code con dead code next(turn) := case blrf==ON : NONE btvc==ON : IR bir==ON : TVC 1 : turn esac Codice CCSP corrispondente S0-> is_blrf_on?.next[Sdead] + is_blrf_off?.next[S1] S1-> is_btvc_on?.next[Stvc] + is_btvc_off?.next[S2] ... Un caso di mutazione hard-to-kill Pseudo-code con dead code next(turn) := case blrf==ON : NONE btvc==ON : IR bir==ON : TVC 1 : turn esac Operatore Var next(turn) := case btvc==ON : LRF btvc==ON : IR bir==ON : TVC 1 : turn esac Codice CCSP corrispondente S0-> is_blrf_on?.next[Sdead] + is_blrf_off?.next[S1] S1-> is_btvc_on?.next[Stvc] + is_btvc_off?.next[S2] ... Codice CCSP corrispondente S0-> is_btvc_on?.next[Sdead] + is_btvc_off?.next[S1] S1-> is_btvc_on?.next[Stvc] + is_btvc_off?.next[S2] ... Effetti della mutazione sugli LTS Operatore Var Uccisione del mutante in TAPAs: 1° tentativo sys è il sistema TAPAs ottenuto dalla specifica originale con dead code sys_hard è il mutante ottenuto applicando Var il mutante sys_hard risulta essere non killable Uccisione del mutante in TAPAs: 2° (definitivo) tentativo Il sistema sys_hard è hard-killable deadlock Caratterizzazione di hard-killable Sia S = ⟨Q, A ∪ {τ}, →, q0⟩ un specifica LTS – q ∊ Q diverge (scritto q⇑) se esiste una sequenza τ infinita qi → qi+1 con i > 0 e q1=q – t è divergente (scritto t⇑) se esiste un prefisso t' t' (anche vuoto) di t tale che q0 ⇒ q e q⇑ – t dati Qt={q ∊ Q : q0 ⇒ q} e L ⊆ A si dice t must L a se ∀ q ∊ Qt q ⇒ q' implica ∃ a ∊ L e q' ⇒ Un mutante S' si dice hard-killable se non è killable ed esiste un test case t di S tale che – t è divergente in S' oppure – per qualche L ⊆ A t must L per S ma non per S' Peace&Love Conclusioni Verifiche formali “esaustive” riscontrano limiti di applicabilità (raramente risultano efficaci) Model/equivalence checker si dimostrano efficaci come strumenti per valutare e generare test set – manca tuttora uno studio sui criteri di copertura che tiene conto di equivalenze comportamentali Tecniche di model extraction possono favorire la diffusione del metodo fuori dal contesto accademico – minor richiesta di conoscenze particolari – manutenzione consistente del modello più facile Conclusioni Verifiche formali “esaustive” riscontrano limiti di applicabilità (raramente risultano efficaci) Model/equivalence checker si dimostrano efficaci come strumenti per valutare e generare test set – manca tuttora uno studio sui criteri di copertura che tiene conto di equivalenze comportamentali Tecniche di model extraction possono favorire la diffusione del metodo fuori dal contesto accademico – minor richiesta di conoscenze particolari – manutenzione consistente del modello più facile – verifica di codice automatica (nuovo seminario?) Letture consigliate [RTCA] Software Considerations in Airborne Systems and Equipment Certification (DO-178B) 1992 [Zhu et al.] Software Unit Test Coverage and Adequacy. ACM Computer Survays 1997 [Gargantini et al.] Using Model Checking to Generate Tests from Requirements Specifications. ACM SIGSOFT 1999 [Ammann et al.] Model Checkers in Software Testing. NIST-IR 6777 2002 [Offutt et al.] Generating Test Data from state-based specifications. Journal of STVR 2003 [Heimdahl et al.] Testing Strategies for Model-Based Development. NASA/CR-214307 2006 ... grazie per l'attenzione Note generali su mutation analysis Si basa su due ipotesi: – il programma da testare è molto simile a quello corretto (competent programmer assumption) – è molto probabile che test capaci di scoprire semplici “piccoli” trovino anche errori più complessi (coupling effect assumption) Ha il vantaggio a essere facilmente automatizzabile Lo svantaggio maggiore è che richiede notevoli risorse di calcolo (#M~n2 per codice P con n linee) Alcune considerazioni su TAPAs Al momento è difficile includere TAPAs in un ambiente di test (anche in caso di piccoli sistemi) Motivi: – generazione contro-esempi (solo in caso di equivalent checking) – modalità linea di comando non disponibile – limitata utilizzabilità dei risultati Modello astratto dei messaggi Variabili di input (o monitored): TVC SID CMDI CMD LSTC 1 3 02A 0 SID CMDI CMD LSTC IR 2 8 25 1 SID CMDI CMD LSTC 0 0 0 0 NONE Variabili di output (o controlled): btvc==ON SID TVSTS IRSTS ACK 1 1 0 0 SID TVSTS IRSTS ACK 1 0 1 0 bir==ON Caratterizzazione alterativa Nell'esempio esiste un test case t tale che se L = {turn_tvc!,turn_ir!} si ha che per S t must L mentre non vale per S' Operatore Var Caratterizzazione alterativa Nell'esempio esiste un test case t tale che se Operatore Var L = {turn_tvc!,turn_ir!} si ha che per S t must L mentre non vale per S' Teorema: Se S' si ottiene da S applicando uno degli operatori di Op, S' hard-killable implica che S' possiede un test che va in deadlock Requisito R2 come formula logica “Un bite per un sensore potrà essere chiamato solo se il bite sull'altro sensore è disabilitato” Formula μ-calculus sulle variabili btvc e bir: max X.([btvc_on!]ff | [*]i[bir_on!]ff) & [*]X) Requisito R2 come formula logica “Un bite per un sensore potrà essere chiamato solo se il bite sull'altro sensore è disabilitato” Formula μ-calculus sulle variabili btvc e bir: max X.([btvc_on!]ff | [*]i[bir_on!]ff) & [*]X) Formule CTL più intuitive: AG(btvc==ON → bir==OFF) AG(bir==ON → btvc==OFF) Oppure nella sola formula CTL: AG(btvc==OFF | bir==OFF) Requisito R3 come formula logica “Il turno-di-bite sarà assegnato in modo alterno fra i sensori” Formula μ-calculus usando la variabile turn: 1. max X.([btvc_on!]ff | [*]i(max Y.(min Z. <turn_ir!>tt | <-step!>Z) & [-step!]Y) & [*]X) 2. max X.([bir_on!]ff | [*]i(max Y.(min Z. <turn_tvc!>tt|<-step!>Z) & [-step!]Y) & [*]X) Requisito R3 come formula logica “Il turno-di-bite sarà assegnato in modo alterno fra i sensori” Formula μ-calculus usando la variabile turn: 1. max X.([btvc_on!]ff | [*]i(max Y.(min Z. <turn_ir!>tt | <-step!>Z) & [-step!]Y) & [*]X) 2. max X.([bir_on!]ff | [*]i(max Y.(min Z. <turn_tvc!>tt|<-step!>Z) & [-step!]Y) & [*]X) Formule CTL più intuitive: 1. AG(btvc==ON → AX turn==IR) 2. AG(bir==ON → AX turn==TVC) Minimizzazione di un test set Per ridurre costi di testing è fondamentale minimizzare le dimensioni del test set Alcune possibili minimizzazioni si ottengono: – rimuovendo test duplicati – eliminando “test prefissi” di altri test – prediligendo quei contro-esempi che soddisfano più di un requisito di copertura Nota: quando da un test set formale si deriva un test tradizionale si possono ottenere ulteriori minimizzazioni (es. solo input/output) Operatore di mutazione Const next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ 1 : 0 esac S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4] S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4] S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4] S3-> inc_timer!.next[...] S4-> reset_timer!.next[...] Operatore Const: sostituisce una costante con un'altra dello stesso tipo, per esempio sid==NONE & btvc==ON & bir==OFF : timer++ S1-> is_btvc_off?.next[S4]+is_btvc_on?.next[S2] Operatore di mutazione Neg next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ 1 : 0 esac S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4] S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4] S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4] S3-> inc_timer!.next[...] S4-> reset_timer!.next[...] Operatore Neg: inserisce una negazione in una espressione, per esempio sid==NONE & !(btvc)==OFF & bir==OFF : timer++ S1-> is_btvc_off?.next[S4]+is_btvc_on?.next[S2] Operatore di mutazione Rel next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ 1 : 0 esac S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4] S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4] S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4] S3-> inc_timer!.next[...] S4-> reset_timer!.next[...] Operatore Rel: sostituisce un operatore con un altro di uguale arietà, per esempio sid==NONE | (btvc==ON & bir==OFF) : timer++ S0-> is_sid_none?.next[S3]+is_not_sid_none?.next[S1] Operatore di mutazione Var next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ 1 : 0 esac S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4] S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4] S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4] S3-> inc_timer!.next[...] S4-> reset_timer!.next[...] Operatore Var: sostituisce una variabile con un'altra dello stesso tipo, per esempio sid==NONE & bir==OFF & bir==OFF : timer++ S1-> is_bir_off?.next[S2]+is_bir_on?.next[S4] Operatore di mutazione Bool next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ 1 : 0 esac S0-> is_sid_none?.next[S1]+is_not_sid_none?.next[S4] S1-> is_btvc_off?.next[S2]+is_btvc_on?.next[S4] S2-> is_bir_off?.next[S3]+is_bir_on?.next[S4] S3-> inc_timer!.next[...] S4-> reset_timer!.next[...] Operatore Bool: sostituisce una condizione con true o false, per esempio sid==NONE & true & bir==OFF : timer++ S0-> is_sid_none?.next[S2]+is_not_sid_none?.next[S4] Definizione di misura di copertura e accuratezza Dati una specifica S, un test set T e un criterio di copertura C, allora misura di copertura è m(C, S, T) = k / N dove N è il numero dei requisiti generati da S e k è il numero dei requisiti soddisfatti da T La misura m(C, S, T) sarà più accurata se si rimuovono quei requisiti – impossibili (es. EF(btvc==ON & timer==1)) – sempre veri (es. AG(turn==IR | turn==TVC)) – duplicati (es. AG(timer ≤ 2) e AG!(timer > 2)) Alcune nozioni generali Un sistema di transizione etichettato (LTS) è una quadrupla ⟨Q, A , →, q0⟩ dove: – Q è un insieme di configurazioni – A è un insieme finito di azioni – → ⊆ (Q ⅹ A) ⅹ Q è una relazione di transizione – q0 ∊ Q è la configurazione iniziale Sia ⟨Q, A , →, q0⟩ un LTS. Una computazione è una sequenza finita o infinita del tipo (q0,a0,q1), (q1,a1,q2), ..., (qi,ai,qi+1) con (qi,ai,qi+1) ∊ → ...altre nozioni (±) generali Data la sequenza s ∊ (A ∪ {τ, ρ})* con – τ detta azione invisibile o interna – ρ detta azione step o passaggio di stato s si definisce la relazione ⇒ nel seguente modo: – – ⇒ = IdQ se s=ε a s – ⇒ τ a τ ⇒ = (→)*→ (→)* se s=a a0 a1 a2 = ⇒ ⇒ ⇒... se s=a0a1a2... per ogni i≥0 Esempio di “passaggi di stato” di due variabili step 1 step 2 step 3 Cos'è per noi un test case Sia S = ⟨Q, A ∪ {τ, ρ}, →, q0⟩ una specifica LTS – un test case t ∊ (A ∪ {ρ})* è una sequenza di t azioni e di passaggi di stato tale che q0 ⇒ q – un test set T è un insieme finito e non vuoto di test case Rispetto ad un test case tradizionale: – un test case non descrive necessariamente sequenze di coppie input/output – da un test case formale di una specifica validata è sempre possibile derivare test case tradizionale Risultato di non-adeguatezza La variabile “bir” non è coperta dal test Risultato di non-adeguatezza ottenuto usando lo strumento TAPAs Risultato di test set adeguato Ok! Risultato di adeguatezza del test ottenuto usando lo strumento TAPAs Caratterizzazione di hard-killable Sia S = ⟨Q, A ∪ {τ, ρ}, →, q0⟩ un specifica LTS – q ∊ Q diverge (scritto q⇑) se esiste una sequenza τ infinita qi → qi+1 con i > 0 e q1=q – t è divergente (scritto t⇑) se esiste un prefisso t' t' (anche vuoto) di t tale che q0 ⇒ q e q⇑ – t dati Qt={q ∊ Q : q0 ⇒ q} e L ⊆ A si dice t must L a se ∀ q ∊ Qt q ⇒ q' implica ∃ a ∊ L e q' ⇒ Un mutante S' si dice hard-killable se non è killable ma esiste un test case t di S tale che – t è divergente in S' oppure – t must L per S ma non per S' per qualche L ⊆ A Minimizzazione di un test set Per ridurre costi di testing è fondamentale minimizzare le dimensioni del test set Alcune possibili minimizzazioni si ottengono: – prediligendo quei contro-esempi che soddisfano più di un requisito di copertura – rimuovendo test duplicati – eliminando “test prefissi” di altri test Definizione della funzione “next” (in forma di pseudo-code) def next(): next(btvc) := case sid==NONE & turn==TVC & timer==MAX : ON 1 : OFF esac next(bir) := case sid==NONE & turn==IR & timer==MAX : ON 1 : OFF esac next(turn) := case btvc==ON : IR bir==ON : TVC sid==LRF : LRF 1 : turn esac next(timer) := case sid==NONE & btvc==OFF & bir==OFF : timer++ btvc==ON & bir==ON : -1 1 : 0 esac