问:
Citrus Framework - Unexplained HTTP 503 from SUT
Background:

I have a simple Spring Boot application consisting of three services. The services communicate via HTTP REST calls. Below is a brief description of the services.

Mission planner (localhost:9100)

Orchestrates the "planning" of a mission. Invokes the Route Generator and Route Assessor services to do the work. The "plan mission" action is triggered by a POST (/v1/missionServices/missionPlanning/planMission) from a "client". A simple response message is returned to the caller.

Route Generator (localhost:9110)

Generates a "route" when invoked by the mission planner (/v1/missionServices/missionPlanning/generateRoute). Returns a response message to the mission planner.

Route Assessor (localhost:9120)

Assesses the generated "route" when invoked by the mission planner (/v1/missionServices/missionPlanning/assessRoute). Returns a response message to the mission planner.

The mission planner "client" is a fourth service that triggers the "plan mission" process by sending a POST request to the mission planner. This is not part of the integration test. Instead, the Citrus test takes its place.

Objective:

I'm attempting to use the Citrus Framework to perform integration tests on the services, separately and as a whole (end-to-end). I have been successful with the simpler service cases (i.e. the route generator and route assessor), but testing the mission planner has proven to present many difficulties.

Below is the Citrus test I've written for the mission planner. Currently I am "mocking" the route generator and route assessor services, but for an end-to-end test, will need to figure out how to do this will all three services "live" - I won't worry about that for now. I have built this based on examples I have found and from what I have learned during my experience.

MissionPlannerIT.java:

```<code>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

}
</code>```

EndpointConfig.java:

```<code>@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();
  }

}
</code>```

There are a couple of ways I run this test: 1) as part of a maven build, and 2) using eclipse. I'm having issues when running it as a maven build, where most of the test console output is not output (see Citrus Framework logging - how to enable/use and Citrus Framework - echo action does not "echo"). When I run it via eclipse, I need to start the mission planner manually before running the test.

Output:

I'm including portions of the console log from the eclipse run method, since it includes information missing when using the maven method. I will try to include what I think are pertinent sections and include my notes/thoughts along the way.

Summary:

TEST STEP 1: send - do the initial POST to mission planner to start process

TEST STEP 3: receive - set the mock route generator to receive a POST request from mission planner to generate a route

TEST STEP 5: send - set the mock route generator to return a response message

TEST STEP 7: receive - set the mock route assessor to receive a POST request from mission planner to assess the route

TEST STEP 9: send - set the mock route assessor to return a response message

TEST STEP 11: receive - expect to receive a response message from mission planner

Test step 1 - Do the initial POST to mission planner to start process:

```<code>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
</code>```

I assume this is recording activity indicating that the mission planner has made the POST request to the route generator:

```<code>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]"
</code>```

Our first indication of a problem - we are still in test step 1 by the way:

```<code>15:00:57.752 [main] DEBUG com.consol.citrus.http.interceptor.LoggingClientInterceptor - Received Http response message
15:00:57.752 [main] DEBUG Logger.Message_IN - HTTP/1.1 503 SERVICE_UNAVAILABLE Service Unavailable
Date:Mon, 10 Feb 2020 20:00:52 GMT
X-Content-Type-Options:nosniff,nosniff
X-XSS-Protection:1; mode=block
Pragma:no-cache
X-Frame-Options:DENY
Content-Type:application/json;charset=utf-8
Transfer-Encoding:chunked

{"timestamp":"2020-02-10T20:00:57.728+0000","status":503,"error":"Service Unavailable","message":"Service Unavailable","path":"/v1/missionServices/missionPlanning/planMission"}
15:00:57.752 [main] DEBUG org.springframework.web.client.RestTemplate - Response 503 SERVICE_UNAVAILABLE
15:00:57.757 [main] INFO com.consol.citrus.http.client.HttpClient - Caught HTTP rest client exception: 503 Service Unavailable
15:00:57.757 [main] INFO com.consol.citrus.http.client.HttpClient - Propagating HTTP rest client exception according to error handling strategy
</code>```

Completion of test step 1:

```<code>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
</code>```

Test step 3 - mock route generator receive request from mission planner:

```<code>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
</code>```

Skip forward to completion of step 10 (an echo). I assume this is step 9 activity finishing up.

```<code>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
</code>```

Finally, this where the test reports a failure, although I think the problem started in step 1.

```<code>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'
</code>```

Thoughts:

The interactions between the SUT (the mission planner service) and the mocked generators seems to have all worked as expected. The messages passed back and forth and there appear to be no problems. What I don't understand is the appearance of the HTTP 503 error. It seems to occur during the first test step, but I have no idea what could be wrong.

I'm not even sure how to try to debug any of this. I'm not that familiar with how HTTP works. From my perspective, a lot of what's happening is going on behind the scenes and I don't know how to see what's going on in there.

If anyone sees something wrong in what I'm doing, please let me know. If anyone has ideas what might be happening, that would be very helpful. Finally, any suggestions on what I might do to try to debug this, would very much appreciated.

UPDATE:

I have modified the test to add timeout calls to the client and server endpoints. E.g.:

```<code>  @Bean
  public HttpClient missionPlannerClient() {
    return CitrusEndpoints.http().client().requestUrl("http://localhost:9100").timeout(30000).build();
  }
</code>```

Unfortunately, this has had no impact on my problem.

I have also added the following to the SUT (mission planner) application.yml:

```<code>@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();
  }

}
</code>```0

This also seems to have no affect. I'm not 100% sure if I'm using the correct properties.

NOTE:

I ran an interesting experiment that did not involve Citrus, but where I ran all three real services and then attempted to POST the "plan mission" call via Postman. I got the same HTTP 503 response.

Now it turns out the real "route" services have a built-in, configurable delay to simulate a long running task. The delay was set to 5 seconds for each service.

I set these delays to 0 and POSTed with Postman again. This time it worked! I'm assuming that Postman has a default timeout and that the service delays exceeded that time, causing the observed result. Maybe? I would think I would get some sort of timeout message rather than "service unavailable".

The delays definitely had an impact on this test result, however, in the Citrus test case, the "route" services are being mocked and should not be introducing any artificial delay.

