You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2024/12/03 15:01:53 UTC

(jackrabbit-oak) branch trunk updated: OAK-11247: Migrated groovy test files to Java (#1851)

This is an automated email from the ASF dual-hosted git repository.

angela pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 711d3fa389 OAK-11247: Migrated groovy test files to Java (#1851)
711d3fa389 is described below

commit 711d3fa38970d492dbcdff549f5f83acb6eea751
Author: Alejandro Moratinos <Am...@users.noreply.github.com>
AuthorDate: Tue Dec 3 16:01:47 2024 +0100

    OAK-11247: Migrated groovy test files to Java (#1851)
    
    * OAK-11247: Migrated groovy test files to Java
    
    * OAK-11247: Removed groovy file after rebase
    
    Removed gmavenplus plugin from pom
---
 oak-pojosr/pom.xml                                 |  37 --
 .../run/osgi/AbstractRepositoryFactoryTest.groovy  | 253 -----------
 .../jackrabbit/oak/run/osgi/ConfigTest.groovy      | 151 -------
 .../run/osgi/DocumentNodeStoreConfigTest.groovy    | 458 -------------------
 .../oak/run/osgi/JaasConfigSpiTest.groovy          | 129 ------
 .../oak/run/osgi/JsonConfigRepFactoryTest.groovy   |  65 ---
 .../oak/run/osgi/LuceneSupportTest.groovy          | 114 -----
 .../oak/run/osgi/MBeanIntegrationTest.groovy       |  49 --
 .../oak/run/osgi/NodeStoreConfigTest.groovy        |  50 ---
 .../run/osgi/PropertyIndexReindexingTest.groovy    |  82 ----
 .../oak/run/osgi/RepositoryClosedTest.groovy       |  72 ---
 .../oak/run/osgi/RepositoryShutdownTest.groovy     |  84 ----
 .../oak/run/osgi/SecondaryStoreConfigIT.groovy     |  83 ----
 .../osgi/SecurityProviderRegistrationTest.groovy   | 390 ----------------
 .../oak/run/osgi/SegmentNodeStoreConfigTest.groovy | 158 -------
 .../run/osgi/TarSegmentNodeStoreConfigTest.groovy  |  70 ---
 .../oak/run/osgi/TokenAuthenticationTest.groovy    | 153 -------
 .../oak/run/osgi/TrackerSupportTest.groovy         |  54 ---
 .../run/osgi/AbstractRepositoryFactoryTest.java    | 285 ++++++++++++
 .../apache/jackrabbit/oak/run/osgi/ConfigTest.java | 168 +++++++
 .../oak/run/osgi/DocumentNodeStoreConfigTest.java  | 498 +++++++++++++++++++++
 .../oak/run/osgi/HybridIndexDisabledTest.java}     |  88 ++--
 .../jackrabbit/oak/run/osgi/JaasConfigSpiTest.java | 129 ++++++
 .../oak/run/osgi/JsonConfigRepFactoryTest.java     |  68 +++
 .../jackrabbit/oak/run/osgi/LuceneSupportTest.java | 145 ++++++
 .../oak/run/osgi/MBeanIntegrationTest.java         |  51 +++
 .../oak/run/osgi/NodeStoreConfigTest.java          |  51 +++
 .../oak/run/osgi/OakOSGiRepositoryFactoryTest.java |  20 +-
 .../oak/run/osgi/PropertyIndexReindexingTest.java  |  89 ++++
 .../oak/run/osgi/RepositoryClosedTest.java         |  68 +++
 .../oak/run/osgi/RepositoryShutdownTest.java       |  83 ++++
 .../oak/run/osgi/SecondaryStoreConfigIT.java       |  85 ++++
 .../run/osgi/SecurityProviderRegistrationTest.java | 392 ++++++++++++++++
 .../oak/run/osgi/SegmentNodeStoreConfigTest.java   | 164 +++++++
 .../oak/run/osgi/SimpleRepositoryFactoryTest.java  |  16 +-
 .../run/osgi/TarSegmentNodeStoreConfigTest.java    |  66 +++
 .../oak/run/osgi/TokenAuthenticationTest.java      | 168 +++++++
 .../oak/run/osgi/TrackerSupportTest.java           |  63 +++
 38 files changed, 2636 insertions(+), 2513 deletions(-)

diff --git a/oak-pojosr/pom.xml b/oak-pojosr/pom.xml
index b9cc14b697..9590e9cac3 100644
--- a/oak-pojosr/pom.xml
+++ b/oak-pojosr/pom.xml
@@ -32,24 +32,6 @@
 
   <build>
     <plugins>
-      <plugin>
-        <groupId>org.codehaus.gmavenplus</groupId>
-        <artifactId>gmavenplus-plugin</artifactId>
-        <executions>
-          <execution>
-            <goals>
-              <goal>addSources</goal>
-              <goal>addTestSources</goal>
-              <goal>generateStubs</goal>
-              <goal>compile</goal>
-              <goal>generateTestStubs</goal>
-              <goal>compileTests</goal>
-              <goal>removeStubs</goal>
-              <goal>removeTestStubs</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
       <plugin>
         <groupId>org.apache.rat</groupId>
         <artifactId>apache-rat-plugin</artifactId>
@@ -311,25 +293,6 @@
       <version>${h2.version}</version>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.codehaus.groovy</groupId>
-      <artifactId>groovy</artifactId>
-      <version>${groovy.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.groovy</groupId>
-      <artifactId>groovy-json</artifactId>
-      <version>${groovy.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.groovy</groupId>
-      <artifactId>groovy-sql</artifactId>
-      <version>${groovy.version}</version>
-      <scope>test</scope>
-    </dependency>
-
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>log4j-over-slf4j</artifactId>
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.groovy
deleted file mode 100644
index 28e5e85c97..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.groovy
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.commons.io.FilenameUtils
-import org.apache.jackrabbit.api.JackrabbitRepository
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.rules.TemporaryFolder
-import org.osgi.framework.BundleContext
-import org.osgi.framework.ServiceEvent
-import org.osgi.framework.ServiceListener
-import org.osgi.framework.ServiceReference
-import org.osgi.service.cm.ConfigurationAdmin
-import org.osgi.service.component.runtime.ServiceComponentRuntime
-import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO
-import org.osgi.util.promise.Promise
-import org.osgi.util.tracker.ServiceTracker
-
-import javax.jcr.Repository
-import javax.jcr.RepositoryFactory
-import javax.jcr.RepositoryException
-import javax.jcr.Session
-import javax.jcr.SimpleCredentials
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_HOME
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_TIMEOUT_IN_SECS
-import static org.junit.Assert.fail
-
-abstract class AbstractRepositoryFactoryTest{
-    static final int SVC_WAIT_TIME = Integer.getInteger("pojosr.waitTime", 10)
-    Map config
-    File workDir
-    Repository repository
-    RepositoryFactory repositoryFactory = new OakOSGiRepositoryFactory();
-
-    @Rule
-    public final TemporaryFolder tmpFolder = new TemporaryFolder(new File("target"))
-
-    @Before
-    void setUp() {
-        workDir = tmpFolder.getRoot();
-        config = [
-                (REPOSITORY_HOME): workDir.absolutePath,
-                (REPOSITORY_TIMEOUT_IN_SECS) : 60,
-        ]
-    }
-
-    @After
-    void tearDown() {
-        try {
-            if (repository == null) {
-                PojoServiceRegistry registry = getRegistry()
-                OakOSGiRepositoryFactory.shutdown(registry, 5)
-            }
-        } catch (AssertionError ignore){
-
-        }
-
-        if (repository instanceof JackrabbitRepository) {
-            ((JackrabbitRepository) repository).shutdown();
-        }
-    }
-
-    protected PojoServiceRegistry getRegistry() {
-        assert repository instanceof ServiceRegistryProvider
-        return ((ServiceRegistryProvider) repository).getServiceRegistry()
-    }
-
-    protected <T> void assertNoService(Class<T> clazz) {
-        ServiceReference<T> sr = registry.getServiceReference(clazz.name)
-        assert sr == null: "Service of type $clazz was found"
-    }
-
-    protected <T> T getService(Class<T> clazz) {
-        ServiceReference<T> sr = registry.getServiceReference(clazz.name)
-        assert sr: "Not able to found a service of type $clazz"
-        return (T) registry.getService(sr)
-    }
-
-    protected <T> T getServiceWithWait(Class<T> clazz) {
-        return getServiceWithWait(clazz, getRegistry().bundleContext)
-    }
-
-    protected static <T> T getServiceWithWait(Class<T> clazz, BundleContext bundleContext) {
-        ServiceTracker st = new ServiceTracker(bundleContext, clazz.name, null)
-        st.open()
-        T sr = (T) st.waitForService(TimeUnit.SECONDS.toMillis(SVC_WAIT_TIME))
-        assert sr , "No service found for ${clazz.name}"
-        return sr
-    }
-
-    protected File getResource(String path){
-        File file = new File(FilenameUtils.concat(getBaseDir(), "src/test/resources/$path"))
-        assert file.exists() : "No file found at ${file.absolutePath}"
-        return file
-    }
-
-    protected void createConfig(Map config){
-        ConfigurationAdmin cm = getService(ConfigurationAdmin.class)
-        ConfigInstaller ci = new ConfigInstaller(cm, getRegistry().bundleContext)
-        ci.installConfigs(config)
-    }
-
-    protected Session createAdminSession() throws RepositoryException {
-        return getRepository().login(new SimpleCredentials("admin", "admin".toCharArray()));
-    }
-
-    protected String createConfigValue(String ... configFiles){
-        return configFiles.collect {getResource(it).absolutePath}.join(',')
-    }
-
-    private static String getBaseDir() {
-        // 'basedir' is set by Maven Surefire. It always points to the current subproject,
-        // even in reactor builds.
-        String baseDir = System.getProperty("basedir");
-        if(baseDir) {
-            return baseDir
-        }
-        return new File(".").getAbsolutePath();
-    }
-
-    static retry(int timeoutSeconds, int intervalBetweenTriesMsec, Closure c) {
-        retry(timeoutSeconds, intervalBetweenTriesMsec, null, c)
-    }
-
-    static retry(int timeoutSeconds, int intervalBetweenTriesMsec, String message, Closure c) {
-        long timeout = System.currentTimeMillis() + timeoutSeconds * 1000L;
-        while (System.currentTimeMillis() < timeout) {
-            try {
-                if (c.call()) {
-                    return;
-                }
-            } catch (AssertionError ignore) {
-            } catch (Exception ignore) {
-            }
-
-            try {
-                Thread.sleep(intervalBetweenTriesMsec);
-            } catch (InterruptedException ignore) {
-            }
-        }
-
-        fail("RetryLoop failed, condition is false after " + timeoutSeconds + " seconds" + (message ?: (":" + message)));
-    }
-
-    /**
-     * Convenience method to be used in conjunction with {@link #awaitServiceEvent}. It creates a filter that matches
-     * the given {@code className} to one of the following properties: {@code objectClass}, {@code service.pid} or
-     * {@code service.factoryPid}.
-     *
-     * @param className The class name to match.
-     * @return The filter expression.
-     */
-    protected static String classNameFilter(String className) {
-        return "(|(objectClass=${className})(service.pid=${className})(service.factoryPid=${className}))"
-    }
-
-    /**
-     * Execute a change in a closure and wait for a ServiceEvent to happen. The method only returns once
-     * an appropriate event is matched. If no event matches within the specified timeout, an AssertionError
-     * is thrown. The error message describes any non-matching events that may have happened for debugging
-     * purposes.
-     *
-     * @param closure The closure that effects a change that should cause the expected ServiceEvent.
-     * @param serviceFilter A filter expression following the syntax of {@link org.osgi.framework.Filter} (default: (objectClass=*))
-     * @param eventTypes An integer bitmap of accepted ServiceEvent types (default: any).
-     * @param timeout A timeout value; the maximum time to wait for the service event. The unit depends on the {@code timeUnit} argument.
-     * @param timeUnit The unit for the timeout value.
-     */
-    protected void awaitServiceEvent(
-            Closure closure,
-            String serviceFilter = "(objectClass=*)",
-            int eventTypes = ServiceEvent.MODIFIED | ServiceEvent.REGISTERED | ServiceEvent.UNREGISTERING | ServiceEvent.MODIFIED_ENDMATCH,
-            long timeout = 1000,
-            TimeUnit timeUnit = TimeUnit.MILLISECONDS) {
-        def filter = registry.bundleContext.createFilter(serviceFilter)
-        def latch = new CountDownLatch(1)
-        def events = []
-        def listener = new ServiceListener() {
-            @Override
-            void serviceChanged(final ServiceEvent event) {
-                events.add([eventType: event.type, serviceProperties: asMap(event.serviceReference)])
-                if ((eventTypes & event.type) > 0 && filter.match(event.serviceReference)) {
-                    latch.countDown()
-                }
-            }
-
-            private static asMap(final ServiceReference<?> serviceReference) {
-                def map = new HashMap<String, Object>()
-                serviceReference.getPropertyKeys().each { key ->
-                    map.put(key, serviceReference.getProperty(key))
-                }
-                return map
-            }
-        }
-
-        try {
-            registry.addServiceListener(listener)
-
-            closure.run()
-
-            if (!latch.await(timeout, timeUnit)) {
-                throw new AssertionError("Exceeded timeout waiting for service event matching " +
-                        "[eventTypes: ${eventTypes}, filter: ${serviceFilter}], " +
-                        "got ${events.size()} non matching events: [${events}]")
-            }
-        } finally {
-            registry.removeServiceListener(listener)
-        }
-    }
-
-    protected void disableComponent(String name) {
-        ServiceComponentRuntime scr = getServiceWithWait(ServiceComponentRuntime.class)
-        ComponentDescriptionDTO dto = getComponentDTO(scr, name)
-        Promise p = scr.disableComponent(dto)
-        p.getValue() //Block on get
-    }
-
-    protected void enableComponent(String name) {
-        ServiceComponentRuntime scr = getServiceWithWait(ServiceComponentRuntime.class)
-        ComponentDescriptionDTO dto = getComponentDTO(scr, name)
-        Promise p = scr.enableComponent(dto)
-        p.getValue() //Block on get
-    }
-
-    ComponentDescriptionDTO getComponentDTO(ServiceComponentRuntime scr, String name) {
-        ComponentDescriptionDTO dto = scr.getComponentDescriptionDTOs().find {ComponentDescriptionDTO d -> (d.name == name) }
-        assert dto : "No component found with name $name"
-        return dto
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/ConfigTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/ConfigTest.groovy
deleted file mode 100644
index 0cb27e3cde..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/ConfigTest.groovy
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.BundleDescriptor
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import groovy.json.JsonOutput
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
-import org.osgi.framework.Constants
-import org.osgi.service.cm.Configuration
-import org.osgi.service.cm.ConfigurationAdmin
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.*
-
-class ConfigTest {
-    TestRepositoryFactory factory = new TestRepositoryFactory()
-    Map config
-    File workDir
-    PojoServiceRegistry registry
-    ConfigurationAdmin cm
-
-    @Rule
-    public final TemporaryFolder tmpFolder = new TemporaryFolder(new File("target"))
-
-    @Before
-    void setUp(){
-        workDir = tmpFolder.getRoot();
-        config  = [
-                (REPOSITORY_HOME) : workDir.absolutePath,
-                'magic.spell' : 'Alohomora'
-        ]
-    }
-
-    @After
-    void shutDown(){
-        OakOSGiRepositoryFactory.shutdown(registry, 5)
-    }
-
-    @Test
-    void testRuntimeConfig(){
-        config[REPOSITORY_CONFIG] = createConfigMap()
-
-        initRegistry(config)
-
-        assertConfig()
-    }
-
-    @Test
-    void testFileConfig(){
-        def jf1 = new File(workDir, "config1.json")
-        def jf2 = new File(workDir, "config2.json")
-        jf1 << JsonOutput.toJson(createConfigMap())
-        jf2 << JsonOutput.toJson([bar : [a:'a3', b:4]])
-        config[REPOSITORY_CONFIG_FILE] = "${jf1.absolutePath},${jf2.absolutePath}" as String
-
-        initRegistry(config)
-
-        assertConfig()
-
-        Configuration c1 = cm.getConfiguration('bar', null)
-        assert c1.properties
-        assert c1.properties.get('a') == 'a3'
-        assert c1.properties.get('b') == 4
-    }
-
-    @Test
-    void testConfigSync(){
-        config[REPOSITORY_CONFIG] = [
-                foo : [a:'a', b:1],
-                bar : [a:'a1', b:2],
-                foo2 : [a:'a2', b:2]
-        ]
-        initRegistry(config)
-        Configuration c = cm.getConfiguration('baz')
-        c.update(new Hashtable([a :'a2']))
-
-        assert cm.getConfiguration('baz').properties.get('a') == 'a2'
-        assert cm.getConfiguration('foo').properties.get('a') == 'a'
-        assert cm.getConfiguration('bar').properties.get('a') == 'a1'
-        assert cm.getConfiguration('foo2').properties.get('a') == 'a2'
-
-        shutDown()
-
-        //Now re init and remove the pid bar
-        config[REPOSITORY_CONFIG] = [
-                foo : [a:'a-new', b:1],
-                foo2 : [a:'a2', b:2]
-        ]
-        initRegistry(config)
-
-        assert cm.getConfiguration('baz').properties.get('a') == 'a2'
-        assert cm.getConfiguration('foo').properties.get('a') == 'a-new'
-        assert cm.getConfiguration('bar').properties == null
-        assert cm.getConfiguration('foo2').properties.get('a') == 'a2'
-    }
-
-    private static Map createConfigMap() {
-        [
-                'foo'            : [a: 'a', b: 1, c:'${magic.spell}'],
-                'foo.bar-default': [a: 'a1', b: 2],
-                'foo.bar-simple' : [a: 'a2', b: 3],
-        ]
-    }
-
-    private void assertConfig() {
-        Configuration c1 = cm.getConfiguration('foo', null)
-        assert c1.properties
-        assert c1.properties.get('a') == 'a'
-        assert c1.properties.get('b') == 1
-        assert c1.properties.get('c') == 'Alohomora'
-
-        Configuration[] fcs = cm.listConfigurations('(service.factoryPid=foo.bar)')
-        assert fcs.size() == 2
-    }
-
-    private void initRegistry(Map config){
-        registry = factory.initializeServiceRegistry(config)
-        cm = registry.getService(registry.getServiceReference(ConfigurationAdmin.class.name)) as ConfigurationAdmin
-    }
-
-    private static class TestRepositoryFactory extends OakOSGiRepositoryFactory {
-        @Override
-        protected List<BundleDescriptor> processDescriptors(List<BundleDescriptor> descriptors) {
-            //skip the oak bundles to prevent repository initialization
-            return super.processDescriptors(descriptors).findAll {BundleDescriptor bd ->
-                !bd.headers[Constants.BUNDLE_SYMBOLICNAME]?.startsWith('org.apache.jackrabbit')
-            }
-        }
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy
deleted file mode 100644
index 78b6a4f4bd..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.jackrabbit.oak.api.Blob
-import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean
-import org.apache.jackrabbit.oak.plugins.blob.CachingBlobStore
-import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore
-import org.apache.jackrabbit.oak.plugins.document.DocumentStoreStatsMBean
-import org.apache.jackrabbit.oak.plugins.document.MongoUtils
-import org.apache.jackrabbit.oak.plugins.document.mongo.MongoBlobStore
-import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection
-import org.apache.jackrabbit.oak.spi.blob.AbstractBlobStore
-import org.apache.jackrabbit.oak.spi.blob.BlobStore
-import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore
-import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore
-import org.apache.jackrabbit.oak.spi.blob.stats.BlobStoreStatsMBean
-import org.apache.jackrabbit.oak.spi.commit.CommitInfo
-import org.apache.jackrabbit.oak.spi.commit.EmptyHook
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder
-import org.apache.jackrabbit.oak.spi.state.NodeStore
-import org.h2.jdbcx.JdbcDataSource
-import org.junit.After
-import org.junit.Test
-import org.osgi.framework.ServiceEvent
-import org.osgi.framework.ServiceReference
-import org.osgi.framework.ServiceRegistration
-
-import javax.sql.DataSource
-import java.sql.Connection
-import java.sql.ResultSet
-import java.util.concurrent.TimeUnit
-
-import static org.junit.Assume.assumeTrue
-
-class DocumentNodeStoreConfigTest extends AbstractRepositoryFactoryTest {
-    private PojoServiceRegistry registry
-    private MongoConnection mongoConn = MongoUtils.getConnection()
-
-    @Test
-    public void testRDBDocumentStore() throws Exception {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-        //1. Register the DataSource as a service
-        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1")
-        registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
-
-        //2. Create config for DocumentNodeStore with RDB enabled
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        documentStoreType: 'RDB'
-                ]
-        ])
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-        // OAK-9668: H2 2.0.206 has a limit of 1MB for BINARY VARYING
-        AbstractBlobStore blobStore = getServiceWithWait(BlobStore.class)
-        blobStore.setBlockSize(1024 * 1024)
-
-        //3. Check that DS contains tables from both RDBBlobStore and RDBDocumentStore
-        assert getExistingTables(ds).containsAll(['NODES', 'DATASTORE_META'])
-
-        //4. Check that only one cluster node was instantiated
-        assert getIdsOfClusterNodes(ds).size() == 1
-        testBlobStoreStats(ns)
-        testDocumentStoreStats(ns)
-    }
-
-    @Test
-    public void testRDBDocumentStore2Datasources() throws Exception {
-        // see https://issues.apache.org/jira/browse/OAK-5098
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-        //1. Register the DataSource as a service
-        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1")
-        ServiceRegistration fds = registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
-
-        //2. Register another DataSource as a service with the same name
-        DataSource ds2 = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1")
-        registry.registerService(DataSource.class.name, ds2, ['datasource.name': 'oak'] as Hashtable)
-
-        //3. Create config for DocumentNodeStore with RDB enabled
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        documentStoreType: 'RDB'
-                ]
-        ])
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-
-        //4. unregister first DS
-        fds.unregister()
-
-        //5. check that nodestore is gone
-        TimeUnit.MILLISECONDS.sleep(500)
-        assertNoService(NodeStore.class)
-    }
-
-    @Test
-    public void testRDBDocumentStoreRestart() throws Exception {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-        //1. Register the DataSource as a service
-        DataSource ds = createDS("jdbc:h2:mem:testRDBrestart;DB_CLOSE_DELAY=-1")
-        ServiceRegistration srds = registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
-
-        //2. Create config for DocumentNodeStore with RDB enabled
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        documentStoreType: 'RDB'
-                ]
-        ])
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-
-        //3. Shut down ds
-        // Wait for service to be unregistered after at most 5s.
-        // Previously, we waited only 500ms; this was extended due to
-        // occasional test failures on Jenkins (see OAK-5612). If 5s
-        // are not sufficient, we should investigate some more.
-        awaitServiceEvent({
-                    srds.unregister();
-                },
-                classNameFilter(NodeStore.class.name),
-                ServiceEvent.UNREGISTERING,
-                5, TimeUnit.SECONDS
-        )
-        assert registry.getServiceReference(NodeStore.class.name) == null
-
-        //4. Restart ds, service should still be down
-        srds = registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
-        assertNoService(NodeStore.class)
-    }
-
-    @Test
-    public void testRDBDocumentStoreLateDataSource() throws Exception {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-        //1. Create config for DocumentNodeStore with RDB enabled
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        documentStoreType: 'RDB'
-                ]
-        ])
-
-        //2. Register the DataSource as a service
-        DataSource ds = createDS("jdbc:h2:mem:testRDBlateds;DB_CLOSE_DELAY=-1")
-        registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-
-        //3. Check that DS contains tables from both RDBBlobStore and RDBDocumentStore
-        assert getExistingTables(ds).containsAll(['NODES', 'DATASTORE_META'])
-
-        //4. Check that only one cluster node was instantiated
-        assert getIdsOfClusterNodes(ds).size() == 1
-    }
-
-    @Test
-    public void testRDBDocumentStore_CustomBlobDataSource() throws Exception {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-        //1. Register the DataSource as a service
-        DataSource ds1 = createDS("jdbc:h2:mem:testRDB1;DB_CLOSE_DELAY=-1")
-        registry.registerService(DataSource.class.name, ds1, ['datasource.name': 'oak'] as Hashtable)
-
-        //2. Create config for DocumentNodeStore with RDB enabled
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        documentStoreType      : 'RDB',
-                        'blobDataSource.target': '(datasource.name=oak-blob)',
-                ]
-        ])
-
-        DataSource ds2 = createDS("jdbc:h2:mem:testRDB2;DB_CLOSE_DELAY=-1")
-        registry.registerService(DataSource.class.name, ds2, ['datasource.name': 'oak-blob'] as Hashtable)
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-
-        //3. Check that DS contains tables from RDBBlobStore and RDBDocumentStore
-        //in there respective DataStores
-        List<String> ds1Tables = getExistingTables(ds1)
-        List<String> ds2Tables = getExistingTables(ds2)
-
-        //DS1 should contain RDBDocumentStore tables
-        assert ds1Tables.contains('NODES')
-        assert !ds1Tables.contains('DATASTORE_META')
-
-        //DS2 should contain only RDBBlobStore tables
-        assert !ds2Tables.contains('NODES')
-        assert ds2Tables.contains('DATASTORE_META')
-
-        //4. Check that only one cluster node was instantiated
-        assert getIdsOfClusterNodes(ds1).size() == 1
-    }
-
-    @Test
-    public void testRDBDocumentStore_CustomBlobStore() throws Exception {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-        //1. Register the DataSource as a service
-        DataSource ds1 = createDS("jdbc:h2:mem:testRDB3;DB_CLOSE_DELAY=-1")
-        ServiceRegistration sdsds = registry.registerService(DataSource.class.name, ds1, ['datasource.name': 'oak'] as Hashtable)
-
-        DataSource ds2 = createDS("jdbc:h2:mem:testRDB3b;DB_CLOSE_DELAY=-1")
-        ServiceRegistration sdsbs = registry.registerService(DataSource.class.name, ds2, ['datasource.name': 'oak-blob'] as Hashtable)
-
-        //2. Create config for DocumentNodeStore with RDB enabled
-        // (supply blobDataSource which should be ignored because customBlob takes precedence)
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        documentStoreType: 'RDB',
-                        'blobDataSource.target': '(datasource.name=oak-blob)',
-                        customBlobStore  : true,
-                ]
-        ])
-
-        registry.registerService(BlobStore.class.name, new MemoryBlobStore(), null)
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-
-        //3. Check that DS1 contains tables only from both RDBDocumentStore
-        List<String> ds1Tables = getExistingTables(ds1)
-
-        //DS1 should contain RDBDocumentStore tables only
-        assert ds1Tables.contains('NODES')
-        assert !ds1Tables.contains('DATASTORE_META')
-
-        //4. Check that DS2 is empty
-        List<String> ds2Tables = getExistingTables(ds2)
-        assert !ds2Tables.contains('NODES')
-        assert !ds2Tables.contains('DATASTORE_META')
-
-        //5. Check that only one cluster node was instantiated
-        assert getIdsOfClusterNodes(ds1).size() == 1
-
-        //6. Unregister the data sources to test resilience wrt
-        //multiple deregistrations (OAK-3383)
-        sdsds.unregister();
-        sdsbs.unregister();
-    }
-
-    @Test
-    public void testMongoDocumentStore_CustomBlobStore() throws Exception {
-        mongoCheck()
-
-        registry = repositoryFactory.initializeServiceRegistry(config)
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        mongouri       : MongoUtils.URL,
-                        db             : MongoUtils.DB,
-                        customBlobStore: true
-                ]
-        ])
-
-        registry.registerService(BlobStore.class.name, new MemoryBlobStore(), null)
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-
-        Collection<String> colNames = getCollectionNames()
-        assert colNames.containsAll(['NODES'])
-        assert !colNames.contains(['BLOBS'])
-        assert registry.getServiceReference(BlobStoreStatsMBean.class.name) == null : "BlobStoreStatsMBean should " +
-                "*NOT* be registered by DocumentNodeStoreService in case custom blobStore used"
-    }
-
-    @Test
-    public void testMongoDocumentStore() throws Exception {
-        mongoCheck()
-
-        registry = repositoryFactory.initializeServiceRegistry(config)
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        mongouri: MongoUtils.URL,
-                        db      : MongoUtils.DB,
-                        blobCacheSize      : 1,
-                ]
-        ])
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-
-        Collection<String> colNames = getCollectionNames()
-        assert colNames.containsAll(['NODES', "BLOBS"])
-
-        assert 1*1024*1024 == ((MongoBlobStore)ns.blobStore).blobCacheSize
-        assert getService(BlobStoreStatsMBean.class) : "BlobStoreStatsMBean should " +
-                "be registered by DocumentNodeStoreService in default blobStore used"
-
-        assert getService(BlobStore.class) : "BlobStore service should be exposed for default setup"
-        testBlobStoreStats(ns)
-        testDocumentStoreStats(ns)
-    }
-
-    @Test
-    public void testBundlingEnabledByDefault() throws Exception {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-        //1. Register the DataSource as a service
-        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1")
-        registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
-
-        //2. Create config for DocumentNodeStore with RDB enabled
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        documentStoreType: 'RDB'
-                ]
-        ])
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-        assert ns.bundlingConfigHandler.enabled
-    }
-
-    @Test
-    public void testBundlingDisabled() throws Exception {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-        //1. Register the DataSource as a service
-        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1")
-        registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
-
-        //2. Create config for DocumentNodeStore with RDB enabled
-        createConfig([
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        documentStoreType: 'RDB',
-                        bundlingDisabled : true
-                ]
-        ])
-
-        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
-        assert !ns.bundlingConfigHandler.enabled
-    }
-
-    private void testDocumentStoreStats(DocumentNodeStore store) {
-        DocumentStoreStatsMBean stats = getService(DocumentStoreStatsMBean.class)
-
-        long createdNodeCount = stats.nodesCreateCount
-        NodeBuilder builder = store.getRoot().builder()
-        builder.child("testDocumentStoreStats").child("a")
-        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        assert stats.nodesCreateCount - createdNodeCount >= 2
-
-    }
-
-    private void testBlobStoreStats(DocumentNodeStore nodeStore) throws Exception{
-        int size = 1024 * 1024 * 5
-        Blob blob = nodeStore.createBlob(testStream(size));
-        BlobStoreStatsMBean stats = getService(BlobStoreStatsMBean.class)
-        assert stats.getUploadTotalSize() == size
-        assert stats.uploadCount > 0
-
-        BlobStore bs = nodeStore.blobStore;
-        assert bs instanceof GarbageCollectableBlobStore
-        bs.clearCache()
-
-        assert size == blob.newStream.getBytes().length
-
-        assert stats.downloadCount > 0
-        assert stats.downloadTotalSize > 0
-
-        assertCacheStatsMBean(CachingBlobStore.MEM_CACHE_NAME)
-
-    }
-
-    @Override
-    protected PojoServiceRegistry getRegistry() {
-        return registry
-    }
-
-    @After
-    public void tearDown() {
-        super.tearDown()
-        if (mongoConn) {
-            MongoUtils.dropCollections(mongoConn.database)
-        }
-    }
-
-    private mongoCheck() {
-        //Somehow in Groovy assumeNotNull cause issue as Groovy probably
-        //does away with null array causing a NPE
-        assumeTrue(MongoUtils.isAvailable())
-    }
-
-    private Collection<String> getCollectionNames() {
-        return mongoConn.database.listCollectionNames().collect { it.toUpperCase() }
-    }
-
-    private List<String> getExistingTables(DataSource ds) {
-        Connection con = ds.connection
-        List<String> existing = []
-        try {
-            ResultSet rs = con.metaData.getTables(null, null, "%", null)
-            while (rs.next()) {
-                existing << rs.toRowResult()['TABLE_NAME'].toUpperCase()
-            }
-        } finally {
-            con.close()
-        }
-        return existing
-    }
-
-    private List<String> getIdsOfClusterNodes(DataSource ds) {
-        Connection con = ds.connection
-        List<String> entries = []
-        try {
-            ResultSet rs = con.prepareStatement("SELECT ID FROM CLUSTERNODES").executeQuery()
-            while (rs.next()) {
-                entries << rs.get(1)
-            }
-        } finally {
-            con.close()
-        }
-        return entries
-    }
-    
-    private DataSource createDS(String url) {
-        DataSource ds = new JdbcDataSource()
-        ds.url = url
-        return ds
-    }
-
-    private InputStream testStream(int size) {
-        //Cannot use NullInputStream as it throws exception upon EOF
-        byte[] data = new byte[size];
-        new Random().nextBytes(data);
-        return new ByteArrayInputStream(data);
-    }
-
-    private void assertCacheStatsMBean(String name){
-        ServiceReference[] refs = registry.getServiceReferences(CacheStatsMBean.class.name,null);
-        def names = []
-        def cacheStatsRef = refs.find { ServiceReference ref ->
-            CacheStatsMBean mbean = registry.getService(ref);
-            names << mbean.name
-            return mbean.name == name
-        }
-
-        assert  cacheStatsRef : "No CacheStat found for [$name]. Registered cache stats $names"
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.groovy
deleted file mode 100644
index a87c837efd..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.groovy
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.jaas.LoginModuleFactory
-import org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule
-import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration
-import org.jetbrains.annotations.NotNull
-import org.junit.Before
-import org.junit.Test
-
-import javax.jcr.Credentials
-import javax.jcr.Session
-import javax.jcr.SimpleCredentials
-import javax.security.auth.login.LoginException
-import javax.security.auth.spi.LoginModule
-import java.security.Principal
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG
-
-
-class JaasConfigSpiTest extends AbstractRepositoryFactoryTest{
-    @Before
-    void setupRepo(){
-        config[REPOSITORY_CONFIG] = [
-                'org.apache.felix.jaas.Configuration.factory-LoginModuleImpl' : [
-                        'jaas.controlFlag' : 'required',
-                        'jaas.classname' : 'org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl'
-                ],
-                'org.apache.felix.jaas.ConfigurationSpi' : [
-                        //jaas.globalConfigPolicy defaults to 'default'
-                        'jaas.defaultRealmName' : 'jackrabbit.oak',
-                        'jaas.configProviderName' : 'FelixJaasProvider',
-                ],
-                'org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl' :[
-                        (AuthenticationConfiguration.PARAM_CONFIG_SPI_NAME) : 'FelixJaasProvider'
-                ],
-                'org.apache.jackrabbit.oak.jcr.osgi.RepositoryManager' : [:],
-                'org.apache.jackrabbit.oak.segment.SegmentNodeStoreService' : [:]
-        ]
-    }
-
-    @Test
-    public void defaultConfigSpiAuth() throws Exception{
-        repository = repositoryFactory.getRepository(config)
-        registry.registerService(LoginModuleFactory.class.name, new LoginModuleFactory() {
-            @Override
-            LoginModule createLoginModule() {
-                return new TestLoginModule();
-            }
-        }, [
-                'jaas.controlFlag' : 'sufficient',
-                'jaas.realmName' : 'jackrabbit.oak',
-                'jaas.ranking' : '150',
-
-        ] as Hashtable)
-
-
-
-        Session session = repository.login(new SimpleCredentials("batman", "password".toCharArray()))
-        assert session
-        session.logout()
-    }
-
-    public static class TestLoginModule extends AbstractLoginModule {
-        private Credentials credentials;
-        private Set<? extends Principal> principals;
-        private String userId;
-
-        @NotNull
-        @Override
-        protected Set<Class> getSupportedCredentials() {
-            return Set.of(SimpleCredentials.class)
-        }
-
-        @Override
-        boolean login() throws LoginException {
-            credentials = getCredentials();
-            if(credentials instanceof SimpleCredentials){
-                SimpleCredentials scred = (SimpleCredentials)credentials;
-                if(scred.getPassword() == "password".toCharArray()
-                    && scred.getUserID() == 'batman'){
-                    userId = 'admin';
-                    principals = getPrincipals(userId);
-                    sharedState.put(SHARED_KEY_CREDENTIALS, credentials);
-                    sharedState.put(SHARED_KEY_LOGIN_NAME, userId);
-                    return true;
-                }
-            }
-            return false
-        }
-
-        @Override
-        public boolean commit() {
-            if (credentials == null || principals == null) {
-                // login attempt in this login module was not successful
-                clearState();
-                return false;
-            } else if (!subject.isReadOnly()) {
-                subject.getPrincipals().addAll(principals);
-                subject.getPublicCredentials().add(credentials);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        boolean logout() throws LoginException {
-            return super.logout(Set.of(credentials), principals);
-        }
-    }
-}
\ No newline at end of file
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JsonConfigRepFactoryTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JsonConfigRepFactoryTest.groovy
deleted file mode 100644
index 3db51f9600..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/JsonConfigRepFactoryTest.groovy
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.jackrabbit.commons.JcrUtils
-import org.apache.jackrabbit.oak.spi.state.NodeStore
-import org.junit.Before
-import org.junit.Test
-
-import javax.jcr.RepositoryException
-import javax.jcr.Session
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE
-
-class JsonConfigRepFactoryTest extends AbstractRepositoryFactoryTest{
-
-    @Before
-    void setupRepo(){
-        config[REPOSITORY_CONFIG_FILE] = getResource("oak-base-config.json").absolutePath
-    }
-
-    @Test
-    public void testRepositoryTar() throws Exception {
-        config[REPOSITORY_CONFIG] = [
-                'org.apache.jackrabbit.oak.segment.SegmentNodeStoreService' : [:]
-        ]
-
-        repository = repositoryFactory.getRepository(config);
-        assert repository
-        assert getService(NodeStore.class)
-        basicCrudTest()
-    }
-
-    def basicCrudTest() throws RepositoryException {
-        Session session = createAdminSession();
-        javax.jcr.Node rootNode = session.getRootNode();
-
-        javax.jcr.Node child = JcrUtils.getOrAddNode(rootNode, "child", "oak:Unstructured");
-        child.setProperty("foo3", "bar3");
-        session.save()
-        session.logout();
-
-        session = createAdminSession();
-        assert session.getProperty('/child/foo3').string == 'bar3'
-        session.logout()
-    }
-}
\ No newline at end of file
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/LuceneSupportTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/LuceneSupportTest.groovy
deleted file mode 100644
index 856a26dc32..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/LuceneSupportTest.groovy
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.PojoServiceRegistry
-
-import org.apache.jackrabbit.oak.plugins.index.aggregate.SimpleNodeAggregator
-import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants
-import org.apache.jackrabbit.oak.plugins.index.search.IndexFormatVersion
-import org.apache.jackrabbit.oak.plugins.index.search.util.IndexHelper
-import org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper
-import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer
-import org.apache.jackrabbit.oak.spi.query.QueryIndex
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-
-import javax.jcr.Node
-import javax.jcr.Session
-import javax.jcr.query.*
-
-import static org.apache.jackrabbit.JcrConstants.JCR_CONTENT
-import static org.apache.jackrabbit.JcrConstants.NT_FILE
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE
-
-class LuceneSupportTest extends AbstractRepositoryFactoryTest {
-    Session session
-
-    @Before
-    void setupRepo() {
-        repositoryFactory = new CustomFactory()
-        config[REPOSITORY_CONFIG_FILE] = createConfigValue("oak-base-config.json", "oak-tar-config.json")
-    }
-
-    @After
-    void logout() {
-        session.logout()
-    }
-
-    @Test
-    public void fullTextSearch() throws Exception {
-        repository = repositoryFactory.getRepository(config)
-        session = createAdminSession()
-
-        Node testNode = session.getRootNode()
-        Node contentNode = testNode.addNode("myFile" ,"nt:file")
-                .addNode("jcr:content", "oak:Unstructured");
-        contentNode.setProperty("jcr:mimeType", "text/plain")
-        contentNode.setProperty("jcr:encoding", "UTF-8")
-        contentNode.setProperty("jcr:data",
-                new ByteArrayInputStream("the quick brown fox jumps over the lazy dog.".getBytes('utf-8')))
-        session.save()
-
-        SimpleNodeAggregator agg = new SimpleNodeAggregator().newRuleWithName(
-                NT_FILE, new ArrayList<>(Arrays.asList(JCR_CONTENT, JCR_CONTENT + "/*")));
-        getRegistry ( ).registerService ( QueryIndex.NodeAggregator.class.name, agg, null )
-
-        //The lucene index is set to synched mode
-        retry(30, 200) {
-            String query = "SELECT * FROM [nt:base] as f WHERE CONTAINS (f.*, 'dog')"
-            assert [ "/myFile", '/myFile/jcr:content' ] as HashSet == execute ( query )
-            return true
-        }
-    }
-
-    Set<String> execute(String stmt){
-        QueryManager qm = session.workspace.queryManager
-        Query query = qm.createQuery(stmt, "JCR-SQL2");
-        QueryResult result = query.execute()
-        RowIterator rowItr = result.getRows()
-        Set<String> paths = new HashSet<>()
-        rowItr.each {Row r -> paths << r.node.path}
-        return paths
-    }
-
-    private static class CustomFactory extends OakOSGiRepositoryFactory {
-        @Override
-        protected void preProcessRegistry(PojoServiceRegistry registry) {
-            registry.registerService(RepositoryInitializer.class.name, new RepositoryInitializer() {
-                @Override
-                void initialize(NodeBuilder builder) {
-                    if (builder.hasChildNode(INDEX_DEFINITIONS_NAME)) {
-                        NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
-                        if (!index.hasChildNode("lucene")) {
-                            NodeBuilder nb = LuceneIndexHelper.newLuceneIndexDefinition(
-                                    index, "lucene", IndexHelper.JR_PROPERTY_INCLUDES, null, "async")
-                            nb.setProperty(FulltextIndexConstants.COMPAT_MODE, IndexFormatVersion.V1.getVersion());
-                        }
-                    }
-                }
-            }, null);
-        }
-    }
-
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/MBeanIntegrationTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/MBeanIntegrationTest.groovy
deleted file mode 100644
index 489b689ecb..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/MBeanIntegrationTest.groovy
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.jackrabbit.oak.api.jmx.RepositoryManagementMBean;
-import org.junit.Before
-import org.junit.Test
-
-import javax.management.MBeanServer
-import javax.management.ObjectInstance
-import javax.management.ObjectName
-import javax.management.Query
-import javax.management.QueryExp
-import java.lang.management.ManagementFactory;
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
-
-public class MBeanIntegrationTest extends AbstractRepositoryFactoryTest {
-    @Before
-    void setupRepo() {
-        config[REPOSITORY_CONFIG_FILE] = createConfigValue("oak-base-config.json", "oak-tar-config.json")
-    }
-
-    @Test
-    public void jmxIntegration() throws Exception{
-        repository = repositoryFactory.getRepository(config)
-        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
-        QueryExp q = Query.isInstanceOf(Query.value(RepositoryManagementMBean.class.name))
-        Set<ObjectInstance> mbeans = server.queryMBeans(new ObjectName("org.apache.jackrabbit.oak:*"), q)
-        assert mbeans.size() == 1
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.groovy
deleted file mode 100644
index 2fe84c4baf..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.groovy
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.jackrabbit.oak.segment.SegmentNodeStore
-import org.apache.jackrabbit.oak.spi.blob.BlobStore
-import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore
-import org.apache.jackrabbit.oak.spi.state.NodeStore
-import org.junit.Test
-
-class NodeStoreConfigTest extends  AbstractRepositoryFactoryTest{
-    private PojoServiceRegistry registry
-    @Test
-    void testNodeStoreWithBlobStore_OAK_1676(){
-        registry = repositoryFactory.initializeServiceRegistry(config)
-        registry.registerService(BlobStore.class.name, new MemoryBlobStore(), null)
-
-        createConfig([
-                'org.apache.jackrabbit.oak.segment.SegmentNodeStoreService' : [:]
-        ])
-
-        SegmentNodeStore ns = getServiceWithWait(NodeStore.class)
-        //NodeStore is of type SegmentNodeStoreService
-        assert ns.blobStore == null , "BlobStore should not be picked up unless 'customBlobStore " +
-                "is set to true"
-    }
-
-    @Override
-    protected PojoServiceRegistry getRegistry() {
-        return registry
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/PropertyIndexReindexingTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/PropertyIndexReindexingTest.groovy
deleted file mode 100644
index a61c0f2e6f..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/PropertyIndexReindexingTest.groovy
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.jackrabbit.JcrConstants
-import org.apache.jackrabbit.commons.JcrUtils
-import org.apache.jackrabbit.oak.plugins.index.IndexConstants
-import org.junit.Before
-import org.junit.Test
-
-import javax.jcr.Node
-import javax.jcr.Repository
-import javax.jcr.Session
-import java.util.concurrent.TimeUnit
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE
-
-class PropertyIndexReindexingTest extends AbstractRepositoryFactoryTest{
-
-    @Before
-    void setupRepo() {
-        config[REPOSITORY_CONFIG_FILE] = createConfigValue("oak-base-config.json", "oak-tar-config.json")
-    }
-
-    @Test
-    public void propertyIndexState() throws Exception{
-        repository = repositoryFactory.getRepository(config)
-        PojoServiceRegistry registry = getRegistry()
-
-        //1. Save a node with 'foo' property
-        Session s = createAdminSession()
-        s.getRootNode().addNode("a1").setProperty("foo", "bar")
-        s.save();  s.logout();
-
-        //2. Create a property index for 'foo'
-        s = createAdminSession()
-        Node fooIndex = JcrUtils.getOrCreateByPath("/oak:index/foo", JcrConstants.NT_UNSTRUCTURED,
-                "oak:QueryIndexDefinition", s, false);
-        fooIndex.setProperty(IndexConstants.TYPE_PROPERTY_NAME, "property");
-        fooIndex.setProperty(IndexConstants.PROPERTY_NAMES, ["foo"] as String[]);
-        s.save();s.logout();
-
-        //3. By the last save reindex flag should be false
-        s = createAdminSession()
-        assert !s.getProperty("/oak:index/foo/reindex").boolean
-        s.logout()
-
-        //4. Disable the PropertyIndexEditor
-        def indexComponent = 'org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider'
-        disableComponent(indexComponent)
-        TimeUnit.SECONDS.sleep(1)
-       assert registry.getServiceReference(Repository.class.name) == null : "Repository should be unregistered " +
-               "if no property index editor found"
-
-        //5. Re-enable the editor and wait untill repository gets re-registered
-        enableComponent(indexComponent)
-        getServiceWithWait(Repository.class, registry.bundleContext)
-
-        //6. Reindex flag should be stable
-        s = createAdminSession()
-        assert !s.getProperty("/oak:index/foo/reindex").boolean
-        s.logout()
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/RepositoryClosedTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/RepositoryClosedTest.groovy
deleted file mode 100644
index caf00263db..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/RepositoryClosedTest.groovy
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import groovy.util.logging.Slf4j
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.junit.Assert
-import org.junit.Before
-import org.junit.Test
-
-import javax.jcr.RepositoryException
-import javax.jcr.Session
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE
-
-@Slf4j
-class RepositoryClosedTest extends AbstractRepositoryFactoryTest{
-
-    @Before
-    void setupRepo() {
-        config[REPOSITORY_CONFIG_FILE] = createConfigValue("oak-base-config.json", "oak-tar-config.json")
-    }
-
-    @Test
-    public void sessionUsePostClose() throws Exception{
-        repository = repositoryFactory.getRepository(config)
-        PojoServiceRegistry registry = getRegistry()
-
-        //1. Obtain handle to a session
-        Session s = createAdminSession()
-
-        //2 Trigger repository shutdown
-        disableComponent('org.apache.jackrabbit.oak.jcr.osgi.RepositoryManager')
-        disableComponent('org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider')
-
-        log.info("Repository shutdown complete. Proceeding with save")
-
-        //Null out repository to prevent shutdown attempt in teardown
-        repository = null
-
-        //3. Now try adding a node with invalid name. Such a commit
-        //should have got failed
-        s.getRootNode().addNode("a\nb");
-        try {
-            s.save()
-            Assert.fail("Session save should have failed due to invalid name")
-        } catch (RepositoryException ignore){
-
-        }
-
-
-        OakOSGiRepositoryFactory.shutdown(registry, 5)
-    }
-
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/RepositoryShutdownTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/RepositoryShutdownTest.groovy
deleted file mode 100644
index 47cf846da0..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/RepositoryShutdownTest.groovy
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.jackrabbit.api.JackrabbitRepository
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
-import org.osgi.framework.BundleActivator
-import org.osgi.framework.BundleContext
-
-import javax.jcr.Repository
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_HOME
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_TIMEOUT_IN_SECS
-import static org.mockito.Mockito.mock
-import static org.mockito.Mockito.times
-import static org.mockito.Mockito.verify
-
-
-class RepositoryShutdownTest {
-
-    @Rule
-    public final TemporaryFolder tmpFolder = new TemporaryFolder(new File("target"))
-
-    @Test
-    public void multipleShutdown() throws Exception{
-        JackrabbitRepository repository = mock(JackrabbitRepository.class)
-        def config = getConfig(repository)
-
-        Repository repo2 = new OakOSGiRepositoryFactory().getRepository(config)
-        assert repo2 instanceof JackrabbitRepository
-        repo2.shutdown()
-
-        verify(repository, times(0)).shutdown()
-    }
-
-    @Test
-    public void multipleShutdownAndWait() throws Exception{
-        JackrabbitRepository repository = mock(JackrabbitRepository.class)
-        def config = getConfig(repository)
-
-        Repository repo2 = new OakOSGiRepositoryFactory().getRepository(config)
-        assert repo2 instanceof JackrabbitRepository
-        repo2.shutdown()
-        repo2.shutdown()
-    }
-
-    private LinkedHashMap<String, Object> getConfig(repository) {
-        def config = [
-                (REPOSITORY_HOME)           : tmpFolder.root.absolutePath,
-                (REPOSITORY_TIMEOUT_IN_SECS): 1,
-                (BundleActivator.class.name): new BundleActivator() {
-                    @Override
-                    void start(BundleContext bundleContext) throws Exception {
-                        bundleContext.registerService(Repository.class.name, repository, null)
-                    }
-
-                    @Override
-                    void stop(BundleContext bundleContext) throws Exception {
-
-                    }
-                }
-        ]
-        config
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecondaryStoreConfigIT.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecondaryStoreConfigIT.groovy
deleted file mode 100644
index 7b48217195..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecondaryStoreConfigIT.groovy
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.jackrabbit.commons.JcrUtils
-import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore
-import org.apache.jackrabbit.oak.plugins.document.MongoUtils
-import org.apache.jackrabbit.oak.spi.state.NodeStateUtils
-import org.apache.jackrabbit.oak.spi.state.NodeStore
-import org.apache.jackrabbit.oak.spi.state.NodeStoreProvider
-import org.junit.Test
-
-import javax.jcr.Session
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE
-import static org.junit.Assume.assumeTrue
-
-
-class SecondaryStoreConfigIT extends AbstractRepositoryFactoryTest{
-
-    @Test
-    void secondaryNodeStoreCache() throws Exception{
-        mongoCheck()
-        MongoUtils.dropDatabase(MongoUtils.DB)
-        config[REPOSITORY_CONFIG_FILE] = createConfigValue("oak-base-config.json")
-        config[REPOSITORY_CONFIG] = [
-                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
-                        mongouri       : MongoUtils.URL,
-                        db             : MongoUtils.DB
-                ],
-                'org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory-secondary.config' : [
-                        role       : "secondary"
-                ],
-                'org.apache.jackrabbit.oak.plugins.document.secondary.SecondaryStoreCacheService' : [
-                        includedPaths : ['/']
-                ]
-        ]
-
-        repository = repositoryFactory.getRepository(config);
-
-        Session session = createAdminSession();
-        javax.jcr.Node rootNode = session.getRootNode();
-
-        javax.jcr.Node child = JcrUtils.getOrAddNode(rootNode, "testNode", "oak:Unstructured");
-        child.setProperty("foo", "bar");
-        session.save()
-        session.logout();
-
-        NodeStoreProvider nsp = getServiceWithWait(NodeStoreProvider.class)
-        NodeStore secondary = nsp.nodeStore
-
-        //Assert that recently created node gets pushed to Secondary and
-        //is accessible in sometime
-        retry(30, 10) {
-            return NodeStateUtils.getNode(secondary.root, "/testNode").exists()
-        }
-
-    }
-
-    private mongoCheck() {
-        //Somehow in Groovy assumeNotNull cause issue as Groovy probably
-        //does away with null array causing a NPE
-        assumeTrue(MongoUtils.isAvailable())
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.groovy
deleted file mode 100644
index ab999f21da..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.groovy
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters
-import org.apache.jackrabbit.oak.spi.security.Context
-import org.apache.jackrabbit.oak.spi.security.SecurityProvider
-import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration
-import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration
-import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider
-import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration
-import org.apache.jackrabbit.oak.spi.security.user.AuthorizableNodeName
-import org.apache.jackrabbit.oak.spi.security.user.UserAuthenticationFactory
-import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration
-import org.apache.jackrabbit.oak.spi.security.user.action.AccessControlAction
-import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableAction
-import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableActionProvider
-import org.junit.Before
-import org.junit.Test
-import org.osgi.framework.ServiceEvent
-import org.osgi.framework.ServiceReference
-import org.osgi.service.cm.ConfigurationAdmin
-
-
-import static org.mockito.Mockito.mock
-import static org.mockito.Mockito.when
-import static org.osgi.service.component.runtime.ServiceComponentRuntime.*
-
-class SecurityProviderRegistrationTest extends AbstractRepositoryFactoryTest {
-
-    private PojoServiceRegistry registry;
-
-    @Before
-    public void initializeRegistry() {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-    }
-
-    @Override
-    protected PojoServiceRegistry getRegistry() {
-        return registry
-    }
-    /**
-     * Test that, without any additional configuration, a SecurityProvider
-     * service is registered by default.
-     */
-    @Test
-    public void testDefaultSetup() {
-        assert securityProviderServiceReferences != null
-    }
-
-    /**
-     * A SecurityProvider shouldn't start without a required
-     * AuthorizationConfiguration service.
-     */
-    @Test
-    public void testRequiredAuthorizationConfigurationNotAvailable() {
-        def m = mock(AuthorizationConfiguration)
-        when(m.getParameters()).thenReturn(ConfigurationParameters.EMPTY)
-        when(m.getContext()).thenReturn(Context.DEFAULT)
-
-        testRequiredService(AuthorizationConfiguration, m)
-    }
-
-    /**
-     * A SecurityProvider shouldn't start without a required
-     * PrincipalConfiguration service.
-     */
-    @Test
-    public void testRequiredPrincipalConfigurationNotAvailable() {
-        def m = mock(PrincipalConfiguration)
-        when(m.getParameters()).thenReturn(ConfigurationParameters.EMPTY)
-        when(m.getContext()).thenReturn(Context.DEFAULT)
-
-        testRequiredService(PrincipalConfiguration, m)
-    }
-
-    /**
-     * A SecurityProvider shouldn't start without a required TokenConfiguration
-     * service.
-     */
-    @Test
-    public void testRequiredTokenConfigurationNotAvailable() {
-        def m = mock(TokenConfiguration)
-        when(m.getParameters()).thenReturn(ConfigurationParameters.EMPTY)
-        when(m.getContext()).thenReturn(Context.DEFAULT)
-
-        testRequiredService(TokenConfiguration, m)
-    }
-
-    /**
-     * A SecurityProvider shouldn't start without a required
-     * AuthorizableNodeName service.
-     */
-    @Test
-    public void testRequiredAuthorizableNodeNameNotAvailable() {
-        testRequiredService(AuthorizableNodeName, mock(AuthorizableNodeName))
-    }
-
-    /**
-     * A SecurityProvider shouldn't start without a required
-     * AuthorizableActionProvider service.
-     */
-    @Test
-    public void testRequiredAuthorizableActionProviderNotAvailable() {
-        testRequiredService(AuthorizableActionProvider, mock(AuthorizableActionProvider))
-    }
-
-    /**
-     * A SecurityProvider shouldn't start without a required RestrictionProvider
-     * service.
-     */
-    @Test
-    public void testRequiredRestrictionProviderNotAvailable() {
-        testRequiredService(RestrictionProvider, mock(RestrictionProvider))
-    }
-
-    /**
-     * A SecurityProvider shouldn't start without a required
-     * UserAuthenticationFactory service.
-     */
-    @Test
-    public void testRequiredUserAuthenticationFactoryNotAvailable() {
-        testRequiredService(UserAuthenticationFactory, mock(UserAuthenticationFactory))
-    }
-
-    /**
-     * A SecurityProvider should be registered only if every every prerequisite
-     * is satisfied.
-     */
-    @Test
-    public void testMultipleRequiredServices() {
-
-        // Set up the SecurityProvider to require 4 services
-        awaitServiceEvent({
-                    setRequiredServicePids(
-                            "test.RequiredAuthorizationConfiguration",
-                            "test.RequiredPrincipalConfiguration",
-                            "test.RequiredTokenConfiguration",
-                            "test.RestrictionProvider")
-                },
-                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
-                ServiceEvent.UNREGISTERING
-        )
-        assert securityProviderServiceReferences == null
-
-        // Start the services and verify that only at the end the
-        // SecurityProvider registers itself
-        def ac = mock(AuthorizationConfiguration)
-        when(ac.getParameters()).thenReturn(ConfigurationParameters.EMPTY)
-        when(ac.getContext()).thenReturn(Context.DEFAULT)
-
-        registry.registerService(AuthorizationConfiguration.class.name, ac, dict("service.pid": "test.RequiredAuthorizationConfiguration"))
-        assert securityProviderServiceReferences == null
-
-        def pc = mock(PrincipalConfiguration)
-        when(pc.getParameters()).thenReturn(ConfigurationParameters.EMPTY)
-        when(pc.getContext()).thenReturn(Context.DEFAULT)
-
-        registry.registerService(PrincipalConfiguration.class.name, pc, dict("service.pid": "test.RequiredPrincipalConfiguration"))
-        assert securityProviderServiceReferences == null
-
-        def tc = mock(TokenConfiguration)
-        when(tc.getParameters()).thenReturn(ConfigurationParameters.EMPTY)
-        when(tc.getContext()).thenReturn(Context.DEFAULT)
-
-        registry.registerService(TokenConfiguration.class.name, tc, dict("service.pid": "test.RequiredTokenConfiguration"))
-        assert securityProviderServiceReferences == null
-
-        registry.registerService(RestrictionProvider.class.name, mock(RestrictionProvider), dict("service.pid": "test.RestrictionProvider"))
-        assert securityProviderServiceReferences != null
-    }
-
-    @Test
-    public void testSecurityConfigurations() {
-        SecurityProvider securityProvider = registry.getService(registry.getServiceReference(SecurityProvider.class.name))
-        assertAuthorizationConfig(securityProvider)
-        assertUserConfig(securityProvider)
-
-        //Keep a dummy reference to UserConfiguration such that SCR does not deactivate it
-        //once SecurityProviderRegistration gets deactivated. Otherwise if SecurityProviderRegistration is
-        //the only component that refers it then upon its deactivation UserConfiguration would also be
-        //deactivate and its internal state would be reset
-        UserConfiguration userConfiguration = getServiceWithWait(UserConfiguration.class)
-
-        def authComponentName = 'org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl'
-
-        // 1. Disable AuthenticationConfiguration such that SecurityProvider is unregistered
-        awaitServiceEvent({
-                    disableComponent(authComponentName)
-                },
-                '(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)',
-                ServiceEvent.UNREGISTERING,
-                5000
-        )
-
-        assert securityProviderServiceReferences == null
-
-        // 2. Modify the config for AuthorizableActionProvider. It's expected that this config change is picked up
-        awaitServiceEvent({
-                    setConfiguration([
-                            "org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider": [
-                                    "groupPrivilegeNames":"jcr:read"
-                            ]
-                    ])
-                },
-                classNameFilter('org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider'),
-                ServiceEvent.MODIFIED | ServiceEvent.REGISTERED
-        )
-
-        // 3. Enable component again such that SecurityProvider gets reactivated
-        awaitServiceEvent({
-                   enableComponent(authComponentName)
-                },
-                '(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)',
-                ServiceEvent.REGISTERED
-        )
-
-        securityProvider = getServiceWithWait(SecurityProvider.class)
-        assertAuthorizationConfig(securityProvider)
-        assertUserConfig(securityProvider, "jcr:read")
-    }
-
-    @Test
-    public void testSecurityConfigurations2() {
-        SecurityProvider securityProvider = registry.getService(registry.getServiceReference(SecurityProvider.class.name))
-        assertAuthorizationConfig(securityProvider)
-        assertUserConfig(securityProvider)
-
-        //Keep a dummy reference to UserConfiguration such that SCR does not deactivate it
-        //once SecurityProviderRegistration gets deactivated. Otherwise if SecurityProviderRegistration is
-        //the only component that refers it then upon its deactivation UserConfiguration would also be
-        //deactivate and its internal state would be reset
-        UserConfiguration userConfiguration = getServiceWithWait(UserConfiguration.class)
-
-        //1. Modify the config for AuthorizableActionProvider. It's expected that this config change is picked up
-        def servicePid = "org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider"
-        awaitServiceEvent({
-            setConfiguration([
-                        (servicePid): [
-                                "groupPrivilegeNames":"jcr:read"
-                        ]
-                ]
-            )},
-            "(service.pid=${servicePid})",
-            ServiceEvent.MODIFIED | ServiceEvent.REGISTERED
-        )
-
-        securityProvider = getServiceWithWait(SecurityProvider.class)
-        assertAuthorizationConfig(securityProvider)
-        assertUserConfig(securityProvider, "jcr:read")
-
-        String authComponentName = 'org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl'
-
-        // 2. Disable AuthenticationConfiguration such that SecurityProvider is unregistered
-        awaitServiceEvent({
-                    disableComponent(authComponentName)
-                },
-                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
-                ServiceEvent.UNREGISTERING
-        )
-
-        assert securityProviderServiceReferences == null
-
-        // 3. Enable component again such that SecurityProvider gets reactivated
-        awaitServiceEvent({
-                    enableComponent(authComponentName)
-                },
-                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
-                ServiceEvent.REGISTERED
-        )
-
-        securityProvider = getServiceWithWait(SecurityProvider.class)
-        assertAuthorizationConfig(securityProvider)
-        assertUserConfig(securityProvider, "jcr:read")
-    }
-
-    private <T> void testRequiredService(Class<T> serviceClass, T service) {
-
-        // Adding a new precondition on a missing service PID forces the
-        // SecurityProvider to unregister.
-
-        awaitServiceEvent({
-                    setRequiredServicePids("test.Required" + serviceClass.simpleName)
-                },
-                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
-                ServiceEvent.UNREGISTERING
-        )
-        assert securityProviderServiceReferences == null
-
-        // If a service is registered, and if the PID of the service matches the
-        // precondition, the SecurityProvider is registered again.
-
-        def registration;
-        awaitServiceEvent({
-                    registration = registry.registerService(serviceClass.name, service, dict("service.pid": "test.Required" + serviceClass.simpleName))
-                },
-                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
-                ServiceEvent.REGISTERED
-        )
-        assert securityProviderServiceReferences != null
-
-        // If the service is unregistered, but the precondition is still in
-        // place, the SecurityProvider unregisters again.
-
-        awaitServiceEvent({
-                    registration.unregister()
-                },
-                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
-                ServiceEvent.UNREGISTERING
-        )
-        assert securityProviderServiceReferences == null
-
-        // Removing the precondition allows the SecurityProvider to register.
-        awaitServiceEvent({
-                    setRequiredServicePids()
-                },
-                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
-                ServiceEvent.REGISTERED
-        )
-        assert securityProviderServiceReferences != null
-    }
-
-    private ServiceReference<?>[] getSecurityProviderServiceReferences() {
-        return registry.getServiceReferences(SecurityProvider.class.name, "(type=default)")
-    }
-
-    private void setRequiredServicePids(String... pids) {
-        setConfiguration([
-                "org.apache.jackrabbit.oak.security.internal.SecurityProviderRegistration": [
-                        "requiredServicePids": pids
-                ]
-        ])
-    }
-
-    private void setConfiguration(Map<String, Map<String, Object>> configuration) {
-        getConfigurationInstaller().installConfigs(configuration)
-    }
-
-    private ConfigInstaller getConfigurationInstaller() {
-        return new ConfigInstaller(getConfigurationAdmin(), registry.bundleContext)
-    }
-
-    private ConfigurationAdmin getConfigurationAdmin() {
-        return registry.getService(registry.getServiceReference(ConfigurationAdmin.class.name)) as ConfigurationAdmin
-    }
-
-    private static <K, V> Dictionary<K, V> dict(Map<K, V> map) {
-        return new Hashtable<K, V>(map);
-    }
-
-    private static void assertAuthorizationConfig(SecurityProvider securityProvider, String... adminPrincipals) {
-        AuthorizationConfiguration ac = securityProvider.getConfiguration(AuthorizationConfiguration.class)
-
-        assert ac.getParameters().containsKey("restrictionProvider")
-        assert ac.getRestrictionProvider() != null
-        assert ac.getParameters().get("restrictionProvider") == ac.getRestrictionProvider()
-
-        String[] found = ac.getParameters().getConfigValue("administrativePrincipals", new String[0])
-        assert Arrays.equals(adminPrincipals, found)
-    }
-
-    private static void assertUserConfig(SecurityProvider securityProvider, String... groupPrivilegeNames) {
-        UserConfiguration uc = securityProvider.getConfiguration(UserConfiguration.class)
-
-        assert uc.getParameters().containsKey("authorizableActionProvider")
-        AuthorizableActionProvider ap = uc.getParameters().get("authorizableActionProvider")
-        assert ap != null;
-
-        List<AuthorizableAction> actionList = ap.getAuthorizableActions(securityProvider)
-        assert actionList.size() == 1
-        AuthorizableAction action = actionList.get(0)
-        assert Arrays.equals(groupPrivilegeNames, ((AccessControlAction) action).groupPrivilegeNames)
-    }
-
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SegmentNodeStoreConfigTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SegmentNodeStoreConfigTest.groovy
deleted file mode 100644
index 5ed0f294eb..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/SegmentNodeStoreConfigTest.groovy
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.jackrabbit.guava.common.collect.Maps
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.jackrabbit.oak.spi.state.NodeState
-import org.apache.jackrabbit.oak.spi.state.NodeStore
-import org.junit.Test
-import org.osgi.framework.BundleContext
-import org.osgi.framework.ServiceReference
-import org.osgi.util.tracker.ServiceTracker
-
-import java.lang.management.ManagementFactory
-import java.util.concurrent.CountDownLatch
-
-import static org.junit.Assert.assertNull
-
-class SegmentNodeStoreConfigTest extends AbstractRepositoryFactoryTest {
-
-    private PojoServiceRegistry registry
-
-    @Test
-    public void testDeadlock() throws Exception {
-        registry = repositoryFactory.initializeServiceRegistry(config)
-
-
-        CountDownLatch deactivateLatch = new CountDownLatch(1)
-        CountDownLatch trackerLatch = new CountDownLatch(1)
-        CountDownLatch mainLatch = new CountDownLatch(1)
-        NodeStoreTracker tracker = new NodeStoreTracker(registry.getBundleContext(), trackerLatch, deactivateLatch, mainLatch)
-
-        //1. Get NodeStore created
-        createConfig([
-                'org.apache.jackrabbit.oak.segment.SegmentNodeStoreService': [
-                        cache: 256,
-                        "tarmk.mode": 32
-                ]
-        ])
-        getServiceWithWait(NodeStore.class)
-        assert tracker.stores
-
-        CountDownLatch allWellLatch = new CountDownLatch(1)
-        //4. Get roots and thus wait on latch holding the lock
-        Thread.start("GetRoots") { tracker.getRoots(); allWellLatch.countDown() }
-
-        //3. Mutate the config. This results in NodeStore deactivate
-        //which first wait for nodeStoreLatch and then on NodeStoreTracker lock
-        createConfig([
-                'org.apache.jackrabbit.oak.segment.SegmentNodeStoreService': [
-                        cache: 200,
-                        "tarmk.mode": 32
-                ]
-        ])
-
-        //4. Wait for the "GetRoots" to indicate that it has acquired "trackerLock"
-        mainLatch.await()
-
-        assertNull("Deadlock detected", ManagementFactory.getThreadMXBean().findDeadlockedThreads())
-        //5. Let NodeStore deactivate thread proceed and wait for "trackerLock"
-        deactivateLatch.countDown()
-        println ("Letting the deactivate call proceed")
-
-        //6. Let "GetRoots" thread proceed and make it fetch Root and thus wait for
-        //lock in SegmentNodeStoreService
-        trackerLatch.countDown()
-        println ("Letting the getRoots call proceed")
-
-        assertNull("Deadlock detected", ManagementFactory.getThreadMXBean().findDeadlockedThreads())
-        allWellLatch.await()
-        tracker.close()
-    }
-
-    @Override
-    protected PojoServiceRegistry getRegistry() {
-        return registry
-    }
-
-    private static class NodeStoreTracker extends ServiceTracker<NodeStore, NodeStore> {
-        private final Map<ServiceReference<NodeStore>, NodeStore> stores = Maps.newHashMap();
-        private final Object trackerLock = new Object();
-        private final CountDownLatch trackerLatch;
-        private final CountDownLatch deactivateLatch;
-        private final CountDownLatch mainLatch;
-
-        NodeStoreTracker(BundleContext context,
-                         CountDownLatch trackerLatch,
-                         CountDownLatch deactivateLatch,
-                         CountDownLatch mainLatch) {
-            super(context, NodeStore.class.name, null)
-            this.trackerLatch = trackerLatch
-            this.deactivateLatch = deactivateLatch
-            this.mainLatch = mainLatch
-            super.open();
-        }
-
-        @Override
-        void removedService(ServiceReference<NodeStore> reference, NodeStore service) {
-            deactivateLatch.await()
-            synchronized (trackerLock) {
-                stores.remove(reference)
-            }
-            super.removedService(reference, service)
-        }
-
-        @Override
-        NodeStore addingService(ServiceReference<NodeStore> reference) {
-            NodeStore store = super.addingService(reference)
-            synchronized (trackerLock) {
-                stores.put(reference, store)
-            }
-            return store;
-        }
-
-        public List<NodeState> getRoots() {
-            List<NodeState> result = new ArrayList<>();
-            synchronized (trackerLock) {
-                mainLatch.countDown()
-                trackerLatch.await()
-
-                for (NodeStore store : stores.values()) {
-                    try {
-                        result.add(store.getRoot());
-                    } catch (Exception e) {
-                        //Exception expected
-                        e.printStackTrace()
-                    }
-                }
-            }
-            return result;
-        }
-
-        public List<NodeStore> getStores() {
-            List<NodeStore> result = new ArrayList<>();
-            synchronized (trackerLock) {
-                result.addAll(stores.values())
-            }
-            return result;
-        }
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TarSegmentNodeStoreConfigTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TarSegmentNodeStoreConfigTest.groovy
deleted file mode 100644
index 5367711032..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TarSegmentNodeStoreConfigTest.groovy
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.jackrabbit.oak.spi.blob.BlobStore
-import org.apache.jackrabbit.oak.spi.state.NodeStore
-import org.junit.Before
-import org.junit.Test
-
-import static org.junit.Assert.assertNotNull
-import static org.junit.Assert.assertNull
-import static org.mockito.Mockito.mock
-
-class TarSegmentNodeStoreConfigTest extends AbstractRepositoryFactoryTest {
-
-    private static final String SEGMENT_TAR_BUNDLE_FILTER = "(&" +
-            "(|" +
-            "(Bundle-SymbolicName=org.apache.jackrabbit*)" +
-            "(Bundle-SymbolicName=org.apache.sling*)" +
-            "(Bundle-SymbolicName=org.apache.felix*)" +
-            "(Bundle-SymbolicName=org.apache.aries*)" +
-            "(Bundle-SymbolicName=groovy-all)" +
-            ")" +
-            "(!(Bundle-SymbolicName=org.apache.jackrabbit.oak-segment))" +
-            ")"
-
-    private PojoServiceRegistry registry
-
-    @Before
-    void adjustConfig() {
-        config[OakOSGiRepositoryFactory.REPOSITORY_BUNDLE_FILTER] = SEGMENT_TAR_BUNDLE_FILTER
-        registry = repositoryFactory.initializeServiceRegistry(config)
-    }
-
-    @Override
-    protected PojoServiceRegistry getRegistry() {
-        return registry
-    }
-
-    @Test
-    void testDynamicBlobStore() {
-        createConfig([
-                'org.apache.jackrabbit.oak.segment.SegmentNodeStoreService': [
-                        "customBlobStore": true
-                ]
-        ])
-        assertNull(registry.getServiceReference(NodeStore.class.name))
-        def registration = registry.registerService(BlobStore.class.name, mock(BlobStore.class), null)
-        assertNotNull(getServiceWithWait(NodeStore.class))
-        registration.unregister()
-        assertNull(registry.getServiceReference(NodeStore.class.name))
-    }
-
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.groovy
deleted file mode 100644
index 5809f55150..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.groovy
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import groovy.util.logging.Slf4j
-import org.apache.felix.jaas.LoginModuleFactory
-import org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule
-import org.apache.jackrabbit.oak.spi.security.authentication.PreAuthenticatedLogin
-import org.jetbrains.annotations.NotNull
-import org.junit.Before
-import org.junit.Test
-
-import javax.jcr.Credentials
-import javax.jcr.Session
-import javax.jcr.SimpleCredentials
-import javax.security.auth.login.LoginException
-import javax.security.auth.spi.LoginModule
-
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE
-
-
-class TokenAuthenticationTest extends AbstractRepositoryFactoryTest {
-
-    @Before
-    void setupRepo(){
-        config[REPOSITORY_CONFIG_FILE] = createConfigValue("oak-base-config.json", "oak-tar-config.json")
-    }
-
-    @Test
-    public void tokenCreationWithPreAuth() throws Exception {
-        repository = repositoryFactory.getRepository(config)
-        registry.registerService(LoginModuleFactory.class.name, new PreAuthLoginModuleFactory(), [
-                'jaas.controlFlag' : 'sufficient',
-                'jaas.realmName' : 'jackrabbit.oak',
-                'jaas.ranking' : '150',
-
-        ] as Hashtable)
-
-        MyCredential myCred = new MyCredential("admin")
-        Session session = repository.login(myCred)
-        assert myCred.getAttribute(".token")
-    }
-
-    private static class PreAuthLoginModuleFactory implements LoginModuleFactory {
-        @Override
-        LoginModule createLoginModule() {
-            return new PreAuthLoginModule()
-        }
-    }
-
-    @Slf4j
-    private static class PreAuthLoginModule extends AbstractLoginModule {
-        private MyCredential credential
-
-        @NotNull
-        @Override
-        protected Set<Class> getSupportedCredentials() {
-            return Set.of(MyCredential.class)
-        }
-
-        @Override
-        boolean login() throws LoginException {
-            Credentials credentials = getCredentials();
-            if (credentials instanceof MyCredential) {
-                credential = ((MyCredential) credentials)
-                String userId = credential.userID;
-                if (userId == null) {
-                    log.debug("Could not extract userId/credentials");
-                } else {
-                    SimpleCredentials sc = new SimpleCredentials(userId, new char[0])
-                    sc.setAttribute(".token","")
-
-                    // we just set the login name and rely on the following login modules to populate the subject
-                    sharedState.put(SHARED_KEY_PRE_AUTH_LOGIN, new PreAuthenticatedLogin(userId));
-                    sharedState.put(SHARED_KEY_CREDENTIALS, sc);
-                    sharedState.put(SHARED_KEY_LOGIN_NAME, userId);
-                    log.debug("login succeeded with trusted user: {}", userId);
-                }
-            }
-            return false;
-        }
-
-        @Override
-        boolean commit() throws LoginException {
-            Credentials sharedCreds = getSharedCredentials()
-            if(sharedCreds instanceof SimpleCredentials) {
-                credential.setAttribute(".token", ((SimpleCredentials)sharedCreds).getAttribute(".token"))
-            }
-            return false;
-        }
-
-        @Override
-        boolean logout() {
-            return false;
-        }
-    }
-
-    private static class MyCredential implements Credentials {
-        final String userID
-        private final HashMap attributes = new HashMap();
-
-        MyCredential(String userID) {
-            this.userID = userID
-        }
-
-        public void setAttribute(String name, Object value) {
-            // name cannot be null
-            if (name == null) {
-                throw new IllegalArgumentException("name cannot be null");
-            }
-
-            // null value is the same as removeAttribute()
-            if (value == null) {
-                removeAttribute(name);
-                return;
-            }
-
-            synchronized (attributes) {
-                attributes.put(name, value);
-            }
-        }
-
-        public void removeAttribute(String name) {
-            synchronized (attributes) {
-                attributes.remove(name);
-            }
-        }
-
-        public Object getAttribute(String name) {
-            synchronized (attributes) {
-                return (attributes.get(name));
-            }
-        }
-
-    }
-}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TrackerSupportTest.groovy b/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TrackerSupportTest.groovy
deleted file mode 100644
index 53b0e8a729..0000000000
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/TrackerSupportTest.groovy
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.jackrabbit.oak.run.osgi
-
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.felix.connect.launch.PojoServiceRegistryFactory
-import org.junit.After
-import org.junit.Test
-
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-
-class TrackerSupportTest {
-    PojoServiceRegistry reg = createServiceRegistry([:])
-
-    @After
-    public void tearDown(){
-        reg.getBundleContext().getBundle().stop()
-    }
-
-    @Test
-    public void runnableTest() throws Exception{
-        new RunnableJobTracker(reg.bundleContext)
-
-        CountDownLatch latch = new CountDownLatch(1)
-        reg.registerService(Runnable.class.name,{latch.countDown()} as Runnable,
-                ['scheduler.period':1] as Hashtable)
-
-        //Wait for latch to get executed otherwise fail with timeout
-        latch.await(5, TimeUnit.SECONDS)
-    }
-
-    private PojoServiceRegistry createServiceRegistry(Map<String, Object> config) {
-        ServiceLoader<PojoServiceRegistryFactory> loader = ServiceLoader.load(PojoServiceRegistryFactory.class);
-        return loader.iterator().next().newPojoServiceRegistry(config);
-    }
-}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.java
new file mode 100644
index 0000000000..3167e9168d
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.java
@@ -0,0 +1,285 @@
+/*
+ *
+ *  * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  * contributor license agreements.  See the NOTICE file distributed with
+ *  * this work for additional information regarding copyright ownership.
+ *  * The ASF licenses this file to You under the Apache License, Version 2.0
+ *  * (the "License"); you may not use this file except in compliance with
+ *  * the License.  You may obtain a copy of the License at
+ *  *
+ *  *      http://www.apache.org/licenses/LICENSE-2.0
+ *  *
+ *  * Unless required by applicable law or agreed to in writing, software
+ *  * distributed under the License is distributed on an "AS IS" BASIS,
+ *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  * See the License for the specific language governing permissions and
+ *  * limitations under the License.
+ *
+ */
+
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_HOME;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_TIMEOUT_IN_SECS;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.runtime.ServiceComponentRuntime;
+import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
+import org.osgi.util.promise.Promise;
+import org.osgi.util.tracker.ServiceTracker;
+
+public abstract class AbstractRepositoryFactoryTest {
+
+    static final int SVC_WAIT_TIME = Integer.getInteger("pojosr.waitTime", 100);
+    Map<String, Object> config;
+    File workDir;
+    Repository repository;
+    OakOSGiRepositoryFactory repositoryFactory = new OakOSGiRepositoryFactory();
+
+    @Rule
+    public final TemporaryFolder tmpFolder = new TemporaryFolder(new File("target"));
+
+    @Before
+    public void setUp() {
+        workDir = tmpFolder.getRoot();
+        config = new HashMap<>();
+        config.put(REPOSITORY_HOME, workDir.getAbsolutePath());
+        config.put(REPOSITORY_TIMEOUT_IN_SECS, 60);
+    }
+
+    @After
+    public void tearDown() {
+        try {
+            if (repository == null) {
+                PojoServiceRegistry registry = getRegistry();
+                OakOSGiRepositoryFactory.shutdown(registry, 5);
+            }
+        } catch (AssertionError ignore) {
+        } catch (BundleException bundleException) {
+            throw new RuntimeException(bundleException);
+        }
+
+        if (repository instanceof JackrabbitRepository) {
+            ((JackrabbitRepository) repository).shutdown();
+        }
+    }
+
+    protected PojoServiceRegistry getRegistry() {
+        assertTrue(repository instanceof ServiceRegistryProvider);
+        return ((ServiceRegistryProvider) repository).getServiceRegistry();
+    }
+
+    protected <T> void assertNoService(Class<T> clazz) {
+        ServiceReference<T> sr = (ServiceReference<T>) getRegistry().getServiceReference(clazz.getName());
+        assertNull("Service of type " + clazz + " was found", sr);
+    }
+
+    protected <T> T getService(Class<T> clazz) {
+        ServiceReference<T> sr = (ServiceReference<T>) getRegistry().getServiceReference(clazz.getName());
+        assertNotNull("Not able to find a service of type " + clazz, sr);
+        return getRegistry().getService(sr);
+    }
+
+    protected <T> T getServiceWithWait(Class<T> clazz) {
+        return getServiceWithWait(clazz, getRegistry().getBundleContext());
+    }
+
+    protected static <T> T getServiceWithWait(Class<T> clazz, BundleContext bundleContext) {
+        try {
+            ServiceTracker<T, T> st = new ServiceTracker<>(bundleContext, clazz.getName(), null);
+            st.open();
+            T sr = st.waitForService(TimeUnit.SECONDS.toMillis(SVC_WAIT_TIME));
+            assertNotNull("No service found for " + clazz.getName(), sr);
+            return sr;
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected File getResource(String path) {
+        File file = new File(FilenameUtils.concat(getBaseDir(), "src/test/resources/" + path));
+        assertTrue("No file found at " + file.getAbsolutePath(), file.exists());
+        return file;
+    }
+
+    protected void createConfig(Map<String, Map<String, Object>> config) {
+        try {
+            ConfigurationAdmin cm = getService(ConfigurationAdmin.class);
+            ConfigInstaller ci = new ConfigInstaller(cm, getRegistry().getBundleContext());
+            ci.installConfigs(config);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected Session createAdminSession() throws RepositoryException {
+        return repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+    }
+
+    protected String createConfigValue(String... configFiles) {
+        StringBuilder sb = new StringBuilder();
+        for (String configFile : configFiles) {
+            sb.append(getResource(configFile).getAbsolutePath()).append(',');
+        }
+        return sb.substring(0, sb.length() - 1);
+    }
+
+    private static String getBaseDir() {
+        String baseDir = System.getProperty("basedir");
+        if (baseDir != null) {
+            return baseDir;
+        }
+        return new File(".").getAbsolutePath();
+    }
+
+    protected static void retry(int timeoutSeconds, int intervalBetweenTriesMsec, Runnable c) {
+        retry(timeoutSeconds, intervalBetweenTriesMsec, null, c);
+    }
+
+    protected static void retry(int timeoutSeconds, int intervalBetweenTriesMsec, String message, Runnable c) {
+        long timeout = System.currentTimeMillis() + timeoutSeconds * 1000L;
+        while (System.currentTimeMillis() < timeout) {
+            try {
+                c.run();
+                return;
+            } catch (AssertionError | Exception ignore) {
+            }
+
+            try {
+                Thread.sleep(intervalBetweenTriesMsec);
+            } catch (InterruptedException ignore) {
+            }
+        }
+
+        fail("RetryLoop failed, condition is false after " + timeoutSeconds + " seconds" + (message != null ? ":"
+                + message : ""));
+    }
+
+    protected static String classNameFilter(String className) {
+        return "(|(objectClass=" + className + ")(service.pid=" + className + ")(service.factoryPid=" + className
+                + "))";
+    }
+
+    protected void awaitServiceEvent(Runnable closure, String serviceFilter, int eventTypes, long timeout,
+            TimeUnit timeUnit) {
+        try {
+            PojoServiceRegistry registry = getRegistry();
+            BundleContext bundleContext = registry.getBundleContext();
+            EventServiceListener listener = new EventServiceListener(eventTypes, bundleContext, serviceFilter);
+
+            bundleContext.addServiceListener(listener);
+            closure.run();
+            if (!listener.getLatch().await(timeout, timeUnit)) {
+                throw new AssertionError("Exceeded timeout waiting for service event matching " +
+                        "[eventTypes: " + eventTypes + ", filter: " + serviceFilter + "], " +
+                        "got " + listener.events.size() + " non matching events: [" + listener.events + "]");
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected void awaitServiceEvent(Runnable closure, String serviceFilter, int eventTypes) {
+        long timeout = 1000;
+        TimeUnit timeUnit = TimeUnit.MILLISECONDS;
+        this.awaitServiceEvent(closure, serviceFilter, eventTypes, timeout, timeUnit);
+    }
+
+    protected void disableComponent(String name) {
+        ServiceComponentRuntime scr = getServiceWithWait(ServiceComponentRuntime.class);
+        ComponentDescriptionDTO dto = getComponentDTO(scr, name);
+        Promise<Void> p = scr.disableComponent(dto);
+        try {
+            p.getValue();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected void enableComponent(String name) {
+        ServiceComponentRuntime scr = getServiceWithWait(ServiceComponentRuntime.class);
+        ComponentDescriptionDTO dto = getComponentDTO(scr, name);
+        Promise<Void> p = scr.enableComponent(dto);
+        try {
+            p.getValue();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private ComponentDescriptionDTO getComponentDTO(ServiceComponentRuntime scr, String name) {
+        return scr.getComponentDescriptionDTOs().stream()
+                .filter(d -> d.name.equals(name))
+                .findFirst()
+                .orElseThrow(() -> new AssertionError("No component found with name " + name));
+    }
+
+    private static class EventServiceListener implements ServiceListener {
+
+        private final CountDownLatch latch;
+        private final Map<String, Object> events;
+        private final int eventTypes;
+        private final BundleContext bundleContext;
+        private final String serviceFilter;
+
+        public EventServiceListener(int eventTypes, BundleContext bundleContext, String serviceFilter) {
+            this.eventTypes = eventTypes;
+            this.bundleContext = bundleContext;
+            this.serviceFilter = serviceFilter;
+            latch = new CountDownLatch(1);
+            events = new HashMap<>();
+        }
+
+        @Override
+        public void serviceChanged(ServiceEvent event) {
+            events.put("eventType", event.getType());
+            events.put("serviceProperties", asMap(event.getServiceReference()));
+            try {
+                if ((eventTypes & event.getType()) > 0 && bundleContext.createFilter(serviceFilter)
+                        .match(event.getServiceReference())) {
+                    latch.countDown();
+                }
+            } catch (InvalidSyntaxException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private Map<String, Object> asMap(ServiceReference<?> serviceReference) {
+            Map<String, Object> map = new HashMap<>();
+            for (String key : serviceReference.getPropertyKeys()) {
+                map.put(key, serviceReference.getProperty(key));
+            }
+            return map;
+        }
+
+        public CountDownLatch getLatch() {
+            return latch;
+        }
+    }
+}
\ No newline at end of file
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/ConfigTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/ConfigTest.java
new file mode 100644
index 0000000000..a4b1d02993
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/ConfigTest.java
@@ -0,0 +1,168 @@
+/*
+ *
+ *  * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  * contributor license agreements.  See the NOTICE file distributed with
+ *  * this work for additional information regarding copyright ownership.
+ *  * The ASF licenses this file to You under the Apache License, Version 2.0
+ *  * (the "License"); you may not use this file except in compliance with
+ *  * the License.  You may obtain a copy of the License at
+ *  *
+ *  *      http://www.apache.org/licenses/LICENSE-2.0
+ *  *
+ *  * Unless required by applicable law or agreed to in writing, software
+ *  * distributed under the License is distributed on an "AS IS" BASIS,
+ *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  * See the License for the specific language governing permissions and
+ *  * limitations under the License.
+ *
+ */
+
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_HOME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.felix.connect.launch.BundleDescriptor;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
+
+
+public class ConfigTest {
+
+    private TestRepositoryFactory factory = new TestRepositoryFactory();
+    private Map<String, Object> config;
+    private File workDir;
+    private PojoServiceRegistry registry;
+    private ConfigurationAdmin cm;
+
+    @Rule
+    public final TemporaryFolder tmpFolder = new TemporaryFolder(new File("target"));
+
+    private ObjectMapper objectMapper;
+
+    @Before
+    public void setUp() {
+        workDir = tmpFolder.getRoot();
+        config = new HashMap<>(Map.of(
+                REPOSITORY_HOME, workDir.getAbsolutePath(),
+                "magic.spell", "Alohomora"));
+        objectMapper = new ObjectMapper();
+    }
+
+    @After
+    public void shutDown() throws BundleException {
+        OakOSGiRepositoryFactory.shutdown(registry, 5);
+    }
+
+    @Test
+    public void testRuntimeConfig() throws Exception {
+        config.put(REPOSITORY_CONFIG, createConfigMap());
+        initRegistry(config);
+        assertConfig();
+    }
+
+    @Test
+    public void testFileConfig() throws Exception {
+        // Open 2 files and write a string
+        File jf1 = new File(workDir, "config1.json");
+        File jf2 = new File(workDir, "config2.json");
+
+        objectMapper.writeValue(jf1, createConfigMap());
+        objectMapper.writeValue(jf2, Map.of("bar", Map.of("a", "a3", "b", 4)));
+        config.put(REPOSITORY_CONFIG_FILE, String.format("%s,%s", jf1.getAbsolutePath(), jf2.getAbsolutePath()));
+
+        initRegistry(config);
+        assertConfig();
+
+        Configuration c1 = cm.getConfiguration("bar", null);
+        assertNotNull(c1.getProperties());
+        assertEquals("a3", c1.getProperties().get("a"));
+        assertEquals("4", c1.getProperties().get("b").toString());
+    }
+
+    @Test
+    public void testConfigSync() throws Exception {
+        config.put(REPOSITORY_CONFIG, Map.of(
+                "foo", Map.of("a", "a", "b", 1),
+                "bar", Map.of("a", "a1", "b", 2),
+                "foo2", Map.of("a", "a2", "b", 2)
+        ));
+        initRegistry(config);
+        Configuration c = cm.getConfiguration("baz");
+        c.update(new Hashtable<>(Map.of("a", "a2")));
+
+        assertEquals("a2", cm.getConfiguration("baz").getProperties().get("a"));
+        assertEquals("a", cm.getConfiguration("foo").getProperties().get("a"));
+        assertEquals("a1", cm.getConfiguration("bar").getProperties().get("a"));
+        assertEquals("a2", cm.getConfiguration("foo2").getProperties().get("a"));
+
+        shutDown();
+
+        config.put(REPOSITORY_CONFIG, Map.of(
+                "foo", Map.of("a", "a-new", "b", 1),
+                "foo2", Map.of("a", "a2", "b", 2)
+        ));
+        initRegistry(config);
+
+        assertEquals("a2",cm.getConfiguration("baz").getProperties().get("a"));
+        assertEquals("a-new",cm.getConfiguration("foo").getProperties().get("a"));
+        assertNull(cm.getConfiguration("bar").getProperties());
+        assertEquals("a2",cm.getConfiguration("foo2").getProperties().get("a"));
+    }
+
+    private static Map<String, Map<String, Object>> createConfigMap() {
+        return Map.of(
+                "foo", Map.of("a", "a", "b", 1, "c", "${magic.spell}"),
+                "foo.bar-default", Map.of("a", "a1", "b", 2),
+                "foo.bar-simple", Map.of("a", "a2", "b", 3)
+        );
+    }
+
+    private void assertConfig() throws Exception {
+        Configuration c1 = cm.getConfiguration("foo", null);
+        assertNotNull(c1.getProperties());
+        assertEquals("a", c1.getProperties().get("a"));
+        // It returns different number types (long or integer) depending how its read
+        assertEquals("1", c1.getProperties().get("b").toString());
+        assertEquals("Alohomora", c1.getProperties().get("c"));
+
+        Configuration[] fcs = cm.listConfigurations("(service.factoryPid=foo.bar)");
+        assertEquals(2, fcs.length);
+    }
+
+    private void initRegistry(Map<String, Object> config) {
+        registry = factory.initializeServiceRegistry(config);
+        cm = (ConfigurationAdmin) registry.getService(registry.getServiceReference(ConfigurationAdmin.class.getName()));
+    }
+
+    private static class TestRepositoryFactory extends OakOSGiRepositoryFactory {
+
+        @Override
+        protected List<BundleDescriptor> processDescriptors(List<BundleDescriptor> descriptors) {
+            return super.processDescriptors(descriptors).stream()
+                    .filter(bd -> !bd.getHeaders()
+                            .get(Constants.BUNDLE_SYMBOLICNAME)
+                            .startsWith("org.apache.jackrabbit"))
+                    .collect(Collectors.toList());
+        }
+    }
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.java
new file mode 100644
index 0000000000..a8e877556b
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.java
@@ -0,0 +1,498 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import javax.sql.DataSource;
+import org.apache.commons.io.IOUtils;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
+import org.apache.jackrabbit.oak.plugins.blob.CachingBlobStore;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.DocumentStoreStatsMBean;
+import org.apache.jackrabbit.oak.plugins.document.MongoUtils;
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoBlobStore;
+import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
+import org.apache.jackrabbit.oak.spi.blob.AbstractBlobStore;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
+import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore;
+import org.apache.jackrabbit.oak.spi.blob.stats.BlobStoreStatsMBean;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.h2.jdbcx.JdbcDataSource;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Test;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+public class DocumentNodeStoreConfigTest extends AbstractRepositoryFactoryTest {
+
+    private PojoServiceRegistry registry;
+    private final MongoConnection mongoConn = MongoUtils.getConnection();
+
+    @Override
+    protected PojoServiceRegistry getRegistry() {
+        return registry;
+    }
+
+    @After
+    public void tearDown() {
+        super.tearDown();
+        if (mongoConn != null) {
+            MongoUtils.dropCollections(mongoConn.getDatabase());
+        }
+    }
+
+    @Test
+    public void testRDBDocumentStore() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        //1. Register the DataSource as a service
+        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1");
+        registry.registerService(DataSource.class.getName(), ds, new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        Map<String, Map<String, Object>> map = Map.of(
+                "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService",
+                Map.of("documentStoreType", "RDB"));
+        createConfig(map);
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+        // OAK-9668: H2 2.0.206 has a limit of 1MB for BINARY VARYING
+        AbstractBlobStore blobStore = (AbstractBlobStore) getServiceWithWait(BlobStore.class);
+        blobStore.setBlockSize(1024 * 1024);
+
+        //3. Check that DS contains tables from both RDBBlobStore and RDBDocumentStore
+        assertTrue(getExistingTables(ds).containsAll(new ArrayList<>(Arrays.asList("NODES", "DATASTORE_META"))));
+
+        //4. Check that only one cluster node was instantiated
+        assertEquals(1, getIdsOfClusterNodes(ds).size());
+        testBlobStoreStats(ns);
+        testDocumentStoreStats(ns);
+    }
+
+    @Test
+    public void testRDBDocumentStore2Datasources() throws Exception {
+        // see https://issues.apache.org/jira/browse/OAK-5098
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        //1. Register the DataSource as a service
+        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1");
+        ServiceRegistration fds = registry.registerService(DataSource.class.getName(),
+                ds,
+                new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        //2. Register another DataSource as a service with the same name
+        DataSource ds2 = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1");
+        registry.registerService(DataSource.class.getName(), ds2, new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        //3. Create config for DocumentNodeStore with RDB enabled
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+        Map<String, Object> map1 = new LinkedHashMap<>(1);
+        map1.put("documentStoreType", "RDB");
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        createConfig(map);
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+
+        //4. unregister first DS
+        fds.unregister();
+
+        //5. check that nodestore is gone
+        TimeUnit.MILLISECONDS.sleep(500);
+        assertNoService(NodeStore.class);
+    }
+
+    @Test
+    public void testRDBDocumentStoreRestart() {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        //1. Register the DataSource as a service
+        DataSource ds = createDS("jdbc:h2:mem:testRDBrestart;DB_CLOSE_DELAY=-1");
+        ServiceRegistration<?> srds = registry.registerService(DataSource.class.getName(),
+                ds,
+                new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+        Map<String, Object> map1 = new LinkedHashMap<>(1);
+        map1.put("documentStoreType", "RDB");
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        createConfig(map);
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+
+        //3. Shut down ds
+        // Wait for service to be unregistered after at most 5s.
+        // Previously, we waited only 500ms; this was extended due to
+        // occasional test failures on Jenkins (see OAK-5612). If 5s
+        // are not sufficient, we should investigate some more.
+        awaitServiceEvent(srds::unregister,
+                AbstractRepositoryFactoryTest.classNameFilter(NodeStore.class.getName()),
+                ServiceEvent.UNREGISTERING,
+                5,
+                TimeUnit.SECONDS);
+        assertNull(registry.getServiceReference(NodeStore.class.getName()));
+
+        //4. Restart ds, service should still be down
+        registry.registerService(DataSource.class.getName(),
+                ds,
+                new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        assertNoService(NodeStore.class);
+    }
+
+    @Test
+    public void testRDBDocumentStoreLateDataSource() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        //1. Create config for DocumentNodeStore with RDB enabled
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+        Map<String, Object> map1 = new LinkedHashMap<>(1);
+        map1.put("documentStoreType", "RDB");
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        createConfig(map);
+
+        //2. Register the DataSource as a service
+        DataSource ds = createDS("jdbc:h2:mem:testRDBlateds;DB_CLOSE_DELAY=-1");
+        registry.registerService(DataSource.class.getName(), ds, new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+
+        //3. Check that DS contains tables from both RDBBlobStore and RDBDocumentStore
+        assertTrue(getExistingTables(ds).containsAll(new ArrayList<>(Arrays.asList("NODES", "DATASTORE_META"))));
+
+        //4. Check that only one cluster node was instantiated
+        assertEquals(1, getIdsOfClusterNodes(ds).size());
+    }
+
+    @Test
+    public void testRDBDocumentStore_CustomBlobDataSource() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        //1. Register the DataSource as a service
+        DataSource ds1 = createDS("jdbc:h2:mem:testRDB1;DB_CLOSE_DELAY=-1");
+        registry.registerService(DataSource.class.getName(), ds1, new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+        Map<String, Object> map1 = new LinkedHashMap<>(1);
+        map1.put("documentStoreType", "RDB");
+        map1.put("blobDataSource.target", "(datasource.name=oak-blob)");
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        createConfig(map);
+
+        DataSource ds2 = createDS("jdbc:h2:mem:testRDB2;DB_CLOSE_DELAY=-1");
+        registry.registerService(DataSource.class.getName(),
+                ds2,
+                new Hashtable<>(Map.of("datasource.name", "oak-blob")));
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+
+        //3. Check that DS contains tables from RDBBlobStore and RDBDocumentStore
+        //in there respective DataStores
+        List<String> ds1Tables = getExistingTables(ds1);
+        List<String> ds2Tables = getExistingTables(ds2);
+
+        //DS1 should contain RDBDocumentStore tables
+        assertTrue(ds1Tables.contains("NODES"));
+        assertFalse(ds1Tables.contains("DATASTORE_META"));
+
+        //DS2 should contain only RDBBlobStore tables
+        assertFalse(ds2Tables.contains("NODES"));
+        assertTrue(ds2Tables.contains("DATASTORE_META"));
+
+        //4. Check that only one cluster node was instantiated
+        assertEquals(1, getIdsOfClusterNodes(ds1).size());
+    }
+
+    @Test
+    public void testRDBDocumentStore_CustomBlobStore() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        //1. Register the DataSource as a service
+        DataSource ds1 = createDS("jdbc:h2:mem:testRDB3;DB_CLOSE_DELAY=-1");
+        ServiceRegistration sdsds = registry.registerService(DataSource.class.getName(),
+                ds1,
+                new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        DataSource ds2 = createDS("jdbc:h2:mem:testRDB3b;DB_CLOSE_DELAY=-1");
+        ServiceRegistration sdsbs = registry.registerService(DataSource.class.getName(),
+                ds2,
+                new Hashtable<>(Map.of("datasource.name", "oak-blob")));
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        // (supply blobDataSource which should be ignored because customBlob takes precedence)
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+        Map<String, Object> map1 = new LinkedHashMap<>(3);
+        map1.put("documentStoreType", "RDB");
+        map1.put("blobDataSource.target", "(datasource.name=oak-blob)");
+        map1.put("customBlobStore", true);
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        createConfig(map);
+
+        registry.registerService(BlobStore.class.getName(), new MemoryBlobStore(), null);
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+
+        //3. Check that DS1 contains tables only from both RDBDocumentStore
+        List<String> ds1Tables = getExistingTables(ds1);
+
+        //DS1 should contain RDBDocumentStore tables only
+        assertTrue(ds1Tables.contains("NODES"));
+        assertFalse(ds1Tables.contains("DATASTORE_META"));
+
+        //4. Check that DS2 is empty
+        List<String> ds2Tables = getExistingTables(ds2);
+        assertFalse(ds2Tables.contains("NODES"));
+        assertFalse(ds2Tables.contains("DATASTORE_META"));
+
+        //5. Check that only one cluster node was instantiated
+        assertEquals(1, getIdsOfClusterNodes(ds1).size());
+
+        //6. Unregister the data sources to test resilience wrt
+        //multiple deregistrations (OAK-3383)
+        sdsds.unregister();
+        sdsbs.unregister();
+    }
+
+    @Test
+    public void testMongoDocumentStore_CustomBlobStore() throws Exception {
+        mongoCheck();
+
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        Map<String, Map<String, Object>> map = Map.of(
+                "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService",
+                Map.of(
+                        "mongouri", MongoUtils.URL,
+                        "db", MongoUtils.DB,
+                        "customBlobStore", true));
+        createConfig(map);
+
+        registry.registerService(BlobStore.class.getName(), new MemoryBlobStore(), null);
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+
+        Collection<String> colNames = getCollectionNames();
+        assertTrue(colNames.contains("NODES"));
+        assertFalse(colNames.contains("BLOBS"));
+        assertNull(
+                "BlobStoreStatsMBean should *NOT* be registered by DocumentNodeStoreService in case custom blobStore used",
+                registry.getServiceReference(BlobStoreStatsMBean.class.getName()));
+    }
+
+    @Test
+    public void testMongoDocumentStore() throws Exception {
+        mongoCheck();
+
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+        Map<String, Object> map1 = new LinkedHashMap<>(3);
+        map1.put("mongouri", MongoUtils.URL);
+        map1.put("db", MongoUtils.DB);
+        map1.put("blobCacheSize", 1);
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        createConfig(map);
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+
+        Collection<String> colNames = getCollectionNames();
+        assertTrue(colNames.containsAll(new ArrayList<>(Arrays.asList("NODES", "BLOBS"))));
+
+        assertEquals(1 * 1024 * 1024, ((MongoBlobStore) ns.getBlobStore()).getBlobCacheSize());
+        assertNotNull("BlobStoreStatsMBean should be registered by DocumentNodeStoreService in default blobStore used",
+                getService(BlobStoreStatsMBean.class));
+
+        assertNotNull("BlobStore service should be exposed for default setup", getService(BlobStore.class));
+        testBlobStoreStats(ns);
+        testDocumentStoreStats(ns);
+    }
+
+    @Test
+    public void testBundlingEnabledByDefault() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        //1. Register the DataSource as a service
+        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1");
+        registry.registerService(DataSource.class.getName(), ds, new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+        Map<String, Object> map1 = new LinkedHashMap<>(1);
+        map1.put("documentStoreType", "RDB");
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        createConfig(map);
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+        assertTrue(ns.getBundlingConfigHandler().isEnabled());
+    }
+
+    @Test
+    public void testBundlingDisabled() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        //1. Register the DataSource as a service
+        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1");
+        registry.registerService(DataSource.class.getName(), ds, new Hashtable<>(Map.of("datasource.name", "oak")));
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+        Map<String, Object> map1 = new LinkedHashMap<>(2);
+        map1.put("documentStoreType", "RDB");
+        map1.put("bundlingDisabled", true);
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        createConfig(map);
+
+        DocumentNodeStore ns = (DocumentNodeStore) getServiceWithWait(NodeStore.class);
+        assertFalse(ns.getBundlingConfigHandler().isEnabled());
+    }
+
+    private void testDocumentStoreStats(DocumentNodeStore store) throws CommitFailedException {
+        DocumentStoreStatsMBean stats = getService(DocumentStoreStatsMBean.class);
+
+        long createdNodeCount = stats.getNodesCreateCount();
+        NodeBuilder builder = store.getRoot().builder();
+        builder.child("testDocumentStoreStats").child("a");
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        assertTrue(stats.getNodesCreateCount() - createdNodeCount >= 2);
+
+    }
+
+    private void testBlobStoreStats(DocumentNodeStore nodeStore) throws Exception {
+        int size = 1024 * 1024 * 5;
+        Blob blob = nodeStore.createBlob(testStream(size));
+        BlobStoreStatsMBean stats = getService(BlobStoreStatsMBean.class);
+        assertEquals(stats.getUploadTotalSize(), size);
+        assertTrue(stats.getUploadCount() > 0);
+
+        BlobStore bs = nodeStore.getBlobStore();
+        assertTrue(bs instanceof GarbageCollectableBlobStore);
+        ((GarbageCollectableBlobStore) bs).clearCache();
+
+        assertEquals(size, IOUtils.toByteArray(blob.getNewStream()).length);
+
+        assertTrue(stats.getDownloadCount() > 0);
+        assertTrue(stats.getDownloadTotalSize() > 0);
+
+        assertCacheStatsMBean(CachingBlobStore.MEM_CACHE_NAME);
+    }
+
+    private void mongoCheck() {
+        Assume.assumeTrue(MongoUtils.isAvailable());
+    }
+
+    private Collection<String> getCollectionNames() {
+        return StreamSupport.stream(
+                        mongoConn.getDatabase()
+                                .listCollectionNames()
+                                .map(String::toUpperCase)
+                                .spliterator(), false)
+                .collect(Collectors.toList());
+    }
+
+    private List<String> getExistingTables(DataSource ds) throws Exception {
+        Connection con = ds.getConnection();
+        List<String> existing = new ArrayList<>();
+        try {
+            ResultSet rs = con.getMetaData().getTables(null, null, "%", null);
+            while (rs.next()) {
+                existing.add(rs.getString("TABLE_NAME").toUpperCase());
+            }
+
+        } finally {
+            con.close();
+        }
+
+        return existing;
+    }
+
+    private List<String> getIdsOfClusterNodes(DataSource ds) throws Exception {
+        Connection con = ds.getConnection();
+        List<String> entries = new ArrayList<>();
+        try {
+            ResultSet rs = con.prepareStatement("SELECT ID FROM CLUSTERNODES").executeQuery();
+            while (rs.next()) {
+                entries.add(rs.getString(1));
+            }
+
+        } finally {
+            con.close();
+        }
+
+        return entries;
+    }
+
+    private DataSource createDS(String url) {
+        JdbcDataSource ds = new JdbcDataSource();
+        ds.setUrl(url);
+        return ds;
+    }
+
+    private InputStream testStream(int size) {
+        //Cannot use NullInputStream as it throws exception upon EOF
+        byte[] data = new byte[size];
+        new Random().nextBytes(data);
+        return new ByteArrayInputStream(data);
+    }
+
+    private void assertCacheStatsMBean(final String name) throws Exception {
+        ServiceReference[] refs = registry.getServiceReferences(CacheStatsMBean.class.getName(), null);
+        final ArrayList<Object> names = new ArrayList<>();
+        Optional<ServiceReference> cacheStatsRef = Stream.of(refs).filter(sr -> {
+            CacheStatsMBean mbean = (CacheStatsMBean) getRegistry().getService(sr);
+            names.add(mbean.getName());
+            return mbean.getName().equals(name);
+        }).findAny();
+
+        assertTrue("No CacheStat found for [" + name + "]. Registered cache stats " + names,
+                cacheStatsRef.isPresent());
+    }
+}
diff --git a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/HybridIndexDisabledTest.groovy b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/HybridIndexDisabledTest.java
similarity index 51%
rename from oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/HybridIndexDisabledTest.groovy
rename to oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/HybridIndexDisabledTest.java
index bf70868e9e..660cce9090 100644
--- a/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/HybridIndexDisabledTest.groovy
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/HybridIndexDisabledTest.java
@@ -16,69 +16,77 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.jackrabbit.oak.run.osgi;
 
-package org.apache.jackrabbit.oak.run.osgi
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
 
-import org.apache.felix.connect.launch.PojoServiceRegistry
-import org.apache.jackrabbit.commons.JcrUtils
-import org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexDefinitionBuilder
-import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
+import java.util.LinkedHashMap;
+import javax.jcr.Node;
+import javax.jcr.Session;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexDefinitionBuilder;
+import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
-import javax.jcr.Node
-import javax.jcr.Session
-
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG
-import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE
-
-
-class HybridIndexDisabledTest extends AbstractRepositoryFactoryTest {
-    Session session
+public class HybridIndexDisabledTest extends AbstractRepositoryFactoryTest {
 
     @Before
-    void setupRepo() {
-        repositoryFactory = new CustomFactory()
-        config[REPOSITORY_CONFIG_FILE] = createConfigValue("oak-base-config.json", "oak-tar-config.json")
+    public void setupRepo() {
+        repositoryFactory = new CustomFactory();
+        config.put(REPOSITORY_CONFIG_FILE, createConfigValue("oak-base-config.json", "oak-tar-config.json"));
     }
 
     @After
-    void logout() {
-        session.logout()
+    public void logout() {
+        session.logout();
     }
 
     @Test
-    void luceneIndexingWithHybridDisabled() throws Exception{
-        config[REPOSITORY_CONFIG] = [
-                'org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexProviderService' : [
-                        'enableHybridIndexing' : false
-                ]
-        ]
-        repository = repositoryFactory.getRepository(config)
+    public void luceneIndexingWithHybridDisabled() throws Exception {
+        LinkedHashMap<String, LinkedHashMap<String, Boolean>> map = new LinkedHashMap<>(1);
+        LinkedHashMap<String, Boolean> map1 = new LinkedHashMap<String, Boolean>(1);
+        map1.put("enableHybridIndexing", false);
+        map.put("org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexProviderService", map1);
+        config.put(REPOSITORY_CONFIG, map);
+        repository = repositoryFactory.getRepository(config);
 
-        session = createAdminSession()
-        Node fooNode = JcrUtils.getOrCreateByPath("/content/fooNode", "oak:Unstructured", session)
-        fooNode.setProperty("foo", "bar")
-        session.save()
+        session = createAdminSession();
+        Node fooNode = JcrUtils.getOrCreateByPath("/content/fooNode", "oak:Unstructured", session);
+        fooNode.setProperty("foo", "bar");
+        session.save();
+
+    }
 
+    public Session getSession() {
+        return session;
     }
 
+    public void setSession(Session session) {
+        this.session = session;
+    }
+
+    private Session session;
+
     private static class CustomFactory extends OakOSGiRepositoryFactory {
+
         @Override
         protected void preProcessRegistry(PojoServiceRegistry registry) {
-            registry.registerService(RepositoryInitializer.class.name, new RepositoryInitializer() {
+            registry.registerService(RepositoryInitializer.class.getName(), new RepositoryInitializer() {
                 @Override
-                void initialize(NodeBuilder builder) {
+                public void initialize(NodeBuilder builder) {
                     if (builder.hasChildNode(INDEX_DEFINITIONS_NAME)) {
                         NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
 
                         LuceneIndexDefinitionBuilder idxBuilder = new LuceneIndexDefinitionBuilder();
-                        idxBuilder.async("async", "sync")
-                        idxBuilder.indexRule("nt:base").property("foo").propertyIndex()
-                        index.setChildNode("fooIndex", idxBuilder.build())
+                        idxBuilder.async("async", "sync");
+                        idxBuilder.indexRule("nt:base").property("foo").propertyIndex();
+                        index.setChildNode("fooIndex", idxBuilder.build());
                     }
                 }
             }, null);
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.java
new file mode 100644
index 0000000000..3930e1d32c
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/JaasConfigSpiTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG;
+import static org.junit.Assert.assertNotNull;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.jcr.Credentials;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.security.auth.login.LoginException;
+import org.apache.felix.jaas.LoginModuleFactory;
+import org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule;
+import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JaasConfigSpiTest extends AbstractRepositoryFactoryTest {
+
+    @Before
+    public void setupRepo() {
+
+        Map<String, String> loginModuleConfMap = Map.of(
+                "jaas.controlFlag", "required",
+                "jaas.classname", "org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl");
+
+        Map<String, String> jaasConfigMap = Map.of("jaas.defaultRealmName", "jackrabbit.oak",
+                "jaas.configProviderName", "FelixJaasProvider");
+
+        Map<String, String> map3 = Map.of(AuthenticationConfiguration.PARAM_CONFIG_SPI_NAME, "FelixJaasProvider");
+
+        Map<String, Map<String, String>> repoConfig = new LinkedHashMap<>(5);
+        repoConfig.put("org.apache.felix.jaas.Configuration.factory-LoginModuleImpl", loginModuleConfMap);
+        repoConfig.put("org.apache.felix.jaas.ConfigurationSpi", jaasConfigMap);
+        repoConfig.put("org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl", map3);
+        repoConfig.put("org.apache.jackrabbit.oak.jcr.osgi.RepositoryManager", Collections.emptyMap());
+        repoConfig.put("org.apache.jackrabbit.oak.segment.SegmentNodeStoreService", Collections.emptyMap());
+        config.put(REPOSITORY_CONFIG, repoConfig);
+    }
+
+    @Test
+    public void defaultConfigSpiAuth() throws Exception {
+        repository = repositoryFactory.getRepository(config);
+        getRegistry().registerService(LoginModuleFactory.class.getName(),
+                (LoginModuleFactory) TestLoginModule::new,
+                new Hashtable<>(Map.of(
+                        "jaas.controlFlag", "sufficient",
+                        "jaas.realmName", "jackrabbit.oak",
+                        "jaas.ranking", "150"
+                )));
+
+        Session session = repository.login(new SimpleCredentials("batman", "password".toCharArray()));
+        assertNotNull(session);
+        session.logout();
+    }
+
+    public static class TestLoginModule extends AbstractLoginModule {
+
+        private Credentials credentials;
+        private Set<? extends Principal> principals;
+        private String userId;
+
+        @NotNull
+        @Override
+        protected Set<Class> getSupportedCredentials() {
+            return Set.of(SimpleCredentials.class);
+        }
+
+        @Override
+        public boolean login() {
+            credentials = getCredentials();
+            if (credentials instanceof SimpleCredentials) {
+                SimpleCredentials scred = (SimpleCredentials) credentials;
+                if (Arrays.equals("password".toCharArray(), scred.getPassword()) && "batman".equals(scred.getUserID())) {
+                    userId = "admin";
+                    principals = getPrincipals(userId);
+                    sharedState.put(SHARED_KEY_CREDENTIALS, credentials);
+                    sharedState.put(SHARED_KEY_LOGIN_NAME, userId);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean commit() {
+            if (credentials == null || principals == null) {
+                // login attempt in this login module was not successful
+                clearState();
+                return false;
+            } else if (!subject.isReadOnly()) {
+                subject.getPrincipals().addAll(principals);
+                subject.getPublicCredentials().add(credentials);
+                return true;
+            }
+
+            return false;
+        }
+
+        @Override
+        public boolean logout() throws LoginException {
+            return super.logout(Set.of(credentials), principals);
+        }
+    }
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/JsonConfigRepFactoryTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/JsonConfigRepFactoryTest.java
new file mode 100644
index 0000000000..d06690f7a1
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/JsonConfigRepFactoryTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Collections;
+import java.util.Map;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JsonConfigRepFactoryTest extends AbstractRepositoryFactoryTest {
+
+    @Before
+    public void setupRepo() {
+        config.put(REPOSITORY_CONFIG_FILE, getResource("oak-base-config.json").getAbsolutePath());
+    }
+
+    @Test
+    public void testRepositoryTar() throws Exception {
+        config.put(REPOSITORY_CONFIG,
+                Map.of("org.apache.jackrabbit.oak.segment.SegmentNodeStoreService", Collections.emptyMap()));
+
+        repository = repositoryFactory.getRepository(config);
+        assertNotNull(repository);
+        assertNotNull(getService(NodeStore.class));
+        basicCrudTest();
+    }
+
+    public void basicCrudTest() throws RepositoryException {
+        Session session = createAdminSession();
+        Node rootNode = session.getRootNode();
+
+        Node child = JcrUtils.getOrAddNode(rootNode, "child", "oak:Unstructured");
+        child.setProperty("foo3", "bar3");
+        session.save();
+        session.logout();
+
+        session = createAdminSession();
+        assertEquals("bar3", session.getProperty("/child/foo3").getString());
+        session.logout();
+    }
+
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/LuceneSupportTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/LuceneSupportTest.java
new file mode 100644
index 0000000000..a127a1fa98
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/LuceneSupportTest.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_CONTENT;
+import static org.apache.jackrabbit.JcrConstants.NT_FILE;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.Row;
+import javax.jcr.query.RowIterator;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.guava.common.collect.Lists;
+import org.apache.jackrabbit.oak.plugins.index.aggregate.SimpleNodeAggregator;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexFormatVersion;
+import org.apache.jackrabbit.oak.plugins.index.search.util.IndexHelper;
+import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.NodeAggregator;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class LuceneSupportTest extends AbstractRepositoryFactoryTest {
+
+    @Before
+    public void setupRepo() {
+        repositoryFactory = new CustomFactory();
+        config.put(REPOSITORY_CONFIG_FILE, createConfigValue("oak-base-config.json", "oak-tar-config.json"));
+    }
+
+    @After
+    public void logout() {
+        session.logout();
+    }
+
+    @Test
+    public void fullTextSearch() throws Exception {
+        repository = repositoryFactory.getRepository(config);
+        session = createAdminSession();
+
+        Node testNode = session.getRootNode();
+        Node contentNode = testNode.addNode("myFile", "nt:file").addNode("jcr:content", "oak:Unstructured");
+        contentNode.setProperty("jcr:mimeType", "text/plain");
+        contentNode.setProperty("jcr:encoding", "UTF-8");
+        contentNode.setProperty("jcr:data",
+                new ByteArrayInputStream("the quick brown fox jumps over the lazy dog.".getBytes("utf-8")));
+        session.save();
+
+        SimpleNodeAggregator agg = new SimpleNodeAggregator().newRuleWithName(NT_FILE,
+                Lists.newArrayList(JCR_CONTENT, JCR_CONTENT + "/*"));
+        getRegistry().registerService(NodeAggregator.class.getName(), agg, null);
+
+        //The lucene index is set to synched mode
+        AbstractRepositoryFactoryTest.retry(30, 200, () -> {
+            try {
+                String query = "SELECT * FROM [nt:base] as f WHERE CONTAINS (f.*, 'dog')";
+                Set<String> queryResult = execute(query);
+                assertTrue(Stream.of("/myFile", "/myFile/jcr:content").allMatch(queryResult::contains));
+            } catch (RepositoryException e) {
+                throw new RuntimeException(e);
+            }
+        });
+    }
+
+    public Set<String> execute(String stmt) throws RepositoryException {
+        QueryManager qm = session.getWorkspace().getQueryManager();
+        Query query = qm.createQuery(stmt, "JCR-SQL2");
+        QueryResult result = query.execute();
+        RowIterator rowItr = result.getRows();
+        final Set<String> paths = new HashSet<String>();
+        while (rowItr.hasNext()) {
+            Row r = rowItr.nextRow();
+            paths.add(r.getNode().getPath());
+        }
+        return paths;
+    }
+
+    public Session getSession() {
+        return session;
+    }
+
+    public void setSession(Session session) {
+        this.session = session;
+    }
+
+    private Session session;
+
+    private static class CustomFactory extends OakOSGiRepositoryFactory {
+
+        @Override
+        protected void preProcessRegistry(PojoServiceRegistry registry) {
+            registry.registerService(RepositoryInitializer.class.getName(), new RepositoryInitializer() {
+                @Override
+                public void initialize(NodeBuilder builder) {
+                    if (builder.hasChildNode(INDEX_DEFINITIONS_NAME)) {
+                        NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+                        if (!index.hasChildNode("lucene")) {
+                            NodeBuilder nb = LuceneIndexHelper.newLuceneIndexDefinition(index,
+                                    "lucene",
+                                    IndexHelper.JR_PROPERTY_INCLUDES,
+                                    null,
+                                    "async");
+                            nb.setProperty(FulltextIndexConstants.COMPAT_MODE, IndexFormatVersion.V1.getVersion());
+                        }
+
+                    }
+
+                }
+
+            }, null);
+        }
+
+    }
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MBeanIntegrationTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MBeanIntegrationTest.java
new file mode 100644
index 0000000000..5c945f33d8
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MBeanIntegrationTest.java
@@ -0,0 +1,51 @@
+/*
+ *
+ *  * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  * contributor license agreements.  See the NOTICE file distributed with
+ *  * this work for additional information regarding copyright ownership.
+ *  * The ASF licenses this file to You under the Apache License, Version 2.0
+ *  * (the "License"); you may not use this file except in compliance with
+ *  * the License.  You may obtain a copy of the License at
+ *  *
+ *  *      http://www.apache.org/licenses/LICENSE-2.0
+ *  *
+ *  * Unless required by applicable law or agreed to in writing, software
+ *  * distributed under the License is distributed on an "AS IS" BASIS,
+ *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  * See the License for the specific language governing permissions and
+ *  * limitations under the License.
+ *
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
+import static org.junit.Assert.assertEquals;
+
+import java.lang.management.ManagementFactory;
+import java.util.Set;
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.Query;
+import javax.management.QueryExp;
+import org.apache.jackrabbit.oak.api.jmx.RepositoryManagementMBean;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MBeanIntegrationTest extends AbstractRepositoryFactoryTest {
+
+    @Before
+    public void setupRepo() {
+        config.put(REPOSITORY_CONFIG_FILE, createConfigValue("oak-base-config.json", "oak-tar-config.json"));
+    }
+
+    @Test
+    public void jmxIntegration() throws Exception {
+        repository = repositoryFactory.getRepository(config);
+        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+        QueryExp q = Query.isInstanceOf(Query.value(RepositoryManagementMBean.class.getName()));
+        Set<ObjectInstance> mbeans = server.queryMBeans(new ObjectName("org.apache.jackrabbit.oak:*"), q);
+        assertEquals(1, mbeans.size());
+    }
+
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.java
new file mode 100644
index 0000000000..1ce3a70e05
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.java
@@ -0,0 +1,51 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.junit.Assert.assertThrows;
+
+import java.util.Map;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.oak.segment.SegmentNodeStore;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Test;
+
+public class NodeStoreConfigTest extends AbstractRepositoryFactoryTest {
+
+    private PojoServiceRegistry registry;
+
+    @Test
+    public void testNodeStoreWithBlobStore_OAK_1676() {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+        registry.registerService(BlobStore.class.getName(), new MemoryBlobStore(), null);
+
+        createConfig(Map.of(
+                "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService", Map.of()));
+
+        SegmentNodeStore ns = (SegmentNodeStore) getServiceWithWait(NodeStore.class, registry.getBundleContext());
+        // NodeStore is of type SegmentNodeStoreService
+        assertThrows("BlobStore should not be picked up unless 'customBlobStore' is set to true",
+                IllegalStateException.class,() -> ns.getBlob("test"));
+    }
+
+    @Override
+    protected PojoServiceRegistry getRegistry() {
+        return registry;
+    }
+}
\ No newline at end of file
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/OakOSGiRepositoryFactoryTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/OakOSGiRepositoryFactoryTest.java
index 16461c21c8..b48b0de6fe 100644
--- a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/OakOSGiRepositoryFactoryTest.java
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/OakOSGiRepositoryFactoryTest.java
@@ -19,6 +19,11 @@
 
 package org.apache.jackrabbit.oak.run.osgi;
 
+import static org.apache.commons.io.FilenameUtils.concat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.Collections;
@@ -26,16 +31,14 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
-
 import javax.jcr.Node;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.RepositoryFactory;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
-
-import org.apache.felix.connect.launch.PojoServiceRegistry;
 import org.apache.commons.io.FileUtils;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
 import org.apache.jackrabbit.api.JackrabbitRepository;
 import org.apache.jackrabbit.api.JackrabbitSession;
 import org.apache.jackrabbit.api.security.user.User;
@@ -55,11 +58,6 @@ import org.junit.rules.TemporaryFolder;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 
-import static org.apache.commons.io.FilenameUtils.concat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
 public class OakOSGiRepositoryFactoryTest {
 
     private String repositoryHome;
@@ -171,12 +169,12 @@ public class OakOSGiRepositoryFactoryTest {
     private class TestActivator implements BundleActivator {
 
         @Override
-        public void start(BundleContext bundleContext) throws Exception {
+        public void start(BundleContext bundleContext) {
             calledOnStart = true;
         }
 
         @Override
-        public void stop(BundleContext bundleContext) throws Exception {
+        public void stop(BundleContext bundleContext) {
             calledOnStop = true;
         }
     }
@@ -185,7 +183,7 @@ public class OakOSGiRepositoryFactoryTest {
 
         @Override
         public void onPasswordChange(@NotNull User user, @Nullable String newPassword,
-                                     @NotNull Root root, @NotNull NamePathMapper namePathMapper) throws RepositoryException {
+                                     @NotNull Root root, @NotNull NamePathMapper namePathMapper) {
             OakOSGiRepositoryFactoryTest.this.newPassword = newPassword;
         }
     }
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/PropertyIndexReindexingTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/PropertyIndexReindexingTest.java
new file mode 100644
index 0000000000..905ccc3f2b
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/PropertyIndexReindexingTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import java.util.concurrent.TimeUnit;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PropertyIndexReindexingTest extends AbstractRepositoryFactoryTest {
+
+    @Before
+    public void setupRepo() {
+        config.put(REPOSITORY_CONFIG_FILE, createConfigValue("oak-base-config.json", "oak-tar-config.json"));
+    }
+
+    @Test
+    public void propertyIndexState() throws Exception {
+        repository = repositoryFactory.getRepository(config);
+        PojoServiceRegistry registry = getRegistry();
+
+        //1. Save a node with 'foo' property
+        Session s = createAdminSession();
+        s.getRootNode().addNode("a1").setProperty("foo", "bar");
+        s.save();
+        s.logout();
+
+        //2. Create a property index for 'foo'
+        s = createAdminSession();
+        Node fooIndex = JcrUtils.getOrCreateByPath("/oak:index/foo",
+                JcrConstants.NT_UNSTRUCTURED,
+                "oak:QueryIndexDefinition",
+                s,
+                false);
+        fooIndex.setProperty(IndexConstants.TYPE_PROPERTY_NAME, "property");
+        fooIndex.setProperty(IndexConstants.PROPERTY_NAMES, new String[]{"foo"});
+        s.save();
+        s.logout();
+
+        //3. By the last save reindex flag should be false
+        s = createAdminSession();
+        assertFalse(s.getProperty("/oak:index/foo/reindex").getBoolean());
+        s.logout();
+
+        //4. Disable the PropertyIndexEditor
+        String indexComponent = "org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider";
+        disableComponent(indexComponent);
+        TimeUnit.SECONDS.sleep(1);
+        assertNull("Repository should be unregistered " + "if no property index editor found",
+                registry.getServiceReference(Repository.class.getName()));
+
+
+        //5. Re-enable the editor and wait untill repository gets re-registered
+        enableComponent(indexComponent);
+        AbstractRepositoryFactoryTest.getServiceWithWait(Repository.class, registry.getBundleContext());
+
+        //6. Reindex flag should be stable
+        s = createAdminSession();
+        assertFalse(s.getProperty("/oak:index/foo/reindex").getBoolean());
+        s.logout();
+    }
+
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/RepositoryClosedTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/RepositoryClosedTest.java
new file mode 100644
index 0000000000..f79722e78d
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/RepositoryClosedTest.java
@@ -0,0 +1,68 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RepositoryClosedTest extends AbstractRepositoryFactoryTest {
+
+    private static final Logger log = LoggerFactory.getLogger(RepositoryClosedTest.class);
+
+    @Before
+    public void setupRepo() {
+        config.put(REPOSITORY_CONFIG_FILE, createConfigValue("oak-base-config.json", "oak-tar-config.json"));
+    }
+
+    @Test
+    public void sessionUsePostClose() throws Exception {
+        repository = repositoryFactory.getRepository(config);
+        PojoServiceRegistry registry = getRegistry();
+
+        // 1. Obtain handle to a session
+        Session s = createAdminSession();
+
+        // 2. Trigger repository shutdown
+        disableComponent("org.apache.jackrabbit.oak.jcr.osgi.RepositoryManager");
+        disableComponent("org.apache.jackrabbit.oak.plugins.name.NameValidatorProvider");
+
+        log.info("Repository shutdown complete. Proceeding with save");
+
+        // Null out repository to prevent shutdown attempt in teardown
+        repository = null;
+
+        // 3. Now try adding a node with invalid name. Such a commit
+        // should have got failed
+        s.getRootNode().addNode("a\nb");
+        try {
+            s.save();
+            Assert.fail("Session save should have failed due to invalid name");
+        } catch (RepositoryException ignore) {
+            // Expected exception
+        }
+
+        OakOSGiRepositoryFactory.shutdown(registry, 5);
+    }
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/RepositoryShutdownTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/RepositoryShutdownTest.java
new file mode 100644
index 0000000000..717c4b49aa
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/RepositoryShutdownTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_HOME;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_TIMEOUT_IN_SECS;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.jcr.Repository;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class RepositoryShutdownTest {
+
+    @Test
+    public void multipleShutdown() throws Exception {
+        JackrabbitRepository repository = Mockito.mock(JackrabbitRepository.class);
+        Map<String, Object> config = getConfig(repository);
+
+        Repository repo2 = new OakOSGiRepositoryFactory().getRepository(config);
+        assertTrue(repo2 instanceof JackrabbitRepository);
+        ((JackrabbitRepository) repo2).shutdown();
+
+        Mockito.verify(repository, Mockito.times(0)).shutdown();
+    }
+
+    @Test
+    public void multipleShutdownAndWait() throws Exception {
+        JackrabbitRepository repository = Mockito.mock(JackrabbitRepository.class);
+        Map<String, Object> config = getConfig(repository);
+
+        Repository repo2 = new OakOSGiRepositoryFactory().getRepository(config);
+        assertTrue(repo2 instanceof JackrabbitRepository);
+        ((JackrabbitRepository) repo2).shutdown();
+        ((JackrabbitRepository) repo2).shutdown();
+    }
+
+    private Map<String, Object> getConfig(final JackrabbitRepository repository) {
+        Map<String, Object> map = new LinkedHashMap<>(3);
+        map.put(REPOSITORY_HOME, tmpFolder.getRoot().getAbsolutePath());
+        map.put(REPOSITORY_TIMEOUT_IN_SECS, 1);
+        map.put(BundleActivator.class.getName(), new BundleActivator() {
+            @Override
+            public void start(BundleContext bundleContext) throws Exception {
+                bundleContext.registerService(Repository.class.getName(), repository, null);
+            }
+
+            @Override
+            public void stop(BundleContext bundleContext) throws Exception {
+
+            }
+
+        });
+        return map;
+    }
+
+    @Rule
+    public final TemporaryFolder tmpFolder = new TemporaryFolder(new File("target"));
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SecondaryStoreConfigIT.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SecondaryStoreConfigIT.java
new file mode 100644
index 0000000000..4f7440c96a
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SecondaryStoreConfigIT.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG;
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import javax.jcr.Node;
+import javax.jcr.Session;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.oak.plugins.document.MongoUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStoreProvider;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class SecondaryStoreConfigIT extends AbstractRepositoryFactoryTest {
+
+    @Test
+    public void secondaryNodeStoreCache() throws Exception {
+        mongoCheck();
+
+        MongoUtils.dropDatabase(MongoUtils.DB);
+        config.put(REPOSITORY_CONFIG_FILE, createConfigValue("oak-base-config.json"));
+        Map<String, Map<String, Object>> map = new LinkedHashMap<>( 3);
+        Map<String, Object> map1 = new LinkedHashMap<>(2);
+        map1.put("mongouri", MongoUtils.URL);
+        map1.put("db", MongoUtils.DB);
+        map.put("org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService", map1);
+        Map<String, Object> map2 = new LinkedHashMap<>(1);
+        map2.put("role", "secondary");
+        map.put("org.apache.jackrabbit.oak.segment.SegmentNodeStoreFactory-secondary.config", map2);
+        Map<String, Object> map3 = new LinkedHashMap<>(1);
+        map3.put("includedPaths", List.of("/"));
+        map.put("org.apache.jackrabbit.oak.plugins.document.secondary.SecondaryStoreCacheService", map3);
+        config.put(REPOSITORY_CONFIG, map);
+
+        repository = repositoryFactory.getRepository(config);
+
+        Session session = createAdminSession();
+        Node rootNode = session.getRootNode();
+
+        Node child = JcrUtils.getOrAddNode(rootNode, "testNode", "oak:Unstructured");
+        child.setProperty("foo", "bar");
+        session.save();
+        session.logout();
+
+        NodeStoreProvider nsp = getServiceWithWait(NodeStoreProvider.class);
+        final NodeStore secondary = nsp.getNodeStore();
+
+        //Assert that recently created node gets pushed to Secondary and
+        //is accessible in sometime
+        AbstractRepositoryFactoryTest.retry(30,
+                10,
+                () -> NodeStateUtils.getNode(secondary.getRoot(), "/testNode").exists());
+
+    }
+
+    private void mongoCheck() {
+        //Check if Mongo is available
+        Assume.assumeTrue(MongoUtils.isAvailable());
+    }
+
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.java
new file mode 100644
index 0000000000..22849d7571
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SecurityProviderRegistrationTest.java
@@ -0,0 +1,392 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Field;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.Context;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration;
+import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration;
+import org.apache.jackrabbit.oak.spi.security.user.AuthorizableNodeName;
+import org.apache.jackrabbit.oak.spi.security.user.UserAuthenticationFactory;
+import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
+import org.apache.jackrabbit.oak.spi.security.user.action.AccessControlAction;
+import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableAction;
+import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableActionProvider;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class SecurityProviderRegistrationTest extends AbstractRepositoryFactoryTest {
+
+    private PojoServiceRegistry registry;
+
+    @Before
+    public void initializeRegistry() {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+    }
+
+    @Override
+    protected PojoServiceRegistry getRegistry() {
+        return registry;
+    }
+    /**
+     * Test that, without any additional configuration, a SecurityProvider service is registered by default.
+     */
+    @Test
+    public void testDefaultSetup() {
+        assertNotNull(getSecurityProviderServiceReferences());
+    }
+
+    /**
+     * A SecurityProvider shouldn't start without a required AuthorizationConfiguration service.
+     */
+    @Test
+    public void testRequiredAuthorizationConfigurationNotAvailable() {
+        AuthorizationConfiguration m = Mockito.mock(AuthorizationConfiguration.class);
+        Mockito.when(m.getParameters()).thenReturn(ConfigurationParameters.EMPTY);
+        Mockito.when(m.getContext()).thenReturn(Context.DEFAULT);
+
+        testRequiredService(AuthorizationConfiguration.class, m);
+    }
+
+    /**
+     * A SecurityProvider shouldn't start without a required PrincipalConfiguration service.
+     */
+    @Test
+    public void testRequiredPrincipalConfigurationNotAvailable() {
+        PrincipalConfiguration m = Mockito.mock(PrincipalConfiguration.class);
+        Mockito.when(m.getParameters()).thenReturn(ConfigurationParameters.EMPTY);
+        Mockito.when(m.getContext()).thenReturn(Context.DEFAULT);
+
+        testRequiredService(PrincipalConfiguration.class, m);
+    }
+
+    /**
+     * A SecurityProvider shouldn't start without a required TokenConfiguration service.
+     */
+    @Test
+    public void testRequiredTokenConfigurationNotAvailable() {
+        TokenConfiguration m = Mockito.mock(TokenConfiguration.class);
+        Mockito.when(m.getParameters()).thenReturn(ConfigurationParameters.EMPTY);
+        Mockito.when(m.getContext()).thenReturn(Context.DEFAULT);
+
+        testRequiredService(TokenConfiguration.class, m);
+    }
+
+    /**
+     * A SecurityProvider shouldn't start without a required AuthorizableNodeName service.
+     */
+    @Test
+    public void testRequiredAuthorizableNodeNameNotAvailable() {
+        testRequiredService(AuthorizableNodeName.class, Mockito.mock(AuthorizableNodeName.class));
+    }
+
+    /**
+     * A SecurityProvider shouldn't start without a required AuthorizableActionProvider service.
+     */
+    @Test
+    public void testRequiredAuthorizableActionProviderNotAvailable() {
+        testRequiredService(AuthorizableActionProvider.class, Mockito.mock(AuthorizableActionProvider.class));
+    }
+
+    /**
+     * A SecurityProvider shouldn't start without a required RestrictionProvider service.
+     */
+    @Test
+    public void testRequiredRestrictionProviderNotAvailable() {
+        testRequiredService(RestrictionProvider.class, Mockito.mock(RestrictionProvider.class));
+    }
+
+    /**
+     * A SecurityProvider shouldn't start without a required UserAuthenticationFactory service.
+     */
+    @Test
+    public void testRequiredUserAuthenticationFactoryNotAvailable() {
+        testRequiredService(UserAuthenticationFactory.class, Mockito.mock(UserAuthenticationFactory.class));
+    }
+
+    /**
+     * A SecurityProvider should be registered only if every every prerequisite is satisfied.
+     */
+    @Test
+    public void testMultipleRequiredServices() {
+
+        // Set up the SecurityProvider to require 4 services
+        awaitServiceEvent(() ->
+                        setRequiredServicePids("test.RequiredAuthorizationConfiguration",
+                                "test.RequiredPrincipalConfiguration",
+                                "test.RequiredTokenConfiguration",
+                                "test.RestrictionProvider"),
+                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)", ServiceEvent.UNREGISTERING);
+
+        assertNull(getSecurityProviderServiceReferences());
+
+        // Start the services and verify that only at the end the
+        // SecurityProvider registers itself
+        AuthorizationConfiguration ac = Mockito.mock(AuthorizationConfiguration.class);
+        Mockito.when(ac.getParameters()).thenReturn(ConfigurationParameters.EMPTY);
+        Mockito.when(ac.getContext()).thenReturn(Context.DEFAULT);
+
+        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
+        map.put("service.pid", "test.RequiredAuthorizationConfiguration");
+        registry.registerService(AuthorizationConfiguration.class.getName(), ac, dict(map));
+        assertNull(getSecurityProviderServiceReferences());
+
+        PrincipalConfiguration pc = Mockito.mock(PrincipalConfiguration.class);
+        Mockito.when(pc.getParameters()).thenReturn(ConfigurationParameters.EMPTY);
+        Mockito.when(pc.getContext()).thenReturn(Context.DEFAULT);
+
+        LinkedHashMap<String, String> map1 = new LinkedHashMap<>(1);
+        map1.put("service.pid", "test.RequiredPrincipalConfiguration");
+        registry.registerService(PrincipalConfiguration.class.getName(), pc, dict(map1));
+        assertNull(getSecurityProviderServiceReferences());
+
+        TokenConfiguration tc = Mockito.mock(TokenConfiguration.class);
+        Mockito.when(tc.getParameters()).thenReturn(ConfigurationParameters.EMPTY);
+        Mockito.when(tc.getContext()).thenReturn(Context.DEFAULT);
+
+        LinkedHashMap<String, String> map2 = new LinkedHashMap<>(1);
+        map2.put("service.pid", "test.RequiredTokenConfiguration");
+        registry.registerService(TokenConfiguration.class.getName(), tc, dict(map2));
+        assertNull(getSecurityProviderServiceReferences());
+
+        LinkedHashMap<String, String> map3 = new LinkedHashMap<>(1);
+        map3.put("service.pid", "test.RestrictionProvider");
+        registry.registerService(RestrictionProvider.class.getName(),
+                Mockito.mock(RestrictionProvider.class),
+                dict(map3));
+        assertNotNull(getSecurityProviderServiceReferences());
+    }
+
+    @Test
+    public void testSecurityConfigurations() {
+        SecurityProvider securityProvider = (SecurityProvider) registry.getService((ServiceReference<?>) registry.getServiceReference(
+                SecurityProvider.class.getName()));
+        assertAuthorizationConfig(securityProvider);
+        assertUserConfig(securityProvider);
+
+        //Keep a dummy reference to UserConfiguration such that SCR does not deactivate it
+        //once SecurityProviderRegistration gets deactivated. Otherwise if SecurityProviderRegistration is
+        //the only component that refers it then upon its deactivation UserConfiguration would also be
+        //deactivate and its internal state would be reset
+        UserConfiguration userConfiguration = getServiceWithWait(UserConfiguration.class);
+
+        final String authComponentName = "org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl";
+
+        // 1. Disable AuthenticationConfiguration such that SecurityProvider is unregistered
+        awaitServiceEvent(() -> disableComponent(authComponentName),
+                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
+                ServiceEvent.UNREGISTERING,
+                5000,
+                TimeUnit.MILLISECONDS);
+
+        assertNull(getSecurityProviderServiceReferences());
+
+        // 2. Modify the config for AuthorizableActionProvider. It's expected that this config change is picked up
+        awaitServiceEvent(() -> {
+                    Map<String, Map<String, Object>> map = new LinkedHashMap<>(1);
+                    map.put("org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider",
+                            Map.of("groupPrivilegeNames", "jcr:read"));
+                    setConfiguration(map);
+                },
+                AbstractRepositoryFactoryTest.classNameFilter(
+                        "org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider"),
+                ServiceEvent.MODIFIED | ServiceEvent.REGISTERED);
+
+        // 3. Enable component again such that SecurityProvider gets reactivated
+        awaitServiceEvent(() -> enableComponent(authComponentName),
+                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
+                ServiceEvent.REGISTERED);
+
+        securityProvider = getServiceWithWait(SecurityProvider.class);
+        assertAuthorizationConfig(securityProvider);
+        assertUserConfig(securityProvider, "jcr:read");
+    }
+
+    @Test
+    public void testSecurityConfigurations2() {
+        SecurityProvider securityProvider = (SecurityProvider) registry.getService(registry.getServiceReference(SecurityProvider.class.getName()));
+        assertAuthorizationConfig(securityProvider);
+        assertUserConfig(securityProvider);
+
+        //Keep a dummy reference to UserConfiguration such that SCR does not deactivate it
+        //once SecurityProviderRegistration gets deactivated. Otherwise if SecurityProviderRegistration is
+        //the only component that refers it then upon its deactivation UserConfiguration would also be
+        //deactivate and its internal state would be reset
+        UserConfiguration userConfiguration = getServiceWithWait(UserConfiguration.class);
+
+        //1. Modify the config for AuthorizableActionProvider. It's expected that this config change is picked up
+        final String servicePid = "org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider";
+        awaitServiceEvent(() -> setConfiguration(Map.of(servicePid, Map.of("groupPrivilegeNames", "jcr:read"))),
+                "(service.pid=" + servicePid + ")", ServiceEvent.MODIFIED | ServiceEvent.REGISTERED);
+
+        securityProvider = getServiceWithWait(SecurityProvider.class);
+        assertAuthorizationConfig(securityProvider);
+        assertUserConfig(securityProvider, "jcr:read");
+
+        final String authComponentName = "org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl";
+
+        // 2. Disable AuthenticationConfiguration such that SecurityProvider is unregistered
+        awaitServiceEvent(() -> disableComponent(authComponentName),
+                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
+                ServiceEvent.UNREGISTERING);
+
+        assertNull(getSecurityProviderServiceReferences());
+
+        // 3. Enable component again such that SecurityProvider gets reactivated
+        awaitServiceEvent(() -> enableComponent(authComponentName),
+                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
+                ServiceEvent.REGISTERED);
+
+        securityProvider = getServiceWithWait(SecurityProvider.class);
+        assertAuthorizationConfig(securityProvider);
+        assertUserConfig(securityProvider, "jcr:read");
+    }
+
+    private <T> void testRequiredService(final Class<T> serviceClass, final T service) {
+
+        // Adding a new precondition on a missing service PID forces the
+        // SecurityProvider to unregister.
+
+        awaitServiceEvent(() -> setRequiredServicePids("test.Required" + serviceClass.getSimpleName()),
+                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
+                ServiceEvent.UNREGISTERING);
+
+        assertNull(getSecurityProviderServiceReferences());
+
+        // If a service is registered, and if the PID of the service matches the
+        // precondition, the SecurityProvider is registered again.
+
+        AtomicReference<ServiceRegistration<?>> registration = new AtomicReference<>();
+        awaitServiceEvent(() -> {
+            Map<String, Object> map = new LinkedHashMap<>(1);
+            map.put("service.pid", "test.Required" + serviceClass.getSimpleName());
+            registration.set(registry.registerService(serviceClass.getName(), service, dict(map)));
+        }, "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)", ServiceEvent.REGISTERED);
+        assertNotNull(getSecurityProviderServiceReferences());
+
+        // If the service is unregistered, but the precondition is still in
+        // place, the SecurityProvider unregisters again.
+
+        awaitServiceEvent(() -> registration.get().unregister(),
+                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
+                ServiceEvent.UNREGISTERING);
+        assertNull(getSecurityProviderServiceReferences());
+
+        // Removing the precondition allows the SecurityProvider to register.
+        awaitServiceEvent(this::setRequiredServicePids,
+                "(objectClass=org.apache.jackrabbit.oak.spi.security.SecurityProvider)",
+                ServiceEvent.REGISTERED);
+        assertNotNull(getSecurityProviderServiceReferences());
+    }
+
+    private ServiceReference<?>[] getSecurityProviderServiceReferences() {
+        try {
+            return registry.getServiceReferences(SecurityProvider.class.getName(), "(type=default)");
+        } catch (InvalidSyntaxException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void setRequiredServicePids(String... pids) {
+        setConfiguration(
+                Map.of("org.apache.jackrabbit.oak.security.internal.SecurityProviderRegistration",
+                        Map.of("requiredServicePids", pids)));
+    }
+
+    private void setConfiguration(Map<String, Map<String, Object>> configuration) {
+        try {
+            getConfigurationInstaller().installConfigs(configuration);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private ConfigInstaller getConfigurationInstaller() {
+        return new ConfigInstaller(getConfigurationAdmin(), registry.getBundleContext());
+    }
+
+    private ConfigurationAdmin getConfigurationAdmin() {
+        return (ConfigurationAdmin) registry.getService(registry.getServiceReference(ConfigurationAdmin.class.getName()));
+    }
+
+    private static <K, V> Dictionary<K, V> dict(Map<K, V> map) {
+        return new Hashtable<>(map);
+    }
+
+    private static void assertAuthorizationConfig(SecurityProvider securityProvider, String... adminPrincipals) {
+        AuthorizationConfiguration ac = securityProvider.getConfiguration(AuthorizationConfiguration.class);
+
+        assertTrue(ac.getParameters().containsKey("restrictionProvider"));
+        assertNotNull(ac.getRestrictionProvider());
+        assertEquals(ac.getParameters().get("restrictionProvider"), ac.getRestrictionProvider());
+
+        String[] found = ac.getParameters().getConfigValue("administrativePrincipals", new String[0]);
+        assertArrayEquals(adminPrincipals, found);
+    }
+
+    private static void assertUserConfig(SecurityProvider securityProvider, String... groupPrivilegeNames) {
+        UserConfiguration uc = securityProvider.getConfiguration(UserConfiguration.class);
+
+        assertTrue(uc.getParameters().containsKey("authorizableActionProvider"));
+        AuthorizableActionProvider ap = (AuthorizableActionProvider) uc.getParameters()
+                .get("authorizableActionProvider");
+        assertNotNull(ap);
+
+        List<AuthorizableAction> actionList = (List<AuthorizableAction>) ap.getAuthorizableActions(securityProvider);
+        assertEquals(1, actionList.size());
+        AuthorizableAction action = actionList.get(0);
+        assertTrue(action instanceof AccessControlAction);
+
+        // Changed implementation to use reflection to access private field
+        // before it was using Groovy advantages to access groupPrivilegeNames internal field
+        try {
+            Field privateField = AccessControlAction.class.getDeclaredField("groupPrivilegeNames");
+            privateField.setAccessible(true);
+            String[] privilegeNames = (String[]) privateField.get(action);
+            assertNotNull(privilegeNames);
+            assertArrayEquals(groupPrivilegeNames, privilegeNames);
+        } catch (IllegalAccessException | NoSuchFieldException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SegmentNodeStoreConfigTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SegmentNodeStoreConfigTest.java
new file mode 100644
index 0000000000..730ccf04fb
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SegmentNodeStoreConfigTest.java
@@ -0,0 +1,164 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.guava.common.collect.Maps;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SegmentNodeStoreConfigTest extends AbstractRepositoryFactoryTest {
+
+    private static final Logger log = LoggerFactory.getLogger(SegmentNodeStoreConfigTest.class);
+
+    @Test
+    public void testDeadlock() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config);
+
+        CountDownLatch deactivateLatch = new CountDownLatch(1);
+        CountDownLatch trackerLatch = new CountDownLatch(1);
+        CountDownLatch mainLatch = new CountDownLatch(1);
+        final NodeStoreTracker tracker = new NodeStoreTracker(registry.getBundleContext(),
+                trackerLatch,
+                deactivateLatch,
+                mainLatch);
+
+        //1. Get NodeStore created
+        createConfig(
+                Map.of("org.apache.jackrabbit.oak.segment.SegmentNodeStoreService",
+                        Map.of("cache", 256, "tarmk.mode", 32)));
+        getServiceWithWait(NodeStore.class);
+        assertNotNull(tracker.getStores());
+
+        final CountDownLatch allWellLatch = new CountDownLatch(1);
+        //4. Get roots and thus wait on latch holding the lock
+        // Create a new thread
+        new Thread(() -> {
+            tracker.getRoots();
+            allWellLatch.countDown();
+        }).start();
+
+        //3. Mutate the config. This results in NodeStore deactivate
+        //which first wait for nodeStoreLatch and then on NodeStoreTracker lock
+        createConfig(Map.of("org.apache.jackrabbit.oak.segment.SegmentNodeStoreService",
+                Map.of("cache", 200, "tarmk.mode", 32)));
+
+        //4. Wait for the "GetRoots" to indicate that it has acquired "trackerLock"
+        mainLatch.await();
+
+        Assert.assertNull("Deadlock detected", ManagementFactory.getThreadMXBean().findDeadlockedThreads());
+        //5. Let NodeStore deactivate thread proceed and wait for "trackerLock"
+        deactivateLatch.countDown();
+        log.info("Letting the deactivate call proceed");
+
+        //6. Let "GetRoots" thread proceed and make it fetch Root and thus wait for
+        //lock in SegmentNodeStoreService
+        trackerLatch.countDown();
+        log.info("Letting the getRoots call proceed");
+
+        Assert.assertNull("Deadlock detected", ManagementFactory.getThreadMXBean().findDeadlockedThreads());
+        allWellLatch.await();
+        tracker.close();
+    }
+
+    @Override
+    protected PojoServiceRegistry getRegistry() {
+        return registry;
+    }
+
+    private PojoServiceRegistry registry;
+
+    private static class NodeStoreTracker extends ServiceTracker<NodeStore, NodeStore> {
+
+        public NodeStoreTracker(BundleContext context, CountDownLatch trackerLatch, CountDownLatch deactivateLatch,
+                CountDownLatch mainLatch) {
+            super(context, NodeStore.class.getName(), null);
+            this.trackerLatch = trackerLatch;
+            this.deactivateLatch = deactivateLatch;
+            this.mainLatch = mainLatch;
+            super.open();
+        }
+
+        @Override
+        public void removedService(ServiceReference<NodeStore> reference, NodeStore service) {
+            try {
+                deactivateLatch.await();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+            synchronized (trackerLock) {
+                stores.remove(reference);
+            }
+
+            super.removedService(reference, service);
+        }
+
+        public List<NodeState> getRoots() {
+            List<NodeState> result = new ArrayList<NodeState>();
+            synchronized (trackerLock) {
+                mainLatch.countDown();
+                try {
+                    trackerLatch.await();
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+
+                for (NodeStore store : stores.values()) {
+                    try {
+                        result.add(store.getRoot());
+                    } catch (Exception e) {
+                        //Exception expected
+                        log.info("Exception expected", e);
+                    }
+
+                }
+
+            }
+
+            return result;
+        }
+
+        public List<NodeStore> getStores() {
+            List<NodeStore> result;
+            synchronized (trackerLock) {
+                result = new ArrayList<NodeStore>(stores.values());
+            }
+
+            return result;
+        }
+
+        private final Map<ServiceReference<NodeStore>, NodeStore> stores = Maps.newHashMap();
+        private final Object trackerLock = new Object();
+        private final CountDownLatch trackerLatch;
+        private final CountDownLatch deactivateLatch;
+        private final CountDownLatch mainLatch;
+    }
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SimpleRepositoryFactoryTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SimpleRepositoryFactoryTest.java
index 07e772a284..0c81652c72 100644
--- a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SimpleRepositoryFactoryTest.java
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/SimpleRepositoryFactoryTest.java
@@ -19,31 +19,27 @@
 
 package org.apache.jackrabbit.oak.run.osgi;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import java.io.File;
-import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
-
 import javax.jcr.Repository;
-
-import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FilenameUtils;
 import org.apache.jackrabbit.api.JackrabbitRepository;
 import org.apache.jackrabbit.commons.JcrUtils;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 
-import static org.junit.Assert.assertNotNull;
-
 public class SimpleRepositoryFactoryTest {
     @Rule
     public final TemporaryFolder tmpFolder = new TemporaryFolder(new File("target"));
 
     @Test(timeout = 60 * 1000)
     public void testRepositoryService() throws Exception{
-        Map<String,String> config = new HashMap<String, String>();
+        Map<String,String> config = new HashMap<>();
         config.put("org.apache.jackrabbit.repository.home",
                 tmpFolder.getRoot().getAbsolutePath());
         config.put("org.apache.jackrabbit.oak.repository.configFile",
@@ -66,9 +62,9 @@ public class SimpleRepositoryFactoryTest {
         return new File(".").getAbsolutePath();
     }
 
-    private static String path(String path){
+    private static String path(String path) {
         File file = new File(FilenameUtils.concat(getBaseDir(), "src/test/resources/"+path));
-        assert file.exists() : "No file found at " + file.getAbsolutePath();
+        assertTrue("No file found at " + file.getAbsolutePath(), file.exists());
         return file.getAbsolutePath();
     }
 }
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TarSegmentNodeStoreConfigTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TarSegmentNodeStoreConfigTest.java
new file mode 100644
index 0000000000..98fc86d933
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TarSegmentNodeStoreConfigTest.java
@@ -0,0 +1,66 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Map;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.ServiceRegistration;
+
+public class TarSegmentNodeStoreConfigTest extends AbstractRepositoryFactoryTest {
+
+    private static final String SEGMENT_TAR_BUNDLE_FILTER =
+            "(&(|(Bundle-SymbolicName=org.apache.jackrabbit*)(Bundle-SymbolicName=org.apache.sling*)"
+                    + "(Bundle-SymbolicName=org.apache.felix*)(Bundle-SymbolicName=org.apache.aries*)"
+                    + "(Bundle-SymbolicName=groovy-all))"
+                    + "(!(Bundle-SymbolicName=org.apache.jackrabbit.oak-segment)))";
+
+    private PojoServiceRegistry registry;
+
+
+    @Before
+    public void adjustConfig() {
+        config.put(OakOSGiRepositoryFactory.REPOSITORY_BUNDLE_FILTER, SEGMENT_TAR_BUNDLE_FILTER);
+        registry = repositoryFactory.initializeServiceRegistry(config);
+    }
+
+    @Override
+    protected PojoServiceRegistry getRegistry() {
+        return registry;
+    }
+
+    @Test
+    public void testDynamicBlobStore() {
+        createConfig(
+                Map.of("org.apache.jackrabbit.oak.segment.SegmentNodeStoreService",
+                        Map.of("customBlobStore", true)));
+        assertNull(registry.getServiceReference(NodeStore.class.getName()));
+        ServiceRegistration<?> registration = registry.registerService(BlobStore.class.getName(),
+                Mockito.mock(BlobStore.class),
+                null);
+        assertNotNull(getServiceWithWait(NodeStore.class));
+        registration.unregister();
+        assertNull(registry.getServiceReference(NodeStore.class.getName()));
+    }
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.java
new file mode 100644
index 0000000000..a408cb6dcd
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TokenAuthenticationTest.java
@@ -0,0 +1,168 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_CONFIG_FILE;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import javax.jcr.Credentials;
+import javax.jcr.SimpleCredentials;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import org.apache.felix.jaas.LoginModuleFactory;
+import org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule;
+import org.apache.jackrabbit.oak.spi.security.authentication.PreAuthenticatedLogin;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TokenAuthenticationTest extends AbstractRepositoryFactoryTest {
+
+    private static final Logger log = LoggerFactory.getLogger(TokenAuthenticationTest.class);
+
+    @Before
+    public void setupRepo() {
+        config.put(REPOSITORY_CONFIG_FILE, createConfigValue("oak-base-config.json", "oak-tar-config.json"));
+    }
+
+    @Test
+    public void tokenCreationWithPreAuth() throws Exception {
+        repository = repositoryFactory.getRepository(config);
+        getRegistry().registerService(LoginModuleFactory.class.getName(),
+                new PreAuthLoginModuleFactory(),
+                new Hashtable<>(Map.of(
+                        "jaas.controlFlag", "sufficient",
+                        "jaas.realmName", "jackrabbit.oak",
+                        "jaas.ranking", "150")));
+
+        MyCredential myCred = new MyCredential("admin");
+        repository.login(myCred);
+        assertNotNull(myCred.getAttribute(".token"));
+    }
+
+    private static class PreAuthLoginModuleFactory implements LoginModuleFactory {
+
+        @Override
+        public LoginModule createLoginModule() {
+            return new PreAuthLoginModule();
+        }
+
+    }
+
+    private static class PreAuthLoginModule extends AbstractLoginModule {
+
+        @NotNull
+        @Override
+        protected Set<Class> getSupportedCredentials() {
+            return Set.of(MyCredential.class);
+        }
+
+        @Override
+        public boolean login() throws LoginException {
+            Credentials credentials = getCredentials();
+            if (credentials instanceof MyCredential) {
+                credential = ((MyCredential) credentials);
+                String userId = credential.getUserID();
+                if (userId == null) {
+                    log.debug("Could not extract userId/credentials");
+                } else {
+                    SimpleCredentials sc = new SimpleCredentials(userId, new char[0]);
+                    sc.setAttribute(".token", "");
+
+                    // we just set the login name and rely on the following login modules to populate the subject
+                    sharedState.put(SHARED_KEY_PRE_AUTH_LOGIN, new PreAuthenticatedLogin(userId));
+                    sharedState.put(SHARED_KEY_CREDENTIALS, sc);
+                    sharedState.put(SHARED_KEY_LOGIN_NAME, userId);
+                    log.info("login succeeded with trusted user: {}", userId);
+                }
+
+            }
+
+            return false;
+        }
+
+        @Override
+        public boolean commit() throws LoginException {
+            Credentials sharedCreds = getSharedCredentials();
+            if (sharedCreds instanceof SimpleCredentials) {
+                credential.setAttribute(".token", ((SimpleCredentials) sharedCreds).getAttribute(".token"));
+            }
+
+            return false;
+        }
+
+        @Override
+        public boolean logout() {
+            return false;
+        }
+
+        private MyCredential credential;
+    }
+
+    private static class MyCredential implements Credentials {
+
+        private final String userID;
+        private final Map<String, Object> attributes = new HashMap<>();
+
+        public MyCredential(String userID) {
+            this.userID = userID;
+        }
+
+        public void setAttribute(String name, Object value) {
+            // name cannot be null
+            if (name == null) {
+                throw new IllegalArgumentException("name cannot be null");
+            }
+
+            // null value is the same as removeAttribute()
+            if (value == null) {
+                removeAttribute(name);
+                return;
+
+            }
+
+            synchronized (attributes) {
+                attributes.put(name, value);
+            }
+
+        }
+
+        public void removeAttribute(String name) {
+            synchronized (attributes) {
+                attributes.remove(name);
+            }
+
+        }
+
+        public Object getAttribute(String name) {
+            synchronized (attributes) {
+                return (attributes.get(name));
+            }
+
+        }
+
+        public final String getUserID() {
+            return userID;
+        }
+    }
+}
diff --git a/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TrackerSupportTest.java b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TrackerSupportTest.java
new file mode 100644
index 0000000000..4249a48844
--- /dev/null
+++ b/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/TrackerSupportTest.java
@@ -0,0 +1,63 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.apache.jackrabbit.oak.run.osgi;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.apache.felix.connect.launch.PojoServiceRegistry;
+import org.apache.felix.connect.launch.PojoServiceRegistryFactory;
+import org.junit.After;
+import org.junit.Test;
+import org.osgi.framework.BundleException;
+
+public class TrackerSupportTest {
+
+    private final PojoServiceRegistry reg = createServiceRegistry(new LinkedHashMap<>());
+
+    @After
+    public void tearDown() throws BundleException {
+        reg.getBundleContext().getBundle().stop();
+    }
+
+    @Test
+    public void runnableTest() throws Exception {
+        try (RunnableJobTracker runnableJobTracker = new RunnableJobTracker(reg.getBundleContext())) {
+
+            final CountDownLatch latch = new CountDownLatch(1);
+            Runnable runnable = latch::countDown;
+            reg.registerService(Runnable.class.getName(), runnable, new Hashtable<>(Map.of("scheduler.period", 1)));
+
+            //Wait for latch to get executed otherwise fail with timeout
+            assertTrue(latch.await(5, TimeUnit.SECONDS));
+        }
+    }
+
+    private PojoServiceRegistry createServiceRegistry(Map<String, Object> config) {
+        try {
+            ServiceLoader<PojoServiceRegistryFactory> loader = ServiceLoader.load(PojoServiceRegistryFactory.class);
+            return loader.iterator().next().newPojoServiceRegistry(config);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}