/* * Copyright 2013 Cloudera. * * Licensed 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.kitesdk.data.spi; import com.google.common.collect.Maps; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.kitesdk.data.TestHelpers; public class TestURIPattern { private Map<String, String> expected = null; @Before public void setup() { expected = Maps.newHashMap(); } @Test public void testNonAbsoluteExactMatch() throws URISyntaxException { URIPattern pattern = new URIPattern("hive"); String uri = "hive"; Assert.assertTrue(pattern.matches(uri)); } @Test public void testSubURI() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme:*sub-uri"); String uri = "scheme:other-scheme:/path/to/data.avro"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); expected.put("sub-uri", "other-scheme:/path/to/data.avro"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testStaticMatch() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme:static"); String uri = "scheme:static"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testPathGlob() throws URISyntaxException { URIPattern pattern = new URIPattern("file:///*path"); String uri = "file:/path/to/data.avro"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "file"); expected.put("path", "path/to/data.avro"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testPathVariables() throws URISyntaxException { URIPattern pattern = new URIPattern("mysql:/:db/:table"); String uri = "mysql:/myDB/myTable"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "mysql"); expected.put("db", "myDB"); expected.put("table", "myTable"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testEmptyPath() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme://authority"); String uri = "scheme://real-authority"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); expected.put("auth:host", "real-authority"); Assert.assertEquals(expected, actual); // should not match any path element or fragment Assert.assertFalse(pattern.matches(uri + "/")); Assert.assertFalse(pattern.matches("scheme:/")); Assert.assertFalse(pattern.matches(uri + "/abc")); Assert.assertFalse(pattern.matches(uri + "#fragment")); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testStaticPathStart() throws URISyntaxException { URIPattern pattern = new URIPattern("mysql:/required/:db/:table"); String uri = "mysql:/required/myDB/myTable"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "mysql"); expected.put("db", "myDB"); expected.put("table", "myTable"); Assert.assertEquals(expected, actual); Assert.assertNull(pattern.getMatch("mysql:/myDB/myTable")); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testStaticPathMixed() throws URISyntaxException { URIPattern pattern = new URIPattern("mysql:/db/:db/table/:table"); String uri = "mysql:/db/myDB/table/myTable"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "mysql"); expected.put("db", "myDB"); expected.put("table", "myTable"); Assert.assertEquals(expected, actual); Assert.assertNull(pattern.getMatch("mysql:/myDB/myTable")); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testStaticPathEnd() throws URISyntaxException { URIPattern pattern = new URIPattern("mysql:/:db/:table/wtf"); String uri = "mysql:/myDB/myTable/wtf"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "mysql"); expected.put("db", "myDB"); expected.put("table", "myTable"); Assert.assertEquals(expected, actual); Assert.assertNull(pattern.getMatch("mysql:/myDB/myTable")); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testIgnoreTrailingSlash() throws URISyntaxException { URIPattern pattern = new URIPattern("mysql:/:db/:table"); String uri = "mysql:/myDB/myTable/"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "mysql"); expected.put("db", "myDB"); expected.put("table", "myTable"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create("mysql:/myDB/myTable"), constructed); } @Test public void testPathVariablesWithGlob() throws URISyntaxException { URIPattern pattern = new URIPattern("mysql:/:db/:table/*the-rest"); String uri = "mysql:/myDB/myTable/a/b/c"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "mysql"); expected.put("db", "myDB"); expected.put("table", "myTable"); expected.put("the-rest", "a/b/c"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testPathVariablesAfterGlob() throws URISyntaxException { URIPattern pattern = new URIPattern("file:/*path/:ns/:ds"); String uri = "file:/a/b/c/namespace/dataset"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "file"); expected.put("ns", "namespace"); expected.put("ds", "dataset"); expected.put("path", "a/b/c"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testOpaquePathVariablesAfterGlob() throws URISyntaxException { URIPattern pattern = new URIPattern("file:*path/:ns/:ds"); String uri = "file:a/b/c/namespace/dataset"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "file"); expected.put("ns", "namespace"); expected.put("ds", "dataset"); expected.put("path", "a/b/c"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testPathVariablesBeforeAndAfterGlob() throws URISyntaxException { URIPattern pattern = new URIPattern("file:/:ns/*path/:ds"); String uri = "file:/namespace/a/b/c/dataset"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "file"); expected.put("ns", "namespace"); expected.put("ds", "dataset"); expected.put("path", "a/b/c"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testOpaquePathVariablesBeforeAndAfterGlob() throws URISyntaxException { URIPattern pattern = new URIPattern("file::ns/*path/:ds"); String uri = "file:namespace/a/b/c/dataset"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "file"); expected.put("ns", "namespace"); expected.put("ds", "dataset"); expected.put("path", "a/b/c"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testDefaultAuthority() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme://user:pass:w0rd@host:3434/*path"); String uri = "scheme:/path/to/data.avro"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); expected.put("auth:host", "host"); expected.put("auth:port", "3434"); expected.put("auth:username", "user"); expected.put("auth:password", "pass:w0rd"); expected.put("path", "path/to/data.avro"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testOverrideAuthority() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme://user:pass:w0rd@host:3434/*path"); String uri = "scheme://other:3435/path/to/data.avro"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); expected.put("auth:host", "other"); expected.put("auth:port", "3435"); expected.put("auth:username", "user"); expected.put("auth:password", "pass:w0rd"); expected.put("path", "path/to/data.avro"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testDefaultQueryArgs() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme:/*path?custom-option=true&use-ssl=false&encoded=a%2Cb"); String uri = "scheme:/path/to/data.avro"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); expected.put("path", "path/to/data.avro"); expected.put("custom-option", "true"); expected.put("use-ssl", "false"); expected.put("encoded", "a%2Cb"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testOpaqueDefaultQueryArgs() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme:*path?custom-option=true&use-ssl=false"); String uri = "scheme:path/to/data.avro"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); expected.put("path", "path/to/data.avro"); expected.put("custom-option", "true"); expected.put("use-ssl", "false"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testOverrideQueryArgs() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme:/*path?custom-option=true&use-ssl=false"); String uri = "scheme:/path/to/data.avro?use-ssl=true"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); expected.put("path", "path/to/data.avro"); expected.put("custom-option", "true"); expected.put("use-ssl", "true"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testOpaqueOverrideQueryArgs() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme:*path?custom-option=true&use-ssl=false"); String uri = "scheme:path/to/data.avro?use-ssl=true"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "scheme"); expected.put("path", "path/to/data.avro"); expected.put("custom-option", "true"); expected.put("use-ssl", "true"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testMixed() throws URISyntaxException { URIPattern pattern = new URIPattern( "mysql://cloudera:cloudera@db-host:3434/:db/:table/*the-rest?custom-option=true&use-ssl=false"); String uri = "mysql://real-db-host/my-db/my-table?use-ssl=true"; Assert.assertTrue(pattern.matches(uri)); Map<String, String> actual = pattern.getMatch(uri); expected.put("uri:scheme", "mysql"); expected.put("auth:host", "real-db-host"); expected.put("auth:port", "3434"); expected.put("auth:username", "cloudera"); expected.put("auth:password", "cloudera"); expected.put("db", "my-db"); expected.put("table", "my-table"); expected.put("custom-option", "true"); expected.put("use-ssl", "true"); Assert.assertEquals(expected, actual); URI constructed = pattern.construct(expected); Assert.assertEquals(URI.create(uri), constructed); } @Test public void testConstructMissingOptions() throws URISyntaxException { final URIPattern pattern = new URIPattern("scheme:/*path/:name"); TestHelpers.assertThrows("Should reject missing name", IllegalArgumentException.class, new Runnable() { @Override public void run() { Map<String, String> options = Maps.newHashMap(); options.put("path", "a/b/c"); pattern.construct(options); } }); // globs are optional Map<String, String> options = Maps.newHashMap(); options.put("name", "table-name"); URI constructed = pattern.construct(options); Assert.assertEquals(URI.create("scheme:/table-name"), constructed); } @Test public void testNotEnoughPathComponents() throws URISyntaxException { URIPattern pattern = new URIPattern("scheme:*path/:ns/:name"); Assert.assertFalse(pattern.matches("scheme://host:3434/dataset")); } @Test public void testEmptyGlobs() throws URISyntaxException { URIPattern pattern = new URIPattern("file:/a/*path"); Map<String, String> match = pattern.getMatch("file:/a"); Assert.assertNotNull(match); Assert.assertNull(match.get("path")); match = pattern.getMatch("file:/a/"); Assert.assertNotNull(match); Assert.assertEquals("", match.get("path")); match = pattern.getMatch("file:/a//"); Assert.assertNotNull(match); Assert.assertEquals("/", match.get("path")); pattern = new URIPattern("file:/a/*path/:dataset"); match = pattern.getMatch("file:/a//dataset"); Assert.assertNotNull(match); Assert.assertEquals("", match.get("path")); match = pattern.getMatch("file:/a/dataset"); Assert.assertNotNull(match); Assert.assertNull(match.get("path")); pattern = new URIPattern("file:/*path"); match = pattern.getMatch("file:/"); Assert.assertNotNull(match); Assert.assertNull(match.get("path")); } @Test public void testQueryEncoding() throws URISyntaxException { URIPattern pattern = new URIPattern("file:/path"); URI original = URI.create("file:/path?f1=a,b,a%2Cb"); Map<String, String> match = pattern.getMatch(original); Assert.assertNotNull(match); Assert.assertEquals("a,b,a%2Cb", match.get("f1")); URI constructed = pattern.construct(match); Assert.assertEquals(original, constructed); } @Test public void testOpaqueQueryEncoding() throws URISyntaxException { URIPattern pattern = new URIPattern("file:path"); URI original = URI.create("file:path?f1=a,b,a%2Cb"); Map<String, String> match = pattern.getMatch(original); Assert.assertNotNull(match); Assert.assertEquals("a,b,a%2Cb", match.get("f1")); URI constructed = pattern.construct(match); Assert.assertEquals(original, constructed); } @Test public void testPathEncoding() throws URISyntaxException { URIPattern pattern = new URIPattern("file:/*path"); URI original = URI.create("file:/a%2Fb/c"); Map<String, String> match = pattern.getMatch(original); Assert.assertNotNull(match); Assert.assertEquals("a%2Fb/c", match.get("path")); URI constructed = pattern.construct(match); Assert.assertEquals(original, constructed); } @Test public void testOpaquePathEncoding() throws URISyntaxException { URIPattern pattern = new URIPattern("file:*path"); URI original = URI.create("file:a%2Fb/c"); Map<String, String> match = pattern.getMatch(original); Assert.assertNotNull(match); Assert.assertEquals("a%2Fb/c", match.get("path")); URI constructed = pattern.construct(match); Assert.assertEquals(original, constructed); } // This is common in this type of matching, but the query part prevents it // @Test // public void testPathVariablesOptional() throws URISyntaxException { // URIPattern pattern = new URIPattern("mysql:/:db/:table?"); // String uri = "mysql:/myDB/myTable"; // Assert.assertTrue(pattern.matches(uri)); // Map<String, String> actual = pattern.getMatch(uri); // expected.put("db", "myDB"); // expected.put("table", "myTable"); // Assert.assertEquals(expected, actual); // // uri = "mysql:/myDB"; // Assert.assertTrue(pattern.matches(uri)); // actual = pattern.getMatch(uri); // expected.put("scheme", "mysql"); // expected.put("db", "myDB"); // expected.put("table", "myTable"); // Assert.assertEquals(expected, actual); // } }