This is an automated email from the ASF dual-hosted git repository. zhangyue19921010 pushed a commit to branch partition-bucket-index in repository https://gitbox.apache.org/repos/asf/hudi.git
commit f3a6f3620967aebca3fe458428f9a51b046c8de1 Author: Alex R <[email protected]> AuthorDate: Mon Mar 17 11:23:00 2025 -0700 [HUDI-9168] Refactor hudi-client-common to not import hudi-aws (#12969) --- hudi-aws/pom.xml | 5 ++ .../cloudwatch/CloudWatchMetricsReporter.java | 3 +- .../cloudwatch/CloudWatchReporter.java | 11 ++-- .../hudi/aws/sync/AWSGlueCatalogSyncClient.java | 2 +- ...amoDBBasedImplicitPartitionKeyLockProvider.java | 2 +- .../java/org/apache/hudi/aws/utils/S3Utils.java | 27 ---------- .../cloudwatch/TestCloudWatchMetricsReporter.java | 61 +++++++++++++++++++--- .../cloudwatch/TestCloudWatchReporter.java | 10 ++-- .../org/apache/hudi/aws/utils/TestS3Utils.java | 59 --------------------- hudi-client/hudi-client-common/pom.xml | 12 ++--- ...ZookeeperBasedImplicitBasePathLockProvider.java | 2 +- .../java/org/apache/hudi/common/fs/FSUtils.java | 5 ++ .../hudi/metrics/MetricsReporterFactory.java | 2 +- .../hudi/metrics/TestMetricsReporterFactory.java | 38 ++++++++++++-- .../org/apache/hudi/common/fs/TestFSUtils.java | 32 ++++++++++++ 15 files changed, 153 insertions(+), 118 deletions(-) diff --git a/hudi-aws/pom.xml b/hudi-aws/pom.xml index 1b2967e5b2c..7ee4a0a7c4a 100644 --- a/hudi-aws/pom.xml +++ b/hudi-aws/pom.xml @@ -42,6 +42,11 @@ </dependency> <!-- Hoodie --> + <dependency> + <groupId>org.apache.hudi</groupId> + <artifactId>hudi-client-common</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.apache.hudi</groupId> <artifactId>hudi-common</artifactId> diff --git a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/metrics/cloudwatch/CloudWatchMetricsReporter.java b/hudi-aws/src/main/java/org/apache/hudi/aws/metrics/cloudwatch/CloudWatchMetricsReporter.java similarity index 96% rename from hudi-client/hudi-client-common/src/main/java/org/apache/hudi/metrics/cloudwatch/CloudWatchMetricsReporter.java rename to hudi-aws/src/main/java/org/apache/hudi/aws/metrics/cloudwatch/CloudWatchMetricsReporter.java index 68e4951f74f..03f71410b36 100644 --- a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/metrics/cloudwatch/CloudWatchMetricsReporter.java +++ b/hudi-aws/src/main/java/org/apache/hudi/aws/metrics/cloudwatch/CloudWatchMetricsReporter.java @@ -16,9 +16,8 @@ * limitations under the License. */ -package org.apache.hudi.metrics.cloudwatch; +package org.apache.hudi.aws.metrics.cloudwatch; -import org.apache.hudi.aws.cloudwatch.CloudWatchReporter; import org.apache.hudi.config.HoodieWriteConfig; import org.apache.hudi.config.metrics.HoodieMetricsConfig; import org.apache.hudi.metrics.MetricsReporter; diff --git a/hudi-aws/src/main/java/org/apache/hudi/aws/cloudwatch/CloudWatchReporter.java b/hudi-aws/src/main/java/org/apache/hudi/aws/metrics/cloudwatch/CloudWatchReporter.java similarity index 97% rename from hudi-aws/src/main/java/org/apache/hudi/aws/cloudwatch/CloudWatchReporter.java rename to hudi-aws/src/main/java/org/apache/hudi/aws/metrics/cloudwatch/CloudWatchReporter.java index bf5ae9f91f3..037bab52db1 100644 --- a/hudi-aws/src/main/java/org/apache/hudi/aws/cloudwatch/CloudWatchReporter.java +++ b/hudi-aws/src/main/java/org/apache/hudi/aws/metrics/cloudwatch/CloudWatchReporter.java @@ -16,7 +16,7 @@ * limitations under the License. */ -package org.apache.hudi.aws.cloudwatch; +package org.apache.hudi.aws.metrics.cloudwatch; import org.apache.hudi.aws.credentials.HoodieAWSCredentialsProviderFactory; import org.apache.hudi.common.util.Option; @@ -196,17 +196,17 @@ public class CloudWatchReporter extends ScheduledReporter { for (Map.Entry<String, Histogram> entry : histograms.entrySet()) { processCounter(entry.getKey(), entry.getValue(), timestampMilliSec, metricsData); - //TODO: Publish other Histogram metrics to cloud watch + // TODO: Publish other Histogram metrics to cloud watch } for (Map.Entry<String, Meter> entry : meters.entrySet()) { processCounter(entry.getKey(), entry.getValue(), timestampMilliSec, metricsData); - //TODO: Publish other Meter metrics to cloud watch + // TODO: Publish other Meter metrics to cloud watch } for (Map.Entry<String, Timer> entry : timers.entrySet()) { processCounter(entry.getKey(), entry.getValue(), timestampMilliSec, metricsData); - //TODO: Publish other Timer metrics to cloud watch + // TODO: Publish other Timer metrics to cloud watch } report(metricsData); @@ -236,6 +236,9 @@ public class CloudWatchReporter extends ScheduledReporter { } catch (final Exception ex) { LOG.error("Error reporting metrics to CloudWatch. The data in this CloudWatch request " + "may have been discarded, and not made it to CloudWatch.", ex); + if (ex instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } } } } diff --git a/hudi-aws/src/main/java/org/apache/hudi/aws/sync/AWSGlueCatalogSyncClient.java b/hudi-aws/src/main/java/org/apache/hudi/aws/sync/AWSGlueCatalogSyncClient.java index abda5a9d988..ce14e87ea23 100644 --- a/hudi-aws/src/main/java/org/apache/hudi/aws/sync/AWSGlueCatalogSyncClient.java +++ b/hudi-aws/src/main/java/org/apache/hudi/aws/sync/AWSGlueCatalogSyncClient.java @@ -101,7 +101,7 @@ import java.util.concurrent.Future; import java.util.function.Consumer; import java.util.stream.Collectors; -import static org.apache.hudi.aws.utils.S3Utils.s3aToS3; +import static org.apache.hudi.common.fs.FSUtils.s3aToS3; import static org.apache.hudi.common.util.MapUtils.containsAll; import static org.apache.hudi.common.util.MapUtils.isNullOrEmpty; import static org.apache.hudi.config.GlueCatalogSyncClientConfig.ALL_PARTITIONS_READ_PARALLELISM; diff --git a/hudi-aws/src/main/java/org/apache/hudi/aws/transaction/lock/DynamoDBBasedImplicitPartitionKeyLockProvider.java b/hudi-aws/src/main/java/org/apache/hudi/aws/transaction/lock/DynamoDBBasedImplicitPartitionKeyLockProvider.java index d9a131cd096..bcb0f4571c0 100644 --- a/hudi-aws/src/main/java/org/apache/hudi/aws/transaction/lock/DynamoDBBasedImplicitPartitionKeyLockProvider.java +++ b/hudi-aws/src/main/java/org/apache/hudi/aws/transaction/lock/DynamoDBBasedImplicitPartitionKeyLockProvider.java @@ -31,7 +31,7 @@ import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import javax.annotation.concurrent.NotThreadSafe; -import static org.apache.hudi.aws.utils.S3Utils.s3aToS3; +import static org.apache.hudi.common.fs.FSUtils.s3aToS3; /** * A DynamoDB based lock. diff --git a/hudi-aws/src/main/java/org/apache/hudi/aws/utils/S3Utils.java b/hudi-aws/src/main/java/org/apache/hudi/aws/utils/S3Utils.java deleted file mode 100644 index bfb208ee150..00000000000 --- a/hudi-aws/src/main/java/org/apache/hudi/aws/utils/S3Utils.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.hudi.aws.utils; - -public final class S3Utils { - - public static String s3aToS3(String s3aUrl) { - return s3aUrl.replaceFirst("(?i)^s3a://", "s3://"); - } -} diff --git a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/metrics/cloudwatch/TestCloudWatchMetricsReporter.java b/hudi-aws/src/test/java/org/apache/hudi/aws/metrics/cloudwatch/TestCloudWatchMetricsReporter.java similarity index 53% rename from hudi-client/hudi-client-common/src/test/java/org/apache/hudi/metrics/cloudwatch/TestCloudWatchMetricsReporter.java rename to hudi-aws/src/test/java/org/apache/hudi/aws/metrics/cloudwatch/TestCloudWatchMetricsReporter.java index 4b1aaffbf86..15cfb06e623 100644 --- a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/metrics/cloudwatch/TestCloudWatchMetricsReporter.java +++ b/hudi-aws/src/test/java/org/apache/hudi/aws/metrics/cloudwatch/TestCloudWatchMetricsReporter.java @@ -16,9 +16,10 @@ * limitations under the License. */ -package org.apache.hudi.metrics.cloudwatch; +package org.apache.hudi.aws.metrics.cloudwatch; -import org.apache.hudi.aws.cloudwatch.CloudWatchReporter; +import org.apache.hudi.common.config.TypedProperties; +import org.apache.hudi.config.HoodieWriteConfig; import org.apache.hudi.config.metrics.HoodieMetricsConfig; import org.apache.hudi.metrics.MetricsReporterFactory; import org.apache.hudi.metrics.MetricsReporterType; @@ -27,19 +28,26 @@ import com.codahale.metrics.MetricRegistry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.concurrent.TimeUnit; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class TestCloudWatchMetricsReporter { +class TestCloudWatchMetricsReporter { + + @Mock + private HoodieWriteConfig writeConfig; @Mock private HoodieMetricsConfig metricsConfig; @@ -51,7 +59,7 @@ public class TestCloudWatchMetricsReporter { private CloudWatchReporter reporter; @Test - public void testReporter() { + void testReporter() { when(metricsConfig.getCloudWatchReportPeriodSeconds()).thenReturn(30); CloudWatchMetricsReporter metricsReporter = new CloudWatchMetricsReporter(metricsConfig, registry, reporter); @@ -66,7 +74,23 @@ public class TestCloudWatchMetricsReporter { } @Test - public void testReporterViaReporterFactory() { + void testReporterUsingMetricsConfig() { + when(writeConfig.getMetricsConfig()).thenReturn(metricsConfig); + when(metricsConfig.getCloudWatchReportPeriodSeconds()).thenReturn(30); + CloudWatchMetricsReporter metricsReporter = new CloudWatchMetricsReporter(writeConfig, registry, reporter); + + metricsReporter.start(); + verify(reporter, times(1)).start(30, TimeUnit.SECONDS); + + metricsReporter.report(); + verify(reporter, times(1)).report(); + + metricsReporter.stop(); + verify(reporter, times(1)).stop(); + } + + @Test + void testReporterViaReporterFactory() { try { when(metricsConfig.getMetricsReporterType()).thenReturn(MetricsReporterType.CLOUDWATCH); // MetricsReporterFactory uses reflection to create CloudWatchMetricsReporter @@ -75,7 +99,32 @@ public class TestCloudWatchMetricsReporter { } catch (Exception e) { assertTrue(e.getCause() instanceof InvocationTargetException); assertTrue(Arrays.stream(((InvocationTargetException) e.getCause()).getTargetException().getStackTrace()).anyMatch( - ste -> ste.toString().contains("org.apache.hudi.aws.cloudwatch.CloudWatchReporter.getAmazonCloudWatchClient"))); + ste -> ste.toString().contains("org.apache.hudi.aws.metrics.cloudwatch.CloudWatchReporter.getAmazonCloudWatchClient"))); + } + } + + @Test + void testCreateCloudWatchReporter() { + when(metricsConfig.getCloudWatchMetricPrefix()).thenReturn("prefix"); + when(metricsConfig.getCloudWatchMetricNamespace()).thenReturn("namespace"); + when(metricsConfig.getCloudWatchMaxDatumsPerRequest()).thenReturn(100); + TypedProperties props = new TypedProperties(); + when(metricsConfig.getProps()).thenReturn(props); + + CloudWatchReporter reporterMock = mock(CloudWatchReporter.class); + CloudWatchReporter.Builder builderMock = mock(CloudWatchReporter.Builder.class); + + try (MockedStatic<CloudWatchReporter> mockedStatic = Mockito.mockStatic(CloudWatchReporter.class)) { + mockedStatic.when(() -> CloudWatchReporter.forRegistry(registry)) + .thenReturn(builderMock); + when(builderMock.prefixedWith("prefix")).thenReturn(builderMock); + when(builderMock.namespace("namespace")).thenReturn(builderMock); + when(builderMock.maxDatumsPerRequest(100)).thenReturn(builderMock); + when(builderMock.build(props)).thenReturn(reporterMock); + + CloudWatchMetricsReporter metricsReporter = + new CloudWatchMetricsReporter(metricsConfig, registry); + assertNotNull(metricsReporter); } } } diff --git a/hudi-aws/src/test/java/org/apache/hudi/aws/cloudwatch/TestCloudWatchReporter.java b/hudi-aws/src/test/java/org/apache/hudi/aws/metrics/cloudwatch/TestCloudWatchReporter.java similarity index 94% rename from hudi-aws/src/test/java/org/apache/hudi/aws/cloudwatch/TestCloudWatchReporter.java rename to hudi-aws/src/test/java/org/apache/hudi/aws/metrics/cloudwatch/TestCloudWatchReporter.java index 7061188a63c..0073f3687db 100644 --- a/hudi-aws/src/test/java/org/apache/hudi/aws/cloudwatch/TestCloudWatchReporter.java +++ b/hudi-aws/src/test/java/org/apache/hudi/aws/metrics/cloudwatch/TestCloudWatchReporter.java @@ -16,7 +16,7 @@ * limitations under the License. */ -package org.apache.hudi.aws.cloudwatch; +package org.apache.hudi.aws.metrics.cloudwatch; import com.codahale.metrics.Clock; import com.codahale.metrics.Counter; @@ -49,10 +49,10 @@ import java.util.TreeMap; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import static org.apache.hudi.aws.cloudwatch.CloudWatchReporter.DIMENSION_COUNT_TYPE_VALUE; -import static org.apache.hudi.aws.cloudwatch.CloudWatchReporter.DIMENSION_GAUGE_TYPE_VALUE; -import static org.apache.hudi.aws.cloudwatch.CloudWatchReporter.DIMENSION_METRIC_TYPE_KEY; -import static org.apache.hudi.aws.cloudwatch.CloudWatchReporter.DIMENSION_TABLE_NAME_KEY; +import static org.apache.hudi.aws.metrics.cloudwatch.CloudWatchReporter.DIMENSION_COUNT_TYPE_VALUE; +import static org.apache.hudi.aws.metrics.cloudwatch.CloudWatchReporter.DIMENSION_GAUGE_TYPE_VALUE; +import static org.apache.hudi.aws.metrics.cloudwatch.CloudWatchReporter.DIMENSION_METRIC_TYPE_KEY; +import static org.apache.hudi.aws.metrics.cloudwatch.CloudWatchReporter.DIMENSION_TABLE_NAME_KEY; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/hudi-aws/src/test/java/org/apache/hudi/aws/utils/TestS3Utils.java b/hudi-aws/src/test/java/org/apache/hudi/aws/utils/TestS3Utils.java deleted file mode 100644 index a0bdd110d83..00000000000 --- a/hudi-aws/src/test/java/org/apache/hudi/aws/utils/TestS3Utils.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.hudi.aws.utils; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class TestS3Utils { - - @Test - void testS3aToS3_AWS() { - // Test cases for AWS S3 URLs - assertEquals("s3://my-bucket/path/to/object", S3Utils.s3aToS3("s3a://my-bucket/path/to/object")); - assertEquals("s3://my-bucket", S3Utils.s3aToS3("s3a://my-bucket")); - assertEquals("s3://MY-BUCKET/PATH/TO/OBJECT", S3Utils.s3aToS3("s3a://MY-BUCKET/PATH/TO/OBJECT")); - assertEquals("s3://my-bucket/path/to/object", S3Utils.s3aToS3("S3a://my-bucket/path/to/object")); - assertEquals("s3://my-bucket/path/to/object", S3Utils.s3aToS3("s3A://my-bucket/path/to/object")); - assertEquals("s3://my-bucket/path/to/object", S3Utils.s3aToS3("S3A://my-bucket/path/to/object")); - assertEquals("s3://my-bucket/s3a://another-bucket/another/path", S3Utils.s3aToS3("s3a://my-bucket/s3a://another-bucket/another/path")); - } - - @ParameterizedTest - @ValueSource(strings = { - "gs://my-bucket/path/to/object", - "gs://my-bucket", - "gs://MY-BUCKET/PATH/TO/OBJECT", - "https://myaccount.blob.core.windows.net/mycontainer/path/to/blob", - "https://myaccount.blob.core.windows.net/MYCONTAINER/PATH/TO/BLOB", - "https://example.com/path/to/resource", - "http://example.com", - "ftp://example.com/resource", - "", - "gs://my-bucket/path/to/s3a://object", - "gs://my-bucket s3a://my-object", - - }) - void testUriDoesNotChange(String uri) { - assertEquals(uri, S3Utils.s3aToS3(uri)); - } -} diff --git a/hudi-client/hudi-client-common/pom.xml b/hudi-client/hudi-client-common/pom.xml index 5178ae92253..67b12413407 100644 --- a/hudi-client/hudi-client-common/pom.xml +++ b/hudi-client/hudi-client-common/pom.xml @@ -48,12 +48,6 @@ <artifactId>hudi-io</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>org.apache.hudi</groupId> - <artifactId>hudi-aws</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> <dependency> <groupId>org.apache.hudi</groupId> <artifactId>hudi-timeline-service</artifactId> @@ -131,6 +125,12 @@ <type>test-jar</type> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.hudi</groupId> + <artifactId>hudi-hadoop-mr</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>org.apache.hudi</groupId> <artifactId>hudi-tests-common</artifactId> diff --git a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/ZookeeperBasedImplicitBasePathLockProvider.java b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/ZookeeperBasedImplicitBasePathLockProvider.java index 199a9b6309d..9c4a57bc271 100644 --- a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/ZookeeperBasedImplicitBasePathLockProvider.java +++ b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/lock/ZookeeperBasedImplicitBasePathLockProvider.java @@ -31,7 +31,7 @@ import org.slf4j.LoggerFactory; import javax.annotation.concurrent.NotThreadSafe; -import static org.apache.hudi.aws.utils.S3Utils.s3aToS3; +import static org.apache.hudi.common.fs.FSUtils.s3aToS3; /** * A zookeeper based lock. This {@link LockProvider} implementation allows to lock table operations diff --git a/hudi-common/src/main/java/org/apache/hudi/common/fs/FSUtils.java b/hudi-common/src/main/java/org/apache/hudi/common/fs/FSUtils.java index 9edc1729dc0..0d78d03b029 100644 --- a/hudi-common/src/main/java/org/apache/hudi/common/fs/FSUtils.java +++ b/hudi-common/src/main/java/org/apache/hudi/common/fs/FSUtils.java @@ -738,6 +738,11 @@ public class FSUtils { ? new Path(null, path.toUri().getAuthority(), path.toUri().getPath()) : path; } + // Converts s3a to s3a + public static String s3aToS3(String s3aUrl) { + return s3aUrl.replaceFirst("(?i)^s3a://", "s3://"); + } + /** * Serializable function interface. * diff --git a/hudi-common/src/main/java/org/apache/hudi/metrics/MetricsReporterFactory.java b/hudi-common/src/main/java/org/apache/hudi/metrics/MetricsReporterFactory.java index 71509d7a9b7..d7d04903576 100644 --- a/hudi-common/src/main/java/org/apache/hudi/metrics/MetricsReporterFactory.java +++ b/hudi-common/src/main/java/org/apache/hudi/metrics/MetricsReporterFactory.java @@ -86,7 +86,7 @@ public class MetricsReporterFactory { reporter = new ConsoleMetricsReporter(registry); break; case CLOUDWATCH: - reporter = (MetricsReporter) ReflectionUtils.loadClass("org.apache.hudi.metrics.cloudwatch.CloudWatchMetricsReporter", + reporter = (MetricsReporter) ReflectionUtils.loadClass("org.apache.hudi.aws.metrics.cloudwatch.CloudWatchMetricsReporter", new Class[]{HoodieMetricsConfig.class, MetricRegistry.class}, metricsConfig, registry); break; case M3: diff --git a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/metrics/TestMetricsReporterFactory.java b/hudi-common/src/test/java/org/apache/hudi/metrics/TestMetricsReporterFactory.java similarity index 75% rename from hudi-client/hudi-client-common/src/test/java/org/apache/hudi/metrics/TestMetricsReporterFactory.java rename to hudi-common/src/test/java/org/apache/hudi/metrics/TestMetricsReporterFactory.java index 5afd27fbea3..d456748d976 100644 --- a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/metrics/TestMetricsReporterFactory.java +++ b/hudi-common/src/test/java/org/apache/hudi/metrics/TestMetricsReporterFactory.java @@ -20,6 +20,7 @@ package org.apache.hudi.metrics; import org.apache.hudi.common.config.TypedProperties; +import org.apache.hudi.common.util.ReflectionUtils; import org.apache.hudi.config.metrics.HoodieMetricsConfig; import org.apache.hudi.exception.HoodieException; import org.apache.hudi.metrics.custom.CustomizableMetricsReporter; @@ -32,17 +33,23 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Properties; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class TestMetricsReporterFactory { +class TestMetricsReporterFactory { @Mock HoodieMetricsConfig metricsConfig; @@ -68,7 +75,27 @@ public class TestMetricsReporterFactory { } @Test - public void metricsReporterFactoryShouldReturnUserDefinedReporter() { + void metricsReporterFactoryShouldReturnCloudWatchReporter() { + when(metricsConfig.getMetricsReporterType()).thenReturn(MetricsReporterType.CLOUDWATCH); + + MetricsReporter reporterMock = mock(MetricsReporter.class); + try (MockedStatic<ReflectionUtils> mockedStatic = Mockito.mockStatic(ReflectionUtils.class)) { + mockedStatic.when(() -> + ReflectionUtils.loadClass( + eq("org.apache.hudi.aws.metrics.cloudwatch.CloudWatchMetricsReporter"), + any(Class[].class), + eq(metricsConfig), + eq(registry) + ) + ).thenReturn(reporterMock); + + MetricsReporter actualReporter = MetricsReporterFactory.createReporter(metricsConfig, registry).get(); + assertSame(reporterMock, actualReporter); + } + } + + @Test + void metricsReporterFactoryShouldReturnUserDefinedReporter() { when(metricsConfig.getMetricReporterClassName()).thenReturn(DummyMetricsReporter.class.getName()); TypedProperties props = new TypedProperties(); @@ -82,7 +109,7 @@ public class TestMetricsReporterFactory { } @Test - public void metricsReporterFactoryShouldThrowExceptionWhenMetricsReporterClassIsIllegal() { + void metricsReporterFactoryShouldThrowExceptionWhenMetricsReporterClassIsIllegal() { when(metricsConfig.getMetricReporterClassName()).thenReturn(IllegalTestMetricsReporter.class.getName()); when(metricsConfig.getProps()).thenReturn(new TypedProperties()); assertThrows(HoodieException.class, () -> MetricsReporterFactory.createReporter(metricsConfig, registry)); @@ -96,14 +123,17 @@ public class TestMetricsReporterFactory { @Override public void start() { + // no-op } @Override public void report() { + // no-op } @Override public void stop() { + // no-op } } @@ -113,5 +143,3 @@ public class TestMetricsReporterFactory { } } } - - diff --git a/hudi-hadoop-common/src/test/java/org/apache/hudi/common/fs/TestFSUtils.java b/hudi-hadoop-common/src/test/java/org/apache/hudi/common/fs/TestFSUtils.java index 19b63a3a5c6..c7d8a28bf76 100644 --- a/hudi-hadoop-common/src/test/java/org/apache/hudi/common/fs/TestFSUtils.java +++ b/hudi-hadoop-common/src/test/java/org/apache/hudi/common/fs/TestFSUtils.java @@ -47,6 +47,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; import java.io.IOException; import java.nio.file.Files; @@ -658,6 +659,37 @@ public class TestFSUtils extends HoodieCommonTestHarness { assertEquals(FSUtils.getPathWithoutScheme(new Path(path1)).toUri().toString(), "//test_bucket_one/table/base/path", "should return false since bucket names dont match"); } + @Test + void testS3aToS3_AWS() { + // Test cases for AWS S3 URLs + assertEquals("s3://my-bucket/path/to/object", FSUtils.s3aToS3("s3a://my-bucket/path/to/object")); + assertEquals("s3://my-bucket", FSUtils.s3aToS3("s3a://my-bucket")); + assertEquals("s3://MY-BUCKET/PATH/TO/OBJECT", FSUtils.s3aToS3("s3a://MY-BUCKET/PATH/TO/OBJECT")); + assertEquals("s3://my-bucket/path/to/object", FSUtils.s3aToS3("S3a://my-bucket/path/to/object")); + assertEquals("s3://my-bucket/path/to/object", FSUtils.s3aToS3("s3A://my-bucket/path/to/object")); + assertEquals("s3://my-bucket/path/to/object", FSUtils.s3aToS3("S3A://my-bucket/path/to/object")); + assertEquals("s3://my-bucket/s3a://another-bucket/another/path", FSUtils.s3aToS3("s3a://my-bucket/s3a://another-bucket/another/path")); + } + + @ParameterizedTest + @ValueSource(strings = { + "gs://my-bucket/path/to/object", + "gs://my-bucket", + "gs://MY-BUCKET/PATH/TO/OBJECT", + "https://myaccount.blob.core.windows.net/mycontainer/path/to/blob", + "https://myaccount.blob.core.windows.net/MYCONTAINER/PATH/TO/BLOB", + "https://example.com/path/to/resource", + "http://example.com", + "ftp://example.com/resource", + "", + "gs://my-bucket/path/to/s3a://object", + "gs://my-bucket s3a://my-object", + }) + + void testUriDoesNotChange(String uri) { + assertEquals(uri, FSUtils.s3aToS3(uri)); + } + private StoragePath getHoodieTempDir() { return new StoragePath(baseUri.toString(), ".hoodie/.temp"); }
