Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camel JBang improvements #1263

Merged
merged 4 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

Expand All @@ -36,6 +40,7 @@
*/
public class JavaTestLoader extends DefaultTestLoader implements TestSourceAware {

private static final Pattern packageNamePattern = Pattern.compile("^package\\s+([a-zA-Z_][.a-zA-Z_]+);$", Pattern.MULTILINE);
private String source;

@Override
Expand All @@ -50,9 +55,12 @@ public void doLoad() {
throw new CitrusRuntimeException("Failed to compile Java source file: %s".formatted(javaSource.getFile().getAbsolutePath()));
}

String packageName = extractPackageName(javaSource);
String qualifiedClassName = StringUtils.hasText(packageName) ? packageName + "." + getClassName() : getClassName();

// Load and instantiate compiled class.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { Paths.get(javaSource.getURI()).getParent().toUri().toURL() });
Class<?> cls = Class.forName(getClassName(), true, classLoader);
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { getClassLoaderBaseURL(packageName, javaSource) });
Class<?> cls = Class.forName(qualifiedClassName, true, classLoader);
Object instance = cls.getDeclaredConstructor().newInstance();

CitrusAnnotations.injectAll(instance, citrus, context);
Expand Down Expand Up @@ -100,6 +108,36 @@ public String getClassName() {
return FileUtils.getBaseName(testName.endsWith(FileUtils.FILE_EXTENSION_JAVA) ? testName : testName + FileUtils.FILE_EXTENSION_JAVA);
}

private static String extractPackageName(Resource javaSource) throws IOException {
String content = FileUtils.readToString(javaSource);
Matcher matcher = packageNamePattern.matcher(content);
if (matcher.find()) {
return matcher.group(1);
}

return "";
}

/**
* Get Class loader base URL for given Java file resource path.
* The package name of the class must be taken into account when walking the parent tree of the folder structure upwards.
* @param packageName
* @param javaSource
* @return
* @throws MalformedURLException
*/
private static URL getClassLoaderBaseURL(String packageName, Resource javaSource) throws MalformedURLException {
Path clBase = Paths.get(javaSource.getURI()).getParent();

if (StringUtils.hasText(packageName)) {
for (int i = 0; i < packageName.split("\\.").length; i++) {
clBase = clBase.getParent();
}
}

return clBase.toUri().toURL();
}

/**
* Sets custom Spring application context file for Java test case.
* @param source
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public final class CamelSettings {

private static final String CONTEXT_NAME_PROPERTY = CAMEL_PROPERTY_PREFIX + "context.name";
private static final String CONTEXT_NAME_ENV = CAMEL_ENV_PREFIX + "CONTEXT_NAME";
private static final String CONTEXT_NAME_DEFAULT = "citrusCamelContext";
private static final String CONTEXT_NAME_DEFAULT = "camelContext";

private static final String TIMEOUT_PROPERTY = CAMEL_PROPERTY_PREFIX + "timeout";
private static final String TIMEOUT_ENV = CAMEL_ENV_PREFIX + "TIMEOUT";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.citrusframework.camel.actions;

import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.citrusframework.AbstractTestActionBuilder;
import org.citrusframework.actions.AbstractTestAction;
import org.citrusframework.camel.CamelSettings;
Expand Down Expand Up @@ -82,8 +83,16 @@ public final T build() {

if (referenceResolver.isResolvable(CamelSettings.getContextName())) {
camelContext = referenceResolver.resolve(CamelSettings.getContextName(), CamelContext.class);
} else {
} else if (referenceResolver.isResolvable(CamelContext.class)) {
camelContext = referenceResolver.resolve(CamelContext.class);
} else {
camelContext = new DefaultCamelContext();
try {
camelContext.start();
} catch (Exception e) {
throw new IllegalStateException("Failed to start Camel context '%s'".formatted(CamelSettings.getContextName()), e);
}
referenceResolver.bind(CamelSettings.getContextName(), camelContext);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

Expand Down Expand Up @@ -52,9 +55,15 @@ public class CamelRunIntegrationAction extends AbstractCamelJBangAction {
/** Camel integration resource */
private final Resource integrationResource;

