View source | Discuss this page | Page history | Printable version   
Toolbox
Main Page
Upload file
What links here
Recent changes
Help

PDF Books
Show collection (0 pages)
Collections help

Search

Retail:Developers Guide/How-to/How to Install, Setup and Run Retail Automated Tests

Contents

Introduction

The Retail Automated tests are are a set of JUnit test cases which use Selenium to execute actions on top of an Openbravo POS session to verify all areas of the application. These tests are executed as part of the Retail Continuous Integration as can be seen here.

Versions used in this guide: Java 11, Tomcat 8.5, PostgreSQL 10 and/or Oracle 11

Setup development environment Ubuntu

During this chapter, a detailed installation guide will be explained. If you are familiarized with software installation under Linux, you can jump directy here to have a more simplified view.

Since all the stack can run on Linux, Mac and Windows and there are several versions supported, there is not guarantee that all the following steps will work. Use it at your own risk.

Bulbgraph.png   Before start, check the the current recommended versions, since could happen that the versions on this guide are obsolete.

Previous steps

Download and install Ubuntu 20.04 64-bit LTS Desktop.

You can obtain the ISO from here (64-bit PC (AMD64) desktop image).

In case there is Ubuntu 20.04.X (being X any minor revision number) instead of just 20.04, it is ok to download and install the most recent revision.

Zsh

This software is optional, but it is the recommended shell. If you do not install it, you can just ignore the ".zsh" sections in the following chapters.

sudo apt install zsh
sudo apt install git
cd $HOME
git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/.oh-my-zsh/custom/themes/powerlevel10k
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf
  1. Double click on each one to open it
  2. Click on install
  1. Right click / preferences
  2. In profiles, on left menu, click on the '+' to add a new profile
  3. Name: zsh
  4. Click on checkbox custom font
  5. Select font mesloLGS NF regular
  6. Optional: probably you want to uncheck the terminal bell
  7. Move to command tab
  8. Click to check "run a custom command instead of my shell"
  9. Write in "custom command": zsh
  10. On the left menu, in zsh profile, click in the down arrow
  11. Select: set as default

https://drive.google.com/file/d/1-_QFX2MaX0SxQ37KkzuNIUD-qOiw2xOH/view?usp=sharing

mv Downloads/p10k.zsh .p10k.zsh
# optionally, later you can do your own config running: p10k configure (in a new terminal)
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
# Initialization code that may require console input (password prompts, [y/n]
# confirmations, etc.) must go above this block; everything else may go below.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
  source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi

# Your PATH Exports
# Path to your oh-my-zsh installation.
export ZSH=$HOME/.oh-my-zsh
ZSH_THEME="powerlevel10k/powerlevel10k"

plugins=(git)
source $ZSH/oh-my-zsh.sh

# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh


HISTFILE="$HOME/.zsh_history"
HISTSIZE=10000000
SAVEHIST=10000000
#setopt BANG_HIST                 # Treat the '!' character specially during expansion.
setopt EXTENDED_HISTORY          # Write the history file in the ":start:elapsed;command" format.
setopt INC_APPEND_HISTORY        # Write to the history file immediately, not when the shell exits.
#setopt SHARE_HISTORY             # Share history between all sessions.
#setopt HIST_EXPIRE_DUPS_FIRST    # Expire duplicate entries first when trimming history.
#setopt HIST_IGNORE_DUPS          # Don't record an entry that was just recorded again.
#setopt HIST_IGNORE_ALL_DUPS      # Delete old recorded entry if new entry is a duplicate.
setopt HIST_FIND_NO_DUPS         # Do not display a line previously found.
setopt HIST_IGNORE_SPACE         # Don't record an entry starting with a space.
setopt HIST_SAVE_NO_DUPS         # Don't write duplicate entries in the history file.
#setopt HIST_REDUCE_BLANKS        # Remove superfluous blanks before recording entry.
#setopt HIST_VERIFY               # Don't execute immediately upon history expansion.
#setopt HIST_BEEP                 # Beep when accessing nonexistent history.


Vim

This software is optional, but it is a useful file editor.

sudo apt install vim
:set nofixendofline
sudo update-alternatives --config editor

Chrome

This is the supported browser, so its installation is mandatory

wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb

# If fails during the installation phase with missing required dependencies, run: "sudo apt install -f ..." instead to fix it.
rm google-chrome-stable_current_amd64.deb

Use different sessions inside chrome

To have different session in each tab of chrome is possible to use a trick: Edit your /etc/hosts , and change:

127.0.0.1	localhost

with

127.0.0.1	localhost  *.localhost

With this, you can access to any *.localhost and will point to your localhost, example:

a.localhost/openbravo
test.localhost/openbravo
b.localhost/openbravo
whatever.localhost/openbravo

a.localhost and b.localhost are taken as different hosts so the session is not shared.

PostgreSQL

This is the recommended database. Alternatively Oracle can be installed but in this chapter only PostgreSQL installation will be covered.

sudo sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ '$(cat /etc/lsb-release | grep DISTRIB_CODENAME | cut -d'=' -f2)'-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt update
sudo apt install postgresql-10
sudo -u postgres psql -c "alter user postgres with password 'syspass';"
# Required at least for correct import.sample.data
# Config value with very bad name, this is not locks per transactions but sizes the
#   total number of possible locks see formula in postgresql.conf
max_locks_per_transaction = 128

# Make sure timezone config is localtime so pg follows system-timezone (as it did up to <9.2 also by default)
# Note: pg has auto-detect based on system timezone, but best to set fixed here to be sure it has value we want
# Note: sed assumes input is UTC or localtime but that was the case in all testing so far
log_timezone = 'localtime'
timezone = 'localtime'

# activate logging of checkpoints
log_checkpoints = on

# activate logging of of all waits > deadlock_timeout (1s by default)
log_lock_waits = on

# track runtime/calls of all pl/sql functions
track_functions = all