Just an interesting observation.

答:
You are missing a fork=true on the very 1st test step where the Http client sends the initial request. Http is a synchronous protocol by nature and this means the the 1st step in your test will wait for the Http response before continuing with the other test steps. This means that all other test steps are not executed so your Http server mocks will not be able to operate properly.

I guess you will be hitting a lot of request timeouts on both client and Http server side because of this. And this may lead to the Http 503.

Body:
Background:

I have a simple Spring Boot application consisting of three services. The services communicate via HTTP REST calls. Below is a brief description of the services.

Mission planner (localhost:9100)

Orchestrates the "planning" of a mission. Invokes the Route Generator and Route Assessor services to do the work. The "plan mission" action is triggered by a POST (/v1/missionServices/missionPlanning/planMission) from a "client". A simple response message is returned to the caller.

Route Generator (localhost:9110)

Generates a "route" when invoked by the mission planner (/v1/missionServices/missionPlanning/generateRoute). Returns a response message to the mission planner.

Route Assessor (localhost:9120)

Assesses the generated "route" when invoked by the mission planner (/v1/missionServices/missionPlanning/assessRoute). Returns a response message to the mission planner.

The mission planner "client" is a fourth service that triggers the "plan mission" process by sending a POST request to the mission planner. This is not part of the integration test. Instead, the Citrus test takes its place.

Objective:

I'm attempting to use the Citrus Framework to perform integration tests on the services, separately and as a whole (end-to-end). I have been successful with the simpler service cases (i.e. the route generator and route assessor), but testing the mission planner has proven to present many difficulties.

Below is the Citrus test I've written for the mission planner. Currently I am "mocking" the route generator and route assessor services, but for an end-to-end test, will need to figure out how to do this will all three services "live" - I won't worry about that for now. I have built this based on examples I have found and from what I have learned during my experience.

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();
  }

}

There are a couple of ways I run this test: 1) as part of a maven build, and 2) using eclipse. I'm having issues when running it as a maven build, where most of the test console output is not output (see Citrus Framework logging - how to enable/use and Citrus Framework - echo action does not "echo"). When I run it via eclipse, I need to start the mission planner manually before running the test.

Output:

I'm including portions of the console log from the eclipse run method, since it includes information missing when using the maven method. I will try to include what I think are pertinent sections and include my notes/thoughts along the way.

Summary:

TEST STEP 1: send - do the initial POST to mission planner to start process

TEST STEP 3: receive - set the mock route generator to receive a POST request from mission planner to generate a route

TEST STEP 5: send - set the mock route generator to return a response message

TEST STEP 7: receive - set the mock route assessor to receive a POST request from mission planner to assess the route

TEST STEP 9: send - set the mock route assessor to return a response message

TEST STEP 11: receive - expect to receive a response message from mission planner

Test step 1 - Do the initial POST to mission planner to start process:

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

I assume this is recording activity indicating that the mission planner has made the POST request to the route generator:

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]"

Our first indication of a problem - we are still in test step 1 by the way:

15:00:57.752 [main] DEBUG com.consol.citrus.http.interceptor.LoggingClientInterceptor - Received Http response message
15:00:57.752 [main] DEBUG Logger.Message_IN - HTTP/1.1 503 SERVICE_UNAVAILABLE Service Unavailable
Date:Mon, 10 Feb 2020 20:00:52 GMT
X-Content-Type-Options:nosniff,nosniff
X-XSS-Protection:1; mode=block
Pragma:no-cache
X-Frame-Options:DENY
Content-Type:application/json;charset=utf-8
Transfer-Encoding:chunked

{"timestamp":"2020-02-10T20:00:57.728+0000","status":503,"error":"Service Unavailable","message":"Service Unavailable","path":"/v1/missionServices/missionPlanning/planMission"}
15:00:57.752 [main] DEBUG org.springframework.web.client.RestTemplate - Response 503 SERVICE_UNAVAILABLE
15:00:57.757 [main] INFO com.consol.citrus.http.client.HttpClient - Caught HTTP rest client exception: 503 Service Unavailable
15:00:57.757 [main] INFO com.consol.citrus.http.client.HttpClient - Propagating HTTP rest client exception according to error handling strategy

Completion of test step 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

Test step 3 - mock route generator receive request from mission planner:

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

Skip forward to completion of step 10 (an echo). I assume this is step 9 activity finishing up.

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

Finally, this where the test reports a failure, although I think the problem started in step 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'

Thoughts:

The interactions between the SUT (the mission planner service) and the mocked generators seems to have all worked as expected. The messages passed back and forth and there appear to be no problems. What I don't understand is the appearance of the HTTP 503 error. It seems to occur during the first test step, but I have no idea what could be wrong.

I'm not even sure how to try to debug any of this. I'm not that familiar with how HTTP works. From my perspective, a lot of what's happening is going on behind the scenes and I don't know how to see what's going on in there.

If anyone sees something wrong in what I'm doing, please let me know. If anyone has ideas what might be happening, that would be very helpful. Finally, any suggestions on what I might do to try to debug this, would very much appreciated.

UPDATE:

I have modified the test to add timeout calls to the client and server endpoints. E.g.:

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

Unfortunately, this has had no impact on my problem.

I have also added the following to the SUT (mission planner) application.yml:

server:
  port: 9100
  ...
  jetty:
    http:
      idleTimeout: 60000
      stopTimeout: 60000
      connection-idle-timeout: 60000
      thread-idle-timeout: 60000

This also seems to have no affect. I'm not 100% sure if I'm using the correct properties.

NOTE:

I ran an interesting experiment that did not involve Citrus, but where I ran all three real services and then attempted to POST the "plan mission" call via Postman. I got the same HTTP 503 response.

Now it turns out the real "route" services have a built-in, configurable delay to simulate a long running task. The delay was set to 5 seconds for each service.

I set these delays to 0 and POSTed with Postman again. This time it worked! I'm assuming that Postman has a default timeout and that the service delays exceeded that time, causing the observed result. Maybe? I would think I would get some sort of timeout message rather than "service unavailable".

The delays definitely had an impact on this test result, however, in the Citrus test case, the "route" services are being mocked and should not be introducing any artificial delay.

