Blame SOURCES/0009-Issue-4440-BUG-ldifgen-with-start-idx-option-fails-w.patch

3bc51a
From 201cb1147c0a34bddbd3e5c03aecd804c47a9905 Mon Sep 17 00:00:00 2001
3bc51a
From: progier389 <72748589+progier389@users.noreply.github.com>
3bc51a
Date: Thu, 19 Nov 2020 10:21:10 +0100
3bc51a
Subject: [PATCH 2/2] Issue 4440 - BUG - ldifgen with --start-idx option fails
3bc51a
 with unsupported operand (#4444)
3bc51a
3bc51a
Bug description:
3bc51a
Got TypeError exception when usign:
3bc51a
  dsctl -v slapd-localhost ldifgen users --suffix
3bc51a
     dc=example,dc=com --parent ou=people,dc=example,dc=com
3bc51a
     --number 100000 --generic --start-idx=50
3bc51a
The reason is that by default python parser provides
3bc51a
 value for numeric options:
3bc51a
  as an integer if specified by "--option value" or
3bc51a
  as a string if specified by "--option=value"
3bc51a
3bc51a
Fix description:
3bc51a
convert the numeric parameters to integer when using it.
3bc51a
 options impacted are:
3bc51a
  - in users subcommand:   --number ,  --start-idx
3bc51a
  - in mod-load subcommand:   --num-users, --add-users,
3bc51a
               --del-users, --modrdn-users, --mod-users
3bc51a
3bc51a
FYI: An alternative solution would have been to indicate the
3bc51a
parser that these values are an integer. But two reasons
3bc51a
 leaded me to implement the first solution:
3bc51a
 - first solution fix the problem for all users while the
3bc51a
   second one fixes only dsctl command.
3bc51a
 - first solution is easier to test:
3bc51a
    I just added a new test file generated by a script
3bc51a
      that duplicated existing ldifgen test, renamed the
3bc51a
       test cases and replaced the numeric arguments by
3bc51a
       strings.
3bc51a
   Second solution would need to redesign the test framework
3bc51a
    to be able to test the parser.
3bc51a
3bc51a
relates: https://github.com/389ds/389-ds-base/issues/4440
3bc51a
3bc51a
Reviewed by:
3bc51a
3bc51a
Platforms tested: F32
3bc51a
3bc51a
(cherry picked from commit 3c3e1f30cdb046a1aabb93aacebcf261a76a0892)
3bc51a
---
3bc51a
 .../tests/suites/clu/dbgen_test_usan.py       | 806 ++++++++++++++++++
3bc51a
 src/lib389/lib389/cli_ctl/dbgen.py            |  10 +-
3bc51a
 src/lib389/lib389/dbgen.py                    |   3 +
3bc51a
 3 files changed, 814 insertions(+), 5 deletions(-)
3bc51a
 create mode 100644 dirsrvtests/tests/suites/clu/dbgen_test_usan.py
3bc51a
3bc51a
diff --git a/dirsrvtests/tests/suites/clu/dbgen_test_usan.py b/dirsrvtests/tests/suites/clu/dbgen_test_usan.py
3bc51a
new file mode 100644
3bc51a
index 000000000..80ff63417
3bc51a
--- /dev/null
3bc51a
+++ b/dirsrvtests/tests/suites/clu/dbgen_test_usan.py
3bc51a
@@ -0,0 +1,806 @@
3bc51a
+# --- BEGIN COPYRIGHT BLOCK ---
3bc51a
+# Copyright (C) 2020 Red Hat, Inc.
3bc51a
+# All rights reserved.
3bc51a
+#
3bc51a
+# License: GPL (version 3 or any later version).
3bc51a
+# See LICENSE for details.
3bc51a
+# --- END COPYRIGHT BLOCK ---
3bc51a
+#
3bc51a
+import time
3bc51a
+
3bc51a
+"""
3bc51a
+ This file contains tests similar to dbgen_test.py
3bc51a
+ except that paramaters that are number are expressed as string
3bc51a
+ (to mimic the parameters parser default behavior which returns an
3bc51a
+   int when parsing "option value" and a string when parsing "option=value"
3bc51a
+ This file has been generated by usign:
3bc51a
+sed '
3bc51a
+9r z1
3bc51a
+s/ test_/ test_usan/
3bc51a
+/args.*= [0-9]/s,[0-9]*$,"&",
3bc51a
+/:id:/s/.$/1/
3bc51a
+' dbgen_test.py > dbgen_test_usan.py
3bc51a
+ ( with z1 file containing this comment )
3bc51a
+"""
3bc51a
+
3bc51a
+ 
3bc51a
+
3bc51a
+import subprocess
3bc51a
+import pytest
3bc51a
+
3bc51a
+from lib389.cli_ctl.dbgen import *
3bc51a
+from lib389.cos import CosClassicDefinitions, CosPointerDefinitions, CosIndirectDefinitions, CosTemplates
3bc51a
+from lib389.idm.account import Accounts
3bc51a
+from lib389.idm.group import Groups
3bc51a
+from lib389.idm.role import ManagedRoles, FilteredRoles, NestedRoles
3bc51a
+from lib389.tasks import *
3bc51a
+from lib389.utils import *
3bc51a
+from lib389.topologies import topology_st
3bc51a
+from lib389.cli_base import FakeArgs
3bc51a
+
3bc51a
+pytestmark = pytest.mark.tier0
3bc51a
+
3bc51a
+LOG_FILE = '/tmp/dbgen.log'
3bc51a
+logging.getLogger(__name__).setLevel(logging.DEBUG)
3bc51a
+log = logging.getLogger(__name__)
3bc51a
+
3bc51a
+
3bc51a
+@pytest.fixture(scope="function")
3bc51a
+def set_log_file_and_ldif(topology_st, request):
3bc51a
+    global ldif_file
3bc51a
+    ldif_file = get_ldif_dir(topology_st.standalone) + '/created.ldif'
3bc51a
+
3bc51a
+    fh = logging.FileHandler(LOG_FILE)
3bc51a
+    fh.setLevel(logging.DEBUG)
3bc51a
+    log.addHandler(fh)
3bc51a
+
3bc51a
+    def fin():
3bc51a
+        log.info('Delete files')
3bc51a
+        os.remove(LOG_FILE)
3bc51a
+        os.remove(ldif_file)
3bc51a
+
3bc51a
+    request.addfinalizer(fin)
3bc51a
+
3bc51a
+
3bc51a
+def run_offline_import(instance, ldif_file):
3bc51a
+    log.info('Stopping the server and running offline import...')
3bc51a
+    instance.stop()
3bc51a
+    assert instance.ldif2db(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX], encrypt=None, excludeSuffixes=None,
3bc51a
+                              import_file=ldif_file)
3bc51a
+    instance.start()
3bc51a
+
3bc51a
+
3bc51a
+def run_ldapmodify_from_file(instance, ldif_file, output_to_check=None):
3bc51a
+    LDAP_MOD = '/usr/bin/ldapmodify'
3bc51a
+    log.info('Add entries from ldif file with ldapmodify')
3bc51a
+    result = subprocess.check_output([LDAP_MOD, '-cx', '-D', DN_DM, '-w', PASSWORD,
3bc51a
+                                      '-h', instance.host, '-p', str(instance.port), '-af', ldif_file])
3bc51a
+    if output_to_check is not None:
3bc51a
+        assert output_to_check in ensure_str(result)
3bc51a
+
3bc51a
+
3bc51a
+def check_value_in_log_and_reset(content_list):
3bc51a
+    with open(LOG_FILE, 'r+') as f:
3bc51a
+        file_content = f.read()
3bc51a
+        log.info('Check if content is present in output')
3bc51a
+        for item in content_list:
3bc51a
+            assert item in file_content
3bc51a
+
3bc51a
+        log.info('Reset log file for next test')
3bc51a
+        f.truncate(0)
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_users(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create ldif with users
3bc51a
+
3bc51a
+    :id: 426b5b94-9923-454d-a736-7e71ca985e91
3bc51a
+    :setup: Standalone instance
3bc51a
+    :steps:
3bc51a
+         1. Create DS instance
3bc51a
+         2. Run ldifgen to generate ldif with users
3bc51a
+         3. Import generated ldif to database
3bc51a
+         4. Check it was properly imported
3bc51a
+    :expectedresults:
3bc51a
+         1. Success
3bc51a
+         2. Success
3bc51a
+         3. Success
3bc51a
+         4. Success
3bc51a
+    """
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.suffix = DEFAULT_SUFFIX
3bc51a
+    args.parent = 'ou=people,dc=example,dc=com'
3bc51a
+    args.number = "1000"
3bc51a
+    args.rdn_cn = False
3bc51a
+    args.generic = True
3bc51a
+    args.start_idx = "50"
3bc51a
+    args.localize = False
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'suffix={}'.format(args.suffix),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'number={}'.format(args.number),
3bc51a
+                    'rdn-cn={}'.format(args.rdn_cn),
3bc51a
+                    'generic={}'.format(args.generic),
3bc51a
+                    'start-idx={}'.format(args.start_idx),
3bc51a
+                    'localize={}'.format(args.localize),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create users ldif')
3bc51a
+    dbgen_create_users(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    log.info('Get number of accounts before import')
3bc51a
+    accounts = Accounts(standalone, DEFAULT_SUFFIX)
3bc51a
+    count_account = len(accounts.filter('(uid=*)'))
3bc51a
+
3bc51a
+    run_offline_import(standalone, ldif_file)
3bc51a
+
3bc51a
+    log.info('Check that accounts are imported')
3bc51a
+    assert len(accounts.filter('(uid=*)')) > count_account
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_groups(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create ldif with group
3bc51a
+
3bc51a
+            :id: 97207413-9a93-4065-a5ec-63aa93801a31
3bc51a
+            :setup: Standalone instance
3bc51a
+            :steps:
3bc51a
+                 1. Create DS instance
3bc51a
+                 2. Run ldifgen to generate ldif with group
3bc51a
+                 3. Import generated ldif to database
3bc51a
+                 4. Check it was properly imported
3bc51a
+            :expectedresults:
3bc51a
+                 1. Success
3bc51a
+                 2. Success
3bc51a
+                 3. Success
3bc51a
+                 4. Success
3bc51a
+            """
3bc51a
+    LDAP_RESULT = 'adding new entry "cn=myGroup-1,ou=groups,dc=example,dc=com"'
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.NAME = 'myGroup'
3bc51a
+    args.parent = 'ou=groups,dc=example,dc=com'
3bc51a
+    args.suffix = DEFAULT_SUFFIX
3bc51a
+    args.number = "1"
3bc51a
+    args.num_members = "1000"
3bc51a
+    args.create_members = True
3bc51a
+    args.member_attr = 'uniquemember'
3bc51a
+    args.member_parent = 'ou=people,dc=example,dc=com'
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'NAME={}'.format(args.NAME),
3bc51a
+                    'number={}'.format(args.number),
3bc51a
+                    'suffix={}'.format(args.suffix),
3bc51a
+                    'num-members={}'.format(args.num_members),
3bc51a
+                    'create-members={}'.format(args.create_members),
3bc51a
+                    'member-parent={}'.format(args.member_parent),
3bc51a
+                    'member-attr={}'.format(args.member_attr),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create group ldif')
3bc51a
+    dbgen_create_groups(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    log.info('Get number of accounts before import')
3bc51a
+    accounts = Accounts(standalone, DEFAULT_SUFFIX)
3bc51a
+    count_account = len(accounts.filter('(uid=*)'))
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    # ldapmodify will complain about already existing parent which causes subprocess to return exit code != 0
3bc51a
+    with pytest.raises(subprocess.CalledProcessError):
3bc51a
+        run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
3bc51a
+
3bc51a
+    log.info('Check that accounts are imported')
3bc51a
+    assert len(accounts.filter('(uid=*)')) > count_account
3bc51a
+
3bc51a
+    log.info('Check that group is imported')
3bc51a
+    groups = Groups(standalone, DEFAULT_SUFFIX)
3bc51a
+    assert groups.exists(args.NAME + '-1')
3bc51a
+    new_group = groups.get(args.NAME + '-1')
3bc51a
+    new_group.present('uniquemember', 'uid=group_entry1-0152,ou=people,dc=example,dc=com')
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_cos_classic(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create a COS definition
3bc51a
+
3bc51a
+        :id: 8557f994-8a91-4f8a-86f6-9cb826a0b8f1
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate ldif with classic COS definition
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    LDAP_RESULT = 'adding new entry "cn=My_Postal_Def,ou=cos definitions,dc=example,dc=com"'
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.type = 'classic'
3bc51a
+    args.NAME = 'My_Postal_Def'
3bc51a
+    args.parent = 'ou=cos definitions,dc=example,dc=com'
3bc51a
+    args.create_parent = True
3bc51a
+    args.cos_specifier = 'businessCategory'
3bc51a
+    args.cos_attr = ['postalcode', 'telephonenumber']
3bc51a
+    args.cos_template = 'cn=sales,cn=classicCoS,dc=example,dc=com'
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'NAME={}'.format(args.NAME),
3bc51a
+                    'type={}'.format(args.type),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'create-parent={}'.format(args.create_parent),
3bc51a
+                    'cos-specifier={}'.format(args.cos_specifier),
3bc51a
+                    'cos-template={}'.format(args.cos_template),
3bc51a
+                    'cos-attr={}'.format(args.cos_attr),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create COS definition ldif')
3bc51a
+    dbgen_create_cos_def(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
3bc51a
+
3bc51a
+    log.info('Check that COS definition is imported')
3bc51a
+    cos_def = CosClassicDefinitions(standalone, args.parent)
3bc51a
+    assert cos_def.exists(args.NAME)
3bc51a
+    new_cos = cos_def.get(args.NAME)
3bc51a
+    assert new_cos.present('cosTemplateDN', args.cos_template)
3bc51a
+    assert new_cos.present('cosSpecifier', args.cos_specifier)
3bc51a
+    assert new_cos.present('cosAttribute', args.cos_attr[0])
3bc51a
+    assert new_cos.present('cosAttribute', args.cos_attr[1])
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_cos_pointer(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create a COS definition
3bc51a
+
3bc51a
+        :id: 6b26ca6d-226a-4f93-925e-faf95cc20211
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate ldif with pointer COS definition
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    LDAP_RESULT = 'adding new entry "cn=My_Postal_Def_pointer,ou=cos pointer definitions,dc=example,dc=com"'
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.type = 'pointer'
3bc51a
+    args.NAME = 'My_Postal_Def_pointer'
3bc51a
+    args.parent = 'ou=cos pointer definitions,dc=example,dc=com'
3bc51a
+    args.create_parent = True
3bc51a
+    args.cos_specifier = None
3bc51a
+    args.cos_attr = ['postalcode', 'telephonenumber']
3bc51a
+    args.cos_template = 'cn=sales,cn=pointerCoS,dc=example,dc=com'
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'NAME={}'.format(args.NAME),
3bc51a
+                    'type={}'.format(args.type),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'create-parent={}'.format(args.create_parent),
3bc51a
+                    'cos-template={}'.format(args.cos_template),
3bc51a
+                    'cos-attr={}'.format(args.cos_attr),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create COS definition ldif')
3bc51a
+    dbgen_create_cos_def(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
3bc51a
+
3bc51a
+    log.info('Check that COS definition is imported')
3bc51a
+    cos_def = CosPointerDefinitions(standalone, args.parent)
3bc51a
+    assert cos_def.exists(args.NAME)
3bc51a
+    new_cos = cos_def.get(args.NAME)
3bc51a
+    assert new_cos.present('cosTemplateDN', args.cos_template)
3bc51a
+    assert new_cos.present('cosAttribute', args.cos_attr[0])
3bc51a
+    assert new_cos.present('cosAttribute', args.cos_attr[1])
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_cos_indirect(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create a COS definition
3bc51a
+
3bc51a
+        :id: ab4b799e-e801-432a-a61d-badad2628201
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate ldif with indirect COS definition
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    LDAP_RESULT = 'adding new entry "cn=My_Postal_Def_indirect,ou=cos indirect definitions,dc=example,dc=com"'
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.type = 'indirect'
3bc51a
+    args.NAME = 'My_Postal_Def_indirect'
3bc51a
+    args.parent = 'ou=cos indirect definitions,dc=example,dc=com'
3bc51a
+    args.create_parent = True
3bc51a
+    args.cos_specifier = 'businessCategory'
3bc51a
+    args.cos_attr = ['postalcode', 'telephonenumber']
3bc51a
+    args.cos_template = None
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'NAME={}'.format(args.NAME),
3bc51a
+                    'type={}'.format(args.type),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'create-parent={}'.format(args.create_parent),
3bc51a
+                    'cos-specifier={}'.format(args.cos_specifier),
3bc51a
+                    'cos-attr={}'.format(args.cos_attr),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create COS definition ldif')
3bc51a
+    dbgen_create_cos_def(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
3bc51a
+
3bc51a
+    log.info('Check that COS definition is imported')
3bc51a
+    cos_def = CosIndirectDefinitions(standalone, args.parent)
3bc51a
+    assert cos_def.exists(args.NAME)
3bc51a
+    new_cos = cos_def.get(args.NAME)
3bc51a
+    assert new_cos.present('cosIndirectSpecifier', args.cos_specifier)
3bc51a
+    assert new_cos.present('cosAttribute', args.cos_attr[0])
3bc51a
+    assert new_cos.present('cosAttribute', args.cos_attr[1])
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_cos_template(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create a COS template
3bc51a
+
3bc51a
+        :id: 544017c7-4a82-4e7d-a047-00b68a28e071
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate ldif with COS template
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    LDAP_RESULT = 'adding new entry "cn=My_Template,ou=cos templates,dc=example,dc=com"'
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.NAME = 'My_Template'
3bc51a
+    args.parent = 'ou=cos templates,dc=example,dc=com'
3bc51a
+    args.create_parent = True
3bc51a
+    args.cos_priority = "1"
3bc51a
+    args.cos_attr_val = 'postalcode:12345'
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'NAME={}'.format(args.NAME),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'create-parent={}'.format(args.create_parent),
3bc51a
+                    'cos-priority={}'.format(args.cos_priority),
3bc51a
+                    'cos-attr-val={}'.format(args.cos_attr_val),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create COS template ldif')
3bc51a
+    dbgen_create_cos_tmp(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
3bc51a
+
3bc51a
+    log.info('Check that COS template is imported')
3bc51a
+    cos_temp = CosTemplates(standalone, args.parent)
3bc51a
+    assert cos_temp.exists(args.NAME)
3bc51a
+    new_cos = cos_temp.get(args.NAME)
3bc51a
+    assert new_cos.present('cosPriority', str(args.cos_priority))
3bc51a
+    assert new_cos.present('postalcode', '12345')
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_managed_role(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create a managed role
3bc51a
+
3bc51a
+        :id: 10e77b41-0bc1-4ad5-a144-2c5107455b91
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate ldif with managed role
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    LDAP_RESULT = 'adding new entry "cn=My_Managed_Role,ou=managed roles,dc=example,dc=com"'
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+
3bc51a
+    args.NAME = 'My_Managed_Role'
3bc51a
+    args.parent = 'ou=managed roles,dc=example,dc=com'
3bc51a
+    args.create_parent = True
3bc51a
+    args.type = 'managed'
3bc51a
+    args.filter = None
3bc51a
+    args.role_dn = None
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'NAME={}'.format(args.NAME),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'create-parent={}'.format(args.create_parent),
3bc51a
+                    'type={}'.format(args.type),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create managed role ldif')
3bc51a
+    dbgen_create_role(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
3bc51a
+
3bc51a
+    log.info('Check that managed role is imported')
3bc51a
+    roles = ManagedRoles(standalone, DEFAULT_SUFFIX)
3bc51a
+    assert roles.exists(args.NAME)
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_filtered_role(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create a filtered role
3bc51a
+
3bc51a
+        :id: cb3c8ea8-4234-40e2-8810-fb6a25973921
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate ldif with filtered role
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    LDAP_RESULT = 'adding new entry "cn=My_Filtered_Role,ou=filtered roles,dc=example,dc=com"'
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+
3bc51a
+    args.NAME = 'My_Filtered_Role'
3bc51a
+    args.parent = 'ou=filtered roles,dc=example,dc=com'
3bc51a
+    args.create_parent = True
3bc51a
+    args.type = 'filtered'
3bc51a
+    args.filter = '"objectclass=posixAccount"'
3bc51a
+    args.role_dn = None
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'NAME={}'.format(args.NAME),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'create-parent={}'.format(args.create_parent),
3bc51a
+                    'type={}'.format(args.type),
3bc51a
+                    'filter={}'.format(args.filter),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create filtered role ldif')
3bc51a
+    dbgen_create_role(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
3bc51a
+
3bc51a
+    log.info('Check that filtered role is imported')
3bc51a
+    roles = FilteredRoles(standalone, DEFAULT_SUFFIX)
3bc51a
+    assert roles.exists(args.NAME)
3bc51a
+    new_role = roles.get(args.NAME)
3bc51a
+    assert new_role.present('nsRoleFilter', args.filter)
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_nested_role(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create a nested role
3bc51a
+
3bc51a
+        :id: 97fff0a8-3103-4adb-be04-2799ff58d8f1
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate ldif with nested role
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    LDAP_RESULT = 'adding new entry "cn=My_Nested_Role,ou=nested roles,dc=example,dc=com"'
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.NAME = 'My_Nested_Role'
3bc51a
+    args.parent = 'ou=nested roles,dc=example,dc=com'
3bc51a
+    args.create_parent = True
3bc51a
+    args.type = 'nested'
3bc51a
+    args.filter = None
3bc51a
+    args.role_dn = ['cn=some_role,ou=roles,dc=example,dc=com']
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'NAME={}'.format(args.NAME),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'create-parent={}'.format(args.create_parent),
3bc51a
+                    'type={}'.format(args.type),
3bc51a
+                    'role-dn={}'.format(args.role_dn),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create nested role ldif')
3bc51a
+    dbgen_create_role(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    run_ldapmodify_from_file(standalone, ldif_file, LDAP_RESULT)
3bc51a
+
3bc51a
+    log.info('Check that nested role is imported')
3bc51a
+    roles = NestedRoles(standalone, DEFAULT_SUFFIX)
3bc51a
+    assert roles.exists(args.NAME)
3bc51a
+    new_role = roles.get(args.NAME)
3bc51a
+    assert new_role.present('nsRoleDN', args.role_dn[0])
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_mod_ldif_mixed(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create mixed modification ldif
3bc51a
+
3bc51a
+        :id: 4a2e0901-2b48-452e-a4a0-507735132c81
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate modification ldif
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.parent = DEFAULT_SUFFIX
3bc51a
+    args.create_users = True
3bc51a
+    args.delete_users = True
3bc51a
+    args.create_parent = False
3bc51a
+    args.num_users = "1000"
3bc51a
+    args.add_users = "100"
3bc51a
+    args.del_users = "999"
3bc51a
+    args.modrdn_users = "100"
3bc51a
+    args.mod_users = "10"
3bc51a
+    args.mod_attrs = ['cn', 'uid', 'sn']
3bc51a
+    args.randomize = False
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'create-users={}'.format(args.create_users),
3bc51a
+                    'parent={}'.format(args.parent),
3bc51a
+                    'create-parent={}'.format(args.create_parent),
3bc51a
+                    'delete-users={}'.format(args.delete_users),
3bc51a
+                    'num-users={}'.format(args.num_users),
3bc51a
+                    'add-users={}'.format(args.add_users),
3bc51a
+                    'del-users={}'.format(args.del_users),
3bc51a
+                    'modrdn-users={}'.format(args.modrdn_users),
3bc51a
+                    'mod-users={}'.format(args.mod_users),
3bc51a
+                    'mod-attrs={}'.format(args.mod_attrs),
3bc51a
+                    'randomize={}'.format(args.randomize),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created LDIF file: {}'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create modification ldif')
3bc51a
+    dbgen_create_mods(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    log.info('Get number of accounts before import')
3bc51a
+    accounts = Accounts(standalone, DEFAULT_SUFFIX)
3bc51a
+    count_account = len(accounts.filter('(uid=*)'))
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    # ldapmodify will complain about a lot of changes done which causes subprocess to return exit code != 0
3bc51a
+    with pytest.raises(subprocess.CalledProcessError):
3bc51a
+        run_ldapmodify_from_file(standalone, ldif_file)
3bc51a
+
3bc51a
+    log.info('Check that some accounts are imported')
3bc51a
+    assert len(accounts.filter('(uid=*)')) > count_account
3bc51a
+
3bc51a
+
3bc51a
+@pytest.mark.ds50545
3bc51a
+@pytest.mark.bz1798394
3bc51a
+@pytest.mark.skipif(ds_is_older("1.4.3"), reason="Not implemented")
3bc51a
+def test_usandsconf_dbgen_nested_ldif(topology_st, set_log_file_and_ldif):
3bc51a
+    """Test ldifgen (formerly dbgen) tool to create nested ldif
3bc51a
+
3bc51a
+        :id: 9c281c28-4169-45e0-8c07-c5502d9a7581
3bc51a
+        :setup: Standalone instance
3bc51a
+        :steps:
3bc51a
+             1. Create DS instance
3bc51a
+             2. Run ldifgen to generate nested ldif
3bc51a
+             3. Import generated ldif to database
3bc51a
+             4. Check it was properly imported
3bc51a
+        :expectedresults:
3bc51a
+             1. Success
3bc51a
+             2. Success
3bc51a
+             3. Success
3bc51a
+             4. Success
3bc51a
+        """
3bc51a
+
3bc51a
+    standalone = topology_st.standalone
3bc51a
+
3bc51a
+    args = FakeArgs()
3bc51a
+    args.suffix = DEFAULT_SUFFIX
3bc51a
+    args.node_limit = "100"
3bc51a
+    args.num_users = "600"
3bc51a
+    args.ldif_file = ldif_file
3bc51a
+
3bc51a
+    content_list = ['Generating LDIF with the following options:',
3bc51a
+                    'suffix={}'.format(args.suffix),
3bc51a
+                    'node-limit={}'.format(args.node_limit),
3bc51a
+                    'num-users={}'.format(args.num_users),
3bc51a
+                    'ldif-file={}'.format(args.ldif_file),
3bc51a
+                    'Writing LDIF',
3bc51a
+                    'Successfully created nested LDIF file ({}) containing 6 nodes/subtrees'.format(args.ldif_file)]
3bc51a
+
3bc51a
+    log.info('Run ldifgen to create nested ldif')
3bc51a
+    dbgen_create_nested(standalone, log, args)
3bc51a
+
3bc51a
+    log.info('Check if file exists')
3bc51a
+    assert os.path.exists(ldif_file)
3bc51a
+
3bc51a
+    check_value_in_log_and_reset(content_list)
3bc51a
+
3bc51a
+    log.info('Get number of accounts before import')
3bc51a
+    accounts = Accounts(standalone, DEFAULT_SUFFIX)
3bc51a
+    count_account = len(accounts.filter('(uid=*)'))
3bc51a
+    count_ou = len(accounts.filter('(ou=*)'))
3bc51a
+
3bc51a
+    # Groups, COS, Roles and modification ldifs are designed to be used by ldapmodify, not ldif2db
3bc51a
+    # ldapmodify will complain about already existing suffix which causes subprocess to return exit code != 0
3bc51a
+    with pytest.raises(subprocess.CalledProcessError):
3bc51a
+        run_ldapmodify_from_file(standalone, ldif_file)
3bc51a
+
3bc51a
+    standalone.restart()
3bc51a
+
3bc51a
+    log.info('Check that accounts are imported')
3bc51a
+    assert len(accounts.filter('(uid=*)')) > count_account
3bc51a
+    assert len(accounts.filter('(ou=*)')) > count_ou
3bc51a
+
3bc51a
+
3bc51a
+if __name__ == '__main__':
3bc51a
+    # Run isolated
3bc51a
+    # -s for DEBUG mode
3bc51a
+    CURRENT_FILE = os.path.realpath(__file__)
3bc51a
+    pytest.main("-s %s" % CURRENT_FILE)
3bc51a
diff --git a/src/lib389/lib389/cli_ctl/dbgen.py b/src/lib389/lib389/cli_ctl/dbgen.py
3bc51a
index 7bc3892ba..058342fb1 100644
3bc51a
--- a/src/lib389/lib389/cli_ctl/dbgen.py
3bc51a
+++ b/src/lib389/lib389/cli_ctl/dbgen.py
3bc51a
@@ -451,13 +451,13 @@ def dbgen_create_mods(inst, log, args):
3bc51a
     props = {
3bc51a
         "createUsers": args.create_users,
3bc51a
         "deleteUsers": args.delete_users,
3bc51a
-        "numUsers": args.num_users,
3bc51a
+        "numUsers": int(args.num_users),
3bc51a
         "parent": args.parent,
3bc51a
         "createParent": args.create_parent,
3bc51a
-        "addUsers": args.add_users,
3bc51a
-        "delUsers": args.del_users,
3bc51a
-        "modrdnUsers": args.modrdn_users,
3bc51a
-        "modUsers": args.mod_users,
3bc51a
+        "addUsers": int(args.add_users),
3bc51a
+        "delUsers": int(args.del_users),
3bc51a
+        "modrdnUsers": int(args.modrdn_users),
3bc51a
+        "modUsers": int(args.mod_users),
3bc51a
         "random": args.randomize,
3bc51a
         "modAttrs": args.mod_attrs
3bc51a
     }
3bc51a
diff --git a/src/lib389/lib389/dbgen.py b/src/lib389/lib389/dbgen.py
3bc51a
index 6273781a2..10fb200f7 100644
3bc51a
--- a/src/lib389/lib389/dbgen.py
3bc51a
+++ b/src/lib389/lib389/dbgen.py
3bc51a
@@ -220,6 +220,9 @@ def dbgen_users(instance, number, ldif_file, suffix, generic=False, entry_name="
3bc51a
     """
3bc51a
     Generate an LDIF of randomly named entries
3bc51a
     """
3bc51a
+    # Lets insure that integer parameters are not string
3bc51a
+    number=int(number)
3bc51a
+    startIdx=int(startIdx)
3bc51a
     familyname_file = os.path.join(instance.ds_paths.data_dir, 'dirsrv/data/dbgen-FamilyNames')
3bc51a
     givename_file = os.path.join(instance.ds_paths.data_dir, 'dirsrv/data/dbgen-GivenNames')
3bc51a
     familynames = []
3bc51a
-- 
3bc51a
2.26.2
3bc51a