Skip to content

Commit

Permalink
test(server): testing the web server config page
Browse files Browse the repository at this point in the history
Refs: #52
  • Loading branch information
nergal-perm committed Aug 3, 2024
1 parent 43fdf3f commit cf63771
Show file tree
Hide file tree
Showing 10 changed files with 305 additions and 86 deletions.
119 changes: 119 additions & 0 deletions src/main/java/ru/ewc/checklogic/FileStateFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* 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.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.SneakyThrows;
import org.yaml.snakeyaml.Yaml;
import ru.ewc.decisions.api.Locator;
import ru.ewc.state.State;

/**
* I am a factory for creating the state of the system.
*
* @since 0.3.2
*/
public final class FileStateFactory extends StateFactory {

/**
* Optional source of locators to be added to the initial (clean) state.
*/
private InputStream src;

public FileStateFactory(final String root) {
super(root);
}

@Override
@SneakyThrows
public State initialState() {
State state;
try (InputStream file = Files.newInputStream(Path.of(this.getRoot(), "application.yaml"))) {
state = FileStateFactory.stateFromAppConfig(file);
state.locators().putAll(this.locatorsFromFile());
} catch (final NoSuchFileException exception) {
state = new NullState(Map.of());
}
return state;
}

@Override
public StateFactory with(final InputStream file) {
this.src = file;
return this;
}

@Override
@SneakyThrows
public void initialize() {
final File config = Path.of(this.getRoot(), "application.yaml").toFile();
if (!config.exists() && config.createNewFile()) {
try (OutputStream out = Files.newOutputStream(config.toPath())) {
out.write("locators:\n - request\n".getBytes(StandardCharsets.UTF_8));
}
}
}

@SuppressWarnings("unchecked")
private Map<String, Locator> locatorsFromFile() {
final Map<String, Locator> locators = new HashMap<>();
if (this.src != null) {
final Map<String, Map<String, Object>> raw =
(Map<String, Map<String, Object>>) new Yaml().loadAll(this.src).iterator().next();
if (raw == null) {
throw new IllegalStateException(
"There is no Arrange section in the test file, you should add one"
);
}
raw.forEach((name, data) -> locators.put(name, new InMemoryStorage(data)));
}
return locators;
}

@SneakyThrows
@SuppressWarnings("unchecked")
private static State stateFromAppConfig(final InputStream file) {
final Map<String, Object> config = new Yaml().load(file);
final Stream<String> names = ((List<String>) config.get("locators")).stream();
return new State(
names.collect(
Collectors.toMap(
name -> name,
name -> new InMemoryStorage(new HashMap<>())
)
)
);
}
}
5 changes: 4 additions & 1 deletion src/main/java/ru/ewc/checklogic/FullServerContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ public final class FullServerContext {
*/
private final StateFactory states;

// @todo #52 Create the testable instance of FullServerContext
FullServerContext(
final StateFactory initial,
final URI tables,
Expand All @@ -90,6 +89,10 @@ public final class FullServerContext {
this.context = new ComputationContext(this.state, tables, commands);
}

public static FullServerContext testable() {
return ServerContextFactory.testable().initialState();
}

public void perform(final String command) {
this.perform(command, Map.of());
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/ru/ewc/checklogic/LogicChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static void main(final String[] args) {
throw new IllegalArgumentException("Please provide the path to the resources");
}
final String root = args[0];
final FullServerContext context = new ServerContextFactory(root).initialState();
final FullServerContext context = ServerContextFactory.create(root).initialState();
final FullSystem minum = FullSystem.initialize();
final WebFramework web = minum.getWebFramework();
registerEndpoints(web, new CommandPage(context));
Expand Down
59 changes: 59 additions & 0 deletions src/main/java/ru/ewc/checklogic/MockStateFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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.io.InputStream;
import java.util.Map;
import ru.ewc.state.State;

/**
* I am a mock state factory for testing purposes.
*
* @since 0.3.2
*/
public final class MockStateFactory extends StateFactory {
public MockStateFactory(final String root) {
super(root);
}

@Override
public State initialState() {
return new State(
Map.of(
"locator", new InMemoryStorage(Map.of("fragment", "value")),
"request", new InMemoryStorage(Map.of())
)
);
}

@Override
public StateFactory with(final InputStream file) {
return this;
}

@Override
public void initialize() {
// do nothing
}
}
23 changes: 19 additions & 4 deletions src/main/java/ru/ewc/checklogic/ServerContextFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,29 @@
*
* @since 0.3.2
*/
public class ServerContextFactory {
@SuppressWarnings("PMD.ProhibitPublicStaticMethods")
public final class ServerContextFactory {
/**
* The root path for the external business logic resources.
*/
private final String root;

public ServerContextFactory(final String root) {
/**
* The factory for creating the state of the system.
*/
private final StateFactory factory;

private ServerContextFactory(final String root, final StateFactory factory) {
this.root = root;
this.factory = factory;
}

public static ServerContextFactory testable() {
return new ServerContextFactory("root folder", new MockStateFactory("root folder"));
}

public static ServerContextFactory create(final String root) {
return new ServerContextFactory(root, new FileStateFactory(root));
}

/**
Expand All @@ -48,7 +63,7 @@ public ServerContextFactory(final String root) {
*/
public FullServerContext initialState() {
final FullServerContext result = new FullServerContext(
new StateFactory(this.root),
this.factory,
Path.of(this.root, "tables").toUri(),
Path.of(this.root, "commands").toUri(),
new WebServerContext()
Expand All @@ -67,7 +82,7 @@ public FullServerContext initialState() {
*/
public FullServerContext fromStateFile(final InputStream file) {
return new FullServerContext(
new StateFactory(this.root).with(file),
this.factory.with(file),
Path.of(this.root, "tables").toUri(),
Path.of(this.root, "commands").toUri(),
new WebServerContext()
Expand Down
91 changes: 14 additions & 77 deletions src/main/java/ru/ewc/checklogic/StateFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,101 +23,38 @@
*/
package ru.ewc.checklogic;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.Getter;
import lombok.SneakyThrows;
import org.yaml.snakeyaml.Yaml;
import ru.ewc.decisions.api.Locator;
import ru.ewc.state.State;

/**
* I am a factory for creating the state of the system.
* I am a factory for creating state objects. My subclasses are responsible for creating the initial
* state and loading the state from a file. They can do that for real or mock the result for testing
* purposes.
*
* @since 0.3.2
*/
public final class StateFactory {
public abstract class StateFactory {
/**
* The root path for the external business logic resources.
*/
@Getter
private final String root;

/**
* Optional source of locators to be added to the initial (clean) state.
*/
private InputStream src;

// @todo #54 Create testable instance of StateFactory
public StateFactory(final String root) {
this.root = root;
}

@SneakyThrows
public State initialState() {
State state;
try (InputStream file = Files.newInputStream(Path.of(this.root, "application.yaml"))) {
state = StateFactory.stateFromAppConfig(file);
state.locators().putAll(this.locatorsFromFile());
} catch (final NoSuchFileException exception) {
state = new NullState(Map.of());
}
return state;
}

public StateFactory with(final InputStream file) {
this.src = file;
return this;
/**
* Returns the path to the root folder of the external business logic resources.
*
* @return Path to the root folder as a string.
*/
public String getRoot() {
return this.root;
}

@SneakyThrows
public void initialize() {
final File config = Path.of(this.root, "application.yaml").toFile();
if (!config.exists() && config.createNewFile()) {
try (OutputStream out = Files.newOutputStream(config.toPath())) {
out.write("locators:\n - request\n".getBytes(StandardCharsets.UTF_8));
}
}
}
public abstract State initialState();

@SuppressWarnings("unchecked")
private Map<String, Locator> locatorsFromFile() {
final Map<String, Locator> locators = new HashMap<>();
if (this.src != null) {
final Map<String, Map<String, Object>> raw =
(Map<String, Map<String, Object>>) new Yaml().loadAll(this.src).iterator().next();
if (raw == null) {
throw new IllegalStateException(
"There is no Arrange section in the test file, you should add one"
);
}
raw.forEach((name, data) -> locators.put(name, new InMemoryStorage(data)));
}
return locators;
}
public abstract StateFactory with(InputStream file);

@SneakyThrows
@SuppressWarnings("unchecked")
private static State stateFromAppConfig(final InputStream file) {
final Map<String, Object> config = new Yaml().load(file);
final Stream<String> names = ((List<String>) config.get("locators")).stream();
return new State(
names.collect(
Collectors.toMap(
name -> name,
name -> new InMemoryStorage(new HashMap<>())
)
)
);
}
public abstract void initialize();
}
6 changes: 4 additions & 2 deletions src/main/java/ru/ewc/checklogic/server/ContextPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void register(final WebFramework web) {
web.registerPath(POST, "context", this::contextPage);
}

private Response contextPage(final Request request) {
Response contextPage(final Request request) {
this.context.cache("command", request.body().asString("availOutcome"));
this.context.cache("request", request.body().asString("reqLocator"));
this.updateContext(request.body().asString("reqValues"));
Expand All @@ -66,6 +66,8 @@ private String availabilityField() {

private void updateContext(final String values) {
final String decoded = URLDecoder.decode(values, StandardCharsets.UTF_8);
this.context.update(Arrays.stream(decoded.split("\n")).collect(Collectors.toList()));
if (!decoded.isBlank()) {
this.context.update(Arrays.stream(decoded.split("\n")).collect(Collectors.toList()));
}
}
}
Loading

2 comments on commit cf63771

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on cf63771 Aug 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 52-7cb7fe64 disappeared from src/main/java/ru/ewc/checklogic/FullServerContext.java), that's why I closed #54. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on cf63771 Aug 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 54-b58b0925 disappeared from src/main/java/ru/ewc/checklogic/StateFactory.java), that's why I closed #55. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

Please sign in to comment.