You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2023/06/01 06:43:16 UTC

[maven-build-cache-extension] branch master updated: [MBUILDCACHE-25] Fixes N+1 cache processings for forked executions (#34)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-build-cache-extension.git


The following commit(s) were added to refs/heads/master by this push:
     new 481fec0  [MBUILDCACHE-25] Fixes N+1 cache processings for forked executions (#34)
481fec0 is described below

commit 481fec0bd313d2c44a11de0d450507658df43242
Author: Alex Ashitkin <as...@gmail.com>
AuthorDate: Thu Jun 1 02:43:10 2023 -0400

    [MBUILDCACHE-25] Fixes N+1 cache processings for forked executions (#34)
    
    Co-authored-by: aashitki <al...@db.com>
    Co-authored-by: Guillaume Nodet <gn...@gmail.com>
---
 pom.xml                                            |  17 ++++
 .../BuildCacheMojosExecutionStrategy.java          |   7 +-
 .../maven/buildcache/LifecyclePhasesHelper.java    |   4 +
 .../its/ForkedExecutionCoreExtensionTest.java      |  24 ++++-
 .../maven/buildcache/its/ForkedExecutionsTest.java | 104 +++++++++++++++++++++
 .../.mvn/extensions.xml                            |  25 +++++
 .../.mvn/maven-build-cache-config.xml              |  28 ++++++
 .../pom.xml                                        |  26 +-----
 .../maven/buildcache/ForkedExecutionClass.java     |  24 +++++
 .../forked-executions-core-extension/pom.xml       |  25 -----
 10 files changed, 229 insertions(+), 55 deletions(-)

diff --git a/pom.xml b/pom.xml
index 2c201cd..5fe6854 100644
--- a/pom.xml
+++ b/pom.xml
@@ -81,6 +81,7 @@ under the License.
     <jxpathVersion>1.3</jxpathVersion>
     <resolverVersion>1.9.7</resolverVersion>
     <slf4jVersion>1.7.32</slf4jVersion>
+    <wiremockVersion>2.35.0</wiremockVersion>
     <xmlunitVersion>2.6.4</xmlunitVersion>
     <maven.test.redirectTestOutputToFile>true</maven.test.redirectTestOutputToFile>
     <maven.site.path>extensions-archives/${project.artifactId}-LATEST</maven.site.path>
@@ -233,6 +234,22 @@ under the License.
       <version>${mockitoVersion}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.github.tomakehurst</groupId>
+      <artifactId>wiremock-jre8</artifactId>
+      <version>${wiremockVersion}</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-alpn-java-client</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-alpn-java-server</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java b/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java
index 0505b17..c9af6c7 100644
--- a/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java
+++ b/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java
@@ -100,7 +100,10 @@ public class BuildCacheMojosExecutionStrategy implements MojosExecutionStrategy
         CacheResult result = CacheResult.empty();
         boolean skipCache = cacheConfig.isSkipCache() || MavenProjectInput.isSkipCache(project);
         boolean cacheIsDisabled = MavenProjectInput.isCacheDisabled(project);
-        if (source == Source.LIFECYCLE) {
+        // Forked execution should be thought as a part of originating mojo internal implementation
+        // If forkedExecution is detected, it means that originating mojo is not cached so forks should rerun too
+        boolean forkedExecution = lifecyclePhasesHelper.isForkedProject(project);
+        if (source == Source.LIFECYCLE && !forkedExecution) {
             List<MojoExecution> cleanPhase = lifecyclePhasesHelper.getCleanSegment(project, mojoExecutions);
             for (MojoExecution mojoExecution : cleanPhase) {
                 mojoExecutionRunner.run(mojoExecution);
@@ -134,7 +137,7 @@ public class BuildCacheMojosExecutionStrategy implements MojosExecutionStrategy
             cacheController.save(result, mojoExecutions, executionEvents);
         }
 
-        if (cacheConfig.isFailFast() && !result.isSuccess() && !skipCache) {
+        if (cacheConfig.isFailFast() && !result.isSuccess() && !skipCache && !forkedExecution) {
             throw new LifecycleExecutionException(
                     "Failed to restore project[" + getVersionlessProjectKey(project) + "] from cache, failing build.",
                     project);
diff --git a/src/main/java/org/apache/maven/buildcache/LifecyclePhasesHelper.java b/src/main/java/org/apache/maven/buildcache/LifecyclePhasesHelper.java
index 33d8a3e..c37facc 100644
--- a/src/main/java/org/apache/maven/buildcache/LifecyclePhasesHelper.java
+++ b/src/main/java/org/apache/maven/buildcache/LifecyclePhasesHelper.java
@@ -213,4 +213,8 @@ public class LifecyclePhasesHelper extends AbstractExecutionListener {
         }
         return list;
     }
+
+    public boolean isForkedProject(MavenProject project) {
+        return forkedProjectToOrigin.containsKey(project);
+    }
 }
diff --git a/src/test/java/org/apache/maven/buildcache/its/ForkedExecutionCoreExtensionTest.java b/src/test/java/org/apache/maven/buildcache/its/ForkedExecutionCoreExtensionTest.java
index 6972e84..d111834 100644
--- a/src/test/java/org/apache/maven/buildcache/its/ForkedExecutionCoreExtensionTest.java
+++ b/src/test/java/org/apache/maven/buildcache/its/ForkedExecutionCoreExtensionTest.java
@@ -32,6 +32,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.apache.maven.buildcache.xml.CacheConfigImpl.CACHE_LOCATION_PROPERTY_NAME;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 /**
  * Runs project which contains plugin with forked execution - pmd
@@ -63,16 +64,33 @@ public class ForkedExecutionCoreExtensionTest {
                 Lists.newArrayList("-D" + CACHE_LOCATION_PROPERTY_NAME + "=" + tempDirectory.toAbsolutePath()));
         verifier.executeGoal("verify");
         verifier.verifyTextInLog("Started forked project");
+        // forked execution actually runs
         verifier.verifyTextInLog(
-                "Mojo execution pmd:pmd:emptyLifecyclePhase:maven-pmd-plugin:org.apache.maven.plugins is forked,"
-                        + " returning phase verify from originating mojo "
-                        + "default:check:verify:maven-pmd-plugin:org.apache.maven.plugins");
+                "[DEBUG] Starting mojo execution: pmd:pmd:emptyLifecyclePhase:maven-pmd-plugin:org.apache.maven.plugins");
+        // checking that forked execution doesn't hook into lifecycle
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(
+                        "Mojo execution pmd:pmd:emptyLifecyclePhase:maven-pmd-plugin:org.apache.maven.plugins is forked,"
+                                + " returning phase verify from originating mojo "
+                                + "default:check:verify:maven-pmd-plugin:org.apache.maven.plugins"));
         verifier.verifyTextInLog("[INFO] BUILD SUCCESS");
 
         verifier.setLogFileName("../log-2.txt");
         verifier.executeGoal("verify");
         verifier.verifyErrorFreeLog();
         verifier.verifyTextInLog("Found cached build, restoring " + PROJECT_NAME + " from cache");
+        // checking that fork originating mojo pmd:check is cached
+        verifier.verifyTextInLog("[INFO] Skipping plugin execution (cached): pmd:check");
+        // and because of that forked execution pmd:pmd didn't run
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog(
+                        "[DEBUG] Starting mojo execution: pmd:pmd:emptyLifecyclePhase:maven-pmd-plugin:org.apache.maven.plugins"));
+        // and didn't appear in cache lifecycle
+        assertThrows(
+                VerificationException.class,
+                () -> verifier.verifyTextInLog("[INFO] Skipping plugin execution (cached): pmd:pmd"));
         verifier.verifyTextInLog("[INFO] BUILD SUCCESS");
     }
 }
diff --git a/src/test/java/org/apache/maven/buildcache/its/ForkedExecutionsTest.java b/src/test/java/org/apache/maven/buildcache/its/ForkedExecutionsTest.java
new file mode 100644
index 0000000..627dd8a
--- /dev/null
+++ b/src/test/java/org/apache/maven/buildcache/its/ForkedExecutionsTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.buildcache.its;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
+import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
+import com.github.tomakehurst.wiremock.matching.UrlPathPattern;
+import com.google.common.collect.Lists;
+import org.apache.commons.io.FileUtils;
+import org.apache.maven.buildcache.its.junit.IntegrationTest;
+import org.apache.maven.it.VerificationException;
+import org.apache.maven.it.Verifier;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.exactly;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.notFound;
+import static com.github.tomakehurst.wiremock.client.WireMock.ok;
+import static com.github.tomakehurst.wiremock.client.WireMock.put;
+import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+
+/**
+ * Verifies MBUILDCACHE-25 - build cache calculated and saved exactly once in presence of forked executions
+ */
+@IntegrationTest("src/test/projects/forked-executions-core-extension-remote")
+public class ForkedExecutionsTest {
+
+    private static final String PROJECT_NAME = "org.apache.maven.caching.test.simple:forked-executions-core-extension";
+
+    @RegisterExtension
+    static WireMockExtension wm = WireMockExtension.newInstance()
+            .options(wireMockConfig().dynamicPort().notifier(new ConsoleNotifier(true)))
+            .build();
+
+    private Path tempDirectory;
+
+    @BeforeEach
+    void setUp() throws IOException {
+        tempDirectory = Files.createTempDirectory("build-cache-test-");
+    }
+
+    @AfterEach
+    void tearDown() throws IOException {
+        FileUtils.deleteDirectory(tempDirectory.toFile());
+    }
+
+    @Test
+    void testForkedExecution(Verifier verifier) throws VerificationException {
+
+        UrlPathPattern buildInfoPath = urlPathMatching(".*/buildinfo.xml");
+        wm.stubFor(get(buildInfoPath).willReturn(notFound()));
+        wm.stubFor(put(buildInfoPath).willReturn(ok()));
+
+        UrlPathPattern jarPath = urlPathMatching(".*/forked-executions-core-extension-remote.jar");
+        wm.stubFor(put(jarPath).willReturn(ok()));
+
+        UrlPathPattern cacheReportPath = urlPathMatching(".*/build-cache-report.xml");
+        wm.stubFor(put(cacheReportPath).willReturn(ok()));
+
+        verifier.setAutoclean(false);
+
+        verifier.setLogFileName("../log-1.txt");
+        verifier.setMavenDebug(true);
+        verifier.setCliOptions(Lists.newArrayList(
+                "-Dmaven.build.cache.location=" + tempDirectory.toAbsolutePath(),
+                "-Dmaven.build.cache.remote.url=http:////localhost:"
+                        + wm.getRuntimeInfo().getHttpPort(),
+                "-Dmaven.build.cache.remote.save.enabled=true"));
+        verifier.executeGoal("verify");
+        verifier.verifyTextInLog("Started forked project");
+        verifier.verifyTextInLog("BUILD SUCCESS");
+
+        wm.verify(exactly(1), getRequestedFor(buildInfoPath));
+        wm.verify(exactly(1), putRequestedFor(buildInfoPath));
+        wm.verify(exactly(1), putRequestedFor(jarPath));
+        wm.verify(exactly(1), putRequestedFor(cacheReportPath));
+    }
+}
diff --git a/src/test/projects/forked-executions-core-extension-remote/.mvn/extensions.xml b/src/test/projects/forked-executions-core-extension-remote/.mvn/extensions.xml
new file mode 100644
index 0000000..8df78f8
--- /dev/null
+++ b/src/test/projects/forked-executions-core-extension-remote/.mvn/extensions.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright 2021 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<extensions>
+    <extension>
+        <groupId>org.apache.maven.extensions</groupId>
+        <artifactId>maven-build-cache-extension</artifactId>
+        <version>${projectVersion}</version>
+    </extension>
+</extensions>
diff --git a/src/test/projects/forked-executions-core-extension-remote/.mvn/maven-build-cache-config.xml b/src/test/projects/forked-executions-core-extension-remote/.mvn/maven-build-cache-config.xml
new file mode 100644
index 0000000..573de40
--- /dev/null
+++ b/src/test/projects/forked-executions-core-extension-remote/.mvn/maven-build-cache-config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<cache xmlns="http://maven.apache.org/BUILD-CACHE-CONFIG/1.0.0">
+    <configuration>
+        <remote>
+            <url>http://to-be-overridden-on-cli-and-point-to-wiremock</url>
+        </remote>
+    </configuration>
+</cache>
diff --git a/src/test/projects/forked-executions-core-extension/pom.xml b/src/test/projects/forked-executions-core-extension-remote/pom.xml
similarity index 59%
copy from src/test/projects/forked-executions-core-extension/pom.xml
copy to src/test/projects/forked-executions-core-extension-remote/pom.xml
index 5069341..ebc9a69 100644
--- a/src/test/projects/forked-executions-core-extension/pom.xml
+++ b/src/test/projects/forked-executions-core-extension-remote/pom.xml
@@ -20,7 +20,7 @@
 
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.apache.maven.caching.test.simple</groupId>
-    <artifactId>forked-executions-core-extension</artifactId>
+    <artifactId>forked-executions-core-extension-remote</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <packaging>jar</packaging>
 
@@ -51,31 +51,7 @@
                     </dependency>
                 </dependencies>
             </plugin>
-<!--            [WARNING] The POM for org.apache.maven.wagon:wagon-http:jar:1.0-beta-6 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for /Users/aashitki/.m2/repository/org/apache/maven/wagon/wagon-http/1.0-beta-6/wagon-http-1.0-beta-6.pom-->
-<!--            <plugin>-->
-<!--                <groupId>org.apache.maven.wagon</groupId>-->
-<!--                <artifactId>wagon-http</artifactId>-->
-<!--                <version>3.5.2</version>-->
-<!--            </plugin>-->
-<!--            <plugin>-->
-<!--                <groupId>org.apache.maven.wagon</groupId>-->
-<!--                <artifactId>wagon-http-shared</artifactId>-->
-<!--                <version>3.5.2</version>-->
-<!--            </plugin>-->
         </plugins>
     </build>
 
-<!--    <dependencies>-->
-<!--        <dependency>-->
-<!--            <groupId>org.apache.maven.wagon</groupId>-->
-<!--            <artifactId>wagon-http</artifactId>-->
-<!--            <version>3.5.2</version>-->
-<!--        </dependency>-->
-<!--        <dependency>-->
-<!--            <groupId>org.apache.maven.wagon</groupId>-->
-<!--            <artifactId>wagon-http-shared</artifactId>-->
-<!--            <version>3.5.2</version>-->
-<!--        </dependency>-->
-<!--    </dependencies>-->
-
 </project>
\ No newline at end of file
diff --git a/src/test/projects/forked-executions-core-extension-remote/src/main/java/org/apache/maven/buildcache/ForkedExecutionClass.java b/src/test/projects/forked-executions-core-extension-remote/src/main/java/org/apache/maven/buildcache/ForkedExecutionClass.java
new file mode 100644
index 0000000..920b9f9
--- /dev/null
+++ b/src/test/projects/forked-executions-core-extension-remote/src/main/java/org/apache/maven/buildcache/ForkedExecutionClass.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.buildcache;
+
+class ForkedExecutionClass
+{
+
+}
\ No newline at end of file
diff --git a/src/test/projects/forked-executions-core-extension/pom.xml b/src/test/projects/forked-executions-core-extension/pom.xml
index 5069341..0effb24 100644
--- a/src/test/projects/forked-executions-core-extension/pom.xml
+++ b/src/test/projects/forked-executions-core-extension/pom.xml
@@ -51,31 +51,6 @@
                     </dependency>
                 </dependencies>
             </plugin>
-<!--            [WARNING] The POM for org.apache.maven.wagon:wagon-http:jar:1.0-beta-6 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for /Users/aashitki/.m2/repository/org/apache/maven/wagon/wagon-http/1.0-beta-6/wagon-http-1.0-beta-6.pom-->
-<!--            <plugin>-->
-<!--                <groupId>org.apache.maven.wagon</groupId>-->
-<!--                <artifactId>wagon-http</artifactId>-->
-<!--                <version>3.5.2</version>-->
-<!--            </plugin>-->
-<!--            <plugin>-->
-<!--                <groupId>org.apache.maven.wagon</groupId>-->
-<!--                <artifactId>wagon-http-shared</artifactId>-->
-<!--                <version>3.5.2</version>-->
-<!--            </plugin>-->
         </plugins>
     </build>
-
-<!--    <dependencies>-->
-<!--        <dependency>-->
-<!--            <groupId>org.apache.maven.wagon</groupId>-->
-<!--            <artifactId>wagon-http</artifactId>-->
-<!--            <version>3.5.2</version>-->
-<!--        </dependency>-->
-<!--        <dependency>-->
-<!--            <groupId>org.apache.maven.wagon</groupId>-->
-<!--            <artifactId>wagon-http-shared</artifactId>-->
-<!--            <version>3.5.2</version>-->
-<!--        </dependency>-->
-<!--    </dependencies>-->
-
 </project>
\ No newline at end of file