Skip to content
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

Resolve the deferred returned by send_multiResponse and send_multiRes… #239

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/NEWS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Changelog
-------------------

- Dropped support for Python 3.5
- The Deferred returned from send_multiResponse and send_multiResponse_ex is
now fired after the final response is handled.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open to suggestions on better wording here. I wasn't sure how to say this differently without getting too technical for release notes.



21.2.0 (2021-02-28)
Expand Down
12 changes: 8 additions & 4 deletions ldaptor/protocols/ldap/ldapclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,11 @@ def send_multiResponse(self, op, handler, *args, **kwargs):

If `handler` is provided, it will receive a LDAP response as
its first argument. The Deferred returned by this function will
never fire.
fire with a result of `None` when the handler returns True to indicate
the final response has been handled.

If `handler` is not provided, the Deferred returned by this
function will fire with the final LDAP response.
function will fire with the first LDAP response.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment was wrong, as is evidenced by the updated test_send_multiResponse_with_handler test


@param op: the operation to send
@type op: LDAPProtocolRequest
Expand All @@ -137,9 +138,10 @@ def send_multiResponse_ex(self, op, controls=None, handler=None, *args, **kwargs
Send an LDAP operation to the server, expecting one or more
responses.

If `handler` is provided, it will receive a LDAP response *and*
If `handler` is provided, it will receive an LDAP response *and*
response controls as its first 2 arguments. The Deferred returned
by this function will never fire.
by this function will fire with a result of `None` when the handler
returns True to indicate the final response has been handled.

If `handler` is not provided, the Deferred returned by this
function will fire with a tuple of the first LDAP response
Expand Down Expand Up @@ -204,9 +206,11 @@ def handle(self, msg):
# Return true to mark request as fully handled
if return_controls:
if handler(msg.value, msg.controls, *args, **kwargs):
d.callback(None)
del self.onwire[msg.id]
else:
if handler(msg.value, *args, **kwargs):
d.callback(None)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functional changes are these two d.callback lines. This lets callers of send_multiResponse and send_multiResponse_ex yield on those methods if they want to yield until all responses have been handled.

del self.onwire[msg.id]

def bind(self, dn="", auth=""):
Expand Down
45 changes: 44 additions & 1 deletion ldaptor/test/test_ldapclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def collect_result_(result):
return True
return False

client.send_multiResponse(op, collect_result_)
d = client.send_multiResponse(op, collect_result_)
expected_value = pureldap.LDAPMessage(op)
expected_value.id -= 1
expected_bytestring = expected_value.toWire()
Expand All @@ -203,12 +203,16 @@ def collect_result_(result):
)
resp_bytestring = response.toWire()
client.dataReceived(resp_bytestring)
self.assertEqual(response.value, results[0])
self.assertFalse(d.called)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making sure the deferred is not fired until the multi-response handler returns True


response = pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(0), id=expected_value.id
)
resp_bytestring = response.toWire()
client.dataReceived(resp_bytestring)
self.assertEqual(response.value, results[1])
self.assertIsNone(self.successResultOf(d))

def test_send_multiResponse_ex(self):
client, transport = self.create_test_client()
Expand All @@ -229,6 +233,45 @@ def test_send_multiResponse_ex(self):
client.dataReceived(resp_bytestring)
self.assertEqual((response.value, response.controls), self.successResultOf(d))

def test_send_multiResponse_ex_with_handler(self):
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was no test covering send_multiResponse_ex when that method was passed a handler.

client, transport = self.create_test_client()
op = self.create_test_search_req()
results = []

def collect_result_(result, controls):
results.append((result, controls))
if isinstance(result, pureldap.LDAPSearchResultDone):
return True
return False

controls = self.create_paged_search_controls()
d = client.send_multiResponse_ex(op, controls, handler=collect_result_)
expected_value = pureldap.LDAPMessage(op, controls)
expected_value.id -= 1
expected_bytestring = expected_value.toWire()
self.assertEqual(transport.value(), expected_bytestring)
resp_controls = self.create_paged_search_controls(0, "magic1")
response = pureldap.LDAPMessage(
pureldap.LDAPSearchResultEntry("cn=foo,ou=baz,dc=example,dc=net", {}),
id=expected_value.id,
controls=resp_controls,
)
resp_bytestring = response.toWire()
client.dataReceived(resp_bytestring)
self.assertEqual(results[0], (response.value, resp_controls))
self.assertFalse(d.called)

resp_controls = self.create_paged_search_controls(0, "magic2")
response = pureldap.LDAPMessage(
pureldap.LDAPSearchResultDone(0),
id=expected_value.id,
controls=resp_controls,
)
resp_bytestring = response.toWire()
client.dataReceived(resp_bytestring)
self.assertEqual(results[1], (response.value, resp_controls))
self.assertIsNone(self.successResultOf(d))

def test_send_noResponse(self):
client, transport = self.create_test_client()
op = pureldap.LDAPAbandonRequest(id=1)
Expand Down