0

我想正确的单元和集成测试用例来测试所有的功能流程。有人可以分享您对我如何创建模拟端点来监视目录以进行文件创建并通过多个路由进一步处理它们并将文件移动到不同目录的想法。

  1. 监视/hello目录以创建新文件。
  2. 如果存在基于文件前缀的文件,则使用容器名称更新标头。
  3. 根据文件名上传到适当的 azure blob 容器。
  4. 处理后进行 api 调用并将文件移动到/success目录。

FileWatcherRoute.java

@Service
public class FileWatcherRoute extends RouteBuilder {

  @Value("${watcher-base-url}")
  private String baseUrl;

  @Value("${watcher-subscription-key}")
  private String subscriptionKey;

  @Override
  public void configure() {

    Processor logResponse = exchange -> log
        .info("The response code is: {}", exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE));

    from("file-watch:hello?events=CREATE&antInclude=**/*.csv&recursive=true")
        .routeId("fileWatch")
        .to("direct:updateHeaders")
        .end();

    from("direct:updateHeaders")
        .routeId("updateHeaders")
        .choice()

            .when((exchange -> exchange.getIn().getHeader(Exchange.FILE_NAME).toString().trim().matches("\\d{8}_\\d{4}(_Inventory.csv)")))
            .setHeader("CamelAzureStorageBlobContainerName", constant(AppConstants.STORE))

                        .when(exchange -> exchange.getIn().getHeader(Exchange.FILE_NAME).toString().trim().matches("\\d{8}-\\d{6}_Idle_Inventory_\\d{4}.csv"))
            .setHeader("CamelAzureStorageBlobContainerName",constant(AppConstants.IDLE_FILE))

        .toD("direct:uploadFileToBlob")
        .end();

    from("direct:uploadFileToBlob")
        .routeId("uploadFile")
        .log("Container Name: ${header.CamelAzureStorageBlobContainerName}")
        .toD("azure-storage-blob://{accName}/${header.CamelAzureStorageBlobContainerName}?blobName=${header.CamelFileName}&operation=uploadBlockBlob&serviceClient=#serviceClient")
        .to("direct:startRestApi")
        .log("${header.CamelFileName} Uploaded to ${header.CamelAzureStorageBlobContainerName} Container Successfully")
        .end();


    from("direct:startRestApi")
        .routeId("restCall")
        .setHeader(Exchange.HTTP_METHOD, constant("GET"))
        .setHeader("Content-Type",constant("application/json"))
        .setHeader("Ocp-Apim-Subscription-Key",constant(subscriptionKey))
        .to(baseUrl)
        .to("direct:processedFiles")
        .process(logResponse)
        .end();

    from("direct:processedFiles")
        .routeId("fileProcessing")
        .choice()
        .when(exchange -> exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE).equals(200))
        .to("file://success")
        .otherwise()
        .to("file://error")
        .end();
  }
}

FileWatcherRouteTest.java

@CamelSpringBootTest
@SpringBootTest
@MockEndpoints
@UseAdviceWith
public class FileWatcherRouteTest {

  @Autowired
  CamelContext camelContext;

  @Autowired
  ProducerTemplate producerTemplate;

  @EndpointInject("mock:processedFiles")
  MockEndpoint mockEndpoint;

  @Test
  void when_new_file_created_should_update_header_with_container_name_and_upload_to_container() throws Exception {

    AdviceWith.adviceWith(camelContext, "fileWatch", routeBuilder -> {
      routeBuilder.replaceFromWith("direct:file-watch");
    });

    camelContext.start();
    mockEndpoint.assertIsSatisfied();

  }

}
4

1 回答 1

1

MockEndpoint only supports producer endpoints. This is due to the fact that it is designed to perform assertions to Exchanges and Messages.

For example:

  • Does the given MockEndpoint receive the correct amount of messages
  • Does the message body match with what is expected.
  • Where the required headers provided to the MockEndpoint

When testing a route you should use ProducerTemplate send methods to start the route under test with whatever body, headers and properties you want to test with it.

In your case you can use java file operations to read a file from test resources folder as string, byte array or stream and use send it as body along with headersCamelFileName and CamelFileEventType to target route.

I would also recommend treating your direct routes like functions to make them easier to test. Meaning that instead of jumping from route to route you could have parent route that just calls the child routes in correct order.

from("file-watch:hello?events=CREATE&antInclude=**/*.csv&recursive=true")
    .routeId("fileWatch")
    .to("direct:processNewFile")

// "Parent route"
from("direct:processNewFile")
    .routeId("processCreatedFile")
    .to("direct:updateHeaders")
    .to("direct:uploadFileToBlob")
    .to("direct:processedFiles")

