测试Camel sFTP端点

时间:2018-03-19 09:21:07

标签: java testing apache-camel

我有以下路线:

  public void configure() throws Exception {
    // @formatter:off
    from(ftpEndpoint).routeId("import-lib-files")
      .log(INFO, "Processing file: '${headers.CamelFileName}' from Libri-FTP")
        .choice()
          .when(method(isFilenameAlreadyImported))
            .log(DEBUG, "'${headers.CamelFileName}' is already imported.")
        .endChoice()
        .otherwise()
          .bean(method(unzipLibFile))
          .bean(method(persistFilename))
          .log(DEBUG, "Import file '${headers.CamelFileName}'.")
        .endChoice()
      .end()
    .end();
    // @formatter:on
  }

unzipLibFile处理器bean中,来自ftp的文件被解压缩并写入HD。

我想测试(集成测试)这条路线,如:

  1. 将文件复制到ftp
  2. 启动路线
  3. 评估'结果'
  4. 像:

      @Before
      public void setUp() throws Exception {
        // delete test-file from sftp
        final String uploaded = ftpPath + "/" + destination + "/libri-testfile.zip";
        final File uploadedFile = new File(uploaded);
        uploadedFile.delete();
    
        // delete unzipped test-file
        final String unzippedFile = unzipped + "/libri-testfile.xml";
        final File expectedFile = new File(unzippedFile);
        expectedFile.delete();
    
        // delete entries from db
        importedLibFilenameRepository.deleteAll();
    
        // copy file to ftp
        final File source =
        new ClassPathResource("vendors/references/lib.zip/libri-testfile.zip").getFile();
        final String target = ftpPath + "/" + destination + "/libri-testfile.zip";
        FileUtils.copyFile(new File(source.getAbsolutePath()), new File(target));
      }
    
    
      @Test
      @Ignore
      public void testStuff() throws Exception {
        // Well here is a problem, I can't fix at the moment
        // the Camel-Context within the SpringContext get started when the tests starts
        // during this process the Camel-Routes are executed and because i copied the file to
        // the ftp all is fine... but I don't want to have a sleep in a test, I want to start the
        // route (like commented code beneath the sleep)
        Thread.sleep(2000);
    
    //    final Map<String, Object> headers = Maps.newHashMap();
    //    headers.put("CamelFileName", "libri-testfile.zip");
    //
    //    final File file =
    //        new ClassPathResource("vendors/references/lib.zip/libri-testfile.zip").getFile();
    //    final GenericFile<File> genericFile =
    //        FileConsumer.asGenericFile(file.getParent(), file, StandardCharsets.UTF_8.name(), false);
    //
    //    final String uri = libFtpConfiguration.getFtpEndpoint();
    //    producer.sendBodyAndHeaders(uri, InOut, genericFile, headers);
    
        // test if entry was made in the database
        final List<ImportedLibFilename> filenames = importedLibFilenameRepository.findAll();
        assertThat(filenames).usingElementComparatorIgnoringFields("id", "timestamp")
        .containsExactly(expectedFilename("libri-testfile.zip"));
    
        // test if content of unzipped file is valid
        final String expected = unzipped + "/libri-testfile.xml";
        final Path targetFile = Paths.get(expected);
        final byte[] encoded = Files.readAllBytes(targetFile);
        final String actualFileContent = new String(encoded, Charset.defaultCharset());
    
        final String expectedFileContent = "This is my little test file for Libri import";
        assertThat(actualFileContent).isEqualTo(expectedFileContent);
      }
    
      private ImportedLibFilename expectedFilename(final String filename) {
        final ImportedLibFilename entity = new ImportedLibFilename();
        entity.setFilename(filename);
        return entity;
      }
    

    问题是:   所有驼峰路线都是自动启动的,因为我将文件复制到FTP,测试是绿色的。但是我的测试里面有一个#sleep,我不想要。我不希望骆驼路线开始,只启动我需要的路线。

    我的问题是:

    1. 如何防止Camel-Routes自动启动
    2. 注释代码(在测试方法中)是否是手动启动路径的正确方法?
    3. 使用ftp
    4. 测试驼峰路线的最佳做法是什么

