blob: fb17f50674c436ea8bae6a615847f72cae84c7d7 [file] [log] [blame]
# Copyright 2024 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import datetime
import typing
from typing import Union
import unittest
from unittest import mock
from blinkpy.w3c import buganizer as blink_buganizer
from bad_machine_finder import buganizer
from bad_machine_finder import detection
# pylint: disable=protected-access
class FakeBuganizerClient:
def __init__(self):
# GetIssueComments
self.issue_comments = []
# NewComment
self.comment_content = None
def GetIssueComments(self, bug_id: int) -> Union[dict, list]:
del bug_id # unused.
return self.issue_comments
def NewComment(self, bug_id: int, comment: str, use_markdown: bool) -> None:
del bug_id, use_markdown # unused.
self.comment_content = comment
def _GetIsoFormatStringForNDaysAgo(num_days: int) -> str:
now = datetime.datetime.now()
n_days_ago = now - datetime.timedelta(days=num_days)
return n_days_ago.isoformat()
class UpdateBugUnittest(unittest.TestCase):
def testBasic(self):
"""Tests the basic behavior of posting an update to a bug."""
client = FakeBuganizerClient()
client.issue_comments = [
{
'timestamp':
_GetIsoFormatStringForNDaysAgo(1),
'comment':
'\n'.join([
buganizer._AUTOMATED_COMMENT_START,
'bot-2',
'bot-3',
]),
},
]
first_machine_list = detection.BadMachineList()
first_machine_list.AddBadMachine('bot-1', 'reason-1a')
first_machine_list.AddBadMachine('bot-1', 'reason-1b')
first_machine_list.AddBadMachine('bot-2', 'reason-2')
second_machine_list = detection.BadMachineList()
second_machine_list.AddBadMachine('bot-3', 'reason-3')
second_machine_list.AddBadMachine('bot-4', 'reason-4')
second_machine_list.AddBadMachine('bot-5', 'reason-5')
mgbm = detection.MixinGroupedBadMachines()
mgbm.AddMixinData('mixin-a', first_machine_list)
mgbm.AddMixinData('mixin-b', second_machine_list)
with mock.patch.object(buganizer,
'_GetBuganizerClient',
return_value=client):
buganizer.UpdateBug(1234, mgbm, 7)
expected_markdown = f"""\
{buganizer._AUTOMATED_COMMENT_START}
Bad machines for mixin-a
* bot-1
* reason-1a
* reason-1b
Bad machines for mixin-b
* bot-4
* reason-4
* bot-5
* reason-5"""
self.assertEqual(client.comment_content, expected_markdown)
def testNoNewBadMachines(self):
"""Tests behavior when all bad machines were recently reported."""
client = FakeBuganizerClient()
client.issue_comments = [
{
'timestamp':
_GetIsoFormatStringForNDaysAgo(1),
'comment':
'\n'.join([
buganizer._AUTOMATED_COMMENT_START,
'bot-1'
'bot-2',
'bot-3',
'bot-4',
'bot-5',
]),
},
]
first_machine_list = detection.BadMachineList()
first_machine_list.AddBadMachine('bot-1', 'reason-1a')
first_machine_list.AddBadMachine('bot-1', 'reason-1b')
first_machine_list.AddBadMachine('bot-2', 'reason-2')
second_machine_list = detection.BadMachineList()
second_machine_list.AddBadMachine('bot-3', 'reason-3')
second_machine_list.AddBadMachine('bot-4', 'reason-4')
second_machine_list.AddBadMachine('bot-5', 'reason-5')
mgbm = detection.MixinGroupedBadMachines()
mgbm.AddMixinData('mixin-a', first_machine_list)
mgbm.AddMixinData('mixin-b', second_machine_list)
with mock.patch.object(buganizer,
'_GetBuganizerClient',
return_value=client):
buganizer.UpdateBug(1234, mgbm, 7)
expected_markdown = f"""\
{buganizer._AUTOMATED_COMMENT_START}
No new bad machines detected"""
self.assertEqual(client.comment_content, expected_markdown)
class GetRecentlyReportedBotsUnittest(unittest.TestCase):
def testBugNotAccessible(self):
"""Tests behavior when accessing the bug returns an error."""
client = typing.cast(blink_buganizer.BuganizerClient, FakeBuganizerClient())
client.issue_comments = {'error': 'error_message'}
with self.assertRaisesRegex(
buganizer.BugNotAccessibleException,
'Failed to get comments from 1234: error_message'):
buganizer._GetRecentlyReportedBots(1234, client, [], 7)
def testBasic(self):
"""Tests the basic behavior of finding recently reported bots."""
client = typing.cast(blink_buganizer.BuganizerClient, FakeBuganizerClient())
client.issue_comments = [
# Should be ignored because it's not an automated comment.
{
'timestamp': _GetIsoFormatStringForNDaysAgo(1),
'comment': '\n'.join([
'bot-1',
'bot-2',
'bot-3',
'bot-4',
]),
},
# Should be ignored because it's too old.
{
'timestamp':
_GetIsoFormatStringForNDaysAgo(14),
'comment':
'\n'.join([
buganizer._AUTOMATED_COMMENT_START,
'bot-1',
'bot-2',
'bot-3',
'bot-4',
]),
},
# Should be parsed.
{
'timestamp':
_GetIsoFormatStringForNDaysAgo(1),
'comment':
'\n'.join([
buganizer._AUTOMATED_COMMENT_START,
'bot-2',
'bot-3',
'bot-5',
]),
},
]
recently_reported_bots = buganizer._GetRecentlyReportedBots(
1234, client, {'bot-1', 'bot-2', 'bot-3', 'bot-4'}, 7)
self.assertEqual(recently_reported_bots, {'bot-2', 'bot-3'})
def testIsoZCompatibility(self):
"""Tests that a trailing Z in an ISO 8601 string does not cause issues."""
client = typing.cast(blink_buganizer.BuganizerClient, FakeBuganizerClient())
client.issue_comments = [
{
'timestamp':
_GetIsoFormatStringForNDaysAgo(1) + 'Z',
'comment':
'\n'.join([
buganizer._AUTOMATED_COMMENT_START,
'bot-2',
'bot-3',
'bot-5',
]),
},
]
recently_reported_bots = buganizer._GetRecentlyReportedBots(
1234, client, {'bot-1', 'bot-2', 'bot-3', 'bot-4'}, 7)
self.assertEqual(recently_reported_bots, {'bot-2', 'bot-3'})