mole 0.0.1

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.
Files changed (46) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +45 -0
  3. data/README.txt +140 -0
  4. data/Rakefile +47 -0
  5. data/bin/mole +8 -0
  6. data/bin/molify +64 -0
  7. data/config/database.yml +21 -0
  8. data/config/test_database.yml +69 -0
  9. data/lib/mole/db/migrate.rb +90 -0
  10. data/lib/mole/e_mole.rb +74 -0
  11. data/lib/mole/logger.rb +131 -0
  12. data/lib/mole/models/mole_feature.rb +45 -0
  13. data/lib/mole/models/mole_log.rb +56 -0
  14. data/lib/mole/module.rb +274 -0
  15. data/lib/mole/moler.rb +51 -0
  16. data/lib/mole/utils/frameworks.rb +22 -0
  17. data/lib/mole/version.rb +15 -0
  18. data/lib/mole.rb +175 -0
  19. data/spec/data/blee.rb +53 -0
  20. data/spec/db/migrate_spec.rb +19 -0
  21. data/spec/emole_spec.rb +43 -0
  22. data/spec/logger_spec.rb +56 -0
  23. data/spec/models/mole_feature_spec.rb +37 -0
  24. data/spec/models/mole_log_spec.rb +73 -0
  25. data/spec/module_spec.rb +171 -0
  26. data/spec/mole_spec.rb +38 -0
  27. data/spec/moler_spec.rb +65 -0
  28. data/spec/spec_helper.rb +59 -0
  29. data/spec/utils/framework_spec.rb +46 -0
  30. data/tasks/ann.rake +76 -0
  31. data/tasks/annotations.rake +22 -0
  32. data/tasks/doc.rake +48 -0
  33. data/tasks/gem.rake +110 -0
  34. data/tasks/manifest.rake +49 -0
  35. data/tasks/mole.rake +115 -0
  36. data/tasks/post_load.rake +26 -0
  37. data/tasks/rubyforge.rake +57 -0
  38. data/tasks/setup.rb +227 -0
  39. data/tasks/spec.rake +54 -0
  40. data/tasks/svn.rake +44 -0
  41. data/tasks/test.rake +38 -0
  42. data/templates/mole/e_mole/exception_alerts.rhtml +14 -0
  43. data/templates/mole/e_mole/feature_alerts.rhtml +11 -0
  44. data/templates/mole/e_mole/perf_alerts.rhtml +12 -0
  45. data/test/test_mole.rb +0 -0
  46. metadata +120 -0
