async def test_update(self): source = fake_controller_source.FakeControllerSource() _FROM = "from" _TO = "to" allowed_transitions = {(_FROM, _TO), (_TO, _TO), (_FROM, _FROM)} def pod(name, check, final): labels = {"check": check} if final: labels["final"] = "true" return V1Pod(metadata=V1ObjectMeta(name=name, labels=labels)) def delete_pod(p): return p.metadata.labels["final"] == "true" async def test(name): name = f"a-{name}" await source.add(pod(name, _FROM, False)) await source.modify(pod(name, _TO, True)) tests = [test] threads = 3 size = threads * len(tests) test_done_queue = asyncio.Queue(maxsize=size) for _ in range(size): test_done_queue.put_nowait(None) watch_event = asyncio.Event() async def watch_func(options): try: return await source.watch(options) finally: watch_event.set() async def update_func(old_obj, new_obj): from_ = old_obj.metadata.labels["check"] to = new_obj.metadata.labels["check"] self.assertIn((from_, to), allowed_transitions) if delete_pod(new_obj): await source.delete(new_obj) async def delete_func(obj): test_done_queue.task_done() lw = TestLW(source.list, watch_func) h = ResourceEventHandlerFuncs(update_func=update_func, delete_func=delete_func) _, controller = new_informer(lw, V1Pod, 0, h) controller_task = asyncio.ensure_future(controller.run()) await watch_event.wait() aws = [f(f"{i}-{j}") for i in range(threads) for j, f in enumerate(tests)] await asyncio.gather(*aws) await test_done_queue.join() controller_task.cancel() await asyncio.gather(controller_task, return_exceptions=True)
async def test_initialization_race(self): source = fake_controller_source.FakeControllerSource() informer = new_shared_informer(source, V1Pod, 1) listener = TestListener("race_listener", 0) asyncio.ensure_future( informer.add_event_handler(listener, resync_period=listener._resync_period)) task = asyncio.ensure_future(informer.run()) task.cancel()
async def test_listener_resync_periods(self): source = fake_controller_source.FakeControllerSource() await source.add(V1Pod(metadata=V1ObjectMeta(name="pod1"))) await source.add(V1Pod(metadata=V1ObjectMeta(name="pod2"))) informer = new_shared_informer(source, V1Pod, 1) clock_ = clock.FakeClock(time.time()) informer._clock = clock_ informer._processor._clock = clock_ listener1 = TestListener("listener1", 0, "pod1", "pod2") await informer.add_event_handler( listener1, resync_period=listener1._resync_period) listener2 = TestListener("listener2", 2, "pod1", "pod2") await informer.add_event_handler( listener2, resync_period=listener2._resync_period) listener3 = TestListener("listener3", 3, "pod1", "pod2") await informer.add_event_handler( listener3, resync_period=listener3._resync_period) listeners = [listener1, listener2, listener3] try: task = asyncio.ensure_future(informer.run()) for listener in listeners: self.assertTrue(await listener._ok()) for listener in listeners: listener._received_item_names = [] await clock_.step(2) self.assertTrue(await listener2._ok()) await asyncio.sleep(1) self.assertEqual(len(listener1._received_item_names), 0) self.assertEqual(len(listener3._received_item_names), 0) for listener in listeners: listener._received_item_names = [] await clock_.step(1) self.assertTrue(await listener3._ok()) await asyncio.sleep(1) self.assertEqual(len(listener1._received_item_names), 0) self.assertEqual(len(listener2._received_item_names), 0) finally: task.cancel() await asyncio.gather(task, return_exceptions=True)
async def test_resync_check_period(self): source = fake_controller_source.FakeControllerSource() informer = new_shared_informer(source, V1Pod, 12 * 3600) clock_ = clock.FakeClock(time.time()) informer._clock = clock_ informer._processor._clock = clock_ listener1 = TestListener("listener1", 0) await informer.add_event_handler( listener1, resync_period=listener1._resync_period) self.assertEqual(informer._resync_check_period, 12 * 3600) self.assertEqual(informer._processor._listeners[0]._resync_period, 0) listener2 = TestListener("listener2", 60) await informer.add_event_handler( listener2, resync_period=listener2._resync_period) self.assertEqual(informer._resync_check_period, 60) self.assertEqual(informer._processor._listeners[0]._resync_period, 0) self.assertEqual(informer._processor._listeners[1]._resync_period, 60) listener3 = TestListener("listener3", 55) await informer.add_event_handler( listener3, resync_period=listener3._resync_period) self.assertEqual(informer._resync_check_period, 55) self.assertEqual(informer._processor._listeners[0]._resync_period, 0) self.assertEqual(informer._processor._listeners[1]._resync_period, 60) self.assertEqual(informer._processor._listeners[2]._resync_period, 55) listener4 = TestListener("listener4", 5) await informer.add_event_handler( listener4, resync_period=listener4._resync_period) self.assertEqual(informer._resync_check_period, 5) self.assertEqual(informer._processor._listeners[0]._resync_period, 0) self.assertEqual(informer._processor._listeners[1]._resync_period, 60) self.assertEqual(informer._processor._listeners[2]._resync_period, 55) self.assertEqual(informer._processor._listeners[3]._resync_period, 5)
async def test_hammer(self): source = fake_controller_source.FakeControllerSource() output_set_lock = asyncio.Lock() output_set = defaultdict(list) async def record_func(event_type, obj): key = deletion_handling_meta_namespace_key_func(obj) async with output_set_lock: output_set[key].append(event_type) async def add_func(obj): await record_func("add", obj) async def update_func(old_obj, new_obj): await record_func("update", new_obj) async def delete_func(obj): await record_func("delete", obj) h = ResourceEventHandlerFuncs( add_func=add_func, update_func=update_func, delete_func=delete_func ) _, controller = new_informer(source, V1Pod, 0.1, h) self.assertFalse(controller.has_synced()) controller_task = asyncio.ensure_future(controller.run()) async def condition(): return controller.has_synced() await wait.poll(0.1, wait.FOREVER_TEST_TIMEOUT, condition) self.assertTrue(controller.has_synced()) async def task(): current_names = set() for _ in range(100): if not current_names or not random.randrange(3): name = "".join( random.choice(string.ascii_letters) for _ in range(16) ) is_new = True else: name = random.choice(list(current_names)) is_new = False # TODO: fuzz pod = V1Pod(metadata=V1ObjectMeta(name=name, namespace="default")) if is_new: current_names.add(name) await source.add(pod) continue if random.randrange(2): current_names.add(name) await source.modify(pod) else: current_names.remove(name) await source.delete(pod) await asyncio.gather(*(task() for _ in range(3))) controller_task.cancel() await asyncio.gather(controller_task, return_exceptions=True) await output_set_lock.acquire()