Hello community,

here is the log from the commit of package salt-shaptools for openSUSE:Factory 
checked in at 2020-05-15 23:52:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/salt-shaptools (Old)
 and      /work/SRC/openSUSE:Factory/.salt-shaptools.new.2738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "salt-shaptools"

Fri May 15 23:52:41 2020 rev:13 rq:805831 version:0.3.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/salt-shaptools/salt-shaptools.changes    
2020-03-08 22:21:29.143979291 +0100
+++ /work/SRC/openSUSE:Factory/.salt-shaptools.new.2738/salt-shaptools.changes  
2020-05-15 23:52:44.657593591 +0200
@@ -1,0 +2,20 @@
+Fri Mar 27 18:06:32 UTC 2020 - Simranpal Singh <simranpal.si...@suse.com>
+
+- Version 0.3.4
+  * Add new salt module and state to extract the sar files using SAPCAR 
+
+-------------------------------------------------------------------
+Fri Mar 20 14:49:04 UTC 2020 - Xabier Arbulu <xarb...@suse.com>
+
+- Version 0.3.3
+  * Add new salt state to extract the HANA python dbapi client 
+
+-------------------------------------------------------------------
+Thu Mar  5 10:03:39 UTC 2020 - Xabier Arbulu <xarb...@suse.com>
+
+- Version 0.3.2
+  * Add a new salt state method to update corosync configuration
+    file
+  * Fix travis file to install the py packages in develop mode 
+
+-------------------------------------------------------------------

Old:
----
  salt-shaptools-0.3.1.tar.gz

New:
----
  salt-shaptools-0.3.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ salt-shaptools.spec ++++++
--- /var/tmp/diff_new_pack.aFKARX/_old  2020-05-15 23:52:45.757595711 +0200
+++ /var/tmp/diff_new_pack.aFKARX/_new  2020-05-15 23:52:45.761595719 +0200
@@ -19,7 +19,7 @@
 # See also https://en.opensuse.org/openSUSE:Specfile_guidelines
 
 Name:           salt-shaptools
-Version:        0.3.1
+Version:        0.3.4
 Release:        0
 Summary:        Salt modules and states for SAP Applications and SLE-HA 
components management
 
@@ -51,7 +51,8 @@
 cp -R salt/states/netweavermod.py %{buildroot}/srv/salt/_states
 cp -R salt/modules/saptunemod.py %{buildroot}/srv/salt/_modules
 cp -R salt/states/saptunemod.py %{buildroot}/srv/salt/_states
-
+cp -R salt/modules/sapcarmod.py %{buildroot}/srv/salt/_modules
+cp -R salt/states/sapcarmod.py %{buildroot}/srv/salt/_states
 
 %files
 %defattr(-,root,root,-)

++++++ salt-shaptools-0.3.1.tar.gz -> salt-shaptools-0.3.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.3.1/salt/modules/hanamod.py 
new/salt-shaptools-0.3.4/salt/modules/hanamod.py
--- old/salt-shaptools-0.3.1/salt/modules/hanamod.py    2020-03-06 
15:03:43.200091220 +0100
+++ new/salt-shaptools-0.3.4/salt/modules/hanamod.py    2020-03-31 
20:02:39.980481668 +0200
@@ -22,9 +22,19 @@
 
 # Import Python libs
 from __future__ import absolute_import, unicode_literals, print_function
+
+import logging
 import time
+import re
+
+try:  # pragma: no cover
+    import importlib as imp
+except ImportError:  # pragma: no cover
+    import imp
 
 from salt import exceptions
+from salt.utils import files as salt_files
+
 
 # Import third party libs
 try:
@@ -35,8 +45,19 @@
 except ImportError:  # pragma: no cover
     HAS_HANA = False
 
+LOGGER = logging.getLogger(__name__)
+
 __virtualname__ = 'hana'
 
+LABEL_FILE = 'LABEL.ASC'
+LABELIDX_FILE = 'LABELIDX.ASC'
+
+
+class SapFolderNotFoundError(Exception):
+    '''
+    SAP folder not found exception
+    '''
+
 
 def __virtual__():  # pragma: no cover
     '''
@@ -865,17 +886,17 @@
     '''
     Wait until HANA is ready trying to connect to the database
 
-    host:
+    host
         Host where HANA is running
-    port:
+    port
         HANA database port
-    user:
+    user
         User to connect to the databse
-    password:
+    password
         Password to connect to the database
-    timeout:
+    timeout
         Timeout to try to connect to the database
-    interval:
+    interval
         Interval to try the connection
 
     CLI Example:
