about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-05-04 02:01:32 -0700
committerEric Wong <normalperson@yhbt.net>2009-05-22 01:54:21 -0700
commit95718a5769e4ab06c86d0531e8a7c70fbd4c2f81 (patch)
tree695d7679021f9437efabaf10a938ca29fa6b2749
parent3d2b5954d70af6abd713bc820b3d7bc1ea115f30 (diff)
downloadunicorn-95718a5769e4ab06c86d0531e8a7c70fbd4c2f81.tar.gz
Ensure we preserve both internal and external encodings
when reopening logs.
-rw-r--r--Manifest1
-rw-r--r--lib/unicorn/util.rb15
-rw-r--r--test/unit/test_util.rb87
3 files changed, 98 insertions, 5 deletions
diff --git a/Manifest b/Manifest
index cfc2ddb..89db23c 100644
--- a/Manifest
+++ b/Manifest
@@ -129,3 +129,4 @@ test/unit/test_server.rb
 test/unit/test_signals.rb
 test/unit/test_socket_helper.rb
 test/unit/test_upload.rb
+test/unit/test_util.rb
diff --git a/lib/unicorn/util.rb b/lib/unicorn/util.rb
index 0400fd0..2d3f827 100644
--- a/lib/unicorn/util.rb
+++ b/lib/unicorn/util.rb
@@ -4,6 +4,8 @@ module Unicorn
   class Util
     class << self
 
+      APPEND_FLAGS = File::WRONLY | File::APPEND
+
       # this reopens logs that have been rotated (using logrotate(8) or
       # similar).  It is recommended that you install
       # A +File+ object is considered for reopening if it is:
@@ -17,17 +19,20 @@ module Unicorn
         ObjectSpace.each_object(File) do |fp|
           next if fp.closed?
           next unless (fp.sync && fp.path[0..0] == "/")
-
-          flags = fp.fcntl(Fcntl::F_GETFL)
-          open_flags = File::WRONLY | File::APPEND
-          next unless (flags & open_flags) == open_flags
+          next unless (fp.fcntl(Fcntl::F_GETFL) & APPEND_FLAGS) == APPEND_FLAGS
 
           begin
             a, b = fp.stat, File.stat(fp.path)
             next if a.ino == b.ino && a.dev == b.dev
           rescue Errno::ENOENT
           end
-          fp.reopen(fp.path, "a")
+
+          open_arg = 'a'
+          if fp.respond_to?(:external_encoding) && enc = fp.external_encoding
+            open_arg << ":#{enc.to_s}"
+            enc = fp.internal_encoding and open_arg << ":#{enc.to_s}"
+          end
+          fp.reopen(fp.path, open_arg)
           fp.sync = true
           nr += 1
         end # each_object
diff --git a/test/unit/test_util.rb b/test/unit/test_util.rb
new file mode 100644
index 0000000..1616eac
--- /dev/null
+++ b/test/unit/test_util.rb
@@ -0,0 +1,87 @@
+require 'test/test_helper'
+require 'tempfile'
+
+class TestUtil < Test::Unit::TestCase
+
+  EXPECT_FLAGS = File::WRONLY | File::APPEND
+  def test_reopen_logs_noop
+    tmp = Tempfile.new(nil)
+    tmp.reopen(tmp.path, 'a')
+    tmp.sync = true
+    ext = tmp.external_encoding rescue nil
+    int = tmp.internal_encoding rescue nil
+    before = tmp.stat.inspect
+    Unicorn::Util.reopen_logs
+    assert_equal before, File.stat(tmp.path).inspect
+    assert_equal ext, (tmp.external_encoding rescue nil)
+    assert_equal int, (tmp.internal_encoding rescue nil)
+  end
+
+  def test_reopen_logs_renamed
+    tmp = Tempfile.new(nil)
+    tmp_path = tmp.path.freeze
+    tmp.reopen(tmp_path, 'a')
+    tmp.sync = true
+    ext = tmp.external_encoding rescue nil
+    int = tmp.internal_encoding rescue nil
+    before = tmp.stat.inspect
+    to = Tempfile.new(nil)
+    File.rename(tmp_path, to.path)
+    assert ! File.exist?(tmp_path)
+    Unicorn::Util.reopen_logs
+    assert_equal tmp_path, tmp.path
+    assert File.exist?(tmp_path)
+    assert before != File.stat(tmp_path).inspect
+    assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect
+    assert_equal ext, (tmp.external_encoding rescue nil)
+    assert_equal int, (tmp.internal_encoding rescue nil)
+    assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL))
+    assert tmp.sync
+  end
+
+  def test_reopen_logs_renamed_with_encoding
+    tmp = Tempfile.new(nil)
+    tmp_path = tmp.path.dup.freeze
+    Encoding.list.each { |encoding|
+      tmp.reopen(tmp_path, "a:#{encoding.to_s}")
+      tmp.sync = true
+      assert_equal encoding, tmp.external_encoding
+      assert_nil tmp.internal_encoding
+      File.unlink(tmp_path)
+      assert ! File.exist?(tmp_path)
+      Unicorn::Util.reopen_logs
+      assert_equal tmp_path, tmp.path
+      assert File.exist?(tmp_path)
+      assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect
+      assert_equal encoding, tmp.external_encoding
+      assert_nil tmp.internal_encoding
+      assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL))
+      assert tmp.sync
+    }
+  end if STDIN.respond_to?(:external_encoding)
+
+  def test_reopen_logs_renamed_with_internal_encoding
+    tmp = Tempfile.new(nil)
+    tmp_path = tmp.path.dup.freeze
+    Encoding.list.each { |ext|
+      Encoding.list.each { |int|
+        next if ext == int
+        tmp.reopen(tmp_path, "a:#{ext.to_s}:#{int.to_s}")
+        tmp.sync = true
+        assert_equal ext, tmp.external_encoding
+        assert_equal int, tmp.internal_encoding
+        File.unlink(tmp_path)
+        assert ! File.exist?(tmp_path)
+        Unicorn::Util.reopen_logs
+        assert_equal tmp_path, tmp.path
+        assert File.exist?(tmp_path)
+        assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect
+        assert_equal ext, tmp.external_encoding
+        assert_equal int, tmp.internal_encoding
+        assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL))
+        assert tmp.sync
+      }
+    }
+  end if STDIN.respond_to?(:external_encoding)
+
+end