【发布时间】:2021-06-21 13:26:29
【问题描述】:
春季批处理项目。有一个 SshIService 接受 ssh 命令并执行它们。当项目在 Jenkins 管道中运行时,它能够创建 ssh 连接并且我的 SshIService 运行良好。
在为此 SshIService 服务编写集成测试时,我创建了一个虚拟 SSH 服务器,该服务可以与之通信。
问题:在集成测试中,当我发送mkdir src/test/resources/Folder1 ; ls src/test/resources/Folder1 ; 之类的命令时,错误是:
mkdir: ls: File exists
mkdir: src/test/resources/Folder1: File exists
mkdir: ;: File exists
服务不认为这些是单独的命令,而是作为mkdir 的参数,这是错误!
该问题并非特定于mkdir。每次在集成测试中执行超过 1 个用分号分隔的命令时,就会出现问题。
我不想对 SshIService 进行更改,因为整个项目一直在使用该逻辑进行工作。问题似乎出在为集成测试创建的 SSH 服务器上。
集成测试代码
@SpringBootTest
@ContextConfiguration(classes = {SshIService.class, SshSftpConfiguration.class})
@ActiveProfiles("test")
public class SshSftpIntegrationTest {
@Autowired
private SshIService SshIService;
private SshServer dummy_sshd;
@SneakyThrows
@BeforeEach
public void setUp() {
dummy_sshd = SshServer.setUpDefaultServer();
dummy_sshd.setPort(9999);
dummy_sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
dummy_sshd.setPasswordAuthenticator((username, password, session) -> username.equals("someUserName") && password.equals("somePassword"));
dummy_sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
dummy_sshd.setCommandFactory(new ProcessShellCommandFactory());
dummy_sshd.start();
}
@SneakyThrows
@AfterEach
public void cleanup() {
dummy_sshd.stop();
}
@SneakyThrows
@Test
public void sendCommandTest() {
SshIService.sendCommand("mkdir src/test/resources/Folder1 ; ls src/test/resources/Folder1 ;");
//Some assertions!
}
}
SshIService 代码
@Slf4j
@Service
public class SshIService {
private final SshSftpConfiguration sshSftpConfiguration;
private final JSch sshTunnel;
private Session sshSession;
private ChannelSftp channelSftp;
public SshIService(SshSftpConfiguration sshSftpConfiguration,
JSch sshTunnel) {
this.sshSftpConfiguration = sshSftpConfiguration;
this.sshTunnel = sshTunnel;
}
public String sendCommand(String command) throws IOException, JSchException, InterruptedException {
try {
connect();
Channel channel = sshSession.openChannel("exec");
((ChannelExec) channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
StringBuilder output = new StringBuilder();
int bytesRead;
byte[] buffer = new byte[1024];
while (!channel.isClosed()) {
while ((bytesRead = in.read(buffer, 0, buffer.length)) != -1) {
output.append(new String(buffer, 0, bytesRead));
}
Thread.sleep(100);
}
channel.disconnect();
return cmdOut;
} catch (IOException | JSchException | InterruptedException ioX) {
log.error("Error: {}", ioX.getMessage());
throw ioX;
}
}
public String getHostAddress() throws UnknownHostException {
return InetAddress.getLocalHost().getHostAddress();
}
public void connect() {
try {
if (sshSession == null || !sshSession.isConnected()) {
sshSession = sshTunnel.getSession(sshSftpConfiguration.getUsername(), sshSftpConfiguration.getHost());
sshSession.setPort(sshSftpConfiguration.getPort());
sshSession.setPassword(sshSftpConfiguration.getPassword());
sshSession.setConfig("StrictHostKeyChecking", "no");
}
if (sshSession != null && !sshSession.isConnected()) {
sshSession.connect();
}
if (sshSession != null && channelSftp == null || !channelSftp.isConnected()) {
channelSftp = (ChannelSftp) sshSession.openChannel("sftp");
channelSftp.connect();
}
} catch (JSchException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
}
public ChannelSftp getChannelSftp() {
return channelSftp;
}
public void setChannelSftp(ChannelSftp channelSftp) {
this.channelSftp = channelSftp;
}
public Session getSshSession() {
return sshSession;
}
public void setSshSession(Session sshSession) {
this.sshSession = sshSession;
}
}
有什么建议吗?
【问题讨论】:
-
既然你有一个
ChannelSftp,为什么不使用它的本地方法(mkDir()、ls()等)而不是使用 exec 通道? -
我无法更改 SshIService 类中的代码。无论必须做什么,都必须在集成测试中。
-
但是你可以在调用
connect()之后使用SshIService.getChannelSftp().mkDir()而不是调用sendCommand()来使用exec通道。 -
在集成测试中,当我尝试
sshSftpService.getChannelSftp().mkdir("src/test/resources/Folder3/test");时,sshSftpService.getChannelSftp()为null。 -
您需要先致电
connect()- 该字段已在那里设置。
标签: java spring ssh spring-batch