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