This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-paimon.git
The following commit(s) were added to refs/heads/master by this push:
new f17193077 [hive] Get rid of flink-connector-hive dependency in
paimon-hive (#776)
f17193077 is described below
commit f17193077bd6be612ce413f524de92d526f457f8
Author: Kerwin <[email protected]>
AuthorDate: Mon Apr 3 14:10:17 2023 +0800
[hive] Get rid of flink-connector-hive dependency in paimon-hive (#776)
---
paimon-hive/paimon-hive-connector-2.3/pom.xml | 16 +-
.../apache/paimon/hive/Hive23CatalogITCase.java | 4 +-
paimon-hive/paimon-hive-connector-3.1/pom.xml | 16 +-
.../apache/paimon/hive/Hive31CatalogITCase.java | 4 +-
paimon-hive/paimon-hive-connector-common/pom.xml | 17 +-
.../apache/paimon/hive/HiveCatalogITCaseBase.java | 4 +-
.../paimon/hive/PaimonStorageHandlerITCase.java | 4 +-
.../hive/runner/PaimonEmbeddedHiveRunner.java | 353 +++++++++++++++++++++
.../runner/PaimonEmbeddedHiveServerContext.java | 233 ++++++++++++++
.../src/test/resources/hive-site.xml | 53 ++++
10 files changed, 656 insertions(+), 48 deletions(-)
diff --git a/paimon-hive/paimon-hive-connector-2.3/pom.xml
b/paimon-hive/paimon-hive-connector-2.3/pom.xml
index 75e950093..c33297b37 100644
--- a/paimon-hive/paimon-hive-connector-2.3/pom.xml
+++ b/paimon-hive/paimon-hive-connector-2.3/pom.xml
@@ -74,31 +74,23 @@ under the License.
<dependency>
<groupId>org.apache.flink</groupId>
-
<artifactId>flink-table-planner_${scala.binary.version}</artifactId>
+ <artifactId>flink-connector-files</artifactId>
<version>${test.flink.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
- <artifactId>flink-table-runtime</artifactId>
- <version>${test.flink.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.flink</groupId>
-
<artifactId>flink-connector-hive_${scala.binary.version}</artifactId>
+
<artifactId>flink-table-planner_${scala.binary.version}</artifactId>
<version>${test.flink.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
-
<artifactId>flink-connector-hive_${scala.binary.version}</artifactId>
+ <artifactId>flink-table-runtime</artifactId>
<version>${test.flink.version}</version>
<scope>test</scope>
- <type>test-jar</type>
</dependency>
<dependency>
@@ -480,7 +472,7 @@ under the License.
</dependency>
<!--
- hive-exec must stay after flink-connector-hive and avro to avoid
conflicts
+ hive-exec must stay after avro to avoid conflicts
-->
<dependency>
<groupId>org.apache.hive</groupId>
diff --git
a/paimon-hive/paimon-hive-connector-2.3/src/test/java/org/apache/paimon/hive/Hive23CatalogITCase.java
b/paimon-hive/paimon-hive-connector-2.3/src/test/java/org/apache/paimon/hive/Hive23CatalogITCase.java
index 2df418e37..b2d38da4b 100644
---
a/paimon-hive/paimon-hive-connector-2.3/src/test/java/org/apache/paimon/hive/Hive23CatalogITCase.java
+++
b/paimon-hive/paimon-hive-connector-2.3/src/test/java/org/apache/paimon/hive/Hive23CatalogITCase.java
@@ -19,11 +19,11 @@
package org.apache.paimon.hive;
import org.apache.paimon.fs.local.LocalFileIO;
+import org.apache.paimon.hive.runner.PaimonEmbeddedHiveRunner;
import org.apache.paimon.schema.SchemaManager;
import com.klarna.hiverunner.annotations.HiveRunnerSetup;
import com.klarna.hiverunner.config.HiveRunnerConfig;
-import org.apache.flink.connectors.hive.FlinkEmbeddedHiveRunner;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableException;
import org.apache.flink.table.api.internal.TableEnvironmentImpl;
@@ -42,7 +42,7 @@ import static
org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** IT cases for using Paimon {@link HiveCatalog} together with Paimon Hive
2.3 connector. */
-@RunWith(FlinkEmbeddedHiveRunner.class)
+@RunWith(PaimonEmbeddedHiveRunner.class)
public class Hive23CatalogITCase extends HiveCatalogITCaseBase {
@HiveRunnerSetup
diff --git a/paimon-hive/paimon-hive-connector-3.1/pom.xml
b/paimon-hive/paimon-hive-connector-3.1/pom.xml
index 942cc340f..4ff741e84 100644
--- a/paimon-hive/paimon-hive-connector-3.1/pom.xml
+++ b/paimon-hive/paimon-hive-connector-3.1/pom.xml
@@ -81,31 +81,23 @@ under the License.
<dependency>
<groupId>org.apache.flink</groupId>
-
<artifactId>flink-table-planner_${scala.binary.version}</artifactId>
+ <artifactId>flink-connector-files</artifactId>
<version>${test.flink.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
- <artifactId>flink-table-runtime</artifactId>
- <version>${test.flink.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.flink</groupId>
-
<artifactId>flink-connector-hive_${scala.binary.version}</artifactId>
+
<artifactId>flink-table-planner_${scala.binary.version}</artifactId>
<version>${test.flink.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
-
<artifactId>flink-connector-hive_${scala.binary.version}</artifactId>
+ <artifactId>flink-table-runtime</artifactId>
<version>${test.flink.version}</version>
<scope>test</scope>
- <type>test-jar</type>
</dependency>
<dependency>
@@ -498,7 +490,7 @@ under the License.
</dependency>
<!--
- hive-exec must stay after flink-connector-hive and avro to avoid
conflicts
+ hive-exec must stay after avro to avoid conflicts
-->
<dependency>
<groupId>org.apache.hive</groupId>
diff --git
a/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/Hive31CatalogITCase.java
b/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/Hive31CatalogITCase.java
index 26d24c74b..84860dcde 100644
---
a/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/Hive31CatalogITCase.java
+++
b/paimon-hive/paimon-hive-connector-3.1/src/test/java/org/apache/paimon/hive/Hive31CatalogITCase.java
@@ -19,11 +19,11 @@
package org.apache.paimon.hive;
import org.apache.paimon.fs.local.LocalFileIO;
+import org.apache.paimon.hive.runner.PaimonEmbeddedHiveRunner;
import org.apache.paimon.schema.SchemaManager;
import com.klarna.hiverunner.annotations.HiveRunnerSetup;
import com.klarna.hiverunner.config.HiveRunnerConfig;
-import org.apache.flink.connectors.hive.FlinkEmbeddedHiveRunner;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableException;
import org.apache.flink.table.api.internal.TableEnvironmentImpl;
@@ -42,7 +42,7 @@ import static
org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** IT cases for using Paimon {@link HiveCatalog} together with Paimon Hive
3.1 connector. */
-@RunWith(FlinkEmbeddedHiveRunner.class)
+@RunWith(PaimonEmbeddedHiveRunner.class)
public class Hive31CatalogITCase extends HiveCatalogITCaseBase {
@HiveRunnerSetup
diff --git a/paimon-hive/paimon-hive-connector-common/pom.xml
b/paimon-hive/paimon-hive-connector-common/pom.xml
index 5736a6000..d9fa60865 100644
--- a/paimon-hive/paimon-hive-connector-common/pom.xml
+++ b/paimon-hive/paimon-hive-connector-common/pom.xml
@@ -121,21 +121,6 @@ under the License.
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.apache.flink</groupId>
-
<artifactId>flink-connector-hive_${scala.binary.version}</artifactId>
- <version>${test.flink.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.flink</groupId>
-
<artifactId>flink-connector-hive_${scala.binary.version}</artifactId>
- <version>${test.flink.version}</version>
- <scope>test</scope>
- <type>test-jar</type>
- </dependency>
-
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-orc</artifactId>
@@ -477,7 +462,7 @@ under the License.
</dependency>
<!--
- hive-exec must stay after flink-connector-hive and avro to avoid
conflicts
+ hive-exec must stay after avro to avoid conflicts
-->
<dependency>
<groupId>org.apache.hive</groupId>
diff --git
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java
index 86b7d4995..d50bb16e2 100644
---
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java
+++
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java
@@ -24,10 +24,10 @@ import org.apache.paimon.catalog.CatalogLock;
import org.apache.paimon.catalog.Identifier;
import org.apache.paimon.flink.FlinkCatalog;
import org.apache.paimon.fs.local.LocalFileIO;
+import org.apache.paimon.hive.runner.PaimonEmbeddedHiveRunner;
import com.klarna.hiverunner.HiveShell;
import com.klarna.hiverunner.annotations.HiveSQL;
-import org.apache.flink.connectors.hive.FlinkEmbeddedHiveRunner;
import org.apache.flink.core.fs.Path;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;
@@ -56,7 +56,7 @@ import static
org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
/** IT cases for using Paimon {@link HiveCatalog} together with Paimon Hive
connector. */
-@RunWith(FlinkEmbeddedHiveRunner.class)
+@RunWith(PaimonEmbeddedHiveRunner.class)
public abstract class HiveCatalogITCaseBase {
@Rule public TemporaryFolder folder = new TemporaryFolder();
diff --git
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/PaimonStorageHandlerITCase.java
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/PaimonStorageHandlerITCase.java
index 28f519b1b..760388d31 100644
---
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/PaimonStorageHandlerITCase.java
+++
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/PaimonStorageHandlerITCase.java
@@ -26,6 +26,7 @@ import org.apache.paimon.data.InternalRow;
import org.apache.paimon.data.Timestamp;
import org.apache.paimon.hive.mapred.PaimonInputFormat;
import org.apache.paimon.hive.objectinspector.PaimonObjectInspectorFactory;
+import org.apache.paimon.hive.runner.PaimonEmbeddedHiveRunner;
import org.apache.paimon.options.CatalogOptions;
import org.apache.paimon.options.Options;
import org.apache.paimon.table.Table;
@@ -39,7 +40,6 @@ import org.apache.paimon.types.RowType;
import com.klarna.hiverunner.HiveShell;
import com.klarna.hiverunner.annotations.HiveSQL;
-import org.apache.flink.connectors.hive.FlinkEmbeddedHiveRunner;
import org.apache.hadoop.hive.common.type.HiveDecimal;
import org.apache.hadoop.hive.serde2.objectinspector.ListObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.MapObjectInspector;
@@ -65,7 +65,7 @@ import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
/** IT cases for {@link PaimonStorageHandler} and {@link PaimonInputFormat}. */
-@RunWith(FlinkEmbeddedHiveRunner.class)
+@RunWith(PaimonEmbeddedHiveRunner.class)
public class PaimonStorageHandlerITCase {
@ClassRule public static TemporaryFolder folder = new TemporaryFolder();
diff --git
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/runner/PaimonEmbeddedHiveRunner.java
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/runner/PaimonEmbeddedHiveRunner.java
new file mode 100644
index 000000000..3289c6a26
--- /dev/null
+++
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/runner/PaimonEmbeddedHiveRunner.java
@@ -0,0 +1,353 @@
+/*
+ * 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.paimon.hive.runner;
+
+import org.apache.paimon.utils.Preconditions;
+
+import com.klarna.hiverunner.HiveServerContainer;
+import com.klarna.hiverunner.HiveServerContext;
+import com.klarna.hiverunner.HiveShell;
+import com.klarna.hiverunner.HiveShellContainer;
+import com.klarna.hiverunner.annotations.HiveProperties;
+import com.klarna.hiverunner.annotations.HiveResource;
+import com.klarna.hiverunner.annotations.HiveRunnerSetup;
+import com.klarna.hiverunner.annotations.HiveSQL;
+import com.klarna.hiverunner.annotations.HiveSetupScript;
+import com.klarna.hiverunner.builder.HiveShellBuilder;
+import com.klarna.hiverunner.config.HiveRunnerConfig;
+import com.klarna.reflection.ReflectionUtils;
+import org.apache.flink.shaded.guava30.com.google.common.io.Resources;
+import org.junit.Ignore;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.internal.runners.model.EachTestNotifier;
+import org.junit.rules.ExternalResource;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.reflections.ReflectionUtils.withAnnotation;
+
+/**
+ * JUnit 4 runner that runs hive sql on a HiveServer residing in this JVM. No
external dependencies
+ * needed. Inspired by StandaloneHiveRunner.java (almost copied).
+ */
+public class PaimonEmbeddedHiveRunner extends BlockJUnit4ClassRunner {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(PaimonEmbeddedHiveRunner.class);
+ private HiveShellContainer container;
+ private final HiveRunnerConfig config = new HiveRunnerConfig();
+ protected HiveServerContext context;
+
+ public PaimonEmbeddedHiveRunner(Class<?> clazz) throws InitializationError
{
+ super(clazz);
+ }
+
+ @Override
+ protected List<TestRule> classRules() {
+ // need to load hive runner config before the context is inited
+ loadAnnotatesHiveRunnerConfig(getTestClass().getJavaClass());
+ final TemporaryFolder temporaryFolder = new TemporaryFolder();
+ context = new PaimonEmbeddedHiveServerContext(temporaryFolder, config);
+ List<TestRule> rules = super.classRules();
+ ExternalResource hiveShell =
+ new ExternalResource() {
+ @Override
+ protected void before() throws Throwable {
+ container =
+
createHiveServerContainer(getTestClass().getJavaClass(), context);
+ }
+
+ @Override
+ protected void after() {
+ tearDown();
+ }
+ };
+ rules.add(hiveShell);
+ rules.add(temporaryFolder);
+ return rules;
+ }
+
+ @Override
+ protected void runChild(final FrameworkMethod method, RunNotifier
notifier) {
+ Description description = describeChild(method);
+ if (method.getAnnotation(Ignore.class) != null) {
+ notifier.fireTestIgnored(description);
+ } else {
+ EachTestNotifier eachNotifier = new EachTestNotifier(notifier,
description);
+ eachNotifier.fireTestStarted();
+ try {
+ runTestMethod(method, eachNotifier);
+ } finally {
+ eachNotifier.fireTestFinished();
+ }
+ }
+ }
+
+ /** Runs a {@link Statement} that represents a leaf (aka atomic) test. */
+ private void runTestMethod(FrameworkMethod method, EachTestNotifier
notifier) {
+ Statement statement = methodBlock(method);
+
+ try {
+ statement.evaluate();
+ } catch (AssumptionViolatedException e) {
+ notifier.addFailedAssumption(e);
+ } catch (Throwable e) {
+ notifier.addFailure(e);
+ }
+ }
+
+ private void tearDown() {
+ if (container != null) {
+ LOGGER.info("Tearing down {}", getName());
+ try {
+ container.tearDown();
+ } catch (Throwable e) {
+ LOGGER.warn("Tear down failed: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Traverses the test class annotations. Will inject a HiveShell in the
test case that envelopes
+ * the HiveServer.
+ */
+ private HiveShellContainer createHiveServerContainer(
+ final Class testClass, HiveServerContext context) throws Exception
{
+
+ context.init();
+
+ final HiveServerContainer hiveServerContainer = new
HiveServerContainer(context);
+
+ HiveShellBuilder hiveShellBuilder = new HiveShellBuilder();
+ setCommandShellEmulation(hiveShellBuilder, config);
+
+ HiveShellField shellSetter = loadScriptsUnderTest(testClass,
hiveShellBuilder);
+
+ hiveShellBuilder.setHiveServerContainer(hiveServerContainer);
+
+ loadAnnotatedResources(testClass, hiveShellBuilder);
+
+ loadAnnotatedProperties(testClass, hiveShellBuilder);
+
+ loadAnnotatedSetupScripts(testClass, hiveShellBuilder);
+
+ // Build shell
+ final HiveShellContainer shell = hiveShellBuilder.buildShell();
+
+ // Set shell
+ shellSetter.setShell(shell);
+
+ if (shellSetter.isAutoStart()) {
+ shell.start();
+ }
+
+ return shell;
+ }
+
+ private void setCommandShellEmulation(HiveShellBuilder builder,
HiveRunnerConfig config)
+ throws Exception {
+ Method method =
config.getClass().getDeclaredMethod("getCommandShellEmulator");
+ Object emulator = method.invoke(config);
+ Class emulatorClz =
Class.forName("com.klarna.hiverunner.sql.cli.CommandShellEmulator");
+ method =
builder.getClass().getDeclaredMethod("setCommandShellEmulation", emulatorClz);
+ method.invoke(builder, emulator);
+ }
+
+ private void loadAnnotatesHiveRunnerConfig(Class testClass) {
+ Set<Field> fields =
+ ReflectionUtils.getAllFields(testClass,
withAnnotation(HiveRunnerSetup.class));
+ Preconditions.checkState(
+ fields.size() <= 1,
+ "Exact one field of type HiveRunnerConfig should to be
annotated with @HiveRunnerSetup");
+
+ // Override the config with test case config. Taking care to not
replace the config instance
+ // since it
+ // has been passes around and referenced by some of the other test
rules.
+ if (!fields.isEmpty()) {
+ Field field = fields.iterator().next();
+ Preconditions.checkState(
+ ReflectionUtils.isOfType(field, HiveRunnerConfig.class),
+ "Field annotated with @HiveRunnerSetup should be of type
HiveRunnerConfig");
+ config.override(
+ ReflectionUtils.getStaticFieldValue(
+ testClass, field.getName(),
HiveRunnerConfig.class));
+ }
+ }
+
+ private HiveShellField loadScriptsUnderTest(
+ final Class testClass, HiveShellBuilder hiveShellBuilder) {
+ try {
+ Set<Field> fields =
+ ReflectionUtils.getAllFields(testClass,
withAnnotation(HiveSQL.class));
+
+ Preconditions.checkState(
+ fields.size() == 1, "Exactly one field should to be
annotated with @HiveSQL");
+
+ final Field field = fields.iterator().next();
+ List<Path> scripts = new ArrayList<>();
+ HiveSQL annotation = field.getAnnotation(HiveSQL.class);
+ for (String scriptFilePath : annotation.files()) {
+ Path file =
Paths.get(Resources.getResource(scriptFilePath).toURI());
+ Preconditions.checkState(Files.exists(file), "File " + file +
" does not exist");
+ scripts.add(file);
+ }
+
+ Charset charset =
+ annotation.encoding().equals("")
+ ? Charset.defaultCharset()
+ : Charset.forName(annotation.encoding());
+
+ final boolean isAutoStart = annotation.autoStart();
+
+ hiveShellBuilder.setScriptsUnderTest(scripts, charset);
+
+ return new HiveShellField() {
+ @Override
+ public void setShell(HiveShell shell) {
+ ReflectionUtils.setStaticField(testClass, field.getName(),
shell);
+ }
+
+ @Override
+ public boolean isAutoStart() {
+ return isAutoStart;
+ }
+ };
+ } catch (Throwable t) {
+ throw new IllegalArgumentException(
+ "Failed to init field annotated with @HiveSQL: " +
t.getMessage(), t);
+ }
+ }
+
+ private void loadAnnotatedSetupScripts(Class testClass, HiveShellBuilder
hiveShellBuilder) {
+ Set<Field> setupScriptFields =
+ ReflectionUtils.getAllFields(testClass,
withAnnotation(HiveSetupScript.class));
+ for (Field setupScriptField : setupScriptFields) {
+ if (ReflectionUtils.isOfType(setupScriptField, String.class)) {
+ String script =
+ ReflectionUtils.getStaticFieldValue(
+ testClass, setupScriptField.getName(),
String.class);
+ hiveShellBuilder.addSetupScript(script);
+ } else if (ReflectionUtils.isOfType(setupScriptField, File.class)
+ || ReflectionUtils.isOfType(setupScriptField, Path.class))
{
+ Path path = getMandatoryPathFromField(testClass,
setupScriptField);
+ hiveShellBuilder.addSetupScript(readAll(path));
+ } else {
+ throw new IllegalArgumentException(
+ "Field annotated with @HiveSetupScript currently only
supports type String, File and Path");
+ }
+ }
+ }
+
+ private static String readAll(Path path) {
+ try {
+ return new String(Files.readAllBytes(path),
StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to read " + path + ": " +
e.getMessage(), e);
+ }
+ }
+
+ private void loadAnnotatedResources(Class testClass, HiveShellBuilder
workFlowBuilder)
+ throws IOException {
+ Set<Field> fields =
+ ReflectionUtils.getAllFields(testClass,
withAnnotation(HiveResource.class));
+
+ for (Field resourceField : fields) {
+
+ HiveResource annotation =
resourceField.getAnnotation(HiveResource.class);
+ String targetFile = annotation.targetFile();
+
+ if (ReflectionUtils.isOfType(resourceField, String.class)) {
+ String data =
+ ReflectionUtils.getStaticFieldValue(
+ testClass, resourceField.getName(),
String.class);
+ workFlowBuilder.addResource(targetFile, data);
+ } else if (ReflectionUtils.isOfType(resourceField, File.class)
+ || ReflectionUtils.isOfType(resourceField, Path.class)) {
+ Path dataFile = getMandatoryPathFromField(testClass,
resourceField);
+ workFlowBuilder.addResource(targetFile, dataFile);
+ } else {
+ throw new IllegalArgumentException(
+ "Fields annotated with @HiveResource currently only
supports field type String, File or Path");
+ }
+ }
+ }
+
+ private Path getMandatoryPathFromField(Class testClass, Field
resourceField) {
+ Path path;
+ if (ReflectionUtils.isOfType(resourceField, File.class)) {
+ File dataFile =
+ ReflectionUtils.getStaticFieldValue(
+ testClass, resourceField.getName(), File.class);
+ path = Paths.get(dataFile.toURI());
+ } else if (ReflectionUtils.isOfType(resourceField, Path.class)) {
+ path =
+ ReflectionUtils.getStaticFieldValue(
+ testClass, resourceField.getName(), Path.class);
+ } else {
+ throw new IllegalArgumentException(
+ "Only Path or File type is allowed on annotated field " +
resourceField);
+ }
+
+ Preconditions.checkArgument(Files.exists(path), "File %s does not
exist", path);
+ return path;
+ }
+
+ private void loadAnnotatedProperties(Class testClass, HiveShellBuilder
workFlowBuilder) {
+ for (Field hivePropertyField :
+ ReflectionUtils.getAllFields(testClass,
withAnnotation(HiveProperties.class))) {
+ Preconditions.checkState(
+ ReflectionUtils.isOfType(hivePropertyField, Map.class),
+ "Field annotated with @HiveProperties should be of type
Map<String, String>");
+ workFlowBuilder.putAllProperties(
+ ReflectionUtils.getStaticFieldValue(
+ testClass, hivePropertyField.getName(),
Map.class));
+ }
+ }
+
+ /**
+ * Used as a handle for the HiveShell field in the test case so that we
may set it once the
+ * HiveShell has been instantiated.
+ */
+ interface HiveShellField {
+ void setShell(HiveShell shell);
+
+ boolean isAutoStart();
+ }
+}
diff --git
a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/runner/PaimonEmbeddedHiveServerContext.java
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/runner/PaimonEmbeddedHiveServerContext.java
new file mode 100644
index 000000000..3de27f66e
--- /dev/null
+++
b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/runner/PaimonEmbeddedHiveServerContext.java
@@ -0,0 +1,233 @@
+/*
+ * 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.paimon.hive.runner;
+
+import com.klarna.hiverunner.HiveServerContext;
+import com.klarna.hiverunner.config.HiveRunnerConfig;
+import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.HADOOPBIN;
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVECONVERTJOIN;
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVEHISTORYFILELOC;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVEMETADATAONLYQUERIES;
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVEOPTINDEXFILTER;
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVESKEWJOIN;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVESTATSAUTOGATHER;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVE_AUTHORIZATION_MANAGER;
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVE_CBO_ENABLED;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVE_INFER_BUCKET_SORT;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVE_SERVER2_LOGGING_OPERATION_ENABLED;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.HIVE_SUPPORT_CONCURRENCY;
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.LOCALSCRATCHDIR;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.METASTORECONNECTURLKEY;
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.METASTOREWAREHOUSE;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.METASTORE_VALIDATE_COLUMNS;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.METASTORE_VALIDATE_CONSTRAINTS;
+import static
org.apache.hadoop.hive.conf.HiveConf.ConfVars.METASTORE_VALIDATE_TABLES;
+import static org.apache.hadoop.hive.conf.HiveConf.ConfVars.SCRATCHDIR;
+
+/** HiveServerContext used by PaimonEmbeddedHiveRunner. */
+public class PaimonEmbeddedHiveServerContext implements HiveServerContext {
+
+ private final HiveConf hiveConf = new HiveConf();
+
+ private final TemporaryFolder basedir;
+ private final HiveRunnerConfig hiveRunnerConfig;
+ private boolean inited = false;
+
+ PaimonEmbeddedHiveServerContext(TemporaryFolder basedir, HiveRunnerConfig
hiveRunnerConfig) {
+ this.basedir = basedir;
+ this.hiveRunnerConfig = hiveRunnerConfig;
+ }
+
+ @Override
+ public final void init() {
+ if (!inited) {
+
+ configureMiscHiveSettings();
+
+ configureMetaStore();
+
+ configureMrExecutionEngine();
+
+ configureJavaSecurityRealm();
+
+ configureSupportConcurrency();
+
+ configureFileSystem();
+
+ configureAssertionStatus();
+
+ overrideHiveConf();
+
+ setHiveSitePath();
+ }
+ inited = true;
+ }
+
+ // Some Hive code may create HiveConf instances relying on the hive-site
in classpath. Make sure
+ // such code can
+ // read the configurations we set here.
+ private void setHiveSitePath() {
+ File hiveSite = new File(newFolder(basedir, "hive-conf"),
"hive-site.xml");
+ try (FileOutputStream outputStream = new FileOutputStream(hiveSite)) {
+ hiveConf.writeXml(outputStream);
+ HiveConf.setHiveSiteLocation(hiveSite.toURI().toURL());
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to write hive-site.xml", e);
+ }
+ }
+
+ private void configureMiscHiveSettings() {
+ hiveConf.setBoolVar(HIVESTATSAUTOGATHER, false);
+
+ // Turn off CBO so we don't depend on calcite
+ hiveConf.setBoolVar(HIVE_CBO_ENABLED, false);
+
+ // Disable to get rid of clean up exception when stopping the Session.
+ hiveConf.setBoolVar(HIVE_SERVER2_LOGGING_OPERATION_ENABLED, false);
+
+ hiveConf.setVar(HADOOPBIN, "NO_BIN!");
+
+ // To avoid https://issues.apache.org/jira/browse/HIVE-13185 when
loading data into tables
+ hiveConf.setBoolVar(HiveConf.ConfVars.HIVECHECKFILEFORMAT, false);
+ }
+
+ private void overrideHiveConf() {
+ for (Map.Entry<String, String> hiveConfEntry :
+ hiveRunnerConfig.getHiveConfSystemOverride().entrySet()) {
+ hiveConf.set(hiveConfEntry.getKey(), hiveConfEntry.getValue());
+ }
+ }
+
+ private void configureMrExecutionEngine() {
+
+ /*
+ * Switch off all optimizers otherwise we didn't
+ * manage to contain the map reduction within this JVM.
+ */
+ hiveConf.setBoolVar(HIVE_INFER_BUCKET_SORT, false);
+ hiveConf.setBoolVar(HIVEMETADATAONLYQUERIES, false);
+ hiveConf.setBoolVar(HIVEOPTINDEXFILTER, false);
+ hiveConf.setBoolVar(HIVECONVERTJOIN, false);
+ hiveConf.setBoolVar(HIVESKEWJOIN, false);
+
+ // Defaults to a 1000 millis sleep in. We can speed up the tests a bit
by setting this to 1
+ // millis instead.
+ // org.apache.hadoop.hive.ql.exec.mr.HadoopJobExecHelper.
+ hiveConf.setLongVar(HiveConf.ConfVars.HIVECOUNTERSPULLINTERVAL, 1L);
+
+ hiveConf.setBoolVar(HiveConf.ConfVars.HIVE_RPC_QUERY_PLAN, true);
+ }
+
+ private void configureJavaSecurityRealm() {
+ // These three properties gets rid of: 'Unable to load realm info from
SCDynamicStore'
+ // which seems to have a timeout of about 5 secs.
+ System.setProperty("java.security.krb5.realm", "EXAMPLE.COM");
+ System.setProperty("java.security.krb5.kdc", "kdc");
+ System.setProperty("java.security.krb5.conf", "/dev/null");
+ }
+
+ private void configureAssertionStatus() {
+ ClassLoader.getSystemClassLoader()
+
.setPackageAssertionStatus("org.apache.hadoop.hive.serde2.objectinspector",
false);
+ }
+
+ private void configureSupportConcurrency() {
+ hiveConf.setBoolVar(HIVE_SUPPORT_CONCURRENCY, false);
+ }
+
+ private void configureMetaStore() {
+
+ String jdbcDriver =
org.apache.derby.jdbc.EmbeddedDriver.class.getName();
+ try {
+ Class.forName(jdbcDriver);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+
+ // set JDO configs
+ String jdoConnectionURL = "jdbc:derby:memory:" +
UUID.randomUUID().toString();
+ hiveConf.setVar(METASTORECONNECTURLKEY, jdoConnectionURL +
";create=true");
+
+ hiveConf.setBoolVar(METASTORE_VALIDATE_CONSTRAINTS, true);
+ hiveConf.setBoolVar(METASTORE_VALIDATE_COLUMNS, true);
+ hiveConf.setBoolVar(METASTORE_VALIDATE_TABLES, true);
+
+ // disable authorization to avoid NPE
+ hiveConf.set(
+ HIVE_AUTHORIZATION_MANAGER.varname,
+
"org.apache.hive.hcatalog.storagehandler.DummyHCatAuthProvider");
+
+ // disable notification event poll
+ hiveConf.set("hive.notification.event.poll.interval", "0s");
+ }
+
+ private void configureFileSystem() {
+
+ createAndSetFolderProperty(METASTOREWAREHOUSE, "warehouse", hiveConf,
basedir);
+ createAndSetFolderProperty(SCRATCHDIR, "scratchdir", hiveConf,
basedir);
+ createAndSetFolderProperty(LOCALSCRATCHDIR, "localscratchdir",
hiveConf, basedir);
+ createAndSetFolderProperty(HIVEHISTORYFILELOC, "tmp", hiveConf,
basedir);
+
+ // HIVE_WAREHOUSE_SUBDIR_INHERIT_PERMS is removed from Hive 3.1.0
+ hiveConf.setBoolean("hive.warehouse.subdir.inherit.perms", true);
+
+ createAndSetFolderProperty("hadoop.tmp.dir", "hadooptmp", hiveConf,
basedir);
+ createAndSetFolderProperty("test.log.dir", "logs", hiveConf, basedir);
+ }
+
+ private File newFolder(TemporaryFolder basedir, String folder) {
+ try {
+ File newFolder = basedir.newFolder(folder);
+ FileUtil.setPermission(newFolder, FsPermission.getDirDefault());
+ return newFolder;
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to create tmp dir: " +
e.getMessage(), e);
+ }
+ }
+
+ public HiveConf getHiveConf() {
+ return hiveConf;
+ }
+
+ @Override
+ public TemporaryFolder getBaseDir() {
+ return basedir;
+ }
+
+ private void createAndSetFolderProperty(
+ HiveConf.ConfVars var, String folder, HiveConf conf,
TemporaryFolder basedir) {
+ conf.setVar(var, newFolder(basedir, folder).getAbsolutePath());
+ }
+
+ private void createAndSetFolderProperty(
+ String key, String folder, HiveConf conf, TemporaryFolder basedir)
{
+ conf.set(key, newFolder(basedir, folder).getAbsolutePath());
+ }
+}
diff --git
a/paimon-hive/paimon-hive-connector-common/src/test/resources/hive-site.xml
b/paimon-hive/paimon-hive-connector-common/src/test/resources/hive-site.xml
new file mode 100644
index 000000000..6dbe4c962
--- /dev/null
+++ b/paimon-hive/paimon-hive-connector-common/src/test/resources/hive-site.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+ 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.
+-->
+
+<configuration>
+
+ <!-- allow integral partition filter pushdown to avoid unstable test -->
+ <property>
+ <name>hive.metastore.integral.jdo.pushdown</name>
+ <value>true</value>
+ </property>
+
+ <property>
+ <name>hive.metastore.schema.verification</name>
+ <value>false</value>
+ </property>
+
+ <property>
+ <name>hive.metastore.client.capability.check</name>
+ <value>false</value>
+ </property>
+
+ <property>
+ <name>datanucleus.schema.autoCreateTables</name>
+ <value>true</value>
+ </property>
+
+ <property>
+ <name>datanucleus.schema.autoCreateAll</name>
+ <value>true</value>
+ </property>
+
+ <property>
+ <name>common-key</name>
+ <value>common-val</value>
+ </property>
+
+</configuration>