Skip to content

Commit

Permalink
Add new xtf.openshift.namespace.per.testcase property which will exec…
Browse files Browse the repository at this point in the history
…ute every test case in its own namespace. Note this property has limitation that consuming test suite must not create static Openshift instances as those are created before name of test case and thus the namespace for the test is known.
  • Loading branch information
mnovak1 committed Jul 12, 2022
1 parent 2a172f2 commit b9e3f2f
Show file tree
Hide file tree
Showing 19 changed files with 571 additions and 140 deletions.
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ Take a look at the
class to see possible configurations. Enabling some of them will allow you to instantiate as
`OpenShift openShift = OpenShifts.master()`.



##### Pull Secrets
There's a convenient method `OpenShift::setupPullSecret()` to set up pull secrets as recommended by OpenShift
[documentation](https://docs.openshift.com/container-platform/4.2/openshift_images/managing-images/using-image-pull-secrets.html).
Expand Down Expand Up @@ -157,6 +159,51 @@ xtf.foo.v2.version=1.0.3

Retrieving an instance with this metadata: `Produts.resolve("product");`

#### Using `TestCaseContext` to get name of currently running test case

If `junit.jupiter.extensions.autodetection.enabled=true` then JUnit 5 extension `cz.xtf.core.context.TestCaseContextExtension` is
automatically registered. It
sets name of currently running test case into `TestCaseContext` before `@BeforeAll` of test case is called.

Following code then can be used to retrieve the name of currently running test case in:
```
String testCase = TestCaseContext.getRunningTestCaseName()
```

#### Automatic creation of namespace(s)

XTF allows to automatically manage creation of testing namespace which is defined by `xtf.openshift.namespace` property. This
namespace is created before any test case is started.

This feature requires to have XTF JUnit5 `cz.xtf.junit5.listeners.ProjectCreator` extension enabled. This can be done by adding
`cz.xtf.junit5.listeners.ProjectCreator` line into files:
```
src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension
src/test/resources/META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter
src/test/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener
```

#### Run test cases in separate namespaces using `xtf.openshift.namespace.per.testcase` property

You can enable running each test case in separate namespace by setting `xtf.openshift.namespace.per.testcase=true`.

Namespace names follow pattern: "`${xtf.openshift.namespace}`-TestCaseName".
For example for `xtf.openshift.namespace=testnamespace` and test case `org.test.SmokeTest` it will be `testnamespace-SmokeTest`.

You can limit the length of created namespace by `xtf.openshift.namespace.per.testcase.length.limit` property. By default it's `25` chars. If limit is breached then
test case name in namespace name is hashed to hold the limit. So namespace name would like `testnamespace-s623jd6332`

**Warning - Limitations**

When enabling this feature in your project, **you may need to replace [OpenShiftConfig.getNamespace()](core/src/main/java/cz/xtf/core/config/OpenShiftConfig.java)
with [NamespaceManager.getNamespace()](core/src/main/java/cz/xtf/core/namespace/NamespaceManager.java). Check method's javadoc to understand difference.**

In case that you're using this feature, consuming test suite must follow those rules to avoid unexpected behaviour when using `cz.xtf.core.openshift.OpenShift` instances:

* **Do not create static `cz.xtf.core.openshift.OpenShift` variable** like: `public static final OpenShift openshift = Openshifts.master()` on class level.
The reason is that during initialization of static instances the test case and corresponsing namespace is not known. To avoid unexpected behaviour `RuntimeException` is thrown, when programmer breaks this rule.
* Similarly as above do not create `cz.xtf.core.openshift.OpenShift` variables in static blocks or do not initialize other static variables which creates `cz.xtf.core.openshift.OpenShift` instance.

#### Service Logs Streaming (SLS)
This feature allows for you to stream the services output while the test is running; this way you can see immediately
what is happening inside the cluster.
Expand Down Expand Up @@ -216,6 +263,7 @@ following information:
**OPTIONAL**, if not assigned, logs will be streamed to `System.out`. When assigned, XTF will attempt to create the
path in case it doesn't exist and default to `System.out` should any error occur.


###### Usage examples
Given what above, enabling SLS for all test classes is possible by executing the following command:

Expand Down
6 changes: 6 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,17 @@
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>system-stubs-jupiter</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/cz/xtf/core/bm/BuildManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public BuildManager(OpenShift openShift) {
// Otherwise you can see:
// $ oc label namespace <name> "label1=foo"
// Error from server (Forbidden): namespaces "<name>" is forbidden: User "<user>" cannot patch resource "namespaces" in API group "" in the namespace "<name>"
OpenShifts.admin().namespaces().withName(openShift.getNamespace())
OpenShifts.admin(openShift.getNamespace()).namespaces().withName(openShift.getNamespace())
.edit(new Visitor<NamespaceBuilder>() {
@Override
public void visit(NamespaceBuilder builder) {
Expand Down
45 changes: 44 additions & 1 deletion core/src/main/java/cz/xtf/core/config/OpenShiftConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import java.nio.file.Paths;

import cz.xtf.core.openshift.OpenShifts;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public final class OpenShiftConfig {
public static final String OPENSHIFT_URL = "xtf.openshift.url";
public static final String OPENSHIFT_TOKEN = "xtf.openshift.token";
Expand All @@ -22,6 +26,19 @@ public final class OpenShiftConfig {
public static final String OPENSHIFT_MASTER_TOKEN = "xtf.openshift.master.token";
public static final String OPENSHIFT_ROUTE_DOMAIN = "xtf.openshift.route_domain";
public static final String OPENSHIFT_PULL_SECRET = "xtf.openshift.pullsecret";
public static final String OPENSHIFT_NAMESPACE_PER_TESTCASE = "xtf.openshift.namespace.per.testcase";
/**
* Used only if xtf.openshift.namespace.per.testcase=true - this property can configure its maximum length. This is useful
* in case
* where namespace is used in first part of URL of route which must have <64 chars length.
*/
public static final String OPENSHIFT_NAMESPACE_NAME_LENGTH_LIMIT = "xtf.openshift.namespace.per.testcase.length.limit";

/**
* Used only if xtf.openshift.namespace.per.testcase=true - this property configures default maximum length of namespace
* name.
*/
private static final String DEFAULT_OPENSHIFT_NAMESPACE_NAME_LENGTH_LIMIT = "25";

public static String url() {
return XTFConfig.get(OPENSHIFT_URL);
Expand All @@ -48,10 +65,36 @@ public static String version() {
return XTFConfig.get(OPENSHIFT_VERSION);
}

/**
* Note that most likely you want to use {@see NamespaceManager#getNamespace()} which returns actual namespace
* used by current tests. For example {@link OpenShifts#master()} is using {@see NamespaceManager#getNamespace()}
* to get default namespace for currently running test.
*
* @return Returns namespace as defined in xtf.openshift.namespace property
*/
public static String namespace() {
return XTFConfig.get(OPENSHIFT_NAMESPACE);
}

/**
* @return if property xtf.openshift.namespace.per.testcase is empty or true then returns true otherwise false
*/
public static boolean useNamespacePerTestCase() {
return XTFConfig.get(OPENSHIFT_NAMESPACE_PER_TESTCASE) != null
&& (XTFConfig.get(OPENSHIFT_NAMESPACE_PER_TESTCASE).equals("")
|| XTFConfig.get(OPENSHIFT_NAMESPACE_PER_TESTCASE).toLowerCase().equals("true"));
}

/**
* Used only if xtf.openshift.namespace.per.testcase=true
*
* @return limit on namespace if it's set by -Dxtf.openshift.namespace.per.testcase.length.limit property
*/
public static int getNamespaceLengthLimitForUniqueNamespacePerTest() {
return Integer.parseInt(XTFConfig.get(OPENSHIFT_NAMESPACE_NAME_LENGTH_LIMIT,
DEFAULT_OPENSHIFT_NAMESPACE_NAME_LENGTH_LIMIT));
}

public static String binaryPath() {
return XTFConfig.get(OPENSHIFT_BINARY_PATH);
}
Expand All @@ -60,7 +103,7 @@ public static String binaryPath() {
* Channel configuration for download of OpenShift client from
* https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/
* Channels are: stable, latest, fast, candidate
*
*
* @return channel as configured in xtf.openshift.binary.url.channel property, or default 'stable'
*/
public static String binaryUrlChannelPath() {
Expand Down
24 changes: 24 additions & 0 deletions core/src/main/java/cz/xtf/core/context/TestCaseContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cz.xtf.core.context;

public class TestCaseContext {

/**
*
* This allows to track currently running test case for correct namespace mapping. This is used to automatically find
* namespace for running test case when
* creating {@link cz.xtf.core.openshift.OpenShift} instances.
*/
private static String runningTestCaseName;

/**
* @return test case name associated with current thread or null if not such mapping exists, for example for com.SmokeTest
* returns SmokeTest
*/
public static String getRunningTestCaseName() {
return runningTestCaseName;
}

public static void setRunningTestCase(String currentlyRunningTestCaseName) {
runningTestCaseName = currentlyRunningTestCaseName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cz.xtf.core.context;

import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

import lombok.extern.slf4j.Slf4j;

/**
* Sets TestCaseContext to name of currently started test case in @BeforeAllCallback
*/
@Slf4j
public class TestCaseContextExtension implements BeforeAllCallback {

@Override
public void beforeAll(ExtensionContext extensionContext) {
TestCaseContext.setRunningTestCase(extensionContext.getTestClass().get().getName());
}
}
Loading

0 comments on commit b9e3f2f

Please sign in to comment.