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

fix: Make sure to use current pid to verify Camel app status #1285

Closed
wants to merge 2 commits into from
Closed
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 @@ -44,6 +44,8 @@ public class ProcessAndOutput {

private BufferedReader reader;

private String app;

ProcessAndOutput(Process process) {
this(process, "");
}
Expand Down Expand Up @@ -134,6 +136,16 @@ private void readChunk() {
}
}

/**
* Get the process id of first descendant or the parent process itself in case there is no descendant process.
* On Linux the shell command represents the parent process and the JBang command as descendant process.
* Typically, we need the JBang command process id.
* @return
*/
public Long getProcessId() {
return getProcessId(app);
}

/**
* Get the process id of first descendant or the parent process itself in case there is no descendant process.
* On Linux the shell command represents the parent process and the JBang command as descendant process.
Expand All @@ -142,7 +154,7 @@ private void readChunk() {
*/
public Long getProcessId(String app) {
try {
if (isUnix()) {
if (app != null && isUnix()) {
// wait for descendant process to be available
await().atMost(5000L, TimeUnit.MILLISECONDS)
.until(() -> process.descendants().findAny().isPresent());
Expand All @@ -165,4 +177,12 @@ private static boolean isUnix() {
String os = System.getProperty("os.name").toLowerCase();
return os.contains("nix") || os.contains("nux") || os.contains("aix");
}

/**
* Sets the application name that identifies this process.
* @param app
*/
public void setApp(String app) {
this.app = app;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,15 @@ public void doExecute(TestContext context) {
.withSystemProperties(systemProperties)
.run(context.replaceDynamicContentInString(scriptOrFile), context.resolveDynamicValuesInList(args));

result.setApp(Objects.requireNonNullElse(app, scriptName));

if (printOutput) {
logger.info("JBang script '%s' output:".formatted(scriptName));
logger.info(result.getOutput());
}

if (pidVar != null) {
context.setVariable(pidVar, result.getProcessId(Objects.requireNonNullElse(app, scriptName)));
context.setVariable(pidVar, result.getProcessId());
}

int exitValue = result.getProcess().exitValue();
Expand All @@ -105,7 +107,7 @@ public void doExecute(TestContext context) {

if (validationProcessor != null) {
validationProcessor.validate(new DefaultMessage(result.getOutput().trim())
.setHeader("pid", result.getProcessId(Objects.requireNonNullElse(app, scriptName)))
.setHeader("pid", result.getProcessId())
.setHeader("exitCode", result.getProcess().exitValue()), context);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,11 @@ public void doExecute(TestContext context) {

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));
logger.info(pao.getOutput());
verifyProcessIsAlive(pao, name);

throw new CitrusRuntimeException(String.format("Failed to start Camel integration - exit code %s", pao.getProcess().exitValue()));
}
pao.setApp(integrationToRun.getFileName().toString());
Long pid = pao.getProcessId();

Long pid = pao.getProcessId(integrationToRun.getFileName().toString());
context.setVariable(name + ":pid", pid);
context.setVariable(name + ":process:" + pid, pao);

Expand All @@ -154,6 +151,15 @@ public void doExecute(TestContext context) {
}
}

private static void verifyProcessIsAlive(ProcessAndOutput pao, String name) {
if (!pao.getProcess().isAlive()) {
logger.info("Failed to start Camel integration '%s'".formatted(name));
logger.info(pao.getOutput());

throw new CitrusRuntimeException(String.format("Failed to start Camel integration - exit code %s", pao.getProcess().exitValue()));
}
}

private String getFileExt(String sourceCode) {
if (IsXmlPredicate.getInstance().test(sourceCode)) {
return "xml";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.citrusframework.camel.actions;

import java.util.Map;
import java.util.Objects;

import org.citrusframework.camel.CamelSettings;
import org.citrusframework.context.TestContext;
Expand Down Expand Up @@ -124,15 +125,8 @@ private Long verifyRouteStatus(String name, String phase, TestContext context) {
for (int i = 0; i < maxAttempts; i++) {
if (context.getVariables().containsKey(name + ":pid")) {
Long pid = context.getVariable(name + ":pid", Long.class);
Map<String, String> properties = camelJBang().get(pid);
if ((phase.equals("Stopped") && properties.isEmpty()) || (!properties.isEmpty() && properties.get("STATUS").equals(phase))) {
logger.info(String.format("Verified Camel integration '%s' state '%s' - All values OK!", name, phase));
if (findProcessAndVerifyStatus(pid, name, phase)) {
return pid;
} else if (phase.equals("Error")) {
logger.info(String.format("Camel integration '%s' is in state 'Error'", name));
if (stopOnErrorStatus) {
throw new CitrusRuntimeException(String.format("Failed to verify Camel integration '%s' - is in state 'Error'", name));
}
}

if (context.getVariables().containsKey(name + ":process:" + pid)) {
Expand All @@ -144,6 +138,15 @@ private Long verifyRouteStatus(String name, String phase, TestContext context) {

throw new CitrusRuntimeException(String.format("Failed to verify Camel integration '%s' - exit code %s", name, pao.getProcess().exitValue()));
}

// Verify that current processId is the same as the one saved in test context
Long appPid = pao.getProcessId();
if (!Objects.equals(pid, appPid)) {
// seems like there is another pid (descendant process) that should be verified
if (findProcessAndVerifyStatus(appPid, name, phase)) {
return appPid;
}
}
}
}

Expand All @@ -162,6 +165,21 @@ private Long verifyRouteStatus(String name, String phase, TestContext context) {

}

private boolean findProcessAndVerifyStatus(Long pid, String name, String phase) {
Map<String, String> properties = camelJBang().get(pid);
if ((phase.equals("Stopped") && properties.isEmpty()) || (!properties.isEmpty() && properties.get("STATUS").equals(phase))) {
logger.info(String.format("Verified Camel integration '%s' state '%s' - All values OK!", name, phase));
return true;
} else if (properties.getOrDefault("STATUS", "").equals("Error")) {
logger.info(String.format("Camel integration '%s' is in state 'Error'", name));
if (stopOnErrorStatus) {
throw new CitrusRuntimeException(String.format("Failed to verify Camel integration '%s' - is in state 'Error'", name));
}
}

return false;
}

public String getIntegrationName() {
return integrationName;
}
Expand Down
Loading