Hello community,
here is the log from the commit of package python-shaptools for
openSUSE:Factory checked in at 2019-07-21 11:33:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-shaptools (Old)
and /work/SRC/openSUSE:Factory/.python-shaptools.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-shaptools"
Sun Jul 21 11:33:39 2019 rev:4 rq:716587 version:0.3.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-shaptools/python-shaptools.changes
2019-06-17 21:34:04.671014358 +0200
+++
/work/SRC/openSUSE:Factory/.python-shaptools.new.4126/python-shaptools.changes
2019-07-21 11:33:40.348784109 +0200
@@ -1,0 +2,6 @@
+Wed Jul 17 09:34:22 UTC 2019 - Xabier Arbulu Insausti <[email protected]>
+
+- Create package version 0.3.0
+- shapcli is provided to expose shaptools api methods as command line tool
+
+-------------------------------------------------------------------
Old:
----
shaptools-0.2.1.tar.gz
New:
----
shaptools-0.3.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-shaptools.spec ++++++
--- /var/tmp/diff_new_pack.xpgQtE/_old 2019-07-21 11:33:41.008783997 +0200
+++ /var/tmp/diff_new_pack.xpgQtE/_new 2019-07-21 11:33:41.008783997 +0200
@@ -22,7 +22,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-shaptools
-Version: 0.2.1
+Version: 0.3.0
Release: 0
Summary: Python tools to interact with SAP HANA utilities
License: Apache-2.0
@@ -67,5 +67,6 @@
%license LICENSE
%endif
%{python_sitelib}/*
+%python3_only %{_bindir}/shapcli
%changelog
++++++ shaptools-0.2.1.tar.gz -> shaptools-0.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/bin/shapcli
new/shaptools-0.3.0/bin/shapcli
--- old/shaptools-0.2.1/bin/shapcli 1970-01-01 01:00:00.000000000 +0100
+++ new/shaptools-0.3.0/bin/shapcli 2019-07-18 11:03:12.820176367 +0200
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+"""
+Shaptools command line tool
+"""
+
+from shaptools import shapcli
+
+if __name__ == "__main__":
+ shapcli.run()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/docs/SHAPCLI.md
new/shaptools-0.3.0/docs/SHAPCLI.md
--- old/shaptools-0.2.1/docs/SHAPCLI.md 1970-01-01 01:00:00.000000000 +0100
+++ new/shaptools-0.3.0/docs/SHAPCLI.md 2019-07-18 11:03:12.820176367 +0200
@@ -0,0 +1,51 @@
+# SHAPCLI
+
+shapcli is an executable tool to use the api provided by shaptools. It wraps
most of the commands and
+exposes them as a command line tool.
+
+In order to use the utility the `shaptools` library must be installed (either
using `pip` or `rpm` package).
+
+## Disclaimer
+
+This tool will only work if `shaptools` is installed for `python 3` version.
+
+## Motivation
+
+The major motivation behind this tools is to provide an easy way to run all of
the tools provided by
+SAP regarding HANA. It wraps the next commands: `HDB`, `hdbnsutil`,
`hdbuserstore`,
+`HDBSettings.sh`, `hdbsql`.
+
+Using this tool be avoid the need to change to SAP users every time we need to
run any of these
+commands. This is really helpful when we are running other commands in the
same time (as `crmsh`
+commands for example). Besides, having all of them gathered in the same place
makes the usage
+easier.
+
+## How to use
+
+`shapcli` can be used providing the SAP HANA database information through
command line or using a
+json configuration file (the options are mutually exclusive).
+Here an example of how to create the configuration file:
[config.json](shapcli.config.example)
+
+Here some examples:
+
+```
+shapcli -s sid -i 00 -p HANAPASSWORD hana version
+shapcli -c config.json hana version
+```
+
+Check how it works and help output running:
+
+```
+shapcli -h
+```
+
+The main options are: `hana` and `sr`;
+
+* `hana`: Commands to manage SAP HANA database general functionalities.
+* `sr`: Commands to manage SAP HANA system replication.
+
+Using the `-h` flag in each option will output a new help output. For example:
+
+```
+shapcli hana -h
+```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/docs/shapcli.config.example
new/shaptools-0.3.0/docs/shapcli.config.example
--- old/shaptools-0.2.1/docs/shapcli.config.example 1970-01-01
01:00:00.000000000 +0100
+++ new/shaptools-0.3.0/docs/shapcli.config.example 2019-07-18
11:03:12.820176367 +0200
@@ -0,0 +1,5 @@
+{
+ "sid": "prd",
+ "instance": "00",
+ "password": "HANAPASSWORD"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/python-shaptools.changes
new/shaptools-0.3.0/python-shaptools.changes
--- old/shaptools-0.2.1/python-shaptools.changes 2019-06-12
15:57:43.139230730 +0200
+++ new/shaptools-0.3.0/python-shaptools.changes 2019-07-18
11:03:12.820176367 +0200
@@ -1,4 +1,10 @@
-------------------------------------------------------------------
+Wed Jul 17 09:34:22 UTC 2019 - Xabier Arbulu Insausti <[email protected]>
+
+- Create package version 0.3.0
+- shapcli is provided to expose shaptools api methods as command line tool
+
+-------------------------------------------------------------------
Tue Jun 11 11:29:44 UTC 2019 - Xabier Arbulu Insausti <[email protected]>
- Create package version 0.2.1 with fixed spec files. Now the package
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/python-shaptools.spec
new/shaptools-0.3.0/python-shaptools.spec
--- old/shaptools-0.2.1/python-shaptools.spec 2019-06-12 15:57:43.139230730
+0200
+++ new/shaptools-0.3.0/python-shaptools.spec 2019-07-18 11:03:12.820176367
+0200
@@ -22,7 +22,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-shaptools
-Version: 0.2.1
+Version: 0.3.0
Release: 0
Summary: Python tools to interact with SAP HANA utilities
License: Apache-2.0
@@ -67,5 +67,6 @@
%license LICENSE
%endif
%{python_sitelib}/*
+%python3_only %{_bindir}/shapcli
%changelog
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/setup.py new/shaptools-0.3.0/setup.py
--- old/shaptools-0.2.1/setup.py 2019-06-12 15:57:43.139230730 +0200
+++ new/shaptools-0.3.0/setup.py 2019-07-18 11:03:12.820176367 +0200
@@ -40,7 +40,7 @@
]
-SCRIPTS = []
+SCRIPTS = ['bin/shapcli']
DEPENDENCIES = read('requirements.txt').split()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/shaptools/__init__.py
new/shaptools-0.3.0/shaptools/__init__.py
--- old/shaptools-0.2.1/shaptools/__init__.py 2019-06-12 15:57:43.139230730
+0200
+++ new/shaptools-0.3.0/shaptools/__init__.py 2019-07-18 11:03:12.820176367
+0200
@@ -6,4 +6,4 @@
:since: 2018-11-15
"""
-__version__ = "0.2.1"
+__version__ = "0.3.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/shaptools/shapcli.py
new/shaptools-0.3.0/shaptools/shapcli.py
--- old/shaptools-0.2.1/shaptools/shapcli.py 1970-01-01 01:00:00.000000000
+0100
+++ new/shaptools-0.3.0/shaptools/shapcli.py 2019-07-18 11:03:12.820176367
+0200
@@ -0,0 +1,353 @@
+"""
+Code to expose some useful methods using the command line
+
+:author: xarbulu
+:organization: SUSE LLC
+:contact: [email protected]
+
+:since: 2019-07-11
+"""
+
+import logging
+import argparse
+import json
+
+from shaptools import hana
+
+PROG = 'shapcli'
+LOGGING_FORMAT = '%(message)s'
+
+
+class DecodedFormatter(logging.Formatter):
+ """
+ Custom formatter to remove the b'' from the logged text
+ """
+
+ def format(self, record):
+ message = super(DecodedFormatter, self).format(record)
+ if message.startswith('b\''):
+ message = message.split('\'')[1]
+ return message
+
+
+def setup_logger(level):
+ """
+ Setup logging
+ """
+ logger = logging.getLogger()
+ handler = logging.StreamHandler()
+ formatter = DecodedFormatter(LOGGING_FORMAT)
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+ logger.setLevel(level=level)
+ return logger
+
+
+def parse_arguments():
+ """
+ Parse command line arguments
+ """
+ parser = argparse.ArgumentParser(PROG)
+
+ parser.add_argument(
+ '-v', '--verbosity',
+ help='Python logging level. Options: DEBUG, INFO, WARN, ERROR (INFO by
default)')
+ parser.add_argument(
+ '-r', '--remotely',
+ help='Run the command in other machine using ssh')
+ parser.add_argument(
+ '-c', '--config',
+ help='JSON configuration file with SAP HANA instance data (sid,
instance and password)')
+ parser.add_argument(
+ '-s', '--sid', help='SAP HANA sid')
+ parser.add_argument(
+ '-i', '--instance', help='SAP HANA instance')
+ parser.add_argument(
+ '-p', '--password', help='SAP HANA password')
+
+ subcommands = parser.add_subparsers(
+ title='subcommands', description='valid subcommands', help='additional
help')
+ hana_subparser = subcommands.add_parser(
+ 'hana', help='Commands to interact with SAP HANA databse')
+ sr_subparser = subcommands.add_parser(
+ 'sr', help='Commands to interact with SAP HANA system replication')
+
+ parse_hana_arguments(hana_subparser)
+ parse_sr_arguments(sr_subparser)
+
+ args = parser.parse_args()
+ return parser, args
+
+
+def parse_hana_arguments(hana_subparser):
+ """
+ Parse hana subcommand arguements
+ """
+ subcommands = hana_subparser.add_subparsers(
+ title='hana', dest='hana', help='Commands to interact with SAP HANA
databse')
+ subcommands.add_parser(
+ 'is_running', help='Check if SAP HANA database is running')
+ subcommands.add_parser(
+ 'version', help='Show SAP HANA database version')
+ subcommands.add_parser(
+ 'start', help='Start SAP HANA database')
+ subcommands.add_parser(
+ 'stop', help='Stop SAP HANA database')
+ subcommands.add_parser(
+ 'info', help='Show SAP HANA database information')
+ subcommands.add_parser(
+ 'kill', help='Kill all SAP HANA database processes')
+ subcommands.add_parser(
+ 'overview', help='Show SAP HANA database overview')
+ subcommands.add_parser(
+ 'landscape', help='Show SAP HANA database landscape')
+ subcommands.add_parser(
+ 'uninstall', help='Uninstall SAP HANA database instance')
+ dummy = subcommands.add_parser(
+ 'dummy', help='Get data from DUMMY table')
+ dummy.add_argument(
+ '--key_name',
+ help='Keystore to connect to sap hana db '\
+ '(if this value is set user, password and database are omitted')
+ dummy.add_argument(
+ '--user_name', help='User to connect to sap hana db')
+ dummy.add_argument(
+ '--user_password', help='Password to connect to sap hana db')
+ dummy.add_argument(
+ '--database', help='Database name to connect')
+
+ hdbsql = subcommands.add_parser(
+ 'hdbsql', help='Run a sql command with hdbsql')
+ hdbsql.add_argument(
+ '--key_name',
+ help='Keystore to connect to sap hana db '\
+ '(if this value is set user, password and database are omitted')
+ hdbsql.add_argument(
+ '--user_name', help='User to connect to sap hana db')
+ hdbsql.add_argument(
+ '--user_password', help='Password to connect to sap hana db')
+ hdbsql.add_argument(
+ '--database', help='Database name to connect')
+ hdbsql.add_argument(
+ '--query', help='Query to execute')
+
+ user_key = subcommands.add_parser(
+ 'user', help='Create a new user key')
+ user_key.add_argument(
+ '--key_name', help='Key name', required=True)
+ user_key.add_argument(
+ '--environment', help='Database location (host:port)', required=True)
+ user_key.add_argument(
+ '--user_name', help='User to connect to sap hana db', required=True)
+ user_key.add_argument(
+ '--user_password', help='Password to connect to sap hana db',
required=True)
+ user_key.add_argument(
+ '--database', help='Database name to connect', required=True)
+
+ backup = subcommands.add_parser(
+ 'backup', help='Create node backup')
+ backup.add_argument(
+ '--name', help='Backup file name', required=True)
+ backup.add_argument(
+ '--database', help='Database name to connect', required=True)
+ backup.add_argument(
+ '--key_name', help='Key name')
+ backup.add_argument(
+ '--user_name', help='User to connect to sap hana db')
+ backup.add_argument(
+ '--user_password', help='Password to connect to sap hana db')
+
+
+def parse_sr_arguments(sr_subparser):
+ """
+ Parse hana sr subcommand arguements
+ """
+ subcommands = sr_subparser.add_subparsers(
+ title='sr', dest='sr', help='Commands to interact with SAP HANA system
replication')
+ state = subcommands.add_parser(
+ 'state', help='Show SAP HANA system replication state')
+ state.add_argument('--sapcontrol', help='Run with sapcontrol',
action='store_true')
+ status = subcommands.add_parser(
+ 'status', help='Show SAP HANAsystem replication status')
+ status.add_argument('--sapcontrol', help='Run with sapcontrol',
action='store_true')
+ subcommands.add_parser(
+ 'disable', help='Disable SAP HANA system replication (to be executed
in Primary node)')
+ cleanup = subcommands.add_parser(
+ 'cleanup', help='Cleanup SAP HANA system replication')
+ cleanup.add_argument('--force', help='Force the cleanup',
action='store_true')
+ subcommands.add_parser(
+ 'takeover', help='Perform a takeover operation (to be executed in
Secondary node)')
+ enable = subcommands.add_parser(
+ 'enable', help='Enable SAP HANA system replication primary site')
+ enable.add_argument('--name', help='Primary site name', required=True)
+ register = subcommands.add_parser(
+ 'register', help='Register SAP HANA system replication secondary site')
+ register.add_argument('--name', help='Secondary site name', required=True)
+ register.add_argument('--remote_host', help='Primary site hostname',
required=True)
+ register.add_argument(
+ '--remote_instance', help='Primary site SAP HANA instance number',
required=True)
+ register.add_argument(
+ '--replication_mode', help='System replication replication mode',
default='sync')
+ register.add_argument(
+ '--operation_mode', help='System replication operation mode',
default='logreplay')
+ unregister = subcommands.add_parser(
+ 'unregister', help='Unegister SAP HANA system replication secondary
site')
+ unregister.add_argument('--name', help='Primary site name', required=True)
+ copy_ssfs = subcommands.add_parser(
+ 'copy_ssfs', help='Copy current node ssfs files to other host')
+ copy_ssfs.add_argument('--remote_host', help='Other host name',
required=True)
+ copy_ssfs.add_argument(
+ '--remote_password',
+ help='Other host SAP HANA instance password (sid and instance must
match '\
+ 'with the current host)', required=True)
+
+
+# pylint:disable=W0212
+def uninstall(hana_instance, logger):
+ """
+ Uninstall SAP HANA database instance
+ """
+ logger.info(
+ 'This command will uninstall SAP HANA instance '\
+ 'with sid %s and instance number %s (y/n): ',
+ hana_instance.sid, hana_instance.inst)
+ response = input()
+ if response == 'y':
+ user = hana.HanaInstance.HANAUSER.format(sid=hana_instance.sid)
+ hana_instance.uninstall(user, hana_instance._password)
+ else:
+ logger.info('Command execution canceled')
+
+
+def run_hdbsql(hana_instance, hana_args, cmd):
+ """
+ Run hdbsql command
+ """
+ hdbsql_cmd = hana_instance._hdbsql_connect(
+ key_name=hana_args.key_name,
+ user_name=hana_args.user_name,
+ user_password=hana_args.user_password)
+ cmd = '{hdbsql_cmd} {database}\\"{cmd}\\"'.format(
+ hdbsql_cmd=hdbsql_cmd,
+ database='-d {} '.format(hana_args.database) if hana_args.database
else '',
+ cmd=cmd)
+ hana_instance._run_hana_command(cmd)
+
+def run_hana_subcommands(hana_instance, hana_args, logger):
+ """
+ Run hana subcommands
+ """
+ str_args = hana_args.hana
+ if str_args == 'is_running':
+ result = hana_instance.is_running()
+ logger.info('SAP HANA database running state: %s', result)
+ elif str_args == 'version':
+ hana_instance.get_version()
+ elif str_args == 'start':
+ hana_instance.start()
+ elif str_args == 'stop':
+ hana_instance.stop()
+ elif str_args == 'info':
+ hana_instance._run_hana_command('HDB info')
+ elif str_args == 'kill':
+ hana_instance._run_hana_command('HDB kill-9')
+ elif str_args == 'overview':
+ hana_instance._run_hana_command('HDBSettings.sh systemOverview.py')
+ elif str_args == 'landscape':
+ hana_instance._run_hana_command('HDBSettings.sh
landscapeHostConfiguration.py')
+ elif str_args == 'uninstall':
+ uninstall(hana_instance, logger)
+ elif str_args == 'dummy':
+ run_hdbsql(hana_instance, hana_args, 'SELECT * FROM DUMMY')
+ elif str_args == 'hdbsql':
+ run_hdbsql(hana_instance, hana_args, hana_args.query)
+ elif str_args == 'user':
+ hana_instance.create_user_key(
+ hana_args.key_name, hana_args.environment, hana_args.user_name,
+ hana_args.user_password, hana_args.database)
+ elif str_args == 'backup':
+ hana_instance.create_backup(
+ hana_args.database, hana_args.name, hana_args.key_name,
+ hana_args.user_name, hana_args.user_password)
+
+
+def run_sr_subcommands(hana_instance, sr_args, logger):
+ """
+ Run hana subcommands
+ """
+ str_args = sr_args.sr
+ if str_args == 'state':
+ # hana_instance.get_sr_state()
+ cmd = 'hdbnsutil -sr_state{}'.format(' --sapcontrol=1' if
sr_args.sapcontrol else '')
+ hana_instance._run_hana_command(cmd)
+ elif str_args == 'status':
+ # hana_instance.get_sr_status()
+ cmd = 'HDBSettings.sh systemReplicationStatus.py{}'.format(
+ ' --sapcontrol=1' if sr_args.sapcontrol else '')
+ hana_instance._run_hana_command(cmd)
+ elif str_args == 'disable':
+ hana_instance.sr_disable_primary()
+ elif str_args == 'cleanup':
+ hana_instance.sr_cleanup(sr_args.force)
+ elif str_args == 'takeover':
+ hana_instance._run_hana_command('hdbnsutil -sr_takeover')
+ elif str_args == 'enable':
+ hana_instance.sr_enable_primary(sr_args.name)
+ elif str_args == 'register':
+ hana_instance.sr_register_secondary(
+ sr_args.name, sr_args.remote_host, sr_args.remote_instance,
+ sr_args.replication_mode, sr_args.operation_mode)
+ elif str_args == 'unregister':
+ hana_instance.sr_unregister_secondary(sr_args.name)
+ elif str_args == 'copy_ssfs':
+ hana_instance.copy_ssfs_files(sr_args.remote_host,
sr_args.remote_password)
+
+
+def load_config_file(config_file, logger):
+ """
+ Load configuration file data
+ """
+ with open(config_file, 'r') as f_ptr:
+ json_data = json.load(f_ptr)
+ try:
+ return (json_data['sid'], json_data['instance'], json_data['password'])
+ except KeyError as err:
+ logger.error(err)
+ logger.error('Configuration file must have the sid, instance and
password entries')
+ raise
+
+
+# pylint:disable=W0212
+def run():
+ """
+ Main execution
+ """
+ parser, args = parse_arguments()
+ logger = setup_logger(args.verbosity or logging.DEBUG)
+
+ if args.config:
+ sid, instance, password = load_config_file(args.config, logger)
+ elif args.sid and args.instance and args.password:
+ sid = args.sid
+ instance = args.instance
+ password = args.password
+ else:
+ logger.info(
+ 'Configuration file or sid,instance and passwords parameters must
be provided\n')
+ parser.print_help()
+ exit(1)
+ try:
+ hana_instance = hana.HanaInstance(sid, instance, password)
+ if vars(args).get('hana'):
+ run_hana_subcommands(hana_instance, args, logger)
+ elif vars(args).get('sr'):
+ run_sr_subcommands(hana_instance, args, logger)
+ else:
+ parser.print_help()
+ except Exception as err:
+ logger.error(err)
+ exit(1)
+
+
+if __name__ == "__main__": # pragma: no cover
+ run()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/shaptools-0.2.1/tests/shapcli_test.py
new/shaptools-0.3.0/tests/shapcli_test.py
--- old/shaptools-0.2.1/tests/shapcli_test.py 1970-01-01 01:00:00.000000000
+0100
+++ new/shaptools-0.3.0/tests/shapcli_test.py 2019-07-18 11:03:12.824176437
+0200
@@ -0,0 +1,613 @@
+"""
+Unitary tests for shaptools/shapcli.py.
+
+:author: xarbulu
+:organization: SUSE LLC
+:contact: [email protected]
+
+:since: 2019-07-16
+"""
+
+# pylint:disable=C0103,C0111,W0212,W0611
+
+import os
+import sys
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
'..')))
+
+import logging
+
+try:
+ from unittest import mock
+except ImportError:
+ import mock
+
+import pytest
+
+from shaptools import shapcli
+
+
+class TestShapCli(object):
+ """
+ Unitary tests for shaptools/shapcli.py.
+ """
+
+ def test_format(self):
+ mock_record = mock.Mock(
+ name='test',
+ level=1,
+ pathname='path',
+ lineno=1,
+ msg='msg',
+ args=(),
+ exc_info=None,
+ exc_text=None,
+ stack_info=None
+ )
+ mock_record.getMessage.return_value = 'msg'
+ formatter = shapcli.DecodedFormatter()
+ message = formatter.format(mock_record)
+ assert message == 'msg'
+
+ mock_record.getMessage.return_value = "b'msg'"
+ formatter = shapcli.DecodedFormatter()
+ message = formatter.format(mock_record)
+ assert message == 'msg'
+
+ @mock.patch('logging.getLogger')
+ @mock.patch('logging.StreamHandler')
+ @mock.patch('shaptools.shapcli.DecodedFormatter')
+ def test_setup_logger(self, mock_formatter, mock_stream_handler,
mock_get_logger):
+
+ mock_logger_instance = mock.Mock()
+ mock_get_logger.return_value = mock_logger_instance
+
+ mock_stream_instance = mock.Mock()
+ mock_stream_handler.return_value = mock_stream_instance
+
+ mock_formatter_instance = mock.Mock()
+ mock_formatter.return_value = mock_formatter_instance
+
+ logger = shapcli.setup_logger('INFO')
+
+ mock_formatter.assert_called_once_with(shapcli.LOGGING_FORMAT)
+ mock_stream_handler.assert_called_once_with()
+ mock_get_logger.assert_called_once_with()
+
mock_stream_instance.setFormatter.assert_called_once_with(mock_formatter_instance)
+
+
mock_logger_instance.addHandler.assert_called_once_with(mock_stream_instance)
+ mock_logger_instance.setLevel.assert_called_once_with(level='INFO')
+
+ assert logger == mock_logger_instance
+
+ @mock.patch('argparse.ArgumentParser')
+ @mock.patch('shaptools.shapcli.parse_hana_arguments')
+ @mock.patch('shaptools.shapcli.parse_sr_arguments')
+ def test_parse_arguments(
+ self, mock_parse_sr_arguments, mock_parse_hana_arguments,
mock_argument_parser):
+
+ mock_argument_parser_instance = mock.Mock()
+ mock_argument_parser.return_value = mock_argument_parser_instance
+ mock_argument_parser_instance.parse_args.return_value = 'args'
+
+ mock_subcommands = mock.Mock()
+ mock_argument_parser_instance.add_subparsers.return_value =
mock_subcommands
+
+ mock_hana = mock.Mock()
+ mock_sr = mock.Mock()
+ mock_subcommands.add_parser.side_effect = [mock_hana, mock_sr]
+
+ my_parser, my_args = shapcli.parse_arguments()
+
+ mock_argument_parser.assert_called_once_with(shapcli.PROG)
+
+ mock_argument_parser_instance.add_argument.assert_has_calls([
+ mock.call('-v', '--verbosity',
+ help='Python logging level. Options: DEBUG, INFO, WARN, ERROR
(INFO by default)'),
+ mock.call('-r', '--remotely',
+ help='Run the command in other machine using ssh'),
+ mock.call('-c', '--config',
+ help='JSON configuration file with SAP HANA instance data
(sid, instance and password)'),
+ mock.call('-s', '--sid',
+ help='SAP HANA sid'),
+ mock.call('-i', '--instance',
+ help='SAP HANA instance'),
+ mock.call('-p', '--password',
+ help='SAP HANA password')
+ ])
+
+ assert mock_argument_parser_instance.add_argument.call_count == 6
+
+ mock_argument_parser_instance.add_subparsers.assert_called_once_with(
+ title='subcommands', description='valid subcommands',
help='additional help')
+
+ mock_subcommands.add_parser.assert_has_calls([
+ mock.call('hana', help='Commands to interact with SAP HANA
databse'),
+ mock.call('sr', help='Commands to interact with SAP HANA system
replication')
+ ])
+
+ mock_parse_sr_arguments.assert_called_once_with(mock_sr)
+ mock_parse_hana_arguments.assert_called_once_with(mock_hana)
+
+ mock_argument_parser_instance.parse_args.assert_called_once_with()
+
+ assert my_parser == mock_argument_parser_instance
+ assert my_args == 'args'
+
+ def test_parse_hana_arguments(self):
+
+ mock_subparser = mock.Mock()
+ mock_subcommands = mock.Mock()
+ mock_subparser.add_subparsers.return_value = mock_subcommands
+
+ mock_dummy = mock.Mock()
+ mock_hdbsql = mock.Mock()
+ mock_user_key = mock.Mock()
+ mock_backup = mock.Mock()
+
+ mock_subcommands.add_parser.side_effect = [
+ None, None, None, None, None, None, None, None, None,
+ mock_dummy, mock_hdbsql, mock_user_key, mock_backup
+ ]
+
+ shapcli.parse_hana_arguments(mock_subparser)
+
+ mock_subparser.add_subparsers.assert_called_once_with(
+ title='hana', dest='hana', help='Commands to interact with SAP
HANA databse')
+
+ mock_subcommands.add_parser.assert_has_calls([
+ mock.call('is_running', help='Check if SAP HANA database is
running'),
+ mock.call('version', help='Show SAP HANA database version'),
+ mock.call('start', help='Start SAP HANA database'),
+ mock.call('stop', help='Stop SAP HANA database'),
+ mock.call('info', help='Show SAP HANA database information'),
+ mock.call('kill', help='Kill all SAP HANA database processes'),
+ mock.call('overview', help='Show SAP HANA database overview'),
+ mock.call('landscape', help='Show SAP HANA database landscape'),
+ mock.call('uninstall', help='Uninstall SAP HANA database
instance'),
+ mock.call('dummy', help='Get data from DUMMY table'),
+ mock.call('hdbsql', help='Run a sql command with hdbsql'),
+ mock.call('user', help='Create a new user key'),
+ mock.call('backup', help='Create node backup')
+ ])
+
+ mock_dummy.add_argument.assert_has_calls([
+ mock.call('--key_name',
+ help='Keystore to connect to sap hana db '\
+ '(if this value is set user, password and database are
omitted'),
+ mock.call('--user_name', help='User to connect to sap hana db'),
+ mock.call('--user_password', help='Password to connect to sap hana
db'),
+ mock.call('--database', help='Database name to connect')
+ ])
+
+ mock_hdbsql.add_argument.assert_has_calls([
+ mock.call('--key_name',
+ help='Keystore to connect to sap hana db '\
+ '(if this value is set user, password and database are
omitted'),
+ mock.call('--user_name', help='User to connect to sap hana db'),
+ mock.call('--user_password', help='Password to connect to sap hana
db'),
+ mock.call('--database', help='Database name to connect'),
+ mock.call('--query', help='Query to execute')
+ ])
+
+ mock_user_key.add_argument.assert_has_calls([
+ mock.call('--key_name', help='Key name', required=True),
+ mock.call('--environment', help='Database location (host:port)',
required=True),
+ mock.call('--user_name', help='User to connect to sap hana db',
required=True),
+ mock.call('--user_password', help='Password to connect to sap hana
db', required=True),
+ mock.call('--database', help='Database name to connect',
required=True)
+ ])
+
+ mock_backup.add_argument.assert_has_calls([
+ mock.call('--name', help='Backup file name', required=True),
+ mock.call('--database', help='Database name to connect',
required=True),
+ mock.call('--key_name', help='Key name'),
+ mock.call('--user_name', help='User to connect to sap hana db'),
+ mock.call('--user_password', help='Password to connect to sap hana
db')
+ ])
+
+ def test_parse_sr_arguments(self):
+
+ mock_subparser = mock.Mock()
+ mock_subcommands = mock.Mock()
+ mock_subparser.add_subparsers.return_value = mock_subcommands
+
+ mock_state = mock.Mock()
+ mock_status = mock.Mock()
+ mock_cleanup = mock.Mock()
+ mock_enable= mock.Mock()
+ mock_register = mock.Mock()
+ mock_unregister= mock.Mock()
+ mock_copy_ssfs= mock.Mock()
+
+ mock_subcommands.add_parser.side_effect = [
+ mock_state, mock_status, None, mock_cleanup, None, mock_enable,
+ mock_register, mock_unregister, mock_copy_ssfs
+ ]
+
+ shapcli.parse_sr_arguments(mock_subparser)
+
+ mock_subparser.add_subparsers.assert_called_once_with(
+ title='sr', dest='sr', help='Commands to interact with SAP HANA
system replication')
+
+ mock_subcommands.add_parser.assert_has_calls([
+ mock.call('state', help='Show SAP HANA system replication state'),
+ mock.call('status', help='Show SAP HANAsystem replication status'),
+ mock.call('disable', help='Disable SAP HANA system replication (to
be executed in Primary node)'),
+ mock.call('cleanup', help='Cleanup SAP HANA system replication'),
+ mock.call('takeover', help='Perform a takeover operation (to be
executed in Secondary node)'),
+ mock.call('enable', help='Enable SAP HANA system replication
primary site'),
+ mock.call('register', help='Register SAP HANA system replication
secondary site'),
+ mock.call('unregister', help='Unegister SAP HANA system
replication secondary site'),
+ mock.call('copy_ssfs', help='Copy current node ssfs files to other
host')
+ ])
+
+ mock_state.add_argument.assert_called_once_with(
+ '--sapcontrol', help='Run with sapcontrol', action='store_true')
+
+ mock_status.add_argument.assert_called_once_with(
+ '--sapcontrol', help='Run with sapcontrol', action='store_true')
+
+ mock_cleanup.add_argument.assert_called_once_with(
+ '--force', help='Force the cleanup', action='store_true'),
+
+ mock_enable.add_argument.assert_called_once_with(
+ '--name', help='Primary site name', required=True)
+
+ mock_register.add_argument.assert_has_calls([
+ mock.call('--name', help='Secondary site name', required=True),
+ mock.call('--remote_host', help='Primary site hostname',
required=True),
+ mock.call('--remote_instance', help='Primary site SAP HANA
instance number', required=True),
+ mock.call('--replication_mode', help='System replication
replication mode', default='sync'),
+ mock.call('--operation_mode', help='System replication operation
mode', default='logreplay')
+ ])
+
+ mock_unregister.add_argument.assert_called_once_with(
+ '--name', help='Primary site name', required=True)
+
+ mock_copy_ssfs.add_argument.assert_has_calls([
+ mock.call('--remote_host', help='Other host name', required=True),
+ mock.call('--remote_password',
+ help='Other host SAP HANA instance password (sid and instance
must match '\
+ 'with the current host)', required=True)
+ ])
+
+ @mock.patch('shaptools.shapcli.input')
+ def test_uninstall(self, mock_input):
+
+ mock_hana_instance = mock.Mock(sid='prd', inst='00', _password='pass')
+ mock_logger = mock.Mock()
+ mock_input.return_value = 'y'
+
+ shapcli.uninstall(mock_hana_instance, mock_logger)
+
+ mock_input.assert_called_once_with()
+ mock_logger.info.assert_called_once_with(
+ 'This command will uninstall SAP HANA instance '\
+ 'with sid %s and instance number %s (y/n): ', 'prd', '00')
+ mock_hana_instance.uninstall.assert_called_once_with('prdadm', 'pass')
+
+ @mock.patch('shaptools.shapcli.input')
+ def test_uninstall_cancel(self, mock_input):
+
+ mock_hana_instance = mock.Mock(sid='prd', inst='00', _password='pass')
+ mock_logger = mock.Mock()
+ mock_input.return_value = 'n'
+
+ shapcli.uninstall(mock_hana_instance, mock_logger)
+
+ mock_input.assert_called_once_with()
+ mock_logger.info.assert_has_calls([
+ mock.call(
+ 'This command will uninstall SAP HANA instance '\
+ 'with sid %s and instance number %s (y/n): ', 'prd', '00'),
+ mock.call('Command execution canceled')
+ ])
+
+ def test_run_hdbsql(self):
+ mock_hana_instance = mock.Mock(sid='prd', inst='00', _password='pass')
+ args = mock.Mock(key_name='key', user_name='user',
user_password='pass', database='db')
+
+ mock_hana_instance._hdbsql_connect.return_value = 'hdbsql'
+
+ shapcli.run_hdbsql(mock_hana_instance, args, 'cmd')
+
+ mock_hana_instance._hdbsql_connect.assert_called_once_with(
+ key_name='key', user_name='user', user_password='pass')
+
+ mock_hana_instance._run_hana_command.assert_called_once_with(
+ 'hdbsql -d db \\"cmd\\"'
+ )
+
+ @mock.patch('shaptools.shapcli.run_hdbsql')
+ @mock.patch('shaptools.shapcli.uninstall')
+ def test_run_hana_subcommands(self, mock_uninstall, mock_run_hdbsql):
+
+ mock_hana_instance = mock.Mock()
+ mock_logger = mock.Mock()
+
+ mock_hana_instance.is_running.return_value = 1
+ mock_hana_args = mock.Mock(hana='is_running')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.is_running.assert_called_once_with()
+ mock_logger.info.assert_called_once_with('SAP HANA database running
state: %s', 1)
+
+ mock_hana_args = mock.Mock(hana='version')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.get_version.assert_called_once_with()
+
+ mock_hana_args = mock.Mock(hana='start')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.start.assert_called_once_with()
+
+ mock_hana_args = mock.Mock(hana='stop')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.stop.assert_called_once_with()
+
+ mock_hana_args = mock.Mock(hana='info')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance._run_hana_command.assert_called_once_with('HDB
info')
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(hana='kill')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance._run_hana_command.assert_called_once_with('HDB
kill-9')
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(hana='overview')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+
mock_hana_instance._run_hana_command.assert_called_once_with('HDBSettings.sh
systemOverview.py')
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(hana='landscape')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+
mock_hana_instance._run_hana_command.assert_called_once_with('HDBSettings.sh
landscapeHostConfiguration.py')
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(hana='uninstall')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_uninstall.assert_called_once_with(mock_hana_instance, mock_logger)
+
+ mock_hana_args = mock.Mock(hana='dummy')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_run_hdbsql.assert_called_once_with(mock_hana_instance,
mock_hana_args, 'SELECT * FROM DUMMY')
+ mock_run_hdbsql.reset_mock()
+
+ mock_hana_args = mock.Mock(hana='hdbsql', query='query')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_run_hdbsql.assert_called_once_with(mock_hana_instance,
mock_hana_args, 'query')
+ mock_run_hdbsql.reset_mock()
+
+ mock_hana_args = mock.Mock(
+ hana='user', key_name='key', environment='env',
+ user_name='user', user_password='pass', database='db')
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.create_user_key.assert_called_once_with('key',
'env', 'user', 'pass', 'db')
+
+ mock_hana_args = mock.Mock(
+ hana='backup', database='db', key_name='key',
+ user_name='user', user_password='pass')
+ mock_hana_args.name = 'name'
+ shapcli.run_hana_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.create_backup.assert_called_once_with('db', 'name',
'key', 'user', 'pass')
+
+ def test_run_sr_subcommands(self):
+
+ mock_hana_instance = mock.Mock()
+ mock_logger = mock.Mock()
+
+ mock_hana_args = mock.Mock(sr='state', sapcontrol=True)
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ cmd = 'hdbnsutil -sr_state --sapcontrol=1'
+ mock_hana_instance._run_hana_command.assert_called_once_with(cmd)
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(sr='state', sapcontrol=False)
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ cmd = 'hdbnsutil -sr_state'
+ mock_hana_instance._run_hana_command.assert_called_once_with(cmd)
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(sr='status', sapcontrol=True)
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ cmd = 'HDBSettings.sh systemReplicationStatus.py --sapcontrol=1'
+ mock_hana_instance._run_hana_command.assert_called_once_with(cmd)
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(sr='status', sapcontrol=False)
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ cmd = 'HDBSettings.sh systemReplicationStatus.py'
+ mock_hana_instance._run_hana_command.assert_called_once_with(cmd)
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(sr='disable')
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.sr_disable_primary.assert_called_once_with()
+
+ mock_hana_args = mock.Mock(sr='cleanup', force=True)
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.sr_cleanup.assert_called_once_with(True)
+
+ mock_hana_args = mock.Mock(sr='takeover')
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+
mock_hana_instance._run_hana_command.assert_called_once_with('hdbnsutil
-sr_takeover')
+ mock_hana_instance.reset_mock()
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(sr='enable')
+ mock_hana_args.name = 'primary'
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.sr_enable_primary.assert_called_once_with('primary')
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(
+ sr='register', remote_host='remote', remote_instance='00',
+ replication_mode='repl', operation_mode='oper')
+ mock_hana_args.name = 'secondary'
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.sr_register_secondary.assert_called_once_with(
+ 'secondary', 'remote', '00', 'repl', 'oper')
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(sr='unregister')
+ mock_hana_args.name = 'secondary'
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+
mock_hana_instance.sr_unregister_secondary.assert_called_once_with('secondary')
+ mock_hana_instance.reset_mock()
+
+ mock_hana_args = mock.Mock(sr='copy_ssfs', remote_host='remote',
remote_password='pass')
+ shapcli.run_sr_subcommands(mock_hana_instance, mock_hana_args,
mock_logger)
+ mock_hana_instance.copy_ssfs_files.assert_called_once_with('remote',
'pass')
+ mock_hana_instance.reset_mock()
+
+ @mock.patch('shaptools.shapcli.json.load')
+ @mock.patch('shaptools.shapcli.open')
+ def test_load_config_file(self, mock_open, mock_json_load):
+
+ mock_logger = mock.Mock()
+ mock_json_load.return_value = {'sid': 'prd', 'instance': '00',
'password': 'pass'}
+
+ data = shapcli.load_config_file('config.json', mock_logger)
+ assert data[0] == 'prd'
+ assert data[1] == '00'
+ assert data[2] == 'pass'
+
+ @mock.patch('shaptools.shapcli.json.load')
+ @mock.patch('shaptools.shapcli.open')
+ def test_load_config_file_error(self, mock_open, mock_json_load):
+
+ mock_logger = mock.Mock()
+ mock_json_load.return_value = {'sid': 'prd', 'instance': '00'}
+
+ with pytest.raises(KeyError) as err:
+ shapcli.load_config_file('config.json', mock_logger)
+
+ mock_logger.error.assert_has_calls([
+ mock.call('Configuration file must have the sid, instance and
password entries')
+ ])
+
+ @mock.patch('shaptools.shapcli.run_hana_subcommands')
+ @mock.patch('shaptools.shapcli.hana.HanaInstance')
+ @mock.patch('shaptools.shapcli.load_config_file')
+ @mock.patch('shaptools.shapcli.setup_logger')
+ @mock.patch('shaptools.shapcli.parse_arguments')
+ def test_run_hana(
+ self, mock_parse_arguments, mock_setup_logger,
+ mock_load_config_file, mock_hana,
+ mock_run_hana_subcommands):
+
+ mock_parser = mock.Mock()
+ mock_args = mock.Mock(verbosity='INFO', config='config.json',
hana=True)
+ mock_logger = mock.Mock()
+ mock_hana_instance = mock.Mock()
+ mock_parse_arguments.return_value = [mock_parser, mock_args]
+ mock_setup_logger.return_value = mock_logger
+ mock_load_config_file.return_value = ['prd', '00', 'pass']
+ mock_hana.return_value = mock_hana_instance
+
+ shapcli.run()
+
+ mock_parse_arguments.assert_called_once_with()
+ mock_setup_logger.assert_called_once_with('INFO')
+ mock_load_config_file.assert_called_once_with('config.json',
mock_logger)
+ mock_hana.assert_called_once_with('prd', '00', 'pass')
+ mock_run_hana_subcommands.assert_called_once_with(mock_hana_instance,
mock_args, mock_logger)
+
+ @mock.patch('shaptools.shapcli.run_sr_subcommands')
+ @mock.patch('shaptools.shapcli.hana.HanaInstance')
+ @mock.patch('shaptools.shapcli.setup_logger')
+ @mock.patch('shaptools.shapcli.parse_arguments')
+ def test_run_sr(
+ self, mock_parse_arguments, mock_setup_logger,
+ mock_hana, mock_run_sr_subcommands):
+
+ mock_parser = mock.Mock()
+ mock_args = mock.Mock(
+ verbosity='INFO', config=False, sid='qas', instance='01',
password='mypass', sr=True)
+ mock_logger = mock.Mock()
+ mock_hana_instance = mock.Mock()
+ mock_parse_arguments.return_value = [mock_parser, mock_args]
+ mock_setup_logger.return_value = mock_logger
+ mock_hana.return_value = mock_hana_instance
+
+ shapcli.run()
+
+ mock_parse_arguments.assert_called_once_with()
+ mock_setup_logger.assert_called_once_with('INFO')
+ mock_hana.assert_called_once_with('qas', '01', 'mypass')
+ mock_run_sr_subcommands.assert_called_once_with(mock_hana_instance,
mock_args, mock_logger)
+
+ @mock.patch('shaptools.shapcli.hana.HanaInstance')
+ @mock.patch('shaptools.shapcli.setup_logger')
+ @mock.patch('shaptools.shapcli.parse_arguments')
+ def test_run_help(
+ self, mock_parse_arguments, mock_setup_logger, mock_hana):
+
+ mock_parser = mock.Mock()
+ mock_args = mock.Mock(
+ verbosity='INFO', config=False, sid='qas', instance='01',
password='mypass')
+ mock_logger = mock.Mock()
+ mock_hana_instance = mock.Mock()
+ mock_parse_arguments.return_value = [mock_parser, mock_args]
+ mock_setup_logger.return_value = mock_logger
+ mock_hana.return_value = mock_hana_instance
+
+ shapcli.run()
+
+ mock_parse_arguments.assert_called_once_with()
+ mock_setup_logger.assert_called_once_with('INFO')
+ mock_hana.assert_called_once_with('qas', '01', 'mypass')
+ mock_parser.print_help.assert_called_once_with()
+
+
+ @mock.patch('shaptools.shapcli.setup_logger')
+ @mock.patch('shaptools.shapcli.parse_arguments')
+ def test_run_sr_invalid_params(self, mock_parse_arguments,
mock_setup_logger):
+
+ mock_parser = mock.Mock()
+ mock_args = mock.Mock(
+ verbosity=False, config=False, sid='qas', instance='01',
password=False, sr=True)
+ mock_logger = mock.Mock()
+ mock_hana_instance = mock.Mock()
+ mock_parse_arguments.return_value = [mock_parser, mock_args]
+ mock_setup_logger.return_value = mock_logger
+
+ with pytest.raises(SystemExit) as my_exit:
+ shapcli.run()
+
+ assert my_exit.type == SystemExit
+ assert my_exit.value.code == 1
+
+ mock_parse_arguments.assert_called_once_with()
+ mock_setup_logger.assert_called_once_with(logging.DEBUG)
+ mock_logger.info.assert_called_once_with(
+ 'Configuration file or sid,instance and passwords parameters must
be provided\n')
+ mock_parser.print_help.assert_called_once_with()
+
+ @mock.patch('shaptools.shapcli.run_sr_subcommands')
+ @mock.patch('shaptools.shapcli.hana.HanaInstance')
+ @mock.patch('shaptools.shapcli.setup_logger')
+ @mock.patch('shaptools.shapcli.parse_arguments')
+ def test_run_error(
+ self, mock_parse_arguments, mock_setup_logger,
+ mock_hana, mock_run_sr_subcommands):
+
+ mock_parser = mock.Mock()
+ mock_args = mock.Mock(
+ verbosity='INFO', config=False, sid='qas', instance='01',
password='mypass', sr=True)
+ mock_logger = mock.Mock()
+ mock_hana_instance = mock.Mock()
+ mock_parse_arguments.return_value = [mock_parser, mock_args]
+ mock_setup_logger.return_value = mock_logger
+ mock_hana.return_value = mock_hana_instance
+ mock_run_sr_subcommands.side_effect = ValueError('my error')
+
+ with pytest.raises(SystemExit) as my_exit:
+ shapcli.run()
+
+ assert my_exit.type == SystemExit
+ assert my_exit.value.code == 1
+
+ mock_parse_arguments.assert_called_once_with()
+ mock_setup_logger.assert_called_once_with('INFO')
+ mock_hana.assert_called_once_with('qas', '01', 'mypass')
+ mock_run_sr_subcommands.assert_called_once_with(mock_hana_instance,
mock_args, mock_logger)