/*
* Copyright 2013-2015 the original author or authors.
*
* 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/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.xd.shell;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.shell.Bootstrap;
import org.springframework.shell.core.CommandResult;
import org.springframework.shell.core.JLineShellComponent;
import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.IdGenerator;
import org.springframework.xd.dirt.integration.bus.MessageBus;
import org.springframework.xd.dirt.module.ResourceModuleRegistry;
import org.springframework.xd.dirt.server.singlenode.SingleNodeApplication;
import org.springframework.xd.dirt.test.SingleNodeIntegrationTestSupport;
import org.springframework.xd.test.RandomConfigurationSupport;
import org.springframework.xd.test.redis.RedisTestSupport;
/**
* Superclass for performing integration tests of spring-xd shell commands.
*
* JUnit's BeforeClass and AfterClass annotations are used to start and stop the XDAdminServer in local mode with the
* default store configured to use in-memory storage.
*
* Note: This isn't ideal as it takes significant time to startup the embedded XDContainer/tomcat and we should do this
* once across all tests.
*
* @author Mark Pollack
* @author Kashyap Parikh
* @author David Turanski
* @author Ilayaperumal Gopinathan
* @author Gary Russell
* @author Gunnar Hillert
*/
public abstract class AbstractShellIntegrationTest {
public static boolean SHUTDOWN_AFTER_RUN = true;
private final IdGenerator idGenerator = new AlternativeJdkIdGenerator();
@ClassRule
public static RedisTestSupport redisAvailableRule = new RedisTestSupport();
private static final Logger logger = LoggerFactory.getLogger(AbstractShellIntegrationTest.class);
protected static SingleNodeApplication application;
protected static JLineShellComponent shell;
private Set<File> toBeDeleted = new HashSet<File>();
protected static SingleNodeIntegrationTestSupport integrationTestSupport;
protected Random random = new Random();
protected static int adminPort;
/**
* Used to capture currently executing test method.
*/
@Rule
public TestName name = new TestName();
public static synchronized void doStartUp() throws InterruptedException, IOException {
RandomConfigurationSupport randomConfigSupport = new RandomConfigurationSupport();
if (application == null) {
application = new SingleNodeApplication().run("--transport", "local", "--analytics", "redis");
integrationTestSupport = new SingleNodeIntegrationTestSupport(application);
integrationTestSupport.addModuleRegistry(new ResourceModuleRegistry("classpath:/spring-xd/xd/modules"));
String adminServerPort = randomConfigSupport.getAdminServerPort();
adminPort = Integer.valueOf(adminServerPort);
Bootstrap bootstrap = new Bootstrap(new String[] { "--port", adminServerPort });
shell = bootstrap.getJLineShellComponent();
}
if (!shell.isRunning()) {
shell.start();
}
}
public static void doShutdown() {
if (SHUTDOWN_AFTER_RUN) {
logger.info("Stopping XD Shell");
shell.stop();
if (application != null) {
logger.info("Stopping Single Node Server");
application.close();
redisAvailableRule.getResource().destroy();
application = null;
}
System.clearProperty("security.basic.enabled");
System.clearProperty("security.user.name");
System.clearProperty("security.user.password");
System.clearProperty("security.user.role");
}
}
public static void startupWithSecurityAndFullPermissions() throws InterruptedException, IOException {
System.setProperty("security.basic.enabled", "true");
System.setProperty("security.user.name", "admin");
System.setProperty("security.user.password", "whosThere");
System.setProperty("security.user.role", "ADMIN, VIEW, CREATE");
doStartUp();
setTargetWithSecurity(shell, adminPort);
}
public static JLineShellComponent getShell() {
return shell;
}
protected MessageBus getMessageBus() {
return integrationTestSupport.messageBus();
}
protected SubscribableChannel getErrorChannel() {
return application.containerContext().getBean("errorChannel", SubscribableChannel.class);
}
private String generateUniqueName(String name) {
return name + "-" + idGenerator.generateId();
}
private String generateUniqueName() {
return generateUniqueName(name.getMethodName().replace('[', '-').replaceAll("]", ""));
}
protected String generateStreamName(String name) {
return (name == null) ? generateUniqueName() : generateUniqueName(name);
}
protected String generateStreamName() {
return generateStreamName(null);
}
protected String generateQueueName() {
StackTraceElement[] element = Thread.currentThread().getStackTrace();
// Assumption here is that generateQueueName() is called from the @Test method
return "queue:" + element[2].getMethodName() + random.nextInt();
}
protected String getTapName(String streamName) {
return "tap:stream:" + streamName;
}
protected String generateJobName(String name) {
return (name == null) ? generateUniqueName() : generateUniqueName(name);
}
protected String generateJobName() {
return generateJobName(null);
}
protected String getJobLaunchQueue(String jobName) {
return "queue:job:" + jobName;
}
/**
* Execute a command and verify the command result.
*/
protected CommandResult executeCommand(String command) {
CommandResult cr = getShell().executeCommand(command);
if (cr.getException() != null) {
cr.getException().printStackTrace();
}
assertTrue("Failure. CommandResult = " + cr.toString(), cr.isSuccess());
return cr;
}
protected CommandResult executeCommandExpectingFailure(String command) {
CommandResult cr = getShell().executeCommand(command);
assertFalse("Expected command to fail. CommandResult = " + cr.toString(), cr.isSuccess());
return cr;
}
public static void setTargetWithSecurity(JLineShellComponent shell, int adminPort) {
CommandResult result = shell.executeCommand(
"admin config server --uri http://localhost:" + adminPort + " --username admin --password whosThere");
assertThat(result.isSuccess(), is(true));
}
}