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.service;
019
020import static org.apache.camel.component.mock.MockEndpoint.assertIsSatisfied;
021import static org.apache.http.HttpStatus.SC_CREATED;
022import static org.fcrepo.camel.FcrepoHeaders.FCREPO_BASE_URL;
023import static org.fcrepo.camel.FcrepoHeaders.FCREPO_IDENTIFIER;
024import static org.fcrepo.camel.FcrepoHeaders.FCREPO_URI;
025import static org.junit.Assert.assertEquals;
026import static org.junit.Assert.assertNotNull;
027import static org.junit.Assert.assertTrue;
028import static org.ops4j.pax.exam.CoreOptions.bundle;
029import static org.ops4j.pax.exam.CoreOptions.maven;
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.io.IOException;
044import java.util.HashMap;
045import java.util.Map;
046import javax.inject.Inject;
047
048import org.apache.camel.CamelContext;
049import org.apache.camel.ProducerTemplate;
050import org.apache.camel.component.mock.MockEndpoint;
051import org.apache.http.HttpResponse;
052import org.apache.http.auth.AuthScope;
053import org.apache.http.auth.UsernamePasswordCredentials;
054import org.apache.http.client.methods.HttpPost;
055import org.apache.http.impl.client.BasicCredentialsProvider;
056import org.apache.http.impl.client.CloseableHttpClient;
057import org.apache.http.impl.client.HttpClients;
058import org.apache.http.util.EntityUtils;
059import org.apache.karaf.features.FeaturesService;
060import org.junit.Test;
061import org.junit.runner.RunWith;
062import org.ops4j.pax.exam.Configuration;
063import org.ops4j.pax.exam.ConfigurationManager;
064import org.ops4j.pax.exam.CoreOptions;
065import org.ops4j.pax.exam.Option;
066import org.ops4j.pax.exam.junit.PaxExam;
067import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
068import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
069import org.ops4j.pax.exam.spi.reactors.PerClass;
070import org.osgi.framework.BundleContext;
071import org.osgi.framework.InvalidSyntaxException;
072import org.osgi.util.tracker.ServiceTracker;
073import org.slf4j.Logger;
074
075/**
076 * @author Aaron Coburn
077 * @since July 21, 2016
078 */
079@RunWith(PaxExam.class)
080@ExamReactorStrategy(PerClass.class)
081public class KarafIT {
082
083    private final static String FEDORA_USERNAME = "fedoraAdmin";
084
085    private final static String FEDORA_PASSWORD = "fedoraAdmin";
086
087    private final BasicCredentialsProvider provider = new BasicCredentialsProvider();
088
089    private final CloseableHttpClient httpclient;
090
091    private static Logger LOGGER = getLogger(KarafIT.class);
092
093    @Inject
094    protected FeaturesService featuresService;
095
096    @Inject
097    protected BundleContext bundleContext;
098
099    public KarafIT() {
100        provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(FEDORA_USERNAME, FEDORA_PASSWORD));
101        httpclient = HttpClients.custom().setDefaultCredentialsProvider(provider).build();
102    }
103
104    @Configuration
105    public Option[] config() throws Exception {
106        final ConfigurationManager cm = new ConfigurationManager();
107        final String artifactName = cm.getProperty("project.artifactId") + "-" + cm.getProperty("project.version");
108        final String fcrepoServiceBundle = "file:" + getBaseDir() + "/target/" + artifactName + ".jar";
109        final String fcrepoPort = cm.getProperty("fcrepo.dynamic.test.port");
110        final String jmsPort = cm.getProperty("fcrepo.dynamic.jms.port");
111        final String rmiRegistryPort = cm.getProperty("karaf.rmiRegistry.port");
112        final String rmiServerPort = cm.getProperty("karaf.rmiServer.port");
113        final String sshPort = cm.getProperty("karaf.ssh.port");
114        return new Option[] {
115            karafDistributionConfiguration()
116                .frameworkUrl(maven().groupId("org.apache.karaf").artifactId("apache-karaf")
117                        .versionAsInProject().type("zip"))
118                .unpackDirectory(new File("target", "exam"))
119                .useDeployFolder(false),
120            logLevel(LogLevel.WARN),
121            keepRuntimeFolder(),
122            configureConsole().ignoreLocalConsole(),
123            features(maven().groupId("org.apache.karaf.features").artifactId("standard")
124                        .type("xml").classifier("features").versionAsInProject(), "scr"),
125            features(maven().groupId("org.apache.camel.karaf").artifactId("apache-camel")
126                        .type("xml").classifier("features").versionAsInProject(), "camel",
127                        "camel-blueprint", "camel-jackson"),
128            features(maven().groupId("org.fcrepo.camel").artifactId("fcrepo-camel")
129                        .type("xml").classifier("features").versionAsInProject(), "fcrepo-camel"),
130
131            CoreOptions.systemProperty("fcrepo.port").value(fcrepoPort),
132            CoreOptions.systemProperty("jms.port").value(jmsPort),
133            CoreOptions.systemProperty("fcrepo.service.bundle").value(fcrepoServiceBundle),
134
135            editConfigurationFilePut("etc/org.fcrepo.camel.service.cfg", "fcrepo.baseUrl",
136                    "http://localhost:" + fcrepoPort + "/fcrepo/rest"),
137            editConfigurationFilePut("etc/org.fcrepo.camel.service.cfg", "fcrepo.authUsername",
138                    FEDORA_USERNAME),
139            editConfigurationFilePut("etc/org.fcrepo.camel.service.cfg", "fcrepo.authPassword",
140                    FEDORA_PASSWORD),
141
142            bundle(fcrepoServiceBundle).start(),
143
144            editConfigurationFilePut("etc/org.apache.karaf.management.cfg", "rmiRegistryPort", rmiRegistryPort),
145            editConfigurationFilePut("etc/org.apache.karaf.management.cfg", "rmiServerPort", rmiServerPort),
146            editConfigurationFilePut("etc/org.apache.karaf.shell.cfg", "sshPort", sshPort)
147       };
148    }
149
150    @Test
151    public void testInstallation() throws Exception {
152        assertTrue(featuresService.isInstalled(featuresService.getFeature("camel-core")));
153        assertTrue(featuresService.isInstalled(featuresService.getFeature("fcrepo-camel")));
154        assertNotNull(bundleContext);
155        assertEquals(ACTIVE,
156                bundleContext.getBundle(System.getProperty("fcrepo.service.bundle")).getState());
157    }
158
159    @Test
160    public void testService() throws Exception {
161        final String baseUrl = "http://localhost:" + System.getProperty("fcrepo.port") + "/fcrepo/rest";
162        final CamelContext ctx = getOsgiService(CamelContext.class,
163                "(camel.context.name=FcrepoService)", 10000);
164
165        assertNotNull(ctx);
166
167        final MockEndpoint resultEndpoint = (MockEndpoint) ctx.getEndpoint("mock:result");
168
169        final String url1 = post(baseUrl).replace(baseUrl, "");
170        final String url2 = post(baseUrl).replace(baseUrl, "");
171
172        final ProducerTemplate template = ctx.createProducerTemplate();
173        final Map<String, Object> headers = new HashMap<>();
174        headers.put(FCREPO_BASE_URL, baseUrl);
175        headers.put(FCREPO_IDENTIFIER, url1);
176        template.sendBodyAndHeaders(ctx.getEndpoint("direct:start"), null, headers);
177
178        template.sendBodyAndHeader(ctx.getEndpoint("direct:start"), null, FCREPO_URI, baseUrl + url2);
179
180        resultEndpoint.expectedMinimumMessageCount(2);
181        assertIsSatisfied(resultEndpoint);
182    }
183
184    private String post(final String url) {
185        try {
186            final HttpPost httppost = new HttpPost(url);
187            final HttpResponse response = httpclient.execute(httppost);
188            assertEquals(SC_CREATED, response.getStatusLine().getStatusCode());
189            return EntityUtils.toString(response.getEntity(), "UTF-8");
190        } catch (final IOException ex) {
191            LOGGER.debug("Unable to extract HttpEntity response into an InputStream: ", ex);
192            return "";
193        }
194    }
195
196    private <T> T getOsgiService(final Class<T> type, final String filter, final long timeout) {
197        try {
198            final ServiceTracker tracker = new ServiceTracker(bundleContext,
199                    createFilter("(&(" + OBJECTCLASS + "=" + type.getName() + ")" + filter + ")"), null);
200            tracker.open(true);
201            final Object svc = type.cast(tracker.waitForService(timeout));
202            if (svc == null) {
203                throw new RuntimeException("Gave up waiting for service " + filter);
204            }
205            return type.cast(svc);
206        } catch (final InvalidSyntaxException e) {
207            throw new IllegalArgumentException("Invalid filter", e);
208        } catch (final InterruptedException e) {
209            throw new RuntimeException(e);
210        }
211    }
212}