Restoring the OCR – 12.2

Backup currently active OCR 
[root@dsctw21 peer]# ocrconfig -manualbackup
dsctw21     2017/05/21 09:07:10     +MGMT:/dsctw/OCRBACKUP/backup_20170521_090710.ocr.292.944557631     0     
[root@dsctw21 peer]#  ocrconfig -showbackup
PROT-24: Auto backups for the Oracle Cluster Registry are not available
dsctw21     2017/05/21 09:07:10     +MGMT:/dsctw/OCRBACKUP/backup_20170521_090710.ocr.292.944557631     0   

Locate all OCR backups 
ASMCMD> find --type OCRBACKUP / *
+MGMT/dsctw/OCRBACKUP/14348721.293.944515403
+MGMT/dsctw/OCRBACKUP/backup_20170521_090710.ocr.292.944557631
ASMCMD> ls -l +MGMT/dsctw/OCRBACKUP/14348721.293.944515403
Type       Redund  Striped  Time             Sys  Name
OCRBACKUP  UNPROT  COARSE   MAY 20 21:00:00  Y    14348721.293.944515403
ASMCMD> ls -l +MGMT/dsctw/OCRBACKUP/backup_20170521_090710.ocr.292.944557631
Type       Redund  Striped  Time             Sys  Name
OCRBACKUP  UNPROT  COARSE   MAY 21 09:00:00  Y    backup_20170521_090710.ocr.292.944557631

--> Note the first backup was created by root.sh !
    After a GNS corruption we need to restore to the OCR created by root.sh

List the nodes and cluster resources in your cluster by running the following command on one node:
[grid@dsctw21 ~]$ olsnodes
dsctw21
dsctw22

[grid@dsctw21 ~]$ crs
*****  Cluster Resources: *****
Resource NAME               INST   TARGET       STATE        SERVER          STATE_DETAILS
--------------------------- ----   ------------ ------------ --------------- -----------------------------------------
ora.LISTENER_SCAN1.lsnr        1   ONLINE       ONLINE       dsctw22         STABLE  
ora.LISTENER_SCAN2.lsnr        1   ONLINE       ONLINE       dsctw21         STABLE  
ora.LISTENER_SCAN3.lsnr        1   ONLINE       ONLINE       dsctw21         STABLE  
ora.MGMTLSNR                   1   ONLINE       ONLINE       dsctw21         169.254.156.94 192.1 68.2.151,STABLE
ora.asm                        1   ONLINE       ONLINE       dsctw21         Started,STABLE  
ora.asm                        2   ONLINE       ONLINE       dsctw22         Started,STABLE  
ora.asm                        3   OFFLINE      OFFLINE      -               STABLE  
ora.cvu                        1   ONLINE       ONLINE       dsctw21         STABLE  
ora.dsctw21.vip                1   ONLINE       ONLINE       dsctw21         STABLE  
ora.dsctw22.vip                1   ONLINE       ONLINE       dsctw22         STABLE  
ora.gns                        1   ONLINE       ONLINE       dsctw21         STABLE  
ora.gns.vip                    1   ONLINE       ONLINE       dsctw21         STABLE  
ora.ioserver                   1   ONLINE       ONLINE       dsctw21         STABLE  
ora.ioserver                   2   ONLINE       ONLINE       dsctw22         STABLE  
ora.ioserver                   3   ONLINE       OFFLINE      -               STABLE  
ora.mgmtdb                     1   ONLINE       ONLINE       dsctw21         Open,STABLE  
ora.qosmserver                 1   ONLINE       ONLINE       dsctw21         STABLE  
ora.rhpserver                  1   ONLINE       ONLINE       dsctw21         STABLE  
ora.scan1.vip                  1   ONLINE       ONLINE       dsctw22         STABLE  
ora.scan2.vip                  1   ONLINE       ONLINE       dsctw21         STABLE  
ora.scan3.vip                  1   ONLINE       ONLINE       dsctw21         STABLE  

If OCR is located in an Oracle ASM disk group, then stop the Oracle Clusterware daemon:
[root@dsctw21 ~]# crsctl stop crs 
[root@dsctw22 ~]# crsctl stop crs 
  
Start the Oracle Clusterware stack on one node in exclusive mode by running the following command as root:
[root@dsctw21 ~]#  crsctl start crs -excl -nocrs

The -nocrs option ensures that the CRSD process and OCR do not start with the rest of the Oracle Clusterware stack.

Ignore any errors that display.
Check whether CRSD is running by running the following command:
[root@dsctw21 ~]# crsi

*****  Local Resources: *****
Resource NAME               INST   TARGET       STATE        SERVER          STATE_DETAILS
--------------------------- ----   ------------ ------------ --------------- -----------------------------------------
ora.asm                        1   ONLINE       ONLINE       dsctw21         Started,STABLE  
ora.cluster_interconnect.haip  1   ONLINE       ONLINE       dsctw21         STABLE  
ora.crf                        1   OFFLINE      OFFLINE      -               STABLE  
ora.crsd                       1   OFFLINE      OFFLINE      -               STABLE  
ora.cssd                       1   ONLINE       ONLINE       dsctw21         STABLE  
ora.cssdmonitor                1   ONLINE       ONLINE       dsctw21         STABLE  
ora.ctssd                      1   ONLINE       ONLINE       dsctw21         OBSERVER,STABLE  
ora.diskmon                    1   OFFLINE      OFFLINE      -               STABLE  
ora.driver.afd                 1   ONLINE       ONLINE       dsctw21         STABLE  
ora.drivers.acfs               1   ONLINE       ONLINE       dsctw21         STABLE  
ora.evmd                       1   ONLINE       INTERMEDIATE dsctw21         STABLE  
ora.gipcd                      1   ONLINE       ONLINE       dsctw21         STABLE  
ora.gpnpd                      1   ONLINE       ONLINE       dsctw21         STABLE  
ora.mdnsd                      1   ONLINE       ONLINE       dsctw21         STABLE  
ora.storage                    1   OFFLINE      OFFLINE      -               STABLE  


    If CRSD is running, then stop it by running the following command as root:
    # crsctl stop resource ora.crsd -init

   
Locate all OCR backups 
ASMCMD> find --type OCRBACKUP / *
+MGMT/dsctw/OCRBACKUP/14348721.293.944515403
+MGMT/dsctw/OCRBACKUP/backup_20170521_090710.ocr.292.944557631
ASMCMD> ls -l +MGMT/dsctw/OCRBACKUP/14348721.293.944515403
Type       Redund  Striped  Time             Sys  Name
OCRBACKUP  UNPROT  COARSE   MAY 20 21:00:00  Y    14348721.293.944515403
ASMCMD> ls -l +MGMT/dsctw/OCRBACKUP/backup_20170521_090710.ocr.292.944557631
Type       Redund  Striped  Time             Sys  Name
OCRBACKUP  UNPROT  COARSE   MAY 21 09:00:00  Y    backup_20170521_090710.ocr.292.944557631