@@ -900,4 +921,75 @@
         raise exceptions.CommandExecutionError(
             'HANA database not available after {} seconds in {}:{}'.format(
                 timeout, host, port
-            ))
\ No newline at end of file
+            ))
+
+
+def reload_hdb_connector():
+    '''
+    As hdb_connector uses pyhdb or dbapi, if these packages are installed on 
the fly,
+    we need to reload the connector to import the correct api
+    '''
+    imp.reload(hdb_connector)
+
+
+def _find_sap_folder(software_folders, folder_pattern):
+    '''
+    Find a SAP folder following a recursive approach using the LABEL and 
LABELIDX files
+    '''
+    for folder in software_folders:
+        label = '{}/{}'.format(folder, LABEL_FILE)
+        try:
+            with salt_files.fopen(label, 'r') as label_file_ptr:
+                label_content = label_file_ptr.read().strip()
+                if folder_pattern.match(label_content):
+                    return folder
+                else:
+                    LOGGER.debug(
+                        '%s folder does not contain %s pattern', folder, 
folder_pattern.pattern)
+        except IOError:
+            LOGGER.debug('%s file not found in %s. Skipping folder', 
LABEL_FILE, folder)
+
+        labelidx = '{}/{}'.format(folder, LABELIDX_FILE)
+        try:
+            with salt_files.fopen(labelidx, 'r') as labelidx_file_ptr:
+                labelidx_content = labelidx_file_ptr.read().splitlines()
+                new_folders = [
+                    '{}/{}'.format(folder, new_folder) for new_folder in 
labelidx_content]
+                try:
+                    return _find_sap_folder(new_folders, folder_pattern)
+                except SapFolderNotFoundError:
+                    continue
+        except IOError:
+            LOGGER.debug('%s file not found in %s. Skipping folder', 
LABELIDX_FILE, folder)
+
+    raise SapFolderNotFoundError(
+        'SAP folder with {} pattern not found'.format(folder_pattern.pattern))
+
+
+def extract_pydbapi(
+        name,
+        software_folders,
+        output_dir,
+        hana_version='20'):
+    '''
+    Extract HANA pydbapi python client from the provided software folders
+
+    name
+        Name of the package that needs to be installed
+    software_folders
+        Folders list where the HANA client is located. It's used as a list as 
the pydbapi client
+        will be found automatically among different folders and providing 
several folders is a
+        standard way in SAP landscape
+    output_dir
+        Folder where the package is extracted
+    '''
+    current_platform = hana.HanaInstance.get_platform()
+    hana_client_pattern = re.compile('^HDB_CLIENT:{}.*:{}:.*'.format(
+        hana_version, current_platform))
+    try:
+        hana_client_folder = _find_sap_folder(software_folders, 
hana_client_pattern)
+    except SapFolderNotFoundError:
+        raise exceptions.CommandExecutionError('HANA client not found')
+    pydbapi_file = '{}/client/{}'.format(hana_client_folder, name)
+    __salt__['archive.tar'](options='xvf', tarfile=pydbapi_file, 
dest=output_dir)
+    return pydbapi_file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.3.1/salt/modules/sapcarmod.py 
new/salt-shaptools-0.3.4/salt/modules/sapcarmod.py
--- old/salt-shaptools-0.3.1/salt/modules/sapcarmod.py  1970-01-01 
01:00:00.000000000 +0100
+++ new/salt-shaptools-0.3.4/salt/modules/sapcarmod.py  2020-03-31 
20:02:39.980481668 +0200
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+'''
+Module to provide SAP tools functionality to Salt
+
+.. versionadded:: pending
+
+:maintainer:    Simranpal Singh <sisi...@suse.com>
+:maturity:      alpha
+:depends:       ``shaptools`` Python module
+:platform:      all
+
+:configuration: This module requires the shaptools package
+'''
+
+
+# Import Python libs
+from __future__ import absolute_import, unicode_literals
+
+from salt import exceptions
+
+# Import third party libs
+try:
+    from shaptools import saputils
+    HAS_SAPUTILS = True
+except ImportError:  # pragma: no cover
+    HAS_SAPUTILS = False
+
+__virtualname__ = 'sapcar'
+
+
+def __virtual__():  # pragma: no cover
+    '''
+    Only load this module if shaptools python module is installed
+    '''
+    if HAS_SAPUTILS:
+        return __virtualname__
+    return (
+        False,
+        'The sapcar execution module failed to load: the shaptools python'
+        ' library is not available.')
+
+
+def extract(
+        sapcar_exe,
+        sar_file,
+        output_dir=None,
+        options=None):
+    '''
+    Extract a SAP sar archive
+
+    sapcar_exe_file
+        Path to the SAPCAR executable file. SAPCAR is a SAP tool to extract 
SAP SAR format archives 
+    sar_file
+        Path to the sar file to be extracted
+    output_dir
+        Location where to extract the SAR file
+    options:
+        Additional parameters to the SAPCAR tool
+    '''
+    try:
+        return saputils.extract_sapcar_file(
+            sapcar_exe=sapcar_exe, sar_file=sar_file, output_dir=output_dir, 
options=options)
+    except saputils.SapUtilsError as err:
+        raise exceptions.CommandExecutionError(err)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.3.1/salt/states/crmshmod.py 
new/salt-shaptools-0.3.4/salt/states/crmshmod.py
--- old/salt-shaptools-0.3.1/salt/states/crmshmod.py    2020-03-06 
15:03:43.200091220 +0100
+++ new/salt-shaptools-0.3.4/salt/states/crmshmod.py    2020-03-31 
20:02:39.980481668 +0200
@@ -35,6 +35,7 @@
 
 # Import salt libs
 from salt import exceptions
+from salt import utils as salt_utils
 from salt.ext import six
 
 
@@ -287,3 +288,110 @@
     except exceptions.CommandExecutionError as err:
         ret['comment'] = six.text_type(err)
         return ret
+
+
+def _convert2dict(file_content_lines):
+    """
+    Convert the corosync configuration file to a dictionary
+    """
+    corodict = {}
+    index = 0
+
+    for i, line in enumerate(file_content_lines):
+        stripped_line = line.strip()
+        if not stripped_line or stripped_line[0] == '#':
+            continue
+
+        if index > i:
+            continue
+
+        line_items = stripped_line.split()
+        if '{' in stripped_line:
+            corodict[line_items[0]], new_index = 
_convert2dict(file_content_lines[i+1:])
+            index = i + new_index
+        elif line_items[0][-1] == ':':
+            corodict[line_items[0][:-1]] = line_items[-1]
+        elif '}' in stripped_line:
+            return corodict, i+2
+
+    return corodict, index
+
+
+def _mergedicts(main_dict, changes_dict, applied_changes, initial_path=''):
+    """
+    Merge the 2 dictionaries. We cannot use update as it changes all the 
children of an entry
+    """
+    for key, value in changes_dict.items():
+        current_path = '{}.{}'.format(initial_path, key)
+        if key in main_dict.keys() and not isinstance(value, dict):
+            if str(main_dict[key]) != str(value):
+                applied_changes[current_path] = value
+            main_dict[key] = value
+        elif key in main_dict.keys():
+            modified_dict, new_changes = _mergedicts(main_dict[key], value, 
applied_changes, current_path)
+            main_dict[key] = modified_dict
+            applied_changes.update(new_changes)
+
+        else:  # Entry not found in current main dictionary, so we can update 
all
+            main_dict[key] = changes_dict[key]
+            applied_changes[current_path] = value
+
+    return main_dict, applied_changes
+
+
+def _convert2corosync(corodict, indentation=''):
+    """
+    Convert a corosync data dictionary to the corosync configuration file 
format
+    """
+    output = ''
+    for key, value in corodict.items():
+        if isinstance(value, dict):
+            output += '{}{} {{\n'.format(indentation, key)
+            indentation += '\t'
+            output += _convert2corosync(value, indentation)
+            indentation = indentation[:-1]
+            output += '{}}}\n'.format(indentation)
+        else:
+            output += '{}{}: {}\n'.format(indentation, key, value)
+    return output
+
+
+def corosync_updated(
+        name,
+        data,
+        backup=True):
+    """
+    Configure corosync configuration file
+
+    name
+        Corosync configuration file path
+    data
+        Dictionary with the values that have to be changed. The method won't 
do any sanity check
+        so, it will put in the configuration file value added in this parameter
+    """
+
+    changes = {}
+    ret = {'name': name,
+           'changes': changes,
+           'result': False,
+           'comment': ''}
+
+    with salt_utils.files.fopen(name, 'r') as file_content:
+        corodict, _ = _convert2dict(file_content.read().splitlines())
+    new_conf_dict, changes = _mergedicts(corodict, data, {})
+
+    if not changes:
+        ret['changes'] = changes
+        ret['comment'] = 'Corosync already has the required configuration'
+        ret['result'] = True
+        return ret
+
+    new_conf_file_content = _convert2corosync(new_conf_dict)
+    if backup:
+        __salt__['file.copy'](name, '{}.backup'.format(name))
+    __salt__['file.write'](name, new_conf_file_content)
+
+    ret['changes'] = changes
+    ret['comment'] = 'Corosync configuration file updated'
+    ret['result'] = True
+    return ret
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.3.1/salt/states/hanamod.py 
new/salt-shaptools-0.3.4/salt/states/hanamod.py
--- old/salt-shaptools-0.3.1/salt/states/hanamod.py     2020-03-06 
15:03:43.200091220 +0100
+++ new/salt-shaptools-0.3.4/salt/states/hanamod.py     2020-03-31 
20:02:39.980481668 +0200
@@ -223,7 +223,7 @@
             software_path=software_path,
             conf_file=TMP_CONFIG_FILE,
             root_user=root_user,
