rtinspect 0.0.1 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,42 @@
1
+ # Contains the TestRuntimeInspectionThread.
2
+ #
3
+ # Copyright (c) 2006-2007 Brad Robel-Forrest.
4
+ #
5
+ # This software can be distributed under the terms of the Ruby license
6
+ # as detailed in the accompanying LICENSE[link:files/LICENSE.html]
7
+ # file.
8
+
9
+ require 'thread'
10
+
11
+ # Extend the Thread class so we can know exactly where a given thread
12
+ # was created to validate that there aren't any leftover in various
13
+ # spots.
14
+ class Thread
15
+ alias orig_initialize initialize
16
+ def initialize( *args, &block )
17
+ orig_initialize( *args, &block )
18
+ self[:caller] = caller
19
+ end
20
+ end
21
+
1
22
  require 'timeout'
2
23
  require 'expect'
3
24
  require 'test/unit'
4
25
 
5
26
  require 'rtinspect'
6
27
 
28
+ if ARGV.include?( '-show_trace' )
29
+ RuntimeInspection.show_trace = true
30
+ end
31
+
32
+ $mybp_line = __LINE__ + 2
33
+ class MyBreakpoint
34
+ def mybreakpoint( i )
35
+ a = 1
36
+ b = 2
37
+ end
38
+ end
39
+
7
40
  class TestRuntimeInspectionThread < Test::Unit::TestCase
8
41
 
9
42
  class Tracker
@@ -11,12 +44,13 @@ class TestRuntimeInspectionThread < Test::Unit::TestCase
11
44
  @@assert_equal = block
12
45
  end
13
46
 
14
- def initialize( &assert_block )
47
+ def initialize
15
48
  $expect_verbose = $DEBUG
16
49
  @sock = TCPSocket.new( 'localhost', 56789 )
17
50
  @cmd_count = 1
18
51
  @block_count = 0
19
52
  @at_prompt = false
53
+ @prompt_name = File.basename( $0, '.rb' )
20
54
  end
21
55
 
22
56
  def assert( cmd=nil, *expected )
@@ -38,7 +72,7 @@ class TestRuntimeInspectionThread < Test::Unit::TestCase
38
72
  timeout( 5 ) do
39
73
  out += @sock.expect( prompt ).first
40
74
  end
