Técnicas Avanzadas de Testing Automatizado Generación basada en Constraint Solving (SAT Solving) SAT-Solving El problema de satisfactibilidad booleana es el siguiente: dada una fórmula proposicional A, encontrar una asignación de valores de verdad para las variables v : Vars(A) ! {T, F} que haga a A verdadera Primer problema en demostrarse NP-completo. Existen varios SAT solvers basados en el algoritmo de Davis-Putnam-Logemann-Loveland algorithm (1960, 1962). El Lenguaje de Modelado Alloy (Jackson, MIT) Permite describir dominios de datos, y operaciones sobre los dominios La herramienta Alloy Analyzer permitea analizar si ciertas propiedades se cumplen en los modelos (pero dentro de cotas para los dominios de datos). Los modelos se traducen a fórmulas proposicionales, y se usa un SAT solver para buscar contraejemplos. Alloy: Ejemplo sig Data { } one sig Null { } sig Node { val: Data, next: Node+Null } sig List { head: Node+Null } definiciones de dominios y su estructura Las operaciones se pueden definir con predicados restricciones sobre la especificación (propiedades supuestas) fact AcyclicLists { all l: List, n: Node | n in l.head.(*next) => n !in n.(^next) } propiedades a ser chequeadas assert NextIsInjective { all l: List, n1, n2: Node | n1+n2 in l.head.*next and n1 != n2 => n1.next != n2.next } Expresiones en Alloy Tanto las signaturas como los campos de las signaturas definen relaciones. Por ejemplo, Node define una relación unaria, y next define una relación binaria entre Node y Node u {Null}. Tenemos algunas constantes relacionales: • none (rel. vacía), univ (relación unaria universal) e iden (relación identidad sobre el universo) Varias operaciones pueden aplicarse a relaciones: • unión (+), intersección (&), diferencia (-) y producto cartesiano (->) • composición (.) • conversa (~) • overriding (r++s = (r - (dom[s]->univ)) + s) • clausura transitiva (^r) y reflexo-transitiva(*r) Fórmulas en Alloy Usando las expresiones relacionales, podemos construir fórmulas: • inclusión relacional (r in s) • igualdad relacional (r = s) • vacuidad relacional (no r) • conjunción (f1 and f2), disyunción (f1 or f2), negación (not f1) e implicación (f1 => f2) de fórmulas • cuantificación universal (all x: D | f1) • cuantificación existencial (some x: D | f1) En Alloy, toda expresión denota una relación. Los elementos se caracterizan mediante singletons (relaciones unarias con un único elemento) Alloy Analyzer sat? Alloy spec aserción spec and (not aserción) contraejemplo unsat? propiedad válida dentro de las cotas provistas ZChaff SAT4J Berkmin MiniSAT cotas para dominios The Alloy Analyzer Alloy Model Alloy Analyzer KodKod model KodKod Propositional formula in CNF SAT-Solver UNSAT or counterexample KodKod (Torlak, Jackson) Para cada símbolo relacional R, existen cotas inferior y superior: lR y uR. Si una tupla t pertenece a lR, entonces t debe ocurrir en toda interpretación de R. Si t no pertenece a uR, entonces t no puede ocurrir en ninguna interpretación de R. KodKod Intuitivamente, KodKod: De Relaciones a Proposiciones Sean R y S relaciones binarias sobre un conjunto A. variables Sea 3 la cota de A. Luego: proposicionales ⇥ ⇥ s11 s12 s13 r11 r12 r13 ⇤ r21 r22 r23 ⌅ S ⇤ s21 s22 s23 ⌅ R r31 r32 r33 s31 s32 s33 rij es una variable proposicional que modela el hecho de que (i,j) está en R. Lo mismo para sij. KodKod: De Relaciones a Proposiciones Para la conversa, tenemos: Los términos s11 s21 s31 relacionales son mapeados ⇤ s s s S̆ 12 22 32 a matrices de s13 s23 s33 fórmulas proposicionales For join (union), we have: R + S̆ r11 ⇤ r21 r31 s11 s12 s13 r12 r22 r32 s21 s22 s23 ⇥ ⌅ r13 r23 r33 ⇥ s31 s32 ⌅ s33 KodKod: De Relaciones a Proposiciones Para igualdades entre términos: R + S̆ = T r11 ⇤ r21 r31 s11 s12 s13 (r11 ⇤ s11 r12 r22 r32 Se extiende a conectivos⇥y t11 s21cuantificadores r13 s31 s22 r23 s32 ⌅ = ⇤ t21 t31 s23 r33 s33 t11 ) ⇥ (r12 ⇤ s21 t12 ) ⇥ (r13 ⇤ s31 t12 t22 t32 ⇥ t13 t23 ⌅ t33 t13 ) ⇥ . . . DynAlloy: Extendiendo Alloy con Acciones • Extensión de Alloy, para describir de mejor manera el cambio de estado y las ejecuciones • provee notación para acciones atómicas, definidas en términos de pre- y post-condiciones • provee operadores para formar acciones compuestas (programas) • las aserciones para programas pueden darse en términos de aserciones de corrección parcial DynAlloy: Una Especificación de Ejemplo act Head(l: List, d: Data) pre = { l.head != Null} post = { d’ = (l.head).val } acciones definidas por pre- y post-condiciones act Tail(l: List) pre = { l.head != Null} post = { l’.head = (l.head).next } assertPartialCorrectness { pre = { l.head != Null and noCycles(l.head) } program = { Tail(l) ; (Head(l,d) + Tail(l))* } post = { noCycles(l’.head) } } propiedades sobre ejecuciones, a ser chequeadas Análisis de Especificaciones DynAlloy Alloy Analyzer cotas para dominios DynAlloy spec {pre} P {post} cotas para iteraciones spec and (pre and not(bwlp(P,post,k))) bwlp(P, post, k) sat? contraejemplo unsat? propiedad válida dentro de las cotas establecidas Cómputo de bwlp • Operadores: • acciones atómicas: {pre} a {post} • test: pred? • elección no determinista: p1+p2 • composición secuencial: p1; p2 • iteración: p* (= p + p;p + p;p;p + ...) Un Ejemplo Simple module example1 open util/integer pred equ[l,r: univ] { l=r } action Inc[x: Int] { pre { gte[x,0] } post { equ[x',add[x,1]]} } action Dec[x: Int] { pre { gt[x,0] } post { equ[x',sub[x,1]]} } assertCorrectness always_gt_zero[y: Int] { pre = { equ[y,0] } program = { Inc[y]; Inc[y]; Inc[y]; Dec[y]; Dec[y] } post = { gt[y',0] } } check always_gt_zero Análisis Automático de Código Java (con DynAlloy) Se mapea la jerarquía de clases Java a una jerarquía de signaturas Alloy. Se mapean las sentencias atómicas Java a acciones atómicas DynAlloy. Se mapea programas Java a programas DynAlloy. jects, and atomic actions that modify an object’s field. We ing class fields modified denote ObjectsC the unary relation (set) that contains is used Dyn parameters of by thethe DynA 2.2 Aby Brief Introduction To DynAlloy the DynAlloy mo the set of objects from class C that are part of the heap at a tion applies to class con DynAlloy is an This extension ofbe Alloy conceived foreffect modeling associated given point[10] in time. set can modified by the of andparameter this isAlloy remov analyzing actions specified through pre and post-conditions written the form of cod an action. The translation in Alloy. From these atomic actions, new, more complex actions, In order to handle creation of objects of class C in DynAlin two steps. We first tra run program fo can be constructed using action combinators. If loy, we introduce an atomic action called NewC, specified as code, and then translate the Alloy Analyze A[x1:T1,...,xn:Tn] follows: code. The techniques b Notice that the set ObjectsC should have been passed as a Normalized Java code and NewC[o worth emphasizin act : C] parameter.B[x1:T1,...,xn:Tn,y1:T1,...,yn:Tn] In order to maintain notation simple, we keep this • models isand partial, pre = { true } constructor meth state variable global. sizesofofprimitive data dom are Alloy an atomic actionand “atomic” declared through literals post formulas, = {o’ !in ObjectsC o’ in isObjectsC’} ty * (iteration) opera An atomic action that sets the value of field “f” of object a triple Java a DynAlloy: Acciones Atómicas bles for oughly f being asserts, ] asser- { } satisfy satisfy “o”, is described in DynAlloy as follows: act atomic[x1:T1,...,xn:Tn] = { A[x1,...,xn] actpre Setf[o : C, v : C’,} f : C -> C’] post } pre == {{ oB[x1,...,xn,x1’,...,xn’] in ObjectsC } post =variable { f’ x=i fin++ ->condition v) } refers to the value Primed the(o post of variable xi upon action termination. As an example, action From the class extension hierarchy in Java, a signature exvarAssign below models assignment of a value to a variable: tension hierarchy is readily defined in DynAlloy. Translation act VarAssign[v1, : C] (seAabrevia v1 := v2) of a class to DynAlloyv2 is immediate. class declaration pre = { true } class postC ={ { v1’ = v2 } C1this field1; Since atomic action is used often, we will use the more pro... notation v1 := v2. Actions denote state (variable valgrammatic Ck fieldk; uations) transitions. Atomic actions relate those pairs of valuations 2.3 The Transl Let us consider th and singly linked public class LN LNode next; int key; } public class Li /*@ @ invariant @ \reach(t @ !\reach( @*/ nted, nts. is a n e1 nts. riate code nted, riate hink data nts. hink data t e1 riate We t e1 hink We data tt pae1 rim- of non-void return type. an According to (1), the result. translation of whose header includes (ouput) parameter In the v.f = -->of DynAlloy action m method m e1.m(p1,...,pk) guarantees existence translation of the body the of m, we translate p1,..., pk] ;parameter Setf[v,result. r, f]. whose m[r, headere1, includes an (ouput) In the return e --> VarAssign[result, e]. translation of the bodyofofthe m,form we translate Return statements “return e” (where e is an For more must complex program constructs, the translation is expression), occur in the body of a Java method m return e --> VarAssign[result, e]. defined as follows: of non-void return type. According to (1), the translation of For more complex program constructs, the translation is method m guarantees the existence of DynAlloy action m while (pred) {stmt} ⇥ ⇤ (pred?; stmt); (!pred)?, definedheader as follows: whose parameter result. In the stmt1 ; stmt2 includes an (ouput) ⇤⇥ stmt1; stmt2, translation of the body of m, ⇤⇥ we translate while (pred) {stmt} (pred?;stmt1) stmt);+ (!pred)?, if (pred) stmt1 else stmt2 (pred?; ((!pred)?; stmt2) , stmt1 ; stmt2 ⇤⇥ stmt1; stmt2, return e --> VarAssign[result, e]. if (pred) stmt1 else stmt2 ⇤⇥ (pred?; stmt1) + For the more complex program translation is where boldface stmt, stmt1constructs, and((!pred)?; stmt2the stand for the, restmt2) defined follows: of the translation to the statements stmt, cursive as application stmt1 and stmt2, respectively. Predicates are translated to Alwhere the boldface stmt, stmt1 and stmt2 stand for the rewhile (pred) {stmt} ⇤⇥ (pred?; stmt); (!pred)?, loy formulas using the translation to be in Section cursive of the translation to presented thestmt2, statements stmt, stmt1 ;application stmt2 ⇤⇥ stmt1; 2.2. and stmt2, respectively. Predicates are translated to Alstmt1 if (pred) stmt1 else stmt2 ⇤⇥ (pred?; stmt1) + loy formulas using the translation to ((!pred)?; be presented in Section stmt2) , 2.2 Translating Annotations to Alloy 2.2. In thisthe section we describe the translation annotations to where boldface stmt, stmt1 and stmt2ofstand for the re- Java a DynAlloy: Código TACO: Análisis Eficiente de Código Java TACO: Translation of Annotated COde. Utiliza una técnica eficiente para reducir las cotas superiores de KodKod. Consigue mejoras en tiempos de análisis de gran magnitud. Algunos experimentos muestran que consigue equipararse o superar a otras herramientas poderosas basadas en SMT solving y otras técnicas Ejemplo de un Problema Generar instancias de AVLs 12 6 3 14 8 1. Árbol binario, 2. Ordenado, 3. Balanceado: |h(left(n)) - h(right(n))| <= 1 1 15 Técnica: Refinamiento Automático de Cotas Para encontrar una instancia el SAT solver intenta encontrar (usando estrategas de poda del espacio de estados) un árbol thiz, y funciones para los campos root, h, left y right tales que satisfacen el invariante de la estructura. Para AVLs En lo que respecta al campo h, notemos que todas las hojas tienen h = 0. Además, dado que estos son árboles balanceados de a lo sumo 7 nodos, ningún nodo satisface h(n) mayor a 3. h=3 h=0 h=1 h=2 h=2 h=0 h=1 h=1 h=0 h=1 h=0 h=0 h=0 h=0 Para AVLs Como los nodos son objetos, un nodo puede estar almacenado en diferentes direcciones (en momentos diferentes). Por ejemplo: N0 N1 N2 2 5 3 N3 6 4 N3 N4 N0 N2 2 5 3 6 4 N4 N1 Para AVLs Pero forzaremos que los nodos sean recorridos en Breadth First Search N0 N1 N3 2 3 5 6 N2 4 N4 N0 Para AVLs N1 N3 2 5 3 6 4 N4 Es posible que N0 apunte a un nodo que no sea ni N1 ni N2? Es posible que N2 sea apuntado por algo que no sea N0? N0 N1 N2 2 3 5 No es un AVL! N2 Casos Insatisfactibles Por ejemplo, para un árbol con a lo sumo 7 nodos, h(n)<=3 for all node n. Left(N0) es o bien N1 o null (pero no N2, N3,...) Right(N0) es N1, N2 o null (pero no N3, N4,...) Right(Ni) != N2 para i != 0. Casos Insatisfactibles En clases con invariantes complejos, estos valores corresponden a tuplas en campos, y por lo tanto a variables proposicionales en la traducción KodKod. Si podemos eliminar estos casos insatisfactibles, el SAT-solver tendría que intentar asignaciones de un menor número de variables. Esta observación es general, no sólo para AVLs!!! Refinar cotas se reduce a... Forzar que se asignen direcciones a los nodos de acuerdo a un recorrido BFS. Descubrir las variables que corresponden a casos insatisfactibles. Hacer esto de manera automática. La Técnica: Instrumentar el modelo relacional con fórmulas que fuercen la asignación de direcciones a nodos en BFS. Chequear, para el modelo resultante, la satisfactibilidad de cada par correspondiente a cada campo de cada clase. Instrumenting the model Regla 2: Dos nodos con el mismo padre se etiquetan de Regla 1: La nuevamente raíz se etiqueta con N0. Aplicando la Regla 2 izquierda a derecha N0 root 5 N1 3 2 N4 6 4 N3 N2 Chequeo de Satisfactibilidad Enfoque Naive: Usar un cluster para chequear la satisfact. de cada par en cada campo Problema N0.left = N0, Generar un AVL con 20 nodos N0.left = N1, no termina. ... N0.h = 0, No se tienen aún N0.h = 1, cotas más ... ajustadas! Para 20 nodos, se deben realizar 2120 chequeos. Un Enfoque efectivo SATs p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0 UNSATs Bound p0 p3 p6 p9 p1 p4 p7 p10 p2 p5 p8 p11 p0 p9 p10 p1 p2 p6 p3 p11 p7 p4 p5 p8 TIMEOUTS Sobre “Cotas Ajustadas” Consideremos la siguiente estructura y su representación Como vimos, los campos son matrices (relaciones), representadas por variables booleanas (una por celda) Sobre “Cotas Ajustadas” La rotura de simetrías hace a algunas de éstas no satisfactibles! Rotura de simetrías: “header es null o N0, y Ni.next es N.(i+1) o null” Esto permite eliminar variables de celdas no satisfactibles: Manejo Booleano de Aritmética Los dominios numéricos se pueden capturar por su representación en bajo nivel: sig integer { bit31: boolean, ... bit0: boolean } pred intEQ[i1, i2 : integer] { i1.bit31 = i2.bit31 i1.bit30 = i2.bit30 ... i1.bit00 = i2.bit00 } SAT Solving Incremental Básicamente: permite agregar más restricciones “on the fly”, sin tener que reiniciar el proceso de SAT solving Esto se usa para obtener cobertura óptima (acotada) con la cantidad mínima de tests Evaluación Aquí tenemos algunas comparaciones del enfoque con otras herramientas basadas en constraint solving Algunos Casos no Capturados por Otras Herramientas No captado por Kiasan No captado ni por Kiasan ni por PEX Evaluación (cont.) Segunda comparación: herramientas de generación de tests sobre estructuras complejas alojadas en memoria dinámica En Conclusión La generación de tests es crucial para el testing Es en general muy costosa, y se realiza de manera manual Es relativamente fácil de automatizar para rutinas con parámetros de tipos básicos (e.g., generación aleatoria) Si se busca conseguir buena cobertura, es en general muy difícil Si los tipos de datos manipulados son complejos, es definitivamente muy difícil Resumen de Técnicas de Generación Automática Generación Aleatoria Generación Basada en Constraint Solving Basada en SAT vs. basada en SMT vs. basada en búsqueda (incl. model checking) White box vs. black box Generación exhaustiva acotada Inherentemente “fuerza bruta”, aunque en general requiere constraint solving