<commit_before>import salt.ext.tornado as tornado
import salt.ext.tornado.testing
import salt.netapi.rest_tornado.saltnado as saltnado
from tests.support.mock import MagicMock, patch

anti_lint = salt.ext.tornado.testing


class TestJobNotRunning(tornado.testing.AsyncTestCase):
    def setUp(self):
        super().setUp()
        self.mock = MagicMock()
        self.mock.opts = {
            "syndic_wait": 0.1,
            "cachedir": "/tmp/testing/cachedir",
            "sock_dir": "/tmp/testing/sock_drawer",
            "transport": "zeromq",
            "extension_modules": "/tmp/testing/moduuuuules",
            "order_masters": False,
            "gather_job_timeout": 10.001,
        }
        self.handler = saltnado.SaltAPIHandler(self.mock, self.mock)
        f = tornado.gen.Future()
        f.set_result({"jid": f, "minions": []})
        self.handler.saltclients.update({"local": lambda *args, **kwargs: f})

    @tornado.testing.gen_test
    def test_when_event_times_out_and_minion_is_not_running_result_should_be_True(self):
        fut = tornado.gen.Future()
        fut.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.return_value = fut
        wrong_future = tornado.gen.Future()

        result = yield self.handler.job_not_running(
            jid=42, tgt="*", tgt_type="glob", minions=[], is_finished=wrong_future
        )

        self.assertTrue(result)

    @tornado.testing.gen_test
    def test_when_event_times_out_and_minion_is_not_running_minion_data_should_not_be_set(
        self,
    ):
        fut = tornado.gen.Future()
        fut.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.return_value = fut
        wrong_future = tornado.gen.Future()
        minions = {}

        result = yield self.handler.job_not_running(
            jid=42, tgt="*", tgt_type="glob", minions=minions, is_finished=wrong_future
        )

        self.assertTrue(len(minions) == 0)

    @tornado.testing.gen_test
    def test_when_event_finally_finishes_and_returned_minion_not_in_minions_it_should_be_set_to_False(
        self,
    ):
        expected_id = 42
        no_data_event = tornado.gen.Future()
        no_data_event.set_result({"data": {}})
        empty_return_event = tornado.gen.Future()
        empty_return_event.set_result({"data": {"return": {}}})
        actual_return_event = tornado.gen.Future()
        actual_return_event.set_result(
            {"data": {"return": {"something happened here": "OK?"}, "id": expected_id}}
        )
        timed_out_event = tornado.gen.Future()
        timed_out_event.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.side_effect = [
            no_data_event,
            empty_return_event,
            actual_return_event,
            timed_out_event,
            timed_out_event,
        ]
        minions = {}

        yield self.handler.job_not_running(
            jid=99,
            tgt="*",
            tgt_type="fnord",
            minions=minions,
            is_finished=tornado.gen.Future(),
        )

        self.assertFalse(minions[expected_id])

    @tornado.testing.gen_test
    def test_when_event_finally_finishes_and_returned_minion_already_in_minions_it_should_not_be_changed(
        self,
    ):
        expected_id = 42
        expected_value = object()
        minions = {expected_id: expected_value}
        no_data_event = tornado.gen.Future()
        no_data_event.set_result({"data": {}})
        empty_return_event = tornado.gen.Future()
        empty_return_event.set_result({"data": {"return": {}}})
        actual_return_event = tornado.gen.Future()
        actual_return_event.set_result(
            {"data": {"return": {"something happened here": "OK?"}, "id": expected_id}}
        )
        timed_out_event = tornado.gen.Future()
        timed_out_event.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.side_effect = [
            no_data_event,
            empty_return_event,
            actual_return_event,
            timed_out_event,
            timed_out_event,
        ]

        yield self.handler.job_not_running(
            jid=99,
            tgt="*",
            tgt_type="fnord",
            minions=minions,
            is_finished=tornado.gen.Future(),
        )

        self.assertIs(minions[expected_id], expected_value)

    @tornado.testing.gen_test
    def test_when_event_returns_early_and_finally_times_out_result_should_be_True(self):
        no_data_event = tornado.gen.Future()
        no_data_event.set_result({"data": {}})
        empty_return_event = tornado.gen.Future()
        empty_return_event.set_result({"data": {"return": {}}})
        actual_return_event = tornado.gen.Future()
        actual_return_event.set_result(
            {"data": {"return": {"something happened here": "OK?"}, "id": "fnord"}}
        )
        timed_out_event = tornado.gen.Future()
        timed_out_event.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.side_effect = [
            no_data_event,
            empty_return_event,
            actual_return_event,
            timed_out_event,
            timed_out_event,
        ]

        result = yield self.handler.job_not_running(
            jid=99,
            tgt="*",
            tgt_type="fnord",
            minions={},
            is_finished=tornado.gen.Future(),
        )
        self.assertTrue(result)

    @tornado.testing.gen_test
    def test_when_event_finishes_but_is_finished_is_done_then_result_should_be_True(
        self,
    ):
        expected_minion_id = "fnord"
        expected_minion_value = object()
        no_data_event = tornado.gen.Future()
        no_data_event.set_result({"data": {}})
        empty_return_event = tornado.gen.Future()
        empty_return_event.set_result({"data": {"return": {}}})
        actual_return_event = tornado.gen.Future()
        actual_return_event.set_result(
            {
                "data": {
                    "return": {"something happened here": "OK?"},
                    "id": expected_minion_id,
                }
            }
        )
        is_finished = tornado.gen.Future()

        def abort(*args, **kwargs):
            yield actual_return_event
            f = tornado.gen.Future()
            f.set_exception(saltnado.TimeoutException())
            is_finished.set_result("This is done")
            yield f
            assert False, "Never should make it here"

        minions = {expected_minion_id: expected_minion_value}

        self.mock.event_listener.get_event.side_effect = (x for x in abort())

        result = yield self.handler.job_not_running(
            jid=99, tgt="*", tgt_type="fnord", minions=minions, is_finished=is_finished,
        )
        self.assertTrue(result)

        # These are failsafes to ensure nothing super sideways happened
        self.assertTrue(len(minions) == 1, str(minions))
        self.assertIs(minions[expected_minion_id], expected_minion_value)

    @tornado.testing.gen_test
    def test_when_is_finished_times_out_before_event_finishes_result_should_be_True(
        self,
    ):
        # Other test times out with event - this one should time out for is_finished
        finished = tornado.gen.Future()
        finished.set_exception(saltnado.TimeoutException())
        wrong_future = tornado.gen.Future()
        self.mock.event_listener.get_event.return_value = wrong_future

        result = yield self.handler.job_not_running(
            jid=42, tgt="*", tgt_type="glob", minions=[], is_finished=finished
        )

        self.assertTrue(result)

    @tornado.testing.gen_test
    def test_when_is_finished_times_out_before_event_finishes_event_should_have_result_set_to_None(
        self,
    ):
        finished = tornado.gen.Future()
        finished.set_exception(saltnado.TimeoutException())
        wrong_future = tornado.gen.Future()
        self.mock.event_listener.get_event.return_value = wrong_future

        result = yield self.handler.job_not_running(
            jid=42, tgt="*", tgt_type="glob", minions=[], is_finished=finished
        )

        self.assertIsNone(wrong_future.result())


