From 4060bed98d2637418955fdb33fc43623c8b95235 Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Tue, 12 Mar 2024 22:20:06 -0600 Subject: [PATCH 1/4] fix: Don't assume ordering of ThreadPoolExecutor submissions --- tests/unittests/test_url_helper.py | 52 +++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) Index: cloud-init-23.3/tests/unittests/test_url_helper.py =================================================================== --- cloud-init-23.3.orig/tests/unittests/test_url_helper.py +++ cloud-init-23.3/tests/unittests/test_url_helper.py @@ -4,6 +4,7 @@ import logging from functools import partial from threading import Event from time import process_time +from unittest.mock import ANY, call import pytest import requests @@ -465,20 +466,72 @@ class TestDualStack: """Assert expected call intervals occur""" stagger = 0.1 with mock.patch(M_PATH + "_run_func_with_delay") as delay_func: + + def identity_of_first_arg(x, _): + return x + dual_stack( - lambda x, _y: x, + identity_of_first_arg, ["you", "and", "me", "and", "dog"], stagger_delay=stagger, timeout=1, ) - # ensure that stagger delay for each subsequent call is: + # ensure that stagger delay for each call is made with args: # [ 0 * N, 1 * N, 2 * N, 3 * N, 4 * N, 5 * N] where N = stagger # it appears that without an explicit wait/join we can't assert # number of calls - for delay, call_item in enumerate(delay_func.call_args_list): - _, kwargs = call_item - assert stagger * delay == kwargs.get("delay") + calls = [ + call( + func=identity_of_first_arg, + addr="you", + timeout=1, + event=ANY, + delay=stagger * 0, + ), + call( + func=identity_of_first_arg, + addr="and", + timeout=1, + event=ANY, + delay=stagger * 1, + ), + call( + func=identity_of_first_arg, + addr="me", + timeout=1, + event=ANY, + delay=stagger * 2, + ), + call( + func=identity_of_first_arg, + addr="and", + timeout=1, + event=ANY, + delay=stagger * 3, + ), + call( + func=identity_of_first_arg, + addr="dog", + timeout=1, + event=ANY, + delay=stagger * 4, + ), + ] + num_calls = 0 + for call_instance in calls: + if call_instance in delay_func.call_args_list: + num_calls += 1 + + # we can't know the order of the submitted functions' execution + # we can't know how many of the submitted functions get called + # in advance + # + # we _do_ know what the possible arg combinations are + # we _do_ know from the mocked function how many got called + # assert that all calls that occurred had known valid arguments + # by checking for the correct number of matches + assert num_calls == len(delay_func.call_args_list) ADDR1 = "https://addr1/"