This is an automated email from the ASF dual-hosted git repository. liubao pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git
commit b6b5855910daa64be64accb69b90d5fbe868d348 Author: wujimin <[email protected]> AuthorDate: Thu Nov 1 15:18:05 2018 +0800 [SCB-1001] add IT. --- .../common/rest/AbstractRestInvocation.java | 11 +++-- integration-tests/it-consumer/pom.xml | 6 +++ .../org/apache/servicecomb/it/ConsumerMain.java | 7 ++++ .../it/testcase/TestDownloadSlowStreamEdge.java | 48 ++++++++++++++++++++++ .../it-edge/src/main/resources/microservice.yaml | 15 +++++++ .../servicecomb/it/schema/DownloadSchema.java | 47 +++++++++++++++++++++ 6 files changed, 131 insertions(+), 3 deletions(-) diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java index 6d95820..932aef4 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java @@ -17,7 +17,6 @@ package org.apache.servicecomb.common.rest; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; @@ -268,12 +267,18 @@ public abstract class AbstractRestInvocation { try { responseEx.flushBuffer(); - } catch (IOException flushException) { + } catch (Throwable flushException) { LOGGER.error("Failed to flush rest response, operation:{}, request uri:{}", getMicroserviceQualifiedName(), requestEx.getRequestURI(), flushException); } - requestEx.getAsyncContext().complete(); + try { + requestEx.getAsyncContext().complete(); + } catch (Throwable completeException) { + LOGGER.error("Failed to complete async rest response, operation:{}, request uri:{}", + getMicroserviceQualifiedName(), requestEx.getRequestURI(), completeException); + } + // if failed to locate path, then will not create invocation // TODO: statistics this case if (invocation != null) { diff --git a/integration-tests/it-consumer/pom.xml b/integration-tests/it-consumer/pom.xml index 9821cab..7e743a8 100644 --- a/integration-tests/it-consumer/pom.xml +++ b/integration-tests/it-consumer/pom.xml @@ -34,6 +34,12 @@ <artifactId>it-common</artifactId> </dependency> <dependency> + <groupId>com.squareup.okhttp3</groupId> + <artifactId>okhttp</artifactId> + <scope>compile</scope> + </dependency> + + <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-model</artifactId> <version>3.3.9</version> diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java index 48da9cd..cbc00d7 100644 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/ConsumerMain.java @@ -29,6 +29,7 @@ import org.apache.servicecomb.it.testcase.TestDataTypePrimitive; import org.apache.servicecomb.it.testcase.TestDefaultJsonValueJaxrsSchema; import org.apache.servicecomb.it.testcase.TestDefaultValue; import org.apache.servicecomb.it.testcase.TestDownload; +import org.apache.servicecomb.it.testcase.TestDownloadSlowStreamEdge; import org.apache.servicecomb.it.testcase.TestIgnoreMethod; import org.apache.servicecomb.it.testcase.TestIgnoreStaticMethod; import org.apache.servicecomb.it.testcase.TestParamCodec; @@ -141,6 +142,9 @@ public class ConsumerMain { // about url len, different deploy have different url len, so only test standalone ITJUnitUtils.runWithRest(TestRestServerConfig.class); ITJUnitUtils.run(TestRestServerConfigEdge.class); + + // currently, only support vertx download + ITJUnitUtils.run(TestDownloadSlowStreamEdge.class); } private static void testH2CStandalone() throws Throwable { @@ -161,6 +165,9 @@ public class ConsumerMain { private static void testSpringBoot2Standalone() throws Throwable { runShareTestCases(); + + // currently, only support vertx download + ITJUnitUtils.run(TestDownloadSlowStreamEdge.class); } private static void testSpringBoot2Servlet() throws Throwable { diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownloadSlowStreamEdge.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownloadSlowStreamEdge.java new file mode 100644 index 0000000..8c9cfa5 --- /dev/null +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDownloadSlowStreamEdge.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.it.testcase; + +import java.io.IOException; + +import org.apache.servicecomb.it.extend.engine.GateRestTemplate; +import org.junit.Test; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +public class TestDownloadSlowStreamEdge { + static GateRestTemplate client = GateRestTemplate.createEdgeRestTemplate("download"); + + @Test + public void clearInputStreamAfterDisconnect() throws IOException { +// URL url = new URL(client.getUrlPrefix() + "/slowInputStream"); +// HttpURLConnection conn = (HttpURLConnection) url.openConnection(); +// conn.getInputStream().close(); +// conn.disconnect(); + + OkHttpClient httpClient = new OkHttpClient(); + Request request = new Request.Builder().url(client.getUrlPrefix() + "/slowInputStream") + .build(); + Response response = httpClient.newCall(request).execute(); + + response.body().byteStream(); + response.body().close(); + + client.getForObject("/waitSlowInputStreamClosed", Void.class); + } +} diff --git a/integration-tests/it-edge/src/main/resources/microservice.yaml b/integration-tests/it-edge/src/main/resources/microservice.yaml index 476f3e9..888f1dd 100644 --- a/integration-tests/it-edge/src/main/resources/microservice.yaml +++ b/integration-tests/it-edge/src/main/resources/microservice.yaml @@ -34,30 +34,45 @@ servicecomb: # emptyAsNull: true operation: it-producer: + download: + slowInputStream: + transport: rest defaultJsonValueJaxrs: jsonInput: transport: rest queryInput: transport: rest it-producer-h2: + download: + slowInputStream: + transport: rest defaultJsonValueJaxrs: jsonInput: transport: rest queryInput: transport: rest it-producer-h2c: + download: + slowInputStream: + transport: rest defaultJsonValueJaxrs: jsonInput: transport: rest queryInput: transport: rest it-producer-deploy-springboot2-servlet: + download: + slowInputStream: + transport: rest defaultJsonValueJaxrs: jsonInput: transport: rest queryInput: transport: rest it-producer-deploy-springboot2-standalone: + download: + slowInputStream: + transport: rest defaultJsonValueJaxrs: jsonInput: transport: rest diff --git a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DownloadSchema.java b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DownloadSchema.java index 89a5d1a..b1123b6 100644 --- a/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DownloadSchema.java +++ b/integration-tests/it-producer/src/main/java/org/apache/servicecomb/it/schema/DownloadSchema.java @@ -20,6 +20,9 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.lang.Thread.State; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; @@ -27,15 +30,18 @@ import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.UUID; +import java.util.concurrent.TimeUnit; import javax.servlet.http.Part; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import org.apache.http.entity.StringEntity; import org.apache.http.impl.bootstrap.HttpServer; import org.apache.http.impl.bootstrap.ServerBootstrap; import org.apache.servicecomb.core.BootListener; import org.apache.servicecomb.foundation.common.part.FilePart; +import org.apache.servicecomb.it.ITUtils; import org.apache.servicecomb.provider.rest.common.RestSchema; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; @@ -194,4 +200,45 @@ public class DownloadSchema implements BootListener { conn.disconnect(); return responseEntity; } + + private Thread slowInputStreamThread; + + @GetMapping(path = "/waitSlowInputStreamClosed") + public void waitSlowInputStreamClosed() { + while (!slowInputStreamThread.getState().equals(State.TERMINATED)) { + ITUtils.forceWait(TimeUnit.MILLISECONDS, 500); + } + } + + @ApiResponses({@ApiResponse(code = 200, response = File.class, message = "")}) + @GetMapping(path = "/slowInputStream") + public ResponseEntity<InputStream> slowInputStream() throws IOException { + PipedInputStream in = new PipedInputStream(); + PipedOutputStream out = new PipedOutputStream(); + in.connect(out); + + slowInputStreamThread = new Thread(() -> { + Thread.currentThread().setName("download thread"); + byte[] bytes = "1".getBytes(); + for (; ; ) { + try { + out.write(bytes); + out.flush(); + Thread.sleep(1000); + } catch (Throwable e) { + break; + } + } + + IOUtils.closeQuietly(out); + }); + slowInputStreamThread.start(); + + ResponseEntity<InputStream> responseEntity = ResponseEntity + .ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=slowInputStream.txt") + .body(in); + return responseEntity; + } }