# TODO: I think we can extract seUp into a superclass -<NAME>, 2020-11-03
class TestGetMinionReturns(tornado.testing.AsyncTestCase):
    def setUp(self):
        super().setUp()
        self.mock = MagicMock()
        self.mock.opts = {
            "syndic_wait": 0.1,
            "cachedir": "/tmp/testing/cachedir",
            "sock_dir": "/tmp/testing/sock_drawer",
            "transport": "zeromq",
            "extension_modules": "/tmp/testing/moduuuuules",
            "order_masters": False,
            "gather_job_timeout": 10.001,
        }
        self.handler = saltnado.SaltAPIHandler(self.mock, self.mock)
        f = tornado.gen.Future()
        f.set_result({"jid": f, "minions": []})

    @tornado.testing.gen_test
    def test_if_finished_before_any_events_return_then_result_should_be_empty_dictionary(
        self,
    ):
        expected_result = {}
        xxx = tornado.gen.Future()
        xxx.set_result(None)
        is_finished = tornado.gen.Future()
        is_finished.set_result(None)
        actual_result = yield self.handler.get_minion_returns(
            events=[],
            is_finished=is_finished,
            is_timed_out=tornado.gen.Future(),
            min_wait_time=xxx,
            minions={},
        )
        self.assertDictEqual(actual_result, expected_result)

    # TODO: Copy above - test with timed out -<NAME>, 2020-11-05

    @tornado.testing.gen_test
    def test_if_is_finished_after_events_return_then_result_should_contain_event_result_data(
        self,
    ):
        expected_result = {
            "minion1": {"fnord": "this is some fnordish data"},
            "minion2": {"fnord": "this is some other fnordish data"},
        }
        xxx = tornado.gen.Future()
        xxx.set_result(None)
        is_finished = tornado.gen.Future()
        # XXX what do I do here?
        events = [
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
        ]
        events[0].set_result(
            {
                "tag": "fnord",
                "data": {"id": "minion1", "return": expected_result["minion1"]},
            }
        )
        events[1].set_result(
            {
                "tag": "fnord",
                "data": {"id": "minion2", "return": expected_result["minion2"]},
            }
        )
        self.io_loop.call_later(0.2, lambda: is_finished.set_result(None))

        actual_result = yield self.handler.get_minion_returns(
            events=events,
            is_finished=is_finished,
            is_timed_out=tornado.gen.Future(),
            min_wait_time=xxx,
            minions={
                "minion1": False,
                "minion2": False,
                "never returning minion": False,
            },
        )

        assert actual_result == expected_result

    @tornado.testing.gen_test
    def test_if_timed_out_after_events_return_then_result_should_contain_event_result_data(
        self,
    ):
        expected_result = {
            "minion1": {"fnord": "this is some fnordish data"},
            "minion2": {"fnord": "this is some other fnordish data"},
        }
        xxx = tornado.gen.Future()
        xxx.set_result(None)
        is_timed_out = tornado.gen.Future()
        # XXX what do I do here?
        events = [
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
        ]
        events[0].set_result(
            {
                "tag": "fnord",
                "data": {"id": "minion1", "return": expected_result["minion1"]},
            }
        )
        events[1].set_result(
            {
                "tag": "fnord",
                "data": {"id": "minion2", "return": expected_result["minion2"]},
            }
        )
        self.io_loop.call_later(0.2, lambda: is_timed_out.set_result(None))

        actual_result = yield self.handler.get_minion_returns(
            events=events,
            is_finished=tornado.gen.Future(),
            is_timed_out=is_timed_out,
            min_wait_time=xxx,
            minions={
                "minion1": False,
                "minion2": False,
                "never returning minion": False,
            },
        )

        assert actual_result == expected_result

    @tornado.testing.gen_test
    def test_if_wait_timer_is_not_done_even_though_results_are_then_data_should_not_yet_be_returned(
        self,
    ):
        expected_result = {
            "one": {"fnordy one": "one has some data"},
            "two": {"fnordy two": "two has some data"},
        }
        events = [tornado.gen.Future(), tornado.gen.Future()]
        events[0].set_result(
            {"tag": "fnord", "data": {"id": "one", "return": expected_result["one"]}}
        )
        events[1].set_result(
            {"tag": "fnord", "data": {"id": "two", "return": expected_result["two"]}}
        )
        wait_timer = tornado.gen.Future()
        fut = self.handler.get_minion_returns(
            events=events,
            is_finished=tornado.gen.Future(),
            is_timed_out=tornado.gen.Future(),
            min_wait_time=wait_timer,
            minions={"one": False, "two": False},
        )

        def boop():
            yield fut

        self.io_loop.spawn_callback(boop)
        yield tornado.gen.sleep(0.1)

        assert not fut.done()

        wait_timer.set_result(None)
        actual_result = yield fut

        assert actual_result == expected_result

    @tornado.testing.gen_test
    def test_when_is_finished_any_other_futures_should_be_canceled(self):
        events = [
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
        ]

        is_finished = tornado.gen.Future()
        is_finished.set_result(None)
        yield self.handler.get_minion_returns(
            events=events,
            is_finished=is_finished,
            is_timed_out=tornado.gen.Future(),
            min_wait_time=tornado.gen.Future(),
            minions={"one": False, "two": False},
        )

        are_done = [event.done() for event in events]
        assert all(are_done)

    @tornado.testing.gen_test
    def test_when_is_timed_out_any_other_futures_should_be_canceled(self):
        # There is some question about whether this test is or should be<commit_msg>Tests for saltnado infinite loop<commit_after>import salt.ext.tornado as tornado
