• Nenhum resultado encontrado

4. Uma fórmula temporal L especificando a condição de progresso do programa.

Depois que se prepara uma especificação de sistema usando TLA+, pode-se checá-la usando a ferramenta TLC. Quando se executa o TLC no modo de checagem de modelo, ele tenta encontrar todos os estados alcançáveis (todos os estados que podem ocorrer em comportamentos satisfazendo uma dada fórmula na forma Init ^rNextsvars). Quando ele

é executado no modo de simulação, ele randomicamente gera comportamentos (behaviors), sem tentar checar todos os estados alcançáveis [58].

Especificações TLA+ são particionadas em módulos. A seguir são apresentados três módulos que foram criados para este trabalho: TestExecution, MonitoredTestExecution e TestExecutionCheckingAssertionInvariant.

7.2

A Especificação Test Execution usando TLA+

No Apêndice A é apresentada uma especificação em TLA+ de uma execução de teste sem usar a abordagem Thread Control for Tests. Essa especificação foi escrita em um arquivo texto chamadoTestExecution.tlae então formatada para impressão usando a ferra- menta TLATeX. A sintaxe dessa especificação foi checada usando a ferramenta verificadora de sintaxetlasany.

Para que fosse possível checar essa especificação utilizando TLC, teve-se de definir no modelo os possíveis estados de threads sendo considerados e o número de threads a serem consideradas no sistema sob teste (SUT). O número de threads foi 3 para o modelo mos- trado no Apêndice A. Cada um dos estados possíveis (e.g. running ) foi definido como uma constante, e definiu-se também uma outra constante para representar o conjunto dos esta- dos possíveis, denominada ThreadsPossibleStates. A definição das constantes do Módulo

TestExecution foi feita da seguinte forma:

CONSTANTThreadsPossibleStates, unstarted ,

started , waiting, running, finished , verifying

Especificou-se que o estado do sistema a ser checado seria o estado das threads que são criadas quando um teste é executado, incluindo a thread de teste. Esse estado é representado na especificação pela variável threadsStates, que é um registro (record). Registros em TLA+ são uma forma de substituir algumas variáveis por uma única variável. A definição dessa

7.2 A Especificação Test Execution usando TLA+ 108

variável foi feita na especificação da seguinte forma:

VARIABLEthreadsStates

Os estados possíveis considerados para as threads do sistema (representando os valores assumidos por tState1, tState2 e tState3 da tupla threadsStates) são: tunstarted , started ,

running, waiting and finishedu e esse conjunto de estados possíveis é representado pela

constante ThreadsPossibleStates, cujo valor é definido em um arquivo de configuração chamado TestExecution.cfg. Os estados possíveis que foram definidos para a th- read de teste (representando os valores assumidos por tState0) são: tunstarted , running,

verifyingu. Na especificação TLA+, a definição dos estados possíveis para as três threads do

sistema e para a thread do teste estão descritos na definição da seguinte invariante: TypeInvariant ∆

^threadsStates P rtState0 : tunstarted , running, verifyingu,

tState1 : ThreadsPossibleStates, tState2 : ThreadsPossibleStates, tState3 : ThreadsPossibleStatess

A idéia básica da especificação denominada Execução de Teste (Test Execution) é que uma execução de teste (TE ) é representada pela fórmula:

TE ∆ TEini^2rTEnxts

xthreadsStatesy

Essa fórmula é apresentada na parte final da especificação e a sintetiza.

A fórmula temporal TE especifica a condição de progresso da execução do teste, a qual indica que o estado inicial deve ser verdadeiro e afirma (asserts) que TEnxt é verdadeiro para qualquer passo no comportamento (que representa uma sequência infinita de estados).

Nessa fórmula, TEini é o predicado de estado que especifica o estado inicial do pro- grama. Esse estado indica que todas as threads, incluindo a thread de teste, devem estar no estado unstarted . Este predicado é definido no arquivoTestExecution.tlada seguinte forma:

TEini ∆

^threadsStates P rtState0 :tunstartedu,

tState1 : tunstartedu, tState2 :tunstartedu,

tState3 : tunstartedus

A ação TEnxt representa todas as transições permitidas pela especificação. Ela é cha- mada de relação de próximo estado (next state relation) e especifica como o valor da variável

7.2 A Especificação Test Execution usando TLA+ 109

threadsStates pode mudar em cada passo (sendo um passo um par de estados sucessivos). A especificação dessa ação é feita da seguinte forma:

TEnxt ∆ _TestStarts _Thread 1Starts _Thread 1Runs _Thread 1FinishesRunning _Thread 1StartsToWait _Thread 2Starts _Thread 2Runs _Thread 2FinishesRunning _Thread 2StartsToWait _Thread 3Starts _Thread 3Runs _Thread 3FinishesRunning _Thread 3StartsToWait _NothingHappens _AssertionPerformed _StartAssertionsBlock _FinishAssertionsBlock

