Skip to content

Commit

Permalink
chore: Support concurrent Citrus bean registry access
Browse files Browse the repository at this point in the history
- Make sure parallel running tests are able to add beans to the Citrus registry
- Add null check when adding beans as it makes no sense to add null values to the registry
  • Loading branch information
christophd committed Jan 30, 2025
1 parent c73c1a3 commit d54c52f
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@ public CreateServiceAction doBuild() {
}
}

if (referenceResolver != null && !referenceResolver.isResolvable(serverName, HttpServer.class)) {
if (httpServer != null && referenceResolver != null &&
!referenceResolver.isResolvable(serverName, HttpServer.class)) {
referenceResolver.bind(serverName, httpServer);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

package org.citrusframework.spi;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.citrusframework.exceptions.CitrusRuntimeException;
Expand All @@ -27,7 +27,7 @@
*/
public class SimpleReferenceResolver implements ReferenceResolver, ReferenceRegistry {

private final Map<String, Object> objectStore = new HashMap<>();
private final ConcurrentHashMap<String, Object> objectStore = new ConcurrentHashMap<>();

@Override
public <T> T resolve(Class<T> type) {
Expand Down Expand Up @@ -85,6 +85,8 @@ public boolean isResolvable(String name, Class<?> type) {

@Override
public void bind(String name, Object value) {
this.objectStore.put(name, value);
if (value != null) {
this.objectStore.put(name, value);
}
}
}
108 changes: 60 additions & 48 deletions core/citrus-base/src/main/java/org/citrusframework/CitrusContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -361,72 +361,84 @@ public void handleTestResults(TestResults testResults) {
}

public void addComponent(String name, Object component) {
if (component == null) {
return;
}

if (component instanceof ReferenceResolverAware referenceResolverAware) {
referenceResolverAware.setReferenceResolver(referenceResolver);
}

if (component instanceof InitializingPhase c) {
c.initialize();
}

referenceResolver.bind(name, component);

if (component instanceof MessageValidator<?> messageValidator) {
messageValidatorRegistry.addMessageValidator(name, messageValidator);
testContextFactory.getMessageValidatorRegistry().addMessageValidator(name, messageValidator);
}
synchronized (this) {
if (component instanceof MessageValidator<?> messageValidator) {
messageValidatorRegistry.addMessageValidator(name, messageValidator);
testContextFactory.getMessageValidatorRegistry().addMessageValidator(name, messageValidator);
}

if (component instanceof MessageProcessor messageProcessor) {
messageProcessors.addMessageProcessor(messageProcessor);
testContextFactory.getMessageProcessors().addMessageProcessor(messageProcessor);
}
if (component instanceof MessageProcessor messageProcessor) {
messageProcessors.addMessageProcessor(messageProcessor);
testContextFactory.getMessageProcessors().addMessageProcessor(messageProcessor);
}

if (component instanceof TestSuiteListener suiteListener) {
testSuiteListeners.addTestSuiteListener(suiteListener);
}
if (component instanceof TestSuiteListener suiteListener) {
testSuiteListeners.addTestSuiteListener(suiteListener);
}

if (component instanceof TestListener testListener) {
testListeners.addTestListener(testListener);
testContextFactory.getTestListeners().addTestListener(testListener);
}
if (component instanceof TestListener testListener) {
testListeners.addTestListener(testListener);
testContextFactory.getTestListeners().addTestListener(testListener);
}

if (component instanceof TestReporter testReporter) {
testReporters.addTestReporter(testReporter);
}
if (component instanceof TestReporter testReporter) {
testReporters.addTestReporter(testReporter);
}

if (component instanceof TestActionListener testActionListener) {
testActionListeners.addTestActionListener(testActionListener);
testContextFactory.getTestActionListeners().addTestActionListener(testActionListener);
}
if (component instanceof TestActionListener testActionListener) {
testActionListeners.addTestActionListener(testActionListener);
testContextFactory.getTestActionListeners().addTestActionListener(testActionListener);
}

if (component instanceof MessageListener messageListener) {
messageListeners.addMessageListener(messageListener);
testContextFactory.getMessageListeners().addMessageListener(messageListener);
}
if (component instanceof MessageListener messageListener) {
messageListeners.addMessageListener(messageListener);
testContextFactory.getMessageListeners().addMessageListener(messageListener);
}

if (component instanceof BeforeTest beforeTest) {
testContextFactory.getBeforeTest().add(beforeTest);
}
if (component instanceof BeforeTest beforeTest) {
testContextFactory.getBeforeTest().add(beforeTest);
}

if (component instanceof AfterTest afterTest) {
testContextFactory.getAfterTest().add(afterTest);
}
if (component instanceof AfterTest afterTest) {
testContextFactory.getAfterTest().add(afterTest);
}

if (component instanceof BeforeSuite beforeSuiteComponent) {
beforeSuite.add(beforeSuiteComponent);
}
if (component instanceof BeforeSuite beforeSuiteComponent) {
beforeSuite.add(beforeSuiteComponent);
}

if (component instanceof AfterSuite afterSuiteComponent) {
afterSuite.add(afterSuiteComponent);
}
if (component instanceof AfterSuite afterSuiteComponent) {
afterSuite.add(afterSuiteComponent);
}

if (component instanceof FunctionLibrary library) {
functionRegistry.addFunctionLibrary(library);
testContextFactory.getFunctionRegistry().addFunctionLibrary(library);
}
if (component instanceof FunctionLibrary library) {
functionRegistry.addFunctionLibrary(library);
testContextFactory.getFunctionRegistry().addFunctionLibrary(library);
}

if (component instanceof ValidationMatcherLibrary library) {
validationMatcherRegistry.addValidationMatcherLibrary(library);
testContextFactory.getValidationMatcherRegistry().addValidationMatcherLibrary(library);
}
if (component instanceof ValidationMatcherLibrary library) {
validationMatcherRegistry.addValidationMatcherLibrary(library);
testContextFactory.getValidationMatcherRegistry().addValidationMatcherLibrary(library);
}

if (component instanceof ReferenceResolverAware referenceResolverAware) {
referenceResolverAware.setReferenceResolver(referenceResolver);
if (component instanceof GlobalVariables vars) {
globalVariables.getVariables().putAll(vars.getVariables());
testContextFactory.getGlobalVariables().getVariables().putAll(vars.getVariables());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,9 @@ public static void parseConfiguration(Object configuration, CitrusContext citrus
try {
String name = ReferenceRegistry.getName(m.getAnnotation(BindToRegistry.class), m.getName());
Object component = m.invoke(configuration);

if (component instanceof Named named) {
if (component == null) {
return;
} if (component instanceof Named named) {
named.setName(name);
}

Expand All @@ -270,8 +271,9 @@ public static void parseConfiguration(Object configuration, CitrusContext citrus
try {
String name = ReferenceRegistry.getName(f.getAnnotation(BindToRegistry.class), f.getName());
Object component = f.get(configuration);

if (component instanceof Named named) {
if (component == null) {
return;
} else if (component instanceof Named named) {
named.setName(name);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,35 +72,35 @@ public boolean shouldExecute(String testName, String packageName, String[] inclu

if (StringUtils.hasText(packageNamePattern)) {
if (!Pattern.compile(packageNamePattern).matcher(packageName).matches()) {
logger.warn(String.format(baseErrorMessage, "test package", getName()));
logger.debug(String.format(baseErrorMessage, "test package", getName()));
return false;
}
}

if (StringUtils.hasText(namePattern)) {
if (!Pattern.compile(sanitizePatten(namePattern)).matcher(testName).matches()) {
logger.warn(String.format(baseErrorMessage, "test name", getName()));
logger.debug(String.format(baseErrorMessage, "test name", getName()));
return false;
}
}

if (!checkTestGroups(includedGroups)) {
logger.warn(String.format(baseErrorMessage, "test groups", getName()));
logger.debug(String.format(baseErrorMessage, "test groups", getName()));
return false;
}

for (Map.Entry<String, String> envEntry : env.entrySet()) {
if (!System.getenv().containsKey(envEntry.getKey()) ||
(StringUtils.hasText(envEntry.getValue()) && !System.getenv().get(envEntry.getKey()).equals(envEntry.getValue()))) {
logger.warn(String.format(baseErrorMessage, "env properties", getName()));
logger.debug(String.format(baseErrorMessage, "env properties", getName()));
return false;
}
}

for (Map.Entry<String, String> systemProperty : systemProperties.entrySet()) {
if (!System.getProperties().containsKey(systemProperty.getKey()) ||
(StringUtils.hasText(systemProperty.getValue()) && !System.getProperties().get(systemProperty.getKey()).equals(systemProperty.getValue()))) {
logger.warn(String.format(baseErrorMessage, "system properties", getName()));
logger.debug(String.format(baseErrorMessage, "system properties", getName()));
return false;
}
}
Expand Down

0 comments on commit d54c52f

Please sign in to comment.