csd 0.0.15 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/COPYING +367 -0
- data/Rakefile +10 -10
- data/VERSION +1 -1
- data/bin/ai +19 -0
- data/csd.gemspec +257 -35
- data/lib/active_support.rb +75 -0
- data/lib/active_support/all.rb +3 -0
- data/lib/active_support/backtrace_cleaner.rb +94 -0
- data/lib/active_support/base64.rb +42 -0
- data/lib/active_support/basic_object.rb +21 -0
- data/lib/active_support/benchmarkable.rb +60 -0
- data/lib/active_support/buffered_logger.rb +132 -0
- data/lib/active_support/builder.rb +6 -0
- data/lib/active_support/cache.rb +626 -0
- data/lib/active_support/cache/compressed_mem_cache_store.rb +13 -0
- data/lib/active_support/cache/file_store.rb +188 -0
- data/lib/active_support/cache/mem_cache_store.rb +191 -0
- data/lib/active_support/cache/memory_store.rb +159 -0
- data/lib/active_support/cache/strategy/local_cache.rb +164 -0
- data/lib/active_support/cache/synchronized_memory_store.rb +11 -0
- data/lib/active_support/callbacks.rb +600 -0
- data/lib/active_support/concern.rb +29 -0
- data/lib/active_support/configurable.rb +36 -0
- data/lib/active_support/core_ext.rb +3 -0
- data/lib/active_support/core_ext/array.rb +7 -0
- data/lib/active_support/core_ext/array/access.rb +46 -0
- data/lib/active_support/core_ext/array/conversions.rb +164 -0
- data/lib/active_support/core_ext/array/extract_options.rb +29 -0
- data/lib/active_support/core_ext/array/grouping.rb +100 -0
- data/lib/active_support/core_ext/array/random_access.rb +20 -0
- data/lib/active_support/core_ext/array/uniq_by.rb +17 -0
- data/lib/active_support/core_ext/array/wrap.rb +22 -0
- data/lib/active_support/core_ext/benchmark.rb +7 -0
- data/lib/active_support/core_ext/big_decimal.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +27 -0
- data/lib/active_support/core_ext/cgi.rb +1 -0
- data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +19 -0
- data/lib/active_support/core_ext/class.rb +4 -0
- data/lib/active_support/core_ext/class/attribute.rb +67 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +63 -0
- data/lib/active_support/core_ext/class/delegating_attributes.rb +44 -0
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +232 -0
- data/lib/active_support/core_ext/class/subclasses.rb +55 -0
- data/lib/active_support/core_ext/date/acts_like.rb +8 -0
- data/lib/active_support/core_ext/date/calculations.rb +240 -0
- data/lib/active_support/core_ext/date/conversions.rb +99 -0
- data/lib/active_support/core_ext/date/freeze.rb +31 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +13 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +113 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +102 -0
- data/lib/active_support/core_ext/date_time/zones.rb +17 -0
- data/lib/active_support/core_ext/enumerable.rb +119 -0
- data/lib/active_support/core_ext/exception.rb +3 -0
- data/lib/active_support/core_ext/file.rb +2 -0
- data/lib/active_support/core_ext/file/atomic.rb +41 -0
- data/lib/active_support/core_ext/file/path.rb +5 -0
- data/lib/active_support/core_ext/float.rb +1 -0
- data/lib/active_support/core_ext/float/rounding.rb +19 -0
- data/lib/active_support/core_ext/hash.rb +8 -0
- data/lib/active_support/core_ext/hash/conversions.rb +150 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +16 -0
- data/lib/active_support/core_ext/hash/diff.rb +13 -0
- data/lib/active_support/core_ext/hash/except.rb +24 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +14 -0
- data/lib/active_support/core_ext/hash/keys.rb +45 -0
- data/lib/active_support/core_ext/hash/reverse_merge.rb +28 -0
- data/lib/active_support/core_ext/hash/slice.rb +38 -0
- data/lib/active_support/core_ext/integer.rb +3 -0
- data/lib/active_support/core_ext/integer/inflections.rb +14 -0
- data/lib/active_support/core_ext/integer/multiple.rb +6 -0
- data/lib/active_support/core_ext/integer/time.rb +39 -0
- data/lib/active_support/core_ext/kernel.rb +5 -0
- data/lib/active_support/core_ext/kernel/agnostics.rb +11 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +16 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +62 -0
- data/lib/active_support/core_ext/kernel/requires.rb +26 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +13 -0
- data/lib/active_support/core_ext/load_error.rb +23 -0
- data/lib/active_support/core_ext/logger.rb +146 -0
- data/lib/active_support/core_ext/module.rb +12 -0
- data/lib/active_support/core_ext/module/aliasing.rb +70 -0
- data/lib/active_support/core_ext/module/anonymous.rb +24 -0
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +31 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +32 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +66 -0
- data/lib/active_support/core_ext/module/delegation.rb +146 -0
- data/lib/active_support/core_ext/module/deprecation.rb +9 -0
- data/lib/active_support/core_ext/module/introspection.rb +88 -0
- data/lib/active_support/core_ext/module/method_names.rb +14 -0
- data/lib/active_support/core_ext/module/reachable.rb +10 -0
- data/lib/active_support/core_ext/module/remove_method.rb +6 -0
- data/lib/active_support/core_ext/module/synchronization.rb +42 -0
- data/lib/active_support/core_ext/name_error.rb +18 -0
- data/lib/active_support/core_ext/numeric.rb +2 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +44 -0
- data/lib/active_support/core_ext/numeric/time.rb +77 -0
- data/lib/active_support/core_ext/object.rb +14 -0
- data/lib/active_support/core_ext/object/acts_like.rb +10 -0
- data/lib/active_support/core_ext/object/blank.rb +76 -0
- data/lib/active_support/core_ext/object/conversions.rb +4 -0
- data/lib/active_support/core_ext/object/duplicable.rb +65 -0
- data/lib/active_support/core_ext/object/extending.rb +11 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +67 -0
- data/lib/active_support/core_ext/object/misc.rb +2 -0
- data/lib/active_support/core_ext/object/returning.rb +42 -0
- data/lib/active_support/core_ext/object/to_param.rb +49 -0
- data/lib/active_support/core_ext/object/to_query.rb +27 -0
- data/lib/active_support/core_ext/object/try.rb +36 -0
- data/lib/active_support/core_ext/object/with_options.rb +26 -0
- data/lib/active_support/core_ext/proc.rb +14 -0
- data/lib/active_support/core_ext/process.rb +1 -0
- data/lib/active_support/core_ext/process/daemon.rb +23 -0
- data/lib/active_support/core_ext/range.rb +4 -0
- data/lib/active_support/core_ext/range/blockless_step.rb +29 -0
- data/lib/active_support/core_ext/range/conversions.rb +21 -0
- data/lib/active_support/core_ext/range/include_range.rb +21 -0
- data/lib/active_support/core_ext/range/overlaps.rb +8 -0
- data/lib/active_support/core_ext/regexp.rb +5 -0
- data/lib/active_support/core_ext/rexml.rb +46 -0
- data/lib/active_support/core_ext/string.rb +12 -0
- data/lib/active_support/core_ext/string/access.rb +99 -0
- data/lib/active_support/core_ext/string/behavior.rb +7 -0
- data/lib/active_support/core_ext/string/conversions.rb +61 -0
- data/lib/active_support/core_ext/string/encoding.rb +11 -0
- data/lib/active_support/core_ext/string/exclude.rb +6 -0
- data/lib/active_support/core_ext/string/filters.rb +49 -0
- data/lib/active_support/core_ext/string/inflections.rb +149 -0
- data/lib/active_support/core_ext/string/interpolation.rb +2 -0
- data/lib/active_support/core_ext/string/multibyte.rb +72 -0
- data/lib/active_support/core_ext/string/output_safety.rb +109 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -0
- data/lib/active_support/core_ext/string/xchar.rb +18 -0
- data/lib/active_support/core_ext/time/acts_like.rb +8 -0
- data/lib/active_support/core_ext/time/calculations.rb +282 -0
- data/lib/active_support/core_ext/time/conversions.rb +85 -0
- data/lib/active_support/core_ext/time/marshal.rb +56 -0
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +10 -0
- data/lib/active_support/core_ext/time/zones.rb +78 -0
- data/lib/active_support/core_ext/uri.rb +22 -0
- data/lib/active_support/dependencies.rb +628 -0
- data/lib/active_support/dependencies/autoload.rb +50 -0
- data/lib/active_support/deprecation.rb +18 -0
- data/lib/active_support/deprecation/behaviors.rb +38 -0
- data/lib/active_support/deprecation/method_wrappers.rb +29 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +74 -0
- data/lib/active_support/deprecation/reporting.rb +56 -0
- data/lib/active_support/duration.rb +105 -0
- data/lib/active_support/gzip.rb +25 -0
- data/lib/active_support/hash_with_indifferent_access.rb +145 -0
- data/lib/active_support/i18n.rb +8 -0
- data/lib/active_support/inflections.rb +56 -0
- data/lib/active_support/inflector.rb +7 -0
- data/lib/active_support/inflector/inflections.rb +211 -0
- data/lib/active_support/inflector/methods.rb +141 -0
- data/lib/active_support/inflector/transliterate.rb +97 -0
- data/lib/active_support/json.rb +2 -0
- data/lib/active_support/json/backends/jsongem.rb +43 -0
- data/lib/active_support/json/backends/yajl.rb +40 -0
- data/lib/active_support/json/backends/yaml.rb +90 -0
- data/lib/active_support/json/decoding.rb +51 -0
- data/lib/active_support/json/encoding.rb +254 -0
- data/lib/active_support/json/variable.rb +11 -0
- data/lib/active_support/lazy_load_hooks.rb +27 -0
- data/lib/active_support/locale/en.yml +36 -0
- data/lib/active_support/memoizable.rb +103 -0
- data/lib/active_support/message_encryptor.rb +71 -0
- data/lib/active_support/message_verifier.rb +62 -0
- data/lib/active_support/multibyte.rb +44 -0
- data/lib/active_support/multibyte/chars.rb +480 -0
- data/lib/active_support/multibyte/exceptions.rb +8 -0
- data/lib/active_support/multibyte/unicode.rb +393 -0
- data/lib/active_support/multibyte/utils.rb +60 -0
- data/lib/active_support/notifications.rb +81 -0
- data/lib/active_support/notifications/fanout.rb +93 -0
- data/lib/active_support/notifications/instrumenter.rb +56 -0
- data/lib/active_support/option_merger.rb +25 -0
- data/lib/active_support/ordered_hash.rb +158 -0
- data/lib/active_support/ordered_options.rb +27 -0
- data/lib/active_support/railtie.rb +100 -0
- data/lib/active_support/rescuable.rb +114 -0
- data/lib/active_support/ruby/shim.rb +22 -0
- data/lib/active_support/secure_random.rb +199 -0
- data/lib/active_support/string_inquirer.rb +21 -0
- data/lib/active_support/test_case.rb +42 -0
- data/lib/active_support/testing/assertions.rb +82 -0
- data/lib/active_support/testing/declarative.rb +40 -0
- data/lib/active_support/testing/default.rb +9 -0
- data/lib/active_support/testing/deprecation.rb +55 -0
- data/lib/active_support/testing/isolation.rb +154 -0
- data/lib/active_support/testing/pending.rb +48 -0
- data/lib/active_support/testing/performance.rb +455 -0
- data/lib/active_support/testing/setup_and_teardown.rb +111 -0
- data/lib/active_support/time.rb +34 -0
- data/lib/active_support/time/autoload.rb +5 -0
- data/lib/active_support/time_with_zone.rb +341 -0
- data/lib/active_support/values/time_zone.rb +377 -0
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +10 -0
- data/lib/active_support/whiny_nil.rb +60 -0
- data/lib/active_support/xml_mini.rb +158 -0
- data/lib/active_support/xml_mini/jdom.rb +168 -0
- data/lib/active_support/xml_mini/libxml.rb +80 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +85 -0
- data/lib/active_support/xml_mini/nokogiri.rb +78 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +83 -0
- data/lib/active_support/xml_mini/rexml.rb +129 -0
- data/lib/csd.rb +82 -2
- data/lib/csd/application.rb +2 -0
- data/lib/csd/application/default.rb +51 -0
- data/lib/csd/application/default/base.rb +15 -0
- data/lib/csd/application/minisip.rb +25 -0
- data/lib/csd/application/minisip/about.yml +14 -0
- data/lib/csd/application/minisip/base.rb +161 -0
- data/lib/csd/application/minisip/error.rb +11 -0
- data/lib/csd/application/minisip/options/common.rb +0 -0
- data/lib/csd/application/minisip/options/compile.rb +59 -0
- data/lib/csd/{applications → application}/minisip/unix/base.rb +10 -11
- data/lib/csd/application/opensips/about.yml +2 -0
- data/lib/csd/applications.rb +55 -0
- data/lib/csd/commands.rb +88 -65
- data/lib/csd/error.rb +31 -0
- data/lib/csd/extensions.rb +1 -0
- data/lib/{extensions → csd/extensions}/core/array.rb +2 -2
- data/lib/csd/extensions/core/dir.rb +46 -0
- data/lib/{extensions → csd/extensions}/core/file.rb +2 -2
- data/lib/{extensions → csd/extensions}/core/object.rb +2 -2
- data/lib/csd/extensions/core/option_parser.rb +33 -0
- data/lib/{extensions → csd/extensions}/core/pathname.rb +12 -3
- data/lib/{extensions → csd/extensions}/core/string.rb +2 -2
- data/lib/{extensions → csd/extensions}/gem/platform.rb +6 -2
- data/lib/csd/global_open_struct.rb +18 -0
- data/lib/csd/options.rb +124 -95
- data/lib/csd/path.rb +31 -0
- data/lib/csd/ui.rb +1 -0
- data/lib/csd/ui/cli.rb +7 -0
- data/lib/csd/ui/ui.rb +46 -0
- data/lib/csd/version.rb +9 -0
- data/lib/term/ansicolor.rb +102 -0
- data/lib/term/ansicolor/.keep +0 -0
- data/lib/term/ansicolor/version.rb +10 -0
- data/test/functional/test_applications.rb +86 -0
- data/test/functional/test_commands.rb +42 -29
- data/test/functional/test_options.rb +98 -0
- data/test/helper.rb +14 -0
- data/test/unit/test_dir.rb +38 -0
- data/test/unit/test_pathname.rb +32 -0
- metadata +253 -40
- data/LICENSE +0 -20
- data/bin/csd +0 -8
- data/lib/csd/applications/base.rb +0 -33
- data/lib/csd/applications/minisip/base.rb +0 -125
- data/lib/csd/applications/minisip/init.rb +0 -20
- data/lib/csd/init.rb +0 -69
- data/lib/csd/path_container.rb +0 -15
- data/publish +0 -29
@@ -0,0 +1,40 @@
|
|
1
|
+
module ActiveSupport
|
2
|
+
module Testing
|
3
|
+
module Declarative
|
4
|
+
|
5
|
+
def self.extended(klass)
|
6
|
+
klass.class_eval do
|
7
|
+
|
8
|
+
unless method_defined?(:describe)
|
9
|
+
def self.describe(text)
|
10
|
+
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
11
|
+
def self.name
|
12
|
+
"#{text}"
|
13
|
+
end
|
14
|
+
RUBY_EVAL
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
unless defined?(Spec)
|
22
|
+
# test "verify something" do
|
23
|
+
# ...
|
24
|
+
# end
|
25
|
+
def test(name, &block)
|
26
|
+
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
27
|
+
defined = instance_method(test_name) rescue false
|
28
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
29
|
+
if block_given?
|
30
|
+
define_method(test_name, &block)
|
31
|
+
else
|
32
|
+
define_method(test_name) do
|
33
|
+
flunk "No implementation provided for #{name}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'active_support/deprecation'
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Testing
|
5
|
+
module Deprecation #:nodoc:
|
6
|
+
def assert_deprecated(match = nil, &block)
|
7
|
+
result, warnings = collect_deprecations(&block)
|
8
|
+
assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
|
9
|
+
if match
|
10
|
+
match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
|
11
|
+
assert warnings.any? { |w| w =~ match }, "No deprecation warning matched #{match}: #{warnings.join(', ')}"
|
12
|
+
end
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
def assert_not_deprecated(&block)
|
17
|
+
result, deprecations = collect_deprecations(&block)
|
18
|
+
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def collect_deprecations
|
24
|
+
old_behavior = ActiveSupport::Deprecation.behavior
|
25
|
+
deprecations = []
|
26
|
+
ActiveSupport::Deprecation.behavior = Proc.new do |message, callstack|
|
27
|
+
deprecations << message
|
28
|
+
end
|
29
|
+
result = yield
|
30
|
+
[result, deprecations]
|
31
|
+
ensure
|
32
|
+
ActiveSupport::Deprecation.behavior = old_behavior
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'test/unit/error'
|
40
|
+
rescue LoadError
|
41
|
+
# Using miniunit, ignore.
|
42
|
+
else
|
43
|
+
module Test
|
44
|
+
module Unit
|
45
|
+
class Error #:nodoc:
|
46
|
+
# Silence warnings when reporting test errors.
|
47
|
+
def message_with_silenced_deprecation
|
48
|
+
ActiveSupport::Deprecation.silence { message_without_silenced_deprecation }
|
49
|
+
end
|
50
|
+
alias_method :message_without_silenced_deprecation, :message
|
51
|
+
alias_method :message, :message_with_silenced_deprecation
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
module ActiveSupport
|
3
|
+
module Testing
|
4
|
+
class RemoteError < StandardError
|
5
|
+
|
6
|
+
attr_reader :message, :backtrace
|
7
|
+
|
8
|
+
def initialize(exception)
|
9
|
+
@message = "caught #{exception.class.name}: #{exception.message}"
|
10
|
+
@backtrace = exception.backtrace
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ProxyTestResult
|
15
|
+
def initialize
|
16
|
+
@calls = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_error(e)
|
20
|
+
e = Test::Unit::Error.new(e.test_name, RemoteError.new(e.exception))
|
21
|
+
@calls << [:add_error, e]
|
22
|
+
end
|
23
|
+
|
24
|
+
def __replay__(result)
|
25
|
+
@calls.each do |name, args|
|
26
|
+
result.send(name, *args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(name, *args)
|
31
|
+
@calls << [name, args]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Isolation
|
36
|
+
def self.forking_env?
|
37
|
+
!ENV["NO_FORK"] && ((Config::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/))
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.included(base)
|
41
|
+
if defined?(::MiniTest) && base < ::MiniTest::Unit::TestCase
|
42
|
+
base.send :include, MiniTest
|
43
|
+
elsif defined?(Test::Unit)
|
44
|
+
base.send :include, TestUnit
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module TestUnit
|
49
|
+
def run(result)
|
50
|
+
unless defined?(@@ran_class_setup)
|
51
|
+
self.class.setup if self.class.respond_to?(:setup)
|
52
|
+
@@ran_class_setup = true
|
53
|
+
end
|
54
|
+
|
55
|
+
yield(Test::Unit::TestCase::STARTED, name)
|
56
|
+
|
57
|
+
@_result = result
|
58
|
+
|
59
|
+
serialized = run_in_isolation do |proxy|
|
60
|
+
begin
|
61
|
+
super(proxy) { }
|
62
|
+
rescue Exception => e
|
63
|
+
proxy.add_error(Test::Unit::Error.new(name, e))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
retval, proxy = Marshal.load(serialized)
|
68
|
+
proxy.__replay__(@_result)
|
69
|
+
|
70
|
+
yield(Test::Unit::TestCase::FINISHED, name)
|
71
|
+
retval
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
module MiniTest
|
76
|
+
def run(runner)
|
77
|
+
unless defined?(@@ran_class_setup)
|
78
|
+
self.class.setup if self.class.respond_to?(:setup)
|
79
|
+
@@ran_class_setup = true
|
80
|
+
end
|
81
|
+
|
82
|
+
serialized = run_in_isolation do |isolated_runner|
|
83
|
+
super(isolated_runner)
|
84
|
+
end
|
85
|
+
|
86
|
+
retval, proxy = Marshal.load(serialized)
|
87
|
+
proxy.__replay__(runner)
|
88
|
+
retval
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
module Forking
|
93
|
+
def run_in_isolation(&blk)
|
94
|
+
read, write = IO.pipe
|
95
|
+
|
96
|
+
pid = fork do
|
97
|
+
read.close
|
98
|
+
proxy = ProxyTestResult.new
|
99
|
+
retval = yield proxy
|
100
|
+
write.puts [Marshal.dump([retval, proxy])].pack("m")
|
101
|
+
exit!
|
102
|
+
end
|
103
|
+
|
104
|
+
write.close
|
105
|
+
result = read.read
|
106
|
+
Process.wait2(pid)
|
107
|
+
return result.unpack("m")[0]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
module Subprocess
|
112
|
+
# Crazy H4X to get this working in windows / jruby with
|
113
|
+
# no forking.
|
114
|
+
def run_in_isolation(&blk)
|
115
|
+
require "tempfile"
|
116
|
+
|
117
|
+
if ENV["ISOLATION_TEST"]
|
118
|
+
proxy = ProxyTestResult.new
|
119
|
+
retval = yield proxy
|
120
|
+
File.open(ENV["ISOLATION_OUTPUT"], "w") do |file|
|
121
|
+
file.puts [Marshal.dump([retval, proxy])].pack("m")
|
122
|
+
end
|
123
|
+
exit!
|
124
|
+
else
|
125
|
+
Tempfile.open("isolation") do |tmpfile|
|
126
|
+
ENV["ISOLATION_TEST"] = @method_name
|
127
|
+
ENV["ISOLATION_OUTPUT"] = tmpfile.path
|
128
|
+
|
129
|
+
load_paths = $-I.map {|p| "-I\"#{File.expand_path(p)}\"" }.join(" ")
|
130
|
+
`#{Gem.ruby} #{load_paths} #{$0} #{ORIG_ARGV.join(" ")} -t\"#{self.class}\"`
|
131
|
+
|
132
|
+
ENV.delete("ISOLATION_TEST")
|
133
|
+
ENV.delete("ISOLATION_OUTPUT")
|
134
|
+
|
135
|
+
return tmpfile.read.unpack("m")[0]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
include forking_env? ? Forking : Subprocess
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Only in subprocess for windows / jruby.
|
147
|
+
if ENV['ISOLATION_TEST']
|
148
|
+
require "test/unit/collector/objectspace"
|
149
|
+
class Test::Unit::Collector::ObjectSpace
|
150
|
+
def include?(test)
|
151
|
+
super && test.method_name == ENV['ISOLATION_TEST']
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Some code from jeremymcanally's "pending"
|
2
|
+
# http://github.com/jeremymcanally/pending/tree/master
|
3
|
+
|
4
|
+
module ActiveSupport
|
5
|
+
module Testing
|
6
|
+
module Pending
|
7
|
+
|
8
|
+
unless defined?(Spec)
|
9
|
+
|
10
|
+
@@pending_cases = []
|
11
|
+
@@at_exit = false
|
12
|
+
|
13
|
+
def pending(description = "", &block)
|
14
|
+
if description.is_a?(Symbol)
|
15
|
+
is_pending = $tags[description]
|
16
|
+
return block.call unless is_pending
|
17
|
+
end
|
18
|
+
|
19
|
+
if block_given?
|
20
|
+
failed = false
|
21
|
+
|
22
|
+
begin
|
23
|
+
block.call
|
24
|
+
rescue Exception
|
25
|
+
failed = true
|
26
|
+
end
|
27
|
+
|
28
|
+
flunk("<#{description}> did not fail.") unless failed
|
29
|
+
end
|
30
|
+
|
31
|
+
caller[0] =~ (/(.*):(.*):in `(.*)'/)
|
32
|
+
@@pending_cases << "#{$3} at #{$1}, line #{$2}"
|
33
|
+
print "P"
|
34
|
+
|
35
|
+
@@at_exit ||= begin
|
36
|
+
at_exit do
|
37
|
+
puts "\nPending Cases:"
|
38
|
+
@@pending_cases.each do |test_case|
|
39
|
+
puts test_case
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,455 @@
|
|
1
|
+
begin
|
2
|
+
require 'ruby-prof'
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
require 'rails/version'
|
6
|
+
require 'active_support/core_ext/class/delegating_attributes'
|
7
|
+
require 'active_support/core_ext/string/inflections'
|
8
|
+
|
9
|
+
module ActiveSupport
|
10
|
+
module Testing
|
11
|
+
module Performance
|
12
|
+
DEFAULTS =
|
13
|
+
if benchmark = ARGV.include?('--benchmark') # HAX for rake test
|
14
|
+
{ :benchmark => true,
|
15
|
+
:runs => 4,
|
16
|
+
:metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time],
|
17
|
+
:output => 'tmp/performance' }
|
18
|
+
else
|
19
|
+
{ :benchmark => false,
|
20
|
+
:runs => 1,
|
21
|
+
:min_percent => 0.01,
|
22
|
+
:metrics => [:process_time, :memory, :objects],
|
23
|
+
:formats => [:flat, :graph_html, :call_tree],
|
24
|
+
:output => 'tmp/performance' }
|
25
|
+
end.freeze
|
26
|
+
|
27
|
+
def self.included(base)
|
28
|
+
base.superclass_delegating_accessor :profile_options
|
29
|
+
base.profile_options = DEFAULTS
|
30
|
+
end
|
31
|
+
|
32
|
+
def full_test_name
|
33
|
+
"#{self.class.name}##{method_name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def run(result)
|
37
|
+
return if method_name =~ /^default_test$/
|
38
|
+
|
39
|
+
yield(self.class::STARTED, name)
|
40
|
+
@_result = result
|
41
|
+
|
42
|
+
run_warmup
|
43
|
+
if profile_options && metrics = profile_options[:metrics]
|
44
|
+
metrics.each do |metric_name|
|
45
|
+
if klass = Metrics[metric_name.to_sym]
|
46
|
+
run_profile(klass.new)
|
47
|
+
result.add_run
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
yield(self.class::FINISHED, name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def run_test(metric, mode)
|
56
|
+
run_callbacks :setup
|
57
|
+
setup
|
58
|
+
metric.send(mode) { __send__ @method_name }
|
59
|
+
rescue ::Test::Unit::AssertionFailedError => e
|
60
|
+
add_failure(e.message, e.backtrace)
|
61
|
+
rescue StandardError, ScriptError
|
62
|
+
add_error($!)
|
63
|
+
ensure
|
64
|
+
begin
|
65
|
+
teardown
|
66
|
+
run_callbacks :teardown, :enumerator => :reverse_each
|
67
|
+
rescue ::Test::Unit::AssertionFailedError => e
|
68
|
+
add_failure(e.message, e.backtrace)
|
69
|
+
rescue StandardError, ScriptError
|
70
|
+
add_error($!)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
def run_warmup
|
76
|
+
GC.start
|
77
|
+
|
78
|
+
time = Metrics::Time.new
|
79
|
+
run_test(time, :benchmark)
|
80
|
+
puts "%s (%s warmup)" % [full_test_name, time.format(time.total)]
|
81
|
+
|
82
|
+
GC.start
|
83
|
+
end
|
84
|
+
|
85
|
+
def run_profile(metric)
|
86
|
+
klass = profile_options[:benchmark] ? Benchmarker : Profiler
|
87
|
+
performer = klass.new(self, metric)
|
88
|
+
|
89
|
+
performer.run
|
90
|
+
puts performer.report
|
91
|
+
performer.record
|
92
|
+
end
|
93
|
+
|
94
|
+
class Performer
|
95
|
+
delegate :run_test, :profile_options, :full_test_name, :to => :@harness
|
96
|
+
|
97
|
+
def initialize(harness, metric)
|
98
|
+
@harness, @metric = harness, metric
|
99
|
+
end
|
100
|
+
|
101
|
+
def report
|
102
|
+
rate = @total / profile_options[:runs]
|
103
|
+
'%20s: %s' % [@metric.name, @metric.format(rate)]
|
104
|
+
end
|
105
|
+
|
106
|
+
protected
|
107
|
+
def output_filename
|
108
|
+
"#{profile_options[:output]}/#{full_test_name}_#{@metric.name}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class Benchmarker < Performer
|
113
|
+
def run
|
114
|
+
profile_options[:runs].to_i.times { run_test(@metric, :benchmark) }
|
115
|
+
@total = @metric.total
|
116
|
+
end
|
117
|
+
|
118
|
+
def record
|
119
|
+
avg = @metric.total / profile_options[:runs].to_i
|
120
|
+
now = Time.now.utc.xmlschema
|
121
|
+
with_output_file do |file|
|
122
|
+
file.puts "#{avg},#{now},#{environment}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def environment
|
127
|
+
unless defined? @env
|
128
|
+
app = "#{$1}.#{$2}" if File.directory?('.git') && `git branch -v` =~ /^\* (\S+)\s+(\S+)/
|
129
|
+
|
130
|
+
rails = Rails::VERSION::STRING
|
131
|
+
if File.directory?('vendor/rails/.git')
|
132
|
+
Dir.chdir('vendor/rails') do
|
133
|
+
rails += ".#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
ruby = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
138
|
+
ruby += "-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
|
139
|
+
|
140
|
+
@env = [app, rails, ruby, RUBY_PLATFORM] * ','
|
141
|
+
end
|
142
|
+
|
143
|
+
@env
|
144
|
+
end
|
145
|
+
|
146
|
+
protected
|
147
|
+
HEADER = 'measurement,created_at,app,rails,ruby,platform'
|
148
|
+
|
149
|
+
def with_output_file
|
150
|
+
fname = output_filename
|
151
|
+
|
152
|
+
if new = !File.exist?(fname)
|
153
|
+
FileUtils.mkdir_p(File.dirname(fname))
|
154
|
+
end
|
155
|
+
|
156
|
+
File.open(fname, 'ab') do |file|
|
157
|
+
file.puts(HEADER) if new
|
158
|
+
yield file
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def output_filename
|
163
|
+
"#{super}.csv"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class Profiler < Performer
|
168
|
+
def initialize(*args)
|
169
|
+
super
|
170
|
+
@supported = @metric.measure_mode rescue false
|
171
|
+
end
|
172
|
+
|
173
|
+
def run
|
174
|
+
return unless @supported
|
175
|
+
|
176
|
+
RubyProf.measure_mode = @metric.measure_mode
|
177
|
+
RubyProf.start
|
178
|
+
RubyProf.pause
|
179
|
+
profile_options[:runs].to_i.times { run_test(@metric, :profile) }
|
180
|
+
@data = RubyProf.stop
|
181
|
+
@total = @data.threads.values.sum(0) { |method_infos| method_infos.sort.last.total_time }
|
182
|
+
end
|
183
|
+
|
184
|
+
def report
|
185
|
+
if @supported
|
186
|
+
super
|
187
|
+
else
|
188
|
+
'%20s: unsupported' % @metric.name
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def record
|
193
|
+
return unless @supported
|
194
|
+
|
195
|
+
klasses = profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact
|
196
|
+
|
197
|
+
klasses.each do |klass|
|
198
|
+
fname = output_filename(klass)
|
199
|
+
FileUtils.mkdir_p(File.dirname(fname))
|
200
|
+
File.open(fname, 'wb') do |file|
|
201
|
+
klass.new(@data).print(file, profile_options.slice(:min_percent))
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
protected
|
207
|
+
def output_filename(printer_class)
|
208
|
+
suffix =
|
209
|
+
case printer_class.name.demodulize
|
210
|
+
when 'FlatPrinter'; 'flat.txt'
|
211
|
+
when 'GraphPrinter'; 'graph.txt'
|
212
|
+
when 'GraphHtmlPrinter'; 'graph.html'
|
213
|
+
when 'CallTreePrinter'; 'tree.txt'
|
214
|
+
else printer_class.name.sub(/Printer$/, '').underscore
|
215
|
+
end
|
216
|
+
|
217
|
+
"#{super()}_#{suffix}"
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
module Metrics
|
222
|
+
def self.[](name)
|
223
|
+
const_get(name.to_s.camelize)
|
224
|
+
rescue NameError
|
225
|
+
nil
|
226
|
+
end
|
227
|
+
|
228
|
+
class Base
|
229
|
+
attr_reader :total
|
230
|
+
|
231
|
+
def initialize
|
232
|
+
@total = 0
|
233
|
+
end
|
234
|
+
|
235
|
+
def name
|
236
|
+
@name ||= self.class.name.demodulize.underscore
|
237
|
+
end
|
238
|
+
|
239
|
+
def measure_mode
|
240
|
+
self.class::Mode
|
241
|
+
end
|
242
|
+
|
243
|
+
def measure
|
244
|
+
0
|
245
|
+
end
|
246
|
+
|
247
|
+
def benchmark
|
248
|
+
with_gc_stats do
|
249
|
+
before = measure
|
250
|
+
yield
|
251
|
+
@total += (measure - before)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def profile
|
256
|
+
RubyProf.resume
|
257
|
+
yield
|
258
|
+
ensure
|
259
|
+
RubyProf.pause
|
260
|
+
end
|
261
|
+
|
262
|
+
protected
|
263
|
+
if GC.respond_to?(:enable_stats)
|
264
|
+
def with_gc_stats
|
265
|
+
GC.enable_stats
|
266
|
+
yield
|
267
|
+
ensure
|
268
|
+
GC.disable_stats
|
269
|
+
end
|
270
|
+
elsif defined?(GC::Profiler)
|
271
|
+
def with_gc_stats
|
272
|
+
GC.start
|
273
|
+
GC.disable
|
274
|
+
GC::Profiler.enable
|
275
|
+
yield
|
276
|
+
ensure
|
277
|
+
GC::Profiler.disable
|
278
|
+
GC.enable
|
279
|
+
end
|
280
|
+
else
|
281
|
+
def with_gc_stats
|
282
|
+
yield
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
class Time < Base
|
288
|
+
def measure
|
289
|
+
::Time.now.to_f
|
290
|
+
end
|
291
|
+
|
292
|
+
def format(measurement)
|
293
|
+
if measurement < 2
|
294
|
+
'%d ms' % (measurement * 1000)
|
295
|
+
else
|
296
|
+
'%.2f sec' % measurement
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
class ProcessTime < Time
|
302
|
+
Mode = RubyProf::PROCESS_TIME
|
303
|
+
|
304
|
+
def measure
|
305
|
+
RubyProf.measure_process_time
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
class WallTime < Time
|
310
|
+
Mode = RubyProf::WALL_TIME
|
311
|
+
|
312
|
+
def measure
|
313
|
+
RubyProf.measure_wall_time
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
class CpuTime < Time
|
318
|
+
Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
|
319
|
+
|
320
|
+
def initialize(*args)
|
321
|
+
# FIXME: yeah my CPU is 2.33 GHz
|
322
|
+
RubyProf.cpu_frequency = 2.33e9
|
323
|
+
super
|
324
|
+
end
|
325
|
+
|
326
|
+
def measure
|
327
|
+
RubyProf.measure_cpu_time
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
class Memory < Base
|
332
|
+
Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
|
333
|
+
|
334
|
+
# ruby-prof wrapper
|
335
|
+
if RubyProf.respond_to?(:measure_memory)
|
336
|
+
def measure
|
337
|
+
RubyProf.measure_memory / 1024.0
|
338
|
+
end
|
339
|
+
|
340
|
+
# Ruby 1.8 + railsbench patch
|
341
|
+
elsif GC.respond_to?(:allocated_size)
|
342
|
+
def measure
|
343
|
+
GC.allocated_size / 1024.0
|
344
|
+
end
|
345
|
+
|
346
|
+
# Ruby 1.8 + lloyd patch
|
347
|
+
elsif GC.respond_to?(:heap_info)
|
348
|
+
def measure
|
349
|
+
GC.heap_info['heap_current_memory'] / 1024.0
|
350
|
+
end
|
351
|
+
|
352
|
+
# Ruby 1.9 with total_malloc_allocated_size patch
|
353
|
+
elsif GC.respond_to?(:malloc_total_allocated_size)
|
354
|
+
def measure
|
355
|
+
GC.total_malloc_allocated_size / 1024.0
|
356
|
+
end
|
357
|
+
|
358
|
+
# Ruby 1.9 unpatched
|
359
|
+
elsif GC.respond_to?(:malloc_allocated_size)
|
360
|
+
def measure
|
361
|
+
GC.malloc_allocated_size / 1024.0
|
362
|
+
end
|
363
|
+
|
364
|
+
# Ruby 1.9 + GC profiler patch
|
365
|
+
elsif defined?(GC::Profiler)
|
366
|
+
def measure
|
367
|
+
GC.enable
|
368
|
+
GC.start
|
369
|
+
kb = GC::Profiler.data.last[:HEAP_USE_SIZE] / 1024.0
|
370
|
+
GC.disable
|
371
|
+
kb
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def format(measurement)
|
376
|
+
'%.2f KB' % measurement
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
class Objects < Base
|
381
|
+
Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
|
382
|
+
|
383
|
+
if RubyProf.respond_to?(:measure_allocations)
|
384
|
+
def measure
|
385
|
+
RubyProf.measure_allocations
|
386
|
+
end
|
387
|
+
|
388
|
+
# Ruby 1.8 + railsbench patch
|
389
|
+
elsif ObjectSpace.respond_to?(:allocated_objects)
|
390
|
+
def measure
|
391
|
+
ObjectSpace.allocated_objects
|
392
|
+
end
|
393
|
+
|
394
|
+
# Ruby 1.9 + GC profiler patch
|
395
|
+
elsif defined?(GC::Profiler)
|
396
|
+
def measure
|
397
|
+
GC.enable
|
398
|
+
GC.start
|
399
|
+
last = GC::Profiler.data.last
|
400
|
+
count = last[:HEAP_LIVE_OBJECTS] + last[:HEAP_FREE_OBJECTS]
|
401
|
+
GC.disable
|
402
|
+
count
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def format(measurement)
|
407
|
+
measurement.to_i.to_s
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
class GcRuns < Base
|
412
|
+
Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
|
413
|
+
|
414
|
+
if RubyProf.respond_to?(:measure_gc_runs)
|
415
|
+
def measure
|
416
|
+
RubyProf.measure_gc_runs
|
417
|
+
end
|
418
|
+
elsif GC.respond_to?(:collections)
|
419
|
+
def measure
|
420
|
+
GC.collections
|
421
|
+
end
|
422
|
+
elsif GC.respond_to?(:heap_info)
|
423
|
+
def measure
|
424
|
+
GC.heap_info['num_gc_passes']
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def format(measurement)
|
429
|
+
measurement.to_i.to_s
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
class GcTime < Base
|
434
|
+
Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
|
435
|
+
|
436
|
+
if RubyProf.respond_to?(:measure_gc_time)
|
437
|
+
def measure
|
438
|
+
RubyProf.measure_gc_time
|
439
|
+
end
|
440
|
+
elsif GC.respond_to?(:time)
|
441
|
+
def measure
|
442
|
+
GC.time
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def format(measurement)
|
447
|
+
'%d ms' % (measurement / 1000)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
rescue LoadError
|
455
|
+
end
|