From d6b570e356d6adc9cab24cc8308a27afae9904c5 Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Mon, 9 Sep 2024 17:01:49 +0200 Subject: [PATCH 1/9] Rename RuntimeHelper methods to match their implementations closer --- .../aceinstaller/BaseAceBeanInstaller.java | 4 +-- .../actool/helper/runtime/RuntimeHelper.java | 4 +-- .../actool/history/impl/HistoryUtils.java | 4 +-- .../actool/impl/AcConfigChangeTracker.java | 4 +-- .../actool/installhook/AcToolInstallHook.java | 2 +- .../ExtendedSlingSettingsServiceImpl.java | 6 ++-- .../impl/AcToolStartupHookServiceImpl.java | 28 +++++++++---------- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceinstaller/BaseAceBeanInstaller.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceinstaller/BaseAceBeanInstaller.java index d39d629d8..47e445ba1 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceinstaller/BaseAceBeanInstaller.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/aceinstaller/BaseAceBeanInstaller.java @@ -111,8 +111,8 @@ public void installPathBasedACEs( private Set filterReadOnlyPaths(Set paths, InstallationLogger history, Session session) { - boolean isCompositeNodeStore = RuntimeHelper.isCompositeNodeStore(session); - if (isCompositeNodeStore) { + boolean isAppsReadOnly = RuntimeHelper.isAppsReadOnly(session); + if (isAppsReadOnly) { Set pathsToKeep = new TreeSet(); Set readOnlyPaths = new TreeSet(); for (final String path : paths) { diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java index aec9ef859..52a111768 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java @@ -30,7 +30,7 @@ public class RuntimeHelper { private static final String INSTALLER_CORE_BUNDLE_SYMBOLIC_ID = "org.apache.sling.installer.core"; - public static boolean isCompositeNodeStore(Session session) { + public static boolean isAppsReadOnly(Session session) { try { String pathToCheck = "/apps"; @@ -60,7 +60,7 @@ public static int getCurrentStartLevel(BundleContext bundleContext) { return bundleContext.getBundle(Constants.SYSTEM_BUNDLE_ID).adapt(FrameworkStartLevel.class).getStartLevel(); } - public static boolean isCloudReadyInstance() { + public static boolean isCompositeNodeStore() { boolean isCloudReadyInstance = true; Bundle[] bundles = FrameworkUtil.getBundle(RuntimeHelper.class).getBundleContext().getBundles(); diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java index 2febe078e..dbfc22d25 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java @@ -127,8 +127,8 @@ public static Node persistHistory(final Session session, trigger = "startup_hook_pckmgr)"; } else { // if the history is not yet copied to apps, it's the image build - boolean isImageBuild = RuntimeHelper.isCloudReadyInstance() && !session.itemExists(AC_HISTORY_PATH_IN_APPS); - if(isImageBuild) { + boolean isCompositeNodeStore = RuntimeHelper.isCompositeNodeStore() && !session.itemExists(AC_HISTORY_PATH_IN_APPS); + if(isCompositeNodeStore) { trigger = "startup_hook_image_build"; } else { trigger = "startup_hook"; diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/impl/AcConfigChangeTracker.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/impl/AcConfigChangeTracker.java index 7700a11c7..50d03fba7 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/impl/AcConfigChangeTracker.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/impl/AcConfigChangeTracker.java @@ -66,10 +66,10 @@ public boolean configIsUnchangedComparedToLastExecution(Map conf } private String createExecutionKey(Map configFiles, String[] restrictedToPaths, Session session) { - boolean isCompositeNodeStore= RuntimeHelper.isCompositeNodeStore(session); + boolean isAppsReadOnly= RuntimeHelper.isAppsReadOnly(session); String restrictedToPathsKey = restrictedToPaths==null || restrictedToPaths.length==0 ? "ALL_PATHS" : StringUtils.join(restrictedToPaths, "+").replace("$", "").replace("^", ""); String effectiveRootPathOfConfigs = getEffectiveConfigRootPath(configFiles); - String executionKey = "hash("+StringUtils.removeEnd(effectiveRootPathOfConfigs, "/").replace('/', '\\') + "," + restrictedToPathsKey.replace('/', '\\').replace(':', '_')+","+(isCompositeNodeStore?"compNodeStore":"stdRepo")+")"; + String executionKey = "hash("+StringUtils.removeEnd(effectiveRootPathOfConfigs, "/").replace('/', '\\') + "," + restrictedToPathsKey.replace('/', '\\').replace(':', '_')+","+(isAppsReadOnly?"compNodeStore":"stdRepo")+")"; return executionKey; } diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHook.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHook.java index 288e5f78a..74eaed0cd 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHook.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook/AcToolInstallHook.java @@ -72,7 +72,7 @@ private void install(InstallContext context) throws PackageException { } alreadyRan = true; - if (RuntimeHelper.isCloudReadyInstance()) { + if (RuntimeHelper.isCompositeNodeStore()) { log("InstallHook is skipped by default in cloud (use package property 'actool.forceInstallHookInCloud = true' to force run)", listener); return; diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/slingsettings/ExtendedSlingSettingsServiceImpl.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/slingsettings/ExtendedSlingSettingsServiceImpl.java index 448e1a573..136439b05 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/slingsettings/ExtendedSlingSettingsServiceImpl.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/slingsettings/ExtendedSlingSettingsServiceImpl.java @@ -80,8 +80,8 @@ public void activate(Config config) { Set defaultRunmodes = slingSettingsService.getRunModes(); extendedRunmodes = new HashSet<>(); extendedRunmodes.addAll(defaultRunmodes); - boolean isCloudReady = RuntimeHelper.isCloudReadyInstance(); - if(isCloudReady) { + boolean isCompositeNodeStore = RuntimeHelper.isCompositeNodeStore(); + if(isCompositeNodeStore) { extendedRunmodes.add(ADDITIONAL_RUNMODE_CLOUD); } @@ -90,7 +90,7 @@ public void activate(Config config) { extendedRunmodes.addAll(additionalRunmodes); } - LOG.info("Default runmodes: {} Extended Runmodes: {} isCloudReady: {}", defaultRunmodes, extendedRunmodes, isCloudReady); + LOG.info("Default runmodes: {} Extended Runmodes: {} isCompositeNodeStore: {}", defaultRunmodes, extendedRunmodes, isCompositeNodeStore); } @Override diff --git a/accesscontroltool-startuphook-bundle/src/main/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImpl.java b/accesscontroltool-startuphook-bundle/src/main/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImpl.java index 35a32dad5..a7da91c17 100644 --- a/accesscontroltool-startuphook-bundle/src/main/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImpl.java +++ b/accesscontroltool-startuphook-bundle/src/main/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImpl.java @@ -67,23 +67,23 @@ public enum StartupHookActivation { @Reference(policyOption = ReferencePolicyOption.GREEDY) private SlingRepository repository; - private boolean isCompositeNodeStore; + private boolean isAppsReadOnly; @Activate public void activate(BundleContext bundleContext, Config config) { - boolean isCloudReady = RuntimeHelper.isCloudReadyInstance(); + boolean isCompositeNodeStore = RuntimeHelper.isCompositeNodeStore(); Config.StartupHookActivation activationMode = config.activationMode(); boolean runAsyncForMutableConent = config.runAsyncForMutableConent(); int currentStartLevel = RuntimeHelper.getCurrentStartLevel(bundleContext); - LOG.info("AcTool Startup Hook (start level: {} isCloudReady: {} activationMode: {} runAsyncForMutableConent: {})", + LOG.info("AcTool Startup Hook (start level: {} isCompositeNodeStore: {} activationMode: {} runAsyncForMutableConent: {})", currentStartLevel, - isCloudReady, + isCompositeNodeStore, activationMode, runAsyncForMutableConent); boolean applyOnStartup = (activationMode == Config.StartupHookActivation.ALWAYS) - || (isCloudReady && activationMode == Config.StartupHookActivation.CLOUD_ONLY); + || (isCompositeNodeStore && activationMode == Config.StartupHookActivation.CLOUD_ONLY); if (applyOnStartup) { @@ -91,16 +91,16 @@ public void activate(BundleContext bundleContext, Config config) { LOG.info("Running AcTool with " + (relevantPathsForInstallation.isEmpty() ? "all paths" : "paths " + relevantPathsForInstallation) + "..."); - if (runAsyncForMutableConent && isCompositeNodeStore) { + if (runAsyncForMutableConent && isAppsReadOnly) { LOG.info( "Running AcTool asynchronously on mutable content of composite node store (config runAsyncForMutableConent=true)..."); - runAcToolAsync(relevantPathsForInstallation, currentStartLevel, isCloudReady); + runAcToolAsync(relevantPathsForInstallation, currentStartLevel, isCompositeNodeStore); } else { - runAcTool(relevantPathsForInstallation, currentStartLevel, isCloudReady); + runAcTool(relevantPathsForInstallation, currentStartLevel, isCompositeNodeStore); } } else { - LOG.debug("Skipping AcTool Startup Hook: activationMode: {} isCloudReady: {}", activationMode, isCloudReady); + LOG.debug("Skipping AcTool Startup Hook: activationMode: {} isCompositeNodeStore: {}", activationMode, isCompositeNodeStore); } } @@ -131,10 +131,10 @@ private List getRelevantPathsForInstallation() { try { session = repository.loginService(null, null); - isCompositeNodeStore = RuntimeHelper.isCompositeNodeStore(session); - LOG.info("Repo is running with Composite NodeStore: {}", isCompositeNodeStore); + isAppsReadOnly = RuntimeHelper.isAppsReadOnly(session); + LOG.info("Repo is running with Composite NodeStore: {}", isAppsReadOnly); - if(!isCompositeNodeStore) { + if(!isAppsReadOnly) { return Collections.emptyList(); } @@ -149,7 +149,7 @@ private List getRelevantPathsForInstallation() { AccessControlConstants.REP_REPO_POLICY).contains(node.getName())) { continue; } - if (isCompositeNodeStore && Arrays.asList("apps", "libs").contains(node.getName())) { + if (isAppsReadOnly && Arrays.asList("apps", "libs").contains(node.getName())) { continue; } relevantPathsForInstallation.add(node.getPath()); @@ -179,7 +179,7 @@ private void copyAcHistoryToOrFromApps(boolean isCloudReady) { try { session = repository.loginService(null, null); - if(isCompositeNodeStore) { + if(isAppsReadOnly) { LOG.info("Restoring history from /apps to /var"); if(session.nodeExists(HistoryUtils.AC_HISTORY_PATH_IN_APPS)) { From 3f1999b5c2dde3065cefef813c799b74fbc3381d Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Tue, 10 Sep 2024 16:51:31 +0200 Subject: [PATCH 2/9] Add a unit test --- .../actool/helper/runtime/RuntimeHelper.java | 2 +- accesscontroltool-startuphook-bundle/pom.xml | 21 +++++ .../impl/AcToolStartupHookServiceImpl.java | 11 +-- .../AcToolStartupHookServiceImplTest.java | 83 +++++++++++++++++++ .../org.mockito.plugins.MockMaker | 1 + pom.xml | 2 +- 6 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java create mode 100644 accesscontroltool-startuphook-bundle/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java index 52a111768..3db3f0be4 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java @@ -28,7 +28,7 @@ public class RuntimeHelper { public static final Logger LOG = LoggerFactory.getLogger(RuntimeHelper.class); - private static final String INSTALLER_CORE_BUNDLE_SYMBOLIC_ID = "org.apache.sling.installer.core"; + public static final String INSTALLER_CORE_BUNDLE_SYMBOLIC_ID = "org.apache.sling.installer.core"; public static boolean isAppsReadOnly(Session session) { diff --git a/accesscontroltool-startuphook-bundle/pom.xml b/accesscontroltool-startuphook-bundle/pom.xml index de3b9b064..029e39c38 100644 --- a/accesscontroltool-startuphook-bundle/pom.xml +++ b/accesscontroltool-startuphook-bundle/pom.xml @@ -61,6 +61,27 @@ javax.servlet-api provided + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + diff --git a/accesscontroltool-startuphook-bundle/src/main/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImpl.java b/accesscontroltool-startuphook-bundle/src/main/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImpl.java index a7da91c17..fa1a0e18a 100644 --- a/accesscontroltool-startuphook-bundle/src/main/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImpl.java +++ b/accesscontroltool-startuphook-bundle/src/main/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImpl.java @@ -62,10 +62,10 @@ public enum StartupHookActivation { } @Reference(policyOption = ReferencePolicyOption.GREEDY) - private AcInstallationService acInstallationService; + AcInstallationService acInstallationService; @Reference(policyOption = ReferencePolicyOption.GREEDY) - private SlingRepository repository; + SlingRepository repository; private boolean isAppsReadOnly; @@ -118,12 +118,7 @@ private void runAcTool(List relevantPathsForInstallation, int currentSta private void runAcToolAsync(final List relevantPathsForInstallation, final int currentStartLevel, final boolean isCloudReady) { final AcToolStartupHookServiceImpl startupHook = this; - new Thread(new Runnable() { - @Override - public void run() { - startupHook.runAcTool(relevantPathsForInstallation, currentStartLevel, isCloudReady); - } - }, THREAD_NAME_ASYNC).start(); + new Thread(() -> startupHook.runAcTool(relevantPathsForInstallation, currentStartLevel, isCloudReady), THREAD_NAME_ASYNC).start(); } private List getRelevantPathsForInstallation() { diff --git a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java new file mode 100644 index 000000000..8b7714b18 --- /dev/null +++ b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java @@ -0,0 +1,83 @@ +package biz.netcentric.cq.tools.actool.startuphook.impl; + +/*- + * #%L + * Access Control Tool Bundle + * %% + * Copyright (C) 2015 - 2024 Cognizant Netcentric + * %% + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * #L% + */ + +import biz.netcentric.cq.tools.actool.api.AcInstallationService; +import biz.netcentric.cq.tools.actool.helper.runtime.RuntimeHelper; +import org.apache.sling.jcr.api.SlingRepository; +import org.junit.jupiter.api.BeforeEach; +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.Spy; +import org.mockito.junit.jupiter.MockitoExtension; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.startlevel.FrameworkStartLevel; + +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AcToolStartupHookServiceImplTest { + + @Mock + Bundle bundle; + + @Mock + BundleContext bundleContext; + + @Mock + AcToolStartupHookServiceImpl.Config config; + + @Mock + SlingRepository repository; + + @Spy + AcInstallationService installationService; + + @BeforeEach + void setup() throws RepositoryException { + FrameworkStartLevel startLevel = Mockito.mock(FrameworkStartLevel.class); + when(startLevel.getStartLevel()).thenReturn(0); + + when(config.activationMode()).thenReturn(AcToolStartupHookServiceImpl.Config.StartupHookActivation.ALWAYS); + + Session session = mock(Session.class); + when(repository.loginService(null, null)).thenReturn(session); + + when(bundle.getBundleContext()).thenReturn(bundleContext); + when(bundle.getSymbolicName()).thenReturn(RuntimeHelper.INSTALLER_CORE_BUNDLE_SYMBOLIC_ID); + when(bundle.adapt(FrameworkStartLevel.class)).thenReturn(startLevel); + + when(bundleContext.getBundles()).thenReturn(new Bundle[] { bundle }); + when(bundleContext.getBundle(anyLong())).thenReturn(bundle); + } + @Test + void testActivation() { + try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { + mockedFrameworkUtil.when(() -> FrameworkUtil.getBundle(RuntimeHelper.class)).thenReturn(bundle); + AcToolStartupHookServiceImpl startupHookService = new AcToolStartupHookServiceImpl(); + startupHookService.repository = repository; + startupHookService.acInstallationService = installationService; + startupHookService.activate(bundleContext, config); + verify(installationService, times(1)).apply(null, new String[]{}, true); + } + } +} \ No newline at end of file diff --git a/accesscontroltool-startuphook-bundle/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/accesscontroltool-startuphook-bundle/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 000000000..1f0955d45 --- /dev/null +++ b/accesscontroltool-startuphook-bundle/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline diff --git a/pom.xml b/pom.xml index c6c9f62e2..d4fddaa4c 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,7 @@ 1.64 8 - 4.8.0 + 5.13.0 5.10.0 ${project.build.directory}/${project.build.finalName}.zip From c657f96d2e5ee8c3ec1b08906d8db105eeb423f8 Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Tue, 10 Sep 2024 17:37:01 +0200 Subject: [PATCH 3/9] Add another unit test for Async execution --- .../AcToolStartupHookServiceImplTest.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java index 8b7714b18..7e2602533 100644 --- a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java +++ b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java @@ -69,15 +69,29 @@ void setup() throws RepositoryException { when(bundleContext.getBundles()).thenReturn(new Bundle[] { bundle }); when(bundleContext.getBundle(anyLong())).thenReturn(bundle); } + @Test - void testActivation() { + void testActivationSync() { try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { - mockedFrameworkUtil.when(() -> FrameworkUtil.getBundle(RuntimeHelper.class)).thenReturn(bundle); - AcToolStartupHookServiceImpl startupHookService = new AcToolStartupHookServiceImpl(); - startupHookService.repository = repository; - startupHookService.acInstallationService = installationService; - startupHookService.activate(bundleContext, config); + createAndActivateStartupHookService(mockedFrameworkUtil, false); verify(installationService, times(1)).apply(null, new String[]{}, true); } } + + @Test + void testActivationAsync() { + try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { + createAndActivateStartupHookService(mockedFrameworkUtil, true); + verify(installationService, times(1)).apply(null, new String[]{}, true); + } + } + + private void createAndActivateStartupHookService(MockedStatic mockedFrameworkUtil, boolean runAsyncForMutableContent) { + mockedFrameworkUtil.when(() -> FrameworkUtil.getBundle(RuntimeHelper.class)).thenReturn(bundle); + AcToolStartupHookServiceImpl startupHookService = new AcToolStartupHookServiceImpl(); + startupHookService.repository = repository; + startupHookService.acInstallationService = installationService; + when(config.runAsyncForMutableConent()).thenReturn(runAsyncForMutableContent); + startupHookService.activate(bundleContext, config); + } } \ No newline at end of file From 8927f9bdcc8c3c0c31be9c2430ddb2ea3c5069c4 Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Tue, 10 Sep 2024 18:28:20 +0200 Subject: [PATCH 4/9] Turn it into parameterized test to increase coverage --- .../actool/helper/runtime/RuntimeHelper.java | 4 +- .../AcToolStartupHookServiceImplTest.java | 53 +++++++++++++------ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java index 3db3f0be4..feb262a2b 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelper.java @@ -45,8 +45,8 @@ public static boolean isAppsReadOnly(Session session) { // see https://issues.apache.org/jira/browse/OAK-6563 boolean hasCapability = session.hasCapability("addNode", appsNode, new Object[] { "nt:folder" }); - boolean isCompositeNode = hasPermission && !hasCapability; - return isCompositeNode; + boolean isAppsReadOnly = hasPermission && !hasCapability; + return isAppsReadOnly; } catch(Exception e) { throw new IllegalStateException("Could not check if session is connected to a composite node store: "+e, e); } diff --git a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java index 7e2602533..3cf1d6dcb 100644 --- a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java +++ b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java @@ -19,6 +19,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.Mockito; @@ -29,9 +31,12 @@ import org.osgi.framework.FrameworkUtil; import org.osgi.framework.startlevel.FrameworkStartLevel; +import javax.jcr.Node; +import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.Session; +import static org.apache.sling.api.resource.runtime.dto.AuthType.no; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @@ -46,20 +51,33 @@ class AcToolStartupHookServiceImplTest { @Mock AcToolStartupHookServiceImpl.Config config; + @Mock + Session session; + @Mock SlingRepository repository; + @Mock + Node rootNode; + + @Mock + NodeIterator noChildren; + @Spy AcInstallationService installationService; - @BeforeEach - void setup() throws RepositoryException { + void setup(boolean canReadApps) throws RepositoryException { FrameworkStartLevel startLevel = Mockito.mock(FrameworkStartLevel.class); when(startLevel.getStartLevel()).thenReturn(0); when(config.activationMode()).thenReturn(AcToolStartupHookServiceImpl.Config.StartupHookActivation.ALWAYS); - Session session = mock(Session.class); + when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(canReadApps); + if (canReadApps) { + when(noChildren.hasNext()).thenReturn(false); + when(rootNode.getNodes()).thenReturn(noChildren); + when(session.getRootNode()).thenReturn(rootNode); + } when(repository.loginService(null, null)).thenReturn(session); when(bundle.getBundleContext()).thenReturn(bundleContext); @@ -70,19 +88,24 @@ void setup() throws RepositoryException { when(bundleContext.getBundle(anyLong())).thenReturn(bundle); } - @Test - void testActivationSync() { - try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { - createAndActivateStartupHookService(mockedFrameworkUtil, false); - verify(installationService, times(1)).apply(null, new String[]{}, true); - } - } - - @Test - void testActivationAsync() { + @ParameterizedTest + @CsvSource({ + "false, false, true", + "false, true, false", + "true, false, true" + // "true, true, false" + /* + last case is excluded, because it starts a thread in AcToolStartupHookServiceImpl#runAcToolAsync + so AcToolStartupHookServiceImpl#apply is invoked asynchronously and can not be checked easily in + unit test + */ + + }) + void testActivationSync(boolean runAsync, boolean canReadApps, boolean pathsForInstallationEmpty) throws RepositoryException { + setup(canReadApps); try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { - createAndActivateStartupHookService(mockedFrameworkUtil, true); - verify(installationService, times(1)).apply(null, new String[]{}, true); + createAndActivateStartupHookService(mockedFrameworkUtil, runAsync); + verify(installationService, times(1)).apply(null, pathsForInstallationEmpty ? new String[]{} : new String[]{ "^/$", "^$" }, true); } } From f5dc3cab2616ce70fcf175ca166e6b948c8321bc Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Tue, 10 Sep 2024 22:38:34 +0200 Subject: [PATCH 5/9] Cover the async part with Thread.sleep --- .../AcToolStartupHookServiceImplTest.java | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java index 3cf1d6dcb..2318d2e13 100644 --- a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java +++ b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java @@ -66,6 +66,25 @@ class AcToolStartupHookServiceImplTest { @Spy AcInstallationService installationService; + @ParameterizedTest + @CsvSource({ + "false, false, true", + "false, true, false", + "true, false, true", + "true, true, false" + }) + void testActivationSync(boolean runAsync, boolean canReadApps, boolean pathsForInstallationEmpty) throws RepositoryException, InterruptedException { + setup(canReadApps); + try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { + createAndActivateStartupHookService(mockedFrameworkUtil, runAsync); + // wait for the thread in AcToolStartupHookServiceImpl#runAcToolAsync to get started + if (runAsync && canReadApps) { + Thread.sleep(1000L); + } + verify(installationService, times(1)).apply(null, pathsForInstallationEmpty ? new String[]{} : new String[]{ "^/$", "^$" }, true); + } + } + void setup(boolean canReadApps) throws RepositoryException { FrameworkStartLevel startLevel = Mockito.mock(FrameworkStartLevel.class); when(startLevel.getStartLevel()).thenReturn(0); @@ -88,27 +107,6 @@ void setup(boolean canReadApps) throws RepositoryException { when(bundleContext.getBundle(anyLong())).thenReturn(bundle); } - @ParameterizedTest - @CsvSource({ - "false, false, true", - "false, true, false", - "true, false, true" - // "true, true, false" - /* - last case is excluded, because it starts a thread in AcToolStartupHookServiceImpl#runAcToolAsync - so AcToolStartupHookServiceImpl#apply is invoked asynchronously and can not be checked easily in - unit test - */ - - }) - void testActivationSync(boolean runAsync, boolean canReadApps, boolean pathsForInstallationEmpty) throws RepositoryException { - setup(canReadApps); - try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { - createAndActivateStartupHookService(mockedFrameworkUtil, runAsync); - verify(installationService, times(1)).apply(null, pathsForInstallationEmpty ? new String[]{} : new String[]{ "^/$", "^$" }, true); - } - } - private void createAndActivateStartupHookService(MockedStatic mockedFrameworkUtil, boolean runAsyncForMutableContent) { mockedFrameworkUtil.when(() -> FrameworkUtil.getBundle(RuntimeHelper.class)).thenReturn(bundle); AcToolStartupHookServiceImpl startupHookService = new AcToolStartupHookServiceImpl(); From e8f1f480ea3176e732b883c137b7fac53c1cac82 Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Wed, 11 Sep 2024 00:43:12 +0200 Subject: [PATCH 6/9] Refactor test methods to increase coverage of activate --- .../AcToolStartupHookServiceImplTest.java | 80 ++++++++++++------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java index 2318d2e13..5d4a22ed7 100644 --- a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java +++ b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java @@ -16,11 +16,8 @@ import biz.netcentric.cq.tools.actool.api.AcInstallationService; import biz.netcentric.cq.tools.actool.helper.runtime.RuntimeHelper; import org.apache.sling.jcr.api.SlingRepository; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.Mockito; @@ -36,7 +33,6 @@ import javax.jcr.RepositoryException; import javax.jcr.Session; -import static org.apache.sling.api.resource.runtime.dto.AuthType.no; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @@ -66,53 +62,81 @@ class AcToolStartupHookServiceImplTest { @Spy AcInstallationService installationService; - @ParameterizedTest - @CsvSource({ - "false, false, true", - "false, true, false", - "true, false, true", - "true, true, false" - }) - void testActivationSync(boolean runAsync, boolean canReadApps, boolean pathsForInstallationEmpty) throws RepositoryException, InterruptedException { - setup(canReadApps); + @Test + void testActivationWithModifiableRoot() throws RepositoryException { + boolean canSetPropertiesOnRootNode = true, runAsync = false, cloudOnly = false; + setup(canSetPropertiesOnRootNode, runAsync, cloudOnly); try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { - createAndActivateStartupHookService(mockedFrameworkUtil, runAsync); - // wait for the thread in AcToolStartupHookServiceImpl#runAcToolAsync to get started - if (runAsync && canReadApps) { - Thread.sleep(1000L); - } - verify(installationService, times(1)).apply(null, pathsForInstallationEmpty ? new String[]{} : new String[]{ "^/$", "^$" }, true); + createAndActivateStartupHookService(mockedFrameworkUtil); + verify(installationService, times(1)).apply(null, new String[]{"^/$", "^$"}, true); } } - void setup(boolean canReadApps) throws RepositoryException { + @Test + void testActivationWithUnmodifiableRoot() throws RepositoryException { + boolean canSetPropertiesOnRootNode = false, runAsync = false, cloudOnly = false; + setup(canSetPropertiesOnRootNode, runAsync, cloudOnly); + try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { + createAndActivateStartupHookService(mockedFrameworkUtil); + verify(installationService, times(1)).apply(null, new String[]{}, true); + } + } + + @Test + void testActivationWithCloudOnly() throws RepositoryException { + boolean canSetPropertiesOnRootNode = false, runAsync = false, cloudOnly = true; + setup(canSetPropertiesOnRootNode, runAsync, cloudOnly); + try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { + createAndActivateStartupHookService(mockedFrameworkUtil); + verify(installationService, never()).apply(null, new String[]{"^/$", "^$"}, true); + } + } + + @Test + void testActivationWithAsync() throws RepositoryException, InterruptedException { + boolean canSetPropertiesOnRootNode = true, runAsync = true, cloudOnly = false; + setup(canSetPropertiesOnRootNode, runAsync, cloudOnly); + try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { + createAndActivateStartupHookService(mockedFrameworkUtil); + Thread.sleep(1000L); + verify(installationService, times(1)).apply(null, new String[]{"^/$", "^$"}, true); + } + } + + void setup(boolean canSetPropertiesOnRootNode, boolean runAsyncForMutableContent, boolean cloudOnly) throws RepositoryException { FrameworkStartLevel startLevel = Mockito.mock(FrameworkStartLevel.class); when(startLevel.getStartLevel()).thenReturn(0); - when(config.activationMode()).thenReturn(AcToolStartupHookServiceImpl.Config.StartupHookActivation.ALWAYS); - - when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(canReadApps); - if (canReadApps) { + if (canSetPropertiesOnRootNode) { + when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(true); when(noChildren.hasNext()).thenReturn(false); when(rootNode.getNodes()).thenReturn(noChildren); when(session.getRootNode()).thenReturn(rootNode); + } else if (!canSetPropertiesOnRootNode && !cloudOnly){ + when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(false); + } + if (!cloudOnly) { + when(repository.loginService(null, null)).thenReturn(session); } - when(repository.loginService(null, null)).thenReturn(session); when(bundle.getBundleContext()).thenReturn(bundleContext); when(bundle.getSymbolicName()).thenReturn(RuntimeHelper.INSTALLER_CORE_BUNDLE_SYMBOLIC_ID); when(bundle.adapt(FrameworkStartLevel.class)).thenReturn(startLevel); - when(bundleContext.getBundles()).thenReturn(new Bundle[] { bundle }); + when(bundleContext.getBundles()).thenReturn(new Bundle[]{bundle}); when(bundleContext.getBundle(anyLong())).thenReturn(bundle); + + when(config.runAsyncForMutableConent()).thenReturn(runAsyncForMutableContent); + when(config.activationMode()).thenReturn(cloudOnly ? + AcToolStartupHookServiceImpl.Config.StartupHookActivation.CLOUD_ONLY : + AcToolStartupHookServiceImpl.Config.StartupHookActivation.ALWAYS); } - private void createAndActivateStartupHookService(MockedStatic mockedFrameworkUtil, boolean runAsyncForMutableContent) { + private void createAndActivateStartupHookService(MockedStatic mockedFrameworkUtil) { mockedFrameworkUtil.when(() -> FrameworkUtil.getBundle(RuntimeHelper.class)).thenReturn(bundle); AcToolStartupHookServiceImpl startupHookService = new AcToolStartupHookServiceImpl(); startupHookService.repository = repository; startupHookService.acInstallationService = installationService; - when(config.runAsyncForMutableConent()).thenReturn(runAsyncForMutableContent); startupHookService.activate(bundleContext, config); } } \ No newline at end of file From 3677c0ea9f39972adc0542a16cbdb677bf14937e Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Wed, 11 Sep 2024 08:58:25 +0200 Subject: [PATCH 7/9] Add tests for RuntimeHelper --- .../helper/runtime/RuntimeHelperTest.java | 44 +++++++++++++++++++ .../AcToolStartupHookServiceImplTest.java | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelperTest.java diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelperTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelperTest.java new file mode 100644 index 000000000..02b5f179f --- /dev/null +++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelperTest.java @@ -0,0 +1,44 @@ +package biz.netcentric.cq.tools.actool.helper.runtime; + +/*- + * #%L + * Access Control Tool Bundle + * %% + * Copyright (C) 2015 - 2024 Cognizant Netcentric + * %% + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * #L% + */ + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class RuntimeHelperTest { + + @Mock + Session session; + + @Test + void shouldBeReadonlyIfRootWritable() throws RepositoryException { + when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(true); + Assertions.assertTrue(RuntimeHelper.isAppsReadOnly(session)); + } + + @Test + void shouldNotBeReadonlyIfRootNotWritable() throws RepositoryException { + when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(false); + Assertions.assertFalse(RuntimeHelper.isAppsReadOnly(session)); + } +} \ No newline at end of file diff --git a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java index 5d4a22ed7..98ee7efb2 100644 --- a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java +++ b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java @@ -112,7 +112,7 @@ void setup(boolean canSetPropertiesOnRootNode, boolean runAsyncForMutableContent when(noChildren.hasNext()).thenReturn(false); when(rootNode.getNodes()).thenReturn(noChildren); when(session.getRootNode()).thenReturn(rootNode); - } else if (!canSetPropertiesOnRootNode && !cloudOnly){ + } else if (!canSetPropertiesOnRootNode && !cloudOnly) { when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(false); } if (!cloudOnly) { From 79204566bd7a361d00c9cc79fb84fa64b243c6fe Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Wed, 11 Sep 2024 09:07:45 +0200 Subject: [PATCH 8/9] Trigger Build From b160bed197a5065670267840d3c84b026c4e2390 Mon Sep 17 00:00:00 2001 From: Igor Rogic Date: Wed, 11 Sep 2024 10:20:39 +0200 Subject: [PATCH 9/9] Test RuntimeHelper#isCompositeNodeStore too --- .../helper/runtime/RuntimeHelperTest.java | 41 +++++++++++++++++-- .../AcToolStartupHookServiceImplTest.java | 3 +- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelperTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelperTest.java index 02b5f179f..fe79438b6 100644 --- a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelperTest.java +++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/helper/runtime/RuntimeHelperTest.java @@ -13,15 +13,21 @@ * #L% */ -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import javax.jcr.RepositoryException; import javax.jcr.Session; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -30,15 +36,44 @@ class RuntimeHelperTest { @Mock Session session; + @Mock + Bundle bundle; + + @Mock + BundleContext bundleContext; + @Test void shouldBeReadonlyIfRootWritable() throws RepositoryException { when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(true); - Assertions.assertTrue(RuntimeHelper.isAppsReadOnly(session)); + assertTrue(RuntimeHelper.isAppsReadOnly(session)); } @Test void shouldNotBeReadonlyIfRootNotWritable() throws RepositoryException { when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(false); - Assertions.assertFalse(RuntimeHelper.isAppsReadOnly(session)); + assertFalse(RuntimeHelper.isAppsReadOnly(session)); + } + + @Test + void shouldNotBeCompositeStoreWhenCoreInstallerPresent() { + try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { + setupOsgi(RuntimeHelper.INSTALLER_CORE_BUNDLE_SYMBOLIC_ID, mockedFrameworkUtil); + assertFalse(RuntimeHelper.isCompositeNodeStore()); + } + } + + @Test + void shouldBeCompositeStoreWhenCoreInstallerNotPresent() { + try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { + setupOsgi("unknown.bundle", mockedFrameworkUtil); + assertTrue(RuntimeHelper.isCompositeNodeStore()); + } + } + + private void setupOsgi(String t, MockedStatic mockedFrameworkUtil) { + when(bundle.getBundleContext()).thenReturn(bundleContext); + when(bundle.getSymbolicName()).thenReturn(t); + when(bundleContext.getBundles()).thenReturn(new Bundle[]{bundle}); + mockedFrameworkUtil.when(() -> FrameworkUtil.getBundle(RuntimeHelper.class)).thenReturn(bundle); } } \ No newline at end of file diff --git a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java index 98ee7efb2..d90ca41ef 100644 --- a/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java +++ b/accesscontroltool-startuphook-bundle/src/test/java/biz/netcentric/cq/tools/actool/startuphook/impl/AcToolStartupHookServiceImplTest.java @@ -98,6 +98,7 @@ void testActivationWithAsync() throws RepositoryException, InterruptedException setup(canSetPropertiesOnRootNode, runAsync, cloudOnly); try (MockedStatic mockedFrameworkUtil = mockStatic(FrameworkUtil.class)) { createAndActivateStartupHookService(mockedFrameworkUtil); + // best attempt to test asynchronous invocation in AcToolStartupHookServiceImpl#runAcToolAsync Thread.sleep(1000L); verify(installationService, times(1)).apply(null, new String[]{"^/$", "^$"}, true); } @@ -112,7 +113,7 @@ void setup(boolean canSetPropertiesOnRootNode, boolean runAsyncForMutableContent when(noChildren.hasNext()).thenReturn(false); when(rootNode.getNodes()).thenReturn(noChildren); when(session.getRootNode()).thenReturn(rootNode); - } else if (!canSetPropertiesOnRootNode && !cloudOnly) { + } else if (!cloudOnly) { when(session.hasPermission("/", Session.ACTION_SET_PROPERTY)).thenReturn(false); } if (!cloudOnly) {