Skip to content

Commit

Permalink
feat(webUI): run tests from the web interface
Browse files Browse the repository at this point in the history
Closes: #30
  • Loading branch information
nergal-perm committed Jul 1, 2024
1 parent 39f87b8 commit e5c1c20
Show file tree
Hide file tree
Showing 11 changed files with 316 additions and 151 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ If it is the assertion on a state, then it's the same format as in the initial s

## Running the tests

The tests are run by issuing the following command:
The tests are run by:

```bash
java -jar logic-checker.jar <absolute-path-to-the-project-folder>
```
1. starting the web server and passing the absolute path to the project folder as an argument:
```bash
java -jar logic-checker.jar <absolute-path-to-the-app-resources>
```
2. and then heading to the `http://localhost:8080/test` in the browser.
34 changes: 6 additions & 28 deletions src/main/java/ru/ewc/checklogic/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
*
* @since 0.3.0
*/
@SuppressWarnings("PMD.ProhibitPublicStaticMethods")
public final class FileUtils {
/**
* Primary hidden constructor.
Expand All @@ -48,36 +49,13 @@ private FileUtils() {
// Utility class
}

static InputStream applicationConfig(final String root) throws IOException {
public static InputStream applicationConfig(final String root) throws IOException {
return Files.newInputStream(Path.of(root, "application.yaml"));
}

/**
* Gets the path to a folder with specified resources.
*
* @param resource Resource name to get its folder.
* @return Path to a resource folder as a String.
*/
static String getFinalPathTo(final String resource) {
final String states;
if (System.getProperties().containsKey("sources")) {
states = String.format("%s/%s", System.getProperty("sources"), resource);
} else if (System.getProperties().containsKey(resource)) {
states = System.getProperty(resource);
} else {
states = String.format(
"%s%s%s",
System.getProperty("user.dir"),
"/src/test/resources/",
resource
);
}
return states;
}

@SneakyThrows
static Stream<LogicChecker.TestData> readFileNames() {
return Files.walk(Paths.get(Computation.uriFrom(getFinalPathTo("states"))))
public static Stream<TestData> readFileNames(final String root) {
return Files.walk(Path.of(root, "states"))
.filter(Files::isRegularFile)
.map(
path -> path.toFile().getAbsolutePath()
Expand All @@ -94,7 +72,7 @@ static Stream<LogicChecker.TestData> readFileNames() {
}

@SuppressWarnings("unchecked")
private static LogicChecker.TestData createTestData(
private static TestData createTestData(
final String path,
final InputStream stream
) {
Expand All @@ -110,7 +88,7 @@ private static LogicChecker.TestData createTestData(
if (iterator.hasNext()) {
expectations = (Map<String, Map<String, String>>) iterator.next();
}
return new LogicChecker.TestData(path, command, expectations);
return new TestData(path, command, expectations);
}

@SuppressWarnings("unchecked")
Expand Down
93 changes: 7 additions & 86 deletions src/main/java/ru/ewc/checklogic/LogicChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,18 @@

package ru.ewc.checklogic;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.SneakyThrows;
import org.assertj.core.api.SoftAssertions;
import org.yaml.snakeyaml.Yaml;
import ru.ewc.checklogic.server.WebServer;
import ru.ewc.decisions.api.ComputationContext;
import ru.ewc.decisions.api.Locator;
import ru.ewc.state.State;

/**
Expand All @@ -50,63 +45,26 @@
*/
@SuppressWarnings("PMD.ProhibitPublicStaticMethods")
public final class LogicChecker {
/**
* The logger.
*/
private static final Logger LOGGER = Logger.getLogger(LogicChecker.class.getName());

private LogicChecker() {
// Utility class
}

public static void main(final String[] args) throws IOException {
if (args.length == 0) {
if (args.length != 1) {
throw new IllegalArgumentException("Please provide the path to the resources");
}
final String root = args[0];
if (args.length > 1 && "server".equals(args[1])) {
final ComputationContext context = new ComputationContext(
stateFromAppConfig(FileUtils.applicationConfig(root)),
Path.of(root, "tables").toUri(),
Path.of(root, "commands").toUri()
);
new WebServer(new Computation(context)).start();
} else {
System.setProperty("sources", root);
final SoftAssertions softly = new SoftAssertions();
FileUtils.readFileNames().forEach(test -> performTest(test, softly, root));
}
new WebServer(new ServerContext(getContext(root)), root).start();
}

@SneakyThrows
static void performTest(
final TestData test,
final SoftAssertions softly,
final String root
) {
final Computation target = new Computation(
new ComputationContext(
stateFromFile(Files.newInputStream(new File(test.file()).toPath()), root),
Path.of(FileUtils.getFinalPathTo("tables")).toUri(),
Path.of(FileUtils.getFinalPathTo("commands")).toUri()
)
private static ComputationContext getContext(final String root) {
return new ComputationContext(
stateFromAppConfig(FileUtils.applicationConfig(root)),
Path.of(root, "tables").toUri(),
Path.of(root, "commands").toUri()
);
try {
if (!test.command.isEmpty()) {
target.perform(test.command);
}
for (final String locator : test.expectations.keySet()) {
softly
.assertThat(target.stateFor(locator, test.expectations.get(locator)))
.describedAs(String.format("State for entity '%s'", locator))
.containsExactlyInAnyOrderEntriesOf(test.expectations.get(locator));
}
softly.assertAll();
LOGGER.info("Running test for %s... done".formatted(test.toString()));
} catch (final AssertionError error) {
LOGGER.severe("Running test for %s... failed".formatted(test.toString()));
LOGGER.severe(error.getMessage());
}
}

@SneakyThrows
Expand All @@ -123,41 +81,4 @@ private static State stateFromAppConfig(final InputStream file) {
)
);
}

@SuppressWarnings("unchecked")
private static State stateFromFile(
final InputStream stream,
final String root
) throws IOException {
final Map<String, Object> config = new Yaml().load(FileUtils.applicationConfig(root));
final List<String> names = (List<String>) config.get("locators");
final Map<String, Locator> locators = HashMap.newHashMap(names.size());
names.forEach(name -> locators.put(name, new InMemoryStorage(new HashMap<>())));
final Map<String, Map<String, Object>> raw =
(Map<String, Map<String, Object>>) new Yaml().loadAll(stream).iterator().next();
raw.keySet().forEach(name -> locators.put(name, new InMemoryStorage(raw.get(name))));
return new State(locators);
}

/**
* I am the helper class containing the data for parameterized state tests.
*
* @param file The path to the file containing state and expectations.
* @param command The name of the command to execute before the decision.
* @param expectations The collection of expected decision table results.
* @since 0.2.3
*/
public record TestData(
String file,
String command,
Map<String, Map<String, String>> expectations) {

@Override
public String toString() {
final String test = this.file
.substring(Math.max(0, this.file.lastIndexOf('\\')))
.substring(Math.max(0, this.file.lastIndexOf('/')));
return String.format("file='%s'", test);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

package ru.ewc.checklogic;

import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -36,32 +35,16 @@
* @since 0.1.0
*/
@SuppressWarnings("PMD.ProhibitPublicStaticMethods")
public final class Computation {
public final class ServerContext {
/**
* The context of the computation.
*/
private final ComputationContext context;

public Computation(final ComputationContext context) {
public ServerContext(final ComputationContext context) {
this.context = context;
}

/**
* Converts a string representation of the file system path to a correct URI.
*
* @param path File system path as a String.
* @return URI that corresponds to a given path.
*/
public static URI uriFrom(final String path) {
final StringBuilder result = new StringBuilder("file:/");
if (path.charAt(0) == '/') {
result.append(path.replace('\\', '/').substring(1));
} else {
result.append(path.replace('\\', '/'));
}
return URI.create(result.toString());
}

public void perform(final String command) {
this.context.perform(command);
}
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/ru/ewc/checklogic/TestData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* MIT License
*
* Copyright (c) 2024 Decision-Driven Development
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package ru.ewc.checklogic;

import java.util.Map;

/**
* I am the helper class containing the data for parameterized state tests.
*
* @param file The path to the file containing state and expectations.
* @param command The name of the command to execute before the decision.
* @param expectations The collection of expected decision table results.
* @since 0.2.3
*/
public record TestData(
String file,
String command,
Map<String, Map<String, String>> expectations) {

@Override
public String toString() {
final String test = this.file
.substring(Math.max(0, this.file.lastIndexOf('\\')))
.substring(Math.max(0, this.file.lastIndexOf('/')));
return String.format("file='%s'", test);
}
}
50 changes: 50 additions & 0 deletions src/main/java/ru/ewc/checklogic/TestResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* MIT License
*
* Copyright (c) 2024 Decision-Driven Development
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package ru.ewc.checklogic;

public record TestResult(
String file,
boolean successful,
String error
) {

public String result() {
final String result;
if (this.successful) {
result = "PASS";
} else {
result = "FAIL";
}
return result;
}

public String asHtmlTableRow() {
return String.format(
"<tr><td>%s</td><td>%s</td><td>%s</td></tr>",
this.file,
this.result(),
this.error
);
}
}
6 changes: 3 additions & 3 deletions src/main/java/ru/ewc/checklogic/server/CommandPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import com.renomad.minum.web.Response;
import com.renomad.minum.web.WebFramework;
import java.util.Map;
import ru.ewc.checklogic.Computation;
import ru.ewc.checklogic.ServerContext;
import ru.ewc.decisions.api.DecitaException;

/**
Expand All @@ -40,7 +40,7 @@ public final class CommandPage implements Endpoints {
/**
* The computation to be used for the command processing.
*/
private final Computation computation;
private final ServerContext computation;

/**
* The template processor for the Command page.
Expand All @@ -57,7 +57,7 @@ public final class CommandPage implements Endpoints {
*
* @param computation The computation to be used for the command processing.
*/
public CommandPage(final Computation computation) {
public CommandPage(final ServerContext computation) {
this.computation = computation;
this.description = TemplateProcessor.buildProcessor(
WebResource.readFileFromResources("templates/command-info.html")
Expand Down
Loading

0 comments on commit e5c1c20

Please sign in to comment.