Skip to content

Commit

Permalink
tree-wide: add support for Function Group Include CRUD
Browse files Browse the repository at this point in the history
  • Loading branch information
Libor Bucek committed Sep 28, 2023
1 parent 96b4600 commit bd15041
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 8 deletions.
59 changes: 54 additions & 5 deletions doc/commands/functiongroup.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# Function Group

1. [create](#create)
2. [write](#write)
3. [activate](#activate)
4. [read](#read)
- [Function Group](#function-group)
- [create](#create)
- [write](#write)
- [activate](#activate)
- [read group](#read-group)
- [Function Group Include](#function-group-include)
- [create](#create-1)
- [write](#write-1)
- [activate](#activate-1)
- [read group](#read-group-1)

## create

Expand Down Expand Up @@ -37,10 +43,53 @@ Activates the given function group.
sapcli functiongroup activate ZFG_PARENT
```

### read group
## read group

Download main source codes of the given function group

```bash
sapcli functiongroup read ZFG_PARENT
```

## Function Group Include

### create

Creates a function group of the given name with the given description in the
given package.

```bash
sapcli functiongroup include create ZFG_PARENT ZFGI_HELLO_WORLD "Function Group Include description"
```

### write

Changes main source code of the given function group.

```
sapcli functiongroup include write [FUNCTION_GROUP_NAME] [FUNCTION_GROUP_INCLUDE_NAME] [FILE_PATH|-] [--corrnr TRANSPORT] [--activate] [--ignore-errors] [--warning-errors]
```

* _FUNCITON\_GROUP\_NAME_ function group name
* _FUNCITON\_GROUP\_INCLUDE\_NAME_ function group include name
* _FILE\_PATH_ a single file path or - for reading _stdin_
* _--corrnr TRANSPORT_ specifies CTS Transport Request Number if needed
* _--activate_ activate after finishing the write operation
* _--ignore-errors_ continue activating objects ignoring errors
* _--warning-errors_ treat activation warnings as errors

### activate

Activates the given function group.

```bash
sapcli functiongroup include activate ZFG_PARENT ZFGI_HELLO_WORLD
```

### read group

Download main source codes of the given function group

```bash
sapcli functiongroup include read ZFG_PARENT ZFGI_HELLO_WORLD
```
57 changes: 57 additions & 0 deletions sap/cli/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,72 @@
import sap.adt
import sap.cli.object

class CommandGroupFunctionGroupInclude(sap.cli.object.CommandGroupObjectTemplate):
"""Container for definition commands."""

def __init__(self):
super().__init__('include')

self.define()

def build_new_metadata(self, connection, args):
return sap.adt.ADTCoreData(language='EN', master_language='EN',
responsible=connection.user.upper())

def build_new_object(self, connection, args, metadata):
return sap.adt.FunctionInclude(connection, args.name.upper(), args.group, metadata=metadata)

def instance(self, connection, name, args, metadata=None):
return sap.adt.FunctionInclude(connection, name.upper(), args.group, metadata=metadata)

def define_create(self, commands):
create_cmd = super().define_create(commands)

# Function Modules belong to a function group and not into a package!
create_cmd.insert_argument(0, 'group')

return create_cmd

def define_read(self, commands):
read_cmd = super().define_read(commands)

# Function Modules belong to a function group and not into a package!
read_cmd.insert_argument(0, 'group')

return read_cmd

def define_write(self, commands):
write_cmd = super().define_write(commands)

# Function Modules belong to a function group and not into a package!
write_cmd.insert_argument(0, 'group')

return write_cmd

def define_activate(self, commands):
activate_cmd = super().define_activate(commands)

# Function Modules belong to a function group and not into a package!
activate_cmd.insert_argument(0, 'group')

return activate_cmd

class CommandGroupFunctionGroup(sap.cli.object.CommandGroupObjectMaster):
"""Commands for Function Groups"""

def __init__(self):
super().__init__('functiongroup')

self.function_group_include_grp = CommandGroupFunctionGroupInclude()

self.define()

def install_parser(self, arg_parser):
activation_group = super().install_parser(arg_parser)

function_group_include_parser = activation_group.add_parser(self.function_group_include_grp.name)
self.function_group_include_grp.install_parser(function_group_include_parser)

def build_new_object(self, connection, args, metadata):
return sap.adt.FunctionGroup(connection, args.name.upper(), package=args.package, metadata=metadata)

Expand Down
24 changes: 24 additions & 0 deletions test/unit/fixtures_adt_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,27 @@
ENDFUNCTION.
'''

FAKE_LOCK_HANDLE = 'lock_handle'

FUNCTION_GROUP_INCLUDE_ADT_XML='''<?xml version="1.0" encoding="utf-8"?>
<finclude:abapFunctionGroupInclude abapsource:sourceUri="source/main" adtcore:name="ZFG_I_HELLO_WORLD" adtcore:type="FUGR/I" adtcore:version="active" adtcore:description="Hello FUGR/I!" adtcore:language="EN"
xmlns:finclude="http://www.sap.com/adt/functions/fincludes"
xmlns:abapsource="http://www.sap.com/adt/abapsource"
xmlns:adtcore="http://www.sap.com/adt/core">
<adtcore:containerRef adtcore:uri="/sap/bc/adt/functions/groups/zfg_hello_world" adtcore:type="FUGR/F" adtcore:name="ZFG_HELLO_WORLD" adtcore:packageName="$PACKAGE"/>
</finclude:abapFunctionGroupInclude>'''

CREATE_FUNCTION_GROUP_INCLUDE_ADT_XML='''<?xml version="1.0" encoding="UTF-8"?>
<finclude:abapFunctionGroupInclude xmlns:finclude="http://www.sap.com/adt/functions/fincludes" xmlns:adtcore="http://www.sap.com/adt/core" adtcore:type="FUGR/I" adtcore:description="Hello FUGR/I!" adtcore:name="ZFG_I_HELLO_WORLD">
<adtcore:containerRef adtcore:name="ZFG_HELLO_WORLD" adtcore:type="FUGR/F" adtcore:uri="/sap/bc/adt/functions/groups/zfg_hello_world"/>
</finclude:abapFunctionGroupInclude>'''

WRITE_FUNCTION_GROUP_INCLUDE_BODY='''DATA: test_write TYPE string.'''

READ_FUNCTION_GROUP_INCLUDE_BODY='''DATA: test_read TYPE string.'''

ACTIVATE_FUNCTION_GROUP_INCLUDE_BODY = '''<?xml version="1.0" encoding="UTF-8"?>
<adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
<adtcore:objectReference adtcore:uri="/sap/bc/adt/functions/groups/zfg_hello_world/includes/zfg_i_hello_world" adtcore:name="ZFG_I_HELLO_WORLD"/>
</adtcore:objectReferences>'''
112 changes: 109 additions & 3 deletions test/unit/test_sap_cli_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,31 @@

import sap.cli.function

from mock import Connection, Response
from mock import Connection, Response, Request
from fixtures_adt import EMPTY_RESPONSE_OK, LOCK_RESPONSE_OK
from fixtures_adt_wb import RESPONSE_ACTIVATION_OK
from fixtures_adt_function import (
CLI_CREATE_FUNCTION_GROUP_ADT_XML,
CREATE_FUNCTION_MODULE_ADT_XML,
GET_FUNCTION_MODULE_ADT_XML,
PUT_FUNCITON_MODULE_ADT_XML)

PUT_FUNCITON_MODULE_ADT_XML,
FAKE_LOCK_HANDLE,
CREATE_FUNCTION_GROUP_INCLUDE_ADT_XML,
WRITE_FUNCTION_GROUP_INCLUDE_BODY,
READ_FUNCTION_GROUP_INCLUDE_BODY,
FUNCTION_GROUP_INCLUDE_ADT_XML,
ACTIVATE_FUNCTION_GROUP_INCLUDE_BODY
)

fugr_parser = ArgumentParser()
sap.cli.function.CommandGroupFunctionGroup().install_parser(fugr_parser)

fm_parser = ArgumentParser()
sap.cli.function.CommandGroupFunctionModule().install_parser(fm_parser)

fugri_parser = ArgumentParser()
sap.cli.function.CommandGroupFunctionGroupInclude().install_parser(fugri_parser)


def fugr_parse_args(*argv):
global fugr_parser
Expand All @@ -33,6 +43,11 @@ def fm_parse_args(*argv):
return fm_parser.parse_args(argv)


def fugri_parse_args(*argv):
global fugri_parser
return fugri_parser.parse_args(argv)


class TestFunctionGroupCreate(unittest.TestCase):

def test_create_fugr_defaults(self):
Expand Down Expand Up @@ -144,5 +159,96 @@ def test_fmod_chattr_rfc(self):
self.assertEqual(put_req.body.decode('utf-8'), PUT_FUNCITON_MODULE_ADT_XML)


class TestFunctionGroupIncludeCreate(unittest.TestCase):

def test_create_fugr_include_defaults(self):
connection = Connection([EMPTY_RESPONSE_OK], user='FILAK')

args = fugri_parse_args('create', 'ZFG_HELLO_WORLD', 'ZFG_I_HELLO_WORLD', 'Hello FUGR/I!')
args.execute(connection, args)

self.assertEqual([(e.method, e.adt_uri) for e in connection.execs], [('POST', '/sap/bc/adt/functions/groups/zfg_hello_world/includes')])

post_req = connection.execs[0]

self.assertEqual(sorted(post_req.headers.keys()), ['Content-Type'])
self.assertEqual(post_req.headers['Content-Type'], 'application/vnd.sap.adt.functions.fincludes.v2+xml; charset=utf-8')

self.assertIsNone(post_req.params)

self.maxDiff = None
self.assertEqual(post_req.body.decode('utf-8'), CREATE_FUNCTION_GROUP_INCLUDE_ADT_XML)


class TestFunctionGroupIncludeWrite(unittest.TestCase):

@patch('sap.adt.objects.ADTObject.lock', return_value=FAKE_LOCK_HANDLE)
@patch('sap.adt.objects.ADTObject.unlock')
def test_write(self, fake_lock, fake_unlock):
connection = Connection()

args = fugri_parse_args('write', 'ZFG_HELLO_WORLD', 'ZFG_I_HELLO_WORLD', '-')
with patch('sys.stdin', StringIO(WRITE_FUNCTION_GROUP_INCLUDE_BODY)):
args.execute(connection, args)

fake_lock.assert_called_once()
fake_unlock.assert_called_once()

expected_request = Request(
adt_uri='/sap/bc/adt/functions/groups/zfg_hello_world/includes/zfg_i_hello_world/source/main',
method='PUT',
headers={'Content-Type': 'text/plain; charset=utf-8', 'Accept': 'text/plain'},
body=bytes(WRITE_FUNCTION_GROUP_INCLUDE_BODY, 'utf-8'),
params={'lockHandle': FAKE_LOCK_HANDLE}
)

self.assertEqual(connection.execs[0], expected_request)


class TestFunctionGroupIncludeRead(unittest.TestCase):

def test_read(self):
connection = Connection([
(
Response(
text=READ_FUNCTION_GROUP_INCLUDE_BODY,
status_code=200,
headers={'Content-Type': 'text/plain; charset=utf-8'}
),
Request.get(
adt_uri='functions/groups/zfg_hello_world/includes/zfg_i_hello_world/source/main',
accept='text/plain'
)
)
], asserter=self)

args = fugri_parse_args('read', 'ZFG_HELLO_WORLD', 'ZFG_I_HELLO_WORLD')
with patch('sys.stdin', StringIO(READ_FUNCTION_GROUP_INCLUDE_BODY)) as mock_print:
args.execute(connection, args)

expected_stdout = READ_FUNCTION_GROUP_INCLUDE_BODY
self.assertEqual(mock_print.getvalue(), expected_stdout)


class TestFunctionGroupIncludeActivate(unittest.TestCase):

def test_activate(self):
connection = Connection([
RESPONSE_ACTIVATION_OK,
Response(text=FUNCTION_GROUP_INCLUDE_ADT_XML, status_code=200, headers={})
])

args = fugri_parse_args('activate', 'ZFG_HELLO_WORLD', 'ZFG_I_HELLO_WORLD')
args.execute(connection, args)

expected_request = Request(
adt_uri='/sap/bc/adt/activation',
method='POST',
headers={'Accept': 'application/xml', 'Content-Type': 'application/xml'},
body=ACTIVATE_FUNCTION_GROUP_INCLUDE_BODY,
params={'method': 'activate', 'preauditRequested': 'true'}
)

self.assertEqual(connection.execs[0], expected_request)
if __name__ == '__main__':
unittest.main()

0 comments on commit bd15041

Please sign in to comment.