Formal Modeling
1 Instructions to Create Formal Model
1.1 Formal Model Elements
1.2 Application Model
1.2.1 Spefication Snippets
1.2.1.1 Model State
- Model Entity
Users
State of entity
Users
is modeled using tla+ moduletla/Timeoff_Users.tla
\* State variable Timeoff_Users initialized to an empty set Timeoff_Users = {};
- Model Entity
Companies
State of entity
Companies
is modeled using tla+ moduletla/Timeoff_Companies.tla
\* State variable Timeoff_Companies initialized to an empty set Timeoff_Companies = {};
1.2.1.2 Model Service
tla/TimeoffRegisterCompany.tla
(* * Service entry point for interface /registerCompany(post). * Calls service implementation in procedure * proc_TimeoffRegisterCompany *) macro TimeoffRegisterCompany( input ) { call proc_TimeoffRegisterCompany( input ); }
tla/proc_TimeoffRegisterCompany.tla
(* * Service implementation for interface /registerCompany(post). * Adds user and company entities for valid input and returns status 200 for * valid input. For invalid input return status "400". *) procedure proc_TimeoffRegisterCompany( input_proc_TimeoffRegisterCompany ) { proc_TimeoffRegisterCompany_start: if ( valid_User( input_proc_TimeoffRegisterCompany ) /\ valid_Company( input_proc_TimeoffRegisterCompany ) ) { TimeoffAddUser( [ user_name |-> input_proc_TimeoffRegisterCompany.user_name, user_lastname |-> input_proc_TimeoffRegisterCompany.user_lastname, user_email |-> input_proc_TimeoffRegisterCompany.user_email ] ); TimeoffAddCompany( [ company_name |-> input_proc_TimeoffRegisterCompany.company_name ] ); InfrastructureServiceReturn( "/registerCompany(post)", "status_200", Nil ); } else { InfrastructureServiceReturn( "/registerCompany(post)", "status_400", Nil ); }; proc_TimeoffRegisterCompany_exit: return; }
1.2.1.3 Actions Modifying Persistent State
- Action: Add new
user
In file
tla/TimeoffAddUser.tla
(* * Add new user entry to model state - if it does not exist *) macro TimeoffAddUser( user ) { if ( ~ user \in Timeoff_Users ) { Timeoff_Users := Timeoff_Users \union { user }; }; }
- Action: Add new
company
In file
tla/TimeoffAddCompany.tla
(* * Add new companry entry to model state - if it does not exist *) macro TimeoffAddCompany( company ) { if ( ~ company \in Timeoff_Companies ) { Timeoff_Companies := Timeoff_Companies \union { company }; }; }
1.2.1.4 Validation Operators
- Operator: validate
User
entityOperator
tla/valid_User.tla
(* * Validate data model entry user *) valid_User( user ) == user # Nil /\ user.user_name # Nil /\ user.user_lastname # Nil /\ user.user_email # Nil
- Operator: Validate
Company
EntityOperator
tla/valid_Company.tla
(* * Validate data model entry companry *) valid_Company( co ) == co # Nil /\ co.company_name # Nil
1.2.2 Correctness Criteria
1.2.2.1 Invariant: verify formal model state
Verify formal model state in tla/correct_Database.tla
as given by
operators valid User and valid Company.
(* * All user and company entries in formal model state are valid *) correct_Database == \A user \in Timeoff_Users: valid_User(user) /\ \A co \in Timeoff_Companies: valid_Company(co)
1.2.3 Possibility Operators
1.3 Environment Setup
1.3.1 Setup cnf/setup_companyRegistered.yaml
The very contrived environment setup below defines cardinality value
1
to domain default_domain
, resolved below. In the formal model,
this translates to a definition of a set with one element plus a
special value Nil
. Value Nil
represent missing data in the formal
model.
The environment setup defines also one step with interface call to
/registerCompany(post)
. The definition does not restrict input to
the interface call, and during model checking, environment model uses
all possible value combinations for the interface call.
- domain-extension: # superflous cardinality 1 is the default - domain: default_domain cardinality: 1 - step-extension: - interface: /registerCompany(post)
1.4 Sbuilder configuration
1.4.1 Create resolver cnf/timeoff-resolver.yaml
A very contrived resolver maps all variables to one deafult_domain
.
# This matches everyting - with default domain - Name: default-resolver Matcher: !ruby/regexp /.*/ Rules: - Matcher: !ruby/regexp /.*/ Domain: default_domain
1.4.2 Sbuilder configuration cnf/sbuider.yaml
The YAML configuration below combiness elements, presented in this document, and controls formal model translation.
preferences: debug-output: false extend: resolvers: - url: cnf/timeoff-resolver.yaml # Use sbuilder API loader extension point interfaces: - className: Sbuilder::ParamSetLoaderSwagger infrastructureServices: true url: ../stage/timeoff-swagger.yaml # Use sbuilder Snippet loader extension point snippets: - className: Sbuilder::SnippetLoaderSimple snippets: # Load - metatype: framework-svc appName: Timeoff_Users url: tla/Timeoff_Users.tla - metatype: framework-svc appName: Timeoff_Companies url: tla/Timeoff_Companies.tla - metatype: framework-svc appName: TimeoffAddUser url: tla/TimeoffAddUser.tla - metatype: framework-svc appName: TimeoffAddCompany url: tla/TimeoffAddCompany.tla - metatype: framework-svc appName: proc_TimeoffRegisterCompany url: tla/proc_TimeoffRegisterCompany.tla - metatype: framework-svc appName: TimeoffRegisterCompany url: tla/TimeoffRegisterCompany.tla # Define - metatype: service_implementation appName: /registerCompany(post) name : TimeoffRegisterCompany - className: Sbuilder::SnippetLoaderSimple snippets: - metatype: framework-svc appName: isCompanyRegistered url: tla/isCompanyRegistered.tla - metatype: framework-svc appName: isCompanyRegisteredFails url: tla/isCompanyRegisteredFails.tla - metatype: framework-svc appName: correct_Database url: tla/correct_Database.tla - metatype: framework-svc appName: valid_User url: tla/valid_User.tla - metatype: framework-svc appName: valid_Company url: tla/valid_Company.tla # Configure setup setups: - setupDirectory: setup1 - setupDirectory: setup_companyRegistered possibilities: - isCompanyRegistered - isCompanyRegisteredFails extensions: - url: cnf/setup_companyRegistered.yaml invariants: - correct_Database: user and companry entries valid
The configuration above
- references YAML resolver in file
cnf/timeoff-resolver.yaml
- references Swagger API interface definition in file
../stage/timeoff-swagger.yaml
- loads TLA+ language snippets into Sbuilder formal model using a
plugin
Sbuilder::SnippetLoaderSimple
- associates interface
/registerCompany(post)
with TLA+ snippetTimeoffRegisterCompany
- instantiates plugin object
ethLoader
from classSbuilder::Eth::Plugin::Plugin
implemented insbuilder-eth
GEM.- defines an empty setup
setup1
andsetup_companyRegistered
, configured above. Setup setupcompanyRegistered defines two possibility operators isCompanyRegistered and isCompanyRegisteredFails - activates operator correctDatabase as an invariant to hold universally
- defines an empty setup
1.5 Smoke Run Using Setup setup1
To validate that a formal model can be succesfully
run the following command
(SETUP=setup1; TLATOOLS_JAR=$(pwd)/java/tla2tools.jar; \ bundle exec sbuilder.rb generate $SETUP; \ cd gen/$SETUP/tla && \ java -cp $TLATOOLS_JAR pcal.trans model; \ java -cp $TLATOOLS_JAR tlc2.TLC setup | \ tee ../tlc.out ) | \ grep 'No error has been found\|states generated' -
and observe the output with the following lines.
Model checking completed. No error has been found. 3 states generated, 2 distinct states found, 0 states left on queue.
The output above shows only two distinct states found. First state is
the initial state, and the second state corresponds to the situation,
where environment model has processed all setup steps. For setup1
,
there were no stesp defined, unlike to setup_companyRegistered
, which
defines one step.