Just an interesting observation.


来源: stackexchange

问:
sql query question for most name in table with multiple most names
fbn table:

```<code>create table fbn (
id int,
name varchar(40),
birthday date,
gender varchar(10));

INSERT into fbn values
(1, "James", "2000-04-22", "male"),
(2, "Julia", "2006-02-27", "female"),
(3, "Ethan", "2013-05-23", "male"),
(4, "Lion", "2014-09-11", "male"),
(5, "Ethan", "2006-01-01", "male"),
(6, "Lion", "2006-02-01", "male");
</code>```

what's the name that occur most? note that there are two names (Ethan and Lion) occur most often. I have two solutions as below:

```<code>select tmp2.name
from (select tmp.name,
             dense_rank() over(order by tmp.name_count desc) rank
      from (select name,
                   count(*) name_count
            from fbn
            group by name) tmp
      ) tmp2
where tmp2.rank = 1;
</code>```

and the 2nd solution:

```<code>select name from fbn
group by name
having count(name) = (select count(name) from fbn
                      group by name
                      order by count(name) desc
                      limit 1);
</code>```

both seem to be working, but both looks like too complicated. is there any other solution that's more concise easier to understand? Thanks

答:
I think you can simply:</p>

```<code>select count(id) as num_names, name from fbn group by name order by num_names desc limit 1;
</code>```

ContentLicense: CC BY-SA 4.0

Body:
fbn table:

create table fbn (
id int,
name varchar(40),
birthday date,
gender varchar(10));

INSERT into fbn values
(1, "James", "2000-04-22", "male"),
(2, "Julia", "2006-02-27", "female"),
(3, "Ethan", "2013-05-23", "male"),
(4, "Lion", "2014-09-11", "male"),
(5, "Ethan", "2006-01-01", "male"),
(6, "Lion", "2006-02-01", "male");

what's the name that occur most? note that there are two names (Ethan and Lion) occur most often. I have two solutions as below:

select tmp2.name
from (select tmp.name,
             dense_rank() over(order by tmp.name_count desc) rank
      from (select name,
                   count(*) name_count
            from fbn
            group by name) tmp
      ) tmp2
where tmp2.rank = 1;

and the 2nd solution:

select name from fbn
group by name
having count(name) = (select count(name) from fbn
                      group by name
                      order by count(name) desc
                      limit 1);

both seem to be working, but both looks like too complicated. is there any other solution that's more concise easier to understand? Thanks

Body:
I think you can simply:

select count(id) as num_names, name from fbn group by name order by num_names desc limit 1;


问:
Modify Code - lookup 2nd Last letter of data in a cell. Google Apps Script / Google Sheets
If data in a cell in Column B has a A or B as the 2nd last letter ONLY - (example of Location G08B1) - Copy that row to another sheet.

I use a modified version of copy row if certain cell has certain word, so not sure how to modify this to what I need.

```<code>  function CopyAorBLocation() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var s = event.source.getActiveSheet();
  var r = event.source.getActiveRange();
  if(s.getName() == "FORKLIFT" && r.getColumn() == 7 && r.getValue() == copy AorB if 2nd last letter - if not ignore)
 {
  var row = r.getRow();
  var numColumns = s.getLastColumn();
  var targetSS =
  SpreadsheetApp.openById("");
  s = SpreadsheetApp.getActiveSheet();
  var tempSheet = s.copyTo(targetSS);
  var targetSheet = targetSS.getSheetByName("ONLINERELOCATION");
  var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
  tempSheet.getRange(row, 4, 1, 3).copyTo(target);
</code>```

Hoping this is not too complicated to achieve.

Thanks in Advance

答:
The input and output sample values are the column "B" and the columns "C:D", respectively.

You want to put the values of column "B" to the column "C" and "D" by the 2nd last character of each value of the column "B".

Put the values ###A# and ###B# to the column "C".

Put the values ###C# and ###D# to the column "D".

You want to achieve this using Google Apps Script.

I could understand like above. If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.

In this answer, the 2nd last character of each value is retrieved by substring().

Sample script:

```<code>function myFunction() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Sheet1");
  var srcValues = sheet.getRange(2, 2, sheet.getLastRow() - 1, 1).getValues();
  var dstValues = srcValues.map(function([b]) {
    var len = b.length;
    var s = b.substring(len - 2, len - 1).toUpperCase();
    return (s == "A" || s == "B") ? [b, ""] : (s == "C" || s == "D") ? ["", b] : ["", ""];
  });
  sheet.getRange(2, 3, dstValues.length, 2).setValues(dstValues);
}
</code>```

In this sample script, Sheet1 is used.

Note:

This sample script is for your shared Spreadsheet. If the format is different from your shared Spreadsheet, the script might not work. Please be careful this.

Reference:

substring()

Body:
If data in a cell in Column B has a A or B as the 2nd last letter ONLY - (example of Location G08B1) - Copy that row to another sheet.

I use a modified version of copy row if certain cell has certain word, so not sure how to modify this to what I need.

  function CopyAorBLocation() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var s = event.source.getActiveSheet();
  var r = event.source.getActiveRange();
  if(s.getName() == "FORKLIFT" && r.getColumn() == 7 && r.getValue() == copy AorB if 2nd last letter - if not ignore)
 {
  var row = r.getRow();
  var numColumns = s.getLastColumn();
  var targetSS =
  SpreadsheetApp.openById("");
  s = SpreadsheetApp.getActiveSheet();
  var tempSheet = s.copyTo(targetSS);
  var targetSheet = targetSS.getSheetByName("ONLINERELOCATION");
  var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
  tempSheet.getRange(row, 4, 1, 3).copyTo(target);

Hoping this is not too complicated to achieve.

Thanks in Advance

Body:
The input and output sample values are the column "B" and the columns "C:D", respectively.

You want to put the values of column "B" to the column "C" and "D" by the 2nd last character of each value of the column "B".

Put the values ###A# and ###B# to the column "C".

Put the values ###C# and ###D# to the column "D".

You want to achieve this using Google Apps Script.

I could understand like above. If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.

In this answer, the 2nd last character of each value is retrieved by substring().

Sample script:

function myFunction() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Sheet1");
  var srcValues = sheet.getRange(2, 2, sheet.getLastRow() - 1, 1).getValues();
  var dstValues = srcValues.map(function([b]) {
    var len = b.length;
    var s = b.substring(len - 2, len - 1).toUpperCase();
    return (s == "A" || s == "B") ? [b, ""] : (s == "C" || s == "D") ? ["", b] : ["", ""];
  });
  sheet.getRange(2, 3, dstValues.length, 2).setValues(dstValues);
}

