Skip to content

Commit decb1b7

Browse files
Merge 26.5 to develop (#2980)
2 parents 56b2e5e + dfa82bd commit decb1b7

4 files changed

Lines changed: 108 additions & 55 deletions

File tree

build.gradle

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,6 @@ project.tasks.named("uiTests").configure {
182182
project.parent.parent.tasks.named("ijConfigure").configure {
183183
dependsOn(initPropertiesTask)
184184
}
185-
project.tasks.withType(RunTestSuite).configureEach { it ->
186-
scanForTestClasses = true // Required for Gradle 9.3
187-
}
188185

189186
if (project.hasProperty('doPublishing'))
190187
{

src/org/labkey/test/Runner.java

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -129,21 +129,24 @@ private void updateRemainingTests(Test test, boolean failed, boolean errored)
129129
Class<?> testClass = getTestClass(test);
130130
_remainingTests.remove(testClass);
131131
if (failed)
132-
_failedTests.add(test.toString());
132+
_failedTests.add(getTestName(test));
133133
else if (errored)
134-
_erroredTests.add(test.toString());
134+
_erroredTests.add(getTestName(test));
135135
else
136-
_passedTests.add(test.toString());
136+
_passedTests.add(getTestName(test));
137137
}
138138

139139
private static void writeRemainingTests()
140140
{
141-
ArrayList<String> failedAndRemaining = new ArrayList<>();
142-
failedAndRemaining.addAll(_failedTests);
143-
failedAndRemaining.addAll(_erroredTests);
144-
for (Class<?> clazz : _remainingTests)
145-
failedAndRemaining.add(clazz.getName());
146-
writeClasses(failedAndRemaining, getRemainingTestsFile());
141+
if (!TestProperties.isTestRunningOnTeamCity()) // Not useful on TeamCity
142+
{
143+
ArrayList<String> failedAndRemaining = new ArrayList<>();
144+
failedAndRemaining.addAll(_failedTests);
145+
failedAndRemaining.addAll(_erroredTests);
146+
for (Class<?> clazz : _remainingTests)
147+
failedAndRemaining.add(clazz.getName());
148+
writeClasses(failedAndRemaining, getRemainingTestsFile());
149+
}
147150
}
148151

149152
private static void writeClasses(List<String> tests, File file)
@@ -203,7 +206,7 @@ private static Class<?>[] readClasses(File recentlyFailedTestsFile, List<Class<?
203206
filteredRecentlyFailedTests.add(item);
204207
}
205208
}
206-
209+
207210
return filteredRecentlyFailedTests.toArray(new Class[0]);
208211
}
209212

@@ -273,8 +276,7 @@ else if (test instanceof JUnit4TestAdapter adapter)
273276

274277
if (_failedTests.size() + _erroredTests.size() < _maxTestFailures || _maxTestFailures <= 0)
275278
{
276-
final Class<?> currentTestClass = getTestClass(test);
277-
final String currentTestName = currentTestClass.getSimpleName();
279+
final String currentTestName = getTestName(test);
278280

279281
TestListener classFailListener = new TestListener()
280282
{
@@ -298,13 +300,16 @@ public void endTest(Test _test) { }
298300
};
299301
testResult.addListener(classFailListener);
300302

301-
logToServer("=== Starting " + currentTestName + getProgress() + " ===");
302-
LOG.info("=============== Starting " + currentTestName + getProgress() + " =================");
303+
if (!(test instanceof JUnitTest.RemoteTest))
304+
{
305+
logToServer("=== Starting " + currentTestName + getProgress() + " ===");
306+
LOG.info("=============== Starting " + currentTestName + getProgress() + " =================");
307+
}
303308

304309
// This stub matches the failure generated by JUnit when it fails during static setup/teardown (e.g. @BeforeClass)
305310
// Without this TeamCity has no way of knowing when a setup/teardown failure has been resolved
306-
final Test loggingStub = test instanceof JUnit4TestAdapter ?
307-
new TestSuite(currentTestClass) :
311+
final Test loggingStub = test instanceof JUnit4TestAdapter jUnit4TestAdapter ?
312+
new TestSuite(jUnit4TestAdapter.getTestClass()) :
308313
null;
309314

310315
if (loggingStub != null)
@@ -317,10 +322,13 @@ public void endTest(Test _test) { }
317322

318323
testResult.removeListener(classFailListener);
319324

320-
String result = failed.booleanValue() || errored.booleanValue() ? "Failed " : "Completed ";
321-
TestLogger.resetLogger();
322-
LOG.info("=============== " + result + currentTestName + getProgress() + " =================");
323-
logToServer("=== " + result + currentTestName + getProgress() + " ===");
325+
if (!(test instanceof JUnitTest.RemoteTest))
326+
{
327+
String result = failed.booleanValue() || errored.booleanValue() ? "Failed " : "Completed ";
328+
TestLogger.resetLogger();
329+
LOG.info("=============== " + result + currentTestName + getProgress() + " =================");
330+
logToServer("=== " + result + currentTestName + getProgress() + " ===");
331+
}
324332

325333
}
326334
else
@@ -547,7 +555,7 @@ public String describe()
547555
}
548556
else if (test.countTestCases() > 0)
549557
{
550-
suite.addTest(test);
558+
flattenSuiteInto(suite, (TestSuite) test);
551559
foundServerSideTest = true;
552560
}
553561
}
@@ -570,7 +578,7 @@ else if (specifiedSuite.startsWith("?") && specifiedSuite.length() > 1)
570578
}
571579
TestSuite dynamicSuite = JUnitTest.dynamicSuite(requestedSuites, excludedSuites);
572580
if (dynamicSuite.countTestCases() > 0)
573-
suite.addTest(dynamicSuite);
581+
flattenSuiteInto(suite, dynamicSuite);
574582
}
575583
}
576584

