edu.si.services.sidora.rest.mci.MCIServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for edu.si.services.sidora.rest.mci.MCIServiceTest.java

Source

/*
 * Copyright 2015-2016 Smithsonian Institution.
 *
 * 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/
 *
 * This software and accompanying documentation is supplied without
 * warranty of any kind. The copyright holder and the Smithsonian Institution:
 * (1) expressly disclaim any warranties, express or implied, including but not
 * limited to any implied warranties of merchantability, fitness for a
 * particular purpose, title or non-infringement; (2) do not assume any legal
 * liability or responsibility for the accuracy, completeness, or usefulness of
 * the software; (3) do not represent that use of the software would not
 * infringe privately owned rights; (4) do not warrant that the software
 * is error-free or will be maintained, supported, updated or enhanced;
 * (5) will not be liable for any indirect, incidental, consequential special
 * or punitive damages of any kind or nature, including but not limited to lost
 * profits or loss of data, on any basis arising from contract, tort or
 * otherwise, even if any of the parties has been warned of the possibility of
 * such loss or damage.
 *
 * This distribution includes several third-party libraries, each with their own
 * license terms. For a complete copy of all copyright and license terms, including
 * those of third-party libraries, please see the product release notes.
 */

package edu.si.services.sidora.rest.mci;

import edu.si.services.fedorarepo.FedoraObjectNotFoundException;
import org.apache.camel.Exchange;
import org.apache.camel.LoggingLevel;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.impl.DefaultExchange;
import org.apache.camel.impl.JndiRegistry;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static org.apache.commons.io.FileUtils.readFileToString;

/**
 * @author jbirkhimer
 */
public class MCIServiceTest extends MCI_BlueprintTestSupport {

    static private String LOG_NAME = "edu.si.mci";

    protected static String MCI_URI;
    private static final String KARAF_HOME = System.getProperty("karaf.home");

    //Default Test Params
    private static File TEST_XML = new File(KARAF_HOME + "/sample-data/MCI_Inbox/valid-mci-payload.xml");
    private static File TEST_BAD_XML = new File(KARAF_HOME + "/sample-data/MCI_Inbox/bad-mci-payload.xml");

    private CloseableHttpClient httpClient;

    @Override
    protected String getBlueprintDescriptor() {
        return "/OSGI-INF/blueprint/blueprint.xml";
    }

    @Override
    protected JndiRegistry createRegistry() throws Exception {
        JndiRegistry reg = super.createRegistry();
        reg.bind("jsonProvider", org.apache.cxf.jaxrs.provider.json.JSONProvider.class);
        reg.bind("jaxbProvider", org.apache.cxf.jaxrs.provider.JAXBElementProvider.class);
        return reg;
    }

    @Before
    @Override
    public void setUp() throws Exception {
        httpClient = HttpClientBuilder.create().build();
        super.setUp();

        MCI_URI = getProps().getProperty("sidora.mci.service.address");
    }

    @After
    @Override
    public void tearDown() throws Exception {
        super.tearDown();
        httpClient.close();
    }

    @Override
    public boolean isUseAdviceWith() {
        return true;
    }