2 个答案:

答案 0 :(得分:2)

  1. 在路线中使用.autoStartup(yourVariable)以使其启动可配置。在正常环境中将变量设置为true,在测试用例中设置为false
  2. 我没有看到启动路线的代码?!?
  3. 好吧,退后一步。考虑拆分FTP路由。有关测试和更多原因:
  4. 例如,将路由拆分为FTP和处理路由。第一个只进行FTP传输,然后将收到的消息发送到处理路由(例如direct:路由)。

    好处:

    • SRP:这两条路线只做一件事,你可以集中注意力。
    • 可测试性:您可以通过向处理路由的direct:端点发送消息来轻松测试处理路由。测试也可以关注一件事。
    • 可扩展性:想象一下有一个新的输入通道(JMS,HTTP,无论如何)。然后,您只需添加另一个也发送到处理路径的输入路径。完成。

    如果您真的要从FTP文件中删除测试整个过程,请考虑使用Citrus test framework或类似的工具。骆驼路线测试(在我看来)是一种对Camel路线&#34;进行的单元测试,而不是完整的集成测试。

答案 1 :(得分:0)

Thx to @burki ...

他建议拆分路线(单一责任)帮助我解决了我的问题:

这是路线:

从sFTP消费的“主要路线”:

  @Override
  public void configure() throws Exception {
    // @formatter:off
    from(endpoint)
      .setHeader("Address", constant(address))
      .log(INFO, "Import Libri changeset: Consuming from '${headers.Address}' the file '${headers.CamelFileName}'.")
      .to("direct:import-new-file");
    // @formatter:on
  }

第一个子路线:

  @Override
  public void configure() throws Exception {
    // @formatter:off
    from("direct:import-new-file")
        .choice()
          .when(method(isFilenameAlreadyImported))
          .log(TRACE, "'${headers.CamelFileName}' is already imported.")
        .endChoice()
        .otherwise()
          .log(TRACE, "Import file '${headers.CamelFileName}'.")
          .multicast()
          .to("direct:persist-filename", "direct:unzip-file")
        .endChoice()
      .end()
    .end();
    // @formatter:on
  }

两个多播:

  @Override
  public void configure() throws Exception {
    // @formatter:off
      from("direct:persist-filename")
        .log(TRACE, "Try to write filename '${headers.CamelFileName}' to database.")
        .bean(method(persistFilename))
      .end();
    // @formatter:on
  }

  @Override
  public void configure() throws Exception {
    // @formatter:off
      from("direct:unzip-file")
        .log(TRACE, "Try to unzip file '${headers.CamelFileName}'.")
        .bean(method(unzipFile))
      .end();
    // @formatter:on
  }

通过这种设置,我可以编写我的测试,如:

  @Test
  public void testRoute_validExtractedFile() throws Exception {
    final File source = ZIP_FILE_RESOURCE.getFile();
    producer.sendBodyAndHeaders(URI, InOut, source, headers());

    final String actual = getFileContent(unzippedPath, FILENAME);
    final String expected = "This is my little test file for Libri import";
    assertThat(actual).isEqualTo(expected);
  }

  @Test
  public void testRoute_databaseEntryExists() throws Exception {
    final File source = ZIP_FILE_RESOURCE.getFile();
    producer.sendBodyAndHeaders(URI, InOut, source, headers());

    final List<ImportedFilename> actual = importedFilenameRepository.findAll();
    final ImportedFilename expected = importedFilename(ZIPPED_FILENAME);
    assertThat(actual).usingElementComparatorIgnoringFields("id", "timestamp")
    .containsExactly(expected);
  }

  private String getFileContent(final String path, final String filename) throws IOException {
    final String targetFile = path + "/" + filename;
    final byte[] encodedFileContent = Files.readAllBytes(Paths.get(targetFile));
    return new String(encodedFileContent, Charset.defaultCharset());
  }

  private Map<String, Object> headers() {
    final Map<String, Object> headers = Maps.newHashMap();
    headers.put("CamelFileName", ZIPPED_FILENAME);
    return headers;
  }

我可以使用ProducerTemplate(生产者)启动camel路由,并将消息发送到直接端点(而不是ftp端点)。