Formal Modeling

1 Instructions to Create Formal Model

1.2 Application Model

1.2.1 Spefication Snippets

1.2.1.1 Model State
  1. Model Entity Users

    State of entity Users is modeled using tla+ module tla/Timeoff_Users.tla

    \* State variable Timeoff_Users initialized to an empty set
    Timeoff_Users = {};
    
  2. Model Entity Companies

    State of entity Companies is modeled using tla+ module tla/Timeoff_Companies.tla

    \* State variable Timeoff_Companies initialized to an empty set
    Timeoff_Companies = {};
    
1.2.1.2 Model Service
  1. tla/TimeoffRegisterCompany.tla
    (*
     * Service entry point for interface /registerCompany(post).
     * Calls service implementation in procedure 
     * proc_TimeoffRegisterCompany
    *)
    macro TimeoffRegisterCompany( input ) {
    
          call proc_TimeoffRegisterCompany( input );
    
    }
    
  2. 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
  1. 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 };
        };
    }
    
  2. 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
  1. Operator: validate User entity

    Operator 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
    
  2. Operator: Validate Company Entity

    Operator 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.2.3.1 Service /registerCompany(post) Executes Successfully

File tla/isCompanyRegistered

(*
 * Evaluate TRUE whe service /registerCompany(post)
 * succeeds i.e. return status 200.
*)
isCompanyRegistered == InfrastructureServiceGetStatus("/registerCompany(post)") = "status_200"
1.2.3.2 Service /registerCompany(post) Execution Fails

In file tla/isCompanyRegisteredFails

 (*
 * Evaluate TRUE whe service /registerCompany(post)
 * fails  i.e. returns status 400.
 *)
  isCompanyRegisteredFails == InfrastructureServiceGetStatus("/registerCompany(post)") = "status_400"

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+ snippet TimeoffRegisterCompany
  • instantiates plugin object ethLoader from class Sbuilder::Eth::Plugin::Plugin implemented in sbuilder-eth GEM.

1.5 Smoke Run Using Setup setup1

To validate that a formal model can be succesfully

  • generated to TLA+language,
  • processed by TLA+tools PlusCal ,
  • and model checked by TLA+tools TLC,

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.