-            root_password=root_password)        
+            root_password=root_password)
         if hdb_pwd_file:
             __salt__['cp.get_file'](
                 path=hdb_pwd_file,
@@ -755,3 +755,57 @@
     except exceptions.CommandExecutionError as err:
         ret['comment'] = six.text_type(err)
         return ret
+
+
+def pydbapi_extracted(
+        name,
+        software_folders,
+        output_dir,
+        hana_version='20',
+        force=False):
+    '''
+    Extract HANA pydbapi python client from the provided software folders
+
+    name
+        Name of the package that needs to be installed
+    software_folders
+        Folders list where the HANA client is located. It's used as a list as 
the pydbapi client
+        will be found automatically among different folders and providing 
several folders is a
+        standard way in SAP landscape
+    output_dir
+        Folder where the package is extracted
+    force
+        Force new extraction if the file already is extracted
+    '''
+
+    ret = {'name': name,
+           'changes': {},
+           'result': False,
+           'comment': ''}
+
+    if not force and __salt__['file.directory_exists'](output_dir):
+        ret['result'] = True
+        ret['comment'] = \
+            '{} already exists. Skipping extraction (set force to True to 
force the '\
+            'extraction)'.format(output_dir)
+        return ret
+
+    if __opts__['test']:
+        ret['result'] = None
+        ret['comment'] = '{} would be extracted'.format(name)
+        ret['changes']['output_dir'] = output_dir
+        return ret
+
+    __salt__['file.mkdir'](output_dir)
+
+    try:
+        client = __salt__['hana.extract_pydbapi'](name, software_folders, 
output_dir, hana_version)
+    except exceptions.CommandExecutionError as err:
+        ret['comment'] = six.text_type(err)
+        return ret
+
+    ret['result'] = True
+    ret['comment'] = '{} correctly extracted'.format(client)
+    ret['changes'] = {'pydbapi': client, 'output_dir': output_dir}
+
+    return ret
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.3.1/salt/states/sapcarmod.py 
new/salt-shaptools-0.3.4/salt/states/sapcarmod.py
--- old/salt-shaptools-0.3.1/salt/states/sapcarmod.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/salt-shaptools-0.3.4/salt/states/sapcarmod.py   2020-03-31 
20:02:39.980481668 +0200
@@ -0,0 +1,86 @@
+'''
+State module to provide SAP utilities functionality to Salt
+
+.. versionadded:: pending
+
+:maintainer:    Simranpal Singh <sisi...@suse.com>
+:maturity:      alpha
+:depends:       python-shaptools
+:platform:      all
+
+:configuration: This module requires the python-shaptools module
+
+:usage:
+
+.. code-block:: yaml
+    extract_sap_car_file:
+      sapcar.extracted:
+      - name: home/sapuser/saprouter_600-80003478.sar
+      - sapcar_exe: ./SAPCAR.exe
+      - output_dir: home/sapuser/saprouter_inst
+      - options: "-manifest SIGNATURE.SMF"
+'''
+
+
+# Import python libs
+from __future__ import absolute_import, unicode_literals
+
+# Import salt libs
+from salt import exceptions
+from salt.ext import six
+
+
+__virtualname__ = 'sapcar'
+
+
+def __virtual__():  # pragma: no cover
+    '''
+    Only load this module if sapcar python module is installed
+    '''
+    return 'sapcar.extract' in __salt__
+
+
+def extracted(
+        name,
+        sapcar_exe,
+        output_dir=None,
+        options=None):
+    """
+    Extract a SAPCAR sar archive
+
+    name
+        SAR file name to be extracted
+    sapcar_exe
+        Path to the SAPCAR executable file. SAPCAR is a SAP tool to extract 
SAP SAR format archives 
+    output_dir
+        Location where to extract the SAR file. If not provided, use current 
directory as name
+    options:
+        Additional parameters to the SAPCAR tool
+    """
+    ret = {'name': name,
+           'changes': {},
+           'result': False,
+           'comment': ''}
+
+    if __opts__['test']:
+        ret['result'] = None
+        ret['comment'] = '{} would be extracted'.format(name)
+        ret['changes']['output_dir'] = output_dir
+        return ret
+    
+    try:
+        #  Here starts the actual process
+        __salt__['sapcar.extract'](
+            sapcar_exe=sapcar_exe,
+            sar_file=name,
+            output_dir=output_dir,
+            options=options)
+            
+        ret['changes']['output_dir'] = output_dir
+        ret['comment'] = '{} file extracted'.format(name)
+        ret['result'] = True
+        return ret
+
+    except exceptions.CommandExecutionError as err:
+        ret['comment'] = six.text_type(err)
+        return ret
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.3.1/salt-shaptools.changes 
new/salt-shaptools-0.3.4/salt-shaptools.changes
--- old/salt-shaptools-0.3.1/salt-shaptools.changes     2020-03-06 
15:03:43.200091220 +0100
+++ new/salt-shaptools-0.3.4/salt-shaptools.changes     2020-03-31 
20:02:39.980481668 +0200
@@ -1,4 +1,24 @@
 -------------------------------------------------------------------
