Skip to content

Commit 8d49da4

Browse files
authored
Merge pull request #1186 from cloudbees-oss/v1-sync
Forward porting from v1
2 parents 394e9af + 1397475 commit 8d49da4

File tree

9 files changed

+75
-28
lines changed

9 files changed

+75
-28
lines changed

smart_tests/commands/subset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ def get_payload(self) -> dict[str, Any]:
400400

401401
def _collect_potential_test_files(self):
402402
LOOSE_TEST_FILE_PATTERN = r'(\.(test|spec)\.|_test\.|Test\.|Spec\.|test/|tests/|__tests__/|src/test/)'
403-
EXCLUDE_PATTERN = r'\.(xml|json|txt|yml|yaml|md)$'
403+
EXCLUDE_PATTERN = r'(BUILD|Makefile|Dockerfile|LICENSE|.gitignore|.gitkeep|.keep|id_rsa|rsa|blank|taglib)|\.(xml|json|jsonl|txt|yml|yaml|toml|md|png|jpg|jpeg|gif|svg|sql|html|css|graphql|proto|gz|zip|rz|bzl|conf|config|snap|pem|crt|key|lock|jpi|hpi|jelly|properties|jar|ini|mod|sum|bmp|env|envrc|sh)$' # noqa E501
404404

405405
try:
406406
git_managed_files = subprocess.run(['git', 'ls-files'], stdout=subprocess.PIPE,

smart_tests/jar/exe_deploy.jar

102 Bytes
Binary file not shown.

smart_tests/test_runners/bazel.py

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import json
2-
import os
32
import sys
3+
import xml.etree.ElementTree as ET
4+
from os import path
45
from pathlib import Path
56
from typing import Annotated, Generator, List
67

78
from junitparser import TestCase, TestSuite # type: ignore
89

10+
import smart_tests.args4p.converters as converters
911
import smart_tests.args4p.typer as typer
1012

11-
from ..args4p.converters import path
1213
from ..commands.subset import Subset
1314
from ..testpath import TestPath
1415
from ..utils.logger import Logger
@@ -44,7 +45,7 @@ def record_tests(
4445
"--build-event-json",
4546
help="set file path generated by --build_event_json_file",
4647
multiple=True,
47-
type=path(exists=True)
48+
type=converters.path(exists=True)
4849
)] = None,
4950
):
5051
"""
@@ -64,15 +65,45 @@ def f(case: TestCase, suite: TestSuite, report_file: str) -> TestPath:
6465

6566
# last path component is the target, the rest is package
6667
# TODO: does this work correctly when on Windows?
67-
path = make_test_path(os.path.dirname(pkgNtarget), os.path.basename(pkgNtarget))
68+
tp = make_test_path(path.dirname(pkgNtarget), path.basename(pkgNtarget))
6869

6970
# let the normal path building kicks in
70-
path.extend(default_path_builder(case, suite, report_file))
71-
return path
71+
tp.extend(default_path_builder(case, suite, report_file))
72+
return tp
7273

7374
client.path_builder = f
7475
client.check_timestamp = False
7576

77+
def parse_func(report: str) -> ET.ElementTree:
78+
"""
79+
test result XML generated by Bazel's java_test rule (and possibly others) do not capture system-out/system-err.
80+
The whole thing gets captured separately as test.log file in the same directory as test.xml.
81+
This limits our ability to do useful things with data, so we go out of our way to capture it.
82+
Ideally Bazel should do this. test.log captures the entire output from the whole session, and therefore
83+
it is incapable of splitting log between different test classes.
84+
"""
85+
tree = ET.parse(report)
86+
root = tree.getroot()
87+
for ts in root.findall('testsuite'):
88+
# be defensive -- future/non-Java test rules might capture those
89+
if ts.findtext('system-out', '') == "" and ts.findtext('system-err', '') == "":
90+
logfile = path.join(path.dirname(report), 'test.log')
91+
if path.exists(logfile):
92+
print("Found {}".format(logfile))
93+
for x in ts.findall('system-out'):
94+
ts.remove(x)
95+
with open(logfile, 'r', encoding='utf-8', errors='replace') as log_file:
96+
log = log_file.read()
97+
98+
for c in ts.findall('testcase'):
99+
if c.findtext('system-out', '') == "" and c.findtext('system-err', '') == "":
100+
system_out = ET.SubElement(c, 'system-out')
101+
system_out.text = log
102+
103+
return tree # type: ignore
104+
105+
client.junitxml_parse_func = parse_func
106+
76107
if build_event_json_files:
77108
for l in parse_build_event_json(build_event_json_files):
78109
if l is None:

src/main/java/com/launchableinc/ingest/commits/CommitGraphCollector.java

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ public class CommitGraphCollector {
8989

9090
private int maxDays;
9191

92+
private boolean reportAllFiles;
93+
9294
private boolean audit;
9395

9496
private boolean dryRun;
@@ -150,7 +152,7 @@ public void transfer(URL service, Authenticator authenticator, boolean enableTim
150152
}
151153
CloseableHttpResponse latestResponse = client.execute(new HttpGet(latestUrl.toExternalForm()));
152154
ImmutableList<ObjectId> advertised = getAdvertisedRefs(handleError(latestUrl, latestResponse));
153-
honorMaxDaysHeader(latestResponse);
155+
honorControlHeaders(latestResponse);
154156

155157
// every time a new stream is needed, supply ByteArrayOutputStream, and when the data is all
156158
// written, turn around and ship that over
@@ -301,16 +303,21 @@ public void accept(VirtualFile f) {
301303
}
302304
}
303305

304-
/**
305-
* When a user incorrectly configures shallow clone, the incremental nature of commit collection
306-
* makes it really hard for us and users to collaboratively reset and repopulate the commit data.
307-
* This server-side override mechanism makes it easier.
308-
*/
309-
private void honorMaxDaysHeader(HttpResponse response) {
306+
private void honorControlHeaders(HttpResponse response) {
307+
// When a user incorrectly configures shallow clone, the incremental nature of commit collection
308+
// makes it really hard for us and users to collaboratively reset and repopulate the commit data.
309+
// This server-side override mechanism makes it easier.
310310
Header h = response.getFirstHeader("X-Max-Days");
311311
if (h!=null) {
312312
maxDays = Integer.parseInt(h.getValue());
313313
}
314+
// File transfer is supposed to work incrementally, but we are investigating the problem where
315+
// not all files get collected prior to commit collection, resulting in incomplete data on the server side.
316+
// As a temporary mitigation, allow the server to request all files to be reported.
317+
h = response.getFirstHeader("X-Report-All-Files");
318+
if (h!=null) {
319+
reportAllFiles = true;
320+
}
314321
}
315322

316323
private ImmutableList<ObjectId> getAdvertisedRefs(HttpResponse response) throws IOException {
@@ -427,16 +434,22 @@ public void transfer(Collection<ObjectId> advertised, Consumer<JSCommit> commitR
427434
// and it drastically cuts down the initial commit consumption of a new large repository.
428435
// ... except we do want to capture the head commit, as that makes it easier to spot integration problems
429436
// when `record build` and `record commit` are separated.
437+
438+
// two RevFilters are order sensitive. This is because CommitTimeRevFilter.after doesn't return false to
439+
// filter things out, it throws StopWalkException to terminate the walk, never giving a chance for the other
440+
// branch of OR to be evaluated. So we need to put ObjectRevFilter first.
430441
walk.setRevFilter(
431442
OrRevFilter.create(
432-
CommitTimeRevFilter.after(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(maxDays)),
433-
new ObjectRevFilter(headId)));
443+
new ObjectRevFilter(headId),
444+
CommitTimeRevFilter.after(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(maxDays))));
434445

435446
for (ObjectId id : advertised) {
436447
try {
437448
RevCommit c = walk.parseCommit(id);
438449
walk.markUninteresting(c);
439-
treeWalk.addTree(c.getTree());
450+
if (!reportAllFiles) {
451+
treeWalk.addTree(c.getTree());
452+
}
440453
} catch (MissingObjectException e) {
441454
// it's possible that the server advertises a commit we don't have.
442455
//
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Dummy standard output
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<?xml version='1.0' encoding='UTF-8'?>
22
<testsuites>
3-
<testsuite name='com.ninjinkun.MyLibTest1' timestamp='2020-12-16T03:11:43.526Z' hostname='localhost' tests='1' failures='0' errors='0' time='2.02' package='' id='0'>
3+
<testsuite name='com.ninjinkun.MyLibTest1' timestamp='2020-12-16T03:11:43.526Z' hostname='localhost' tests='1' failures='1' errors='0' time='2.02' package='' id='0'>
44
<properties />
5-
<testcase name='testFibonacci' classname='com.ninjinkun.MyLibTest1' time='2.02' />
5+
<testcase name='testFibonacci' classname='com.ninjinkun.MyLibTest1' time='2.02'>
6+
<failure message='Yo!' type='java.lang.Exception'>java.lang.Exception: Yo!
7+
at somewhere(Somewhere.java:33)</failure></testcase>
68
<system-out />
79
<system-err /></testsuite></testsuites>

tests/data/bazel/record_test_result.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
{ "type": "testcase", "name": "testFibonacci" }
2424
],
2525
"duration": 2.02,
26-
"status": 1,
27-
"stdout": "",
28-
"stderr": "",
26+
"status": 0,
27+
"stdout": "Dummy standard output\n",
28+
"stderr": "java.lang.Exception: Yo!\n at somewhere(Somewhere.java:33)",
2929
"data": null
3030
},
3131
{

tests/data/bazel/record_test_with_build_event_json_result.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
{ "type": "testcase", "name": "testFibonacci" }
1010
],
1111
"duration": 2.02,
12-
"status": 1,
13-
"stdout": "",
14-
"stderr": "",
12+
"status": 0,
13+
"stdout": "Dummy standard output\n",
14+
"stderr": "java.lang.Exception: Yo!\n at somewhere(Somewhere.java:33)",
1515
"data": null
1616
},
1717
{

tests/data/bazel/record_test_with_multiple_build_event_json_result.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
{ "type": "testcase", "name": "testFibonacci" }
1010
],
1111
"duration": 2.02,
12-
"status": 1,
13-
"stdout": "",
14-
"stderr": "",
12+
"status": 0,
13+
"stdout": "Dummy standard output\n",
14+
"stderr": "java.lang.Exception: Yo!\n at somewhere(Somewhere.java:33)",
1515
"data": null
1616
},
1717
{

0 commit comments

Comments
 (0)