Skip to content

Commit 9028c86

Browse files
committed
contest: backend: add flakiness query
Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ddbc9ed commit 9028c86

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

contest/backend/query.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
psql = psycopg2.connect(database=db_name)
1919
psql.autocommit = True
2020

21+
# How many branches to query to get flakes for last month
22+
flake_cnt = 300
23+
2124

2225
@app.route('/')
2326
def hello():
@@ -190,3 +193,85 @@ def dev_info():
190193
data = [{columns[i]: value for i, value in enumerate(row)} for row in rows]
191194

192195
return data
196+
197+
198+
@app.route('/flaky-tests')
199+
def flaky_tests():
200+
"""
201+
Returns tests that are flaky (first try fails, retry passes, and no crash).
202+
"""
203+
global flake_cnt
204+
limit = request.args.get('limit')
205+
try:
206+
limit = int(limit)
207+
month = False
208+
except:
209+
month = True # Default to querying last month
210+
limit = flake_cnt # Default limit
211+
212+
# Find branches with incomplete results, psql JSON helpers fail for them
213+
t = datetime.datetime.now()
214+
with psql.cursor() as cur:
215+
query = f"""
216+
SELECT branch
217+
FROM results
218+
WHERE json_normal NOT LIKE '%"results": [%'
219+
GROUP BY branch;
220+
"""
221+
222+
cur.execute(query)
223+
rows = cur.fetchall()
224+
branches = ""
225+
if rows:
226+
branches = " AND branch != ".join([""] + [f"'{r[0]}'" for r in rows])
227+
print(f"Query for in-prog execs took: {str(datetime.datetime.now() - t)}")
228+
229+
t = datetime.datetime.now()
230+
with psql.cursor() as cur:
231+
# Query for tests where first try failed, retry passed, and no crash
232+
query = f"""
233+
SELECT remote, executor, test, branch, branch_date
234+
FROM results, jsonb_to_recordset(json_normal::jsonb->'results') as
235+
x(test text, result text, retry text, crashes text)
236+
WHERE x.result = 'fail'
237+
AND x.retry = 'pass'
238+
AND x.crashes IS NULL
239+
{branches}
240+
ORDER BY branch_date DESC LIMIT {limit};
241+
"""
242+
243+
cur.execute(query)
244+
rows = cur.fetchall()
245+
246+
print(f"Query for flaky tests took: {str(datetime.datetime.now() - t)}")
247+
248+
target_date = datetime.datetime.now() - datetime.timedelta(days=14)
249+
two_weeks = target_date.strftime("%Y-%m-%d--%H-%M")
250+
target_date = datetime.datetime.now() - datetime.timedelta(days=28)
251+
four_weeks = target_date.strftime("%Y-%m-%d--%H-%M")
252+
cnt = 0
253+
res = {}
254+
for row in rows:
255+
rem, exe, test, branch, br_date = row
256+
key = (rem, exe, test)
257+
if not month:
258+
res[key] = res.get(key, 0) + 1
259+
else:
260+
if key not in res:
261+
res[key] = [0, 0]
262+
if br_date >= two_weeks:
263+
res[key][0] += 1
264+
elif br_date >= four_weeks:
265+
res[key][1] += 1
266+
else:
267+
break
268+
cnt += 1
269+
# JSON needs a simple array, not a dict
270+
data = []
271+
for k, v in res.items():
272+
data.append({"remote": k[0], "executor": k[1], "test": k[2], "count": v})
273+
274+
if month:
275+
# Overcount by 30 to account for fluctuation in flakiness
276+
flake_cnt = cnt + 30
277+
return data

ui/status.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ <h3>Build processing</h3>
5252
<th>Memory Use</th>
5353
</tr>
5454
</table>
55+
<br />
56+
<h3>Flakiest tests</h3>
57+
<table id="flakes">
58+
<tr>
59+
<th>Remote</th>
60+
<th>Executor</th>
61+
<th>Test</th>
62+
<th>Flakes (now - 2w)</th>
63+
<th>Flakes (2w - 4w)</th>
64+
<th>Ignored</th>
65+
</tr>
66+
</table>
5567
</div>
5668
<div class="column">
5769
<h3>Continuous testing results</h3>

ui/status.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,37 @@ function branches_loaded(data_raw)
10051005
loaded_one();
10061006
}
10071007

1008+
function flakes_doit(data_raw)
1009+
{
1010+
let flakes = document.getElementById("flakes");
1011+
1012+
data_raw.sort(function(a, b){
1013+
if (a["count"][0] != b["count"][0])
1014+
return b["count"][0] - a["count"][0];
1015+
if (a["count"][1] != b["count"][1])
1016+
return b["count"][1] - a["count"][1];
1017+
return 0;
1018+
})
1019+
1020+
$.each(data_raw, function(i, v) {
1021+
let row = flakes.insertRow();
1022+
let reported = nipa_pw_reported(v, v);
1023+
let ignored = "";
1024+
1025+
if (v["count"][0] < 3 && reported)
1026+
return 1;
1027+
if (!reported)
1028+
ignored = "yes";
1029+
1030+
row.insertCell(0).innerText = v["remote"];
1031+
row.insertCell(1).innerText = v["executor"];
1032+
row.insertCell(2).innerText = v["test"];
1033+
row.insertCell(3).innerText = v["count"][0];
1034+
row.insertCell(4).innerText = v["count"][1];
1035+
row.insertCell(5).innerText = ignored;
1036+
});
1037+
}
1038+
10081039
function do_it()
10091040
{
10101041
/*
@@ -1028,4 +1059,7 @@ function do_it()
10281059
$(document).ready(function() {
10291060
$.get("static/nipa/branches-info.json", branches_loaded)
10301061
});
1062+
$(document).ready(function() {
1063+
$.get("query/flaky-tests", flakes_doit)
1064+
});
10311065
}

0 commit comments

Comments
 (0)