appmap 0.34.0 → 0.35.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,7 +22,7 @@ describe 'AppMap class Hooking', docker: false do
22
22
  while tracer.event?
23
23
  events << tracer.next_event.to_h
24
24
  end
25
- end.map(&AppMap::Util.method(:sanitize_event)).to_yaml
25
+ end.map(&AppMap::Util.method(:sanitize_event))
26
26
  end
27
27
 
28
28
  def invoke_test_file(file, setup: nil, &block)
@@ -50,7 +50,7 @@ describe 'AppMap class Hooking', docker: false do
50
50
  def test_hook_behavior(file, events_yaml, setup: nil, &block)
51
51
  config, tracer = invoke_test_file(file, setup: setup, &block)
52
52
 
53
- events = collect_events(tracer)
53
+ events = collect_events(tracer).to_yaml
54
54
 
55
55
  expect(Diffy::Diff.new(events_yaml, events).to_s).to eq('')
56
56
 
@@ -342,7 +342,7 @@ describe 'AppMap class Hooking', docker: false do
342
342
  :defined_class: SingletonMethod
343
343
  :method_id: added_method
344
344
  :path: spec/fixtures/hook/singleton_method.rb
345
- :lineno: 44
345
+ :lineno: 21
346
346
  :static: false
347
347
  :parameters: []
348
348
  :receiver:
@@ -350,10 +350,10 @@ describe 'AppMap class Hooking', docker: false do
350
350
  :value: Singleton Method fixture
351
351
  - :id: 2
352
352
  :event: :call
353
- :defined_class: AddMethod
353
+ :defined_class: SingletonMethod::AddMethod
354
354
  :method_id: _added_method
355
355
  :path: spec/fixtures/hook/singleton_method.rb
356
- :lineno: 50
356
+ :lineno: 27
357
357
  :static: false
358
358
  :parameters: []
359
359
  :receiver:
@@ -395,10 +395,44 @@ describe 'AppMap class Hooking', docker: false do
395
395
  load 'spec/fixtures/hook/singleton_method.rb'
396
396
  setup = -> { SingletonMethod.new_with_instance_method }
397
397
  test_hook_behavior 'spec/fixtures/hook/singleton_method.rb', events_yaml, setup: setup do |s|
398
+ # Make sure we're testing the right thing
399
+ say_instance_defined = s.method(:say_instance_defined)
400
+ expect(say_instance_defined.owner.to_s).to start_with('#<Class:#<SingletonMethod:')
401
+
402
+ # Verify the native extension works as expected
403
+ expect(AppMap::Hook.singleton_method_owner_name(say_instance_defined)).to eq('SingletonMethod')
404
+
398
405
  expect(s.say_instance_defined).to eq('defined for an instance')
399
406
  end
400
407
  end
401
408
 
409
+ it 'hooks a singleton method on an embedded struct' do
410
+ events_yaml = <<~YAML
411
+ ---
412
+ - :id: 1
413
+ :event: :call
414
+ :defined_class: SingletonMethod::STRUCT_TEST
415
+ :method_id: say_struct_singleton
416
+ :path: spec/fixtures/hook/singleton_method.rb
417
+ :lineno: 52
418
+ :static: true
419
+ :parameters: []
420
+ :receiver:
421
+ :class: Class
422
+ :value: SingletonMethod::STRUCT_TEST
423
+ - :id: 2
424
+ :event: :return
425
+ :parent_id: 1
426
+ :return_value:
427
+ :class: String
428
+ :value: singleton for a struct
429
+ YAML
430
+
431
+ test_hook_behavior 'spec/fixtures/hook/singleton_method.rb', events_yaml do
432
+ expect(SingletonMethod::STRUCT_TEST.say_struct_singleton).to eq('singleton for a struct')
433
+ end
434
+ end
435
+
402
436
  it 'Reports exceptions' do
403
437
  events_yaml = <<~YAML
404
438
  ---