+Fri Mar 27 18:06:32 UTC 2020 - Simranpal Singh <simranpal.si...@suse.com>
+
+- Version 0.3.4
+  * Add new salt module and state to extract the sar files using SAPCAR 
+
+-------------------------------------------------------------------
+Fri Mar 20 14:49:04 UTC 2020 - Xabier Arbulu <xarb...@suse.com>
+
+- Version 0.3.3
+  * Add new salt state to extract the HANA python dbapi client 
+
+-------------------------------------------------------------------
+Thu Mar  5 10:03:39 UTC 2020 - Xabier Arbulu <xarb...@suse.com>
+
+- Version 0.3.2
+  * Add a new salt state method to update corosync configuration
+    file
+  * Fix travis file to install the py packages in develop mode 
+
+-------------------------------------------------------------------
 Fri Jan 24 10:40:26 UTC 2020 - Xabier Arbulu <xarb...@suse.com>
 
 - Version 0.3.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.3.1/salt-shaptools.spec 
new/salt-shaptools-0.3.4/salt-shaptools.spec
--- old/salt-shaptools-0.3.1/salt-shaptools.spec        2020-03-06 
15:03:43.200091220 +0100
+++ new/salt-shaptools-0.3.4/salt-shaptools.spec        2020-03-31 
20:02:39.980481668 +0200
@@ -19,7 +19,7 @@
 # See also https://en.opensuse.org/openSUSE:Specfile_guidelines
 
 Name:           salt-shaptools
-Version:        0.3.1
+Version:        0.3.4
 Release:        0
 Summary:        Salt modules and states for SAP Applications and SLE-HA 
components management
 
@@ -51,7 +51,8 @@
 cp -R salt/states/netweavermod.py %{buildroot}/srv/salt/_states
 cp -R salt/modules/saptunemod.py %{buildroot}/srv/salt/_modules
 cp -R salt/states/saptunemod.py %{buildroot}/srv/salt/_states
-
+cp -R salt/modules/sapcarmod.py %{buildroot}/srv/salt/_modules
+cp -R salt/states/sapcarmod.py %{buildroot}/srv/salt/_states
 
 %files
 %defattr(-,root,root,-)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/salt-shaptools-0.3.1/tests/run.sh 
