This is an automated email from the ASF dual-hosted git repository. sdanilov pushed a commit to branch ignite-18970 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit c0e5d087cda1d7ee2c7f303d3c5eb54e6f629c1d Author: Semyon Danilov <[email protected]> AuthorDate: Mon Mar 6 14:46:22 2023 +0400 IGNITE-18970 Allow WorkDirectoryExtension to preserve work directories of specific tests --- .../testframework/WorkDirectoryExtensionTest.java | 77 ++++++++++++++++- .../testframework/WorkDirectoryExtension.java | 99 ++++++++++++++++++---- 2 files changed, 158 insertions(+), 18 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtensionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtensionTest.java index d56f78ef1e..2553d00e13 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtensionTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtensionTest.java @@ -31,8 +31,10 @@ import static org.junit.platform.testkit.engine.TestExecutionResultConditions.me import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashSet; import java.util.Set; +import org.apache.ignite.internal.util.IgniteUtils; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -204,16 +206,33 @@ class WorkDirectoryExtensionTest { private static Path file2; + private static Path file3; + + private static final String TMP_PATH; + + static { + try { + TMP_PATH = Files.createTempDirectory("testdir").toString(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @AfterAll - static void verify() throws IOException { + static void verify() { assertTrue(Files.exists(file1)); assertFalse(Files.exists(file2)); + assertFalse(Files.exists(file3)); + assertTrue(Files.exists(Paths.get(TMP_PATH))); + + IgniteUtils.deleteIfExists(file1.getParent()); + IgniteUtils.deleteIfExists(Paths.get(TMP_PATH)); - Files.delete(file1); + System.clearProperty(WorkDirectoryExtension.ARTIFACT_DIR_PROPERTY); } @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") - @WithSystemProperty(key = WorkDirectoryExtension.KEEP_WORK_DIR_PROPERTY, value = "true") + @WithSystemProperty(key = WorkDirectoryExtension.KEEP_WORK_DIR_PROPERTY, value = "SystemPropertiesTest.test1") @Test void test1(@WorkDirectory Path workDir) throws IOException { file1 = Files.createFile(workDir.resolve("foo")); @@ -224,6 +243,50 @@ class WorkDirectoryExtensionTest { void test2(@WorkDirectory Path workDir) throws IOException { file2 = Files.createFile(workDir.resolve("foo")); } + + @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") + @WithSystemProperty(key = WorkDirectoryExtension.KEEP_WORK_DIR_PROPERTY, value = "SystemPropertiesTest.test3") + @Test + void test3(@WorkDirectory Path workDir) throws IOException { + file3 = Files.createFile(workDir.resolve("foo")); + + System.setProperty(WorkDirectoryExtension.ARTIFACT_DIR_PROPERTY, TMP_PATH); + } + } + + /** + * Test class for the {@link #testSystemPropertyWithStaticWorkDir()} test. + */ + @ExtendWith(SystemPropertiesExtension.class) + @ExtendWith(WorkDirectoryExtension.class) + @WithSystemProperty(key = WorkDirectoryExtension.KEEP_WORK_DIR_PROPERTY, value = "SystemPropertiesTestWithStaticWorkDir") + static class SystemPropertiesTestWithStaticWorkDir { + private static Path file1; + + private static Path file2; + + @WorkDirectory + static Path workDir; + + @AfterAll + static void verify() { + assertTrue(Files.exists(file1)); + assertTrue(Files.exists(file2)); + + IgniteUtils.deleteIfExists(file1.getParent()); + } + + @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") + @Test + void test1() throws IOException { + file1 = Files.createFile(workDir.resolve("foo")); + } + + @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") + @Test + void test2() throws IOException { + file2 = Files.createFile(workDir.resolve("bar")); + } } /** @@ -234,6 +297,14 @@ class WorkDirectoryExtensionTest { assertExecutesSuccessfully(SystemPropertiesTest.class); } + /** + * Tests that a static work directory can be preserved when a special system property is set. + */ + @Test + void testSystemPropertyWithStaticWorkDir() { + assertExecutesSuccessfully(SystemPropertiesTestWithStaticWorkDir.class); + } + /** * Test class for the {@link #testEmptyClass()} test. */ diff --git a/modules/core/src/testFixtures/java/org/apache/ignite/internal/testframework/WorkDirectoryExtension.java b/modules/core/src/testFixtures/java/org/apache/ignite/internal/testframework/WorkDirectoryExtension.java index 213f160d87..34c2881725 100644 --- a/modules/core/src/testFixtures/java/org/apache/ignite/internal/testframework/WorkDirectoryExtension.java +++ b/modules/core/src/testFixtures/java/org/apache/ignite/internal/testframework/WorkDirectoryExtension.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.testframework; +import static java.util.stream.Collectors.toSet; import static org.apache.ignite.internal.testframework.IgniteTestUtils.isWindowsOs; import static org.junit.jupiter.api.extension.ExtensionContext.Namespace; @@ -26,9 +27,15 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.lang.IgniteSystemProperties; import org.jetbrains.annotations.Nullable; @@ -61,8 +68,8 @@ import org.junit.platform.commons.support.HierarchyTraversalMode; * </ol> * * <p>Temporary folders are removed after tests have finished running, but this behaviour can be controlled by setting the - * {@link WorkDirectoryExtension#KEEP_WORK_DIR_PROPERTY} property to {@code true}, in which case the created folder can - * be kept intact for debugging purposes. + * {@link WorkDirectoryExtension#KEEP_WORK_DIR_PROPERTY} property. See {@link #KEEP_WORK_DIR_PROPERTY} and {@link #ARTIFACT_DIR_PROPERTY} + * for more information. */ public class WorkDirectoryExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, ParameterResolver { @@ -70,10 +77,21 @@ public class WorkDirectoryExtension private static final Namespace NAMESPACE = Namespace.create(WorkDirectoryExtension.class); /** - * System property that, when set to {@code true}, will make the extension preserve the created directories. Default is {@code false}. + * System property that can be used to provide a comma-separated list of test names whose work directories should be preserved after + * test execution. Test name consists of test class name, a dot and a test method name. In case if work directory is injected into the + * static field and is shared between different tests, only test class name should be put into the list. + * <br> + * Example: {@code "FooBarTest.test1,FooBarTest.test2,StaticWorkDirectoryFieldTest,FooBarTest.test3"}. + * Default value is {@code null}. */ public static final String KEEP_WORK_DIR_PROPERTY = "KEEP_WORK_DIR"; + /** + * System property that denotes the directory where archived work directory of the test, kept using {@link #KEEP_WORK_DIR_PROPERTY}, + * should be saved in. If defined, original work directory will be deleted. Default value is {@code null}. + */ + public static final String ARTIFACT_DIR_PROPERTY = "ARTIFACT_DIR"; + /** Base path for all temporary folders in a module. */ private static final Path BASE_PATH = getBasePath(); @@ -99,7 +117,7 @@ public class WorkDirectoryExtension /** {@inheritDoc} */ @Override public void afterAll(ExtensionContext context) throws Exception { - removeWorkDir(context); + cleanupWorkDir(context); Path testClassDir = getTestClassDir(context); @@ -133,7 +151,7 @@ public class WorkDirectoryExtension /** {@inheritDoc} */ @Override public void afterEach(ExtensionContext context) throws Exception { - removeWorkDir(context); + cleanupWorkDir(context); } /** {@inheritDoc} */ @@ -212,11 +230,69 @@ public class WorkDirectoryExtension /** * Removes a previously created work directory. */ - private static void removeWorkDir(ExtensionContext context) { + private static void cleanupWorkDir(ExtensionContext context) { Path workDir = context.getStore(NAMESPACE).remove(context.getUniqueId(), Path.class); - if (workDir != null && shouldRemoveDir()) { - IgniteUtils.deleteIfExists(workDir); + String testClassName = context.getRequiredTestClass().getSimpleName(); + + String testName = context.getTestMethod().map(method -> testClassName + "." + method.getName()).orElse(testClassName); + + if (workDir != null) { + if (shouldKeepWorkDir(testName)) { + String artifactDir = IgniteSystemProperties.getString(ARTIFACT_DIR_PROPERTY); + + if (artifactDir != null) { + Path artifactDirPath = Paths.get(artifactDir, testName + ".zip"); + + zipDirectory(workDir, artifactDirPath); + + IgniteUtils.deleteIfExists(workDir); + } + } else { + IgniteUtils.deleteIfExists(workDir); + } + } + } + + private static boolean shouldKeepWorkDir(String testName) { + String keepWorkDirStr = IgniteSystemProperties.getString(KEEP_WORK_DIR_PROPERTY); + + Set<String> keepWorkDirForTests; + + if (keepWorkDirStr != null) { + keepWorkDirForTests = Arrays.stream(keepWorkDirStr.split(",")).collect(toSet()); + } else { + keepWorkDirForTests = Collections.emptySet(); + } + + return keepWorkDirForTests.contains(testName); + } + + private static void zipDirectory(Path source, Path target) { + try { + Files.createDirectories(target.getParent()); + + Files.createFile(target); + + try (var zs = new ZipOutputStream(Files.newOutputStream(target))) { + try (Stream<Path> filesStream = Files.walk(source)) { + filesStream.filter(path -> !Files.isDirectory(path)) + .forEach(path -> { + var zipEntry = new ZipEntry(source.relativize(path).toString()); + try { + zs.putNextEntry(zipEntry); + + Files.copy(path, zs); + + zs.closeEntry(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + } + } catch (IOException e) { + throw new RuntimeException(e); } } @@ -250,13 +326,6 @@ public class WorkDirectoryExtension return fields.get(0); } - /** - * Returns {@code true} if the extension should remove the created directories. - */ - private static boolean shouldRemoveDir() { - return !IgniteSystemProperties.getBoolean(KEEP_WORK_DIR_PROPERTY); - } - /** * Returns {@code true} if the given directory is empty or {@code false} if the given directory contains files or does not exist. */