@@ -466,7 +500,7 @@ describe 'AppMap class Hooking', docker: false do
466
500
  :event: :call
467
501
  :defined_class: ActiveSupport::SecurityUtils
468
502
  :method_id: secure_compare
469
- :path: gems/activesupport-6.0.3.2/lib/active_support/security_utils.rb
503
+ :path: lib/active_support/security_utils.rb
470
504
  :lineno: 26
471
505
  :static: true
472
506
  :parameters:
@@ -564,7 +598,7 @@ describe 'AppMap class Hooking', docker: false do
564
598
  :children:
565
599
  - :name: secure_compare
566
600
  :type: function
567
- :location: gems/activesupport-6.0.3.2/lib/active_support/security_utils.rb:26
601
+ :location: lib/active_support/security_utils.rb:26
568
602
  :static: true
569
603
  :labels:
570
604
  - security
@@ -590,7 +624,7 @@ describe 'AppMap class Hooking', docker: false do
590
624
  config, tracer = invoke_test_file 'spec/fixtures/hook/compare.rb' do
591
625
  expect(Compare.compare('string', 'string')).to be_truthy
592
626
  end
593
- cm = AppMap::ClassMap.build_from_methods(config, tracer.event_methods)
627
+ cm = AppMap::Util.sanitize_paths(AppMap::ClassMap.build_from_methods(tracer.event_methods))
594
628
  entry = cm[1][:children][0][:children][0][:children][0]
595
629
  # Sanity check, make sure we got the right one
596
630
  expect(entry[:name]).to eq('secure_compare')
@@ -599,4 +633,47 @@ describe 'AppMap class Hooking', docker: false do
599
633
  expect(Diffy::Diff.new(classmap_yaml, cm.to_yaml).to_s).to eq('')
600
634
  end
601
635
  end
636
+
637
+ it "doesn't cause expectations on Time.now to fail" do
638
+ events_yaml = <<~YAML
639
+ ---
640
+ - :id: 1
641
+ :event: :call
642
+ :defined_class: InstanceMethod
643
+ :method_id: say_the_time
644
+ :path: spec/fixtures/hook/instance_method.rb
645
+ :lineno: 24
646
+ :static: false
647
+ :parameters: []
648
+ :receiver:
649
+ :class: InstanceMethod
650
+ :value: Instance Method fixture
651
+ - :id: 2
652
+ :event: :return
653
+ :parent_id: 1
654
+ :return_value:
655
+ :class: String
656
+ :value: '2020-01-01 00:00:00 +0000'
657
+ YAML
658
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
659
+ require 'timecop'
660
+ begin
661
+ tz = ENV['TZ']
662
+ ENV['TZ'] = 'UTC'
663
+ Timecop.freeze(Time.utc('2020-01-01')) do
664
+ expect(Time).to receive(:now).exactly(3).times.and_call_original
665
+ expect(InstanceMethod.new.say_the_time).to be
666
+ end
667
+ ensure
668
+ ENV['TZ'] = tz
669
+ end
670
+ end
671
+ end
672
+
673
+ it "preserves the arity of hooked methods" do
674
+ invoke_test_file 'spec/fixtures/hook/instance_method.rb' do
675
+ expect(InstanceMethod.instance_method(:say_echo).arity).to be(1)
676
+ expect(InstanceMethod.new.method(:say_echo).arity).to be(1)
677
+ end
678
+ end
602
679
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.34.0
4
+ version: 0.35.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Gilpin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-21 00:00:00.000000000 Z
11
+ date: 2020-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rake-compiler
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: climate_control
169
183
  requirement: !ruby/object:Gem::Requirement
@@ -248,16 +262,46 @@ dependencies:
248
262
  - - "~>"
249
263
  - !ruby/object:Gem::Version
250
264
  version: '4.0'
265
+ - !ruby/object:Gem::Dependency
266
+ name: timecop
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ">="
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ">="
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: hashie
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ">="
291
+ - !ruby/object:Gem::Version
292
+ version: '0'
251
293
  description:
