Author: markt
Date: Tue Apr 30 14:13:28 2013
New Revision: 1477644
URL: http://svn.apache.org/r1477644
Log:
Add a simple unit test for async writes.
This (unexpectedly) passes on all three connectors.
Added:
tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteOutputStream.java
(with props)
Modified:
tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=1477644&r1=1477643&r2=1477644&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Tue Apr
30 14:13:28 2013
@@ -615,15 +615,10 @@ public class Http11NioProcessor extends
return;
}
AtomicBoolean canWrite = (AtomicBoolean)param;
- RequestInfo rp = request.getRequestProcessor();
- if (rp.getStage() == org.apache.coyote.Constants.STAGE_SERVICE) {
- if (outputBuffer.isWritable()) {
- canWrite.set(true);
- } else {
- canWrite.set(false);
- }
+ if (outputBuffer.isWritable()) {
+ canWrite.set(true);
} else {
- throw new IllegalStateException("Calling canWrite
asynchronously is illegal.");
+ canWrite.set(false);
}
}
}
Added:
tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteOutputStream.java?rev=1477644&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteOutputStream.java
(added)
+++ tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteOutputStream.java
Tue Apr 30 14:13:28 2013
@@ -0,0 +1,192 @@
+/*
+ * 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.catalina.connector;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+public class TestCoyoteOutputStream extends TomcatBaseTest {
+
+ @Test
+ public void testNonBlockingWriteNoneBlockingWriteNone() throws Exception {
+ doNonBlockingTest(0, 0);
+ }
+
+ @Test
+ public void testNonBlockingWriteOnceBlockingWriteNone() throws Exception {
+ doNonBlockingTest(1, 0);
+ }
+
+ @Test
+ public void testNonBlockingWriteTwiceBlockingWriteNone() throws Exception {
+ doNonBlockingTest(2, 0);
+ }
+
+ @Test
+ public void testNonBlockingWriteNoneBlockingWriteOnce() throws Exception {
+ doNonBlockingTest(0, 1);
+ }
+
+ @Test
+ public void testNonBlockingWriteOnceBlockingWriteOnce() throws Exception {
+ doNonBlockingTest(1, 1);
+ }
+
+ @Test
+ public void testNonBlockingWriteTwiceBlockingWriteOnce() throws Exception {
+ doNonBlockingTest(2, 1);
+ }
+
+ private void doNonBlockingTest(int asyncWriteTarget, int syncWriteTarget)
+ throws Exception {
+
+ Tomcat tomcat = getTomcatInstance();
+
+ Context root = tomcat.addContext("", TEMP_DIR);
+ Wrapper w = Tomcat.addServlet(root, "nbWrite",
+ new NonBlockingWriteServlet(asyncWriteTarget,
syncWriteTarget));
+ w.setAsyncSupported(true);
+ root.addServletMapping("/", "nbWrite");
+
+ tomcat.start();
+
+ ByteChunk bc = new ByteChunk();
+ int rc = getUrl("http://localhost:" + getPort() + "/", bc, null, null);
+
+ int totalCount = asyncWriteTarget + syncWriteTarget;
+ StringBuilder sb = new StringBuilder(totalCount * 16);
+ for (int i = 0; i < totalCount; i++) {
+ sb.append("OK - " + i + System.lineSeparator());
+ }
+ String expected = null;
+ if (sb.length() > 0) {
+ expected = sb.toString();
+ }
+ Assert.assertEquals(200, rc);
+ Assert.assertEquals(expected, bc.toString());
+ }
+
+ private static final class NonBlockingWriteServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+ private final int asyncWriteTarget;
+ private final int syncWriteTarget;
+ private final AtomicInteger asyncWriteCount = new AtomicInteger(0);
+
+ public NonBlockingWriteServlet(int asyncWriteTarget,
+ int syncWriteTarget) {
+ this.asyncWriteTarget = asyncWriteTarget;
+ this.syncWriteTarget = syncWriteTarget;
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ resp.setContentType("text/plain");
+ resp.setCharacterEncoding("UTF-8");
+ ServletOutputStream sos = resp.getOutputStream();
+
+
+ AsyncContext asyncCtxt = req.startAsync();
+ asyncCtxt.start(new AsyncTask(asyncCtxt, sos));
+ }
+
+ private void doAsyncWrite(AsyncContext asyncCtxt,
+ ServletOutputStream sos) {
+ PrintWriter pw = new PrintWriter(sos);
+ while (sos.isReady()) {
+ int next = asyncWriteCount.getAndIncrement();
+ if (next < asyncWriteTarget) {
+ pw.println("OK - " + next);
+ pw.flush();
+ } else {
+ doSyncWrite(asyncCtxt, sos);
+ break;
+ }
+ }
+ }
+
+ private void doSyncWrite(AsyncContext asyncCtxt,
+ ServletOutputStream sos) {
+ asyncCtxt.complete();
+ PrintWriter pw = new PrintWriter(sos);
+ for (int i = asyncWriteTarget;
+ i < syncWriteTarget + asyncWriteTarget; i++) {
+ pw.println("OK - " + i);
+ pw.flush();
+ }
+ }
+
+ private class AsyncTask implements Runnable {
+
+ private final AsyncContext asyncCtxt;
+ private final ServletOutputStream sos;
+
+ public AsyncTask(AsyncContext asyncCtxt, ServletOutputStream sos) {
+ this.asyncCtxt = asyncCtxt;
+ this.sos = sos;
+ }
+
+ @Override
+ public void run() {
+ sos.setWriteListener(new MyWriteListener(asyncCtxt, sos));
+ doAsyncWrite(asyncCtxt, sos);
+ }
+ }
+
+ private final class MyWriteListener implements WriteListener {
+
+ private final AsyncContext asyncCtxt;
+ private final ServletOutputStream sos;
+
+ public MyWriteListener(AsyncContext asyncCtxt,
+ ServletOutputStream sos) {
+ this.asyncCtxt = asyncCtxt;
+ this.sos = sos;
+ }
+
+ @Override
+ public void onWritePossible() throws IOException {
+ doAsyncWrite(asyncCtxt, sos);
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ // TODO Auto-generated method stub
+ }
+ }
+ }
+}
Propchange:
tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteOutputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]