This is an automated email from the ASF dual-hosted git repository.

sdanilov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new b1128c227e IGNITE-18970 Allow WorkDirectoryExtension to preserve work 
directories of specific tests (#1753)
b1128c227e is described below

commit b1128c227edc07489a5045c269466f6c1c544407
Author: Semyon Danilov <samvi...@yandex.ru>
AuthorDate: Tue Mar 7 14:10:20 2023 +0400

    IGNITE-18970 Allow WorkDirectoryExtension to preserve work directories of 
specific tests (#1753)
---
 .../testframework/WorkDirectoryExtensionTest.java  | 135 ++++++++++++++++++++-
 .../testframework/WorkDirectoryExtension.java      | 111 ++++++++++++++---
 2 files changed, 228 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..0ab278b651 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
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.testframework;
 
 import static 
org.apache.ignite.internal.testframework.JunitExtensionTestUtils.assertExecutesSuccessfully;
 import static 
org.apache.ignite.internal.testframework.JunitExtensionTestUtils.assertExecutesWithFailure;
+import static 
org.apache.ignite.internal.testframework.WorkDirectoryExtension.keepWorkDirPropertyValid;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.not;
@@ -31,8 +32,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 +207,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)));
 
-            Files.delete(file1);
+            IgniteUtils.deleteIfExists(file1.getParent());
+            IgniteUtils.deleteIfExists(Paths.get(TMP_PATH));
+
+            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 +244,83 @@ 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"));
+        }
+    }
+
+    /**
+     * Test class for the {@link #testSystemPropertyWithMultipleTests()} test.
+     */
+    @ExtendWith(SystemPropertiesExtension.class)
+    @ExtendWith(WorkDirectoryExtension.class)
+    @WithSystemProperty(key = WorkDirectoryExtension.KEEP_WORK_DIR_PROPERTY, 
value = "SystemPropertiesTestWithMultipleTests.test1,"
+            + "SystemPropertiesTestWithMultipleTests.test2")
+    static class SystemPropertiesTestWithMultipleTests {
+        private static Path file1;
+
+        private static Path file2;
+
+        @AfterAll
+        static void verify() {
+            assertTrue(Files.exists(file1));
+            assertTrue(Files.exists(file2));
+
+            IgniteUtils.deleteIfExists(file1.getParent());
+        }
+
+        @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
+        @Test
+        void test1(@WorkDirectory Path workDir) throws IOException {
+            file1 = Files.createFile(workDir.resolve("foo"));
+        }
+
+        @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
+        @Test
+        void test2(@WorkDirectory Path workDir) throws IOException {
+            file2 = Files.createFile(workDir.resolve("bar"));
+        }
     }
 
     /**
@@ -234,6 +331,38 @@ 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(SystemPropertiesTestWithMultipleTests.class);
+    }
+
+    /**
+     * Tests that a static work directory can be preserved when a special 
system property is set.
+     */
+    @Test
+    void testSystemPropertyWithMultipleTests() {
+        
assertExecutesSuccessfully(SystemPropertiesTestWithMultipleTests.class);
+    }
+
+    /**
+     * Tests {@link WorkDirectoryExtension#keepWorkDirPropertyValid}.
+     */
+    @Test
+    void testKeepWorkDirectoryPattern() {
+        assertTrue(keepWorkDirPropertyValid("Foo"));
+        assertTrue(keepWorkDirPropertyValid("Foo.bar"));
+        assertTrue(keepWorkDirPropertyValid("Foo,Foo"));
+        assertTrue(keepWorkDirPropertyValid("Foo.bar,Foo"));
+        assertTrue(keepWorkDirPropertyValid("Foo.bar,Foo.bar"));
+
+        assertFalse(keepWorkDirPropertyValid("Foo#bar"));
+        assertFalse(keepWorkDirPropertyValid("Foo.bar, Foo"));
+        assertFalse(keepWorkDirPropertyValid("Foo ,Foo.bar"));
+    }
+
     /**
      * 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..ef45afd5fe 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,16 @@ 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.regex.Pattern;
 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 +69,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,16 +78,30 @@ 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();
 
     /** Name of the work directory that will be injected into {@link 
BeforeAll} methods or static members. */
     private static final String STATIC_FOLDER_NAME = "static";
 
+    /** Pattern for the {@link #KEEP_WORK_DIR_PROPERTY}. */
+    private static final Pattern PATTERN = 
Pattern.compile("\\b\\w+(?:\\.\\w+)?(?:,\\b\\w+(?:\\.\\w+)?)*\\b");
+
     /**
      * Creates and injects a temporary directory into a static field.
      */
@@ -99,7 +121,7 @@ public class WorkDirectoryExtension
     /** {@inheritDoc} */
     @Override
     public void afterAll(ExtensionContext context) throws Exception {
-        removeWorkDir(context);
+        cleanupWorkDir(context);
 
         Path testClassDir = getTestClassDir(context);
 
@@ -133,7 +155,7 @@ public class WorkDirectoryExtension
     /** {@inheritDoc} */
     @Override
     public void afterEach(ExtensionContext context) throws Exception {
-        removeWorkDir(context);
+        cleanupWorkDir(context);
     }
 
     /** {@inheritDoc} */
@@ -212,11 +234,77 @@ 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) {
+            if (!keepWorkDirPropertyValid(keepWorkDirStr)) {
+                throw new IllegalArgumentException(KEEP_WORK_DIR_PROPERTY + " 
value " + keepWorkDirStr + " doesn't match pattern");
+            }
+
+            keepWorkDirForTests = 
Arrays.stream(keepWorkDirStr.split(",")).collect(toSet());
+        } else {
+            keepWorkDirForTests = Collections.emptySet();
+        }
+
+        return keepWorkDirForTests.contains(testName);
+    }
+
+    static boolean keepWorkDirPropertyValid(String property) {
+        return PATTERN.matcher(property).matches();
+    }
+
+    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 +338,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.
      */

Reply via email to