Skip to content
This repository has been archived by the owner on Aug 30, 2023. It is now read-only.

Commit

Permalink
Support sequential execution of several tests suites
Browse files Browse the repository at this point in the history
Introduced SequentialExecution class gives ability to run several
suites sequentially and reports aggregated report for them. This change
gives more freedom in defining tests suites and the combinations of the
tests setups.

#134
  • Loading branch information
extsoft committed Feb 8, 2019
1 parent c62c73b commit 103882e
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 2 deletions.
16 changes: 16 additions & 0 deletions docs/md/entry-points.md
Expand Up @@ -115,3 +115,19 @@ new Sun(
)
).shine();
```

### Sequential execution of `Kernel`s
There is a suite of tests which needs to be checked with several different listeners. For instance,
if a listener is not configured, the tests will use some cache, otherwise, no cache before each test.
And we have to run the suite with and without the listener.

There is a specific `Kernel` called `SequentialExecution` which allows execution of described use case:
```java
final Kernel<ITestNGListener> suite = new TestNGKernel(....);
new Sun(
new SequentialExecution<>(
suite,
suite.with(new CleanCacheListener())
)
).shine();
```
@@ -0,0 +1,70 @@
package org.tatools.sunshine.core;

import java.util.List;

/**
* The class represents several {@link Status}es as a single instance.
*
* @author Dmytro Serdiuk (dmytro.serdiuk@gmail.com)
* @version $Id$
*/
public final class CompositeStatus implements Status {

private final List<Status> sources;

/**
* Constructs a new instance.
*
* @param statuses available statuses
*/
public CompositeStatus(List<Status> statuses) {
this.sources = statuses;
}

/**
* Returns the exit code of an execution provided by xunit tests runner.
* <p>
* The code will be a maximum value from all available codes expect zero ones. If there is no
* maximal value, 0 is given (means all are passed), otherwise, a non-zero number (if there is at least one failure).
*
* @return a calculated exit code
*/
@Override
public short code() {
return this.sources.stream()
.map(Status::code)
.filter(code -> code != 0)
.max(Short::compareTo)
.orElse((short) 0);
}

/**
* Returns a sum of all tests of all statuses.
*
* @return a count of total tests
*/
@Override
public int runCount() {
return this.sources.stream().mapToInt(Status::runCount).sum();
}

/**
* Returns a sum of failed tests of all statuses.
*
* @return a count of failed tests
*/
@Override
public int failureCount() {
return this.sources.stream().mapToInt(Status::failureCount).sum();
}

/**
* Returns a sum of ignored tests of all statuses.
*
* @return a count of ignored tests
*/
@Override
public int ignoreCount() {
return this.sources.stream().mapToInt(Status::ignoreCount).sum();
}
}
29 changes: 27 additions & 2 deletions sunshine-core/src/main/java/org/tatools/sunshine/core/Kernel.java
@@ -1,5 +1,9 @@
package org.tatools.sunshine.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* The {@link Kernel} interface declares a way to implement different xnit test runners.
*
Expand Down Expand Up @@ -28,9 +32,26 @@ public interface Kernel<Listener> {
final class Fake implements Kernel {

private final Status result;
private final List<Object> listeners;

/**
* Constructs a new object. All listeners are stored internally.
*
* @param status a status of the execution
*/
public Fake(Status status) {
this(status, new ArrayList<>());
}

/**
* Constructs a new object.
*
* @param status a status of the execution
* @param availableListeners a list which will store all listeners
*/
public Fake(Status status, List<Object> availableListeners) {
this.result = status;
this.listeners = availableListeners;
}

@Override
Expand All @@ -39,8 +60,12 @@ public Status status() {
}

@Override
public Kernel<?> with(Object[] objects) {
return null;
public Kernel<?> with(Object... objects) {
this.listeners.addAll(Arrays.asList(objects));
return new Fake(
this.result,
this.listeners
);
}
}
}
@@ -0,0 +1,44 @@
package org.tatools.sunshine.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
* The class encapsulates several {@link Kernel}s and runs them sequentially.
*
* @author Dmytro Serdiuk (dmytro.serdiuk@gmail.com)
* @version $Id$
*/
public class SequentialExecution<Listener> implements Kernel<Listener> {

private final List<Kernel<Listener>> elements;

@SafeVarargs
public SequentialExecution(Kernel<Listener>... kernels) {
this(Arrays.asList(kernels));
}

public SequentialExecution(List<Kernel<Listener>> kernels) {
this.elements = kernels;
}

@Override
public Status status() throws KernelException {
final List<Status> results = new ArrayList<>();
for (Kernel<Listener> kernel : this.elements) {
results.add(kernel.status());
}
return new CompositeStatus(results);
}

@Override
public Kernel<Listener> with(Listener... listeners) {
return new SequentialExecution<>(
this.elements.stream()
.map(listenerKernel -> listenerKernel.with(listeners))
.collect(Collectors.toList())
);
}
}
@@ -0,0 +1,72 @@
package org.tatools.sunshine.core;

import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Test;

import java.util.Arrays;

/**
* @author Dmytro Serdiuk (dmytro.serdiuk@gmail.com)
* @version $Id$
*/
public class CompositeStatusTest {

@Test
public void testZeroCode() {
MatcherAssert.assertThat(
new CompositeStatus(Arrays.asList(new Status.Fake(), new Status.Fake())).code(),
Matchers.is((short) 0)
);
}

@Test
public void testNonZeroPositiveCode() {
MatcherAssert.assertThat(
new CompositeStatus(Arrays.asList(
new Status.Fake((short) 3, 0, 1, 1), new Status.Fake((short) 2, 0, 1, 1)
)).code(),
Matchers.is((short) 3)
);
}

@Test
public void testNonZeroNegativeCode() {
MatcherAssert.assertThat(
new CompositeStatus(Arrays.asList(
new Status.Fake((short) -3, 0, 1, 1), new Status.Fake((short) 0, 0, 1, 1)
)).code(),
Matchers.is((short) -3)
);
}

@Test
public void testSumOfRunCount() {
MatcherAssert.assertThat(
new CompositeStatus(Arrays.asList(
new Status.Fake((short) 3, 1, 2, 3), new Status.Fake((short) 2, 4, 5, 6)
)).runCount(),
Matchers.is(5)
);
}

@Test
public void testSumOfFailureCount() {
MatcherAssert.assertThat(
new CompositeStatus(Arrays.asList(
new Status.Fake((short) 3, 1, 2, 3), new Status.Fake((short) 2, 4, 5, 6)
)).failureCount(),
Matchers.is(7)
);
}

@Test
public void testSumOfIgnoreCount() {
MatcherAssert.assertThat(
new CompositeStatus(Arrays.asList(
new Status.Fake((short) 3, 1, 2, 3), new Status.Fake((short) 2, 4, 5, 6)
)).ignoreCount(),
Matchers.is(9)
);
}
}
@@ -0,0 +1,33 @@
package org.tatools.sunshine.core;

import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
* @author Dmytro Serdiuk (dmytro.serdiuk@gmail.com)
* @version $Id$
*/
public class SequentialExecutionTest {

@Test
public void testStatus() throws KernelException {
MatcherAssert.assertThat(
new SequentialExecution<Object>(
new Kernel.Fake(new Status.Fake()),
new Kernel.Fake(new Status.Fake((short) 1, 2, 1, 1))
).status().code(),
Matchers.is((short) 1)
);
}

@Test
public void testWithListeners() {
final List<Object> listeners = new ArrayList<>();
new SequentialExecution<Object>(new Kernel.Fake(new Status.Fake(), listeners)).with(new Object());
MatcherAssert.assertThat(listeners, Matchers.hasSize(1));
}
}

0 comments on commit 103882e

Please sign in to comment.