Restore OCR with an OCR backup that you can identify in "Listing Backup Files" by running the following command as root:
[root@dsctw21 ~]# ocrconfig -restore +MGMT/dsctw/OCRBACKUP/14348721.293.944515403

    Note:
        If the original OCR location does not exist, then you must create an empty (0 byte) OCR location before 
        you run the ocrconfig -restore command.
        Ensure that the OCR devices that you specify in the OCR configuration exist and that these OCR devices are valid.
        If you configured OCR in an Oracle ASM disk group, then ensure that the Oracle ASM disk group exists and is mounted.
        If the OCR backup file is located in an Oracle ASM disk group, then ensure that the disk group exists and is mounted.

[root@dsctw21 ~]# ocrcheck
Status of Oracle Cluster Registry is as follows :
     Version                  :          4
     Total space (kbytes)     :     409568
     Used space (kbytes)      :       3992
     Available space (kbytes) :     405576
     ID                       : 2008703361
     Device/File Name         :      +DATA
                                    Device/File integrity check succeeded
                                    Device/File not configured
                                    Device/File not configured
                                    Device/File not configured
                                    Device/File not configured
     Cluster registry integrity check succeeded
     Logical corruption check succeeded

[root@dsctw21 ~]# crsctl stop crs -f
    
    Run the ocrconfig -repair -replace command as root on all the nodes in the cluster where you did not the 
    ocrconfig -restore command. For example, if you ran the ocrconfig -restore command on node 1 of a four-node 
    cluster, then you must run the ocrconfig -repair -replace command on nodes 2, 3, and 4.

Begin to start Oracle Clusterware by running the following command as root on all of the nodes:
[root@dsctw21 ~]#  crsctl start crs
[root@dsctw22 ~]#  crsctl start crs

Verify OCR integrity of all of the cluster nodes that are configured as part of your cluster by running the following CVU command:
[grid@dsctw21 ~]$  cluvfy comp ocr -n all -verbose
Verifying OCR Integrity ...PASSED
Verification of OCR integrity was successful. 
CVU operation performed:      OCR integrity
Date:                         May 21, 2017 8:13:54 PM
CVU home:                     /u01/app/122/grid/
User:                         grid

Verify cluster resources 
[root@dsctw22 ~]#  crs
*****  Cluster Resources: *****
Resource NAME               INST   TARGET       STATE        SERVER          STATE_DETAILS
--------------------------- ----   ------------ ------------ --------------- -----------------------------------------
ora.LISTENER_SCAN1.lsnr        1   ONLINE       ONLINE       dsctw22         STABLE  
ora.LISTENER_SCAN2.lsnr        1   ONLINE       ONLINE       dsctw21         STABLE  
ora.LISTENER_SCAN3.lsnr        1   ONLINE       ONLINE       dsctw21         STABLE  
ora.MGMTLSNR                   1   ONLINE       ONLINE       dsctw21         169.254.156.94 192.1 68.2.151,STABLE
ora.asm                        1   ONLINE       ONLINE       dsctw21         Started,STABLE  
ora.asm                        2   ONLINE       ONLINE       dsctw22         Started,STABLE  
ora.asm                        3   OFFLINE      OFFLINE      -               STABLE  
ora.cvu                        1   ONLINE       ONLINE       dsctw21         STABLE  
ora.dsctw21.vip                1   ONLINE       ONLINE       dsctw21         STABLE  
ora.dsctw22.vip                1   ONLINE       ONLINE       dsctw22         STABLE  
ora.gns                        1   ONLINE       ONLINE       dsctw21         STABLE  
ora.gns.vip                    1   ONLINE       ONLINE       dsctw21         STABLE  
ora.ioserver                   1   ONLINE       ONLINE       dsctw21         STABLE  
ora.ioserver                   2   ONLINE       ONLINE       dsctw22         STABLE  
ora.ioserver                   3   ONLINE       OFFLINE      -               STABLE  
ora.mgmtdb                     1   ONLINE       ONLINE       dsctw21         Open,STABLE  
ora.qosmserver                 1   ONLINE       ONLINE       dsctw21         STABLE  
ora.rhpserver                  1   ONLINE       ONLINE       dsctw21         STABLE  
ora.scan1.vip                  1   ONLINE       ONLINE       dsctw22         STABLE  
ora.scan2.vip                  1   ONLINE       ONLINE       dsctw21         STABLE  
ora.scan3.vip                  1   ONLINE       ONLINE       dsctw21         STABLE

Cleanup a failed 12.2 GRID installation

Cleanup GRID resources and directories

Log in as the root user on a node where you encountered an error.
Change directory to Grid_home/crs/install. For example:
Run rootcrs.sh with the -deconfig and -force flags. For example:

[root@dsctw21 ~]# export GRID_HOME=/u01/app/122/grid
[root@dsctw22 ~]# $GRID_HOME/crs/install/rootcrs.sh -verbose -deconfig -force

Repeat on other nodes as required.
If you are deconfiguring Oracle Clusterware on all nodes in the cluster, then on the last node, enter the following command:

[root@dsctw21 ~]# export GRID_HOME=/u01/app/122/grid
[root@dsctw21 ~]# $GRID_HOME/crs/install/rootcrs.sh -verbose -deconfig -force -lastnode

The -lastnode flag completes deconfiguration of the cluster, including the OCR and voting files.

Current Settings
ORACLE_BASE=/u01/app/grid
ORACLE_HOME=/u01/app/122/grid

Remove oraInventory Files
[root@dsctw21 oraInventory]# rm -rf  /u01/app/oraInventory/*

Remove Files from ORACLE_BASE, ORACLE_HOME
[root@dsctw21 ~]# rm -rf /u01/app/grid/*
[root@dsctw21 ~]# rm -rf /u01/app/122/grid/*

Remove above files/directories on the 2.nd node too !

[root@dsctw21 grid]# chown  grid:oinstall /u01/app/122/grid
[root@dsctw21 grid]# chown  grid:oinstall /u01/app/grid
[root@dsctw21 grid]# chown  grid:oinstall /u01/app/oraInventory/