In this sample script, Sheet1 is used.

Note:

This sample script is for your shared Spreadsheet. If the format is different from your shared Spreadsheet, the script might not work. Please be careful this.

Reference:

substring()


问:
CUploadedFile create manyally
I want to offer 2 ways of uploading files - with <input type='file'> and remote upload by URL.

Is it possible to create a CUploadedFile using data from a remote url?

答:
The remote upload is actually not an upload, rather the user submits the link and you need to copy it over to your server.
Consider CUploadedFile to be used only for the upload part and handover to the next file handler.
Once done with upload or copy, You might want to use another file management utility like cfile extension here http://www.yiiframework.com/extension/cfile/ to manage both your files already "copied/uploaded" to your desired directory.</p>

ContentLicense: CC BY-SA 3.0

Title: CUploadedFile create manyally


问:
How to pass the data from list Component to edit component for data modification
//edit file

```<code>export class EditStoreComponent implements OnInit {
name = '';
id: ''

  constructor(private api:APIService, private router:Router, private cookieService: CookieService, private route:ActivatedRoute) {

      }
  ngOnInit() {

  }

  async updateStore(){
    let req = {
      id:this.id,
      name:this.name
    }
    console.log(req)
  let result = await this.api.UpdateStore(req)

  if (result){
    this.router.navigate(['../admin/liststore']);
    console.log(result)
    }
  }
}
</code>```

//list file

```<code>  rawlist;
  name = '';
  id = '';
  storeid = "";
  store: Store;

  constructor(private api: APIService, private router: Router, private route: ActivatedRoute, private cookieService: CookieService) { }

  ngOnInit() {
    this.storelist();

  }
  //store list
  async storelist() {
    this.rawlist = await this.api.ListStores();
    this.storelist = this.rawlist.items;
  }
</code>```

I am not sure how to pass ID from list to edit component. Basically i calling the api to update my data in the list. I only can passing the name, but I can not pass the id for specific user

答:
First you should do this in the list file :

```<code>      import { Modal, BSModalContext } from 'angular2-modal/plugins/bootstrap';

      this.modal.open(EditComponent, overlayConfigFactory({
      dataToBePassed }, BSModalContext));
</code>```

Then in the EditComponent do the following:

```<code>      export class AdditionPopupWindowData extends BSModalContext {
      public dataToBePassed: any;
       }

       context: AdditionPopupWindowData;
       public dataToBePassed: any;
</code>```

Then inside the constructor do the following:

```<code>      this.context = dialog.context;
      this.dataToBePassed = this.context.dataToBePassed;
</code>```

Cheers !

Body:
//edit file

export class EditStoreComponent implements OnInit {
name = '';
id: ''

  constructor(private api:APIService, private router:Router, private cookieService: CookieService, private route:ActivatedRoute) {

      }
  ngOnInit() {

  }

  async updateStore(){
    let req = {
      id:this.id,
      name:this.name
    }
    console.log(req)
  let result = await this.api.UpdateStore(req)

  if (result){
    this.router.navigate(['../admin/liststore']);
    console.log(result)
    }
  }
}

//list file

  rawlist;
  name = '';
  id = '';
  storeid = "";
  store: Store;

  constructor(private api: APIService, private router: Router, private route: ActivatedRoute, private cookieService: CookieService) { }

  ngOnInit() {
    this.storelist();

  }
  //store list
  async storelist() {
    this.rawlist = await this.api.ListStores();
    this.storelist = this.rawlist.items;
  }

I am not sure how to pass ID from list to edit component. Basically i calling the api to update my data in the list. I only can passing the name, but I can not pass the id for specific user

Body:
First you should do this in the list file :

      import { Modal, BSModalContext } from 'angular2-modal/plugins/bootstrap';

      this.modal.open(EditComponent, overlayConfigFactory({
      dataToBePassed }, BSModalContext));

Then in the EditComponent do the following:

      export class AdditionPopupWindowData extends BSModalContext {
      public dataToBePassed: any;
       }

       context: AdditionPopupWindowData;
       public dataToBePassed: any;

Then inside the constructor do the following:

      this.context = dialog.context;
      this.dataToBePassed = this.context.dataToBePassed;

Cheers !


问:
How can i List any actors
I’m trying to list the actors (male/female) that have starred in 10 or more different film genres I have a table called actors which contains three columns:actorID,name,gender and another table called movies which contains movieID,title,year, last table is movies_actor it contains movieID,actorID,as_charachter,leading

答:
To get the count of movie for each actor You need the actor_name and the movieid which are in two different table. First you can take the actorid and the count of movieid from movies_actors table and the join it with the actor_table to get the name of the actor. You have to apply a condition in select statement >9 as you want the actor name who has done 10 or more than 10 movies. For genres you can try once from your end if you get any error then you can ask question.

```<code>     select name from
       (select s.*,a.name from
          (select actorid, count(distinct movieid)no_of_movies from movies_actors group by  actorid)s
      join
      actor_table a
      on a.actorid=s.actorid
       )b
where no_of_movies>9
</code>```

But It will be good for you if you try first from your end and then you can ask questions here like if you stuck or if you get any error or not get the desired output. In this way you can learn more.

Title: How can i List any actors

Body:
To get the count of movie for each actor You need the actor_name and the movieid which are in two different table. First you can take the actorid and the count of movieid from movies_actors table and the join it with the actor_table to get the name of the actor. You have to apply a condition in select statement >9 as you want the actor name who has done 10 or more than 10 movies. For genres you can try once from your end if you get any error then you can ask question.

     select name from
       (select s.*,a.name from
          (select actorid, count(distinct movieid)no_of_movies from movies_actors group by  actorid)s
      join
      actor_table a
      on a.actorid=s.actorid
       )b
