appmap 0.43.0 → 0.47.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.releaserc.yml +11 -0
  3. data/.travis.yml +33 -2
  4. data/CHANGELOG.md +44 -0
  5. data/README.md +66 -11
  6. data/README_CI.md +29 -0
  7. data/Rakefile +4 -2
  8. data/appmap.gemspec +5 -3
  9. data/lib/appmap.rb +3 -7
  10. data/lib/appmap/class_map.rb +11 -22
  11. data/lib/appmap/command/record.rb +1 -1
  12. data/lib/appmap/config.rb +180 -67
  13. data/lib/appmap/cucumber.rb +1 -1
  14. data/lib/appmap/event.rb +29 -28
  15. data/lib/appmap/handler/function.rb +19 -0
  16. data/lib/appmap/handler/net_http.rb +107 -0
  17. data/lib/appmap/handler/rails/request_handler.rb +124 -0
  18. data/lib/appmap/handler/rails/sql_handler.rb +152 -0
  19. data/lib/appmap/handler/rails/template.rb +149 -0
  20. data/lib/appmap/hook.rb +111 -70
  21. data/lib/appmap/hook/method.rb +6 -8
  22. data/lib/appmap/middleware/remote_recording.rb +1 -1
  23. data/lib/appmap/minitest.rb +22 -20
  24. data/lib/appmap/railtie.rb +5 -5
  25. data/lib/appmap/record.rb +1 -1
  26. data/lib/appmap/rspec.rb +22 -21
  27. data/lib/appmap/trace.rb +47 -6
  28. data/lib/appmap/util.rb +57 -2
  29. data/lib/appmap/version.rb +2 -2
  30. data/package-lock.json +3 -3
  31. data/release.sh +17 -0
  32. data/spec/abstract_controller_base_spec.rb +76 -15
  33. data/spec/class_map_spec.rb +5 -13
  34. data/spec/config_spec.rb +33 -1
  35. data/spec/fixtures/hook/custom_instance_method.rb +11 -0
  36. data/spec/fixtures/hook/method_named_call.rb +11 -0
  37. data/spec/hook_spec.rb +143 -22
  38. data/spec/record_net_http_spec.rb +160 -0
  39. data/spec/spec_helper.rb +10 -0
  40. data/spec/util_spec.rb +18 -1
  41. data/test/expectations/openssl_test_key_sign1.json +2 -4
  42. data/test/gem_test.rb +1 -1
  43. data/test/rspec_test.rb +0 -13
  44. metadata +20 -14
  45. data/exe/appmap +0 -154
  46. data/lib/appmap/rails/request_handler.rb +0 -140
  47. data/lib/appmap/rails/sql_handler.rb +0 -150
  48. data/test/cli_test.rb +0 -116
data/lib/appmap/trace.rb CHANGED
@@ -2,14 +2,36 @@
2
2
 
3
3
  module AppMap
4
4
  module Trace
5
- class ScopedMethod < SimpleDelegator
6
- attr_reader :package, :defined_class, :static
5
+ class RubyMethod
6
+ attr_reader :class_name, :static
7
7
 
8
- def initialize(package, defined_class, method, static)
8
+ def initialize(package, class_name, method, static)
9
9
  @package = package
10
- @defined_class = defined_class
10
+ @class_name = class_name
11
+ @method = method
11
12
  @static = static
12
- super(method)
13
+ end
14
+
15
+ def source_location
16
+ @method.source_location
17
+ end
18
+
19
+ def comment
20
+ @method.comment
21
+ rescue MethodSource::SourceNotFoundError
22
+ nil
23
+ end
24
+
25
+ def package
26
+ @package.name
27
+ end
28
+
29
+ def name
30
+ @method.name
31
+ end
32
+
33
+ def labels
34
+ @package.labels
13
35
  end
14
36
  end
15
37
 
@@ -43,6 +65,12 @@ module AppMap
43
65
  end
44
66
  end
45
67
 
68
+ def record_method(method)
69
+ @tracers.each do |tracer|
70
+ tracer.record_method(method)
71
+ end
72
+ end
73
+
46
74
  def delete(tracer)
