From 3d47d3efcec1cda1b011e3741ac4d92dcad2d662 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 14:15:40 +0100 Subject: [PATCH 01/36] JwtTokenNeededFilter : skipTokenValidityCheck becomes final Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/ws/server/utils/JwtTokenNeededFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afs-ws/afs-ws-server-utils/src/main/java/com/powsybl/afs/ws/server/utils/JwtTokenNeededFilter.java b/afs-ws/afs-ws-server-utils/src/main/java/com/powsybl/afs/ws/server/utils/JwtTokenNeededFilter.java index 573c0b42..4aed0a88 100644 --- a/afs-ws/afs-ws-server-utils/src/main/java/com/powsybl/afs/ws/server/utils/JwtTokenNeededFilter.java +++ b/afs-ws/afs-ws-server-utils/src/main/java/com/powsybl/afs/ws/server/utils/JwtTokenNeededFilter.java @@ -38,7 +38,7 @@ public class JwtTokenNeededFilter implements ContainerRequestFilter { @Inject private KeyGenerator keyGenerator; - private boolean skipTokenValidityCheck; + private final boolean skipTokenValidityCheck; public JwtTokenNeededFilter() { this(PlatformConfig.defaultConfig()); From c5646a2aafda5b865f11de65367a1fb4aa365ba9 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 14:44:06 +0100 Subject: [PATCH 02/36] Clean Utils Signed-off-by: Nicolas Rol --- .../java/com/powsybl/afs/storage/Utils.java | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/afs-storage-api/src/main/java/com/powsybl/afs/storage/Utils.java b/afs-storage-api/src/main/java/com/powsybl/afs/storage/Utils.java index b6c83e30..41dc5d30 100644 --- a/afs-storage-api/src/main/java/com/powsybl/afs/storage/Utils.java +++ b/afs-storage-api/src/main/java/com/powsybl/afs/storage/Utils.java @@ -38,28 +38,27 @@ private Utils() throws IllegalAccessException { /** * zip a directory * - * @param dir directory path to zip + * @param dir directory path to zip * @param zipPath path to the zip to create * @throws IllegalArgumentException IllegalArgumentException */ public static void zip(Path dir, Path zipPath, boolean deleteDirectory) throws IOException { try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(zipPath)); - Stream walk = Files.walk(dir);) { + Stream walk = Files.walk(dir)) { walk.filter(someFileToZip -> !someFileToZip.equals(dir)) - .forEach( - someFileToZip -> { - Path pathInZip = dir.relativize(someFileToZip); - try { - if (Files.isDirectory(someFileToZip)) { - addDirectory(zos, pathInZip); - } else { - addFile(zos, someFileToZip, pathInZip); - } - } catch (IOException e) { - throw new AfsStorageException(e.getMessage()); - } - - }); + .forEach(someFileToZip -> { + Path pathInZip = dir.relativize(someFileToZip); + try { + if (Files.isDirectory(someFileToZip)) { + addDirectory(zos, pathInZip); + } else { + addFile(zos, someFileToZip, pathInZip); + } + } catch (IOException e) { + throw new AfsStorageException(e.getMessage()); + } + + }); } catch (IOException | AfsStorageException e) { throw new IOException(e); } @@ -71,6 +70,7 @@ public static void zip(Path dir, Path zipPath, boolean deleteDirectory) throws I /** * Check that there is enough space on the disk + * * @param dir directory to save * @throws IOException IOException */ @@ -91,18 +91,24 @@ public static void checkDiskSpace(Path dir) throws IOException { */ public static void unzip(Path zipPath, Path nodeDir) throws IOException { try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(zipPath))) { - Files.createDirectory(nodeDir); - ZipEntry entry = zis.getNextEntry(); - while (entry != null) { - Path outputEntryPath = nodeDir.resolve(entry.getName()); - if (entry.isDirectory() && !Files.exists(outputEntryPath)) { - Files.createDirectory(outputEntryPath); - } else if (!entry.isDirectory()) { + Files.createDirectories(nodeDir); + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + Path outputEntryPath = nodeDir.resolve(entry.getName()).normalize(); + + // Validation against Zip Slip + if (!outputEntryPath.startsWith(nodeDir)) { + throw new IOException("Invalid path detected: " + entry.getName()); + } + + if (entry.isDirectory()) { + Files.createDirectories(outputEntryPath); + } else { + Files.createDirectories(outputEntryPath.getParent()); try (OutputStream fos = Files.newOutputStream(outputEntryPath)) { ByteStreams.copy(zis, fos); } } - entry = zis.getNextEntry(); } zis.closeEntry(); } @@ -126,7 +132,6 @@ private static void addFile(ZipOutputStream zos, Path filePath, Path zipFilePath * delete directory * * @param directoryToBeDeleted directory to be deleted - * @return true if directory deleted */ public static void deleteDirectory(Path directoryToBeDeleted) throws IOException { if (Files.isDirectory(directoryToBeDeleted)) { From 3aff3ea9e6aeded260bd108427a192fd86b347de Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 15:11:32 +0100 Subject: [PATCH 03/36] Create SafeLogger class and use it Signed-off-by: Nicolas Rol --- afs-core/pom.xml | 10 ++- .../main/java/com/powsybl/afs/SafeLogger.java | 65 +++++++++++++++++++ .../afs/ws/storage/RemoteTaskMonitor.java | 9 +-- pom.xml | 6 ++ 4 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 afs-core/src/main/java/com/powsybl/afs/SafeLogger.java diff --git a/afs-core/pom.xml b/afs-core/pom.xml index aa9fdf92..a24e78f9 100644 --- a/afs-core/pom.xml +++ b/afs-core/pom.xml @@ -55,14 +55,18 @@ + + ${project.groupId} + powsybl-afs-storage-api + ${project.version} + com.powsybl powsybl-computation-local - ${project.groupId} - powsybl-afs-storage-api - ${project.version} + org.owasp.encoder + encoder diff --git a/afs-core/src/main/java/com/powsybl/afs/SafeLogger.java b/afs-core/src/main/java/com/powsybl/afs/SafeLogger.java new file mode 100644 index 00000000..e08b0188 --- /dev/null +++ b/afs-core/src/main/java/com/powsybl/afs/SafeLogger.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025, RTE (https://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.afs; + +import org.owasp.encoder.Encode; +import org.slf4j.Logger; + +import java.util.Arrays; + +/** + * @author Nicolas Rol {@literal } + */ +public class SafeLogger { + private final Logger logger; + + public SafeLogger(Logger logger) { + this.logger = logger; + } + + public void error(String message, Object... args) { + logger.error(message, sanitizeInputs(args)); + } + + public void warn(String message, Object... args) { + logger.warn(message, sanitizeInputs(args)); + } + + public void debug(String message, Object... args) { + logger.debug(message, sanitizeInputs(args)); + } + + public void info(String message, Object... args) { + logger.info(message, sanitizeInputs(args)); + } + + public void trace(String message, Object... args) { + logger.trace(message, sanitizeInputs(args)); + } + + private Object[] sanitizeInputs(Object... args) { + return Arrays.stream(args) + .map(this::sanitizeObject) + .toArray(); + } + + private Object sanitizeObject(Object arg) { + if (arg instanceof String string) { + return sanitizeInput(string); + } + return arg; + } + + private String sanitizeInput(String input) { + if (input == null) { + return null; + } + return Encode.forJava(input.replaceAll("[\r\n\t]", "_")); + } +} + diff --git a/afs-ws/afs-ws-storage/src/main/java/com/powsybl/afs/ws/storage/RemoteTaskMonitor.java b/afs-ws/afs-ws-storage/src/main/java/com/powsybl/afs/ws/storage/RemoteTaskMonitor.java index 70b9aab9..339020c8 100644 --- a/afs-ws/afs-ws-storage/src/main/java/com/powsybl/afs/ws/storage/RemoteTaskMonitor.java +++ b/afs-ws/afs-ws-storage/src/main/java/com/powsybl/afs/ws/storage/RemoteTaskMonitor.java @@ -8,13 +8,13 @@ import com.powsybl.afs.Project; import com.powsybl.afs.ProjectFile; +import com.powsybl.afs.SafeLogger; import com.powsybl.afs.TaskListener; import com.powsybl.afs.TaskMonitor; import com.powsybl.afs.ws.client.utils.ClientUtils; import com.powsybl.afs.ws.client.utils.UncheckedDeploymentException; import com.powsybl.afs.ws.utils.AfsRestApi; import com.powsybl.afs.ws.utils.JsonProvider; -import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jakarta.websocket.ContainerProvider; @@ -27,6 +27,7 @@ import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; + import java.io.IOException; import java.io.UncheckedIOException; import java.net.URI; @@ -45,8 +46,8 @@ */ public class RemoteTaskMonitor implements TaskMonitor { - private static final Logger LOGGER = LoggerFactory.getLogger(RemoteTaskMonitor.class); public static final String FILE_SYSTEM_NAME = "fileSystemName"; + private static final SafeLogger LOGGER = new SafeLogger(LoggerFactory.getLogger(RemoteTaskMonitor.class)); private static final String TASK_ID = "taskId"; private static final String TASK_PATH = "fileSystems/{fileSystemName}/tasks"; @@ -68,7 +69,7 @@ public RemoteTaskMonitor(String fileSystemName, URI restUri, String token) { this.token = token; client = ClientUtils.createClient() - .register(new JsonProvider()); + .register(new JsonProvider()); webTarget = getWebTarget(client, restUri); } @@ -169,7 +170,7 @@ public void addListener(TaskListener listener) { URI wsUri = SocketsUtils.getWebSocketUri(restUri); URI endPointUri = URI.create(wsUri + "/messages/" + AfsRestApi.RESOURCE_ROOT + "/" + - AfsRestApi.VERSION + "/task_events/" + fileSystemName + "/" + listener.getProjectId()); + AfsRestApi.VERSION + "/task_events/" + fileSystemName + "/" + listener.getProjectId()); LOGGER.debug("Connecting to task event websocket for file system {} at {}", fileSystemName, endPointUri); diff --git a/pom.xml b/pom.xml index 38a5962e..83a4a50d 100644 --- a/pom.xml +++ b/pom.xml @@ -95,6 +95,7 @@ 3.13.0 1.9.18 5.12.0 + 1.3.1 6.2.10.Final 2.0.13 3.4.0 @@ -336,6 +337,11 @@ mapdb ${mapdb.version} + + org.owasp.encoder + encoder + ${owasp.version} + org.slf4j slf4j-api From 60ae9562d5ce6f3fd95209ee4008154987f33aad Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 15:13:36 +0100 Subject: [PATCH 04/36] add comment Signed-off-by: Nicolas Rol --- afs-core/src/main/java/com/powsybl/afs/SafeLogger.java | 1 + 1 file changed, 1 insertion(+) diff --git a/afs-core/src/main/java/com/powsybl/afs/SafeLogger.java b/afs-core/src/main/java/com/powsybl/afs/SafeLogger.java index e08b0188..60a26c74 100644 --- a/afs-core/src/main/java/com/powsybl/afs/SafeLogger.java +++ b/afs-core/src/main/java/com/powsybl/afs/SafeLogger.java @@ -13,6 +13,7 @@ import java.util.Arrays; /** + * Logger based on slf4j where all String inputs are sanitized * @author Nicolas Rol {@literal } */ public class SafeLogger { From 1e520f07906765bd2894618deccb8ca73ff563bb Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 15:20:54 +0100 Subject: [PATCH 05/36] clean EventsTest Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/ext/base/EventsTest.java | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/EventsTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/EventsTest.java index 05826e00..864b9159 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/EventsTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/EventsTest.java @@ -11,58 +11,64 @@ import com.powsybl.afs.ext.base.events.VirtualCaseCreated; import org.junit.jupiter.api.Test; -import java.io.IOException; +import java.nio.file.Path; import java.nio.file.Paths; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * @author Geoffroy Jamgotchian {@literal } */ class EventsTest { + private final Path path = Paths.get("/tmp/foo"); @Test - void caseImportedTest() throws IOException { - CaseImported caseImported = new CaseImported("a", "b", Paths.get("/tmp/foo").toString()); + void caseImportedTest() { + CaseImported caseImported = new CaseImported("a", "b", path.toString()); assertEquals("a", caseImported.getId()); assertEquals(CaseImported.TYPENAME, caseImported.getType()); assertEquals("b", caseImported.getParentId()); assertNotNull(caseImported.toString()); - assertEquals(Paths.get("/tmp/foo").toString(), caseImported.getPath()); + assertEquals(path.toString(), caseImported.getPath()); - CaseImported caseImported2 = new CaseImported("a", "c", Paths.get("/tmp/foo").toString()); + CaseImported caseImported2 = new CaseImported("a", "c", path.toString()); assertNotEquals(caseImported, caseImported2); assertNotEquals(caseImported.hashCode(), caseImported2.hashCode()); - assertNotEquals(caseImported, new ScriptModified("", "", Paths.get("/tmp/foo").toString())); + Object scriptModified = new ScriptModified("", "", path.toString()); + assertNotEquals(caseImported, scriptModified); } @Test - void scriptModifiedTest() throws IOException { - ScriptModified scriptModified = new ScriptModified("a", "b", Paths.get("/tmp/foo").toString()); + void scriptModifiedTest() { + ScriptModified scriptModified = new ScriptModified("a", "b", path.toString()); assertEquals("a", scriptModified.getId()); assertEquals(ScriptModified.TYPENAME, scriptModified.getType()); assertEquals("b", scriptModified.getParentId()); assertNotNull(scriptModified.toString()); - ScriptModified scriptModified2 = new ScriptModified("a", "c", Paths.get("/tmp/foo").toString()); + ScriptModified scriptModified2 = new ScriptModified("a", "c", path.toString()); assertNotEquals(scriptModified, scriptModified2); assertNotEquals(scriptModified.hashCode(), scriptModified2.hashCode()); - assertNotEquals(scriptModified, new CaseImported("", "", Paths.get("/tmp/foo").toString())); + Object caseImported = new CaseImported("", "", path.toString()); + assertNotEquals(caseImported, scriptModified); } @Test - void virtualCaseCreatedTest() throws IOException { - VirtualCaseCreated virtualCaseCreated = new VirtualCaseCreated("a", "b", Paths.get("/tmp/foo").toString()); + void virtualCaseCreatedTest() { + VirtualCaseCreated virtualCaseCreated = new VirtualCaseCreated("a", "b", path.toString()); assertEquals("a", virtualCaseCreated.getId()); assertEquals(VirtualCaseCreated.TYPENAME, virtualCaseCreated.getType()); assertEquals("b", virtualCaseCreated.getParentId()); assertNotNull(virtualCaseCreated.toString()); - assertEquals(Paths.get("/tmp/foo").toString(), virtualCaseCreated.getPath()); + assertEquals(path.toString(), virtualCaseCreated.getPath()); - VirtualCaseCreated virtualCaseCreated2 = new VirtualCaseCreated("a", "c", Paths.get("/tmp/foo").toString()); + VirtualCaseCreated virtualCaseCreated2 = new VirtualCaseCreated("a", "c", path.toString()); assertNotEquals(virtualCaseCreated, virtualCaseCreated2); assertNotEquals(virtualCaseCreated.hashCode(), virtualCaseCreated2.hashCode()); - assertNotEquals(virtualCaseCreated, new CaseImported("", "", Paths.get("/tmp/foo").toString())); + Object caseImported = new CaseImported("", "", path.toString()); + assertNotEquals(caseImported, virtualCaseCreated); } } From 3ac12fcc55954e8f23792d9d5907175578631a82 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 15:30:24 +0100 Subject: [PATCH 06/36] use regex: !([\w().]+)\.isPresent\(\) to replace !isPresent by isEmpty() Signed-off-by: Nicolas Rol --- afs-core/src/main/java/com/powsybl/afs/Node.java | 2 +- .../src/main/java/com/powsybl/afs/ext/base/VirtualCase.java | 2 +- .../java/com/powsybl/afs/security/SecurityAnalysisRunner.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/afs-core/src/main/java/com/powsybl/afs/Node.java b/afs-core/src/main/java/com/powsybl/afs/Node.java index 7c8978bb..c0f31d6d 100644 --- a/afs-core/src/main/java/com/powsybl/afs/Node.java +++ b/afs-core/src/main/java/com/powsybl/afs/Node.java @@ -41,7 +41,7 @@ public Optional getParent() { } private static boolean pathStop(Node node) { - return !node.getParent().isPresent(); + return node.getParent().isEmpty(); } private static String pathToString(List path) { diff --git a/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/VirtualCase.java b/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/VirtualCase.java index 92bc2a19..1b681828 100644 --- a/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/VirtualCase.java +++ b/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/VirtualCase.java @@ -109,6 +109,6 @@ protected List invalidate() { @Override public boolean mandatoryDependenciesAreMissing() { - return !getCase().isPresent() || !getScript().isPresent(); + return getCase().isEmpty() || getScript().isEmpty(); } } diff --git a/afs-security-analysis/src/main/java/com/powsybl/afs/security/SecurityAnalysisRunner.java b/afs-security-analysis/src/main/java/com/powsybl/afs/security/SecurityAnalysisRunner.java index d30a11c5..b881e2e9 100644 --- a/afs-security-analysis/src/main/java/com/powsybl/afs/security/SecurityAnalysisRunner.java +++ b/afs-security-analysis/src/main/java/com/powsybl/afs/security/SecurityAnalysisRunner.java @@ -138,6 +138,6 @@ public void clearResult() { @Override public boolean mandatoryDependenciesAreMissing() { - return !getCase().isPresent() || !getContingencyStore().isPresent(); + return getCase().isEmpty() || getContingencyStore().isEmpty(); } } From 405bf9f525a8c2ad865068badaafcb032731471c Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 15:32:25 +0100 Subject: [PATCH 07/36] clean NodeInfoTest Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/storage/NodeInfoTest.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeInfoTest.java b/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeInfoTest.java index 1fd4f98b..15a55a98 100644 --- a/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeInfoTest.java +++ b/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeInfoTest.java @@ -24,22 +24,24 @@ class NodeInfoTest { private ObjectMapper objectMapper; @BeforeEach - public void setUp() throws Exception { + public void setUp() { objectMapper = JsonUtil.createObjectMapper() - .registerModule(new AppStorageJsonModule()); + .registerModule(new AppStorageJsonModule()); } @Test void nodeInfoTest() throws IOException { - NodeInfo info = new NodeInfo("a", "b", "c", "d", 1000000, 1000001, 0, - new NodeGenericMetadata().setString("s1", "s1") - .setDouble("d1", 1d) - .setInt("i1", 2) - .setBoolean("b1", true)); + NodeInfo info = new NodeInfo("a", "b", "c", "d", 1000000, 1000001, 0, new NodeGenericMetadata() + .setString("s1", "s1") + .setDouble("d1", 1d) + .setInt("i1", 2) + .setBoolean("b1", true) + ); NodeInfo info2 = objectMapper.readValue(objectMapper.writeValueAsString(info), NodeInfo.class); assertEquals(info, info2); info.setVersion(1); assertEquals(1, info.getVersion()); - assertNotEquals("A non NodeInfo object", info); + Object string = "A non NodeInfo object"; + assertNotEquals(string, info); } } From c0e845a04b55fe4ae27af18e74b41f7070906eca Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 15:40:57 +0100 Subject: [PATCH 08/36] remove method same as parent Signed-off-by: Nicolas Rol --- .../java/com/powsybl/afs/ws/storage/RemoteAppStorage.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/afs-ws/afs-ws-storage/src/main/java/com/powsybl/afs/ws/storage/RemoteAppStorage.java b/afs-ws/afs-ws-storage/src/main/java/com/powsybl/afs/ws/storage/RemoteAppStorage.java index f7d97b69..2060bd39 100644 --- a/afs-ws/afs-ws-storage/src/main/java/com/powsybl/afs/ws/storage/RemoteAppStorage.java +++ b/afs-ws/afs-ws-storage/src/main/java/com/powsybl/afs/ws/storage/RemoteAppStorage.java @@ -673,11 +673,6 @@ public void removeDependency(String nodeId, String name, String toNodeId) { } } - @Override - public EventsBus getEventsBus() { - return eventsBus; - } - @Override public void createTimeSeries(String nodeId, TimeSeriesMetadata metadata) { Objects.requireNonNull(nodeId); From c38bef2821ee78d071eabd0d4ddf185ae2c56f84 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 15:44:32 +0100 Subject: [PATCH 09/36] clean ActionScriptTest Signed-off-by: Nicolas Rol --- .../afs/action/dsl/ActionScriptTest.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/afs-action-dsl/src/test/java/com/powsybl/afs/action/dsl/ActionScriptTest.java b/afs-action-dsl/src/test/java/com/powsybl/afs/action/dsl/ActionScriptTest.java index df96fc9b..88c68c9d 100644 --- a/afs-action-dsl/src/test/java/com/powsybl/afs/action/dsl/ActionScriptTest.java +++ b/afs-action-dsl/src/test/java/com/powsybl/afs/action/dsl/ActionScriptTest.java @@ -39,7 +39,7 @@ protected AppStorage createStorage() { @Override protected List getProjectFileExtensions() { - return ImmutableList.of(new ActionScriptExtension()); + return List.of(new ActionScriptExtension()); } @Test @@ -49,13 +49,13 @@ void test() { // create contingency list ActionScript actionScript = project.getRootFolder().fileBuilder(ActionScriptBuilder.class) - .withName("contingencies") - .withContent(String.join(System.lineSeparator(), - "contingency('c1') {", - " equipments 'l1'", - "}", - "")) - .build(); + .withName("contingencies") + .withContent(String.join(System.lineSeparator(), + "contingency('c1') {", + " equipments 'l1'", + "}", + "")) + .build(); List contingencies = Collections.singletonList(new Contingency("c1", new LineContingency("l1"))); Network network = Mockito.mock(Network.class); @@ -75,15 +75,15 @@ void testActionScripCreationWithCustomPseudoClass() { // Build an ActionScript using the custom pseudo-class project.getRootFolder().fileBuilder(ActionScriptBuilder.class) - .withName("customScript") - .withContent("script content") - .withPseudoClass(customPseudoClass) - .build(); + .withName("customScript") + .withContent("script content") + .withPseudoClass(customPseudoClass) + .build(); // Retrieve the node info for the created script from storage NodeInfo nodeInfo = storage - .getChildNode(project.getRootFolder().getId(), "customScript") - .orElseThrow(() -> new AssertionError("Node 'customScript' not found")); + .getChildNode(project.getRootFolder().getId(), "customScript") + .orElseThrow(() -> new AssertionError("Node 'customScript' not found")); // Assert that the pseudo-class of the node is set to the custom value assertEquals(customPseudoClass, nodeInfo.getPseudoClass()); @@ -96,14 +96,14 @@ void testActionScripCreationWithDefaultPseudoClass() { // Build an ActionScript without specifying a pseudo-class project.getRootFolder().fileBuilder(ActionScriptBuilder.class) - .withName("defaultScript") - .withContent("script content") - .build(); + .withName("defaultScript") + .withContent("script content") + .build(); // Retrieve the node info for the created script from storage NodeInfo nodeInfo = storage - .getChildNode(project.getRootFolder().getId(), "defaultScript") - .orElseThrow(() -> new AssertionError("Node 'defaultScript' not found")); + .getChildNode(project.getRootFolder().getId(), "defaultScript") + .orElseThrow(() -> new AssertionError("Node 'defaultScript' not found")); // Assert that the pseudo-class of the node is set to the default value defined in ActionScript.PSEUDO_CLASS assertEquals(ActionScript.PSEUDO_CLASS, nodeInfo.getPseudoClass()); From c2075cfe64db3c470a5357b3a80bf174b66ecb9f Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 15:45:58 +0100 Subject: [PATCH 10/36] replace ImmutableList.of with List.of Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/contingency/ContingencyStoreTest.java | 2 +- afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java | 2 +- .../java/com/powsybl/afs/ext/base/ImportedCaseTest.java | 6 +++--- .../com/powsybl/afs/ext/base/ModificationScriptTest.java | 4 ++-- .../test/java/com/powsybl/afs/ext/base/TestImporter.java | 2 +- .../test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java | 6 +++--- .../com/powsybl/afs/local/storage/LocalAppStorageTest.java | 2 +- .../java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java | 2 +- .../local/LocalSecurityAnalysisRunningServiceTest.java | 2 +- .../powsybl/afs/security/SecurityAnalysisRunnerTest.java | 6 +++--- .../test/java/com/powsybl/afs/server/StorageServerTest.java | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/afs-contingency/src/test/java/com/powsybl/afs/contingency/ContingencyStoreTest.java b/afs-contingency/src/test/java/com/powsybl/afs/contingency/ContingencyStoreTest.java index 223f53d8..296c5809 100644 --- a/afs-contingency/src/test/java/com/powsybl/afs/contingency/ContingencyStoreTest.java +++ b/afs-contingency/src/test/java/com/powsybl/afs/contingency/ContingencyStoreTest.java @@ -35,7 +35,7 @@ protected AppStorage createStorage() { @Override protected List getProjectFileExtensions() { - return ImmutableList.of(new ContingencyStoreExtension()); + return List.of(new ContingencyStoreExtension()); } @Test diff --git a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java index 5d8b3ca6..f2b9ae82 100644 --- a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java +++ b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java @@ -198,7 +198,7 @@ public void childRemoved(String nodeId) { ProjectFolder dir5 = rootFolder.createFolder("dir5"); ProjectFolder dir6 = dir5.createFolder("dir6"); - assertEquals(ImmutableList.of("dir5", "dir6"), dir6.getPath().toList().subList(1, 3)); + assertEquals(List.of("dir5", "dir6"), dir6.getPath().toList().subList(1, 3)); assertEquals("dir5/dir6", dir6.getPath().toString()); assertEquals("dir6", rootFolder.getChild("dir5/dir6").orElseThrow(AssertionError::new).getName()); diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java index 9d732a2b..1f8098e6 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java @@ -64,17 +64,17 @@ private ImportersLoader createImportersLoader() { @Override protected List getFileExtensions() { - return ImmutableList.of(new CaseExtension(createImportersLoader())); + return List.of(new CaseExtension(createImportersLoader())); } @Override protected List getProjectFileExtensions() { - return ImmutableList.of(new ImportedCaseExtension(createExportersLoader(), createImportersLoader(), new ImportConfig())); + return List.of(new ImportedCaseExtension(createExportersLoader(), createImportersLoader(), new ImportConfig())); } @Override protected List getServiceExtensions() { - return ImmutableList.of(new LocalNetworkCacheServiceExtension()); + return List.of(new LocalNetworkCacheServiceExtension()); } @Override diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java index a967147e..0ecbdd4f 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java @@ -32,12 +32,12 @@ protected AppStorage createStorage() { @Override protected List getFileExtensions() { - return ImmutableList.of(new CaseExtension()); + return List.of(new CaseExtension()); } @Override protected List getProjectFileExtensions() { - return ImmutableList.of(new ModificationScriptExtension(), new GenericScriptExtension()); + return List.of(new ModificationScriptExtension(), new GenericScriptExtension()); } @Test diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java index 1ef0d59c..cae4b58c 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java @@ -47,7 +47,7 @@ public String getComment() { @Override public List getParameters() { - return ImmutableList.of(new Parameter("param1", ParameterType.BOOLEAN, "", Boolean.TRUE), + return List.of(new Parameter("param1", ParameterType.BOOLEAN, "", Boolean.TRUE), new Parameter("param2", ParameterType.STRING, "", "value")); } diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java index 7f74e8bb..7ed31e9e 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java @@ -47,19 +47,19 @@ protected AppStorage createStorage() { @Override protected List getFileExtensions() { - return ImmutableList.of(new CaseExtension(createImportersLoader())); + return List.of(new CaseExtension(createImportersLoader())); } @Override protected List getProjectFileExtensions() { - return ImmutableList.of(new ImportedCaseExtension(createImportersLoader(), new ImportConfig()), + return List.of(new ImportedCaseExtension(createImportersLoader(), new ImportConfig()), new ModificationScriptExtension(), new VirtualCaseExtension()); } @Override protected List getServiceExtensions() { - return ImmutableList.of(new LocalNetworkCacheServiceExtension()); + return List.of(new LocalNetworkCacheServiceExtension()); } @BeforeEach diff --git a/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java b/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java index 883892eb..82a5335d 100644 --- a/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java +++ b/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java @@ -79,7 +79,7 @@ void test() { assertFalse(storage.isWritable(rootNodeInfo.getId())); assertTrue(storage.isConsistent(rootNodeInfo.getId())); assertFalse(storage.getParentNode(rootNodeInfo.getId()).isPresent()); - assertEquals(ImmutableList.of("%2Fcases%2Fn.tst", "%2Fcases%2Fn2.tst"), + assertEquals(List.of("%2Fcases%2Fn.tst", "%2Fcases%2Fn2.tst"), storage.getChildNodes(rootNodeInfo.getId()).stream().map(NodeInfo::getId).collect(Collectors.toList())); Optional case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst"); assertTrue(case1.isPresent()); diff --git a/afs-mapdb-storage/src/main/java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java b/afs-mapdb-storage/src/main/java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java index b88b58e3..5f629c77 100644 --- a/afs-mapdb-storage/src/main/java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java +++ b/afs-mapdb-storage/src/main/java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java @@ -194,7 +194,7 @@ private static Map> addToList(Map> map, K key, V va List values = map.get(key); List values2; if (values == null) { - values2 = ImmutableList.of(value); + values2 = List.of(value); } else { values2 = ImmutableList.builder() .addAll(values) diff --git a/afs-security-analysis-local/src/test/java/com/powsybl/afs/security/local/LocalSecurityAnalysisRunningServiceTest.java b/afs-security-analysis-local/src/test/java/com/powsybl/afs/security/local/LocalSecurityAnalysisRunningServiceTest.java index 46b32e8f..6a257e93 100644 --- a/afs-security-analysis-local/src/test/java/com/powsybl/afs/security/local/LocalSecurityAnalysisRunningServiceTest.java +++ b/afs-security-analysis-local/src/test/java/com/powsybl/afs/security/local/LocalSecurityAnalysisRunningServiceTest.java @@ -29,7 +29,7 @@ protected List getServiceExtensions() { Constructor constructor = SecurityAnalysis.Runner.class.getDeclaredConstructor(SecurityAnalysisProvider.class); constructor.setAccessible(true); SecurityAnalysis.Runner runner = constructor.newInstance(new SecurityAnalysisProviderMock()); - return ImmutableList.of(new LocalSecurityAnalysisRunningServiceExtension(runner), + return List.of(new LocalSecurityAnalysisRunningServiceExtension(runner), new LocalNetworkCacheServiceExtension()); } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new AssertionError(); diff --git a/afs-security-analysis/src/test/java/com/powsybl/afs/security/SecurityAnalysisRunnerTest.java b/afs-security-analysis/src/test/java/com/powsybl/afs/security/SecurityAnalysisRunnerTest.java index 72830272..d800cb2c 100644 --- a/afs-security-analysis/src/test/java/com/powsybl/afs/security/SecurityAnalysisRunnerTest.java +++ b/afs-security-analysis/src/test/java/com/powsybl/afs/security/SecurityAnalysisRunnerTest.java @@ -107,19 +107,19 @@ protected AppStorage createStorage() { @Override protected List getFileExtensions() { - return ImmutableList.of(new CaseExtension(importersLoader)); + return List.of(new CaseExtension(importersLoader)); } @Override protected List getProjectFileExtensions() { - return ImmutableList.of(new ImportedCaseExtension(importersLoader, new ImportConfig()), + return List.of(new ImportedCaseExtension(importersLoader, new ImportConfig()), new ContingencyStoreExtension(), new SecurityAnalysisRunnerExtension(new SecurityAnalysisParameters())); } @Override protected List getServiceExtensions() { - return ImmutableList.of(new SecurityAnalysisServiceExtensionMock(), + return List.of(new SecurityAnalysisServiceExtensionMock(), new LocalNetworkCacheServiceExtension()); } diff --git a/afs-spring-server/src/test/java/com/powsybl/afs/server/StorageServerTest.java b/afs-spring-server/src/test/java/com/powsybl/afs/server/StorageServerTest.java index 8b959c07..af79e0c4 100644 --- a/afs-spring-server/src/test/java/com/powsybl/afs/server/StorageServerTest.java +++ b/afs-spring-server/src/test/java/com/powsybl/afs/server/StorageServerTest.java @@ -74,7 +74,7 @@ public AppData getAppData() { AppFileSystem fs = new AppFileSystem(FS_TEST_NAME, true, storage, new LocalTaskMonitor()); ComputationManager cm = Mockito.mock(ComputationManager.class); - List fsProviders = ImmutableList.of(m -> ImmutableList.of(fs)); + List fsProviders = List.of(m -> List.of(fs)); return new AppData(cm, cm, fsProviders, eventBus); } } From 01a2249ebebfb73b5ea5614fa45854fe0c18d9fd Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 16:14:31 +0100 Subject: [PATCH 11/36] clean import and some checkstyle Signed-off-by: Nicolas Rol --- .../afs/action/dsl/ActionScriptTest.java | 1 - .../afs/contingency/ContingencyStoreTest.java | 1 - .../java/com/powsybl/afs/AfsBaseTest.java | 106 ++++--- .../afs/ext/base/ImportedCaseTest.java | 54 ++-- .../afs/ext/base/ModificationScriptTest.java | 98 ++++--- .../powsybl/afs/ext/base/TestImporter.java | 7 +- .../powsybl/afs/ext/base/VirtualCaseTest.java | 117 ++++---- .../local/storage/LocalAppStorageTest.java | 11 +- .../afs/mapdb/storage/MapDbAppStorage.java | 274 +++++++++--------- ...calSecurityAnalysisRunningServiceTest.java | 1 - .../security/SecurityAnalysisRunnerTest.java | 202 +++++++------ .../powsybl/afs/server/StorageServerTest.java | 21 +- 12 files changed, 493 insertions(+), 400 deletions(-) diff --git a/afs-action-dsl/src/test/java/com/powsybl/afs/action/dsl/ActionScriptTest.java b/afs-action-dsl/src/test/java/com/powsybl/afs/action/dsl/ActionScriptTest.java index 88c68c9d..163b1c91 100644 --- a/afs-action-dsl/src/test/java/com/powsybl/afs/action/dsl/ActionScriptTest.java +++ b/afs-action-dsl/src/test/java/com/powsybl/afs/action/dsl/ActionScriptTest.java @@ -6,7 +6,6 @@ */ package com.powsybl.afs.action.dsl; -import com.google.common.collect.ImmutableList; import com.powsybl.afs.AbstractProjectFileTest; import com.powsybl.afs.Project; import com.powsybl.afs.ProjectFileExtension; diff --git a/afs-contingency/src/test/java/com/powsybl/afs/contingency/ContingencyStoreTest.java b/afs-contingency/src/test/java/com/powsybl/afs/contingency/ContingencyStoreTest.java index 296c5809..181df3a4 100644 --- a/afs-contingency/src/test/java/com/powsybl/afs/contingency/ContingencyStoreTest.java +++ b/afs-contingency/src/test/java/com/powsybl/afs/contingency/ContingencyStoreTest.java @@ -6,7 +6,6 @@ */ package com.powsybl.afs.contingency; -import com.google.common.collect.ImmutableList; import com.powsybl.afs.AbstractProjectFileTest; import com.powsybl.afs.Project; import com.powsybl.afs.ProjectFileExtension; diff --git a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java index f2b9ae82..baacbd86 100644 --- a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java +++ b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java @@ -6,11 +6,14 @@ */ package com.powsybl.afs; -import com.google.common.collect.ImmutableList; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import com.powsybl.afs.mapdb.storage.MapDbAppStorage; -import com.powsybl.afs.storage.*; +import com.powsybl.afs.storage.AfsStorageException; +import com.powsybl.afs.storage.AppStorage; +import com.powsybl.afs.storage.InMemoryEventsBus; +import com.powsybl.afs.storage.NodeGenericMetadata; +import com.powsybl.afs.storage.NodeInfo; import com.powsybl.afs.storage.events.NodeEvent; import com.powsybl.computation.ComputationManager; import com.powsybl.iidm.network.NetworkFactoryService; @@ -31,10 +34,24 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; import java.util.function.BiConsumer; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Geoffroy Jamgotchian {@literal } @@ -54,7 +71,7 @@ public void setup() { fileSystem = Jimfs.newFileSystem(Configuration.unix()); ComputationManager computationManager = Mockito.mock(ComputationManager.class); ad = new AppData(computationManager, computationManager, Collections.emptyList(), - Collections.emptyList(), List.of(new FooFileExtension(), new WithDependencyFileExtension()), Collections.emptyList()); + Collections.emptyList(), List.of(new FooFileExtension(), new WithDependencyFileExtension()), Collections.emptyList()); storage = MapDbAppStorage.createMem("mem", ad.getEventsBus()); @@ -258,7 +275,7 @@ void archiveAndUnarchiveTestWithDirAndBlackList() throws IOException { ProjectFolder rootFolder = project.getRootFolder(); ProjectFolder dir1 = rootFolder.createFolder("dir1"); try (Writer writer = new OutputStreamWriter(storage.writeBinaryData(dir1.getId(), "data1")); - Writer writer2 = new OutputStreamWriter(storage.writeBinaryData(dir1.getId(), "data2"))) { + Writer writer2 = new OutputStreamWriter(storage.writeBinaryData(dir1.getId(), "data2"))) { } catch (IOException e) { throw new UncheckedIOException(e); } @@ -290,11 +307,10 @@ void archiveAndUnarchiveTestWithDependency() throws IOException { ProjectFolder dir2 = rootFolder.createFolder("dir2"); NodeInfo testDataInfo = storage.createNode(dir1.getId(), "data", "data", "", 0, new NodeGenericMetadata()); - NodeInfo testData2Info = storage.createNode(dir2.getId(), "data2", "data", "", 0, - new NodeGenericMetadata().setString("s1", "v1") - .setDouble("d1", 1d) - .setInt("i1", 2) - .setBoolean("b1", false)); + NodeInfo testData2Info = storage.createNode(dir2.getId(), "data2", "data", "", 0, new NodeGenericMetadata().setString("s1", "v1") + .setDouble("d1", 1d) + .setInt("i1", 2) + .setBoolean("b1", false)); storage.setConsistent(testDataInfo.getId()); storage.setConsistent(testData2Info.getId()); storage.addDependency(testDataInfo.getId(), "mylink2", testData2Info.getId()); @@ -326,7 +342,7 @@ void archiveAndUnarchiveTestRemoveTS() throws IOException { NodeInfo virtualTimeSeries = storage.createNode(dir1.getId(), "virtualTimeSeries", "TSV", "", 0, new NodeGenericMetadata()); RegularTimeSeriesIndex index = RegularTimeSeriesIndex.create(Interval.parse("2015-01-01T00:00:00Z/2015-01-01T01:45:00Z"), - Duration.ofMinutes(15)); + Duration.ofMinutes(15)); storage.createTimeSeries(metrix.getId(), new TimeSeriesMetadata("ts1", TimeSeriesDataType.STRING, index)); storage.createTimeSeries(virtualTimeSeries.getId(), new TimeSeriesMetadata("ts2", TimeSeriesDataType.DOUBLE, index)); @@ -357,16 +373,14 @@ void archiveAndUnarchiveTestWithDependencies() throws IOException { ProjectFolder dir2 = rootFolder.createFolder("dir2"); NodeInfo testDataInfo = storage.createNode(dir1.getId(), "data", "data", "", 0, new NodeGenericMetadata()); - NodeInfo testData2Info = storage.createNode(dir2.getId(), "data2", "data", "", 0, - new NodeGenericMetadata().setString("s1", "v1") - .setDouble("d1", 1d) - .setInt("i1", 2) - .setBoolean("b1", false)); - NodeInfo testData3Info = storage.createNode(dir2.getId(), "data3", "data", "", 0, - new NodeGenericMetadata().setString("s1", "v1") - .setDouble("d1", 1d) - .setInt("i1", 2) - .setBoolean("b1", false)); + NodeInfo testData2Info = storage.createNode(dir2.getId(), "data2", "data", "", 0, new NodeGenericMetadata().setString("s1", "v1") + .setDouble("d1", 1d) + .setInt("i1", 2) + .setBoolean("b1", false)); + NodeInfo testData3Info = storage.createNode(dir2.getId(), "data3", "data", "", 0, new NodeGenericMetadata().setString("s1", "v1") + .setDouble("d1", 1d) + .setInt("i1", 2) + .setBoolean("b1", false)); storage.setConsistent(testDataInfo.getId()); storage.setConsistent(testData2Info.getId()); storage.setConsistent(testData3Info.getId()); @@ -406,16 +420,14 @@ void archiveAndUnarchiveTestWithDeepDependencies() throws IOException { ProjectFolder dir2 = rootFolder.createFolder("dir2"); NodeInfo testDataInfo = storage.createNode(dir1.getId(), "data", "data", "", 0, new NodeGenericMetadata()); - NodeInfo testData2Info = storage.createNode(dir1.getId(), "data2", "data", "", 0, - new NodeGenericMetadata().setString("s1", "v1") - .setDouble("d1", 1d) - .setInt("i1", 2) - .setBoolean("b1", false)); - NodeInfo testData3Info = storage.createNode(dir2.getId(), "data3", "data", "", 0, - new NodeGenericMetadata().setString("s1", "v1") - .setDouble("d1", 1d) - .setInt("i1", 2) - .setBoolean("b1", false)); + NodeInfo testData2Info = storage.createNode(dir1.getId(), "data2", "data", "", 0, new NodeGenericMetadata().setString("s1", "v1") + .setDouble("d1", 1d) + .setInt("i1", 2) + .setBoolean("b1", false)); + NodeInfo testData3Info = storage.createNode(dir2.getId(), "data3", "data", "", 0, new NodeGenericMetadata().setString("s1", "v1") + .setDouble("d1", 1d) + .setInt("i1", 2) + .setBoolean("b1", false)); storage.setConsistent(testDataInfo.getId()); storage.setConsistent(testData2Info.getId()); storage.setConsistent(testData3Info.getId()); @@ -448,8 +460,8 @@ void moveToTest() { ProjectFolder test1 = project.getRootFolder().createFolder("test1"); ProjectFolder test2 = project.getRootFolder().createFolder("test2"); FooFile file = test1.fileBuilder(FooFileBuilder.class) - .withName("foo") - .build(); + .withName("foo") + .build(); assertEquals(test1.getId(), file.getParent().orElseThrow(AssertionError::new).getId()); assertEquals(1, test1.getChildren().size()); assertTrue(test2.getChildren().isEmpty()); @@ -477,8 +489,8 @@ void findProjectFolderTest() { void findProjectFileTest() { Project project = afs.getRootFolder().createProject("test"); FooFile createdFile = project.getRootFolder().fileBuilder(FooFileBuilder.class) - .withName("foo") - .build(); + .withName("foo") + .build(); ProjectFile foundFile = afs.findProjectFile(createdFile.getId(), FooFile.class); assertNotNull(foundFile); assertEquals(createdFile.getId(), foundFile.getId()); @@ -510,14 +522,14 @@ void fetchNodeTest() { Folder folder = afs.getRootFolder().createFolder("testFolder"); Project project = folder.createProject("test"); FooFile createdFile = project.getRootFolder().fileBuilder(FooFileBuilder.class) - .withName("foo") - .build(); + .withName("foo") + .build(); ProjectFolder projectFolder = project.getRootFolder().createFolder("testFolder"); FooFile nestedFile = projectFolder.fileBuilder(FooFileBuilder.class) - .withName("bar") - .build(); + .withName("bar") + .build(); - BiConsumer checkResult = (source, result) -> { + BiConsumer, AbstractNodeBase> checkResult = (source, result) -> { assertNotNull(result); assertEquals(source.getClass(), result.getClass()); assertEquals(source.getId(), result.getId()); @@ -552,11 +564,11 @@ void fetchNodeTest() { void hasDeepDependencyTest() { Project project = afs.getRootFolder().createProject("test"); FooFile createdFile = project.getRootFolder().fileBuilder(FooFileBuilder.class) - .withName("foo") - .build(); + .withName("foo") + .build(); FooFile otherFile = project.getRootFolder().fileBuilder(FooFileBuilder.class) - .withName("bar") - .build(); + .withName("bar") + .build(); createdFile.setDependencies("dep", Collections.singletonList(otherFile)); assertTrue(createdFile.hasDeepDependency(otherFile)); assertFalse(createdFile.hasDeepDependency(createdFile)); @@ -604,8 +616,8 @@ void invalidate() { assertEquals(WithDependencyFile.class, connectedBackwardDependencies.get(0).getClass()); WithDependencyFile withDependencyFile = (WithDependencyFile) connectedBackwardDependencies.get(0); Optional updateEvent2 = withDependencyFile.events.stream() - .filter(nodeEvent -> nodeEventType.equals(nodeEvent.getType())) - .findFirst(); + .filter(nodeEvent -> nodeEventType.equals(nodeEvent.getType())) + .findFirst(); assertFalse(updateEvent2.isEmpty()); assertEquals(event, updateEvent2.get()); } diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java index 1f8098e6..404aad0b 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java @@ -6,22 +6,29 @@ */ package com.powsybl.afs.ext.base; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; -import com.powsybl.afs.*; +import com.powsybl.afs.AbstractProjectFileTest; +import com.powsybl.afs.AfsException; +import com.powsybl.afs.FileExtension; +import com.powsybl.afs.Folder; +import com.powsybl.afs.Project; +import com.powsybl.afs.ProjectFileExtension; +import com.powsybl.afs.ProjectFolder; +import com.powsybl.afs.ProjectNode; +import com.powsybl.afs.ServiceExtension; import com.powsybl.afs.mapdb.storage.MapDbAppStorage; import com.powsybl.afs.storage.AppStorage; import com.powsybl.afs.storage.InMemoryEventsBus; import com.powsybl.afs.storage.NodeGenericMetadata; import com.powsybl.afs.storage.NodeInfo; +import com.powsybl.iidm.network.DefaultNetworkListener; import com.powsybl.iidm.network.ExportersLoader; import com.powsybl.iidm.network.ExportersLoaderList; import com.powsybl.iidm.network.ImportConfig; import com.powsybl.iidm.network.ImportersLoader; import com.powsybl.iidm.network.ImportersLoaderList; -import com.powsybl.iidm.network.DefaultNetworkListener; import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.NetworkListener; import com.powsybl.iidm.serde.XMLExporter; @@ -37,7 +44,12 @@ import java.util.Collections; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -84,7 +96,7 @@ public void setup() throws IOException { NodeInfo rootFolderInfo = storage.createRootNodeIfNotExists("root", Folder.PSEUDO_CLASS); NodeInfo nodeInfo = storage.createNode(rootFolderInfo.getId(), "network", Case.PSEUDO_CLASS, "Test format", Case.VERSION, - new NodeGenericMetadata().setString("format", TestImporter.FORMAT)); + new NodeGenericMetadata().setString("format", TestImporter.FORMAT)); storage.setConsistent(nodeInfo.getId()); fileSystem = Jimfs.newFileSystem(Configuration.unix()); @@ -122,15 +134,15 @@ void test() { // import case into project try { folder.fileBuilder(ImportedCaseBuilder.class) - .build(); + .build(); fail(); } catch (AfsException ignored) { } ImportedCase importedCase = folder.fileBuilder(ImportedCaseBuilder.class) - .withCase(aCase) - .withParameter("param1", "true") - .withParameters(ImmutableMap.of("param2", "1")) - .build(); + .withCase(aCase) + .withParameter("param1", "true") + .withParameters(ImmutableMap.of("param2", "1")) + .build(); assertNotNull(importedCase); assertFalse(importedCase.isFolder()); assertNotNull(importedCase.getNetwork()); @@ -141,7 +153,7 @@ void test() { assertNotNull(importedCase.getNetwork(Collections.singletonList(mockedListener))); network.getSubstation("s1").setTso("tso_new"); verify(mockedListener, times(1)) - .onUpdate(network.getSubstation("s1"), "tso", null, "TSO", "tso_new"); + .onUpdate(network.getSubstation("s1"), "tso", null, "TSO", "tso_new"); // test network query assertEquals("[\"s1\"]", importedCase.queryNetwork(ScriptType.GROOVY, "network.substations.collect { it.id }")); @@ -180,15 +192,15 @@ void testFile() { assertTrue(folder.getChildren().isEmpty()); ImportedCase importedCase = folder.fileBuilder(ImportedCaseBuilder.class) - .withFile(fileSystem.getPath("/work/network.tst")) - .withName("test") - .build(); + .withFile(fileSystem.getPath("/work/network.tst")) + .withName("test") + .build(); assertNotNull(importedCase); assertEquals("test", importedCase.getName()); ImportedCase importedCase2 = folder.fileBuilder(ImportedCaseBuilder.class) - .withFile(fileSystem.getPath("/work/network.tst")) - .build(); + .withFile(fileSystem.getPath("/work/network.tst")) + .build(); assertNotNull(importedCase2); assertEquals("network", importedCase2.getName()); } @@ -207,15 +219,15 @@ void testNetwork() { Network network = Network.create("NetworkID", "scripting"); ImportedCase importedCase1 = folder.fileBuilder(ImportedCaseBuilder.class) - .withName("test") - .withNetwork(network) - .build(); + .withName("test") + .withNetwork(network) + .build(); assertNotNull(importedCase1); assertEquals("test", importedCase1.getName()); ImportedCase importedCase2 = folder.fileBuilder(ImportedCaseBuilder.class) - .withNetwork(network) - .build(); + .withNetwork(network) + .build(); assertNotNull(importedCase2); assertEquals("NetworkID", importedCase2.getName()); } diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java index 0ecbdd4f..858bade2 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java @@ -6,8 +6,14 @@ */ package com.powsybl.afs.ext.base; -import com.google.common.collect.ImmutableList; -import com.powsybl.afs.*; +import com.powsybl.afs.AbstractProjectFileTest; +import com.powsybl.afs.AfsCircularDependencyException; +import com.powsybl.afs.AfsException; +import com.powsybl.afs.FileExtension; +import com.powsybl.afs.Project; +import com.powsybl.afs.ProjectFileExtension; +import com.powsybl.afs.ProjectFolder; +import com.powsybl.afs.ProjectNode; import com.powsybl.afs.mapdb.storage.MapDbAppStorage; import com.powsybl.afs.storage.AppStorage; import com.powsybl.afs.storage.InMemoryEventsBus; @@ -18,7 +24,13 @@ import java.util.concurrent.atomic.AtomicBoolean; import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Geoffroy Jamgotchian {@literal } @@ -48,33 +60,33 @@ void test() { // create groovy script try { rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withType(ScriptType.GROOVY) - .withContent("println 'hello'") - .build(); + .withType(ScriptType.GROOVY) + .withContent("println 'hello'") + .build(); fail(); } catch (AfsException ignored) { } try { rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("script") - .withContent("println 'hello'") - .build(); + .withName("script") + .withContent("println 'hello'") + .build(); fail(); } catch (AfsException ignored) { } try { rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("script") - .withType(ScriptType.GROOVY) - .build(); + .withName("script") + .withType(ScriptType.GROOVY) + .build(); fail(); } catch (AfsException ignored) { } ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("script") - .withType(ScriptType.GROOVY) - .withContent("println 'hello'") - .build(); + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'hello'") + .build(); assertNotNull(script); assertEquals("script", script.getName()); assertFalse(script.isFolder()); @@ -95,10 +107,10 @@ void test() { assertEquals("script", firstNode.getName()); ModificationScript include1 = rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("include_script1") - .withType(ScriptType.GROOVY) - .withContent("var foo=\"bar\"") - .build(); + .withName("include_script1") + .withType(ScriptType.GROOVY) + .withContent("var foo=\"bar\"") + .build(); assertNotNull(include1); script.addScript(include1); String contentWithInclude = script.readScript(true); @@ -109,10 +121,10 @@ void test() { assertEquals(contentWithInclude, "var foo=\"bar\"\n\nvar foo=\"bar\"\n\nprintln 'bye'"); ModificationScript include2 = rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("include_script2") - .withType(ScriptType.GROOVY) - .withContent("var p0=1") - .build(); + .withName("include_script2") + .withType(ScriptType.GROOVY) + .withContent("var p0=1") + .build(); script.removeScript(include1.getId()); script.addScript(include1); script.addScript(include2); @@ -120,10 +132,10 @@ void test() { assertEquals(contentWithInclude, "var foo=\"bar\"\n\nvar p0=1\n\nprintln 'bye'"); ModificationScript include3 = rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("include_script3") - .withType(ScriptType.GROOVY) - .withContent("var pmax=2") - .build(); + .withName("include_script3") + .withType(ScriptType.GROOVY) + .withContent("var pmax=2") + .build(); script.addScript(include3); script.removeScript(include2.getId()); contentWithInclude = script.readScript(true); @@ -141,10 +153,10 @@ void test() { assertThatCode(() -> script.addScript(script)).isInstanceOf(AfsCircularDependencyException.class); GenericScript genericScript = rootFolder.fileBuilder(GenericScriptBuilder.class) - .withContent("some list") - .withType(ScriptType.GROOVY) - .withName("genericScript") - .build(); + .withContent("some list") + .withType(ScriptType.GROOVY) + .withName("genericScript") + .build(); assertEquals("some list", genericScript.readScript()); script.addGenericScript(genericScript); @@ -193,15 +205,15 @@ void testModificationScriptCreationWithCustomPseudoClass() { // Build a ModificationScript using the custom pseudo-class ModificationScript modificationScript = project.getRootFolder().fileBuilder(ModificationScriptBuilder.class) - .withName("customScript") - .withType(ScriptType.GROOVY) - .withContent("script content") - .withPseudoClass(customPseudoClass) - .build(); + .withName("customScript") + .withType(ScriptType.GROOVY) + .withContent("script content") + .withPseudoClass(customPseudoClass) + .build(); // Retrieve the node info for the created script from storage NodeInfo nodeInfo = storage.getChildNode(project.getRootFolder().getId(), "customScript") - .orElseThrow(() -> new AssertionError("Node 'customScript' not found")); + .orElseThrow(() -> new AssertionError("Node 'customScript' not found")); // Assert that the pseudo-class of the node is set to the custom value assertEquals(customPseudoClass, nodeInfo.getPseudoClass()); @@ -214,14 +226,14 @@ void testModificationScriptCreationWithDefaultPseudoClass() { // Build a ModificationScript without specifying a pseudo-class, so the default should be used ModificationScript modificationScript = project.getRootFolder().fileBuilder(ModificationScriptBuilder.class) - .withName("defaultScript") - .withType(ScriptType.GROOVY) - .withContent("script content") - .build(); + .withName("defaultScript") + .withType(ScriptType.GROOVY) + .withContent("script content") + .build(); // Retrieve the node info for the created script from storage NodeInfo nodeInfo = storage.getChildNode(project.getRootFolder().getId(), "defaultScript") - .orElseThrow(() -> new AssertionError("Node 'defaultScript' not found")); + .orElseThrow(() -> new AssertionError("Node 'defaultScript' not found")); // Assert that the pseudo-class of the node is set to the default value defined in ModificationScript.PSEUDO_CLASS assertEquals(ModificationScript.PSEUDO_CLASS, nodeInfo.getPseudoClass()); diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java index cae4b58c..97432184 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java @@ -6,13 +6,12 @@ */ package com.powsybl.afs.ext.base; -import com.google.common.collect.ImmutableList; import com.powsybl.commons.datasource.DataSource; import com.powsybl.commons.datasource.ReadOnlyDataSource; -import com.powsybl.iidm.network.Importer; -import com.powsybl.iidm.network.Network; import com.powsybl.commons.parameters.Parameter; import com.powsybl.commons.parameters.ParameterType; +import com.powsybl.iidm.network.Importer; +import com.powsybl.iidm.network.Network; import com.powsybl.iidm.network.NetworkFactory; import java.io.IOException; @@ -48,7 +47,7 @@ public String getComment() { @Override public List getParameters() { return List.of(new Parameter("param1", ParameterType.BOOLEAN, "", Boolean.TRUE), - new Parameter("param2", ParameterType.STRING, "", "value")); + new Parameter("param2", ParameterType.STRING, "", "value")); } @Override diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java index 7ed31e9e..f44516f2 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java @@ -6,17 +6,25 @@ */ package com.powsybl.afs.ext.base; -import com.google.common.collect.ImmutableList; -import com.powsybl.afs.*; +import com.powsybl.afs.AbstractProjectFileTest; +import com.powsybl.afs.AfsCircularDependencyException; +import com.powsybl.afs.AfsException; +import com.powsybl.afs.FileExtension; +import com.powsybl.afs.Folder; +import com.powsybl.afs.Project; +import com.powsybl.afs.ProjectFile; +import com.powsybl.afs.ProjectFileExtension; +import com.powsybl.afs.ProjectFolder; +import com.powsybl.afs.ServiceExtension; import com.powsybl.afs.mapdb.storage.MapDbAppStorage; import com.powsybl.afs.storage.AppStorage; import com.powsybl.afs.storage.InMemoryEventsBus; import com.powsybl.afs.storage.NodeGenericMetadata; import com.powsybl.afs.storage.NodeInfo; +import com.powsybl.iidm.network.DefaultNetworkListener; import com.powsybl.iidm.network.ImportConfig; import com.powsybl.iidm.network.ImportersLoader; import com.powsybl.iidm.network.ImportersLoaderList; -import com.powsybl.iidm.network.DefaultNetworkListener; import com.powsybl.iidm.network.NetworkListener; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,7 +34,12 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -53,8 +66,8 @@ protected List getFileExtensions() { @Override protected List getProjectFileExtensions() { return List.of(new ImportedCaseExtension(createImportersLoader(), new ImportConfig()), - new ModificationScriptExtension(), - new VirtualCaseExtension()); + new ModificationScriptExtension(), + new VirtualCaseExtension()); } @Override @@ -67,7 +80,7 @@ public void setup() throws IOException { super.setup(); NodeInfo rootFolderInfo = storage.createRootNodeIfNotExists("root", Folder.PSEUDO_CLASS); NodeInfo nodeInfo = storage.createNode(rootFolderInfo.getId(), "network", Case.PSEUDO_CLASS, "", Case.VERSION, - new NodeGenericMetadata().setString(Case.FORMAT, TestImporter.FORMAT)); + new NodeGenericMetadata().setString(Case.FORMAT, TestImporter.FORMAT)); storage.setConsistent(nodeInfo.getId()); } @@ -84,49 +97,49 @@ void test() { // import case into project ImportedCase importedCase = folder.fileBuilder(ImportedCaseBuilder.class) - .withCase(aCase) - .build(); + .withCase(aCase) + .build(); // create groovy script ModificationScript script = folder.fileBuilder(ModificationScriptBuilder.class) - .withName("script") - .withType(ScriptType.GROOVY) - .withContent("print 'hello'") - .build(); + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("print 'hello'") + .build(); // create virtual by applying groovy script on imported case try { VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) - .withCase(importedCase) - .withScript(script) - .build(); + .withCase(importedCase) + .withScript(script) + .build(); fail(); } catch (AfsException ignored) { } try { VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) - .withName("network2") - .withScript(script) - .build(); + .withName("network2") + .withScript(script) + .build(); fail(); } catch (AfsException ignored) { } try { VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) - .withName("network2") - .withCase(importedCase) - .build(); + .withName("network2") + .withCase(importedCase) + .build(); fail(); } catch (AfsException ignored) { } VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) - .withName("network2") - .withCase(importedCase) - .withScript(script) - .build(); + .withName("network2") + .withCase(importedCase) + .withScript(script) + .build(); assertEquals("network2", virtualCase.getName()); assertTrue(virtualCase.getCase().isPresent()); @@ -149,16 +162,16 @@ void test() { // test script error ModificationScript scriptWithError = folder.fileBuilder(ModificationScriptBuilder.class) - .withName("scriptWithError") - .withType(ScriptType.GROOVY) - .withContent("prin 'hello'") - .build(); + .withName("scriptWithError") + .withType(ScriptType.GROOVY) + .withContent("prin 'hello'") + .build(); VirtualCase virtualCaseWithError = folder.fileBuilder(VirtualCaseBuilder.class) - .withName("network2") - .withCase(importedCase) - .withScript(scriptWithError) - .build(); + .withName("network2") + .withCase(importedCase) + .withScript(scriptWithError) + .build(); try { virtualCaseWithError.getNetwork(); @@ -191,17 +204,17 @@ void test() { //test missing dependencies VirtualCase virtualCase3 = folder.fileBuilder(VirtualCaseBuilder.class) - .withName("network3") - .withCase(importedCase) - .withScript(scriptWithError) - .build(); + .withName("network3") + .withCase(importedCase) + .withScript(scriptWithError) + .build(); importedCase.delete(); assertTrue(virtualCase3.mandatoryDependenciesAreMissing()); ImportedCase importedCase2 = folder.fileBuilder(ImportedCaseBuilder.class) - .withCase(aCase) - .build(); + .withCase(aCase) + .build(); virtualCase3.setCase(importedCase2); @@ -212,9 +225,9 @@ void test() { assertEquals(importedCase2.getName(), virtualCase3.getCase().map(ProjectFile::getName).orElse(null)); ImportedCase importedCase3 = folder.fileBuilder(ImportedCaseBuilder.class) - .withCase(aCase) - .withName("importedCase3") - .build(); + .withCase(aCase) + .withName("importedCase3") + .build(); virtualCase3.replaceDependency(importedCase2.getId(), importedCase3); @@ -225,19 +238,19 @@ void test() { // test network listener ModificationScript scriptModif = folder.fileBuilder(ModificationScriptBuilder.class) - .withName("scriptModif") - .withType(ScriptType.GROOVY) - .withContent("network.getSubstation('s1').setTso('tso_new')") - .build(); + .withName("scriptModif") + .withType(ScriptType.GROOVY) + .withContent("network.getSubstation('s1').setTso('tso_new')") + .build(); VirtualCase virtualCase4 = folder.fileBuilder(VirtualCaseBuilder.class) - .withName("network4") - .withCase(importedCase3) - .withScript(scriptModif) - .build(); + .withName("network4") + .withCase(importedCase3) + .withScript(scriptModif) + .build(); NetworkListener mockedListener = mock(DefaultNetworkListener.class); virtualCase4.getNetwork(Collections.singletonList(mockedListener)); verify(mockedListener, times(1)) - .onUpdate(network.getSubstation("s1"), "tso", null, "TSO", "tso_new"); + .onUpdate(network.getSubstation("s1"), "tso", null, "TSO", "tso_new"); } } diff --git a/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java b/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java index 82a5335d..9f8a8c08 100644 --- a/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java +++ b/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java @@ -6,7 +6,6 @@ */ package com.powsybl.afs.local.storage; -import com.google.common.collect.ImmutableList; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import com.powsybl.afs.Folder; @@ -32,7 +31,11 @@ import java.util.Optional; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Geoffroy Jamgotchian {@literal } @@ -55,7 +58,7 @@ public void setUp() throws Exception { ComputationManager computationManager = Mockito.mock(ComputationManager.class); Network network = Mockito.mock(Network.class); List fileExtensions - = Collections.singletonList(new LocalCaseScanner(new ImportConfig(), new ImportersLoaderList(new TestImporter(network)))); + = Collections.singletonList(new LocalCaseScanner(new ImportConfig(), new ImportersLoaderList(new TestImporter(network)))); storage = new LocalAppStorage(rootDir, "mem", fileExtensions, Collections.emptyList(), computationManager); } @@ -80,7 +83,7 @@ void test() { assertTrue(storage.isConsistent(rootNodeInfo.getId())); assertFalse(storage.getParentNode(rootNodeInfo.getId()).isPresent()); assertEquals(List.of("%2Fcases%2Fn.tst", "%2Fcases%2Fn2.tst"), - storage.getChildNodes(rootNodeInfo.getId()).stream().map(NodeInfo::getId).collect(Collectors.toList())); + storage.getChildNodes(rootNodeInfo.getId()).stream().map(NodeInfo::getId).collect(Collectors.toList())); Optional case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst"); assertTrue(case1.isPresent()); assertEquals(rootNodeInfo, storage.getParentNode(case1.get().getId()).orElseThrow(AssertionError::new)); diff --git a/afs-mapdb-storage/src/main/java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java b/afs-mapdb-storage/src/main/java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java index 5f629c77..064dc45b 100644 --- a/afs-mapdb-storage/src/main/java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java +++ b/afs-mapdb-storage/src/main/java/com/powsybl/afs/mapdb/storage/MapDbAppStorage.java @@ -6,22 +6,48 @@ */ package com.powsybl.afs.mapdb.storage; -import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.powsybl.afs.storage.*; +import com.powsybl.afs.storage.AbstractAppStorage; +import com.powsybl.afs.storage.AfsStorageException; +import com.powsybl.afs.storage.EventsBus; +import com.powsybl.afs.storage.NodeDependency; +import com.powsybl.afs.storage.NodeGenericMetadata; +import com.powsybl.afs.storage.NodeInfo; import com.powsybl.afs.storage.events.*; -import com.powsybl.timeseries.*; +import com.powsybl.timeseries.AbstractPoint; +import com.powsybl.timeseries.DataChunk; +import com.powsybl.timeseries.DoubleDataChunk; +import com.powsybl.timeseries.StringDataChunk; +import com.powsybl.timeseries.TimeSeriesDataType; +import com.powsybl.timeseries.TimeSeriesMetadata; +import com.powsybl.timeseries.TimeSeriesVersions; import org.apache.commons.lang3.SystemUtils; import org.mapdb.Atomic; import org.mapdb.DB; import org.mapdb.DBMaker; import org.mapdb.Serializer; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.time.ZonedDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentMap; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -30,69 +56,24 @@ */ public class MapDbAppStorage extends AbstractAppStorage { - @FunctionalInterface - public interface MapDbAppStorageProvider { - public R apply(F first, S second, T third); - } - - public static MapDbAppStorage createMem(String fileSystemName, EventsBus eventsBus) { - DBMaker.Maker maker = DBMaker.memoryDB(); - return new MapDbAppStorage(fileSystemName, maker::make, eventsBus); - } - - public static MapDbAppStorage createHeap(String fileSystemName, EventsBus eventsBus) { - DBMaker.Maker maker = DBMaker.heapDB(); - return new MapDbAppStorage(fileSystemName, maker::make, eventsBus); - } - - public static MapDbAppStorage createMmapFile(String fileSystemName, File dbFile, EventsBus eventsBus) { - return new MapDbAppStorage(fileSystemName, () -> { - DBMaker.Maker maker = DBMaker.fileDB(dbFile) - .transactionEnable(); - // it is not recommanded to use mmap on Windows (crash) - // http://www.mapdb.org/blog/mmap_files_alloc_and_jvm_crash/ - if (!SystemUtils.IS_OS_WINDOWS) { - maker.fileMmapEnableIfSupported() - .fileMmapPreclearDisable(); - } - return maker.make(); - }, eventsBus); - } - + private static final String NODE = "Node "; private final String fileSystemName; - private final DB db; - private final Atomic.Var rootNodeVar; - private final ConcurrentMap> childNodesMap; - private final ConcurrentMap childNodeMap; - private final ConcurrentMap parentNodeMap; - private final ConcurrentMap nodeInfoMap; - private final ConcurrentMap dataMap; - private final ConcurrentMap> dataNamesMap; - private final ConcurrentMap nodeConsistencyMap; - private final ConcurrentMap> timeSeriesNamesMap; - private final ConcurrentMap timeSeriesMetadataMap; - private final ConcurrentMap timeSeriesLastChunkMap; - private final ConcurrentMap doubleTimeSeriesChunksMap; - private final ConcurrentMap stringTimeSeriesChunksMap; - private final ConcurrentMap> dependencyNodesMap; - private final ConcurrentMap> dependencyNodesByNameMap; - private final ConcurrentMap> backwardDependencyNodesMap; protected MapDbAppStorage(String fileSystemName, Supplier db, EventsBus eventsBus) { @@ -100,71 +81,95 @@ protected MapDbAppStorage(String fileSystemName, Supplier db, EventsBus even this.db = db.get(); rootNodeVar = this.db.atomicVar("rootNode", NodeInfoSerializer.INSTANCE) - .createOrOpen(); + .createOrOpen(); childNodesMap = this.db - .hashMap("childNodes", UuidSerializer.INSTANCE, UuidListSerializer.INSTANCE) - .createOrOpen(); + .hashMap("childNodes", UuidSerializer.INSTANCE, UuidListSerializer.INSTANCE) + .createOrOpen(); childNodeMap = this.db - .hashMap("childNode", NamedLinkSerializer.INSTANCE, UuidSerializer.INSTANCE) - .createOrOpen(); + .hashMap("childNode", NamedLinkSerializer.INSTANCE, UuidSerializer.INSTANCE) + .createOrOpen(); parentNodeMap = this.db - .hashMap("parentNode", UuidSerializer.INSTANCE, UuidSerializer.INSTANCE) - .createOrOpen(); + .hashMap("parentNode", UuidSerializer.INSTANCE, UuidSerializer.INSTANCE) + .createOrOpen(); nodeInfoMap = this.db - .hashMap("nodeInfo", UuidSerializer.INSTANCE, NodeInfoSerializer.INSTANCE) - .createOrOpen(); + .hashMap("nodeInfo", UuidSerializer.INSTANCE, NodeInfoSerializer.INSTANCE) + .createOrOpen(); dataMap = this.db - .hashMap("data", NamedLinkSerializer.INSTANCE, Serializer.BYTE_ARRAY) - .createOrOpen(); + .hashMap("data", NamedLinkSerializer.INSTANCE, Serializer.BYTE_ARRAY) + .createOrOpen(); dataNamesMap = this.db - .hashMap("dataNames", UuidSerializer.INSTANCE, StringSetSerializer.INSTANCE) - .createOrOpen(); + .hashMap("dataNames", UuidSerializer.INSTANCE, StringSetSerializer.INSTANCE) + .createOrOpen(); nodeConsistencyMap = this.db - .hashMap("nodeConsistency", UuidSerializer.INSTANCE, Serializer.BOOLEAN) - .createOrOpen(); + .hashMap("nodeConsistency", UuidSerializer.INSTANCE, Serializer.BOOLEAN) + .createOrOpen(); timeSeriesNamesMap = this.db - .hashMap("timeSeriesNamesMap", UuidSerializer.INSTANCE, StringSetSerializer.INSTANCE) - .createOrOpen(); + .hashMap("timeSeriesNamesMap", UuidSerializer.INSTANCE, StringSetSerializer.INSTANCE) + .createOrOpen(); timeSeriesMetadataMap = this.db - .hashMap("timeSeriesMetadataMap", NamedLinkSerializer.INSTANCE, TimeSeriesMetadataSerializer.INSTANCE) - .createOrOpen(); + .hashMap("timeSeriesMetadataMap", NamedLinkSerializer.INSTANCE, TimeSeriesMetadataSerializer.INSTANCE) + .createOrOpen(); timeSeriesLastChunkMap = this.db - .hashMap("timeSeriesLastChunkMap", TimeSeriesKeySerializer.INSTANCE, Serializer.INTEGER) - .createOrOpen(); + .hashMap("timeSeriesLastChunkMap", TimeSeriesKeySerializer.INSTANCE, Serializer.INTEGER) + .createOrOpen(); doubleTimeSeriesChunksMap = this.db - .hashMap("doubleTimeSeriesChunksMap", TimeSeriesChunkKeySerializer.INSTANCE, DoubleDataChunkSerializer.INSTANCE) - .createOrOpen(); + .hashMap("doubleTimeSeriesChunksMap", TimeSeriesChunkKeySerializer.INSTANCE, DoubleDataChunkSerializer.INSTANCE) + .createOrOpen(); stringTimeSeriesChunksMap = this.db - .hashMap("stringTimeSeriesChunksMap", TimeSeriesChunkKeySerializer.INSTANCE, StringDataChunkSerializer.INSTANCE) - .createOrOpen(); + .hashMap("stringTimeSeriesChunksMap", TimeSeriesChunkKeySerializer.INSTANCE, StringDataChunkSerializer.INSTANCE) + .createOrOpen(); dependencyNodesMap = this.db - .hashMap("dependencyNodes", UuidSerializer.INSTANCE, NamedLinkListSerializer.INSTANCE) - .createOrOpen(); + .hashMap("dependencyNodes", UuidSerializer.INSTANCE, NamedLinkListSerializer.INSTANCE) + .createOrOpen(); dependencyNodesByNameMap = this.db - .hashMap("dependencyNodesByName", NamedLinkSerializer.INSTANCE, UuidListSerializer.INSTANCE) - .createOrOpen(); + .hashMap("dependencyNodesByName", NamedLinkSerializer.INSTANCE, UuidListSerializer.INSTANCE) + .createOrOpen(); backwardDependencyNodesMap = this.db - .hashMap("backwardDependencyNodes", UuidSerializer.INSTANCE, UuidListSerializer.INSTANCE) - .createOrOpen(); + .hashMap("backwardDependencyNodes", UuidSerializer.INSTANCE, UuidListSerializer.INSTANCE) + .createOrOpen(); this.eventsBus = Objects.requireNonNull(eventsBus); } + public static MapDbAppStorage createMem(String fileSystemName, EventsBus eventsBus) { + DBMaker.Maker maker = DBMaker.memoryDB(); + return new MapDbAppStorage(fileSystemName, maker::make, eventsBus); + } + + public static MapDbAppStorage createHeap(String fileSystemName, EventsBus eventsBus) { + DBMaker.Maker maker = DBMaker.heapDB(); + return new MapDbAppStorage(fileSystemName, maker::make, eventsBus); + } + + public static MapDbAppStorage createMmapFile(String fileSystemName, File dbFile, EventsBus eventsBus) { + return new MapDbAppStorage(fileSystemName, () -> { + DBMaker.Maker maker = DBMaker.fileDB(dbFile) + .transactionEnable(); + // it is not recommanded to use mmap on Windows (crash) + // http://www.mapdb.org/blog/mmap_files_alloc_and_jvm_crash/ + if (!SystemUtils.IS_OS_WINDOWS) { + maker.fileMmapEnableIfSupported() + .fileMmapPreclearDisable(); + } + return maker.make(); + }, eventsBus); + } + private static Map> addToSet(Map> map, K key, V value) { Objects.requireNonNull(map); Objects.requireNonNull(key); @@ -175,9 +180,9 @@ private static Map> addToSet(Map> map, K key, V value values2 = ImmutableSet.of(value); } else { values2 = ImmutableSet.builder() - .addAll(values) - .add(value) - .build(); + .addAll(values) + .add(value) + .build(); } map.put(key, values2); return map; @@ -197,9 +202,9 @@ private static Map> addToList(Map> map, K key, V va values2 = List.of(value); } else { values2 = ImmutableList.builder() - .addAll(values) - .add(value) - .build(); + .addAll(values) + .add(value) + .build(); } map.put(key, values2); return map; @@ -233,7 +238,20 @@ private static boolean removeFromSet(Map> map, K key, V value) return removed; } - private static final String NODE = "Node "; + static UUID checkNodeId(String nodeId) { + try { + return UUID.fromString(nodeId); + } catch (IllegalArgumentException e) { + throw new AfsStorageException("Node id '" + nodeId + "' is expected to be a UUID"); + } + } + + private static UUID checkNullableNodeId(String nodeId) { + if (nodeId == null) { + return null; + } + return checkNodeId(nodeId); + } @Override public String getFileSystemName() { @@ -260,27 +278,12 @@ private void checkConsistency(UUID nodeUuid) { } } - static UUID checkNodeId(String nodeId) { - try { - return UUID.fromString(nodeId); - } catch (IllegalArgumentException e) { - throw new AfsStorageException("Node id '" + nodeId + "' is expected to be a UUID"); - } - } - private void checkNodeExists(UUID nodeUuid) { if (!nodeInfoMap.containsKey(nodeUuid)) { throw createNodeNotFoundException(nodeUuid); } } - private static UUID checkNullableNodeId(String nodeId) { - if (nodeId == null) { - return null; - } - return checkNodeId(nodeId); - } - @Override public NodeInfo createRootNodeIfNotExists(String name, String nodePseudoClass) { NodeInfo rootNodeInfo = rootNodeVar.get(); @@ -359,18 +362,18 @@ private List getAllChildNodes(String nodeId) { public List getChildNodes(String nodeId) { List childNodes = getAllChildNodes(nodeId); return childNodes.stream().map(this::getNodeInfo).filter(nodeInfo -> isConsistent(nodeInfo.getId())) - .collect(Collectors.toList()); + .collect(Collectors.toList()); } private List getInconsistentNodes(String nodeId) { List childNodes = getAllChildNodes(nodeId); List inconsistentNodesInfos = childNodes.stream().map(this::getNodeInfo) - .filter(nodeInfo -> !isConsistent(nodeInfo.getId())) - .collect(Collectors.toList()); + .filter(nodeInfo -> !isConsistent(nodeInfo.getId())) + .collect(Collectors.toList()); List consistentNodesInfos = childNodes.stream().map(this::getNodeInfo) - .filter(nodeInfo -> isConsistent(nodeInfo.getId())) - .collect(Collectors.toList()); + .filter(nodeInfo -> isConsistent(nodeInfo.getId())) + .toList(); // now get recursively inconsistent nodes of consistent child nodes for (NodeInfo nodeInfo : consistentNodesInfos) { @@ -663,10 +666,10 @@ public Set getTimeSeriesDataVersions(String nodeId) { checkConsistency(nodeUuid); return Stream.concat(doubleTimeSeriesChunksMap.keySet().stream(), stringTimeSeriesChunksMap.keySet().stream()) - .map(TimeSeriesChunkKey::getTimeSeriesKey) - .filter(key -> key.getNodeUuid().equals(nodeUuid)) - .map(TimeSeriesKey::getVersion) - .collect(Collectors.toSet()); + .map(TimeSeriesChunkKey::getTimeSeriesKey) + .filter(key -> key.getNodeUuid().equals(nodeUuid)) + .map(TimeSeriesKey::getVersion) + .collect(Collectors.toSet()); } @Override @@ -676,11 +679,11 @@ public Set getTimeSeriesDataVersions(String nodeId, String timeSeriesNa checkConsistency(nodeUuid); Objects.requireNonNull(timeSeriesName); return Stream.concat(doubleTimeSeriesChunksMap.keySet().stream(), - stringTimeSeriesChunksMap.keySet().stream()) - .map(TimeSeriesChunkKey::getTimeSeriesKey) - .filter(key -> key.getNodeUuid().equals(nodeUuid) && key.getTimeSeriesName().equals(timeSeriesName)) - .map(TimeSeriesKey::getVersion) - .collect(Collectors.toSet()); + stringTimeSeriesChunksMap.keySet().stream()) + .map(TimeSeriesChunkKey::getTimeSeriesKey) + .filter(key -> key.getNodeUuid().equals(nodeUuid) && key.getTimeSeriesName().equals(timeSeriesName)) + .map(TimeSeriesKey::getVersion) + .collect(Collectors.toSet()); } private

> List getChunks(UUID nodeId, int version, String timeSeriesName, @@ -705,8 +708,8 @@ private

> List getChunks(U return chunks; } - private

> - Map> getTimeSeriesData(String nodeId, Set timeSeriesNames, int version, ConcurrentMap map) { + private

> Map> getTimeSeriesData( + String nodeId, Set timeSeriesNames, int version, ConcurrentMap map) { UUID nodeUuid = checkNodeId(nodeId); Objects.requireNonNull(timeSeriesNames); checkConsistency(nodeUuid); @@ -716,8 +719,8 @@ Map> getTimeSeriesData(String nodeId, Set timeSeriesName for (String timeSeriesName : timeSeriesNames) { TimeSeriesMetadata metadata = timeSeriesMetadataMap.get(new NamedLink(nodeUuid, timeSeriesName)); if (metadata != null && - (metadata.getDataType() == TimeSeriesDataType.DOUBLE && map == doubleTimeSeriesChunksMap - || metadata.getDataType() == TimeSeriesDataType.STRING && map == stringTimeSeriesChunksMap)) { + (metadata.getDataType() == TimeSeriesDataType.DOUBLE && map == doubleTimeSeriesChunksMap + || metadata.getDataType() == TimeSeriesDataType.STRING && map == stringTimeSeriesChunksMap)) { List chunks = getChunks(nodeUuid, version, timeSeriesName, metadata, map); timeSeriesData.put(timeSeriesName, chunks); } @@ -754,8 +757,8 @@ private

> void clearTimeSerie UUID nodeUuid = checkNodeId(nodeId); Objects.requireNonNull(map); List keys = map.keySet().stream() - .filter(chunkKey -> chunkKey.getTimeSeriesKey().getNodeUuid().compareTo(nodeUuid) == 0) - .collect(Collectors.toList()); + .filter(chunkKey -> chunkKey.getTimeSeriesKey().getNodeUuid().compareTo(nodeUuid) == 0) + .collect(Collectors.toList()); keys.forEach(key -> map.remove(key)); } @@ -790,8 +793,8 @@ public void clearTimeSeries(String nodeId) { timeSeriesNamesMap.remove(nodeUuid); } List keys = timeSeriesLastChunkMap.keySet().stream() - .filter(key -> key.getNodeUuid().compareTo(nodeUuid) == 0) - .collect(Collectors.toList()); + .filter(key -> key.getNodeUuid().compareTo(nodeUuid) == 0) + .toList(); keys.forEach(timeSeriesLastChunkMap::remove); clearTimeSeriesData(nodeId, doubleTimeSeriesChunksMap); clearTimeSeriesData(nodeId, stringTimeSeriesChunksMap); @@ -822,7 +825,7 @@ public Set getDependencies(String nodeId, String name) { return Collections.emptySet(); } return dependencyNodes.stream().map(this::getNodeInfo).filter(nodeInfo -> isConsistent(nodeInfo.getId())) - .collect(Collectors.toCollection(LinkedHashSet::new)); + .collect(Collectors.toCollection(LinkedHashSet::new)); } @Override @@ -834,9 +837,9 @@ public Set getDependencies(String nodeId) { throw createNodeNotFoundException(nodeUuid); } return dependencyNodes.stream() - .filter(namedLink -> isConsistent(getNodeInfo(namedLink.getNodeUuid()).getId())) - .map(namedLink -> new NodeDependency(namedLink.getName(), getNodeInfo(namedLink.getNodeUuid()))) - .collect(Collectors.toSet()); + .filter(namedLink -> isConsistent(getNodeInfo(namedLink.getNodeUuid()).getId())) + .map(namedLink -> new NodeDependency(namedLink.getName(), getNodeInfo(namedLink.getNodeUuid()))) + .collect(Collectors.toSet()); } @Override @@ -848,9 +851,9 @@ public Set getBackwardDependencies(String nodeId) { throw createNodeNotFoundException(nodeUuid); } return backwardDependencyNodes.stream() - .map(this::getNodeInfo) - .filter(nodeInfo -> isConsistent(nodeInfo.getId())) - .collect(Collectors.toSet()); + .map(this::getNodeInfo) + .filter(nodeInfo -> isConsistent(nodeInfo.getId())) + .collect(Collectors.toSet()); } @Override @@ -883,4 +886,9 @@ public void close() { db.commit(); db.close(); } + + @FunctionalInterface + public interface MapDbAppStorageProvider { + R apply(F first, S second, T third); + } } diff --git a/afs-security-analysis-local/src/test/java/com/powsybl/afs/security/local/LocalSecurityAnalysisRunningServiceTest.java b/afs-security-analysis-local/src/test/java/com/powsybl/afs/security/local/LocalSecurityAnalysisRunningServiceTest.java index 6a257e93..33112815 100644 --- a/afs-security-analysis-local/src/test/java/com/powsybl/afs/security/local/LocalSecurityAnalysisRunningServiceTest.java +++ b/afs-security-analysis-local/src/test/java/com/powsybl/afs/security/local/LocalSecurityAnalysisRunningServiceTest.java @@ -6,7 +6,6 @@ */ package com.powsybl.afs.security.local; -import com.google.common.collect.ImmutableList; import com.powsybl.afs.ServiceExtension; import com.powsybl.afs.ext.base.LocalNetworkCacheServiceExtension; import com.powsybl.afs.security.SecurityAnalysisRunnerTest; diff --git a/afs-security-analysis/src/test/java/com/powsybl/afs/security/SecurityAnalysisRunnerTest.java b/afs-security-analysis/src/test/java/com/powsybl/afs/security/SecurityAnalysisRunnerTest.java index d800cb2c..f94c04bb 100644 --- a/afs-security-analysis/src/test/java/com/powsybl/afs/security/SecurityAnalysisRunnerTest.java +++ b/afs-security-analysis/src/test/java/com/powsybl/afs/security/SecurityAnalysisRunnerTest.java @@ -7,12 +7,22 @@ package com.powsybl.afs.security; import com.google.auto.service.AutoService; -import com.google.common.collect.ImmutableList; -import com.powsybl.afs.*; +import com.powsybl.afs.AbstractProjectFileTest; +import com.powsybl.afs.FileExtension; +import com.powsybl.afs.Folder; +import com.powsybl.afs.Project; +import com.powsybl.afs.ProjectFileExtension; +import com.powsybl.afs.ServiceCreationContext; +import com.powsybl.afs.ServiceExtension; import com.powsybl.afs.contingency.ContingencyStore; import com.powsybl.afs.contingency.ContingencyStoreBuilder; import com.powsybl.afs.contingency.ContingencyStoreExtension; -import com.powsybl.afs.ext.base.*; +import com.powsybl.afs.ext.base.Case; +import com.powsybl.afs.ext.base.CaseExtension; +import com.powsybl.afs.ext.base.ImportedCase; +import com.powsybl.afs.ext.base.ImportedCaseBuilder; +import com.powsybl.afs.ext.base.ImportedCaseExtension; +import com.powsybl.afs.ext.base.LocalNetworkCacheServiceExtension; import com.powsybl.afs.mapdb.storage.MapDbAppStorage; import com.powsybl.afs.storage.AppStorage; import com.powsybl.afs.storage.InMemoryEventsBus; @@ -22,10 +32,19 @@ import com.powsybl.commons.datasource.ReadOnlyDataSource; import com.powsybl.contingency.BranchContingency; import com.powsybl.contingency.Contingency; -import com.powsybl.iidm.network.*; +import com.powsybl.iidm.network.ImportConfig; +import com.powsybl.iidm.network.Importer; +import com.powsybl.iidm.network.ImportersLoader; +import com.powsybl.iidm.network.ImportersLoaderList; +import com.powsybl.iidm.network.Network; +import com.powsybl.iidm.network.NetworkFactory; import com.powsybl.iidm.network.test.EurostagTutorialExample1Factory; import com.powsybl.loadflow.LoadFlowResult; -import com.powsybl.security.*; +import com.powsybl.security.LimitViolation; +import com.powsybl.security.LimitViolationType; +import com.powsybl.security.LimitViolationsResult; +import com.powsybl.security.SecurityAnalysisParameters; +import com.powsybl.security.SecurityAnalysisResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,72 +53,25 @@ import java.util.List; import java.util.Properties; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Geoffroy Jamgotchian {@literal } */ public class SecurityAnalysisRunnerTest extends AbstractProjectFileTest { + private final ImportersLoader importersLoader = new ImportersLoaderList(new ImporterMock()); + private static SecurityAnalysisResult createResult() { - LimitViolationsResult preContingencyResult = new LimitViolationsResult(ImmutableList - .of(new LimitViolation("s1", LimitViolationType.HIGH_VOLTAGE, 400.0, 1f, 440.0))); + LimitViolationsResult preContingencyResult = new LimitViolationsResult( + List.of(new LimitViolation("s1", LimitViolationType.HIGH_VOLTAGE, 400.0, 1f, 440.0))); return new SecurityAnalysisResult(preContingencyResult, LoadFlowResult.ComponentResult.Status.CONVERGED, Collections.emptyList()); } - private static final class SecurityAnalysisServiceMock implements SecurityAnalysisRunningService { - - @Override - public void run(SecurityAnalysisRunner runner) { - runner.writeResult(createResult()); - } - } - - @AutoService(ServiceExtension.class) - public static class SecurityAnalysisServiceExtensionMock implements ServiceExtension { - - @Override - public ServiceKey getServiceKey() { - return new ServiceKey<>(SecurityAnalysisRunningService.class, false); - } - - @Override - public SecurityAnalysisRunningService createService(ServiceCreationContext context) { - return new SecurityAnalysisServiceMock(); - } - } - - private static final class ImporterMock implements Importer { - - static final String FORMAT = "net"; - - @Override - public String getFormat() { - return FORMAT; - } - - @Override - public String getComment() { - return ""; - } - - @Override - public boolean exists(ReadOnlyDataSource dataSource) { - return true; - } - - @Override - public Network importData(ReadOnlyDataSource dataSource, NetworkFactory networkFactory, Properties parameters) { - return EurostagTutorialExample1Factory.createWithFixedCurrentLimits(); - } - - @Override - public void copy(ReadOnlyDataSource fromDataSource, DataSource toDataSource) { - } - } - - private final ImportersLoader importersLoader = new ImportersLoaderList(new ImporterMock()); - @Override protected AppStorage createStorage() { return MapDbAppStorage.createMem("mem", new InMemoryEventsBus()); @@ -113,14 +85,14 @@ protected List getFileExtensions() { @Override protected List getProjectFileExtensions() { return List.of(new ImportedCaseExtension(importersLoader, new ImportConfig()), - new ContingencyStoreExtension(), - new SecurityAnalysisRunnerExtension(new SecurityAnalysisParameters())); + new ContingencyStoreExtension(), + new SecurityAnalysisRunnerExtension(new SecurityAnalysisParameters())); } @Override protected List getServiceExtensions() { return List.of(new SecurityAnalysisServiceExtensionMock(), - new LocalNetworkCacheServiceExtension()); + new LocalNetworkCacheServiceExtension()); } @BeforeEach @@ -131,11 +103,11 @@ public void setup() throws IOException { // create network.net NodeInfo caseNode = storage.createNode(rootFolderInfo.getId(), "network", Case.PSEUDO_CLASS, "", Case.VERSION, - new NodeGenericMetadata().setString(Case.FORMAT, ImporterMock.FORMAT)); + new NodeGenericMetadata().setString(Case.FORMAT, ImporterMock.FORMAT)); // create network2.net NodeInfo caseNode2 = storage.createNode(rootFolderInfo.getId(), "network2", Case.PSEUDO_CLASS, "", Case.VERSION, - new NodeGenericMetadata().setString(Case.FORMAT, ImporterMock.FORMAT)); + new NodeGenericMetadata().setString(Case.FORMAT, ImporterMock.FORMAT)); storage.setConsistent(caseNode.getId()); storage.setConsistent(caseNode2.getId()); } @@ -143,29 +115,29 @@ public void setup() throws IOException { @Test void test() { Case aCase = afs.getRootFolder().getChild(Case.class, "network") - .orElseThrow(AssertionError::new); + .orElseThrow(AssertionError::new); // create project in the root folder Project project = afs.getRootFolder().createProject("project"); // import network.net in root folder of the project ImportedCase importedCase = project.getRootFolder().fileBuilder(ImportedCaseBuilder.class) - .withCase(aCase) - .build(); + .withCase(aCase) + .build(); // create contingency list ContingencyStore contingencyStore = project.getRootFolder().fileBuilder(ContingencyStoreBuilder.class) - .withName("contingencies") - .build(); + .withName("contingencies") + .build(); contingencyStore.write(new Contingency("c1", new BranchContingency("NHV1_NHV2_1")), - new Contingency("c1", new BranchContingency("NHV1_NHV2_2"))); + new Contingency("c1", new BranchContingency("NHV1_NHV2_2"))); // create a security analysis runner that point to imported case SecurityAnalysisRunner runner = project.getRootFolder().fileBuilder(SecurityAnalysisRunnerBuilder.class) - .withName("sa") - .withCase(importedCase) - .withContingencyStore(contingencyStore) - .build(); + .withName("sa") + .withCase(importedCase) + .withContingencyStore(contingencyStore) + .build(); assertTrue(runner.getCase().isPresent()); assertEquals(importedCase.getId(), runner.getCase().get().getId()); @@ -200,13 +172,13 @@ void test() { // update dependencies Case aCase2 = afs.getRootFolder().getChild(Case.class, "network2") - .orElseThrow(AssertionError::new); + .orElseThrow(AssertionError::new); ImportedCase importedCase2 = project.getRootFolder().fileBuilder(ImportedCaseBuilder.class) - .withCase(aCase2) - .build(); + .withCase(aCase2) + .build(); ContingencyStore contingencyStore2 = project.getRootFolder().fileBuilder(ContingencyStoreBuilder.class) - .withName("contingencies2") - .build(); + .withName("contingencies2") + .build(); runner.setCase(importedCase2); runner.setContingencyStore(contingencyStore2); assertTrue(runner.getCase().isPresent()); @@ -216,10 +188,10 @@ void test() { //test missing dependencies SecurityAnalysisRunner runner2 = project.getRootFolder().fileBuilder(SecurityAnalysisRunnerBuilder.class) - .withName("sar") - .withCase(importedCase) - .withContingencyStore(contingencyStore) - .build(); + .withName("sar") + .withCase(importedCase) + .withContingencyStore(contingencyStore) + .build(); contingencyStore.delete(); assertTrue(runner2.mandatoryDependenciesAreMissing()); @@ -227,16 +199,68 @@ void test() { assertTrue(runner2.mandatoryDependenciesAreMissing()); ImportedCase importedCase3 = project.getRootFolder().fileBuilder(ImportedCaseBuilder.class) - .withCase(aCase) - .build(); + .withCase(aCase) + .build(); runner2.setCase(importedCase3); ContingencyStore contingencyStore3 = project.getRootFolder().fileBuilder(ContingencyStoreBuilder.class) - .withName("contingencies3") - .build(); + .withName("contingencies3") + .build(); contingencyStore3.write(new Contingency("c3", new BranchContingency("l3"))); runner2.setContingencyStore(contingencyStore3); assertFalse(runner2.mandatoryDependenciesAreMissing()); } + + private static final class SecurityAnalysisServiceMock implements SecurityAnalysisRunningService { + + @Override + public void run(SecurityAnalysisRunner runner) { + runner.writeResult(createResult()); + } + } + + @AutoService(ServiceExtension.class) + public static class SecurityAnalysisServiceExtensionMock implements ServiceExtension { + + @Override + public ServiceKey getServiceKey() { + return new ServiceKey<>(SecurityAnalysisRunningService.class, false); + } + + @Override + public SecurityAnalysisRunningService createService(ServiceCreationContext context) { + return new SecurityAnalysisServiceMock(); + } + } + + private static final class ImporterMock implements Importer { + + static final String FORMAT = "net"; + + @Override + public String getFormat() { + return FORMAT; + } + + @Override + public String getComment() { + return ""; + } + + @Override + public boolean exists(ReadOnlyDataSource dataSource) { + return true; + } + + @Override + public Network importData(ReadOnlyDataSource dataSource, NetworkFactory networkFactory, Properties parameters) { + return EurostagTutorialExample1Factory.createWithFixedCurrentLimits(); + } + + @Override + public void copy(ReadOnlyDataSource fromDataSource, DataSource toDataSource) { + // Nothing here + } + } } diff --git a/afs-spring-server/src/test/java/com/powsybl/afs/server/StorageServerTest.java b/afs-spring-server/src/test/java/com/powsybl/afs/server/StorageServerTest.java index af79e0c4..0859151e 100644 --- a/afs-spring-server/src/test/java/com/powsybl/afs/server/StorageServerTest.java +++ b/afs-spring-server/src/test/java/com/powsybl/afs/server/StorageServerTest.java @@ -7,10 +7,22 @@ package com.powsybl.afs.server; -import com.google.common.collect.ImmutableList; -import com.powsybl.afs.*; +import com.powsybl.afs.AppData; +import com.powsybl.afs.AppFileSystem; +import com.powsybl.afs.AppFileSystemProvider; +import com.powsybl.afs.Folder; +import com.powsybl.afs.LocalTaskMonitor; +import com.powsybl.afs.Project; +import com.powsybl.afs.ProjectFile; +import com.powsybl.afs.TaskMonitor; import com.powsybl.afs.mapdb.storage.MapDbAppStorage; -import com.powsybl.afs.storage.*; +import com.powsybl.afs.storage.AbstractAppStorageTest; +import com.powsybl.afs.storage.AfsStorageException; +import com.powsybl.afs.storage.AppStorage; +import com.powsybl.afs.storage.EventsBus; +import com.powsybl.afs.storage.InMemoryEventsBus; +import com.powsybl.afs.storage.NodeGenericMetadata; +import com.powsybl.afs.storage.NodeInfo; import com.powsybl.afs.storage.check.FileSystemCheckIssue; import com.powsybl.afs.storage.check.FileSystemCheckOptions; import com.powsybl.afs.storage.check.FileSystemCheckOptionsBuilder; @@ -41,7 +53,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; From a7a0dda8ebc137159151f9fa48ca3eb817b74ba2 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 16:19:14 +0100 Subject: [PATCH 12/36] clean part of AppData Signed-off-by: Nicolas Rol --- .../main/java/com/powsybl/afs/AppData.java | 98 +++++++++---------- 1 file changed, 45 insertions(+), 53 deletions(-) diff --git a/afs-core/src/main/java/com/powsybl/afs/AppData.java b/afs-core/src/main/java/com/powsybl/afs/AppData.java index f64de674..af3a0625 100644 --- a/afs-core/src/main/java/com/powsybl/afs/AppData.java +++ b/afs-core/src/main/java/com/powsybl/afs/AppData.java @@ -17,7 +17,7 @@ /** * An instance of AppData is the root of an application file system. - * + *

* Usually, an application will only have one instance of AppData. * It is the first entrypoint of AFS, through which you can access to individual {@link AppFileSystem} objects. * @@ -45,28 +45,17 @@ */ public class AppData implements AutoCloseable { - private ComputationManager shortTimeExecutionComputationManager; - - private ComputationManager longTimeExecutionComputationManager; - - private Map fileSystems; - private final List fileSystemProviders; - private final List serviceExtensions; - private final Map, FileExtension> fileExtensions = new HashMap<>(); - private final Map fileExtensionsByPseudoClass = new HashMap<>(); - private final Map, ProjectFileExtension> projectFileExtensions = new HashMap<>(); - private final Map projectFileExtensionsByPseudoClass = new HashMap<>(); - private final Set> projectFileClasses = new HashSet<>(); - private final EventsBus eventsBus; - + private ComputationManager shortTimeExecutionComputationManager; + private ComputationManager longTimeExecutionComputationManager; + private Map fileSystems; private Map services; private SecurityTokenProvider tokenProvider = () -> null; @@ -77,31 +66,35 @@ public AppData(ComputationManager shortTimeExecutionComputationManager, Computat public AppData(ComputationManager shortTimeExecutionComputationManager, ComputationManager longTimeExecutionComputationManager, EventsBus eventsBus) { this(shortTimeExecutionComputationManager, longTimeExecutionComputationManager, - getDefaultFileSystemProviders(), getDefaultFileExtensions(), getDefaultProjectFileExtensions(), getDefaultServiceExtensions(), eventsBus); + getDefaultFileSystemProviders(), getDefaultFileExtensions(), getDefaultProjectFileExtensions(), getDefaultServiceExtensions(), eventsBus); } - public AppData(ComputationManager shortTimeExecutionComputationManager, - ComputationManager longTimeExecutionComputationManager, List fileSystemProviders) { + public AppData( + ComputationManager shortTimeExecutionComputationManager, + ComputationManager longTimeExecutionComputationManager, List fileSystemProviders) { this(shortTimeExecutionComputationManager, longTimeExecutionComputationManager, - fileSystemProviders, getDefaultEventsBus()); + fileSystemProviders, getDefaultEventsBus()); } - public AppData(ComputationManager shortTimeExecutionComputationManager, - ComputationManager longTimeExecutionComputationManager, List fileSystemProviders, EventsBus eventsBus) { + public AppData( + ComputationManager shortTimeExecutionComputationManager, + ComputationManager longTimeExecutionComputationManager, List fileSystemProviders, EventsBus eventsBus) { this(shortTimeExecutionComputationManager, longTimeExecutionComputationManager, - fileSystemProviders, getDefaultFileExtensions(), getDefaultProjectFileExtensions(), getDefaultServiceExtensions(), eventsBus); + fileSystemProviders, getDefaultFileExtensions(), getDefaultProjectFileExtensions(), getDefaultServiceExtensions(), eventsBus); } - public AppData(ComputationManager shortTimeExecutionComputationManager, ComputationManager longTimeExecutionComputationManager, - List fileSystemProviders, List fileExtensions, - List projectFileExtensions, List serviceExtensions) { + public AppData( + ComputationManager shortTimeExecutionComputationManager, ComputationManager longTimeExecutionComputationManager, + List fileSystemProviders, List fileExtensions, + List projectFileExtensions, List serviceExtensions) { this(shortTimeExecutionComputationManager, longTimeExecutionComputationManager, fileSystemProviders, fileExtensions, - projectFileExtensions, serviceExtensions, getDefaultEventsBus()); + projectFileExtensions, serviceExtensions, getDefaultEventsBus()); } - public AppData(ComputationManager shortTimeExecutionComputationManager, ComputationManager longTimeExecutionComputationManager, - List fileSystemProviders, List fileExtensions, - List projectFileExtensions, List serviceExtensions, EventsBus eventsBus) { + public AppData( + ComputationManager shortTimeExecutionComputationManager, ComputationManager longTimeExecutionComputationManager, + List fileSystemProviders, List fileExtensions, + List projectFileExtensions, List serviceExtensions, EventsBus eventsBus) { Objects.requireNonNull(fileSystemProviders); Objects.requireNonNull(fileExtensions); Objects.requireNonNull(projectFileExtensions); @@ -110,11 +103,11 @@ public AppData(ComputationManager shortTimeExecutionComputationManager, Computat this.longTimeExecutionComputationManager = longTimeExecutionComputationManager; this.fileSystemProviders = Objects.requireNonNull(fileSystemProviders); this.serviceExtensions = Objects.requireNonNull(serviceExtensions); - for (FileExtension extension : fileExtensions) { + for (FileExtension extension : fileExtensions) { this.fileExtensions.put(extension.getFileClass(), extension); this.fileExtensionsByPseudoClass.put(extension.getFilePseudoClass(), extension); } - for (ProjectFileExtension extension : projectFileExtensions) { + for (ProjectFileExtension extension : projectFileExtensions) { this.projectFileExtensions.put(extension.getProjectFileClass(), extension); this.projectFileExtensions.put(extension.getProjectFileBuilderClass(), extension); this.projectFileExtensionsByPseudoClass.put(extension.getProjectFilePseudoClass(), extension); @@ -142,6 +135,10 @@ private static List getDefaultServiceExtensions() { return new ServiceLoaderCache<>(ServiceExtension.class).getServices(); } + private static String[] more(String[] path) { + return path.length > 2 ? Arrays.copyOfRange(path, 2, path.length - 1) : new String[] {}; + } + private synchronized void loadFileSystems() { if (fileSystems == null) { fileSystems = new HashMap<>(); @@ -159,7 +156,7 @@ private synchronized void loadServices() { if (services == null) { services = new HashMap<>(); ServiceCreationContext context = new ServiceCreationContext(tokenProvider.getToken()); - for (ServiceExtension extension : serviceExtensions) { + for (ServiceExtension extension : serviceExtensions) { services.put(extension.getServiceKey(), extension.createService(context)); } } @@ -214,10 +211,6 @@ public void setTokenProvider(SecurityTokenProvider tokenProvider) { services = null; } - private static String[] more(String[] path) { - return path.length > 2 ? Arrays.copyOfRange(path, 2, path.length - 1) : new String[] {}; - } - public Optional getNode(String pathStr) { Objects.requireNonNull(pathStr); loadFileSystems(); @@ -231,7 +224,7 @@ public Optional getNode(String pathStr) { return Optional.empty(); } return path.length == 1 ? Optional.of(fileSystem.getRootFolder()) - : fileSystem.getRootFolder().getChild(path[1], more(path)); + : fileSystem.getRootFolder().getChild(path[1], more(path)); } public Set> getProjectFileClasses() { @@ -240,7 +233,7 @@ public Set> getProjectFileClasses() { FileExtension getFileExtension(Class fileClass) { Objects.requireNonNull(fileClass); - FileExtension extension = fileExtensions.get(fileClass); + FileExtension extension = fileExtensions.get(fileClass); if (extension == null) { throw new AfsException("No extension found for file class '" + fileClass.getName() + "'"); } @@ -254,10 +247,10 @@ FileExtension getFileExtensionByPseudoClass(String filePseudoClass) { ProjectFileExtension getProjectFileExtension(Class projectFileOrProjectFileBuilderClass) { Objects.requireNonNull(projectFileOrProjectFileBuilderClass); - ProjectFileExtension extension = projectFileExtensions.get(projectFileOrProjectFileBuilderClass); + ProjectFileExtension extension = projectFileExtensions.get(projectFileOrProjectFileBuilderClass); if (extension == null) { throw new AfsException("No extension found for project file or project file builder class '" - + projectFileOrProjectFileBuilderClass.getName() + "'"); + + projectFileOrProjectFileBuilderClass.getName() + "'"); } return extension; } @@ -271,20 +264,27 @@ public ComputationManager getShortTimeExecutionComputationManager() { return shortTimeExecutionComputationManager; } + public void setShortTimeExecutionComputationManager(ComputationManager shortTimeExecutionComputationManager) { + this.shortTimeExecutionComputationManager = shortTimeExecutionComputationManager; + } + public ComputationManager getLongTimeExecutionComputationManager() { return longTimeExecutionComputationManager != null ? longTimeExecutionComputationManager : shortTimeExecutionComputationManager; } + public void setLongTimeExecutionComputationManager(ComputationManager longTimeExecutionComputationManager) { + this.longTimeExecutionComputationManager = longTimeExecutionComputationManager; + } + /** * Gets the list of remotely accessible file systems. Should not be used by the AFS API users. */ public List getRemotelyAccessibleFileSystemNames() { loadFileSystems(); - return fileSystems.entrySet().stream() - .map(Map.Entry::getValue) - .filter(AppFileSystem::isRemotelyAccessible) - .map(AppFileSystem::getName) - .collect(Collectors.toList()); + return fileSystems.values().stream() + .filter(AppFileSystem::isRemotelyAccessible) + .map(AppFileSystem::getName) + .collect(Collectors.toList()); } /** @@ -333,12 +333,4 @@ public EventsBus getEventsBus() { public void close() { closeFileSystems(); } - - public void setShortTimeExecutionComputationManager(ComputationManager shortTimeExecutionComputationManager) { - this.shortTimeExecutionComputationManager = shortTimeExecutionComputationManager; - } - - public void setLongTimeExecutionComputationManager(ComputationManager longTimeExecutionComputationManager) { - this.longTimeExecutionComputationManager = longTimeExecutionComputationManager; - } } From c93e1abb28404e595873307ed350c00d17617e1b Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 16:20:46 +0100 Subject: [PATCH 13/36] clean part of AppFileSystem Signed-off-by: Nicolas Rol --- afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java b/afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java index f68360e9..b1b38e0d 100644 --- a/afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java +++ b/afs-core/src/main/java/com/powsybl/afs/AppFileSystem.java @@ -6,7 +6,6 @@ */ package com.powsybl.afs; -import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.powsybl.afs.storage.AfsStorageException; import com.powsybl.afs.storage.AppStorage; @@ -18,6 +17,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.function.Supplier; /** * An AppFileSystem instance is a tree of {@link Node} objects, starting with its root folder. @@ -98,7 +98,7 @@ public Node createNode(NodeInfo nodeInfo) { } else if (Project.PSEUDO_CLASS.equals(nodeInfo.getPseudoClass())) { return new Project(context); } else { - FileExtension extension = data.getFileExtensionByPseudoClass(nodeInfo.getPseudoClass()); + FileExtension extension = data.getFileExtensionByPseudoClass(nodeInfo.getPseudoClass()); if (extension != null) { return extension.createFile(context); } else { @@ -153,7 +153,7 @@ public AbstractNodeBase fetchNode(String nodeId, boolean connected) { return new ProjectFolder(context); } - ProjectFileExtension extension = data.getProjectFileExtensionByPseudoClass(projectFileInfo.getPseudoClass()); + ProjectFileExtension extension = data.getProjectFileExtensionByPseudoClass(projectFileInfo.getPseudoClass()); if (extension != null) { return extension.createProjectFile(context); } From 076cb46b84e875478d069d0ca00c7ce9d32ac417 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 16:28:44 +0100 Subject: [PATCH 14/36] clean part of AppFileSystemTool Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/AppFileSystemTool.java | 201 +++++++++--------- 1 file changed, 101 insertions(+), 100 deletions(-) diff --git a/afs-core/src/main/java/com/powsybl/afs/AppFileSystemTool.java b/afs-core/src/main/java/com/powsybl/afs/AppFileSystemTool.java index 99e07b89..faf6c59b 100644 --- a/afs-core/src/main/java/com/powsybl/afs/AppFileSystemTool.java +++ b/afs-core/src/main/java/com/powsybl/afs/AppFileSystemTool.java @@ -45,9 +45,24 @@ public class AppFileSystemTool implements Tool { private static final ServiceLoaderCache PROJECT_FILE_EXECUTION = new ServiceLoaderCache<>(ProjectFileExtension.class); + private static InconsistentNodeParam getInconsistentNodeParam(CommandLine line, String optionName) { + String[] values = line.getOptionValues(optionName); + if (values == null) { + throw new IllegalArgumentException("Invalid values for option: " + optionName); + } + InconsistentNodeParam param = new InconsistentNodeParam(); + if (values.length == 2) { + param.fileSystemName = values[0]; + param.nodeId = values[1]; + } else if (values.length == 1) { + param.fileSystemName = values[0]; + } + return param; + } + protected AppData createAppData(ToolRunningContext context) { return new AppData(context.getShortTimeExecutionComputationManager(), - context.getLongTimeExecutionComputationManager()); + context.getLongTimeExecutionComputationManager()); } @Override @@ -73,72 +88,72 @@ public Options getOptions() { Options options = new Options(); OptionGroup topLevelOptions = new OptionGroup(); topLevelOptions.addOption(Option.builder() - .longOpt(LS) - .desc("list files") - .hasArg() - .optionalArg(true) - .argName("PATH") - .build()); + .longOpt(LS) + .desc("list files") + .hasArg() + .optionalArg(true) + .argName("PATH") + .build()); topLevelOptions.addOption(Option.builder() - .longOpt(ARCHIVE) - .desc("archive file system") - .hasArg() - .optionalArg(true) - .argName(FILE_SYSTEM_NAME) - .build()); + .longOpt(ARCHIVE) + .desc("archive file system") + .hasArg() + .optionalArg(true) + .argName(FILE_SYSTEM_NAME) + .build()); topLevelOptions.addOption(Option.builder() - .longOpt(UNARCHIVE) - .desc("unarchive file system") - .hasArg() - .optionalArg(true) - .argName(FILE_SYSTEM_NAME) - .build()); + .longOpt(UNARCHIVE) + .desc("unarchive file system") + .hasArg() + .optionalArg(true) + .argName(FILE_SYSTEM_NAME) + .build()); topLevelOptions.addOption(Option.builder() - .longOpt(LS_INCONSISTENT_NODES) - .desc("list the inconsistent nodes") - .hasArg() - .optionalArg(true) - .argName(FILE_SYSTEM_NAME) - .build()); + .longOpt(LS_INCONSISTENT_NODES) + .desc("list the inconsistent nodes") + .hasArg() + .optionalArg(true) + .argName(FILE_SYSTEM_NAME) + .build()); topLevelOptions.addOption(Option.builder() - .longOpt(FIX_INCONSISTENT_NODES) - .desc("make inconsistent nodes consistent") - .optionalArg(true) - .argName(FILE_SYSTEM_NAME + "> keepTs = new ArrayList<>(); if (deleteResult) { outputBlackList = PROJECT_FILE_EXECUTION.getServices().stream() - .collect(Collectors.toMap(ProjectFileExtension::getProjectFilePseudoClass, - ProjectFileExtension::getOutputList)); + .collect(Collectors.toMap(ProjectFileExtension::getProjectFilePseudoClass, + ProjectFileExtension::getOutputList)); keepTs = PROJECT_FILE_EXECUTION.getServices().stream().filter(ProjectFileExtension::removeTSWhenArchive).map(ProjectFileExtension::getProjectFilePseudoClass) - .collect(Collectors.toList()); + .collect(Collectors.toList()); } fs.getRootFolder().archive(dir, mustZip, archiveDependencies, outputBlackList, keepTs); } @@ -250,35 +266,15 @@ private void fixInconsistentNodes(ToolRunningContext context, AppFileSystem fs, }); } else { nodeInfos.stream() - .filter(nodeInfo -> nodeId.equals(nodeInfo.getId())) - .forEach(nodeInfo -> { - fs.getStorage().setConsistent(nodeInfo.getId()); - context.getOutputStream().println(nodeInfo.getId() + " fixed"); - }); + .filter(nodeInfo -> nodeId.equals(nodeInfo.getId())) + .forEach(nodeInfo -> { + fs.getStorage().setConsistent(nodeInfo.getId()); + context.getOutputStream().println(nodeInfo.getId() + " fixed"); + }); } } } - static class InconsistentNodeParam { - String fileSystemName; - String nodeId; - } - - private static InconsistentNodeParam getInconsistentNodeParam(CommandLine line, String optionName) { - String[] values = line.getOptionValues(optionName); - if (values == null) { - throw new IllegalArgumentException("Invalid values for option: " + optionName); - } - InconsistentNodeParam param = new InconsistentNodeParam(); - if (values.length == 2) { - param.fileSystemName = values[0]; - param.nodeId = values[1]; - } else if (values.length == 1) { - param.fileSystemName = values[0]; - } - return param; - } - private void runFixInconsistentNodes(CommandLine line, ToolRunningContext context) { try (AppData appData = createAppData(context)) { InconsistentNodeParam param = getInconsistentNodeParam(line, FIX_INCONSISTENT_NODES); @@ -307,11 +303,11 @@ private void removeInconsistentNodes(ToolRunningContext context, AppFileSystem f }); } else { nodeInfos.stream() - .filter(nodeInfo -> nodeId.equals(nodeInfo.getId())) - .forEach(nodeInfo -> { - fs.getStorage().deleteNode(nodeInfo.getId()); - context.getOutputStream().println(nodeInfo.getId() + " cleaned"); - }); + .filter(nodeInfo -> nodeId.equals(nodeInfo.getId())) + .forEach(nodeInfo -> { + fs.getStorage().deleteNode(nodeInfo.getId()); + context.getOutputStream().println(nodeInfo.getId() + " cleaned"); + }); } } } @@ -352,4 +348,9 @@ public void run(CommandLine line, ToolRunningContext context) throws IOException CommandLineTools.printCommandUsage(command.getName(), command.getOptions(), command.getUsageFooter(), context.getErrorStream()); } } + + static class InconsistentNodeParam { + String fileSystemName; + String nodeId; + } } From 2a79c7fbaa50c8ac35863792a76986ed6c1e06a9 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 16:31:24 +0100 Subject: [PATCH 15/36] clean LocalTaskMonitor Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/LocalTaskMonitor.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/afs-core/src/main/java/com/powsybl/afs/LocalTaskMonitor.java b/afs-core/src/main/java/com/powsybl/afs/LocalTaskMonitor.java index 3bc65d70..a026f82e 100644 --- a/afs-core/src/main/java/com/powsybl/afs/LocalTaskMonitor.java +++ b/afs-core/src/main/java/com/powsybl/afs/LocalTaskMonitor.java @@ -6,10 +6,12 @@ */ package com.powsybl.afs; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.Future; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -20,15 +22,12 @@ */ public class LocalTaskMonitor implements TaskMonitor { - private static final Logger LOGGER = LoggerFactory.getLogger(LocalTaskMonitor.class); + private static final String TASK_NOT_FOUND = "Task '%s' not found"; private final Map tasks = new HashMap<>(); private final Map tasksFuture = new HashMap<>(); - - private long revision = 0L; - private final Lock lock = new ReentrantLock(); - private final List listeners = new ArrayList<>(); + private long revision = 0L; @Override public Task startTask(ProjectFile projectFile) { @@ -68,7 +67,7 @@ public void stopTask(UUID id) { try { Task task = tasks.remove(id); if (task == null) { - throw new IllegalArgumentException("Task '" + id + "' not found"); + throw new IllegalArgumentException(String.format(TASK_NOT_FOUND, id)); } revision++; @@ -87,9 +86,9 @@ public Snapshot takeSnapshot(String projectId) { lock.lock(); try { return new Snapshot(tasks.values().stream() - .filter(task -> projectId == null || task.getProjectId().equals(projectId)) - .map(Task::new).collect(Collectors.toList()), - revision); + .filter(task -> projectId == null || task.getProjectId().equals(projectId)) + .map(Task::new).collect(Collectors.toList()), + revision); } finally { lock.unlock(); } @@ -110,7 +109,7 @@ public void updateTaskMessage(UUID id, String message) { try { Task task = tasks.get(id); if (task == null) { - throw new IllegalArgumentException("Task '" + id + "' not found"); + throw new IllegalArgumentException(String.format(TASK_NOT_FOUND, id)); } revision++; task.setMessage(message); @@ -160,7 +159,7 @@ public void updateTaskFuture(UUID taskId, Future future) { try { Task task = tasks.get(taskId); if (task == null) { - throw new IllegalArgumentException("Task '" + taskId + "' not found"); + throw new IllegalArgumentException(String.format(TASK_NOT_FOUND, taskId)); } tasksFuture.put(taskId, future); task.setCancellable(future != null); From 39fd6aa003ecd63f1c1df5c22a8a968afaf2c9f6 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 16:32:21 +0100 Subject: [PATCH 16/36] clean AbstractProjectFileTest Signed-off-by: Nicolas Rol --- .../powsybl/afs/AbstractProjectFileTest.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/afs-core/src/test/java/com/powsybl/afs/AbstractProjectFileTest.java b/afs-core/src/test/java/com/powsybl/afs/AbstractProjectFileTest.java index 7acf4c13..3b1e763e 100644 --- a/afs-core/src/test/java/com/powsybl/afs/AbstractProjectFileTest.java +++ b/afs-core/src/test/java/com/powsybl/afs/AbstractProjectFileTest.java @@ -10,7 +10,6 @@ import com.powsybl.computation.ComputationManager; import com.powsybl.computation.local.LocalComputationManager; import com.powsybl.iidm.network.Network; -import com.powsybl.iidm.network.Substation; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -48,18 +47,18 @@ protected List getServiceExtensions() { @BeforeEach public void setup() throws IOException { network = Network.create("test", "test"); - Substation s = network.newSubstation() - .setId("s1") - .setTso("TSO") - .add(); + network.newSubstation() + .setId("s1") + .setTso("TSO") + .add(); ComputationManager computationManager = new LocalComputationManager(); storage = createStorage(); afs = new AppFileSystem("mem", false, storage); ad = new AppData(computationManager, computationManager, - Collections.singletonList(computationManager1 -> Collections.singletonList(afs)), - getFileExtensions(), - getProjectFileExtensions(), - getServiceExtensions()); + Collections.singletonList(computationManager1 -> Collections.singletonList(afs)), + getFileExtensions(), + getProjectFileExtensions(), + getServiceExtensions()); afs.setData(ad); } From adc251bd631c56149e866fd9ce4521a234223e9f Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 14 Feb 2025 17:25:11 +0100 Subject: [PATCH 17/36] start to clean AfsBaseTest Signed-off-by: Nicolas Rol --- .../java/com/powsybl/afs/AfsBaseTest.java | 240 +++++++++++++----- 1 file changed, 170 insertions(+), 70 deletions(-) diff --git a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java index baacbd86..efb0fb5a 100644 --- a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java +++ b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java @@ -50,6 +50,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -64,20 +65,20 @@ class AfsBaseTest { private AppFileSystem afs; - private AppData ad; + private AppData appData; @BeforeEach public void setup() { fileSystem = Jimfs.newFileSystem(Configuration.unix()); ComputationManager computationManager = Mockito.mock(ComputationManager.class); - ad = new AppData(computationManager, computationManager, Collections.emptyList(), + appData = new AppData(computationManager, computationManager, Collections.emptyList(), Collections.emptyList(), List.of(new FooFileExtension(), new WithDependencyFileExtension()), Collections.emptyList()); - storage = MapDbAppStorage.createMem("mem", ad.getEventsBus()); + storage = MapDbAppStorage.createMem("mem", appData.getEventsBus()); afs = new AppFileSystem("mem", true, storage); - afs.setData(ad); - ad.addFileSystem(afs); + afs.setData(appData); + appData.addFileSystem(afs); } @AfterEach @@ -87,21 +88,32 @@ public void tearDown() throws Exception { } @Test - void baseTest() { - assertSame(InMemoryEventsBus.class, ad.getEventsBus().getClass()); - assertSame(afs, ad.getFileSystem("mem")); - assertNull(ad.getFileSystem("???")); - assertEquals(Collections.singletonList("mem"), ad.getRemotelyAccessibleFileSystemNames()); - assertNotNull(ad.getRemotelyAccessibleStorage("mem")); + void appDataTest() { + assertSame(InMemoryEventsBus.class, appData.getEventsBus().getClass()); + assertSame(afs, appData.getFileSystem("mem")); + assertNull(appData.getFileSystem("???")); + assertEquals(Collections.singletonList("mem"), appData.getRemotelyAccessibleFileSystemNames()); + assertNotNull(appData.getRemotelyAccessibleStorage("mem")); assertEquals("mem", afs.getName()); - assertEquals(2, ad.getProjectFileClasses().size()); + assertEquals(2, appData.getProjectFileClasses().size()); + } + + @Test + void rootTest() { Folder root = afs.getRootFolder(); assertNotNull(root); + } + + @Test + void directoryTest() { + Folder root = afs.getRootFolder(); + + // Create a directory under root Folder dir1 = root.createFolder("dir1"); assertTrue(storage.isConsistent(dir1.getId())); assertNotNull(dir1); - dir1.createFolder("dir2"); - dir1.createFolder("dir3"); + + // Check from getting it back from root dir1 = root.getFolder("dir1").orElse(null); assertNotNull(dir1); assertTrue(dir1.isFolder()); @@ -113,75 +125,175 @@ void baseTest() { assertFalse(dir1.isAheadOfVersion()); assertEquals(dir1.getName(), dir1.toString()); assertEquals("mem", dir1.getParent().orElseThrow(AssertionError::new).getName()); + } + + @Test + void subdirectoriesTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + + // Create two subdirectories under dir1 + dir1.createFolder("dir2"); + dir1.createFolder("dir3"); + + // Check that dir1 has 2 children + assertEquals(2, dir1.getChildren().size()); + + // Tests on dir1/dir2 Folder dir2 = dir1.getFolder("dir2").orElse(null); assertNotNull(dir2); assertNotNull(dir2.getParent()); assertEquals("mem:/dir1", dir2.getParent().orElseThrow(AssertionError::new).getPath().toString()); - assertEquals(2, dir1.getChildren().size()); - Folder dir3 = root.getFolder("dir3").orElse(null); - assertNull(dir3); String str = dir2.getPath().toString(); assertEquals("mem:/dir1/dir2", str); + + // One way to get to dir1/dir2 Folder mayBeDir2 = afs.getRootFolder().getFolder("dir1/dir2").orElse(null); assertNotNull(mayBeDir2); assertEquals("dir2", mayBeDir2.getName()); + + // Another way to get to dir1/dir2 Folder mayBeDir2otherWay = afs.getRootFolder().getChild(Folder.class, "dir1", "dir2").orElse(null); assertNotNull(mayBeDir2otherWay); assertEquals("dir2", mayBeDir2otherWay.getName()); + // dir3 doest not exist but dir1/dir3 does + Folder dir3 = root.getFolder("dir3").orElse(null); + assertNull(dir3); + dir3 = root.getFolder("dir1/dir3").orElse(null); + assertNotNull(dir3); + } + + @Test + void projectTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Folder dir2 = dir1.createFolder("dir2"); + + // Create a project under dir1/dir2 Project project1 = dir2.createProject("project1"); project1.setDescription("test project"); assertNotNull(project1); assertEquals("project1", project1.getName()); assertEquals("test project", project1.getDescription()); + + // Check the project parent assertNotNull(project1.getParent()); assertEquals("mem:/dir1/dir2", project1.getParent().orElseThrow(AssertionError::new).getPath().toString()); + + // Check that the root folder of the project is empty assertTrue(project1.getRootFolder().getChildren().isEmpty()); + + // Check the file system assertSame(project1.getFileSystem(), afs); + } - Project project2 = dir2.createProject("project2"); - project2.rename("project22"); - assertEquals("project22", project2.getName()); + @Test + void renameProjectTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Project project = dir1.createProject("project2"); + project.rename("project22"); + assertEquals("project22", project.getName()); + } - dir2.createProject("project5"); - Project project102 = dir2.createProject("project6"); - try { - project102.rename("project5"); - fail(); - } catch (AfsException ignored) { - } + @Test + void renameProjectExceptionTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); - Folder dir41 = dir2.createFolder("dir41"); - Project project3 = dir41.createProject("project3"); - project3.delete(); - assertTrue(dir41.getChildren().isEmpty()); + // Create a first project called project1 + dir1.createProject("project1"); - Folder dir51 = dir2.createFolder("dir51"); - dir51.createProject("project5"); - try { - dir51.delete(); - fail(); - } catch (AfsException ignored) { - } + // Create another project and try to rename it project1 + Project project = dir1.createProject("project2"); + AfsException exception = assertThrows(AfsException.class, () -> project.rename("project1")); + assertEquals("name already exists", exception.getMessage()); + } + + @Test + void deleteProjectTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + + // Create a project + Project project = dir1.createProject("project3"); + assertFalse(dir1.getChildren().isEmpty()); + + // Delete the project + project.delete(); + assertTrue(dir1.getChildren().isEmpty()); + } + + @Test + void deleteNonEmptyFolderTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + + // Create a project + dir1.createProject("project5"); + AfsException exception = assertThrows(AfsException.class, dir1::delete, "non-empty folders can not be deleted"); + assertEquals("non-empty folders can not be deleted", exception.getMessage()); + } + + @Test + void moveProjectTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Folder dir2 = root.createFolder("dir2"); + + // Create a project in dir1 + Project project = dir1.createProject("projet4"); + + // Check the directories content + assertFalse(dir1.getChildren().isEmpty()); + assertTrue(dir2.getChildren().isEmpty()); + + // Move the project + project.moveTo(dir2); + + // Check the directories content + assertTrue(dir1.getChildren().isEmpty()); + assertFalse(dir2.getChildren().isEmpty()); + } - Folder dir71 = root.createFolder("dir7"); - Project project4 = dir41.createProject("projet4"); - project4.moveTo(dir71); - assertFalse(dir71.getChildren().isEmpty()); + @Test + void moveFolderInChildFolderTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Folder dir2 = dir1.createFolder("dir2"); + AfsException exception = assertThrows(AfsException.class, () -> dir1.moveTo(dir2)); + assertEquals("The source node is an ancestor of the target node", exception.getMessage()); + } + + @Test + void ancestryTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Folder dir2 = dir1.createFolder("dir2"); + assertTrue(dir1.isParentOf(dir2)); + assertTrue(root.isAncestorOf(dir2)); + dir2.moveTo(dir1); // Does nothing + assertTrue(dir1.isParentOf(dir2)); + assertTrue(root.isAncestorOf(dir2)); + } + + @Test + void baseTest() throws IOException { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + dir1.createFolder("dir2"); + dir1.createFolder("dir3"); + Folder dir2 = dir1.getFolder("dir2").orElse(null); + + Project project1 = dir2.createProject("project1"); + project1.setDescription("test project"); + + dir2.createProject("project5"); Folder dir81 = root.createFolder("dir8"); Folder dir82 = dir81.createFolder("dir9"); - try { - dir81.moveTo(dir82); - fail(); - } catch (AfsException ignored) { - } - - assertTrue(dir81.isParentOf(dir82)); - assertTrue(root.isAncestorOf(dir82)); - dir82.moveTo(dir81); // Does nothing - assertTrue(dir81.isParentOf(dir82)); - assertTrue(root.isAncestorOf(dir82)); + assertThrows(AfsException.class, () -> dir81.moveTo(dir82)); List added = new ArrayList<>(); List removed = new ArrayList<>(); @@ -207,11 +319,7 @@ public void childRemoved(String nodeId) { dir4.delete(); assertTrue(rootFolder.getChildren().isEmpty()); - try { - dir4.getChildren(); - fail(); - } catch (Exception ignored) { - } + assertThrows(Exception.class, dir4::getChildren); ProjectFolder dir5 = rootFolder.createFolder("dir5"); ProjectFolder dir6 = dir5.createFolder("dir6"); @@ -227,11 +335,8 @@ public void childRemoved(String nodeId) { assertEquals("dir77", dir7.getName()); Path rootDir = fileSystem.getPath("/root"); - try { - Files.createDirectories(rootDir); - dir7.archive(rootDir); - } catch (IOException ignored) { - } + Files.createDirectories(rootDir); + dir7.archive(rootDir); Path child = rootDir.resolve(dir7.getId()); assertTrue(Files.exists(child)); @@ -242,13 +347,8 @@ public void childRemoved(String nodeId) { assertEquals("dir77", dir8.getChildren().get(0).getName()); Path testDirNotExists = rootDir.resolve("testDirNotExists"); - try { - dir7.archive(testDirNotExists); - fail(); - dir8.findService(NetworkFactoryService.class); - fail(); - } catch (UncheckedIOException ignored) { - } + assertThrows(UncheckedIOException.class, () -> dir7.archive(testDirNotExists)); + assertThrows(AfsException.class, () -> dir8.findService(NetworkFactoryService.class)); } @Test From 8f3d0771dc271193289b9356eaed574241024837 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 17 Feb 2025 11:07:56 +0100 Subject: [PATCH 18/36] clean AfsBaseTest Signed-off-by: Nicolas Rol --- .../java/com/powsybl/afs/AfsBaseTest.java | 149 ++++++++++++------ 1 file changed, 102 insertions(+), 47 deletions(-) diff --git a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java index efb0fb5a..d5865208 100644 --- a/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java +++ b/afs-core/src/test/java/com/powsybl/afs/AfsBaseTest.java @@ -43,6 +43,7 @@ import java.util.Optional; import java.util.UUID; import java.util.function.BiConsumer; +import java.util.regex.Pattern; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -67,6 +68,9 @@ class AfsBaseTest { private AppData appData; + private static final String NODE_NOT_FOUND_REGEX = "Node [0-9a-fA-F-]{36} not found"; + private static final Pattern NODE_NOT_FOUND_PATTERN = Pattern.compile(NODE_NOT_FOUND_REGEX); + @BeforeEach public void setup() { fileSystem = Jimfs.newFileSystem(Configuration.unix()); @@ -257,6 +261,37 @@ void moveProjectTest() { assertFalse(dir2.getChildren().isEmpty()); } + @Test + void createFolderInProjectTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Project project = dir1.createProject("projet4"); + ProjectFolder rootFolder = project.getRootFolder(); + + // Create a new folder inside the root folder + ProjectFolder dir2 = rootFolder.createFolder("dir2"); + + // Some checks on the new folder + assertTrue(dir2.isFolder()); + assertEquals("dir2", dir2.getName()); + assertNotNull(dir2.getParent()); + assertTrue(dir2.getChildren().isEmpty()); + assertEquals(1, rootFolder.getChildren().size()); + + // Remove the new folder + dir2.delete(); + assertTrue(rootFolder.getChildren().isEmpty()); + AfsStorageException exception = assertThrows(AfsStorageException.class, dir2::getChildren); + assertTrue(NODE_NOT_FOUND_PATTERN.matcher(exception.getMessage()).matches()); + + // Create new folders + ProjectFolder dir5 = rootFolder.createFolder("dir5"); + ProjectFolder dir6 = dir5.createFolder("dir6"); + assertEquals(List.of("dir5", "dir6"), dir6.getPath().toList().subList(1, 3)); + assertEquals("dir5/dir6", dir6.getPath().toString()); + assertEquals("dir6", rootFolder.getChild("dir5/dir6").orElseThrow(AssertionError::new).getName()); + } + @Test void moveFolderInChildFolderTest() { Folder root = afs.getRootFolder(); @@ -279,22 +314,11 @@ void ancestryTest() { } @Test - void baseTest() throws IOException { + void listenerTest() { Folder root = afs.getRootFolder(); Folder dir1 = root.createFolder("dir1"); - dir1.createFolder("dir2"); - dir1.createFolder("dir3"); - Folder dir2 = dir1.getFolder("dir2").orElse(null); - - Project project1 = dir2.createProject("project1"); - project1.setDescription("test project"); - - dir2.createProject("project5"); - - Folder dir81 = root.createFolder("dir8"); - Folder dir82 = dir81.createFolder("dir9"); - assertThrows(AfsException.class, () -> dir81.moveTo(dir82)); - + Project project = dir1.createProject("projet4"); + // Configure listeners List added = new ArrayList<>(); List removed = new ArrayList<>(); ProjectFolderListener l = new ProjectFolderListener() { @@ -308,47 +332,77 @@ public void childRemoved(String nodeId) { removed.add(nodeId); } }; - ProjectFolder rootFolder = project1.getRootFolder(); + + // Add the listener to the project's root folder + ProjectFolder rootFolder = project.getRootFolder(); rootFolder.addListener(l); - ProjectFolder dir4 = rootFolder.createFolder("dir4"); - assertTrue(dir4.isFolder()); - assertEquals("dir4", dir4.getName()); - assertNotNull(dir4.getParent()); - assertTrue(dir4.getChildren().isEmpty()); - assertEquals(1, rootFolder.getChildren().size()); - dir4.delete(); - assertTrue(rootFolder.getChildren().isEmpty()); - assertThrows(Exception.class, dir4::getChildren); + // Create a new folder inside the root folder + ProjectFolder dir2 = rootFolder.createFolder("dir2"); - ProjectFolder dir5 = rootFolder.createFolder("dir5"); - ProjectFolder dir6 = dir5.createFolder("dir6"); - assertEquals(List.of("dir5", "dir6"), dir6.getPath().toList().subList(1, 3)); - assertEquals("dir5/dir6", dir6.getPath().toString()); - assertEquals("dir6", rootFolder.getChild("dir5/dir6").orElseThrow(AssertionError::new).getName()); + // Remove the new folder + dir2.delete(); - assertEquals(Arrays.asList(dir4.getId(), dir5.getId()), added); - assertEquals(Collections.singletonList(dir4.getId()), removed); + // Create a new folder + ProjectFolder dir3 = rootFolder.createFolder("dir3"); - ProjectFolder dir7 = rootFolder.createFolder("dir7"); - dir7.rename("dir77"); - assertEquals("dir77", dir7.getName()); + // Check the listeners + assertEquals(Arrays.asList(dir2.getId(), dir3.getId()), added); + assertEquals(Collections.singletonList(dir2.getId()), removed); + } + @Test + void renameProjectFolderTest() { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Project project = dir1.createProject("projet1"); + ProjectFolder rootFolder = project.getRootFolder(); + + ProjectFolder dir2 = rootFolder.createFolder("dir2"); + dir2.rename("dir22"); + assertEquals("dir22", dir2.getName()); + } + + @Test + void archivingTest() throws IOException { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Project project = dir1.createProject("projet1"); + ProjectFolder rootFolder = project.getRootFolder(); + ProjectFolder dir2 = rootFolder.createFolder("dir2"); Path rootDir = fileSystem.getPath("/root"); Files.createDirectories(rootDir); - dir7.archive(rootDir); - Path child = rootDir.resolve(dir7.getId()); + + // Archive + dir2.archive(rootDir); + Path child = rootDir.resolve(dir2.getId()); assertTrue(Files.exists(child)); + // Unarchive ProjectFolder dir8 = rootFolder.createFolder("dir8"); assertEquals(0, dir8.getChildren().size()); dir8.unarchive(child); assertEquals(1, dir8.getChildren().size()); - assertEquals("dir77", dir8.getChildren().get(0).getName()); + assertEquals("dir2", dir8.getChildren().get(0).getName()); + } + + @Test + void archiveExceptionTest() throws IOException { + Folder root = afs.getRootFolder(); + Folder dir1 = root.createFolder("dir1"); + Project project = dir1.createProject("projet1"); + ProjectFolder rootFolder = project.getRootFolder(); + ProjectFolder dir2 = rootFolder.createFolder("dir2"); + Path rootDir = fileSystem.getPath("/root"); + Files.createDirectories(rootDir); + // Archive a non-existing folder Path testDirNotExists = rootDir.resolve("testDirNotExists"); - assertThrows(UncheckedIOException.class, () -> dir7.archive(testDirNotExists)); - assertThrows(AfsException.class, () -> dir8.findService(NetworkFactoryService.class)); + assertThrows(UncheckedIOException.class, () -> dir2.archive(testDirNotExists)); + + ProjectFolder dir3 = rootFolder.createFolder("dir3"); + AfsException exception = assertThrows(AfsException.class, () -> dir3.findService(NetworkFactoryService.class)); + assertEquals("No service found for class interface com.powsybl.iidm.network.NetworkFactoryService", exception.getMessage()); } @Test @@ -356,12 +410,11 @@ void archiveAndUnarchiveTestWithZip() throws IOException { Project project = afs.getRootFolder().createProject("test"); ProjectFolder rootFolder = project.getRootFolder(); ProjectFolder dir1 = rootFolder.createFolder("dir1"); - Path child = null; Path rootDir = fileSystem.getPath("/root"); Files.createDirectory(rootDir); Files.createDirectory(rootDir.resolve("test")); dir1.archive(rootDir.resolve("test"), true, false, new HashMap<>()); - child = rootDir.resolve("test.zip"); + Path child = rootDir.resolve("test.zip"); assertTrue(Files.exists(child)); ProjectFolder dir2 = rootFolder.createFolder("dir2"); @@ -374,20 +427,22 @@ void archiveAndUnarchiveTestWithDirAndBlackList() throws IOException { Project project = afs.getRootFolder().createProject("test"); ProjectFolder rootFolder = project.getRootFolder(); ProjectFolder dir1 = rootFolder.createFolder("dir1"); - try (Writer writer = new OutputStreamWriter(storage.writeBinaryData(dir1.getId(), "data1")); - Writer writer2 = new OutputStreamWriter(storage.writeBinaryData(dir1.getId(), "data2"))) { + Path rootDir = fileSystem.getPath("/root"); + Files.createDirectory(rootDir); + + // Write two files associated with the same node + try (Writer ignored = new OutputStreamWriter(storage.writeBinaryData(dir1.getId(), "data1")); + Writer ignored1 = new OutputStreamWriter(storage.writeBinaryData(dir1.getId(), "data2"))) { + // Nothing to write inside, we just want to create the files } catch (IOException e) { throw new UncheckedIOException(e); } - Path child = null; - Path rootDir = fileSystem.getPath("/root"); - Files.createDirectory(rootDir); Map> blackList = new HashMap<>(); List deleteExtension = new ArrayList<>(); deleteExtension.add("data1"); blackList.put("projectFolder", deleteExtension); dir1.archive(rootDir, blackList); - child = rootDir.resolve(dir1.getId()); + Path child = rootDir.resolve(dir1.getId()); assertTrue(Files.exists(child)); ProjectFolder dir2 = rootFolder.createFolder("dir2"); From 324054af786df19393a6e965427abcf5282ae940 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 17 Feb 2025 13:13:07 +0100 Subject: [PATCH 19/36] clean LocalTaskMonitorTest Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/LocalTaskMonitorTest.java | 236 ++++++++++++------ 1 file changed, 163 insertions(+), 73 deletions(-) diff --git a/afs-core/src/test/java/com/powsybl/afs/LocalTaskMonitorTest.java b/afs-core/src/test/java/com/powsybl/afs/LocalTaskMonitorTest.java index b6e46267..14196aaf 100644 --- a/afs-core/src/test/java/com/powsybl/afs/LocalTaskMonitorTest.java +++ b/afs-core/src/test/java/com/powsybl/afs/LocalTaskMonitorTest.java @@ -13,24 +13,60 @@ import com.powsybl.afs.storage.InMemoryEventsBus; import com.powsybl.commons.json.JsonUtil; import com.powsybl.computation.CompletableFutureTask; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; -import java.util.*; +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.List; +import java.util.UUID; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * @author Geoffroy Jamgotchian {@literal } */ class LocalTaskMonitorTest extends AbstractProjectFileTest { + private Project test; + private FooFile foo; + private Deque events; + private TaskListener listener; + + @Override + @BeforeEach + public void setup() throws IOException { + super.setup(); + + test = afs.getRootFolder().createProject("test"); + foo = test.getRootFolder().fileBuilder(FooFileBuilder.class) + .withName("foo") + .build(); + events = new ArrayDeque<>(); + listener = new TaskListener() { + @Override + public String getProjectId() { + return test.getId(); + } + + @Override + public void onEvent(TaskEvent event) { + events.add(event); + } + }; + } + @Override protected List getProjectFileExtensions() { return Collections.singletonList(new FooFileExtension()); @@ -42,42 +78,48 @@ protected AppStorage createStorage() { } @Test - void test() throws IOException, TaskMonitor.NotACancellableTaskMonitor, InterruptedException { - Project test = afs.getRootFolder().createProject("test"); - FooFile foo = test.getRootFolder().fileBuilder(FooFileBuilder.class) - .withName("foo") - .build(); - + void legacyTaskTest() { TaskMonitor.Task legacyTask = new TaskMonitor.Task("test", "test", 1L, test.getId()); assertNull(legacyTask.getNodeId()); + } + @Test + void snapshotOnNullTest() { try (TaskMonitor monitor = new LocalTaskMonitor()) { - Deque events = new ArrayDeque<>(); - TaskListener listener = new TaskListener() { - @Override - public String getProjectId() { - return test.getId(); - } - - @Override - public void onEvent(TaskEvent event) { - events.add(event); - } - }; - monitor.addListener(listener); assertEquals(0L, monitor.takeSnapshot(null).getRevision()); assertTrue(monitor.takeSnapshot(null).getTasks().isEmpty()); + } + } + @Test + void startTaskTest() { + try (TaskMonitor monitor = new LocalTaskMonitor()) { + // Add a listener and start a task + monitor.addListener(listener); TaskMonitor.Task task = monitor.startTask(foo); + + // Checks on the task assertEquals("foo", task.getName()); - assertEquals(1, events.size()); assertEquals(foo.getId(), task.getNodeId()); + + // Checks on the listener + assertEquals(1, events.size()); assertEquals(new StartTaskEvent(task.getId(), 1L, "foo"), events.pop()); + // Checks on the TaskMonitor assertEquals(1L, monitor.takeSnapshot(null).getRevision()); assertEquals(1, monitor.takeSnapshot(null).getTasks().size()); assertEquals(task.getId(), monitor.takeSnapshot(null).getTasks().get(0).getId()); assertEquals(1L, monitor.takeSnapshot(null).getTasks().get(0).getRevision()); + } + } + + @Test + void serDeSnapshotTest() throws IOException { + try (TaskMonitor monitor = new LocalTaskMonitor()) { + // Add a listener and start a task + monitor.addListener(listener); + monitor.startTask(foo); // test Snapshot -> json -> Snapshot ObjectMapper objectMapper = JsonUtil.createObjectMapper(); @@ -85,26 +127,54 @@ public void onEvent(TaskEvent event) { String snJsonRef = objectMapper.writeValueAsString(snapshotRef); TaskMonitor.Snapshot snapshotConverted = objectMapper.readValue(snJsonRef, TaskMonitor.Snapshot.class); assertEquals(snapshotRef, snapshotConverted); + } + } + + @Test + void updateTaskTest() { + try (TaskMonitor monitor = new LocalTaskMonitor()) { + // Start a task and add a listener + TaskMonitor.Task task = monitor.startTask(foo); + monitor.addListener(listener); + // Update task monitor.updateTaskMessage(task.getId(), "hello"); + + // Check on the listener assertEquals(1, events.size()); assertEquals(new UpdateTaskMessageEvent(task.getId(), 2L, "hello"), events.pop()); + // Checks on the TaskMonitor assertEquals(2L, monitor.takeSnapshot(null).getRevision()); assertEquals(1, monitor.takeSnapshot(null).getTasks().size()); assertEquals(task.getId(), monitor.takeSnapshot(null).getTasks().get(0).getId()); assertEquals("hello", monitor.takeSnapshot(null).getTasks().get(0).getMessage()); assertEquals(2L, monitor.takeSnapshot(null).getTasks().get(0).getRevision()); + } + } - try { - monitor.updateTaskMessage(new UUID(0L, 0L), ""); - fail(); - } catch (IllegalArgumentException ignored) { - } + @Test + void updateTaskMessageExceptionTest() { + try (TaskMonitor monitor = new LocalTaskMonitor()) { + UUID uuid = new UUID(0L, 0L); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> monitor.updateTaskMessage(uuid, "")); + assertEquals("Task '00000000-0000-0000-0000-000000000000' not found", exception.getMessage()); + } + } + @Test + void taskInterruptionTest() throws TaskMonitor.NotACancellableTaskMonitor, InterruptedException { + try (TaskMonitor monitor = new LocalTaskMonitor()) { + // Start a task and add a listener + TaskMonitor.Task task = monitor.startTask(foo); + monitor.addListener(listener); + + // Update the task monitor.updateTaskFuture(task.getId(), null); + + // Check on the listener assertEquals(1, events.size()); - assertEquals(new TaskCancellableStatusChangeEvent(task.getId(), 3L, false), events.pop()); + assertEquals(new TaskCancellableStatusChangeEvent(task.getId(), 2L, false), events.pop()); CountDownLatch waitForStart = new CountDownLatch(1); CountDownLatch waitIndefinitely = new CountDownLatch(1); @@ -123,34 +193,54 @@ public void onEvent(TaskEvent event) { return null; }, Executors.newSingleThreadExecutor()); - //Cancel after task has actually started + // Start the task waitForStart.await(); monitor.updateTaskFuture(task.getId(), dummyTaskProcess); + + // Checks on the listener assertEquals(1, events.size()); - assertEquals(new TaskCancellableStatusChangeEvent(task.getId(), 4L, true), events.pop()); - boolean success = monitor.cancelTaskComputation(task.getId()); - assertThat(success).isTrue(); + assertEquals(new TaskCancellableStatusChangeEvent(task.getId(), 3L, true), events.pop()); + + // Cancel the task + assertThat(monitor.cancelTaskComputation(task.getId())).isTrue(); assertThat(dummyTaskProcess.isCancelled()).isTrue(); - assertThatCode(dummyTaskProcess::get).isInstanceOf(CancellationException.class); + + assertThrows(CancellationException.class, dummyTaskProcess::get); waitForInterruption.await(); + + // Check that the task has really been interrupted assertThat(waitForInterruption.getCount()).isZero(); assertThat(interrupted.get()).isTrue(); assertThat(waitIndefinitely.getCount()).isEqualTo(1); + } + } + @Test + void stopTaskTest() { + try (TaskMonitor monitor = new LocalTaskMonitor()) { + // Start a task and add a listener + TaskMonitor.Task task = monitor.startTask(foo); + monitor.updateTaskMessage(task.getId(), "hello"); + monitor.addListener(listener); + + // Stop the task monitor.stopTask(task.getId()); + + // Checks on the listener assertEquals(1, events.size()); - assertEquals(new StopTaskEvent(task.getId(), 5L), events.pop()); + assertEquals(new StopTaskEvent(task.getId(), 3L), events.pop()); - assertEquals(5L, monitor.takeSnapshot(null).getRevision()); + assertEquals(3L, monitor.takeSnapshot(null).getRevision()); assertTrue(monitor.takeSnapshot(null).getTasks().isEmpty()); + } + } - try { - monitor.stopTask(new UUID(0L, 0L)); - fail(); - } catch (IllegalArgumentException ignored) { - } - - monitor.removeListener(listener); + @Test + void stopTaskExceptionTest() { + try (TaskMonitor monitor = new LocalTaskMonitor()) { + UUID uuid = new UUID(0L, 0L); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> monitor.stopTask(uuid)); + assertEquals("Task '00000000-0000-0000-0000-000000000000' not found", exception.getMessage()); } } @@ -160,23 +250,23 @@ void startTaskEventTest() throws IOException { assertEquals("StartTaskEvent(taskId=00000000-0000-0000-0000-000000000000, revision=0, nodeId=null, name=e1)", event.toString()); ObjectMapper objectMapper = JsonUtil.createObjectMapper(); String json = objectMapper.writerWithDefaultPrettyPrinter() - .writeValueAsString(event); + .writeValueAsString(event); String jsonRef = String.join(System.lineSeparator(), - "{", - " \"@c\" : \".StartTaskEvent\",", - " \"taskId\" : \"00000000-0000-0000-0000-000000000000\",", - " \"revision\" : 0,", - " \"name\" : \"e1\",", - " \"nodeId\" : null", - "}"); + "{", + " \"@c\" : \".StartTaskEvent\",", + " \"taskId\" : \"00000000-0000-0000-0000-000000000000\",", + " \"revision\" : 0,", + " \"name\" : \"e1\",", + " \"nodeId\" : null", + "}"); assertEquals(jsonRef, json); TaskEvent event2 = objectMapper.readValue(json, TaskEvent.class); assertEquals(event, event2); new EqualsTester() - .addEqualityGroup(new StartTaskEvent(new UUID(0L, 0L), 0L, "e1"), new StartTaskEvent(new UUID(0L, 0L), 0L, "e1")) - .addEqualityGroup(new StartTaskEvent(new UUID(0L, 1L), 1L, "e2"), new StartTaskEvent(new UUID(0L, 1L), 1L, "e2")) - .testEquals(); + .addEqualityGroup(new StartTaskEvent(new UUID(0L, 0L), 0L, "e1"), new StartTaskEvent(new UUID(0L, 0L), 0L, "e1")) + .addEqualityGroup(new StartTaskEvent(new UUID(0L, 1L), 1L, "e2"), new StartTaskEvent(new UUID(0L, 1L), 1L, "e2")) + .testEquals(); } @Test @@ -185,21 +275,21 @@ void stopTaskEventTest() throws IOException { assertEquals("StopTaskEvent(taskId=00000000-0000-0000-0000-000000000001, revision=1)", event.toString()); ObjectMapper objectMapper = JsonUtil.createObjectMapper(); String json = objectMapper.writerWithDefaultPrettyPrinter() - .writeValueAsString(event); + .writeValueAsString(event); String jsonRef = String.join(System.lineSeparator(), - "{", - " \"@c\" : \".StopTaskEvent\",", - " \"taskId\" : \"00000000-0000-0000-0000-000000000001\",", - " \"revision\" : 1", - "}"); + "{", + " \"@c\" : \".StopTaskEvent\",", + " \"taskId\" : \"00000000-0000-0000-0000-000000000001\",", + " \"revision\" : 1", + "}"); assertEquals(jsonRef, json); TaskEvent event2 = objectMapper.readValue(json, TaskEvent.class); assertEquals(event, event2); new EqualsTester() - .addEqualityGroup(new StopTaskEvent(new UUID(0L, 0L), 0L), new StopTaskEvent(new UUID(0L, 0L), 0L)) - .addEqualityGroup(new StopTaskEvent(new UUID(0L, 1L), 1L), new StopTaskEvent(new UUID(0L, 1L), 1L)) - .testEquals(); + .addEqualityGroup(new StopTaskEvent(new UUID(0L, 0L), 0L), new StopTaskEvent(new UUID(0L, 0L), 0L)) + .addEqualityGroup(new StopTaskEvent(new UUID(0L, 1L), 1L), new StopTaskEvent(new UUID(0L, 1L), 1L)) + .testEquals(); } @Test @@ -208,21 +298,21 @@ void updateTaskMessageEventTest() throws IOException { assertEquals("UpdateTaskMessageEvent(taskId=00000000-0000-0000-0000-000000000002, revision=2, message=hello)", event.toString()); ObjectMapper objectMapper = JsonUtil.createObjectMapper(); String json = objectMapper.writerWithDefaultPrettyPrinter() - .writeValueAsString(event); + .writeValueAsString(event); String jsonRef = String.join(System.lineSeparator(), - "{", - " \"@c\" : \".UpdateTaskMessageEvent\",", - " \"taskId\" : \"00000000-0000-0000-0000-000000000002\",", - " \"revision\" : 2,", - " \"message\" : \"hello\"", - "}"); + "{", + " \"@c\" : \".UpdateTaskMessageEvent\",", + " \"taskId\" : \"00000000-0000-0000-0000-000000000002\",", + " \"revision\" : 2,", + " \"message\" : \"hello\"", + "}"); assertEquals(jsonRef, json); TaskEvent event2 = objectMapper.readValue(json, TaskEvent.class); assertEquals(event, event2); new EqualsTester() - .addEqualityGroup(new UpdateTaskMessageEvent(new UUID(0L, 0L), 0L, "hello"), new UpdateTaskMessageEvent(new UUID(0L, 0L), 0L, "hello")) - .addEqualityGroup(new UpdateTaskMessageEvent(new UUID(0L, 1L), 1L, "bye"), new UpdateTaskMessageEvent(new UUID(0L, 1L), 1L, "bye")) - .testEquals(); + .addEqualityGroup(new UpdateTaskMessageEvent(new UUID(0L, 0L), 0L, "hello"), new UpdateTaskMessageEvent(new UUID(0L, 0L), 0L, "hello")) + .addEqualityGroup(new UpdateTaskMessageEvent(new UUID(0L, 1L), 1L, "bye"), new UpdateTaskMessageEvent(new UUID(0L, 1L), 1L, "bye")) + .testEquals(); } } From d6a4528e99373adee2da507d2149bb1b7e1e8409 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 17 Feb 2025 13:15:35 +0100 Subject: [PATCH 20/36] add deprecation date on AbstractModificationScript Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/ext/base/AbstractModificationScript.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/AbstractModificationScript.java b/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/AbstractModificationScript.java index 30fc095d..99b71251 100644 --- a/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/AbstractModificationScript.java +++ b/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/AbstractModificationScript.java @@ -11,9 +11,10 @@ import com.powsybl.afs.ProjectFileCreationContext; /** + * @deprecated since a long time ago * @author Paul Bui-Quang {@literal } */ -@Deprecated +@Deprecated(since = "a long time ago") public abstract class AbstractModificationScript extends AbstractScript { public AbstractModificationScript(ProjectFileCreationContext context, int codeVersion, String scriptContentName) { super(context, codeVersion, scriptContentName); From 83a575c652f6213654d8512b0fda340d1034aa8b Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 17 Feb 2025 13:18:03 +0100 Subject: [PATCH 21/36] clean AbstractScript Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/ext/base/AbstractScript.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/AbstractScript.java b/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/AbstractScript.java index 963ca868..085c8d33 100644 --- a/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/AbstractScript.java +++ b/afs-ext-base/src/main/java/com/powsybl/afs/ext/base/AbstractScript.java @@ -28,10 +28,10 @@ public abstract class AbstractScript extends ProjectFi private static final String INCLUDED_SCRIPTS_DEPENDENCY_NAME = "scriptIncludes"; private static final String DEFAULT_SCRIPTS_DELIMITER = "\n\n"; + protected final OrderedDependencyManager orderedDependencyManager = new OrderedDependencyManager(this); private final String scriptContentName; private final List listeners = new ArrayList<>(); private final AppStorageListener l = eventList -> processEvents(eventList.getEvents(), info.getId(), listeners); - protected final OrderedDependencyManager orderedDependencyManager = new OrderedDependencyManager(this); public AbstractScript(ProjectFileCreationContext context, int codeVersion, String scriptContentName) { super(context, codeVersion); @@ -93,10 +93,10 @@ public String readScript(boolean withIncludes) { String ownContent = readScript(); if (withIncludes) { String includesScript = orderedDependencyManager - .getDependencies(INCLUDED_SCRIPTS_DEPENDENCY_NAME, AbstractScript.class) - .stream() - .map(script -> script.readScript(true)) - .collect(Collectors.joining(DEFAULT_SCRIPTS_DELIMITER)); + .getDependencies(INCLUDED_SCRIPTS_DEPENDENCY_NAME, AbstractScript.class) + .stream() + .map(script -> script.readScript(true)) + .collect(Collectors.joining(DEFAULT_SCRIPTS_DELIMITER)); if (StringUtils.isNotBlank(includesScript)) { includesScript += DEFAULT_SCRIPTS_DELIMITER; } @@ -117,7 +117,7 @@ public String readScript() { @Override public void writeScript(String content) { try (Reader reader = new StringReader(content); - Writer writer = new OutputStreamWriter(storage.writeBinaryData(info.getId(), scriptContentName), StandardCharsets.UTF_8)) { + Writer writer = new OutputStreamWriter(storage.writeBinaryData(info.getId(), scriptContentName), StandardCharsets.UTF_8)) { CharStreams.copy(reader, writer); } catch (IOException e) { throw new UncheckedIOException(e); From 0c8440a796c3b04af9941cecd32719562e4c1dbd Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 17 Feb 2025 13:47:24 +0100 Subject: [PATCH 22/36] clean ImportedCaseTest Signed-off-by: Nicolas Rol --- .../afs/ext/base/ImportedCaseTest.java | 126 ++++++++++++++---- 1 file changed, 103 insertions(+), 23 deletions(-) diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java index 404aad0b..9ddec4d8 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ImportedCaseTest.java @@ -19,6 +19,7 @@ import com.powsybl.afs.ProjectNode; import com.powsybl.afs.ServiceExtension; import com.powsybl.afs.mapdb.storage.MapDbAppStorage; +import com.powsybl.afs.storage.AfsStorageException; import com.powsybl.afs.storage.AppStorage; import com.powsybl.afs.storage.InMemoryEventsBus; import com.powsybl.afs.storage.NodeGenericMetadata; @@ -43,13 +44,14 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.regex.Pattern; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -59,6 +61,8 @@ */ class ImportedCaseTest extends AbstractProjectFileTest { + private static final String NODE_NOT_FOUND_REGEX = "Node [0-9a-fA-F-]{36} not found"; + private static final Pattern NODE_NOT_FOUND_PATTERN = Pattern.compile(NODE_NOT_FOUND_REGEX); private FileSystem fileSystem; @Override @@ -112,7 +116,7 @@ public void tearDown() throws IOException { } @Test - void test() { + void caseExistsTest() { Folder root = afs.getRootFolder(); // check case exist @@ -122,61 +126,137 @@ void test() { assertEquals("network", aCase.getName()); assertEquals("Test format", aCase.getDescription()); assertFalse(aCase.isFolder()); + } - // create project - Project project = root.createProject("project"); - assertNotNull(project); + @Test + void importCaseInProject() { + Folder root = afs.getRootFolder(); + Case aCase = (Case) root.getChildren().get(0); - // create project folder + // create project end project folder + Project project = root.createProject("project"); ProjectFolder folder = project.getRootFolder().createFolder("folder"); - assertTrue(folder.getChildren().isEmpty()); - // import case into project - try { - folder.fileBuilder(ImportedCaseBuilder.class) - .build(); - fail(); - } catch (AfsException ignored) { - } - ImportedCase importedCase = folder.fileBuilder(ImportedCaseBuilder.class) + // Create a builder + ImportedCaseBuilder builder = folder.fileBuilder(ImportedCaseBuilder.class); + + // Building the case does not wirk when parameters are missing + AfsException exception = assertThrows(AfsException.class, builder::build); + assertEquals("Case or data source is not set", exception.getMessage()); + + // Build the ImportedCase + ImportedCase importedCase = builder .withCase(aCase) .withParameter("param1", "true") .withParameters(ImmutableMap.of("param2", "1")) .build(); + + // Check the ImportedCase assertNotNull(importedCase); assertFalse(importedCase.isFolder()); assertNotNull(importedCase.getNetwork()); assertTrue(importedCase.getDependencies().isEmpty()); + } - // test network listener + @Test + void listenerTest() { + Folder root = afs.getRootFolder(); + Case aCase = (Case) root.getChildren().get(0); + Project project = root.createProject("project"); + ProjectFolder folder = project.getRootFolder().createFolder("folder"); + ImportedCase importedCase = folder.fileBuilder(ImportedCaseBuilder.class) + .withCase(aCase) + .withParameter("param1", "true") + .withParameters(ImmutableMap.of("param2", "1")) + .build(); + + // Mock a listener NetworkListener mockedListener = mock(DefaultNetworkListener.class); + + // Get the network and add the listener to it assertNotNull(importedCase.getNetwork(Collections.singletonList(mockedListener))); + + // Update something in the network network.getSubstation("s1").setTso("tso_new"); + + // Check that the listener saw it verify(mockedListener, times(1)) .onUpdate(network.getSubstation("s1"), "tso", null, "TSO", "tso_new"); + } + + @Test + void queryNetworkTest() { + Folder root = afs.getRootFolder(); + Case aCase = (Case) root.getChildren().get(0); + Project project = root.createProject("project"); + ProjectFolder folder = project.getRootFolder().createFolder("folder"); + ImportedCase importedCase = folder.fileBuilder(ImportedCaseBuilder.class) + .withCase(aCase) + .withParameter("param1", "true") + .withParameters(ImmutableMap.of("param2", "1")) + .build(); // test network query assertEquals("[\"s1\"]", importedCase.queryNetwork(ScriptType.GROOVY, "network.substations.collect { it.id }")); + } - // try to reload the imported case + @Test + void reloadImportedCaseTest() { + Folder root = afs.getRootFolder(); + Case aCase = (Case) root.getChildren().get(0); + Project project = root.createProject("project"); + ProjectFolder folder = project.getRootFolder().createFolder("folder"); + folder.fileBuilder(ImportedCaseBuilder.class) + .withCase(aCase) + .withParameter("param1", "true") + .withParameters(ImmutableMap.of("param2", "1")) + .build(); assertEquals(1, folder.getChildren().size()); + + // try to reload the imported case ProjectNode projectNode = folder.getChildren().get(0); assertNotNull(projectNode); - assertTrue(projectNode instanceof ImportedCase); + assertInstanceOf(ImportedCase.class, projectNode); ImportedCase importedCase2 = (ImportedCase) projectNode; assertEquals(TestImporter.FORMAT, importedCase2.getImporter().getFormat()); assertEquals(2, importedCase2.getParameters().size()); assertEquals("true", importedCase2.getParameters().getProperty("param1")); + } + + @Test + void checkChildByNameTest() { + Folder root = afs.getRootFolder(); + Case aCase = (Case) root.getChildren().get(0); + Project project = root.createProject("project"); + ProjectFolder folder = project.getRootFolder().createFolder("folder"); + folder.fileBuilder(ImportedCaseBuilder.class) + .withCase(aCase) + .withParameter("param1", "true") + .withParameters(ImmutableMap.of("param2", "1")) + .build(); assertTrue(folder.getChild(ImportedCase.class, "network").isPresent()); + } + + @Test + void deletedImportedCaseTest() { + Folder root = afs.getRootFolder(); + Case aCase = (Case) root.getChildren().get(0); + Project project = root.createProject("project"); + ProjectFolder folder = project.getRootFolder().createFolder("folder"); + folder.fileBuilder(ImportedCaseBuilder.class) + .withCase(aCase) + .withParameter("param1", "true") + .withParameters(ImmutableMap.of("param2", "1")) + .build(); + ProjectNode projectNode = folder.getChildren().get(0); - // delete imported case + // Delete the imported case projectNode.delete(); assertTrue(folder.getChildren().isEmpty()); - try { - projectNode.getName(); - } catch (Exception ignored) { - } + String deletedNodeId = projectNode.getId(); + AfsStorageException deletedNodeException = assertThrows(AfsStorageException.class, () -> storage.getNodeInfo(deletedNodeId)); + assertTrue(NODE_NOT_FOUND_PATTERN.matcher(deletedNodeException.getMessage()).matches()); } @Test From ddc7f6c7d13bc390430c2bf7d282cfa181b49d71 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 17 Feb 2025 15:15:16 +0100 Subject: [PATCH 23/36] clean ModificationScriptTest + create GenericScriptTest Signed-off-by: Nicolas Rol --- .../afs/ext/base/GenericScriptTest.java | 85 +++++ .../afs/ext/base/ModificationScriptTest.java | 329 ++++++++++++++---- 2 files changed, 341 insertions(+), 73 deletions(-) create mode 100644 afs-ext-base/src/test/java/com/powsybl/afs/ext/base/GenericScriptTest.java diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/GenericScriptTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/GenericScriptTest.java new file mode 100644 index 00000000..770f012f --- /dev/null +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/GenericScriptTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025, RTE (https://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.afs.ext.base; + +import com.powsybl.afs.AbstractProjectFileTest; +import com.powsybl.afs.AfsException; +import com.powsybl.afs.FileExtension; +import com.powsybl.afs.Project; +import com.powsybl.afs.ProjectFileExtension; +import com.powsybl.afs.ProjectFolder; +import com.powsybl.afs.mapdb.storage.MapDbAppStorage; +import com.powsybl.afs.storage.AppStorage; +import com.powsybl.afs.storage.InMemoryEventsBus; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author Nicolas Rol {@literal } + */ +public class GenericScriptTest extends AbstractProjectFileTest { + + private Project project; + private ProjectFolder rootFolder; + + @Override + protected AppStorage createStorage() { + return MapDbAppStorage.createMem("mem", new InMemoryEventsBus()); + } + + @Override + protected List getFileExtensions() { + return List.of(new CaseExtension()); + } + + @Override + protected List getProjectFileExtensions() { + return List.of(new ModificationScriptExtension(), new GenericScriptExtension()); + } + + @Override + @BeforeEach + public void setup() throws IOException { + super.setup(); + project = afs.getRootFolder().createProject("project"); + rootFolder = project.getRootFolder(); + } + + @Test + void buildingScriptExceptionsTest() { + GenericScriptBuilder builder; + AfsException exception; + + // Missing name + builder = rootFolder.fileBuilder(GenericScriptBuilder.class) + .withType(ScriptType.GROOVY) + .withContent("println 'hello'"); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Name is not set", exception.getMessage()); + + // Missing Type + builder = rootFolder.fileBuilder(GenericScriptBuilder.class) + .withName("script") + .withContent("println 'hello'"); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Script type is not set", exception.getMessage()); + + // Missing Content + builder = rootFolder.fileBuilder(GenericScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Content is not set", exception.getMessage()); + } +} diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java index 858bade2..158099f2 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/ModificationScriptTest.java @@ -18,25 +18,29 @@ import com.powsybl.afs.storage.AppStorage; import com.powsybl.afs.storage.InMemoryEventsBus; import com.powsybl.afs.storage.NodeInfo; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.io.IOException; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -import static org.assertj.core.api.Assertions.assertThatCode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; /** * @author Geoffroy Jamgotchian {@literal } */ class ModificationScriptTest extends AbstractProjectFileTest { + private Project project; + private ProjectFolder rootFolder; + @Override protected AppStorage createStorage() { return MapDbAppStorage.createMem("mem", new InMemoryEventsBus()); @@ -52,144 +56,329 @@ protected List getProjectFileExtensions() { return List.of(new ModificationScriptExtension(), new GenericScriptExtension()); } + @Override + @BeforeEach + public void setup() throws IOException { + super.setup(); + project = afs.getRootFolder().createProject("project"); + rootFolder = project.getRootFolder(); + } + @Test - void test() { - Project project = afs.getRootFolder().createProject("project"); - ProjectFolder rootFolder = project.getRootFolder(); - - // create groovy script - try { - rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withType(ScriptType.GROOVY) - .withContent("println 'hello'") - .build(); - fail(); - } catch (AfsException ignored) { - } - try { - rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("script") - .withContent("println 'hello'") - .build(); - fail(); - } catch (AfsException ignored) { - } - try { - rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("script") - .withType(ScriptType.GROOVY) - .build(); - fail(); - } catch (AfsException ignored) { - } + void buildingScriptExceptionsTest() { + ModificationScriptBuilder builder; + AfsException exception; + + // Missing name + builder = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withType(ScriptType.GROOVY) + .withContent("println 'hello'"); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Name is not set", exception.getMessage()); + + // Missing Type + builder = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withContent("println 'hello'"); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Script type is not set", exception.getMessage()); + + // Missing Content + builder = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Content is not set", exception.getMessage()); + } + + @Test + void createScriptTest() { + // Create script ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) .withName("script") .withType(ScriptType.GROOVY) .withContent("println 'hello'") .build(); + + // Check creation assertNotNull(script); assertEquals("script", script.getName()); assertFalse(script.isFolder()); assertTrue(script.getDependencies().isEmpty()); assertEquals("println 'hello'", script.readScript()); + } + + @Test + void listenerTest() { + ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'hello'") + .build(); + + // Add listener AtomicBoolean scriptUpdated = new AtomicBoolean(false); ScriptListener listener = () -> scriptUpdated.set(true); script.addListener(listener); + + // Update the script script.writeScript("println 'bye'"); + + // Check the update assertEquals("println 'bye'", script.readScript()); assertTrue(scriptUpdated.get()); - script.removeListener(listener); + } + + @Test + void scriptDetectedInFolder() { + rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'hello'") + .build(); - // check script file is correctly scanned + // Check in root folder assertEquals(1, rootFolder.getChildren().size()); ProjectNode firstNode = rootFolder.getChildren().get(0); assertInstanceOf(ModificationScript.class, firstNode); assertEquals("script", firstNode.getName()); + } + @Test + void includesTest() { + ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'bye'") + .build(); + + // Create some scripts to include ModificationScript include1 = rootFolder.fileBuilder(ModificationScriptBuilder.class) .withName("include_script1") .withType(ScriptType.GROOVY) .withContent("var foo=\"bar\"") .build(); - assertNotNull(include1); + ModificationScript include2 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script2") + .withType(ScriptType.GROOVY) + .withContent("var p0=1") + .build(); + ModificationScript include3 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script3") + .withType(ScriptType.GROOVY) + .withContent("var pmax=2") + .build(); + + // Add the first one script.addScript(include1); String contentWithInclude = script.readScript(true); - assertEquals(contentWithInclude, "var foo=\"bar\"\n\nprintln 'bye'"); + assertEquals("var foo=\"bar\"\n\nprintln 'bye'", contentWithInclude); + // Include it a second time script.addScript(include1); contentWithInclude = script.readScript(true); - assertEquals(contentWithInclude, "var foo=\"bar\"\n\nvar foo=\"bar\"\n\nprintln 'bye'"); + assertEquals("var foo=\"bar\"\n\nvar foo=\"bar\"\n\nprintln 'bye'", contentWithInclude); - ModificationScript include2 = rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("include_script2") - .withType(ScriptType.GROOVY) - .withContent("var p0=1") - .build(); + // Remove the first and add it one time and then the second one script.removeScript(include1.getId()); script.addScript(include1); script.addScript(include2); contentWithInclude = script.readScript(true); - assertEquals(contentWithInclude, "var foo=\"bar\"\n\nvar p0=1\n\nprintln 'bye'"); + assertEquals("var foo=\"bar\"\n\nvar p0=1\n\nprintln 'bye'", contentWithInclude); - ModificationScript include3 = rootFolder.fileBuilder(ModificationScriptBuilder.class) - .withName("include_script3") - .withType(ScriptType.GROOVY) - .withContent("var pmax=2") - .build(); + // Add the third and remove the second script.addScript(include3); script.removeScript(include2.getId()); contentWithInclude = script.readScript(true); - assertEquals(contentWithInclude, "var foo=\"bar\"\n\nvar pmax=2\n\nprintln 'bye'"); + assertEquals("var foo=\"bar\"\n\nvar pmax=2\n\nprintln 'bye'", contentWithInclude); + // Add the second again but in the third one include3.addScript(include2); contentWithInclude = script.readScript(true); - assertEquals(contentWithInclude, "var foo=\"bar\"\n\nvar p0=1\n\nvar pmax=2\n\nprintln 'bye'"); + assertEquals("var foo=\"bar\"\n\nvar p0=1\n\nvar pmax=2\n\nprintln 'bye'", contentWithInclude); + // List of included scripts List includes = script.getIncludedScripts(); assertEquals(2, includes.size()); - assertEquals(includes.get(0).getId(), include1.getId()); - assertEquals(includes.get(1).getId(), include3.getId()); + assertEquals(include1.getId(), includes.get(0).getId()); + assertEquals(include3.getId(), includes.get(1).getId()); + } - assertThatCode(() -> script.addScript(script)).isInstanceOf(AfsCircularDependencyException.class); + @Test + void circularInclusionTest() { + ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'hello'") + .build(); + + // Include the script in itself + AfsCircularDependencyException exception = assertThrows(AfsCircularDependencyException.class, () -> script.addScript(script)); + assertEquals("Circular dependency detected", exception.getMessage()); + } + + @Test + void includeGenericScriptTest() { + ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'bye'") + .build(); + ModificationScript include1 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script1") + .withType(ScriptType.GROOVY) + .withContent("var foo=\"bar\"") + .build(); + ModificationScript include2 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script2") + .withType(ScriptType.GROOVY) + .withContent("var p0=1") + .build(); + ModificationScript include3 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script3") + .withType(ScriptType.GROOVY) + .withContent("var pmax=2") + .build(); + script.addScript(include1); + script.addScript(include3); + include3.addScript(include2); + // Create a generic script GenericScript genericScript = rootFolder.fileBuilder(GenericScriptBuilder.class) .withContent("some list") .withType(ScriptType.GROOVY) .withName("genericScript") .build(); - assertEquals("some list", genericScript.readScript()); + + // Include the generic script to the script script.addGenericScript(genericScript); assertEquals("var foo=\"bar\"\n\nvar p0=1\n\nvar pmax=2\n\nsome list\n\nprintln 'bye'", script.readScript(true)); - assertThatCode(() -> genericScript.addGenericScript(genericScript)).isInstanceOf(AfsCircularDependencyException.class); - script.removeScript(genericScript.getId()); + } + + @Test + void genericScriptCircularDependencyTest() { + GenericScript genericScript = rootFolder.fileBuilder(GenericScriptBuilder.class) + .withContent("some list") + .withType(ScriptType.GROOVY) + .withName("genericScript") + .build(); + + // Include the script in itself + AfsCircularDependencyException exception = assertThrows(AfsCircularDependencyException.class, () -> genericScript.addGenericScript(genericScript)); + assertEquals("Circular dependency detected", exception.getMessage()); + } + + @Test + void switchDependencyTest() { + ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'bye'") + .build(); + ModificationScript include1 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script1") + .withType(ScriptType.GROOVY) + .withContent("var foo=\"bar\"") + .build(); + ModificationScript include2 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script2") + .withType(ScriptType.GROOVY) + .withContent("var p0=1") + .build(); + ModificationScript include3 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script3") + .withType(ScriptType.GROOVY) + .withContent("var pmax=2") + .build(); + script.addScript(include1); + script.addScript(include3); + include3.addScript(include2); + // Switch the two included scripts script.switchIncludedDependencies(0, 1); + String contentWithInclude = script.readScript(true); + assertEquals("var p0=1\n\nvar pmax=2\n\nvar foo=\"bar\"\n\nprintln 'bye'", contentWithInclude); - List includedScripts = script.getIncludedScripts(); + // List of included scripts + List includes = script.getIncludedScripts(); assertEquals(2, includes.size()); - assertEquals(includedScripts.get(0).getId(), include3.getId()); - assertEquals(includedScripts.get(1).getId(), include1.getId()); + assertEquals(include3.getId(), includes.get(0).getId()); + assertEquals(include1.getId(), includes.get(1).getId()); + } - assertThatCode(() -> script.switchIncludedDependencies(0, -1)).isInstanceOf(AfsException.class); - assertThatCode(() -> script.switchIncludedDependencies(1, 2)).isInstanceOf(AfsException.class); + @Test + void switchDependencyExceptionsTest() { + ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'bye'") + .build(); + ModificationScript include1 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script1") + .withType(ScriptType.GROOVY) + .withContent("var foo=\"bar\"") + .build(); + ModificationScript include2 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script2") + .withType(ScriptType.GROOVY) + .withContent("var p0=1") + .build(); + ModificationScript include3 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script3") + .withType(ScriptType.GROOVY) + .withContent("var pmax=2") + .build(); + script.addScript(include1); + script.addScript(include3); + include3.addScript(include2); - assertThatCode(() -> rootFolder.fileBuilder(GenericScriptBuilder.class).build()).isInstanceOf(AfsException.class).hasMessage("Name is not set"); - assertThatCode(() -> rootFolder.fileBuilder(GenericScriptBuilder.class).withName("foo").build()).isInstanceOf(AfsException.class).hasMessage("Script type is not set"); - assertThatCode(() -> rootFolder.fileBuilder(GenericScriptBuilder.class).withName("foo").withType(ScriptType.GROOVY).build()).isInstanceOf(AfsException.class).hasMessage("Content is not set"); - assertThatCode(() -> rootFolder.fileBuilder(GenericScriptBuilder.class).withName("include_script2").withType(ScriptType.GROOVY).withContent("hello").build()).isInstanceOf(AfsException.class).hasMessage("Parent folder already contains a 'include_script2' node"); + // Switch non-existing dependencies + AfsException exception = assertThrows(AfsException.class, () -> script.switchIncludedDependencies(0, -1)); + assertEquals("One or both indexes values are out of bounds", exception.getMessage()); + exception = assertThrows(AfsException.class, () -> script.switchIncludedDependencies(1, 2)); + assertEquals("One or both indexes values are out of bounds", exception.getMessage()); + } - //assert that the cache is correctly cleared + @Test + void renameAndCacheTest() { + ModificationScript script = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("println 'bye'") + .build(); + ModificationScript include1 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script1") + .withType(ScriptType.GROOVY) + .withContent("var foo=\"bar\"") + .build(); + ModificationScript include2 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script2") + .withType(ScriptType.GROOVY) + .withContent("var p0=1") + .build(); + ModificationScript include3 = rootFolder.fileBuilder(ModificationScriptBuilder.class) + .withName("include_script3") + .withType(ScriptType.GROOVY) + .withContent("var pmax=2") + .build(); + script.addScript(include3); + script.addScript(include1); + include3.addScript(include2); + + // Original names assertEquals("include_script1", include1.getName()); assertEquals("include_script3", include3.getName()); assertEquals("include_script1", script.getIncludedScripts().get(1).getName()); assertEquals("include_script3", script.getIncludedScripts().get(0).getName()); + // Rename a script without clearing the cache - the name change is not taken into account include1.rename("include_script11"); assertEquals("include_script11", include1.getName()); assertNotEquals("include_script11", script.getIncludedScripts().get(1).getName()); assertEquals("include_script1", script.getIncludedScripts().get(1).getName()); + // Clear the cache - the name change is taken into account script.clearDependenciesCache(); assertEquals("include_script11", include1.getName()); assertEquals("include_script11", script.getIncludedScripts().get(1).getName()); @@ -197,14 +386,11 @@ void test() { @Test void testModificationScriptCreationWithCustomPseudoClass() { - // Create a project in the root folder - Project project = afs.getRootFolder().createProject("project"); - // Define a custom pseudo-class value String customPseudoClass = "customPseudo"; // Build a ModificationScript using the custom pseudo-class - ModificationScript modificationScript = project.getRootFolder().fileBuilder(ModificationScriptBuilder.class) + project.getRootFolder().fileBuilder(ModificationScriptBuilder.class) .withName("customScript") .withType(ScriptType.GROOVY) .withContent("script content") @@ -221,11 +407,8 @@ void testModificationScriptCreationWithCustomPseudoClass() { @Test void testModificationScriptCreationWithDefaultPseudoClass() { - // Create a project in the root folder - Project project = afs.getRootFolder().createProject("project"); - // Build a ModificationScript without specifying a pseudo-class, so the default should be used - ModificationScript modificationScript = project.getRootFolder().fileBuilder(ModificationScriptBuilder.class) + project.getRootFolder().fileBuilder(ModificationScriptBuilder.class) .withName("defaultScript") .withType(ScriptType.GROOVY) .withContent("script content") From 5dce23d0b4011320839da59ce4a123832ea36e5b Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 17 Feb 2025 15:15:41 +0100 Subject: [PATCH 24/36] clean GenericScriptTest Signed-off-by: Nicolas Rol --- .../test/java/com/powsybl/afs/ext/base/GenericScriptTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/GenericScriptTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/GenericScriptTest.java index 770f012f..2fd8e7d5 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/GenericScriptTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/GenericScriptTest.java @@ -30,7 +30,6 @@ */ public class GenericScriptTest extends AbstractProjectFileTest { - private Project project; private ProjectFolder rootFolder; @Override @@ -52,7 +51,7 @@ protected List getProjectFileExtensions() { @BeforeEach public void setup() throws IOException { super.setup(); - project = afs.getRootFolder().createProject("project"); + Project project = afs.getRootFolder().createProject("project"); rootFolder = project.getRootFolder(); } From 833357aa7878925cadd8fa0bf77dc3440712325c Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Mon, 17 Feb 2025 15:16:27 +0100 Subject: [PATCH 25/36] clean TestImporter Signed-off-by: Nicolas Rol --- .../src/test/java/com/powsybl/afs/ext/base/TestImporter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java index 97432184..bf6aa77d 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/TestImporter.java @@ -66,5 +66,6 @@ public Network importData(ReadOnlyDataSource dataSource, NetworkFactory networkF @Override public void copy(ReadOnlyDataSource fromDataSource, DataSource toDataSource) { + // Nothing to do here } } From f32459f6e851dc1ae28c105c831f33c9d383e33f Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Tue, 18 Feb 2025 12:35:58 +0100 Subject: [PATCH 26/36] clean VirtualCaseTest Signed-off-by: Nicolas Rol --- .../powsybl/afs/ext/base/VirtualCaseTest.java | 216 ++++++++++++------ 1 file changed, 144 insertions(+), 72 deletions(-) diff --git a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java index f44516f2..45bf10c5 100644 --- a/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java +++ b/afs-ext-base/src/test/java/com/powsybl/afs/ext/base/VirtualCaseTest.java @@ -33,13 +33,12 @@ import java.util.Collections; import java.util.List; -import static org.assertj.core.api.Assertions.assertThatCode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -49,6 +48,10 @@ */ class VirtualCaseTest extends AbstractProjectFileTest { + private Case aCase; + private ProjectFolder folder; + private ImportedCase importedCase; + private ImportersLoader createImportersLoader() { return new ImportersLoaderList(new TestImporter(network)); } @@ -82,65 +85,73 @@ public void setup() throws IOException { NodeInfo nodeInfo = storage.createNode(rootFolderInfo.getId(), "network", Case.PSEUDO_CLASS, "", Case.VERSION, new NodeGenericMetadata().setString(Case.FORMAT, TestImporter.FORMAT)); storage.setConsistent(nodeInfo.getId()); - } - @Test - void test() { // get case - Case aCase = (Case) afs.getRootFolder().getChildren().get(0); + aCase = (Case) afs.getRootFolder().getChildren().get(0); // create project Project project = afs.getRootFolder().createProject("project"); // create project folder - ProjectFolder folder = project.getRootFolder().createFolder("folder"); + folder = project.getRootFolder().createFolder("folder"); // import case into project - ImportedCase importedCase = folder.fileBuilder(ImportedCaseBuilder.class) + importedCase = folder.fileBuilder(ImportedCaseBuilder.class) .withCase(aCase) .build(); + } - // create groovy script + @Test + void buildingVirtualCaseExceptionsTest() { + VirtualCaseBuilder builder; + AfsException exception; + + // Create groovy script ModificationScript script = folder.fileBuilder(ModificationScriptBuilder.class) .withName("script") .withType(ScriptType.GROOVY) .withContent("print 'hello'") .build(); - // create virtual by applying groovy script on imported case - try { - VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) - .withCase(importedCase) - .withScript(script) - .build(); - fail(); - } catch (AfsException ignored) { - } - - try { - VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) - .withName("network2") - .withScript(script) - .build(); - fail(); - } catch (AfsException ignored) { - } - - try { - VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) - .withName("network2") - .withCase(importedCase) - .build(); - fail(); - } catch (AfsException ignored) { - } + // Missing name + builder = folder.fileBuilder(VirtualCaseBuilder.class) + .withCase(importedCase) + .withScript(script); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Name is not set", exception.getMessage()); + + // Missing Type + builder = folder.fileBuilder(VirtualCaseBuilder.class) + .withName("network2") + .withScript(script); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Case is not set", exception.getMessage()); + + // Missing Content + builder = folder.fileBuilder(VirtualCaseBuilder.class) + .withName("network2") + .withCase(importedCase); + exception = assertThrows(AfsException.class, builder::build); + assertEquals("Script is not set", exception.getMessage()); + } + + @Test + void buildingVirtualCaseTest() { + // create groovy script + ModificationScript script = folder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("print 'hello'") + .build(); + // Build the virtual case VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) .withName("network2") .withCase(importedCase) .withScript(script) .build(); + // Checks on the virtual case assertEquals("network2", virtualCase.getName()); assertTrue(virtualCase.getCase().isPresent()); assertTrue(virtualCase.getScript().isPresent()); @@ -150,16 +161,38 @@ void test() { assertNotNull(virtualCase.getNetwork()); assertFalse(virtualCase.mandatoryDependenciesAreMissing()); assertEquals("hello", virtualCase.getOutput()); + } - // test cache invalidation + @Test + void invalidateCacheOnUpdateTest() { + ModificationScript script = folder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("print 'hello'") + .build(); + VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) + .withName("network2") + .withCase(importedCase) + .withScript(script) + .build(); + + // Update script content script.writeScript("print 'bye'"); + + // Check that content has been updated in backwards dependencies too assertNotNull(virtualCase.getNetwork()); assertEquals("bye", virtualCase.getOutput()); + // Delete the virtual case virtualCase.delete(); + + // Check that the dependencies do not have anymore backward dependencies assertTrue(importedCase.getBackwardDependencies().isEmpty()); assertTrue(script.getBackwardDependencies().isEmpty()); + } + @Test + void buildingVirtualCaseWithScriptExceptionTest() { // test script error ModificationScript scriptWithError = folder.fileBuilder(ModificationScriptBuilder.class) .withName("scriptWithError") @@ -173,83 +206,122 @@ void test() { .withScript(scriptWithError) .build(); - try { - virtualCaseWithError.getNetwork(); - fail(); - } catch (ScriptException e) { - assertNotNull(e.getError()); - assertTrue(e.getError().getMessage().contains("No signature of method: test.prin() is applicable")); - } + ScriptException exception = assertThrows(ScriptException.class, virtualCaseWithError::getNetwork); + assertNotNull(exception.getError()); + assertTrue(exception.getMessage().contains("No signature of method: test.prin() is applicable")); + } - // test script error with MultipleCompilationErrorsException - scriptWithError = folder.fileBuilder(ModificationScriptBuilder.class) + @Test + void buildingVirtualCaseWithMultipleCompilationErrorsExceptionTest() { + // test script error + ModificationScript scriptWithError = folder.fileBuilder(ModificationScriptBuilder.class) .withName("scriptWithError_MultipleCompilationErrorsException") .withType(ScriptType.GROOVY) .withContent("print('hello'") .build(); - virtualCaseWithError = folder.fileBuilder(VirtualCaseBuilder.class) + VirtualCase virtualCaseWithError = folder.fileBuilder(VirtualCaseBuilder.class) .withName("network2_MultipleCompilationErrorsException") .withCase(importedCase) .withScript(scriptWithError) .build(); - try { - virtualCaseWithError.getNetwork(); - fail(); - } catch (ScriptException e) { - assertNotNull(e.getError()); - assertEquals("Unexpected input: '(' @ line 1, column 6.", e.getError().getMessage()); - } + ScriptException exception = assertThrows(ScriptException.class, virtualCaseWithError::getNetwork); + assertNotNull(exception.getError()); + assertEquals("Unexpected input: '(' @ line 1, column 6.", exception.getError().getMessage()); + } - //test missing dependencies - VirtualCase virtualCase3 = folder.fileBuilder(VirtualCaseBuilder.class) + @Test + void missingDependenciesTest() { + ModificationScript script = folder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("print 'hello'") + .build(); + + VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) .withName("network3") .withCase(importedCase) - .withScript(scriptWithError) + .withScript(script) .build(); + // Delete the imported case dependency importedCase.delete(); - assertTrue(virtualCase3.mandatoryDependenciesAreMissing()); + assertTrue(virtualCase.mandatoryDependenciesAreMissing()); - ImportedCase importedCase2 = folder.fileBuilder(ImportedCaseBuilder.class) + // Create a new imported case and set it as a dependency of the virtual case + ImportedCase newImportedCase = folder.fileBuilder(ImportedCaseBuilder.class) .withCase(aCase) .build(); + virtualCase.setCase(newImportedCase); - virtualCase3.setCase(importedCase2); + // Delete the script dependency + script.delete(); + assertTrue(virtualCase.mandatoryDependenciesAreMissing()); + } - scriptWithError.delete(); - assertTrue(virtualCase3.mandatoryDependenciesAreMissing()); + @Test + void replaceDependenciesTest() { + ModificationScript script = folder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("print 'hello'") + .build(); + + VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) + .withName("network3") + .withCase(importedCase) + .withScript(script) + .build(); //test replace dependencies - assertEquals(importedCase2.getName(), virtualCase3.getCase().map(ProjectFile::getName).orElse(null)); + assertEquals(importedCase.getName(), virtualCase.getCase().map(ProjectFile::getName).orElse(null)); - ImportedCase importedCase3 = folder.fileBuilder(ImportedCaseBuilder.class) + // Replace the dependency + ImportedCase newImportedCase = folder.fileBuilder(ImportedCaseBuilder.class) .withCase(aCase) - .withName("importedCase3") + .withName("newImportedCase") .build(); + virtualCase.replaceDependency(importedCase.getId(), newImportedCase); - virtualCase3.replaceDependency(importedCase2.getId(), importedCase3); + assertNotEquals(importedCase.getName(), virtualCase.getCase().map(ProjectFile::getName).orElse(null)); + assertEquals(newImportedCase.getName(), virtualCase.getCase().map(ProjectFile::getName).orElse(null)); + } - assertNotEquals(importedCase2.getName(), virtualCase3.getCase().map(ProjectFile::getName).orElse(null)); - assertEquals(importedCase3.getName(), virtualCase3.getCase().map(ProjectFile::getName).orElse(null)); + @Test + void circularDependencyExceptionTest() { + ModificationScript script = folder.fileBuilder(ModificationScriptBuilder.class) + .withName("script") + .withType(ScriptType.GROOVY) + .withContent("print 'hello'") + .build(); + VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) + .withName("network3") + .withCase(importedCase) + .withScript(script) + .build(); - assertThatCode(() -> virtualCase3.setCase(virtualCase3)).isInstanceOf(AfsCircularDependencyException.class); + // Include the virtual case in itself + AfsCircularDependencyException exception = assertThrows(AfsCircularDependencyException.class, () -> virtualCase.setCase(virtualCase)); + assertEquals("Circular dependency detected", exception.getMessage()); + } + @Test + void networkListenerTest() { // test network listener ModificationScript scriptModif = folder.fileBuilder(ModificationScriptBuilder.class) .withName("scriptModif") .withType(ScriptType.GROOVY) .withContent("network.getSubstation('s1').setTso('tso_new')") .build(); - VirtualCase virtualCase4 = folder.fileBuilder(VirtualCaseBuilder.class) + VirtualCase virtualCase = folder.fileBuilder(VirtualCaseBuilder.class) .withName("network4") - .withCase(importedCase3) + .withCase(importedCase) .withScript(scriptModif) .build(); NetworkListener mockedListener = mock(DefaultNetworkListener.class); - virtualCase4.getNetwork(Collections.singletonList(mockedListener)); + virtualCase.getNetwork(Collections.singletonList(mockedListener)); verify(mockedListener, times(1)) .onUpdate(network.getSubstation("s1"), "tso", null, "TSO", "tso_new"); } From aa1b57dd3d341e61c7fa66b4e9c404c87b9595e8 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Tue, 18 Feb 2025 12:55:59 +0100 Subject: [PATCH 27/36] clean LocalAppFileSystemConfigTest Signed-off-by: Nicolas Rol --- .../local/LocalAppFileSystemConfigTest.java | 60 ++++++++++++++----- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/afs-local/src/test/java/com/powsybl/afs/local/LocalAppFileSystemConfigTest.java b/afs-local/src/test/java/com/powsybl/afs/local/LocalAppFileSystemConfigTest.java index 7fe96b7f..e8015efa 100644 --- a/afs-local/src/test/java/com/powsybl/afs/local/LocalAppFileSystemConfigTest.java +++ b/afs-local/src/test/java/com/powsybl/afs/local/LocalAppFileSystemConfigTest.java @@ -8,6 +8,7 @@ import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; +import com.powsybl.afs.AfsException; import com.powsybl.commons.config.InMemoryPlatformConfig; import com.powsybl.commons.config.MapModuleConfig; import org.junit.jupiter.api.AfterEach; @@ -16,9 +17,13 @@ import java.nio.file.FileSystem; import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Geoffroy Jamgotchian {@literal } @@ -30,45 +35,70 @@ class LocalAppFileSystemConfigTest { private InMemoryPlatformConfig platformConfig; @BeforeEach - public void setUp() throws Exception { + void setUp() throws Exception { fileSystem = Jimfs.newFileSystem(Configuration.unix()); Files.createDirectories(fileSystem.getPath("/tmp")); Files.createFile(fileSystem.getPath("/test")); platformConfig = new InMemoryPlatformConfig(fileSystem); MapModuleConfig moduleConfig = platformConfig.createModuleConfig("local-app-file-system"); + // Config 1 moduleConfig.setStringProperty("drive-name", "local"); moduleConfig.setPathProperty("root-dir", fileSystem.getPath("/work")); moduleConfig.setStringProperty("max-additional-drive-count", "2"); + + // Config 2 moduleConfig.setStringProperty("drive-name-1", "local1"); moduleConfig.setStringProperty("remotely-accessible-1", "true"); moduleConfig.setPathProperty("root-dir-1", fileSystem.getPath("/work")); } @AfterEach - public void tearDown() throws Exception { + void tearDown() throws Exception { fileSystem.close(); } @Test void loadTest() { List configs = LocalAppFileSystemConfig.load(platformConfig); + + // Number of configs assertEquals(2, configs.size()); - LocalAppFileSystemConfig config = configs.get(0); - LocalAppFileSystemConfig config1 = configs.get(1); - assertEquals("local", config.getDriveName()); - assertFalse(config.isRemotelyAccessible()); - assertEquals(fileSystem.getPath("/work"), config.getRootDir()); - assertEquals("local1", config1.getDriveName()); - assertTrue(config1.isRemotelyAccessible()); + LocalAppFileSystemConfig config1 = configs.get(0); + LocalAppFileSystemConfig config2 = configs.get(1); + + // Checks on config 1 + assertEquals("local", config1.getDriveName()); + assertFalse(config1.isRemotelyAccessible()); assertEquals(fileSystem.getPath("/work"), config1.getRootDir()); + + // Check on config 2 + assertEquals("local1", config2.getDriveName()); + assertTrue(config2.isRemotelyAccessible()); + assertEquals(fileSystem.getPath("/work"), config2.getRootDir()); + } + + @Test + void configModificationTest() { + List configs = LocalAppFileSystemConfig.load(platformConfig); + LocalAppFileSystemConfig config = configs.get(0); + + // Change some configuration parameters config.setDriveName("local2"); config.setRootDir(fileSystem.getPath("/tmp")); + + // Check that the parameters are updated assertEquals("local2", config.getDriveName()); assertEquals(fileSystem.getPath("/tmp"), config.getRootDir()); - try { - config.setRootDir(fileSystem.getPath("/test")); - fail(); - } catch (Exception ignored) { - } + } + + @Test + void setRootDirToFileExceptionTest() { + List configs = LocalAppFileSystemConfig.load(platformConfig); + LocalAppFileSystemConfig config = configs.get(0); + + // Try to set rootDir to a file instead of a directory + Path filePath = fileSystem.getPath("/test"); + AfsException exception = assertThrows(AfsException.class, () -> config.setRootDir(filePath)); + assertEquals("Root path /test is not a directory", exception.getMessage()); } } From 61bd6ddb50dc00544865404b820d77e2ffe3b5f2 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Tue, 18 Feb 2025 12:57:02 +0100 Subject: [PATCH 28/36] clean LocalAppFileSystemProviderTest Signed-off-by: Nicolas Rol --- .../afs/local/LocalAppFileSystemProviderTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/afs-local/src/test/java/com/powsybl/afs/local/LocalAppFileSystemProviderTest.java b/afs-local/src/test/java/com/powsybl/afs/local/LocalAppFileSystemProviderTest.java index db99a2d7..311f3f72 100644 --- a/afs-local/src/test/java/com/powsybl/afs/local/LocalAppFileSystemProviderTest.java +++ b/afs-local/src/test/java/com/powsybl/afs/local/LocalAppFileSystemProviderTest.java @@ -25,7 +25,9 @@ import java.util.Collections; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Geoffroy Jamgotchian {@literal } @@ -35,12 +37,12 @@ class LocalAppFileSystemProviderTest { private FileSystem fileSystem; @BeforeEach - public void setUp() throws Exception { + void setUp() { fileSystem = Jimfs.newFileSystem(Configuration.unix()); } @AfterEach - public void tearDown() throws Exception { + void tearDown() throws Exception { fileSystem.close(); } @@ -50,9 +52,9 @@ void test() { LocalAppFileSystemConfig config = new LocalAppFileSystemConfig("drive", true, fileSystem.getPath("/work")); LocalFileScanner extension = new LocalCaseScanner(new ImportConfig(), new ImportersLoaderList()); List fileSystems = new LocalAppFileSystemProvider(Collections.singletonList(config), - Collections.singletonList(extension), - Collections.emptyList()) - .getFileSystems(new AppFileSystemProviderContext(computationManager, null, new InMemoryEventsBus())); + Collections.singletonList(extension), + Collections.emptyList()) + .getFileSystems(new AppFileSystemProviderContext(computationManager, null, new InMemoryEventsBus())); assertEquals(1, fileSystems.size()); assertInstanceOf(LocalAppFileSystem.class, fileSystems.get(0)); assertEquals("drive", fileSystems.get(0).getName()); From ea9ffd88d32794ca83b5bbc0369c183bdbe81fc9 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Tue, 18 Feb 2025 13:33:54 +0100 Subject: [PATCH 29/36] clean LocalAppStorageTest Signed-off-by: Nicolas Rol --- .../local/storage/LocalAppStorageTest.java | 97 +++++++++++++++---- 1 file changed, 80 insertions(+), 17 deletions(-) diff --git a/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java b/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java index 9f8a8c08..ad9ba268 100644 --- a/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java +++ b/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java @@ -11,9 +11,7 @@ import com.powsybl.afs.Folder; import com.powsybl.afs.ext.base.Case; import com.powsybl.afs.ext.base.TestImporter; -import com.powsybl.afs.storage.AppStorageDataSource; import com.powsybl.afs.storage.NodeInfo; -import com.powsybl.commons.datasource.DataSource; import com.powsybl.computation.ComputationManager; import com.powsybl.iidm.network.ImportConfig; import com.powsybl.iidm.network.ImportersLoaderList; @@ -33,7 +31,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -47,14 +44,20 @@ class LocalAppStorageTest { private LocalAppStorage storage; @BeforeEach - public void setUp() throws Exception { + void setUp() throws Exception { fileSystem = Jimfs.newFileSystem(Configuration.unix()); + + // Create the root directory Path rootDir = fileSystem.getPath("/cases"); Files.createDirectories(rootDir); + + // Create two files in the root directory Path path1 = rootDir.resolve("n.tst"); Path path2 = rootDir.resolve("n2.tst"); Files.createFile(path1); Files.createFile(path2); + + // Create the LocalAppStorage ComputationManager computationManager = Mockito.mock(ComputationManager.class); Network network = Mockito.mock(Network.class); List fileExtensions @@ -63,7 +66,7 @@ public void setUp() throws Exception { } @AfterEach - public void tearDown() throws Exception { + void tearDown() throws Exception { storage.close(); fileSystem.close(); } @@ -76,27 +79,87 @@ void testConsistent() { } @Test - void test() { + void rootNodeInfoTest() { NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); assertEquals("mem", rootNodeInfo.getName()); + assertEquals(Folder.PSEUDO_CLASS, rootNodeInfo.getPseudoClass()); + } + + @Test + void rootNodeParametersTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); assertFalse(storage.isWritable(rootNodeInfo.getId())); assertTrue(storage.isConsistent(rootNodeInfo.getId())); - assertFalse(storage.getParentNode(rootNodeInfo.getId()).isPresent()); + } + + @Test + void getChildNodesTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + + // Check the child nodes assertEquals(List.of("%2Fcases%2Fn.tst", "%2Fcases%2Fn2.tst"), storage.getChildNodes(rootNodeInfo.getId()).stream().map(NodeInfo::getId).collect(Collectors.toList())); + } + + @Test + void getChildNodeTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + + // Case 1 Optional case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst"); assertTrue(case1.isPresent()); - assertEquals(rootNodeInfo, storage.getParentNode(case1.get().getId()).orElseThrow(AssertionError::new)); + + // Case 2 Optional case2 = storage.getChildNode(rootNodeInfo.getId(), "n2.tst"); assertTrue(case2.isPresent()); - assertEquals("%2Fcases%2Fn.tst", case1.get().getId()); - assertFalse(storage.getChildNode(rootNodeInfo.getId(), "n3.tst").isPresent()); - assertEquals(Folder.PSEUDO_CLASS, rootNodeInfo.getPseudoClass()); - assertEquals(Case.PSEUDO_CLASS, case1.get().getPseudoClass()); - assertEquals("TEST", case1.get().getGenericMetadata().getString("format")); - assertEquals("Test format", case1.get().getDescription()); - DataSource ds = new AppStorageDataSource(storage, case1.get().getId(), case1.get().getName()); - assertNotNull(ds); - assertTrue(ds.isDataExtension("foo")); + + // Case 3 (not present) + Optional case3 = storage.getChildNode(rootNodeInfo.getId(), "n3.tst"); + assertTrue(case3.isEmpty()); + } + + @Test + void childNodeIdTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + NodeInfo case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst").orElseThrow(AssertionError::new); + assertEquals("%2Fcases%2Fn.tst", case1.getId()); + } + + @Test + void childNodePseudoClassTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + NodeInfo case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst").orElseThrow(AssertionError::new); + assertEquals(Case.PSEUDO_CLASS, case1.getPseudoClass()); + } + + @Test + void childNodeGenericMetadataTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + NodeInfo case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst").orElseThrow(AssertionError::new); + assertEquals("TEST", case1.getGenericMetadata().getString("format")); + } + + @Test + void childNodeDescriptionTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + NodeInfo case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst").orElseThrow(AssertionError::new); + assertEquals("Test format", case1.getDescription()); + } + + @Test + void getParentNodeForRootNodeTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + + // Check parent node for root node + assertFalse(storage.getParentNode(rootNodeInfo.getId()).isPresent()); + } + + @Test + void getParentNodeForChildNodeTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + + // Check parent node for node child + Optional case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst"); + assertEquals(rootNodeInfo, storage.getParentNode(case1.orElseThrow(AssertionError::new).getId()).orElseThrow(AssertionError::new)); } } From 4a1398b370383646c6602286308454efb34dbb6c Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Thu, 20 Feb 2025 17:52:18 +0100 Subject: [PATCH 30/36] clean some classes Signed-off-by: Nicolas Rol --- .../local/storage/LocalAppStorageTest.java | 12 ++ .../afs/storage/AppStorageDataSource.java | 189 +++++++++--------- 2 files changed, 105 insertions(+), 96 deletions(-) diff --git a/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java b/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java index ad9ba268..1532d369 100644 --- a/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java +++ b/afs-local/src/test/java/com/powsybl/afs/local/storage/LocalAppStorageTest.java @@ -11,7 +11,9 @@ import com.powsybl.afs.Folder; import com.powsybl.afs.ext.base.Case; import com.powsybl.afs.ext.base.TestImporter; +import com.powsybl.afs.storage.AppStorageDataSource; import com.powsybl.afs.storage.NodeInfo; +import com.powsybl.commons.datasource.DataSource; import com.powsybl.computation.ComputationManager; import com.powsybl.iidm.network.ImportConfig; import com.powsybl.iidm.network.ImportersLoaderList; @@ -31,6 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -162,4 +165,13 @@ void getParentNodeForChildNodeTest() { Optional case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst"); assertEquals(rootNodeInfo, storage.getParentNode(case1.orElseThrow(AssertionError::new).getId()).orElseThrow(AssertionError::new)); } + + @Test + void appStorageDataSourceFromChildNodeTest() { + NodeInfo rootNodeInfo = storage.createRootNodeIfNotExists("mem", Folder.PSEUDO_CLASS); + NodeInfo case1 = storage.getChildNode(rootNodeInfo.getId(), "n.tst").orElseThrow(AssertionError::new); + DataSource ds = new AppStorageDataSource(storage, case1.getId(), case1.getName()); + assertNotNull(ds); + assertTrue(ds.isDataExtension("foo")); + } } diff --git a/afs-storage-api/src/main/java/com/powsybl/afs/storage/AppStorageDataSource.java b/afs-storage-api/src/main/java/com/powsybl/afs/storage/AppStorageDataSource.java index 50d80328..de054d21 100755 --- a/afs-storage-api/src/main/java/com/powsybl/afs/storage/AppStorageDataSource.java +++ b/afs-storage-api/src/main/java/com/powsybl/afs/storage/AppStorageDataSource.java @@ -29,6 +29,99 @@ public class AppStorageDataSource implements DataSource { private static final String SEPARATOR = "__"; + private static final Logger LOG = LoggerFactory.getLogger(AppStorageDataSource.class); + private final AppStorage storage; + private final String nodeId; + private final String nodeName; + + public AppStorageDataSource(AppStorage storage, String nodeId, String nodeName) { + this.storage = Objects.requireNonNull(storage); + this.nodeId = Objects.requireNonNull(nodeId); + this.nodeName = Objects.requireNonNull(nodeName); + } + + @Override + public String getBaseName() { + return nodeName; + } + + /** + * {@inheritDoc} + * + * @return true + */ + @Override + public boolean isDataExtension(String ext) { + return true; + } + + @Override + public OutputStream newOutputStream(final String suffix, final String ext, boolean append) { + if (append) { + throw new UnsupportedOperationException("Append mode not supported"); + } + return storage.writeBinaryData(nodeId, new SuffixAndExtension(suffix, ext).toString()); + } + + @Override + public OutputStream newOutputStream(String fileName, boolean append) { + Objects.requireNonNull(fileName); + if (append) { + throw new UnsupportedOperationException("Append mode not supported"); + } + return storage.writeBinaryData(nodeId, new FileName(fileName).toString()); + } + + @Override + public boolean exists(String suffix, String ext) { + return storage.dataExists(nodeId, new SuffixAndExtension(suffix, ext).toString()); + } + + @Override + public boolean exists(String fileName) { + return storage.dataExists(nodeId, new FileName(fileName).toString()); + } + + @Override + public InputStream newInputStream(String suffix, String ext) throws IOException { + return storage.readBinaryData(nodeId, new SuffixAndExtension(suffix, ext).toString()) + .orElseThrow(() -> new IOException("*" + Objects.toString(suffix, "") + "." + Objects.toString(ext, "") + " does not exist")); + } + + @Override + public InputStream newInputStream(String fileName) throws IOException { + return storage.readBinaryData(nodeId, new FileName(fileName).toString()) + .orElseThrow(() -> new IOException(fileName + " does not exist")); + } + + @Override + public Set listNames(String regex) throws IOException { + Pattern p = Pattern.compile(regex); + Set names = storage.getDataNames(nodeId).stream() + .filter(name -> p.matcher(name).matches()) + .map(name -> Name.parse(name, new NameHandler() { + + @Override + public String onSuffixAndExtension(SuffixAndExtension suffixAndExtension) throws IOException { + throw new AssertionError("Don't know how to unmap suffix-and-extension to a data source name " + name); + } + + @Override + public String onFileName(FileName fileName) throws IOException { + return fileName.getName(); + } + + @Override + public String onOther(Name otherName) { + // Return the original name + return name; + } + })) + .collect(Collectors.toSet()); + LOG.info("AppStorageDataSource::listNames()"); + names.forEach(n -> LOG.info(" {}", n)); + return names; + } public interface Name { @@ -124,100 +217,4 @@ public String toString() { return START_PATTERN + name; } } - - private final AppStorage storage; - - private final String nodeId; - - private final String nodeName; - - public AppStorageDataSource(AppStorage storage, String nodeId, String nodeName) { - this.storage = Objects.requireNonNull(storage); - this.nodeId = Objects.requireNonNull(nodeId); - this.nodeName = Objects.requireNonNull(nodeName); - } - - @Override - public String getBaseName() { - return nodeName; - } - - /** - * {@inheritDoc} - * @return true - */ - @Override - public boolean isDataExtension(String ext) { - return true; - } - - @Override - public OutputStream newOutputStream(final String suffix, final String ext, boolean append) { - if (append) { - throw new UnsupportedOperationException("Append mode not supported"); - } - return storage.writeBinaryData(nodeId, new SuffixAndExtension(suffix, ext).toString()); - } - - @Override - public OutputStream newOutputStream(String fileName, boolean append) { - Objects.requireNonNull(fileName); - if (append) { - throw new UnsupportedOperationException("Append mode not supported"); - } - return storage.writeBinaryData(nodeId, new FileName(fileName).toString()); - } - - @Override - public boolean exists(String suffix, String ext) { - return storage.dataExists(nodeId, new SuffixAndExtension(suffix, ext).toString()); - } - - @Override - public boolean exists(String fileName) { - return storage.dataExists(nodeId, new FileName(fileName).toString()); - } - - @Override - public InputStream newInputStream(String suffix, String ext) throws IOException { - return storage.readBinaryData(nodeId, new SuffixAndExtension(suffix, ext).toString()) - .orElseThrow(() -> new IOException("*" + Objects.toString(suffix, "") + "." + Objects.toString(ext, "") + " does not exist")); - } - - @Override - public InputStream newInputStream(String fileName) throws IOException { - return storage.readBinaryData(nodeId, new FileName(fileName).toString()) - .orElseThrow(() -> new IOException(fileName + " does not exist")); - } - - @Override - public Set listNames(String regex) throws IOException { - Pattern p = Pattern.compile(regex); - Set names = storage.getDataNames(nodeId).stream() - .filter(name -> p.matcher(name).matches()) - .map(name -> Name.parse(name, new NameHandler() { - - @Override - public String onSuffixAndExtension(SuffixAndExtension suffixAndExtension) throws IOException { - throw new AssertionError("Don't know how to unmap suffix-and-extension to a data source name " + name); - } - - @Override - public String onFileName(FileName fileName) throws IOException { - return fileName.getName(); - } - - @Override - public String onOther(Name otherName) { - // Return the original name - return name; - } - })) - .collect(Collectors.toSet()); - LOG.info("AppStorageDataSource::listNames()"); - names.forEach(n -> LOG.info(" {}", n)); - return names; - } - - private static final Logger LOG = LoggerFactory.getLogger(AppStorageDataSource.class); } From a3f072a95667a690caf83211da5ea7ea6ed23d98 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 21 Feb 2025 13:46:43 +0100 Subject: [PATCH 31/36] clean NodeGenericMetadataTest Signed-off-by: Nicolas Rol --- .../afs/storage/NodeGenericMetadataTest.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeGenericMetadataTest.java b/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeGenericMetadataTest.java index 1be400ca..fda56d4f 100644 --- a/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeGenericMetadataTest.java +++ b/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeGenericMetadataTest.java @@ -11,8 +11,8 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; /** * @author Geoffroy Jamgotchian {@literal } @@ -23,11 +23,11 @@ class NodeGenericMetadataTest { void test() { // check getters NodeGenericMetadata metadata = new NodeGenericMetadata() - .setString("s1", "a") - .setString("s2", "b") - .setDouble("d1", 0d) - .setInt("i1", 1) - .setBoolean("b1", true); + .setString("s1", "a") + .setString("s2", "b") + .setDouble("d1", 0d) + .setInt("i1", 1) + .setBoolean("b1", true); assertEquals("a", metadata.getString("s1")); assertEquals("b", metadata.getString("s2")); assertEquals(ImmutableMap.of("s1", "a", "s2", "b"), metadata.getStrings()); @@ -39,18 +39,15 @@ void test() { assertEquals(ImmutableMap.of("b1", true), metadata.getBooleans()); // check metadata not found - try { - metadata.getString("s3"); - fail(); - } catch (IllegalArgumentException ignored) { - } + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> metadata.getString("s3")); + assertEquals("String metadata 's3' not found", exception.getMessage()); // check equality new EqualsTester() - .addEqualityGroup(new NodeGenericMetadata().setString("s1", "a"), - new NodeGenericMetadata().setString("s1", "a")) - .addEqualityGroup(new NodeGenericMetadata().setDouble("d1", 3d), - new NodeGenericMetadata().setDouble("d1", 3d)) - .testEquals(); + .addEqualityGroup(new NodeGenericMetadata().setString("s1", "a"), + new NodeGenericMetadata().setString("s1", "a")) + .addEqualityGroup(new NodeGenericMetadata().setDouble("d1", 3d), + new NodeGenericMetadata().setDouble("d1", 3d)) + .testEquals(); } } From c7552b7e84e1752c8f8c91db4b5f8dfb37e50732 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 21 Feb 2025 13:49:31 +0100 Subject: [PATCH 32/36] clean NodeInfoTest Signed-off-by: Nicolas Rol --- .../src/test/java/com/powsybl/afs/storage/NodeInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeInfoTest.java b/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeInfoTest.java index 15a55a98..cc3bb17b 100644 --- a/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeInfoTest.java +++ b/afs-storage-api/src/test/java/com/powsybl/afs/storage/NodeInfoTest.java @@ -24,7 +24,7 @@ class NodeInfoTest { private ObjectMapper objectMapper; @BeforeEach - public void setUp() { + void setUp() { objectMapper = JsonUtil.createObjectMapper() .registerModule(new AppStorageJsonModule()); } From 47bb97e0c8ed2d70e1dbad6101693fc84b598aa9 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 21 Feb 2025 14:06:22 +0100 Subject: [PATCH 33/36] clean UtilsTest Signed-off-by: Nicolas Rol --- .../com/powsybl/afs/storage/UtilsTest.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/afs-storage-api/src/test/java/com/powsybl/afs/storage/UtilsTest.java b/afs-storage-api/src/test/java/com/powsybl/afs/storage/UtilsTest.java index ff177cbf..f0be6b87 100644 --- a/afs-storage-api/src/test/java/com/powsybl/afs/storage/UtilsTest.java +++ b/afs-storage-api/src/test/java/com/powsybl/afs/storage/UtilsTest.java @@ -7,11 +7,14 @@ package com.powsybl.afs.storage; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; @@ -22,12 +25,13 @@ */ class UtilsTest { - + private FileSystem fileSystem; private Path rootDir; @BeforeEach - public void setup() throws IOException { - rootDir = Files.createTempDirectory("test1"); + void setup() throws IOException { + fileSystem = Jimfs.newFileSystem(Configuration.unix()); + rootDir = Files.createTempDirectory(String.valueOf(fileSystem.getPath("test1"))); Path folder = rootDir.resolve("test"); Files.createDirectory(folder); Files.createDirectory(folder.resolve("subTest")); @@ -35,8 +39,8 @@ public void setup() throws IOException { } @AfterEach - public void tearDown() throws Exception { - Utils.deleteDirectory(rootDir); + void tearDown() throws Exception { + fileSystem.close(); } @Test @@ -62,21 +66,15 @@ void zipWithoutDeleteDirectoryTest() throws IOException { @Test void deleteDirectoryTest() throws IOException { - Path rootDir2 = Files.createTempDirectory("test1"); - Files.createFile(rootDir2.resolve("test")); - Utils.deleteDirectory(rootDir2); - assertTrue(Files.notExists(rootDir2)); + Files.createFile(rootDir.resolve("test2")); + Utils.deleteDirectory(rootDir); + assertTrue(Files.notExists(rootDir)); } @Test void checkDiskSpaceTest() throws IOException { - Path rootDir2 = Files.createTempDirectory("test1"); - Files.createFile(rootDir2.resolve("test")); - try { - Utils.checkDiskSpace(rootDir2); - } catch (IOException ignored) { - } - + Files.createFile(rootDir.resolve("test3")); + Utils.checkDiskSpace(rootDir); } } From 42cd73eecea9dd528256f671030b2d56faa85504 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 21 Feb 2025 14:06:57 +0100 Subject: [PATCH 34/36] clean StorageChangeTest Signed-off-by: Nicolas Rol --- .../java/com/powsybl/afs/storage/buffer/StorageChangeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afs-storage-api/src/test/java/com/powsybl/afs/storage/buffer/StorageChangeTest.java b/afs-storage-api/src/test/java/com/powsybl/afs/storage/buffer/StorageChangeTest.java index 2f5a16a1..039cda27 100644 --- a/afs-storage-api/src/test/java/com/powsybl/afs/storage/buffer/StorageChangeTest.java +++ b/afs-storage-api/src/test/java/com/powsybl/afs/storage/buffer/StorageChangeTest.java @@ -26,7 +26,7 @@ class StorageChangeTest { private ObjectMapper objectMapper; @BeforeEach - public void setUp() throws Exception { + void setUp() { objectMapper = JsonUtil.createObjectMapper() .registerModule(new AppStorageJsonModule()); } From d09994bd74aff1c663b1e405d6d8d2fff744f883 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 21 Feb 2025 14:07:23 +0100 Subject: [PATCH 35/36] clean NodeEventTest Signed-off-by: Nicolas Rol --- .../test/java/com/powsybl/afs/storage/events/NodeEventTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afs-storage-api/src/test/java/com/powsybl/afs/storage/events/NodeEventTest.java b/afs-storage-api/src/test/java/com/powsybl/afs/storage/events/NodeEventTest.java index 84ad370a..0612d178 100644 --- a/afs-storage-api/src/test/java/com/powsybl/afs/storage/events/NodeEventTest.java +++ b/afs-storage-api/src/test/java/com/powsybl/afs/storage/events/NodeEventTest.java @@ -24,7 +24,7 @@ class NodeEventTest { private ObjectMapper objectMapper; @BeforeEach - public void setUp() throws Exception { + void setUp() { objectMapper = JsonUtil.createObjectMapper(); } From ed8ce3d6d9701281c0162f5cf3069ef3779f3812 Mon Sep 17 00:00:00 2001 From: Nicolas Rol Date: Fri, 21 Feb 2025 15:24:24 +0100 Subject: [PATCH 36/36] add RemoteAppFileSystemProviderTest Signed-off-by: Nicolas Rol --- afs-ws/afs-ws-client/pom.xml | 14 +++ .../client/RemoteAppFileSystemProvider.java | 12 +- .../afs/ws/client/CodeCoverageTest.java | 20 ---- .../RemoteAppFileSystemProviderTest.java | 108 ++++++++++++++++++ pom.xml | 6 + 5 files changed, 138 insertions(+), 22 deletions(-) delete mode 100644 afs-ws/afs-ws-client/src/test/java/com/powsybl/afs/ws/client/CodeCoverageTest.java create mode 100644 afs-ws/afs-ws-client/src/test/java/com/powsybl/afs/ws/client/RemoteAppFileSystemProviderTest.java diff --git a/afs-ws/afs-ws-client/pom.xml b/afs-ws/afs-ws-client/pom.xml index c4c9e922..1a3bcc23 100644 --- a/afs-ws/afs-ws-client/pom.xml +++ b/afs-ws/afs-ws-client/pom.xml @@ -64,11 +64,25 @@ + + com.powsybl + powsybl-config-test + org.junit.jupiter junit-jupiter-engine test + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + org.slf4j slf4j-simple diff --git a/afs-ws/afs-ws-client/src/main/java/com/powsybl/afs/ws/client/RemoteAppFileSystemProvider.java b/afs-ws/afs-ws-client/src/main/java/com/powsybl/afs/ws/client/RemoteAppFileSystemProvider.java index 6aa35b3d..83c74a1a 100644 --- a/afs-ws/afs-ws-client/src/main/java/com/powsybl/afs/ws/client/RemoteAppFileSystemProvider.java +++ b/afs-ws/afs-ws-client/src/main/java/com/powsybl/afs/ws/client/RemoteAppFileSystemProvider.java @@ -55,8 +55,8 @@ public List getFileSystems(AppFileSystemProviderContext context) return RemoteAppStorage.getFileSystemNames(uri, context.getToken()).stream() .map(fileSystemName -> { WebsocketConnectionPolicy websocketPolicy = WebsocketConnectionPolicy.forConfig(config); - RemoteAppStorage storage = new RemoteAppStorage(fileSystemName, uri, context.getToken(), websocketPolicy); - RemoteTaskMonitor taskMonitor = new RemoteTaskMonitor(fileSystemName, uri, context.getToken()); + RemoteAppStorage storage = createRemoteAppStorage(fileSystemName, uri, context.getToken(), websocketPolicy); + RemoteTaskMonitor taskMonitor = createRemoteTaskMonitor(fileSystemName, uri, context.getToken()); return new AppFileSystem(fileSystemName, true, storage, taskMonitor); }) .collect(Collectors.toList()); @@ -69,4 +69,12 @@ public List getFileSystems(AppFileSystemProviderContext context) return Collections.emptyList(); } } + + protected RemoteAppStorage createRemoteAppStorage(String fileSystemName, URI uri, String token, WebsocketConnectionPolicy websocketPolicy) { + return new RemoteAppStorage(fileSystemName, uri, token, websocketPolicy); + } + + protected RemoteTaskMonitor createRemoteTaskMonitor(String fileSystemName, URI uri, String token) { + return new RemoteTaskMonitor(fileSystemName, uri, token); + } } diff --git a/afs-ws/afs-ws-client/src/test/java/com/powsybl/afs/ws/client/CodeCoverageTest.java b/afs-ws/afs-ws-client/src/test/java/com/powsybl/afs/ws/client/CodeCoverageTest.java deleted file mode 100644 index 2aa551da..00000000 --- a/afs-ws/afs-ws-client/src/test/java/com/powsybl/afs/ws/client/CodeCoverageTest.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2018, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package com.powsybl.afs.ws.client; - -import org.junit.jupiter.api.Test; - -/** - * @author Mathieu Bague {@literal } - */ -class CodeCoverageTest { - - @Test - void testNothing() { - // TODO: remove this class once a real test has been added - } -} diff --git a/afs-ws/afs-ws-client/src/test/java/com/powsybl/afs/ws/client/RemoteAppFileSystemProviderTest.java b/afs-ws/afs-ws-client/src/test/java/com/powsybl/afs/ws/client/RemoteAppFileSystemProviderTest.java new file mode 100644 index 00000000..b2ddcd77 --- /dev/null +++ b/afs-ws/afs-ws-client/src/test/java/com/powsybl/afs/ws/client/RemoteAppFileSystemProviderTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025, RTE (https://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.afs.ws.client; + +import com.powsybl.afs.AppFileSystem; +import com.powsybl.afs.AppFileSystemProviderContext; +import com.powsybl.afs.ws.client.utils.RemoteServiceConfig; +import com.powsybl.afs.ws.storage.RemoteAppStorage; +import com.powsybl.afs.ws.storage.RemoteTaskMonitor; +import jakarta.ws.rs.ProcessingException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +/** + * @author Nicolas Rol {@literal } + */ +@ExtendWith(MockitoExtension.class) +class RemoteAppFileSystemProviderTest { + + @Test + void getFileSystemsNullContextExceptionTest() { + RemoteAppFileSystemProvider provider = new RemoteAppFileSystemProvider(Optional::empty); + assertThrows(NullPointerException.class, () -> provider.getFileSystems(null)); + } + + @Test + void getFileSystemsWithMissingConfigTest() { + RemoteAppFileSystemProvider provider = new RemoteAppFileSystemProvider(Optional::empty); + AppFileSystemProviderContext context = mock(AppFileSystemProviderContext.class); + List fileSystems = provider.getFileSystems(context); + assertTrue(fileSystems.isEmpty()); + } + + @Test + void getFileSystemsWithProcessingExceptionTest() { + // Mock some URI for the test + RemoteServiceConfig config = mock(RemoteServiceConfig.class); + when(config.getRestUri()).thenReturn(URI.create("http://test-uri")); + + // Mock a token + AppFileSystemProviderContext context = mock(AppFileSystemProviderContext.class); + when(context.getToken()).thenReturn("test-token"); + + // Initialize the provider + RemoteAppFileSystemProvider provider = new RemoteAppFileSystemProvider(() -> Optional.of(config)); + + // Mock the exception on the RemoteAppStorage + try (var mockedStatic = mockStatic(RemoteAppStorage.class)) { + mockedStatic.when(() -> RemoteAppStorage.getFileSystemNames(any(), any())) + .thenThrow(new ProcessingException("Test exception")); + + // Check that we get an empty list + List fileSystems = provider.getFileSystems(context); + assertTrue(fileSystems.isEmpty()); + } + } + + @Test + void testGetFileSystemsWithValidConfig() { + // Mock some URI for the test + RemoteServiceConfig config = mock(RemoteServiceConfig.class); + when(config.getRestUri()).thenReturn(URI.create("http://test-uri")); + + // Mock a token + AppFileSystemProviderContext context = mock(AppFileSystemProviderContext.class); + when(context.getToken()).thenReturn("test-token"); + + // Initialize the provider with a spy in order to mock some methods inside + RemoteAppFileSystemProvider provider = spy(new RemoteAppFileSystemProvider(() -> Optional.of(config))); + + try (RemoteAppStorage mockStorage = mock(RemoteAppStorage.class); + RemoteTaskMonitor mockTaskMonitor = mock(RemoteTaskMonitor.class); + var mockedStaticStorage = mockStatic(RemoteAppStorage.class)) { + mockedStaticStorage.when(() -> RemoteAppStorage.getFileSystemNames(any(), any())) + .thenReturn(Collections.singletonList("test-fs")); + + // Stub de la factory method + doReturn(mockStorage).when(provider).createRemoteAppStorage(any(), any(), any(), any()); + doReturn(mockTaskMonitor).when(provider).createRemoteTaskMonitor(any(), any(), any()); + + // Check that we get the correct list + List fileSystems = provider.getFileSystems(context); + assertEquals(1, fileSystems.size()); + assertEquals("test-fs", fileSystems.get(0).getName()); + } + } +} diff --git a/pom.xml b/pom.xml index 83a4a50d..d7133cea 100644 --- a/pom.xml +++ b/pom.xml @@ -397,6 +397,12 @@ ${mockito.version} test + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + org.slf4j slf4j-simple