where no_of_movies>9

But It will be good for you if you try first from your end and then you can ask questions here like if you stuck or if you get any error or not get the desired output. In this way you can learn more.


问:
React - get element.getBoundingClientRect() after window resize
I have a class that needs to get the size of a DOM element. It works well, but when I resize the window it doesn't update until I change the state in my app, forcing a rerender. I've tried adding this.forceUpdate to a 'resize' event listener in componentDidMount(), but it didn't work. Perhaps I did something wrong? Ideally I'd like to avoid using this.forceUpdate for perfomance implications anyway. Any work arounds for this? Thanks in advance!

My code:

class MyComponent extends React.Component {
  state = { x: 0, y: 0 }

  refCallback = (element) => {
    if (!element) {
      return
    }
    const { x, y } = element.getBoundingClientRect()
    this.setState({ x, y })
  }

  render() {
    console.log('STATE:', this.state) // Outputs the correct x and y values.
    return (

        <button>Hello world</button>

    )
  }
}
```

答:
That happening because:

From the React documentation:

Adding a Ref to a DOM Element

React supports a special attribute that you can attach to any component. The ref attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.

React will call the ref callback with the DOM element when the component mounts, and call it with null when it unmounts.

So, that's why when you refresh you get the value. To overcome the problem you can do something like this:

```<code>import React from "react";

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
    this.state = {
      x: 0,
      y: 0
    };
  }

  updateDimensions = () => {
    if (this.myRef.current) {
      const {x, y} = this.myRef.current.getBoundingClientRect();
      this.setState({ x, y });
    }
  };
  componentDidMount() {
    window.addEventListener("resize", this.updateDimensions);
  }
  componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions);
  }

  render() {
    console.log("STATE:", this.state); // Outputs the correct x and y values.
    return (
      <div ref={this.myRef}>
        <button>Hello world</button>
      </div>
    );
  }
}

export default MyComponent;
</code>```

Hope this works for you.

Body:
That happening because:

From the React documentation:

Adding a Ref to a DOM Element

React supports a special attribute that you can attach to any component. The ref attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.

React will call the ref callback with the DOM element when the component mounts, and call it with null when it unmounts.

So, that's why when you refresh you get the value. To overcome the problem you can do something like this:

import React from "react";

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
    this.state = {
      x: 0,
      y: 0
    };
  }

  updateDimensions = () => {
    if (this.myRef.current) {
      const {x, y} = this.myRef.current.getBoundingClientRect();
      this.setState({ x, y });
    }
  };
  componentDidMount() {
    window.addEventListener("resize", this.updateDimensions);
  }
  componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions);
  }

  render() {
    console.log("STATE:", this.state); // Outputs the correct x and y values.
    return (
      <div ref={this.myRef}>
        <button>Hello world</button>
      </div>
    );
  }
}

export default MyComponent;

Hope this works for you.


问:
How to override the Windows tree command?

C:\Users\client>npm install -g tree-cli
+ tree-cli@0.6.4
updated 1 package in 2.374s

C:\Users\client>tree --help
卷 Windows-SSD 的文件夹 PATH 列表
卷序列号为 B20D-EC93
C:\USERS\CLIENT\--HELP
无效的路径 - \USERS\CLIENT\--HELP
```

I installed tree-cli. https://github.com/MrRaindrop/tree-cli

But this command is occupied by windows.

I want to use the tree of tree-cli, not the tree of windows.

答: You need to use the command treee. See the note in the README here.

Body:
C:\Users\client>npm install -g tree-cli
+ tree-cli@0.6.4
updated 1 package in 2.374s

C:\Users\client>tree --help
卷 Windows-SSD 的文件夹 PATH 列表
卷序列号为 B20D-EC93
C:\USERS\CLIENT\--HELP
无效的路径 - \USERS\CLIENT\--HELP

I installed tree-cli. https://github.com/MrRaindrop/tree-cli

But this command is occupied by windows.

I want to use the tree of tree-cli, not the tree of windows.


问:
Can the time to live (TTL) for a memcached key be set to infinite?
I have implemented memcache in my PHP-MySQL based app and it gets updated regularly from a backend process.

Due to this some data is conflicting with the expiration time and other backend processes, so I came up with a solution but for that I would have to make the TTL = infinite.

答:
You can set the TTL to 0, which means that it should 'never' expire.

But remember that it will never really be infinite. The data is stored in memory and will be lost under some circumstances, the most obvious being the server being rebooted. :)

You should always have the possibility to reconstruct that data when the memcache fails.

More details to be found here.


问:
how to display the data per hour in angular
How to display the data per hour?

for example:

```<code>data = [
    {
        'name' : 'sample'
        'date' : '2020-02-18 13:50:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 13:20:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 12:30:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 11:50:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 07:50:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 01:50:01'
    }
]
</code>```

what I want to do here is display the data from hour.
example
14:00:00 - 13:00:00

```<code>const sample = data.filter((data) => { return data.date });

console.log(sample);
</code>```

Body:
How to display the data per hour?

for example:

data = [
    {
        'name' : 'sample'
        'date' : '2020-02-18 13:50:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 13:20:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 12:30:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 11:50:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 07:50:01'
    },
    {
        'name' : 'sample'
        'date' : '2020-02-18 01:50:01'
    }
]

what I want to do here is display the data from hour.
example
14:00:00 - 13:00:00

const sample = data.filter((data) => { return data.date });

console.log(sample);

Body:
Live demo: https://runkit.com/embed/21avr87izvdn

    const data = [
    {
        'name' : 'sample',
        'date' : '2020-02-18 13:50:01'
    },
    {
        'name' : 'sample',
        'date' : '2020-02-18 13:20:01',
    },
    {
        'name' : 'sample',
        'date' : '2020-02-18 12:70:01'
    },
    {
        'name' : 'sample',
        'date' : '2020-02-18 11:50:01'
    },
    {
        'name' : 'sample',
        'date' : '2020-02-18 07:50:01'
    },
    {
        'name' : 'sample',
        'date' : '2020-02-18 01:50:01'
    }
];

const getTime = date => date.split(' ')[1];

