def setUp(self): self._client_sys = FakeSys() self._server_sys = FakeSys() self._fake_clock = scalyr_util.FakeClock() self._client_channel = FakeClientChannel(self._fake_clock) self._server_channel = FakeServerChannel(self._client_channel) self._client = RedirectorClient(self._client_channel, sys_impl=self._client_sys, fake_clock=self._fake_clock) self._server = RedirectorServer(self._server_channel, sys_impl=self._server_sys) self._client.start() self._server.start()
def setUp(self): self._fake_sys = FakeSys() # Since the client is an actual other thread that blocks waiting for input from the server, we have to # simulate the time using a fake clock. That will allow us to wait up the client thread from time to time. self._fake_clock = scalyr_util.FakeClock() # The fake channel allows us to insert bytes being sent by the server. self._client_channel = FakeClientChannel(self._fake_clock) self._client = RedirectorClient(self._client_channel, sys_impl=self._fake_sys, fake_clock=self._fake_clock) self._client.start() # Wait until the client thread begins to block for the initial accept from the server. self._fake_clock.block_until_n_waiting_threads(1)
def test_user_agent_polling(self): """Test polling of user-agent fragments and invocation of the callback (only on change) A MonitorsManager + 2 monitors are started (each has their own threads). 1 monitor returns non-empty frags. 1 returns None. We then verify that the callback is invoked correctly, only if the fragments change. Notes: - FakeClocks are used to avoid having to wait for thread loops. - A FakeAgentLogger is defined so we can modify local test state - Even though this test could have been broken up into 2 smaller ones, it is kept as one to minimize overhead time taken by stop_manager() """ counter = {"callback_invocations": 0} test_frag = "some_frag" poll_interval = 30 # Create MonitorsManager + 2 monitors. Set each to daemon otherwise unit test doesn't terminate # Fake the clock to fast-forward MonitorsManager sleep loop fake_clock = scalyr_util.FakeClock() test_manager, _ = ScalyrTestUtils.create_test_monitors_manager( config_monitors=[ { "module": "scalyr_agent.builtin_monitors.test_monitor", "gauss_mean": 0, }, { "module": "scalyr_agent.builtin_monitors.test_monitor", "gauss_mean": 0, }, { "module": "scalyr_agent.builtin_monitors.test_monitor", "gauss_mean": 0, }, ], platform_monitors=[], extra_toplevel_config={"user_agent_refresh_interval": poll_interval}, null_logger=True, fake_clock=fake_clock, ) self.assertEquals( test_manager._user_agent_refresh_interval, 30 ) # ensure config setting works self.assertEquals(len(test_manager.monitors), 3) patched_monitor_0 = test_manager.monitors[0] patched_monitor_1 = test_manager.monitors[1] unpatched_monitor = test_manager.monitors[2] # The MonitorsManager + 3 monitor threads will wait on the fake clock fragment_polls = FakeClockCounter(fake_clock, num_waiters=4) # Mock the function that returns user_agent_fragment (normally invoked on a Monitor) def mock_get_user_agent_fragment(): # Will be called on 2 patched monitors concurrently fragment_polls.increment() return test_frag for mon in [patched_monitor_0, patched_monitor_1]: mon.get_user_agent_fragment = mock_get_user_agent_fragment self.assertEquals( mon.get_user_agent_fragment(), test_frag ) # monkey patched self.assertEquals( unpatched_monitor.get_user_agent_fragment(), None ) # not patched # Mock the callback (that would normally be invoked on ScalyrClientSession) # Check that the exact fragment returned by the 2 patched monitors are deduplicated. def augment_user_agent(fragments): counter["callback_invocations"] += 1 self.assertEquals(fragments, [test_frag]) test_manager.set_user_agent_augment_callback(augment_user_agent) # We're finally ready start all threads and assert correct behavior. # Wait for MonitorsManager to poll for user-agent fragments 10x # Since 2 monitors are being polled for fragments, num polls should reach 2 x 10 = 20. # However, the monitors always return a non-changing frag, so the callback should be invoked only once. # (Note: FakeClock ensures all the above happen within a split second) test_manager.start_manager() self.assertTrue( fragment_polls.sleep_until_count_or_maxwait(20, poll_interval, 1) ) self.assertEquals(counter["callback_invocations"], 1) # Rerun the above test but this time have monitors return changing fragments. # This will cause the user agent callback to be invoked during each round of polling. # (The manager polls monitors 10x, and each poll results in a callback invocation). fragment_polls = FakeClockCounter(fake_clock, num_waiters=4) counter["callback_invocations"] = 0 def mock_get_user_agent_fragment_2(): fragment_polls.increment() return test_frag + str(fragment_polls.count()) for mon in [patched_monitor_0, patched_monitor_1]: mon.get_user_agent_fragment = mock_get_user_agent_fragment_2 variable_frag_pattern = re.compile(test_frag + r"\d+") def augment_user_agent_2(fragments): counter["callback_invocations"] += 1 self.assertIsNotNone(variable_frag_pattern.match(fragments[0])) test_manager.set_user_agent_augment_callback(augment_user_agent_2) self.assertTrue( fragment_polls.sleep_until_count_or_maxwait(20, poll_interval, 1) ) self.assertEquals(counter["callback_invocations"], 10) # set_daemon=True obviates the following (saves a few seconds in cleanup): test_manager.stop_manager(wait_on_join=False) fake_clock.advance_time(increment_by=poll_interval)