Support running base testsuite on Windows
Closes #12648 Co-authored-by: Dominik Guhr <dguhr@redhat.com>
This commit is contained in:
parent
fa383bf76c
commit
e3af0610e2
7 changed files with 109 additions and 17 deletions
|
@ -41,8 +41,8 @@ public final class Environment {
|
|||
public static final String IMPORT_EXPORT_MODE = "import_export";
|
||||
public static final String PROFILE ="kc.profile";
|
||||
public static final String ENV_PROFILE ="KC_PROFILE";
|
||||
public static final String DATA_PATH = "/data";
|
||||
public static final String DEFAULT_THEMES_PATH = "/themes";
|
||||
public static final String DATA_PATH = File.separator + "data";
|
||||
public static final String DEFAULT_THEMES_PATH = File.separator + "themes";
|
||||
public static final String DEV_PROFILE_VALUE = "dev";
|
||||
public static final String PROD_PROFILE_VALUE = "prod";
|
||||
public static final String LAUNCH_MODE = "kc.launch.mode";
|
||||
|
|
|
@ -8,6 +8,7 @@ import io.smallrye.config.ConfigSourceInterceptorContext;
|
|||
import static java.util.Optional.of;
|
||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Optional;
|
||||
|
||||
final class CachingPropertyMappers {
|
||||
|
@ -46,7 +47,7 @@ final class CachingPropertyMappers {
|
|||
if (homeDir == null) {
|
||||
pathPrefix = "";
|
||||
} else {
|
||||
pathPrefix = homeDir + "/conf/";
|
||||
pathPrefix = homeDir + File.separator + "conf" + File.separator;
|
||||
}
|
||||
|
||||
return of(pathPrefix + value.get());
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<shrinkwrap-resolver.version>3.1.4</shrinkwrap-resolver.version>
|
||||
<selenium.version>3.14.0</selenium.version>
|
||||
<arquillian-drone.version>2.5.5</arquillian-drone.version>
|
||||
<arquillian-graphene.version>2.5.4</arquillian-graphene.version>
|
||||
<arquillian-graphene.version>3.0.0-alpha.3</arquillian-graphene.version>
|
||||
<arquillian-wildfly-container.version>3.0.1.Final</arquillian-wildfly-container.version>
|
||||
<arquillian-wls-container.version>1.0.1.Final</arquillian-wls-container.version>
|
||||
<arquillian-jetty9-container.version>1.0.0.CR3</arquillian-jetty9-container.version>
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
<arg value="--http-relative-path=/auth"/>
|
||||
<arg value="--cache=local"/>
|
||||
</exec>
|
||||
<exec osfamily="windows" executable="${auth.server.home}/bin/kc.bat" failonerror="true">
|
||||
<arg value="build"/>
|
||||
<arg value="--http-relative-path=/auth"/>
|
||||
<arg value="--cache=local"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<macrodef name="bin-chmod">
|
||||
|
|
|
@ -46,4 +46,4 @@ spi-login-protocol-saml-known-protocols=http=8180,https=8543
|
|||
|
||||
# File-Based Vault
|
||||
vault=file
|
||||
vault-dir=${kc.home.dir}secrets
|
||||
vault-dir=${kc.home.dir}/secrets
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
<mvel.version>2.4.0.Final</mvel.version>
|
||||
<systemrules.version>1.19.0</systemrules.version>
|
||||
<common.resources>${basedir}/../../servers/auth-server/jboss/common</common.resources>
|
||||
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -365,7 +369,10 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
|
|
@ -14,21 +14,26 @@ import java.net.HttpURLConnection;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.exec.StreamPumper;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
|
||||
import org.jboss.arquillian.container.spi.client.container.DeploymentException;
|
||||
|
@ -48,6 +53,7 @@ import org.keycloak.testsuite.arquillian.SuiteContext;
|
|||
*/
|
||||
public class KeycloakQuarkusServerDeployableContainer implements DeployableContainer<KeycloakQuarkusConfiguration> {
|
||||
|
||||
private static final int DEFAULT_SHUTDOWN_TIMEOUT_SECONDS = 10;
|
||||
private static final String AUTH_SERVER_QUARKUS_MAP_STORAGE_PROFILE = "auth.server.quarkus.mapStorage.profile";
|
||||
|
||||
private static final Logger log = Logger.getLogger(KeycloakQuarkusServerDeployableContainer.class);
|
||||
|
@ -87,11 +93,15 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
|||
|
||||
@Override
|
||||
public void stop() throws LifecycleException {
|
||||
container.destroy();
|
||||
try {
|
||||
container.waitFor(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
container.destroyForcibly();
|
||||
if (container.isAlive()) {
|
||||
try {
|
||||
destroyDescendantsOnWindows(container, false);
|
||||
container.destroy();
|
||||
container.waitFor(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
destroyDescendantsOnWindows(container, true);
|
||||
container.destroyForcibly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,6 +128,10 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
|||
public void undeploy(Archive<?> archive) throws DeploymentException {
|
||||
File wrkDir = configuration.getProvidersPath().resolve("providers").toFile();
|
||||
try {
|
||||
if (isWindows()) {
|
||||
// stop before updating providers to avoid file locking issues on Windows
|
||||
stop();
|
||||
}
|
||||
Files.deleteIfExists(wrkDir.toPath().resolve(archive.getName()));
|
||||
restartServer();
|
||||
} catch (Exception e) {
|
||||
|
@ -172,7 +186,7 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
|||
builder.environment().put("KEYCLOAK_ADMIN_PASSWORD", "admin");
|
||||
|
||||
if (restart.compareAndSet(false, true)) {
|
||||
FileUtils.deleteDirectory(configuration.getProvidersPath().resolve("data").toFile());
|
||||
deleteDirectory(configuration.getProvidersPath().resolve("data"));
|
||||
}
|
||||
|
||||
return builder.start();
|
||||
|
@ -346,7 +360,11 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
|||
additionalBuildArgs = Collections.emptyList();
|
||||
}
|
||||
|
||||
private void deployArchiveToServer(Archive<?> archive) throws IOException {
|
||||
private void deployArchiveToServer(Archive<?> archive) throws IOException, LifecycleException {
|
||||
if (isWindows()) {
|
||||
// stop before updating providers to avoid file locking issues on Windows
|
||||
stop();
|
||||
}
|
||||
File providersDir = configuration.getProvidersPath().resolve("providers").toFile();
|
||||
InputStream zipStream = archive.as(ZipExporter.class).exportAsInputStream();
|
||||
Files.copy(zipStream, providersDir.toPath().resolve(archive.getName()), StandardCopyOption.REPLACE_EXISTING);
|
||||
|
@ -357,9 +375,9 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
|||
start();
|
||||
}
|
||||
|
||||
private static String getCommand() {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
return "kc.bat";
|
||||
private String getCommand() {
|
||||
if (isWindows()) {
|
||||
return configuration.getProvidersPath().resolve("bin").resolve("kc.bat").toString();
|
||||
}
|
||||
return "./kc.sh";
|
||||
}
|
||||
|
@ -371,4 +389,65 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
|||
public void setAdditionalBuildArgs(List<String> newArgs) {
|
||||
additionalBuildArgs = newArgs;
|
||||
}
|
||||
|
||||
private void destroyDescendantsOnWindows(Process parent, boolean force) {
|
||||
if (!isWindows()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture allProcesses = CompletableFuture.completedFuture(null);
|
||||
|
||||
for (ProcessHandle process : parent.descendants().collect(Collectors.toList())) {
|
||||
if (force) {
|
||||
process.destroyForcibly();
|
||||
} else {
|
||||
process.destroy();
|
||||
}
|
||||
|
||||
allProcesses = CompletableFuture.allOf(allProcesses, process.onExit());
|
||||
}
|
||||
|
||||
try {
|
||||
allProcesses.get(DEFAULT_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
} catch (Exception cause) {
|
||||
throw new RuntimeException("Failed to terminate descendants processes", cause);
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: remove this. do not ask why, but on Windows we are here even though the process was previously terminated
|
||||
// without this pause, tests re-installing dist before tests should fail
|
||||
// looks like pausing the current thread let windows to cleanup processes?
|
||||
// more likely it is env dependent
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isWindows() {
|
||||
return SystemUtils.IS_OS_WINDOWS;
|
||||
}
|
||||
|
||||
public static void deleteDirectory(final Path directory) throws IOException {
|
||||
if (Files.isDirectory(directory, new LinkOption[0])) {
|
||||
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
try {
|
||||
Files.delete(file);
|
||||
} catch (IOException var4) {
|
||||
}
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
try {
|
||||
Files.delete(dir);
|
||||
} catch (IOException var4) {
|
||||
}
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue