/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed 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.kie.workbench.common.services.refactoring.backend.server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.io.FileUtils; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopScoreDocCollector; import org.guvnor.common.services.project.model.Package; import org.junit.AfterClass; import org.junit.BeforeClass; import org.kie.workbench.common.services.refactoring.backend.server.indexing.ImpactAnalysisAnalyzerWrapperFactory; import org.kie.workbench.common.services.shared.project.KieProject; import org.kie.workbench.common.services.shared.project.KieProjectService; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.uberfire.ext.metadata.backend.lucene.LuceneConfig; import org.uberfire.ext.metadata.backend.lucene.LuceneConfigBuilder; import org.uberfire.ext.metadata.backend.lucene.index.CustomAnalyzerWrapperFactory; import org.uberfire.ext.metadata.backend.lucene.index.LuceneIndex; import org.uberfire.ext.metadata.backend.lucene.index.LuceneIndexManager; import org.uberfire.ext.metadata.backend.lucene.util.KObjectUtil; import org.uberfire.ext.metadata.engine.Index; import org.uberfire.ext.metadata.io.IOServiceIndexedImpl; import org.uberfire.ext.metadata.io.IndexersFactory; import org.uberfire.ext.metadata.model.KObject; import org.uberfire.io.IOService; import org.uberfire.java.nio.file.Path; import org.uberfire.workbench.type.ResourceTypeDefinition; public abstract class IndexingTest<T extends ResourceTypeDefinition> { public static final String TEST_PROJECT_ROOT = "/a/mock/project/root"; public static final String TEST_PROJECT_NAME = "mock-project"; public static final String TEST_PACKAGE_NAME = "org.kie.workbench.mock.package"; protected static final Logger logger = LoggerFactory.getLogger(IndexingTest.class); protected static final List<File> tempFiles = new ArrayList<File>(); private static LuceneConfig config; private IOService ioService = null; @AfterClass @BeforeClass public static void cleanup() { for (final File tempFile : tempFiles) { FileUtils.deleteQuietly(tempFile); } if (config != null) { config.dispose(); config = null; } } protected static LuceneConfig getConfig() { return config; } protected static File createTempDirectory() throws IOException { final File temp = File.createTempFile("temp", Long.toString(System.nanoTime())); if (!(temp.delete())) { throw new IOException("Could not delete temp file: " + temp.getAbsolutePath()); } if (!(temp.mkdir())) { throw new IOException("Could not create temp directory: " + temp.getAbsolutePath()); } tempFiles.add(temp); return temp; } protected abstract TestIndexer<T> getIndexer(); protected abstract Map<String, Analyzer> getAnalyzers(); protected CustomAnalyzerWrapperFactory getAnalyzerWrapperFactory() { return ImpactAnalysisAnalyzerWrapperFactory.getInstance(); } protected abstract T getResourceTypeDefinition(); protected void loadProperties(final String fileName, final Path basePath) throws IOException { final Path path = basePath.resolve(fileName); final Properties properties = new Properties(); properties.load(this.getClass().getResourceAsStream(fileName)); ioService().write(path, propertiesToString(properties)); } protected String loadText(final String fileName) throws IOException { InputStream fileInputStream = this.getClass().getResourceAsStream(fileName); if (fileInputStream == null) { File file = new File(fileName); if (file.exists()) { fileInputStream = new FileInputStream(file); } } final BufferedReader br = new BufferedReader(new InputStreamReader(fileInputStream)); try { StringBuilder sb = new StringBuilder(); String line = br.readLine(); while (line != null) { sb.append(line); sb.append(System.getProperty("line.separator")); line = br.readLine(); } return sb.toString(); } finally { br.close(); } } protected String propertiesToString(final Properties properties) { final StringBuilder sb = new StringBuilder(); for (String name : properties.stringPropertyNames()) { sb.append(name).append("=").append(properties.getProperty(name)).append("\n"); } return sb.toString(); } protected IOService ioService() { if (ioService == null) { final Map<String, Analyzer> analyzers = getAnalyzers(); LuceneConfigBuilder configBuilder = new LuceneConfigBuilder() .withInMemoryMetaModelStore() .usingAnalyzers(analyzers) .usingAnalyzerWrapperFactory(getAnalyzerWrapperFactory()) .useInMemoryDirectory() // If you want to use Luke to inspect the index, // comment ".useInMemoryDirectory(), and uncomment below.. // .useNIODirectory() .useDirectoryBasedIndex(); if (config == null) { config = configBuilder.build(); } ioService = new IOServiceIndexedImpl(config.getIndexEngine()); final TestIndexer indexer = getIndexer(); IndexersFactory.clear(); IndexersFactory.addIndexer(indexer); //Mock CDI injection and setup indexer.setIOService(ioService); indexer.setProjectService(getProjectService()); indexer.setResourceTypeDefinition(getResourceTypeDefinition()); } return ioService; } public void dispose() { ioService().dispose(); ioService = null; } protected KieProjectService getProjectService() { final KieProject mockProject = getKieProjectMock(TEST_PROJECT_ROOT, TEST_PROJECT_NAME); final Package mockPackage = mock(Package.class); when(mockPackage.getPackageName()).thenReturn(TEST_PACKAGE_NAME); final KieProjectService mockProjectService = mock(KieProjectService.class); when(mockProjectService.resolveProject(any(org.uberfire.backend.vfs.Path.class))).thenReturn(mockProject); when(mockProjectService.resolvePackage(any(org.uberfire.backend.vfs.Path.class))).thenReturn(mockPackage); return mockProjectService; } protected KieProject getKieProjectMock(final String testProjectRoot, final String testProjectName) { final org.uberfire.backend.vfs.Path mockRoot = mock(org.uberfire.backend.vfs.Path.class); when(mockRoot.toURI()).thenReturn(testProjectRoot); final KieProject mockProject = mock(KieProject.class); when(mockProject.getRootPath()).thenReturn(mockRoot); when(mockProject.getProjectName()).thenReturn(testProjectName); return mockProject; } protected void assertContains(final List<KObject> results, final Path path) { for (KObject kObject : results) { final String key = kObject.getKey(); final String fileName = path.getFileName().toString(); if (key.endsWith(fileName)) { return; } } fail("Results do not contain expected Path '" + path.toUri().toString()); } public void searchFor(Index index, Query query, int expectedNumHits, Path... paths) throws IOException { final IndexSearcher searcher = ((LuceneIndex) index).nrtSearcher(); searchFor(searcher, query, expectedNumHits, paths); } public void searchFor(Query query, int expectedNumHits) throws IOException { final IndexSearcher searcher = ((LuceneIndexManager) getConfig().getIndexManager()).getIndexSearcher(); searchFor(searcher, query, expectedNumHits); } private void searchFor(IndexSearcher searcher, Query query, int expectedNumHits, Path... paths) throws IOException { try { final TopScoreDocCollector collector = TopScoreDocCollector.create(10 > expectedNumHits ? 10 : expectedNumHits); searcher.search(query, collector); final ScoreDoc[] hits = collector.topDocs().scoreDocs; assertEquals("Number of docs fulfilling the given query criteria", expectedNumHits, hits.length); if (paths != null && paths.length > 0) { final List<KObject> results = new ArrayList<KObject>(); for (int i = 0; i < hits.length; i++) { results.add(KObjectUtil.toKObject(searcher.doc(hits[i].doc))); } for (Path path : paths) { assertContains(results, path); } } } finally { ((LuceneIndexManager) getConfig().getIndexManager()).release(searcher); } } }