зеркало из https://github.com/mozilla/treeherder.git
Bug 1702410 - Reflect backfill bot' s new name in logs
* rename backfill bot' s packages to Sherlock * slight logs adjustments to Sherlock * replace 'Perfsheriff bot' prefix with 'Sherlock' * adjust comment referring to Sherlock * rename SecretaryTool to Secretary
This commit is contained in:
Родитель
b2dc38e2a8
Коммит
a7e1f79283
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"title": "PerfSheriffBot's schema for storing logs",
|
||||
"description": "Used to store the outcome of PerfSheriffBot actions (i.e. backfill, retrigger)",
|
||||
"title": "Sherlock' schema for storing logs",
|
||||
"description": "Used to store the outcome of Sherlock' s actions (i.e. backfill, retrigger)",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
from copy import copy, deepcopy
|
||||
from datetime import datetime, timedelta
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
import simplejson as json
|
||||
import taskcluster
|
||||
from freezegun import freeze_time
|
||||
|
||||
from tests.conftest import SampleDataJSONLoader, create_perf_signature, create_perf_alert
|
||||
from treeherder.model.models import MachinePlatform, Job
|
||||
from treeherder.perf.auto_perf_sheriffing.secretary_tool import SecretaryTool
|
||||
from treeherder.perf.auto_perf_sherrifing.secretary import Secretary
|
||||
from treeherder.perf.models import (
|
||||
BackfillReport,
|
||||
BackfillRecord,
|
||||
|
@ -16,10 +18,11 @@ from treeherder.perf.models import (
|
|||
PerformanceAlert,
|
||||
)
|
||||
|
||||
# For testing PerfSheriffBot
|
||||
# For testing Sherlock
|
||||
from treeherder.services.taskcluster import notify_client_factory
|
||||
from treeherder.utils import default_serializer
|
||||
|
||||
load_json_fixture = SampleDataJSONLoader('perf_sheriff_bot')
|
||||
load_json_fixture = SampleDataJSONLoader('sherlock')
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
|
@ -116,11 +119,11 @@ def backfill_tool_mock():
|
|||
|
||||
@pytest.fixture
|
||||
def secretary():
|
||||
return SecretaryTool()
|
||||
return Secretary()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sheriff_settings(secretary, db):
|
||||
def sherlock_settings(secretary, db):
|
||||
secretary.validate_settings()
|
||||
return PerformanceSettings.objects.get(name='perf_sheriff_bot')
|
||||
|
||||
|
@ -133,7 +136,7 @@ def empty_sheriff_settings(secretary):
|
|||
return PerformanceSettings.objects.get(name='perf_sheriff_bot')
|
||||
|
||||
|
||||
# For testing SecretaryTool
|
||||
# For testing Secretary
|
||||
@pytest.fixture
|
||||
def performance_settings(db):
|
||||
settings = {
|
||||
|
@ -165,3 +168,20 @@ def create_record():
|
|||
return BackfillRecord.objects.create(alert=alert, report=report)
|
||||
|
||||
return _create_record
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def notify_client_mock() -> taskcluster.Notify:
|
||||
return MagicMock(
|
||||
spec=notify_client_factory('https://fakerooturl.org', 'FAKE_CLIENT_ID', 'FAKE_ACCESS_TOKEN')
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def job_from_try(eleven_job_blobs, create_jobs):
|
||||
job_blob = eleven_job_blobs[0]
|
||||
job = create_jobs([job_blob])[0]
|
||||
|
||||
job.repository.is_try_repo = True
|
||||
job.repository.save()
|
||||
return job
|
|
@ -8,7 +8,7 @@ import pytest
|
|||
|
||||
from tests.conftest import create_perf_alert
|
||||
from treeherder.model.models import Job, Option, OptionCollection, MachinePlatform
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_reports import AlertsPicker
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_reports import AlertsPicker
|
||||
from treeherder.perf.models import PerformanceAlert, PerformanceDatum, PerformanceSignature
|
||||
|
||||
# For testing BackfillReportMaintainer
|
|
@ -3,7 +3,7 @@ from unittest.mock import Mock
|
|||
|
||||
import pytest
|
||||
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_reports import AlertsPicker
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_reports import AlertsPicker
|
||||
|
||||
|
||||
def test_init():
|
|
@ -1,7 +1,7 @@
|
|||
import datetime
|
||||
from typing import Tuple
|
||||
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_reports import (
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_reports import (
|
||||
BackfillReportMaintainer,
|
||||
)
|
||||
from treeherder.perf.models import (
|
|
@ -5,7 +5,7 @@ from operator import itemgetter as get_key
|
|||
import pytest
|
||||
|
||||
from .conftest import NON_RETRIGGERABLE_JOB_ID, ONE_DAY_INTERVAL
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_reports import IdentifyAlertRetriggerables
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_reports import IdentifyAlertRetriggerables
|
||||
|
||||
|
||||
# Unit tests
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_tool import BackfillTool
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_tool import BackfillTool
|
||||
from treeherder.perf.exceptions import CannotBackfill
|
||||
from treeherder.services.taskcluster import TaskclusterModelProxy
|
||||
|
|
@ -7,10 +7,10 @@ import simplejson as json
|
|||
from django.db.models import Q
|
||||
|
||||
from treeherder.config.settings import IS_WINDOWS
|
||||
from treeherder.perf.auto_perf_sheriffing.secretary_tool import SecretaryTool
|
||||
from treeherder.perf.auto_perf_sherrifing.secretary import Secretary
|
||||
from treeherder.model.models import Job, Push
|
||||
from treeherder.perf.models import BackfillRecord, BackfillReport, PerformanceSettings
|
||||
from treeherder.perf.auto_perf_sheriffing.outcome_checker import OutcomeChecker, OutcomeStatus
|
||||
from treeherder.perf.auto_perf_sherrifing.outcome_checker import OutcomeChecker, OutcomeStatus
|
||||
|
||||
# we're testing against this (automatically provided by fixtures)
|
||||
JOB_TYPE_ID = 1
|
||||
|
@ -125,7 +125,7 @@ def get_outcome_checker_mock():
|
|||
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS, reason="datetime logic does not work when OS not on GMT")
|
||||
def test_secretary_tool_updates_only_matured_reports(
|
||||
def test_secretary_updates_only_matured_reports(
|
||||
test_perf_alert, create_record, record_from_mature_report
|
||||
):
|
||||
# create new report with records
|
||||
|
@ -134,36 +134,36 @@ def test_secretary_tool_updates_only_matured_reports(
|
|||
assert BackfillRecord.objects.count() == 2
|
||||
assert BackfillRecord.objects.filter(status=BackfillRecord.PRELIMINARY).count() == 2
|
||||
|
||||
SecretaryTool.mark_reports_for_backfill()
|
||||
Secretary.mark_reports_for_backfill()
|
||||
assert BackfillRecord.objects.filter(status=BackfillRecord.PRELIMINARY).count() == 1
|
||||
|
||||
|
||||
def test_secretary_tool_uses_existing_settings(performance_settings):
|
||||
def test_secretary_uses_existing_settings(performance_settings):
|
||||
assert PerformanceSettings.objects.count() == 1
|
||||
last_reset_date_before = json.loads(performance_settings.settings)["last_reset_date"]
|
||||
|
||||
SecretaryTool.validate_settings()
|
||||
Secretary.validate_settings()
|
||||
|
||||
assert PerformanceSettings.objects.count() == 1
|
||||
settings_after = PerformanceSettings.objects.filter(name="perf_sheriff_bot").first()
|
||||
assert json.loads(settings_after.settings)["last_reset_date"] == last_reset_date_before
|
||||
|
||||
|
||||
def test_secretary_tool_resets_settings_if_expired(expired_performance_settings):
|
||||
def test_secretary_resets_settings_if_expired(expired_performance_settings):
|
||||
assert PerformanceSettings.objects.count() == 1
|
||||
expired_last_reset_date = json.loads(expired_performance_settings.settings)["last_reset_date"]
|
||||
|
||||
SecretaryTool.validate_settings()
|
||||
Secretary.validate_settings()
|
||||
|
||||
assert PerformanceSettings.objects.count() == 1
|
||||
settings_after = PerformanceSettings.objects.filter(name="perf_sheriff_bot").first()
|
||||
assert json.loads(settings_after.settings)["last_reset_date"] != expired_last_reset_date
|
||||
|
||||
|
||||
def test_secretary_tool_creates_new_settings_if_none_exist(db):
|
||||
def test_secretary_creates_new_settings_if_none_exist(db):
|
||||
assert PerformanceSettings.objects.count() == 0
|
||||
|
||||
SecretaryTool.validate_settings()
|
||||
Secretary.validate_settings()
|
||||
|
||||
assert PerformanceSettings.objects.count() == 1
|
||||
|
||||
|
@ -201,7 +201,7 @@ def test_outcome_checker_identifies_pushes_in_range(
|
|||
|
||||
def test_check_outcome_after_success(get_outcome_checker_mock, record_backfilled):
|
||||
outcome_checker_mock = get_outcome_checker_mock(OutcomeStatus.SUCCESSFUL)
|
||||
secretary = SecretaryTool(outcome_checker_mock)
|
||||
secretary = Secretary(outcome_checker_mock)
|
||||
|
||||
assert BackfillRecord.objects.filter(status=BackfillRecord.BACKFILLED).count() == 1
|
||||
assert BackfillRecord.objects.filter(status=BackfillRecord.SUCCESSFUL).count() == 0
|
||||
|
@ -212,7 +212,7 @@ def test_check_outcome_after_success(get_outcome_checker_mock, record_backfilled
|
|||
|
||||
def test_check_outcome_after_fail(get_outcome_checker_mock, record_backfilled):
|
||||
outcome_checker_mock = get_outcome_checker_mock(OutcomeStatus.FAILED)
|
||||
secretary = SecretaryTool(outcome_checker_mock)
|
||||
secretary = Secretary(outcome_checker_mock)
|
||||
|
||||
assert BackfillRecord.objects.filter(status=BackfillRecord.BACKFILLED).count() == 1
|
||||
assert BackfillRecord.objects.filter(status=BackfillRecord.FAILED).count() == 0
|
||||
|
@ -223,7 +223,7 @@ def test_check_outcome_after_fail(get_outcome_checker_mock, record_backfilled):
|
|||
|
||||
def test_no_action_when_in_progress(get_outcome_checker_mock, record_backfilled):
|
||||
outcome_checker_mock = get_outcome_checker_mock(OutcomeStatus.IN_PROGRESS)
|
||||
secretary = SecretaryTool(outcome_checker_mock)
|
||||
secretary = Secretary(outcome_checker_mock)
|
||||
|
||||
assert BackfillRecord.objects.filter(status=BackfillRecord.BACKFILLED).count() == 1
|
||||
secretary.check_outcome()
|
|
@ -6,7 +6,7 @@ import pytest
|
|||
from django.db import models
|
||||
|
||||
from treeherder.model.models import Job, Push
|
||||
from treeherder.perf.auto_perf_sheriffing.perf_sheriff_bot import PerfSheriffBot
|
||||
from treeherder.perf.auto_perf_sherrifing.sherlock import Sherlock
|
||||
from treeherder.perf.email import BackfillNotificationWriter
|
||||
from treeherder.perf.exceptions import MaxRuntimeExceeded
|
||||
from treeherder.perf.models import BackfillRecord, BackfillReport
|
||||
|
@ -33,18 +33,18 @@ class TestEmailIntegration:
|
|||
backfill_tool_mock,
|
||||
secretary,
|
||||
record_ready_for_processing,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
notify_client_mock,
|
||||
):
|
||||
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
sherlock = Sherlock(
|
||||
report_maintainer_mock,
|
||||
backfill_tool_mock,
|
||||
secretary,
|
||||
notify_client_mock,
|
||||
email_writer=self.email_writer_mock(),
|
||||
)
|
||||
sheriff_bot.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
sherlock.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
record_ready_for_processing.refresh_from_db()
|
||||
|
||||
assert notify_client_mock.email.call_count == 1
|
||||
|
@ -55,7 +55,7 @@ class TestEmailIntegration:
|
|||
backfill_tool_mock,
|
||||
secretary,
|
||||
record_ready_for_processing,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
notify_client_mock,
|
||||
broken_context_str,
|
||||
# Note: parametrizes the test
|
||||
|
@ -63,13 +63,13 @@ class TestEmailIntegration:
|
|||
record_ready_for_processing.context = broken_context_str
|
||||
record_ready_for_processing.save()
|
||||
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
sherlock = Sherlock(
|
||||
report_maintainer_mock,
|
||||
backfill_tool_mock,
|
||||
secretary,
|
||||
notify_client_mock,
|
||||
)
|
||||
sheriff_bot.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
sherlock.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
|
||||
assert notify_client_mock.email.call_count == 1
|
||||
|
||||
|
@ -79,18 +79,16 @@ class TestEmailIntegration:
|
|||
backfill_tool_mock,
|
||||
secretary,
|
||||
record_ready_for_processing,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
notify_client_mock,
|
||||
):
|
||||
no_time_left = timedelta(seconds=0)
|
||||
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
sherlock = Sherlock(
|
||||
report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock, no_time_left
|
||||
)
|
||||
try:
|
||||
sheriff_bot.sheriff(
|
||||
since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland']
|
||||
)
|
||||
sherlock.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
except MaxRuntimeExceeded:
|
||||
pass
|
||||
|
||||
|
@ -108,7 +106,7 @@ def test_records_change_to_ready_for_processing(
|
|||
report_maintainer_mock,
|
||||
backfill_tool_mock,
|
||||
secretary,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
notify_client_mock,
|
||||
):
|
||||
# create new report with records - the report will not be mature
|
||||
|
@ -121,13 +119,13 @@ def test_records_change_to_ready_for_processing(
|
|||
assert ready_records.count() == 0
|
||||
assert frozen_reports.count() == 0
|
||||
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
sherlock = Sherlock(
|
||||
report_maintainer_mock,
|
||||
backfill_tool_mock,
|
||||
secretary,
|
||||
notify_client_mock,
|
||||
)
|
||||
sheriff_bot.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
sherlock.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
|
||||
assert preliminary_records.count() == 1
|
||||
assert ready_records.count() == 1
|
||||
|
@ -139,16 +137,16 @@ def test_assert_can_run_throws_exception_when_runtime_exceeded(
|
|||
backfill_tool_mock,
|
||||
secretary,
|
||||
record_ready_for_processing,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
notify_client_mock,
|
||||
):
|
||||
no_time_left = timedelta(seconds=0)
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
sherlock_bot = Sherlock(
|
||||
report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock, no_time_left
|
||||
)
|
||||
|
||||
with pytest.raises(MaxRuntimeExceeded):
|
||||
sheriff_bot.assert_can_run()
|
||||
sherlock_bot.assert_can_run()
|
||||
|
||||
|
||||
def test_assert_can_run_doesnt_throw_exception_when_enough_time_left(
|
||||
|
@ -157,15 +155,15 @@ def test_assert_can_run_doesnt_throw_exception_when_enough_time_left(
|
|||
secretary,
|
||||
notify_client_mock,
|
||||
record_ready_for_processing,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
):
|
||||
enough_time_left = timedelta(minutes=10)
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
sherlock = Sherlock(
|
||||
report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock, enough_time_left
|
||||
)
|
||||
|
||||
try:
|
||||
sheriff_bot.assert_can_run()
|
||||
sherlock.assert_can_run()
|
||||
except MaxRuntimeExceeded:
|
||||
pytest.fail()
|
||||
|
||||
|
@ -175,16 +173,14 @@ def test_records_and_db_limits_remain_unchanged_if_no_records_suitable_for_backf
|
|||
backfill_tool_mock,
|
||||
secretary,
|
||||
notify_client_mock,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
record_unsuited_for_backfill,
|
||||
):
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock
|
||||
)
|
||||
sheriff_bot._backfill()
|
||||
sherlock = Sherlock(report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock)
|
||||
sherlock._backfill()
|
||||
|
||||
assert not has_changed(record_unsuited_for_backfill)
|
||||
assert not has_changed(sheriff_settings)
|
||||
assert not has_changed(sherlock_settings)
|
||||
|
||||
|
||||
def test_records_remain_unchanged_if_no_backfills_left(
|
||||
|
@ -195,10 +191,8 @@ def test_records_remain_unchanged_if_no_backfills_left(
|
|||
record_ready_for_processing,
|
||||
empty_sheriff_settings,
|
||||
):
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock
|
||||
)
|
||||
sheriff_bot._backfill()
|
||||
sherlock = Sherlock(report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock)
|
||||
sherlock._backfill()
|
||||
|
||||
assert not has_changed(record_ready_for_processing)
|
||||
|
||||
|
@ -208,20 +202,20 @@ def test_records_and_db_limits_remain_unchanged_if_runtime_exceeded(
|
|||
backfill_tool_mock,
|
||||
secretary,
|
||||
record_ready_for_processing,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
notify_client_mock,
|
||||
):
|
||||
no_time_left = timedelta(seconds=0)
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
sherlock = Sherlock(
|
||||
report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock, no_time_left
|
||||
)
|
||||
try:
|
||||
sheriff_bot.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
sherlock.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
except MaxRuntimeExceeded:
|
||||
pass
|
||||
|
||||
assert not has_changed(record_ready_for_processing)
|
||||
assert not has_changed(sheriff_settings)
|
||||
assert not has_changed(sherlock_settings)
|
||||
|
||||
|
||||
def test_db_limits_update_if_backfills_left(
|
||||
|
@ -229,14 +223,12 @@ def test_db_limits_update_if_backfills_left(
|
|||
backfill_tool_mock,
|
||||
secretary,
|
||||
record_ready_for_processing,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
notify_client_mock,
|
||||
):
|
||||
initial_backfills = secretary.backfills_left(on_platform='linux')
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock
|
||||
)
|
||||
sheriff_bot.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
sherlock = Sherlock(report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock)
|
||||
sherlock.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
|
||||
record_ready_for_processing.refresh_from_db()
|
||||
assert record_ready_for_processing.status == BackfillRecord.BACKFILLED
|
||||
|
@ -248,22 +240,20 @@ def test_backfilling_gracefully_handles_invalid_json_contexts_without_blowing_up
|
|||
backfill_tool_mock,
|
||||
secretary,
|
||||
record_ready_for_processing,
|
||||
sheriff_settings,
|
||||
sherlock_settings,
|
||||
notify_client_mock,
|
||||
broken_context_str, # Note: parametrizes the test
|
||||
):
|
||||
record_ready_for_processing.context = broken_context_str
|
||||
record_ready_for_processing.save()
|
||||
|
||||
sheriff_bot = PerfSheriffBot(
|
||||
report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock
|
||||
)
|
||||
sherlock = Sherlock(report_maintainer_mock, backfill_tool_mock, secretary, notify_client_mock)
|
||||
try:
|
||||
sheriff_bot.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
sherlock.sheriff(since=EPOCH, frameworks=['raptor', 'talos'], repositories=['autoland'])
|
||||
except (JSONDecodeError, KeyError, Job.DoesNotExist, Push.DoesNotExist):
|
||||
pytest.fail()
|
||||
|
||||
record_ready_for_processing.refresh_from_db()
|
||||
|
||||
assert record_ready_for_processing.status == BackfillRecord.FAILED
|
||||
assert not has_changed(sheriff_settings)
|
||||
assert not has_changed(sherlock_settings)
|
|
@ -5,7 +5,6 @@ from requests import Session
|
|||
|
||||
from treeherder.perf.sheriffing_criteria import NonBlockableSession
|
||||
|
||||
|
||||
CASSETTE_LIBRARY_DIR = 'tests/sample_data/betamax_cassettes/perf_sheriffing_criteria'
|
||||
CASSETTES_RECORDING_DATE = 'June 2nd, 2020' # when VCR has been conducted
|
||||
|
||||
|
|
|
@ -1,27 +1,3 @@
|
|||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
import taskcluster
|
||||
|
||||
from treeherder.services.taskcluster import notify_client_factory
|
||||
|
||||
from tests.conftest import SampleDataJSONLoader
|
||||
|
||||
load_json_fixture = SampleDataJSONLoader('perf_sheriff_bot')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def job_from_try(eleven_job_blobs, create_jobs):
|
||||
job_blob = eleven_job_blobs[0]
|
||||
job = create_jobs([job_blob])[0]
|
||||
|
||||
job.repository.is_try_repo = True
|
||||
job.repository.save()
|
||||
return job
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def notify_client_mock() -> taskcluster.Notify:
|
||||
return MagicMock(
|
||||
spec=notify_client_factory('https://fakerooturl.org', 'FAKE_CLIENT_ID', 'FAKE_ACCESS_TOKEN')
|
||||
)
|
||||
load_json_fixture = SampleDataJSONLoader('sherlock')
|
||||
|
|
|
@ -8,7 +8,7 @@ from treeherder.services.taskcluster import (
|
|||
NotifyAdapter,
|
||||
)
|
||||
|
||||
load_json_fixture = SampleDataJSONLoader('perf_sheriff_bot')
|
||||
load_json_fixture = SampleDataJSONLoader('sherlock')
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
|
|
|
@ -464,14 +464,15 @@ PERFHERDER_ENABLE_MULTIDATA_INGESTION = env.bool(
|
|||
'PERFHERDER_ENABLE_MULTIDATA_INGESTION', default=True
|
||||
)
|
||||
|
||||
# Performance sheriff bot settings
|
||||
# Sherlock' settings (the performance sheriff robot)
|
||||
MAX_BACKFILLS_PER_PLATFORM = {
|
||||
'linux': 200,
|
||||
}
|
||||
RESET_BACKFILL_LIMITS = timedelta(hours=24)
|
||||
TIME_TO_MATURE = timedelta(hours=4)
|
||||
|
||||
# Taskcluster credentials for PerfSheriffBot
|
||||
# Taskcluster credentials for Sherlock
|
||||
# TODO: rename PERF_SHERIFF_BOT prefixes to SHERLOCK
|
||||
PERF_SHERIFF_BOT_CLIENT_ID = env('PERF_SHERIFF_BOT_CLIENT_ID', default=None)
|
||||
PERF_SHERIFF_BOT_ACCESS_TOKEN = env('PERF_SHERIFF_BOT_ACCESS_TOKEN', default=None)
|
||||
|
||||
|
|
|
@ -2,25 +2,25 @@ from datetime import timedelta
|
|||
|
||||
from django.conf import settings
|
||||
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_reports import (
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_reports import (
|
||||
BackfillReportMaintainer,
|
||||
AlertsPicker,
|
||||
IdentifyAlertRetriggerables,
|
||||
)
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_tool import BackfillTool
|
||||
from treeherder.perf.auto_perf_sheriffing.perf_sheriff_bot import PerfSheriffBot
|
||||
from treeherder.perf.auto_perf_sheriffing.secretary_tool import SecretaryTool
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_tool import BackfillTool
|
||||
from treeherder.perf.auto_perf_sherrifing.sherlock import Sherlock
|
||||
from treeherder.perf.auto_perf_sherrifing.secretary import Secretary
|
||||
from treeherder.services.taskcluster import DEFAULT_ROOT_URL, notify_client_factory
|
||||
from treeherder.services.taskcluster import TaskclusterModelProxy
|
||||
|
||||
|
||||
def perf_sheriff_bot_factory(days_to_lookup: timedelta) -> PerfSheriffBot:
|
||||
def sherlock_factory(days_to_lookup: timedelta) -> Sherlock:
|
||||
report_maintainer = __report_maintainer_factory(days_to_lookup)
|
||||
backfill_tool = __backfill_tool_factory()
|
||||
secretary_tool = SecretaryTool()
|
||||
secretary = Secretary()
|
||||
notify_client = notify_client_factory()
|
||||
|
||||
return PerfSheriffBot(report_maintainer, backfill_tool, secretary_tool, notify_client)
|
||||
return Sherlock(report_maintainer, backfill_tool, secretary, notify_client)
|
||||
|
||||
|
||||
def __report_maintainer_factory(days_to_lookup: timedelta) -> BackfillReportMaintainer:
|
|
@ -6,14 +6,14 @@ from django.conf import settings as django_settings
|
|||
|
||||
from treeherder.perf.models import BackfillRecord, BackfillReport, PerformanceSettings
|
||||
from treeherder.utils import default_serializer
|
||||
from treeherder.perf.auto_perf_sheriffing.outcome_checker import OutcomeChecker, OutcomeStatus
|
||||
from treeherder.perf.auto_perf_sherrifing.outcome_checker import OutcomeChecker, OutcomeStatus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO: update the backfill status using data (bug 1626548)
|
||||
# TODO: consider making this a singleton (bug 1639112)
|
||||
class SecretaryTool:
|
||||
class Secretary:
|
||||
"""
|
||||
* marks which records can be backfilled
|
||||
* provides & maintains backfill limits
|
||||
|
@ -25,7 +25,8 @@ class SecretaryTool:
|
|||
|
||||
@classmethod
|
||||
def validate_settings(cls):
|
||||
perf_sheriff_settings, created = PerformanceSettings.objects.get_or_create(
|
||||
sherlock_settings, created = PerformanceSettings.objects.get_or_create(
|
||||
# TODO: rename perf_sheriff_bot settings name to sherlock
|
||||
name="perf_sheriff_bot",
|
||||
defaults={"settings": cls._get_default_settings()},
|
||||
)
|
||||
|
@ -37,13 +38,13 @@ class SecretaryTool:
|
|||
return
|
||||
|
||||
# reset limits if the settings expired
|
||||
settings = json.loads(perf_sheriff_settings.settings)
|
||||
logger.info(f"Perfsheriff bot settings: {settings}")
|
||||
settings = json.loads(sherlock_settings.settings)
|
||||
logger.info(f"Sherlock settings: {settings}.")
|
||||
if cls.are_expired(settings):
|
||||
logger.info(f"Settings are expired. Expired settings: {settings}")
|
||||
logger.info(f"Settings are expired. Expired settings: {settings}.")
|
||||
|
||||
perf_sheriff_settings.settings = cls._get_default_settings()
|
||||
perf_sheriff_settings.save()
|
||||
sherlock_settings.settings = cls._get_default_settings()
|
||||
sherlock_settings.save()
|
||||
|
||||
@classmethod
|
||||
def mark_reports_for_backfill(cls):
|
||||
|
@ -53,7 +54,7 @@ class SecretaryTool:
|
|||
frozen=False, last_updated__lte=mature_date_limit
|
||||
)
|
||||
|
||||
logger.info('Perfsheriff bot: %s mature reports found', mature_reports.count())
|
||||
logger.info(f"Sherlock: {mature_reports.count()} mature reports found.")
|
||||
|
||||
# Only for logging alternative strategy for choosing maturity limit
|
||||
alternative_date_limit = datetime.utcnow() - timedelta(days=1)
|
||||
|
@ -61,20 +62,16 @@ class SecretaryTool:
|
|||
frozen=False, created__lte=alternative_date_limit
|
||||
)
|
||||
logger.info(
|
||||
'Perfsheriff bot: %s mature reports found with alternative strategy (not marking)',
|
||||
alternative_mature_reports.count(),
|
||||
f"Sherlock: {alternative_mature_reports.count()} mature reports found with alternative strategy (not marking).",
|
||||
)
|
||||
|
||||
for report in mature_reports:
|
||||
should_freeze = False
|
||||
logger.info(
|
||||
'Perfsheriff bot: marking report with id %s for backfill', report.summary.id
|
||||
)
|
||||
logger.info(f"Sherlock: Marking report with id {report.summary.id} for backfill...")
|
||||
for record in report.records.all():
|
||||
if record.status == BackfillRecord.PRELIMINARY:
|
||||
logger.info(
|
||||
'Perfsheriff bot: marking record with id %s READY_FOR_PROCESSING',
|
||||
record.alert.id,
|
||||
f"Sherlock: Marking record with id {record.alert.id} READY_FOR_PROCESSING..."
|
||||
)
|
||||
record.status = BackfillRecord.READY_FOR_PROCESSING
|
||||
record.save()
|
|
@ -10,9 +10,9 @@ from django.db.models import QuerySet
|
|||
from taskcluster.helper import TaskclusterConfig
|
||||
|
||||
from treeherder.model.models import Job
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_reports import BackfillReportMaintainer
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_tool import BackfillTool
|
||||
from treeherder.perf.auto_perf_sheriffing.secretary_tool import SecretaryTool
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_reports import BackfillReportMaintainer
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_tool import BackfillTool
|
||||
from treeherder.perf.auto_perf_sherrifing.secretary import Secretary
|
||||
from treeherder.perf.email import BackfillNotificationWriter, EmailWriter
|
||||
from treeherder.perf.exceptions import CannotBackfill, MaxRuntimeExceeded
|
||||
from treeherder.perf.models import BackfillRecord, BackfillReport
|
||||
|
@ -23,8 +23,10 @@ CLIENT_ID = settings.PERF_SHERIFF_BOT_CLIENT_ID
|
|||
ACCESS_TOKEN = settings.PERF_SHERIFF_BOT_ACCESS_TOKEN
|
||||
|
||||
|
||||
class PerfSheriffBot:
|
||||
class Sherlock:
|
||||
"""
|
||||
Robot variant of a performance sheriff (the main class)
|
||||
|
||||
Automates backfilling of skipped perf jobs.
|
||||
"""
|
||||
|
||||
|
@ -34,14 +36,14 @@ class PerfSheriffBot:
|
|||
self,
|
||||
report_maintainer: BackfillReportMaintainer,
|
||||
backfill_tool: BackfillTool,
|
||||
secretary_tool: SecretaryTool,
|
||||
secretary: Secretary,
|
||||
notify_client: taskcluster.Notify,
|
||||
max_runtime: timedelta = None,
|
||||
email_writer: EmailWriter = None,
|
||||
):
|
||||
self.report_maintainer = report_maintainer
|
||||
self.backfill_tool = backfill_tool
|
||||
self.secretary = secretary_tool
|
||||
self.secretary = secretary
|
||||
self._notify = notify_client
|
||||
self._max_runtime = self.DEFAULT_MAX_RUNTIME if max_runtime is None else max_runtime
|
||||
self._email_writer = email_writer or BackfillNotificationWriter()
|
||||
|
@ -51,28 +53,28 @@ class PerfSheriffBot:
|
|||
|
||||
def sheriff(self, since: datetime, frameworks: List[str], repositories: List[str]):
|
||||
self.assert_can_run()
|
||||
logger.info('Perfsheriff bot: Validating settings')
|
||||
logger.info("Sherlock: Validating settings...")
|
||||
self.secretary.validate_settings()
|
||||
|
||||
logger.info('Perfsheriff bot: Marking reports for backfill')
|
||||
logger.info("Sherlock: Marking reports for backfill...")
|
||||
self.secretary.mark_reports_for_backfill()
|
||||
self.assert_can_run()
|
||||
|
||||
# secretary tool checks the status of all backfilled jobs
|
||||
# secretary checks the status of all backfilled jobs
|
||||
# TODO: should not be enabled during soft launch - enable for the real launch
|
||||
# self.secretary.check_outcome()
|
||||
|
||||
# reporter tool should always run *(only handles preliminary records/reports)*
|
||||
logger.info('Perfsheriff bot: Reporter tool is creating/maintaining reports')
|
||||
logger.info("Sherlock: Reporter tool is creating/maintaining reports...")
|
||||
self._report(since, frameworks, repositories)
|
||||
self.assert_can_run()
|
||||
|
||||
# backfill tool follows
|
||||
logger.info('Perfsheriff bot: Start backfills')
|
||||
logger.info("Sherlock: Starting to backfill...")
|
||||
self._backfill()
|
||||
self.assert_can_run()
|
||||
|
||||
logger.info('Perfsheriff bot: Notify backfill outcome')
|
||||
logger.info("Sherlock: Notifying backfill outcome...")
|
||||
self._notify_backfill_outcome()
|
||||
|
||||
def runtime_exceeded(self) -> bool:
|
||||
|
@ -94,18 +96,18 @@ class PerfSheriffBot:
|
|||
|
||||
# TODO: make this platform generic
|
||||
records_to_backfill = self.__fetch_records_requiring_backfills()
|
||||
logger.info('Perfsheriff bot: %s records found to backfill', records_to_backfill.count())
|
||||
logger.info(f"Sherlock: {records_to_backfill.count()} records found to backfill.")
|
||||
for record in records_to_backfill:
|
||||
if left <= 0 or self.runtime_exceeded():
|
||||
break
|
||||
left, consumed = self._backfill_record(record, left)
|
||||
logger.info('Perfsheriff bot: backfilled record with id %s', record.alert.id)
|
||||
logger.info(f"Sherlock: Backfilled record with id {record.alert.id}.")
|
||||
self.backfilled_records.append(record)
|
||||
total_consumed += consumed
|
||||
|
||||
self.secretary.consume_backfills('linux', total_consumed)
|
||||
logger.info('Perfsheriff bot: consumed %s backfills for linux', total_consumed)
|
||||
logger.debug(f'Perfsheriff bot: Having {left} backfills left.')
|
||||
logger.info(f"Sherlock: Consumed {total_consumed} backfills for Linux.")
|
||||
logger.debug(f"Sherlock: Having {left} backfills left.")
|
||||
|
||||
@staticmethod
|
||||
def __fetch_records_requiring_backfills() -> QuerySet:
|
||||
|
@ -187,7 +189,7 @@ class PerfSheriffBot:
|
|||
@staticmethod
|
||||
def _is_queue_overloaded(provisioner_id: str, worker_type: str, acceptable_limit=100) -> bool:
|
||||
"""
|
||||
Helper method for PerfSheriffBot to check load on processing queue.
|
||||
Helper method for Sherlock to check load on processing queue.
|
||||
Usage example: _queue_is_too_loaded('gecko-3', 'b-linux')
|
||||
:return: True/False
|
||||
"""
|
|
@ -10,7 +10,7 @@ functionality of the `BackfillTool`.
|
|||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from treeherder.perf.auto_perf_sheriffing.backfill_tool import BackfillTool
|
||||
from treeherder.perf.auto_perf_sherrifing.backfill_tool import BackfillTool
|
||||
from treeherder.services.taskcluster import DEFAULT_ROOT_URL as root_url
|
||||
from treeherder.services.taskcluster import TaskclusterModel
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from typing import List, Tuple
|
|||
from django.core.management.base import BaseCommand
|
||||
|
||||
from treeherder.model.models import Repository
|
||||
from treeherder.perf.auto_perf_sheriffing.factories import perf_sheriff_bot_factory
|
||||
from treeherder.perf.auto_perf_sherrifing.factories import sherlock_factory
|
||||
from treeherder.perf.exceptions import MaxRuntimeExceeded
|
||||
from treeherder.perf.models import PerformanceFramework
|
||||
|
||||
|
@ -49,13 +49,13 @@ class Command(BaseCommand):
|
|||
def handle(self, *args, **options):
|
||||
frameworks, repositories, since, days_to_lookup = self._parse_args(**options)
|
||||
|
||||
perf_sheriff_bot = perf_sheriff_bot_factory(days_to_lookup)
|
||||
sherlock = sherlock_factory(days_to_lookup)
|
||||
try:
|
||||
perf_sheriff_bot.sheriff(since, frameworks, repositories)
|
||||
sherlock.sheriff(since, frameworks, repositories)
|
||||
except MaxRuntimeExceeded as ex:
|
||||
logging.info(ex)
|
||||
|
||||
logging.info("Perfsheriff bot: Going back to sleep")
|
||||
logging.info("Sherlock: Going back to sleep.")
|
||||
|
||||
def _parse_args(self, **options) -> Tuple[List, List, datetime, timedelta]:
|
||||
return (
|
||||
|
|
|
@ -535,7 +535,7 @@ class PerformanceBugTemplate(models.Model):
|
|||
return '{} bug template'.format(self.framework.name)
|
||||
|
||||
|
||||
# TODO: we actually need this name for the PerfSheriffBot' s hourly report
|
||||
# TODO: we actually need this name for the Sherlock' s hourly report
|
||||
class BackfillReport(models.Model):
|
||||
"""
|
||||
Groups & stores all context required to retrigger/backfill
|
||||
|
|
Загрузка…
Ссылка в новой задаче