#!/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 nightly_revert_checker.""" import io import unittest from unittest.mock import patch import cros_utils.tiny_render as tiny_render import get_upstream_patch import nightly_revert_checker import revert_checker # pylint: disable=protected-access class Test(unittest.TestCase): """Tests for nightly_revert_checker.""" def test_email_rendering_works_for_singular_revert(self): def prettify_sha(sha: str) -> tiny_render.Piece: return "pretty_" + sha def get_sha_description(sha: str) -> tiny_render.Piece: return "subject_" + sha email = nightly_revert_checker._generate_revert_email( repository_name="${repo}", friendly_name="${name}", sha="${sha}", prettify_sha=prettify_sha, get_sha_description=get_sha_description, new_reverts=[ revert_checker.Revert( sha="${revert_sha}", reverted_sha="${reverted_sha}" ) ], ) expected_email = nightly_revert_checker._Email( subject="[revert-checker/${repo}] new revert discovered across ${name}", body=[ "It looks like there may be a new revert across ${name} (", "pretty_${sha}", ").", tiny_render.line_break, tiny_render.line_break, "That is:", tiny_render.UnorderedList( [ [ "pretty_${revert_sha}", " (appears to revert ", "pretty_${reverted_sha}", "): ", "subject_${revert_sha}", ] ] ), tiny_render.line_break, "PTAL and consider reverting them locally.", ], ) self.assertEqual(email, expected_email) def test_email_rendering_works_for_multiple_reverts(self): def prettify_sha(sha: str) -> tiny_render.Piece: return "pretty_" + sha def get_sha_description(sha: str) -> tiny_render.Piece: return "subject_" + sha email = nightly_revert_checker._generate_revert_email( repository_name="${repo}", friendly_name="${name}", sha="${sha}", prettify_sha=prettify_sha, get_sha_description=get_sha_description, new_reverts=[ revert_checker.Revert( sha="${revert_sha1}", reverted_sha="${reverted_sha1}" ), revert_checker.Revert( sha="${revert_sha2}", reverted_sha="${reverted_sha2}" ), # Keep this out-of-order to check that we sort based on SHAs revert_checker.Revert( sha="${revert_sha0}", reverted_sha="${reverted_sha0}" ), ], ) expected_email = nightly_revert_checker._Email( subject="[revert-checker/${repo}] new reverts discovered across " "${name}", body=[ "It looks like there may be new reverts across ${name} (", "pretty_${sha}", ").", tiny_render.line_break, tiny_render.line_break, "These are:", tiny_render.UnorderedList( [ [ "pretty_${revert_sha0}", " (appears to revert ", "pretty_${reverted_sha0}", "): ", "subject_${revert_sha0}", ], [ "pretty_${revert_sha1}", " (appears to revert ", "pretty_${reverted_sha1}", "): ", "subject_${revert_sha1}", ], [ "pretty_${revert_sha2}", " (appears to revert ", "pretty_${reverted_sha2}", "): ", "subject_${revert_sha2}", ], ] ), tiny_render.line_break, "PTAL and consider reverting them locally.", ], ) self.assertEqual(email, expected_email) def test_llvm_ebuild_parsing_appears_to_function(self): llvm_ebuild = io.StringIO( "\n".join( ( "foo", '#LLVM_HASH="123"', 'LLVM_HASH="123" # comment', 'LLVM_NEXT_HASH="456"', ) ) ) shas = nightly_revert_checker._parse_llvm_ebuild_for_shas(llvm_ebuild) self.assertEqual( shas, [ ("llvm", "123"), ("llvm-next", "456"), ], ) def test_llvm_ebuild_parsing_fails_if_both_hashes_arent_present(self): bad_bodies = [ "", 'LLVM_HASH="123" # comment', 'LLVM_NEXT_HASH="123" # comment', 'LLVM_NEXT_HASH="123" # comment\n#LLVM_HASH="123"', ] for bad in bad_bodies: with self.assertRaises(ValueError) as e: nightly_revert_checker._parse_llvm_ebuild_for_shas( io.StringIO(bad) ) self.assertIn("Failed to detect SHAs", str(e.exception)) @patch("revert_checker.find_reverts") @patch("get_upstream_patch.get_from_upstream") def test_do_cherrypick_is_called(self, do_cherrypick, find_reverts): find_reverts.return_value = [ revert_checker.Revert("12345abcdef", "fedcba54321") ] nightly_revert_checker.do_cherrypick( chroot_path="/path/to/chroot", llvm_dir="/path/to/llvm", interesting_shas=[("12345abcdef", "fedcba54321")], state={}, reviewers=["meow@chromium.org"], cc=["purr@chromium.org"], ) do_cherrypick.assert_called_once() find_reverts.assert_called_once() @patch("revert_checker.find_reverts") @patch("get_upstream_patch.get_from_upstream") def test_do_cherrypick_handles_cherrypick_error( self, do_cherrypick, find_reverts ): find_reverts.return_value = [ revert_checker.Revert("12345abcdef", "fedcba54321") ] do_cherrypick.side_effect = get_upstream_patch.CherrypickError( "Patch at 12345abcdef already exists in PATCHES.json" ) nightly_revert_checker.do_cherrypick( chroot_path="/path/to/chroot", llvm_dir="/path/to/llvm", interesting_shas=[("12345abcdef", "fedcba54321")], state={}, reviewers=["meow@chromium.org"], cc=["purr@chromium.org"], ) do_cherrypick.assert_called_once() find_reverts.assert_called_once() if __name__ == "__main__": unittest.main()