def setUp(self): super(TestReportStatus, self).setUp() self.saved_env = dict( (k, v) for k, v in six.iteritems(os_environ_unicode)) os.environ.clear() self.time = 1409958853 self.status = AgentStatus() self.status.launch_time = self.time - 86400 self.status.log_path = "/var/logs/scalyr-agent/agent.log" self.status.scalyr_server = "https://agent.scalyr.com" self.status.server_host = "test_machine" self.status.user = "******" self.status.version = "2.0.0.beta.7" self.status.revision = "git revision" self.status.python_version = "3.6.8" config_status = ConfigStatus() self.status.config_status = config_status config_status.last_read_time = self.time - 43200 config_status.last_check_time = self.time config_status.last_good_read = self.time - 43000 config_status.path = "/etc/scalyr-agent-2/agent.json" config_status.status = "Good" config_status.additional_paths = [ "/etc/scalyr-agent-2/agent.d/server.json" ] copying_status = CopyingManagerStatus() self.status.copying_manager_status = copying_status copying_status.last_attempt_size = 10000 copying_status.last_attempt_time = self.time - 60 copying_status.last_response_status = "success" copying_status.total_errors = 0 copying_status.total_bytes_uploaded = 10000 copying_status.last_success_time = self.time - 60 # Add in one log path that isn't a glob but does not have any matches yet. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = False log_matcher.last_check_time = self.time - 10 log_matcher.log_path = "/var/logs/tomcat6/access.log" # Add in another matcher that isn't a glob but does have a match. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = False log_matcher.last_check_time = self.time - 10 log_matcher.log_path = "/var/logs/tomcat6/catalina.log" process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = "/var/logs/tomcat6/catalina.log" process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 2341234 process_status.total_bytes_pending = 1243 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 0 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 0 process_status.total_redactions = 0 # Add in another matcher that is a glob and has two matches. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = True log_matcher.last_check_time = self.time - 10 log_matcher.log_path = "/var/logs/cron/*.log" process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = "/var/logs/cron/logrotate.log" process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 2341234 process_status.total_bytes_pending = 1243 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 0 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 0 process_status.total_redactions = 0 process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = "/var/logs/cron/ohno.log" process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 23434 process_status.total_bytes_pending = 12943 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 5 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 10 process_status.total_redactions = 10 # One more glob that doesn't have any matches. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = True log_matcher.last_check_time = self.time - 10 log_matcher.log_path = "/var/logs/silly/*.log" # Now for the monitors. monitor_manager = MonitorManagerStatus() self.status.monitor_manager_status = monitor_manager monitor_manager.total_alive_monitors = 2 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = True monitor_status.monitor_name = "linux_process_metrics(agent)" monitor_status.reported_lines = 50 monitor_status.errors = 2 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = True monitor_status.monitor_name = "linux_system_metrics()" monitor_status.reported_lines = 20 monitor_status.errors = 0 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = False monitor_status.monitor_name = "bad_monitor()" monitor_status.reported_lines = 20 monitor_status.errors = 40
def setUp(self): self.time = 1409958853 self.status = AgentStatus() self.status.launch_time = self.time - 86400 self.status.log_path = '/var/logs/scalyr-agent/agent.log' self.status.scalyr_server = 'https://agent.scalyr.com' self.status.server_host = 'test_machine' self.status.user = '******' self.status.version = '2.0.0.beta.7' config_status = ConfigStatus() self.status.config_status = config_status config_status.last_read_time = self.time - 43200 config_status.last_check_time = self.time config_status.last_good_read = self.time - 43000 config_status.path = '/etc/scalyr-agent-2/agent.json' config_status.status = 'Good' config_status.additional_paths = ['/etc/scalyr-agent-2/agent.d/server.json'] copying_status = CopyingManagerStatus() self.status.copying_manager_status = copying_status copying_status.last_attempt_size = 10000 copying_status.last_attempt_time = self.time - 60 copying_status.last_response_status = 'success' copying_status.total_errors = 0 copying_status.total_bytes_uploaded = 10000 copying_status.last_success_time = self.time - 60 # Add in one log path that isn't a glob but does not have any matches yet. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = False log_matcher.last_check_time = self.time - 10 log_matcher.log_path = '/var/logs/tomcat6/access.log' # Add in another matcher that isn't a glob but does have a match. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = False log_matcher.last_check_time = self.time - 10 log_matcher.log_path = '/var/logs/tomcat6/catalina.log' process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = '/var/logs/tomcat6/catalina.log' process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 2341234 process_status.total_bytes_pending = 1243 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 0 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 0 process_status.total_redactions = 0 # Add in another matcher that is a glob and has two matches. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = True log_matcher.last_check_time = self.time - 10 log_matcher.log_path = '/var/logs/cron/*.log' process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = '/var/logs/cron/logrotate.log' process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 2341234 process_status.total_bytes_pending = 1243 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 0 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 0 process_status.total_redactions = 0 process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = '/var/logs/cron/ohno.log' process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 23434 process_status.total_bytes_pending = 12943 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 5 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 10 process_status.total_redactions = 10 # One more glob that doesn't have any matches. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = True log_matcher.last_check_time = self.time - 10 log_matcher.log_path = '/var/logs/silly/*.log' # Now for the monitors. monitor_manager = MonitorManagerStatus() self.status.monitor_manager_status = monitor_manager monitor_manager.total_alive_monitors = 2 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = True monitor_status.monitor_name = 'linux_process_metrics(agent)' monitor_status.reported_lines = 50 monitor_status.errors = 2 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = True monitor_status.monitor_name = 'linux_system_metrics()' monitor_status.reported_lines = 20 monitor_status.errors = 0 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = False monitor_status.monitor_name = 'bad_monitor()' monitor_status.reported_lines = 20 monitor_status.errors = 40
class TestReportStatus(ScalyrTestCase): def tearDown(self): os.environ.clear() os.environ.update(self.saved_env) def setUp(self): super(TestReportStatus, self).setUp() self.saved_env = dict( (k, v) for k, v in six.iteritems(os_environ_unicode)) os.environ.clear() self.time = 1409958853 self.status = AgentStatus() self.status.launch_time = self.time - 86400 self.status.log_path = "/var/logs/scalyr-agent/agent.log" self.status.scalyr_server = "https://agent.scalyr.com" self.status.server_host = "test_machine" self.status.user = "******" self.status.version = "2.0.0.beta.7" self.status.revision = "git revision" self.status.python_version = "3.6.8" config_status = ConfigStatus() self.status.config_status = config_status config_status.last_read_time = self.time - 43200 config_status.last_check_time = self.time config_status.last_good_read = self.time - 43000 config_status.path = "/etc/scalyr-agent-2/agent.json" config_status.status = "Good" config_status.additional_paths = [ "/etc/scalyr-agent-2/agent.d/server.json" ] copying_status = CopyingManagerStatus() self.status.copying_manager_status = copying_status copying_status.last_attempt_size = 10000 copying_status.last_attempt_time = self.time - 60 copying_status.last_response_status = "success" copying_status.total_errors = 0 copying_status.total_bytes_uploaded = 10000 copying_status.last_success_time = self.time - 60 # Add in one log path that isn't a glob but does not have any matches yet. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = False log_matcher.last_check_time = self.time - 10 log_matcher.log_path = "/var/logs/tomcat6/access.log" # Add in another matcher that isn't a glob but does have a match. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = False log_matcher.last_check_time = self.time - 10 log_matcher.log_path = "/var/logs/tomcat6/catalina.log" process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = "/var/logs/tomcat6/catalina.log" process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 2341234 process_status.total_bytes_pending = 1243 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 0 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 0 process_status.total_redactions = 0 # Add in another matcher that is a glob and has two matches. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = True log_matcher.last_check_time = self.time - 10 log_matcher.log_path = "/var/logs/cron/*.log" process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = "/var/logs/cron/logrotate.log" process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 2341234 process_status.total_bytes_pending = 1243 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 0 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 0 process_status.total_redactions = 0 process_status = LogProcessorStatus() log_matcher.log_processors_status.append(process_status) process_status.log_path = "/var/logs/cron/ohno.log" process_status.last_scan_time = self.time - 120 process_status.total_bytes_copied = 23434 process_status.total_bytes_pending = 12943 process_status.total_bytes_skipped = 12 process_status.total_bytes_failed = 1432 process_status.total_bytes_dropped_by_sampling = 5 process_status.total_lines_copied = 214324 process_status.total_lines_dropped_by_sampling = 10 process_status.total_redactions = 10 # One more glob that doesn't have any matches. log_matcher = LogMatcherStatus() copying_status.log_matchers.append(log_matcher) log_matcher.is_glob = True log_matcher.last_check_time = self.time - 10 log_matcher.log_path = "/var/logs/silly/*.log" # Now for the monitors. monitor_manager = MonitorManagerStatus() self.status.monitor_manager_status = monitor_manager monitor_manager.total_alive_monitors = 2 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = True monitor_status.monitor_name = "linux_process_metrics(agent)" monitor_status.reported_lines = 50 monitor_status.errors = 2 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = True monitor_status.monitor_name = "linux_system_metrics()" monitor_status.reported_lines = 20 monitor_status.errors = 0 monitor_status = MonitorStatus() monitor_manager.monitors_status.append(monitor_status) monitor_status.is_alive = False monitor_status.monitor_name = "bad_monitor()" monitor_status.reported_lines = 20 monitor_status.errors = 40 def test_basic(self): output = io.StringIO() # Environment variables os.environ["SCALYR_API_KEY"] = "This private key should be redacted" # intentionally leave out required scalyr_server os.environ["scalyr_K8S_CLUSTER_NAME"] = "test_cluster" os.environ[ "K8S_EVENT_DISABLE"] = "Special-case-included despite missing prefix. Appears at end of main keys." os.environ["SCALYR_K8S_EVENT_DISABLE"] = "true" os.environ["SCALYR_AAA"] = "Should appear just after main keys" os.environ["SCALYR_XXX_A"] = "A before b (ignores case)" os.environ["sCaLyR_XXX_b"] = "b after A (ignores case)" os.environ["SCALYR_ZZZ"] = "Should appear at the end" report_status(output, self.status, self.time) expected_output = """Scalyr Agent status. See https://www.scalyr.com/help/scalyr-agent-2 for help Current time: Fri Sep 5 23:14:13 2014 UTC Agent started at: Thu Sep 4 23:14:13 2014 UTC Version: 2.0.0.beta.7 VCS revision: git revision Python version: 3.6.8 Agent running as: root Agent log: /var/logs/scalyr-agent/agent.log ServerHost: test_machine View data from this agent at: https://www.scalyr.com/events?filter=$serverHost%3D%27test_machine%27 Agent configuration: ==================== Configuration files: /etc/scalyr-agent-2/agent.json /etc/scalyr-agent-2/agent.d/server.json Status: Good (files parsed successfully) Last checked: Fri Sep 5 23:14:13 2014 UTC Last changed observed: Fri Sep 5 11:14:13 2014 UTC Environment variables: SCALYR_API_KEY = <Redacted> SCALYR_SERVER = <Missing> K8S_EVENT_DISABLE = Special-case-included despite missing prefix. Appears at end of main keys. SCALYR_AAA = Should appear just after main keys scalyr_K8S_CLUSTER_NAME = test_cluster SCALYR_K8S_EVENT_DISABLE = true SCALYR_XXX_A = A before b (ignores case) sCaLyR_XXX_b = b after A (ignores case) SCALYR_ZZZ = Should appear at the end Log transmission: ================= (these statistics cover the period from Fri Sep 5 11:14:13 2014 UTC) Bytes uploaded successfully: 10000 Last successful communication with Scalyr: Fri Sep 5 23:13:13 2014 UTC Last attempt: Fri Sep 5 23:13:13 2014 UTC Last copy request size: 10000 Path /var/logs/tomcat6/access.log: no matching readable file, last checked Fri Sep 5 23:14:03 2014 UTC Path /var/logs/tomcat6/catalina.log: copied 2341234 bytes (214324 lines), 1243 bytes pending, 12 bytes skipped, 1432 bytes failed, last checked Fri Sep 5 23:12:13 2014 UTC Glob: /var/logs/cron/*.log:: last scanned for glob matches at Fri Sep 5 23:14:03 2014 UTC /var/logs/cron/logrotate.log: copied 2341234 bytes (214324 lines), 1243 bytes pending, 12 bytes skipped, 1432 bytes failed, last checked Fri Sep 5 23:12:13 2014 UTC /var/logs/cron/ohno.log: copied 23434 bytes (214324 lines), 12943 bytes pending, 12 bytes skipped, 1432 bytes failed, 5 bytes dropped by sampling (10 lines), 10 redactions, last checked Fri Sep 5 23:12:13 2014 UTC Glob: /var/logs/silly/*.log:: last scanned for glob matches at Fri Sep 5 23:14:03 2014 UTC Monitors: ========= (these statistics cover the period from Fri Sep 5 11:14:13 2014 UTC) Running monitors: linux_process_metrics(agent): 50 lines emitted, 2 errors linux_system_metrics(): 20 lines emitted, 0 errors Failed monitors: bad_monitor() 20 lines emitted, 40 errors """ self.assertEquals(expected_output, output.getvalue()) def test_bad_config(self): self.status.config_status.last_error = "Bad stuff" output = io.StringIO() report_status(output, self.status, self.time) expected_output = """Scalyr Agent status. See https://www.scalyr.com/help/scalyr-agent-2 for help Current time: Fri Sep 5 23:14:13 2014 UTC Agent started at: Thu Sep 4 23:14:13 2014 UTC Version: 2.0.0.beta.7 VCS revision: git revision Python version: 3.6.8 Agent running as: root Agent log: /var/logs/scalyr-agent/agent.log ServerHost: test_machine View data from this agent at: https://www.scalyr.com/events?filter=$serverHost%3D%27test_machine%27 Agent configuration: ==================== Configuration files: /etc/scalyr-agent-2/agent.json /etc/scalyr-agent-2/agent.d/server.json Status: Bad (could not parse, using last good version) Last checked: Fri Sep 5 23:14:13 2014 UTC Last changed observed: Fri Sep 5 11:14:13 2014 UTC Parsing error: Bad stuff Environment variables: SCALYR_API_KEY = <Missing> SCALYR_SERVER = <Missing> Log transmission: ================= (these statistics cover the period from Fri Sep 5 11:14:13 2014 UTC) Bytes uploaded successfully: 10000 Last successful communication with Scalyr: Fri Sep 5 23:13:13 2014 UTC Last attempt: Fri Sep 5 23:13:13 2014 UTC Last copy request size: 10000 Path /var/logs/tomcat6/access.log: no matching readable file, last checked Fri Sep 5 23:14:03 2014 UTC Path /var/logs/tomcat6/catalina.log: copied 2341234 bytes (214324 lines), 1243 bytes pending, 12 bytes skipped, 1432 bytes failed, last checked Fri Sep 5 23:12:13 2014 UTC Glob: /var/logs/cron/*.log:: last scanned for glob matches at Fri Sep 5 23:14:03 2014 UTC /var/logs/cron/logrotate.log: copied 2341234 bytes (214324 lines), 1243 bytes pending, 12 bytes skipped, 1432 bytes failed, last checked Fri Sep 5 23:12:13 2014 UTC /var/logs/cron/ohno.log: copied 23434 bytes (214324 lines), 12943 bytes pending, 12 bytes skipped, 1432 bytes failed, 5 bytes dropped by sampling (10 lines), 10 redactions, last checked Fri Sep 5 23:12:13 2014 UTC Glob: /var/logs/silly/*.log:: last scanned for glob matches at Fri Sep 5 23:14:03 2014 UTC Monitors: ========= (these statistics cover the period from Fri Sep 5 11:14:13 2014 UTC) Running monitors: linux_process_metrics(agent): 50 lines emitted, 2 errors linux_system_metrics(): 20 lines emitted, 0 errors Failed monitors: bad_monitor() 20 lines emitted, 40 errors """ self.assertEquals(expected_output, output.getvalue()) def test_bad_copy_response(self): self.status.copying_manager_status.last_response = "Some weird stuff" self.status.copying_manager_status.last_response_status = "error" self.status.copying_manager_status.total_errors = 5 output = io.StringIO() report_status(output, self.status, self.time) expected_output = """Scalyr Agent status. See https://www.scalyr.com/help/scalyr-agent-2 for help Current time: Fri Sep 5 23:14:13 2014 UTC Agent started at: Thu Sep 4 23:14:13 2014 UTC Version: 2.0.0.beta.7 VCS revision: git revision Python version: 3.6.8 Agent running as: root Agent log: /var/logs/scalyr-agent/agent.log ServerHost: test_machine View data from this agent at: https://www.scalyr.com/events?filter=$serverHost%3D%27test_machine%27 Agent configuration: ==================== Configuration files: /etc/scalyr-agent-2/agent.json /etc/scalyr-agent-2/agent.d/server.json Status: Good (files parsed successfully) Last checked: Fri Sep 5 23:14:13 2014 UTC Last changed observed: Fri Sep 5 11:14:13 2014 UTC Environment variables: SCALYR_API_KEY = <Missing> SCALYR_SERVER = <Missing> Log transmission: ================= (these statistics cover the period from Fri Sep 5 11:14:13 2014 UTC) Bytes uploaded successfully: 10000 Last successful communication with Scalyr: Fri Sep 5 23:13:13 2014 UTC Last attempt: Fri Sep 5 23:13:13 2014 UTC Last copy request size: 10000 Last copy response size: 16 Last copy response status: error Last copy response: Some weird stuff Total responses with errors: 5 (see '/var/logs/scalyr-agent/agent.log' for details) Path /var/logs/tomcat6/access.log: no matching readable file, last checked Fri Sep 5 23:14:03 2014 UTC Path /var/logs/tomcat6/catalina.log: copied 2341234 bytes (214324 lines), 1243 bytes pending, 12 bytes skipped, 1432 bytes failed, last checked Fri Sep 5 23:12:13 2014 UTC Glob: /var/logs/cron/*.log:: last scanned for glob matches at Fri Sep 5 23:14:03 2014 UTC /var/logs/cron/logrotate.log: copied 2341234 bytes (214324 lines), 1243 bytes pending, 12 bytes skipped, 1432 bytes failed, last checked Fri Sep 5 23:12:13 2014 UTC /var/logs/cron/ohno.log: copied 23434 bytes (214324 lines), 12943 bytes pending, 12 bytes skipped, 1432 bytes failed, 5 bytes dropped by sampling (10 lines), 10 redactions, last checked Fri Sep 5 23:12:13 2014 UTC Glob: /var/logs/silly/*.log:: last scanned for glob matches at Fri Sep 5 23:14:03 2014 UTC Monitors: ========= (these statistics cover the period from Fri Sep 5 11:14:13 2014 UTC) Running monitors: linux_process_metrics(agent): 50 lines emitted, 2 errors linux_system_metrics(): 20 lines emitted, 0 errors Failed monitors: bad_monitor() 20 lines emitted, 40 errors """ self.assertEquals(expected_output, output.getvalue()) def test_status_to_dict(self): result = self.status.to_dict() # Simple value on the OverallStats object self.assertEqual(result["user"], "root") self.assertEqual(result["version"], "2.0.0.beta.7") self.assertEqual(result["revision"], "git revision") # Verify nested status objects are recursively serialized to simple native types config_status = result["config_status"] self.assertEqual(config_status["status"], "Good") self.assertEqual(config_status["last_error"], None) self.assertEqual(config_status["last_check_time"], 1409958853) copying_manager_status = result["copying_manager_status"] self.assertEqual(copying_manager_status["last_attempt_size"], 10000) self.assertEqual(copying_manager_status["log_matchers"][0]["is_glob"], False) self.assertEqual( copying_manager_status["log_matchers"][0]["log_path"], "/var/logs/tomcat6/access.log", ) monitor_manager_status = result["monitor_manager_status"] self.assertEqual(monitor_manager_status["total_alive_monitors"], 2) self.assertEqual( monitor_manager_status["monitors_status"][0]["errors"], 2) self.assertEqual( monitor_manager_status["monitors_status"][0]["is_alive"], True) self.assertEqual( monitor_manager_status["monitors_status"][0]["monitor_name"], "linux_process_metrics(agent)", ) # Verify dict contains only simple types - JSON.dumps would fail if it doesn't result_json = json.dumps(result) self.assertEqual(json.loads(result_json), result)