From 4be81275f839b0437ad3603300217bbbed4d7a5e Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 27 Jun 2025 16:10:49 +0200 Subject: [PATCH] Added tests --- __pycache__/main.cpython-313.pyc | Bin 0 -> 11243 bytes .../test_manage_schema.cpython-313.pyc | Bin 0 -> 3734 bytes main.py | 9 ++- test_manage_schema.py | 63 ++++++++++++++++++ 4 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 __pycache__/main.cpython-313.pyc create mode 100644 __pycache__/test_manage_schema.cpython-313.pyc create mode 100644 test_manage_schema.py diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ac6c39249f7e5ca571cb9cce2f371db613b6155 GIT binary patch literal 11243 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 literal 0 HcmV?d00001 diff --git a/__pycache__/test_manage_schema.cpython-313.pyc b/__pycache__/test_manage_schema.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cace6d72f1d0faef11b4025b02cd3199ef5bc74 GIT binary patch literal 3734 zcmb_fO>7&-6`uVewWR*73i`2SuaznkWr-B2AIGlhR&~_amMEiIvyf|}i`8-@ZcXm8 zvrAc4(ZDFshQ|a!P#=2esZh{Edvwu5d(3fVDUdJ;&;sqDzR8ty>8WpaxfDgSwF`6r zzI`+A&6_tf?|t)l+}<8V&{lu*!~8Yi{>C~%3ssrp_ksBYDM;ZK5n*3`k-Nnc{+2)l z*&i24s2>d@MHobicpt5_1x8N3GlI{Pmiv+ty1I&xb_OBPl}>a5ZWzr}Ss86`8(cj6 zob{LEJPnmJN6*tpM%ys-jHN%&gGuaLT>~A1dGPr@BAkKA*RCVEKP+VBH$3an+N99x^otR2Y%kuJk zW)W-icNJ3IjuC|`!L~qM3N5Ng?h@pMClQY zdBZg~Rf3DwCbm_)S^F}5V~dy1b=(IhRITC$BUK7;oHf5>8+zM8hD?pv>%R7x>Mi%Z0NI2H@)g! zy6cYppb|Nd26v^weJKW7-5I_TI&4o@c(5=St0LLZ-oUrq{%=>>zwD6@dd8mhjP1<) zZtl~$-(K76xmtz3v%AvSCz+j#yXVGt^83DaWnRY?G-(LF>JigZpEXwWeT(fjfH=;}yp85b}=F3|~!O+MfS!Xt4 z@_csn=F-jimAi6g{w|anweYe z0uUOqbe2OcehTNvFbvx40_#&|z)Kk|ms267RLk3;>bXb9nx{!K-M5+P4}d&IfB)Lh zsl=E_xl;>&CT{wcduh=fTdGTlzjkdxHk|4E<@iVAA15j;5Yrt~6}}dtei+X_?Ry$= zCtST=57ZWb270K-&(;h-Y)kx;H8A=G64EOnh&MHS+~tB@>{rkdYw-9n91-hp-PQ6Ny4b>66m zUv`{5=!iY*i0z1b9TOFyR-!%WanDbEE=_yz@hSYhh*C*aO|6Jkl}1%~D{|!md?S#C8gXiA_sYNf)d|*rkyXMlLau0z!LL)pj(;&`%)V2K_0fz#z*z1HwYx zBkbnvc_6<){}hGL4emu0g9&icvwE51n(4!(#_AgUnCx2Z7VDLPg262PyRGRb8=o+~O zQWnSd6(C0f$8lev&cC3sFVMM{;w(4w;nqRl=x*QWO9Y)G!XdG(vb`q^9ExopWPX bytes: """ return re.sub(rb'\s+', b' ', def_str.strip()) +def extract_oid(ldif: str) -> str: + match = re.search(r'\(\s*([\d\.]+)', ldif) + return match.group(1) if match else '' + def main(): parser = argparse.ArgumentParser( description='Create or update OpenLDAP schema entries under cn=config' @@ -162,11 +166,6 @@ def main(): norm_existing = [normalize(v) for v in existing] norm_encoded = normalize(encoded) - - # Extract OID from definition (assumes it is the first word in parentheses) - def extract_oid(ldif: str) -> str: - return ldif.split()[0].strip('(') - oid = extract_oid(atdef) # Normalize existing diff --git a/test_manage_schema.py b/test_manage_schema.py new file mode 100644 index 0000000..8365375 --- /dev/null +++ b/test_manage_schema.py @@ -0,0 +1,63 @@ +import unittest +from unittest.mock import patch, MagicMock +import main as manage_schema + +class TestManageSchema(unittest.TestCase): + + def test_normalize_removes_extra_whitespace(self): + input_data = b' ( 1.2.3.4 NAME \'foo\' \n DESC \t "bar" ) ' + expected = b'( 1.2.3.4 NAME \'foo\' DESC "bar" )' + self.assertEqual(manage_schema.normalize(input_data), expected) + + @patch('ldap.initialize') + def test_existing_attribute_type_replaced(self, mock_ldap_init): + # Setup mock connection and search result + mock_conn = MagicMock() + mock_ldap_init.return_value = mock_conn + + # Fake result for olcAttributeTypes containing old version + existing_attr = b"( 1.3.6.1.4.1.99999.1 NAME 'nextcloudQuota' DESC 'Old desc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )" + mock_conn.search_s.return_value = [(None, {'olcAttributeTypes': [existing_attr]})] + + # Call modify_s and simulate replace + atdef = "( 1.3.6.1.4.1.99999.1 NAME 'nextcloudQuota' DESC 'Quota for Nextcloud' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )" + dn = "cn={0}nextcloud,cn=schema,cn=config" + + # Manually test logic: normalize and modify decision + norm_existing = [manage_schema.normalize(existing_attr)] + norm_new = manage_schema.normalize(atdef.encode()) + self.assertNotEqual(norm_existing[0], norm_new) + + # Simulate replace + mock_conn.modify_s.reset_mock() + mock_conn.modify_s(dn, [(2, 'olcAttributeTypes', [atdef.encode()])]) + mock_conn.modify_s.assert_called_once_with( + dn, [(2, 'olcAttributeTypes', [atdef.encode()])] + ) + + @patch('ldap.initialize') + def test_add_new_object_class(self, mock_ldap_init): + mock_conn = MagicMock() + mock_ldap_init.return_value = mock_conn + + # No existing object classes + mock_conn.search_s.return_value = [(None, {'olcObjectClasses': []})] + + ocdef = "( 1.3.6.1.4.1.99999.2 NAME 'nextcloudUser' DESC 'Auxiliary class' AUXILIARY MAY ( nextcloudQuota ) )" + encoded = ocdef.encode() + + # Simulate adding + dn = "cn={0}nextcloud,cn=schema,cn=config" + mock_conn.modify_s(dn, [(0, 'olcObjectClasses', [encoded])]) + mock_conn.modify_s.assert_called_once_with( + dn, [(0, 'olcObjectClasses', [encoded])] + ) + + def test_extract_oid_from_definition(self): + ldif = "( 1.3.6.1.4.1.99999.1 NAME 'example' DESC 'something' )" + oid = manage_schema.extract_oid(ldif) + self.assertEqual(oid, "1.3.6.1.4.1.99999.1") + + +if __name__ == '__main__': + unittest.main()