new/salt-shaptools-0.3.4/tests/run.sh
--- old/salt-shaptools-0.3.1/tests/run.sh       2020-03-06 15:03:43.200091220 
+0100
+++ new/salt-shaptools-0.3.4/tests/run.sh       2020-03-31 20:02:39.980481668 
+0200
@@ -2,4 +2,4 @@
 cp salt/states/*.py ../salt/salt/states/
 cp tests/unit/modules/*.py ../salt/tests/unit/modules/
 cp tests/unit/states/*.py ../salt/tests/unit/states/
-py.test -vv ../salt/tests/unit/modules/test_hanamod.py 
../salt/tests/unit/states/test_hanamod.py  
../salt/tests/unit/modules/test_crmshmod.py  
../salt/tests/unit/modules/test_saptunemod.py 
../salt/tests/unit/states/test_crmshmod.py 
../salt/tests/unit/modules/test_drbdmod.py 
../salt/tests/unit/states/test_drbdmod.py 
../salt/tests/unit/states/test_saptunemod.py 
../salt/tests/unit/modules/test_netweavermod.py 
../salt/tests/unit/states/test_netweavermod.py --cov=salt.modules.hanamod 
--cov=salt.states.hanamod --cov=salt.modules.crmshmod 
--cov=salt.states.crmshmod --cov=salt.modules.drbdmod 
--cov=salt.modules.saptunemod --cov=salt.states.saptunemod 
--cov=salt.states.drbdmod --cov=salt.modules.netweavermod 
--cov=salt.states.netweavermod --cov-config .coveragerc --cov-report term 
--cov-report xml --cov-report html
+py.test -vv ../salt/tests/unit/modules/test_hanamod.py 
../salt/tests/unit/states/test_hanamod.py  
../salt/tests/unit/modules/test_crmshmod.py  
../salt/tests/unit/modules/test_saptunemod.py 
../salt/tests/unit/modules/test_sapcarmod.py 
../salt/tests/unit/states/test_crmshmod.py 
../salt/tests/unit/modules/test_drbdmod.py 
../salt/tests/unit/states/test_drbdmod.py 
../salt/tests/unit/states/test_saptunemod.py 
../salt/tests/unit/modules/test_netweavermod.py 
../salt/tests/unit/states/test_netweavermod.py 
../salt/tests/unit/states/test_sapcarmod.py --cov=salt.modules.hanamod 
--cov=salt.states.hanamod --cov=salt.modules.crmshmod 
--cov=salt.states.crmshmod --cov=salt.modules.drbdmod 
--cov=salt.modules.saptunemod --cov=salt.modules.sapcarmod 
--cov=salt.states.saptunemod --cov=salt.states.drbdmod 
--cov=salt.modules.netweavermod --cov=salt.states.netweavermod 
--cov=salt.states.sapcarmod --cov-config .coveragerc --cov-report term 
--cov-report xml --cov-report html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/salt-shaptools-0.3.1/tests/unit/modules/test_hanamod.py 
new/salt-shaptools-0.3.4/tests/unit/modules/test_hanamod.py
--- old/salt-shaptools-0.3.1/tests/unit/modules/test_hanamod.py 2020-03-06 
15:03:43.200091220 +0100
+++ new/salt-shaptools-0.3.4/tests/unit/modules/test_hanamod.py 2020-03-31 
20:02:39.980481668 +0200
@@ -17,6 +17,7 @@
 from tests.support.mock import (
     MagicMock,
     patch,
+    mock_open,
     NO_MOCK,
     NO_MOCK_REASON
 )
@@ -813,3 +814,106 @@
             mock.call('192.168.10.15', 30015, user='SYSTEM', password='pass')
         ])
         assert 'HANA database not available after 2 seconds in 
192.168.10.15:30015' in str(err.value)
+
+    @mock.patch('salt.modules.hanamod.hdb_connector')
+    @mock.patch('importlib.reload')
+    def test_reload_hdb_connector(self, mock_reload, mock_hdb_connector):
+        hanamod.reload_hdb_connector()
+        mock_reload.assert_called_once_with(mock_hdb_connector)
+
+    @mock.patch('logging.Logger.debug')
+    @mock.patch('salt.utils.files.fopen')
+    def test_find_sap_folder_error(self, mock_fopen, mock_debug):
+        mock_pattern = mock.Mock(pattern='my_pattern')
+        mock_fopen.side_effect = [
+            IOError, IOError, IOError, IOError]
+        with pytest.raises(hanamod.SapFolderNotFoundError) as err:
+            hanamod._find_sap_folder(['1234', '5678'], mock_pattern)
+
+        assert 'SAP folder with my_pattern pattern not found' in str(err.value)
+        mock_debug.assert_has_calls([
+            mock.call('%s file not found in %s. Skipping folder', 'LABEL.ASC', 
'1234'),
+            mock.call('%s file not found in %s. Skipping folder', 
'LABELIDX.ASC', '1234'),
+            mock.call('%s file not found in %s. Skipping folder', 'LABEL.ASC', 
'5678'),
+            mock.call('%s file not found in %s. Skipping folder', 
'LABELIDX.ASC', '5678')
+        ])
+
+    def test_find_sap_folder_contain_hana(self):
+        mock_pattern = mock.Mock(return_value=True)
+        with patch('salt.utils.files.fopen', mock_open(read_data='data\n')) as 
mock_file:
+            folder = hanamod._find_sap_folder(['1234', '5678'], mock_pattern)
+
+        mock_pattern.match.assert_called_once_with('data')
+        assert folder in '1234'
+
+    @mock.patch('logging.Logger.debug')
+    def test_find_sap_folder_contain_units(self, mock_debug):
+        mock_pattern = mock.Mock(pattern='my_pattern')
+        mock_pattern.match.side_effect = [False, True]
+        with patch('salt.utils.files.fopen', mock_open(read_data=
+                ['data\n', 'DATA_UNITS\n', 'data_2\n'])) as mock_file:
+            folder = hanamod._find_sap_folder(['1234', '5678'], mock_pattern)
+
+        mock_pattern.match.assert_has_calls([
+            mock.call('data'),
+            mock.call('data_2')
+        ])
+        mock_debug.assert_has_calls([
+            mock.call('%s folder does not contain %s pattern', '1234', 
'my_pattern')
+        ])
+        assert folder in '1234/DATA_UNITS'
+
+    @mock.patch('logging.Logger.debug')
+    def test_find_sap_folder_contain_units_error(self, mock_debug):
+        mock_pattern = mock.Mock(pattern='my_pattern')
+        mock_pattern.match.side_effect = [False, False]
+        with patch('salt.utils.files.fopen', mock_open(read_data=[
+                'data\n', 'DATA_UNITS\n', 'data_2\n', IOError])) as mock_file:
+            with pytest.raises(hanamod.SapFolderNotFoundError) as err:
+                folder = hanamod._find_sap_folder(['1234'], mock_pattern)
+
+        mock_pattern.match.assert_has_calls([
+            mock.call('data'),
+            mock.call('data_2')
+        ])
+        mock_debug.assert_has_calls([
+            mock.call('%s folder does not contain %s pattern', '1234', 
'my_pattern')
+        ])
+        assert 'SAP folder with my_pattern pattern not found' in str(err.value)
+
+    @mock.patch('re.compile')
+    @mock.patch('salt.modules.hanamod._find_sap_folder')
+    @mock.patch('salt.modules.hanamod.hana.HanaInstance.get_platform')
+    def test_extract_pydbapi(self, mock_get_platform, mock_find_sap_folders, 
mock_compile):
+        mock_get_platform.return_value = 'LINUX_X86_64'
+        mock_find_sap_folders.return_value = 'my_folder'
+        compile_mocked = mock.Mock()
+        mock_compile.return_value = compile_mocked
+        mock_tar = MagicMock()
+        with patch.dict(hanamod.__salt__, {'archive.tar': mock_tar}):
+            pydbapi_file = hanamod.extract_pydbapi(
+                'PYDBAPI.tar.gz', ['1234', '5678'], '/tmp/output')
+
+        
mock_compile.assert_called_once_with('^HDB_CLIENT:20.*:LINUX_X86_64:.*')
+        mock_find_sap_folders.assert_called_once_with(
+            ['1234', '5678'], compile_mocked)
+        mock_tar.assert_called_once_with(
+            options='xvf', tarfile='my_folder/client/PYDBAPI.tar.gz', 
dest='/tmp/output')
+        assert pydbapi_file == 'my_folder/client/PYDBAPI.tar.gz'
+
+    @mock.patch('re.compile')
+    @mock.patch('salt.modules.hanamod._find_sap_folder')
+    @mock.patch('salt.modules.hanamod.hana.HanaInstance.get_platform')
+    def test_extract_pydbapi_error(self, mock_get_platform, 
mock_find_sap_folders, mock_compile):
+        mock_get_platform.return_value = 'LINUX_X86_64'
+        compile_mocked = mock.Mock()
+        mock_compile.return_value = compile_mocked
+        mock_find_sap_folders.side_effect = hanamod.SapFolderNotFoundError
+        with pytest.raises(exceptions.CommandExecutionError) as err:
+            pydbapi_file = hanamod.extract_pydbapi(
+                'PYDBAPI.tar.gz', ['1234', '5678'], '/tmp/output')
+
+        
mock_compile.assert_called_once_with('^HDB_CLIENT:20.*:LINUX_X86_64:.*')
+        mock_find_sap_folders.assert_called_once_with(
+            ['1234', '5678'], compile_mocked)
+        assert 'HANA client not found' in str(err.value)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/salt-shaptools-0.3.1/tests/unit/modules/test_sapcarmod.py 
new/salt-shaptools-0.3.4/tests/unit/modules/test_sapcarmod.py
--- old/salt-shaptools-0.3.1/tests/unit/modules/test_sapcarmod.py       
1970-01-01 01:00:00.000000000 +0100
+++ new/salt-shaptools-0.3.4/tests/unit/modules/test_sapcarmod.py       
2020-03-31 20:02:39.980481668 +0200
@@ -0,0 +1,60 @@
+
+# -*- coding: utf-8 -*-
+'''
+    :codeauthor: Simranpal Singh <sisi...@suse.com>
+'''
+
+# Import Python Libs
+from __future__ import absolute_import, print_function, unicode_literals
+import pytest
+
+from salt import exceptions
+
+# Import Salt Testing Libs
+from tests.support.mixins import LoaderModuleMockMixin
+from tests.support.unit import TestCase, skipIf
+from tests.support import mock
+from tests.support.mock import (
+    MagicMock,
+    patch,
+    mock_open,
+    NO_MOCK,
+    NO_MOCK_REASON
+)
+
+# Import Salt Libs
+import salt.modules.sapcarmod as sapcarmod
+
+
+@skipIf(NO_MOCK, NO_MOCK_REASON)
+class SapcarModuleTest(TestCase, LoaderModuleMockMixin):
+    '''
+    This class contains a set of functions that test salt.modules.sapcarmod.
+    '''
+
+    def setup_loader_modules(self):
+        return {sapcarmod: {}}
+
+    @patch('salt.modules.sapcarmod.saputils.extract_sapcar_file')
+    def test_extract_return(self, mock_extract):
+        '''
+        Test extract method - return
+        '''
+        mock_extract.return_value = 0
+        assert 
sapcarmod.extract('/sapmedia/SAPCAR','/sapmedia/IMDB_SERVER_LINUX.SAR', 
'/sapmedia/HANA', '-v') == 0
+        mock_extract.assert_called_once_with(
+            sapcar_exe='/sapmedia/SAPCAR', 
sar_file='/sapmedia/IMDB_SERVER_LINUX.SAR',
+            output_dir='/sapmedia/HANA', options='-v')
+
+    @patch('salt.modules.sapcarmod.saputils.extract_sapcar_file')
+    def test_extract_raise(self, mock_extract):
+        '''
+        Test extract method - raise
+        '''
+        mock_extract.side_effect = sapcarmod.saputils.SapUtilsError('error')
+        with pytest.raises(exceptions.CommandExecutionError) as err:
+            
sapcarmod.extract('/sapmedia/SAPCAR','/sapmedia/IMDB_SERVER_LINUX.SAR', 
'/sapmedia/HANA', '-v')
+        mock_extract.assert_called_once_with(
+            sapcar_exe='/sapmedia/SAPCAR', 
sar_file='/sapmedia/IMDB_SERVER_LINUX.SAR',
+            output_dir='/sapmedia/HANA', options='-v')
+        
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/salt-shaptools-0.3.1/tests/unit/states/test_crmshmod.py 
new/salt-shaptools-0.3.4/tests/unit/states/test_crmshmod.py
--- old/salt-shaptools-0.3.1/tests/unit/states/test_crmshmod.py 2020-03-06 
15:03:43.200091220 +0100
+++ new/salt-shaptools-0.3.4/tests/unit/states/test_crmshmod.py 2020-03-31 
20:02:39.980481668 +0200
@@ -6,6 +6,7 @@
 # Import Python libs
 from __future__ import absolute_import, unicode_literals, print_function
 
+import sys
 from salt import exceptions
 
 # Import Salt Testing Libs
@@ -15,6 +16,7 @@
 from tests.support.mock import (
     NO_MOCK,
     NO_MOCK_REASON,
+    mock_open,
     MagicMock,
     patch
 )
@@ -480,3 +482,244 @@
                 method='update',
                 url='file.config',
                 is_xml=False)
+
+    def test_convert2dict(self):
+        corofile = """
+# Please read the corosync.conf.5 manual page
+totem {
+    version: 2
+    max_messages: 20
+    interface {
+        ringnumber: 0
+
+    }
+    transport: udpu
+}
+
+logging {
+    timestamp: on
+    logger_subsys {
+        debug: off
+    }
+
+}
+
+quorum {
+    expected_votes: 1
+    two_node: 0
+}"""
+
+        corodict, _ = crmshmod._convert2dict(corofile.splitlines())
+
+        assert corodict == {
+            'totem': {
+                'version': '2',
+                'max_messages': '20',
+                'interface': {
+                    'ringnumber': '0'
+                },
+                'transport': 'udpu'
+            },
+            'logging': {
+                'timestamp': 'on',
+                'logger_subsys': {
+                    'debug': 'off'
+                }
+            },
+            'quorum': {
+                'expected_votes': '1',
+                'two_node': '0'
+            }
+        }
+
+    def test_merge_dicts1(self):
+        main_dict = {
+            'a': {
+                'b': 1,
+                'c': 2
+            },
+            'd': 3
+        }
+        changed_dict = {
+            'a': {
+                'c': 4
+            },
+            'd': 5
+        }
+        merged_dict, applied_changes = crmshmod._mergedicts(
+            main_dict, changed_dict, {}, '')
+
+        assert merged_dict == {
+            'a': {
+                'b': 1,
+                'c': 4
+            },
+            'd': 5
+        }
+
+        assert applied_changes == {
+            '.a.c': 4,
+            '.d': 5
+        }
+
+    def test_merge_dicts2(self):
+        main_dict = {
+            'a': {
+                'b': {
+                    'f': 7
+                },
+                'c': 2
+            },
+            'd': 3
+        }
+        changed_dict = {
+            'a': {
+                'b': {
+                    'f': 8
+                },
+            },
+            'd': 5
+        }
+        merged_dict, applied_changes = crmshmod._mergedicts(
+            main_dict, changed_dict, {}, '')
+
+        assert merged_dict == {
+            'a': {
+                'b': {
+                    'f': 8
+                },
+                'c': 2
+            },
+            'd': 5
+        }
+
+        assert applied_changes == {
+            '.d': 5,
+            '.a.b.f': 8
+        }
+
+    def test_merge_dicts3(self):
+        main_dict = {
+            'a': {
+                'b': 1,
+                'c': 2
+            },
+            'd': 3
+        }
+        changed_dict = {
+            'e': {
+                'c': 4
+            },
+            'a': {
+                'b': 3
+            },
+            'd': 5
+        }
+        merged_dict, applied_changes = crmshmod._mergedicts(
+            main_dict, changed_dict, {}, '')
+
+        assert merged_dict == {
+            'a': {
+                'b': 3,
+                'c': 2
+            },
+            'e': {
+                'c': 4
+            },
+            'd': 5
+        }
+
+        assert applied_changes == {
+            '.d': 5,
+            '.a.b': 3,
+            '.e': {'c': 4}
+        }
+
+    def test_convert2corosync(self):
+        main_dict = {
+            'a': {
+                'b': {
+                    'f': 7
+                },
+                'c': 2
+            },
+            'd': 3
+        }
+
+        output = crmshmod._convert2corosync(main_dict, '')
+
+        # Py2 and py3 have different way of ordering the `items` method
+        # For the functionality this does not really affect
+        if sys.version_info[0] == 2:
+            assert output == "a {\n\tc: 2\n\tb {\n\t\tf: 7\n\t}\n}\nd: 3\n"
+        else:
+            assert output == "a {\n\tb {\n\t\tf: 7\n\t}\n\tc: 2\n}\nd: 3\n"
+
+    @mock.patch('salt.states.crmshmod._convert2dict')
+    @mock.patch('salt.states.crmshmod._mergedicts')
+    def test_corosync_updated_already(self, mock_mergedicts, 
mock_convert2dict):
+        '''
+        Test to check corosync_updated when configuration is already applied
+        '''
+
+        ret = {'name': '/etc/corosync/corosync.conf',
+               'changes': {},
+               'result': True,
+               'comment': 'Corosync already has the required configuration'}
+
+        mock_convert2dict.return_value = ({'data': 1}, {})
+        mock_mergedicts.return_value = ({}, {})
+
+        file_content = "my corosync file content\nmy corosync file 2nd line 
content"
+        with patch("salt.utils.files.fopen", 
mock_open(read_data=file_content)):
+            assert crmshmod.corosync_updated(
+                name='/etc/corosync/corosync.conf',
+                data={'my_data': 1}) == ret
+
+        mock_convert2dict.assert_called_once_with(
+            ['my corosync file content', 'my corosync file 2nd line content']
+        )
+        mock_mergedicts.assert_called_once_with(
+            {'data': 1}, {'my_data': 1}, {})
+
+    @mock.patch('salt.states.crmshmod._convert2corosync')
+    @mock.patch('salt.states.crmshmod._convert2dict')
+    @mock.patch('salt.states.crmshmod._mergedicts')
+    def test_corosync_updated(self, mock_mergedicts, mock_convert2dict, 
mock_convert2corosync):
+        '''
+        Test to check corosync_updated when configuration is applied
+        '''
+
+        ret = {'name': '/etc/corosync/corosync.conf',
+               'changes': {'change1': 1, 'change2': 2},
+               'result': True,
+               'comment': 'Corosync configuration file updated'}
+
+        mock_copy = MagicMock()
+        mock_write = MagicMock()
+        mock_convert2dict.return_value = ({'data': 1}, {})
+        mock_mergedicts.return_value = ({'updated': 2}, {'change1': 1, 
'change2': 2})
+        mock_convert2corosync.return_value = 'new content'
+
+        file_content = "my corosync file content\nmy corosync file 2nd line 
content"
+
+        with patch.dict(crmshmod.__salt__, {'file.copy': mock_copy,
+                                            'file.write': mock_write}):
+            with patch("salt.utils.files.fopen", 
mock_open(read_data=file_content)):
+                assert crmshmod.corosync_updated(
+                    name='/etc/corosync/corosync.conf',
+                    data={'my_data': 1}) == ret
+
+        mock_convert2dict.assert_called_once_with(
+            ['my corosync file content', 'my corosync file 2nd line content']
+        )
+        mock_mergedicts.assert_called_once_with(
+            {'data': 1}, {'my_data': 1}, {})
+
+        mock_convert2corosync.assert_called_once_with({'updated': 2})
+
+        mock_copy.assert_called_once_with(
+            '/etc/corosync/corosync.conf', 
'/etc/corosync/corosync.conf.backup')
+
+        mock_write.assert_called_once_with(
+            '/etc/corosync/corosync.conf', 'new content')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/salt-shaptools-0.3.1/tests/unit/states/test_hanamod.py 
new/salt-shaptools-0.3.4/tests/unit/states/test_hanamod.py
--- old/salt-shaptools-0.3.1/tests/unit/states/test_hanamod.py  2020-03-06 
15:03:43.200091220 +0100
+++ new/salt-shaptools-0.3.4/tests/unit/states/test_hanamod.py  2020-03-31 
20:02:39.980481668 +0200
@@ -262,7 +262,7 @@
             assert hanamod.installed(
                 'prd', '00', 'pass', '/software',
                 'root', 'pass') == ret
-            
+
             mock_create.assert_called_once_with(
                 software_path='/software',
                 conf_file=hanamod.TMP_CONFIG_FILE,
@@ -1041,3 +1041,64 @@
                 sid='prd',
                 inst='00',
                 password='pass')
+
+    def test_pydbapi_extracted_already_exists(self):
+        ret = {'name': 'PYDBAPI.tar',
+               'changes': {},
+               'result': True,
+               'comment': '/tmp/output already exists. Skipping extraction 
(set force to True to force the extraction)'}
+
+        mock_dir_exists = MagicMock(return_value=True)
+
+        with patch.dict(hanamod.__salt__, {'file.directory_exists': 
mock_dir_exists}):
+            assert hanamod.pydbapi_extracted(
+                'PYDBAPI.tar', ['1234', '5678'], '/tmp/output') == ret
+
+        mock_dir_exists.assert_called_once_with('/tmp/output')
+
+    def test_pydbapi_extracted_test(self):
+        ret = {'name': 'PYDBAPI.tar',
+               'changes': {'output_dir': '/tmp/output'},
+               'result': None,
+               'comment': 'PYDBAPI.tar would be extracted'}
+
+        with patch.dict(hanamod.__opts__, {'test': True}):
+            assert hanamod.pydbapi_extracted(
+                'PYDBAPI.tar', ['1234', '5678'], '/tmp/output', force=True) == 
ret
+
+    def test_pydbapi_extracted_error(self):
+        ret = {'name': 'PYDBAPI.tar',
+               'changes': {},
+               'result': False,
+               'comment': 'error extracting'}
+
+        mock_mkdir = MagicMock()
+        mock_extract_pydbapi = MagicMock(
+            side_effect=exceptions.CommandExecutionError('error extracting'))
+
+        with patch.dict(hanamod.__salt__, {'file.mkdir': mock_mkdir,
+                                           'hana.extract_pydbapi': 
mock_extract_pydbapi}):
+            assert hanamod.pydbapi_extracted(
+                'PYDBAPI.tar', ['1234', '5678'], '/tmp/output', force=True) == 
ret
+
+        mock_mkdir.assert_called_once_with('/tmp/output')
+        mock_extract_pydbapi.assert_called_once_with(
+            'PYDBAPI.tar', ['1234', '5678'], '/tmp/output', '20')
+
+    def test_pydbapi_extracted_correct(self):
+        ret = {'name': 'PYDBAPI.tar',
+               'changes': {'pydbapi': 'py_client', 'output_dir': 
'/tmp/output'},
+               'result': True,
+               'comment': 'py_client correctly extracted'}
+
+        mock_mkdir = MagicMock()
+        mock_extract_pydbapi = MagicMock(return_value='py_client')
+
+        with patch.dict(hanamod.__salt__, {'file.mkdir': mock_mkdir,
+                                           'hana.extract_pydbapi': 
mock_extract_pydbapi}):
+            assert hanamod.pydbapi_extracted(
+                'PYDBAPI.tar', ['1234', '5678'], '/tmp/output', force=True) == 
ret
+
+        mock_mkdir.assert_called_once_with('/tmp/output')
+        mock_extract_pydbapi.assert_called_once_with(
+            'PYDBAPI.tar', ['1234', '5678'], '/tmp/output', '20')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/salt-shaptools-0.3.1/tests/unit/states/test_sapcarmod.py 
new/salt-shaptools-0.3.4/tests/unit/states/test_sapcarmod.py
--- old/salt-shaptools-0.3.1/tests/unit/states/test_sapcarmod.py        
1970-01-01 01:00:00.000000000 +0100
+++ new/salt-shaptools-0.3.4/tests/unit/states/test_sapcarmod.py        
2020-03-31 20:02:39.980481668 +0200
@@ -0,0 +1,90 @@
+
+# -*- coding: utf-8 -*-
+'''
+    :codeauthor: Simranpal Singh <sisi...@suse.com>
+'''
+# Import Python libs
+from __future__ import absolute_import, unicode_literals, print_function
+
+from salt import exceptions
+
+# Import Salt Testing Libs
+from tests.support.mixins import LoaderModuleMockMixin
+from tests.support.unit import skipIf, TestCase
+from tests.support import mock
+from tests.support.mock import (
+    NO_MOCK,
+    NO_MOCK_REASON,
+    MagicMock,
+    patch
+)
+
+# Import Salt Libs
+import salt.states.sapcarmod as sapcar
+
+
+@skipIf(NO_MOCK, NO_MOCK_REASON)
+class SapcarmodTestCase(TestCase, LoaderModuleMockMixin):
+    '''
+    Test cases for salt.states.sapcarmod
+    '''
+    def setup_loader_modules(self):
+        return {sapcar: {'__opts__': {'test': False}}}
+
+    def test_available_test(self):
+        '''
+        Test to check extracted in test mode
+        '''
+
+        ret = {'name': '/sapmedia/IMDB_SERVER_LINUX.SAR',
+               'changes': {'output_dir': '/sapmedia'},
+               'result': None,
+               'comment': '/sapmedia/IMDB_SERVER_LINUX.SAR would be extracted'}
+
+        with patch.dict(sapcar.__opts__, {'test': True}):
+            assert sapcar.extracted(
+                name='/sapmedia/IMDB_SERVER_LINUX.SAR',  
output_dir='/sapmedia',
+                sapcar_exe='/sapmedia/SAPCAR')
+
+    def test_extracted_basic(self):
+        '''
+        Test to check extracted when sapcar successfully extracts a sar file
+        '''
+
+        expected_ret = {
+            'name': '/sapmedia/IMDB_SERVER_LINUX.SAR',
+            'changes': {'output_dir': '/sapmedia'},
+            'result': True,
+            'comment': '/sapmedia/IMDB_SERVER_LINUX.SAR file extracted'
+        }
+
+        mock_extract = MagicMock()
+        with patch.dict(sapcar.__salt__, {
+                'sapcar.extract': mock_extract}):
+            assert sapcar.extracted(
+                name='/sapmedia/IMDB_SERVER_LINUX.SAR',  
output_dir='/sapmedia',
+                sapcar_exe='/sapmedia/SAPCAR') == expected_ret
+        mock_extract.assert_called_once_with(
+            sapcar_exe='/sapmedia/SAPCAR', 
sar_file='/sapmedia/IMDB_SERVER_LINUX.SAR',
+            output_dir='/sapmedia', options=None)
+
+    def test_extracted_error_exception(self):
+        '''
+        Test to check extracted when sapcar fails to extracts a sar file
+        '''
+
+        expected_ret = {
+            'changes': {},
+            'result': False,
+            'name': '/sapmedia/IMDB_SERVER_LINUX.SAR',
+            'comment': 'sapcar error'
+        }
+
+        mock_extract = 
MagicMock(side_effect=exceptions.CommandExecutionError('sapcar error'))
+        with patch.dict(sapcar.__salt__, {
+                'sapcar.extract': mock_extract}):
+            assert sapcar.extracted(
+                '/sapmedia/IMDB_SERVER_LINUX.SAR','/sapmedia/SAPCAR', 
options='-v') == expected_ret
+        mock_extract.assert_called_once_with(
+            sapcar_exe='/sapmedia/SAPCAR', 
sar_file='/sapmedia/IMDB_SERVER_LINUX.SAR',
+            output_dir=None, options='-v')


Reply via email to