Skip to content

Commit

Permalink
Allow for bugzilla management to use a minimum threshold for 'reopene…
Browse files Browse the repository at this point in the history
…d bugs' (#8144)
  • Loading branch information
jmaher authored Aug 6, 2024
1 parent abe2ae2 commit f24ee11
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 19 deletions.
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,11 @@ def test_job(eleven_job_blobs, create_jobs):
return create_jobs([job])[0]


@pytest.fixture
def test_jobs(eleven_job_blobs_new_date, create_jobs):
return create_jobs(eleven_job_blobs_new_date)


@pytest.fixture
def test_two_jobs_tc_metadata(eleven_job_blobs_new_date, create_jobs):
job_1, job_2 = eleven_job_blobs_new_date[0:2]
Expand Down
49 changes: 36 additions & 13 deletions tests/etl/test_bugzilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,50 @@ def test_bz_api_process(mock_bugzilla_api_request):
assert Bugscache.objects.count() == 28


def test_bz_reopen_bugs(request, mock_bugzilla_reopen_request, client, test_job, test_user, bugs):
@pytest.mark.parametrize(
"minimum_failures_to_reopen",
[1, 3],
)
def test_bz_reopen_bugs(
request,
mock_bugzilla_reopen_request,
client,
test_jobs,
test_user,
bugs,
minimum_failures_to_reopen,
):
"""
Test expected bugs get reopened.
"""
bug = bugs[0]
client.force_authenticate(user=test_user)
request.config.cache.set("reopened_bugs", {})

incomplete_bugs = [bug for bug in bugs if bug.resolution == "INCOMPLETE"]
not_incomplete_bugs = [bug for bug in bugs if bug.resolution != "INCOMPLETE"]
idx = 0
for bug in [
not_incomplete_bugs[0],
not_incomplete_bugs[2],
incomplete_bugs[0],
incomplete_bugs[2],
incomplete_bugs[0],
incomplete_bugs[2],
incomplete_bugs[0],
not_incomplete_bugs[0],
not_incomplete_bugs[2],
]:
submit_obj = {"job_id": test_job.id, "bug_id": bug.id, "type": "manual"}
submit_obj = {"job_id": test_jobs[idx].id, "bug_id": bug.id, "type": "manual"}

client.post(
reverse("bug-job-map-list", kwargs={"project": test_job.repository.name}),
reverse("bug-job-map-list", kwargs={"project": test_jobs[idx].repository.name}),
data=submit_obj,
)

idx += 1
if idx % 11 == 0:
idx = 0

process = BzApiBugProcess()
process.minimum_failures_to_reopen = minimum_failures_to_reopen
process.run()

reopened_bugs = request.config.cache.get("reopened_bugs", None)
Expand All @@ -53,19 +74,21 @@ def test_bz_reopen_bugs(request, mock_bugzilla_reopen_request, client, test_job,
{
"status": "REOPENED",
"comment": {
"body": "New failure instance: https://treeherder.mozilla.org/logviewer?job_id=1&repo=mozilla-central"
"body": "New failure instance: https://treeherder.mozilla.org/logviewer?job_id=5&repo=mozilla-central"
},
"comment_tags": "treeherder",
}
},
),
"https://thisisnotbugzilla.org/rest/bug/404": json.dumps(
}

if process.minimum_failures_to_reopen == 1:
expected_reopen_attempts["https://thisisnotbugzilla.org/rest/bug/404"] = json.dumps(
{
"status": "REOPENED",
"comment": {
"body": "New failure instance: https://treeherder.mozilla.org/logviewer?job_id=1&repo=mozilla-central"
"body": "New failure instance: https://treeherder.mozilla.org/logviewer?job_id=4&repo=mozilla-central"
},
"comment_tags": "treeherder",
}
),
}
},
)
assert reopened_bugs == expected_reopen_attempts
16 changes: 10 additions & 6 deletions treeherder/etl/bugzilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import dateutil.parser
from datetime import datetime, timedelta
from django.conf import settings
from django.db.models import Max
from django.db.models import Count, Max

from treeherder.model.models import Bugscache, BugJobMap
from treeherder.utils.github import fetch_json
Expand All @@ -17,7 +17,7 @@ def reopen_request(url, method, headers, json):
make_request(url, method=method, headers=headers, json=json)


def reopen_intermittent_bugs():
def reopen_intermittent_bugs(minimum_failures_to_reopen=1):
# Don't reopen bugs from non-production deployments.
if settings.BUGFILER_API_KEY is None:
return
Expand All @@ -29,9 +29,11 @@ def reopen_intermittent_bugs():
# https://github.com/mozilla/relman-auto-nag/blob/c7439e247677333c1cd8c435234b3ef3adc49680/auto_nag/scripts/close_intermittents.py#L17
recent_days = 7
recently_used_bugs = set(
BugJobMap.objects.filter(created__gt=datetime.now() - timedelta(recent_days)).values_list(
"bug_id", flat=True
)
BugJobMap.objects.filter(created__gt=(datetime.now() - timedelta(recent_days)))
.values("bug_id")
.annotate(num_failures=Count("bug_id"))
.filter(num_failures__gte=minimum_failures_to_reopen)
.values_list("bug_id", flat=True)
)
bugs_to_reopen = incomplete_bugs & recently_used_bugs

Expand Down Expand Up @@ -90,6 +92,8 @@ def fetch_intermittent_bugs(additional_params, limit, duplicate_chain_length):


class BzApiBugProcess:
minimum_failures_to_reopen = 1

def run(self):
year_ago = datetime.utcnow() - timedelta(days=365)
last_change_time_max = (
Expand Down Expand Up @@ -302,4 +306,4 @@ def run(self):
modified=last_change_time_max
)

reopen_intermittent_bugs()
reopen_intermittent_bugs(self.minimum_failures_to_reopen)

0 comments on commit f24ee11

Please sign in to comment.