[root@dsctw22 oraInventory]# chown  grid:oinstall /u01/app/122/grid
[root@dsctw22 oraInventory]# chown  grid:oinstall /u01/app/grid
[root@dsctw22 oraInventory]# chown  grid:oinstall /u01/app/oraInventory/

Verify directories
[root@dsctw21 ~]# ls  -lasi /u01/app/122/grid
total 0
33595586 0 drwxr-xr-x. 2 grid oinstall  6 May  4 15:49 .
50331840 0 drwxr-xr-x. 3 root oinstall 17 May  4 15:49 ..
[root@dsctw22 ~]#  ls  -lasi /u01/app/122/grid
total 0
33595586 0 drwxr-xr-x. 2 grid oinstall  6 May  4 15:49 .
50331840 0 drwxr-xr-x. 3 root oinstall 17 May  4 15:49 ..
.....

Cleanup our ASM Disks

On Node 1 run 
[root@dsctw21 ~]# ./cleanupASM_Disks.sh
Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 
..
brw-rw----. 1 root disk     8,   0 May  5 07:36 /dev/sda
brw-rw----. 1 root disk     8,   1 May  5 07:36 /dev/sda1
brw-rw----. 1 root disk     8,   2 May  5 07:36 /dev/sda2
brw-rw----. 1 grid asmadmin 8,  16 May  5 08:21 /dev/sdb
brw-rw----. 1 grid asmadmin 8,  32 May  5 08:21 /dev/sdc
brw-rw----. 1 grid asmadmin 8,  48 May  5 08:21 /dev/sdd
brw-rw----. 1 grid asmadmin 8,  64 May  5 08:21 /dev/sde
brw-rw----. 1 grid asmadmin 8,  80 May  5 08:21 /dev/sdf
brw-rw----. 1 grid asmadmin 8,  96 May  5 08:21 /dev/sdg
brw-rw----. 1 grid asmadmin 8, 112 May  5 08:21 /dev/sdh
brw-rw----. 1 root disk     8, 128 May  5 07:36 /dev/sdi
brw-rw----. 1 root disk     8, 129 May  5 07:36 /dev/sdi1

On Node 2 just run 
[root@dsctw22 ~]# ./modifyASM_Disks.sh
Model: ATA VBOX HARDDISK (scsi)
Disk /dev/sdb: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 
....
brw-rw----. 1 root disk     8,   0 May  5 07:22 /dev/sda
brw-rw----. 1 root disk     8,   1 May  5 07:22 /dev/sda1
brw-rw----. 1 root disk     8,   2 May  5 07:22 /dev/sda2
brw-rw----. 1 grid asmadmin 8,  16 May  5 08:25 /dev/sdb
brw-rw----. 1 grid asmadmin 8,  32 May  5 08:25 /dev/sdc
brw-rw----. 1 grid asmadmin 8,  48 May  5 08:25 /dev/sdd
brw-rw----. 1 grid asmadmin 8,  64 May  5 08:25 /dev/sde
brw-rw----. 1 grid asmadmin 8,  80 May  5 08:25 /dev/sdf
brw-rw----. 1 grid asmadmin 8,  96 May  5 08:25 /dev/sdg
brw-rw----. 1 grid asmadmin 8, 112 May  5 07:25 /dev/sdh
brw-rw----. 1 root disk     8, 128 May  5 07:22 /dev/sdi
brw-rw----. 1 root disk     8, 129 May  5 07:22 /dev/sdi1

Note protections on both nodes should be identical !

Scripts used in this article

[root@dsctw21 ~]# cat  cleanupASM_Disks.sh
parted /dev/sdb mklabel msdos
parted /dev/sdc mklabel msdos
parted /dev/sdd mklabel msdos
parted /dev/sde mklabel msdos
parted /dev/sdf mklabel msdos
parted /dev/sdg mklabel msdos
parted /dev/sdh mklabel msdos

parted /dev/sdb print
parted /dev/sdc print
parted /dev/sdd print
parted /dev/sde print
parted /dev/sdf print
parted /dev/sdg print
parted /dev/sdh print
./modifyASM_Disks.sh

[root@dsctw21 ~]# cat  modifyASM_Disks.sh
parted /dev/sdb print
parted /dev/sdc print
parted /dev/sdd print
parted /dev/sde print
parted /dev/sdf print
parted /dev/sdg print
parted /dev/sdh print

chmod 660 /dev/sdb
chmod 660 /dev/sdc
chmod 660 /dev/sdd
chmod 660 /dev/sde
chmod 660 /dev/sdf
chmod 660 /dev/sdg
chmod 660 /dev/sdh

chown grid:asmadmin /dev/sdb
chown grid:asmadmin /dev/sdc
chown grid:asmadmin /dev/sdd
chown grid:asmadmin /dev/sde
chown grid:asmadmin /dev/sdf
chown grid:asmadmin /dev/sdg
chown grid:asmadmin /dev/sdh

ls -l /dev/sd*

Convert a administrator managed RAC database to policy managed [ 12.2 ]

Check Database and Pool Status

Check RAC database status
[grid@ractw21 ~]$   srvctl config database -d ractw
Database unique name: ractw
Database name: ractw
Oracle home: /u01/app/oracle/product/122/ractw2
Oracle user: oracle
Spfile: +DATA/RACTW/PARAMETERFILE/spfile.325.941894301
Password file: +DATA/RACTW/PASSWORD/pwdractw.284.941893247
Domain: example.com
Start options: open
Stop options: immediate
Database role: PRIMARY
Management policy: AUTOMATIC
Server pools: 
Disk Groups: DATA
Mount point paths: 
Services: 
Type: RAC
Start concurrency: 
Stop concurrency: 
OSDBA group: dba
OSOPER group: 
Database instances: ractw1,ractw2
Configured nodes: ractw21,ractw22
CSS critical: no
CPU count: 0
Memory target: 0
Maximum memory: 0
Default network number for database services: 
Database is administrator managed

Check pool status 
[oracle@ractw21 ~]$  srvctl status srvpool -a
Server pool name: Free
Active servers count: 0
Active server names: 
Server pool name: Generic
Active servers count: 2
Active server names: ractw21,ractw22
NAME=ractw21 STATE=ONLINE
NAME=ractw22 STATE=ONLINE

Convert Database to Policy Managed

Stop database,add RAC database to pool and finally check pool status [grid@ractw21 grid]$ srvctl stop database -d ractw
[grid@ractw21 grid]$ srvctl add srvpool -g TopPriority  -l 1 -u 2 -i 5
[grid@ractw21 grid]$ srvctl modify database -d ractw -g TopPriority
                        
