1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright 2018 The ChromiumOS Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Tests for redact_profile.py.""" 8 9 10import io 11import unittest 12 13from afdo_redaction import redact_profile 14 15 16_redact_limit = redact_profile.dedup_records.__defaults__[0] 17 18 19def _redact(input_lines, summary_to=None): 20 if isinstance(input_lines, str): 21 input_lines = input_lines.splitlines() 22 23 if summary_to is None: 24 summary_to = io.StringIO() 25 26 output_to = io.StringIO() 27 redact_profile.run( 28 profile_input_file=input_lines, 29 summary_output_file=summary_to, 30 profile_output_file=output_to, 31 ) 32 return output_to.getvalue() 33 34 35def _redact_with_summary(input_lines): 36 summary = io.StringIO() 37 result = _redact(input_lines, summary_to=summary) 38 return result, summary.getvalue() 39 40 41def _generate_repeated_function_body(repeats, fn_name="_some_name"): 42 # Arbitrary function body ripped from a textual AFDO profile. 43 function_header = fn_name + ":1234:185" 44 function_body = [ 45 " 6: 83", 46 " 15: 126", 47 " 62832: 126", 48 " 6: _ZNK5blink10PaintLayer14GroupedMappingEv:2349", 49 " 1: 206", 50 " 1: _ZNK5blink10PaintLayer14GroupedMappersEv:2060", 51 " 1: 206", 52 " 11: _ZNK5blink10PaintLayer25GetCompositedLayerMappingEv:800", 53 " 2.1: 80", 54 ] 55 56 # Be sure to zfill this, so the functions are output in sorted order. 57 num_width = len(str(repeats)) 58 59 lines = [] 60 for i in range(repeats): 61 num = str(i).zfill(num_width) 62 lines.append(num + function_header) 63 lines.extend(function_body) 64 return lines 65 66 67class Tests(unittest.TestCase): 68 """All of our tests for redact_profile.""" 69 70 def test_no_input_works(self): 71 self.assertEqual(_redact(""), "") 72 73 def test_single_function_works(self): 74 lines = _generate_repeated_function_body(1) 75 result_file = "\n".join(lines) + "\n" 76 self.assertEqual(_redact(lines), result_file) 77 78 def test_duplicate_of_single_function_works(self): 79 lines = _generate_repeated_function_body(2) 80 result_file = "\n".join(lines) + "\n" 81 self.assertEqual(_redact(lines), result_file) 82 83 def test_not_too_many_duplicates_of_single_function_redacts_none(self): 84 lines = _generate_repeated_function_body(_redact_limit - 1) 85 result_file = "\n".join(lines) + "\n" 86 self.assertEqual(_redact(lines), result_file) 87 88 def test_many_duplicates_of_single_function_redacts_them_all(self): 89 lines = _generate_repeated_function_body(_redact_limit) 90 self.assertEqual(_redact(lines), "") 91 92 def test_many_duplicates_of_single_function_leaves_other_functions(self): 93 kept_lines = _generate_repeated_function_body(1, fn_name="_keep_me") 94 # Something to distinguish us from the rest. Just bump a random counter. 95 kept_lines[1] += "1" 96 97 result_file = "\n".join(kept_lines) + "\n" 98 99 lines = _generate_repeated_function_body( 100 _redact_limit, fn_name="_discard_me" 101 ) 102 self.assertEqual(_redact(kept_lines + lines), result_file) 103 self.assertEqual(_redact(lines + kept_lines), result_file) 104 105 more_lines = _generate_repeated_function_body( 106 _redact_limit, fn_name="_and_discard_me" 107 ) 108 self.assertEqual(_redact(lines + kept_lines + more_lines), result_file) 109 self.assertEqual(_redact(lines + more_lines), "") 110 111 def test_correct_summary_is_printed_when_nothing_is_redacted(self): 112 lines = _generate_repeated_function_body(1) 113 _, summary = _redact_with_summary(lines) 114 self.assertIn("Retained 1/1 functions", summary) 115 self.assertIn("Retained 827/827 samples, total", summary) 116 # Note that top-level samples == "samples without inlining taken into 117 # account," not "sum(entry_counts)" 118 self.assertIn("Retained 335/335 top-level samples", summary) 119 120 def test_correct_summary_is_printed_when_everything_is_redacted(self): 121 lines = _generate_repeated_function_body(_redact_limit) 122 _, summary = _redact_with_summary(lines) 123 self.assertIn("Retained 0/100 functions", summary) 124 self.assertIn("Retained 0/82,700 samples, total", summary) 125 self.assertIn("Retained 0/33,500 top-level samples", summary) 126 127 def test_correct_summary_is_printed_when_most_everything_is_redacted(self): 128 kept_lines = _generate_repeated_function_body(1, fn_name="_keep_me") 129 kept_lines[1] += "1" 130 131 lines = _generate_repeated_function_body(_redact_limit) 132 _, summary = _redact_with_summary(kept_lines + lines) 133 self.assertIn("Retained 1/101 functions", summary) 134 self.assertIn("Retained 1,575/84,275 samples, total", summary) 135 self.assertIn("Retained 1,083/34,583 top-level samples", summary) 136 137 138if __name__ == "__main__": 139 unittest.main() 140