001/**
002 * Copyright 2015 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;
017
018import static org.apache.commons.lang3.StringUtils.normalizeSpace;
019import static org.fcrepo.camel.integration.FcrepoTestUtils.getFcrepoEndpointUri;
020import static org.fcrepo.camel.integration.FcrepoTestUtils.getN3Document;
021import static org.fcrepo.camel.integration.FcrepoTestUtils.getTurtleDocument;
022import static java.net.URLEncoder.encode;
023
024import java.io.IOException;
025import java.util.HashMap;
026import java.util.Map;
027
028import org.apache.camel.EndpointInject;
029import org.apache.camel.Exchange;
030import org.apache.camel.Processor;
031import org.apache.camel.Produce;
032import org.apache.camel.ProducerTemplate;
033import org.apache.camel.builder.RouteBuilder;
034import org.apache.camel.component.mock.MockEndpoint;
035import org.apache.camel.test.junit4.CamelTestSupport;
036import org.fcrepo.camel.processor.SparqlUpdateProcessor;
037import org.junit.Test;
038
039/**
040 * Test adding a non-RDF resource
041 * @author Aaron Coburn
042 * @since November 7, 2014
043 */
044public class SparqlUpdateProcessorTest extends CamelTestSupport {
045
046    @EndpointInject(uri = "mock:result")
047    protected MockEndpoint resultEndpoint;
048
049    @Produce(uri = "direct:start")
050    protected ProducerTemplate template;
051
052    @Test
053    public void testNamedGraph() throws IOException, InterruptedException {
054        final String base = "http://localhost/rest";
055        final String path = "/path/a/b/c";
056        final String graph = "foo";
057        final String document = getN3Document();
058        // Reverse the lines as the RDF may be serialized in opposite order
059
060        final String responsePrefix =
061              "DELETE WHERE { GRAPH <" + graph + "> { <" + base + path + "> ?p ?o } };\n" +
062              "DELETE WHERE { GRAPH <" + graph + "> { <" + base + path + "/fcr:export?format=jcr/xml> ?p ?o } };\n" +
063              "INSERT DATA { GRAPH <" + graph + "> { ";
064        final String responseSuffix = "\n} }";
065
066        // Assertions
067        resultEndpoint.allMessages().body().startsWith("update=" + encode(responsePrefix, "UTF-8"));
068        resultEndpoint.allMessages().body().endsWith(encode(responseSuffix, "UTF-8"));
069        for (final String s : document.split("\n")) {
070            resultEndpoint.expectedBodyReceived().body().contains(encode(s, "UTF-8"));
071        }
072        resultEndpoint.expectedBodyReceived().body().contains(
073                encode("<" + base + path + "> dc:title \"some title\" .", "UTF-8"));
074        resultEndpoint.expectedHeaderReceived("Content-Type", "application/x-www-form-urlencoded");
075        resultEndpoint.expectedHeaderReceived(Exchange.HTTP_METHOD, "POST");
076
077        // Test
078        final Map<String, Object> headers = new HashMap<>();
079        headers.put(FcrepoHeaders.FCREPO_BASE_URL, base + "/");
080        headers.put(FcrepoHeaders.FCREPO_IDENTIFIER, path);
081        headers.put(FcrepoHeaders.FCREPO_NAMED_GRAPH, graph);
082        headers.put(Exchange.CONTENT_TYPE, "application/n-triples");
083        template.sendBodyAndHeaders(document, headers);
084
085        headers.clear();
086        headers.put(JmsHeaders.BASE_URL, base + "/");
087        headers.put(JmsHeaders.IDENTIFIER, path);
088        headers.put(FcrepoHeaders.FCREPO_NAMED_GRAPH, graph);
089        headers.put(Exchange.CONTENT_TYPE, "text/turtle");
090        template.sendBodyAndHeaders(getTurtleDocument(), headers);
091
092        headers.clear();
093        headers.put(JmsHeaders.BASE_URL, base);
094        headers.put(FcrepoHeaders.FCREPO_IDENTIFIER, path);
095        headers.put(FcrepoHeaders.FCREPO_NAMED_GRAPH, graph);
096        headers.put(Exchange.CONTENT_TYPE, "application/n-triples");
097        template.sendBodyAndHeaders(document, headers);
098
099        headers.clear();
100        headers.put(FcrepoHeaders.FCREPO_BASE_URL, base);
101        headers.put(JmsHeaders.IDENTIFIER, path);
102        headers.put(FcrepoHeaders.FCREPO_NAMED_GRAPH, graph);
103        headers.put(Exchange.CONTENT_TYPE, "application/n-triples");
104        template.sendBodyAndHeaders(document, headers);
105
106        // Confirm that assertions passed
107        resultEndpoint.expectedMessageCount(4);
108        resultEndpoint.assertIsSatisfied();
109    }
110
111    @Test
112    public void testUpdate() throws IOException, InterruptedException {
113        final String base = "http://localhost/rest";
114        final String path = "/path/a/b/c";
115        final String document = getN3Document();
116        // Reverse the lines as the RDF may be serialized in opposite order
117
118        final String responsePrefix =
119                  "DELETE WHERE { <" + base + path + "> ?p ?o };\n" +
120                  "DELETE WHERE { <" + base + path + "/fcr:export?format=jcr/xml> ?p ?o };\n" +
121                  "INSERT DATA { ";
122        final String responseSuffix = "\n}";
123
124        // Assertions
125        resultEndpoint.allMessages().body().startsWith("update=" + encode(responsePrefix, "UTF-8"));
126        resultEndpoint.allMessages().body().endsWith(encode(responseSuffix, "UTF-8"));
127        for (final String s : document.split("\n")) {
128            resultEndpoint.expectedBodyReceived().body().contains(encode(s, "UTF-8"));
129        }
130        resultEndpoint.expectedBodyReceived().body().contains(
131                encode("<" + base + path + "> dc:title \"some title\" .", "UTF-8"));
132        resultEndpoint.expectedHeaderReceived("Content-Type", "application/x-www-form-urlencoded");
133        resultEndpoint.expectedHeaderReceived(Exchange.HTTP_METHOD, "POST");
134
135        // Test
136        final Map<String, Object> headers = new HashMap<>();
137        headers.put(FcrepoHeaders.FCREPO_BASE_URL, base + "/");
138        headers.put(FcrepoHeaders.FCREPO_IDENTIFIER, path);
139        headers.put(Exchange.CONTENT_TYPE, "application/n-triples");
140        template.sendBodyAndHeaders(document, headers);
141
142        headers.clear();
143        headers.put(JmsHeaders.BASE_URL, base + "/");
144        headers.put(JmsHeaders.IDENTIFIER, path);
145        headers.put(Exchange.CONTENT_TYPE, "text/turtle");
146        template.sendBodyAndHeaders(getTurtleDocument(), headers);
147
148        headers.clear();
149        headers.put(JmsHeaders.BASE_URL, base);
150        headers.put(FcrepoHeaders.FCREPO_IDENTIFIER, path);
151        headers.put(Exchange.CONTENT_TYPE, "application/n-triples");
152        template.sendBodyAndHeaders(document, headers);
153
154        headers.clear();
155        headers.put(FcrepoHeaders.FCREPO_BASE_URL, base);
156        headers.put(JmsHeaders.IDENTIFIER, path);
157        headers.put(Exchange.CONTENT_TYPE, "application/n-triples");
158        template.sendBodyAndHeaders(document, headers);
159
160        // Confirm that assertions passed
161        resultEndpoint.expectedMessageCount(4);
162        resultEndpoint.assertIsSatisfied();
163    }
164
165    @Override
166    protected RouteBuilder createRouteBuilder() {
167        return new RouteBuilder() {
168            @Override
169            public void configure() throws IOException {
170
171                final String fcrepo_uri = getFcrepoEndpointUri();
172
173                from("direct:start")
174                    .process(new SparqlUpdateProcessor())
175                    // Normalize the whitespace to make it easier to compare
176                    .process(new Processor() {
177                        public void process(final Exchange exchange) throws Exception {
178                           final String payload = exchange.getIn().getBody(String.class);
179                           exchange.getIn().setBody(normalizeSpace(payload));
180                       }
181                    })
182                    .to("mock:result");
183            }
184        };
185    }
186}