41
- out.sub!( /test:\d+:\d> $/, '' )
75
+ out.sub!( /#{@prompt_name}:\d+:\d> $/, '' )
42
76
  end
43
77
 
44
78
  if @block_count > 0
@@ -48,13 +82,23 @@ class TestRuntimeInspectionThread < Test::Unit::TestCase
48
82
  timeout( 5 ) do
49
83
  out += @sock.expect( prompt ).first
50
84
  end
51
- out.sub!( /test:\d+:\d> $/, '' )
85
+ out.sub!( /#{@prompt_name}:\d+:\d> $/, '' )
52
86
  end
53
87
 
54
88
  @at_prompt = true
55
89
 
56
90
  out.chomp!
57
- @@assert_equal.call( expected.join("\n") + "\n", out )
91
+ if expected.empty?
92
+ return out
93
+ else
94
+ if expected.last == :no_newline
95
+ expected.pop
96
+ nl = ''
97
+ else
98
+ nl = "\n"
99
+ end
100
+ @@assert_equal.call( expected.join("\n") + nl, out )
101
+ end
58
102
  end
59
103
 
60
104
  def puts( msg )
@@ -86,7 +130,7 @@ class TestRuntimeInspectionThread < Test::Unit::TestCase
86
130
  private
87
131
 
88
132
  def prompt
89
- "test:#{'%03d'%@cmd_count}:#{@block_count}> "
133
+ "#{@prompt_name}:#{'%03d'%@cmd_count}:#{@block_count}> "
90
134
  end
91
135
  end
92
136
 
@@ -96,9 +140,22 @@ class TestRuntimeInspectionThread < Test::Unit::TestCase
96
140
  end
97
141
  end
98
142
 
143
+ def teardown
144
+ # Ensure that the RTI is not running so if one test fails,
145
+ # future ones won't just because it can't take the port.
146
+ rti_th = nil
147
+ Thread.list.each do |th|
148
+ if th.kind_of?( RuntimeInspection::Thread )
149
+ rti_th = th
150
+ break
151
+ end
152
+ end
153
+ rti_th.kill if rti_th
154
+ end
155
+
99
156
  def test_prompt
100
157
  threads = Thread.list.dup
101
- r = RuntimeInspectionThread.new
158
+ r = RuntimeInspection::Thread.new
102
159
  assert_not_equal( threads, Thread.list )
103
160
  t = Tracker.new
104
161
  t.assert
@@ -112,33 +169,37 @@ class TestRuntimeInspectionThread < Test::Unit::TestCase
112
169
  end
113
170
 
114
171
  def test_locals
115
- r = RuntimeInspectionThread.new
172
+ r = RuntimeInspection::Thread.new
116
173
  t = Tracker.new
117
174
 
118
175
  t.assert( 'rti.state.use_yaml = true', "=> --- true" )
119
176
 
120
- t.assert( 'local_variables',
121
- '=> --- ',
122
- '- rti' )
177
+ # As in the case of running within the GEM framework, the
178
+ # toplevel binding is not clean. Thus, we can only check that
179
+ # at least rti is around.
180
+ out = t.assert( 'local_variables' )
181
+ out.sub!( /^=> /, '' )
182
+ assert( YAML.load( out ).include?( 'rti' ), 'Missing rti local' )
123
183
 
124
184
  r.kill
125
185
  end
126
186
 
187
+ RTI_LIST = ["backtrace", "bp_add", "bp_attach", "bp_continue", "bp_delete",
188
+ "bp_finish", "bp_list", "bp_next", "bp_start", "bp_step",
189
+ "bp_stop", "get_object", "list", "name2class", "start_world",
190
+ "state", "stop_world", "threads"]
191
+
127
192
  def test_list
128
- r = RuntimeInspectionThread.new
193
+ r = RuntimeInspection::Thread.new
129
194
  t = Tracker.new
130
195
 
131
- t.assert( 'rti.list',
132
- '=> ["bp_add", "bp_continue", "bp_del", "bp_fin", "bp_list", ' +
133
- '"bp_next", "bp_start", "bp_step", "bp_stop", "get_object", ' +
134
- '"initialize", "list", "name2class", "start_world", "state", ' +
135
- '"stop_world"]' )
196
+ t.assert( 'rti.list', "=> #{RTI_LIST.inspect}" )
136
197
 
137
198
  r.kill
138
199
  end
139
200
 
140
201
  def test_lookup
141
- r = RuntimeInspectionThread.new
202
+ r = RuntimeInspection::Thread.new
142
203
  t = Tracker.new
143
204
 
144
205
  Struct.new( 'Foo', :one, :two, :three )
@@ -159,4 +220,174 @@ class TestRuntimeInspectionThread < Test::Unit::TestCase
159
220
  r.kill
160
221
  end
161
222
 
223
+ def test_signal
224
+ assert_raise( Errno::ECONNREFUSED ) do
225
+ t = Tracker.new
226
+ end
227
+
228
+ RuntimeInspection.on_signal
229
+
230
+ Process.kill( 'USR1', $$ )
231
+ t = Tracker.new
232
+
233
+ t.assert( 'rti.list', "=> #{RTI_LIST.inspect}" )
234
+
235
+ Process.kill( 'USR1', $$ )
236
+
237
+ assert_raise( Errno::ECONNREFUSED ) do
238
+ t = Tracker.new
239
+ end
240
+ end
241
+
242
+ def test_breakpoints
243
+ r = RuntimeInspection::Thread.new
244
+ t = Tracker.new
245
+
246
+ # Try some invalid breakpoints.
247
+ t.assert( '.bp_add Foo#bar',
248
+ '=> "Unable to find matching module or class for Foo"' )
249
+ t.assert( '.bp_add MyBreakpoint#doesnotexist',
250
+ '=> "Unable to find doesnotexist method in MyBreakpoint"' )
251
+ t.assert( '.bp_add bar',
252
+ '=> "Unable to find containing class or module for bar"' )
253
+
254
+ # Now let's run through a simple breakpoint analysis.
255
+ t.assert( '.bp_add MyBreakpoint#mybreakpoint',
256
+ '=> "Added breakpoint 1"' )
257
+
258
+ line = __LINE__
259
+ th = Thread.new do
260
+ bp = MyBreakpoint.new
261
+ 5.times do |i|
262
+ sleep 0.3
263
+ bp.mybreakpoint( i )
264
+ end
265
+ end
266
+
267
+ begin
268
+ t.assert( '.bp_start',
269
+ '=> nil', '',
270
+ 'Breakpoint 1 in MyBreakpoint#mybreakpoint ' +
271
+ "from #{__FILE__}:#{$mybp_line} (call) in #{th}",
272
+ :no_newline )
273
+
274
+ t.assert( 'local_variables',
275
+ '=> ["i", "a", "b", "rti"]', '',
276
+ 'Breakpoint 1 in MyBreakpoint#mybreakpoint ' +
277
+ "from #{__FILE__}:#{$mybp_line} (call) in #{th}",
278
+ :no_newline )
279
+
280
+ t.assert( '.bp_next',
281
+ '=> nil', '',
282
+ 'Stopped in MyBreakpoint#mybreakpoint ' +
283
+ "from #{__FILE__}:#{$mybp_line+1} (line) in #{th}",
284
+ :no_newline )
285
+
286
+ t.assert( 'rti.backtrace',
287
+ "=> [\"#{__FILE__}:#{$mybp_line+1}:in `mybreakpoint'\"," +
288
+ " \"#{__FILE__}:#{line+5}:in `test_breakpoints'\", " +
289
+ "\"#{__FILE__}:#{line+3}:in `test_breakpoints'\", " +
290
+ "\"#{__FILE__}:17:in `initialize'\", " +
291
+ "\"#{__FILE__}:#{line+1}:in `test_breakpoints'\"]",
292
+ '',
293
+ 'Stopped in MyBreakpoint#mybreakpoint ' +
294
+ "from #{__FILE__}:#{$mybp_line+1} (line) in #{th}",
295
+ :no_newline )
296
+
297
+ out = t.assert( 'rti.threads' )
298
+ assert_match( / :main sleep/, out )
299
+ assert_no_match( /RuntimeInspection::Thread:/, out )
300
+ assert_no_match( /:rti_/, out )
301
+
302
+ t.assert( '.bp_continue',
303
+ '=> nil', '',
304
+ 'Breakpoint 1 in MyBreakpoint#mybreakpoint ' +
305
+ "from #{__FILE__}:#{$mybp_line} (call) in #{th}",
306
+ :no_newline )
307
+ ensure
308
+ t.assert( '.bp_stop', '=> nil' )
309
+ th.kill
310
+ end
311
+
312
+ r.kill
313
+ end
314
+
315
+ def test_attach
316
+ r = RuntimeInspection::Thread.new
317
+ t = Tracker.new
318
+
319
+ line = __LINE__ + 4
320
+ th = Thread.new do
321
+ Thread.current[:thread_name] = :mybreakpoint
322
+ 5.times do
323
+ sleep( 0.1 )
324
+ end
325
+ end
326
+
327
+ begin
328
+ t.assert( '.bp_attach :mybreakpoint',
329
+ '=> nil', '',
330
+ 'Breakpoint 1 in TestRuntimeInspectionThread#test_attach ' +
331
+ "from #{__FILE__}:#{line} (line) in #{th}",
332
+ :no_newline )
333
+ ensure
334
+ t.assert( '.bp_stop', '=> nil' )
335
+ th.kill
336
+ end
337
+
338
+ r.kill
339
+ end
340
+
341
+ def test_client_close
342
+ r = RuntimeInspection::Thread.new
343
+ t = Tracker.new
344
+
345
+ # Have the client disconnect while waiting in the bp_start
346
+ # method.
347
+
348
+ t.assert( '.bp_add MyBreakpoint#mybreakpoint',
349
+ '=> "Added breakpoint 1"' )
350
+
351
+ th = Thread.new do
352
+ t.assert( '.bp_start' )
353
+ end
354
+
355
+ sleep 0.2
356
+
357
+ th.kill
358
+ t.close
359
+
360
+ def r.breakpoints
361
+ @breakpoints
362
+ end
363
+
364
+ def r.clients
365
+ @clients
366
+ end
367
+
368
+ sleep 0.2
369
+
370
+ assert_equal( {}, r.breakpoints )
371
+ assert_equal( [], r.clients )
372
+
373
+ found = {}
374
+ Thread.list.each do |th|
375
+ if th.kind_of?( RuntimeInspection::Thread )
376
+ found[:rti] = true
377
+ elsif name = th[:thread_name]
378
+ if name == :rti_gc
379
+ found[:rti_gc] = true
380
+ end
381
+ elsif th == Thread.main
382
+ found[:main] = true
383
+ else
384
+ flunk( "Found unknown thread (#{th.inspect}): " +
385
+ "#{th[:caller].inspect}" )
386
+ end
387
+ end
388
+ assert_equal( {:rti=>true, :rti_gc=>true, :main=>true}, found )
389
+
390
+ r.kill
391
+ end
392
+
162
393
  end
metadata CHANGED
@@ -3,19 +3,19 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: rtinspect
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.1
7
- date: 2007-01-01 00:00:00 -08:00
6
+ version: 0.0.19
7
+ date: 2007-01-09 00:00:00 -08:00
8
8
  summary: A thread that will enable remote access capabilities in a running Ruby process for debugging and inspection.
9
9
  require_paths:
10
10
  - lib
11
11
  email: bradrf@gigglewax.com
12
12
  homepage: http://rtinspect.rubyforge.org/
13
- rubyforge_project:
13
+ rubyforge_project: rtinspect
14
14
  description: This is a class that will enable remote access capabilities in a running Ruby process, exposing the ability to enable breakpoints, walk code (e.g. step/next/continue), inspect variables, modify codepaths, and many other debugging actions.
15
15
  autorequire:
16
16
  default_executable:
17
17
  bindir: bin
18
- has_rdoc: false
18
+ has_rdoc: true
19
19
  required_ruby_version: !ruby/object:Gem::Version::Requirement
20
20
  requirements:
21
21
  - - ">"
@@ -30,11 +30,17 @@ authors:
30
30
  - Brad Robel-Forrest
31
31
  files:
32
32
  - lib/rtinspect.rb
33
+ - lib/rti/manager.rb
34
+ - lib/rti/redirect.rb
35
+ - lib/rti/state.rb
36
+ - lib/rti/thread.rb
37
+ - lib/rti/tracer.rb
33
38
  - test/test.rb
34
39
  - README
35
40
  - LICENSE
36
41
  - COPYING
37
42
  - TODO
43
+ - VERSION
38
44
  test_files:
39
45
  - test/test.rb
40
46
  rdoc_options: []
@@ -44,8 +50,9 @@ extra_rdoc_files:
44
50
  - LICENSE
45
51
  - COPYING
46
52
  - TODO
47
- executables: []
48
-
53
+ - VERSION
54
+ executables:
55
+ - rti
49
56
  extensions: []
50
57
 
51
58
  requirements: []