You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by ch...@apache.org on 2022/09/15 10:31:21 UTC

[flink] 01/02: [FLINK-29287][tests] Add PackagingTestUtils

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

chesnay pushed a commit to branch release-1.16
in repository https://gitbox.apache.org/repos/asf/flink.git

commit c4d254a92a2346a5d29da9f41c4df0022d6c2f36
Author: Chesnay Schepler <ch...@apache.org>
AuthorDate: Tue Sep 13 18:26:15 2022 +0200

    [FLINK-29287][tests] Add PackagingTestUtils
---
 .../apache/flink/packaging/PackagingTestUtils.java | 104 ++++++++++++++++
 .../flink/packaging/PackagingTestUtilsTest.java    | 134 +++++++++++++++++++++
 2 files changed, 238 insertions(+)

diff --git a/flink-test-utils-parent/flink-test-utils/src/main/java/org/apache/flink/packaging/PackagingTestUtils.java b/flink-test-utils-parent/flink-test-utils/src/main/java/org/apache/flink/packaging/PackagingTestUtils.java
new file mode 100644
index 00000000000..69cc2faa4ca
--- /dev/null
+++ b/flink-test-utils-parent/flink-test-utils/src/main/java/org/apache/flink/packaging/PackagingTestUtils.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.packaging;
+
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Test utils around jar packaging. */
+public class PackagingTestUtils {
+
+    /**
+     * Verifies that all files in the jar match one of the provided allow strings.
+     *
+     * <p>An allow item ending on a {@code "/"} is treated as an allowed parent directory.
+     * Otherwise, it is treated as an allowed file.
+     *
+     * <p>For example, given a jar containing a file {@code META-INF/NOTICES}:
+     *
+     * <p>These would pass:
+     *
+     * <ul>
+     *   <li>{@code "META-INF/"}
+     *   <li>{@code "META-INF/NOTICES"}
+     * </ul>
+     *
+     * <p>These would fail:
+     *
+     * <ul>
+     *   <li>{@code "META-INF"}
+     *   <li>{@code "META-INF/NOTICE"}
+     *   <li>{@code "META-INF/NOTICES/"}
+     * </ul>
+     */
+    public static void assertJarContainsOnlyFilesMatching(
+            Path jarPath, Collection<String> allowedPaths) throws Exception {
+        final URI jar = jarPath.toUri();
+
+        try (final FileSystem fileSystem =
+                FileSystems.newFileSystem(
+                        new URI("jar:file", jar.getHost(), jar.getPath(), jar.getFragment()),
+                        Collections.emptyMap())) {
+            try (Stream<Path> walk = Files.walk(fileSystem.getPath("/"))) {
+                walk.filter(file -> !Files.isDirectory(file))
+                        .map(file -> file.toAbsolutePath().toString())
+                        .map(file -> file.startsWith("/") ? file.substring(1) : file)
+                        .forEach(
+                                file ->
+                                        assertThat(allowedPaths)
+                                                .as("Bad file in JAR: %s", file)
+                                                .anySatisfy(
+                                                        allowedPath -> {
+                                                            if (allowedPath.endsWith("/")) {
+                                                                assertThat(file)
+                                                                        .startsWith(allowedPath);
+                                                            } else {
+                                                                assertThat(file)
+                                                                        .isEqualTo(allowedPath);
+                                                            }
+                                                        }));
+            }
+        }
+    }
+
+    /**
+     * Verifies that the given jar contains a service entry file for the given service.
+     *
+     * <p>Caution: This only checks that the file exists; the content is not verified.
+     */
+    public static void assertJarContainsServiceEntry(Path jarPath, Class<?> service)
+            throws Exception {
+        final URI jar = jarPath.toUri();
+
+        try (final FileSystem fileSystem =
+                FileSystems.newFileSystem(
+                        new URI("jar:file", jar.getHost(), jar.getPath(), jar.getFragment()),
+                        Collections.emptyMap())) {
+            assertThat(fileSystem.getPath("META-INF", "services", service.getName())).exists();
+        }
+    }
+}
diff --git a/flink-test-utils-parent/flink-test-utils/src/test/java/org/apache/flink/packaging/PackagingTestUtilsTest.java b/flink-test-utils-parent/flink-test-utils/src/test/java/org/apache/flink/packaging/PackagingTestUtilsTest.java
new file mode 100644
index 00000000000..451693c38dd
--- /dev/null
+++ b/flink-test-utils-parent/flink-test-utils/src/test/java/org/apache/flink/packaging/PackagingTestUtilsTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.packaging;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class PackagingTestUtilsTest {
+
+    @Test
+    void testAssertJarContainsOnlyFilesMatching(@TempDir Path tmp) throws Exception {
+        Path jar = createJar(tmp, Entry.fileEntry("", Arrays.asList("META-INF", "NOTICES")));
+
+        PackagingTestUtils.assertJarContainsOnlyFilesMatching(
+                jar, Collections.singleton("META-INF/"));
+        PackagingTestUtils.assertJarContainsOnlyFilesMatching(
+                jar, Collections.singleton("META-INF/NOTICES"));
+
+        assertThatThrownBy(
+                        () ->
+                                PackagingTestUtils.assertJarContainsOnlyFilesMatching(
+                                        jar, Collections.singleton("META-INF")))
+                .isInstanceOf(AssertionError.class);
+        assertThatThrownBy(
+                        () ->
+                                PackagingTestUtils.assertJarContainsOnlyFilesMatching(
+                                        jar, Collections.singleton("META-INF/NOTICE")))
+                .isInstanceOf(AssertionError.class);
+        assertThatThrownBy(
+                        () ->
+                                PackagingTestUtils.assertJarContainsOnlyFilesMatching(
+                                        jar, Collections.singleton("META-INF/NOTICES/")))
+                .isInstanceOf(AssertionError.class);
+    }
+
+    @Test
+    void testAssertJarContainsServiceEntry(@TempDir Path tmp) throws Exception {
+        final String service = PackagingTestUtilsTest.class.getName();
+        Path jar =
+                createJar(tmp, Entry.fileEntry("", Arrays.asList("META-INF", "services", service)));
+
+        PackagingTestUtils.assertJarContainsServiceEntry(jar, PackagingTestUtilsTest.class);
+
+        assertThatThrownBy(
+                        () ->
+                                PackagingTestUtils.assertJarContainsServiceEntry(
+                                        jar, PackagingTestUtils.class))
+                .isInstanceOf(AssertionError.class);
+    }
+
+    private static class Entry {
+        final String contents;
+        final List<String> path;
+        final boolean isDirectory;
+
+        public static Entry directoryEntry(List<String> path) {
+            return new Entry("", path, true);
+        }
+
+        public static Entry fileEntry(String contents, List<String> path) {
+            return new Entry(contents, path, false);
+        }
+
+        private Entry(String contents, List<String> path, boolean isDirectory) {
+            this.contents = contents;
+            this.path = path;
+            this.isDirectory = isDirectory;
+        }
+    }
+
+    private static Path createJar(Path tempDir, Entry... entries) throws Exception {
+        final Path path = tempDir.resolve(UUID.randomUUID().toString() + ".jar");
+
+        final URI uri = path.toUri();
+
+        final URI jarUri = new URI("jar:file", uri.getHost(), uri.getPath(), uri.getFragment());
+
+        // causes FileSystems#newFileSystem to automatically create a valid zip file
+        // this is easier than manually creating a valid empty zip file manually
+        final Map<String, String> env = new HashMap<>();
+        env.put("create", "true");
+
+        try (FileSystem zip = FileSystems.newFileSystem(jarUri, env)) {
+            // shortcut to getting the single root
+            final Path root = zip.getPath("/");
+            for (Entry entry : entries) {
+                final Path zipPath =
+                        root.resolve(
+                                zip.getPath(
+                                        entry.path.get(0),
+                                        entry.path
+                                                .subList(1, entry.path.size())
+                                                .toArray(new String[] {})));
+                if (entry.isDirectory) {
+                    Files.createDirectories(zipPath);
+                } else {
+                    Files.createDirectories(zipPath.getParent());
+                    Files.write(zipPath, entry.contents.getBytes());
+                }
+            }
+        }
+        return path;
+    }
+}