Java tutorial
/* * $Id$ * -------------------------------------------------------------------------------------- * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.transport.sftp; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mule.context.notification.EndpointMessageNotification.MESSAGE_DISPATCHED; import static org.mule.context.notification.EndpointMessageNotification.MESSAGE_SENT; import org.mule.api.MuleEvent; import org.mule.api.MuleEventContext; import org.mule.api.MuleException; import org.mule.api.context.notification.EndpointMessageNotificationListener; import org.mule.api.context.notification.ServerNotification; import org.mule.api.endpoint.EndpointBuilder; import org.mule.api.endpoint.EndpointURI; import org.mule.api.endpoint.ImmutableEndpoint; import org.mule.api.exception.MessagingExceptionHandler; import org.mule.api.exception.RollbackSourceCallback; import org.mule.api.exception.SystemExceptionHandler; import org.mule.api.model.Model; import org.mule.api.service.Service; import org.mule.api.transport.Connector; import org.mule.context.notification.EndpointMessageNotification; import org.mule.module.client.MuleClient; import org.mule.tck.AbstractServiceAndFlowTestCase; import org.mule.tck.functional.EventCallback; import org.mule.tck.junit4.rule.DynamicPort; import org.mule.transport.sftp.util.SftpServer; import org.mule.transport.sftp.util.ValueHolder; import org.mule.util.StringMessageUtils; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.SftpException; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.lang.SystemUtils; import org.junit.Before; import org.junit.Rule; /** * @author Lennart Hggkvist, Magnus Larsson Date: Jun 8, 2009 */ public abstract class AbstractSftpTestCase extends AbstractServiceAndFlowTestCase { private static final String HOST = "localhost"; private static final String USER = "muletest1"; private static final String PASSWORD = "muletest1"; private static final String FILENAME_HEADER = "filename"; protected static final Map<String, String> MESSAGE_PROPERTIES = new HashMap<String, String>(); protected static String INBOUND_ENDPOINT_DIR = "inbound"; protected static String OUTBOUND_ENDPOINT_DIR = "outbound"; { MESSAGE_PROPERTIES.put(FILENAME_HEADER, FILENAME); } protected static final String FILENAME = "file.txt"; @Rule public DynamicPort port = new DynamicPort("SFTP_PORT"); protected SftpServer sftpServer; protected SftpClient sftpClient; public AbstractSftpTestCase(ConfigVariant variant, String configResources) { super(variant, configResources); } /** * Deletes all files in the directory, useful when testing to ensure that no * files are in the way... */ // protected void cleanupRemoteFtpDirectory(MuleClient muleClient, String // endpointName) throws IOException // { // SftpClient sftpClient = getSftpClient(muleClient, endpointName); // // EndpointURI endpointURI = getUriByEndpointName(muleClient, endpointName); // sftpClient.changeWorkingDirectory(sftpClient.getAbsolutePath(endpointURI.getPath())); // // String[] files = sftpClient.listFiles(); // for (String file : files) // { // sftpClient.deleteFile(file); // } // } /** * Deletes a directory with all its files and sub-directories. The reason it do a * "chmod 700" before the delete is that some tests changes the permission, and * thus we have to restore the right to delete it... * * @param muleClient * @param endpointName * @param relativePath * @throws IOException */ protected void recursiveDelete(MuleClient muleClient, SftpClient sftpClient, String endpointName, String relativePath) throws IOException { EndpointURI endpointURI = getUriByEndpointName(muleClient, endpointName); String path = endpointURI.getPath() + relativePath; try { // Ensure that we can delete the current directory and the below // directories (if write is not permitted then delete is either) sftpClient.chmod(path, 00700); sftpClient.changeWorkingDirectory(sftpClient.getAbsolutePath(path)); // Delete all sub-directories String[] directories = sftpClient.listDirectories(); for (String directory : directories) { recursiveDelete(muleClient, sftpClient, endpointName, relativePath + "/" + directory); } // Needs to change the directory back after the recursiveDelete sftpClient.changeWorkingDirectory(sftpClient.getAbsolutePath(path)); // Delete all files String[] files = sftpClient.listFiles(); for (String file : files) { sftpClient.deleteFile(file); } // Delete the directory try { sftpClient.deleteDirectory(path); } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Failed delete directory " + path, e); } } catch (Exception e) { if (logger.isDebugEnabled()) logger.debug("Failed to recursivly delete directory " + path, e); } } /** Creates the <i>directoryName</i> under the endpoint path */ protected void createRemoteDirectory(MuleClient muleClient, String endpointName, String directoryName) throws IOException { SftpClient sftpClient = getSftpClient(muleClient, endpointName); try { EndpointURI endpointURI = getUriByEndpointName(muleClient, endpointName); sftpClient.changeWorkingDirectory(sftpClient.getAbsolutePath(endpointURI.getPath())); try { sftpClient.mkdir(directoryName); } catch (IOException e) { e.printStackTrace(); // Expected if the directory didnt exist } try { sftpClient.changeWorkingDirectory(endpointURI.getPath() + "/" + directoryName); } catch (IOException e) { fail("The directory should have been created"); } } finally { sftpClient.disconnect(); } } protected EndpointURI getUriByEndpointName(MuleClient muleClient, String endpointName) throws IOException { ImmutableEndpoint endpoint = getImmutableEndpoint(muleClient, endpointName); return endpoint.getEndpointURI(); } /** * @param muleClient * @param endpointName * @return the endpoint address in the form 'sftp://user:password@host/path' */ protected String getAddressByEndpoint(MuleClient muleClient, String endpointName) { ImmutableEndpoint endpoint = (ImmutableEndpoint) muleClient.getProperty(endpointName); EndpointURI endpointURI = endpoint.getEndpointURI(); return "sftp://" + endpointURI.getUser() + ":" + endpointURI.getPassword() + "@" + endpointURI.getHost() + endpointURI.getPath(); } protected String getPathByEndpoint(MuleClient muleClient, SftpClient sftpClient, String endpointName) { ImmutableEndpoint endpoint = (ImmutableEndpoint) muleClient.getProperty(endpointName); EndpointURI endpointURI = endpoint.getEndpointURI(); return sftpClient.getAbsolutePath(endpointURI.getPath()); } /** * Returns a SftpClient that is logged in to the sftp server that the endpoint is * configured against. */ protected SftpClient getSftpClient(MuleClient muleClient, String endpointName) throws IOException { ImmutableEndpoint endpoint = getImmutableEndpoint(muleClient, endpointName); EndpointURI endpointURI = endpoint.getEndpointURI(); SftpClient sftpClient = new SftpClient(endpointURI.getHost()); sftpClient.setPort(endpointURI.getPort()); SftpConnector sftpConnector = (SftpConnector) endpoint.getConnector(); if (sftpConnector.getIdentityFile() != null) { try { sftpClient.login(endpointURI.getUser(), sftpConnector.getIdentityFile(), sftpConnector.getPassphrase()); } catch (Exception e) { fail("Login failed: " + e); } } else { try { sftpClient.login(endpointURI.getUser(), endpointURI.getPassword()); } catch (Exception e) { fail("Login failed: " + e); } } return sftpClient; } /** * Returns a SftpClient that is logged in to the sftp server that the endpoint is * configured against. */ protected SftpClient getSftpClient(String host, int port, String user, String password) throws IOException { SftpClient sftpClient = new SftpClient(host); sftpClient.setPort(port); try { sftpClient.login(user, password); } catch (Exception e) { fail("Login failed: " + e); } return sftpClient; } /** Checks if the file exists on the server */ protected boolean verifyFileExists(SftpClient sftpClient, EndpointURI endpointURI, String file) throws IOException { return verifyFileExists(sftpClient, endpointURI.getPath(), file); } protected boolean verifyFileExists(SftpClient sftpClient, String path, String file) throws IOException { sftpClient.changeWorkingDirectory(sftpClient.getAbsolutePath(path)); String[] files = sftpClient.listFiles(); for (String remoteFile : files) { if (remoteFile.equals(file)) { return true; } } return false; } /** Base method for executing tests... */ protected void executeBaseTest(String inputEndpointName, String sendUrl, String filename, final int size, String receivingTestComponentName, long timeout) throws Exception { executeBaseTest(inputEndpointName, sendUrl, filename, size, receivingTestComponentName, timeout, null); } protected void executeBaseTest(String inputEndpointName, String sendUrl, String filename, final int size, String receivingTestComponentName, long timeout, String expectedFailingConnector) throws Exception { executeBaseTest(inputEndpointName, sendUrl, filename, size, receivingTestComponentName, timeout, expectedFailingConnector, null); } /** Base method for executing tests... */ protected void executeBaseTest(String inputEndpointName, String sendUrl, String filename, final int size, String receivingTestComponentName, long timeout, String expectedFailingConnector, String serviceName) throws Exception { MuleClient client = new MuleClient(muleContext); // Do some cleaning so that the endpoint doesn't have any other files // We don't need to do this anymore since we are deleting and then creating // the directory for each test // cleanupRemoteFtpDirectory(client, inputEndpointName); final CountDownLatch latch = new CountDownLatch(1); final AtomicInteger loopCount = new AtomicInteger(0); final AtomicInteger totalReceivedSize = new AtomicInteger(0); // Random byte that we want to send a lot of final int testByte = 42; EventCallback callback = new EventCallback() { @Override public void eventReceived(MuleEventContext context, Object component) throws Exception { if (logger.isInfoEnabled()) logger.info("called " + loopCount.incrementAndGet() + " times"); InputStream sftpInputStream = (InputStream) context.getMessage().getPayload(); BufferedInputStream bif = new BufferedInputStream(sftpInputStream); byte[] buffer = new byte[1024 * 4]; try { int n; while (-1 != (n = bif.read(buffer))) { totalReceivedSize.addAndGet(n); // Simple check to verify the data... for (byte b : buffer) { if (b != testByte) { fail("Incorrect received byte (was '" + b + "', expected '" + testByte + "'"); } } } } finally { bif.close(); } latch.countDown(); } }; getFunctionalTestComponent(receivingTestComponentName).setEventCallback(callback); final ValueHolder<Exception> exceptionHolder = new ValueHolder<Exception>(); if (expectedFailingConnector != null) { // Register an exception-listener on the connector that expects to fail // and count down the latch after saving the thrown exception muleContext.setExceptionListener(new SystemExceptionHandler() { @Override public void handleException(Exception e, RollbackSourceCallback rollbackMethod) { if (logger.isInfoEnabled()) logger.info("expected exception occurred: " + e, e); exceptionHolder.value = e; latch.countDown(); } @Override public void handleException(Exception exception) { handleException(exception, null); } }); if (serviceName != null && !(serviceName.length() == 0)) { muleContext.getRegistry().lookupService(serviceName) .setExceptionListener(new MessagingExceptionHandler() { @Override public MuleEvent handleException(Exception e, MuleEvent event) { if (logger.isInfoEnabled()) logger.info("expected exception occurred: " + e, e); exceptionHolder.value = e; latch.countDown(); return event; } }); } } // InputStream that generates the data without using a file InputStream os = new InputStream() { int totSize = 0; @Override public int read() throws IOException { totSize++; if (totSize <= size) { return testByte; } else { return -1; } } }; HashMap<String, String> props = new HashMap<String, String>(1); props.put(SftpConnector.PROPERTY_FILENAME, filename); props.put(SftpConnector.PROPERTY_ORIGINAL_FILENAME, filename); if (logger.isInfoEnabled()) logger.info(StringMessageUtils.getBoilerPlate( "Note! If this test fails due to timeout please add '-Dmule.test.timeoutSecs=XX' to the mvn command!")); executeBaseAssertionsBeforeCall(); // Send the content using stream client.dispatch(sendUrl, os, props); boolean workDone = latch.await(timeout, TimeUnit.MILLISECONDS); assertTrue("Test timed out. It took more than " + timeout + " milliseconds. If this error occurs the test probably needs a longer time out (on your computer/network)", workDone); // Rethrow any exception that we have caught in an exception-listener if (exceptionHolder.value != null) { throw exceptionHolder.value; } executeBaseAssertionsAfterCall(size, totalReceivedSize.intValue()); } /** * To be overridden by the test-classes if required */ protected void executeBaseAssertionsBeforeCall() { // empty } /** * To be overridden by the test-classes if required */ protected void executeBaseAssertionsAfterCall(int sendSize, int receivedSize) { // Make sure that the file we received had the same size as the one we sent if (logger.isInfoEnabled()) { logger.info("Sent size: " + sendSize); logger.info("Received size: " + receivedSize); } assertEquals("The received file should have the same size as the sent file", sendSize, receivedSize); } protected ImmutableEndpoint getImmutableEndpoint(MuleClient muleClient, String endpointName) throws IOException { ImmutableEndpoint endpoint = null; Object o = muleClient.getProperty(endpointName); if (o instanceof ImmutableEndpoint) { // For Inbound and Outbound Endpoints endpoint = (ImmutableEndpoint) o; } else if (o instanceof EndpointBuilder) { // For Endpoint-references EndpointBuilder eb = (EndpointBuilder) o; try { endpoint = eb.buildInboundEndpoint(); } catch (Exception e) { throw new IOException(e.getMessage()); } } return endpoint; } protected void remoteChmod(MuleClient muleClient, SftpClient sftpClient, String endpointName, int permissions) throws SftpException { ChannelSftp channelSftp = sftpClient.getChannelSftp(); ImmutableEndpoint endpoint = (ImmutableEndpoint) muleClient.getProperty(endpointName); EndpointURI endpointURI = endpoint.getEndpointURI(); // RW - so that we can do initial cleanup channelSftp.chmod(permissions, sftpClient.getAbsolutePath(endpointURI.getPath())); } /** * Initiates a list of sftp-endpoint-directories. Ensures that affected services * are stopped during the initiation. * * @param serviceNames * @param endpointNames * @throws Exception */ protected void initEndpointDirectories(String[] serviceNames, String[] endpointNames) throws Exception { // Stop all named services List<Service> services = new ArrayList<Service>(); for (String serviceName : serviceNames) { try { Service service = muleContext.getRegistry().lookupService(serviceName); service.stop(); services.add(service); } catch (Exception e) { logger.error("Error '" + e.getMessage() + "' occured while stopping the service " + serviceName + ". Perhaps the service did not exist in the config?"); throw e; } } // Now init the directory for each named endpoint, one by one for (String endpointName : endpointNames) { initEndpointDirectory(endpointName); } // We are done, startup the services again so that the test can begin... for (Service service : services) { service.start(); } } /** * Ensures that the directory exists and is writable by deleting the directory * and then recreate it. * * @param endpointName * @throws org.mule.api.MuleException * @throws java.io.IOException * @throws com.jcraft.jsch.SftpException */ protected void initEndpointDirectory(String endpointName) throws MuleException, IOException, SftpException { MuleClient muleClient = new MuleClient(muleContext); SftpClient sftpClient = getSftpClient(muleClient, endpointName); try { ChannelSftp channelSftp = sftpClient.getChannelSftp(); try { recursiveDelete(muleClient, sftpClient, endpointName, ""); } catch (IOException e) { if (logger.isErrorEnabled()) logger.error("Failed to recursivly delete endpoint " + endpointName, e); } String path = getPathByEndpoint(muleClient, sftpClient, endpointName); channelSftp.mkdir(path); } finally { sftpClient.disconnect(); if (logger.isDebugEnabled()) logger.debug("Done init endpoint directory: " + endpointName); } } /** * Helper method for initiating a test and wait for the test to complete. The * method sends a file to an inbound endpoint and waits for a dispatch event on a * outbound endpoint, i.e. that the file has been consumed by the inbound * endpoint and that the content of the file has been sent to the outgoing * endpoint. * * @param p where inboundEndpoint and outboundEndpoint are mandatory, @see * DispatchParameters for details. */ @SuppressWarnings("rawtypes") protected void dispatchAndWaitForDelivery(final DispatchParameters p) { // Declare countdown latch and listener final CountDownLatch latch = new CountDownLatch(1); EndpointMessageNotificationListener listener = null; MuleClient muleClient = p.getMuleClient(); boolean localMuleClient = muleClient == null; try { // First create a local muleClient instance if not supplied if (localMuleClient) muleClient = new MuleClient(muleContext); // Next create a listener that listens for dispatch events on the // outbound endpoint listener = new EndpointMessageNotificationListener() { @Override public void onNotification(ServerNotification notification) { // Only care about EndpointMessageNotification if (notification instanceof EndpointMessageNotification) { EndpointMessageNotification endpointNotification = (EndpointMessageNotification) notification; // Extract action and name of the endpoint int action = endpointNotification.getAction(); String endpoint = endpointNotification.getEndpoint(); // If it is a dispatch event on our outbound endpoint then // countdown the latch. if ((action == MESSAGE_DISPATCHED || action == MESSAGE_SENT) && endpoint.equals(p.getOutboundEndpoint())) { if (logger.isDebugEnabled()) logger.debug("Expected notification received on " + p.getOutboundEndpoint() + " (action: " + action + "), time to countdown the latch"); latch.countDown(); } } } }; // Now register the listener muleContext.getNotificationManager().addListener(listener); // Initiate the test by sending a file to the SFTP server, which the // inbound-endpoint then can pick up // Prepare message headers, set filename-header and if supplied any // headers supplied in the call. Map<String, String> headers = new HashMap<String, String>(); headers.put("filename", p.getFilename()); if (p.getHeaders() != null) { headers.putAll(p.getHeaders()); } // Setup connect string and perform the actual dispatch String connectString = (p.getSftpConnector() == null) ? "" : "?connector=" + p.getSftpConnector(); muleClient.dispatch(getAddressByEndpoint(muleClient, p.getInboundEndpoint()) + connectString, TEST_MESSAGE, headers); // Wait for the delivery to occur... if (logger.isDebugEnabled()) logger.debug("Waiting for file to be delivered to the endpoint..."); boolean workDone = latch.await(p.getTimeout(), TimeUnit.MILLISECONDS); if (logger.isDebugEnabled()) logger.debug((workDone) ? "File delivered, continue..." : "No file delivered, timeout occurred!"); // Raise a fault if the test timed out // FIXME DZ: i dont this is necessary since we have an overall test // timeout // assertTrue("Test timed out. It took more than " + p.getTimeout() + // " milliseconds. If this error occurs the test probably needs a longer time out (on your computer/network)", // workDone); } catch (Exception e) { e.printStackTrace(); fail("An unexpected error occurred: " + e.getMessage()); } finally { // Dispose muleClient if created locally if (localMuleClient) muleClient.dispose(); // Always remove the listener if created if (listener != null) muleContext.getNotificationManager().removeListener(listener); } } protected Exception dispatchAndWaitForException(final DispatchParameters p, String expectedFailingConnector) { return dispatchAndWaitForException(p, expectedFailingConnector, null); } /** * Helper method for initiating a test and wait for an exception to be caught by * the sftp-connector. * * @param p where sftpConnector and inboundEndpoint are mandatory, @see * DispatchParameters for details. */ protected Exception dispatchAndWaitForException(final DispatchParameters p, String expectedFailingConnector, String serviceName) { // Declare countdown latch and listener final CountDownLatch latch = new CountDownLatch(1); SystemExceptionHandler listener = null; MessagingExceptionHandler messagingListener = null; MuleClient muleClient = p.getMuleClient(); boolean localMuleClient = muleClient == null; SystemExceptionHandler currentExceptionListener = null; MessagingExceptionHandler currentMessagingListener = null; final ValueHolder<Exception> exceptionHolder = new ValueHolder<Exception>(); try { // First create a local muleClient instance if not supplied if (localMuleClient) muleClient = new MuleClient(muleContext); // Next create a listener that listens for exception on the // sftp-connector listener = new SystemExceptionHandler() { @Override public void handleException(Exception e, RollbackSourceCallback rollbackMethod) { exceptionHolder.value = e; if (logger.isDebugEnabled()) logger.debug( "Expected exception occurred: " + e.getMessage() + ", time to countdown the latch"); latch.countDown(); } @Override public void handleException(Exception exception) { handleException(exception, null); } }; messagingListener = new MessagingExceptionHandler() { @Override public MuleEvent handleException(Exception e, MuleEvent event) { exceptionHolder.value = e; if (logger.isDebugEnabled()) logger.debug( "Expected exception occurred: " + e.getMessage() + ", time to countdown the latch"); latch.countDown(); return event; } }; currentMessagingListener = muleContext.getRegistry().lookupService(serviceName).getExceptionListener(); muleContext.getRegistry().lookupService(serviceName).setExceptionListener(messagingListener); // Now register an exception-listener on the connector that expects to // fail currentExceptionListener = muleContext.getExceptionListener(); muleContext.setExceptionListener(listener); // Initiate the test by sending a file to the SFTP server, which the // inbound-endpoint then can pick up // Prepare message headers, set filename-header and if supplied any // headers supplied in the call. Map<String, String> headers = new HashMap<String, String>(); headers.put("filename", p.getFilename()); if (p.getHeaders() != null) { headers.putAll(p.getHeaders()); } // Setup connect string and perform the actual dispatch String connectString = (p.getSftpConnector() == null) ? "" : "?connector=" + p.getSftpConnector(); muleClient.dispatch(getAddressByEndpoint(muleClient, p.getInboundEndpoint()) + connectString, TEST_MESSAGE, headers); // Wait for the exception to occur... if (logger.isDebugEnabled()) logger.debug("Waiting for an exception to occur..."); boolean workDone = latch.await(p.getTimeout(), TimeUnit.MILLISECONDS); if (logger.isDebugEnabled()) logger.debug((workDone) ? "Exception occurred, continue..." : "No exception, instead a timeout occurred!"); // Raise a fault if the test timed out assertTrue("Test timed out. It took more than " + p.getTimeout() + " milliseconds. If this error occurs the test probably needs a longer time out (on your computer/network)", workDone); } catch (Exception e) { e.printStackTrace(); fail("An unexpected error occurred: " + e.getMessage()); } finally { // Dispose muleClient if created locally if (localMuleClient) muleClient.dispose(); // Always reset the current listener muleContext.setExceptionListener(currentExceptionListener); muleContext.getRegistry().lookupService(serviceName).setExceptionListener(currentMessagingListener); } return exceptionHolder.value; } protected void recursiveDeleteInLocalFilesystem(File parent) throws IOException { // If this file is a directory then first delete all its children if (parent.isDirectory()) { for (File child : parent.listFiles()) { recursiveDeleteInLocalFilesystem(child); } } // Now delete this file, but first check write permissions on its parent... File parentParent = parent.getParentFile(); if (!parentParent.canWrite()) { // setWritable is only available on JDK6 and beyond //if (!parentParent.setWritable(true)) //throw new IOException("Failed to set readonly-folder: " + parentParent + " to writeable"); // FIXME DZ: since setWritable doesnt exist on jdk5, need to detect os to make dir writable if (SystemUtils.IS_OS_WINDOWS) { Runtime.getRuntime().exec("attrib -r /D" + parentParent.getAbsolutePath()); } else if (SystemUtils.IS_OS_UNIX || SystemUtils.IS_OS_LINUX) { Runtime.getRuntime().exec("chmod +w " + parentParent.getAbsolutePath()); } else { throw new IOException( "This test is not supported on your detected platform : " + SystemUtils.OS_NAME); } } if (parent.exists()) { // FIXME DZ: since setWritable doesnt exist on jdk5, need to detect os to make dir writable if (SystemUtils.IS_OS_WINDOWS) { Runtime.getRuntime().exec("attrib -r /D" + parent.getAbsolutePath()); } else if (SystemUtils.IS_OS_UNIX || SystemUtils.IS_OS_LINUX) { Runtime.getRuntime().exec("chmod +w " + parent.getAbsolutePath()); } else { throw new IOException( "This test is not supported on your detected platform : " + SystemUtils.OS_NAME); } if (!parent.delete()) throw new IOException("Failed to delete folder: " + parent); } } /** * Asserts that there are no files found on the path <i>path</i>. * * @param path The path in the local filesystem to check * @throws IOException Exception */ protected void assertNoFilesInLocalFilesystem(String path) throws IOException { assertFilesInLocalFilesystem(path, new String[] {}); } /** * Asserts that no files are found on the path that the <i>endpointName</i> use. * * @param muleClient MuleClient * @param endpointName The endpoint name * @throws IOException Exception */ protected void assertNoFilesInEndpoint(MuleClient muleClient, String endpointName) throws IOException { assertFilesInEndpoint(muleClient, endpointName, new String[] {}); } /** * Asserts that no files are found on the sub directory <i>subDirectory</i> under * the path that <i>endpointName</i> use. * * @param muleClient MuleClient * @param endpointName The endpoint name * @param subDirectory The sub directory * @throws IOException Exception */ protected void assertNoFilesInEndpoint(MuleClient muleClient, String endpointName, String subDirectory) throws IOException { assertFilesInEndpoint(muleClient, endpointName, subDirectory, new String[] {}); } /** * Asserts that only the <i>expectedFile</i> is found on the path <i>path</i>, * where filenames can be expressed as a regular expression. * * @param path The path in the local filesystem to check * @param expectedFile Expected file * @throws IOException Exception */ protected void assertFilesInLocalFilesystem(String path, String expectedFile) throws IOException { assertFilesInLocalFilesystem(path, new String[] { expectedFile }); } /** * Asserts that only the <i>expectedFiles</i> are found on the path <i>path</i>, * where filenames can be expressed as a regular expression. * * @param path The path in the local filesystem to check * @param expectedFiles Expected files * @throws IOException Exception */ protected void assertFilesInLocalFilesystem(String path, String[] expectedFiles) throws IOException { File parent = new File(path); String[] files = parent.list(); assertFilesInFileArray(path, expectedFiles, files); } /** * Asserts that only the <i>expectedFile</i> is found on the path that the * <i>endpointName</i> use, where filenames can be expressed as a regular * expression. * * @param muleClient MuleClient * @param endpointName The endpoint name * @param expectedFile Expected file * @throws IOException Exception */ protected void assertFilesInEndpoint(MuleClient muleClient, String endpointName, String expectedFile) throws IOException { assertFilesInEndpoint(muleClient, endpointName, null, new String[] { expectedFile }); } /** * Asserts that only the <i>expectedFiles</i> are found on the path that the * <i>endpointName</i> use, where filenames can be expressed as a regular * expression. * * @param muleClient MuleClient * @param endpointName The endpoint name * @param expectedFiles Expected files * @throws IOException Exception */ protected void assertFilesInEndpoint(MuleClient muleClient, String endpointName, String[] expectedFiles) throws IOException { assertFilesInEndpoint(muleClient, endpointName, null, expectedFiles); } /** * Asserts that only the <i>expectedFile</i> is found on the sub directory * <i>subDirectory</i> under the path that <i>endpointName</i> use, where * filenames can be expressed as a regular expression. * * @param muleClient MuleClient * @param endpointName The endpoint name * @param subDirectory The sub directory * @param expectedFile Expected files * @throws IOException Exception */ protected void assertFilesInEndpoint(MuleClient muleClient, String endpointName, String subDirectory, String expectedFile) throws IOException { assertFilesInEndpoint(muleClient, endpointName, subDirectory, new String[] { expectedFile }); } /** * Asserts that only the <i>expectedFiles</i> are found on the sub directory * <i>subDirectory</i> under the path that <i>endpointName</i> use, where * filenames can be expressed as a regular expression. * * @param muleClient MuleClient * @param endpointName The endpoint name * @param subDirectory The sub directory * @param expectedFiles Expected files * @throws IOException Exception */ protected void assertFilesInEndpoint(MuleClient muleClient, String endpointName, String subDirectory, String[] expectedFiles) throws IOException { SftpClient sftpClient = getSftpClient(muleClient, endpointName); ImmutableEndpoint tEndpoint = (ImmutableEndpoint) muleClient.getProperty(endpointName); try { String path = tEndpoint.getEndpointURI().getPath(); if (subDirectory != null) { path += '/' + subDirectory; } assertFilesInPath(sftpClient, path, expectedFiles); } finally { sftpClient.disconnect(); } } /** * Asserts that only the <i>expectedFiles</i> are found on the path <i>path</i>, * where filenames can be expressed as a regular expression. * * @param sftpClient SftpClient * @param path The path to check * @param expectedFiles Expected files * @throws IOException Exception */ private void assertFilesInPath(SftpClient sftpClient, String path, String[] expectedFiles) throws IOException { sftpClient.changeWorkingDirectory(sftpClient.getAbsolutePath(path)); String[] files = sftpClient.listFiles(); assertFilesInFileArray(path, expectedFiles, files); } /** * Asserts that only the <i>expectedFiles</i> are found in the file-array * <i>path</i>, where filenames can be expressed as a regular expression. * * @param path * @param expectedFiles * @param foundFiles */ private void assertFilesInFileArray(String path, String[] expectedFiles, String[] foundFiles) { // First, make a list of the array of found files List<String> foundFileList = new ArrayList<String>(foundFiles.length); foundFileList.addAll(Arrays.asList(foundFiles)); List<String> missingExpectedFiles = new ArrayList<String>(); // lookup each expected file in the list of found files and remove each found // file that match the expected file // Note that the expected file can contain a regexp for (String expectedFile : expectedFiles) { String foundFile = lookupListByRegexp(foundFileList, expectedFile); if (foundFile != null) { foundFileList.remove(foundFile); } else { missingExpectedFiles.add(expectedFile); } } // Check if that no remaining files are left in the list of found files, i.e. // unwanted found files assertTrue("Expected files not found on path " + path + ". File(s):" + missingExpectedFiles, missingExpectedFiles.size() == 0); assertTrue("The following file(s) was found but not expected: " + foundFileList + " on path " + path, foundFileList.size() == 0); } /** * Return the first string in a string-list that matches the regexp * * @param list * @param regexp * @return the first string that match the regexp or null if no match */ private String lookupListByRegexp(List<String> list, String regexp) { // Look for matches of the regexp in the list for (String value : list) { if (value.matches(regexp)) { // Found it, return the full string that matched return value; } } // Noop, nothing found, return null return null; } /** * Helper class for dynamic assignment of parameters to the method * dispatchAndWaitForDelivery() Only inboundEndpoint and outboundEndpoint are * mandatory, the rest of the parameters are optional. * * @author Magnus Larsson */ public class DispatchParameters { /** * Optional MuleClient, the method will create an own if not supplied. */ private MuleClient muleClient = null; /** * Optional name of sftp-connector, if not supplied it is assumed that only * one sftp-conector is speficied in the mule configuration. If more than one * sftp-connector is specified this paramter has to be specified to point out * what connector to use for the dispatch. */ private String sftpConnector = null; /** * Mandatory name of the inbound endpoint, i.e. where to dispatch the file */ private String inboundEndpoint = null; /** * Optional message headers */ private Map<String, String> headers = null; /** * Optional content of the file, if not specified then it defaults to * AbstractMuleTestCase.TEST_MESSAGE. */ private String message = TEST_MESSAGE; /** * Optional name of the file, defaults to FILE_NAME */ private String filename = FILENAME; /** * Mandatory name of the outbound endpoint, i.e. where we will wait for a * message to be delivered to in the end */ private String outboundEndpoint = null; /** * Optional timeout for how long we will wait for a message to be delivered * to the outbound endpoint */ private long timeout = 100000; public DispatchParameters(String inboundEndpoint, String outboundEndpoint) { this.inboundEndpoint = inboundEndpoint; this.outboundEndpoint = outboundEndpoint; } public MuleClient getMuleClient() { return muleClient; } public void setMuleClient(MuleClient muleClient) { this.muleClient = muleClient; } public String getSftpConnector() { return sftpConnector; } public void setSftpConnector(String sftpConnector) { this.sftpConnector = sftpConnector; } public String getInboundEndpoint() { return inboundEndpoint; } public void setInboundEndpoint(String inboundEndpoint) { this.inboundEndpoint = inboundEndpoint; } public Map<String, String> getHeaders() { return headers; } public void setHeaders(Map<String, String> headers) { this.headers = headers; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } public String getOutboundEndpoint() { return outboundEndpoint; } public void setOutboundEndpoint(String outboundEndpoint) { this.outboundEndpoint = outboundEndpoint; } public long getTimeout() { return timeout; } public void setTimeout(long timeout) { this.timeout = timeout; } } /** * Check that all of the connectors are running. I don't know if this makes a * difference in test reliability per se; it may just delay the start of the test * long enough for the MuleContext to be usable. */ public void checkConnectors() { assertTrue("context is not started", muleContext.getLifecycleManager().getState().isStarted()); Map<String, Connector> connectorMap = muleContext.getRegistry().lookupByType(Connector.class); Map<String, Service> serviceMap = muleContext.getRegistry().lookupByType(Service.class); Map<String, Model> modelMap = muleContext.getRegistry().lookupByType(Model.class); Iterator<Map.Entry<String, Connector>> connectorItr = connectorMap.entrySet().iterator(); while (connectorItr.hasNext()) { Map.Entry<String, Connector> pairs = connectorItr.next(); logger.debug("checking connector : " + pairs.getKey()); assertTrue(pairs.getKey() + " is not started", pairs.getValue().isStarted()); } Iterator<Map.Entry<String, Service>> serviceItr = serviceMap.entrySet().iterator(); while (serviceItr.hasNext()) { Map.Entry<String, Service> pairs = serviceItr.next(); assertTrue(pairs.getKey() + " is not started", pairs.getValue().isStarted()); } Iterator<Map.Entry<String, Model>> modelItr = modelMap.entrySet().iterator(); while (modelItr.hasNext()) { Map.Entry<String, Model> pairs = modelItr.next(); assertTrue(pairs.getKey() + " is not started", pairs.getValue().getLifecycleState().isStarted()); } } @Before public void before() throws Exception { sftpServer = new SftpServer(this.port.getNumber()); sftpServer.start(); sftpClient = getSftpClient(HOST, port.getNumber(), USER, PASSWORD); } }