const filterByRange = (start, end) =>
      data.filter(item =>  getTime(item.date) > start &&
                           getTime(item.date) < end);

filterByRange('13:00', '14:00');


问:
How to redirect output from start-ed console?
I have the following command: C:\start MyApp.exe Parameter > C:\Temp\result.log.  I have this in batch file. The output is not redirected to result.log. How do I achieve that?

答:
Assuming that your command is

```<code>start MyApp.exe Parameter > result.log
</code>```

This logs the output of the start command only, and that output is always empty.

If you want to redirect the output of the called program you need to escape the redirection.

But the redirection only works, when parsed by cmd.exe, else it's only a parameter to the application.

```<code>start cmd /c MyApp.exe Parameter ^> result.log
</code>```

Body:
Assuming that your command is

start MyApp.exe Parameter > result.log

This logs the output of the start command only, and that output is always empty.

If you want to redirect the output of the called program you need to escape the redirection.

But the redirection only works, when parsed by cmd.exe, else it's only a parameter to the application.

start cmd /c MyApp.exe Parameter ^> result.log


答:
If you want to measure some element in your component whenever the window resizes, it's going to look something like this:

class MyComponent extends React.Component {
  state = {
    x: 0,
    y: 0,
  };

  element = React.createRef();

  onWindowResize = () => {
    if (this.element.current) {
      const {x, y} = this.element.current.getBoundingClientRect();
      this.setState({x, y}, () => {
        console.log(this.state);
      });
    }
  };

  componentDidMount() {
    window.addEventListener('resize', this.onWindowResize);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.onWindowResize);
  }

  render() {
    return (

        <button>Hello, World</button>

    );
  }
}
```

The trick here is that your ref callback is only called once, when the element is initially added to the DOM. If you want to update state whenever you resize the window, you're going to need a 'resize' event handler.

Title: React - get element.getBoundingClientRect() after window resize

Body:
I have a class that needs to get the size of a DOM element. It works well, but when I resize the window it doesn't update until I change the state in my app, forcing a rerender. I've tried adding this.forceUpdate to a 'resize' event listener in componentDidMount(), but it didn't work. Perhaps I did something wrong? Ideally I'd like to avoid using this.forceUpdate for perfomance implications anyway. Any work arounds for this? Thanks in advance!

My code:

class MyComponent extends React.Component {
  state = { x: 0, y: 0 }

  refCallback = (element) => {
    if (!element) {
      return
    }
    const { x, y } = element.getBoundingClientRect()
    this.setState({ x, y })
  }

  render() {
    console.log('STATE:', this.state) // Outputs the correct x and y values.
    return (

        <button>Hello world</button>

    )
  }
}

Body:
If you want to measure some element in your component whenever the window resizes, it's going to look something like this:

class MyComponent extends React.Component {
  state = {
    x: 0,
    y: 0,
  };

  element = React.createRef();

  onWindowResize = () => {
    if (this.element.current) {
      const {x, y} = this.element.current.getBoundingClientRect();
      this.setState({x, y}, () => {
        console.log(this.state);
      });
    }
  };

  componentDidMount() {
    window.addEventListener('resize', this.onWindowResize);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.onWindowResize);
  }

  render() {
    return (
      <div ref={this.element}>
        <button>Hello, World</button>
      </div>
    );
  }
}

The trick here is that your ref callback is only called once, when the element is initially added to the DOM. If you want to update state whenever you resize the window, you're going to need a 'resize' event handler.


问:
Python - If/Elif statement (loops)
Can someone tell me why I'm getting 4 as the outcome? Should 3 be printing instead because the code is satisfied in the If section.</p>

```<code>a = 15

if a&5  == 0:
    print('3')
elif a% 5 == 0:
    print('4')

else:
    print('5')
</code>```

答:
You are comparing the bits of 15 with the bits of 5, resulting in the ones they have in common.

```<code>1111 & 101 => 101
</code>```

so the result is 5, not 0.

Title: Python - If/Elif statement (loops)

Body:
Can someone tell me why I'm getting 4 as the outcome? Should 3 be printing instead because the code is satisfied in the If section.

a = 15

if a&5  == 0:
    print('3')
elif a% 5 == 0:
    print('4')

else:
    print('5')

Body:
You are comparing the bits of 15 with the bits of 5, resulting in the ones they have in common.

1111 & 101 => 101

so the result is 5, not 0.


问:
Rolling Precision
I have a dataframe with binary predictions (data['ypred'] which is either 1 or 0) and actual realizations (data['y']) and I would like to write a function that computes a rolling Precision (that is percentage of correct predictions out of all predictions) for the last n values (the data is sorted by date already). Below is an example for the last 2 observations (notice how the first row is NA, and the last row is 50% since only 1 out of 2 is correct):

```<code> dict = [{'ypred': '1','y': '1','rolWinProb': 'NA'},
 {'ypred': '1','y': '1','rolWinProb': '100'},
 {'ypred': '0','y': '1','rolWinProb': '100'},
 {'ypred': '0','y': '1','rolWinProb': '100'},
 {'ypred': '1','y': '0','rolWinProb': '50'}]

 data = pd.DataFrame(dict)
</code>```

Can anyone suggest an approach?

Maybe something like this:

```<code>data[(data['y'] ==1 ) & (data['ypred']==1)].rolling(10)
</code>```

答:
Not sure, where you've got your values from, but what you can do:

N=2
data["rollwinprob"]=data["ypred"].eq(data["y"]).rolling(N).mean().mul(100)
```

Ref. https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.rolling.html

Title: Rolling Precision

Body:
I have a dataframe with binary predictions (data['ypred'] which is either 1 or 0) and actual realizations (data['y']) and I would like to write a function that computes a rolling Precision (that is percentage of correct predictions out of all predictions) for the last n values (the data is sorted by date already). Below is an example for the last 2 observations (notice how the first row is NA, and the last row is 50% since only 1 out of 2 is correct):

 dict = [{'ypred': '1','y': '1','rolWinProb': 'NA'},
 {'ypred': '1','y': '1','rolWinProb': '100'},
 {'ypred': '0','y': '1','rolWinProb': '100'},
 {'ypred': '0','y': '1','rolWinProb': '100'},
 {'ypred': '1','y': '0','rolWinProb': '50'}]

 data = pd.DataFrame(dict)

