| /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| ~ 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.sling.capabilities.jcr; |
| |
| import java.io.IOException; |
| import java.math.BigDecimal; |
| import java.util.Dictionary; |
| import java.util.Hashtable; |
| import java.util.Map; |
| import java.util.UUID; |
| import javax.inject.Inject; |
| import javax.jcr.Node; |
| import javax.jcr.Session; |
| import org.apache.sling.capabilities.CapabilitiesSource; |
| import org.apache.sling.jcr.api.SlingRepository; |
| import org.apache.sling.serviceusermapping.ServiceUserMapped; |
| import org.apache.sling.testing.mock.osgi.ReferenceViolationException; |
| import org.apache.sling.testing.mock.sling.ResourceResolverType; |
| import org.apache.sling.testing.mock.sling.junit.SlingContext; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.osgi.service.cm.Configuration; |
| import org.osgi.service.cm.ConfigurationAdmin; |
| |
| public class SearchSourceTest { |
| |
| @Rule |
| public final SlingContext context = new SlingContext(ResourceResolverType.JCR_OAK); |
| |
| private static final String SIMILARITY_ACTIVE_CAP = "similarity.search.active"; |
| |
| private CapabilitiesSource searchSource; |
| |
| private Dictionary<String, Object> props(Object ... nameValuePairs) { |
| final Dictionary<String, Object> props = new Hashtable<>(); |
| for(int i=0 ; i < nameValuePairs.length; i+=2) { |
| props.put(nameValuePairs[i].toString(), nameValuePairs[i+1]); |
| } |
| return props; |
| } |
| |
| private void registerSearchSource(boolean withServiceUserMapped, Object ... configNameValuePairs) throws IOException { |
| final ConfigurationAdmin ca = context.getService(ConfigurationAdmin.class); |
| assertNotNull("Expecting a ConfigurationAdmin service", ca); |
| final Configuration cfg = ca.getConfiguration(SearchSource.class.getName()); |
| cfg.update(props(configNameValuePairs)); |
| |
| if(withServiceUserMapped) { |
| final ServiceUserMapped sum = new ServiceUserMapped() {}; |
| context.registerService(ServiceUserMapped.class, sum, |
| props(ServiceUserMapped.SUBSERVICENAME, SearchSource.SUBSERVICE_NAME)); |
| } |
| |
| final SearchSource ss = new SearchSource(); |
| context.registerInjectActivateService(ss); |
| |
| searchSource = context.getService(CapabilitiesSource.class); |
| assertNotNull("Expecting our SearchSource to be registered", searchSource); |
| assertEquals("Expecting the SearchSource namespace", SearchSource.NAMESPACE, searchSource.getNamespace()); |
| } |
| |
| private void createMockIndexNode(String parentPath, String path, String propertyName, boolean value) throws Exception { |
| final SlingRepository repository = context.getService(SlingRepository.class); |
| assertNotNull("Expecting a SlingRepository", repository); |
| final Session s = repository.loginAdministrative(null); |
| try { |
| final Node n = s.getNode(parentPath).addNode(path); |
| n.setProperty(propertyName, value); |
| s.save(); |
| } finally { |
| s.logout(); |
| } |
| } |
| |
| @Test |
| public void testNoSimilarity() throws Exception { |
| registerSearchSource(true); |
| assertNotNull(searchSource.getCapabilities()); |
| assertEquals("false", searchSource.getCapabilities().get(SIMILARITY_ACTIVE_CAP)); |
| } |
| |
| @Test |
| public void testHasSimilarity() throws Exception { |
| registerSearchSource(true); |
| createMockIndexNode("/oak:index", "foo", "useInSimilarity", true); |
| |
| assertNotNull(searchSource.getCapabilities()); |
| assertEquals("true", searchSource.getCapabilities().get(SIMILARITY_ACTIVE_CAP)); |
| } |
| |
| @Test(expected=ReferenceViolationException.class) |
| public void testNoServiceUserMapped() throws Exception { |
| registerSearchSource(false); |
| } |
| |
| @Test |
| public void testCustomQueryAndCacheLifetime() throws Exception { |
| final int lifetimeSeconds = 2; |
| final String uniquePath = "testCustomQuery_" + UUID.randomUUID(); |
| registerSearchSource( |
| true, |
| "similarityIndexQuery", "/jcr:root/" + uniquePath, |
| "cacheLifetimeSeconds", lifetimeSeconds); |
| |
| // With our custom query we get false first |
| assertNotNull(searchSource.getCapabilities()); |
| assertEquals("false", searchSource.getCapabilities().get(SIMILARITY_ACTIVE_CAP)); |
| |
| // Create a node that causes the query to return something |
| // The capability value will change after some time, once its cache expires |
| createMockIndexNode("/", uniquePath, "someProperty", true); |
| |
| // Must get a few false results and then true, once the cache expires |
| // (might fail if the box running this test is very very slow) |
| int nFalse = 0; |
| int nTrue = 0; |
| final long testEnd = System.currentTimeMillis() + lifetimeSeconds * 1000L + 1500L; |
| while(System.currentTimeMillis() < testEnd) { |
| final Object value = searchSource.getCapabilities().get(SIMILARITY_ACTIVE_CAP); |
| if("false".equals(value)) { |
| assertEquals("Expecting true value to come after all false values", 0, nTrue); |
| nFalse++; |
| } else { |
| nTrue++; |
| } |
| Thread.sleep(100L); |
| } |
| |
| assertTrue("Expecting a few true values", nTrue > 0); |
| assertTrue("Expecting a few false values", nTrue > 0); |
| } |
| } |