From e30851b4d8708e4cba7801f733d32107b87eacfe Mon Sep 17 00:00:00 2001 From: wulingxiao <1251605638@qqcom> Date: Sat, 9 Jul 2022 19:35:28 +0800 Subject: [PATCH] support MetadataContext transfer in thread poll --- .../metadata/concurrent/MetadataCallable.java | 100 +++++++++++++ .../metadata/concurrent/MetadataRunnable.java | 97 ++++++++++++ .../metadata/concurrent/MetadataWrap.java | 42 ++++++ .../concurrent/executor/MetadataExecutor.java | 71 +++++++++ .../executor/MetadataExecutorService.java | 141 ++++++++++++++++++ .../executor/MetadataExecutors.java | 105 +++++++++++++ .../MetadataScheduledExecutorService.java | 97 ++++++++++++ .../concurrent/MetadataCallableTest.java | 131 ++++++++++++++++ .../concurrent/MetadataRunnableTest.java | 133 +++++++++++++++++ .../metadata/concurrent/MetadataTestUtil.java | 49 ++++++ .../executor/MetadataExecutorServiceTest.java | 126 ++++++++++++++++ .../executor/MetadataExecutorTest.java | 102 +++++++++++++ .../executor/MetadataExecutorsTest.java | 64 ++++++++ .../MetadataScheduledExecutorServiceTest.java | 88 +++++++++++ 14 files changed, 1346 insertions(+) create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataCallable.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataRunnable.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataWrap.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutor.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorService.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutors.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataScheduledExecutorService.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataCallableTest.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataRunnableTest.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataTestUtil.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorServiceTest.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorTest.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorsTest.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataScheduledExecutorServiceTest.java diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataCallable.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataCallable.java new file mode 100644 index 000000000..fb45a08f0 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataCallable.java @@ -0,0 +1,100 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +/** + * {@link MetadataCallable} decorate {@link Callable} to get {@link MetadataContext} value + * and transfer it to the time of {@link Callable} execution, needed when use {@link Callable} to thread pool. + *

+ * Use factory methods {@link #get} / {@link #gets} to create instance. + * + * @author wlx + * @date 2022/7/8 9:31 下午 + */ +public final class MetadataCallable implements Callable, + MetadataWrap> { + + private final Callable delegate; + + private final AtomicReference metadataContextReference; + + private MetadataCallable(Callable delegate) { + this.delegate = delegate; + this.metadataContextReference = new AtomicReference<>(MetadataContextHolder.get()); + } + + @Override + public V call() throws Exception { + MetadataContext metadataContext = metadataContextReference.get(); + MetadataContext metadataContextBackup = MetadataContextHolder.get(); + MetadataContextHolder.set(metadataContext); + try { + return delegate.call(); + } finally { + MetadataContextHolder.set(metadataContextBackup); + } + } + + /** + * Factory method to create {@link MetadataCallable} instance. + * + * @param delegate delegate + * @param MetadataCallable return type + * @return {@link MetadataCallable} instance + */ + public static Callable get(Callable delegate) { + if (null == delegate || delegate instanceof MetadataCallable) { + return delegate; + } else { + return new MetadataCallable<>(delegate); + } + } + + + /** + * Factory method to create some {@link MetadataCallable} instance. + * + * @param delegates delegates + * @param MetadataCallable return type + * @return some {@link MetadataCallable} instance + */ + public static List> gets(Collection> delegates) { + if (delegates == null) { + return Collections.emptyList(); + } + return delegates.stream().map( + MetadataCallable::get + ).collect(Collectors.toList()); + } + + @Override + public Callable unWrap() { + return this.delegate; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataRunnable.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataRunnable.java new file mode 100644 index 000000000..0a60ee4fb --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataRunnable.java @@ -0,0 +1,97 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +/** + * {@link MetadataRunnable} decorate {@link Runnable} to get {@link MetadataContext} value + * and transfer it to the time of {@link Runnable} execution, needed when use {@link Runnable} to thread pool. + *

+ * Use factory methods {@link #get} / {@link #gets} to create instance. + *

+ * + * @author wlx + * @date 2022/7/8 9:16 下午 + */ +public final class MetadataRunnable implements Runnable, + MetadataWrap { + + private final Runnable delegate; + + private final AtomicReference metadataContextReference; + + private MetadataRunnable(Runnable delegate) { + this.delegate = delegate; + this.metadataContextReference = new AtomicReference<>(MetadataContextHolder.get()); + } + + @Override + public void run() { + MetadataContext metadataContext = metadataContextReference.get(); + MetadataContext metadataContextBackup = MetadataContextHolder.get(); + MetadataContextHolder.set(metadataContext); + try { + delegate.run(); + } finally { + MetadataContextHolder.set(metadataContextBackup); + } + } + + /** + * Factory method to create {@link MetadataRunnable} instance. + * + * @param delegate delegate + * @return MetadataRunnable instance + */ + public static Runnable get(Runnable delegate) { + if (null == delegate || delegate instanceof MetadataRunnable) { + return delegate; + } else { + return new MetadataRunnable(delegate); + } + } + + /** + * Factory method to create {@link MetadataRunnable} instance. + * + * @param delegates delegates + * @return MetadataRunnable instances + */ + public static List gets(Collection delegates) { + if (delegates == null) { + return Collections.emptyList(); + } + return delegates.stream().map( + MetadataRunnable::get + ).collect(Collectors.toList()); + } + + @Override + public Runnable unWrap() { + return this.delegate; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataWrap.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataWrap.java new file mode 100644 index 000000000..6b9b2077d --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/MetadataWrap.java @@ -0,0 +1,42 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent; + +/** + * Metadata Wrapper interface. + *

+ * Used to mark wrapper types, for example: + *

+ * + * @author wlx + * @date 2022/7/9 9:17 上午 + */ + +public interface MetadataWrap { + + /** + * unwrap to the original/underneath one. + * + * @return a unWrap instance + */ + T unWrap(); +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutor.java new file mode 100644 index 000000000..62cab1a91 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutor.java @@ -0,0 +1,71 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent.executor; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.metadata.concurrent.MetadataRunnable; +import com.tencent.cloud.metadata.concurrent.MetadataWrap; +import org.springframework.lang.NonNull; + +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * {@link MetadataContext} Wrapper of {@link Executor}, + * transfer the {@link MetadataContext} from the task submit time of {@link Runnable} + * to the execution time of {@link Runnable}. + * + * @author wlx + * * @date 2022/7/8 9:35 下午 + */ +class MetadataExecutor implements Executor, MetadataWrap { + + private final Executor delegate; + + public MetadataExecutor(Executor delegate) { + this.delegate = delegate; + } + + @Override + public void execute(@NonNull Runnable command) { + delegate.execute(MetadataRunnable.get(command)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MetadataExecutor that = (MetadataExecutor) o; + return delegate.equals(that.delegate); + } + + @Override + public int hashCode() { + return Objects.hash(delegate); + } + + @Override + public Executor unWrap() { + return this.delegate; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorService.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorService.java new file mode 100644 index 000000000..e293e9503 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorService.java @@ -0,0 +1,141 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent.executor; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.metadata.concurrent.MetadataCallable; +import com.tencent.cloud.metadata.concurrent.MetadataRunnable; +import org.springframework.lang.NonNull; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * {@link MetadataContext} Wrapper of {@link ExecutorService}, + * transfer the {@link MetadataContext} from the task submit time of {@link Runnable} or {@link Callable} + * to the execution time of {@link Runnable} or {@link Callable}. + * + * @author wlx + * @date 2022/7/8 9:36 下午 + */ +class MetadataExecutorService extends MetadataExecutor implements ExecutorService { + + private final ExecutorService delegate; + + public MetadataExecutorService(ExecutorService delegate) { + super(delegate); + this.delegate = delegate; + } + + @Override + public void shutdown() { + this.delegate.shutdown(); + } + + @Override + @NonNull + public List shutdownNow() { + return this.delegate.shutdownNow(); + } + + @Override + public boolean isShutdown() { + return this.delegate.isShutdown(); + } + + @Override + public boolean isTerminated() { + return this.delegate.isTerminated(); + } + + @Override + public boolean awaitTermination(long timeout, @NonNull TimeUnit unit) throws InterruptedException { + return this.delegate.awaitTermination(timeout, unit); + } + + @Override + @NonNull + public Future submit(@NonNull Callable task) { + return this.delegate.submit(MetadataCallable.get(task)); + } + + @Override + @NonNull + public Future submit(@NonNull Runnable task, T result) { + return this.delegate.submit(MetadataRunnable.get(task), result); + } + + @Override + @NonNull + public Future submit(@NonNull Runnable task) { + return this.delegate.submit(MetadataRunnable.get(task)); + } + + @Override + @NonNull + public List> invokeAll(@NonNull Collection> tasks) throws InterruptedException { + return this.delegate.invokeAll(MetadataCallable.gets(tasks)); + } + + @Override + @NonNull + public List> invokeAll(@NonNull Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { + return this.delegate.invokeAll(MetadataCallable.gets(tasks), timeout, unit); + } + + @Override + @NonNull + public T invokeAny(@NonNull Collection> tasks) throws InterruptedException, ExecutionException { + return this.delegate.invokeAny(MetadataCallable.gets(tasks)); + } + + @Override + public T invokeAny(@NonNull Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return this.delegate.invokeAny(MetadataCallable.gets(tasks), timeout, unit); + } + + @Override + public ExecutorService unWrap() { + return this.delegate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MetadataExecutorService that = (MetadataExecutorService) o; + return delegate.equals(that.delegate); + } + + @Override + public int hashCode() { + return Objects.hash(delegate); + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutors.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutors.java new file mode 100644 index 000000000..2435b6fec --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutors.java @@ -0,0 +1,105 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent.executor; + +import com.tencent.cloud.metadata.concurrent.MetadataWrap; +import org.springframework.lang.Nullable; + +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; + +/** + * Util methods for Metadata wrapper of jdk executors. + * + * @author wlx + * @date 2022/7/8 11:58 下午 + */ +public class MetadataExecutors { + + /** + * wrap Executor instance to MetadataExecutorService instance. + * + * @param executor executor + * @return MetadataExecutorService instance + */ + public static Executor getMetadataExecutor(Executor executor) { + if (null == executor || isMetadataWrap(executor)) { + return executor; + } + return new MetadataExecutor(executor); + } + + /** + * wrap ExecutorService instance to MetadataExecutorService instance. + * + * @param executorService executorService + * @return MetadataExecutorService instance + */ + public static ExecutorService getMetadataExecutorService(ExecutorService executorService) { + if (null == executorService || isMetadataWrap(executorService)) { + return executorService; + } + return new MetadataExecutorService(executorService); + } + + /** + * wrap ScheduledExecutorService instance to MetadataScheduledExecutorService instance. + * + * @param scheduledExecutorService scheduledExecutorService + * @return MetadataScheduledExecutorService instance + */ + public static ScheduledExecutorService getMetadataScheduledExecutorService(ScheduledExecutorService + scheduledExecutorService) { + if (null == scheduledExecutorService || isMetadataWrap(scheduledExecutorService)) { + return scheduledExecutorService; + } + return new MetadataScheduledExecutorService(scheduledExecutorService); + + } + + /** + * unwrap to the original/underneath one. + * + * @param executor input executor + * @param Executor type + * @return original/underneath one instance. + */ + @SuppressWarnings("unchecked") + public static T unwrap(@Nullable T executor) { + if (!isMetadataWrap(executor)) { + return executor; + } + return (T) ((MetadataExecutor) executor).unWrap(); + } + + /** + * check the executor is a MetadataExecutor wrapper or not. + *

+ * if the parameter executor is MetadataExecutor wrapper, return {@code true}, otherwise {@code false}. + *

+ * NOTE: if input executor is {@code null}, return {@code false}. + * + * @param executor input executor + * @param Executor type + */ + public static boolean isMetadataWrap(@Nullable T executor) { + return executor instanceof MetadataWrap; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataScheduledExecutorService.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataScheduledExecutorService.java new file mode 100644 index 000000000..34c7560f7 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/concurrent/executor/MetadataScheduledExecutorService.java @@ -0,0 +1,97 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent.executor; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.metadata.concurrent.MetadataCallable; +import com.tencent.cloud.metadata.concurrent.MetadataRunnable; +import org.springframework.lang.NonNull; + +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * {@link MetadataContext} Wrapper of {@link ScheduledExecutorService}, + * transfer the {@link MetadataContext} from the task submit time of {@link Runnable} or {@link Callable} + * to the execution time of {@link Runnable} or {@link Callable}. + * + * @author wlx + * @date 2022/7/8 9:40 下午 + */ +class MetadataScheduledExecutorService extends MetadataExecutorService + implements ScheduledExecutorService { + + private final ScheduledExecutorService delegate; + + public MetadataScheduledExecutorService(ScheduledExecutorService delegate) { + super(delegate); + this.delegate = delegate; + } + + @Override + @NonNull + public ScheduledFuture schedule(@NonNull Runnable command, long delay, @NonNull TimeUnit unit) { + return this.delegate.schedule(MetadataRunnable.get(command), delay, unit); + } + + @Override + @NonNull + public ScheduledFuture schedule(@NonNull Callable callable, long delay, @NonNull TimeUnit unit) { + return this.delegate.schedule(MetadataCallable.get(callable), delay, unit); + } + + @Override + @NonNull + public ScheduledFuture scheduleAtFixedRate(@NonNull Runnable command, long initialDelay, + long period, @NonNull TimeUnit unit) { + return this.delegate.scheduleAtFixedRate(MetadataRunnable.get(command), initialDelay, period, unit); + } + + @Override + @NonNull + public ScheduledFuture scheduleWithFixedDelay(@NonNull Runnable command, long initialDelay, + long delay, @NonNull TimeUnit unit) { + return this.delegate.scheduleAtFixedRate(MetadataRunnable.get(command), initialDelay, delay, unit); + } + + @Override + public ScheduledExecutorService unWrap() { + return this.delegate; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MetadataScheduledExecutorService that = (MetadataScheduledExecutorService) o; + return delegate.equals(that.delegate); + } + + @Override + public int hashCode() { + return Objects.hash(delegate); + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataCallableTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataCallableTest.java new file mode 100644 index 000000000..2bf827656 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataCallableTest.java @@ -0,0 +1,131 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import org.assertj.core.api.Assertions; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Test for {@link MetadataCallable}. + * + * @author wlx + * @date 2022/7/9 12:11 下午 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = MetadataCallableTest.TestApplication.class, + properties = {"spring.config.location = classpath:application-test.yml", + "spring.main.web-application-type = servlet", + "spring.cloud.gateway.enabled = false"}) +public class MetadataCallableTest { + + private static final ExecutorService executor = Executors.newFixedThreadPool(1); + + @Test + public void threadMultiplexingTest() throws InterruptedException, ExecutionException, TimeoutException { + + Future> future = executor.submit(() -> { + return MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + }); + Map map = future.get(200, TimeUnit.MILLISECONDS); + + // init after new Task, won't see parent value in in task! + MetadataTestUtil.initMetadataContext(); + + Future> future1 = executor.submit(() -> { + return MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + }); + + Map map1 = future1.get(200, TimeUnit.MILLISECONDS); + + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Assertions.assertThat(fragmentContext.get("a")).isEqualTo("1"); + Assertions.assertThat(fragmentContext.get("b")).isEqualTo("2"); + + // init after new Task, won't see parent value in in task!,so before init and after init task res will be same! + Assertions.assertThat(map.equals(map1)).isTrue(); + } + + @Test + public void metadataCallableTest() throws InterruptedException, ExecutionException, TimeoutException { + Future> future = executor.submit( + MetadataCallable.get( + () -> MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE) + ) + ); + Map map = future.get(200, TimeUnit.MILLISECONDS); + + Assertions.assertThat(map.equals(MetadataContextHolder.get() + .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE))); + + MetadataTestUtil.initMetadataContext(); + + Future> future1 = executor.submit( + MetadataCallable.get( + () -> MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE) + ) + ); + + Map map1 = future1.get(200, TimeUnit.MILLISECONDS); + + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Assertions.assertThat(fragmentContext.get("a")).isEqualTo("1"); + Assertions.assertThat(fragmentContext.get("b")).isEqualTo("2"); + + Assertions.assertThat(fragmentContext.equals(map1)).isTrue(); + } + + @Test + public void metadataCallableWrap() { + Callable> callable = MetadataCallable.get( + () -> MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE) + ); + Assertions.assertThat(callable instanceof MetadataCallable).isTrue(); + } + + @AfterClass + public static void cleanUp() { + executor.shutdownNow(); + } + + @SpringBootApplication + protected static class TestApplication { + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataRunnableTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataRunnableTest.java new file mode 100644 index 000000000..91a64924c --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataRunnableTest.java @@ -0,0 +1,133 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import org.assertj.core.api.Assertions; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Test for {@link MetadataRunnable}. + * + * @author wlx + * @date 2022/7/9 3:28 下午 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = MetadataRunnableTest.TestApplication.class, + properties = {"spring.config.location = classpath:application-test.yml", + "spring.main.web-application-type = servlet", + "spring.cloud.gateway.enabled = false"}) +public class MetadataRunnableTest { + + private static final ExecutorService executor = Executors.newFixedThreadPool(1); + + @Test + public void threadMultiplexingTest() { + Map fragmentContextBeforeInit = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + executor.submit(() -> { + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Assertions.assertThat(fragmentContextBeforeInit.equals(fragmentContext)).isTrue(); + }); + + // init after new Task, won't see parent value in in task! + MetadataTestUtil.initMetadataContext(); + + Map fragmentContextAfterInit = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + + executor.submit(() -> { + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + // init after new Task, won't see parent value in in task! + // so before init and after init task res will be same! + Assertions.assertThat(fragmentContextBeforeInit.equals(fragmentContext)).isTrue(); + }); + + Assertions.assertThat(fragmentContextAfterInit.get("a")).isEqualTo("1"); + Assertions.assertThat(fragmentContextAfterInit.get("b")).isEqualTo("2"); + + } + + @Test + public void metadataRunnableTest() { + Map fragmentContextBeforeInit = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + executor.submit(MetadataRunnable.get( + () -> { + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Assertions.assertThat(fragmentContextBeforeInit.equals(fragmentContext)); + } + )); + + MetadataTestUtil.initMetadataContext(); + + Map fragmentContextAfterInit = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + executor.submit(MetadataRunnable.get( + () -> { + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Assertions.assertThat(fragmentContextBeforeInit.equals(fragmentContext)).isFalse(); + Assertions.assertThat(fragmentContextAfterInit.equals(fragmentContext)).isTrue(); + } + )); + + Assertions.assertThat(fragmentContextAfterInit.get("a")).isEqualTo("1"); + Assertions.assertThat(fragmentContextAfterInit.get("b")).isEqualTo("2"); + } + + @Test + public void metadataRunnableWrapTest() { + Runnable runnable = MetadataRunnable.get( + () -> { + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + } + ); + Assertions.assertThat(runnable instanceof MetadataRunnable).isTrue(); + } + + @AfterClass + public static void cleanUp() { + executor.shutdownNow(); + } + + @SpringBootApplication + protected static class TestApplication { + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataTestUtil.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataTestUtil.java new file mode 100644 index 000000000..3968df10e --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/MetadataTestUtil.java @@ -0,0 +1,49 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import org.assertj.core.api.Assertions; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author wlx + * @date 2022/7/9 3:23 下午 + */ +public class MetadataTestUtil { + + public static void initMetadataContext() { + Map customMetadata = new HashMap<>(); + customMetadata.put("a", "1"); + customMetadata.put("b", "2"); + + MetadataContext metadataContext = MetadataContextHolder.get(); + + metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, customMetadata); + MetadataContextHolder.set(metadataContext); + + customMetadata = MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); + Assertions.assertThat(customMetadata.get("b")).isEqualTo("2"); + + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorServiceTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorServiceTest.java new file mode 100644 index 000000000..f8c651fae --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorServiceTest.java @@ -0,0 +1,126 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent.executor; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import org.assertj.core.api.Assertions; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Test for {@link MetadataExecutorService}. + * + * @author wlx + * @date 2022/7/9 4:04 下午 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = MetadataExecutorServiceTest.TestApplication.class, + properties = {"spring.config.location = classpath:application-test.yml", + "spring.main.web-application-type = servlet", + "spring.cloud.gateway.enabled = false"}) +public class MetadataExecutorServiceTest { + + private static final ExecutorService executorService = Executors.newFixedThreadPool(1); + + @Test + public void submitTest() throws InterruptedException, ExecutionException, TimeoutException { + MetadataExecutorService metadataExecutorService = new MetadataExecutorService(executorService); + Future> future = metadataExecutorService.submit( + () -> { + return MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + } + ); + Map res = future.get(200, TimeUnit.MILLISECONDS); + Assertions.assertThat(res).isEqualTo( + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE) + ); + } + + @Test + public void invokeAnyTest() throws ExecutionException, InterruptedException { + MetadataExecutorService metadataExecutorService = new MetadataExecutorService(executorService); + Map res = metadataExecutorService.invokeAny(getCallableList()); + Assertions.assertThat(res).isEqualTo( + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE) + ); + } + + @Test + public void invokeAllTest() throws InterruptedException { + MetadataExecutorService metadataExecutorService = new MetadataExecutorService(executorService); + List>> futures = metadataExecutorService.invokeAll(getCallableList()); + List> resList = futures.stream().map( + future -> { + try { + return future.get(); + } catch (InterruptedException | ExecutionException e) { + return null; + } + } + ).collect(Collectors.toList()); + + resList.forEach( + res -> { + Assertions.assertThat(res).isEqualTo( + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE) + ); + } + ); + } + + @AfterClass + public static void cleanUp() { + executorService.shutdownNow(); + } + + @SpringBootApplication + protected static class TestApplication { + } + + private List>> getCallableList() { + List>> callableList = new ArrayList<>(); + callableList.add(() -> { + return MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + }); + callableList.add(() -> { + return MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + }); + return callableList; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorTest.java new file mode 100644 index 000000000..b776ab17f --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorTest.java @@ -0,0 +1,102 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent.executor; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.metadata.concurrent.MetadataTestUtil; +import org.assertj.core.api.Assertions; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Test for {@link MetadataExecutor}. + * + * @author wlx + * @date 2022/7/9 3:44 下午 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = MetadataExecutorTest.TestApplication.class, + properties = {"spring.config.location = classpath:application-test.yml", + "spring.main.web-application-type = servlet", + "spring.cloud.gateway.enabled = false"}) +public class MetadataExecutorTest { + + private static final Executor executorService = Executors.newFixedThreadPool(1); + + @Test + public void metadataExecutorTest() throws InterruptedException { + MetadataExecutor metadataExecutor = new MetadataExecutor(executorService); + Map fragmentContextBeforeInit = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + metadataExecutor.execute(() -> { + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Assertions.assertThat(fragmentContextBeforeInit.equals(fragmentContext)); + }); + + // wait 200ms for metadataExecutor execute task + TimeUnit.MILLISECONDS.sleep(200); + + MetadataTestUtil.initMetadataContext(); + + Map fragmentContextAfterInit = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + metadataExecutor.execute(() -> { + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Assertions.assertThat(fragmentContextAfterInit.equals(fragmentContext)); + }); + + // wait 200ms for metadataExecutor execute task + TimeUnit.MILLISECONDS.sleep(200); + } + + @Test + public void metadataExecutorUnWrap() { + MetadataExecutor metadataExecutor = new MetadataExecutor(executorService); + Executor executor = metadataExecutor.unWrap(); + Assertions.assertThat(executor).isEqualTo(executorService); + } + + @AfterClass + public static void cleanUp() { + if (executorService instanceof ExecutorService) { + ExecutorService executorService = (ExecutorService) MetadataExecutorTest.executorService; + executorService.shutdownNow(); + } + } + + @SpringBootApplication + protected static class TestApplication { + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorsTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorsTest.java new file mode 100644 index 000000000..734ce4617 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataExecutorsTest.java @@ -0,0 +1,64 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent.executor; + +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +/** + * Test for {@link MetadataExecutors}. + * + * @author wlx + * @date 2022/7/9 4:05 下午 + */ +public class MetadataExecutorsTest { + + @Test + public void getMetadataExecutor() { + Executor metadataExecutor = MetadataExecutors.getMetadataExecutor(Executors.newFixedThreadPool(1)); + Assertions.assertThat(metadataExecutor instanceof MetadataExecutor).isTrue(); + } + + @Test + public void getMetadataExecutorService() { + ExecutorService metadataExecutorService = + MetadataExecutors.getMetadataExecutorService(Executors.newFixedThreadPool(1)); + Assertions.assertThat(metadataExecutorService instanceof MetadataExecutorService).isTrue(); + } + + @Test + public void getMetadataScheduledExecutorService() { + ScheduledExecutorService metadataScheduledExecutorService = + MetadataExecutors.getMetadataScheduledExecutorService(Executors.newSingleThreadScheduledExecutor()); + Assertions.assertThat(metadataScheduledExecutorService instanceof MetadataScheduledExecutorService).isTrue(); + } + + @Test + public void unWrap() { + ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + ScheduledExecutorService unwrap = MetadataExecutors.unwrap( + MetadataExecutors.getMetadataScheduledExecutorService(scheduledExecutorService)); + Assertions.assertThat(unwrap).isEqualTo(scheduledExecutorService); + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataScheduledExecutorServiceTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataScheduledExecutorServiceTest.java new file mode 100644 index 000000000..9711e0154 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/concurrent/executor/MetadataScheduledExecutorServiceTest.java @@ -0,0 +1,88 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.metadata.concurrent.executor; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import org.assertj.core.api.Assertions; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Test for {@link MetadataScheduledExecutorService}. + * + * @author wlx + * @date 2022/7/9 4:04 下午 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = MetadataScheduledExecutorServiceTest.TestApplication.class, + properties = {"spring.config.location = classpath:application-test.yml", + "spring.main.web-application-type = servlet", + "spring.cloud.gateway.enabled = false"}) +public class MetadataScheduledExecutorServiceTest { + + private static final ScheduledExecutorService scheduledExecutorService = + Executors.newSingleThreadScheduledExecutor(); + + @Test + public void scheduleRunnableTest() throws ExecutionException, InterruptedException { + Map fragmentContext = + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + ScheduledFuture schedule = scheduledExecutorService.schedule(() -> { + Assertions.assertThat(fragmentContext). + isEqualTo(MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE)); + }, 100, TimeUnit.MILLISECONDS); + schedule.get(); + } + + @Test + public void scheduleCallableTest() throws ExecutionException, InterruptedException { + ScheduledFuture> schedule = scheduledExecutorService.schedule(() -> { + return MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + }, 100, TimeUnit.MILLISECONDS); + Map res = schedule.get(); + Assertions.assertThat(res).isEqualTo( + MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE) + ); + } + + @AfterClass + public static void cleanUp() { + scheduledExecutorService.shutdownNow(); + } + + @SpringBootApplication + protected static class TestApplication { + } +}