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);
+ }
+ }
+}