Skip to content

Commit 98351c1

Browse files
authored
tests: rremove some flakyness from client tests (#2375)
Update test_send_remote_failover_sync_non_transport_exception_error to remove some flakyness: - use a custom transport class instead of mocking it because *sometime* the send method won't get mocked :O - then before asserting the transport state give it a bit more slack time to the queue to process and flush the data - Finally retry the check of the stat for the send without error to give the queue enough time to process it
1 parent 8fb2039 commit 98351c1

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

tests/client/client_tests.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -274,33 +274,44 @@ def test_send_remote_failover_sync(should_try, sending_elasticapm_client, caplog
274274
assert not sending_elasticapm_client._transport.state.did_fail()
275275

276276

277-
@mock.patch("elasticapm.transport.http.Transport.send")
278-
@mock.patch("elasticapm.transport.base.TransportState.should_try")
279-
def test_send_remote_failover_sync_non_transport_exception_error(should_try, http_send, caplog):
280-
should_try.return_value = True
281-
277+
@mock.patch("elasticapm.transport.base.TransportState.should_try", return_value=True)
278+
def test_send_remote_failover_sync_non_transport_exception_error(should_try, caplog):
282279
client = Client(
283280
server_url="http://example.com",
284281
service_name="app_name",
285282
secret_token="secret",
286-
transport_class="elasticapm.transport.http.Transport",
283+
transport_class="tests.fixtures.MockSendHTTPTransport",
287284
metrics_interval="0ms",
288285
metrics_sets=[],
289286
)
287+
290288
# test error
291-
http_send.side_effect = ValueError("oopsie")
289+
client._transport.send_mock.side_effect = ValueError("oopsie")
292290
with caplog.at_level("ERROR", "elasticapm.transport"):
293291
client.capture_message("foo", handled=False)
294-
client._transport.flush()
292+
try:
293+
client._transport.flush()
294+
except ValueError:
295+
# give flush a bit more room because we may take a bit more than the max timeout to flush
296+
client._transport._flushed.wait(timeout=1)
295297
assert client._transport.state.did_fail()
296298
assert_any_record_contains(caplog.records, "oopsie", "elasticapm.transport")
297299

298300
# test recovery
299-
http_send.side_effect = None
301+
client._transport.send_mock.side_effect = None
300302
client.capture_message("foo", handled=False)
301-
client.close()
303+
try:
304+
client._transport.flush()
305+
except ValueError:
306+
# give flush a bit more room because we may take a bit more than the max timeout to flush
307+
client._transport._flushed.wait(timeout=1)
308+
# We have a race here with the queue where we would end up checking for did_fail before the message
309+
# is being handled by the queue, so sleep a bit and retry to give it enough time
310+
retries = 0
311+
while client._transport.state.did_fail() and retries < 3:
312+
time.sleep(0.1)
313+
retries += 1
302314
assert not client._transport.state.did_fail()
303-
client.close()
304315

305316

306317
@pytest.mark.parametrize("validating_httpserver", [{"skip_validate": True}], indirect=True)

tests/fixtures.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
from elasticapm.conf.constants import SPAN
6060
from elasticapm.instrumentation import register
6161
from elasticapm.traces import execution_context
62+
from elasticapm.transport.http import Transport
6263
from elasticapm.transport.http_base import HTTPTransportBase
6364
from elasticapm.utils.threading import ThreadManager
6465

@@ -396,6 +397,18 @@ def get_config(self, current_version=None, keys=None):
396397
return False, None, 30
397398

398399

400+
class MockSendHTTPTransport(Transport):
401+
"""Mocking the send method of the Transport class sometimes fails silently in client tests.
402+
After spending some time trying to understand this with no luck just use this class instead."""
403+
404+
def __init__(self, url, *args, **kwargs):
405+
self.send_mock = mock.Mock()
406+
super().__init__(url, *args, **kwargs)
407+
408+
def send(self, data, forced_flush=False, custom_url=None, custom_headers=None):
409+
return self.send_mock(data, forced_flush, custom_url, custom_headers)
410+
411+
399412
class TempStoreClient(Client):
400413
def __init__(self, config=None, **inline) -> None:
401414
inline.setdefault("transport_class", "tests.fixtures.DummyTransport")

0 commit comments

Comments
 (0)