Skip to content

Commit 8c74428

Browse files
committed
[MBUILDCACHE-73] Integration test for reconcile expressions
1 parent ff979c4 commit 8c74428

File tree

6 files changed

+431
-0
lines changed

6 files changed

+431
-0
lines changed
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.maven.buildcache.its;
20+
21+
import java.nio.file.Paths;
22+
import java.util.List;
23+
24+
import org.apache.maven.buildcache.its.junit.BeforeEach;
25+
import org.apache.maven.buildcache.its.junit.IntegrationTest;
26+
import org.apache.maven.buildcache.its.junit.IntegrationTestExtension;
27+
import org.apache.maven.it.VerificationException;
28+
import org.apache.maven.it.Verifier;
29+
import org.junit.jupiter.api.Test;
30+
31+
/**
32+
* Integration tests for the reconcile expression feature.
33+
* This feature allows plugin execution cache to depend on arbitrary Maven expressions
34+
* such as ${project.version}, ${project.groupId}, or any custom property.
35+
*/
36+
@IntegrationTest("src/test/projects/reconcile-expressions")
37+
class ReconcileExpressionsTest {
38+
39+
private static final String PROJECT_NAME = "org.apache.maven.caching.test.reconcile:reconcile-expressions";
40+
private static final String RESTORED_MESSAGE = "Found cached build, restoring " + PROJECT_NAME + " from cache";
41+
42+
// start every test case with clear cache
43+
@BeforeEach
44+
void setUp() {
45+
IntegrationTestExtension.deleteDir(Paths.get("target/build-cache/"));
46+
}
47+
/**
48+
* Test basic expression reconciliation - cache should be restored when expressions match.
49+
*/
50+
@Test
51+
void cacheRestoredWhenExpressionsMatch(Verifier verifier) throws VerificationException {
52+
verifier.setAutoclean(false);
53+
54+
// First build - should create cache
55+
verifier.setLogFileName("../log-1.txt");
56+
verifier.executeGoal("compile");
57+
verifier.verifyErrorFreeLog();
58+
verifyTextNotInLog(verifier, RESTORED_MESSAGE);
59+
60+
// Second build with same expressions - should restore from cache
61+
verifier.setLogFileName("../log-2.txt");
62+
verifier.executeGoal("compile");
63+
verifier.verifyErrorFreeLog();
64+
verifier.verifyTextInLog(RESTORED_MESSAGE);
65+
}
66+
67+
/**
68+
* Test that changing project.version invalidates cache through expression reconciliation.
69+
*/
70+
@Test
71+
void cacheInvalidatedWhenVersionChanges(Verifier verifier) throws VerificationException {
72+
verifier.setAutoclean(false);
73+
74+
// First build with initial version
75+
verifier.setLogFileName("../log-version-1.txt");
76+
verifier.executeGoal("compile");
77+
verifier.verifyErrorFreeLog();
78+
verifyTextNotInLog(verifier, RESTORED_MESSAGE);
79+
80+
// Second build - should restore from cache
81+
verifier.setLogFileName("../log-version-2.txt");
82+
verifier.executeGoal("compile");
83+
verifier.verifyErrorFreeLog();
84+
verifier.verifyTextInLog(RESTORED_MESSAGE);
85+
86+
// Change version using versions-maven-plugin
87+
verifier.setLogFileName("../log-version-set.txt");
88+
verifier.getCliOptions().clear();
89+
verifier.addCliOption("-DoldVersion=1.0.0-SNAPSHOT");
90+
verifier.addCliOption("-DnewVersion=2.0.0-SNAPSHOT");
91+
verifier.addCliOption("-DgenerateBackupPoms=false");
92+
verifier.executeGoal("versions:set");
93+
verifier.verifyErrorFreeLog();
94+
95+
// Third build with changed version - cache should be invalidated
96+
verifier.getCliOptions().clear();
97+
verifier.setLogFileName("../log-version-3.txt");
98+
verifier.executeGoal("compile");
99+
verifier.verifyErrorFreeLog();
100+
// The project.version expression changed, so mojo parameters don't match
101+
verifier.verifyTextInLog("Plugin parameter mismatch found");
102+
103+
// Restore original version for other tests
104+
verifier.setLogFileName("../log-version-restore.txt");
105+
verifier.addCliOption("-DoldVersion=2.0.0-SNAPSHOT");
106+
verifier.addCliOption("-DnewVersion=1.0.0-SNAPSHOT");
107+
verifier.addCliOption("-DgenerateBackupPoms=false");
108+
verifier.executeGoal("versions:set");
109+
verifier.verifyErrorFreeLog();
110+
}
111+
112+
/**
113+
* Test that changing a custom property invalidates cache through expression reconciliation.
114+
*/
115+
@Test
116+
void cacheInvalidatedWhenCustomPropertyChanges(Verifier verifier) throws VerificationException {
117+
verifier.setAutoclean(false);
118+
119+
// First build with default product.name
120+
verifier.setLogFileName("../log-prop-1.txt");
121+
verifier.executeGoal("process-resources");
122+
verifier.verifyErrorFreeLog();
123+
verifyTextNotInLog(verifier, RESTORED_MESSAGE);
124+
125+
// Second build with same property - should restore from cache
126+
verifier.setLogFileName("../log-prop-2.txt");
127+
verifier.executeGoal("process-resources");
128+
verifier.verifyErrorFreeLog();
129+
verifier.verifyTextInLog(RESTORED_MESSAGE);
130+
131+
// Third build with different property value via command line
132+
verifier.setLogFileName("../log-prop-3.txt");
133+
verifier.getCliOptions().clear();
134+
verifier.addCliOption("-Dproduct.name=DifferentProduct");
135+
verifier.executeGoal("process-resources");
136+
verifier.verifyErrorFreeLog();
137+
// The property changed, so mojo parameters don't match
138+
verifier.verifyTextInLog("Plugin parameter mismatch found");
139+
}
140+
141+
/**
142+
* Test that multiple expressions are all evaluated correctly.
143+
*/
144+
@Test
145+
void multipleExpressionsEvaluated(Verifier verifier) throws VerificationException {
146+
verifier.setAutoclean(false);
147+
verifier.setMavenDebug(true);
148+
149+
// Build with debug to see expression evaluation
150+
verifier.setLogFileName("../log-multi-1.txt");
151+
verifier.executeGoal("compile");
152+
verifier.verifyErrorFreeLog();
153+
154+
// Verify that the expressions are being tracked
155+
// The build info should contain the evaluated expression values
156+
verifier.setLogFileName("../log-multi-2.txt");
157+
verifier.executeGoal("compile");
158+
verifier.verifyErrorFreeLog();
159+
verifier.verifyTextInLog(RESTORED_MESSAGE);
160+
}
161+
162+
/**
163+
* Test that expressions with undefined properties are handled gracefully.
164+
* When an expression references an undefined property, it should not crash
165+
* and should handle the missing value appropriately.
166+
*/
167+
@Test
168+
void undefinedPropertyInExpressionHandledGracefully(Verifier verifier) throws VerificationException {
169+
verifier.setAutoclean(false);
170+
171+
// First build - expressions with undefined properties should not cause failure
172+
verifier.setLogFileName("../log-undefined-1.txt");
173+
verifier.executeGoal("compile");
174+
verifier.verifyErrorFreeLog();
175+
176+
// Second build - should still work with cache
177+
verifier.setLogFileName("../log-undefined-2.txt");
178+
verifier.executeGoal("compile");
179+
verifier.verifyErrorFreeLog();
180+
}
181+
182+
/**
183+
* Test that expressions correctly track changes across multiple consecutive builds.
184+
*/
185+
@Test
186+
void expressionChangesTrackedAcrossBuilds(Verifier verifier) throws VerificationException {
187+
verifier.setAutoclean(false);
188+
189+
// Build 1: with environment=development (default)
190+
verifier.setLogFileName("../log-track-1.txt");
191+
verifier.executeGoal("process-resources");
192+
verifier.verifyErrorFreeLog();
193+
verifyTextNotInLog(verifier, RESTORED_MESSAGE);
194+
195+
// Build 2: same environment - should use cache
196+
verifier.setLogFileName("../log-track-2.txt");
197+
verifier.executeGoal("process-resources");
198+
verifier.verifyErrorFreeLog();
199+
verifier.verifyTextInLog(RESTORED_MESSAGE);
200+
201+
// Build 3: change to production - should invalidate cache
202+
verifier.setLogFileName("../log-track-3.txt");
203+
verifier.getCliOptions().clear();
204+
verifier.addCliOption("-Dbuild.environment=production");
205+
verifier.executeGoal("process-resources");
206+
verifier.verifyErrorFreeLog();
207+
verifier.verifyTextInLog("Plugin parameter mismatch found");
208+
209+
// Build 4: same production environment - should use cache
210+
verifier.setLogFileName("../log-track-4.txt");
211+
verifier.getCliOptions().clear();
212+
verifier.addCliOption("-Dbuild.environment=production");
213+
verifier.executeGoal("process-resources");
214+
verifier.verifyErrorFreeLog();
215+
// Note: May or may not use cache depending on how the cache key is calculated
216+
// The important thing is it doesn't fail
217+
}
218+
219+
/**
220+
* Test that expressions work correctly with the resources:resources goal.
221+
*/
222+
@Test
223+
void expressionsWorkWithResourcesGoal(Verifier verifier) throws VerificationException {
224+
verifier.setAutoclean(false);
225+
226+
// First build targeting resources specifically
227+
verifier.setLogFileName("../log-resources-1.txt");
228+
verifier.executeGoal("process-resources");
229+
verifier.verifyErrorFreeLog();
230+
231+
// Second build - should restore from cache
232+
verifier.setLogFileName("../log-resources-2.txt");
233+
verifier.executeGoal("process-resources");
234+
verifier.verifyErrorFreeLog();
235+
verifier.verifyTextInLog(RESTORED_MESSAGE);
236+
}
237+
238+
/**
239+
* Helper method to verify that a specific text is NOT present in the log.
240+
*/
241+
private static void verifyTextNotInLog(Verifier verifier, String text) throws VerificationException {
242+
List<String> lines = verifier.loadFile(verifier.getBasedir(), verifier.getLogFileName(), false);
243+
for (String line : lines) {
244+
if (Verifier.stripAnsi(line).contains(text)) {
245+
throw new VerificationException("Text found in log but should not be present: " + text);
246+
}
247+
}
248+
}
249+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright 2021 the original author or authors.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
-->
19+
<extensions>
20+
<extension>
21+
<groupId>org.apache.maven.extensions</groupId>
22+
<artifactId>maven-build-cache-extension</artifactId>
23+
<version>${projectVersion}</version>
24+
</extension>
25+
</extensions>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
3+
<!--
4+
Licensed to the Apache Software Foundation (ASF) under one
5+
or more contributor license agreements. See the NOTICE file
6+
distributed with this work for additional information
7+
regarding copyright ownership. The ASF licenses this file
8+
to you under the Apache License, Version 2.0 (the
9+
"License"); you may not use this file except in compliance
10+
with the License. You may obtain a copy of the License at
11+
12+
http://www.apache.org/licenses/LICENSE-2.0
13+
14+
Unless required by applicable law or agreed to in writing,
15+
software distributed under the License is distributed on an
16+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
KIND, either express or implied. See the License for the
18+
specific language governing permissions and limitations
19+
under the License.
20+
-->
21+
22+
<cache xmlns="http://maven.apache.org/BUILD-CACHE-CONFIG/1.3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
23+
xsi:schemaLocation="http://maven.apache.org/BUILD-CACHE-CONFIG/1.3.0 https://maven.apache.org/xsd/build-cache-config-1.3.0.xsd">
24+
25+
<executionControl>
26+
<reconcile>
27+
<plugins>
28+
<!-- Test expression reconciliation for resources plugin -->
29+
<plugin goal="resources" artifactId="maven-resources-plugin" groupId="org.apache.maven.plugins">
30+
<reconciles>
31+
<!-- Test with project.version expression -->
32+
<reconcile propertyName="project.version" expression="${project.version}"/>
33+
<!-- Test with custom property expression -->
34+
<reconcile propertyName="product.name" expression="${product.name}"/>
35+
<!-- Test with build environment property -->
36+
<reconcile propertyName="build.environment" expression="${build.environment}"/>
37+
</reconciles>
38+
</plugin>
39+
<!-- Test expression reconciliation for compiler plugin -->
40+
<plugin goal="compile" artifactId="maven-compiler-plugin" groupId="org.apache.maven.plugins">
41+
<reconciles>
42+
<!-- Test with project groupId expression -->
43+
<reconcile propertyName="project.groupId" expression="${project.groupId}"/>
44+
<!-- Test with project artifactId expression -->
45+
<reconcile propertyName="project.artifactId" expression="${project.artifactId}"/>
46+
<!-- Test with combined expression using multiple properties -->
47+
<reconcile propertyName="custom.timestamp" expression="${custom.timestamp}"/>
48+
</reconciles>
49+
</plugin>
50+
</plugins>
51+
</reconcile>
52+
</executionControl>
53+
</cache>

0 commit comments

Comments
 (0)