#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright 2020 The Chromium OS Authors. All rights reserved. # 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.""" # pylint: disable=cros-logging-import 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()