PRCD-1130 : Failed to convert administrator-managed database ractw into a policy-managed database to use server pool TopPriority
PRCR-1071 : Failed to register or update resource ora.ractw.db
CRS-0245:  User doesn't have enough privilege to perform the operation

Run as user Oracle :
[oracle@ractw21 ~]$ srvctl modify database -d ractw -g TopPriority

[grid@ractw21 grid]$ srvctl config  srvpool -g TopPriority
Server pool name: TopPriority
Importance: 5, Min: 1, Max: 2
Category: hub
Candidate server names: 

[grid@ractw21 grid]$  srvctl config  database -d ractw
Database unique name: ractw
Database name: ractw
Oracle home: /u01/app/oracle/product/122/ractw2
Oracle user: oracle
Spfile: +DATA/RACTW/PARAMETERFILE/spfile.325.941894301
Password file: +DATA/RACTW/PASSWORD/pwdractw.284.941893247
Domain: example.com
Start options: open
Stop options: immediate
Database role: PRIMARY
Management policy: AUTOMATIC
Server pools: TopPriority
Disk Groups: DATA
Mount point paths: 
Services: 
Type: RAC
Start concurrency: 
Stop concurrency: 
OSDBA group: dba
OSOPER group: 
Database instances: 
Configured nodes: 
CSS critical: no
CPU count: 0
Memory target: 0
Maximum memory: 0
Default network number for database services: 
Database is policy managed

[oracle@ractw21 ~]$ srvctl start database -d ractw
PRCR-1079 : Failed to start resource ora.ractw.db
CRS-2643: The server pool(s) where resource 'ora.ractw.db' could run have no servers

Remove category and add servers 

Trying to add servers 
[grid@ractw21 ~]$ srvctl modify srvpool -serverpool TopPriority  -servers  "ractw21,ractw22" -verbose
[grid@ractw21 ~]$ srvctl config srvpool -serverpool TopPriority 
Server pool name: TopPriority
Importance: 5, Min: 1, Max: 2
Category: 
Candidate server names: ractw21,ractw22

[grid@ractw21 ~]$  srvctl status srvpool -a
Server pool name: Free
Active servers count: 0
Active server names: 
Server pool name: Generic
Active servers count: 2
Active server names: ractw21,ractw22
NAME=ractw21 STATE=ONLINE
NAME=ractw22 STATE=ONLINE
Server pool name: TopPriority
Active servers count: 0
Active server names: 

Both severs  ractw21,ractw22 still assigned to GENERIC pool !

Removing our admin managed test database ! 
[oracle@ractw21 ~]$ srvctl remove database -db test
Remove the database test? (y/[n]) y

Verify Database Status and Pool Status after changes

Now verify pool 
[grid@ractw21 ~]$  srvctl status srvpool -a
Server pool name: Free
Active servers count: 0
Active server names: 
Server pool name: Generic
Active servers count: 0
Active server names: 
Server pool name: TopPriority
Active servers count: 2
Active server names: ractw21,ractw22
NAME=ractw21 STATE=ONLINE
NAME=ractw22 STATE=ONLINE
--> Now both servers are assigned to our TopPriority pool 

Starting ractw database and confirm cluster resource status
[oracle@ractw21 dbs]$ srvctl start  database -db ractw

*****  Cluster Resources: *****
Resource NAME               INST   TARGET    STATE        SERVER          STATE_DETAILS
--------------------------- ----   ------------ ------------ --------------- -----------------------------------------
ora.ractw.db                   1   ONLINE    ONLINE       ractw21         Open,HOME=/u01/app/oracle/product/122/ractw2,STABLE
ora.ractw.db                   2   ONLINE    ONLINE       ractw22         Open,HOME=/u01/app/oracle/product/122/ractw2,STABLE

Installing Dtrace on OEL 7.3

 # yum install dtrace-modules-4.1.12-61.1.33.el7uek.x86_64
 # yum install dtrace-modules-provider-headers.x86_64 0.5.3-2.el7     
 # yum install libdtrace-ctf-devel.x86_64 

[root@ractw21 OEL73]# rpm -ihv dtrace-utils-devel-0.5.1-3.el7.x86_64.rpm  dtrace-utils-0.5.1-3.el7.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:dtrace-utils-0.5.1-3.el7         ################################# [ 50%]
   2:dtrace-utils-devel-0.5.1-3.el7   ################################# [100%]

[root@ractw21 OEL73]# dtrace -l
   ID   PROVIDER            MODULE                          FUNCTION NAME
    1     dtrace                                                     BEGIN
    2     dtrace                                                     END
    3     dtrace                                                     ERROR
[root@ractw21 OEL73]# modprobe systrace
[root@ractw21 OEL73]# dtrace -l | more
   ID   PROVIDER            MODULE                          FUNCTION NAME
    1     dtrace                                                     BEGIN
    2     dtrace                                                     END
    3     dtrace                                                     ERROR
    4    syscall           vmlinux                              read entry
    5    syscall           vmlinux                              read return
    6    syscall           vmlinux                             write entry
    7    syscall           vmlinux                             write return
    8    syscall           vmlinux                              open entry
....

Reference

Using Recursions and Closures

  • Note: Use setTimeout to avoid Error Call Stack Size Exceeded
  • JavaScript Code:
cPanel.scheduleMapsSliderStatus = function (rc, func) {
    var runCount = rc;
    var funcName = 'scheduleMapsSliderStatus()';
    var logHeader = myControlPanel.getLogHeaderCF(funcName, func);

    var slideShowStatusSummaryField =  myObjects.getPanel("slideShowStatusSummaryField");
    var bgColor = slideShowStatusSummaryField.css('background-color');
    var fgColor =  slideShowStatusSummaryField.css('color');
    
    function MapsSliderStatusClosure() {
        var mesgFlag = runCount % 2;
        var panelMode = myControlPanel.getPanelMode(funcName);
        var slideShowStatusSummaryField = null;
        if (mesgFlag === 0) {
            updateSliderStatus("Click on PLAY button to start Animation! ");
                // Need to reread slideShowStatusSummaryField Objects as this is recreated by  updateSliderStatus()
            slideShowStatusSummaryField =  myObjects.getPanel("slideShowStatusSummaryField");
            slideShowStatusSummaryField.css('background-color', bgColor);

        } else {
            updateSliderStatus("Click on GREEN Marker to start Slideshow !");
                // Need to reread slideShowStatusSummaryField Objects as this is recreated by  updateSliderStatus()
            slideShowStatusSummaryField =  myObjects.getPanel("slideShowStatusSummaryField");
            slideShowStatusSummaryField.css('background-color', 'green');
        }
        if (runCount === 10 ) {   // run this Animation ONLY 10x
            return;
         }
        if (panelMode === "maps") { // Don't schedule again if panelMode !='maps'
            runCount++;
            setTimeout(MapsSliderStatusClosure, 2000, runCount, funcName)
        }
    };
    MapsSliderStatusClosure();   // Just all the closure function a first time
};

 

 

