about summary refs log tree commit homepage
path: root/test/test_expect_100.rb
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2013-10-26 01:13:29 +0000
committerEric Wong <normalperson@yhbt.net>2013-10-26 02:00:17 +0000
commitf38e54f8d54f8cdfdc15f43b2394f0acfff5d413 (patch)
tree5a26e626a3fcee6787f62d1dd885137604db97c5 /test/test_expect_100.rb
parent8671b632849216476305573e87b5626bc34fedf1 (diff)
downloadyahns-f38e54f8d54f8cdfdc15f43b2394f0acfff5d413.tar.gz
The tiny responses for check_client_connection and "100-Continue"
responses may occasionally fail with EAGAIN.  We must be prepared
for those corner cases and buffer the output appropriately.  We can
safely use a string for buffering here (for once(!)), since the
buffer sizes are bounded and known at buffer time, unlike the
response headers/bodies sent by the Rack application.
Diffstat (limited to 'test/test_expect_100.rb')
-rw-r--r--test/test_expect_100.rb94
1 files changed, 94 insertions, 0 deletions
diff --git a/test/test_expect_100.rb b/test/test_expect_100.rb
index 338a50a..5b1ffa8 100644
--- a/test/test_expect_100.rb
+++ b/test/test_expect_100.rb
@@ -14,10 +14,18 @@ class TestExpect100 < Testcase
       code = env["HTTP_X_FORCE_RCODE"] || 100
       [ code, h, [] ]
     else
+      env["rack.input"].read
       [ 201, h, [] ]
     end
   end
 
+  module TrywriteBlocked
+    def kgio_trywrite(*args)
+      return :wait_writable if $_tw_block_on.include?($_tw_blocked += 1)
+      super
+    end
+  end
+
   def test_buffer_noccc; _test_expect_100(true, false); end
   def test_nobuffer_noccc; _test_expect_100(false, false); end
   def test_lazybuffer_noccc; _test_expect_100(:lazy, false); end
@@ -88,4 +96,90 @@ class TestExpect100 < Testcase
   def test_reject_true_noccc; _test_reject(false, false); end
   def test_reject_lazy_ccc; _test_reject(:lazy, true); end
   def test_reject_true_ccc; _test_reject(false, true); end
+
+  def test_swait_t_t; _swait(true, true, [1]); end
+  def test_swait_f_f; _swait(false, false, [1]); end
+  def test_swait_t_f; _swait(true, false, [1]); end
+  def test_swait_f_t; _swait(false, true, [1]); end
+  def test_swait_l_t; _swait(:lazy, true, [1]); end
+  def test_swait_l_f; _swait(:lazy, false, [1]); end
+
+  def test_swait2_t_t; _swait(true, true, [1,2]); end
+  def test_swait2_f_f; _swait(false, false, [1,2]); end
+  def test_swait2_t_f; _swait(true, false, [1,2]); end
+  def test_swait2_f_t; _swait(false, true, [1,2]); end
+  def test_swait2_l_t; _swait(:lazy, true, [1,2]); end
+  def test_swait2_l_f; _swait(:lazy, false, [1,2]); end
+
+  def test_swait3_t_t; _swait(true, true, [1,3]); end
+  def test_swait3_f_f; _swait(false, false, [1,3]); end
+  def test_swait3_t_f; _swait(true, false, [1,3]); end
+  def test_swait3_f_t; _swait(false, true, [1,3]); end
+  def test_swait3_l_t; _swait(:lazy, true, [1,3]); end
+  def test_swait3_l_f; _swait(:lazy, false, [1,3]); end
+
+  def test_swait_t_t_ccc; _swait(true, true, [1], true); end
+  def test_swait_f_f_ccc; _swait(false, false, [1], true); end
+  def test_swait_t_f_ccc; _swait(true, false, [1], true); end
+  def test_swait_f_t_ccc; _swait(false, true, [1], true); end
+  def test_swait_l_t_ccc; _swait(:lazy, true, [1], true); end
+  def test_swait_l_f_ccc; _swait(:lazy, false, [1], true); end
+
+  def test_swait2_t_t_ccc; _swait(true, true, [1,2], true); end
+  def test_swait2_f_f_ccc; _swait(false, false, [1,2], true); end
+  def test_swait2_t_f_ccc; _swait(true, false, [1,2], true); end
+  def test_swait2_f_t_ccc; _swait(false, true, [1,2], true); end
+  def test_swait2_l_t_ccc; _swait(:lazy, true, [1,2], true); end
+  def test_swait2_l_f_ccc; _swait(:lazy, false, [1,2], true); end
+
+  def test_swait3_t_t_ccc; _swait(true, true, [1,3], true); end
+  def test_swait3_f_f_ccc; _swait(false, false, [1,3], true); end
+  def test_swait3_t_f_ccc; _swait(true, false, [1,3], true); end
+  def test_swait3_f_t_ccc; _swait(false, true, [1,3], true); end
+  def test_swait3_l_t_ccc; _swait(:lazy, true, [1,3], true); end
+  def test_swait3_l_f_ccc; _swait(:lazy, false, [1,3], true); end
+
+  def test_swait3_t_t_ccc_body; _swait(true, true, [1,3], true, "HI"); end
+  def test_swait3_f_f_ccc_body; _swait(false, false, [1,3], true, "HI"); end
+  def test_swait3_t_f_ccc_body; _swait(true, false, [1,3], true, "HI"); end
+  def test_swait3_f_t_ccc_body; _swait(false, true, [1,3], true, "HI"); end
+  def test_swait3_l_t_ccc_body; _swait(:lazy, true, [1,3], true, "HI"); end
+  def test_swait3_l_f_ccc_body; _swait(:lazy, false, [1,3], true, "HI"); end
+
+  def _swait(ibtype, obtype, block_on, ccc = false, body = "")
+    err = @err
+    cfg = Yahns::Config.new
+    host, port = @srv.addr[3], @srv.addr[1]
+    cfg.instance_eval do
+      stderr_path err.path
+      GTL.synchronize {
+        app(:rack, APP) {
+         listen "#{host}:#{port}"
+         output_buffering obtype
+         input_buffering ibtype
+         check_client_connection ccc
+        }
+      }
+    end
+    pid = fork do
+      ENV["YAHNS_FD"] = @srv.fileno.to_s
+      $_tw_blocked = 0
+      $_tw_block_on = block_on
+      Yahns::HttpClient.__send__(:include, TrywriteBlocked)
+      Yahns::Server.new(cfg).start.join
+    end
+    c = get_tcp_client(host, port)
+    if body.size > 0
+      r = "PUT / HTTP/1.0\r\nExpect: 100-continue\r\n"
+      r << "Content-Length: #{body.size}\r\n\r\n#{body}"
+    else
+      r = "PUT / HTTP/1.0\r\nExpect: 100-continue\r\n\r\n"
+    end
+    c.write(r)
+    assert c.wait(10), "timed out"
+    buf = c.read
+    assert_match(%r{\AHTTP/1\.1 100 Continue\r\n\r\nHTTP/1\.1 201}, buf)
+  ensure
+    quit_wait(pid)
+  end
 end