[ https://issues.apache.org/jira/browse/DRILL-6272?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16473231#comment-16473231 ]
ASF GitHub Bot commented on DRILL-6272: --------------------------------------- amansinha100 closed pull request #1225: DRILL-6272: Refactor dynamic UDFs and function initializer tests to g… URL: https://github.com/apache/drill/pull/1225 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/common/src/test/java/org/apache/drill/test/TestTools.java b/common/src/test/java/org/apache/drill/test/TestTools.java index 8cf7ca7c42..2735c54379 100644 --- a/common/src/test/java/org/apache/drill/test/TestTools.java +++ b/common/src/test/java/org/apache/drill/test/TestTools.java @@ -47,7 +47,7 @@ .indexOf("-agentlib:jdwp") > 0; public static TestRule getTimeoutRule(int timeout) { - return IS_DEBUG ? new TestName() : new Timeout(timeout); + return IS_DEBUG ? new TestName() : Timeout.millis(timeout); } /** diff --git a/exec/java-exec/pom.xml b/exec/java-exec/pom.xml index cbc3a02aa6..345e240143 100644 --- a/exec/java-exec/pom.xml +++ b/exec/java-exec/pom.xml @@ -584,6 +584,54 @@ <artifactId>netty-tcnative</artifactId> <classifier>${netty.tcnative.classifier}</classifier> </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-embedder</artifactId> + <version>3.5.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-compat</artifactId> + <version>3.5.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.aether</groupId> + <artifactId>aether-connector-basic</artifactId> + <version>1.1.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.aether</groupId> + <artifactId>aether-transport-wagon</artifactId> + <version>1.1.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.maven.wagon</groupId> + <artifactId>wagon-http</artifactId> + <version>3.0.0</version> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.maven.wagon</groupId> + <artifactId>wagon-provider-api</artifactId> + <version>3.0.0</version> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </exclusion> + </exclusions> + </dependency> </dependencies> <profiles> diff --git a/exec/java-exec/src/test/java/org/apache/drill/TestTpchDistributedConcurrent.java b/exec/java-exec/src/test/java/org/apache/drill/TestTpchDistributedConcurrent.java index 8991b8b10a..74b9a5ceb6 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/TestTpchDistributedConcurrent.java +++ b/exec/java-exec/src/test/java/org/apache/drill/TestTpchDistributedConcurrent.java @@ -33,6 +33,7 @@ import org.apache.drill.test.BaseTestQuery; import org.apache.drill.test.QueryTestUtil; import org.junit.Rule; +import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TestRule; @@ -176,7 +177,7 @@ public void run() { } } - //@Test + @Test public void testConcurrentQueries() throws Exception { QueryTestUtil.testRunAndPrint(client, UserBitShared.QueryType.SQL, alterSession); diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/coord/zk/TestZookeeperClient.java b/exec/java-exec/src/test/java/org/apache/drill/exec/coord/zk/TestZookeeperClient.java index 87cf72d30f..e0e6c79905 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/coord/zk/TestZookeeperClient.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/coord/zk/TestZookeeperClient.java @@ -125,7 +125,7 @@ public void testHasPathThrowsDrillRuntimeException() { Mockito .when(client.getCache().getCurrentData(absPath)) - .thenThrow(Exception.class); + .thenThrow(RuntimeException.class); client.hasPath(path); } diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/expr/fn/FunctionInitializerTest.java b/exec/java-exec/src/test/java/org/apache/drill/exec/expr/fn/FunctionInitializerTest.java index 7c10bd3ca9..2ecb8a0c75 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/expr/fn/FunctionInitializerTest.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/expr/fn/FunctionInitializerTest.java @@ -19,20 +19,20 @@ import com.google.common.collect.Lists; import org.apache.drill.categories.SqlFunctionTest; -import org.apache.drill.test.TestTools; +import org.apache.drill.exec.udf.dynamic.JarBuilder; import org.apache.drill.exec.util.JarUtil; import org.codehaus.janino.Java.CompilationUnit; import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; +import org.junit.rules.TemporaryFolder; +import java.io.File; +import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; -import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -45,25 +45,27 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; -@RunWith(MockitoJUnitRunner.class) @Category(SqlFunctionTest.class) public class FunctionInitializerTest { - private static final String CLASS_NAME = "com.drill.udf.CustomLowerFunction"; + @ClassRule + public static final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private static final String CLASS_NAME = "org.apache.drill.udf.dynamic.CustomLowerFunction"; private static URLClassLoader classLoader; @BeforeClass public static void init() throws Exception { - Path jars = TestTools.WORKING_PATH - .resolve(TestTools.TEST_RESOURCES_REL) - .resolve("jars"); - String binaryName = "DrillUDF-1.0.jar"; - String sourceName = JarUtil.getSourceName(binaryName); - URL[] urls = {jars.resolve(binaryName).toUri().toURL(), jars.resolve(sourceName).toUri().toURL()}; + File buildDirectory = temporaryFolder.getRoot(); + String binaryName = "drill-custom-lower"; + + JarBuilder jarBuilder = new JarBuilder("src/test/resources/drill-udf"); + String binaryJar = jarBuilder.build(binaryName, buildDirectory.getAbsolutePath(), "**/CustomLowerFunction.java", null); + + URL[] urls = { + Paths.get(buildDirectory.getPath(), binaryJar).toUri().toURL(), + Paths.get(buildDirectory.getPath(), JarUtil.getSourceName(binaryJar)).toUri().toURL()}; classLoader = new URLClassLoader(urls); } @@ -94,27 +96,21 @@ public void testGetMethod() { @Test public void testConcurrentFunctionBodyLoad() throws Exception { - final FunctionInitializer spyFunctionInitializer = spy(new FunctionInitializer(CLASS_NAME, classLoader)); final AtomicInteger counter = new AtomicInteger(); - - doAnswer(new Answer<CompilationUnit>() { + final FunctionInitializer functionInitializer = new FunctionInitializer(CLASS_NAME, classLoader) { @Override - public CompilationUnit answer(InvocationOnMock invocation) throws Throwable { + CompilationUnit convertToCompilationUnit(Class<?> clazz) throws IOException { counter.incrementAndGet(); - return (CompilationUnit) invocation.callRealMethod(); + return super.convertToCompilationUnit(clazz); } - }).when(spyFunctionInitializer).convertToCompilationUnit(any(Class.class)); + }; int threadsNumber = 5; ExecutorService executor = Executors.newFixedThreadPool(threadsNumber); try { - List<Future<String>> results = executor.invokeAll(Collections.nCopies(threadsNumber, new Callable<String>() { - @Override - public String call() { - return spyFunctionInitializer.getMethod("eval"); - } - })); + List<Future<String>> results = executor.invokeAll(Collections.nCopies(threadsNumber, + (Callable<String>) () -> functionInitializer.getMethod("eval"))); final Set<String> uniqueResults = new HashSet<>(); for (Future<String> result : results) { diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/rpc/user/TemporaryTablesAutomaticDropTest.java b/exec/java-exec/src/test/java/org/apache/drill/exec/rpc/user/TemporaryTablesAutomaticDropTest.java index 5553519db3..5aef6f7628 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/rpc/user/TemporaryTablesAutomaticDropTest.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/rpc/user/TemporaryTablesAutomaticDropTest.java @@ -19,39 +19,40 @@ import mockit.Mock; import mockit.MockUp; +import org.apache.drill.exec.store.StorageStrategy; import org.apache.drill.test.BaseTestQuery; import org.apache.drill.common.config.DrillConfig; -import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.store.StoragePluginRegistry; import org.apache.drill.exec.util.StoragePluginTestUtils; import org.apache.drill.test.DirTestWatcher; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.LocatedFileStatus; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.RemoteIterator; import org.junit.Before; import org.junit.Test; import java.io.File; -import java.util.Properties; import java.util.UUID; import static org.apache.drill.exec.util.StoragePluginTestUtils.DFS_TMP_SCHEMA; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class TemporaryTablesAutomaticDropTest extends BaseTestQuery { - private static final String session_id = "sessionId"; + private static final UUID SESSION_UUID = UUID.randomUUID(); @Before - public void setup() throws Exception { + public void setup() { new MockUp<UUID>() { @Mock public UUID randomUUID() { - return UUID.nameUUIDFromBytes(session_id.getBytes()); + return SESSION_UUID; } }; - - Properties testConfigurations = cloneDefaultTestConfigProperties(); - testConfigurations.put(ExecConstants.DEFAULT_TEMPORARY_WORKSPACE, DFS_TMP_SCHEMA); - updateTestCluster(1, DrillConfig.create(testConfigurations)); + updateTestCluster(1, DrillConfig.create(cloneDefaultTestConfigProperties())); } @Test @@ -90,14 +91,25 @@ public void testAutomaticDropOfSeveralSessionTemporaryLocations() throws Excepti } private File createAndCheckSessionTemporaryLocation(String suffix, File schemaLocation) throws Exception { - final String temporaryTableName = "temporary_table_automatic_drop_" + suffix; - final File sessionTemporaryLocation = schemaLocation - .toPath() - .resolve(UUID.nameUUIDFromBytes(session_id.getBytes()).toString()) - .toFile(); + String temporaryTableName = "temporary_table_automatic_drop_" + suffix; + File sessionTemporaryLocation = schemaLocation.toPath().resolve(SESSION_UUID.toString()).toFile(); test("create TEMPORARY table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); - assertTrue("Session temporary location should exist", sessionTemporaryLocation.exists()); + + FileSystem fs = getLocalFileSystem(); + Path sessionPath = new Path(sessionTemporaryLocation.getAbsolutePath()); + assertTrue("Session temporary location should exist", fs.exists(sessionPath)); + assertEquals("Directory permission should match", + StorageStrategy.TEMPORARY.getFolderPermission(), fs.getFileStatus(sessionPath).getPermission()); + Path tempTablePath = new Path(sessionPath, SESSION_UUID.toString()); + assertTrue("Temporary table location should exist", fs.exists(tempTablePath)); + assertEquals("Directory permission should match", + StorageStrategy.TEMPORARY.getFolderPermission(), fs.getFileStatus(tempTablePath).getPermission()); + RemoteIterator<LocatedFileStatus> fileIterator = fs.listFiles(tempTablePath, false); + while (fileIterator.hasNext()) { + LocatedFileStatus file = fileIterator.next(); + assertEquals("File permission should match", StorageStrategy.TEMPORARY.getFilePermission(), file.getPermission()); + } return sessionTemporaryLocation; } } diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/sql/TestCTTAS.java b/exec/java-exec/src/test/java/org/apache/drill/exec/sql/TestCTTAS.java index 318e4c95d3..f2c0c82439 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/sql/TestCTTAS.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/sql/TestCTTAS.java @@ -18,78 +18,42 @@ package org.apache.drill.exec.sql; import com.google.common.collect.Lists; -import mockit.Mock; -import mockit.MockUp; import org.apache.drill.exec.store.StoragePluginRegistry; import org.apache.drill.exec.store.dfs.FileSystemConfig; import org.apache.drill.exec.store.dfs.WorkspaceConfig; import org.apache.drill.test.BaseTestQuery; import org.apache.drill.categories.SqlTest; -import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.UserRemoteException; -import org.apache.drill.exec.ExecConstants; -import org.apache.drill.exec.store.StorageStrategy; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.fs.LocatedFileStatus; -import org.apache.hadoop.fs.Path; -import org.apache.hadoop.fs.RemoteIterator; -import org.apache.hadoop.fs.permission.FsPermission; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; import java.io.File; -import java.io.IOException; import java.nio.file.Paths; import java.util.List; -import java.util.Properties; -import java.util.UUID; import static org.apache.drill.exec.util.StoragePluginTestUtils.DFS_PLUGIN_NAME; import static org.apache.drill.exec.util.StoragePluginTestUtils.DFS_TMP_SCHEMA; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; @Category(SqlTest.class) public class TestCTTAS extends BaseTestQuery { - private static final UUID session_id = UUID.nameUUIDFromBytes("sessionId".getBytes()); private static final String temp2_wk = "tmp2"; private static final String temp2_schema = String.format("%s.%s", DFS_PLUGIN_NAME, temp2_wk); - private static FileSystem fs; - private static FsPermission expectedFolderPermission; - private static FsPermission expectedFilePermission; + @Rule + public ExpectedException thrown = ExpectedException.none(); @BeforeClass public static void init() throws Exception { - MockUp<UUID> uuidMockUp = mockRandomUUID(session_id); - Properties testConfigurations = cloneDefaultTestConfigProperties(); - testConfigurations.put(ExecConstants.DEFAULT_TEMPORARY_WORKSPACE, DFS_TMP_SCHEMA); - updateTestCluster(1, DrillConfig.create(testConfigurations)); - uuidMockUp.tearDown(); - File tmp2 = dirTestWatcher.makeSubDir(Paths.get("tmp2")); - StoragePluginRegistry pluginRegistry = getDrillbitContext().getStorage(); FileSystemConfig pluginConfig = (FileSystemConfig) pluginRegistry.getPlugin(DFS_PLUGIN_NAME).getConfig(); pluginConfig.workspaces.put(temp2_wk, new WorkspaceConfig(tmp2.getAbsolutePath(), true, null, false)); pluginRegistry.createOrUpdate(DFS_PLUGIN_NAME, pluginConfig, true); - - fs = getLocalFileSystem(); - expectedFolderPermission = new FsPermission(StorageStrategy.TEMPORARY.getFolderPermission()); - expectedFilePermission = new FsPermission(StorageStrategy.TEMPORARY.getFilePermission()); - } - - private static MockUp<UUID> mockRandomUUID(final UUID uuid) { - return new MockUp<UUID>() { - @Mock - public UUID randomUUID() { - return uuid; - } - }; } @Test @@ -105,10 +69,8 @@ public void testCreateTableWithDifferentStorageFormats() throws Exception { try { for (String storageFormat : storageFormats) { String temporaryTableName = "temp_" + storageFormat; - mockRandomUUID(UUID.nameUUIDFromBytes(temporaryTableName.getBytes())); test("alter session set `store.format`='%s'", storageFormat); test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); - checkPermission(temporaryTableName); testBuilder() .sqlQuery("select * from %s", temporaryTableName) @@ -164,121 +126,91 @@ public void testResolveTemporaryTableWithPartialSchema() throws Exception { @Test public void testPartitionByWithTemporaryTables() throws Exception { String temporaryTableName = "temporary_table_with_partitions"; - mockRandomUUID(UUID.nameUUIDFromBytes(temporaryTableName.getBytes())); test("create TEMPORARY table %s partition by (c1) as select * from (" + "select 'A' as c1 from (values(1)) union all select 'B' as c1 from (values(1))) t", temporaryTableName); - checkPermission(temporaryTableName); } - @Test(expected = UserRemoteException.class) + @Test public void testCreationOutsideOfDefaultTemporaryWorkspace() throws Exception { - try { - String temporaryTableName = "temporary_table_outside_of_default_workspace"; - test("create TEMPORARY table %s.%s as select 'A' as c1 from (values(1))", temp2_schema, temporaryTableName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: Temporary tables are not allowed to be created / dropped " + - "outside of default temporary workspace [%s].", DFS_TMP_SCHEMA))); - throw e; - } + String temporaryTableName = "temporary_table_outside_of_default_workspace"; + + expectUserRemoteExceptionWithMessage(String.format( + "VALIDATION ERROR: Temporary tables are not allowed to be created / dropped " + + "outside of default temporary workspace [%s].", DFS_TMP_SCHEMA)); + + test("create TEMPORARY table %s.%s as select 'A' as c1 from (values(1))", temp2_schema, temporaryTableName); } - @Test(expected = UserRemoteException.class) + @Test public void testCreateWhenTemporaryTableExistsWithoutSchema() throws Exception { String temporaryTableName = "temporary_table_exists_without_schema"; - try { - test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); - test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: A table or view with given name [%s]" + - " already exists in schema [%s]", temporaryTableName, DFS_TMP_SCHEMA))); - throw e; - } + test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); + + expectUserRemoteExceptionWithTableExistsMessage(temporaryTableName, DFS_TMP_SCHEMA); + + test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); } - @Test(expected = UserRemoteException.class) + @Test public void testCreateWhenTemporaryTableExistsCaseInsensitive() throws Exception { - String temporaryTableName = "temporary_table_exists_without_schema"; - try { - test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); - test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName.toUpperCase()); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: A table or view with given name [%s]" + - " already exists in schema [%s]", temporaryTableName.toUpperCase(), DFS_TMP_SCHEMA))); - throw e; - } + String temporaryTableName = "temporary_table_exists_case_insensitive"; + test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); + + expectUserRemoteExceptionWithTableExistsMessage(temporaryTableName.toUpperCase(), DFS_TMP_SCHEMA); + + test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName.toUpperCase()); } - @Test(expected = UserRemoteException.class) + @Test public void testCreateWhenTemporaryTableExistsWithSchema() throws Exception { String temporaryTableName = "temporary_table_exists_with_schema"; - try { - test("create TEMPORARY table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); - test("create TEMPORARY table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: A table or view with given name [%s]" + - " already exists in schema [%s]", temporaryTableName, DFS_TMP_SCHEMA))); - throw e; - } + test("create TEMPORARY table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); + + expectUserRemoteExceptionWithTableExistsMessage(temporaryTableName, DFS_TMP_SCHEMA); + + test("create TEMPORARY table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); } - @Test(expected = UserRemoteException.class) + @Test public void testCreateWhenPersistentTableExists() throws Exception { String persistentTableName = "persistent_table_exists"; - try { - test("create table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, persistentTableName); - test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", persistentTableName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: A table or view with given name [%s]" + - " already exists in schema [%s]", persistentTableName, DFS_TMP_SCHEMA))); - throw e; - } + test("create table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, persistentTableName); + + expectUserRemoteExceptionWithTableExistsMessage(persistentTableName, DFS_TMP_SCHEMA); + + test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", persistentTableName); } - @Test(expected = UserRemoteException.class) + @Test public void testCreateWhenViewExists() throws Exception { String viewName = "view_exists"; - try { - test("create view %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, viewName); - test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", viewName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: A table or view with given name [%s]" + - " already exists in schema [%s]", viewName, DFS_TMP_SCHEMA))); - throw e; - } + test("create view %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, viewName); + + expectUserRemoteExceptionWithTableExistsMessage(viewName, DFS_TMP_SCHEMA); + + test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", viewName); } - @Test(expected = UserRemoteException.class) + @Test public void testCreatePersistentTableWhenTemporaryTableExists() throws Exception { String temporaryTableName = "temporary_table_exists_before_persistent"; - try { - test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); - test("create table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: A table or view with given name [%s]" + - " already exists in schema [%s]", temporaryTableName, DFS_TMP_SCHEMA))); - throw e; - } + test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); + + expectUserRemoteExceptionWithTableExistsMessage(temporaryTableName, DFS_TMP_SCHEMA); + + test("create table %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); } - @Test(expected = UserRemoteException.class) + @Test public void testCreateViewWhenTemporaryTableExists() throws Exception { String temporaryTableName = "temporary_table_exists_before_view"; - try { - test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); - test("create view %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: A non-view table with given name [%s] already exists in schema [%s]", - temporaryTableName, DFS_TMP_SCHEMA))); - throw e; - } + test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); + + expectUserRemoteExceptionWithMessage(String.format( + "VALIDATION ERROR: A non-view table with given name [%s] already exists in schema [%s]", + temporaryTableName, DFS_TMP_SCHEMA)); + + test("create view %s.%s as select 'A' as c1 from (values(1))", DFS_TMP_SCHEMA, temporaryTableName); } @Test @@ -358,21 +290,18 @@ public void testTemporaryTableAndViewPriority() throws Exception { .go(); } - @Test(expected = UserRemoteException.class) + @Test public void testTemporaryTablesInViewDefinitions() throws Exception { String temporaryTableName = "temporary_table_for_view_definition"; test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); - try { - test("create view %s.view_with_temp_table as select * from %s", DFS_TMP_SCHEMA, temporaryTableName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: Temporary tables usage is disallowed. Used temporary table name: [%s]", temporaryTableName))); - throw e; - } + expectUserRemoteExceptionWithMessage(String.format( + "VALIDATION ERROR: Temporary tables usage is disallowed. Used temporary table name: [%s]", temporaryTableName)); + + test("create view %s.view_with_temp_table as select * from %s", DFS_TMP_SCHEMA, temporaryTableName); } - @Test(expected = UserRemoteException.class) + @Test public void testTemporaryTablesInViewExpansionLogic() throws Exception { String tableName = "table_for_expansion_logic_test"; String viewName = "view_for_expansion_logic_test"; @@ -389,73 +318,48 @@ public void testTemporaryTablesInViewExpansionLogic() throws Exception { test("drop table %s", tableName); test("create temporary table %s as select 'TEMP' as c1 from (values(1))", tableName); - try { - test("select * from %s", viewName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: Temporary tables usage is disallowed. Used temporary table name: [%s]", tableName))); - throw e; - } + + expectUserRemoteExceptionWithMessage(String.format( + "VALIDATION ERROR: Temporary tables usage is disallowed. Used temporary table name: [%s]", tableName)); + + test("select * from %s", viewName); } @Test // DRILL-5952 public void testCreateTemporaryTableIfNotExistsWhenTableWithSameNameAlreadyExists() throws Exception{ final String newTblName = "createTemporaryTableIfNotExistsWhenATableWithSameNameAlreadyExists"; + test("CREATE TEMPORARY TABLE %s.%s AS SELECT * from cp.`region.json`", DFS_TMP_SCHEMA, newTblName); - try { - String ctasQuery = String.format("CREATE TEMPORARY TABLE %s.%s AS SELECT * from cp.`region.json`", DFS_TMP_SCHEMA, newTblName); - - test(ctasQuery); - - ctasQuery = - String.format("CREATE TEMPORARY TABLE IF NOT EXISTS %s AS SELECT * FROM cp.`employee.json`", newTblName); + testBuilder() + .sqlQuery("CREATE TEMPORARY TABLE IF NOT EXISTS %s AS SELECT * FROM cp.`employee.json`", newTblName) + .unOrdered() + .baselineColumns("ok", "summary") + .baselineValues(false, String.format("A table or view with given name [%s] already exists in schema [%s]", newTblName, DFS_TMP_SCHEMA)) + .go(); - testBuilder() - .sqlQuery(ctasQuery) - .unOrdered() - .baselineColumns("ok", "summary") - .baselineValues(false, String.format("A table or view with given name [%s] already exists in schema [%s]", newTblName, DFS_TMP_SCHEMA)) - .go(); - } finally { - test(String.format("DROP TABLE IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName)); - } + test("DROP TABLE IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName); } @Test // DRILL-5952 public void testCreateTemporaryTableIfNotExistsWhenViewWithSameNameAlreadyExists() throws Exception{ final String newTblName = "createTemporaryTableIfNotExistsWhenAViewWithSameNameAlreadyExists"; + test("CREATE VIEW %s.%s AS SELECT * from cp.`region.json`", DFS_TMP_SCHEMA, newTblName); - try { - String ctasQuery = String.format("CREATE VIEW %s.%s AS SELECT * from cp.`region.json`", DFS_TMP_SCHEMA, newTblName); - - test(ctasQuery); - - ctasQuery = - String.format("CREATE TEMPORARY TABLE IF NOT EXISTS %s.%s AS SELECT * FROM cp.`employee.json`", DFS_TMP_SCHEMA, newTblName); + testBuilder() + .sqlQuery("CREATE TEMPORARY TABLE IF NOT EXISTS %s.%s AS SELECT * FROM cp.`employee.json`", DFS_TMP_SCHEMA, newTblName) + .unOrdered() + .baselineColumns("ok", "summary") + .baselineValues(false, String.format("A table or view with given name [%s] already exists in schema [%s]", newTblName, DFS_TMP_SCHEMA)) + .go(); - testBuilder() - .sqlQuery(ctasQuery) - .unOrdered() - .baselineColumns("ok", "summary") - .baselineValues(false, String.format("A table or view with given name [%s] already exists in schema [%s]", newTblName, DFS_TMP_SCHEMA)) - .go(); - } finally { - test(String.format("DROP VIEW IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName)); - } + test("DROP VIEW IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName); } @Test // DRILL-5952 public void testCreateTemporaryTableIfNotExistsWhenTableWithSameNameDoesNotExist() throws Exception{ final String newTblName = "createTemporaryTableIfNotExistsWhenATableWithSameNameDoesNotExist"; - - try { - String ctasQuery = String.format("CREATE TEMPORARY TABLE IF NOT EXISTS %s.%s AS SELECT * FROM cp.`employee.json`", DFS_TMP_SCHEMA, newTblName); - - test(ctasQuery); - - } finally { - test(String.format("DROP TABLE IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName)); - } + test("CREATE TEMPORARY TABLE IF NOT EXISTS %s.%s AS SELECT * FROM cp.`employee.json`", DFS_TMP_SCHEMA, newTblName); + test("DROP TABLE IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName); } @Test @@ -498,47 +402,26 @@ public void testDropTemporaryTableAsViewWithoutException() throws Exception { .go(); } - @Test(expected = UserRemoteException.class) + @Test public void testDropTemporaryTableAsViewWithException() throws Exception { String temporaryTableName = "temporary_table_to_drop_like_view_with_exception"; test("create TEMPORARY table %s as select 'A' as c1 from (values(1))", temporaryTableName); - try { - test("drop view %s.%s", DFS_TMP_SCHEMA, temporaryTableName); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString(String.format( - "VALIDATION ERROR: Unknown view [%s] in schema [%s]", temporaryTableName, DFS_TMP_SCHEMA))); - throw e; - } + expectUserRemoteExceptionWithMessage(String.format( + "VALIDATION ERROR: Unknown view [%s] in schema [%s]", temporaryTableName, DFS_TMP_SCHEMA)); + + test("drop view %s.%s", DFS_TMP_SCHEMA, temporaryTableName); } - private void checkPermission(String tmpTableName) throws IOException { - List<Path> matchingPath = findTemporaryTableLocation(tmpTableName); - assertEquals("Only one directory should match temporary table name " + tmpTableName, 1, matchingPath.size()); - Path tmpTablePath = matchingPath.get(0); - assertEquals("Directory permission should match", - expectedFolderPermission, fs.getFileStatus(tmpTablePath).getPermission()); - RemoteIterator<LocatedFileStatus> fileIterator = fs.listFiles(tmpTablePath, false); - while (fileIterator.hasNext()) { - assertEquals("File permission should match", expectedFilePermission, fileIterator.next().getPermission()); - } + private void expectUserRemoteExceptionWithMessage(String message) { + thrown.expect(UserRemoteException.class); + thrown.expectMessage(containsString(message)); } - private List<Path> findTemporaryTableLocation(String tableName) throws IOException { - Path sessionTempLocation = new Path(dirTestWatcher.getDfsTestTmpDir().getAbsolutePath(), session_id.toString()); - assertTrue("Session temporary location must exist", fs.exists(sessionTempLocation)); - assertEquals("Session temporary location permission should match", - expectedFolderPermission, fs.getFileStatus(sessionTempLocation).getPermission()); - String tableUUID = UUID.nameUUIDFromBytes(tableName.getBytes()).toString(); - - RemoteIterator<LocatedFileStatus> pathList = fs.listLocatedStatus(sessionTempLocation); - List<Path> matchingPath = Lists.newArrayList(); - while (pathList.hasNext()) { - LocatedFileStatus path = pathList.next(); - if (path.isDirectory() && path.getPath().getName().equals(tableUUID)) { - matchingPath.add(path.getPath()); - } - } - return matchingPath; + private void expectUserRemoteExceptionWithTableExistsMessage(String tableName, String schemaName) { + expectUserRemoteExceptionWithMessage(String.format( + "VALIDATION ERROR: A table or view with given name [%s]" + + " already exists in schema [%s]", tableName, schemaName)); } + } diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/JarBuilder.java b/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/JarBuilder.java new file mode 100644 index 0000000000..4861c3076f --- /dev/null +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/JarBuilder.java @@ -0,0 +1,96 @@ +/* + * 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.drill.exec.udf.dynamic; + +import org.apache.maven.cli.MavenCli; +import org.apache.maven.cli.logging.Slf4jLogger; +import org.codehaus.plexus.DefaultPlexusContainer; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.logging.BaseLoggerManager; + +import java.util.LinkedList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class JarBuilder { + + private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(JarBuilder.class); + private static final String MAVEN_MULTI_MODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory"; + + private final MavenCli cli; + private final String projectDirectory; + + public JarBuilder(String projectDirectory) { + this.cli = new MavenCli() { + @Override + protected void customizeContainer(PlexusContainer container) { + ((DefaultPlexusContainer) container).setLoggerManager(new BaseLoggerManager() { + @Override + protected org.codehaus.plexus.logging.Logger createLogger(String s) { + return new Slf4jLogger(logger); + } + }); + } + }; + this.projectDirectory = projectDirectory; + } + + /** + * Builds jars using embedded maven in provided build directory. + * Includes files / resources based given pattern, otherwise using defaults provided in pom.xml. + * Checks if build exit code is 0, i.e. build was successful. + * + * @param jarName jar name + * @param buildDirectory build directory + * @param includeFiles pattern indicating which files should be included + * @param includeResources pattern indicating which resources should be included + * + * @return binary jar name with jar extension (my-jar.jar) + */ + public String build(String jarName, String buildDirectory, String includeFiles, String includeResources) { + String originalPropertyValue = System.setProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY, projectDirectory); + try { + List<String> params = new LinkedList<>(); + params.add("clean"); + params.add("package"); + params.add("-DskipTests"); + // uncomment to build with current Drill version + // params.add("-Ddrill.version=" + DrillVersionInfo.getVersion()); + params.add("-Djar.finalName=" + jarName); + params.add("-Dcustom.buildDirectory=" + buildDirectory); + if (includeFiles != null) { + params.add("-Dinclude.files=" + includeFiles); + } + if (includeResources != null) { + params.add("-Dinclude.resources=" + includeResources); + } + int result = cli.doMain(params.toArray(new String[params.size()]), projectDirectory, System.out, System.err); + assertEquals("Build should be successful.", 0, result); + return jarName + ".jar"; + } finally { + if (originalPropertyValue != null) { + System.setProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY, originalPropertyValue); + } else { + System.clearProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY); + } + } + } + +} + diff --git a/exec/java-exec/src/test/java/org/apache/drill/TestDynamicUDFSupport.java b/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/TestDynamicUDFSupport.java similarity index 65% rename from exec/java-exec/src/test/java/org/apache/drill/TestDynamicUDFSupport.java rename to exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/TestDynamicUDFSupport.java index 41da12334f..047026d65a 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/TestDynamicUDFSupport.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/udf/dynamic/TestDynamicUDFSupport.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.drill; +package org.apache.drill.exec.udf.dynamic; import com.google.common.collect.Lists; import org.apache.commons.io.FileUtils; @@ -26,7 +26,6 @@ import org.apache.drill.common.config.CommonConstants; import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.UserRemoteException; -import org.apache.drill.test.TestTools; import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.exception.VersionMismatchException; import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry; @@ -40,16 +39,13 @@ import org.apache.drill.test.BaseTestQuery; import org.apache.drill.test.TestBuilder; import org.apache.hadoop.fs.FileSystem; +import org.junit.After; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; -import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; +import org.junit.rules.ExpectedException; import java.io.File; import java.io.IOException; @@ -66,9 +62,10 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.reset; @@ -76,23 +73,37 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -@RunWith(MockitoJUnitRunner.class) @Category({SlowTest.class, SqlFunctionTest.class}) public class TestDynamicUDFSupport extends BaseTestQuery { - private static final Path jars = TestTools.WORKING_PATH - .resolve(TestTools.TEST_RESOURCES_REL) - .resolve("jars"); - private static final String default_binary_name = "DrillUDF-1.0.jar"; - private static final String UDF_SUB_DIR = "udf"; - private static final String default_source_name = JarUtil.getSourceName(default_binary_name); + private static final String DEFAULT_JAR_NAME = "drill-custom-lower"; private static URI fsUri; private static File udfDir; + private static File jarsDir; + private static File buildDirectory; + private static JarBuilder jarBuilder; + private static String defaultBinaryJar; + private static String defaultSourceJar; + + @Rule + public ExpectedException thrown = ExpectedException.none(); @BeforeClass - public static void setup() throws IOException { - udfDir = dirTestWatcher.makeSubDir(Paths.get(UDF_SUB_DIR)); + public static void buildAndStoreDefaultJars() throws IOException { + jarsDir = dirTestWatcher.makeSubDir(Paths.get("jars")); + buildDirectory = dirTestWatcher.makeSubDir(Paths.get("drill-udf")); + + jarBuilder = new JarBuilder("src/test/resources/drill-udf"); + defaultBinaryJar = buildJars(DEFAULT_JAR_NAME, "**/CustomLowerFunction.java", null); + defaultSourceJar = JarUtil.getSourceName(defaultBinaryJar); + + FileUtils.copyFileToDirectory(new File(buildDirectory, defaultBinaryJar), jarsDir); + FileUtils.copyFileToDirectory(new File(buildDirectory, defaultSourceJar), jarsDir); + } + @Before + public void setupNewDrillbit() throws Exception { + udfDir = dirTestWatcher.makeSubDir(Paths.get("udf")); Properties overrideProps = new Properties(); overrideProps.setProperty(ExecConstants.UDF_DIRECTORY_ROOT, udfDir.getAbsolutePath()); overrideProps.setProperty(ExecConstants.UDF_DIRECTORY_FS, FileSystem.DEFAULT_FS); @@ -101,29 +112,12 @@ public static void setup() throws IOException { fsUri = getLocalFileSystem().getUri(); } - @Rule - public final TestWatcher clearDirs = new TestWatcher() { - @Override - protected void succeeded(Description description) { - reset(); - } - - @Override - protected void failed(Throwable e, Description description) { - reset(); - } - - private void reset() { - try { - closeClient(); - FileUtils.cleanDirectory(udfDir); - dirTestWatcher.clear(); - setup(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }; + @After + public void cleanup() throws Exception { + closeClient(); + FileUtils.cleanDirectory(udfDir); + dirTestWatcher.clear(); + } @Test public void testSyntax() throws Exception { @@ -143,18 +137,26 @@ public void testEnableDynamicSupport() throws Exception { } @Test - public void testDisableDynamicSupport() throws Exception { + public void testDisableDynamicSupportCreate() throws Exception { try { test("alter system set `exec.udf.enable_dynamic_support` = false"); - String[] actions = new String[] {"create", "drop"}; - String query = "%s function using jar 'jar_name.jar'"; - for (String action : actions) { - try { - test(query, action); - } catch (UserRemoteException e) { - assertThat(e.getMessage(), containsString("Dynamic UDFs support is disabled.")); - } - } + String query = "create function using jar 'jar_name.jar'"; + thrown.expect(UserRemoteException.class); + thrown.expectMessage(containsString("Dynamic UDFs support is disabled.")); + test(query); + } finally { + test("alter system reset `exec.udf.enable_dynamic_support`"); + } + } + + @Test + public void testDisableDynamicSupportDrop() throws Exception { + try { + test("alter system set `exec.udf.enable_dynamic_support` = false"); + String query = "drop function using jar 'jar_name.jar'"; + thrown.expect(UserRemoteException.class); + thrown.expectMessage(containsString("Dynamic UDFs support is disabled.")); + test(query); } finally { test("alter system reset `exec.udf.enable_dynamic_support`"); } @@ -162,13 +164,13 @@ public void testDisableDynamicSupport() throws Exception { @Test public void testAbsentBinaryInStaging() throws Exception { - final Path staging = hadoopToJavaPath(getDrillbitContext().getRemoteFunctionRegistry().getStagingArea()); + Path staging = hadoopToJavaPath(getDrillbitContext().getRemoteFunctionRegistry().getStagingArea()); String summary = String.format("File %s does not exist on file system %s", - staging.resolve(default_binary_name).toUri().getPath(), fsUri); + staging.resolve(defaultBinaryJar).toUri().getPath(), fsUri); testBuilder() - .sqlQuery("create function using jar '%s'", default_binary_name) + .sqlQuery("create function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(false, summary) @@ -177,15 +179,14 @@ public void testAbsentBinaryInStaging() throws Exception { @Test public void testAbsentSourceInStaging() throws Exception { - final Path staging = hadoopToJavaPath(getDrillbitContext().getRemoteFunctionRegistry().getStagingArea()); - - copyJar(jars, staging, default_binary_name); + Path staging = hadoopToJavaPath(getDrillbitContext().getRemoteFunctionRegistry().getStagingArea()); + copyJar(jarsDir.toPath(), staging, defaultBinaryJar); String summary = String.format("File %s does not exist on file system %s", - staging.resolve(default_source_name).toUri().getPath(), fsUri); + staging.resolve(defaultSourceJar).toUri().getPath(), fsUri); testBuilder() - .sqlQuery("create function using jar '%s'", default_binary_name) + .sqlQuery("create function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(false, summary) @@ -194,32 +195,32 @@ public void testAbsentSourceInStaging() throws Exception { @Test public void testJarWithoutMarkerFile() throws Exception { - String jarWithNoMarkerFile = "DrillUDF_NoMarkerFile-1.0.jar"; - copyJarsToStagingArea(jarWithNoMarkerFile, JarUtil.getSourceName(jarWithNoMarkerFile)); + String jarName = "drill-no-marker"; + String jar = buildAndCopyJarsToStagingArea(jarName, null, "**/dummy.conf"); String summary = "Marker file %s is missing in %s"; testBuilder() - .sqlQuery("create function using jar '%s'", jarWithNoMarkerFile) + .sqlQuery("create function using jar '%s'", jar) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(false, String.format(summary, - CommonConstants.DRILL_JAR_MARKER_FILE_RESOURCE_PATHNAME, jarWithNoMarkerFile)) + CommonConstants.DRILL_JAR_MARKER_FILE_RESOURCE_PATHNAME, jar)) .go(); } @Test public void testJarWithoutFunctions() throws Exception { - String jarWithNoFunctions = "DrillUDF_Empty-1.0.jar"; - copyJarsToStagingArea(jarWithNoFunctions, JarUtil.getSourceName(jarWithNoFunctions)); + String jarName = "drill-no-functions"; + String jar = buildAndCopyJarsToStagingArea(jarName, "**/CustomLowerDummyFunction.java", null); String summary = "Jar %s does not contain functions"; testBuilder() - .sqlQuery("create function using jar '%s'", jarWithNoFunctions) + .sqlQuery("create function using jar '%s'", jar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(false, String.format(summary, jarWithNoFunctions)) + .baselineValues(false, String.format(summary, jar)) .go(); } @@ -231,10 +232,10 @@ public void testSuccessfulRegistration() throws Exception { "[custom_lower(VARCHAR-REQUIRED)]"; testBuilder() - .sqlQuery("create function using jar '%s'", default_binary_name) + .sqlQuery("create function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(true, String.format(summary, default_binary_name)) + .baselineValues(true, String.format(summary, defaultBinaryJar)) .go(); RemoteFunctionRegistry remoteFunctionRegistry = getDrillbitContext().getRemoteFunctionRegistry(); @@ -243,79 +244,81 @@ public void testSuccessfulRegistration() throws Exception { assertFalse("Staging area should be empty", fs.listFiles(remoteFunctionRegistry.getStagingArea(), false).hasNext()); assertFalse("Temporary area should be empty", fs.listFiles(remoteFunctionRegistry.getTmpArea(), false).hasNext()); - final Path path = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); + Path path = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); assertTrue("Binary should be present in registry area", - path.resolve(default_binary_name).toFile().exists()); + path.resolve(defaultBinaryJar).toFile().exists()); assertTrue("Source should be present in registry area", - path.resolve(default_source_name).toFile().exists()); + path.resolve(defaultBinaryJar).toFile().exists()); Registry registry = remoteFunctionRegistry.getRegistry(new DataChangeVersion()); assertEquals("Registry should contain one jar", registry.getJarList().size(), 1); - assertEquals(registry.getJar(0).getName(), default_binary_name); + assertEquals(registry.getJar(0).getName(), defaultBinaryJar); } @Test public void testDuplicatedJarInRemoteRegistry() throws Exception { copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); + test("create function using jar '%s'", defaultBinaryJar); copyDefaultJarsToStagingArea(); String summary = "Jar with %s name has been already registered"; testBuilder() - .sqlQuery("create function using jar '%s'", default_binary_name) + .sqlQuery("create function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(false, String.format(summary, default_binary_name)) + .baselineValues(false, String.format(summary, defaultBinaryJar)) .go(); } @Test public void testDuplicatedJarInLocalRegistry() throws Exception { - copyDefaultJarsToStagingArea(); + String jarName = "drill-custom-upper"; + String jar = buildAndCopyJarsToStagingArea(jarName, "**/CustomUpperFunction.java", null); - test("create function using jar '%s'", default_binary_name); - test("select custom_lower('A') from (values(1))"); + test("create function using jar '%s'", jar); + test("select custom_upper('A') from (values(1))"); - copyDefaultJarsToStagingArea(); + copyJarsToStagingArea(buildDirectory.toPath(), jar,JarUtil.getSourceName(jar)); String summary = "Jar with %s name has been already registered"; testBuilder() - .sqlQuery("create function using jar '%s'", default_binary_name) + .sqlQuery("create function using jar '%s'", jar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(false, String.format(summary, default_binary_name)) + .baselineValues(false, String.format(summary, jar)) .go(); } @Test public void testDuplicatedFunctionsInRemoteRegistry() throws Exception { - String jarWithDuplicate = "DrillUDF_Copy-1.0.jar"; copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); - copyJarsToStagingArea(jarWithDuplicate, JarUtil.getSourceName(jarWithDuplicate)); + test("create function using jar '%s'", defaultBinaryJar); + + String jarName = "drill-custom-lower-copy"; + String jar = buildAndCopyJarsToStagingArea(jarName, "**/CustomLowerFunction.java", null); String summary = "Found duplicated function in %s: custom_lower(VARCHAR-REQUIRED)"; testBuilder() - .sqlQuery("create function using jar '%s'", jarWithDuplicate) + .sqlQuery("create function using jar '%s'", jar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(false, String.format(summary, default_binary_name)) + .baselineValues(false, String.format(summary, defaultBinaryJar)) .go(); } @Test public void testDuplicatedFunctionsInLocalRegistry() throws Exception { - String jarWithDuplicate = "DrillUDF_DupFunc-1.0.jar"; - copyJarsToStagingArea(jarWithDuplicate, JarUtil.getSourceName(jarWithDuplicate)); + String jarName = "drill-lower"; + String jar = buildAndCopyJarsToStagingArea(jarName, "**/LowerFunction.java", null); String summary = "Found duplicated function in %s: lower(VARCHAR-REQUIRED)"; testBuilder() - .sqlQuery("create function using jar '%s'", jarWithDuplicate) + .sqlQuery("create function using jar '%s'", jar) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(false, String.format(summary, LocalFunctionRegistry.BUILT_IN)) @@ -324,10 +327,10 @@ public void testDuplicatedFunctionsInLocalRegistry() throws Exception { @Test public void testSuccessfulRegistrationAfterSeveralRetryAttempts() throws Exception { - final RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); - final Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); - final Path stagingPath = hadoopToJavaPath(remoteFunctionRegistry.getStagingArea()); - final Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea()); + RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); + Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); + Path stagingPath = hadoopToJavaPath(remoteFunctionRegistry.getStagingArea()); + Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea()); copyDefaultJarsToStagingArea(); @@ -340,10 +343,10 @@ public void testSuccessfulRegistrationAfterSeveralRetryAttempts() throws Excepti "[custom_lower(VARCHAR-REQUIRED)]"; testBuilder() - .sqlQuery("create function using jar '%s'", default_binary_name) + .sqlQuery("create function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(true, String.format(summary, default_binary_name)) + .baselineValues(true, String.format(summary, defaultBinaryJar)) .go(); verify(remoteFunctionRegistry, times(3)) @@ -353,20 +356,20 @@ public void testSuccessfulRegistrationAfterSeveralRetryAttempts() throws Excepti assertTrue("Temporary area should be empty", ArrayUtils.isEmpty(tmpPath.toFile().listFiles())); assertTrue("Binary should be present in registry area", - registryPath.resolve(default_binary_name).toFile().exists()); + registryPath.resolve(defaultBinaryJar).toFile().exists()); assertTrue("Source should be present in registry area", - registryPath.resolve(default_source_name).toFile().exists()); + registryPath.resolve(defaultSourceJar).toFile().exists()); Registry registry = remoteFunctionRegistry.getRegistry(new DataChangeVersion()); assertEquals("Registry should contain one jar", registry.getJarList().size(), 1); - assertEquals(registry.getJar(0).getName(), default_binary_name); + assertEquals(registry.getJar(0).getName(), defaultBinaryJar); } @Test public void testSuccessfulUnregistrationAfterSeveralRetryAttempts() throws Exception { RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); + test("create function using jar '%s'", defaultBinaryJar); reset(remoteFunctionRegistry); doThrow(new VersionMismatchException("Version mismatch detected", 1)) @@ -378,10 +381,10 @@ public void testSuccessfulUnregistrationAfterSeveralRetryAttempts() throws Excep "[custom_lower(VARCHAR-REQUIRED)]"; testBuilder() - .sqlQuery("drop function using jar '%s'", default_binary_name) + .sqlQuery("drop function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(true, String.format(summary, default_binary_name)) + .baselineValues(true, String.format(summary, defaultBinaryJar)) .go(); verify(remoteFunctionRegistry, times(3)) @@ -396,10 +399,10 @@ public void testSuccessfulUnregistrationAfterSeveralRetryAttempts() throws Excep @Test public void testExceedRetryAttemptsDuringRegistration() throws Exception { - final RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); - final Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); - final Path stagingPath = hadoopToJavaPath(remoteFunctionRegistry.getStagingArea()); - final Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea()); + RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); + Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); + Path stagingPath = hadoopToJavaPath(remoteFunctionRegistry.getStagingArea()); + Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea()); copyDefaultJarsToStagingArea(); @@ -409,7 +412,7 @@ public void testExceedRetryAttemptsDuringRegistration() throws Exception { String summary = "Failed to update remote function registry. Exceeded retry attempts limit."; testBuilder() - .sqlQuery("create function using jar '%s'", default_binary_name) + .sqlQuery("create function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(false, summary) @@ -419,9 +422,9 @@ public void testExceedRetryAttemptsDuringRegistration() throws Exception { .updateRegistry(any(Registry.class), any(DataChangeVersion.class)); assertTrue("Binary should be present in staging area", - stagingPath.resolve(default_binary_name).toFile().exists()); + stagingPath.resolve(defaultBinaryJar).toFile().exists()); assertTrue("Source should be present in staging area", - stagingPath.resolve(default_source_name).toFile().exists()); + stagingPath.resolve(defaultSourceJar).toFile().exists()); assertTrue("Registry area should be empty", ArrayUtils.isEmpty(registryPath.toFile().listFiles())); assertTrue("Temporary area should be empty", ArrayUtils.isEmpty(tmpPath.toFile().listFiles())); @@ -432,11 +435,11 @@ public void testExceedRetryAttemptsDuringRegistration() throws Exception { @Test public void testExceedRetryAttemptsDuringUnregistration() throws Exception { - final RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); - final Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); + RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); + Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); + test("create function using jar '%s'", defaultBinaryJar); reset(remoteFunctionRegistry); doThrow(new VersionMismatchException("Version mismatch detected", 1)) @@ -445,7 +448,7 @@ public void testExceedRetryAttemptsDuringUnregistration() throws Exception { String summary = "Failed to update remote function registry. Exceeded retry attempts limit."; testBuilder() - .sqlQuery("drop function using jar '%s'", default_binary_name) + .sqlQuery("drop function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(false, summary) @@ -455,25 +458,23 @@ public void testExceedRetryAttemptsDuringUnregistration() throws Exception { .updateRegistry(any(Registry.class), any(DataChangeVersion.class)); assertTrue("Binary should be present in registry area", - registryPath.resolve(default_binary_name).toFile().exists()); + registryPath.resolve(defaultBinaryJar).toFile().exists()); assertTrue("Source should be present in registry area", - registryPath.resolve(default_source_name).toFile().exists()); + registryPath.resolve(defaultSourceJar).toFile().exists()); Registry registry = remoteFunctionRegistry.getRegistry(new DataChangeVersion()); assertEquals("Registry should contain one jar", registry.getJarList().size(), 1); - assertEquals(registry.getJar(0).getName(), default_binary_name); + assertEquals(registry.getJar(0).getName(), defaultBinaryJar); } @Test public void testLazyInit() throws Exception { - try { - test("select custom_lower('A') from (values(1))"); - } catch (UserRemoteException e){ - assertThat(e.getMessage(), containsString("No match found for function signature custom_lower(<CHARACTER>)")); - } + thrown.expect(UserRemoteException.class); + thrown.expectMessage(containsString("No match found for function signature custom_lower(<CHARACTER>)")); + test("select custom_lower('A') from (values(1))"); copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); + test("create function using jar '%s'", defaultBinaryJar); testBuilder() .sqlQuery("select custom_lower('A') as res from (values(1))") .unOrdered() @@ -485,21 +486,19 @@ public void testLazyInit() throws Exception { getDrillbitContext().getFunctionImplementationRegistry(), "localUdfDir", true)); assertTrue("Binary should exist in local udf directory", - localUdfDirPath.resolve(default_binary_name).toFile().exists()); + localUdfDirPath.resolve(defaultBinaryJar).toFile().exists()); assertTrue("Source should exist in local udf directory", - localUdfDirPath.resolve(default_source_name).toFile().exists()); + localUdfDirPath.resolve(defaultSourceJar).toFile().exists()); } @Test public void testLazyInitWhenDynamicUdfSupportIsDisabled() throws Exception { - try { - test("select custom_lower('A') from (values(1))"); - } catch (UserRemoteException e){ - assertThat(e.getMessage(), containsString("No match found for function signature custom_lower(<CHARACTER>)")); - } + thrown.expect(UserRemoteException.class); + thrown.expectMessage(containsString("No match found for function signature custom_lower(<CHARACTER>)")); + test("select custom_lower('A') from (values(1))"); copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); + test("create function using jar '%s'", defaultBinaryJar); try { testBuilder() @@ -516,9 +515,10 @@ public void testLazyInitWhenDynamicUdfSupportIsDisabled() throws Exception { @Test public void testOverloadedFunctionPlanningStage() throws Exception { - String jarName = "DrillUDF-overloading-1.0.jar"; - copyJarsToStagingArea(jarName, JarUtil.getSourceName(jarName)); - test("create function using jar '%s'", jarName); + String jarName = "drill-custom-abs"; + String jar = buildAndCopyJarsToStagingArea(jarName, "**/CustomAbsFunction.java", null); + + test("create function using jar '%s'", jar); testBuilder() .sqlQuery("select abs('A', 'A') as res from (values(1))") @@ -530,9 +530,10 @@ public void testOverloadedFunctionPlanningStage() throws Exception { @Test public void testOverloadedFunctionExecutionStage() throws Exception { - String jarName = "DrillUDF-overloading-1.0.jar"; - copyJarsToStagingArea(jarName, JarUtil.getSourceName(jarName)); - test("create function using jar '%s'", jarName); + String jarName = "drill-custom-log"; + String jar = buildAndCopyJarsToStagingArea(jarName, "**/CustomLogFunction.java", null); + + test("create function using jar '%s'", jar); testBuilder() .sqlQuery("select log('A') as res from (values(1))") @@ -545,67 +546,65 @@ public void testOverloadedFunctionExecutionStage() throws Exception { @Test public void testDropFunction() throws Exception { copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); + test("create function using jar '%s'", defaultBinaryJar); test("select custom_lower('A') from (values(1))"); Path localUdfDirPath = hadoopToJavaPath((org.apache.hadoop.fs.Path)FieldUtils.readField( getDrillbitContext().getFunctionImplementationRegistry(), "localUdfDir", true)); assertTrue("Binary should exist in local udf directory", - localUdfDirPath.resolve(default_binary_name).toFile().exists()); + localUdfDirPath.resolve(defaultBinaryJar).toFile().exists()); assertTrue("Source should exist in local udf directory", - localUdfDirPath.resolve(default_source_name).toFile().exists()); + localUdfDirPath.resolve(defaultSourceJar).toFile().exists()); String summary = "The following UDFs in jar %s have been unregistered:\n" + "[custom_lower(VARCHAR-REQUIRED)]"; testBuilder() - .sqlQuery("drop function using jar '%s'", default_binary_name) + .sqlQuery("drop function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(true, String.format(summary, default_binary_name)) + .baselineValues(true, String.format(summary, defaultBinaryJar)) .go(); - try { - test("select custom_lower('A') from (values(1))"); - } catch (UserRemoteException e){ - assertThat(e.getMessage(), containsString("No match found for function signature custom_lower(<CHARACTER>)")); - } + thrown.expect(UserRemoteException.class); + thrown.expectMessage(containsString("No match found for function signature custom_lower(<CHARACTER>)")); + test("select custom_lower('A') from (values(1))"); - final RemoteFunctionRegistry remoteFunctionRegistry = getDrillbitContext().getRemoteFunctionRegistry(); - final Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); + RemoteFunctionRegistry remoteFunctionRegistry = getDrillbitContext().getRemoteFunctionRegistry(); + Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); assertEquals("Remote registry should be empty", remoteFunctionRegistry.getRegistry(new DataChangeVersion()).getJarList().size(), 0); assertFalse("Binary should not be present in registry area", - registryPath.resolve(default_binary_name).toFile().exists()); + registryPath.resolve(defaultBinaryJar).toFile().exists()); assertFalse("Source should not be present in registry area", - registryPath.resolve(default_source_name).toFile().exists()); + registryPath.resolve(defaultSourceJar).toFile().exists()); assertFalse("Binary should not be present in local udf directory", - localUdfDirPath.resolve(default_binary_name).toFile().exists()); + localUdfDirPath.resolve(defaultBinaryJar).toFile().exists()); assertFalse("Source should not be present in local udf directory", - localUdfDirPath.resolve(default_source_name).toFile().exists()); + localUdfDirPath.resolve(defaultSourceJar).toFile().exists()); } @Test public void testReRegisterTheSameJarWithDifferentContent() throws Exception { copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); + test("create function using jar '%s'", defaultBinaryJar); testBuilder() .sqlQuery("select custom_lower('A') as res from (values(1))") .unOrdered() .baselineColumns("res") .baselineValues("a") .go(); - test("drop function using jar '%s'", default_binary_name); + test("drop function using jar '%s'", defaultBinaryJar); Thread.sleep(1000); - Path src = jars.resolve("v2"); - copyJarsToStagingArea(src, default_binary_name, default_source_name); - test("create function using jar '%s'", default_binary_name); + buildAndCopyJarsToStagingArea(DEFAULT_JAR_NAME, "**/CustomLowerFunctionV2.java", null); + + test("create function using jar '%s'", defaultBinaryJar); testBuilder() .sqlQuery("select custom_lower('A') as res from (values(1))") .unOrdered() @@ -619,36 +618,33 @@ public void testDropAbsentJar() throws Exception { String summary = "Jar %s is not registered in remote registry"; testBuilder() - .sqlQuery("drop function using jar '%s'", default_binary_name) + .sqlQuery("drop function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(false, String.format(summary, default_binary_name)) + .baselineValues(false, String.format(summary, defaultBinaryJar)) .go(); } @Test public void testRegistrationFailDuringRegistryUpdate() throws Exception { - final RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); - final Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); - final Path stagingPath = hadoopToJavaPath(remoteFunctionRegistry.getStagingArea()); - final Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea()); + RemoteFunctionRegistry remoteFunctionRegistry = spyRemoteFunctionRegistry(); + Path registryPath = hadoopToJavaPath(remoteFunctionRegistry.getRegistryArea()); + Path stagingPath = hadoopToJavaPath(remoteFunctionRegistry.getStagingArea()); + Path tmpPath = hadoopToJavaPath(remoteFunctionRegistry.getTmpArea()); final String errorMessage = "Failure during remote registry update."; - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - assertTrue("Binary should be present in registry area", - registryPath.resolve(default_binary_name).toFile().exists()); - assertTrue("Source should be present in registry area", - registryPath.resolve(default_source_name).toFile().exists()); - throw new RuntimeException(errorMessage); - } + doAnswer(invocation -> { + assertTrue("Binary should be present in registry area", + registryPath.resolve(defaultBinaryJar).toFile().exists()); + assertTrue("Source should be present in registry area", + registryPath.resolve(defaultSourceJar).toFile().exists()); + throw new RuntimeException(errorMessage); }).when(remoteFunctionRegistry).updateRegistry(any(Registry.class), any(DataChangeVersion.class)); copyDefaultJarsToStagingArea(); testBuilder() - .sqlQuery("create function using jar '%s'", default_binary_name) + .sqlQuery("create function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(false, errorMessage) @@ -657,8 +653,8 @@ public Void answer(InvocationOnMock invocation) throws Throwable { assertTrue("Registry area should be empty", ArrayUtils.isEmpty(registryPath.toFile().listFiles())); assertTrue("Temporary area should be empty", ArrayUtils.isEmpty(tmpPath.toFile().listFiles())); - assertTrue("Binary should be present in staging area", stagingPath.resolve(default_binary_name).toFile().exists()); - assertTrue("Source should be present in staging area", stagingPath.resolve(default_source_name).toFile().exists()); + assertTrue("Binary should be present in staging area", stagingPath.resolve(defaultBinaryJar).toFile().exists()); + assertTrue("Source should be present in staging area", stagingPath.resolve(defaultSourceJar).toFile().exists()); } @Test @@ -668,21 +664,18 @@ public void testConcurrentRegistrationOfTheSameJar() throws Exception { final CountDownLatch latch1 = new CountDownLatch(1); final CountDownLatch latch2 = new CountDownLatch(1); - doAnswer(new Answer<String>() { - @Override - public String answer(InvocationOnMock invocation) throws Throwable { - String result = (String) invocation.callRealMethod(); - latch2.countDown(); - latch1.await(); - return result; - } + doAnswer(invocation -> { + String result = (String) invocation.callRealMethod(); + latch2.countDown(); + latch1.await(); + return result; }) .doCallRealMethod() .doCallRealMethod() .when(remoteFunctionRegistry).addToJars(anyString(), any(RemoteFunctionRegistry.Action.class)); - final String query = String.format("create function using jar '%s'", default_binary_name); + final String query = String.format("create function using jar '%s'", defaultBinaryJar); Thread thread = new Thread(new SimpleQueryRunner(query)); thread.start(); @@ -695,14 +688,14 @@ public String answer(InvocationOnMock invocation) throws Throwable { .sqlQuery(query) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(false, String.format(summary, default_binary_name)) + .baselineValues(false, String.format(summary, defaultBinaryJar)) .go(); testBuilder() - .sqlQuery("drop function using jar '%s'", default_binary_name) + .sqlQuery("drop function using jar '%s'", defaultBinaryJar) .unOrdered() .baselineColumns("ok", "summary") - .baselineValues(false, String.format(summary, default_binary_name)) + .baselineValues(false, String.format(summary, defaultBinaryJar)) .go(); } finally { @@ -719,51 +712,45 @@ public void testConcurrentRemoteRegistryUpdateWithDuplicates() throws Exception final CountDownLatch latch2 = new CountDownLatch(1); final CountDownLatch latch3 = new CountDownLatch(1); - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - latch3.countDown(); - latch1.await(); - invocation.callRealMethod(); - latch2.countDown(); - return null; - } - }).doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - latch1.countDown(); - latch2.await(); - invocation.callRealMethod(); - return null; - } + doAnswer(invocation -> { + latch3.countDown(); + latch1.await(); + invocation.callRealMethod(); + latch2.countDown(); + return null; + }).doAnswer(invocation -> { + latch1.countDown(); + latch2.await(); + invocation.callRealMethod(); + return null; }) .when(remoteFunctionRegistry).updateRegistry(any(Registry.class), any(DataChangeVersion.class)); + final String jar1 = defaultBinaryJar; + copyDefaultJarsToStagingArea(); - final String jarName1 = default_binary_name; - final String jarName2 = "DrillUDF_Copy-1.0.jar"; - final String query = "create function using jar '%s'"; + final String copyJarName = "drill-custom-lower-copy"; + final String jar2 = buildAndCopyJarsToStagingArea(copyJarName, "**/CustomLowerFunction.java", null); - copyDefaultJarsToStagingArea(); - copyJarsToStagingArea(jarName2, JarUtil.getSourceName(jarName2)); + final String query = "create function using jar '%s'"; Thread thread1 = new Thread(new TestBuilderRunner( testBuilder() - .sqlQuery(query, jarName1) + .sqlQuery(query, jar1) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(true, String.format("The following UDFs in jar %s have been registered:\n" + - "[custom_lower(VARCHAR-REQUIRED)]", jarName1)) + "[custom_lower(VARCHAR-REQUIRED)]", jar1)) )); Thread thread2 = new Thread(new TestBuilderRunner( testBuilder() - .sqlQuery(query, jarName2) + .sqlQuery(query, jar2) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(false, - String.format("Found duplicated function in %s: custom_lower(VARCHAR-REQUIRED)", jarName1)) + String.format("Found duplicated function in %s: custom_lower(VARCHAR-REQUIRED)", jar1)) )); thread1.start(); @@ -778,7 +765,7 @@ public Void answer(InvocationOnMock invocation) throws Throwable { assertEquals("Remote registry version should match", 1, version.getVersion()); List<Jar> jarList = registry.getJarList(); assertEquals("Only one jar should be registered", 1, jarList.size()); - assertEquals("Jar name should match", jarName1, jarList.get(0).getName()); + assertEquals("Jar name should match", jar1, jarList.get(0).getName()); verify(remoteFunctionRegistry, times(2)).updateRegistry(any(Registry.class), any(DataChangeVersion.class)); } @@ -789,43 +776,40 @@ public void testConcurrentRemoteRegistryUpdateForDifferentJars() throws Exceptio final CountDownLatch latch1 = new CountDownLatch(1); final CountDownLatch latch2 = new CountDownLatch(2); - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - latch2.countDown(); - latch1.await(); - invocation.callRealMethod(); - return null; - } + doAnswer(invocation -> { + latch2.countDown(); + latch1.await(); + invocation.callRealMethod(); + return null; }) .when(remoteFunctionRegistry).updateRegistry(any(Registry.class), any(DataChangeVersion.class)); - final String jarName1 = default_binary_name; - final String jarName2 = "DrillUDF-2.0.jar"; - final String query = "create function using jar '%s'"; - + final String jar1 = defaultBinaryJar; copyDefaultJarsToStagingArea(); - copyJarsToStagingArea(jarName2, JarUtil.getSourceName(jarName2)); + final String upperJarName = "drill-custom-upper"; + final String jar2 = buildAndCopyJarsToStagingArea(upperJarName, "**/CustomUpperFunction.java", null); + + final String query = "create function using jar '%s'"; Thread thread1 = new Thread(new TestBuilderRunner( testBuilder() - .sqlQuery(query, jarName1) + .sqlQuery(query, jar1) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(true, String.format("The following UDFs in jar %s have been registered:\n" + - "[custom_lower(VARCHAR-REQUIRED)]", jarName1)) + "[custom_lower(VARCHAR-REQUIRED)]", jar1)) )); Thread thread2 = new Thread(new TestBuilderRunner( testBuilder() - .sqlQuery(query, jarName2) + .sqlQuery(query, jar2) .unOrdered() .baselineColumns("ok", "summary") .baselineValues(true, String.format("The following UDFs in jar %s have been registered:\n" + - "[custom_upper(VARCHAR-REQUIRED)]", jarName2)) + "[custom_upper(VARCHAR-REQUIRED)]", jar2)) )); thread1.start(); @@ -842,7 +826,7 @@ public Void answer(InvocationOnMock invocation) throws Throwable { assertEquals("Remote registry version should match", 2, version.getVersion()); List<Jar> actualJars = registry.getJarList(); - List<String> expectedJars = Lists.newArrayList(jarName1, jarName2); + List<String> expectedJars = Lists.newArrayList(jar1, jar2); assertEquals("Only one jar should be registered", 2, actualJars.size()); for (Jar jar : actualJars) { @@ -856,32 +840,26 @@ public Void answer(InvocationOnMock invocation) throws Throwable { public void testLazyInitConcurrent() throws Exception { FunctionImplementationRegistry functionImplementationRegistry = spyFunctionImplementationRegistry(); copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); + test("create function using jar '%s'", defaultBinaryJar); final CountDownLatch latch1 = new CountDownLatch(1); final CountDownLatch latch2 = new CountDownLatch(1); final String query = "select custom_lower('A') from (values(1))"; - doAnswer(new Answer<Boolean>() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - latch1.await(); - boolean result = (boolean) invocation.callRealMethod(); - assertTrue("syncWithRemoteRegistry() should return true", result); - latch2.countDown(); - return true; - } + doAnswer(invocation -> { + latch1.await(); + boolean result = (boolean) invocation.callRealMethod(); + assertTrue("syncWithRemoteRegistry() should return true", result); + latch2.countDown(); + return true; }) - .doAnswer(new Answer() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - latch1.countDown(); - latch2.await(); - boolean result = (boolean) invocation.callRealMethod(); - assertTrue("syncWithRemoteRegistry() should return true", result); - return true; - } + .doAnswer(invocation -> { + latch1.countDown(); + latch2.await(); + boolean result = (boolean) invocation.callRealMethod(); + assertTrue("syncWithRemoteRegistry() should return true", result); + return true; }) .when(functionImplementationRegistry).syncWithRemoteRegistry(anyLong()); @@ -905,23 +883,17 @@ public Boolean answer(InvocationOnMock invocation) throws Throwable { public void testLazyInitNoReload() throws Exception { FunctionImplementationRegistry functionImplementationRegistry = spyFunctionImplementationRegistry(); copyDefaultJarsToStagingArea(); - test("create function using jar '%s'", default_binary_name); - - doAnswer(new Answer<Boolean>() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - boolean result = (boolean) invocation.callRealMethod(); - assertTrue("syncWithRemoteRegistry() should return true", result); - return true; - } + test("create function using jar '%s'", defaultBinaryJar); + + doAnswer(invocation -> { + boolean result = (boolean) invocation.callRealMethod(); + assertTrue("syncWithRemoteRegistry() should return true", result); + return true; }) - .doAnswer(new Answer() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - boolean result = (boolean) invocation.callRealMethod(); - assertFalse("syncWithRemoteRegistry() should return false", result); - return false; - } + .doAnswer(invocation -> { + boolean result = (boolean) invocation.callRealMethod(); + assertFalse("syncWithRemoteRegistry() should return false", result); + return false; }) .when(functionImplementationRegistry).syncWithRemoteRegistry(anyLong()); @@ -929,6 +901,7 @@ public Boolean answer(InvocationOnMock invocation) throws Throwable { try { test("select unknown_lower('A') from (values(1))"); + fail(); } catch (UserRemoteException e){ assertThat(e.getMessage(), containsString("No match found for function signature unknown_lower(<CHARACTER>)")); } @@ -939,12 +912,18 @@ public Boolean answer(InvocationOnMock invocation) throws Throwable { assertEquals("Sync function registry version should match", 1L, localFunctionRegistry.getVersion()); } + private static String buildJars(String jarName, String includeFiles, String includeResources) { + return jarBuilder.build(jarName, buildDirectory.getAbsolutePath(), includeFiles, includeResources); + } + private void copyDefaultJarsToStagingArea() throws IOException { - copyJarsToStagingArea(jars, default_binary_name, default_source_name); + copyJarsToStagingArea(jarsDir.toPath(), defaultBinaryJar, defaultSourceJar); } - private void copyJarsToStagingArea(String binaryName, String sourceName) throws IOException { - copyJarsToStagingArea(jars, binaryName, sourceName); + private String buildAndCopyJarsToStagingArea(String jarName, String includeFiles, String includeResources) throws IOException { + String binaryJar = buildJars(jarName, includeFiles, includeResources); + copyJarsToStagingArea(buildDirectory.toPath(), binaryJar, JarUtil.getSourceName(binaryJar)); + return binaryJar; } private void copyJarsToStagingArea(Path src, String binaryName, String sourceName) throws IOException { diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/vector/complex/TestEmptyPopulation.java b/exec/java-exec/src/test/java/org/apache/drill/exec/vector/complex/TestEmptyPopulation.java index c2add4195b..307faab152 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/vector/complex/TestEmptyPopulation.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/vector/complex/TestEmptyPopulation.java @@ -28,10 +28,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; -@RunWith(MockitoJUnitRunner.class) public class TestEmptyPopulation extends BaseTestQuery { private UInt4Vector offsets; diff --git a/exec/java-exec/src/test/resources/drill-udf/pom.xml b/exec/java-exec/src/test/resources/drill-udf/pom.xml new file mode 100644 index 0000000000..73618451b2 --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/pom.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.drill.udf</groupId> + <artifactId>drill-udf</artifactId> + <version>1.0</version> + + <properties> + <jar.finalName>${project.name}</jar.finalName> + <custom.buildDirectory>${project.basedir}/target</custom.buildDirectory> + <drill.version>1.13.0</drill.version> + <include.files>**/*.java</include.files> + <include.resources>**/*.conf</include.resources> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.drill.exec</groupId> + <artifactId>drill-java-exec</artifactId> + <version>${drill.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <directory>${custom.buildDirectory}</directory> + <resources> + <resource> + <directory>src/main/resources</directory> + <includes> + <include>${include.resources}</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <includes> + <include>${include.files}</include> + </includes> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>2.4</version> + <configuration> + <finalName>${jar.finalName}</finalName> + <includes> + <include>${include.files}</include> + </includes> + </configuration> + <executions> + <execution> + <id>attach-sources</id> + <phase>package</phase> + <goals> + <goal>jar-no-fork</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + +</project> diff --git a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomAbsFunction.java b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomAbsFunction.java new file mode 100644 index 0000000000..9bdcffb657 --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomAbsFunction.java @@ -0,0 +1,63 @@ +/* + * 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.drill.udf.dynamic; + +import io.netty.buffer.DrillBuf; +import org.apache.drill.exec.expr.DrillSimpleFunc; +import org.apache.drill.exec.expr.annotations.FunctionTemplate; +import org.apache.drill.exec.expr.annotations.Output; +import org.apache.drill.exec.expr.annotations.Param; +import org.apache.drill.exec.expr.holders.VarCharHolder; + +import javax.inject.Inject; + +@FunctionTemplate( + name="abs", + scope= FunctionTemplate.FunctionScope.SIMPLE, + nulls = FunctionTemplate.NullHandling.NULL_IF_NULL +) +public class CustomAbsFunction implements DrillSimpleFunc { + + @Param + VarCharHolder input1; + + @Param + VarCharHolder input2; + + @Output + VarCharHolder out; + + @Inject + DrillBuf buffer; + + public void setup() { + + } + + public void eval() { + String inputString1 = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input1.start, input1.end, input1.buffer); + String inputString2 = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input2.start, input2.end, input2.buffer); + String outputValue = String.format("ABS was overloaded. Input: %s, %s", inputString1, inputString2); + + out.buffer = buffer; + out.start = 0; + out.end = outputValue.getBytes().length; + buffer.setBytes(0, outputValue.getBytes()); + } +} + diff --git a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLogFunction.java b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLogFunction.java new file mode 100644 index 0000000000..fa49a35c77 --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLogFunction.java @@ -0,0 +1,58 @@ +/* + * 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.drill.udf.dynamic; + +import io.netty.buffer.DrillBuf; +import org.apache.drill.exec.expr.DrillSimpleFunc; +import org.apache.drill.exec.expr.annotations.FunctionTemplate; +import org.apache.drill.exec.expr.annotations.Param; +import org.apache.drill.exec.expr.annotations.Output; +import org.apache.drill.exec.expr.holders.VarCharHolder; +import javax.inject.Inject; + +@FunctionTemplate( + name="log", + scope= FunctionTemplate.FunctionScope.SIMPLE, + nulls = FunctionTemplate.NullHandling.NULL_IF_NULL +) +public class CustomLogFunction implements DrillSimpleFunc { + + @Param + VarCharHolder input; + + @Output + VarCharHolder out; + + @Inject + DrillBuf buffer; + + public void setup() { + + } + + public void eval() { + String inputString = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start, input.end, input.buffer); + String outputValue = "LOG was overloaded. Input: " + inputString; + + out.buffer = buffer; + out.start = 0; + out.end = outputValue.getBytes().length; + buffer.setBytes(0, outputValue.getBytes()); + } +} + diff --git a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerDummyFunction.java b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerDummyFunction.java new file mode 100644 index 0000000000..1e401d1068 --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerDummyFunction.java @@ -0,0 +1,58 @@ +/* + * 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.drill.udf.dynamic; + +import io.netty.buffer.DrillBuf; +import org.apache.drill.exec.expr.DrillSimpleFunc; +import org.apache.drill.exec.expr.annotations.Output; +import org.apache.drill.exec.expr.annotations.Param; +import org.apache.drill.exec.expr.holders.VarCharHolder; + +import javax.inject.Inject; + +public class CustomLowerDummyFunction implements DrillSimpleFunc { + + @Param + VarCharHolder input; + + @Output + VarCharHolder output; + + @Inject + DrillBuf buffer; + + public void setup() { + } + + public void eval() { + + // get value + String inputString = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start, input.end, input.buffer); + + // convert to lower case + String outputValue = inputString.toLowerCase(); + + // put the output value into output buffer + output.buffer = buffer; + output.start = 0; + output.end = outputValue.getBytes().length; + buffer.setBytes(0, outputValue.getBytes()); + + } +} + diff --git a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunction.java b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunction.java new file mode 100644 index 0000000000..f868be310f --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunction.java @@ -0,0 +1,64 @@ +/* + * 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.drill.udf.dynamic; + +import io.netty.buffer.DrillBuf; +import org.apache.drill.exec.expr.DrillSimpleFunc; +import org.apache.drill.exec.expr.annotations.FunctionTemplate; +import org.apache.drill.exec.expr.annotations.Output; +import org.apache.drill.exec.expr.annotations.Param; +import org.apache.drill.exec.expr.holders.VarCharHolder; + +import javax.inject.Inject; + +@FunctionTemplate( + name="custom_lower", + scope = FunctionTemplate.FunctionScope.SIMPLE, + nulls = FunctionTemplate.NullHandling.NULL_IF_NULL +) +public class CustomLowerFunction implements DrillSimpleFunc { + + @Param + VarCharHolder input; + + @Output + VarCharHolder output; + + @Inject + DrillBuf buffer; + + public void setup() { + } + + public void eval() { + + // get value + String inputString = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start, input.end, input.buffer); + + // convert to lower case + String outputValue = inputString.toLowerCase(); + + // put the output value into output buffer + output.buffer = buffer; + output.start = 0; + output.end = outputValue.getBytes().length; + buffer.setBytes(0, outputValue.getBytes()); + + } +} + diff --git a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunctionV2.java b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunctionV2.java new file mode 100644 index 0000000000..e564d7ff09 --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomLowerFunctionV2.java @@ -0,0 +1,64 @@ +/* + * 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.drill.udf.dynamic; + +import io.netty.buffer.DrillBuf; +import org.apache.drill.exec.expr.DrillSimpleFunc; +import org.apache.drill.exec.expr.annotations.FunctionTemplate; +import org.apache.drill.exec.expr.annotations.Output; +import org.apache.drill.exec.expr.annotations.Param; +import org.apache.drill.exec.expr.holders.VarCharHolder; + +import javax.inject.Inject; + +@FunctionTemplate( + name="custom_lower", + scope = FunctionTemplate.FunctionScope.SIMPLE, + nulls = FunctionTemplate.NullHandling.NULL_IF_NULL +) +public class CustomLowerFunctionV2 implements DrillSimpleFunc { + + @Param + VarCharHolder input; + + @Output + VarCharHolder output; + + @Inject + DrillBuf buffer; + + public void setup() { + } + + public void eval() { + + // get value + String inputString = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start, input.end, input.buffer); + + // convert to lower case + String outputValue = inputString.toLowerCase() + "_v2"; + + // put the output value into output buffer + output.buffer = buffer; + output.start = 0; + output.end = outputValue.getBytes().length; + buffer.setBytes(0, outputValue.getBytes()); + + } +} + diff --git a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomUpperFunction.java b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomUpperFunction.java new file mode 100644 index 0000000000..9ac473b10a --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/CustomUpperFunction.java @@ -0,0 +1,64 @@ +/* + * 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.drill.udf.dynamic; + +import io.netty.buffer.DrillBuf; +import org.apache.drill.exec.expr.DrillSimpleFunc; +import org.apache.drill.exec.expr.annotations.FunctionTemplate; +import org.apache.drill.exec.expr.annotations.Output; +import org.apache.drill.exec.expr.annotations.Param; +import org.apache.drill.exec.expr.holders.VarCharHolder; + +import javax.inject.Inject; + +@FunctionTemplate( + name="custom_upper", + scope = FunctionTemplate.FunctionScope.SIMPLE, + nulls = FunctionTemplate.NullHandling.NULL_IF_NULL +) +public class CustomUpperFunction implements DrillSimpleFunc { + + @Param + VarCharHolder input; + + @Output + VarCharHolder output; + + @Inject + DrillBuf buffer; + + public void setup() { + } + + public void eval() { + + // get value + String inputString = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start, input.end, input.buffer); + + // convert to upper case + String outputValue = inputString.toUpperCase(); + + // put the output value into output buffer + output.buffer = buffer; + output.start = 0; + output.end = outputValue.getBytes().length; + buffer.setBytes(0, outputValue.getBytes()); + + } +} + diff --git a/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/LowerFunction.java b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/LowerFunction.java new file mode 100644 index 0000000000..0d5d149a5c --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/src/main/java/org/apache/drill/udf/dynamic/LowerFunction.java @@ -0,0 +1,64 @@ +/* + * 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.drill.udf.dynamic; + +import io.netty.buffer.DrillBuf; +import org.apache.drill.exec.expr.DrillSimpleFunc; +import org.apache.drill.exec.expr.annotations.FunctionTemplate; +import org.apache.drill.exec.expr.annotations.Output; +import org.apache.drill.exec.expr.annotations.Param; +import org.apache.drill.exec.expr.holders.VarCharHolder; + +import javax.inject.Inject; + +@FunctionTemplate( + name="lower", + scope = FunctionTemplate.FunctionScope.SIMPLE, + nulls = FunctionTemplate.NullHandling.NULL_IF_NULL +) +public class LowerFunction implements DrillSimpleFunc { + + @Param + VarCharHolder input; + + @Output + VarCharHolder output; + + @Inject + DrillBuf buffer; + + public void setup() { + } + + public void eval() { + + // get value + String inputString = org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(input.start, input.end, input.buffer); + + // convert to lower case + String outputValue = inputString.toLowerCase(); + + // put the output value into output buffer + output.buffer = buffer; + output.start = 0; + output.end = outputValue.getBytes().length; + buffer.setBytes(0, outputValue.getBytes()); + + } +} + diff --git a/exec/java-exec/src/test/resources/drill-udf/src/main/resources/drill-module.conf b/exec/java-exec/src/test/resources/drill-udf/src/main/resources/drill-module.conf new file mode 100644 index 0000000000..0b2948a2ca --- /dev/null +++ b/exec/java-exec/src/test/resources/drill-udf/src/main/resources/drill-module.conf @@ -0,0 +1 @@ +drill.classpath.scanning.packages += "org.apache.drill.udf.dynamic" diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-1.0-sources.jar b/exec/java-exec/src/test/resources/jars/DrillUDF-1.0-sources.jar deleted file mode 100644 index b5965c958f..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-1.0-sources.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-1.0.jar b/exec/java-exec/src/test/resources/jars/DrillUDF-1.0.jar deleted file mode 100644 index 7cd2eeb342..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-1.0.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-2.0-sources.jar b/exec/java-exec/src/test/resources/jars/DrillUDF-2.0-sources.jar deleted file mode 100644 index 1c8308c31c..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-2.0-sources.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-2.0.jar b/exec/java-exec/src/test/resources/jars/DrillUDF-2.0.jar deleted file mode 100644 index 3522c1e84d..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-2.0.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0-sources.jar b/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0-sources.jar deleted file mode 100644 index f6b250ec0b..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0-sources.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0.jar b/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0.jar deleted file mode 100644 index 4b5ef8bc48..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF-overloading-1.0.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0-sources.jar b/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0-sources.jar deleted file mode 100644 index fa449e270d..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0-sources.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0.jar b/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0.jar deleted file mode 100644 index 8945fe7585..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_Copy-1.0.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0-sources.jar b/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0-sources.jar deleted file mode 100644 index b19ade6371..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0-sources.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0.jar b/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0.jar deleted file mode 100644 index 56a649c470..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_DupFunc-1.0.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0-sources.jar b/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0-sources.jar deleted file mode 100644 index 2a82dc9e2f..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0-sources.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0.jar b/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0.jar deleted file mode 100644 index 11ed28b66e..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_Empty-1.0.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0-sources.jar b/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0-sources.jar deleted file mode 100644 index dbc97dd6c2..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0-sources.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0.jar b/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0.jar deleted file mode 100644 index cba65da475..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/DrillUDF_NoMarkerFile-1.0.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0-sources.jar b/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0-sources.jar deleted file mode 100644 index 583b1c4a8f..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0-sources.jar and /dev/null differ diff --git a/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0.jar b/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0.jar deleted file mode 100644 index 42df4a4016..0000000000 Binary files a/exec/java-exec/src/test/resources/jars/v2/DrillUDF-1.0.jar and /dev/null differ diff --git a/pom.xml b/pom.xml index 42729781b0..151f2084c0 100644 --- a/pom.xml +++ b/pom.xml @@ -798,9 +798,9 @@ <!-- Test Dependencies --> <dependency> <!-- JMockit needs to be on class path before JUnit. --> - <groupId>com.googlecode.jmockit</groupId> + <groupId>org.jmockit</groupId> <artifactId>jmockit</artifactId> - <version>1.3</version> + <version>1.39</version> <scope>test</scope> </dependency> <dependency> @@ -814,7 +814,8 @@ long as Mockito _contains_ older Hamcrest classes. See DRILL-2130. --> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>1.9.5</version> + <version>2.18.3</version> + <scope>test</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > Remove binary jars files from source distribution > ------------------------------------------------- > > Key: DRILL-6272 > URL: https://issues.apache.org/jira/browse/DRILL-6272 > Project: Apache Drill > Issue Type: Task > Reporter: Vlad Rozov > Assignee: Arina Ielchiieva > Priority: Critical > Labels: ready-to-commit > Fix For: 1.14.0 > > > Per [~vrozov] the source distribution contains binary jar files under > exec/java-exec/src/test/resources/jars -- This message was sent by Atlassian JIRA (v7.6.3#76005)