    /**
     * Test the correct return response is received
     *
     * @throws Exception
     */
    @Test
    public void testRequestOKResponse() throws Exception {

        context.getRouteDefinition("AddMCIProject").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                //Skip adding request to database
                weaveById("createRequest").remove();
                //Skip further processing since all we are interested in is the return response
                weaveByToString(".*seda:processProject.*").remove();
            }
        });

        HttpPost post = new HttpPost(MCI_URI + "/addProject");
        post.addHeader("Content-Type", "application/xml");
        post.addHeader("Accept", "application/xml");
        //post.setEntity(new StringEntity(readFileToString(new File(KARAF_HOME + "/sample-data/MCI_Inbox/small.xml"))));
        post.setEntity(new StringEntity(readFileToString(TEST_XML)));
        HttpResponse response = httpClient.execute(post);
        assertEquals(200, response.getStatusLine().getStatusCode());

        String responseBody = EntityUtils.toString(response.getEntity());

        assertStringContains(responseBody, "OK :: Created");

        assertMockEndpointsSatisfied();
    }

    /**
     * Test the correct return response is received when bad xml payload is received. Validation errors throw exception
     * and is handled by onException sending errors to log, and body for the response and skipping recording errors to database
     * @throws Exception
     */
    @Test
    public void testValidationFailedErrorResponse() throws Exception {

        String payload = "<Fields>\n"
                + "    <Field Type=\"Text\" Name=\"Title\" DisplayName=\"Project Title\">Testing of MCI Project request - all approval go\n"
                + "        through.\n" + "    </Field>\n"
                + "    <Field Type=\"User\" Name=\"Folder_x0020_Holder\" DisplayName=\"Folder Holder\">i:0#.w|us\\testFolderHolder</Field>\n"
                + "    <Field Type=\"User\" Name=\"Folder_x0020_Holder\" DisplayName=\"Folder Holder\">i:0#.w|us\\testFolderHolder</Field>\n"
                + "</Fields>";

        context.getRouteDefinition("AddMCIProject").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                //Skip adding request to database
                weaveById("createRequest").remove();
                weaveById("onExceptionAddValidationErrorsToDB").remove();
                //Skip further processing since all we are interested in is the return response
                weaveByToString(".*seda:processProject.*").remove();
            }
        });

        //for (int i = 0; i < 25; i++) {

        HttpPost post = new HttpPost(MCI_URI + "/addProject");
        post.addHeader("Content-Type", "application/xml");
        post.addHeader("Accept", "application/xml");
        //post.setEntity(new StringEntity(readFileToString(TEST_BAD_XML)));
        post.setEntity(new StringEntity(payload));
        HttpResponse response = httpClient.execute(post);
        assertEquals(400, response.getStatusLine().getStatusCode());

        String responseBody = EntityUtils.toString(response.getEntity());
        String responseHeaders = Arrays.toString(response.getAllHeaders());

        assertStringContains(responseBody, "Error reported: Validation failed for");
        //}
    }

    /**
     * Test onException in AddMCIProject route for SQL exceptions retries and continues routing after retries are exhausted
     *
     * @throws Exception
     */
    @Test
    public void testSQLExceptionAndRetriesForAddMCIProjectRoute() throws Exception {
        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMessageCount(1);
        mockResult.message(0).exchangeProperty(Exchange.EXCEPTION_CAUGHT).isInstanceOf(SQLException.class);
        mockResult.expectedHeaderReceived("redeliveryCount", 3);

        context.getRouteDefinition("AddMCIProject").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                //processor used to replace sql query to test onException and retries
                final Processor processor = new Processor() {
                    public void process(Exchange exchange) throws SQLException {
                        Message in = exchange.getIn();
                        in.setHeader("redeliveryCount", in.getHeader(Exchange.REDELIVERY_COUNTER, Integer.class));
                        throw new SQLException("Testing AddMCIProject SQL exception handling");
                    }
                };

                //advice sending to database and replace with processor
                weaveById("createRequest").replace().process(processor);
                weaveById("sedaProcessProject").remove();
                weaveAddLast().to("mock:result");
            }
        });

        context.start();

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setHeader("mciFolderHolder", "testUser");
        exchange.getIn().setBody(readFileToString(TEST_XML));

        template.send("direct:addProject", exchange);

        assertMockEndpointsSatisfied();
    }

    /**
     * Test onException retries when folder holder is not found in the Drupal dB and continues routing after
     * retries are exhausted setting the user pid to the default user.
     *
     * @throws Exception
     */
    @Test
    public void testFolderHolderNotFoundRetry() throws Exception {

        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMessageCount(1);
        mockResult.expectedHeaderReceived("mciFolderHolder", "testUser");
        mockResult.expectedHeaderReceived("mciOwnerPID", getProps().getProperty("mci.default.owner.pid"));
        mockResult.message(0).exchangeProperty(Exchange.EXCEPTION_CAUGHT).isInstanceOf(MCI_Exception.class);
        mockResult.expectedHeaderReceived("redeliveryCount", 10);

        MockEndpoint mockError = getMockEndpoint("mock:error");
        mockError.expectedMessageCount(1);
        mockError.expectedHeaderReceived("redeliveryCount", 10);

        context.getRouteDefinition("ProcessMCIProject").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                weaveById("MCI_ExceptionOnException").after().to("mock:error");
                weaveById("consumeRequest").remove();
                weaveById("folderHolderXpath").remove();
                weaveById("researchProjectLabelXpath").remove();
                weaveById("setOwnerPID").before().to("mock:result").stop();
            }
        });

        context.getRouteDefinition("MCIFindFolderHolderUserPID").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {

                //processor used to replace sql query to test onException and retries
                final Processor processor = new Processor() {
                    public void process(Exchange exchange) throws MCI_Exception {
                        Message in = exchange.getIn();
                        in.setHeader("redeliveryCount", in.getHeader(Exchange.REDELIVERY_COUNTER, Integer.class));
                        throw new MCI_Exception("Folder Holder User PID Not Found!!!");
                    }
                };

                weaveById("queryFolderHolder").remove();
                weaveById("throwMCIException").replace().process(processor);

            }
        });

        context.start();

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setHeader("mciFolderHolder", "testUser");

        template.send("seda:processProject", exchange);

        assertMockEndpointsSatisfied(5, TimeUnit.SECONDS); // make sure the redeliveries finish
    }

    /**
     * Test the onException handling during processing without sending errors to database
     *
     * @throws Exception
     */
    @Test
    public void testAllOtherExceptionsDuringProcessMCIProjectRoute() throws Exception {
        MockEndpoint mockError = getMockEndpoint("mock:error");
        mockError.expectedMessageCount(1);
        mockError.expectedHeaderReceived(Exchange.REDELIVERY_COUNTER, 10);
        mockError.expectedHeaderReceived(Exchange.REDELIVERY_MAX_COUNTER, 10);
        mockError.expectedHeaderReceived(Exchange.REDELIVERED, true);

        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMessageCount(0);

        context.getRouteDefinition("ProcessMCIProject").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {

                //processor used to to test onException
                final Processor processor = new Processor() {
                    public void process(Exchange exchange) throws FedoraObjectNotFoundException {
                        throw new FedoraObjectNotFoundException("The fedora object not found");
                    }
                };

                weaveById("processProjectOnExceptionSQL").replace().to("mock:error");
                interceptFrom().process(processor).to("mock:result");

            }
        });

        context.start();

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setBody("Testing OnException");

        template.send("seda:processProject", exchange);

        //Give the redeliveries time to finish
        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
    }

    /**
     * Testing the generic resource and FITS object creation
     *
     * NOTE: FITS must be installed
     *
     * @throws Exception
     */
    @Test
    public void testMCICreateResource() throws Exception {

        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMessageCount(1);

        MockEndpoint mockFedora = getMockEndpoint("mock:fedora");
        mockFedora.expectedMessageCount(6);

        context.getRouteDefinition("MCICreateResource").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                interceptSendToEndpoint(".*fedora:.*").skipSendToOriginalEndpoint()
                        .log(LoggingLevel.INFO, LOG_NAME, "Skip Sending to Fedora").to("mock:fedora");
                weaveAddLast().to("mock:result").stop();
            }
        });

        context.getRouteDefinition("MCIProjectAddFITSDataStream").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                interceptSendToEndpoint(".*fedora:.*").skipSendToOriginalEndpoint()
                        .log(LoggingLevel.INFO, LOG_NAME, "Skip Sending to Fedora").to("mock:fedora");

                weaveById("fitsRequest").replace().setHeader("CamelHttpResponseCode", simple("200")).setBody()
                        .simple("Test Fits Output");
            }
        });

        context.start();

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setHeader("mciFolderHolder", "testUser");
        exchange.getIn().setHeader("mciOwnerPID", "test-user:123");
        exchange.getIn().setHeader("projectPID", "test:0001");
        exchange.getIn().setHeader("CamelFedoraPid", "test:0002");
        exchange.getIn().setHeader("mciProjectXML", readFileToString(TEST_XML));

        template.send("direct:mciCreateResource", exchange);

        for (Exchange fedoraExchange : mockFedora.getExchanges()) {
            log.info(fedoraExchange.getIn().getBody(String.class));
        }

        assertMockEndpointsSatisfied();

        assertStringContains(mockFedora.getExchanges().get(5).getIn().getBody(String.class), "Test Fits Output");

        deleteDirectory("staging");
    }

    /**
     * Test the processProjectXpath body
     *
     * @throws Exception
     */
    @Test
    public void testResourceProjectLabelProcessMCIProjectRoute() throws Exception {

        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMessageCount(1);
        mockResult.expectedHeaderReceived("mciResearchProjectLabel", "Testing of MCI Project request #2");
        mockResult.setAssertPeriod(1500);

        context.getRouteDefinition("ProcessMCIProject").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                weaveById("consumeRequest").remove();
                weaveById("researchProjectLabelXpath").after()
                        .to("log:testMCI?showAll=true&multiline=true&maxChars=100000").to("mock:result").stop();
            }
        });

        context.start();

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setHeader("mciProjectXML", readFileToString(TEST_XML));

        template.send("seda:processProject", exchange);

        assertMockEndpointsSatisfied();
    }

    @Test
    public void testWorkbenchLoginSetCookie() throws Exception {
        ArrayList<String> testCookie = new ArrayList<>();
        testCookie.add(String.valueOf(UUID.randomUUID()) + "=" + String.valueOf(UUID.randomUUID()) + ";");
        testCookie.add(String.valueOf(UUID.randomUUID()) + "=" + String.valueOf(UUID.randomUUID()));

        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMessageCount(1);
        mockResult.expectedHeaderReceived("Cookie", testCookie.toString().replaceAll("[\\[,\\]]", ""));
        mockResult.setAssertPeriod(1500);

        context.getRouteDefinition("MCIWorkbenchLogin").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                weaveById("workbenchLogin").replace().setHeader(Exchange.HTTP_RESPONSE_CODE).simple("302");
                weaveById("workbenchLoginCreateResearchProjectCall").replace().to("mock:result");
            }
        });

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setBody("test body");
        exchange.getIn().setHeader("Set-Cookie", testCookie);

        template.send("direct:workbenchLogin", exchange);

        assertMockEndpointsSatisfied();
    }

    @Test
    @Ignore
    public void testWorkbenchLoginException() throws Exception {
    }

    @Test
    public void testWorkbenchCreateResearchProject() throws Exception {
        String testPidResponse = "test:12345";

        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMessageCount(1);
        mockResult.expectedHeaderReceived("researchProjectPid", testPidResponse);
        mockResult.setAssertPeriod(1500);

        context.getRouteDefinition("MCIWorkbenchCreateResearchProject").adviceWith(context,
                new AdviceWithRouteBuilder() {
                    @Override
                    public void configure() throws Exception {
                        weaveById("workbenchCreateResearchProject").replace().setBody().simple(testPidResponse)
                                .setHeader(Exchange.HTTP_RESPONSE_CODE).simple("200");
                        weaveAddLast().to("mock:result");
                    }
                });

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setHeader("mciResearchProjectLabel", "testLabel");

        template.send("direct:workbenchCreateResearchProject", exchange);

        assertMockEndpointsSatisfied();
    }

    @Test
    @Ignore
    public void testWorkbenchCreateResearchProjectException() throws Exception {
    }

    @Test
    public void testMciProjectTemplate() throws Exception {
        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMinimumMessageCount(1);

        context.addRoutes(new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:start")
                        .toD("xslt:file:{{karaf.home}}/Input/xslt/MCIProjectToSIdoraProject.xsl?saxon=true")
                        .log(LoggingLevel.DEBUG, "Transform Successful")
                        .setHeader("mciProjectDESCMETA", simple("${body}", String.class))
                        .to("direct:mciCreateConcept");
            }
        });
        context.getRouteDefinition("MCICreateConcept").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                interceptSendToEndpoint(".*fedora:.*").skipSendToOriginalEndpoint().log(LoggingLevel.INFO, LOG_NAME,
                        "Skip Sending to Fedora");
                weaveById("mciCreateResource").replace().log("Skipping Create Resource");
                weaveById("velocityMCIProjectTemplate").after().to("mock:result");
            }
        });

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setBody(readFileToString(TEST_XML));
        exchange.getIn().setHeader("researchProjectPid", "test:001");
        exchange.getIn().setHeader("CamelFedoraPid", "test:002");
        exchange.getIn().setHeader("projectResourcePID", "test:003");
        template.send("direct:start", exchange);

        log.info("MciProjectTemplate result body: {}", mockResult.getExchanges().get(0).getIn().getBody());
    }

    @Test
    public void testMciLabel() throws Exception {
        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.expectedMinimumMessageCount(1);

        context.addRoutes(new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:start")
                        .toD("xslt:file:{{karaf.home}}/Input/xslt/MCIProjectToSIdoraProject.xsl?saxon=true")
                        .log(LoggingLevel.DEBUG, "Transform Successful")
                        .setHeader("mciProjectDESCMETA", simple("${body}", String.class))
                        .to("direct:mciCreateConcept");
            }
        });
        context.getRouteDefinition("MCICreateConcept").adviceWith(context, new AdviceWithRouteBuilder() {
            @Override
            public void configure() throws Exception {
                weaveById("mciLabel1").after().setBody().simple("${header.mciLabel}").to("mock:result").stop();
            }
        });

        Exchange exchange = new DefaultExchange(context);
        exchange.getIn().setBody(readFileToString(TEST_XML));
        exchange.getIn().setHeader("researchProjectPid", "test:001");
        exchange.getIn().setHeader("CamelFedoraPid", "test:002");
        exchange.getIn().setHeader("projectResourcePID", "test:003");
        template.send("direct:start", exchange);

        log.info("MciProjectTemplate result body: {}", mockResult.getExchanges().get(0).getIn().getBody());

        log.info("Body Type: {}", mockResult.getExchanges().get(0).getIn().getBody().getClass());
        assertIsInstanceOf(String.class, mockResult.getExchanges().get(0).getIn().getHeader("mciLabel"));
    }
}