Java 柑橘框架-来自SUT的未解释HTTP 503

Java 柑橘框架-来自SUT的未解释HTTP 503,java,spring-boot,spring-rest,citrus-framework,Java,Spring Boot,Spring Rest,Citrus Framework,背景: 我有一个简单的Spring启动应用程序,由三个服务组成。这些服务通过HTTP REST调用进行通信。以下是服务的简要说明 任务规划器(localhost:9100) 协调任务的“规划”。调用Route Generator和Route Assessor服务来执行此工作。“计划任务”操作由来自“客户”的帖子(/v1/missionServices/missionPlanning/planMission)触发。将向调用者返回一条简单的响应消息 路由生成器(localhost:9110)

背景

我有一个简单的Spring启动应用程序,由三个服务组成。这些服务通过HTTP REST调用进行通信。以下是服务的简要说明

  • 任务规划器(
    localhost:9100

    • 协调任务的“规划”。调用Route Generator和Route Assessor服务来执行此工作。“计划任务”操作由来自“客户”的帖子(
      /v1/missionServices/missionPlanning/planMission
      )触发。将向调用者返回一条简单的响应消息
  • 路由生成器(
    localhost:9110

    • 由任务规划器调用时生成“路由”(
      /v1/missionServices/missionPlanning/generaterout
      )。向任务规划器返回响应消息
  • 路线评估员(
    localhost:9120

    • 当任务计划员调用时,评估生成的“路线”(
      /v1/missionServices/missionPlanning/assessRoute
      )。向任务规划器返回响应消息
任务规划器“客户端”是第四个服务,通过向任务规划器发送POST请求来触发“计划任务”流程。这不是集成测试的一部分。取而代之的是柑橘测试

目标

我正试图使用Citrus框架单独或作为一个整体(端到端)对服务执行集成测试。我成功地使用了更简单的服务案例(即路线生成器和路线评估器),但测试任务规划器已证明存在许多困难

下面是我为任务计划员编写的柑橘测试。目前我正在“模拟”路由生成器和路由评估器服务,但对于端到端测试,我需要弄清楚如何做到这一点,这三个服务都将“运行”——我现在不担心这一点。我是根据我所发现的例子和我在经历中所学到的东西来构建这个模型的

MissionPlannerIT.java:

public class MissionPlannerIT extends JUnit4CitrusTest {

  @Autowired
  @Qualifier("routeGeneratorServer")
  private HttpServer rgServer;
  @Autowired
  @Qualifier("routeAssessorServer")
  private HttpServer raServer;

  @Autowired
  @Qualifier("missionPlannerClient")
  private HttpClient sutClient;

  @Test
  @CitrusTest
  // @formatter:off
  public void testPlanMission(@CitrusResource TestRunner runner) {
    runner.description("Test mission planning 'plan mission' REST endpoint");

    // Call mission planner to plan a mission.
    runner.http(builder -> builder
        .client(sutClient)
        .send()
        .post("/v1/missionServices/missionPlanning/planMission"));
    runner.echo("Sent plan mission");

    // Set route generator to receive and validate generate route command.
    runner.http(builder -> builder
        .server(rgServer)
        .receive()
        .post("/v1/missionServices/missionPlanning/generateRoute")
        .accept(ContentType.APPLICATION_JSON.getMimeType())
        .payload(new ClassPathResource("templates/gen-route-command.json")));
    runner.echo("RG received generate route");

    // Set route generator to return response.
    runner.http(builder -> builder
        .server(rgServer)
        .send()
        .response(HttpStatus.OK)
        .messageType(MessageType.JSON)
        .contentType(ContentType.APPLICATION_JSON.getMimeType())
        .payload(new ClassPathResource("templates/gen-route-status.json")));
    runner.echo("RG sent generate route status");

    // Set route assessor to receive and validate assess route command.
    runner.http(builder -> builder
        .server(raServer)
        .receive()
        .post("/v1/missionServices/missionPlanning/assessRoute")
        .accept(ContentType.APPLICATION_JSON.getMimeType())
        .payload(new ClassPathResource("templates/assess-route-command.json")));
    runner.echo("RA received assess route");

    // Set route assessor to return response.
    runner.http(builder -> builder
        .server(raServer)
        .send()
        .response(HttpStatus.OK)
        .messageType(MessageType.JSON)
        .contentType(ContentType.APPLICATION_JSON.getMimeType())
        .payload(new ClassPathResource("templates/assess-route-status.json")));
    runner.echo("RA sent assess route status");

    // Expect a success response from mission planner.
    runner.http(builder -> builder
        .client(sutClient)
        .receive()
        .response(HttpStatus.OK)
        .messageType(MessageType.JSON)
        .payload(new ClassPathResource("templates/plan-mission-response.json")));
    runner.echo("Received MP response");

    // Shut down route services. TODO may not need this
    runner.stop(rgServer);
    runner.stop(raServer);
  }
  // @formatter:on

}
EndpointConfig.java:

@Configuration
public class EndpointConfig {

  @Bean
  public HttpClient missionPlannerClient() {
    return CitrusEndpoints.http().client().requestUrl("http://localhost:9100").build();
  }

  @Bean
  public Server routeGeneratorServer() {
    return CitrusEndpoints.http().server().port(9110).timeout(10000).autoStart(true).build();
  }

  @Bean
  public Server routeAssessorServer() {
    return CitrusEndpoints.http().server().port(9120).timeout(10000).autoStart(true).build();
  }

  @Bean("defaultJsonMessageValidator")
  public JsonTextMessageValidator jsonValidator() {
    return new JsonTextMessageValidator();
  }

}
我运行此测试的方法有两种:1)作为maven构建的一部分,2)使用eclipse。我在以maven构建运行它时遇到了问题,其中大多数测试控制台输出都不是输出(请参阅和)。当我通过eclipse运行它时,我需要在运行测试之前手动启动mission planner

输出

我将包含来自eclipse运行方法的部分控制台日志,因为它包含使用maven方法时丢失的信息。我会尽量将我认为相关的部分包括在内,并在整个过程中包括我的笔记/想法

总结:

  • 测试步骤1:发送-向任务计划员发送初始POST以启动流程
  • 测试步骤3:接收-将模拟路线生成器设置为接收任务计划员发出的生成路线的POST请求
  • 测试步骤5:发送-设置模拟路由生成器以返回响应消息
  • 测试步骤7:接收-将模拟路线评估器设置为接收任务计划员的POST请求,以评估路线
  • 测试步骤9:发送-设置模拟路由评估器以返回响应消息
  • 测试步骤11:接收-期望从任务规划器接收响应消息
测试步骤1-执行首次向任务计划员发布以启动流程:

15:00:50.689 [main] DEBUG com.consol.citrus.report.LoggingReporter - TEST STEP 1: send
15:00:52.598 [main] DEBUG com.consol.citrus.message.correlation.DefaultCorrelationManager - Saving correlation key for 'citrus_message_correlator_missionPlannerClient'
15:00:52.598 [main] DEBUG com.consol.citrus.context.TestContext - Setting variable: citrus_message_correlator_missionPlannerClient with value: 'citrus_message_id = '3f242515-7eb2-4aed-a85c-53a4560029b4''
15:00:52.598 [main] DEBUG com.consol.citrus.http.client.HttpClient - Sending HTTP message to: 'http://localhost:9100/v1/missionServices/missionPlanning/planMission'
15:00:52.598 [main] DEBUG com.consol.citrus.http.client.HttpClient - Message to send:

15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - outboundHeaderNames=[Accept, Accept-Charset, Accept-Encoding, Accept-Language, Accept-Ranges, Authorization, Cache-Control, Connection, Content-Length, Content-Type, Cookie, Date, Expect, From, Host, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Max-Forwards, Pragma, Proxy-Authorization, Range, Referer, TE, Upgrade, User-Agent, Via, Warning]
15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - headerName=[citrus_message_timestamp] WILL NOT be mapped
15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - headerName=[citrus_message_type] WILL NOT be mapped
15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - headerName=[citrus_request_path] WILL NOT be mapped
15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - headerName=[citrus_http_request_uri] WILL NOT be mapped
15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - headerName=[id] WILL NOT be mapped
15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - headerName=[citrus_message_id] WILL NOT be mapped
15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - headerName=[citrus_http_method] WILL NOT be mapped
15:00:52.601 [main] DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper - headerName=[timestamp] WILL NOT be mapped
15:00:52.607 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP POST http://localhost:9100/v1/missionServices/missionPlanning/planMission
15:00:52.610 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
15:00:52.611 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [] as "text/plain;charset=UTF-8"
15:00:52.656 [main] DEBUG com.consol.citrus.http.interceptor.LoggingClientInterceptor - Sending Http request message
15:00:52.657 [main] DEBUG Logger.Message_OUT - POST http://localhost:9100/v1/missionServices/missionPlanning/planMission
Accept:text/plain, application/json, application/*+json, */*
Content-Type:text/plain;charset=UTF-8
Content-Length:0
Accept-Charset:big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1166, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp
我假设这是记录活动,表明任务计划员已向路线生成器发出POST请求:

15:00:52.801 [qtp923083575-34] DEBUG org.eclipse.jetty.server.HttpChannel - REQUEST for //localhost:9110/v1/missionServices/missionPlanning/generateRoute on HttpChannelOverHttp@4df838fc{r=1,c=false,c=false/false,a=IDLE,uri=//localhost:9110/v1/missionServices/missionPlanning/generateRoute,age=1}
POST //localhost:9110/v1/missionServices/missionPlanning/generateRoute HTTP/1.1
Accept: application/json
Content-Type: application/json
elastic-apm-traceparent: 00-eb0d1dffcf09adda45d39323efc6f883-7236b8b42e4e90d5-01
Content-Length: 311
Host: localhost:9110
Connection: keep-alive
User-Agent: Apache-HttpClient/4.5.9 (Java/1.8.0_201)
Accept-Encoding: gzip,deflate

...
15:00:52.828 [qtp923083575-34] DEBUG com.consol.citrus.http.interceptor.LoggingHandlerInterceptor - Received Http request:
HTTP/1.1 POST /v1/missionServices/missionPlanning/generateRoute
elastic-apm-traceparent:00-eb0d1dffcf09adda45d39323efc6f883-7236b8b42e4e90d5-01
Accept:application/json
Connection:keep-alive
User-Agent:Apache-HttpClient/4.5.9 (Java/1.8.0_201)
Host:localhost:9110
Accept-Encoding:gzip,deflate
Content-Length:311
Content-Type:application/json
{"header":{"timestamp":1581364852723,"typeID":"edu.mit.ll.mission_services.messages.GenerateRouteCommand","transaction":{"id":2,"startTime":1581364852723},"signature":{"algorithm":null,"keySize":0,"keyValue":null,"sender":null}},"commandID":"60b684f1-5065-47d6-8e7d-a4f101b44d22","commandType":"GENERATE_ROUTE"}
...
15:00:52.851 [qtp923083575-34] DEBUG com.consol.citrus.channel.ChannelSyncProducer - Sending message to channel: 'routeGeneratorServer.inbound'
15:00:52.851 [qtp923083575-34] DEBUG com.consol.citrus.channel.ChannelSyncProducer - Message to send is:
HTTPMESSAGE [id: 900d8f51-b1cf-427e-9f00-cd5b242b5dca, payload: {"header":{"timestamp":1581364852723,"typeID":"edu.mit.ll.mission_services.messages.GenerateRouteCommand","transaction":{"id":2,"startTime":1581364852723},"signature":{"algorithm":null,"keySize":0,"keyValue":null,"sender":null}},"commandID":"60b684f1-5065-47d6-8e7d-a4f101b44d22","commandType":"GENERATE_ROUTE"}][headers: {Accept=application/json, Connection=keep-alive, User-Agent=Apache-HttpClient/4.5.9 (Java/1.8.0_201), Host=localhost:9110, Accept-Encoding=gzip,deflate, Content-Length=311, contentType=application/json;charset=UTF-8, citrus_message_id=900d8f51-b1cf-427e-9f00-cd5b242b5dca, citrus_message_timestamp=1581364852849, elastic-apm-traceparent=00-eb0d1dffcf09adda45d39323efc6f883-7236b8b42e4e90d5-01, Content-Type=application/json;charset=UTF-8, citrus_http_request_uri=/v1/missionServices/missionPlanning/generateRoute, citrus_request_path=/v1/missionServices/missionPlanning/generateRoute, citrus_endpoint_uri=/v1/missionServices/missionPlanning/generateRoute, citrus_http_context_path=, citrus_http_query_params=, citrus_query_params=, citrus_http_version=HTTP/1.1, citrus_http_method=POST}]
15:00:52.851 [qtp923083575-34] INFO com.consol.citrus.channel.ChannelSyncProducer - Message was sent to channel: 'routeGeneratorServer.inbound'
15:00:57.729 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "HTTP/1.1 503 Service Unavailable[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Date: Mon, 10 Feb 2020 20:00:52 GMT[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "X-Content-Type-Options: nosniff[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "X-XSS-Protection: 1; mode=block[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Pragma: no-cache[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "X-Frame-Options: DENY[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "X-Content-Type-Options: nosniff[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Content-Type: application/json;charset=utf-8[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "Transfer-Encoding: chunked[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "B0[\r][\n]"
15:00:57.730 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "{"timestamp":"2020-02-10T20:00:57.728+0000","status":503,"error":"Service Unavailable","message":"Service Unavailable","path":"/v1/missionServices/missionPlanning/planMission"}"
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << HTTP/1.1 503 Service Unavailable
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Date: Mon, 10 Feb 2020 20:00:52 GMT
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << X-Content-Type-Options: nosniff
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << X-XSS-Protection: 1; mode=block
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Pragma: no-cache
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << X-Frame-Options: DENY
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << X-Content-Type-Options: nosniff
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Content-Type: application/json;charset=utf-8
15:00:57.736 [main] DEBUG org.apache.http.headers - http-outgoing-0 << Transfer-Encoding: chunked
15:00:57.747 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Connection can be kept alive indefinitely
15:00:57.751 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\r][\n]"
15:00:57.751 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "0[\r][\n]"
15:00:57.751 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "[\r][\n]"
完成测试步骤1:

15:00:57.760 [main] DEBUG com.consol.citrus.message.correlation.DefaultCorrelationManager - Saving correlated object for 'citrus_message_id = '3f242515-7eb2-4aed-a85c-53a4560029b4''
15:00:57.760 [main] INFO com.consol.citrus.report.LoggingReporter - 
15:00:57.760 [main] DEBUG com.consol.citrus.report.LoggingReporter - TEST STEP 1 SUCCESS
测试步骤3-模拟路线生成器接收任务计划员的请求:

15:00:57.779 [main] DEBUG com.consol.citrus.util.FileUtils - Reading file resource: 'gen-route-command.json' (encoding is 'UTF-8')
15:00:57.781 [main] INFO com.consol.citrus.report.LoggingReporter - 
15:00:57.781 [main] DEBUG com.consol.citrus.report.LoggingReporter - TEST STEP 3: receive
15:00:57.791 [main] DEBUG com.consol.citrus.channel.ChannelConsumer - Receiving message from: routeGeneratorServer.inbound
15:00:57.792 [main] DEBUG com.consol.citrus.channel.ChannelConsumer - Received message from: routeGeneratorServer.inbound
... Received request from mission planner
15:00:57.801 [main] DEBUG com.consol.citrus.validation.MessageValidatorRegistry - Found 4 message validators for message type: XML
15:00:57.801 [main] DEBUG com.consol.citrus.validation.json.JsonTextMessageValidator - Start JSON message validation ...
15:00:57.801 [main] DEBUG com.consol.citrus.validation.json.JsonTextMessageValidator - Received message:
HTTPMESSAGE [id: 900d8f51-b1cf-427e-9f00-cd5b242b5dca, payload: {"header":{"timestamp":1581364852723,"typeID":"edu.mit.ll.mission_services.messages.GenerateRouteCommand","transaction":{"id":2,"startTime":1581364852723},"signature":{"algorithm":null,"keySize":0,"keyValue":null,"sender":null}},"commandID":"60b684f1-5065-47d6-8e7d-a4f101b44d22","commandType":"GENERATE_ROUTE"}][headers: {Accept=application/json, Connection=keep-alive, User-Agent=Apache-HttpClient/4.5.9 (Java/1.8.0_201), Host=localhost:9110, Accept-Encoding=gzip,deflate, Content-Length=311, contentType=application/json;charset=UTF-8, citrus_message_id=900d8f51-b1cf-427e-9f00-cd5b242b5dca, citrus_message_timestamp=1581364852849, elastic-apm-traceparent=00-eb0d1dffcf09adda45d39323efc6f883-7236b8b42e4e90d5-01, Content-Type=application/json;charset=UTF-8, citrus_http_request_uri=/v1/missionServices/missionPlanning/generateRoute, citrus_request_path=/v1/missionServices/missionPlanning/generateRoute, citrus_endpoint_uri=/v1/missionServices/missionPlanning/generateRoute, citrus_http_context_path=, citrus_http_query_params=, citrus_query_params=, citrus_http_version=HTTP/1.1, citrus_http_method=POST, replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3db663d0, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3db663d0, id=10be4cec-6d61-d00a-f0e6-baed32421725, timestamp=1581364852856}]
15:00:57.802 [main] DEBUG com.consol.citrus.validation.json.JsonTextMessageValidator - Control message:
HTTPMESSAGE [id: d0d27c94-533e-4724-b87a-5a8d4d05950d, payload: {
    "header": {
        "timestamp": "@isNumber()@",
        "typeID": "edu.mit.ll.mission_services.messages.GenerateRouteCommand",
        "transaction": {
            "id": "@isNumber()@",
            "startTime": "@isNumber()@"
        },
        "signature": {
            "algorithm": null,
            "keySize": 0,
            "keyValue": null,
            "sender": null
        }
    },
    "commandID": "@ignore@",
    "commandType": "GENERATE_ROUTE"
}][headers: {citrus_message_id=d0d27c94-533e-4724-b87a-5a8d4d05950d, citrus_message_timestamp=1581364857769, citrus_http_method=POST, citrus_http_request_uri=/v1/missionServices/missionPlanning/generateRoute, citrus_request_path=/v1/missionServices/missionPlanning/generateRoute, Accept=application/json, citrus_message_type=XML}]

15:00:57.923 [main] DEBUG com.consol.citrus.report.LoggingReporter - TEST STEP 3 SUCCESS
向前跳至完成步骤10(回音)。我想这是第9步活动的结束

15:00:57.986 [main] DEBUG com.consol.citrus.report.LoggingReporter - TEST STEP 10 SUCCESS
15:00:57.987 [qtp203936099-36] DEBUG org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor - Found 'Content-Type:application/json' in response
15:00:57.987 [qtp203936099-36] DEBUG org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor - Writing ["{
    "header": {
        "timestamp": 1580761681867,
        "typeID": "edu.mit.ll.mission_services.messages.Asse (truncated)...]
15:00:57.987 [qtp203936099-36] DEBUG com.consol.citrus.http.interceptor.LoggingHandlerInterceptor - Sending Http response:
com.consol.citrus.http.servlet.GzipHttpServletResponseWrapper@61196037
{
    "header": {
        "timestamp": 1580761681867,
        "typeID": "edu.mit.ll.mission_services.messages.AssessRouteStatus",
        "transaction": {
            "id": 1,
            "startTime": 1580761681867
        },
        "signature": {
            "algorithm": null,
            "keySize": 0,
            "keyValue": null,
            "sender": null
        }
    },
    "commandID": "0710d523-43da-4f68-90c7-a2b4544a955d",
    "status": "COMPLETED"
}
15:00:57.987 [qtp203936099-36] DEBUG com.consol.citrus.http.servlet.CitrusDispatcherServlet - Completed 200 OK
最后,这是测试报告失败的地方,尽管我认为问题是从步骤1开始的

15:00:57.998 [main] DEBUG com.consol.citrus.report.LoggingReporter - TEST STEP 11: receive
15:00:58.000 [main] DEBUG com.consol.citrus.validation.MessageValidatorRegistry - Found 4 message validators for message type: JSON
15:00:58.000 [main] DEBUG com.consol.citrus.validation.json.JsonTextMessageValidator - Start JSON message validation ...
15:00:58.000 [main] DEBUG com.consol.citrus.validation.json.JsonTextMessageValidator - Received message:
HTTPMESSAGE [id: 43da4bd7-9929-4536-a9e6-caaabcb72c62, payload: {"timestamp":"2020-02-10T20:00:57.728+0000","status":503,"error":"Service Unavailable","message":"Service Unavailable","path":"/v1/missionServices/missionPlanning/planMission"}][headers: {Transfer-Encoding=chunked, Pragma=no-cache, contentType=application/json;charset=utf-8, Date=1581364852000, citrus_message_id=43da4bd7-9929-4536-a9e6-caaabcb72c62, citrus_message_timestamp=1581364857760, X-Frame-Options=DENY, X-Content-Type-Options=nosniff,nosniff, X-XSS-Protection=1; mode=block, Content-Type=application/json;charset=utf-8, citrus_http_status_code=503, citrus_http_reason_phrase=SERVICE_UNAVAILABLE, citrus_http_version=HTTP/1.1}]
15:00:58.000 [main] DEBUG com.consol.citrus.validation.json.JsonTextMessageValidator - Control message:
HTTPMESSAGE [id: 069509f7-2591-452f-886a-f3c1bb556b09, payload: {
  "message": "Transaction complete"
}][headers: {citrus_message_id=069509f7-2591-452f-886a-f3c1bb556b09, citrus_message_timestamp=1581364857989, citrus_http_status_code=200, citrus_http_reason_phrase=OK, citrus_message_type=JSON}]
15:00:58.002 [main] INFO com.consol.citrus.report.LoggingReporter - 
15:00:58.004 [main] ERROR com.consol.citrus.report.LoggingReporter - TEST FAILED MissionPlannerIT.testPlanMission <edu.mit.ll.mission_services.service.mission_planner> Nested exception is: 
com.consol.citrus.exceptions.TestCaseFailedException: Failed to validate JSON text:
{"timestamp":"2020-02-10T20:00:57.728+0000","status":503,"error":"Service Unavailable","message":"Service Unavailable","path":"/v1/missionServices/missionPlanning/planMission"} Number of JSON entries not equal for element: '$.', expected '1' but was '5'
不幸的是,这对我的问题没有任何影响

我还将以下内容添加到SUT(mission planner)application.yml中:

server:
  port: 9100
  ...
  jetty:
    http:
      idleTimeout: 60000
      stopTimeout: 60000
      connection-idle-timeout: 60000
      thread-idle-timeout: 60000
这似乎也没有影响。我不能100%确定我是否使用了正确的属性

注意

我做了一个有趣的实验,不涉及柑橘,但我运行了所有三个真正的服务,然后试图通过邮递员发布“计划任务”电话。我得到了相同的HTTP503响应

现在,真正的“路由”服务有一个内置的、可配置的延迟来模拟长时间运行的任务。每次服务的延迟设置为5秒

我将这些延迟设置为0,并再次与邮递员一起发布。这次成功了!我假设邮递员有一个默认超时,并且服务延迟超过了这个时间,导致了观察到的结果。大概我想我会收到某种超时消息,而不是“服务不可用”

延迟肯定会对测试结果产生影响,但是,在Citrus测试用例中,“路由”服务正在被模拟,不应该引入任何人为延迟


这只是一个有趣的观察。

在Http客户端发送初始请求的第一个测试步骤中,您缺少了一个
fork=true
。Http本质上是一个同步协议,这意味着测试的第一步将在继续其他测试步骤之前等待Http响应。这意味着不会执行所有其他测试步骤,因此Http服务器模拟将无法正常运行

我猜,由于这个原因,您将在客户端和Http服务器端遇到很多请求超时。这可能导致Http 503

  @Bean
  public HttpClient missionPlannerClient() {
    return CitrusEndpoints.http().client().requestUrl("http://localhost:9100").timeout(30000).build();
  }
server:
  port: 9100
  ...
  jetty:
    http:
      idleTimeout: 60000
      stopTimeout: 60000
      connection-idle-timeout: 60000
      thread-idle-timeout: 60000