about summary refs log tree commit homepage
path: root/test/epoll_enospc.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/epoll_enospc.rb')
-rw-r--r--test/epoll_enospc.rb100
1 files changed, 100 insertions, 0 deletions
diff --git a/test/epoll_enospc.rb b/test/epoll_enospc.rb
new file mode 100644
index 0000000..5c254c0
--- /dev/null
+++ b/test/epoll_enospc.rb
@@ -0,0 +1,100 @@
+#!/usr/bin/env ruby
+# -*- encoding: binary -*-
+# Copyright (C) 2012-2013, Eric Wong <normalperson@yhbt.net>
+# License: GPLv3 or later (see COPYING for details)
+require 'test/test_helper'
+
+TEST_PROG = 'test/epoll-wrap'
+has_epoll = false
+if File.exist?(TEST_PROG) && `which lsof 2>/dev/null`.strip.size > 0
+  s = `strings test/epoll-wrap`.split(/\n/)
+  has_epoll = !!s.grep(/epoll_ctl failure injection/)[0]
+end
+
+class TestEpollEnospc < Test::Unit::TestCase
+  def setup
+    @tmpdir = Dir.mktmpdir('cmogstored-epoll-enospc-test')
+    @to_close = []
+    @host = TEST_HOST
+    srv = TCPServer.new(@host, 0)
+    @port = srv.addr[1]
+    srv.close
+    @err = Tempfile.new("stderr")
+    cmd = [ TEST_PROG, "--docroot=#@tmpdir", "--httplisten=#@host:#@port",
+            "--maxconns=500" ]
+    vg = ENV["VALGRIND"] and cmd = vg.split(/\s+/).concat(cmd)
+    @pid = fork {
+      $stderr.reopen(@err)
+      @err.close
+      exec(*cmd)
+    }
+    @client = get_client
+  end
+
+  def wait_for(sec, reason)
+    stop = Time.now + sec
+    begin
+      return if yield
+      sleep 0.1
+    end while Time.now < stop
+    assert false, reason
+  end
+
+  def test_close_file
+    sparse_file_prepare
+    @client.write "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
+    buf = @client.readpartial(1000)
+    assert_match(/\r\n\r\n\z/, buf)
+    Process.kill(:TTIN, @pid)
+
+    wait_for(5, "ENOSPC injection signal") do
+      File.readlines(@err.path).grep(/ENOSPC on/)[0]
+    end
+    @client.write("GET /dev666/sparse-file.fid HTTP/1.1\r\n" \
+                  "Host: example.com\r\n\r\n")
+    sleep 1
+    bytes = 0
+    buf = ""
+    begin
+      bytes += @client.readpartial(666666, buf).bytesize
+    rescue EOFError
+      break
+    end while true
+
+    wait_for(5, "failure injection message") do
+      File.readlines(@err.path).grep(/epoll_ctl failure injection/)[0]
+    end
+
+    wait_for(5, "sparse file close") do
+      `lsof -p #@pid` !~ /sparse-file\.fid/
+    end
+  end
+
+  def teardown
+    Process.kill(:QUIT, @pid) rescue nil
+    _, status = Process.waitpid2(@pid)
+    @to_close.each { |io| io.close unless io.closed? }
+    FileUtils.rm_rf(@tmpdir)
+    @err.rewind
+    #$stderr.write(@err.read)
+    assert status.success?, status.inspect
+  end
+
+  def sparse_file_prepare(big = nil)
+    Dir.mkdir("#@tmpdir/dev666")
+    if nil == big
+      big = 1024 * 1024 * 500 # only 500M
+      big /= 10 if ENV["VALGRIND"] # valgrind slows us down enough :P
+    end
+    File.open("#@tmpdir/dev666/sparse-file.fid", "w") do |fp|
+      begin
+        fp.seek(big - 1)
+      rescue Errno::EINVAL, Errno::ENOSPC
+        big /= 2
+        warn "trying large file size: #{big}"
+        retry
+      end
+      fp.write('.')
+    end
+  end
+end if has_epoll