47
75
  return unless @tracers.member?(tracer)
48
76
 
@@ -82,10 +110,23 @@ module AppMap
82
110
 
83
111
  @last_package_for_thread[Thread.current.object_id] = package if package
84
112
  @events << event
85
- @methods << Trace::ScopedMethod.new(package, defined_class, method, event.static) \
113
+ static = event.static if event.respond_to?(:static)
114
+ @methods << Trace::RubyMethod.new(package, defined_class, method, static) \
86
115
  if package && defined_class && method && (event.event == :call)
87
116
  end
88
117
 
118
+ # +method+ should be duck-typed to respond to the following:
119
+ # * package
120
+ # * defined_class
121
+ # * name
122
+ # * static
123
+ # * comment
124
+ # * labels
125
+ # * source_location
126
+ def record_method(method)
127
+ @methods << method
128
+ end
129
+
89
130
  # Gets the last package which was observed on the current thread.
90
131
  def last_package_for_current_thread
91
132
  @last_package_for_thread[Thread.current.object_id]
data/lib/appmap/util.rb CHANGED
@@ -61,8 +61,16 @@ module AppMap
61
61
  delete_object_id = ->(obj) { (obj || {}).delete(:object_id) }
62
62
  delete_object_id.call(event[:receiver])
63
63
  delete_object_id.call(event[:return_value])
64
- (event[:parameters] || []).each(&delete_object_id)
65
- (event[:exceptions] || []).each(&delete_object_id)
64
+ %i[parameters exceptions message].each do |field|
65
+ (event[field] || []).each(&delete_object_id)
66
+ end
67
+ %i[http_client_request http_client_response http_server_request http_server_response].each do |field|
68
+ headers = event.dig(field, :headers)
69
+ next unless headers
70
+
71
+ headers['Date'] = '<instanceof date>' if headers['Date']
72
+ headers['Server'] = headers['Server'].match(/^(\w+)/)[0] if headers['Server']
73
+ end
66
74
 
67
75
  case event[:event]
68
76
  when :call
@@ -71,6 +79,53 @@ module AppMap
71
79
 
72
80
  event
73
81
  end
82
+
83
+ def select_headers(env)
84
+ # Rack prepends HTTP_ to all client-sent headers.
85
+ matching_headers = env
86
+ .select { |k,v| k.start_with? 'HTTP_'}
87
+ .reject { |k,v| v.blank? }
88
+ .each_with_object({}) do |kv, memo|
89
+ key = kv[0].sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-')
90
+ value = kv[1]
91
+ memo[key] = value
92
+ end
93
+ matching_headers.blank? ? nil : matching_headers
94
+ end
95
+
96
+ def normalize_path(path)
97
+ if path.index(Dir.pwd) == 0
98
+ path[Dir.pwd.length + 1..-1]
99
+ else
100
+ path
101
+ end
102
+ end
103
+
104
+ # Convert a Rails-style path from /org/:org_id(.:format)
105
+ # to Swagger-style paths like /org/{org_id}
106
+ def swaggerize_path(path)
107
+ path = path.split('(.')[0]
108
+ tokens = path.split('/')
109
+ tokens.map do |token|
110
+ token.gsub /^:(.*)/, '{\1}'
111
+ end.join('/')
112
+ end
113
+
114
+ # Atomically writes AppMap data to +filename+.
115
+ def write_appmap(filename, appmap)
116
+ require 'fileutils'
117
+ require 'tmpdir'
118
+
119
+ # This is what Ruby Tempfile does; but we don't want the file to be unlinked.
120
+ mode = File::RDWR | File::CREAT | File::EXCL
121
+ ::Dir::Tmpname.create([ 'appmap_', '.json' ]) do |tmpname|
122
+ tempfile = File.open(tmpname, mode)
123
+ tempfile.write(appmap)
124
+ tempfile.close
125
+ # Atomically move the tempfile into place.
126
+ FileUtils.mv tempfile.path, filename
127
+ end
128
+ end
74
129
  end
