001/*
002 * Copyright 2016 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.camel.service;
017
018import static org.apache.camel.component.mock.MockEndpoint.assertIsSatisfied;
019import static org.apache.http.HttpStatus.SC_CREATED;
020import static org.apache.http.impl.client.HttpClients.createDefault;
021import static org.fcrepo.camel.FcrepoHeaders.FCREPO_BASE_URL;
022import static org.fcrepo.camel.FcrepoHeaders.FCREPO_IDENTIFIER;
023import static org.junit.Assert.assertEquals;
024import static org.junit.Assert.assertNotNull;
025import static org.junit.Assert.assertTrue;
026import static org.ops4j.pax.exam.CoreOptions.bundle;
027import static org.ops4j.pax.exam.CoreOptions.maven;
028import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
029import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
030import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features;
031import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
032import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
033import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
034import static org.ops4j.pax.exam.util.PathUtils.getBaseDir;
035import static org.osgi.framework.Bundle.ACTIVE;
036import static org.osgi.framework.Constants.OBJECTCLASS;
037import static org.osgi.framework.FrameworkUtil.createFilter;
038import static org.slf4j.LoggerFactory.getLogger;
039
040import java.io.File;
041import java.io.IOException;
042import java.util.HashMap;
043import java.util.Map;
044import javax.inject.Inject;
045
046import org.apache.camel.CamelContext;
047import org.apache.camel.ProducerTemplate;
048import org.apache.camel.component.mock.MockEndpoint;
049import org.apache.http.HttpResponse;
050import org.apache.http.client.methods.HttpPost;
051import org.apache.http.impl.client.CloseableHttpClient;
052import org.apache.http.util.EntityUtils;
053import org.apache.karaf.features.FeaturesService;
054import org.junit.Test;
055import org.junit.runner.RunWith;
056import org.ops4j.pax.exam.Configuration;
057import org.ops4j.pax.exam.ConfigurationManager;
058import org.ops4j.pax.exam.CoreOptions;
059import org.ops4j.pax.exam.Option;
060import org.ops4j.pax.exam.junit.PaxExam;
061import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
062import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
063import org.ops4j.pax.exam.spi.reactors.PerClass;
064import org.osgi.framework.BundleContext;
065import org.osgi.framework.InvalidSyntaxException;
066import org.osgi.util.tracker.ServiceTracker;
067import org.slf4j.Logger;
068
069/**
070 * @author Aaron Coburn
071 * @since July 21, 2016
072 */
073@RunWith(PaxExam.class)
074@ExamReactorStrategy(PerClass.class)
075public class KarafIT {
076
077    private final CloseableHttpClient httpclient = createDefault();
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() throws Exception {
088        final ConfigurationManager cm = new ConfigurationManager();
089        final String artifactName = cm.getProperty("project.artifactId") + "-" + cm.getProperty("project.version");
090        final String fcrepoServiceBundle = "file:" + getBaseDir() + "/target/" + artifactName + ".jar";
091        final String fcrepoPort = cm.getProperty("fcrepo.dynamic.test.port");
092        final String jmsPort = cm.getProperty("fcrepo.dynamic.jms.port");
093        final String rmiRegistryPort = cm.getProperty("karaf.rmiRegistry.port");
094        final String rmiServerPort = cm.getProperty("karaf.rmiServer.port");
095        final String sshPort = cm.getProperty("karaf.ssh.port");
096        return new Option[] {
097            karafDistributionConfiguration()
098                .frameworkUrl(maven().groupId("org.apache.karaf").artifactId("apache-karaf")
099                        .versionAsInProject().type("zip"))
100                .unpackDirectory(new File("target", "exam"))
101                .useDeployFolder(false),
102            logLevel(LogLevel.WARN),
103            keepRuntimeFolder(),
104            configureConsole().ignoreLocalConsole(),
105            features(maven().groupId("org.apache.karaf.features").artifactId("standard")
106                        .type("xml").classifier("features").versionAsInProject(), "scr"),
107            features(maven().groupId("org.apache.camel.karaf").artifactId("apache-camel")
108                        .type("xml").classifier("features").versionAsInProject(), "camel",
109                        "camel-blueprint"),
110            features(maven().groupId("org.fcrepo.camel").artifactId("fcrepo-camel")
111                        .type("xml").classifier("features").versionAsInProject(), "fcrepo-camel"),
112
113            CoreOptions.systemProperty("fcrepo.port").value(fcrepoPort),
114            CoreOptions.systemProperty("jms.port").value(jmsPort),
115            CoreOptions.systemProperty("fcrepo.service.bundle").value(fcrepoServiceBundle),
116
117            editConfigurationFilePut("etc/org.fcrepo.camel.service.cfg", "fcrepo.baseUrl",
118                    "http://localhost:" + fcrepoPort + "/fcrepo/rest"),
119
120            bundle(fcrepoServiceBundle).start(),
121
122            editConfigurationFilePut("etc/org.apache.karaf.management.cfg", "rmiRegistryPort", rmiRegistryPort),
123            editConfigurationFilePut("etc/org.apache.karaf.management.cfg", "rmiServerPort", rmiServerPort),
124            editConfigurationFilePut("etc/org.apache.karaf.shell.cfg", "sshPort", sshPort)
125       };
126    }
127
128    @Test
129    public void testInstallation() throws Exception {
130        assertTrue(featuresService.isInstalled(featuresService.getFeature("camel-core")));
131        assertTrue(featuresService.isInstalled(featuresService.getFeature("fcrepo-camel")));
132        assertNotNull(bundleContext);
133        assertEquals(ACTIVE,
134                bundleContext.getBundle(System.getProperty("fcrepo.service.bundle")).getState());
135    }
136
137    @Test
138    public void testService() throws Exception {
139        final String baseUrl = "http://localhost:" + System.getProperty("fcrepo.port") + "/fcrepo/rest";
140        final CamelContext ctx = getOsgiService(CamelContext.class,
141                "(camel.context.name=FcrepoService)", 10000);
142
143        assertNotNull(ctx);
144
145        final MockEndpoint resultEndpoint = (MockEndpoint) ctx.getEndpoint("mock:result");
146
147        final String url1 = post(baseUrl).replace(baseUrl, "");
148        final String url2 = post(baseUrl).replace(baseUrl, "");
149
150        final ProducerTemplate template = ctx.createProducerTemplate();
151        final Map<String, Object> headers = new HashMap<>();
152        headers.put(FCREPO_BASE_URL, baseUrl);
153        headers.put(FCREPO_IDENTIFIER, url1);
154        template.sendBodyAndHeaders(ctx.getEndpoint("direct:start"), null, headers);
155
156        headers.put(FCREPO_IDENTIFIER, url2);
157        template.sendBodyAndHeaders(ctx.getEndpoint("direct:start"), null, headers);
158
159        resultEndpoint.expectedMinimumMessageCount(2);
160        assertIsSatisfied(resultEndpoint);
161    }
162
163    private String post(final String url) {
164        try {
165            final HttpPost httppost = new HttpPost(url);
166            final HttpResponse response = httpclient.execute(httppost);
167            assertEquals(SC_CREATED, response.getStatusLine().getStatusCode());
168            return EntityUtils.toString(response.getEntity(), "UTF-8");
169        } catch (IOException ex) {
170            LOGGER.debug("Unable to extract HttpEntity response into an InputStream: ", ex);
171            return "";
172        }
173    }
174
175    private <T> T getOsgiService(final Class<T> type, final String filter, final long timeout) {
176        try {
177            final ServiceTracker tracker = new ServiceTracker(bundleContext,
178                    createFilter("(&(" + OBJECTCLASS + "=" + type.getName() + ")" + filter + ")"), null);
179            tracker.open(true);
180            final Object svc = type.cast(tracker.waitForService(timeout));
181            if (svc == null) {
182                throw new RuntimeException("Gave up waiting for service " + filter);
183            }
184            return type.cast(svc);
185        } catch (InvalidSyntaxException e) {
186            throw new IllegalArgumentException("Invalid filter", e);
187        } catch (InterruptedException e) {
188            throw new RuntimeException(e);
189        }
190    }
191}