@@ -603,9 +611,9 @@ public void run(TestResult testResult)
603611

604612
private static void writeTimeReport()
605613
{
606-
int width = 60;
614+
int width = 64;
607615
long total = 0;
608-
LOG.info("======================= Time Report ========================");
616+
LOG.info(getCenteredText("Time Report", '=', width));
609617

610618
Duration totalCrawlTime = Duration.ZERO;
611619
int totalUniquePages = 0;
@@ -619,7 +627,7 @@ private static void writeTimeReport()
619627
}
620628
for (Map.Entry<Test, Long> entry : _testStats.entrySet())
621629
{
622-
String testName = entry.getKey().toString();
630+
String testName = getTestName(entry.getKey());
623631
long duration = entry.getValue();
624632

625633
long percent = Math.round(100.0 * (duration / (double) total));
@@ -630,7 +638,6 @@ private static void writeTimeReport()
630638
(_erroredTests.contains(testName) ? "ERROR" : "not run"))) +
631639
" - " +
632640
formatDuration(duration) + " " + percentStr;
633-
testName = testName.substring(testName.lastIndexOf('.') + 1);
634641

635642
LOG.info(getFixedWidthString(testName, durationAndPercent, width));
636643

@@ -686,7 +693,7 @@ private static void writeTimeReport()
686693
}
687694
if (!TeamCityUtils.getBuildStatistics().isEmpty())
688695
{
689-
LOG.info("--------------------- Build Statistics ---------------------");
696+
LOG.info(getCenteredText("Build Statistics", '-', width));
690697
for (String stat : TeamCityUtils.getBuildStatistics().keySet())
691698
{
692699
List<Number> values = TeamCityUtils.getBuildStatistics().get(stat);
@@ -702,7 +709,7 @@ private static void writeTimeReport()
702709
Map<String, Collection<String>> actionWarnings = WebDriverWrapper.getActionWarnings();
703710
if (!actionWarnings.isEmpty())
704711
{
705-
LOG.info("---------------------- Test Warnings -----------------------");
712+
LOG.info(getCenteredText("Test Warnings", '-', width));
706713
for (String warning : actionWarnings.keySet())
707714
{
708715
LOG.info(" " + warning + ":");
@@ -714,7 +721,7 @@ private static void writeTimeReport()
714721
}
715722
}
716723
}
717-
LOG.info("------------------------------------------------------------");
724+
LOG.info("-".repeat(width));
718725
LOG.info(getFixedWidthString("Total duration:", formatDuration(total), width) + "\n");
719726
LOG.info("Completed " + FastDateFormat.getInstance("yyyy-MM-dd HH:mm").format(new Date()));
720727
}
@@ -744,10 +751,23 @@ private static String getRowString(String[] list, int columnWidth)
744751
private static String getFixedWidthString(String prefix, String suffix, int length)
745752
{
746753
int contentLength = prefix.length() + suffix.length();
747-
int padding = Math.max(0, length - contentLength);
754+
int padding = Math.max(1, length - contentLength);
748755
return prefix + " ".repeat(padding) + suffix;
749756
}
750757