data/lib/mole.rb ADDED
@@ -0,0 +1,175 @@
1
+ # $Id$
2
+
3
+ # Equivalent to a header guard in C/C++
4
+ # Used to prevent the class/module from being loaded more than once
5
+ unless defined? Mole
6
+ require 'activerecord'
7
+ module Mole
8
+ # :stopdoc:
9
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
+
12
+ # :startdoc:
13
+ # The MOle can be ran in a couple of modes: Transient and Persistent
14
+ # Transient mode will log the output to the specified log file
15
+ # Persistent mode will log the mole output to your db
16
+ # The default is :transient
17
+ def self.run_modes #:nodoc:
18
+ [:transient, :persistent]
19
+ end
20
+
21
+ # MOle Default settings
22
+ def self.defaults #:nodoc:
23
+ @defaults ||= {
24
+ :moleable => false,
25
+ :application => "Default",
26
+ :perf_threshold => 5,
27
+ :mode => :transient,
28
+ :emole_from => "MOleBeatch",
29
+ :mole_config => nil,
30
+ :emole_recipients => [],
31
+
32
+ # logging options
33
+ :log_file => $stdout,
34
+ :log_level => :info,
35
+ :email_alerts_to => "MOleBeatch",
36
+ :email_alert_level => :error }
37
+ end
38
+
39
+ # Reset the configuration to what it would be when the class is parsed
40
+ # this is needed mainly for running specs. This resets the class to the
41
+ # state it was before initialize is called. initialize MUST be called
42
+ # after reset_configuration! is invoked
43
+ def self.reset_configuration! #:nodoc:
44
+ @logger.clear_appenders if @logger
45
+ @logger = nil
46
+ @config = nil
47
+ end
48
+
49
+ # Initialize the MOle
50
+ # Valid options are
51
+ # <tt>moleable</tt>:: specify if this application is moleable.
52
+ # Defaults to false.
53
+ # <tt>application</tt>:: the name of the application to be moled.
54
+ # <tt>perf_threshold</tt>:: the performance threshold over which a Mole condition will be issued.
55
+ # Defaults to 5 seconds
56
+ # <tt>mode</tt>:: the MOle logging mole. The mole can either log information to a db via
57
+ # the :persistent option or to a log file via the :transient flag.
58
+ # Defaults to transient
59
+ # <tt>emole_from</tt>:: the EMole originator when sending eMOle alerts.
60
+ # <tt>emole_recipients</tt>:: a collection of EMOle recipients
61
+ # <tt>mole_config</tt>:: the location of the MOle configuration file where the interceptors will
62
+ # be defined.
63
+ # <tt>log_file</tt>:: The log file to be used to log MOle interceptions
64
+ # <tt>log_level</tt>:: logging level ie :info, :debug, :error, :warn...
65
+ # <tt>email_alerts_to</tt>:: log level email alert recipients.
66
+ # <tt>email_alert_level</tt>:: specifies which log level will trigger email alerts to be sent
67
+ def self.initialize( opts={} )
68
+ @config = defaults.merge( opts )
69
+ @config[:email_alerts_to] = @config[:emole_recipients] if @config[:emole_recipients] and !@config[:emole_recipients].empty?
70
+ # dump
71
+ # Add the mode to the ruby lib path...
72
+ $: << libpath
73
+ Mole.require_all_libs_relative_to __FILE__
74
+
75
+ raise "Unable to find the MOle configuration file #{conf_file}" if conf_file and !File.exists? conf_file
76
+ load conf_file if conf_file and moleable?
77
+ end
78
+
79
+ # Fetch the MOle configuration file
80
+ def self.conf_file #:nodoc:
81
+ config[:mole_config]
82
+ end
83
+
84
+ # EMole alert sender
85
+ def self.emole_from #:nodoc:
86
+ config[:emole_from]
87
+ end
88
+
89
+ # EMole alert recipients
90
+ def self.emole_recipients #:nodoc:
91
+ config[:emole_recipients]
92
+ end
93
+
94
+ # Fetch the MOle configuration
95
+ def self.config #:nodoc:
96
+ @config
97
+ end
98
+
99
+ # Debug
100
+ def self.dump #:nodoc:
101
+ puts ""
102
+ puts "Mole Configuration Landscape"
103
+ config.keys.sort{ |a,b| a.to_s <=> b.to_s }.each do |k|
104
+ key = k.to_s.rjust(20)
105
+ value = config[k].to_s.rjust(97,".")
106
+ puts "#{key} : #{value}"
107
+ end
108
+ end
109
+
110
+ # get a hold of a logger. This is the global logger for sentiment.
111
+ def self.logger #:nodoc:
112
+ @logger ||= ::Mole::Logger.new( { :log_file => config[:log_file],
113
+ :logger_name => "MOle",
114
+ :log_level => config[:log_level],
115
+ :email_alerts_to => config[:email_alerts_to],
116
+ :email_alert_level => config[:email_alert_level],
117
+ :additive => false } )
118
+ end
119
+
120
+ # The name of the MOled application
121
+ def self.application #:nodoc:
122
+ config[:application]
123
+ end
124
+
125
+ # Is this application is MOleable
126
+ def self.moleable? #:nodoc:
127
+ config[:moleable]
128
+ end
129
+
130
+ # Returns the MOle perf threshold. If any MOled features takes longer
131
+ # than this time to complete, then an alarm will be triggered...
132
+ def self.perf_threshold #:nodoc:
133
+ config[:perf_threshold]
134
+ end
135
+
136
+ # Enable to toggle between different log modes ie :persistent/:transient
137
+ def self.switch_mode( mode )
138
+ config[:mode] = mode
139
+ end
140
+
141
+ # Check if the MOle is running in persistent mode
142
+ def self.persistent?
143
+ config[:mode] == :persistent
144
+ end
145
+
146
+ # Returns the library path for the module. If any arguments are given,
147
+ # they will be joined to the end of the libray path using
148
+ # <tt>File.join</tt>.
149
+ #
150
+ def self.libpath( *args ) #:nodoc:
151
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, *args)
152
+ end
153
+
154
+ # Returns the lpath for the module. If any arguments are given,
155
+ # they will be joined to the end of the path using
156
+ # <tt>File.join</tt>.
157
+ #
158
+ def self.path( *args ) #:nodoc:
159
+ args.empty? ? PATH : ::File.join(PATH, *args)
160
+ end
161
+
162
+ # Utility method used to rquire all files ending in .rb that lie in the
163
+ # directory below this file that has the same name as the filename passed
164
+ # in. Optionally, a specific _directory_ name can be passed in such that
165
+ # the _filename_ does not have to be equivalent to the directory.
166
+ #
167
+ def self.require_all_libs_relative_to( fname, dir = nil ) #:nodoc:
168
+ dir ||= ::File.basename(fname, '.*')
169
+ search_me = ::File.expand_path(
170
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
171
+
172
+ Dir.glob(search_me).sort.each {|rb| require rb}
173
+ end
174
+ end
175
+ end
data/spec/data/blee.rb ADDED
@@ -0,0 +1,53 @@
1
+ require 'mole/module'
2
+
3
+ class Blee
4
+ def self.blee_static
5
+ end
6
+
7
+ def crap_out
8
+ end
9
+
10
+ def crap_out_too
11
+ end
12
+
13
+ def blee_no_args
14
+ # puts ">>> Blee_No_Args"
15
+ end
16
+
17
+ def blee_args( i, p )
18
+ # puts ">>> Blee_Args #{i} -- #{p}"
19
+ end
20
+
21
+ def blee_args_ret( p )
22
+ "Hello #{p}"
23
+ end
24
+
25
+ def blee_raise
26
+ raise "Blee exception"
27
+ end
28
+
29
+ def blee_raise_too
30
+ raise "Blee exception"
31
+ end
32
+
33
+ def blee_slow
34
+ sleep( 1 )
35
+ end
36
+
37
+ def blee_slow_too
38
+ sleep( 1 )
39
+ end
40
+
41
+ private
42
+
43
+ def blee_private( arg )
44
+ arg
45
+ end
46
+
47
+ protected
48
+
49
+ def blee_protected( arg )
50
+ arg
51
+ end
52
+
53
+ end
@@ -0,0 +1,19 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper" )
2
+
3
+ describe Mole::Db::Migrate do
4
+ before( :all ) do
5
+ ::Mole.reset_configuration!
6
+ ::Mole.initialize( :moleable => true )
7
+ @config = ::File.expand_path( ::File.join(::File.dirname(__FILE__), %w[.. .. config database.yml] ) )
8
+ end
9
+
10
+ it "migrates down correctly" do
11
+ mgt = Mole::Db::Migrate.new( OpenStruct.new( :direction => :down, :configuration => @config, :environment => 'test' ) )
12
+ mgt.apply
13
+ end
14
+
15
+ it "migrates up correctly" do
16
+ mgt = Mole::Db::Migrate.new( OpenStruct.new( :direction => :up, :configuration => @config, :environment => 'test' ) )
17
+ mgt.apply
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper" )
2
+
3
+ require 'action_mailer'
4
+ ActionMailer::Base.delivery_method = :sendmail
5
+ ActionMailer::Base.raise_delivery_errors = true
6
+
7
+ # TODO Figure out how to auto check email was sent
8
+ describe Mole::EMole do
9
+ before( :each ) do
10
+ ::Mole.reset_configuration!
11
+ ::Mole.initialize( :moleable => true,
12
+ :emole_from => "MOleBeatch@liquidrail.com",
13
+ :emole_recipients => ['fernand@liquidrail.com'] )
14
+ end
15
+
16
+ it "should send out a correct perf alert" do
17
+ Mole::EMole.deliver_perf_alerts(
18
+ self,
19
+ "fernand",
20
+ :feature => "test",
21
+ :elapsed_time => 10 )
22
+ end
23
+
24
+ it "should send out a correct feature alert" do
25
+ Mole::EMole.deliver_feature_alerts(
26
+ self,
27
+ "fernand",
28
+ :feature => "test",
29
+ :fred => "blee" )
30
+ end
31
+
32
+ it "should send out a correct exception alert" do
33
+ begin
34
+ raise "Something craped out"
35
+ rescue => boom
36
+ Mole::EMole.deliver_exception_alerts(
37
+ self,
38
+ "fernand",
39
+ :feature => "test",
40
+ :boom => boom )
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,56 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper" )
2
+
3
+ require 'stringio'
4
+ require File.join(File.dirname(__FILE__), %w[.. lib mole logger] )
5
+
6
+ describe Mole::Logger do
7
+ it "raises an error if the email addresses passed in is empty" do
8
+ lambda { Mole::Logger.new( { :email_alerts_to => [] } ) }.should raise_error( Mole::Logger::ConfigurationError )
9
+ end
10
+
11
+ it "configures an email appender if :email_alerts is set" do
12
+ l = Mole::Logger.new( { :logger_name => "Test2", :email_alerts_to => "fernand@invalid.address", :email_alert_level => :off })
13
+ l.email_appender.should_not == nil
14
+ end
15
+
16
+ it "does not configure an email appender if :email_alerts is not set" do
17
+ l = Mole::Logger.new( { :logger_name => "Test3" })
18
+ lambda { l.email_appender }.should raise_error( Mole::Logger::ConfigurationError )
19
+ end
20
+
21
+ it "raises an error if an invalid object is passed in for the :log_file" do
22
+ lambda { l = Mole::Logger.new( { :log_file => Object.new } ) }.should raise_error( Mole::Logger::ConfigurationError )
23
+ end
24
+
25
+ it "logs to an IO stream if given" do
26
+ io = StringIO.new
27
+ l = Mole::Logger.new( { :log_file => io, :logger_name => "Test4" })
28
+ l.info "This is a test io message"
29
+ io.string.split("\n").should have(1).item
30
+ io.string.should =~ /This is a test io message/
31
+ io.string.should =~ /INFO/
32
+ end
33
+
34
+ it "logs to a file if given a file name to log to" do
35
+ log_file = "/tmp/mole_logger_test.log"
36
+ FileUtils.rm( log_file ) if File.exists?( log_file )
37
+ l = Mole::Logger.new({ :log_file => log_file, :logger_name => "Test5" })
38
+ l.info "This is a test log file message"
39
+
40
+ log_lines = IO.readlines(log_file)
41
+
42
+ log_lines.should have(1).items
43
+ log_lines.first.should =~ /This is a test log file message/
44
+ log_lines.first.should =~ /INFO/
45
+ end
46
+
47
+ it "creates a logger from another logger" do
48
+ io = StringIO.new
49
+ l = Mole::Logger.new( { :log_file => io, :logger_name => ::Mole})
50
+ child_l = l.for(Mole)
51
+
52
+ child_l.info "This is a child log message"
53
+ io.string.should =~ /This is a child log message/
54
+ io.string.should =~ /INFO/
55
+ end
56
+ end
@@ -0,0 +1,37 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper" )
2
+
3
+ describe MoleFeature do
4
+ before( :each ) do
5
+ ::Mole.reset_configuration!
6
+ ::Mole.initialize( :mode => :persistent, :log_level => :debug, :moleable => true )
7
+ end
8
+
9
+ it "should find or create known features correctly" do
10
+ %w[ all performance exception].each do |f|
11
+ feature = MoleFeature.send( "find_#{f}_feature".to_sym, ::Mole.application )
12
+ feature.should_not be_nil
13
+ feature.name.downcase.should == f
14
+ end
15
+ end
16
+
17
+ it "should create a new feature" do
18
+ feature = MoleFeature.find_feature( "Fred", ::Mole.application, self.class.name )
19
+ feature.should_not be_nil
20
+ feature.name.should == "Fred"
21
+ feature.context.should == self.class.name
22
+ end
23
+
24
+ it "should not create a feature with no name" do
25
+ feature = MoleFeature.find_feature( "", ::Mole.application, self.class.name )
26
+ feature.should be_nil
27
+ end
28
+
29
+ it "should find all features for a given application correctly" do
30
+ %w[ all performance exception].each do |f|
31
+ MoleFeature.send( "find_#{f}_feature".to_sym, ::Mole.application )
32
+ end
33
+ MoleFeature.find_feature( "Fred", ::Mole.application, self.class.name )
34
+ features = MoleFeature.find_features( ::Mole.application )
35
+ features.should have(4).mole_features
36
+ end
37
+ end
@@ -0,0 +1,73 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper" )
2
+
3
+ describe MoleLog do
4
+ before( :each ) do
5
+ ::Mole.reset_configuration!
6
+ ::Mole.initialize( :mode => :persistent, :log_level => :info, :moleable => true )
7
+ end
8
+
9
+ it "should log unchecked exceptions correctly" do
10
+ begin
11
+ raise "Something crapped out"
12
+ rescue => boom
13
+ MoleLog.check_it( self, 100, :blee => "Hello", :duh => "World", :boom => boom )
14
+ end
15
+ except_feature = MoleFeature.find_exception_feature( ::Mole.application )
16
+ except_feature.should_not be_nil
17
+
18
+ log = MoleLog.find( :all, :conditions => ['mole_feature_id = ?', except_feature.id] )
19
+ log.should_not be_nil
20
+ log.should have(1).mole_log
21
+ log.first.user_id.should == 100
22
+ end
23
+
24
+ it "should log perf exception correctly" do
25
+ MoleLog.perf_it( self, 100, :blee => "Hello", :duh => "World" )
26
+ perf_feature = MoleFeature.find_performance_feature( ::Mole.application )
27
+ perf_feature.should_not be_nil
28
+
29
+ log = MoleLog.find( :all, :conditions => ['mole_feature_id = ?', perf_feature.id] )
30
+ log.should_not be_nil
31
+ log.should have(1).mole_log
32
+ log.first.user_id.should == 100
33
+ end
34
+
35
+ it "should mole a feature correctly" do
36
+ MoleLog.mole_it( "Test", "fred", 100, :blee => "Hello", :duh => "World" )
37
+ feature = MoleFeature.find_feature( "fred", ::Mole.application, "Test".class.name )
38
+ feature.should_not be_nil
39
+
40
+ log = MoleLog.find( :all, :conditions => ['mole_feature_id = ?', feature.id] )
41
+ log.should_not be_nil
42
+ log.should have(1).mole_log
43
+ log.first.user_id.should == 100
44
+ end
45
+
46
+ it "should log request info correctly" do
47
+ ctrl = Moled::Controller.new
48
+ MoleLog.mole_it( ctrl, "fred", 100, :blee => "Hello", :duh => "World" )
49
+ feature = MoleFeature.find_feature( "fred", ::Mole.application, ctrl.class.name )
50
+ feature.should_not be_nil
51
+
52
+ log = MoleLog.find( :all, :conditions => ['mole_feature_id = ?', feature.id] )
53
+ log.should_not be_nil
54
+ log.should have(1).mole_log
55
+ log.first.user_id.should == 100
56
+ log.first.ip_address.should == "1.1.1.1"
57
+ log.first.browser_type.should == "GodZilla"
58
+ end
59
+
60
+ module Moled
61
+ class Controller
62
+ class Request
63
+ def env
64
+ {'REMOTE_ADDR' => "1.1.1.1", 'HTTP_USER_AGENT' => 'GodZilla' }
65
+ end
66
+ end
67
+
68
+ def request
69
+ Request.new
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,171 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper" )
2
+
3
+
4
+ describe Module do
5
+ before( :all ) do
6
+ ::Mole.initialize( :perf_threshold => 1 )
7
+ require File.join( File.dirname(__FILE__), %w[data blee] )
8
+ end
9
+
10
+ before( :each ) do
11
+ @blee = Blee.new
12
+ CallStackChecker.reset
13
+ end
14
+
15
+ it "should trap mole before handler exceptions" do
16
+ Blee.mole_before( :feature => :crap_out ) { |context, feature, *args|
17
+ raise "Before - Something did crap out"
18
+ CallStackChecker.called
19
+ }
20
+ @blee.crap_out
21
+ CallStackChecker.should_not be_called
22
+ end
23
+
24
+ it "should trap mole after handler exceptions" do
25
+ Blee.mole_after( :feature => :crap_out ) { |context, feature, *args|
26
+ raise "After - Something did crap out"
27
+ CallStackChecker.called
28
+ }
29
+ @blee.crap_out
30
+ CallStackChecker.should_not be_called
31
+ end
32
+
33
+ it "should trap mole handler exceptions" do
34
+ Blee.mole_unchecked( :features => [:blee_raise_too] ) { |context, feature, *args|
35
+ raise "Unchecked - Something did crap out"
36
+ CallStackChecker.called
37
+ }
38
+ @blee.blee_raise_too rescue nil
39
+ CallStackChecker.should_not be_called
40
+ end
41
+
42
+ it "should trap a perf handler exception" do
43
+ Blee.mole_perf( :features => [:blee_slow_too] ) do |context, feature, elapsed_time, args, block|
44
+ raise "Perf - Something did crap out"
45
+ CallStackChecker.called
46
+ end
47
+ @blee.blee_slow_too
48
+ CallStackChecker.should_not be_called
49
+ end
50
+
51
+ it "should trap mole handler exceptions" do
52
+ Blee.mole_before( :feature => :crap_out ) { |context, feature, *args|
53
+ raise "Something did crap out"
54
+ CallStackChecker.called
55
+ }
56
+ @blee.crap_out
57
+ CallStackChecker.should_not be_called
58
+ end
59
+
60
+ it "should correctly setup a before call" do
61
+ Blee.mole_before( :feature => :blee_no_args ) { |context, feature, *args|
62
+ context.class.should == Blee
63
+ feature.should == "blee_no_args"
64
+ args.should have(0).items
65
+ CallStackChecker.called
66
+ }
67
+ @blee.blee_no_args
68
+ CallStackChecker.should be_called
69
+ end
70
+
71
+ it "should correctly setup an after call" do
72
+ Blee.mole_after( :feature => :blee_no_args ) { |context, feature, *args|
73
+ context.class.should == Blee
74
+ feature.should == "blee_no_args"
75
+ args.should have(0).items
76
+ CallStackChecker.called
77
+ }
78
+ @blee.blee_no_args
79
+ CallStackChecker.should be_called
80
+ end
81
+
82
+ it "should correctly trap an exception" do
83
+ Blee.mole_unchecked( :features => [:blee_raise] ) do |context, feature, boom, args, block|
84
+ context.class.should == Blee
85
+ feature.should == "blee_raise"
86
+ boom.to_s.should == "Blee exception"
87
+ CallStackChecker.called
88
+ end
89
+ @blee.blee_raise rescue nil
90
+ CallStackChecker.should be_called
91
+ end
92
+
93
+ it "should not trap a before call" do
94
+ @blee.blee_args( "Hello", "World" )
95
+ CallStackChecker.should_not be_called
96
+ end
97
+
98
+ it "should correctly trap the before call arguments" do
99
+ Blee.mole_before( :feature => :blee_args ) { |context, feature, *args|
100
+ context.class.should == Blee
101
+ feature.should == "blee_args"
102
+ args.should have(2).items
103
+ args[0].should == "Hello"
104
+ args[1].should == "World"
105
+ CallStackChecker.called
106
+ }
107
+ @blee.blee_args( "Hello", "World" )
108
+ CallStackChecker.should be_called
109
+ end
110
+
111
+ it "should correctly trap the after call arguments" do
112
+ Blee.mole_after( :feature => :blee_args ) { |context, feature, *args|
113
+ context.class.should == Blee
114
+ feature.should == "blee_args"
115
+ args.size.should == 2
116
+ args[0].should == "Hello"
117
+ args[1].should == "World"
118
+ CallStackChecker.called
119
+ }
120
+ @blee.blee_args( "Hello", "World" )
121
+ CallStackChecker.should be_called
122
+ end
123
+
124
+ it "should correctly trap a slow call" do
125
+ Blee.mole_perf( :features => [:blee_slow] ) do |context, feature, elapsed_time, args, block|
126
+ context.class.should == Blee
127
+ feature.should == "blee_slow"
128
+ elapsed_time.should > 1
129
+ CallStackChecker.called
130
+ end
131
+ @blee.blee_slow rescue nil
132
+ CallStackChecker.should be_called
133
+ end
134
+
135
+ it "should trap a private method correctly" do
136
+ Blee.mole_after( :feature => :blee_private ) { |context, feature, *args|
137
+ context.class.should == Blee
138
+ feature.should == "blee_private"
139
+ args.size.should == 1
140
+ args[0].should == "Hello"
141
+ CallStackChecker.called
142
+ }
143
+ @blee.send( :blee_private, "Hello" )
144
+ CallStackChecker.should be_called
145
+ end
146
+
147
+ it "should trap a protected method correctly" do
148
+ Blee.mole_after( :feature => :blee_protected ) { |context, feature, *args|
149
+ context.class.should == Blee
150
+ feature.should == "blee_protected"
151
+ args.size.should == 1
152
+ args[0].should == "Hello"
153
+ CallStackChecker.called
154
+ }
155
+ @blee.send( :blee_protected, "Hello" )
156
+ CallStackChecker.should be_called
157
+ end
158
+
159
+ it "should mole a static method correctly" do
160
+ pending do
161
+ Blee.mole_after( :feature => :blee_static ) { |context, feature, *args|
162
+ context.class.should == Blee
163
+ feature.should == "blee_static"
164
+ args.size.should == 0
165
+ CallStackChecker.called
166
+ }
167
+ Blee.blee_static
168
+ CallStackChecker.should be_called
169
+ end
170
+ end
171
+ end
data/spec/mole_spec.rb ADDED
@@ -0,0 +1,38 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper" )
2
+
3
+ describe Mole do
4
+ before( :all ) do
5
+ ::Mole.reset_configuration!
6
+ ::Mole.initialize( :moleable => true )
7
+ @root = ::File.expand_path( ::File.join(::File.dirname(__FILE__), ".." ) )
8
+ end
9
+
10
+ it "is versioned" do
11
+ ::Mole::Version.version.should =~ /\d+\.\d+\.\d+/
12
+ end
13
+
14
+ it "should have the right defaults" do
15
+ Mole.should be_moleable
16
+ Mole.logger.should_not be_nil
17
+ Mole.perf_threshold.should == 5
18
+ Mole.should_not be_persistent
19
+ Mole.application.should == "Default"
20
+ end
21
+
22
+ it "generates a correct path relative to root" do
23
+ Mole.path( "mole.rb" ).should == ::File.join(@root, "mole.rb" )
24
+ end
25
+
26
+ it "generates a correct path relative to lib" do
27
+ Mole.libpath(%w[ mole db_mole.rb]).should == ::File.join(@root, "lib", "mole", "db_mole.rb")
28
+ end
29
+
30
+ it "should define the correct run modes" do
31
+ Mole.run_modes.should == [:transient,:persistent]
32
+ end
33
+
34
+ it "should dump config info to console" do
35
+ Mole.dump
36
+ end
37
+
38
+ end