Can anyone suggest an approach?

Maybe something like this:

data[(data['y'] ==1 ) & (data['ypred']==1)].rolling(10)

Body:
Not sure, where you've got your values from, but what you can do:

N=2
data["rollwinprob"]=data["ypred"].eq(data["y"]).rolling(N).mean().mul(100)

Ref. https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.rolling.html


问:
Momentjs format: apply italic text styling
I'm using momentjs in reactjs and I want hours of the date as italic. E.g. 18 Feb 20 11:11

```<code>moment().format('DD MMM YY HH:mm')
</code>```

I can create separate date and hours and apply italic styling to hours.
But how can I do the "HH:mm" italic without calculating separate date and hours?

答:
moment.js will not determine the how the date is displayed on your application , it should be done by CSS in your application. Moment js is a javascript library which will help you in calculation of dates and times.
So I advice to calculate hours and minutes separately in span and apply your styles there.</p>

Body:
I'm using momentjs in reactjs and I want hours of the date as italic. E.g. 18 Feb 20 11:11

moment().format('DD MMM YY HH:mm')

I can create separate date and hours and apply italic styling to hours.
But how can I do the "HH:mm" italic without calculating separate date and hours?


Title: Python - If/Elif statement (loops)

Body:
& is bitwise AND and works like this:

15 & 5

  1111
& 0101
------
  0101 != 0


问:
Unable to downgrade angular cli to 1.0.0-Beta.24
I am new to angular, I want to run an angular project that uses angular- cli version 1.0.0-beta.24.

I tried uninstalling the current npm version, clean cache and than npm install -g angular-cli@1.0.0-beta.24. but it doesn't work. I am using node version 0.35.1

I have installed node -v v6.0.0 and nvm doesnt work

答:
Usually when you are downgrading/upgrading Angular projects you have
  to make sure that Angular CLI version matches Angular version and
  Typescript version. More details here

In your case if you are downgrading to 1.0.0-beta.24 you have to use NodeJS v6.x and make sure you are using Typescript v2.0.x

Also, when downgrading versions, make sure you removed node_modules folder and package-lock.json or yarn.lock files if you have any in your project. Then run npm i or yarn to pull the old packages.

If you are having issues switching NodeJS versions try NVM

UPDATE:

The error you are getting might be related to connectivity issues. If you are behind the proxy try that:

```<code>npm config set proxy http://your.company.proxy.com:port
npm config set https-proxy http://your.compny.company.com:port
</code>```

Body:
Usually when you are downgrading/upgrading Angular projects you have
  to make sure that Angular CLI version matches Angular version and
  Typescript version. More details here

In your case if you are downgrading to 1.0.0-beta.24 you have to use NodeJS v6.x and make sure you are using Typescript v2.0.x

Also, when downgrading versions, make sure you removed node_modules folder and package-lock.json or yarn.lock files if you have any in your project. Then run npm i or yarn to pull the old packages.

If you are having issues switching NodeJS versions try NVM

UPDATE:

The error you are getting might be related to connectivity issues. If you are behind the proxy try that:

npm config set proxy http://your.company.proxy.com:port
npm config set https-proxy http://your.compny.company.com:port


问:
How to check if any checkbox is selected or not in android with kotlin?
```<code>    submit_btn.setOnClickListener {
                var result = ""
                if(rb_gender.checkedRadioButtonId != -1)
                    {
                        result += " Gender: "
                    }
                    if(rb_male.isChecked) result += " Male \n"
                    if(rb_female.isChecked)  result += "Female \n"

       result += " Language Known:  "

            if(cb_english.isChecked) result+= " English"
            if(cb_hindi.isChecked) result+= " Hindi "
            if(cb_punjabi.isChecked) result+= " Punjabi"

               else   result = " PLEASE SELECT GENDER AND LANGUAGE \n"

            result_textView.text = result
        }
    }
}
</code>```

<p>//This code is not working on some condition like if I select Male and English then complier run else part......but that's not true</p>

答: you can use  string and check if its value is empty or null that means user did not select any checkbox and if its have value that mean user select a check box simple.</p>

Body:
    submit_btn.setOnClickListener {
                var result = ""
                if(rb_gender.checkedRadioButtonId != -1)
                    {
                        result += " Gender: "
                    }
                    if(rb_male.isChecked) result += " Male \n"
                    if(rb_female.isChecked)  result += "Female \n"

       result += " Language Known:  "

            if(cb_english.isChecked) result+= " English"
            if(cb_hindi.isChecked) result+= " Hindi "
            if(cb_punjabi.isChecked) result+= " Punjabi"

               else   result = " PLEASE SELECT GENDER AND LANGUAGE \n"

            result_textView.text = result
        }
    }
}

//This code is not working on some condition like if I select Male and English then complier run else part......but that's not true


答:
Check whether below query give your expected result. </p>

```<code>SELECT
  a.name,
  a.gender,
  COUNT(ac.movieid) NoOf_Movies
FROM
  actors a
  INNER JOIN actor_movie am ON a.id = am.actorID
GROUP BY
  a.name,
  a.gender
HAVING
  COUNT(ac.movieid) > 9
ORDER BY
  am.movieID DESC
</code>```

Title: How can i List any actors

Body: I’m trying to list the actors (male/female) that have starred in 10 or more different film genres I have a table called actors which contains three columns:actorID,name,gender and another table called movies which contains movieID,title,year, last table is movies_actor it contains movieID,actorID,as_charachter,leading

Body:
Check whether below query give your expected result.

SELECT
  a.name,
  a.gender,
  COUNT(ac.movieid) NoOf_Movies
FROM
  actors a
  INNER JOIN actor_movie am ON a.id = am.actorID
GROUP BY
  a.name,
  a.gender
HAVING
  COUNT(ac.movieid) > 9
ORDER BY
  am.movieID DESC


问:
axios get function not working in Reactjs
I am working on a web dev using ReactJs, NodeJs and Mysql. I got problem in displaying fetching data using axios.

here is my API :