# activate logging of slow queries (>30s to balance usefulness versus log-volume)
log_min_duration_statement = 30000

# set locale for number formatting to en_US.UTF-8
lc_numeric = 'en_US.UTF-8'

# only edit this file

#log_min_duration_statement = 0
#checkpoint_timeout = 1h

# pg stat
#shared_preload_libraries = 'pg_stat_statements'

#pg_stat_statements.max = 10000
#pg_stat_statements.track = all
sudo /etc/init.d/postgresql restart

PostgreSQL clients

Extracted from: https://www.pgadmin.org/download/pgadmin-4-apt/

curl https://www.pgadmin.org/static/packages_pgadmin_org.pub | sudo apt-key add
sudo sh -c 'echo "deb https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/$(lsb_release -cs) pgadmin4 main" > /etc/apt/sources.list.d/pgadmin4.list && apt update'
sudo apt install pgadmin4

It is installed as part of postgres, if you create a workspace with dt scripts with name 'test', to access it will be:

PGPASSWORD=tad psql -d postgres -U tad -h localhost -d db_test

Java

sudo apt install openjdk-11-jdk
sudo sh -c 'echo "JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64" >> /etc/environment'

Note: change only be effective after restart

Ant

sudo apt install ant
sudo sh -c 'echo "export ANT_OPTS=\"-Xmx1024M\"" >> /etc/environment'


Tomcat

cd ~/Downloads
tar xf apache-tomcat-8.5.*.tar.gz
rm apache-tomcat-8.5.*.tar.gz
sudo mv apache-tomcat-8.5.* /opt/
cd /opt
sudo ln -s apache-tomcat-8.5.* apache-tomcat-8.5
sudo sh -c 'echo "export CATALINA_OPTS=\"-server -Djava.awt.headless=true -Xms512M -Xmx1024M\"" >> /etc/environment'
sudo sh -c 'echo "export CATALINA_HOME=/opt/apache-tomcat-8.5" >> /etc/environment'
sudo sh -c 'echo "export CATALINA_BASE=/opt/apache-tomcat-8.5" >> /etc/environment'

Apache

