New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DRILL-6272: Refactor dynamic UDFs and function initializer tests to g… #1225
Conversation
@vrozov please review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will it be easier to use (embedded) maven to create necessary jars?
URL[] urls = {jars.resolve(binaryName).toUri().toURL(), jars.resolve(sourceName).toUri().toURL()}; | ||
String binaryName = "DrillUDF-1.0"; | ||
URL template = ClassLoader.getSystemClassLoader().getResource("udf/dynamic/CustomLowerFunctionTemplate"); | ||
assert template != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use junit assert in unit tests.
@@ -0,0 +1,45 @@ | |||
package org.apache.drill.udf.dynamic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apache license
out.end = outputValue.getBytes().length; | ||
buffer.setBytes(0, outputValue.getBytes()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LF
d17439f
to
ac2c97d
Compare
@vrozov addressed code review comments. |
@arina-ielchiieva I don't see why using maven embedder is a less preferable option. Using maven it is possible to create source jars using standard maven plugin. IMO, it will be easier to modify test UDF project if necessary and it is still possible to debug and run tests using IDE or maven. There will be no dependency on a build tool, it is a dependency on an external jar similar to any other external jar dependency. |
@vrozov I'll re-work PR with maven embedder, thanks for the idea. I'll ping you when changes are done. |
ac2c97d
to
7ac9f12
Compare
@vrozov re-implemented using maven embedder. Had to upgrade jmokcit lib to the latest version since it caused NPE with maven embedder (NPE from jmockit even if no mocks are used, fixed in newer version). Please review. |
pom.xml
Outdated
@@ -798,7 +798,7 @@ | |||
<!-- JMockit needs to be on class path before JUnit. --> | |||
<groupId>com.googlecode.jmockit</groupId> | |||
<artifactId>jmockit</artifactId> | |||
<version>1.3</version> | |||
<version>1.7</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can it be done as a precursor PR? 1.7 version is quite old too. Can it be upgraded to the latest (org.jmockit:jmockit:1.39)?
exec/java-exec/pom.xml
Outdated
<dependency> | ||
<groupId>org.apache.maven</groupId> | ||
<artifactId>maven-embedder</artifactId> | ||
<version>3.3.9</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using the latest release available.
7ac9f12
to
2169aa2
Compare
@vrozov now PR contains two commits:
|
@@ -177,7 +177,7 @@ public void run() { | |||
} | |||
} | |||
|
|||
//@Test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason the test was disabled before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have accidentally disabled in my previous PR. Did not want to create separate Jira for one line fix so included it here.
@@ -125,7 +125,7 @@ public void testHasPathThrowsDrillRuntimeException() { | |||
|
|||
Mockito | |||
.when(client.getCache().getCurrentData(absPath)) | |||
.thenThrow(Exception.class); | |||
.thenThrow(RuntimeException.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but I am not sure what does this method test. ZookeeperClient.hasPath(String path)
is not used in production.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just fixed this test to work with new mockito lib version. I suspect this test checks if exception thrown from client.getCache().getCurrentData(absPath)
method will be wrapped in DrillRuntimeException.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, this method needs to be changed to test ZookeeperClient.hasPath(String path, boolean consistent)
. It is OK to do it in this PR or in a separate commit/JIRA/PR. If you decide to do it in a separate commit, please file JIRA.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do it in different PR.
@BeforeClass | ||
public static void init() throws Exception { | ||
MockUp<UUID> uuidMockUp = mockRandomUUID(session_id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is hard to say whether you want to change test logic or need a workaround for the removed MockUp.tearDown()
method. In the latter case consider adding getTemporaryName()
method to the UserSession
class. The method can delegate to UUID.randomUUID()
in production and can be mocked to return a predefined value in tests like this one. It will allow not to mock UUID.randomUUID()
at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to re-write this part since MockUp.tearDown()
is not present in newer jmockit version. Now we don't mock session id at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UUID.randomUUID()
was mocked both for session id and temporary table name. Can you get temporary table name the same way you do it for session id?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, from user session: userSession.resolveTemporaryTableName(tableName)
.
} | ||
String temporaryTableName = "temporary_table_outside_of_default_workspace"; | ||
|
||
thrown.expect(UserRemoteException.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider introducing a new method to set thrown
and message, something like void expectUserRemoteExceptionWithMessage(String message)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
thrown.expect(UserRemoteException.class); | ||
thrown.expectMessage(containsString(String.format( | ||
"VALIDATION ERROR: A table or view with given name [%s]" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and possibly expectUserRemoteExceptionWithTableExistsMessage(String tableName, String schemaName)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
test("drop view %s.%s", DFS_TMP_SCHEMA, temporaryTableName); | ||
} | ||
|
||
private static String getSessionId() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider mocking getSessionId() in the UserSession
. This method needs to be tested by itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-written, it turned out I have access to UserSession
through DrillbitContext
, so no mock is required at all.
return cli.doMain(params.toArray(new String[params.size()]), projectDir, System.out, System.err); | ||
} | ||
|
||
private static Logger setupLogger(String string, Level logLevel) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, since I want to output info level logging when creating jars. Otherwise, no logs on how jars were created will appear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should depend on log level and not be forcefully overridden. To debug, you have two options, either add "-X" to maven arguments or change log level for that logger in logback-test.xml
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, removed.
String sourceName = JarUtil.getSourceName(binaryName); | ||
URL[] urls = {jars.resolve(binaryName).toUri().toURL(), jars.resolve(sourceName).toUri().toURL()}; | ||
File projectDir = dirTestWatcher.makeSubDir(Paths.get("drill-udf")); | ||
FileUtils.copyDirectory(getResourceFile(Paths.get(projectDir.getName())), projectDir); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using <directory>
in pom.xml if the goal here is to avoid creating files in the src
path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks.
|
||
<properties> | ||
<jar.finalName>${project.name}</jar.finalName> | ||
<drill.version>1.13.0</drill.version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it OK to use old version? Does Drill support semver API compatibility for UDFs? If yes, how is it enforced? If no, compilation may fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My previous jars used 1.8.0. for example, since I created them when that only version was available. API for Drill UDFs is public so we should not change it. There is no enforcement though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is a reason not to use the SNAPSHOT version? Let's say somebody wants to introduce a new API for UDF and test it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used DrillVersionInfo.getVersion()
to pas current Drill project version to the build.
@vrozov addressed code review comments in the new commit. Please review. |
@Category(SqlFunctionTest.class) | ||
public class FunctionInitializerTest { | ||
|
||
private static final String CLASS_NAME = "com.drill.udf.CustomLowerFunction"; | ||
@ClassRule | ||
public static final BaseDirTestWatcher dirTestWatcher = new BaseDirTestWatcher(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, missed that in my previous review. Consider using TemporaryFolder
rule instead of BaseDirTestWatcher
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, fixed.
|
||
JarBuilder jarBuilder = new JarBuilder("src/test/resources/drill-udf"); | ||
int result = jarBuilder.build(binaryName, buildDirectory.getAbsolutePath(), "**/CustomLowerFunction.java", null); | ||
assertEquals("Build should be successful.", 0, result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider moving assertEquals
inside JarBuilder.build()
and returning name of the binary jar instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
throw e; | ||
} | ||
|
||
expectUserRemoteExceptionWithTableExistsMessage(temporaryTableName, DFS_TMP_SCHEMA); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move it between test
calls. My understanding the first one should succeed without exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely the same pattern applies to other unit tests with mulitple calls to test
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, fixed.
<groupId>org.apache.drill.exec</groupId> | ||
<artifactId>drill-java-exec</artifactId> | ||
<version>${drill.version}</version> | ||
<scope>compile</scope> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be provided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
* @return build exit code, 0 if build was successful | ||
*/ | ||
public int build(String jarName, String buildDirectory, String includeFiles, String includeResources) { | ||
System.setProperty("maven.multiModuleProjectDirectory", projectDirectory); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check if the property already set. It probably will be good to restore the property to it's original value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
f96c741
to
fc7aac5
Compare
@vrozov addressed code review comments in two new commits. Please review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly LGTM (see few minor comments). Rebase and squash to two commits.
throw e; | ||
} | ||
|
||
expectUserRemoteExceptionWithTableExistsMessage(temporaryTableName, DFS_TMP_SCHEMA); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this one too.
assertEquals("Build should be successful.", 0, result); | ||
return jarName + ".jar"; | ||
} finally { | ||
if (originalPropertyValue != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider originalPropertyValue != null ? System.setProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY, originalPropertyValue) : System.clearProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY);
.
@@ -101,6 +110,9 @@ public static void setup() throws IOException { | |||
fsUri = getLocalFileSystem().getUri(); | |||
} | |||
|
|||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
|
|||
@Rule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the rule necessary? Can @After
provide the same functionality? If yes, please file JIRA.
|
||
@BeforeClass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider @Before
instead of calling it from reset()
.
fc7aac5
to
9834869
Compare
@vrozov done all the changes. One point regarding using current drill snapshot version as dependency when building jars. I decided to leave it hard-coded to 1.13.0 because
|
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 FileSystem fs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can fs
and permissions be declared as local variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, they are defined in @BeforeClass
and the same for all tests.
@Before | ||
public void setup() throws Exception { | ||
public void setup() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to mock UUID
?. You mentioned that there is a way to get sessionId from UserSession.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, yes. It turned out that there is no good way to retrieve session information in tests. Sorry for confusion.
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"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case mocking is required, consider replacing String with UUID: uuid = UUID.nameUUIDFromBytes(session_id.getBytes())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced it to UUID.randomUUID()
.
assertEquals("Build should be successful.", 0, result); | ||
return jarName + ".jar"; | ||
} finally { | ||
if (originalPropertyValue != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
public String build(String jarName, String buildDirectory, String includeFiles, String includeResources) { | ||
String originalPropertyValue = null; | ||
try { | ||
originalPropertyValue = System.setProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY, projectDirectory); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not split into two assignments. Move System.setProperty()
call outside of try/finally block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
9834869
to
99e2cf3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vrozov done the changes.
public String build(String jarName, String buildDirectory, String includeFiles, String includeResources) { | ||
String originalPropertyValue = null; | ||
try { | ||
originalPropertyValue = System.setProperty(MAVEN_MULTI_MODULE_PROJECT_DIRECTORY, projectDirectory); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
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"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced it to UUID.randomUUID()
.
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 FileSystem fs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, they are defined in @BeforeClass
and the same for all tests.
@Before | ||
public void setup() throws Exception { | ||
public void setup() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, yes. It turned out that there is no good way to retrieve session information in tests. Sorry for confusion.
assertEquals("Build should be successful.", 0, result); | ||
return jarName + ".jar"; | ||
} finally { | ||
if (originalPropertyValue != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
b5fc082
to
166a7b1
Compare
@arina-ielchiieva I encountered some merge conflicts. Can you pls rebase on master ? |
166a7b1
to
4b65235
Compare
@amansinha100 done. |
@@ -47,7 +48,7 @@ | |||
.indexOf("-agentlib:jdwp") > 0; | |||
|
|||
public static TestRule getTimeoutRule(int timeout) { | |||
return IS_DEBUG ? new TestName() : new Timeout(timeout); | |||
return IS_DEBUG ? new TestName() : new Timeout(timeout, TimeUnit.MILLISECONDS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Timeout.millis(timeout)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, fixed.
…enerate needed binary and source jars at runtime
4b65235
to
670f252
Compare
LGTM |
…enerate needed binary and source jars at runtime
Details in DRILL-6272.