import unittest from lxml import etree try: from unittest import mock except ImportError: import mock from crmsh import cibconfig from crmsh.ui_context import Context from crmsh.ui_resource import RscMgmt from crmsh.ui_root import Root class TestRATrace(unittest.TestCase): """Unit tests for enabling/disabling RA tracing.""" context = Context(Root()) factory = cibconfig.cib_factory def setUp(self): self.factory._push_state() def tearDown(self): self.factory._pop_state() @mock.patch('logging.Logger.error') def test_ratrace_resource(self, mock_error): """Check setting RA tracing for a resource.""" xml = '''''' obj = self.factory.create_from_node(etree.fromstring(xml)) # Trace the resource. RscMgmt()._trace_resource(self.context, obj.obj_id, obj, '/var/lib/heartbeat/trace_ra') self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-start-0', 'r1-stop-0']) self.assertEqual(obj.node.xpath('operations/op[@id="r1-start-0"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1']) self.assertEqual(obj.node.xpath('operations/op[@id="r1-stop-0"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1']) # Untrace the resource. RscMgmt()._untrace_resource(self.context, obj.obj_id, obj) self.assertEqual(obj.node.xpath('operations/op/@id'), []) self.assertEqual(obj.node.xpath('.//*[@name="trace_ra"]'), []) @mock.patch('logging.Logger.error') def test_ratrace_op(self, mock_error): """Check setting RA tracing for a specific operation.""" xml = ''' ''' obj = self.factory.create_from_node(etree.fromstring(xml)) # Trace the operation. RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor', '/var/lib/heartbeat/trace_ra') self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10']) self.assertEqual(obj.node.xpath('operations/op[@id="r1-monitor-10"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1']) # Untrace the operation. RscMgmt()._untrace_op(self.context, obj.obj_id, obj, 'monitor') self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10']) self.assertEqual(obj.node.xpath('.//*[@name="trace_ra"]'), []) # Try untracing a non-existent operation. with self.assertRaises(ValueError) as err: RscMgmt()._untrace_op(self.context, obj.obj_id, obj, 'invalid-op') self.assertEqual(str(err.exception), "Operation invalid-op not found in r1") @mock.patch('logging.Logger.error') def test_ratrace_new(self, mock_error): """Check setting RA tracing for an operation that is not in CIB.""" xml = ''' ''' obj = self.factory.create_from_node(etree.fromstring(xml)) # Trace a regular operation that is not yet defined in CIB. The request # should succeed and introduce an op node for the operation. RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'start', '/var/lib/heartbeat/trace_ra') self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-start-0']) self.assertEqual(obj.node.xpath('operations/op[@id="r1-start-0"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1']) # Try tracing the monitor operation in the same way. The request should # get rejected because no explicit interval is specified. with self.assertRaises(ValueError) as err: RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor', '/var/lib/heartbeat/trace_ra') self.assertEqual(str(err.exception), "No monitor operation configured for r1") @mock.patch('logging.Logger.error') def test_ratrace_op_stateful(self, mock_error): """Check setting RA tracing for an operation on a stateful resource.""" xml = ''' ''' obj = self.factory.create_from_node(etree.fromstring(xml)) # Trace the operation. RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor', '/var/lib/heartbeat/trace_ra') self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10', 'r1-monitor-11']) self.assertEqual(obj.node.xpath('operations/op[@id="r1-monitor-10"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1']) self.assertEqual(obj.node.xpath('operations/op[@id="r1-monitor-11"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1']) # Untrace the operation. RscMgmt()._untrace_op(self.context, obj.obj_id, obj, 'monitor') self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10', 'r1-monitor-11']) self.assertEqual(obj.node.xpath('.//*[@name="trace_ra"]'), []) @mock.patch('logging.Logger.error') def test_ratrace_op_interval(self, mock_error): """Check setting RA tracing for an operation+interval.""" xml = ''' ''' obj = self.factory.create_from_node(etree.fromstring(xml)) # Trace the operation. RscMgmt()._trace_op_interval(self.context, obj.obj_id, obj, 'monitor', '10', '/var/lib/heartbeat/trace_ra') self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10']) self.assertEqual(obj.node.xpath('operations/op[@id="r1-monitor-10"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1']) # Untrace the operation. RscMgmt()._untrace_op_interval(self.context, obj.obj_id, obj, 'monitor', '10') self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10']) self.assertEqual(obj.node.xpath('.//*[@name="trace_ra"]'), []) # Try untracing a non-existent operation. with self.assertRaises(ValueError) as err: RscMgmt()._untrace_op_interval(self.context, obj.obj_id, obj, 'invalid-op', '10') self.assertEqual(str(err.exception), "Operation invalid-op with interval 10 not found in r1")