def test_create_treemap_csv_different_stack_lengths(self): """ Again, tests multidigit weights, now with bigger input """ # The expected output expected = self.tmap.data_options.weight_units + ";" + \ ';'.join([str(i) for i in range(1, self.tmap.display_options.depth + 1)]) + \ '\n' + \ "1;pname;call1;call2;call3\n" \ "2;pname;call1\n" \ "3;pname;call1;call2\n" data = iter(("00000" + consts.field_separator + "pname;call1;call2;call3;call4;call5\n", "000000000" + consts.field_separator + "pname;call1;call2\n", "000" + consts.field_separator + "pname;call1;call2;call3")) datum_generator = ( data_io.StackDatum(1, ('pname', 'call1', 'call2', 'call3')), data_io.StackDatum(2, ('pname', 'call1')), data_io.StackDatum(3, ('pname', 'call1', 'call2')) ) data = data_io.StackData(datum_generator, None, None, None, None) out = self._get_output(data) # Check that we got the desired output self.assertEqual(expected, out)
def test_create_treemap_csv_multidigit(self): """ Tests multidigit weight values """ # The expected output expected = self.tmap.data_options.weight_units + ";" + \ ';'.join([str(i) for i in range(1, self.tmap.display_options.depth + 1)]) + \ '\n' + \ "1;pname;call1;call2\n" \ "2;pname;call3;call4\n" # Get the output from a collapsed stack (first line in inpt is the # empty header datum_generator = ( data_io.StackDatum(1, ('pname', 'call1', 'call2')), data_io.StackDatum(2, ('pname', 'call3', 'call4')) ) data = data_io.StackData(datum_generator, None, None, None, None) outpt = self._get_output(data) # Check that we got the desired output self.assertEqual(expected, outpt)
def stack_collapse(self): """ Goes through input line by line to fold the stacks. Calls the appropriate function to parse each line. Returns a generator to get single stacks lazily. :return: An iterable of tuples that contain information about stacks. """ for line in self.data: # If end of stack, save cached data. if self._line_is_empty(line): # Matches empty line stack_folded = self._make_stack() if stack_folded: # @@@ TODO: generalise to allow different weights yield data_io.StackDatum(weight=1, stack=stack_folded) # event record start elif self._line_is_baseline(line): # Matches "perf script" output, first line of a stack self._parse_baseline(line) # stack line elif self._line_is_stackline(line): # Matches the other lines of a stack above the baseline self._parse_stackline(line) # if nothing matches, log an error else: logger.error("Unrecognized line: %s", line)
def test_to_string(self): """Test datapoints are correctly converted to strings.""" sd = data_io.StackDatum(0, ('A', 'B')) expected = self.standard_field actual = str(sd) self.assertEqual(expected, actual, msg='Expected {}, got {}' .format(expected, actual))
async def test_basic_collect(self): """ Basic test case where everything should work as expected """ mock_return_popen_stdout = str.encode(consts.field_separator.join( ["123123", "proc1", "func1", "func2"]) + "\n") + \ str.encode(consts.field_separator.join( ["321321", "proc2", "func1", "func2", "func3"]) + "\n") expected = [ data_io.StackDatum(123123, ("proc1", "func1", "func2")), data_io.StackDatum(321321, ("proc2", "func1", "func2", "func3")) ] output = await self.mock(mock_return_popen_stdout) self.assertEqual(expected, output)
async def test_strange_symbols(self): """ Basic test case where everything should work as expected """ mock_return_popen_stdout = b"123123" + \ str.encode(consts.field_separator) +\ b"1 []#'" + \ str.encode(consts.field_separator) + \ b"[]-=1 2=\n" expected = [data_io.StackDatum(123123, ("1 []#'", "[]-=1 2="))] output = await self.mock(mock_return_popen_stdout) self.assertEqual(output, expected)
class _FlamegraphBaseTest(unittest.TestCase): """ Base class for flamegraph tests """ coloring = 'test_color' weight_units = "kb" datum_generator = ( data_io.StackDatum(1, ('2', '3', '4', '5')) ) data = data_io.StackData(datum_generator, None, None, None, data_io.StackData.DataOptions("kb")) outfile = mock.MagicMock() outfilename = "test_output" outfile.__str__.return_value = outfilename file_mock = StringIO("") # Set up blank flamegraph fg = object.__new__(flamegraph.Flamegraph) fg.display_options = flamegraph.Flamegraph.DisplayOptions(coloring) fg.data_options = data_io.StackData.DataOptions("kb") fg.data = data
def test_StackParser_complete(self): # Example of a single stack from perf extracted stack data sample_stack = \ "swapper 0 [003] 687886.672908: 108724462 cycles:ppp:\n" \ "ffffffffa099768b intel_idle ([kernel.kallsyms])\n" \ "ffffffffa07e5ce4 cpuidle_enter_state ([kernel.kallsyms])\n" \ "ffffffffa07e5f97 cpuidle_enter ([kernel.kallsyms])\n" \ "ffffffffa00d299c do_idle ([kernel.kallsyms])\n" \ "ffffffffa00d2723 call_cpuidle ([kernel.kallsyms])\n" \ "ffffffffa00d2be3 cpu_startup_entry ([kernel.kallsyms])\n" \ "ffffffffa00581cb start_secondary ([kernel.kallsyms])\n" \ "ffffffffa00000d5 secondary_startup_64 ([kernel.kallsyms])\n" \ "\n" # Expected output data expected = [ data_io.StackDatum( weight=1, stack=("swapper", "secondary_startup_64", "start_secondary", "cpu_startup_entry", "call_cpuidle", "do_idle", "cpuidle_enter", "cpuidle_enter_state", "intel_idle")) ] # # Mock a file with sample data # file_mock = StringIO("") # file_mock.writelines(sample_stack) # context_mock = open_mock.return_value # context_mock.__enter__.return_value = file_mock self.stack_parser.data = StringIO(sample_stack) self.stack_parser.event_filter = "" # Run the whole stack_collapse function events = list(self.stack_parser.stack_collapse()) self.assertEqual(expected, events)
class MakeTest(_FlamegraphBaseTest): """ Test the flamegraph creation """ # Set up test data and expected values test_stack_datums = [ data_io.StackDatum(1, ('A1', 'A2', 'A3')), data_io.StackDatum(2, ('B1', 'B2', 'B3', 'B4')), data_io.StackDatum(3, ('A1', 'A2', 'A3')) ] test_stack_data = data_io.StackData(test_stack_datums, None, None, None, data_io.StackData.DataOptions("kb")) expected = collections.Counter({('A1', 'A2', 'A3'): 4, ('B1', 'B2', 'B3', 'B4'): 2}) expected_temp_file = "A1;A2;A3 4\n" \ "B1;B2;B3;B4 2\n" @mock.patch('marple.display.interface.flamegraph.file') @mock.patch('builtins.open') @mock.patch('marple.display.interface.flamegraph.subprocess') def test_no_options(self, subproc_mock, open_mock, temp_file_mock): """ Test without display options """ temp_file_mock.TempFileName.return_value.__str__.return_value = \ "test_temp_file" fg = flamegraph.Flamegraph(self.test_stack_data) context_mock1, context_mock2 = mock.MagicMock(), mock.MagicMock() file_mock1, file_mock2 = StringIO(""), StringIO("") open_mock.side_effect = [context_mock1, context_mock2] context_mock1.__enter__.return_value = file_mock1 context_mock2.__enter__.return_value = file_mock2 actual = fg._make() temp_file_mock.TempFileName.return_value.__str__.\ assert_has_calls((mock.call(), mock.call())) open_mock.assert_has_calls([ mock.call("test_temp_file", "w"), mock.call("test_temp_file", "w") ]) self.assertEqual(file_mock1.getvalue(), self.expected_temp_file) subproc_mock.Popen.assert_called_once_with( [flamegraph.FLAMEGRAPH_DIR, "--color=hot", "--countname=kb", "test_temp_file"], stdout=file_mock2 ) self.assertEqual(self.expected, actual) @mock.patch('marple.display.interface.flamegraph.file') @mock.patch('builtins.open') @mock.patch('marple.display.interface.flamegraph.subprocess') def test_with_coloring(self, subproc_mock, open_mock, temp_file_mock): """ Test with a options """ temp_file_mock.TempFileName.return_value.__str__.return_value = \ "test_temp_file" fg = flamegraph.Flamegraph(self.test_stack_data) context_mock1, context_mock2 = mock.MagicMock(), mock.MagicMock() file_mock1, file_mock2 = StringIO(""), StringIO("") open_mock.side_effect = [context_mock1, context_mock2] context_mock1.__enter__.return_value = file_mock1 context_mock2.__enter__.return_value = file_mock2 actual = fg._make() temp_file_mock.TempFileName.return_value.__str__.\ assert_has_calls((mock.call(), mock.call())) open_mock.assert_has_calls([ mock.call("test_temp_file", "w"), mock.call("test_temp_file", "w") ]) self.assertEqual(file_mock1.getvalue(), self.expected_temp_file) subproc_mock.Popen.assert_called_once_with( [flamegraph.FLAMEGRAPH_DIR, '--color=hot', '--countname=kb', 'test_temp_file'], stdout=file_mock2 ) self.assertEqual(self.expected, actual)
def test_without_newline(self): """Ensure from_string works without newlines""" expected = data_io.StackDatum(0, ('A', 'B')) self.check_from_str(self.standard_field, expected)
def test_with_newline_rn(self): """Ensure from_string copes with newlines""" expected = data_io.StackDatum(0, ('A', 'B')) self.check_from_str(self.standard_field + '\r\n', expected)