sudo apt-get install apache2 libapache2-mod-jk
JkMount /* ajp13_worker
jkMountCopy all
sudo sh -c 'echo "openbravo ALL = NOPASSWD: /etc/init.d/apache2" > /etc/sudoers.d/97-ob-apache'
# If you are not using openbravo user, change it in the previous command
sudo a2enmod ssl
sudo a2ensite default-ssl.conf
sudo /etc/init.d/apache2 restart

Git

sudo apt install git
git config --global pull.ff only

You can follow these steps, if you don't have yet a ssh key you can follow this guide to create one.

Replace with your name and last name, and your email for work
git config --global user.name "FIRST_NAME LAST_NAME"
git config --global user.email "MY_NAME@example.com"

After setup the dt scripts you can add the githooks.

Optional git config

PRETTY_FORMAT="--pretty='format:%C(auto)%h%d %s %C(magenta dim)%an %ar'"
alias galo="glo $PRETTY_FORMAT"
alias galog="glog $PRETTY_FORMAT"
alias galoga="gloga $PRETTY_FORMAT"

A good UI tool for help solving merge conflicts if p4merge.

Extracted from: https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration

- Download p4merge from:

https://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools

- Extract it:

tar xf p4v.tgz

- Move to opt

sudo mv p4v-* /opt/p4merge

- Create file /usr/local/bin/extMerge , with contents:

#!/bin/sh
/opt/p4merge/bin/p4merge $*

- Give execution permissions:

sudo chmod +x /usr/local/bin/extMerge

- Make it default merge tool:

git config --global merge.tool extMerge
git config --global mergetool.extMerge.cmd \
 'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
git config --global mergetool.extMerge.trustExitCode false

For solve merge conflicts a recommendation is go file by file:

Node and npm

sudo apt-get install -y curl
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt-get install -y nodejs

If the npm and node commands are not available, try opening a new terminal or restarting the computer

If needed to install a specific version of npm, for example 6: sudo npm install -g npm@6

Eclipse IDE

cd ~/Downloads
tar xf eclipse-jee-*.tar.gz
rm eclipse-jee-*.tar.gz
mv eclipse eclipse-2020-09 # set the version that you have download
sudo mv  eclipse-2020-09 /opt/
cd /opt
sudo ln -s eclipse-2020-09 eclipse
cd /usr/local/bin
sudo ln -s /opt/eclipse/eclipse eclipse
[Desktop Entry]
Type=Application
Encoding=UTF-8
Name=Eclipse
Comment=Eclipse
Exec=eclipse
Icon=eclipse.png
Terminal=false


If you have already cloned the openbravo repos, this is the guide for the workspace setup.


Visual Code

https://go.microsoft.com/fwlink/?LinkID=760868
sudo apt install./<file>.deb
sudo sh -c "echo fs.inotify.max_user_watches=524288 >> /etc/sysctl.conf"
sudo sysctl -p


Workspace config file

Workspaces done by dt scripts will already have this file, this is ONLY needed for workspaces done manually:

dt fix-vscode-workspace-file

Execute test file after edit it

  "saveAndRun": {
       "commands": [
           {
               "match": ".test.",
               "cmd": "npm run test ${file}",
               "useShortcut": false,
               "silent": false
           },
       ]
   }

dt scripts setup

git clone git@gitlab.com:openbravo/ci/retail_scripts.git ~/Documents/retail_scripts
git clone git@gitlab.com:openbravo/ci/dev_tools.git ~/Documents/dev_tools
# dt scripts
export PATH="$PATH:/home/openbravo/Documents/retail_scripts"
export PATH="$PATH:/home/openbravo/Documents/dev_tools"
autoload bashcompinit # only for zsh
bashcompinit                 # only for zsh
source /home/openbravo/Documents/retail_scripts/dt-completion
cp devtools.config.template devtools.config
PRISTINES_PATH:     $HOME/Documents/hg_pristines
GIT_PRISTINES_PATH: $HOME/Documents/git_pristines
WORKSPACES_PATH:    $HOME/Documents/workspaces
mkdir /home/openbravo/Documents/workspaces
sudo apt install python3-tqdm

Githooks

git config --global core.hooksPath /home/openbravo/Documents/retail_scripts/githooks

Setup development environment in MacOS

This guide was tested in macOs Catalina (10.15.7) and macOS Big Sur (11.2.1)

Bulbgraph.png   Before start, check the the current recommended versions, since could happen that the versions on this guide are obsolete.

Previous steps and local vs global installation

# Open a terminal:
cd $HOME
open .
# In the finder opened at your home, you should have an Applications folder, you can drag to the left part of finder to have it a hand
# If doesn't exist you can create mkdir #HOME/Applications (in finder will recognise it, and put an 'A' logo like the apple store)

Zsh

Zsh is already the default shell in Mac, so only needed to install ohMyZsh and powerlevel10k:

cd $HOME
git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/.oh-my-zsh/custom/themes/powerlevel10k
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf
https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf

https://drive.google.com/file/d/1-_QFX2MaX0SxQ37KkzuNIUD-qOiw2xOH/view?usp=sharing

mv Downloads/p10k.zsh .p10k.zsh
# optionally, later you can do your own config running: p10k configure (in a new terminal)
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
# Initialization code that may require console input (password prompts, [y/n]
# confirmations, etc.) must go above this block; everything else may go below.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
  source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi

# Your PATH Exports
# Path to your oh-my-zsh installation.
export ZSH=$HOME/.oh-my-zsh
ZSH_THEME="powerlevel10k/powerlevel10k"

plugins=(git)
source $ZSH/oh-my-zsh.sh

# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh


HISTFILE="$HOME/.zsh_history"
HISTSIZE=10000000
SAVEHIST=10000000
#setopt BANG_HIST                 # Treat the '!' character specially during expansion.
setopt EXTENDED_HISTORY          # Write the history file in the ":start:elapsed;command" format.
setopt INC_APPEND_HISTORY        # Write to the history file immediately, not when the shell exits.
#setopt SHARE_HISTORY             # Share history between all sessions.
#setopt HIST_EXPIRE_DUPS_FIRST    # Expire duplicate entries first when trimming history.
#setopt HIST_IGNORE_DUPS          # Don't record an entry that was just recorded again.
#setopt HIST_IGNORE_ALL_DUPS      # Delete old recorded entry if new entry is a duplicate.
setopt HIST_FIND_NO_DUPS         # Do not display a line previously found.
setopt HIST_IGNORE_SPACE         # Don't record an entry starting with a space.
setopt HIST_SAVE_NO_DUPS         # Don't write duplicate entries in the history file.
#setopt HIST_REDUCE_BLANKS        # Remove superfluous blanks before recording entry.
#setopt HIST_VERIFY               # Don't execute immediately upon history expansion.
#setopt HIST_BEEP                 # Beep when accessing nonexistent history.

Vim

:set nofixendofline

Chrome

PostgreSQL

PostgresSQL clients

export PATH="$PATH:/Applications/Postgres.app/Contents/Versions/10/bin"

Java

Guide extracted from: https://sdkman.io/install

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 11.0.2-open
cd ~/Documents
ln -s /Users/openbravo/.sdkman/candidates/java/current/ java
# Check in the System Preferences / Security and privacy
# Check Files and folders / java has access to  Documents folder
# If java don't have access it will show this error:
#  Buildfile: build.xml does not exist!
sdk current    # to see all the current versions
sdk list java   # to see available versions of java
sdk use java 11.0.0. # to change the used version of java

Ant

sdk install ant
export ANT_OPTS="-Xmx1024M"

Tomcat

sdk list tomcat  # select the last minor of 8.5
sdk install tomcat 8.5.60
cd ~/Documents
ln -s /Users/openbravo/.sdkman/candidates/tomcat/current tomcat

Apache

Normally is not needed to use Apache, only for execute offline tests of selenium, so you can skip this step till needed.

In case of needed: apache already comes installed in Mac. Apart of apache is needed to configure the mod_proxy.

<IfModule !proxy_module>
  LoadModule proxy_module libexec/apache2/mod_proxy.so
</IfModule>

<IfModule !proxy_http_module>
  LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so
</IfModule>

<IfModule mod_proxy.c>
    ProxyRequests On
    ProxyPreserveHost On

    ProxyStatus On
    <Location /status>
        SetHandler server-status

        Order Deny,Allow
        Deny from all
        Allow from 127.0.0.1
    </Location>

    ProxyPass    /openbravo    http://localhost:8080/openbravo
</IfModule>
sudo mkdir /etc/init.d
#!/bin/bash

case $1 in
  start)
  sudo apachectl start && echo 'Starting apache2'
  ;;
  stop)
  sudo apachectl stop && echo 'Stopping apache2'
  ;;
  status)
  [ "$(ps aux | grep httpd | grep -v grep)" != "" ] && echo 'is running'
  ;;
esac
sudo chmod +x /etc/init.d/apache2
openbravo ALL = (ALL)  NOPASSWD: /usr/sbin/apachectl
openbravo ALL = (ALL)  NOPASSWD: /etc/init.d/apache2

Git

git config --global pull.ff only

You can follow these steps, if you don't have yet a ssh key you can follow this guide to create one.

Replace with your name and last name, and your email for work
git config --global user.name "FIRST_NAME LAST_NAME"
git config --global user.email "MY_NAME@example.com"

After setup the dt scripts you can add the githooks.

Optional git config

PRETTY_FORMAT="--pretty='format:%C(auto)%h%d %s %C(magenta dim)%an %ar'"
alias galo="glo $PRETTY_FORMAT"
alias galog="glog $PRETTY_FORMAT"
alias galoga="gloga $PRETTY_FORMAT"

A good UI tool for help solving merge conflicts if p4merge.

Extracted from: https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration

https://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools
git config --global merge.tool p4mergetool
git config --global mergetool.extMerge.cmd \
 'Applications/p4merge.app/Contents/MacOS/p4merge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
git config --global mergetool.extMerge.trustExitCode false

For solve merge conflicts a recommendation is go file by file:

sudo npm install --global git-open

Node and npm

Eclipse

export PATH="$PATH:/Users/openbravo/Applications/Eclipse.app/Contents/MacOS"

Chromedriver

mkdir ~/Documents/chromedrivers/
cd Downloads
mv ~/Downloads/chromedriver ~/Documents/chromedrivers/chromedriver-88.0.4324.96
cd ~/Documents/chromedrivers/
ln -s chromedriver-88.0.4324.96 chromedriver-default

If using dt scripts to build the environment, this will be already added

chromedriverPath=/Users/openbravo/Documents/chromedrivers/chromedriver-default
forceUrl=http://localhost/

VSCode

Other Mac Specific

Fix home and end shortcut

Edit the profile, go to keyboard, 
- press +, key home, modifier none, action send text, command: \001
- press +, key end, modifier none, action send text, command: \005
Go to preferences, filter by keys
- search: line start, edit binding, press home
- search: line end, edit binding, press end
Also fix the conflicts, to go to start and end of page
- search: text start, press control home
- search: text end, press control end
Click on apply and close
mkdir ~/Library/KeyBindings

Create file ~/Library/KeyBindings/DefaultKeyBinding.dict , with :

{
  "\UF729"  = moveToBeginningOfParagraph:; // home
  "\UF72B"  = moveToEndOfParagraph:; // end
  "^\UF729" = moveToBeginningOfDocument:; // ctrl-home
  "^\UF72B" = moveToEndOfDocument:; // ctrl-end
}

Note: it will apply after reboot

dt scripts setup

git clone git@gitlab.com:openbravo/ci/retail_scripts.git ~/Documents/retail_scripts
git clone git@gitlab.com:openbravo/ci/dev_tools.git ~/Documents/dev_tools
# dt scripts
export DT_SCRIPTS_FOLDER="/Users/openbravo/Documents/retail_scripts"
export PATH="$PATH:/Users/openbravo/Documents/retail_scripts"
export PATH="$PATH:/Users/openbravo/Documents/dev_tools"
autoload bashcompinit
bashcompinit
source /Users/openbravo/Documents/retail_scripts/dt-completion
cp devtools.config.template devtools.config
PRISTINES_PATH:     $HOME/Documents/hg_pristines
GIT_PRISTINES_PATH: $HOME/Documents/git_pristines
WORKSPACES_PATH:    $HOME/Documents/workspaces
mkdir /Users/openbravo/Documents/workspaces
sudo -H pip3 install tqdm

Githooks

git config --global core.hooksPath /Users/openbravo/Documents/retail_scripts/githooks

VisualCode configuration

Needed VSCode Extensions

Important : First time eslint will be disabled, needed to click in the bottom right entry of eslint and enable always.

Recommended shortcuts


Example settings.json

Go to File > preferences > Settings, and in the top right there is a button to change the view from form to json file, click on it, and set this content:

{
   // js format on save
   "[javascript]": {
       "editor.formatOnSave": true,
       "editor.defaultFormatter": "esbenp.prettier-vscode"
   },
   "[javascriptreact]": {
       "editor.formatOnSave": true,
       "editor.defaultFormatter": "esbenp.prettier-vscode"
   },
   "[css]": {
       "editor.formatOnSave": true,
       "editor.defaultFormatter": "esbenp.prettier-vscode"
   },
   "[scss]": {
       "editor.formatOnSave": true,
       "editor.defaultFormatter": "esbenp.prettier-vscode"
   },
   "prettier.requireConfig": true,   

   // Copy edited files from modules to webContent and from webContent to modules
   "emeraldwalk.runonsave": {
       "commands": [
           {
               "match": "WebContent/web/(?!org.openbravo.userinterface.smartclient|org.openbravo.userinterface.smartclient.dev|userinterface.skin.250to300Comp)",
               "cmd": "dir=$( echo ${file} | sed -r 's#.*WebContent/web/([^/]+)/.*#\\1#') && file_mod=$(echo ${file} | sed -r 's#WebContent/web/'$dir'/#modules/'$dir'/web/'$dir'/#' ) && cp ${file} $file_mod"
           },
           {
               "match": "modules/(?!org.openbravo.userinterface.smartclient|org.openbravo.userinterface.smartclient.dev|userinterface.skin.250to300Comp)",
               "cmd": "dir=$( echo ${file} | sed -r 's#.*modules/([^/]+)/.*#\\1#') && file_mod=$(echo ${file} | sed -r 's#modules/'$dir'/web/'$dir'/#WebContent/web/'$dir'/#' ) && cp ${file} $file_mod"
           }
       ]
   },

   // default vscode config
   "editor.suggestSelection": "first",
   "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",

   // exclude in search window the generated js files (i.e. ab7bbbd81f40d14b3b44c3241ec26a7b.js)
   "files.exclude": {
       "**/WebContent": true,
       "**/WebContent/web/js/gen": true
   }

   // ignore gitignore for allow search in external modules
   // better to add the needed repo to the folder workspace
   // "search.useIgnoreFiles": false,
}

