[Groonga-commit] groonga/grntest [master] Add memory leak check

Back to archive index

Kouhei Sutou null+****@clear*****
Tue Sep 25 23:08:40 JST 2012


Kouhei Sutou	2012-09-25 23:08:40 +0900 (Tue, 25 Sep 2012)

  New Revision: b1222e89aeb8076561ecf06dd125be6b4d4fb746
  https://github.com/groonga/grntest/commit/b1222e89aeb8076561ecf06dd125be6b4d4fb746

  Log:
    Add memory leak check

  Modified files:
    lib/grntest/tester.rb

  Modified: lib/grntest/tester.rb (+114 -16)
===================================================================
--- lib/grntest/tester.rb    2012-09-25 22:38:39 +0900 (1364f21)
+++ lib/grntest/tester.rb    2012-09-25 23:08:40 +0900 (dc79830)
@@ -396,12 +396,14 @@ module Grntest
     end
 
     class WorkerResult < Result
-      attr_reader :n_tests, :n_passed_tests, :n_not_checked_tests
+      attr_reader :n_tests, :n_passed_tests, :n_leaked_tests
+      attr_reader :n_not_checked_tests
       attr_reader :failed_tests
       def initialize
         super
         @n_tests = 0
         @n_passed_tests = 0
+        @n_leaked_tests = 0
         @n_not_checked_tests = 0
         @failed_tests = []
       end
@@ -422,6 +424,10 @@ module Grntest
         @failed_tests << name
       end
 
+      def test_leaked(name)
+        @n_leaked_tests += 1
+      end
+
       def test_not_checked
         @n_not_checked_tests += 1
       end
@@ -501,6 +507,12 @@ module Grntest
         @reporter.fail_test(self, result)
       end
 
+      def leaked_test(result)
+        @status = "leaked(#{result.n_leaked_objects})"
+        @result.test_leaked(test_name)
+        @reporter.leaked_test(self, result)
+      end
+
       def not_checked_test(result)
         @status = "not checked"
         @result.test_not_checked
@@ -545,6 +557,10 @@ module Grntest
         collect_count(:n_failed_tests)
       end
 
+      def n_leaked_tests
+        collect_count(:n_leaked_tests)
+      end
+
       def n_not_checked_tests
         collect_count(:n_not_checked_tests)
       end
@@ -633,24 +649,33 @@ module Grntest
 
     class TestResult < Result
       attr_accessor :worker_id, :test_name
-      attr_accessor :expected, :actual
+      attr_accessor :expected, :actual, :n_leaked_objects
       def initialize(worker)
         super()
         @worker_id = worker.id
         @test_name = worker.test_name
         @actual = nil
         @expected = nil
+        @n_leaked_objects = 0
       end
 
       def status
         if @expected
           if @actual == @expected
-            :success
+            if @n_leaked_objects.zero?
+              :success
+            else
+              :leaked
+            end
           else
             :failure
           end
         else
-          :not_checked
+          if @n_leaked_objects.zero?
+            :not_checked
+          else
+            :leaked
+          end
         end
       end
     end
@@ -673,7 +698,7 @@ module Grntest
         result.measure do
           result.actual = execute_groonga_script
         end
-        result.actual = normalize_result(result.actual)
+        normalize_actual_result(result)
         result.expected = read_expected_result
         case result.status
         when :success
@@ -683,6 +708,9 @@ module Grntest
           @worker.fail_test(result)
           output_reject_file(result.actual)
           succeeded = false
+        when :leaked
+          @worker.leaked_test(result)
+          succeeded = false
         else
           @worker.not_checked_test(result)
           output_actual_file(result.actual)
@@ -708,6 +736,7 @@ module Grntest
           run_groonga(context) do |executor|
             executor.execute(test_script_path)
           end
+          check_memory_leak(context)
           context.result
         end
       end
@@ -950,9 +979,9 @@ EOF
         output_fd.close(true)
       end
 
-      def normalize_result(result)
+      def normalize_actual_result(result)
         normalized_result = ""
-        result.each do |tag, content, options|
+        result.actual.each do |tag, content, options|
           case tag
           when :input
             normalized_result << content
@@ -960,9 +989,11 @@ EOF
             normalized_result << normalize_output(content, options)
           when :error
             normalized_result << normalize_raw_content(content)
+          when :n_leaked_objects
+            result.n_leaked_objects = content
           end
         end
-        normalized_result
+        result.actual = normalized_result
       end
 
       def normalize_raw_content(content)
@@ -1069,6 +1100,17 @@ EOF
           result_file.print(actual_result)
         end
       end
