java - JSch 算法协商仅在单元测试中失败

标签 java junit powermock jsch

我正在使用 JSch 执行 sftp get 操作。当我使用 main 方法运行测试时,一切都很好,但使用单元测试时我遇到了问题。错误如下:

java.lang.RuntimeException: com.jcraft.jsch.JSchException: Algorithm negotiation fail

这是失败的方法:

private ChannelSftp sftpInitKeyfile(String host, String username, String keyfile, int port) throws IOException, JSchException {
    JSch jsch = new JSch();
    byte[] keyBytes = Resources.toByteArray(Resources.getResource(keyfile));
    jsch.addIdentity(username, keyBytes, null, null);

    Session session = jsch.getSession(username, host, port);
    session.setConfig("StrictHostKeyChecking", "no");
    session.connect(); // This line is what's failing

    ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
    sftpChannel.connect();
    return sftpChannel;
}

我做了一些记录,发现了一些我无法弄清楚的差异。这是我运行主要方法时的日志:

Connecting to (redacted) port 22
Connection established
Remote version string: SSH-2.0-OpenSSH_5.3
Local version string: SSH-2.0-JSCH-0.1.53
CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256
aes256-ctr is not available.
aes192-ctr is not available.
aes256-cbc is not available.
aes192-cbc is not available.
CheckKexes: diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521
diffie-hellman-group14-sha1 is not available.
CheckSignatures: ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
SSH_MSG_KEXINIT sent
SSH_MSG_KEXINIT received

这是我运行单元测试时的日志:

Connecting to (redacted) port 22
Connection established
Remote version string: SSH-2.0-OpenSSH_5.3
Local version string: SSH-2.0-JSCH-0.1.53
CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256
aes256-ctr is not available.
aes192-ctr is not available.
aes128-ctr is not available.
aes256-cbc is not available.
aes192-cbc is not available.
aes128-cbc is not available.
3des-ctr is not available.
CheckKexes: diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521
diffie-hellman-group14-sha1 is not available.
ecdh-sha2-nistp256 is not available.
ecdh-sha2-nistp384 is not available.
ecdh-sha2-nistp521 is not available.
CheckSignatures: ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
SSH_MSG_KEXINIT sent
SSH_MSG_KEXINIT received

请注意,第二个日志中的“不可用”消息比第一个日志更多,最明显的是密码下的 aes128-ctr 和 kexes 下的 ecdh-sha2-nistp256。我不明白为什么,他们都使用相同的库调用相同的代码。无论我在 IntelliJ 中运行单元测试还是通过命令行上的 mvn test 运行单元测试,都会发生这种情况。可能是什么原因造成的?我正在运行 JUnit 4.1.2 和 powermock 1.6.2。

以下是支持代码失败的测试之一:

@RunWith(PowerMockRunner.class)
@PrepareForTest( {DCGSGenerator.class, DocumentHelper.class, ZipFile.class, String.class, IOUtils.class, JBlocksClassificationToVisibility.class} )
public class DCGSGeneratorTest {

    public static Properties properties;

    @BeforeClass
    public static void setUp() throws Exception {

        InputStream propertiesStream = DCGSGeneratorTest.class.getClassLoader().getResourceAsStream("ezbake-config.properties");
        properties = new Properties();
        properties.load(propertiesStream);
    }

    @Test
    public void generateTest() throws Exception {
        PowerMockito.mockStatic(DCGSGenerator.class);
        PowerMockito.doNothing().when(DCGSGenerator.class, "deleteFile", any(String.class));
        PowerMockito.doCallRealMethod().when(DCGSGenerator.class, "classificationFromDoc", any(Document.class));

        DCGSGenerator generator = PowerMockito.spy(createGenerator("sample_data"));

        PowerMockito.doNothing().when(generator, "outputToPipes", Mockito.isA(Visibility.class), Mockito.isA(String.class));

        generator.generate();

        PowerMockito.verifyPrivate(generator, VerificationModeFactory.times(7)).invoke("outputToPipes", Mockito.isA(Visibility.class), Mockito.isA(String.class));
    }

    private DCGSGenerator createGenerator(String dir) {
        return new DCGSGenerator(
                properties.getProperty("dcgs.input.sftp.host"),
                properties.getProperty("dcgs.input.sftp.username"),
                null,//properties.getProperty("dcgs.input.sftp.password", null),
                properties.getProperty("dcgs.input.sftp.keyfile", null),
                22,
                String.format("%s/%s", properties.getProperty("dcgs.input.sftp.path"), dir)
        );
    }
}

这是我的主要方法:

public static void main(String[] args) throws IOException {
    InputStream propertiesStream = DCGSGenerator.class.getClassLoader().getResourceAsStream("ezbake-config.properties");
    Properties properties = new Properties();
    properties.load(propertiesStream);
    DCGSGenerator gen = new DCGSGenerator(
            properties.getProperty("dcgs.input.sftp.host"),
            properties.getProperty("dcgs.input.sftp.username"),
            null,//properties.getProperty("dcgs.input.sftp.password", null),
            properties.getProperty("dcgs.input.sftp.keyfile", null),
            22,
            properties.getProperty("dcgs.input.sftp.path")
    );
    gen.generate();
}

最后是有问题的构造函数:

public DCGSGenerator(String sftpHost, String sftpUser, String sftpPassword, String sftpKeyfile, int sftpPort, String sftpPath) {
        super();

        try {
            this.sftpPath = sftpPath;
            if (sftpKeyfile != null) {
                sftp = sftpInitKeyfile(sftpHost, sftpUser, sftpKeyfile, sftpPort);
            } else {
                LOGGER.error("Must specify either sftp keyfile");
                throw new RuntimeException();
            }
        } catch (JSchException e) {
            LOGGER.error("Error initializing sftp connection: {}", e.getMessage());
            throw new RuntimeException(e);
        } catch (IOException e) {
            LOGGER.error("Error reading keyfile {}: {}", sftpKeyfile, e.getMessage());
            throw new RuntimeException(e);
        }
    }
}

最佳答案

我明白了。尽管我没有明确 mock 与 JSch 相关的任何内容,但看起来 PowerMockito 搞砸了一些事情。

@PowerMockIgnore("com.jcraft.jsch.*")

这样就解决了。

关于java - JSch 算法协商仅在单元测试中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35635578/

相关文章:

java - 创建 Maven 项目,无法解析原型(prototype),连接被拒绝

java - Mockito 模拟不适用于此方法。难道我做错了什么?

java - 使用@Mock注解的对象是否应该设置详细值?

android - 如何模拟采用回调对象和调用者使用回调委托(delegate)结果的方法

java - 如何使用camel和Spring监听activemq?

java - 野蝇中的 headless 异常

java - Tomcat(6) 在将文本包含到结果 html 之前从 bean 中转义文本

java - 如何在play framework中编写模板测试代码?

java - 在仪器测试期间将大写字母发送到 TextEdit

java - 将 Powermock 与 Weld 混合使用?