#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright 2020 The ChromiumOS Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Tests for bisect_clang_crashes.""" import glob import logging import os.path import subprocess import unittest import unittest.mock as mock import bisect_clang_crashes class Test(unittest.TestCase): """Tests for bisect_clang_crashes.""" class _SilencingFilter(object): """Silences all log messages. Also collects info about log messages that would've been emitted. """ def __init__(self): self.messages = [] def filter(self, record): self.messages.append(record.getMessage()) return 0 @mock.patch.object(subprocess, "check_output") def test_get_artifacts(self, mock_gsutil_ls): pattern = ( "gs://chromeos-toolchain-artifacts/clang-crash-diagnoses/" "**/*clang_crash_diagnoses.tar.xz" ) mock_gsutil_ls.return_value = "artifact1\nartifact2\nartifact3" results = bisect_clang_crashes.get_artifacts(pattern) self.assertEqual(results, ["artifact1", "artifact2", "artifact3"]) mock_gsutil_ls.assert_called_once_with( ["gsutil.py", "ls", pattern], stderr=subprocess.STDOUT, encoding="utf-8", ) @mock.patch.object(os.path, "exists") @mock.patch.object(glob, "glob") def test_get_crash_reproducers_succeed( self, mock_file_search, mock_file_check ): working_dir = "SomeDirectory" mock_file_search.return_value = ["a.c", "b.cpp", "c.cc"] mock_file_check.side_effect = [True, True, True] results = bisect_clang_crashes.get_crash_reproducers(working_dir) mock_file_search.assert_called_once_with("%s/*.c*" % working_dir) self.assertEqual(mock_file_check.call_count, 3) self.assertEqual(mock_file_check.call_args_list[0], mock.call("a.sh")) self.assertEqual(mock_file_check.call_args_list[1], mock.call("b.sh")) self.assertEqual(mock_file_check.call_args_list[2], mock.call("c.sh")) self.assertEqual( results, [("a.c", "a.sh"), ("b.cpp", "b.sh"), ("c.cc", "c.sh")] ) @mock.patch.object(os.path, "exists") @mock.patch.object(glob, "glob") def test_get_crash_reproducers_no_matching_script( self, mock_file_search, mock_file_check ): def silence_logging(): root = logging.getLogger() filt = self._SilencingFilter() root.addFilter(filt) self.addCleanup(root.removeFilter, filt) return filt log_filter = silence_logging() working_dir = "SomeDirectory" mock_file_search.return_value = ["a.c", "b.cpp", "c.cc"] mock_file_check.side_effect = [True, False, True] results = bisect_clang_crashes.get_crash_reproducers(working_dir) mock_file_search.assert_called_once_with("%s/*.c*" % working_dir) self.assertEqual(mock_file_check.call_count, 3) self.assertEqual(mock_file_check.call_args_list[0], mock.call("a.sh")) self.assertEqual(mock_file_check.call_args_list[1], mock.call("b.sh")) self.assertEqual(mock_file_check.call_args_list[2], mock.call("c.sh")) self.assertEqual(results, [("a.c", "a.sh"), ("c.cc", "c.sh")]) self.assertTrue( any( "could not find the matching script of b.cpp" in x for x in log_filter.messages ), log_filter.messages, ) if __name__ == "__main__": unittest.main()