75
130
  end
76
131
  end
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.43.0'
6
+ VERSION = '0.47.0'
7
7
 
8
- APPMAP_FORMAT_VERSION = '1.4'
8
+ APPMAP_FORMAT_VERSION = '1.5.0'
9
9
  end
data/package-lock.json CHANGED
@@ -551,9 +551,9 @@
551
551
  }
552
552
  },
553
553
  "lodash": {
554
- "version": "4.17.19",
555
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
556
- "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
554
+ "version": "4.17.21",
555
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
556
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
557
557
  },
558
558
  "longest": {
559
559
  "version": "1.0.1",
data/release.sh ADDED
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+ # using bash wrapper as Rake blows up in `require/extentiontask` (line 10)
3
+
4
+ RELEASE_FLAGS=""
5
+ if [ ! -z "$TRAVIS_REPO_SLUG" ]; then
6
+ RELEASE_FLAGS="-r git+https://github.com/${TRAVIS_REPO_SLUG}.git"
7
+ fi
8
+
9
+ if [ ! -z "$GEM_ALTERNATIVE_NAME" ]; then
10
+ echo "Release: GEM_ALTERNATIVE_NAME=$GEM_ALTERNATIVE_NAME"
11
+ else
12
+ echo "No GEM_ALTERNATIVE_NAME is provided, releasing gem with default name ('appmap')"
13
+ fi
14
+
15
+ set -x
16
+ exec semantic-release $RELEASE_FLAGS
17
+
@@ -27,6 +27,8 @@ describe 'Rails' do
27
27
  end
28
28
 
29
29
  let(:appmap) { JSON.parse File.read File.join tmpdir, 'appmap/rspec', appmap_json_file }
30
+ let(:appmap_json_path) { File.join(tmpdir, 'appmap/rspec', appmap_json_file) }
31
+ let(:appmap) { JSON.parse File.read(appmap_json_path) }
30
32
  let(:events) { appmap['events'] }
31
33
 
32
34
  describe 'an API route' do
@@ -35,16 +37,12 @@ describe 'Rails' do
35
37
  'Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json'
36
38
  end
37
39
 
38
- it 'inventory file is printed' do
39
- expect(File).to exist(File.join(tmpdir, 'appmap/rspec/Inventory.appmap.json'))
40
- end
41
-
42
40
  it 'http_server_request is recorded in the appmap' do
43
41
  expect(events).to include(
44
42
  hash_including(
45
43
  'http_server_request' => hash_including(
46
44
  'request_method' => 'POST',
47
- 'normalized_path_info' => '/api/users(.:format)',
45
+ 'normalized_path_info' => '/api/users',
48
46
  'path_info' => '/api/users'
49
47
  ),
50
48
  'message' => include(
@@ -69,8 +67,8 @@ describe 'Rails' do
69
67
  expect(events).to include(
70
68
  hash_including(
71
69
  'http_server_response' => hash_including(
72
- 'status' => 201,
73
- 'mime_type' => 'application/json; charset=utf-8'
70
+ 'status_code' => 201,
71
+ 'mime_type' => 'application/json; charset=utf-8',
74
72
  )
75
73
  )
76
74
  )
@@ -146,7 +144,49 @@ describe 'Rails' do
146
144
  end
147
145
 
148
146
  describe 'a UI route' do
149
- describe 'rendering a page' do
147
+ describe 'rendering a page using a template file' do
148
+ let(:appmap_json_file) do
149
+ 'UsersController_GET_users_lists_the_users.appmap.json'
150
+ end
151
+
152
+ it 'records the template file' do
153
+ expect(events).to include hash_including(
154
+ 'event' => 'call',
155
+ 'defined_class' => 'app_views_users_index_html_haml',
156
+ 'method_id' => 'render',
157
+ 'path' => 'app/views/users/index.html.haml'
158
+ )
159
+
160
+ expect(appmap['classMap']).to include hash_including(
161
+ 'name' => 'app/views',
162
+ 'children' => include(hash_including(
163
+ 'name' => 'app_views_users_index_html_haml',
164
+ 'children' => include(hash_including(
165
+ 'name' => 'render',
166
+ 'type' => 'function',
167
+ 'location' => 'app/views/users/index.html.haml',
168
+ 'static' => true,
169
+ 'labels' => [ 'mvc.template' ]
170
+ ))
171
+ ))
172
+ )
173
+ expect(appmap['classMap']).to include hash_including(
174
+ 'name' => 'app/views',
175
+ 'children' => include(hash_including(
176
+ 'name' => 'app_views_layouts_application_html_haml',
177
+ 'children' => include(hash_including(
178
+ 'name' => 'render',
179
+ 'type' => 'function',
180
+ 'location' => 'app/views/layouts/application.html.haml',
181
+ 'static' => true,
182
+ 'labels' => [ 'mvc.template' ]
183
+ ))
184
+ ))
185
+ )
186
+ end
187
+ end
188
+
189
+ describe 'rendering a page using a text template' do
150
190
  let(:appmap_json_file) do
151
191
  'UsersController_GET_users_login_shows_the_user.appmap.json'
152
192
  end
@@ -157,25 +197,46 @@ describe 'Rails' do
157
197
  'http_server_request' => {
158
198
  'request_method' => 'GET',
159
199
  'path_info' => '/users/alice',
160
- 'normalized_path_info' => '/users/:id(.:format)'
200
+ 'normalized_path_info' => '/users/{id}',
201
+ 'headers' => {
202
+ 'Host' => 'test.host',
203
+ 'User-Agent' => 'Rails Testing'
204
+ }
161
205
  }
162
206
  )
163
207
  )
164
208
  end
165
209
 
210
+ it 'ignores the text template' do
211
+ expect(events).to_not include hash_including(
212
+ 'event' => 'call',
213
+ 'method_id' => 'render',
214
+ 'render_template' => anything
215
+ )
216
+
217
+ expect(appmap['classMap']).to_not include hash_including(
218
+ 'name' => 'views',
219
+ 'children' => include(hash_including(
220
+ 'name' => 'ViewTemplate',
221
+ 'children' => include(hash_including(
222
+ 'name' => 'render',
223
+ 'type' => 'function',
224
+ 'location' => 'text template'
225
+ ))
226
+ ))
227
+ )
228
+ end
229
+
166
230
  it 'records and labels view rendering' do
167
231
  expect(events).to include hash_including(
168
232
  'event' => 'call',
169
233
  'thread_id' => Numeric,
170
- 'defined_class' => 'ActionView::Renderer',
171
- 'method_id' => 'render',
172
- 'path' => String,
173
- 'lineno' => Integer,
174
- 'static' => false
234
+ 'defined_class' => 'inline_template',
235
+ 'method_id' => 'render'
175
236
  )
176
237
 
177
238
  expect(appmap['classMap']).to include hash_including(
178
- 'name' => 'action_view',
239
+ 'name' => 'actionview',
179
240
  'children' => include(hash_including(
180
241
  'name' => 'ActionView',
181
242
  'children' => include(hash_including(
@@ -4,18 +4,10 @@ require 'spec_helper'
4
4
 
5
5
  describe 'AppMap::ClassMap' do
6
6
  describe '.build_from_methods' do
7
- it 'includes source code if available' do
8
- map = AppMap.class_map([scoped_method(method(:test_method))])
7
+ it 'includes method comment' do
8
+ map = AppMap.class_map([ruby_method((method :test_method))])
9
9
  function = dig_map(map, 5)[0]
10
- expect(function[:source]).to include 'test method body'
11
- expect(function[:comment]).to include 'test method comment'
12
- end
13
-
14
- it 'can omit source code even if available' do
15
- map = AppMap.class_map([scoped_method((method :test_method))], include_source: false)
16
- function = dig_map(map, 5)[0]
17
- expect(function).to_not include(:source)
18
- expect(function).to_not include(:comment)
10
+ expect(function).to include(:comment)
19
11
  end
20
12
 
21
13
  # test method comment
@@ -23,8 +15,8 @@ describe 'AppMap::ClassMap' do
23
15
  'test method body'
24
16
  end
25
17
 
26
- def scoped_method(method)
27
- AppMap::Trace::ScopedMethod.new AppMap::Config::Package.new, method.receiver.class.name, method, false
18
+ def ruby_method(method)
19
+ AppMap::Trace::RubyMethod.new AppMap::Config::Package.new, method.receiver.class.name, method, false
28
20
  end
29
21
 
30
22
  def dig_map(map, depth)
data/spec/config_spec.rb CHANGED
@@ -17,10 +17,42 @@ describe AppMap::Config, docker: false do
17
17
  path: 'path-2',
18
18
  exclude: [ 'exclude-1' ]
19
19
  }
20
+ ],
21
+ functions: [
22
+ {
23
+ package: 'pkg',
24
+ class: 'cls',
25
+ function: 'fn',
26
+ label: 'lbl'
27
+ }
20
28
  ]
21
29
  }.deep_stringify_keys!
22
30
  config = AppMap::Config.load(config_data)
23
31
 
24
- expect(config.to_h.deep_stringify_keys!).to eq(config_data)
32
+ config_expectation = {
33
+ exclude: [],
34
+ name: 'test',
35
+ packages: [
36
+ {
37
+ path: 'path-1',
38
+ handler_class: 'AppMap::Handler::Function'
39
+ },
40
+ {
41
+ path: 'path-2',
42
+ handler_class: 'AppMap::Handler::Function',
43
+ exclude: [ 'exclude-1' ]
44
+ }
45
+ ],
46
+ functions: [
47
+ {
48
+ package: 'pkg',
49
+ class: 'cls',
50
+ functions: [ :fn ],
51
+ labels: ['lbl']
52
+ }
53
+ ]
54
+ }.deep_stringify_keys!
55
+
56
+ expect(config.to_h.deep_stringify_keys!).to eq(config_expectation)
25
57
  end
26
58
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CustomInstanceMethod
4
+ def to_s
5
+ 'CustomInstance Method fixture'
6
+ end
7
+
8
+ def say_default
9
+ 'default'
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MethodNamedCall
4
+ def to_s
5
+ 'MethodNamedCall'
6
+ end
7
+
8
+ def call(a, b, c, d, e)
9
+ [ a, b, c, d, e ].join(' ')
10
+ end
11
+ end
data/spec/hook_spec.rb CHANGED
@@ -16,14 +16,7 @@ end
16
16
  Psych::Visitors::YAMLTree.prepend(ShowYamlNulls)
17
17
 
18
18
  describe 'AppMap class Hooking', docker: false do
19
- require 'appmap/util'
20
- def collect_events(tracer)
21
- [].tap do |events|
22
- while tracer.event?
23
- events << tracer.next_event.to_h
24
- end
25
- end.map(&AppMap::Util.method(:sanitize_event))
26
- end
19
+ include_context 'collect events'
27
20
 
28
21
  def invoke_test_file(file, setup: nil, &block)
29
22
  AppMap.configuration = nil
@@ -64,11 +57,144 @@ describe 'AppMap class Hooking', docker: false do
64
57
  it 'excludes named classes and methods' do
65
58
  load 'spec/fixtures/hook/exclude.rb'
66
59
  package = AppMap::Config::Package.build_from_path('spec/fixtures/hook/exclude.rb')
67
- config = AppMap::Config.new('hook_spec', [ package ], %w[ExcludeTest])
60
+ config = AppMap::Config.new('hook_spec', [ package ], exclude: %w[ExcludeTest])
68
61
  AppMap.configuration = config
69
62
 
70
- expect(config.never_hook?(ExcludeTest.new.method(:instance_method))).to be_truthy
71
- expect(config.never_hook?(ExcludeTest.method(:cls_method))).to be_truthy
63
+ expect(config.never_hook?(ExcludeTest, ExcludeTest.new.method(:instance_method))).to be_truthy
64
+ expect(config.never_hook?(ExcludeTest, ExcludeTest.method(:cls_method))).to be_truthy
65
+ end
66
+
67
+ it "handles an instance method named 'call' without issues" do
68
+ events_yaml = <<~YAML
69
+ ---
70
+ - :id: 1
71
+ :event: :call
72
+ :defined_class: MethodNamedCall
73
+ :method_id: call
74
+ :path: spec/fixtures/hook/method_named_call.rb
75
+ :lineno: 8
76
+ :static: false
77
+ :parameters:
78
+ - :name: :a
79
+ :class: Integer
80
+ :value: '1'
81
+ :kind: :req
82
+ - :name: :b
83
+ :class: Integer
84
+ :value: '2'
85
+ :kind: :req
86
+ - :name: :c
87
+ :class: Integer
88
+ :value: '3'
89
+ :kind: :req
90
+ - :name: :d
91
+ :class: Integer
92
+ :value: '4'
93
+ :kind: :req
94
+ - :name: :e
95
+ :class: Integer
96
+ :value: '5'
97
+ :kind: :req
98
+ :receiver:
99
+ :class: MethodNamedCall
100
+ :value: MethodNamedCall
101
+ - :id: 2
102
+ :event: :return
103
+ :parent_id: 1
104
+ :return_value:
105
+ :class: String
106
+ :value: 1 2 3 4 5
107
+ YAML
108
+
109
+ _, tracer = test_hook_behavior 'spec/fixtures/hook/method_named_call.rb', events_yaml do
110
+ expect(MethodNamedCall.new.call(1, 2, 3, 4, 5)).to eq('1 2 3 4 5')
111
+ end
112
+ class_map = AppMap.class_map(tracer.event_methods)
113
+ expect(Diffy::Diff.new(<<~CLASSMAP, YAML.dump(class_map)).to_s).to eq('')
114
+ ---
115
+ - :name: spec/fixtures/hook/method_named_call.rb
116
+ :type: package
117
+ :children:
118
+ - :name: MethodNamedCall
119
+ :type: class
120
+ :children:
121
+ - :name: call
122
+ :type: function
123
+ :location: spec/fixtures/hook/method_named_call.rb:8
124
+ :static: false
125
+ CLASSMAP
126
+ end
127
+
128
+ it 'can custom hook and label a function' do
129
+ events_yaml = <<~YAML
130
+ ---
131
+ - :id: 1
132
+ :event: :call
133
+ :defined_class: CustomInstanceMethod
134
+ :method_id: say_default
135
+ :path: spec/fixtures/hook/custom_instance_method.rb
136
+ :lineno: 8
137
+ :static: false
138
+ :parameters: []
139
+ :receiver:
140
+ :class: CustomInstanceMethod
141
+ :value: CustomInstance Method fixture
142
+ - :id: 2
143
+ :event: :return
144
+ :parent_id: 1
145
+ :return_value:
146
+ :class: String
147
+ :value: default
148
+ YAML
149
+
150
+ config = AppMap::Config.load({
151
+ functions: [
152
+ {
153
+ package: 'hook_spec',
154
+ class: 'CustomInstanceMethod',
155
+ functions: [ :say_default ],
156
+ labels: ['cowsay']
157
+ }
158
+ ]
159
+ }.deep_stringify_keys)
160
+
161
+ load 'spec/fixtures/hook/custom_instance_method.rb'
162
+ hook_cls = CustomInstanceMethod
163
+ method = hook_cls.instance_method(:say_default)
164
+
165
+ require 'appmap/hook/method'
166
+ package = config.lookup_package(hook_cls, method)
167
+ expect(package).to be
168
+ hook_method = AppMap::Hook::Method.new(package, hook_cls, method)
169
+ hook_method.activate
170
+
171
+ tracer = AppMap.tracing.trace
172
+ AppMap::Event.reset_id_counter
173
+ begin
174
+ expect(CustomInstanceMethod.new.say_default).to eq('default')
175
+ ensure
176
+ AppMap.tracing.delete(tracer)
177
+ end
178
+
179
+ events = collect_events(tracer).to_yaml
180
+
181
+ expect(Diffy::Diff.new(events_yaml, events).to_s).to eq('')
182
+ class_map = AppMap.class_map(tracer.event_methods)
183
+ expect(Diffy::Diff.new(<<~CLASSMAP, YAML.dump(class_map)).to_s).to eq('')
184
+ ---
185
+ - :name: hook_spec
186
+ :type: package
187
+ :children:
188
+ - :name: CustomInstanceMethod
189
+ :type: class
190
+ :children:
191
+ - :name: say_default
192
+ :type: function
193
+ :location: spec/fixtures/hook/custom_instance_method.rb:8
194
+ :static: false
195
+ :labels:
196
+ - cowsay
197
+ CLASSMAP
72
198
  end
73
199
 
74
200
  it 'parses labels from comments' do
@@ -91,9 +217,6 @@ describe 'AppMap class Hooking', docker: false do
91
217
  :labels:
92
218
  - has-fn-label
93
219
  :comment: "# @label has-fn-label\\n"
94
- :source: |2
95
- def fn_with_label
96
- end
97
220
  YAML
98
221
  end
99
222
 
@@ -127,8 +250,8 @@ describe 'AppMap class Hooking', docker: false do
127
250
  _, tracer = invoke_test_file 'spec/fixtures/hook/instance_method.rb' do
128
251
  InstanceMethod.new.say_default
129
252
  end
130
- expect(tracer.event_methods.to_a.map(&:defined_class)).to eq([ 'InstanceMethod' ])
131
- expect(tracer.event_methods.to_a.map(&:to_s)).to eq([ InstanceMethod.public_instance_method(:say_default).to_s ])
253
+ expect(tracer.event_methods.to_a.map(&:class_name)).to eq([ 'InstanceMethod' ])
254
+ expect(tracer.event_methods.to_a.map(&:name)).to eq([ InstanceMethod.public_instance_method(:say_default).name ])
132
255
  end
133
256
 
134
257
  it 'builds a class map of invoked methods' do
@@ -148,10 +271,6 @@ describe 'AppMap class Hooking', docker: false do
148
271
  :type: function
149
272
  :location: spec/fixtures/hook/instance_method.rb:8
150
273
  :static: false
151
- :source: |2
152
- def say_default
153
- 'default'
154
- end
155
274
  YAML
156
275
  end
157
276
 
@@ -744,8 +863,11 @@ describe 'AppMap class Hooking', docker: false do
744
863
  _, _, events = test_hook_behavior 'spec/fixtures/hook/compare.rb', nil do
745
864
  expect(Compare.compare('string', 'string')).to be_truthy
746
865
  end
866
+
747
867
  secure_compare_event = YAML.load(events).find { |evt| evt[:defined_class] == 'ActiveSupport::SecurityUtils' }
868
+ expect(secure_compare_event).to be_truthy
748
869
  secure_compare_event.delete(:lineno)
870
+ secure_compare_event.delete(:path)
749
871
 
750
872
  expect(Diffy::Diff.new(<<~YAML, secure_compare_event.to_yaml).to_s).to eq('')
751
873
  ---
@@ -753,7 +875,6 @@ describe 'AppMap class Hooking', docker: false do
753
875
  :event: :call
754
876
  :defined_class: ActiveSupport::SecurityUtils
755
877
  :method_id: secure_compare
756
- :path: lib/active_support/security_utils.rb
757
878
  :static: true
758
879
  :parameters:
759
880
  - :name: :a
@@ -837,7 +958,7 @@ describe 'AppMap class Hooking', docker: false do
837
958
  entry = cm[1][:children][0][:children][0][:children][0]
838
959
  # Sanity check, make sure we got the right one
839
960
  expect(entry[:name]).to eq('secure_compare')
840
- expect(entry[:labels]).to eq(%w[provider.secure_compare])
961
+ expect(entry[:labels]).to eq(%w[crypto.secure_compare])
841
962
  end
842
963
  end
843
964