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

Draft: deprecate test loader #1109

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
@@ -1,5 +1,28 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.citrusframework;

import org.citrusframework.message.MessageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
Expand All @@ -11,10 +34,10 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.citrusframework.common.TestLoader;
import org.citrusframework.message.MessageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.citrusframework.common.TestLoader.GROOVY;
import static org.citrusframework.common.TestLoader.SPRING;
import static org.citrusframework.common.TestLoader.XML;
import static org.citrusframework.common.TestLoader.YAML;

/**
* @author Christoph Deppisch
Expand Down Expand Up @@ -287,16 +310,11 @@ public static Set<String> getLogMaskKeywords() {
* @return
*/
public static Set<String> getTestFileNamePattern(String type) {
switch (type) {
case TestLoader.XML:
case TestLoader.SPRING:
return CitrusSettings.getXmlTestFileNamePattern();
case TestLoader.GROOVY:
return CitrusSettings.getGroovyTestFileNamePattern();
case TestLoader.YAML:
return CitrusSettings.getYamlTestFileNamePattern();
default:
return Collections.emptySet();
}
return switch (type) {
case SPRING, XML -> CitrusSettings.getXmlTestFileNamePattern();
case GROOVY -> CitrusSettings.getGroovyTestFileNamePattern();
case YAML -> CitrusSettings.getYamlTestFileNamePattern();
default -> Collections.emptySet();
};
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 the original author or authors.
* Copyright 2023-2024 the original author or authors.
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
Expand Down Expand Up @@ -28,6 +28,7 @@
* @since 4.0
*/
public interface TestCaseRunnerProvider {

/**
* Creates a TestCaseRunner which runs the given {@link TestCase} and the given {@link TestContext}.
* @param testCase
Expand All @@ -42,5 +43,4 @@ public interface TestCaseRunnerProvider {
* @return
*/
TestCaseRunner createTestCaseRunner(TestContext context);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2006-2013 the original author or authors.
* Copyright 2006-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,21 +16,30 @@

package org.citrusframework.common;

import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

import org.citrusframework.TestCase;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.citrusframework.spi.ResourcePathTypeResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

import static java.util.stream.Collectors.toMap;

/**
* Test loader interface.
* <p>
* <b>Deprecation notice:</b> Implementations of this interface load <i>and</i> execute test cases in one breath. That
* is very intransparent to end-users. It is therefore supersed by the {@link TestLoaderAndExecutor}, which splits
* loading and execution of test cases into multiple methods, or at least has a more transparent API.
*
* @author Christoph Deppisch
* @since 2.1
* @deprecated use {@link TestLoaderAndExecutor} instead
*/
@Deprecated
public interface TestLoader {

/** Logger */
Expand All @@ -48,19 +57,18 @@ public interface TestLoader {
String GROOVY = "groovy";

/**
* Loads and creates new test case object.
* @return
* Loads and creates new test case object. The test case is expected to be cached and returned by {@link TestLoader#getTestCase()}.
*/
void load();

/**
* Adds test case handler that is called before test case gets executed.
* @param handler
* @param configurer
*/
void configureTestCase(Consumer<TestCase> handler);
void configureTestCase(Consumer<TestCase> configurer);

/**
* Adds test case handler that is called once the test case has been loaded.
* Adds test case handler that is called once the test case has been executed.
* @param handler
*/
void doWithTestCase(Consumer<TestCase> handler);
Expand All @@ -80,29 +88,37 @@ public interface TestLoader {
/**
* Resolves all available test loader from resource path lookup. Scans classpath for test loader meta information
* and instantiates the components.
* @return
*
* @return the available test loaders
*/
static Map<String, TestLoader> lookup() {
Map<String, TestLoader> loader = TYPE_RESOLVER.resolveAll();
Map<String, TestLoader> loader = TYPE_RESOLVER.resolveAll()
.entrySet().stream()
.filter(entry -> entry.getValue() instanceof TestLoader)
.collect(toMap(Map.Entry::getKey, e -> ((TestLoader) e.getValue())));

if (logger.isDebugEnabled()) {
loader.forEach((k, v) -> logger.debug(String.format("Found test loader '%s' as %s", k, v.getClass())));
}

return loader;
}

/**
* Resolves test loader from resource path lookup with given resource name. Scans classpath for test loader meta information
* with given name and returns instance of the loader. Returns optional instead of throwing exception when no test loader
* could be found.
* @param loader
* @return
*
* @param loader the name of the test loader
* @return the test loader, if present
*/
static Optional<TestLoader> lookup(String loader) {
try {
return Optional.of(TYPE_RESOLVER.resolve(loader));
} catch (CitrusRuntimeException e) {
logger.warn(String.format("Failed to resolve test loader from resource '%s/%s'", RESOURCE_PATH, loader));
} catch (ClassCastException ignore) {
// Ignore exception
}

return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.citrusframework.common;

import org.citrusframework.TestCase;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.citrusframework.spi.Resource;

import java.util.Map;
import java.util.Optional;

import static java.util.stream.Collectors.toMap;

/**
* Provides an interface for loading and executing test cases.
* <p>
* This interface extends both {@link InitializingPhase} and {@link TestLoader}, offering methods to discover, load, and
* execute test cases. Test cases are resolved using resource path lookup and can be executed immediately upon loading
* or loaded for later execution.
*/
public interface TestLoaderAndExecutor extends InitializingPhase, TestLoader {

/**
* Discovers and returns all available {@link TestLoaderAndExecutor} instances by scanning the classpath for test
* loader meta-information. This method facilitates the dynamic discovery of test loader and executor components.
*
* @return A map of test loader and executor names to their respective {@link TestLoaderAndExecutor} instances.
*/
static Map<String, TestLoaderAndExecutor> lookup() {
Map<String, TestLoaderAndExecutor> testLoaderAndExecutors = TYPE_RESOLVER.resolveAll();
testLoaderAndExecutors = testLoaderAndExecutors.entrySet()
.stream()
.filter(entry -> entry.getValue() instanceof TestLoaderAndExecutor)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));

if (logger.isDebugEnabled()) {
testLoaderAndExecutors.forEach((k, v) -> logger.debug(String.format("Found test loader and executor '%s' as %s", k, v.getClass())));
}

return testLoaderAndExecutors;
}


/**
* Attempts to resolve a specific {@link TestLoaderAndExecutor} by its name. This method scans the classpath for
* test loader meta-information matching the given name. It returns an Optional to avoid exceptions when a test
* loader is not found.
*
* @param loader the name of the test loader to resolve.
* @return An {@link Optional} containing the resolved {@link TestLoaderAndExecutor}, if found.
*/
static Optional<TestLoaderAndExecutor> lookup(String loader) {
try {
return Optional.of(TYPE_RESOLVER.resolve(loader));
} catch (CitrusRuntimeException e) {
logger.warn(String.format("Failed to resolve test loader and executor from resource '%s/%s'", RESOURCE_PATH, loader));
} catch (ClassCastException ignore) {
// Ignore exception
}

return Optional.empty();
}

/**
* Loads a new test case and immediately executes it. This method combines the process of loading a test case from
* resources and executing it in one step.
*
* @return The executed {@link TestCase} instance.
*/
default TestCase loadAndExecute() {
load();
return getTestCase();
}

/**
* Loads a test case from the specified resource without executing it. This method allows for deferred execution
* of the test case.
*
* @param resource the resource from which to load the test case.
* @return The loaded {@link TestCase} instance.
*/
TestCase loadTestCase(Resource resource);

/**
* Executes the provided test case. This method allows for the execution of a preloaded test case.
*
* @param testCase the test case to execute.
* @return The executed {@link TestCase} instance.
*/
TestCase executeTestCase(TestCase testCase);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2006-2010 the original author or authors.
* Copyright 2006-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -904,6 +904,7 @@ public boolean isSuccess(TestResult testResult) {
* Empty test case implementation used as test result when tests fail before execution.
*/
private static class EmptyTestCase implements TestCase {

private final String testName;
private final String packageName;

Expand Down
Loading
Loading