From 7138f27eb9d7156d1e6b40a7aac79c68656ad003 Mon Sep 17 00:00:00 2001 From: Peter Hoffmann <954078+p-hoffmann@users.noreply.github.com> Date: Wed, 4 Nov 2026 07:38:53 +0800 Subject: [PATCH] Report plugin activation in /info at request time, not at startup --- .../org/ohdsi/webapi/info/InfoService.java | 20 ++++---- .../plugins/PluginsConfigurationInfo.java | 23 +++++++-- .../ohdsi/webapi/info/InfoServiceTest.java | 38 +++++++++++++++ .../plugins/PluginsConfigurationInfoTest.java | 47 +++++++++++++++++++ 4 files changed, 114 insertions(+), 14 deletions(-) create mode 100644 src/test/java/org/ohdsi/webapi/info/InfoServiceTest.java create mode 100644 src/test/java/org/ohdsi/webapi/plugins/PluginsConfigurationInfoTest.java diff --git a/src/main/java/org/ohdsi/webapi/info/InfoService.java b/src/main/java/org/ohdsi/webapi/info/InfoService.java index a15a841364..1642243d08 100644 --- a/src/main/java/org/ohdsi/webapi/info/InfoService.java +++ b/src/main/java/org/ohdsi/webapi/info/InfoService.java @@ -34,17 +34,15 @@ @RequestMapping("/info") public class InfoService { - private final Info info; + private final String version; + private final BuildInfo buildInfo; + private final List configurationInfoList; public InfoService(BuildProperties buildProperties, BuildInfo buildInfo, List configurationInfoList) { - String version = getVersion(buildProperties); - - this.info = new Info( - version, - buildInfo, - configurationInfoList.stream().collect(Collectors.toMap(ConfigurationInfo::getKey, ConfigurationInfo::getProperties)) - ); + this.version = getVersion(buildProperties); + this.buildInfo = buildInfo; + this.configurationInfoList = configurationInfoList; } /** @@ -53,7 +51,11 @@ public InfoService(BuildProperties buildProperties, BuildInfo buildInfo, List plugins; + private final Boolean atlasgisEnabled; + public PluginsConfigurationInfo( @Autowired(required = false) List plugins, @Value("${atlasgis.enabled}") Boolean atlasgisEnabled) { - if (plugins == null) { - plugins = Collections.emptyList(); - } + this.plugins = plugins == null ? Collections.emptyList() : plugins; + this.atlasgisEnabled = atlasgisEnabled; + } + + // A plugin can only report itself active once its engine has started, which + // may happen after this bean is built, and it can stop again at runtime. + // Ask on every read rather than freezing whatever was true at construction. + @Override + public Map getProperties() { + Map current = new LinkedHashMap<>(); for (WebApiPlugin plugin : plugins) { - properties.put(plugin.getId() + "Enabled", plugin.isActive()); + current.put(plugin.getId() + "Enabled", plugin.isActive()); } - properties.put("atlasgisEnabled", atlasgisEnabled); + current.put("atlasgisEnabled", atlasgisEnabled); + return current; } @Override diff --git a/src/test/java/org/ohdsi/webapi/info/InfoServiceTest.java b/src/test/java/org/ohdsi/webapi/info/InfoServiceTest.java new file mode 100644 index 0000000000..e4c044aa50 --- /dev/null +++ b/src/test/java/org/ohdsi/webapi/info/InfoServiceTest.java @@ -0,0 +1,38 @@ +package org.ohdsi.webapi.info; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.Test; +import org.ohdsi.webapi.plugins.PluginsConfigurationInfo; +import org.ohdsi.webapi.plugins.WebApiPlugin; +import org.springframework.boot.info.BuildProperties; + +public class InfoServiceTest { + + @Test + public void infoReflectsPluginStateAtRequestTime() { + + AtomicBoolean active = new AtomicBoolean(false); + WebApiPlugin plugin = mock(WebApiPlugin.class); + when(plugin.getId()).thenReturn("trexsql"); + when(plugin.isActive()).thenAnswer(invocation -> active.get()); + + BuildProperties buildProperties = mock(BuildProperties.class); + when(buildProperties.getVersion()).thenReturn("3.0.0-SNAPSHOT"); + + InfoService service = new InfoService( + buildProperties, + mock(BuildInfo.class), + Collections.singletonList(new PluginsConfigurationInfo(Collections.singletonList(plugin), false))); + + assertEquals("3.0.0", service.getInfo().getVersion()); + assertEquals(false, service.getInfo().getConfiguration().get("plugins").get("trexsqlEnabled")); + + active.set(true); + assertEquals(true, service.getInfo().getConfiguration().get("plugins").get("trexsqlEnabled")); + } +} diff --git a/src/test/java/org/ohdsi/webapi/plugins/PluginsConfigurationInfoTest.java b/src/test/java/org/ohdsi/webapi/plugins/PluginsConfigurationInfoTest.java new file mode 100644 index 0000000000..8227d40fec --- /dev/null +++ b/src/test/java/org/ohdsi/webapi/plugins/PluginsConfigurationInfoTest.java @@ -0,0 +1,47 @@ +package org.ohdsi.webapi.plugins; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.Test; + +public class PluginsConfigurationInfoTest { + + private static WebApiPlugin plugin(String id, AtomicBoolean active) { + + return new WebApiPlugin() { + public String getId() { return id; } + public String getName() { return id; } + public String getVersion() { return "1.0"; } + public boolean isActive() { return active.get(); } + }; + } + + @Test + public void reportsPluginActivationAtReadTimeNotConstructionTime() { + + AtomicBoolean active = new AtomicBoolean(false); + PluginsConfigurationInfo info = + new PluginsConfigurationInfo(Collections.singletonList(plugin("trexsql", active)), false); + + assertEquals(false, info.getProperties().get("trexsqlEnabled")); + + active.set(true); + assertEquals(true, info.getProperties().get("trexsqlEnabled")); + + active.set(false); + assertEquals(false, info.getProperties().get("trexsqlEnabled")); + } + + @Test + public void omitsPluginKeysWhenNoPluginsAreRegistered() { + + PluginsConfigurationInfo info = new PluginsConfigurationInfo(null, true); + + assertEquals(1, info.getProperties().size()); + assertEquals(true, info.getProperties().get("atlasgisEnabled")); + assertTrue(!info.getProperties().containsKey("trexsqlEnabled")); + } +}