import salt.ext.tornado.testing
import salt.netapi.rest_tornado.saltnado as saltnado
from tests.support.mock import MagicMock, patch

anti_lint = salt.ext.tornado.testing


class TestJobNotRunning(tornado.testing.AsyncTestCase):
    def setUp(self):
        super().setUp()
        self.mock = MagicMock()
        self.mock.opts = {
            "syndic_wait": 0.1,
            "cachedir": "/tmp/testing/cachedir",
            "sock_dir": "/tmp/testing/sock_drawer",
            "transport": "zeromq",
            "extension_modules": "/tmp/testing/moduuuuules",
            "order_masters": False,
            "gather_job_timeout": 10.001,
        }
        self.handler = saltnado.SaltAPIHandler(self.mock, self.mock)
        self.handler._write_buffer = []
        self.handler._transforms = []
        self.handler.lowstate = []
        self.handler.content_type = "text/plain"
        self.handler.dumper = lambda x: x
        f = tornado.gen.Future()
        f.set_result({"jid": f, "minions": []})
        self.handler.saltclients.update({"local": lambda *args, **kwargs: f})

    @tornado.testing.gen_test
    def test_when_disbatch_has_already_finished_then_writing_return_should_not_fail(
        self,
    ):
        self.handler.finish()
        result = yield self.handler.disbatch()

    @tornado.testing.gen_test
    def test_when_disbatch_has_already_finished_then_finishing_should_not_fail(self):
        self.handler.finish()
        result = yield self.handler.disbatch()

    @tornado.testing.gen_test
    def test_when_event_times_out_and_minion_is_not_running_result_should_be_True(self):
        fut = tornado.gen.Future()
        fut.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.return_value = fut
        wrong_future = tornado.gen.Future()

        result = yield self.handler.job_not_running(
            jid=42, tgt="*", tgt_type="glob", minions=[], is_finished=wrong_future
        )

        self.assertTrue(result)

    @tornado.testing.gen_test
    def test_when_event_times_out_and_minion_is_not_running_minion_data_should_not_be_set(
        self,
    ):
        fut = tornado.gen.Future()
        fut.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.return_value = fut
        wrong_future = tornado.gen.Future()
        minions = {}

        result = yield self.handler.job_not_running(
            jid=42, tgt="*", tgt_type="glob", minions=minions, is_finished=wrong_future
        )

        self.assertTrue(len(minions) == 0)

    @tornado.testing.gen_test
    def test_when_event_finally_finishes_and_returned_minion_not_in_minions_it_should_be_set_to_False(
        self,
    ):
        expected_id = 42
        no_data_event = tornado.gen.Future()
        no_data_event.set_result({"data": {}})
        empty_return_event = tornado.gen.Future()
        empty_return_event.set_result({"data": {"return": {}}})
        actual_return_event = tornado.gen.Future()
        actual_return_event.set_result(
            {"data": {"return": {"something happened here": "OK?"}, "id": expected_id}}
        )
        timed_out_event = tornado.gen.Future()
        timed_out_event.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.side_effect = [
            no_data_event,
            empty_return_event,
            actual_return_event,
            timed_out_event,
            timed_out_event,
        ]
        minions = {}

        yield self.handler.job_not_running(
            jid=99,
            tgt="*",
            tgt_type="fnord",
            minions=minions,
            is_finished=tornado.gen.Future(),
        )

        self.assertFalse(minions[expected_id])

    @tornado.testing.gen_test
    def test_when_event_finally_finishes_and_returned_minion_already_in_minions_it_should_not_be_changed(
        self,
    ):
        expected_id = 42
        expected_value = object()
        minions = {expected_id: expected_value}
        no_data_event = tornado.gen.Future()
        no_data_event.set_result({"data": {}})
        empty_return_event = tornado.gen.Future()
        empty_return_event.set_result({"data": {"return": {}}})
        actual_return_event = tornado.gen.Future()
        actual_return_event.set_result(
            {"data": {"return": {"something happened here": "OK?"}, "id": expected_id}}
        )
        timed_out_event = tornado.gen.Future()
        timed_out_event.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.side_effect = [
            no_data_event,
            empty_return_event,
            actual_return_event,
            timed_out_event,
            timed_out_event,
        ]

        yield self.handler.job_not_running(
            jid=99,
            tgt="*",
            tgt_type="fnord",
            minions=minions,
            is_finished=tornado.gen.Future(),
        )

        self.assertIs(minions[expected_id], expected_value)

    @tornado.testing.gen_test
    def test_when_event_returns_early_and_finally_times_out_result_should_be_True(self):
        no_data_event = tornado.gen.Future()
        no_data_event.set_result({"data": {}})
        empty_return_event = tornado.gen.Future()
        empty_return_event.set_result({"data": {"return": {}}})
        actual_return_event = tornado.gen.Future()
        actual_return_event.set_result(
            {"data": {"return": {"something happened here": "OK?"}, "id": "fnord"}}
        )
        timed_out_event = tornado.gen.Future()
        timed_out_event.set_exception(saltnado.TimeoutException())
        self.mock.event_listener.get_event.side_effect = [
            no_data_event,
            empty_return_event,
            actual_return_event,
            timed_out_event,
            timed_out_event,
        ]

        result = yield self.handler.job_not_running(
            jid=99,
            tgt="*",
            tgt_type="fnord",
            minions={},
            is_finished=tornado.gen.Future(),
        )
        self.assertTrue(result)

    @tornado.testing.gen_test
    def test_when_event_finishes_but_is_finished_is_done_then_result_should_be_True(
        self,
    ):
        expected_minion_id = "fnord"
        expected_minion_value = object()
        no_data_event = tornado.gen.Future()
        no_data_event.set_result({"data": {}})
        empty_return_event = tornado.gen.Future()
        empty_return_event.set_result({"data": {"return": {}}})
        actual_return_event = tornado.gen.Future()
        actual_return_event.set_result(
            {
                "data": {
                    "return": {"something happened here": "OK?"},
                    "id": expected_minion_id,
                }
            }
        )
        is_finished = tornado.gen.Future()

        def abort(*args, **kwargs):
            yield actual_return_event
            f = tornado.gen.Future()
            f.set_exception(saltnado.TimeoutException())
            is_finished.set_result("This is done")
            yield f
            assert False, "Never should make it here"

        minions = {expected_minion_id: expected_minion_value}

        self.mock.event_listener.get_event.side_effect = (x for x in abort())

        result = yield self.handler.job_not_running(
            jid=99, tgt="*", tgt_type="fnord", minions=minions, is_finished=is_finished,
        )
        self.assertTrue(result)

        # These are failsafes to ensure nothing super sideways happened
        self.assertTrue(len(minions) == 1, str(minions))
        self.assertIs(minions[expected_minion_id], expected_minion_value)

    @tornado.testing.gen_test
    def test_when_is_finished_times_out_before_event_finishes_result_should_be_True(
        self,
    ):
        # Other test times out with event - this one should time out for is_finished
        finished = tornado.gen.Future()
        finished.set_exception(saltnado.TimeoutException())
        wrong_future = tornado.gen.Future()
        self.mock.event_listener.get_event.return_value = wrong_future

        result = yield self.handler.job_not_running(
            jid=42, tgt="*", tgt_type="glob", minions=[], is_finished=finished
        )

        self.assertTrue(result)

    @tornado.testing.gen_test
    def test_when_is_finished_times_out_before_event_finishes_event_should_have_result_set_to_None(
        self,
    ):
        finished = tornado.gen.Future()
        finished.set_exception(saltnado.TimeoutException())
        wrong_future = tornado.gen.Future()
        self.mock.event_listener.get_event.return_value = wrong_future

        result = yield self.handler.job_not_running(
            jid=42, tgt="*", tgt_type="glob", minions=[], is_finished=finished
        )

        self.assertIsNone(wrong_future.result())