Copy a Maven based JPA project to new project folder

New Project Details

ArtifactId                   : WFJPA2PC
New Project Home             : /home/oracle/NetBeansProjects/GIT/WFJPA2PC 
New persistence.xml location :  /home/oracle/NetBeansProjects/GIT/WFJPA2PC/src/main/resources/META-INF/persistence.xml Your old and working project should have a working pom.xml and persistence.xml 

Modify and copy pom,xml

Modify artifactId and name in your pom.xml 
    <artifactId>WFJPA2PC</artifactId>
    <name>WFJPA2PC</name>

Copy pom.xml to your new Project Folder 
$ cp pom.xml   /home/oracle/NetBeansProjects/GIT/WFJPA2PC

Add JSF support to our project 
Project -> Properties -> Framework -> Add JavaServerFaces 
                                   -> Components -> PrimeFaces 

Create new Entity Classes

Create new Entity Classes as needed [ in our sample we use Entity Class : Accounts 

Source package -> New -> EnititY Class form Database 
  -> Select Datasource 
  -> Select Table Name : Accounts  
  -> Add 
  -> Finish 

Create a new JPA persistence.xml and copy over the working persistence.xml

Netbeans : File -> NEW ->  Persistence Unit 

Locate your Persistence Location of persistence.xml:
  /home/oracle/NetBeansProjects/GIT/WFJPA2PC/src/main/resources/META-INF/persistence.xml

-> Copy over your new RAC XA persistence.xml to   src/main/resources/META-INF/persistence.xml
   and add your newly created Entitly Classes    

Sample for a Hibernate persistence.xml with Entity Class : Accounts
<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">

    <persistence-unit name="RacBankAHibPU" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:/jboss/datasources/xa_rac12g_banka</jta-data-source>
        <class>com.hhu.wfjpa2pc.Accounts</class>
        <properties>
            <property name="hibernate.transaction.jta.platform"
                 value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
            <property name="hibernate.show_sql" value="true" />
        </properties>
</persistence>

Connection timeout message when running nslookup against GNS SCAN Address

Nslookup Error
[root@ns1 named]#  nslookup grac4-scan.grid4.example.com
;; connection timed out; trying next origin
Server:        192.168.5.50
Address:    192.168.5.50#53
** server can't find grac4-scan.grid4.example.com: NXDOMAIN

/var/log/messages of the BIND Nameserver  contains  a lot of IPV6 related errors 
  using GNS host : GNSTESTHOST 
..
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 202.12.27.33#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:503:ba3e::2:30#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 2001:503:ba3e::2:30#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:500:2::c#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 2001:500:2::c#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:500:2d::d#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 2001:500:2d::d#53
....
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:dc3::35#53
Jun 24 15:19:08 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/AAAA/IN': 2001:dc3::35#53
Jun 24 15:19:18 ns1 named[7529]: error (network unreachable) resolving 'GNSTESTHOST.grid4.example.com.de.oracle.com/A/IN': 2001:502:f3ff::64#53

-> All the failed IVPV6 requests add a delay for the request and leads to the nslookup Timeout
-> As our network can't handle IPV6 we need to disable IVP6. 

FIX : Disable ipv6 on CentOS 6/7 / RHEL 6/7 

Edit the /etc/sysctl.conf.
# vi /etc/sysctl.conf
Put the following entry to disable IPv6 for all adapter.
net.ipv6.conf.all.disable_ipv6 = 1

[root@ns1 named]#  ifconfig eth1
eth1      Link encap:Ethernet  HWaddr 08:00:27:2B:5E:DD
          inet addr:192.168.5.50  Bcast:192.168.5.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2171 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1461 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:159819 (156.0 KiB)  TX bytes:185391 (181.0 KiB)
-> No IPV6 reference anymore 

After disabling IPV6 only very less named records should be logged in /var/log/messages : 
Jun 24 15:49:07 ns1 named[3152]: zone 2.168.192.in-addr.arpa/IN: sending notifies (serial 2009011201)
Jun 24 15:49:07 ns1 named[3152]: zone 5.168.192.in-addr.arpa/IN: sending notifies (serial 2009011201)
Jun 24 15:50:45 ns1 named[3152]: error (FORMERR) resolving 'GNSTESTHOST.grid4.example.com/AAAA/IN': 192.168.5.54#53
Jun 24 16:00:48 ns1 named[3152]: error (FORMERR) resolving 'GNSTESTHOST.grid4.example.com/AAAA/IN': 192.168.5.54#53
Jun 24 16:10:50 ns1 named[3152]: error (FORMERR) resolving 'GNSTESTHOST.grid4.example.com/AAAA/IN': 192.168.5.54#53
Jun 24 16:16:52 ns1 named[3152]: client 192.168.5.101#29873: RFC 1918 response from Internet for 5.1.168.192.in-addr.arpa
...

Nslookup should now  work fine 
[root@ns1 log]#  nslookup grac4-scan.grid4.example.com
Server:        192.168.5.50
Address:    192.168.5.50#53

Non-authoritative answer:
Name:    grac4-scan.grid4.example.com
Address: 192.168.5.200
Name:    grac4-scan.grid4.example.com
Address: 192.168.5.165
Name:    grac4-scan.grid4.example.com
Address: 192.168.5.166

How to fix a RAC database startup problem with orachk in 5 minutes ?

New TFA Collector bundles ORAchk and other RAC tools

TFA Collector Features

Installation of TFA Lite /  ORACHK

Note orachk is now bundled with TFA collector  
Use the MOS article below to download TFA collector 
    TFA Collector - Tool for Enhanced Diagnostic Gathering (Doc ID 1513912.2)

Extract and install orachk as root user 
root@grac41 t]# ls
installTFALite  TFACollectorDocV121250.pdf  TFALite_121250.zip
[root@grac41 t]# ./installTFALite
Starting TFA installation
Enter a location for installing TFA (/tfa will be appended if not supplied) [/home/oracle/t/tfa]: 
/home/oracle/TFA
...
---------------------------------.
|            TFA Users            |
+-----------+-----------+---------+
| User Name | User Type | Status  |
+-----------+-----------+---------+
| asmadmin  | GROUP     | Allowed |
| grid      | USER      | Allowed |
| oinstall  | GROUP     | Allowed |
| oracle    | USER      | Allowed |
'-----------+-----------+---------'
Summary of TFA Installation:
.------------------------------------------------------------.
|                           grac41                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac41/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
.------------------------------------------------------------.
|                           grac42                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac42/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
.------------------------------------------------------------.
|                           grac43                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac43/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
TFA is successfully installed...

 