A idéia básica da ação TEnxt é que os passos permitidos em uma execução de teste (es- pecificados na definição dessa ação) são os seguintes: o teste inicia (TestStarts) ou a thread1 começa (Thread 1Starts) ou a thread1 roda (Thread 1Runs), ou a thread1 para de rodar (Thread 1FinishesRunning ) ou a thread1 começa a esperar (Thread 1StartsToWait) ou a thread2 começa (Thread 2Starts) ou a thread2 roda (Thread 2Runs) ou a thread2 termina de rodar (Thread 2FinishesRunning ), ou a thread2 começa a esperar (Thread 2StartsToWait) ou a thread3 começa (Thread 3Starts), ou a thread3 roda (Thread 3Runs) ou a th- read3 termina de rodar (Thread 3FinishesRunning ) ou a thread3 começa a esperar (Thread 3StartsToWait) ou nada acontece (NothingHappens), ou seja, passos do tipo stut-

tering) são permitidos, ou ainda uma asserção é executada (AssertionPerformed ), ou ainda

7.2 A Especificação Test Execution usando TLA+ 110

minado (FinishAssertionsBlock ). Todas essas ações possíveis são definidas no arquivo

TestExecution.tlailustrado no Apêndice A, indicando as pré-condições para que es- ses passos sejam habilitados e os novos valores de variáveis após a ocorrência desses passos, os quais são representados pela variável primed chamada threadsStates1

.

Por exemplo, a ação indicando quando um teste inicia (TestStarts) é definida da seguinte forma:

TestStarts ∆

^threadsStates P rtState0 :tunstartedu,

tState1 : tunstartedu,

tState2 : tunstartedu,tState3 : tunstartedus

^threadsStates 1

rthreadsStates EXCEPT !.tState0runnings

Essa definição indica que esse passo só é habilitado quando todas as threads estão no estado unstarted , e depois que ele ocorre, o novo estado do sistema threadsStates1

indica que todas as threads permanecem no mesmo estado, exceto a thread do teste, cujo estado, representado por tState0 muda para running .

A mesma idéia é seguida pelas outras ações definidas nessa especificação em TLA+. Algumas das ações são definidas como locais (LOCAL) para indicar que em Módulos que estendem o módulo TestExecution elas podem ser redefinidas. Um exemplo de ação nesse estilo é a que indica que a thread1 roda (Thread 1Runs). Esta ação é definida da seguinte forma:

LOCALThread 1Runs ∆

^pthreadsStates.tState1started _threadsStates.tState1waitingq ^threadsStates

1

rthreadsStates EXCEPT !.tState1runnings

Esta ação indica que o passo de fazer a thread1 rodar só é habilitado quando esta thread estava no estado started ou waiting . Além disso, uma vez que esse passo ocorre, o novo estado da thread1 passa a ser running e os estados das demais threads se mantêm.

Em TLA+, uma fórmula temporal satisfeita por todo comportamento é chamada um teo- rema. Na especificação Test Execution, o seguinte teorema é estabelecido:

THEOREMTE ñ2TypeInvariant

Esse teorema indica que a fórmula temporal TE implica que a definição de invariante TypeInvariant é sempre verdadeira. Essa invariante indica que para cada estado possível

7.2 A Especificação Test Execution usando TLA+ 111

de uma execução de teste, o estado de cada thread do sistema (SUT thread) é o conjunto ThreadsPossibleStates  tunstarted , started , running, waiting and finishedue que o es-

tado da thread do teste está no conjuntotunstarted , running, verifyingu.

Um outro invariante é definido no arquivo TestExecution.tla, o NotEarlyOrLateAssertionInvariant. No entanto, a especificaçãoTestExecution.tla

não contém o teorema indicando que essa invariante deve ser sempre verdadeira. Isso é feito apenas na segunda e na terceira especificações, mostradas nos Apêndices B e C e descritas nas próximas seções. Esse invariante representa a não ocorrência de asserções antecipadas e tardias e sua especificação indica que quando a thread do teste está no estado verifying (executando alguma asserção), todas as threads do SUT devem estar waiting ou finished . A definição desse invariante é feita da seguinte forma:

NotEarlyOrLateAssertion ∆

_threadsStates P rtState0 : tverifyingu,

tState1 : twaiting, finishedu, tState2 :twaiting, finishedu,

tState3 : twaiting, finishedus

_threadsStates P rtState0 : trunningu,

tState1 : ThreadsPossibleStates, tState2 : ThreadsPossibleStates, tState3 : ThreadsPossibleStatess

_threadsStates P rtState0 : tunstartedu,

tState1 : tunstartedu,tState2 : tunstartedu,

tState3 : tunstartedus

É importante perceber que a execução de teste descrita pela especificação do arquivo

TestExecution.tlailustra uma execução de teste em que as threads não são monitora- das. Isso pode ser observado na definição da ação StartAssertionsBlock , que está ilustrada a seguir:

LOCALStartAssertionsBlock ∆

^pthreadsStates.tState0runningq ^threadsStates

1

rthreadsStates EXCEPT !.tState0verifyings

A única pré-condição especificada nessa ação para que um bloco de asserções se inicie é que a thread do teste esteja no estado running . Depois que essa ação acontece, o novo estado da thread de teste tState0 será verifying .