252
294
  email:
253
295
  - kgilpin@gmail.com
254
296
  executables:
255
297
  - appmap
256
- extensions: []
298
+ extensions:
299
+ - ext/appmap/extconf.rb
257
300
  extra_rdoc_files: []
258
301
  files:
259
302
  - ".dockerignore"
260
303
  - ".gitignore"
304
+ - ".rbenv-gemsets"
261
305
  - ".rubocop.yml"
262
306
  - ".ruby-version"
263
307
  - ".travis.yml"
@@ -277,6 +321,8 @@ files:
277
321
  - examples/mock_webapp/lib/mock_webapp/request.rb
278
322
  - examples/mock_webapp/lib/mock_webapp/user.rb
279
323
  - exe/appmap
324
+ - ext/appmap/appmap.c
325
+ - ext/appmap/extconf.rb
280
326
  - lib/appmap.rb
281
327
  - lib/appmap/algorithm/prune_class_map.rb
282
328
  - lib/appmap/algorithm/stats.rb
@@ -292,7 +338,7 @@ files:
292
338
  - lib/appmap/middleware/remote_recording.rb
293
339
  - lib/appmap/minitest.rb
294
340
  - lib/appmap/open.rb
295
- - lib/appmap/rails/action_handler.rb
341
+ - lib/appmap/rails/request_handler.rb
296
342
  - lib/appmap/rails/sql_handler.rb
297
343
  - lib/appmap/railtie.rb
298
344
  - lib/appmap/record.rb
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'appmap/event'
4
-
5
- module AppMap
6
- module Rails
7
- module ActionHandler
8
- Context = Struct.new(:id, :start_time)
9
-
10
- module ContextKey
11
- def context_key
12
- "#{HTTPServerRequest.name}#call"
13
- end
14
- end
15
-
16
- class HTTPServerRequest
17
- include ContextKey
18
-
19
- class Call < AppMap::Event::MethodCall
20
- attr_accessor :payload
21
-
22
- def initialize(payload)
23
- super AppMap::Event.next_id_counter, :call, Thread.current.object_id
24
-
25
- self.payload = payload
26
- end
27
-
28
- def to_h
29
- super.tap do |h|
30
- h[:http_server_request] = {
31
- request_method: payload[:method],
32
- path_info: payload[:path]
33
- }
34
-
35
- params = payload[:params]
36
- h[:message] = params.keys.map do |key|
37
- val = params[key]
38
- {
39
- name: key,
40
- class: val.class.name,
41
- value: self.class.display_string(val),
42
- object_id: val.__id__
43
- }
44
- end
45
- end
46
- end
47
- end
48
-
49
- def call(_, started, finished, _, payload) # (name, started, finished, unique_id, payload)
50
- event = Call.new(payload)
51
- Thread.current[context_key] = Context.new(event.id, Time.now)
52
- AppMap.tracing.record_event(event)
53
- end
54
- end
55
-
56
- class HTTPServerResponse
57
- include ContextKey
58
-
59
- class Call < AppMap::Event::MethodReturnIgnoreValue
60
- attr_accessor :payload
61
-
62
- def initialize(payload, parent_id, elapsed)
63
- super AppMap::Event.next_id_counter, :return, Thread.current.object_id
64
-
65
- self.payload = payload
66
- self.parent_id = parent_id
67
- self.elapsed = elapsed
68
- end
69
-
70
- def to_h
71
- super.tap do |h|
72
- h[:http_server_response] = {
73
- status: payload[:status]
74
- }
75
- end
76
- end
77
- end
78
-
79
- def call(_, started, finished, _, payload) # (name, started, finished, unique_id, payload)
80
- return unless Thread.current[context_key]
81
-
82
- context = Thread.current[context_key]
83
- Thread.current[context_key] = nil
84
-
85
- event = Call.new(payload, context.id, Time.now - context.start_time)
86
- AppMap.tracing.record_event(event)
87
- end
88
- end
89
- end
90
- end
91
- end