Problem description

 
Either starting RAC instance with sqlplus or srvctl fails with errors :  

[oracle@grac43 dbs]$  sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Tue Jun 23 13:01:15 2015
Copyright (c) 1982, 2013, Oracle.  All rights reserved.
Connected to an idle instance.
SQL>  startup nomount
ORA-01078: failure in processing system parameters
ORA-01565: error in identifying file '+DATA/grac4/spfilegrac4.ora'
ORA-17503: ksfdopn:2 Failed to open file +DATA/grac4/spfilegrac4.ora
ORA-01034: ORACLE not available
ORA-27123: unable to attach to shared memory segment
Linux-x86_64 Error: 13: Permission denied
Additional information: 26
Additional information: 229382

Run Orack and review the HTML file for Errors and Warnings


[root@grac41 orachk]# ./orachk -v
ORACHK  VERSION: 12.1.0.2.3_20150305

[root@grac41 orachk]# ./orachk
CRS stack is running and CRS_HOME is not set. Do you want to set CRS_HOME to /u01/app/11204/grid?[y/n][y]


Check generated HTML file for WARNINGS and ERRORS 
..
Cluster Wide Status 
WARNING => RDBMS software owner UID does not match across cluster

DATA FROM GRAC41 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),506(asmdba)

DATA FROM GRAC42 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),506(asmdba)

DATA FROM GRAC43 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=501(grid) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),504(asmadmin),506(asmdba),507(asmoper) 

-> Here we see easily can see  that uid on GRAC43 is wrong  

Fix the error and verify database status  
[root@grac43 bin]# chown oracle oracle
[root@grac43 bin]# chmod 6751 oracle
[root@grac43 bin]# ls -l oracle
-rwsr-s--x. 1 oracle asmadmin 239732402 Jul 21  2014 oracle
[grid@grac43 ~]$ srvctl start instance -d grac4 -i grac43
[oracle@grac43 dbs]$ srvctl status database -d grac4
Instance grac41 is running on node grac41
Instance grac42 is running on node grac42
Instance grac43 is running on node grac43



WebDriver a perfect API testing your JEE application

Overview

  • Selenium WebDriver marks a leap forward in terms of browser automation
  • WebDriver can be used by multiple Languages : Java, C#, PHP, Phyton, Perl, JS, …
  • Selenium-WebDriver makes direct calls to the browser and can issue Buttons clicks , ..
  • Selenium-WebDriver supports multiple Browers like Firefox , Chrome, HtmlUnitDriver,  …
  • HtmlUnitDriver is a  headless (GUI-less) browser simulator ( good for Load Testing )
  • Before switching to HtmlUnitDriver you may first use  a GUI based Driver like FirefoxDriver

Preparing Test Environment

For testing WebDriver we use 2 Wildfly instances :
Instance 1 (Port 8081 ) : Production  Server  
   publishes our Website to be tested - Session Scoped Bean using following annotations
      @Named("jPATestBean")
      @SessionScoped 
Instance 2 ( Port 8180) : Test Server 
   Simulates a Webbrowser - using following annotations   
      @RunAsClient annotation 
   This project only has a single Java test Class 


Note: The WFJPA2EL-1.0 Web application is deployed to both Server 

 

Testing the same Webapplication running on  different Application Servers

The main purpose of these tests [ test1() and test2() ] are:

  • Review the Page and verify the Page title
  • Dynamically click  the JSF button j_idt8:cBtn32
  • Use View Page Source from your firefox Browser  to find out your IDs for your Button.  Sample:
    <td><input id=“j_idt8:cBtn32” type=”submit” name=”j_idt8:cBtn32″ value=”Check running RAC Instances and JPA Version ” /></td>
  • Verify that we are connecting to the correct  RAC database named:  BANKA
  • Test  using different URLs
    http://localhost:8081/WFJPA2EL-1.0/     http://localhost:8180/WFJPA2EL-1.0/
  • Sleep between HTTP request to allow users to read the HTML page
Java Code
@Test
@RunAsClient
public void test1() throws InterruptedException
{
testJPARunAsClient("http://localhost:8081/WFJPA2EL-1.0/");
}

@Test
@RunAsClient
public void test2() throws InterruptedException
{
testJPARunAsClient("http://localhost:8180/WFJPA2EL-1.0/");
}

public void testJPARunAsClient(String URL) throws InterruptedException
{
String methodName = "testJPARunAsClient()";
System.out.println("Inside: " + methodName + "- URL: " + URL );
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get(URL);
String pageTitle = driver.getTitle();
System.out.println(" URL " + contextPath +  " - " +methodName + " - Found Page Title:  " + pageTitle);
Assert.assertEquals( "Testing RAC - J2EE JPA2 API!", pageTitle);
// Press the Check RAC instance Button
driver.findElement(By.id("j_idt8:cBtn32")).click();
String rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
if ( rtInfo != null )
{
System.out.println(rtInfo);
Assert.assertTrue(rtInfo.contains("DB Name:  BANKA"));
}
// Close brower window after 5 seconds
Thread.sleep(5000);
driver.quit();
System.out.println("Leaving: " + methodName);
}
}

Note our tested URL should return
Inside: testJPARunAsClient()- URL: http://localhost:8081/WFJPA2EL-1.0/
URL http://127.0.0.1:8180/testJPABeanUsingWebdriver/ - testJPARunAsClient() - Found Page Title:  Testing RAC - J2EE JPA2 API!
10:34:11.045 Calling  getRacInfo() in progress ...
10:34:11.046 EclipseLink Version: 2.5.2 - [ EclipseLink 2.5.2 == JPA 2.1]
10:34:11.047 Driver Name             : Oracle JDBC driver
10:34:11.047 Driver Version          : 12.1.0.2.0
10:34:11.048 Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Advanced Analytics and Real Application Testing options
10:34:11.056 DB Name:  BANKA
10:34:11.057 1. Instance Name: bankA_3 - Host: hract21.example.com
10:34:11.057 Leaving getRacInfo() without Exceptions !
Leaving: testJPARunAsClient()