Note: eslint don't need any especial config and should work directly, only needed to do a npm install in the openbravo source path (this is already done by dt setup workspace scripts

Dev-scripts

Setup

git hook

Make eclipse available in the path

The dt scripts after build a workspace opens eclipse and also use it to run a clean command in the workspace copied, so it is very recommended to make eclipse available in the path.

To make this, follow the eclipse installation guide that you can found in this doc for linux or Mac.

Create workspaces with dt scripts

Create eclipse workspace with the retail pack

 dt pack-setup-workspace name: i33000  #i33000 is the name you want for this particular workspace

Note: first run will guide you to how to create the template of eclipse that will be used in next workspaces

Note2: always when creating a new eclipse workspace with the script needs to delete the trl, wad and core projects and re-import them again.

Workspace with the retail pack and the external modules

 dt modules-setup-workspace name: i41000_with_modules

Workspace of modules linked to a pack workspace

 dt pack-setup-workspace name: i2300
 dt modules-setup-workspace link-to-pack: i2300    # same name used for the pack

This creates a normal pack workspace, and in the modules workspace create links for:

The name of the modules workspace in this example will be i2300-modules.

So changes done in the pack in any of the workspaces is directly done in the other.

Useful for:

Known issue:

Workspace of backports

dt pack-setup-workspace name: 20q3 --context-definition: retail/try-retail-20Q3