758+
private static String getCenteredText(String text, char paddingChar, int width)
759+
{
760+
text = StringUtils.trimToEmpty(text);
761+
if (text.length() > width)
762+
return text;
763+
764+
text = text.isEmpty() ? "" : " " + text + " ";
765+
int paddingLength = width - text.length();
766+
int leftPadding = paddingLength / 2;
767+
int rightPadding = paddingLength - leftPadding;
768+
return Character.toString(paddingChar).repeat(leftPadding) + text + Character.toString(paddingChar).repeat(rightPadding);
769+
}
770+
751771
private static TestSet getCompositeTestSet(List<String> suitesColl)
752772
{
753773
if (suitesColl.isEmpty())
@@ -1021,7 +1041,7 @@ else if (testNames.isEmpty())
10211041
Test test = e.nextElement();
10221042
Class<?> testClass = getTestClass(test);
10231043
_remainingTests.add(testClass);
1024-
LOG.info(" " + testClass.getSimpleName());
1044+
LOG.info(" " + getTestName(test));
10251045
for (String testMethod : specifiedTestMethods.getOrDefault(testClass, Collections.emptyList()))
10261046
{
10271047
LOG.info(" ." + testMethod);
@@ -1126,10 +1146,43 @@ private static String getModuleNameFromPath(File path)
11261146
return null;
11271147
}
11281148

1149+
private static void flattenSuiteInto(TestSuite destination, TestSuite source)
1150+
{
1151+
if (TestProperties.isTestRunningOnTeamCity())
1152+
{
1153+
// Flatten test suites so that TeamCity will correlate with results from before Gradle 9.3
1154+
Enumeration<Test> tests = source.tests();
1155+
while (tests.hasMoreElements())
1156+
{
1157+
Test t = tests.nextElement();
1158+
if (t instanceof TestSuite nested)
1159+
flattenSuiteInto(destination, nested);
1160+
else
1161+
destination.addTest(t);
1162+
}
1163+
}
1164+
else
1165+
{
1166+
destination.addTest(source);
1167+
}
1168+
}
1169+
1170+
private static String getTestName(Test test)
1171+
{
1172+
if (test instanceof JUnit4TestAdapter testAdapter)
1173+
return testAdapter.getTestClass().getSimpleName();
1174+
else if (test instanceof JUnitTest.RemoteTest remoteTest)
1175+
return remoteTest.getName();
1176+
else
1177+
return test.getClass().getSimpleName();
1178+
}
1179+
11291180
private static Class<?> getTestClass(Test test)
11301181
{
1131-
if (test instanceof JUnit4TestAdapter)
1132-
return ((JUnit4TestAdapter) test).getTestClass();
1182+
if (test instanceof JUnit4TestAdapter testAdapter)
1183+
return testAdapter.getTestClass();
1184+
else if (test instanceof JUnitTest.RemoteTest)
1185+
return JUnitTest.class;
11331186
else
11341187
return test.getClass();
11351188
}

src/org/labkey/test/tests/CustomizeViewTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,18 @@ public void saveFilterTest()
303303
FieldKey fieldKey = FieldKey.fromParts(LAST_NAME_COLUMN);
304304
String op = "Starts With";
305305
String value = "J";
306-
String[] viewNames = {TRICKY_CHARACTERS + "view", "AAC", "aaa", "aad", "zzz"};
306+
String[] viewNames = {TRICKY_CHARACTERS + "view", "AAC", "aaa", "aad", "zzz", "view,with,comma"};
307307

308308
setColumns(LAST_NAME_COLUMN);
309309
for(String name : viewNames)
310310
{
311311
_customizeViewsHelper.openCustomizeViewPanel();
312312
_customizeViewsHelper.addFilter(fieldKey, op, value);
313313
_customizeViewsHelper.saveCustomView(name);
314+
_customizeViewsHelper.openCustomizeViewPanel();
315+
// GitHub Issue #936 : ensure custom view can be edited
316+
assertElementNotPresent(Locator.tagWithClass("div", "alert-warning").withText(String.format("Custom Grid View '%s' not found.", name)));
317+
_customizeViewsHelper.closePanel();
314318
}
315319

316320
DataRegionTable drt = new DataRegionTable("query", getDriver());

src/org/labkey/test/tests/JUnitTest.java

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public JUnitTest()
8484

8585
public static TestSuite suite() throws Exception
8686
{
87-
return JUnitTest._suite((p) -> true, false);
87+
return JUnitTest._suite(_ -> true, false);
8888
}
8989

9090
private static String getWhen(Map<String,Object> test)
@@ -136,12 +136,9 @@ private static void upgradeHelper(boolean skipInitialUserChecks)
136136
}
137137
catch (Throwable t)
138138
{
139-
if (bootstrapBrowser.getWrappedDriver() != null)
140-
{
141-
ArtifactCollector artifactCollector = new ArtifactCollector(bootstrapBrowser, JUnitTest.class.getSimpleName());
142-
artifactCollector.dumpPageSnapshot("ServerBootstrap", null);
143-
artifactCollector.publishDumpedArtifacts();
144-
}
139+
ArtifactCollector artifactCollector = new ArtifactCollector(bootstrapBrowser, JUnitTest.class.getSimpleName());
140+
artifactCollector.dumpPageSnapshot("ServerBootstrap", null);
141+
artifactCollector.publishDumpedArtifacts();
145142
throw t;
146143
}
147144
finally
@@ -176,8 +173,7 @@ public static TestSuite dynamicSuite(Collection<String> categories, Collection<S
176173
}
177174
catch (Throwable t)
178175
{
179-
LOG.error("Unable to fetch Remote JUnit tests");
180-
t.printStackTrace();
176+
LOG.error("Unable to fetch Remote JUnit tests", t);
181177
TestSuite testSuite = new TestSuite();
182178
testSuite.addTest(new Runner.ErrorTest(JUnitTest.class.getSimpleName(), t));
183179
return testSuite;
@@ -289,7 +285,7 @@ else if (responseBody.contains("<title>Upgrade Status</title>") ||
289285
catch (Throwable t)
290286
{
291287
upgradeError = t;
292-
t.printStackTrace();
288+
LOG.warn("Error during upgrade/bootstrap", t);
293289
}
294290
TestSuite testSuite;
295291
try
@@ -298,7 +294,7 @@ else if (responseBody.contains("<title>Upgrade Status</title>") ||
298294
}
299295
catch (Exception retryException)
300296
{
301-
retryException.printStackTrace();
297+
LOG.warn("Error fetching remote test suite", retryException);
302298
testSuite = new TestSuite();
303299
testSuite.addTest(new Runner.ErrorTest("", retryException));
304300
}
@@ -321,7 +317,7 @@ else if (responseBody.contains("<title>Upgrade Status</title>") ||
321317
for (String key : json.keySet())
322318
{
323319
AtomicInteger ioeCounter = new AtomicInteger(0);
324-
TestSuite testsuite = new TestSuite(key);
320+
TestSuite moduleSuite = new TestSuite(key + " Tests");
325321
JSONArray testClassArray = json.getJSONArray(key);
326322
// Individual tests include both the class name and the requested timeout
327323
for (int i = 0; i < testClassArray.length(); i++)
@@ -334,17 +330,20 @@ else if (responseBody.contains("<title>Upgrade Status</title>") ||
334330
// Timeout is represented in seconds
335331
int timeout = testClass.getInt("timeout");
336332
if (accept.test(testClass.toMap()))
337-
testsuite.addTest(new RemoteTest(className, timeout, ioeCounter));
333+
moduleSuite.addTest(new RemoteTest(className, timeout, ioeCounter));
338334
}
339335

340336
}
341-
if (!addedHeader && testsuite.countTestCases() > 0)
337+
if (moduleSuite.countTestCases() > 0)
342338
{
343-
BaseJUnitTestWrapper.extraSetup = !skipInitialUserChecks;
344-
remotesuite.addTest(new JUnit4TestAdapter(JUnitHeader.class));
345-
addedHeader = true;
339+
if (!addedHeader)
340+
{
341+
BaseJUnitTestWrapper.extraSetup = !skipInitialUserChecks;
342+
remotesuite.addTest(new JUnit4TestAdapter(JUnitHeader.class));
343+
addedHeader = true;
344+
}
345+
remotesuite.addTest(moduleSuite);
346346
}
347-
remotesuite.addTest(testsuite);
348347
}
349348
if (addedHeader)
350349
{

0 commit comments

Comments
 (0)