Use View Page Source from firefox to find out our GUI IDs
<td><input id="j_idt8:cBtn32" type="submit" name="j_idt8:cBtn32" value="Check running RAC Instances and JPA Version " /></td>

Starting the test using Maven
$ mvn test

This tests should do the following
- Start 2 firfox browser session and execute the JSF function invoked by j_idt8:cBtn32 button
- After each test the browser should be  closed automatically

The above maven command should return
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 51.583 sec
Results :
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:06.197s
[INFO] Finished at: Thu Jun 18 15:23:00 CEST 2015
[INFO] Final Memory: 19M/55M
[INFO] ------------------------------------------------------------------------

 

Testing a quite complex JTA transaction application by using multiple Browsers


For running test3() and test4() we use a SessionScoped Web application.
This application runs  the following 5 HTTP request :
 - HTTP Request1: Request the initial page via HTTP GET request
 - HTTP Request2: Cleanup table records
 - HTTP Request3: Uses  a HTTP post request to START and SUSPEND a Transaction 
     - Start a JTA transaction
     - Run JPA flush [ == Insert a new db record )
     - Suspend the JTA transaction using the JEE TransactionManager API
     - Add JTA transaction object, Entity Manager object to our HTTPSession Object 
  - HTTP Request4: Uses  a HTTP post request to RESUME and COMMIT the Transaction      
     - retrieve JTA transaction object and Entity Manager object from our HTTPSession Object
     - Resume the Transaction and update the record
     - Commit the record -  in case of any errors rollback the transaction
     - Cleanup HTTP session object , clear the Entity Manager 
  - HTTP Request5: Uses  a HTTP post request to invalidate the HTTP session          
     - Invalidate the HTTP session 

-> This is a quite complex Transaction sample and we will see whether WebDriver 
   can handle this ! 

The main purpose of these tests [ test3() and test4() ]  are 
- Test a SessionScoped JEE application with different Browser [ Firefox and GUIless HtmlUnitDriver ]
- Track the JSESSIONID cookie 
- test3() uses Firefox Driver  
   - start a Firfox session
   - Display the HTML page 
   - Use wait times to display the HTTP pages 
 
- test4()  uses the GUIless HtmlUnitDriver 
   - don't start any browser and display any HTLM page  ( useful for GUI test )
   - Don't use any wait times between the HTTP requests ( useful for performance test ) 

JAVA Code 
  @Test 
     public void test3() throws InterruptedException
      {
         testJPARunAsClientTestSession("http://localhost:8180/WFJPA2EL-1.0/", true);
      }  
    
     @Test 
     public void test4() throws InterruptedException
      {
         testJPARunAsClientTestSession("http://localhost:8180/WFJPA2EL-1.0/", false);
      }  
      public void testJPARunAsClientTestSession(String URL , boolean useGUI) throws InterruptedException
      {
        WebDriver driver = null; 
        String methodName = "testJPARunAsClient()";
        System.out.println("Inside: " + methodName + "- URL: " + URL );
        if (useGUI)
            driver = new FirefoxDriver();
        else 
            driver = new HtmlUnitDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 
        driver.get(URL);  
            //driver.get("http://localhost:8081/WFJPA2EL-1.0/");
            // browser.get("http://localhost:8180/WFJPA2EL-1.0/");
        String pageTitle = driver.getTitle();        
        System.out.println(" URL " + contextPath +  " - " +methodName + " - Found Page Title:  " + pageTitle);
        Assert.assertEquals( "Testing RAC - J2EE JPA2 API!", pageTitle);  
       
            // Press Clean Table Button
        driver.findElement(By.id("j_idt8:cBtn15")).click();       
        String rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("Leaving cleanTable() without Exceptions - Data commited"));
         }
        checkCookie(driver, "Action: Clean Table");
        if (useGUI)
            Thread.sleep(2000);
        
            // click Start and Resume Button
        driver.findElement(By.id("j_idt8:cBtn13")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("-> Suspend Transaction - Status: SUSPEND - Salary:1500"));
         }
        checkCookie(driver, "Action: Start and Suspend Transaction");
        if (useGUI)
            Thread.sleep(5000);
        
            // Click Resumee and Commit button
        driver.findElement(By.id("j_idt8:cBtn14")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                    System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("-> Transaction Commited  -  Salary after update:1599"));
         }
        checkCookie(driver, "Action: Resume and Commit Transaction");
        if (useGUI)
            Thread.sleep(10000);
        
               // Click Session Invalidation button
        driver.findElement(By.id("j_idt8:cBtn31")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            System.out.println(rtInfo);          
         }
        checkCookie(driver, "Action: Invalidate JSF session");
        if (useGUI)
            Thread.sleep(1000);
        driver.quit();
      }
     
    private void checkCookie(WebDriver driver, String info)
      {
        Cookie cookie= driver.manage().getCookieNamed("JSESSIONID");
        System.out.println(info + " - JSESSIONID cookie: " + cookie.getValue());
      }
    

Let's verify the Output :  
Action: Clean Table - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Start and Suspend Transaction - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Resume and Commit Transaction - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Invalidate JSF session - JSESSIONID cookie: E9uqbcDsgyCr5aTxu6bQxX26.wls1
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 42.93 sec

-> After invalidation of our JSF session we get a new JSESSIONID cookie - Perfect !

Summary:

  • WebDriver is an easy API for GUI testing and functional testing
  • WebDriver can be used with JMETER ( used for Multithreading testing )
  • WebDriver is able the run even complex JEE application
  • WebDriver perfect deals with the  JSESSIONID cookie

Reference

Using ExecutorService, Callable API to run Multi-threaded JUNIT tests

Overview

  • In this tutorial we use ExecutorService, Callable API  and JUNIT to test your program for thread safty
  • Callable vs Runable
    • Runnable interface is older than Callable, there from JDK 1.0, while Callable is added on Java 5.0.
    • Runnable interface has run() method to define task while Callable interface uses call() method for task definition.
    • run() method does not return any value, it’s return type is void while call method returns value. Callable interface is a generic parameterized interface and Type of value is provided, when instance of Callable implementation is created.
    • Another difference on run and call method is that run method can not throw checked exception, while call method can throw checked exception in Java.

Test case details

  • Assume on of your developer has created the following ThreadCounter class.
  • This class works fine in single threaded Apps but fails if more than 1 Thread is using this Counter

JAVA code : JUnitTest/src/main/java/com/hhu/junittest/ThreadCounter.java