```<code>app.get('/enduser',(req, res) => {
    let ENDUSER_QUERY = "SELECT * FROM enduser_tbl";
    let query = dbConn.query(ENDUSER_QUERY, (err, results) => {
      if(err) {
        console.log(err)
      } else {
        return res.status(200).json({"status": 200, "err" : null, "response": results});
      }
    });
  });

</code>```

and I call the API in my reactjs page component

```<code>class ProjectList extends Component {
    constructor(props){
        super(props);
        this.state = {
            enduser_tbl : []
        }
    }

    async componentDidMount() {
        const Url = "http://localhost:4000/enduser"
        await axios.get(Url)
        .then( enduser_tbl => {
            console.log(enduser_tbl.data)
            this.setState({
                enduser_tbl : enduser_tbl.data
            })
        })
    }

    render() {
        const enduser_tbl = this.state;
        return (
            <Container>
                { enduser_tbl.map ((enduser, project_id) =>
                    <ListGroup>
                        <ListGroup.Item key={project_id}> {enduser.project_type} </ListGroup.Item>
                    </ListGroup>
                )}
            </Container>
        )
    }
}

export default ProjectList
</code>```

I got no error in my terminal but many problem appears in Chrome. here is the response from chrome

答:
I think that you are trying to map an object because this.state is an object. Try changing the code as given below.</p>

```<code>class ProjectList extends Component {
    constructor(props){
        super(props);
        this.state = {
            enduser_tbl : []
        }
    }

    async componentDidMount() {
        const Url = "http://localhost:4000/enduser"
        await axios.get(Url)
        .then( enduser_tbl => {
            console.log(enduser_tbl.data)
            this.setState({
                enduser_tbl : enduser_tbl.data
            })
        })
    }

    render() {
        const enduser_tbl = this.state.enduser_tbl;
        return (
            <Container>
                { enduser_tbl.map ((enduser, project_id) =>
                    <ListGroup>
                        <ListGroup.Item key={project_id}> {enduser.project_type} </ListGroup.Item>
                    </ListGroup>
                )}
            </Container>
        )
    }
}
</code>```

Body:
I am working on a web dev using ReactJs, NodeJs and Mysql. I got problem in displaying fetching data using axios.

here is my API :

app.get('/enduser',(req, res) => {
    let ENDUSER_QUERY = "SELECT * FROM enduser_tbl";
    let query = dbConn.query(ENDUSER_QUERY, (err, results) => {
      if(err) {
        console.log(err)
      } else {
        return res.status(200).json({"status": 200, "err" : null, "response": results});
      }
    });
  });

and I call the API in my reactjs page component

class ProjectList extends Component {
    constructor(props){
        super(props);
        this.state = {
            enduser_tbl : []
        }
    }

    async componentDidMount() {
        const Url = "http://localhost:4000/enduser"
        await axios.get(Url)
        .then( enduser_tbl => {
            console.log(enduser_tbl.data)
            this.setState({
                enduser_tbl : enduser_tbl.data
            })
        })
    }

    render() {
        const enduser_tbl = this.state;
        return (
            <Container>
                { enduser_tbl.map ((enduser, project_id) =>
                    <ListGroup>
                        <ListGroup.Item key={project_id}> {enduser.project_type} </ListGroup.Item>
                    </ListGroup>
                )}
            </Container>
        )
    }
}

export default ProjectList

I got no error in my terminal but many problem appears in Chrome. here is the response from chrome

Body:
I think that you are trying to map an object because this.state is an object. Try changing the code as given below.

class ProjectList extends Component {
    constructor(props){
        super(props);
        this.state = {
            enduser_tbl : []
        }
    }

    async componentDidMount() {
        const Url = "http://localhost:4000/enduser"
        await axios.get(Url)
        .then( enduser_tbl => {
            console.log(enduser_tbl.data)
            this.setState({
                enduser_tbl : enduser_tbl.data
            })
        })
    }

    render() {
        const enduser_tbl = this.state.enduser_tbl;
        return (
            <Container>
                { enduser_tbl.map ((enduser, project_id) =>
                    <ListGroup>
                        <ListGroup.Item key={project_id}> {enduser.project_type} </ListGroup.Item>
                    </ListGroup>
                )}
            </Container>
        )
    }
}


问:
How to pass arguments in native sql query in Repository file in java?
This is my query, I have written in Repository file.

```<code>@Query(value = "select * from A a join B b ON a.allocateBy = b.empNo join D d ON b.departmentName = d.departmentName where a.allocateBy in (:allocateByList)",  nativeQuery = true)

ArrayList<A> findAllByAllocateByIn(@Param("allocateByList") String allocateByList);
</code>```

There are no errors but :allocateByList is not getting data. I have printed the value of allocateByList just before. It has data.

Am I missing Something?

答:
Change allocateByList to list and use below query</p>

```<code>@Query(value = "select * from A a join B b ON a.allocateBy = b.empNo join D d ON b.departmentName = d.departmentName where a.allocateBy in ?1",  nativeQuery = true);

ArrayList<PointAllocation> findAllByAllocateByIn(List<String> allocateByList);
</code>```

Body:
This is my query, I have written in Repository file.

@Query(value = "select * from A a join B b ON a.allocateBy = b.empNo join D d ON b.departmentName = d.departmentName where a.allocateBy in (:allocateByList)",  nativeQuery = true)

ArrayList findAllByAllocateByIn(@Param("allocateByList") String allocateByList);

There are no errors but :allocateByList is not getting data. I have printed the value of allocateByList just before. It has data.

Am I missing Something?

Body:
Change allocateByList to list and use below query

@Query(value = "select * from A a join B b ON a.allocateBy = b.empNo join D d ON b.departmentName = d.departmentName where a.allocateBy in ?1",  nativeQuery = true);

ArrayList<PointAllocation> findAllByAllocateByIn(List<String> allocateByList);


问:
most frequently used queries mysql
I'am a little confused about how to find most frequently used queries in mysql. I'm looking this query because I want use memcache tool in php application. Is really only way to find them is log every query to log file and after work on it?</p>

答: Using General Query Log is only the solution to do that. I couldn't find any other way. If the purpose is to optimize slow queries then you can use Slow Query Log to find the slowest queries.</p>

Title: most frequently used queries mysql