# TODO: I think we can extract seUp into a superclass -<NAME>, 2020-11-03
class TestGetMinionReturns(tornado.testing.AsyncTestCase):
    def setUp(self):
        super().setUp()
        self.mock = MagicMock()
        self.mock.opts = {
            "syndic_wait": 0.1,
            "cachedir": "/tmp/testing/cachedir",
            "sock_dir": "/tmp/testing/sock_drawer",
            "transport": "zeromq",
            "extension_modules": "/tmp/testing/moduuuuules",
            "order_masters": False,
            "gather_job_timeout": 10.001,
        }
        self.handler = saltnado.SaltAPIHandler(self.mock, self.mock)
        f = tornado.gen.Future()
        f.set_result({"jid": f, "minions": []})

    @tornado.testing.gen_test
    def test_if_finished_before_any_events_return_then_result_should_be_empty_dictionary(
        self,
    ):
        expected_result = {}
        xxx = tornado.gen.Future()
        xxx.set_result(None)
        is_finished = tornado.gen.Future()
        is_finished.set_result(None)
        actual_result = yield self.handler.get_minion_returns(
            events=[],
            is_finished=is_finished,
            is_timed_out=tornado.gen.Future(),
            min_wait_time=xxx,
            minions={},
        )
        self.assertDictEqual(actual_result, expected_result)

    # TODO: Copy above - test with timed out -<NAME>, 2020-11-05

    @tornado.testing.gen_test
    def test_if_is_finished_after_events_return_then_result_should_contain_event_result_data(
        self,
    ):
        expected_result = {
            "minion1": {"fnord": "this is some fnordish data"},
            "minion2": {"fnord": "this is some other fnordish data"},
        }
        xxx = tornado.gen.Future()
        xxx.set_result(None)
        is_finished = tornado.gen.Future()
        # XXX what do I do here?
        events = [
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
        ]
        events[0].set_result(
            {
                "tag": "fnord",
                "data": {"id": "minion1", "return": expected_result["minion1"]},
            }
        )
        events[1].set_result(
            {
                "tag": "fnord",
                "data": {"id": "minion2", "return": expected_result["minion2"]},
            }
        )
        self.io_loop.call_later(0.2, lambda: is_finished.set_result(None))

        actual_result = yield self.handler.get_minion_returns(
            events=events,
            is_finished=is_finished,
            is_timed_out=tornado.gen.Future(),
            min_wait_time=xxx,
            minions={
                "minion1": False,
                "minion2": False,
                "never returning minion": False,
            },
        )

        assert actual_result == expected_result

    @tornado.testing.gen_test
    def test_if_timed_out_after_events_return_then_result_should_contain_event_result_data(
        self,
    ):
        expected_result = {
            "minion1": {"fnord": "this is some fnordish data"},
            "minion2": {"fnord": "this is some other fnordish data"},
        }
        xxx = tornado.gen.Future()
        xxx.set_result(None)
        is_timed_out = tornado.gen.Future()
        # XXX what do I do here?
        events = [
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
        ]
        events[0].set_result(
            {
                "tag": "fnord",
                "data": {"id": "minion1", "return": expected_result["minion1"]},
            }
        )
        events[1].set_result(
            {
                "tag": "fnord",
                "data": {"id": "minion2", "return": expected_result["minion2"]},
            }
        )
        self.io_loop.call_later(0.2, lambda: is_timed_out.set_result(None))

        actual_result = yield self.handler.get_minion_returns(
            events=events,
            is_finished=tornado.gen.Future(),
            is_timed_out=is_timed_out,
            min_wait_time=xxx,
            minions={
                "minion1": False,
                "minion2": False,
                "never returning minion": False,
            },
        )

        assert actual_result == expected_result

    @tornado.testing.gen_test
    def test_if_wait_timer_is_not_done_even_though_results_are_then_data_should_not_yet_be_returned(
        self,
    ):
        expected_result = {
            "one": {"fnordy one": "one has some data"},
            "two": {"fnordy two": "two has some data"},
        }
        events = [tornado.gen.Future(), tornado.gen.Future()]
        events[0].set_result(
            {"tag": "fnord", "data": {"id": "one", "return": expected_result["one"]}}
        )
        events[1].set_result(
            {"tag": "fnord", "data": {"id": "two", "return": expected_result["two"]}}
        )
        wait_timer = tornado.gen.Future()
        fut = self.handler.get_minion_returns(
            events=events,
            is_finished=tornado.gen.Future(),
            is_timed_out=tornado.gen.Future(),
            min_wait_time=wait_timer,
            minions={"one": False, "two": False},
        )

        def boop():
            yield fut

        self.io_loop.spawn_callback(boop)
        yield tornado.gen.sleep(0.1)

        assert not fut.done()

        wait_timer.set_result(None)
        actual_result = yield fut

        assert actual_result == expected_result

    @tornado.testing.gen_test
    def test_when_is_finished_any_other_futures_should_be_canceled(self):
        events = [
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
        ]

        is_finished = tornado.gen.Future()
        is_finished.set_result(None)
        yield self.handler.get_minion_returns(
            events=events,
            is_finished=is_finished,
            is_timed_out=tornado.gen.Future(),
            min_wait_time=tornado.gen.Future(),
            minions={"one": False, "two": False},
        )

        are_done = [event.done() for event in events]
        assert all(are_done)

    @tornado.testing.gen_test
    def test_when_an_event_times_out_then_we_should_not_enter_an_infinite_loop(self):
        # NOTE: this test will enter an infinite loop if the code is broken. I
        # was not able to figure out a way to ensure that the test exits with
        # failure rather than stalling forever. That is because the
        # TimeoutException happens first and then tornado will never yield
        # control to another coroutine. Like a coroutine to remove the future
        # with the TimeoutException. It is also not possible to clear the
        # TimeoutException.

        events = [
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
            tornado.gen.Future(),
        ]

        # Arguably any event would work, but 3 isn't the first, so it
        # gives us a little more confidence that this test is testing
        # correctly
        events[3].set_exception(saltnado.TimeoutException())
        times_out_later = tornado.gen.Future()
        # 0.5s should be long enough that the test gets through doing other
        # things before hitting this timeout, which will cancel all the
        # in-flight futures.
        self.io_loop.call_later(0.5, lambda: times_out_later.set_result(None))
        yield self.handler.get_minion_returns(
            events=events,
            is_finished=tornado.gen.Future(),
            is_timed_out=times_out_later,
            min_wait_time=tornado.gen.Future(),
            minions={"one": False, "two": False},
        )

        # Technically we don't /need/ to check that all events are done,
        # but it's incorrect to exit the function without ensuring all
        # futures are canceled.
        are_done = [event.done() for event in events]
        assert all(are_done)
        assert times_out_later.done()

    @tornado.testing.gen_test
    def test_when_is_timed_out_any_other_futures_should_be_canceled(self):
        # There is some question about whether this test is or should be
{'fraction_non_alphanumeric': 0.11048132026430338, 'fraction_numerical': 0.005198384116744434, 'mean_word_length': 2.204616156547918, 'pattern_counts': {'":': 188, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3099839', 'n_tokens_mistral': 10049, 'n_tokens_neox': 9745, 'n_words': 1576}