diff --git a/sap/adt/atc.py b/sap/adt/atc.py index db0ae925..33886603 100644 --- a/sap/adt/atc.py +++ b/sap/adt/atc.py @@ -224,18 +224,6 @@ def run_for(self, obj_sets, max_verdicts=100): worklist = WorkList() Marshal.deserialize(resp.text, worklist) - - # increase all priorities by 1 to be in sync with SAPGui. ADT protocol sends priorities - # decreased by one - for obj in worklist.objects: - for finding in obj.findings: - # increment only if priority is integer - try: - finding_number = int(finding.priority) - finding.priority = str(finding_number + 1) - except ValueError: - pass - return WorkListRunResult(run_response, worklist) diff --git a/sap/adt/core.py b/sap/adt/core.py index dcf351d2..1d87d289 100644 --- a/sap/adt/core.py +++ b/sap/adt/core.py @@ -52,6 +52,9 @@ def endElement(self, name): self._collection = None self._mimetypes = None elif name == 'app:accept': + if not self._accept: + return + self._mimetypes.append(self._accept) self._accept = None diff --git a/sap/adt/objects.py b/sap/adt/objects.py index 02745a90..63c829cd 100644 --- a/sap/adt/objects.py +++ b/sap/adt/objects.py @@ -63,8 +63,8 @@ def find_mime_version(connection, objtype): seri_mime = next((mime for mime in mimes if mime in objtype.all_mimetypes), None) if seri_mime is None: # pylint: disable=consider-using-f-string - raise SAPCliError('Not supported mimes: {} not in {}' - .format(';'.join(mimes), ';'.join(objtype.all_mimetypes))) + raise SAPCliError('Not supported mimes for {}: "{}" not in "{}"' + .format(objtype.basepath, ';'.join(mimes), ';'.join(objtype.all_mimetypes))) version = mimetype_to_version(seri_mime) return (seri_mime, version) diff --git a/sap/platform/abap/run.py b/sap/platform/abap/run.py index 26381e86..6da9db02 100644 --- a/sap/platform/abap/run.py +++ b/sap/platform/abap/run.py @@ -2,6 +2,7 @@ import secrets import string +import warnings import sap.adt import sap.adt.checks @@ -90,6 +91,10 @@ def execute_abap(connection, user_code, prefix=DEFAULT_PREFIX, package=DEFAULT_P result = clas.execute() finally: - clas.delete() + try: + clas.delete() + except SAPCliError as delete_exception: + warn_message = f'Warning: failed to delete temporary class {class_name}: {str(delete_exception)}' + warnings.warn(warn_message, stacklevel=2) return result diff --git a/test/unit/fixtures_adt.py b/test/unit/fixtures_adt.py index 14ada59c..40ce915f 100644 --- a/test/unit/fixtures_adt.py +++ b/test/unit/fixtures_adt.py @@ -236,6 +236,20 @@ + + Stub Object With Empty Accept + + Stub Test Object + + + + + Stub Object With Empty Accept + + Stub Test Object + application/sapcli.test + + ''' diff --git a/test/unit/test_sap_adt_atc.py b/test/unit/test_sap_adt_atc.py index 0fd4816c..0a88ad73 100644 --- a/test/unit/test_sap_adt_atc.py +++ b/test/unit/test_sap_adt_atc.py @@ -261,7 +261,7 @@ def test_run_for_not_empty(self): self.assertEqual(len(atcobject.findings), 2) finding = atcobject.findings[0] - self.assertEqual(finding.priority, '2') + self.assertEqual(finding.priority, '1') self.assertEqual(finding.check_id, '005056AB5B8D1ED4BFDA1CA5D9EBA6C4') self.assertEqual(finding.check_title, 'Test Environment (CHK_ZDM)') self.assertEqual(finding.message_id, '0898') diff --git a/test/unit/test_sap_adt_connection.py b/test/unit/test_sap_adt_connection.py index 30b1606f..72af6379 100644 --- a/test/unit/test_sap_adt_connection.py +++ b/test/unit/test_sap_adt_connection.py @@ -312,6 +312,24 @@ def test_property_collection_init(self, mock_exec): self.assertIsNotNone(collection_types) self.assertIsNotNone(self.connection._collection_types) + self.assertEqual(list(self.connection.collection_types.keys()), [ + '/sap/bc/adt/bopf/businessobjects', + '/sap/bc/adt/packages', + '/sap/bc/adt/functions/groups/{groupname}/fmodules', + '/sap/bc/adt/functions/groups/{groupname}/includes', + '/sap/bc/adt/functions/groups', + '/sap/bc/adt/ddic/ddl/formatter/identifiers', + '/sap/bc/adt/sadl/gw/mde', + '/sap/bc/adt/quickfixes/evaluation', + '/sap/bc/adt/wdy/views', + '/sap/bc/adt/stub/test_accept', + ]) + + mime_stub_empty = self.connection.collection_types.get('/sap/bc/adt/stub/test_empty') + self.assertIsNone(mime_stub_empty) + + mime_stub_accept = self.connection.collection_types.get('/sap/bc/adt/stub/test_accept') + self.assertEqual(mime_stub_accept, ['application/sapcli.test']) def test_property_collection_cache(self): fake_value = Mock() diff --git a/test/unit/test_sap_adt_object.py b/test/unit/test_sap_adt_object.py index 65e48500..fb9dcd2b 100755 --- a/test/unit/test_sap_adt_object.py +++ b/test/unit/test_sap_adt_object.py @@ -239,7 +239,8 @@ def test_create_mime_not_found(self): with self.assertRaises(sap.errors.SAPCliError) as caught: victory.create() - self.assertEqual(str(caught.exception), 'Not supported mimes: application/something.else+xml not in application/vnd.sap.super.cool.txt+xml;application/vnd.sap.super.cool.txt.v2+xml') + self.assertEqual(str(caught.exception), + 'Not supported mimes for awesome/success: "application/something.else+xml" not in "application/vnd.sap.super.cool.txt+xml;application/vnd.sap.super.cool.txt.v2+xml"') def test_delete(self): conn = Connection([EMPTY_RESPONSE_OK]) diff --git a/test/unit/test_sap_platform_abap_run.py b/test/unit/test_sap_platform_abap_run.py index 6c66592a..827248b4 100644 --- a/test/unit/test_sap_platform_abap_run.py +++ b/test/unit/test_sap_platform_abap_run.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import unittest +import warnings from unittest.mock import patch, call from sap.errors import SAPCliError @@ -239,6 +240,44 @@ def test_check_failure_skips_write_and_activate_but_still_deletes(self): # Delete still happens. self.assertIn('deletion/delete', connection.execs[-1].adt_uri) + def test_delete_failure_emits_warning_instead_of_exception(self): + connection = Connection([ + EMPTY_RESPONSE_OK, # create + _make_check_response(), # check_before_save + LOCK_RESPONSE_OK, # lock + EMPTY_RESPONSE_OK, # write source + EMPTY_RESPONSE_OK, # unlock + EMPTY_RESPONSE_OK, # activate (POST) + _make_activate_response(), # fetch after activate (GET) + Response(text='output', status_code=200, + headers={'Content-Type': 'text/plain'}), # execute + Response(text='Not found', status_code=404, headers={}), # delete fails + ]) + + with patch('sap.platform.abap.run.generate_class_name', return_value=FIXED_CLASS_NAME): + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter('always') + result = execute_abap(connection, 'WRITE "hello".') + + self.assertEqual(result, 'output') + self.assertEqual(len(caught), 1) + self.assertIn(FIXED_CLASS_NAME, str(caught[0].message)) + + def test_delete_failure_after_create_failure_emits_warning(self): + connection = Connection([ + Response(text='Create failed', status_code=500, headers={}), # create fails + Response(text='Not found', status_code=404, headers={}), # delete fails too + ]) + + with patch('sap.platform.abap.run.generate_class_name', return_value=FIXED_CLASS_NAME): + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter('always') + with self.assertRaises(Exception): + execute_abap(connection, 'WRITE "hello".') + + self.assertEqual(len(caught), 1) + self.assertIn(FIXED_CLASS_NAME, str(caught[0].message)) + def test_check_disabled_via_env_skips_check_post(self): connection = Connection([ EMPTY_RESPONSE_OK, # create