package com.hhu.junittest;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class ThreadCounter
    {
    private  int count = 0;
    public final VolatileInt vi = new VolatileInt();    
    
    public ThreadCounter()
      {
      }    
    public ThreadCounter( int count)
      {
        this.count = count;
      }        
    public void setCounter( int count)
      {
        this.count = count;
      }
    public static void main(String[] args)
      {
        System.out.println("Hallo from ThreadCounter Class");
          // TODO code application logic here
        // final VolatileInt vi = new VolatileInt();
        ThreadCounter tc = new ThreadCounter();
        tc.setCounter(100*1000*1000);
        for (int j = 0; j < tc.count; j++)
            tc.testIncrement();
        tc. counterStatus();
      }
    
    public void testIncrement()
      {
        vi.num++;
      }
    
    public int getCounter()
      {
        return vi.num;
      }
    static class VolatileInt 
      {
        volatile int num = 0;
      }
    
    public void counterStatus()
      {
         System.out.printf("Total %,d but was %,d", count, getCounter() );
          if ( count == vi.num   )
                System.out.printf(" - Test : OK \n");
            else
               System.out.printf(" - Test : FAILED \n");
      }   
    }

The single Thread test works fine and returns : 
  Hallo from ThreadCounter Class
  Total 100,000,000 but was 100,000,000 - Test : OK 

Test Code for testing thread-safty : JUnitTest/src/test/java/ThreadTest.java

JAVA Code :
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import com.hhu.junittest.ThreadCounter;

import org.junit.Assert;
import org.junit.Test;
 
public class ThreadTest
  {
    
    /*
     static class VolatileInt 
      {
        volatile int num = 0;
      }
    */
    private void test(final int threadCount, boolean atomicTest ) throws InterruptedException, ExecutionException 
      {
        final boolean atomicTestf = atomicTest;        
       // final VolatileInt vi = new VolatileInt();          // This test fails for threadCount > 1
        final AtomicInteger num = new AtomicInteger();     // This test works for any threadCount value
        
        final int count = 100 *1000*1000;
        
        final ThreadCounter tc = new ThreadCounter(100*1000*1000);
            // Create an Anonymous Innner Class with a Callable Object
            // Use Callable  object so we get some results back from our thread test
        Callable<String> task = new Callable<String>() 
          {
            @Override
            public String call() 
              {
                for (int j = 0; j < count; j += threadCount)
                  {
                    if (atomicTestf)
                        num.incrementAndGet();
                    else 
                      //  vi.num++;
                      tc.testIncrement();
                  }       
                return "atomicTest: " + atomicTestf + " - Leaving Thread:  " + Thread.currentThread().getName() +
                   " - nThreads: "  + threadCount; 
              }                
          };
           // As we want to run the same Callable Objects on all threads use:  Collections.nCopies   
           // Collections.nCopies returns an immutable list consisting of n copies of the specified object. 
           // Note the newly allocated data object contains only a single reference to the data object.
        List<Callable<String>> tasks = Collections.nCopies(threadCount, task);
           //Get ExecutorService from Executors utility class, thread pool size is threadCount 
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
           // The invokeAll() method invokes all of the Callable objects you pass to it in the collection passed as parameter. 
           // The invokeAll() returns a list of Future objects via which you can obtain the results of the executions of each Callable.
        List<Future<String>> futures = executorService.invokeAll(tasks);
           // create new and empty String ArrayList
        List<String> resultList = new ArrayList<String>(futures.size());
        // Check for exceptions - our Futures are returning  String Objects
        for (Future<String> future : futures) 
          {
            // Throws an exception if an exception was thrown by the task.
            resultList.add(future.get());
          }
        // Note the future.get() blocks until we get some return value
        // At this stage all tasks are finished - either with an Exception or be a regular method return
        // Validate the final Thread Counter status        
        if (atomicTest)
          {
            System.out.printf("With %,d threads should total %,d but was %,d",
                threadCount , count, num.intValue() ); 
             if ( count == num.intValue()   )
                System.out.printf(" - Test : OK \n");
            else
               System.out.printf(" - Test : FAILED \n");
            Assert.assertEquals(count,num.intValue());
          }
        else
          {
            System.out.printf("With %,d threads should total %,d but was %,d",
                threadCount , count,  tc.getCounter()  ); 
            if ( count == tc.getCounter()  )
                System.out.printf(" - Test : OK \n");
            else
               System.out.printf(" - Test : FAILED \n"); 
            Assert.assertEquals(count,  tc.getCounter());
          }
           // Display the results 
        for ( int i = 0; i<resultList.size(); i++)
            System.out.println(resultList.get(i) );
      }
 
    @Test
    public void test01() throws InterruptedException, ExecutionException 
      {
        test(1,false);
      }
 
    @Test
    public void test02() throws InterruptedException, ExecutionException 
      {
        test(2,false);
      } 
 
    @Test
    public void test04() throws InterruptedException, ExecutionException 
      {
        test(4,false);
      }
 
    @Test
    public void test08() throws InterruptedException, ExecutionException 
      {
        test(8,false);
      }
 
    @Test
    public void test16() throws InterruptedException, ExecutionException 
      {
        test(8,true);    
   } 
 }

Test results

[oracle@wls1 JUnitTest]$ mvn test
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running ThreadTest
With 1 threads should total 100,000,000 but was 100,000,000 - Test : OK 
atomicTest: false - Leaving Thread:  pool-1-thread-1 - nThreads: 1
With 2 threads should total 100,000,000 but was 74,553,473 - Test : FAILED 
With 4 threads should total 100,000,000 but was 40,718,556 - Test : FAILED 
With 8 threads should total 100,000,000 but was 23,405,246 - Test : FAILED 
With 8 threads should total 100,000,000 but was 100,000,000 - Test : OK 
atomicTest: true - Leaving Thread:  pool-5-thread-1 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-2 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-3 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-4 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-5 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-6 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-7 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-8 - nThreads: 8
Tests run: 5, Failures: 3, Errors: 0, Skipped: 0, Time elapsed: 2.253 sec <<< FAILURE!

Results :
Failed tests:   
  test02(ThreadTest): expected:<100000000> but was:<74553473>
  test04(ThreadTest): expected:<100000000> but was:<40718556>
  test08(ThreadTest): expected:<100000000> but was:<23405246>
Tests run: 5, Failures: 3, Errors: 0, Skipped: 0

Some comments on above test results

  • test01 works as we use only a single Thread
  • test02, test04, test08 fails if using 2,4 or 8 Threads and if using volatile int as ThreadCounter
  • test08 works even for 8 Threads if using AtomicInteger() instead of volatile int as ThreadCounter
  • test08 with AtomicInteger() returns a String object for each Thread by using our Future objects

 

Reference