/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch 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.opensearch.hadoop; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.file.Files; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.opensearch.hadoop.util.IOUtils; import org.opensearch.hadoop.util.OsUtil; import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.internal.AssumptionViolatedException; import org.junit.rules.TemporaryFolder; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class VersionTest { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Test public void testNormalize() throws Exception { List<URL> urls = new ArrayList<URL>(); urls.add(new URL("jar:file:/tmp/mesos/slaves/3014350f-cd05-44af-9c9c-3974bdeed86e-S1/frameworks/3014350f-cd05-44af-9c9c-3974bdeed86e-0016/executors/3014350f-cd05-44af-9c9c-3974bdeed86e-S1/runs/3697bc14-f0bd-48b9-8599-9683867eec63/opensearch-spark_2.10-2.2.0-m1.jar!/")); urls.add(new URL("jar:file:/tmp/mesos/slaves/3014350f-cd05-44af-9c9c-3974bdeed86e-S1/frameworks/3014350f-cd05-44af-9c9c-3974bdeed86e-0016/executors/3014350f-cd05-44af-9c9c-3974bdeed86e-S1/runs/3697bc14-f0bd-48b9-8599-9683867eec63/./opensearch-spark_2.10-2.2.0-m1.jar!/")); Set<String> normalized = new LinkedHashSet<String>(); for (URL url : urls) { // try normalization first String norm = IOUtils.toCanonicalFilePath(url); normalized.add(norm); } assertEquals(1, normalized.size()); } @Test public void testWindowsNormalizeCanonicalPath() throws Exception { Assume.assumeTrue("Windows Only Test", OsUtil.IS_OS_WINDOWS); // null begets null assertNull(IOUtils.toCanonicalFilePath(null)); // Windows backslashes converted to forward slashes assertEquals("file:/C:/Windows/System32/", IOUtils.toCanonicalFilePath(new File("C:\\Windows\\System32\\").toURI().toURL())); // A colon outside of the scheme should be treated as part of the path element name assertEquals("file:/C:/f/ile:/test", IOUtils.toCanonicalFilePath(new URL("file:/C:/f/ile:/test/"))); // ensure this works with backslashes too assertEquals("file:/C:/f/ile:/test", IOUtils.toCanonicalFilePath(new File("C:\\f\\ile:\\test\\").toURI().toURL())); // colon denotes a prefix for the file if no slash is in the prefix assertEquals("file:/C:/test", IOUtils.toCanonicalFilePath(new File("C:\\test\\").toURI().toURL())); // ensure this works for jar urls assertEquals("file:/C:/test", IOUtils.toCanonicalFilePath(new URL("jar:file:/C:/test/!/some/package/Hello.class"))); // Ignore dots assertEquals("file:/C:/test/test", IOUtils.toCanonicalFilePath(new URL("file:/C:/test/./test/"))); // Remove parent dots assertEquals("file:/C:/test", IOUtils.toCanonicalFilePath(new URL("file:/C:/test/test/.."))); // Windows jvm lacks the ability to link without special privileges. // FS Links are less common on Windows, so skip. } @Test public void testNormalizeCanonicalPaths() throws Exception { Assume.assumeFalse("Non Windows Test Only", OsUtil.IS_OS_WINDOWS); // null begets null assertNull(IOUtils.toCanonicalFilePath(null)); // A colon outside of the scheme should be treated as part of the path element name assertEquals("file:/f/ile:/test", IOUtils.toCanonicalFilePath(new URL("file:/f/ile:/test/"))); // colon denotes a prefix for the file if no slash is in the prefix assertEquals("file:/test", IOUtils.toCanonicalFilePath(new URL("file:/test/"))); // ensure this works for jar urls assertEquals("file:/test", IOUtils.toCanonicalFilePath(new URL("jar:file:/test/!/some/package/Hello.class"))); // Ignore dots assertEquals("file:/test/test", IOUtils.toCanonicalFilePath(new URL("file:/test/./test/"))); // Remove parent dots assertEquals("file:/test", IOUtils.toCanonicalFilePath(new URL("file:/test/test/.."))); // Create a linked directory (like Mac's /tmp dir) File linkTest = temporaryFolder.newFolder("linkTest"); File privateDir = new File(linkTest, "private"); mkdirSafe(privateDir); File privateTmpDir = new File(privateDir, "tmp"); mkdirSafe(privateTmpDir); File privateTmpOtherDir = new File(privateTmpDir, "other"); mkdirSafe(privateTmpOtherDir); File tmpDir = new File(linkTest, "tmp"); linkDir(tmpDir, privateTmpDir); // File in original directory File testFile = new File(privateTmpDir, "test"); createSafe(testFile); // Same file but in linked dir File linkedTestFile = new File(tmpDir, "test"); // Same file but referenced in an absolute, but non-canonical manner File awkwardTestFile = new File(linkTest.getAbsolutePath() + "/private/tmp/./test"); File awkwardParentTestFile = new File(linkTest.getAbsolutePath() + "/private/tmp/other/../test"); // Assert paths are different but canonical resolves as the same assertTrue(testFile.exists()); assertTrue(linkedTestFile.exists()); assertTrue(awkwardTestFile.exists()); assertTrue(awkwardParentTestFile.exists()); assertNotEquals(testFile.getAbsolutePath(), linkedTestFile.getAbsolutePath()); assertNotEquals(testFile.getAbsolutePath(), awkwardTestFile.getAbsolutePath()); assertNotEquals(testFile.getAbsolutePath(), awkwardParentTestFile.getAbsolutePath()); assertEquals(IOUtils.toCanonicalFilePath(testFile.toURI().toURL()), IOUtils.toCanonicalFilePath(linkedTestFile.toURI().toURL())); assertEquals(IOUtils.toCanonicalFilePath(testFile.toURI().toURL()), IOUtils.toCanonicalFilePath(awkwardTestFile.toURI().toURL())); assertEquals(IOUtils.toCanonicalFilePath(testFile.toURI().toURL()), IOUtils.toCanonicalFilePath(awkwardParentTestFile.toURI().toURL())); URL testURL = new URL("jar:file:" + testFile.getAbsolutePath() + "!/some/package/Hello.class"); URL linkedTestURL = new URL("jar:file:" + linkedTestFile.getAbsolutePath() + "!/some/package/Hello.class"); URL awkwardTestURL = new URL("jar:file:" + awkwardTestFile.getAbsolutePath() + "!/some/package/Hello.class"); URL awkwardParentTestURL = new URL("jar:file:" + awkwardParentTestFile.getAbsolutePath() + "!/some/package/Hello.class"); assertNotEquals(testURL.toString(), linkedTestURL.toString()); assertNotEquals(testURL.toString(), awkwardTestURL.toString()); assertNotEquals(testURL.toString(), awkwardParentTestFile.toString()); assertEquals(IOUtils.toCanonicalFilePath(testURL), IOUtils.toCanonicalFilePath(linkedTestURL)); assertEquals(IOUtils.toCanonicalFilePath(testURL), IOUtils.toCanonicalFilePath(awkwardTestURL)); assertEquals(IOUtils.toCanonicalFilePath(testURL), IOUtils.toCanonicalFilePath(awkwardParentTestURL)); } private void createSafe(File testFile) throws IOException { if (!testFile.createNewFile()) { throw new IOException("Could not create test file " + testFile.toString()); } } private void mkdirSafe(File dir) throws IOException { if (!dir.mkdirs()) { throw new IOException("Could not create " + dir + " folder"); } } private void linkDir(File tmpDir, File privateTmpDir) throws IOException { try { Files.createSymbolicLink(tmpDir.toPath(), privateTmpDir.toPath()); } catch (UnsupportedOperationException e) { throw new AssumptionViolatedException("OS does not support symlinks", e); } } }