Skip to content

Commit afdd607

Browse files
authored
Merge pull request #711 from cqse/ts/42917_service_npe
TS-42917 Ensure partition and clusterId are not null
2 parents 29d41a3 + f9a7493 commit afdd607

15 files changed

Lines changed: 79 additions & 57 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ We use [semantic versioning](http://semver.org/):
55
- PATCH version when you make backwards compatible bug fixes.
66

77
# Next version
8+
- [fix] _agent_: Bad request error when starting a test run in some cases
89

910
# 35.2.0
1011
- [feature] _agent_: Access token can be passed via environment variable `TEAMSCALE_ACCESS_TOKEN`

agent/src/main/java/com/teamscale/jacoco/agent/ResourceBase.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.teamscale.jacoco.agent.logging.LoggingUtils;
77
import com.teamscale.report.testwise.model.RevisionInfo;
88
import org.conqat.lib.commons.string.StringUtils;
9+
import org.jetbrains.annotations.Contract;
910
import org.slf4j.Logger;
1011

1112
import javax.ws.rs.BadRequestException;
@@ -135,6 +136,7 @@ private RevisionInfo getRevisionInfo() {
135136
/**
136137
* Handles bad requests to the endpoints.
137138
*/
139+
@Contract(value = "_ -> fail")
138140
protected void handleBadRequest(String message) throws BadRequestException {
139141
logger.error(message);
140142
throw new BadRequestException(message);

agent/src/main/java/com/teamscale/jacoco/agent/testimpact/CoverageToJsonStrategyBase.java

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
11
package com.teamscale.jacoco.agent.testimpact;
22

3-
import static java.util.stream.Collectors.toList;
4-
5-
import java.io.File;
6-
import java.io.IOException;
7-
import java.util.ArrayList;
8-
import java.util.List;
9-
10-
import org.slf4j.Logger;
11-
123
import com.teamscale.client.ClusteredTestDetails;
134
import com.teamscale.client.JsonUtils;
145
import com.teamscale.client.PrioritizableTestCluster;
156
import com.teamscale.jacoco.agent.JacocoRuntimeController;
16-
import com.teamscale.jacoco.agent.options.AgentOptions;
177
import com.teamscale.jacoco.agent.logging.LoggingUtils;
8+
import com.teamscale.jacoco.agent.options.AgentOptions;
189
import com.teamscale.report.testwise.jacoco.JaCoCoTestwiseReportGenerator;
1910
import com.teamscale.report.testwise.jacoco.cache.CoverageGenerationException;
2011
import com.teamscale.report.testwise.model.TestExecution;
@@ -23,6 +14,14 @@
2314
import com.teamscale.report.testwise.model.TestwiseCoverageReport;
2415
import com.teamscale.report.testwise.model.builder.TestCoverageBuilder;
2516
import com.teamscale.report.testwise.model.builder.TestwiseCoverageReportBuilder;
17+
import org.slf4j.Logger;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
24+
import static java.util.stream.Collectors.toList;
2625

2726
/**
2827
* Base for strategies that produce testwise coverage information in JSON and store or send this data further.
@@ -45,16 +44,16 @@ public abstract class CoverageToJsonStrategyBase extends TestEventHandlerStrateg
4544
private final JaCoCoTestwiseReportGenerator reportGenerator;
4645

4746
public CoverageToJsonStrategyBase(JacocoRuntimeController controller, AgentOptions agentOptions,
48-
JaCoCoTestwiseReportGenerator reportGenerator) {
47+
JaCoCoTestwiseReportGenerator reportGenerator) {
4948
super(agentOptions, controller);
5049
this.reportGenerator = reportGenerator;
5150
}
5251

5352
@Override
5453
public List<PrioritizableTestCluster> testRunStart(List<ClusteredTestDetails> availableTests,
55-
boolean includeNonImpactedTests,
56-
boolean includeAddedTests, boolean includeFailedAndSkipped,
57-
String baseline, String baselineRevision) throws IOException {
54+
boolean includeNonImpactedTests,
55+
boolean includeAddedTests, boolean includeFailedAndSkipped,
56+
String baseline, String baselineRevision) throws IOException {
5857
if (availableTests != null) {
5958
this.availableTests = new ArrayList<>(availableTests);
6059
}
@@ -65,17 +64,16 @@ public List<PrioritizableTestCluster> testRunStart(List<ClusteredTestDetails> av
6564
@Override
6665
public void testStart(String uniformPath) {
6766
super.testStart(uniformPath);
68-
6967
if (availableTests.stream().noneMatch(test -> test.uniformPath.equals(uniformPath))) {
7068
// ensure that we can at least generate a report for the tests that were actually run,
7169
// even if the caller did not provide a list of tests up-front in testRunStart
72-
availableTests.add(new ClusteredTestDetails(uniformPath, uniformPath, null, null, null));
70+
availableTests.add(new ClusteredTestDetails(uniformPath, uniformPath, null, null));
7371
}
7472
}
7573

7674
@Override
7775
public TestInfo testEnd(String test,
78-
TestExecution testExecution) throws JacocoRuntimeController.DumpException, CoverageGenerationException {
76+
TestExecution testExecution) throws JacocoRuntimeController.DumpException, CoverageGenerationException {
7977
super.testEnd(test, testExecution);
8078
if (testExecution != null) {
8179
testExecutions.add(testExecution);
@@ -100,6 +98,7 @@ public TestInfo testEnd(String test,
10098
public void testRunEnd(boolean partial) throws IOException, CoverageGenerationException {
10199
if (testExecFile == null) {
102100
logger.warn("Tried to end a test run that contained no tests!");
101+
clearTestRun();
103102
return;
104103
}
105104

@@ -132,16 +131,22 @@ private String createTestwiseCoverageReport(boolean partial) throws IOException,
132131
reportGenerator.updateClassDirCache();
133132
TestwiseCoverage testwiseCoverage = reportGenerator.convert(testExecFile);
134133
logger.debug("Created testwise coverage report (containing coverage for tests `{}`)",
135-
testwiseCoverage.getTests().values().stream().map(TestCoverageBuilder::getUniformPath).collect(toList()));
134+
testwiseCoverage.getTests().values().stream().map(TestCoverageBuilder::getUniformPath)
135+
.collect(toList()));
136136

137-
TestwiseCoverageReport report = TestwiseCoverageReportBuilder.createFrom(availableTests, testwiseCoverage.getTests().values(), testExecutions, partial);
137+
TestwiseCoverageReport report = TestwiseCoverageReportBuilder.createFrom(availableTests,
138+
testwiseCoverage.getTests().values(), testExecutions, partial);
138139

139140
testExecFile.delete();
140141
testExecFile = null;
141-
availableTests.clear();
142-
testExecutions.clear();
142+
clearTestRun();
143143

144144
return JsonUtils.serializeToJson(report);
145145
}
146146

147+
private void clearTestRun() {
148+
availableTests.clear();
149+
testExecutions.clear();
150+
}
151+
147152
}

agent/src/main/java/com/teamscale/jacoco/agent/testimpact/TestEventHandlerStrategyBase.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.teamscale.client.HttpUtils;
55
import com.teamscale.client.PrioritizableTestCluster;
66
import com.teamscale.client.TeamscaleClient;
7+
import com.teamscale.client.TestWithClusterId;
78
import com.teamscale.jacoco.agent.JacocoRuntimeController;
89
import com.teamscale.jacoco.agent.logging.LoggingUtils;
910
import com.teamscale.jacoco.agent.options.AgentOptions;
@@ -17,6 +18,7 @@
1718
import java.io.IOException;
1819
import java.util.Collections;
1920
import java.util.List;
21+
import java.util.stream.Collectors;
2022

2123
/** Base class for strategies to handle test events. */
2224
public abstract class TestEventHandlerStrategyBase {
@@ -88,15 +90,20 @@ public List<PrioritizableTestCluster> testRunStart(List<ClusteredTestDetails> av
8890
boolean includeAddedTests, boolean includeFailedAndSkipped,
8991
String baseline, String baselineRevision) throws IOException {
9092
int availableTestCount = 0;
93+
List<TestWithClusterId> availableTestsWithClusterId = null;
9194
if (availableTests != null) {
9295
availableTestCount = availableTests.size();
96+
availableTestsWithClusterId = availableTests.stream()
97+
.map(availableTest -> TestWithClusterId.Companion.fromClusteredTestDetails(availableTest, getPartition()))
98+
.collect(
99+
Collectors.toList());
93100
}
94101
logger.debug("Test run started with {} available tests. baseline = {}, includeNonImpactedTests = {}",
95102
availableTestCount, baseline, includeNonImpactedTests);
96103
validateConfiguration();
97104

98105
Response<List<PrioritizableTestCluster>> response = teamscaleClient
99-
.getImpactedTests(availableTests, baseline, baselineRevision,
106+
.getImpactedTests(availableTestsWithClusterId, baseline, baselineRevision,
100107
agentOptions.getTeamscaleServerOptions().commit,
101108
agentOptions.getTeamscaleServerOptions().revision,
102109
agentOptions.getTeamscaleServerOptions().repository,
@@ -114,6 +121,18 @@ public List<PrioritizableTestCluster> testRunStart(List<ClusteredTestDetails> av
114121
}
115122
}
116123

124+
/**
125+
* Returns the partition defined in the agent options. Asserts that the partition is defined.
126+
*/
127+
private String getPartition() {
128+
String partition = agentOptions.getTeamscaleServerOptions().partition;
129+
if (partition == null) {
130+
throw new UnsupportedOperationException(
131+
"You must provide a partition via the agent's '" + TeamscaleConfig.TEAMSCALE_PARTITION_OPTION + "' option or using the /partition REST endpoint.");
132+
}
133+
return partition;
134+
}
135+
117136
private void validateConfiguration() {
118137
if (teamscaleClient == null) {
119138
throw new UnsupportedOperationException("You did not configure a connection to Teamscale in the agent." +

agent/src/main/java/com/teamscale/jacoco/agent/upload/teamscale/TeamscaleConfig.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public class TeamscaleConfig {
3232
/** Option name that allows to specify a jar file that contains the branch name and timestamp in a MANIFEST.MF file. */
3333
public static final String TEAMSCALE_COMMIT_MANIFEST_JAR_OPTION = "teamscale-commit-manifest-jar";
3434

35+
/** Option name that allows to specify a partition to which coverage should be uploaded to. */
36+
public static final String TEAMSCALE_PARTITION_OPTION = "teamscale-partition";
37+
3538
private final ILogger logger;
3639
private final FilePatternResolver filePatternResolver;
3740

@@ -61,7 +64,7 @@ public boolean handleTeamscaleOptions(TeamscaleServer teamscaleServer,
6164
case "teamscale-access-token":
6265
teamscaleServer.userAccessToken = value;
6366
return true;
64-
case "teamscale-partition":
67+
case TEAMSCALE_PARTITION_OPTION:
6568
teamscaleServer.partition = value;
6669
return true;
6770
case TEAMSCALE_COMMIT_OPTION:

agent/src/test/java/com/teamscale/jacoco/agent/testimpact/CoverageToTeamscaleStrategyTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public void testValidCallSequence(boolean useRevision) throws Exception {
9090

9191
strategy.testRunStart(
9292
Collections.singletonList(
93-
new ClusteredTestDetails("mytest", "mytest", "content", "cluster", "partition")), false,
93+
new ClusteredTestDetails("mytest", "mytest", "content", "cluster")), false,
9494
true, true,
9595
null, null);
9696
strategy.testStart("mytest");

agent/src/test/java/com/teamscale/jacoco/agent/testimpact/TestwiseCoverageAgentTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ public class TestwiseCoverageAgentTest {
6464
@Test
6565
public void testAccessViaTiaClientAndReportUploadToTeamscale() throws Exception {
6666
List<ClusteredTestDetails> availableTests = Arrays
67-
.asList(new ClusteredTestDetails("test1", "test1", "content", "cluster", "partition"),
68-
new ClusteredTestDetails("test2", "test2", "content", "cluster", "partition"));
67+
.asList(new ClusteredTestDetails("test1", "test1", "content", "cluster"),
68+
new ClusteredTestDetails("test2", "test2", "content", "cluster"));
6969
List<PrioritizableTestCluster> impactedClusters = Collections
7070
.singletonList(new PrioritizableTestCluster("cluster",
7171
Collections.singletonList(new PrioritizableTest("test2"))));

impacted-test-engine/src/main/kotlin/com/teamscale/test_impacted/engine/InternalImpactedTestEngine.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ internal class InternalImpactedTestEngine(
6666
*/
6767
fun execute(request: ExecutionRequest) {
6868
val rootTestDescriptor = request.rootTestDescriptor
69-
val availableTests = getAvailableTests(rootTestDescriptor, partition)
69+
val availableTests = getAvailableTests(rootTestDescriptor)
7070

7171
LOG.fine {
7272
"Starting selection and sorting ${ImpactedTestEngine.ENGINE_ID}:\n${

impacted-test-engine/src/main/kotlin/com/teamscale/test_impacted/engine/executor/ImpactedTestsProvider.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.teamscale.test_impacted.engine.executor
22

3-
import com.teamscale.client.ClusteredTestDetails
43
import com.teamscale.client.CommitDescriptor
54
import com.teamscale.client.PrioritizableTestCluster
65
import com.teamscale.client.TeamscaleClient
6+
import com.teamscale.client.TestWithClusterId
77
import com.teamscale.test_impacted.commons.LoggerUtils.createLogger
88
import retrofit2.Response
99
import java.io.IOException
@@ -37,7 +37,7 @@ open class ImpactedTestsProvider(
3737
) {
3838
/** Queries Teamscale for impacted tests. */
3939
fun getImpactedTestsFromTeamscale(
40-
availableTestDetails: List<ClusteredTestDetails>
40+
availableTestDetails: List<TestWithClusterId>
4141
): List<PrioritizableTestCluster>? {
4242
try {
4343
LOG.info { "Getting impacted tests..." }
@@ -73,7 +73,7 @@ open class ImpactedTestsProvider(
7373
*/
7474
private fun testCountIsPlausible(
7575
testClusters: List<PrioritizableTestCluster>,
76-
availableTestDetails: List<ClusteredTestDetails>
76+
availableTestDetails: List<TestWithClusterId>
7777
): Boolean {
7878
val returnedTests = testClusters.stream().mapToLong {
7979
it.tests?.size?.toLong() ?: 0

impacted-test-engine/src/main/kotlin/com/teamscale/test_impacted/engine/executor/ImpactedTestsSorter.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
package com.teamscale.test_impacted.engine.executor
22

3+
import com.teamscale.client.TestWithClusterId.Companion.fromClusteredTestDetails
34
import com.teamscale.test_impacted.engine.ImpactedTestEngine
45
import com.teamscale.test_impacted.test_descriptor.TestDescriptorUtils.getAvailableTests
56
import org.junit.platform.engine.TestDescriptor
67
import java.util.*
78

89
/**
9-
* Test sorter that requests impacted tests from Teamscale and rewrites the [TestDescriptor] to take the returned
10-
* order into account when executing the tests.
11-
*/
10+
* Test sorter that requests impacted tests from Teamscale and rewrites the [TestDescriptor] to take the returned
11+
* order into account when executing the tests.
12+
*/
1213
class ImpactedTestsSorter(private val impactedTestsProvider: ImpactedTestsProvider) : ITestSorter {
1314

1415
override fun selectAndSort(testDescriptor: TestDescriptor) {
15-
val availableTests = getAvailableTests(testDescriptor, impactedTestsProvider.partition)
16+
val availableTests = getAvailableTests(testDescriptor)
1617

17-
val testClusters = impactedTestsProvider.getImpactedTestsFromTeamscale(availableTests.testList)
18+
val testClusters = impactedTestsProvider.getImpactedTestsFromTeamscale(
19+
availableTests.testList
20+
.map { fromClusteredTestDetails(it, impactedTestsProvider.partition) })
1821

1922
if (testClusters == null) {
2023
ImpactedTestEngine.LOG.fine { "Falling back to execute all!" }

0 commit comments

Comments
 (0)