001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.camel.karaf;
019
020import static java.net.URI.create;
021import static org.apache.camel.component.mock.MockEndpoint.assertIsSatisfied;
022import static org.apache.http.HttpStatus.SC_OK;
023import static org.apache.http.impl.client.HttpClients.createDefault;
024import static org.junit.Assert.assertEquals;
025import static org.junit.Assert.assertNotNull;
026import static org.junit.Assert.assertTrue;
027import static org.ops4j.pax.exam.CoreOptions.bundle;
028import static org.ops4j.pax.exam.CoreOptions.maven;
029import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
030import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
031import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
032import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features;
033import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
034import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
035import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
036import static org.ops4j.pax.exam.util.PathUtils.getBaseDir;
037import static org.osgi.framework.Bundle.ACTIVE;
038import static org.osgi.framework.Constants.OBJECTCLASS;
039import static org.osgi.framework.FrameworkUtil.createFilter;
040import static org.slf4j.LoggerFactory.getLogger;
041
042import java.io.File;
043import java.net.URI;
044import javax.inject.Inject;
045
046import org.apache.camel.CamelContext;
047import org.apache.camel.component.mock.MockEndpoint;
048import org.apache.http.client.methods.CloseableHttpResponse;
049import org.apache.http.client.methods.HttpGet;
050import org.apache.http.client.methods.HttpPost;
051import org.apache.http.entity.StringEntity;
052import org.apache.http.impl.client.CloseableHttpClient;
053import org.apache.karaf.features.FeaturesService;
054import org.fcrepo.client.FcrepoClient;
055import org.junit.Test;
056import org.junit.runner.RunWith;
057import org.ops4j.pax.exam.Configuration;
058import org.ops4j.pax.exam.ConfigurationManager;
059import org.ops4j.pax.exam.CoreOptions;
060import org.ops4j.pax.exam.Option;
061import org.ops4j.pax.exam.junit.PaxExam;
062import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
063import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
064import org.ops4j.pax.exam.spi.reactors.PerClass;
065import org.osgi.framework.BundleContext;
066import org.osgi.framework.InvalidSyntaxException;
067import org.osgi.util.tracker.ServiceTracker;
068import org.slf4j.Logger;
069
070/**
071 * @author Aaron Coburn
072 * @since February 8, 2016
073 */
074@RunWith(PaxExam.class)
075@ExamReactorStrategy(PerClass.class)
076public class KarafIT {
077
078    private static Logger LOGGER = getLogger(KarafIT.class);
079
080    @Inject
081    protected FeaturesService featuresService;
082
083    @Inject
084    protected BundleContext bundleContext;
085
086    @Configuration
087    public Option[] config() {
088        final ConfigurationManager cm = new ConfigurationManager();
089        final String fcrepoPort = cm.getProperty("fcrepo.dynamic.test.port");
090        final String jmsPort = cm.getProperty("fcrepo.dynamic.jms.port");
091        final String reindexingPort = cm.getProperty("fcrepo.dynamic.reindexing.port");
092        final String rmiRegistryPort = cm.getProperty("karaf.rmiRegistry.port");
093        final String rmiServerPort = cm.getProperty("karaf.rmiServer.port");
094        final String sshPort = cm.getProperty("karaf.ssh.port");
095        final String fcrepoBaseUrl = "localhost:" + fcrepoPort + "/fcrepo/rest";
096
097        final String version = cm.getProperty("project.version");
098        final String fcrepoAudit = getBundleUri("fcrepo-audit-triplestore", version);
099        final String fcrepoFixity = getBundleUri("fcrepo-fixity", version);
100        final String fcrepoReindexing = getBundleUri("fcrepo-reindexing", version);
101        final String fcrepoSerialization = getBundleUri("fcrepo-serialization", version);
102        final String fcrepoIndexingSolr = getBundleUri("fcrepo-indexing-solr", version);
103        final String fcrepoIndexingTriplestore = getBundleUri("fcrepo-indexing-triplestore", version);
104        final String fcrepoServiceAmq = getBundleUri("fcrepo-service-activemq", version);
105        final String fcrepoService = getBundleUri("fcrepo-service-camel", version);
106
107        return new Option[] {
108            karafDistributionConfiguration()
109                .frameworkUrl(maven().groupId("org.apache.karaf").artifactId("apache-karaf")
110                        .versionAsInProject().type("zip"))
111                .unpackDirectory(new File("target", "exam"))
112                .useDeployFolder(false),
113            logLevel(LogLevel.WARN),
114            keepRuntimeFolder(),
115            configureConsole().ignoreLocalConsole(),
116            features(maven().groupId("org.apache.karaf.features").artifactId("standard")
117                        .versionAsInProject().classifier("features").type("xml"), "scr"),
118            features(maven().groupId("org.apache.camel.karaf").artifactId("apache-camel")
119                        .type("xml").classifier("features").versionAsInProject(), "camel-mustache",
120                        "camel-blueprint", "camel-http4", "camel-spring", "camel-exec", "camel-jetty9",
121                        "camel-jacksonxml"),
122            features(maven().groupId("org.apache.activemq").artifactId("activemq-karaf")
123                        .type("xml").classifier("features").versionAsInProject(), "activemq-camel"),
124            features(maven().groupId("org.fcrepo.camel").artifactId("fcrepo-camel")
125                        .type("xml").classifier("features").versionAsInProject(), "fcrepo-camel"),
126            mavenBundle().groupId("org.codehaus.woodstox").artifactId("woodstox-core-asl").versionAsInProject(),
127
128            CoreOptions.systemProperty("o.f.c.serialization-bundle").value(fcrepoSerialization),
129            CoreOptions.systemProperty("o.f.c.fixity-bundle").value(fcrepoFixity),
130            CoreOptions.systemProperty("o.f.c.reindexing-bundle").value(fcrepoReindexing),
131            CoreOptions.systemProperty("o.f.c.a.triplestore-bundle").value(fcrepoAudit),
132            CoreOptions.systemProperty("o.f.c.i.triplestore-bundle").value(fcrepoIndexingTriplestore),
133            CoreOptions.systemProperty("o.f.c.i.solr-bundle").value(fcrepoIndexingSolr),
134            CoreOptions.systemProperty("o.f.c.s.activemq-bundle").value(fcrepoServiceAmq),
135            CoreOptions.systemProperty("o.f.c.s.camel-bundle").value(fcrepoService),
136
137            bundle(fcrepoAudit).start(),
138            bundle(fcrepoIndexingSolr).start(),
139            bundle(fcrepoIndexingTriplestore).start(),
140            bundle(fcrepoFixity).start(),
141            bundle(fcrepoSerialization).start(),
142            bundle(fcrepoReindexing).start(),
143            bundle(fcrepoServiceAmq).start(),
144            bundle(fcrepoService).start(),
145
146            CoreOptions.systemProperty("fcrepo.port").value(fcrepoPort),
147            CoreOptions.systemProperty("karaf.reindexing.port").value(reindexingPort),
148            editConfigurationFilePut("etc/org.apache.karaf.management.cfg", "rmiRegistryPort", rmiRegistryPort),
149            editConfigurationFilePut("etc/org.apache.karaf.management.cfg", "rmiServerPort", rmiServerPort),
150            editConfigurationFilePut("etc/org.apache.karaf.shell.cfg", "sshPort", sshPort),
151            editConfigurationFilePut("etc/org.fcrepo.camel.serialization.cfg", "serialization.descriptions",
152                    "data/tmp/descriptions"),
153            editConfigurationFilePut("etc/org.fcrepo.camel.reindexing.cfg", "rest.port", reindexingPort),
154            editConfigurationFilePut("etc/org.fcrepo.camel.service.cfg", "fcrepo.baseUrl", fcrepoBaseUrl),
155            editConfigurationFilePut("etc/org.fcrepo.camel.service.activemq.cfg", "jms.brokerUrl",
156                    "tcp://localhost:" + jmsPort)
157       };
158    }
159
160
161    @Test
162    public void testInstallation() throws Exception {
163
164        assertTrue(featuresService.isInstalled(featuresService.getFeature("camel-core")));
165        assertTrue(featuresService.isInstalled(featuresService.getFeature("fcrepo-camel")));
166        assertTrue(featuresService.isInstalled(featuresService.getFeature("activemq-camel")));
167        assertTrue(featuresService.isInstalled(featuresService.getFeature("camel-blueprint")));
168        assertTrue(featuresService.isInstalled(featuresService.getFeature("camel-http4")));
169        assertTrue(featuresService.isInstalled(featuresService.getFeature("camel-jetty9")));
170        assertNotNull(bundleContext);
171
172        assertEquals(ACTIVE, bundleContext.getBundle(System.getProperty("o.f.c.serialization-bundle")).getState());
173        assertEquals(ACTIVE, bundleContext.getBundle(System.getProperty("o.f.c.fixity-bundle")).getState());
174        assertEquals(ACTIVE, bundleContext.getBundle(System.getProperty("o.f.c.reindexing-bundle")).getState());
175        assertEquals(ACTIVE, bundleContext.getBundle(System.getProperty("o.f.c.i.solr-bundle")).getState());
176        assertEquals(ACTIVE, bundleContext.getBundle(System.getProperty("o.f.c.i.triplestore-bundle")).getState());
177        assertEquals(ACTIVE, bundleContext.getBundle(System.getProperty("o.f.c.s.activemq-bundle")).getState());
178        assertEquals(ACTIVE, bundleContext.getBundle(System.getProperty("o.f.c.s.camel-bundle")).getState());
179    }
180
181    @Test
182    public void testReindexingService() throws Exception {
183        final CamelContext ctx = getOsgiService(CamelContext.class, "(camel.context.name=FcrepoIndexer)", 10000);
184        assertNotNull(ctx);
185
186        // We aren't running solr or a triplestore, so stop these to prevent
187        // unnecessary errors.
188        bundleContext.getBundle(System.getProperty("o.f.c.i.solr-bundle")).stop();
189        bundleContext.getBundle(System.getProperty("o.f.c.i.triplestore-bundle")).stop();
190        bundleContext.getBundle(System.getProperty("o.f.c.a.triplestore-bundle")).stop();
191
192        final FcrepoClient fcrepoClient = new FcrepoClient(null, null, null, true);
193        final URI baseUrl = create("http://localhost:" + System.getProperty("fcrepo.port") + "/fcrepo/rest");
194        final URI url1 = fcrepoClient.post(baseUrl, null, null).getLocation();
195        final URI url2 = fcrepoClient.post(baseUrl, null, null).getLocation();
196        fcrepoClient.post(url1, null, null);
197        fcrepoClient.post(url2, null, null);
198
199        final MockEndpoint resultEndpoint = (MockEndpoint) ctx.getEndpoint("mock:results");
200        resultEndpoint.expectedMessageCount(5);
201
202        final CloseableHttpClient client = createDefault();
203        final String reindexingUrl = "http://localhost:" + System.getProperty("karaf.reindexing.port") + "/reindexing/";
204        try (final CloseableHttpResponse response = client.execute(new HttpGet(reindexingUrl))) {
205            assertEquals(SC_OK, response.getStatusLine().getStatusCode());
206        }
207
208        final HttpPost post = new HttpPost(reindexingUrl);
209        post.addHeader("Content-Type", "application/json");
210        post.setEntity(new StringEntity("[\"mock:results\"]"));
211        try (final CloseableHttpResponse response = client.execute(post)) {
212            assertEquals(SC_OK, response.getStatusLine().getStatusCode());
213        }
214
215        assertIsSatisfied(resultEndpoint);
216    }
217
218    private <T> T getOsgiService(final Class<T> type, final String filter, final long timeout) {
219        try {
220            final ServiceTracker tracker = new ServiceTracker(bundleContext,
221                    createFilter("(&(" + OBJECTCLASS + "=" + type.getName() + ")" + filter + ")"), null);
222            tracker.open(true);
223            final Object svc = type.cast(tracker.waitForService(timeout));
224            if (svc == null) {
225                throw new RuntimeException("Gave up waiting for service " + filter);
226            }
227            return type.cast(svc);
228        } catch (InvalidSyntaxException e) {
229            throw new IllegalArgumentException("Invalid filter", e);
230        } catch (InterruptedException e) {
231            throw new RuntimeException(e);
232        }
233    }
234
235    private static String getBundleUri(final String artifactId, final String version) {
236        final File artifact = new File(getBaseDir() + "/../" + artifactId + "/target/" +
237                artifactId + "-" + version + ".jar");
238        if (artifact.exists()) {
239            return artifact.toURI().toString();
240        }
241        return "mvn:org.fcrepo.camel/" + artifactId + "/" + version;
242    }
243
244}