Skip to content

Tests/t_ldapobject.py fails on pypy3 CI run #460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
droideck opened this issue Feb 1, 2022 · 3 comments · Fixed by #544
Closed

Tests/t_ldapobject.py fails on pypy3 CI run #460

droideck opened this issue Feb 1, 2022 · 3 comments · Fixed by #544

Comments

@droideck
Copy link
Contributor

droideck commented Feb 1, 2022

CI tests start to fail in Tests/t_ldapobject.py with the next error:

        self.server.slapadd(SCHEMA_TEMPLATE, ["-n0"])
        self.server.restart()
>       self.reset_connection()

# Or

      def tearDown(self):
  >       self._sock.close()

But always it points to:

    def _real_close(self, _ss=_socket.socket):
        # This function should not reference any globals. See issue #808164.
>       _ss.close(self)
E       OSError: [Errno 9] Bad file descriptor

Possibly, we're trying to close the socket that was already closed.
And, it's possibly a race condition because sometimes it happens and sometimes it's not (and only on pypy3 runs).

Further investigation is required.

@droideck
Copy link
Contributor Author

Fixed by e5959b3

@droideck
Copy link
Contributor Author

Reopening as the new failure has appeared in the same test as the tearDown issue was fixed:

=================================== FAILURES ===================================
___________ Test03_SimpleLDAPObjectWithFileno.test_reject_bytes_base ___________

self = <Tests.t_ldapobject.Test03_SimpleLDAPObjectWithFileno testMethod=test_reject_bytes_base>

    def setUp(self):
        try:
>           self._ldap_conn
E           AttributeError: 'Test03_SimpleLDAPObjectWithFileno' object has no attribute '_ldap_conn'

Tests/t_ldapobject.py:114: AttributeError

During handling of the above exception, another exception occurred:

self = <Tests.t_ldapobject.Test03_SimpleLDAPObjectWithFileno testMethod=test_reject_bytes_base>

    def setUp(self):
        try:
            self._ldap_conn
        except AttributeError:
            # open local LDAP connection
>           self._ldap_conn = self._open_ldap_conn(bytes_mode=False)

Tests/t_ldapobject.py:117: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
Tests/t_ldapobject.py:656: in _open_ldap_conn
    who=who, cred=cred, fileno=self._sock.fileno(), **kwargs
.tox/pypy3/site-packages/slapdtest/_slapdtest.py:598: in _open_ldap_conn
    ldap_conn.simple_bind_s(who or self.server.root_dn, cred or self.server.root_pw)
.tox/pypy3/site-packages/ldap/ldapobject.py:248: in simple_bind_s
    msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
.tox/pypy3/site-packages/ldap/ldapobject.py:242: in simple_bind
    return self._ldap_call(self._l.simple_bind,who,cred,RequestControlTuples(serverctrls),RequestControlTuples(clientctrls))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ldap.ldapobject.SimpleLDAPObject object at 0x00000000059230c0>
func = <bound method simple_bind of <LDAP object at 0x0000000005928c20>>
args = ('cn=Manager,dc=slapd-test,dc=python-ldap,dc=org', 'password', None, None)
kwargs = {}, diagnostic_message_success = None

    def _ldap_call(self,func,*args,**kwargs):
      """
      Wrapper method mainly for serializing calls into OpenLDAP libs
      and trace logs
      """
      self._ldap_object_lock.acquire()
      if __debug__:
        if self._trace_level>=1:
          self._trace_file.write('*** {} {} - {}\n{}\n'.format(
            repr(self),
            self._uri,
            '.'.join((self.__class__.__name__,func.__name__)),
            pprint.pformat((args,kwargs))
          ))
          if self._trace_level>=9:
            traceback.print_stack(limit=self._trace_stack_limit,file=self._trace_file)
      diagnostic_message_success = None
      try:
        try:
>         result = func(*args,**kwargs)
E         ldap.SERVER_DOWN: {'result': -1, 'desc': "Can't contact LDAP server", 'errno': 9, 'ctrls': [], 'info': 'Bad file descriptor'}

@pmhahn
Copy link
Contributor

pmhahn commented Jan 27, 2023

While working on #507 I created this patch: It removed one testing failing but still (other) tests error out. So this patch is not enough and more fixes the test, while fixing the underlying problem might be more worthwhile.

From 26d417d97f4aae2bd47b7205d86b24407285dfb8 Mon Sep 17 00:00:00 2001
Message-Id: <26d417d97f4aae2bd47b7205d86b24407285dfb8.1674804446.git.hahn@univention.de>
From: Philipp Hahn <hahn@univention.de>
Date: Wed, 25 Jan 2023 16:14:44 +0100
Subject: [PATCH] fix(Tests/t_ldapobject): Handle closed socket

`pypy3` may have already closed the socket as it is unspecified, when objects
are really freed.
Do not double-close it.

> =================================== FAILURES ===================================
> ________________ Test03_SimpleLDAPObjectWithFileno.test_slapadd ________________
>
> self = <Tests.t_ldapobject.Test03_SimpleLDAPObjectWithFileno testMethod=test_slapadd>
>
>     def test_slapadd(self):
>         with self.assertRaises(ldap.INVALID_DN_SYNTAX):
>             self._ldap_conn.add_s("myAttribute=foobar,ou=Container,%s" % self.server.suffix, [
>                 ("objectClass", b'myClass'),
>                 ("myAttribute", b'foobar'),
>             ])
>
>         self.server.slapadd(SCHEMA_TEMPLATE, ["-n0"])
>         self.server.restart()
> >       self.reset_connection()
>
> Tests/t_ldapobject.py:561:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> Tests/t_ldapobject.py:665: in reset_connection
>     self._sock.close()
> /usr/lib64/pypy3.9/socket.py:501: in close
>     self._real_close()
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> self = <socket.socket [closed] fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6>
> _ss = <class '_socket.socket'>
>
>     def _real_close(self, _ss=_socket.socket):
>         # This function should not reference any globals. See issue #808164.
> >       _ss.close(self)
> E       OSError: [Errno 9] Bad file descriptor
>
> /usr/lib64/pypy3.9/socket.py:495: OSError
---
 Tests/t_ldapobject.py | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git Tests/t_ldapobject.py Tests/t_ldapobject.py
index ccc7d21..5617b63 100644
--- Tests/t_ldapobject.py
+++ Tests/t_ldapobject.py
@@ -656,14 +656,20 @@ class Test03_SimpleLDAPObjectWithFileno(Test00_SimpleLDAPObject):
             who=who, cred=cred, fileno=self._sock.fileno(), **kwargs
         )
 
-    def tearDown(self):
-        self._sock.close()
+    def __close_sock(self):
+        try:
+            self._sock.close()
+        except OSError as exc:
+            if exc.errno != errno.EBADF:
+                raise
         delattr(self, '_sock')
+
+    def tearDown(self):
+        self.__close_sock()
         super().tearDown()
 
     def reset_connection(self):
-        self._sock.close()
-        delattr(self, '_sock')
+        self.__close_sock()
         super(Test03_SimpleLDAPObjectWithFileno, self).reset_connection()
 
 
-- 
2.30.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants