From 1de8c91fba76fc345dca64cea300839bef436cba Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Sun, 6 Mar 2022 18:39:11 +1000 Subject: [PATCH] MCOMPILER 346 workaround to jdk bug: assertion error from javaxcompiler javax.tools API (#97) * [MCOMPILER-346] use plexus-compiler snapshot to avoid jdk bug add an it for it * use release 2.11.0 of plexus-compilers Signed-off-by: Olivier Lamy --- pom.xml | 2 +- src/it/MCOMPILER-346/invoker.properties | 20 ++ src/it/MCOMPILER-346/pom.xml | 63 ++++++ .../server/PooledJenkinsController.java | 212 ++++++++++++++++++ src/it/MCOMPILER-346/verify.groovy | 25 +++ 5 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 src/it/MCOMPILER-346/invoker.properties create mode 100644 src/it/MCOMPILER-346/pom.xml create mode 100644 src/it/MCOMPILER-346/src/main/java/org/jenkinsci/test/acceptance/server/PooledJenkinsController.java create mode 100644 src/it/MCOMPILER-346/verify.groovy diff --git a/pom.xml b/pom.xml index e2f44427..b21709d0 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ under the License. ! The following property is used in the integration tests MCOMPILER-157 --> 3.5 - 2.10.0 + 2.11.0 2.4.21 3.7.0 diff --git a/src/it/MCOMPILER-346/invoker.properties b/src/it/MCOMPILER-346/invoker.properties new file mode 100644 index 00000000..727ec07c --- /dev/null +++ b/src/it/MCOMPILER-346/invoker.properties @@ -0,0 +1,20 @@ +# 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. + +invoker.java.version = 11+ +invoker.goals = clean compile +invoker.buildResult = failure diff --git a/src/it/MCOMPILER-346/pom.xml b/src/it/MCOMPILER-346/pom.xml new file mode 100644 index 00000000..36907517 --- /dev/null +++ b/src/it/MCOMPILER-346/pom.xml @@ -0,0 +1,63 @@ + + + + + + 4.0.0 + com.basilcrow + MCOMPILER-346-mre + 1.0 + jar + MCOMPILER-346 Minimal Reproducible Example (MRE) + https://github.com/basil/MCOMPILER-346-mre + + UTF-8 + + + + org.eclipse.sisu + org.eclipse.sisu.plexus + 0.2.0 + + + org.jenkins-ci.main + remoting + 3.2 + + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + + org.apache.maven.plugins + maven-compiler-plugin + @project.version@ + + 11 + + + + + diff --git a/src/it/MCOMPILER-346/src/main/java/org/jenkinsci/test/acceptance/server/PooledJenkinsController.java b/src/it/MCOMPILER-346/src/main/java/org/jenkinsci/test/acceptance/server/PooledJenkinsController.java new file mode 100644 index 00000000..f7fbf61f --- /dev/null +++ b/src/it/MCOMPILER-346/src/main/java/org/jenkinsci/test/acceptance/server/PooledJenkinsController.java @@ -0,0 +1,212 @@ +package org.jenkinsci.test.acceptance.server; + +/* + * 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. + */ + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Executors; + +import org.jenkinsci.remoting.RoleChecker; +import org.jenkinsci.test.acceptance.controller.IJenkinsController; +import org.jenkinsci.test.acceptance.controller.JenkinsController; +import org.jenkinsci.test.acceptance.controller.LocalController.LocalFactoryImpl; +import org.jenkinsci.test.acceptance.log.LogListenable; +import org.jenkinsci.test.acceptance.log.LogListener; +import org.jenkinsci.test.acceptance.log.LogSplitter; + +import com.cloudbees.sdk.extensibility.Extension; +import com.google.inject.Injector; + +import hudson.remoting.Callable; +import hudson.remoting.Channel; +import hudson.remoting.Channel.Mode; +import hudson.remoting.ChannelBuilder; +import jnr.unixsocket.UnixSocketAddress; +import jnr.unixsocket.UnixSocketChannel; +import static java.lang.System.*; + +/** + * {@link JenkinsController} that talks to {@link JenkinsControllerPoolProcess} over Unix domain socket. + * + * @author Kohsuke Kawaguchi + */ +public class PooledJenkinsController extends JenkinsController implements LogListenable { + private URL url; + private final File socket; + private UnixSocketChannel conn; + private final LogSplitter splitter = new LogSplitter(); + private Channel channel; + private IJenkinsController controller; + private final List toUnpack = new LinkedList<>(); + + public PooledJenkinsController(Injector i, File socket) { + super(i); + this.socket = socket; + } + + @Override + public void addLogListener(LogListener l) { + splitter.addLogListener(l); + } + + @Override + public void removeLogListener(LogListener l) { + splitter.removeLogListener(l); + } + + private boolean connect() throws IOException { + if (conn != null) return false; + + System.out.println("Requesting jut instance using socket " + socket.getAbsolutePath()); + UnixSocketAddress address = new UnixSocketAddress(socket); + conn = UnixSocketChannel.open(address); + + channel = new ChannelBuilder("JenkinsPool", Executors.newCachedThreadPool()) + .withMode(Mode.BINARY) + .build(ChannelStream.in(conn), ChannelStream.out(conn)); + + try { + controller = (IJenkinsController)channel.waitForRemoteProperty("controller"); + controller.start(); + url = controller.getUrl(); + + if (!isQuite) { + splitter.addLogListener(getLogPrinter()); + } + + final LogListener l = channel.export(LogListener.class, splitter); + channel.call(new InstallLogger(controller,l)); + + for (byte[] content : toUnpack) { + controller.populateJenkinsHome(content, false); + } + toUnpack.clear(); + } catch (InterruptedException e) { + throw new IOException(e); + } + + return true; + } + + @Override + public void startNow() throws IOException { + connect(); + } + + @Override + public void stopNow() throws IOException { + controller.stop(); + } + + @Override + public void populateJenkinsHome(byte[] template, boolean clean) throws IOException { + if (controller != null) { + controller.populateJenkinsHome(template, clean); + } else { + if (clean) { + throw new UnsupportedOperationException("clean mode unsupported for now"); + } + toUnpack.add(template); + } + } + + @Override + public URL getUrl() { + if (url==null) + throw new IllegalStateException("This controller has not been started"); + return url; + } + + @Override + public void tearDown() throws IOException { + channel.close(); + try { + channel.join(3000); + } catch (InterruptedException e) { + throw new IOException(e); + } finally { + if (conn !=null) + conn.close(); + conn = null; + } + } + + @Override + public void diagnose(Throwable cause) { + // TODO: Report jenkins log + cause.printStackTrace(out); + if(getenv("INTERACTIVE") != null && getenv("INTERACTIVE").equals("true")){ + out.println("Commencing interactive debugging. Browser session was kept open."); + out.println("Press return to proceed."); + try { + in.read(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + @Extension + public static class FactoryImpl extends LocalFactoryImpl { + @Inject Injector i; + + @Override + public String getId() { + return "pool"; + } + + @Override + public JenkinsController create() { + return i.getInstance(PooledJenkinsController.class); + } + } + + /** + * Runs on the pool server to install logger. + */ + private static class InstallLogger implements Callable { + private final IJenkinsController controller; + private final LogListener l; + + private InstallLogger(IJenkinsController controller, LogListener l) { + this.controller = controller; + this.l = l; + } + + @Override + public Void call() throws IOException { + if (controller instanceof LogListenable) { + LogListenable ll = (LogListenable) controller; + ll.addLogListener(l); + } + return null; + } + + @Override + public void checkRoles(RoleChecker checker) throws SecurityException { + } + + private static final long serialVersionUID = 1L; + } +} diff --git a/src/it/MCOMPILER-346/verify.groovy b/src/it/MCOMPILER-346/verify.groovy new file mode 100644 index 00000000..837bdd79 --- /dev/null +++ b/src/it/MCOMPILER-346/verify.groovy @@ -0,0 +1,25 @@ +/* + * 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. + */ + +def logFile = new File( basedir, 'build.log' ) +assert logFile.exists() +content = logFile.text + +assert content.contains( 'package org.jenkinsci.test.acceptance.controller does not exist' ) +assert content.contains( 'package org.jenkinsci.test.acceptance.log does not exist' )