diff --git a/src/main/java/run/halo/app/core/extension/Plugin.java b/src/main/java/run/halo/app/core/extension/Plugin.java index f10241773..0f2fe5f1d 100644 --- a/src/main/java/run/halo/app/core/extension/Plugin.java +++ b/src/main/java/run/halo/app/core/extension/Plugin.java @@ -112,6 +112,8 @@ public class Plugin extends AbstractExtension { private String entry; private String stylesheet; + + private String logo; } @JsonIgnore diff --git a/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java index b4060f812..5e44e49c8 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java @@ -4,22 +4,29 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.pf4j.PluginRuntimeException; import org.pf4j.PluginState; import org.pf4j.PluginWrapper; import org.pf4j.RuntimeMode; import run.halo.app.core.extension.Plugin; +import run.halo.app.core.extension.ReverseProxy; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.Metadata; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; import run.halo.app.infra.utils.JsonUtils; +import run.halo.app.infra.utils.PathUtils; import run.halo.app.plugin.HaloPluginManager; +import run.halo.app.plugin.PluginConst; import run.halo.app.plugin.PluginStartingError; import run.halo.app.plugin.resources.BundleResourceUtils; @@ -51,6 +58,7 @@ public class PluginReconciler implements Reconciler { } addFinalizerIfNecessary(plugin); reconcilePluginState(plugin.getMetadata().getName()); + createInitialReverseProxyIfNotPresent(plugin); }); return new Result(false, null); } @@ -78,6 +86,15 @@ public class PluginReconciler implements Reconciler { } } + String logo = plugin.getSpec().getLogo(); + if (PathUtils.isAbsoluteUri(logo)) { + pluginStatus.setLogo(logo); + } else { + String assetsPrefix = + PluginConst.assertsRoutePrefix(plugin.getMetadata().getName()); + pluginStatus.setLogo(PathUtils.combinePath(assetsPrefix, logo)); + } + if (!plugin.equals(oldPlugin)) { client.update(plugin); } @@ -213,4 +230,45 @@ public class PluginReconciler implements Reconciler { } } } + + void createInitialReverseProxyIfNotPresent(Plugin plugin) { + String pluginName = plugin.getMetadata().getName(); + String reverseProxyName = initialReverseProxyName(pluginName); + ReverseProxy reverseProxy = new ReverseProxy(); + reverseProxy.setMetadata(new Metadata()); + reverseProxy.getMetadata().setName(reverseProxyName); + // put label to identify this reverse + reverseProxy.getMetadata().setLabels(new HashMap<>()); + reverseProxy.getMetadata().getLabels().put(PluginConst.PLUGIN_NAME_LABEL_NAME, pluginName); + + reverseProxy.setRules(new ArrayList<>()); + + String logo = plugin.getSpec().getLogo(); + if (StringUtils.isNotBlank(logo) && !PathUtils.isAbsoluteUri(logo)) { + ReverseProxy.ReverseProxyRule logoRule = new ReverseProxy.ReverseProxyRule(logo, + new ReverseProxy.FileReverseProxyProvider(null, logo)); + reverseProxy.getRules().add(logoRule); + } + + client.fetch(ReverseProxy.class, reverseProxyName) + .ifPresentOrElse(persisted -> { + if (isDevelopmentMode(pluginName)) { + reverseProxy.getMetadata() + .setVersion(persisted.getMetadata().getVersion()); + client.update(reverseProxy); + } + }, () -> client.create(reverseProxy)); + } + + static String initialReverseProxyName(String pluginName) { + return pluginName + "-system-generated-reverse-proxy"; + } + + private boolean isDevelopmentMode(String name) { + PluginWrapper pluginWrapper = haloPluginManager.getPlugin(name); + if (pluginWrapper == null) { + return false; + } + return RuntimeMode.DEVELOPMENT.equals(pluginWrapper.getRuntimeMode()); + } } diff --git a/src/main/java/run/halo/app/infra/utils/PathUtils.java b/src/main/java/run/halo/app/infra/utils/PathUtils.java index bd7b13819..d2d22a79f 100644 --- a/src/main/java/run/halo/app/infra/utils/PathUtils.java +++ b/src/main/java/run/halo/app/infra/utils/PathUtils.java @@ -1,5 +1,7 @@ package run.halo.app.infra.utils; +import java.net.URI; +import java.net.URISyntaxException; import lombok.experimental.UtilityClass; import org.apache.commons.lang3.StringUtils; @@ -12,6 +14,38 @@ import org.apache.commons.lang3.StringUtils; @UtilityClass public class PathUtils { + /** + * Every HTTP URL conforms to the syntax of a generic URI. The URI generic syntax consists of + * components organized hierarchically in order of decreasing significance from left to + * right: + *
+     * URI = scheme ":" ["//" authority] path ["?" query] ["#" fragment]
+     * 
+ * The authority component consists of subcomponents: + *
+     * authority = [userinfo "@"] host [":" port]
+     * 
+ * Examples of popular schemes include http, https, ftp, mailto, file, data and irc. URI + * schemes should be registered with the + * Internet Assigned Numbers Authority (IANA), although + * non-registered schemes are used in practice. + * + * @param uriString url or path + * @return true if the linkBase is absolute, otherwise false + * @see URL + */ + public static boolean isAbsoluteUri(final String uriString) { + if (StringUtils.isBlank(uriString)) { + return false; + } + try { + URI uri = new URI(uriString); + return uri.isAbsolute(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + /** * Combine paths based on the passed in path segments parameters. * diff --git a/src/main/java/run/halo/app/plugin/resources/BundleResourceUtils.java b/src/main/java/run/halo/app/plugin/resources/BundleResourceUtils.java index 5c4592f20..4ef135a4d 100644 --- a/src/main/java/run/halo/app/plugin/resources/BundleResourceUtils.java +++ b/src/main/java/run/halo/app/plugin/resources/BundleResourceUtils.java @@ -76,7 +76,7 @@ public abstract class BundleResourceUtils { } @Nullable - private static DefaultResourceLoader getResourceLoader(HaloPluginManager pluginManager, + public static DefaultResourceLoader getResourceLoader(HaloPluginManager pluginManager, String pluginName) { Assert.notNull(pluginManager, "Plugin manager must not be null"); PluginWrapper plugin = pluginManager.getPlugin(pluginName); diff --git a/src/main/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionFactory.java b/src/main/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionFactory.java index 584f90259..39776f114 100644 --- a/src/main/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionFactory.java +++ b/src/main/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionFactory.java @@ -4,10 +4,13 @@ import static org.springframework.http.MediaType.ALL; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationContext; +import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; import org.springframework.http.server.PathContainer; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; @@ -22,8 +25,10 @@ import reactor.core.publisher.Mono; import run.halo.app.core.extension.ReverseProxy; import run.halo.app.core.extension.ReverseProxy.FileReverseProxyProvider; import run.halo.app.core.extension.ReverseProxy.ReverseProxyRule; +import run.halo.app.infra.exception.NotFoundException; import run.halo.app.infra.utils.PathUtils; -import run.halo.app.plugin.PluginApplicationContext; +import run.halo.app.plugin.ExtensionContextRegistry; +import run.halo.app.plugin.HaloPluginManager; import run.halo.app.plugin.PluginConst; /** @@ -36,39 +41,40 @@ import run.halo.app.plugin.PluginConst; */ @Slf4j @Component +@AllArgsConstructor public class ReverseProxyRouterFunctionFactory { + private final HaloPluginManager haloPluginManager; + private final ApplicationContext applicationContext; + /** *

Create {@link RouterFunction} according to the {@link ReverseProxy} custom resource * configuration of the plugin.

*

Note that: returns {@code Null} if the plugin does not have a {@link ReverseProxy} custom * resource.

* - * @param applicationContext plugin application context or system application context + * @param pluginName plugin name(nullable if system) * @return A reverse proxy RouterFunction handle(nullable) */ @NonNull public Mono> create(ReverseProxy reverseProxy, - ApplicationContext applicationContext) { - return createReverseProxyRouterFunction(reverseProxy, applicationContext); + String pluginName) { + return createReverseProxyRouterFunction(reverseProxy, nullSafePluginName(pluginName)); } private Mono> createReverseProxyRouterFunction( - ReverseProxy reverseProxy, - ApplicationContext applicationContext) { + ReverseProxy reverseProxy, @NonNull String pluginName) { Assert.notNull(reverseProxy, "The reverseProxy must not be null."); - Assert.notNull(applicationContext, "The applicationContext must not be null."); - final var pluginId = getPluginId(applicationContext); var rules = getReverseProxyRules(reverseProxy); return rules.map(rule -> { - String routePath = buildRoutePath(pluginId, rule); - log.debug("Plugin [{}] registered reverse proxy route path [{}]", pluginId, + String routePath = buildRoutePath(pluginName, rule); + log.debug("Plugin [{}] registered reverse proxy route path [{}]", pluginName, routePath); return RouterFunctions.route(GET(routePath).and(accept(ALL)), request -> { Resource resource = - loadResourceByFileRule(pluginId, applicationContext, rule, request); + loadResourceByFileRule(pluginName, rule, request); if (!resource.exists()) { return ServerResponse.notFound().build(); } @@ -78,11 +84,8 @@ public class ReverseProxyRouterFunctionFactory { }).reduce(RouterFunction::and); } - private String getPluginId(ApplicationContext applicationContext) { - if (applicationContext instanceof PluginApplicationContext pluginApplicationContext) { - return pluginApplicationContext.getPluginId(); - } - return PluginConst.SYSTEM_PLUGIN_NAME; + private String nullSafePluginName(String pluginName) { + return pluginName == null ? PluginConst.SYSTEM_PLUGIN_NAME : pluginName; } private Flux getReverseProxyRules(ReverseProxy reverseProxy) { @@ -105,15 +108,14 @@ public class ReverseProxyRouterFunctionFactory { *

Note that a returned Resource handle does not imply an existing resource; you need to * invoke {@link Resource#exists()} to check for existence

* - * @param pluginApplicationContext load file from plugin + * @param pluginName plugin to load file by name * @param rule reverse proxy rule * @param request client request * @return a Resource handle for the specified resource location by the plugin(never null); */ @NonNull - private Resource loadResourceByFileRule(String pluginId, - ApplicationContext pluginApplicationContext, - ReverseProxyRule rule, ServerRequest request) { + private Resource loadResourceByFileRule(String pluginName, ReverseProxyRule rule, + ServerRequest request) { Assert.notNull(rule.file(), "File rule must not be null."); FileReverseProxyProvider file = rule.file(); String directory = file.directory(); @@ -124,14 +126,30 @@ public class ReverseProxyRouterFunctionFactory { if (StringUtils.isNotBlank(configuredFilename)) { filename = configuredFilename; } else { - String routePath = buildRoutePath(pluginId, rule); + String routePath = buildRoutePath(pluginName, rule); PathContainer pathContainer = PathPatternParser.defaultInstance.parse(routePath) .extractPathWithinPattern(PathContainer.parsePath(request.path())); filename = pathContainer.value(); } String filePath = PathUtils.combinePath(directory, filename); - return pluginApplicationContext.getResource(filePath); + return getResourceLoader(pluginName).getResource(filePath); + } + + private ResourceLoader getResourceLoader(String pluginName) { + ExtensionContextRegistry registry = ExtensionContextRegistry.getInstance(); + if (registry.containsContext(pluginName)) { + return registry.getByPluginId(pluginName); + } + if (PluginConst.SYSTEM_PLUGIN_NAME.equals(pluginName)) { + return applicationContext; + } + DefaultResourceLoader resourceLoader = + BundleResourceUtils.getResourceLoader(haloPluginManager, pluginName); + if (resourceLoader == null) { + throw new NotFoundException("Plugin [" + pluginName + "] not found."); + } + return resourceLoader; } } diff --git a/src/main/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionRegistry.java b/src/main/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionRegistry.java index 19399f2ee..062db66fe 100644 --- a/src/main/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionRegistry.java +++ b/src/main/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionRegistry.java @@ -12,8 +12,6 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; import run.halo.app.core.extension.ReverseProxy; -import run.halo.app.plugin.ExtensionContextRegistry; -import run.halo.app.plugin.PluginApplicationContext; /** * A registry for {@link RouterFunction} of plugin. @@ -48,11 +46,7 @@ public class ReverseProxyRouterFunctionRegistry { long stamp = lock.writeLock(); try { pluginIdReverseProxyMap.put(pluginId, proxyName); - - // Obtain plugin application context - PluginApplicationContext pluginApplicationContext = - ExtensionContextRegistry.getInstance().getByPluginId(pluginId); - return reverseProxyRouterFunctionFactory.create(reverseProxy, pluginApplicationContext) + return reverseProxyRouterFunctionFactory.create(reverseProxy, pluginId) .map(routerFunction -> { proxyNameRouterFunctionRegistry.put(proxyName, routerFunction); return routerFunction; diff --git a/src/test/java/run/halo/app/core/extension/reconciler/PluginReconcilerTest.java b/src/test/java/run/halo/app/core/extension/reconciler/PluginReconcilerTest.java index 2fbbe2959..a43ddfa1f 100644 --- a/src/test/java/run/halo/app/core/extension/reconciler/PluginReconcilerTest.java +++ b/src/test/java/run/halo/app/core/extension/reconciler/PluginReconcilerTest.java @@ -4,13 +4,18 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static run.halo.app.core.extension.reconciler.PluginReconciler.initialReverseProxyName; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import org.json.JSONException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -21,8 +26,12 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.pf4j.PluginRuntimeException; import org.pf4j.PluginState; import org.pf4j.PluginWrapper; +import org.pf4j.RuntimeMode; +import org.skyscreamer.jsonassert.JSONAssert; import run.halo.app.core.extension.Plugin; +import run.halo.app.core.extension.ReverseProxy; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.Metadata; import run.halo.app.extension.controller.Reconciler; import run.halo.app.infra.utils.JsonUtils; import run.halo.app.plugin.HaloPluginManager; @@ -52,8 +61,8 @@ class PluginReconcilerTest { void setUp() { pluginReconciler = new PluginReconciler(extensionClient, haloPluginManager); - when(haloPluginManager.getPlugin(any())).thenReturn(pluginWrapper); - when(haloPluginManager.getUnresolvedPlugins()).thenReturn(List.of()); + lenient().when(haloPluginManager.getPlugin(any())).thenReturn(pluginWrapper); + lenient().when(haloPluginManager.getUnresolvedPlugins()).thenReturn(List.of()); } @Test @@ -66,7 +75,7 @@ class PluginReconcilerTest { when(pluginWrapper.getPluginState()).thenReturn(PluginState.STOPPED); ArgumentCaptor pluginCaptor = doReconcileWithoutRequeue(); - verify(extensionClient, times(2)).update(any()); + verify(extensionClient, times(3)).update(isA(Plugin.class)); Plugin updateArgs = pluginCaptor.getValue(); assertThat(updateArgs).isNotNull(); @@ -118,7 +127,7 @@ class PluginReconcilerTest { when(pluginWrapper.getPluginState()).thenReturn(PluginState.STARTED); ArgumentCaptor pluginCaptor = doReconcileWithoutRequeue(); - verify(extensionClient, times(2)).update(any()); + verify(extensionClient, times(3)).update(any(Plugin.class)); Plugin updateArgs = pluginCaptor.getValue(); assertThat(updateArgs).isNotNull(); @@ -153,7 +162,7 @@ class PluginReconcilerTest { when(pluginWrapper.getPluginState()).thenReturn(PluginState.STARTED); ArgumentCaptor pluginCaptor = doReconcileWithoutRequeue(); - verify(extensionClient, times(3)).update(any()); + verify(extensionClient, times(3)).update(any(Plugin.class)); Plugin updateArgs = pluginCaptor.getValue(); assertThat(updateArgs).isNotNull(); @@ -192,6 +201,80 @@ class PluginReconcilerTest { .hasMessage("error message"); } + @Test + void createInitialReverseProxyWhenNotExistAndLogoIsPath() throws JSONException { + Plugin plugin = need2ReconcileForStopState(); + String reverseProxyName = initialReverseProxyName(plugin.getMetadata().getName()); + when(extensionClient.fetch(eq(ReverseProxy.class), eq(reverseProxyName))) + .thenReturn(Optional.empty()); + + plugin.getSpec().setLogo("/logo.png"); + pluginReconciler.createInitialReverseProxyIfNotPresent(plugin); + ArgumentCaptor captor = ArgumentCaptor.forClass(ReverseProxy.class); + verify(extensionClient, times(1)).create(captor.capture()); + ReverseProxy value = captor.getValue(); + JSONAssert.assertEquals(""" + { + "rules": [ + { + "path": "/logo.png", + "file": { + "filename": "/logo.png" + } + } + ], + "apiVersion": "plugin.halo.run/v1alpha1", + "kind": "ReverseProxy", + "metadata": { + "name": "apples-system-generated-reverse-proxy", + "labels": { + "plugin.halo.run/plugin-name": "apples" + } + } + } + """, + JsonUtils.objectToJson(value), + true); + } + + @Test + void createInitialReverseProxyWhenNotExistAndLogoIsAbsolute() { + Plugin plugin = need2ReconcileForStopState(); + String reverseProxyName = initialReverseProxyName(plugin.getMetadata().getName()); + when(extensionClient.fetch(eq(ReverseProxy.class), eq(reverseProxyName))) + .thenReturn(Optional.empty()); + + plugin.getSpec().setLogo("http://example.com/logo"); + pluginReconciler.createInitialReverseProxyIfNotPresent(plugin); + ArgumentCaptor captor = ArgumentCaptor.forClass(ReverseProxy.class); + verify(extensionClient, times(1)).create(captor.capture()); + ReverseProxy value = captor.getValue(); + assertThat(value.getRules()).isEmpty(); + } + + @Test + void createInitialReverseProxyWhenExist() { + Plugin plugin = need2ReconcileForStopState(); + plugin.getSpec().setLogo("/logo.png"); + + String reverseProxyName = initialReverseProxyName(plugin.getMetadata().getName()); + ReverseProxy reverseProxy = new ReverseProxy(); + reverseProxy.setMetadata(new Metadata()); + reverseProxy.getMetadata().setName(reverseProxyName); + reverseProxy.setRules(new ArrayList<>()); + + when(extensionClient.fetch(eq(ReverseProxy.class), eq(reverseProxyName))) + .thenReturn(Optional.of(reverseProxy)); + when(pluginWrapper.getRuntimeMode()).thenReturn(RuntimeMode.DEPLOYMENT); + + pluginReconciler.createInitialReverseProxyIfNotPresent(plugin); + verify(extensionClient, times(0)).update(any()); + + when(pluginWrapper.getRuntimeMode()).thenReturn(RuntimeMode.DEVELOPMENT); + pluginReconciler.createInitialReverseProxyIfNotPresent(plugin); + verify(extensionClient, times(1)).update(any()); + } + private ArgumentCaptor doReconcileNeedRequeue() { ArgumentCaptor pluginCaptor = ArgumentCaptor.forClass(Plugin.class); doNothing().when(extensionClient).update(pluginCaptor.capture()); diff --git a/src/test/java/run/halo/app/infra/utils/PathUtilsTest.java b/src/test/java/run/halo/app/infra/utils/PathUtilsTest.java index 5e53778bc..da6356539 100644 --- a/src/test/java/run/halo/app/infra/utils/PathUtilsTest.java +++ b/src/test/java/run/halo/app/infra/utils/PathUtilsTest.java @@ -59,4 +59,40 @@ class PathUtilsTest { assertThat(PathUtils.simplifyPathPattern("/archives/{year:\\d{4}}/page/{page:\\d+}")) .isEqualTo("/archives/{year}/page/{page}"); } + + @Test + void isAbsoluteUri() { + String[] absoluteUris = new String[] { + "ftp://ftp.is.co.za/rfc/rfc1808.txt", + "http://www.ietf.org/rfc/rfc2396.txt", + "ldap://[2001:db8::7]/c=GB?objectClass?one", + "mailto:John.Doe@example.com", + "news:comp.infosystems.www.servers.unix", + "tel:+1-816-555-1212", + "telnet://192.0.2.16:80/", + "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", + "data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh", + "irc://irc.example.com:6667/#some-channel", + "ircs://irc.example.com:6667/#some-channel", + "irc6://irc.example.com:6667/#some-channel" + }; + for (String uri : absoluteUris) { + assertThat(PathUtils.isAbsoluteUri(uri)).isTrue(); + } + + String[] paths = new String[] { + "//example.com/path/resource.txt", + "/path/resource.txt", + "path/resource.txt", + "../resource.txt", + "./resource.txt", + "resource.txt", + "#fragment", + "", + null + }; + for (String path : paths) { + assertThat(PathUtils.isAbsoluteUri(path)).isFalse(); + } + } } \ No newline at end of file diff --git a/src/test/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionFactoryTest.java b/src/test/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionFactoryTest.java index 6f6bc0507..46f080d98 100644 --- a/src/test/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionFactoryTest.java +++ b/src/test/java/run/halo/app/plugin/resources/ReverseProxyRouterFunctionFactoryTest.java @@ -1,18 +1,17 @@ package run.halo.app.plugin.resources; -import static org.mockito.Mockito.when; - import java.util.List; import java.util.Map; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationContext; import reactor.test.StepVerifier; import run.halo.app.core.extension.ReverseProxy; import run.halo.app.extension.Metadata; -import run.halo.app.plugin.PluginApplicationContext; +import run.halo.app.plugin.HaloPluginManager; import run.halo.app.plugin.PluginConst; /** @@ -25,22 +24,18 @@ import run.halo.app.plugin.PluginConst; class ReverseProxyRouterFunctionFactoryTest { @Mock - private PluginApplicationContext pluginApplicationContext; + private HaloPluginManager haloPluginManager; + @Mock + private ApplicationContext applicationContext; + + @InjectMocks private ReverseProxyRouterFunctionFactory reverseProxyRouterFunctionFactory; - @BeforeEach - void setUp() { - reverseProxyRouterFunctionFactory = - new ReverseProxyRouterFunctionFactory(); - - when(pluginApplicationContext.getPluginId()).thenReturn("fakeA"); - } - @Test void create() { var routerFunction = - reverseProxyRouterFunctionFactory.create(mockReverseProxy(), pluginApplicationContext); + reverseProxyRouterFunctionFactory.create(mockReverseProxy(), "fakeA"); StepVerifier.create(routerFunction) .expectNextCount(1) .verifyComplete();