Rework SingleFeatureTest
[odlparent.git] / features-test-plugin / src / main / java / org / opendaylight / odlparent / features / test / plugin / PaxOptionUtils.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech s.r.o. and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.odlparent.features.test.plugin;
9
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;
22
23 import java.io.File;
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;
35
36 final class PaxOptionUtils {
37
38     private PaxOptionUtils() {
39         // utility class
40     }
41
42     public static Option[] vmOptions(final String maxHeap, final String heapDumpPath) {
43         return new Option[]{
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")
53             ),
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/*")
83         };
84     }
85
86     static Option[] profileOptions(final boolean profile) throws MojoExecutionException {
87         if (profile) {
88             try {
89                 final var jfrFile = Files.createTempFile("SingleFeatureTest-Karaf-JavaFlightRecorder", ".jfr");
90                 return new Option[]{
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.*"),
95                 };
96             } catch (IOException e) {
97                 throw new MojoExecutionException("Failed to create JFR file", e);
98             }
99         }
100         return new Option[0];
101     }
102
103     static Option[] miscOptions() {
104         return new Option[]{
105             // Needed for Agrona/aeron.io
106             systemPackages("com.sun.media.sound", "sun.net", "sun.nio.ch")
107         };
108     }
109
110     static Option[] karafDistroOptions(final String url, final boolean keepUnpack, final String buildDir) {
111         return new Option[]{
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(),
119         };
120     }
121
122     static Option[] karafConfigOptions(final String buildDir, final String localRepository)
123             throws MojoExecutionException {
124         final var karafLogPath = Path.of(buildDir, "SFT", "karaf.log");
125         try {
126             Files.createDirectories(karafLogPath.getParent());
127         } catch (IOException e) {
128             throw new MojoExecutionException("Failed to create log directory", e);
129         }
130         return new Option[]{
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"),
138             // local repository
139             editConfigurationFilePut("etc/org.ops4j.pax.url.mvn.cfg", "org.ops4j.pax.url.mvn.localRepository",
140                 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")
146         };
147     }
148
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);
154     }
155
156     static Option[] probePropertiesOptions() {
157         return new Option[]{propagateSystemProperties(TestProbe.ALL_PROPERTY_KEYS)};
158     }
159
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());
164     }
165
166     static Option[] concat(final Option[]... options) {
167         return Arrays.stream(options).flatMap(Arrays::stream).toArray(Option[]::new);
168     }
169 }