blob: 7f72acf9292c1daff983bd1bccd2c0504e4a70a7 [file] [log] [blame]
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ 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);
}
}