/* * 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.beam.sdk.util.gcsfs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * Tests of GcsPath. */ @RunWith(JUnit4.class) public class GcsPathTest { /** * Test case, which tests parsing and building of GcsPaths. */ static final class TestCase { final String uri; final String expectedBucket; final String expectedObject; final String[] namedComponents; TestCase(String uri, String... namedComponents) { this.uri = uri; this.expectedBucket = namedComponents[0]; this.namedComponents = namedComponents; this.expectedObject = uri.substring(expectedBucket.length() + 6); } } // Each test case is an expected URL, then the components used to build it. // Empty components result in a double slash. static final List<TestCase> PATH_TEST_CASES = Arrays.asList( new TestCase("gs://bucket/then/object", "bucket", "then", "object"), new TestCase("gs://bucket//then/object", "bucket", "", "then", "object"), new TestCase("gs://bucket/then//object", "bucket", "then", "", "object"), new TestCase("gs://bucket/then///object", "bucket", "then", "", "", "object"), new TestCase("gs://bucket/then/object/", "bucket", "then", "object/"), new TestCase("gs://bucket/then/object/", "bucket", "then/", "object/"), new TestCase("gs://bucket/then/object//", "bucket", "then", "object", ""), new TestCase("gs://bucket/then/object//", "bucket", "then", "object/", ""), new TestCase("gs://bucket/", "bucket") ); @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void testGcsPathParsing() throws Exception { for (TestCase testCase : PATH_TEST_CASES) { String uriString = testCase.uri; GcsPath path = GcsPath.fromUri(URI.create(uriString)); // Deconstruction - check bucket, object, and components. assertEquals(testCase.expectedBucket, path.getBucket()); assertEquals(testCase.expectedObject, path.getObject()); assertEquals(testCase.uri, testCase.namedComponents.length, path.getNameCount()); // Construction - check that the path can be built from components. GcsPath built = GcsPath.fromComponents(null, null); for (String component : testCase.namedComponents) { built = built.resolve(component); } assertEquals(testCase.uri, built.toString()); } } @Test public void testParentRelationship() throws Exception { GcsPath path = GcsPath.fromComponents("bucket", "then/object"); assertEquals("bucket", path.getBucket()); assertEquals("then/object", path.getObject()); assertEquals(3, path.getNameCount()); assertTrue(path.endsWith("object")); assertTrue(path.startsWith("bucket/then")); GcsPath parent = path.getParent(); // gs://bucket/then/ assertEquals("bucket", parent.getBucket()); assertEquals("then/", parent.getObject()); assertEquals(2, parent.getNameCount()); assertThat(path, Matchers.not(Matchers.equalTo(parent))); assertTrue(path.startsWith(parent)); assertFalse(parent.startsWith(path)); assertTrue(parent.endsWith("then/")); assertTrue(parent.startsWith("bucket/then")); assertTrue(parent.isAbsolute()); GcsPath root = path.getRoot(); assertEquals(0, root.getNameCount()); assertEquals("gs://", root.toString()); assertEquals("", root.getBucket()); assertEquals("", root.getObject()); assertTrue(root.isAbsolute()); assertThat(root, Matchers.equalTo(parent.getRoot())); GcsPath grandParent = parent.getParent(); // gs://bucket/ assertEquals(1, grandParent.getNameCount()); assertEquals("gs://bucket/", grandParent.toString()); assertTrue(grandParent.isAbsolute()); assertThat(root, Matchers.equalTo(grandParent.getParent())); assertThat(root.getParent(), Matchers.nullValue()); assertTrue(path.startsWith(path.getRoot())); assertTrue(parent.startsWith(path.getRoot())); } @Test public void testRelativeParent() throws Exception { GcsPath path = GcsPath.fromComponents(null, "a/b"); GcsPath parent = path.getParent(); assertEquals("a/", parent.toString()); GcsPath grandParent = parent.getParent(); assertNull(grandParent); } @Test public void testUriSupport() throws Exception { URI uri = URI.create("gs://bucket/some/path"); GcsPath path = GcsPath.fromUri(uri); assertEquals("bucket", path.getBucket()); assertEquals("some/path", path.getObject()); URI reconstructed = path.toUri(); assertEquals(uri, reconstructed); path = GcsPath.fromUri("gs://bucket"); assertEquals("gs://bucket/", path.toString()); } @Test public void testBucketParsing() throws Exception { GcsPath path = GcsPath.fromUri("gs://bucket"); GcsPath path2 = GcsPath.fromUri("gs://bucket/"); assertEquals(path, path2); assertEquals(path.toString(), path2.toString()); assertEquals(path.toUri(), path2.toUri()); } @Test public void testGcsPathToString() throws Exception { String filename = "gs://some_bucket/some/file.txt"; GcsPath path = GcsPath.fromUri(filename); assertEquals(filename, path.toString()); } @Test public void testEquals() { GcsPath a = GcsPath.fromComponents(null, "a/b/c"); GcsPath a2 = GcsPath.fromComponents(null, "a/b/c"); assertFalse(a.isAbsolute()); assertFalse(a2.isAbsolute()); GcsPath b = GcsPath.fromComponents("bucket", "a/b/c"); GcsPath b2 = GcsPath.fromComponents("bucket", "a/b/c"); assertTrue(b.isAbsolute()); assertTrue(b2.isAbsolute()); assertEquals(a, a); assertThat(a, Matchers.not(Matchers.equalTo(b))); assertThat(b, Matchers.not(Matchers.equalTo(a))); assertEquals(a, a2); assertEquals(a2, a); assertEquals(b, b2); assertEquals(b2, b); assertThat(a, Matchers.not(Matchers.equalTo(Paths.get("/tmp/foo")))); assertTrue(a != null); } @Test(expected = IllegalArgumentException.class) public void testInvalidGcsPath() { @SuppressWarnings("unused") GcsPath filename = GcsPath.fromUri("file://invalid/gcs/path"); } @Test(expected = IllegalArgumentException.class) public void testInvalidBucket() { GcsPath.fromComponents("invalid/", ""); } @Test(expected = IllegalArgumentException.class) public void testInvalidObject_newline() { GcsPath.fromComponents(null, "a\nb"); } @Test(expected = IllegalArgumentException.class) public void testInvalidObject_cr() { GcsPath.fromComponents(null, "a\rb"); } @Test public void testResolveUri() { GcsPath path = GcsPath.fromComponents("bucket", "a/b/c"); GcsPath d = path.resolve("gs://bucket2/d"); assertEquals("gs://bucket2/d", d.toString()); } @Test public void testResolveOther() { GcsPath a = GcsPath.fromComponents("bucket", "a"); GcsPath b = a.resolve(Paths.get("b")); assertEquals("a/b", b.getObject()); } @Test public void testGetFileName() { assertEquals("foo", GcsPath.fromUri("gs://bucket/bar/foo").getFileName().toString()); assertEquals("foo", GcsPath.fromUri("gs://bucket/foo").getFileName().toString()); thrown.expect(UnsupportedOperationException.class); GcsPath.fromUri("gs://bucket/").getFileName(); } @Test public void testResolveSibling() { assertEquals( "gs://bucket/bar/moo", GcsPath.fromUri("gs://bucket/bar/foo").resolveSibling("moo").toString()); assertEquals( "gs://bucket/moo", GcsPath.fromUri("gs://bucket/foo").resolveSibling("moo").toString()); thrown.expect(UnsupportedOperationException.class); GcsPath.fromUri("gs://bucket/").resolveSibling("moo"); } @Test public void testCompareTo() { GcsPath a = GcsPath.fromComponents("bucket", "a"); GcsPath b = GcsPath.fromComponents("bucket", "b"); GcsPath b2 = GcsPath.fromComponents("bucket2", "b"); GcsPath brel = GcsPath.fromComponents(null, "b"); GcsPath a2 = GcsPath.fromComponents("bucket", "a"); GcsPath arel = GcsPath.fromComponents(null, "a"); assertThat(a.compareTo(b), Matchers.lessThan(0)); assertThat(b.compareTo(a), Matchers.greaterThan(0)); assertThat(a.compareTo(a2), Matchers.equalTo(0)); assertThat(a.hashCode(), Matchers.equalTo(a2.hashCode())); assertThat(a.hashCode(), Matchers.not(Matchers.equalTo(b.hashCode()))); assertThat(b.hashCode(), Matchers.not(Matchers.equalTo(brel.hashCode()))); assertThat(brel.compareTo(b), Matchers.lessThan(0)); assertThat(b.compareTo(brel), Matchers.greaterThan(0)); assertThat(arel.compareTo(brel), Matchers.lessThan(0)); assertThat(brel.compareTo(arel), Matchers.greaterThan(0)); assertThat(b.compareTo(b2), Matchers.lessThan(0)); assertThat(b2.compareTo(b), Matchers.greaterThan(0)); } @Test public void testCompareTo_ordering() { GcsPath ab = GcsPath.fromComponents("bucket", "a/b"); GcsPath abc = GcsPath.fromComponents("bucket", "a/b/c"); GcsPath a1b = GcsPath.fromComponents("bucket", "a-1/b"); assertThat(ab.compareTo(a1b), Matchers.lessThan(0)); assertThat(a1b.compareTo(ab), Matchers.greaterThan(0)); assertThat(ab.compareTo(abc), Matchers.lessThan(0)); assertThat(abc.compareTo(ab), Matchers.greaterThan(0)); } @Test public void testCompareTo_buckets() { GcsPath a = GcsPath.fromComponents(null, "a/b/c"); GcsPath b = GcsPath.fromComponents("bucket", "a/b/c"); assertThat(a.compareTo(b), Matchers.lessThan(0)); assertThat(b.compareTo(a), Matchers.greaterThan(0)); } @Test public void testIterator() { GcsPath a = GcsPath.fromComponents("bucket", "a/b/c"); Iterator<Path> it = a.iterator(); assertTrue(it.hasNext()); assertEquals("gs://bucket/", it.next().toString()); assertTrue(it.hasNext()); assertEquals("a", it.next().toString()); assertTrue(it.hasNext()); assertEquals("b", it.next().toString()); assertTrue(it.hasNext()); assertEquals("c", it.next().toString()); assertFalse(it.hasNext()); } @Test public void testSubpath() { GcsPath a = GcsPath.fromComponents("bucket", "a/b/c/d"); assertThat(a.subpath(0, 1).toString(), Matchers.equalTo("gs://bucket/")); assertThat(a.subpath(0, 2).toString(), Matchers.equalTo("gs://bucket/a")); assertThat(a.subpath(0, 3).toString(), Matchers.equalTo("gs://bucket/a/b")); assertThat(a.subpath(0, 4).toString(), Matchers.equalTo("gs://bucket/a/b/c")); assertThat(a.subpath(1, 2).toString(), Matchers.equalTo("a")); assertThat(a.subpath(2, 3).toString(), Matchers.equalTo("b")); assertThat(a.subpath(2, 4).toString(), Matchers.equalTo("b/c")); assertThat(a.subpath(2, 5).toString(), Matchers.equalTo("b/c/d")); } @Test public void testGetName() { GcsPath a = GcsPath.fromComponents("bucket", "a/b/c/d"); assertEquals(5, a.getNameCount()); assertThat(a.getName(0).toString(), Matchers.equalTo("gs://bucket/")); assertThat(a.getName(1).toString(), Matchers.equalTo("a")); assertThat(a.getName(2).toString(), Matchers.equalTo("b")); assertThat(a.getName(3).toString(), Matchers.equalTo("c")); assertThat(a.getName(4).toString(), Matchers.equalTo("d")); } @Test(expected = IllegalArgumentException.class) public void testSubPathError() { GcsPath a = GcsPath.fromComponents("bucket", "a/b/c/d"); a.subpath(1, 1); // throws IllegalArgumentException Assert.fail(); } }