+
+      def check_memory_leak(context)
+        context.log.each_line do |line|
+          timestamp, log_level, message = line.split(/\|\s*/, 3)
+          _ = timestamp # suppress warning
+          next unless /^grn_fin \(\d+\)$/ =~ message
+          n_leaked_objects = $1.to_i
+          next if n_leaked_objects.zero?
+          context.result << [:n_leaked_objects, n_leaked_objects, {}]
+        end
+      end
     end
 
     class Executor
@@ -1513,6 +1555,7 @@ EOF
       end
 
       def report_summary(result)
+        puts(statistics_header)
         puts(colorize(statistics(result), result))
         pass_ratio = result.pass_ratio
         elapsed_time = result.elapsed_time
@@ -1520,14 +1563,28 @@ EOF
         puts(colorize(summary, result))
       end
 
+      def statistics_header
+        items = [
+          "tests/sec",
+          "tests",
+          "passes",
+          "failures",
+          "leaked",
+          "!checked",
+        ]
+        "  " + ((["%-9s"] * items.size).join(" | ") % items) + " |"
+      end
+
       def statistics(result)
         items = [
-          "#{result.n_tests} tests",
-          "#{result.n_passed_tests} passes",
-          "#{result.n_failed_tests} failures",
-          "#{result.n_not_checked_tests} not checked_tests",
+          "%9.2f" % throughput(result),
+          "%9d" % result.n_tests,
+          "%9d" % result.n_passed_tests,
+          "%9d" % result.n_failed_tests,
+          "%9d" % result.n_leaked_tests,
+          "%9d" % result.n_not_checked_tests,
         ]
-        "#{throughput(result)}: " + items.join(", ")
+        "  " + items.join(" | ") + " |"
       end
 
       def throughput(result)
@@ -1536,7 +1593,7 @@ EOF
         else
           tests_per_second = result.n_tests / result.elapsed_time
         end
-        "%.2f tests/sec" % tests_per_second
+        tests_per_second
       end
 
       def report_failure(result)
@@ -1689,6 +1746,8 @@ EOF
           "%s%s%s" % [success_color, message, reset_color]
         when :failure
           "%s%s%s" % [failure_color, message, reset_color]
+        when :leaked
+          "%s%s%s" % [leaked_color, message, reset_color]
         when :not_checked
           "%s%s%s" % [not_checked_color, message, reset_color]
         else
@@ -1722,6 +1781,19 @@ EOF
                         })
       end
 
+      def leaked_color
+        escape_sequence({
+                          :color => :magenta,
+                          :color_256 => [3, 0, 3],
+                          :background => true,
+                        },
+                        {
+                          :color => :white,
+                          :color_256 => [5, 5, 5],
+                          :bold => true,
+                        })
+      end
+
       def not_checked_color
         escape_sequence({
                           :color => :cyan,
@@ -1823,6 +1895,12 @@ EOF
         end
       end
 
+      def leaked_test(worker, result)
+        synchronize do
+          report_test_result_mark("L(#{result.n_leaked_objects})", result)
+        end
+      end
+
       def not_checked_test(worker, result)
         synchronize do
           report_test_result_mark("N", result)
@@ -1892,6 +1970,10 @@ EOF
         report_failure(result)
       end
 
+      def leaked_test(worker, result)
+        report_test_result(result, worker.status)
+      end
+
       def not_checked_test(worker, result)
         report_test_result(result, worker.status)
         report_actual(result)
@@ -1945,6 +2027,13 @@ EOF
         end
       end
 
+      def leaked_test(worker, result)
+        redraw do
+          report_test(worker, result)
+          report_marker(result)
+        end
+      end
+
       def not_checked_test(worker, result)
         redraw do
           report_test(worker, result)
@@ -1972,6 +2061,7 @@ EOF
 
       private
       def draw
+        draw_statistics_header_line
         @test_suites_result.workers.each do |worker|
           draw_status_line(worker)
           draw_test_line(worker)
@@ -1979,6 +2069,10 @@ EOF
         draw_progress_line
       end
 
+      def draw_statistics_header_line
+        puts(statistics_header)
+      end
+
       def draw_status_line(worker)
         clear_line
         left = "[#{colorize(worker.id, worker.result)}] "
@@ -1994,7 +2088,7 @@ EOF
         if worker.test_name
           label = "  #{worker.test_name}"
         else
-          label = "  #{statistics(worker.result)}"
+          label = statistics(worker.result)
         end
         puts(justify(label, @term_width))
       end
@@ -2054,7 +2148,11 @@ EOF
       end
 
       def n_using_lines
-        n_worker_lines * n_workers + n_progress_lines
+        n_statistics_header_line + n_worker_lines * n_workers + n_progress_lines
+      end
+
+      def n_statistics_header_line
+        1
       end
 
       def n_worker_lines
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index