2 * Copyright (c) 2023 PANTHEON.tech s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.odlparent.features.test.plugin;
10 import static org.opendaylight.odlparent.features.test.plugin.DependencyUtils.KARAF_VERSION;
11 import static org.ops4j.pax.exam.CoreOptions.bootDelegationPackages;
12 import static org.ops4j.pax.exam.CoreOptions.maven;
13 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
14 import static org.ops4j.pax.exam.CoreOptions.systemPackages;
15 import static org.ops4j.pax.exam.CoreOptions.when;
16 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
17 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
18 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features;
19 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
20 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
21 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
24 import java.io.IOException;
25 import java.nio.file.Files;
26 import java.nio.file.Path;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import org.apache.maven.plugin.MojoExecutionException;
30 import org.eclipse.aether.artifact.Artifact;
31 import org.ops4j.pax.exam.Option;
32 import org.ops4j.pax.exam.karaf.options.LogLevelOption;
33 import org.ops4j.pax.exam.options.MavenArtifactUrlReference;
34 import org.ops4j.pax.exam.options.extra.VMOption;
36 final class PaxOptionUtils {
38 private PaxOptionUtils() {
42 public static Option[] vmOptions(final String maxHeap, final String heapDumpPath) {
44 new VMOption("-Xmx" + maxHeap),
45 new VMOption("-XX:+HeapDumpOnOutOfMemoryError"),
46 new VMOption("-XX:HeapDumpPath=" + heapDumpPath),
47 // inspired by org.apache.commons.lang.SystemUtils
48 when("Linux".equals(System.getProperty("os.name"))).useOptions(
49 // This prevents low entropy issues on Linux to affect Java random numbers
50 // which can block crypto such as the SSH server in netconf
51 // see https://jira.opendaylight.org/browse/ODLPARENT-49
52 new VMOption("-Djava.security.egd=file:/dev/./urandom")
54 new VMOption("--add-reads=java.xml=java.logging"),
55 new VMOption("--add-exports=java.base/org.apache.karaf.specs.locator=java.xml,ALL-UNNAMED"),
56 new VMOption("--patch-module"),
57 new VMOption("java.base=lib/endorsed/org.apache.karaf.specs.locator-" + KARAF_VERSION + ".jar"),
58 new VMOption("--patch-module"),
59 new VMOption("java.xml=lib/endorsed/org.apache.karaf.specs.java.xml-" + KARAF_VERSION + ".jar"),
60 new VMOption("--add-opens"),
61 new VMOption("java.base/java.security=ALL-UNNAMED"),
62 new VMOption("--add-opens"),
63 new VMOption("java.base/java.net=ALL-UNNAMED"),
64 new VMOption("--add-opens"),
65 new VMOption("java.base/java.lang=ALL-UNNAMED"),
66 new VMOption("--add-opens"),
67 new VMOption("java.base/java.util=ALL-UNNAMED"),
68 new VMOption("--add-opens"),
69 new VMOption("java.naming/javax.naming.spi=ALL-UNNAMED"),
70 new VMOption("--add-opens"),
71 new VMOption("java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"),
72 new VMOption("--add-exports=java.base/sun.net.www.protocol.file=ALL-UNNAMED"),
73 new VMOption("--add-exports=java.base/sun.net.www.protocol.ftp=ALL-UNNAMED"),
74 new VMOption("--add-exports=java.base/sun.net.www.protocol.http=ALL-UNNAMED"),
75 new VMOption("--add-exports=java.base/sun.net.www.protocol.https=ALL-UNNAMED"),
76 new VMOption("--add-exports=java.base/sun.net.www.protocol.jar=ALL-UNNAMED"),
77 new VMOption("--add-exports=java.base/sun.net.www.content.text=ALL-UNNAMED"),
78 new VMOption("--add-exports=jdk.naming.rmi/com.sun.jndi.url.rmi=ALL-UNNAMED"),
79 new VMOption("--add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED"),
80 new VMOption("-classpath"),
81 new VMOption("lib/jdk9plus/*" + File.pathSeparator + "lib/boot/*"
82 + File.pathSeparator + "lib/endorsed/*")
86 static Option[] profileOptions(final boolean profile) throws MojoExecutionException {
89 final var jfrFile = Files.createTempFile("SingleFeatureTest-Karaf-JavaFlightRecorder", ".jfr");
91 new VMOption("-XX:StartFlightRecording=disk=true,settings=profile,dumponexit=true,filename="
92 + jfrFile.toAbsolutePath()),
93 bootDelegationPackages("jdk.jfr", "jdk.jfr.consumer", "jdk.jfr.event", "jdk.jfr.event.handlers",
94 "jdk.jfr.internal.*"),
96 } catch (IOException e) {
97 throw new MojoExecutionException("Failed to create JFR file", e);
100 return new Option[0];
103 static Option[] miscOptions() {
105 // Needed for Agrona/aeron.io
106 systemPackages("com.sun.media.sound", "sun.net", "sun.nio.ch")
110 static Option[] karafDistroOptions(final String url, final boolean keepUnpack, final String buildDir) {
112 karafDistributionConfiguration().frameworkUrl(url)
113 .name("OpenDaylight")
114 .unpackDirectory(new File(buildDir, "pax"))
115 .useDeployFolder(false),
116 when(keepUnpack).useOptions(keepRuntimeFolder()),
117 // configureSecurity().disableKarafMBeanServerBuilder(),
118 configureConsole().ignoreLocalConsole().ignoreRemoteShell(),
122 static Option[] karafConfigOptions(final String buildDir, final String localRepository)
123 throws MojoExecutionException {
124 final var karafLogPath = Path.of(buildDir, "SFT", "karaf.log");
126 Files.createDirectories(karafLogPath.getParent());
127 } catch (IOException e) {
128 throw new MojoExecutionException("Failed to create log directory", e);
131 logLevel(LogLevelOption.LogLevel.INFO),
132 // Make sure karaf's default repository is consulted before anything else
133 editConfigurationFilePut("etc/org.ops4j.pax.url.mvn.cfg", "org.ops4j.pax.url.mvn.defaultRepositories",
134 "file:${karaf.home}/${karaf.default.repository}@id=system.repository"),
135 // remote repository, exclude snapshots
136 editConfigurationFilePut("etc/org.ops4j.pax.url.mvn.cfg", "org.ops4j.pax.url.mvn.repositories",
137 "https://repo1.maven.org/maven2@id=central"),
139 editConfigurationFilePut("etc/org.ops4j.pax.url.mvn.cfg", "org.ops4j.pax.url.mvn.localRepository",
141 // redirect karaf log output
142 editConfigurationFilePut("etc/org.ops4j.pax.logging.cfg", "log4j2.appender.rolling.fileName",
143 karafLogPath.toString()),
144 editConfigurationFilePut("etc/org.ops4j.pax.logging.cfg", "log4j2.appender.rolling.filePattern",
145 karafLogPath + ".%i")
149 static Option[] dependencyFeaturesOptions(final Collection<FeatureDependency> featureDependencies) {
150 return featureDependencies == null ? new Option[0] :
151 featureDependencies.stream()
152 .map(fd -> features(urlReferenceOf(fd.artifact()), fd.featureNames().toArray(String[]::new)))
153 .toArray(Option[]::new);
156 static Option[] probePropertiesOptions() {
157 return new Option[]{propagateSystemProperties(TestProbe.ALL_PROPERTY_KEYS)};
160 private static MavenArtifactUrlReference urlReferenceOf(final Artifact artifact) {
161 return maven().groupId(artifact.getGroupId()).artifactId(artifact.getArtifactId())
162 .type(artifact.getExtension()).classifier(artifact.getClassifier())
163 .version(artifact.getVersion());
166 static Option[] concat(final Option[]... options) {
167 return Arrays.stream(options).flatMap(Arrays::stream).toArray(Option[]::new);