/** Optional list of resource files to include */
private final List<String> resourceFiles;

/** Source code to run as a Camel integration */
private final String sourceCode;

/** Camel Jbang command arguments */
private final List<String> args;

/** Environment variables set on the Camel JBang process */
private final Map<String, String> envVars;

Expand All @@ -63,6 +72,8 @@ public class CamelRunIntegrationAction extends AbstractCamelJBangAction {

private final boolean autoRemoveResources;

private final boolean waitForRunningState;

/**
* Default constructor.
*/
Expand All @@ -71,10 +82,13 @@ public CamelRunIntegrationAction(Builder builder) {

this.integrationName = builder.integrationName;
this.integrationResource = builder.integrationResource;
this.resourceFiles = builder.resourceFiles;
this.sourceCode = builder.sourceCode;
this.args = builder.args;
this.envVars = builder.envVars;
this.systemProperties = builder.systemProperties;
this.autoRemoveResources = builder.autoRemoveResources;
this.waitForRunningState = builder.waitForRunningState;
}

@Override
Expand Down Expand Up @@ -102,7 +116,7 @@ public void doExecute(TestContext context) {
camelJBang().camelApp().withEnvs(context.resolveDynamicValuesInMap(envVars));
camelJBang().camelApp().withSystemProperties(context.resolveDynamicValuesInMap(systemProperties));

ProcessAndOutput pao = camelJBang().run(name, integrationToRun);
ProcessAndOutput pao = camelJBang().run(name, integrationToRun, resourceFiles, args.toArray(String[]::new));

if (!pao.getProcess().isAlive()) {
logger.info("Failed to start Camel integration '%s'".formatted(name));
Expand All @@ -122,6 +136,16 @@ public void doExecute(TestContext context) {
.jbang()
.stop(name));
}

logger.info("Waiting for the Camel integration '%s' (%s) to be running ...".formatted(name, pid));

if (waitForRunningState) {
new CamelVerifyIntegrationAction.Builder()
.integrationName(name)
.isRunning()
.build()
.execute(context);
}
} catch (IOException e) {
throw new CitrusRuntimeException("Failed to create temporary file from Camel integration");
}
Expand Down Expand Up @@ -157,13 +181,16 @@ public static final class Builder extends AbstractCamelJBangAction.Builder<Camel
private String sourceCode;
private String integrationName = "route";
private Resource integrationResource;
private final List<String> resourceFiles = new ArrayList<>();

private final List<String> args = new ArrayList<>();
private final Map<String, String> envVars = new HashMap<>();
private Resource envVarsFile;
private final Map<String, String> systemProperties = new HashMap<>();
private Resource systemPropertiesFile;

private boolean autoRemoveResources = CamelJBangSettings.isAutoRemoveResources();
private boolean waitForRunningState = CamelJBangSettings.isWaitForRunningState();

/**
* Runs Camel integration from given source code.
Expand All @@ -188,6 +215,26 @@ public Builder integration(Resource resource) {
return this;
}

/**
* Add resource file to the integration run.
* @param resource
* @return
*/
public Builder addResource(Resource resource) {
this.resourceFiles.add(resource.getFile().getAbsolutePath());
return this;
}

/**
* Construct resource from given path and add file as resource to the integration run.
* @param resourcePath
* @return
*/
public Builder addResource(String resourcePath) {
this.resourceFiles.add(resourcePath);
return this;
}

/**
* Adds route using one of the supported languages XML or Groovy.
* @param name
Expand All @@ -210,6 +257,38 @@ public Builder integrationName(String name) {
return this;
}

/**
* Adds a command argument.
* @param arg
* @return
*/
public Builder withArg(String arg) {
this.args.add(arg);
return this;
}

/**
* Adds a command argument with name and value.
* @param name
* @param value
* @return
*/
public Builder withArg(String name, String value) {
this.args.add(name);
this.args.add(value);
return this;
}

/**
* Adds command arguments.
* @param args
* @return
*/
public Builder withArgs(String... args) {
this.args.addAll(Arrays.asList(args));
return this;
}

/**
* Adds an environment variable.
* @param key
Expand Down Expand Up @@ -277,6 +356,11 @@ public Builder autoRemove(boolean enabled) {
return this;
}

public Builder waitForRunningState(boolean enabled) {
this.waitForRunningState = enabled;
return this;
}

@Override
public CamelRunIntegrationAction build() {
if (systemPropertiesFile != null) {
Expand All @@ -301,5 +385,6 @@ public CamelRunIntegrationAction build() {

return new CamelRunIntegrationAction(this);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public void doExecute(TestContext context) {
Long pid = verifyRouteStatus(name, context.replaceDynamicContentInString(phase), context);

if (logMessage != null) {
verifyRouteLogs(pid, name, context.replaceDynamicContentInString(logMessage), context);
verifyRouteLogs(pid, name, context.replaceDynamicContentInString(logMessage.trim()), context);
}

logger.info("Successfully verified Camel integration '%s'".formatted(name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.citrusframework.spi.ReferenceResolverAware;
import org.citrusframework.spi.Resource;
import org.citrusframework.util.FileUtils;
import org.citrusframework.util.StringUtils;

/**
* Creates component and binds it to the given Camel context.
Expand Down Expand Up @@ -88,6 +89,11 @@ public static Builder bind() {
return new Builder();
}

public Builder componentName(String componentName) {
this.name = componentName;
return this;
}

public Builder component(String name, Object component) {
if (component instanceof String) {
return component(name, component.toString());
Expand All @@ -99,7 +105,12 @@ public Builder component(String name, Object component) {
}

public Builder component(Resource resource) {
return component(FileUtils.getBaseName(FileUtils.getFileName(resource.getLocation())), resource);
if (StringUtils.hasText(this.name)) {
return component(this.name, resource);
} else {
return component(FileUtils.getBaseName(FileUtils.getFileName(resource.getLocation())), resource);

}
}

public Builder component(String name, Resource resource) {
Expand All @@ -116,6 +127,11 @@ public Builder component(String name, String script) {
return this;
}

public Builder component(String script) {
this.script = script;
return this;
}

@Override
public CreateCamelComponentAction doBuild() {
return new CreateCamelComponentAction(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.apache.camel.CamelContext;
import org.citrusframework.TestActor;
import org.citrusframework.camel.CamelSettings;
import org.citrusframework.camel.endpoint.CamelEndpoint;
import org.citrusframework.camel.endpoint.CamelEndpointBuilder;
import org.citrusframework.camel.message.CamelMessageConverter;
Expand All @@ -35,8 +36,8 @@ public CamelEndpoint parse(CamelEndpointConfig annotation, ReferenceResolver ref

if (StringUtils.hasText(annotation.camelContext())) {
builder.camelContext(referenceResolver.resolve(annotation.camelContext(), CamelContext.class));
} else if (referenceResolver.isResolvable("camelContext")) {
builder.camelContext(referenceResolver.resolve("camelContext", CamelContext.class));
} else if (referenceResolver.isResolvable(CamelSettings.getContextName())) {
builder.camelContext(referenceResolver.resolve(CamelSettings.getContextName(), CamelContext.class));
} else {
builder.camelContext(referenceResolver.resolve(CamelContext.class));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.apache.camel.CamelContext;
import org.citrusframework.TestActor;
import org.citrusframework.camel.CamelSettings;
import org.citrusframework.camel.endpoint.CamelSyncEndpoint;
import org.citrusframework.camel.endpoint.CamelSyncEndpointBuilder;
import org.citrusframework.camel.message.CamelMessageConverter;
Expand All @@ -36,8 +37,8 @@ public CamelSyncEndpoint parse(CamelSyncEndpointConfig annotation, ReferenceReso

if (StringUtils.hasText(annotation.camelContext())) {
builder.camelContext(referenceResolver.resolve(annotation.camelContext(), CamelContext.class));
} else if (referenceResolver.isResolvable("camelContext")) {
builder.camelContext(referenceResolver.resolve("camelContext", CamelContext.class));
} else if (referenceResolver.isResolvable(CamelSettings.getContextName())) {
builder.camelContext(referenceResolver.resolve(CamelSettings.getContextName(), CamelContext.class));
} else {
builder.camelContext(referenceResolver.resolve(CamelContext.class));
}
Expand Down
Loading
Loading