If needed also modules:

dt modules-setup-workspace name: 20q3 --context-definition: retail/try-retail-20Q3

Or if you want linked to the pack workspace:

dt modules-setup-workspace link-to-pack: 20q3 --context-definition: retail/try-retail-20Q3

context_definitions

Workspace of pos2

Add these aliases to .zshrc or .bashrc:

alias c2start="(cd modules/org.openbravo.core2/web-jspack/org.openbravo.core2 && npm start)"
alias c2story="(cd modules/org.openbravo.core2/web-jspack/org.openbravo.core2 && npm run storybook)"
alias c2build="(cd modules/org.openbravo.core2/ && ant build)"
alias c2gen="(cd modules/org.openbravo.core2/ && ant generate.app)"
alias c2bs="c2build && c2start"

Pack:

dt modules-setup-workspace name: pos2 --context-definition: retail/pos2
   # NOTE: needed modules-setup-workspace instead pack-setup-workspace, if not there is a problem with the sampledatas and will not build

With restaurant and other modules:

dt modules-setup-workspace name: pos2modules --context-definition: retail/pos2-modules

After create the workspace execute (in openbravo folder):

c2bs
   # Also needed to execute after any change in old pos (mobile.core, posterminal, etc)
   # It will build old pos part and start npm to be accessible in port 3000

Url:

The port in which is started npm and the url of the backend can be edited, creating a file modules/org.openbravo.core2/web-jspack/org.openbravo.core2/.env :

PORT=3000
REACT_APP_SERVER_URL=http://localhost/openbravo

For more information about core2 builds: https://gitlab.com/openbravo/product/pmods/org.openbravo.core2/-/blob/master/README.md

Workspace of clients

dt modules-setup-workspace name: customer_env --context-definition-from-codesnapshot-file: /home/openbravo/snapshots/mycustomersnapshot --dump: /home/openbravo/dumps/mycustomerdump.dmp

gitr, gitp and gitb

gitp and gitr are equal than hgp and hgr.

bitb is to execute the same git command in all the git repos that is using the branch specified.

For example:

gitb  projectA status

It will execute git status in all git repos of the workspace that the current branch is projectA.

If you want to list the last commits of all the repos that you are using in your branch:

gitb projectA --no-pager log -1 --oneline

# or with author and antiquity
gitb projectA --no-pager log -1 --pretty='format:%C(auto)%h%d %s %C(magenta dim)%an %ar'

Add new modules to the workspace

dt add-new-modules-to-workspace

Note: can be used with the option --context-definition to fix origins and branches

Push to try-retail

Setup: Needed to have configured the dev_tools and have them added in the path.

In openbravo folder:

 run-try.py --retail --desc push-description

For info about the options:

 run-try.py --help

Personal forks

Important: To send from a personal forks to try-retail you need to give 'reporter' access to @OBBuildsReadOnly user to your personal fork.

Redistribute suites

When the time that takes each job of try-retail is unbalanced there is script that redistribute the suites along the jobs:

dt redistribute-suites retail-html-path: /home/openbravo/retail.html

Update eclipse template

The scripts has a template of eclipse configuration in the folder of the scripts.

This template includes the java formater, the projects imported, the tomcat servers, the opened files, etc.

If over time needs to be updated, for example a change in the formater or tomcat, follow these steps:

tar czf eclipse.tgz Servers/ RemoteSystemsTempFiles/ .metadata/
mv eclipse.tgz $(which dt | sed 's/dt$//')

Migration from Mercurial to GIT

Remember: the repos in product can be used when you don't plan to do changes on it, they have automatic sync from mercurial repos, but you will never push to these repos.

The repos in project/retail can be used when you want to create development branches, they don't have autosync from mercurial repos.

It is very recommended to use zsh with some customizations to work with git, it adds many useful information in the prompt line.

To install zsh follow the zsh install guide.

git config --global pull.ff only

Eclipse workspace setup

1.- Import -> existing projects into workspace
   - Choose folder of the workspace
   - Mark search for nested projects
   - Choose openbravo, mobile-test and openbravoCore, (unmark the rest)
2.- Import preferences:
   - Import, general, preferences
   - openbravo/config/eclipse/openbravo-eclipse-prefs.epf
   - finish
3.- Create new server
   - Check serve modules without publishing
   - Check modules auto reload by default
   - Timeout increase to 120 both
   - Double click on the server, general information, open launch configuration, arguments, vm arguments, add:
      -Djava.awt.headless=true -Xms512M -Xmx1024M
   - go to modules
      - add web module, select openbravo
      - click edit, disable reload

Optional workspace setup

Manual guide

1. Create a new directory in your computer

2. Navigate to that directory

3. Download Eclipse IDE (https://eclipse.org/downloads/) and copy it into that directory

4. Download Tomcat (http://tomcat.apache.org/) and copy it into that directory

5. Clone pi-mobile

 FIXME: hg clone https://code.openbravo.com/tools/automation/pi-mobile

6. Clone the ERP

 FIXME: hg clone https://code.openbravo.com/erp/devel/pi openbravo

7. Clone the retail repositories in the Navigate to the openbravo/modules directory. (from the ret-test-* repository list that can be found below):

 cd openbravo/modules
 FIXME: hg clone https://code.openbravo.com/erp/pmods/org.openbravo.mobile.core
 FIXME: hg clone https://code.openbravo.com/erp/pmods/org.openbravo.retail.config
 FIXME: hg clone https://code.openbravo.com/erp/pmods/org.openbravo.retail.discounts
 FIXME: hg clone https://code.openbravo.com/erp/pmods/org.openbravo.retail.pack
 FIXME: hg clone https://code.openbravo.com/erp/pmods/org.openbravo.retail.poshwmanager
 FIXME: hg clone https://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal
 FIXME: hg clone https://code.openbravo.com/erp/pmods/org.openbravo.retail.returns
 FIXME: hg clone https://code.openbravo.com/erp/pmods/org.openbravo.retail.sampledata

8. Execute ant.setup and configure the ERP

 cd openbravo
 ant setup

9. Execute setup.py to configure pi-mobile

 cd pi-mobile
 python3 setup.py ../openbravo

10. Run install.source

 cd openbravo
 ant install.source

11. Start the Eclipse that you downloaded in the directory

12. Start the ERP/tomcat. Verify that you can navigate to a terminal

13. Start selenium from the command line. Open a terminal and execute:

 cd pi-mobile/seleniumTools
 sh standalone.sh

14. Run a test

Repositories and continuous integration jobs

Currently there are 2 test repositories :

The pi-mobile repository is used as the main repository for the tests and is used for the main jobs, the ones included in the continuous integration process for Retail. These jobs include:

The same jobs can be found in the try server:

The pi-mobile-sandbox repository, on the other hand, is used for the ret-sandbox-* jobs. The sandbox repository works as a test repository for the tests' modifications, meaning that it is possible to push changes to the tests without affecting the continuous integration cycle. For developers, pi-mobile-sandbox also works as a time-saving strategy to execute the tests after pushing changes to retail modules, that is, sandbox jobs can be executed before the code passes continuous integration.

Bulbgraph.png   ret-test-* and ret-modules-* will not reflect code changes until previous integration steps have finished successfully.

Repositories used in the continuous integration servers

ret-test-*

ret-modules-*

Planned:

About the sampledata used:

The Retail Sampledata repository varies from the test jobs to the modules jobs. Ret-*-test-* jobs use the standard retail sampledata repository (https://code.openbravo.com/erp/pmods/org.openbravo.retail.sampledata) while ret-*-modules-* jobs use a different branch of the repo (https://code.openbravo.com/erp/pmods-branches/org.openbravo.test.mobile.sampledata) together with (https://code.openbravo.com/erp/pmods/org.openbravo.retail.testsampledata).


Bulbgraph.png   org.openbravo.retail.sampledata and org.openbravo.test.mobile.sampledata are branches of the same module (they have the same AD_MODULE_ID) so they MUST NOT be used together.

Setting Up the Automated Test Environment

Assuming we will be working with the pi-mobile repository to execute the tests, the following steps must be followed:

Clone these repositories in your projects directory http://code.openbravo.com/tools/automation/pi-mobile/ Do not place it inside an openbravo directory. The automation makes use of a running ERP, not its sources.

From this point there are 2 ways of configuring the automation context. The script is still not working for Oracle, so you should execute it and then manually fix the database references

1a. The scripted way: - Navigate to the root of the local pi-mobile - Execute the setup.py file pointing to the openbravo directory of the context that will be tested

e.g:

 [openbravo@ManjaroPC pi-mobile]$ python3 setup.py /home/openbravo/clones/tip/openbravo
 
 *** tool to configure Retail automation context v0.3 ***
 
 copying .classpath.template » .classpath
 copying config/OpenbravoERPTest.properties.template » config/OpenbravoERPTest.properties
 copying config/log4j.properties.template » config/log4j.properties
 database = obtip
 new tomcat log path: /tmp/tip/tomcat.log
 last results path: /tmp/tip/
 
 *** end ***

1b. The Manual way:

- Rename/copy the .classpath.template file to .classpath

- Rename/copy config/OpenbravoERPTest.properties.template to config/OpenbravoERPTest.properties

- Rename/copy config/log4j.properties.template to config/log4j.properties

- verify that the config/OpenbravoERPTest.properties has the correct database credentials (bbdd.sid, ...). These credentials must match the values of the openbravo server database.

- In order to run the tests on a Java 7 machine:

Open the .classpath file and find the following line:

 <classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>

Replace the line with:

 <classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>

2. Add autodiscovering of the hamcrest imports. This will add intellisense entries when adding assertThat code

-. Add these favorite imports in Window » Preferences » Java » Editor » Content Assist » Favorites

Running Selenium

There are several ways of starting a Selenium server. It can be used locally (within the same machine as the Openbravo server) or on a different computer (remotely).

Local execution of Selenium.

Selenium can be run locally in two different ways. The easiest way is to change to the seleniumTools/ directory and run one of the standalone scripts. If the server is running but an exception is thrown every time a test is run, check if the exception mentions a missing chromedriver. If that’s the case, open the lib/test/ folder, copy the name of one of the chromedrivers there, edit the script used to start selenium and set the correct webdriver.chrome.driver parameter.

A second option to start Selenium locally is to run ant selenium.start from the test repo root. The chromedriver and seleniumdriver versions used will be taken from the OpenbravoERPTest.properties file.


Bulbgraph.png   In a modules environment it is required to remove the following file

modules/org.openbravo.certification.france/src/org/openbravo/certification/france/ticket/TicketInitialValidation.java

Remote execution of Selenium

Bulbgraph.png   We need 2 test repos for this execution tipe; one on the openbravo server (for the test files) and one on the remote computer (for the selenium files).

In order to execute Selenium in a different computer, we need to use the hub.sh and nodes.sh scripts.

On the remote computer (the one holding Selenium), open the nodes.json configuration file and change the host and hubHost values to 127.0.0.1.

Launch hub.js

Launch nodes.js

Write down the IP of the selenium-holding computer to configure the test repo.

On the local computer (the one with the openbravo server), open the OpenbravoERPTest.properties file and change the selenium.server property to the IP of the remote computer.

Open the ConfigurationProperties.java file, find the following line:

 return openbravoBaseURLTemp.replace(localhostReferenceToChange, ip.getHostAddress());

And change it to

 return openbravoBaseURLTemp.replace(localhostReferenceToChange, "local_ip_as_seen_on_the_lan");

local_ip_as_seen_on_the_lan is the IP of the computer with the openbravo server.

Now when a test is executed the browser will run on the remote machine. In order to run a test, simply right click on it and select Debug As > JUnit Test.

After finishing the tests, remember to terminate the Selenium server (either Ctrl+C the process, or run ant selenium.stop if ant was used to start the server).

Local Offline Execution

Setup offline execution

Bulbgraph.png   This option is included starting from 3.0PR16Q3

First of all, you need to install and configure different components. You will need to install Apache:

 sudo apt-get install apache2 libapache2-mod-jk

Then you have to edit or create /etc/apache2/conf-available/openbravo-jk-mount.conf adding this content:

 JkMount /* ajp13_worker
 jkMountCopy all

This will redirect all petitions from Apache to Tomcat, to enable this configuration:

 sudo a2enconf openbravo-jk-mount.conf

Finally, to be able to start/stop Apache from the tests, you need to execute these instructions without typing the root’s password. To make it possible, you have to edit sudoers file in order to grant the access. It can be done by using:

 sudo su -
 echo "openbravo ALL = NOPASSWD: /etc/init.d/apache2" > /etc/sudoers.d/97-ob-apache
 #Note: this command works for openbravo user, if you have a different user, replace it in previous line.

Now you can start/stop Apache manually through:

 sudo /etc/init.d/apache2 {start | stop}

Note: It should not ask for password.

Configuration and how to use offline

Note: If using the scripts no needed to do this part

After completing all these steps, you only have to edit the OpenbravoERPTest.properties and remove the port from openbravo.url:

 # Openbravo server properties
 openbravo.url=http://localhost/

All the test using offline features need to be included in the class AllowedErrorsHelper inside the method getTestsAllowedToHaveJavascriptErrors and the method getTestsAllowedToHaveTomcatErrors.

In the tests you can use these methods to go online and offline:

goOffline();
goOnline();

Note: this methods are defined in WebPOSTerminalHelper so should be available in all terminals.

Trick to test quick updates

Prerequisite to have configured the offline execution with apache.

To move quickly between two workspaces, for example when testing the update from one version to the other.

A trick could be create a script to change the port that uses mod-jk to connect apache to tomcat, for these needed to do these steps:

alias s1='sudo sed -i /etc/libapache2-mod-jk/workers.properties -e '\s/8109/8009/'\ && sudo /etc/init.d/apache2 restart'
alias s2='sudo sed -i /etc/libapache2-mod-jk/workers.properties -e '\s/8009/8109/'\ && sudo /etc/init.d/apache2 restart'

With this you can switch to workspace using these commands:

s1  // configure apache to use the first tomcat
s2  // configure apache to use the second tomcat

The application will be allways available at http://localhost/openbravo (no need to specify port, it will use default one :80 in which apache is listening)

Test Folder Structure

The tests are divided into two main subgroups. Those tests belonging to the package org.openbravo.test.mobile.retail.pack (“pack” tests) are the tests being run on the ret-*-test-* jobs, while the tests belonging to the org.openbravo.test.mobile.retail.extmodules package are the ones executed on ret-*-modules-* jobs.

Adding new tests to the “pack” tests

In order to add a new test to the pack tests, pick the most fitting area (returns, cashup, sales,...) and create a new java file there. Find a test of the same area and copy&paste it for a quick start. As long as the new test is inside an existing category, there is a mechanism that will automatically add that test to the respective suite when the suite is executed.

Adding a new test to the "modules" tests

The modules test are organized by module. Each module has its own suite. Unlike the pack tests, there isn’t a mechanism to add all the tests of a module into the suite; this process needs to be done manually. So for every new test added, it must be added to the corresponding suite manually.

Creating a new test

As already explained, the basic flow to create a test is copy&paste an existing similar test, and, using that as a base, add our test actions. This is done to ensure that the correct test class is extended: pack tests extend WebPOSTerminalHelper, while modules tests extend WebPOSExtModulesTerminalHelper (if they are POS tests) or other different terminals (procurement, mobile warehouse).

The TestId.java holds a mapping between the POS elements (buttons, labels, popups, messages, ...) and a unique name to be used within the tests. Each POS element is identified by a unique idtest[*]. This idtest is obtained on the browser console, using the TestRegistry javascript object. If we open the browser console and execute TestRegistry.appendIdTestToDOM() each element currently existing on the POS will be assigned an idtest property (if applicable). This idtest can be used on the TestId java class to identify the element.

[*]Note that due to some TestRegistry limitations, some elements can’t be assigned a unique idtest and therefore cannot be directly used from the tests.

Using a POS element in our test

Firstly we go to the POS, open the browser console and recover the idtest property of the element we want to use.

Then we go to the TestId class and look for our idtest. If it exists, we can al ready use the TestId.OUR_ELEMENT_NAME. If not, we create it.

Always try to create new TestIds near related TestIds. The syntax to create new TestId elements is: OUR_ELEMENT_NAME(“idtest”, [EnyoKind]).

EnyoKind is a helper class used to identify special elements (buttons, product rows,...). Go to the EnyoKind class to check all the available options.

Fixing an Unstable test

There are some tests that fails randomly and they are marked as "unstable" in the Test Status sheet(Google Spreadsheet). Follow these steps to fix an unstable test:

For any suggestion/help go directly to retail team.

Actions that can be performed on TestId elements

Currently tap, write, verify and get operations are supported.

Finally, the TestRegistry can also be used to get the enyoObject of an element on the browser console: TestRegistry.registry(‘idtest’).enyoObject

High volume automated test

Starting from RR15Q4, to support high volumes of products, customers and tickets, Openbravo Commerce allows you to work remotely with master data from the WebPOS client. The high volume master data is then not loaded into the WebPOS client database but accesses when needed on a server. The server can be a locally in-store server or a server available in the cloud.

To run a test in remote or high volume mode it is necessary to add the following annotation in the java class test:

 public class HighVolumeTest extends WebPOSTerminalHelper {
 @TestClassAnnotations(isHighVolumeCompatible = true)

When a test is running in high volume mode there is a method called "verifyHgvolTime" which checks that a specific action takes no more than some specific time, and the test fails if it takes too long. "verifyHgvolTime" function is called inside each "tap" action.

Hybrid remote automated test

Starting from RR18Q4, tests can activate some of high volumes preference to automate some scenarios which are not exactly a "pure" high volumes test.

To run a test with hybrid remote configuration it is necessary to implement in each java test class:

The preference defined for the test are set after the first login and are unset after the end of the test. If the testClassAnnotation is present but the activateRemoteModels method is not overrided or the array of remote model is null or is an empty array, the test will fail and will not be executed.

Other important topics to consider

The Constants.java file defines several values used all around the test project, such as timeouts or retry values.

Sometimes a test will fail because certain element hasn’t reached the required state. In this cases, increasing the WAIT_DEFAULT_RETRIES might work. Other interesting values to tweak might be:

Although the tests are prepared to be run with the application in development status (there is a test verifying that) they can be executed with the application in production (no modules in development).

If the tests fail because a javascript error regarding the Synchronization Helper and the dropTables process, it means that the dropTables process is taking more than 8 seconds, which is not necessarily wrong. Open the ob-synchronization.js file (in the org.openbravo.mobile.core module), find the following lines:

 OB.UTIL.Debug.execute(function () {
   // the timeout is forced active while in development to catch unbalanced calls and/or adjust the timeoutThreshold
   timeoutThreshold = 8000;
   isTimeoutThresholdActivated = true;
 });

and increase the timeoutThreshold value. Increasing this value will reduce the amount of “false failures” and will only slow the application in case of a real error (which should never happen anyway).

Authentication Managers and the tests

The authentication manager feature is not compatible with the tests. Firstly, it might try to login with wrong credentials (e.g. wrong POS organization). Besides, the first step of the tests is to automate the login, so they will fail if the login has already been done.

Throttle and the tests

After throttle changes random tests fail in try-retail, not able to fix all of them, we opted to disable the throttle in all ci servers.

This is just a workaround and plan is to enable again as soon as possible.

For the moment, to make a try-retail run with the throttle enabled is needed to use an extra param ACTIVATE_THROTTLE=true in the push a try-retail.

For more details this is the issue: https://issues.openbravo.com/view.php?id=37416


Howto add a new module to the Retail Integration

First: create a new json copy of the try-retail one, plus your new module and push to try-retail.


After test it, for put in production it is needed to update 3 jsons:


Ensure that each json format is correct after edit, passing a json formater.


IMPORTANT

How to add a new junit to retail

If it is a junit for the pack can be executed in try-retail, but if it needs the external modules, for the moment can not be executed in try-retail and can be only executed in mod-retail.

To add a junit suite to mod-retail:

Check list of actions on release package

Add new tables to sample data

When a new feature is developed, a common requirement while developing a set of automatic tests is to create new sample data for tables added by the new feature.

Here you can find the steps required to add new tables to the sample data.

Logged as system administrator:

  1. Open "Module" window and mark module "Core" as "In development"
  2. Open Dataset Window and search the dataset by "Client definition"
  3. Open it in form view and change the value of the property "Data Access Level" from "System Only" to "Client/organization"
  4. Having "Client definition" selected move to the tab "Table"
  5. Add new registry with the new table
    1. Remember to set the value of the "Module" property with the module which is owner of that table
    2. Property "HQL/SQL Where clause" should have the following value "client.id=:ClientID"
    3. In general, all the columns of the table will be added to the sample data so we will check the property "Include All Columns". In the strange case that you don't want to include all the columns in the sample data then this check will be unmarked and columns should be specified in "Column" child tab
  6. Repeat step 5 until you have added all of your tables.
  7. Return to the header "Client definition" and revert the change done in step 3
  8. Return to "Modules" window and revert the change done in step 1
  9. Stop tomcat
  10. Finally, Execute
ant export.database

Once executed, check changes in your module's file "src-db/database/sourcedata/AD_DATASET_TABLE.xml" and push your changes

Now you can create new data in the new tables and then execute "export" commands which are explained below.

Export retail sampledata

ant export.sample.data -Dclient="The White Valley Group" -Dmodule=org.openbravo.retail.sampledata
ant export.sample.data -Dclient="The White Valley Group" -Dmodule=org.openbravo.test.mobile.sampledata
ant export.sample.data -Dclient="Retail Test" -Dmodule=org.openbravo.retail.testsampledata

Setup SSL

For retail is mandatory to use always ssl, only exception is localhost (or 127.*.*.*)

For testing is posible to use the self signed certificate created by apache on install, to do that:

first step, do the apache setup
sudo a2enmod ssl
sudo a2ensite default-ssl.conf
sudo /etc/init.d/apache2 restart

The URL for access with ssl: https://ip/... (note that is not needed to specify a port)

Setup axisc3 for development

axisc3 guide: http://wiki.openbravo.com/wiki/Retail:AXISC3_Payment_Provider

Retrieved from "http://wiki.openbravo.com/wiki/Retail:Developers_Guide/How-to/How_to_Install,_Setup_and_Run_Retail_Automated_Tests"

This page has been accessed 19,202 times. This page was last modified on 18 November 2021, at 16:50. Content is available under Creative Commons Attribution-ShareAlike 2.5 Spain License.