This allows you easily write individual tests for direct:updateHeaders, direct:uploadFileToBlob and direct:processedFiles

For example:

  • Test that direct:uploadFileToBlob throws proper exception if one of the required headers is missing or somehow invalid.
  • Test that direct:uploadFileToBlob properly handles connection exceptions with azure.
  • Test that direct:processedFiles places files to correct folders.

If you want to test file output you can use JUnits TemporaryFolder to create temporary folder which you can then target with your file producer endpoint. After route has completed you can use basic assertEquals and file operations to check whether the output meets your test requirements.

Apache Commons IO is also pretty handy library for tests for reading files from resources and copying files to TemporaryFolder.

Couple examples with files, ProducerTemplate, Commons IO and CamelTestSupport:

package com.example;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.camel.Exchange;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class ExampleTest  extends CamelTestSupport {
    
    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();
    
    File inputFolder;
    File outputFolder;

    @Test
    public void temporaryFolderExampleTest() throws Exception {

        context.adviceWith(context.getRouteDefinition("processInputFile"), 
            new AdviceWithRouteBuilder(){

                @Override
                public void configure() throws Exception {
                    
                    replaceFromWith("direct:start");

                    weaveAddLast()
                        .to("mock:result");
                }
            }
        );

        MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
        resultMockEndpoint.expectedMessageCount(1);
        resultMockEndpoint.message(0).body().isEqualTo("Hello world!");

        InputStream body = fetchFileFromResourcesFolderAsStream("test-files/Hello.txt");
        Map<String, Object> headers = new HashMap<>();
        headers.put(Exchange.FILE_NAME, "Hello.txt");

        startCamelContext();
        template.sendBodyAndHeaders("direct:start", body, headers);

        resultMockEndpoint.assertIsSatisfied();

        File resultFile = new File(outputFolder, "Hello.txt");
        assertEquals(true, resultFile.exists());

        // FileUtils from commons-io/commons-io/2.11.0
        String result = FileUtils.readFileToString(resultFile, StandardCharsets.UTF_8);
        assertEquals("Hello world!", result);
    }

    @Test
    public void pollEnrichExampleTest() throws Exception {

        context.adviceWith(context.getRouteDefinition("pollEnrichExample"), 
            new AdviceWithRouteBuilder(){

                @Override
                public void configure() throws Exception {

                    weaveAddLast()
                        .to("mock:result");
                }
            }
        );

        MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
        resultMockEndpoint.expectedMessageCount(1);
        resultMockEndpoint.message(0).body().isEqualTo("Hello");

        File resourceFile = fetchFileFromResourcesFolder("test-files/Hello.txt");
        File testFile = new File(outputFolder, "Hello.txt");
        FileUtils.copyFile(resourceFile, testFile);
        
        startCamelContext();
        template.sendBody("direct:pollEnrichExample", null);

        resultMockEndpoint.assertIsSatisfied();
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
    
        return new RouteBuilder() {

            @Override
            public void configure() throws Exception {
             
                from("file:{{file.input}}")
                    .routeId("processInputFile")
                    .convertBodyTo(String.class)
                    .setBody(simple("${body} world!"))
                    .log("${body}")
                    .to("file:{{file.output}}");

                from("direct:pollEnrichExample")
                    .routeId("pollEnrichExample")
                    .pollEnrich("file:{{file.output}}", 3000)
                    .convertBodyTo(String.class)
                    .log("${body}");
            }
        };
    }

    // use of placeholder properties and configuration files is highly encouraged
    @Override
    protected Properties useOverridePropertiesWithPropertiesComponent() {
        
        try {
            inputFolder = temporaryFolder.newFolder("input");
            outputFolder = temporaryFolder.newFolder("output");

        } catch (Exception e) {
            e.printStackTrace();
        }

        Properties prop = new Properties();
        prop.setProperty("file.input", inputFolder.getPath());
        prop.setProperty("file.output", outputFolder.getPath());
        return prop;
    }

    @Override
    public boolean isUseAdviceWith() {
        return true;
    }

    public File fetchFileFromResourcesFolder(String pathInResources){
        
        ClassLoader classLoader = ExampleTest.class.getClassLoader();
        return new File(classLoader.getResource(pathInResources).getFile());
    }

    public InputStream fetchFileFromResourcesFolderAsStream(String pathInResources){

        try {
            return new FileInputStream(fetchFileFromResourcesFolder(pathInResources));   
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>

Above examples using Camel 3.4.4

于 2022-01-04T21:14:39.097 回答