【问题标题】:Integration tests - Dummy SSH Server not executing ssh commands correctly集成测试 - 虚拟 SSH 服务器未正确执行 ssh 命令
【发布时间】: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


【解决方案1】:

您不是通过 SSH 连接到真实服务器,而是连接到 Apache Mina SSH 服务器,只有一个 SFTP 子系统。

这并不意味着它可以接受任意 OS/shell 命令。

https://mina.apache.org/sshd-project/

SSHD 的真正目标并不是替代 Unix 操作系统中的 SSH 客户端或 SSH 服务器,而是为需要 SSH 支持的基于 Java 的应用程序提供支持。

【讨论】:

  • 除了 Apache Mina SSH 服务器或 SftpSubsystemFactory 之外,是否还有其他服务器可以在此处使用,并且支持串联命令?或任何其他替代方法来测试sendCommand()
【解决方案2】:

试试 sshIService.sendCommand("mkdir src/test/resources/Folder1 && ls src/test/resources/Folder1 ");

【讨论】:

  • 它最终也创建了一个名为“&&”的文件夹!
  • 我认为这是一个语法错误尝试 SshIService.sendCommand("mkdir src/test/resources/Folder1 ;" ) SshIService.sendCommand("ls src/test/resources/Folder1 ;" )跨度>
  • 目标是发送多个ssh命令(用';'分隔)作为sendCommand()方法的一个输入参数并验证结果。
  • 无法识别“;”您可以尝试使用管道 SshIService.sendCommand ("mkdir src/test/resources/Folder1 | ls src/test/resources/Folder1");
  • 还是同样的问题。 mkdir: src: 文件存在 mkdir: /: 是目录 mkdir: /: 是目录 mkdir: /: 是目录 mkdir: src: 文件存在 mkdir: /: 是目录 mkdir: test: 文件存在 mkdir: /:是目录 mkdir: 资源: 文件存在 mkdir: /: 是目录 mkdir: Folder1: 文件存在
猜你喜欢
  • 2011-03-12
  • 1970-01-01
  • 2013-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-02
相关资源
最近更新 更多