appmap 0.44.0 → 0.45.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -72,6 +80,19 @@ module AppMap
72
80
  event
73
81
  end
74
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
+
75
96
  # Atomically writes AppMap data to +filename+.
76
97
  def write_appmap(filename, appmap)
77
98
  require 'fileutils'
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.44.0'
6
+ VERSION = '0.45.0'
7
7
 
8
- APPMAP_FORMAT_VERSION = '1.4'
8
+ APPMAP_FORMAT_VERSION = '1.5.0'
9
9
  end
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
+
@@ -67,8 +67,8 @@ describe 'Rails' do
67
67
  expect(events).to include(
68
68
  hash_including(
69
69
  'http_server_response' => hash_including(
70
- 'status' => 201,
71
- 'mime_type' => 'application/json; charset=utf-8'
70
+ 'status_code' => 201,
71
+ 'mime_type' => 'application/json; charset=utf-8',
72
72
  )
73
73
  )
74
74
  )
@@ -155,7 +155,11 @@ describe 'Rails' do
155
155
  'http_server_request' => {
156
156
  'request_method' => 'GET',
157
157
  'path_info' => '/users/alice',
158
- 'normalized_path_info' => '/users/:id(.:format)'
158
+ 'normalized_path_info' => '/users/:id(.:format)',
159
+ 'headers' => {
160
+ 'Host' => 'test.host',
161
+ 'User-Agent' => 'Rails Testing'
162
+ }
159
163
  }
160
164
  )
161
165
  )
data/spec/config_spec.rb CHANGED
@@ -34,10 +34,12 @@ describe AppMap::Config, docker: false do
34
34
  name: 'test',
35
35
  packages: [
36
36
  {
37
- path: 'path-1'
37
+ path: 'path-1',
38
+ handler_class: 'AppMap::Handler::Function'
38
39
  },
39
40
  {
40
41
  path: 'path-2',
42
+ handler_class: 'AppMap::Handler::Function',
41
43
  exclude: [ 'exclude-1' ]
42
44
  }
43
45
  ],
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
@@ -0,0 +1,160 @@
1
+ require 'spec_helper'
2
+ require 'diffy'
3
+ require 'rack'
4
+ require 'rack/handler/webrick'
5
+
6
+ class HelloWorldApp
7
+ def call(env)
8
+ req = Rack::Request.new(env)
9
+ case req.path_info
10
+ when /hello/
11
+ [200, {"Content-Type" => "text/html"}, ["Hello World!"]]
12
+ when /goodbye/
13
+ [500, {"Content-Type" => "text/html"}, ["Goodbye Cruel World!"]]
14
+ else
15
+ [404, {"Content-Type" => "text/html"}, ["I'm Lost!"]]
16
+ end
17
+ end
18
+ end
19
+
20
+ describe 'Net::HTTP handler' do
21
+ include_context 'collect events'
22
+
23
+ def get_hello(params: nil)
24
+ http = Net::HTTP.new('localhost', 19292)
25
+ http.get [ '/hello', params ].compact.join('?')
26
+ end
27
+
28
+ before(:all) do
29
+ @rack_thread = Thread.new do
30
+ Rack::Handler::WEBrick.run HelloWorldApp.new, Port: 19292
31
+ end
32
+ 10.times do
33
+ sleep 0.1
34
+ break if get_hello.code.to_i == 200
35
+ end
36
+ raise "Web server didn't start" unless get_hello.code.to_i == 200
37
+ end
38
+
39
+ after(:all) do
40
+ @rack_thread.kill
41
+ end
42
+
43
+ def start_recording
44
+ AppMap.configuration = configuration
45
+ AppMap::Hook.new(configuration).enable
46
+
47
+ @tracer = AppMap.tracing.trace
48
+ AppMap::Event.reset_id_counter
49
+ end
50
+
51
+ def record(&block)
52
+ start_recording
53
+ begin
54
+ yield
55
+ ensure
56
+ stop_recording
57
+ end
58
+ end
59
+
60
+ def stop_recording
61
+ AppMap.tracing.delete(@tracer)
62
+ end
63
+
64
+ context 'with trace enabled' do
65
+ let(:configuration) { AppMap::Config.new('record_net_http_spec', []) }
66
+
67
+ after do
68
+ AppMap.configuration = nil
69
+ end
70
+
71
+ describe 'GET request' do
72
+ it 'with a single query parameter' do
73
+ record do
74
+ get_hello(params: 'msg=hi')
75
+ end
76
+
77
+ events = collect_events(@tracer).to_yaml
78
+ expect(Diffy::Diff.new(<<~EVENTS, events).to_s).to eq('')
79
+ ---
80
+ - :id: 1
81
+ :event: :call
82
+ :http_client_request:
83
+ :request_method: GET
84
+ :url: http://localhost:19292/hello
85
+ :headers:
86
+ Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
87
+ Accept: "*/*"
88
+ User-Agent: Ruby
89
+ Connection: close
90
+ :message:
91
+ - :name: msg
92
+ :class: String
93
+ :value: hi
94
+ - :id: 2
95
+ :event: :return
96
+ :parent_id: 1
97
+ :http_client_response:
98
+ :status_code: 200
99
+ :headers:
100
+ Content-Type: text/html
101
+ Server: WEBrick
102
+ Date: "<instanceof date>"
103
+ Content-Length: '12'
104
+ Connection: close
105
+ EVENTS
106
+ end
107
+
108
+ it 'with a multi-valued query parameter' do
109
+ record do
110
+ get_hello(params: 'ary[]=1&ary[]=2')
111
+ end
112
+
113
+ event = collect_events(@tracer).first.to_yaml
114
+ expect(Diffy::Diff.new(<<~EVENT, event).to_s).to eq('')
115
+ ---
116
+ :id: 1
117
+ :event: :call
118
+ :http_client_request:
119
+ :request_method: GET
120
+ :url: http://localhost:19292/hello
121
+ :headers:
122
+ Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
123
+ Accept: "*/*"
124
+ User-Agent: Ruby
125
+ Connection: close
126
+ :message:
127
+ - :name: ary
128
+ :class: Array
129
+ :value: '["1", "2"]'
130
+ EVENT
131
+ end
132
+
133
+ it 'with a URL encoded query parameter' do
134
+ msg = 'foo/bar?baz'
135
+ record do
136
+ get_hello(params: "msg=#{CGI.escape msg}")
137
+ end
138
+
139
+ event = collect_events(@tracer).first.to_yaml
140
+ expect(Diffy::Diff.new(<<~EVENT, event).to_s).to eq('')
141
+ ---
142
+ :id: 1
143
+ :event: :call
144
+ :http_client_request:
145
+ :request_method: GET
146
+ :url: http://localhost:19292/hello
147
+ :headers:
148
+ Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
149
+ Accept: "*/*"
150
+ User-Agent: Ruby
151
+ Connection: close
152
+ :message:
153
+ - :name: msg
154
+ :class: String
155
+ :value: #{msg}
156
+ EVENT
157
+ end
158
+ end
159
+ end
160
+ end
data/spec/spec_helper.rb CHANGED
@@ -20,3 +20,13 @@ end
20
20
  def use_existing_data?
21
21
  ENV['USE_EXISTING_DATA'] == 'true'
22
22
  end
23
+
24
+ shared_context 'collect events' do
25
+ def collect_events(tracer)
26
+ [].tap do |events|
27
+ while tracer.event?
28
+ events << tracer.next_event.to_h
29
+ end
30
+ end.map(&AppMap::Util.method(:sanitize_event))
31
+ end
32
+ 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.44.0
4
+ version: 0.45.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Gilpin
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-28 00:00:00.000000000 Z
11
+ date: 2021-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -304,7 +304,7 @@ dependencies:
304
304
  - - ">="
305
305
  - !ruby/object:Gem::Version
306
306
  version: '0'
307
- description:
307
+ description:
308
308
  email:
309
309
  - kgilpin@gmail.com
310
310
  executables: []
@@ -315,6 +315,7 @@ files:
315
315
  - ".dockerignore"
316
316
  - ".gitignore"
317
317
  - ".rbenv-gemsets"
318
+ - ".releaserc.yml"
318
319
  - ".rubocop.yml"
319
320
  - ".travis.yml"
320
321
  - CHANGELOG.md
@@ -323,6 +324,7 @@ files:
323
324
  - Gemfile
324
325
  - LICENSE.txt
325
326
  - README.md
327
+ - README_CI.md
326
328
  - Rakefile
327
329
  - appmap.gemspec
328
330
  - appmap.yml
@@ -344,6 +346,8 @@ files:
344
346
  - lib/appmap/config.rb
345
347
  - lib/appmap/cucumber.rb
346
348
  - lib/appmap/event.rb
349
+ - lib/appmap/handler/function.rb
350
+ - lib/appmap/handler/net_http.rb
347
351
  - lib/appmap/hook.rb
348
352
  - lib/appmap/hook/method.rb
349
353
  - lib/appmap/metadata.rb
@@ -377,7 +381,7 @@ files:
377
381
  - lore/public/stylesheets/style.css
378
382
  - package-lock.json
379
383
  - package.json
380
- - patch
384
+ - release.sh
381
385
  - spec/abstract_controller_base_spec.rb
382
386
  - spec/class_map_spec.rb
383
387
  - spec/config_spec.rb
@@ -547,6 +551,7 @@ files:
547
551
  - spec/open_spec.rb
548
552
  - spec/rails_spec_helper.rb
549
553
  - spec/railtie_spec.rb
554
+ - spec/record_net_http_spec.rb
550
555
  - spec/record_sql_rails_pg_spec.rb
551
556
  - spec/remote_recording_spec.rb
552
557
  - spec/spec_helper.rb
@@ -600,7 +605,7 @@ homepage: https://github.com/applandinc/appmap-ruby
600
605
  licenses:
601
606
  - MIT
602
607
  metadata: {}
603
- post_install_message:
608
+ post_install_message:
604
609
  rdoc_options: []
605
610
  require_paths:
606
611
  - lib
@@ -615,8 +620,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
615
620
  - !ruby/object:Gem::Version
616
621
  version: '0'
617
622
  requirements: []
618
- rubygems_version: 3.0.3
619
- signing_key:
623
+ rubygems_version: 3.0.8
624
+ signing_key:
620
625
  specification_version: 4
621
626
  summary: Record the operation of a Ruby program, using the AppLand 'AppMap' format.
622
627
  test_files: []
data/patch DELETED
@@ -1,1447 +0,0 @@
1
- diff --git a/.travis.yml b/.travis.yml
2
- index ab6ccca..f165339 100644
3
- --- a/.travis.yml
4
- +++ b/.travis.yml
5
- @@ -13,11 +13,26 @@ services:
6
- # necessary.
7
- before_script:
8
- - unset RAILS_ENV
9
- -
10
- +
11
- +cache:
12
- + bundler: true
13
- + directories:
14
- + - $HOME/docker
15
- +
16
- +# https://stackoverflow.com/a/41975912
17
- +before_cache:
18
- + # Save tagged docker images
19
- + - >
20
- + mkdir -p $HOME/docker && docker images -a --filter='dangling=false' --format '{{.Repository}}:{{.Tag}} {{.ID}}'
21
- + | xargs -n 2 -t sh -c 'test -e $HOME/docker/$1.tar.gz || docker save $0 | gzip -2 > $HOME/docker/$1.tar.gz'
22
- +
23
- +before_install:
24
- + # Load cached docker images
25
- + - if [[ -d $HOME/docker ]]; then ls $HOME/docker/*.tar.gz | xargs -I {file} sh -c "zcat {file} | docker load"; fi
26
- +
27
- jobs:
28
- include:
29
- - stage: test
30
- script:
31
- - mkdir tmp
32
- - bundle exec rake test
33
- -
34
- diff --git a/CHANGELOG.md b/CHANGELOG.md
35
- index e3ea210..4a25fba 100644
36
- --- a/CHANGELOG.md
37
- +++ b/CHANGELOG.md
38
- @@ -1,3 +1,12 @@
39
- +# v0.44.0
40
- +
41
- +* Support recording and labeling of indivudal functions via `functions:` section in *appmap.yml*.
42
- +* Remove deprecated `exe/appmap`.
43
- +* Add `test_status` and `exception` fields to AppMap metadata.
44
- +* Write AppMap file atomically, by writing to a temp file first and then moving it into place.
45
- +* Remove printing of `Inventory.json` file.
46
- +* Remove source code from `classMap`.
47
- +
48
- # v0.43.0
49
-
50
- * Record `name` and `class` of each entry in Hash-like parameters, messages, and return values.
51
- diff --git a/README.md b/README.md
52
- index b9e6eca..e5674d9 100644
53
- --- a/README.md
54
- +++ b/README.md
55
- @@ -110,6 +110,9 @@ name: my_project
56
- packages:
57
- - path: app/controllers
58
- - path: app/models
59
- + # Exclude sub-paths within the package path
60
- + exclude:
61
- + - concerns/accessor
62
- - path: app/jobs
63
- - path: app/helpers
64
- # Include the gems that you want to see in the dependency maps.
65
- @@ -118,15 +121,22 @@ packages:
66
- - gem: devise
67
- - gem: aws-sdk
68
- - gem: will_paginate
69
- +# Global exclusion of a class name
70
- exclude:
71
- - MyClass
72
- - MyClass#my_instance_method
73
- - MyClass.my_class_method
74
- +functions:
75
- +- packages: myapp
76
- + class: ControllerHelper
77
- + function: logged_in_user
78
- + labels: [ authentication ]
79
- ```
80
-
81
- * **name** Provides the project name (required)
82
- * **packages** A list of source code directories which should be recorded.
83
- * **exclude** A list of classes and/or methods to definitively exclude from recording.
84
- +* **functions** A list of specific functions, scoped by package and class, to record.
85
-
86
- **packages**
87
-
88
- @@ -145,6 +155,11 @@ Each entry in the `packages` list is a YAML object which has the following keys:
89
-
90
- Optional list of fully qualified class and method names. Separate class and method names with period (`.`) for class methods and hash (`#`) for instance methods.
91
-
92
- +**functions**
93
- +
94
- +Optional list of `class, function` pairs. The `package` name is used to place the function within the class map, and does not have to match
95
- +the folder or gem name. The primary use of `functions` is to apply specific labels to functions whose source code is not accessible (e.g., it's in a Gem).
96
- +For functions which are part of the application code, use `@label` or `@labels` in code comments to apply labels.
97
-
98
- # Labels
99
-
100
- @@ -344,7 +359,7 @@ Each interactive diagram links directly to the source code, and the information
101
- # AppMap Swagger
102
-
103
- [appmap_swagger](https://github.com/applandinc/appmap_swagger-ruby) is a tool to generate Swagger files from AppMap data. With `appmap_swagger`, you can add Swagger to your Ruby or Ruby on Rails project, with no need to write or modify code. Use the Swagger UI to interact with your web services API as you build it, and use diffs of Swagger to perform code review of web service changes.
104
- -
105
- +n
106
- # Uploading AppMaps
107
-
108
- [https://app.land](https://app.land) can be used to store, analyze, and share AppMaps.
109
- diff --git a/appmap.gemspec b/appmap.gemspec
110
- index 7a01cb9..8b2af31 100644
111
- --- a/appmap.gemspec
112
- +++ b/appmap.gemspec
113
- @@ -20,8 +20,6 @@ Gem::Specification.new do |spec|
114
- ")
115
- spec.extensions << "ext/appmap/extconf.rb"
116
-
117
- - spec.bindir = 'exe'
118
- - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
119
- spec.require_paths = ['lib']
120
-
121
- spec.add_dependency 'activesupport'
122
- diff --git a/exe/appmap b/exe/appmap
123
- deleted file mode 100755
124
- index c6bd228..0000000
125
- --- a/exe/appmap
126
- +++ /dev/null
127
- @@ -1,154 +0,0 @@
128
- -#!/usr/bin/env ruby
129
- -# frozen_string_literal: true
130
- -
131
- -require 'gli'
132
- -
133
- -ENV['APPMAP_INITIALIZE'] = 'false'
134
- -
135
- -require 'appmap'
136
- -require 'appmap/version'
137
- -
138
- -# AppMap CLI.
139
- -module AppMap
140
- - class App
141
- - extend GLI::App
142
- -
143
- - program_desc 'AppMap client'
144
- -
145
- - version AppMap::VERSION
146
- -
147
- - subcommand_option_handling :normal
148
- - arguments :strict
149
- - preserve_argv true
150
- -
151
- - class << self
152
- - protected
153
- -
154
- - def default_appmap_file
155
- - ENV['APPMAP_FILE'] || 'appmap.json'
156
- - end
157
- -
158
- - def output_file_flag(c, default_value: nil)
159
- - c.desc 'Name of the output file'
160
- - c.long_desc <<~DESC
161
- - Use a single dash '-' for stdout.
162
- - DESC
163
- - c.default_value default_value if default_value
164
- - c.arg_name 'filename'
165
- - c.flag %i[o output]
166
- - end
167
- - end
168
- -
169
- - desc 'AppMap configuration file name'
170
- - default_value ENV['APPMAP_CONFIG'] || 'appmap.yml'
171
- - arg_name 'filename'
172
- - flag %i[c config]
173
- -
174
- - desc 'Record the execution of a program and generate an AppMap.'
175
- - arg_name 'program'
176
- - command :record do |c|
177
- - output_file_flag(c, default_value: default_appmap_file)
178
- -
179
- - c.action do |_, _, args|
180
- - # My subcommand name
181
- - ARGV.shift
182
- -
183
- - # Consume the :output option, if provided
184
- - if %w[-o --output].find { |arg_name| ARGV[0] == arg_name.to_s }
185
- - ARGV.shift
186
- - ARGV.shift
187
- - end
188
- -
189
- - # Name of the program to execute. GLI will ensure that it's present.
190
- - program = args.shift or help_now!("'program' argument is required")
191
- -
192
- - # Also pop the program name from ARGV, because the command will use raw ARGV
193
- - # to load the extra arguments into this Ruby process.
194
- - ARGV.shift
195
- -
196
- - require 'appmap/command/record'
197
- - AppMap::Command::Record.new(@config, program).perform do |version, metadata, class_map, events|
198
- - @output_file.write JSON.generate(version: version,
199
- - metadata: metadata,
200
- - classMap: class_map,
201
- - events: events)
202
- - end
203
- - end
204
- - end
205
- -
206
- - desc 'Calculate and print statistics of scenario files.'
207
- - arg_name 'filename'
208
- - command :stats do |c|
209
- - output_file_flag(c, default_value: '-')
210
- -
211
- - c.desc 'Display format for the result (text | json)'
212
- - c.default_value 'text'
213
- - c.flag %i[f format]
214
- -
215
- - c.desc 'Maximum number of lines to display for each stat'
216
- - c.flag %i[l limit]
217
- -
218
- - c.action do |_, options, args|
219
- - require 'appmap/command/stats'
220
- -
221
- - limit = options[:limit].to_i if options[:limit]
222
- -
223
- - # Name of the file to analyze. GLI will ensure that it's present.
224
- - filenames = args
225
- - help_now!("'filename' argument is required") if filenames.empty?
226
- -
227
- - require 'appmap/algorithm/stats'
228
- - result = filenames.inject(::AppMap::Algorithm::Stats::Result.new([], [])) do |stats_result, filename|
229
- - appmap = begin
230
- - JSON.parse(File.read(filename))
231
- - rescue JSON::ParserError
232
- - STDERR.puts "#{filename} is not valid JSON : #{$!}"
233
- - nil
234
- - end
235
- - stats_result.tap do
236
- - if appmap
237
- - limit = options[:limit].to_i if options[:limit]
238
- - stats_for_file = AppMap::Command::Stats.new(appmap).perform(limit: limit)
239
- - stats_result.merge!(stats_for_file)
240
- - end
241
- - end
242
- - end
243
- -
244
- - result.sort!
245
- - result.limit!(limit) if limit
246
- -
247
- - display = case options[:format]
248
- - when 'json'
249
- - JSON.pretty_generate(result.as_json)
250
- - else
251
- - result.as_text
252
- - end
253
- - @output_file.write display
254
- - end
255
- - end
256
- -
257
- - pre do |global, _, options, _|
258
- - @config = interpret_config_option(global[:config])
259
- - @output_file = interpret_output_file_option(options[:output])
260
- -
261
- - true
262
- - end
263
- -
264
- - class << self
265
- - protected
266
- -
267
- - def interpret_config_option(fname)
268
- - AppMap.initialize fname
269
- - end
270
- -
271
- - def interpret_output_file_option(file_name)
272
- - Hash.new { |_, fname| -> { File.new(fname, 'w') } }.tap do |open_output_file|
273
- - open_output_file[nil] = -> { nil }
274
- - open_output_file['-'] = -> { $stdout }
275
- - end[file_name].call
276
- - end
277
- - end
278
- - end
279
- -end
280
- -
281
- -exit AppMap::App.run(ARGV)
282
- diff --git a/lib/appmap.rb b/lib/appmap.rb
283
- index ccf7bb5..998513c 100644
284
- --- a/lib/appmap.rb
285
- +++ b/lib/appmap.rb
286
- @@ -43,6 +43,7 @@ module AppMap
287
- # Call this function before the program code is loaded by the Ruby VM, otherwise
288
- # the load events won't be seen and the hooks won't activate.
289
- def initialize(config_file_path = 'appmap.yml')
290
- + raise "AppMap configuration file #{config_file_path} does not exist" unless ::File.exists?(config_file_path)
291
- warn "Configuring AppMap from path #{config_file_path}"
292
- Config.load_from_file(config_file_path).tap do |configuration|
293
- self.configuration = configuration
294
- @@ -50,11 +51,6 @@ module AppMap
295
- end
296
- end
297
-
298
- - # Whether to include source and comments in all class maps.
299
- - def include_source?
300
- - ENV['APPMAP_SOURCE'] == 'true'
301
- - end
302
- -
303
- # Used to start tracing, stop tracing, and record events.
304
- def tracing
305
- @tracing ||= Trace::Tracing.new
306
- @@ -88,8 +84,8 @@ module AppMap
307
- end
308
-
309
- # Builds a class map from a config and a list of Ruby methods.
310
- - def class_map(methods, options = {})
311
- - ClassMap.build_from_methods(methods, options)
312
- + def class_map(methods)
313
- + ClassMap.build_from_methods(methods)
314
- end
315
-
316
- # Returns default metadata detected from the Ruby system and from the
317
- diff --git a/lib/appmap/class_map.rb b/lib/appmap/class_map.rb
318
- index 4d19a27..0023c1c 100644
319
- --- a/lib/appmap/class_map.rb
320
- +++ b/lib/appmap/class_map.rb
321
- @@ -71,17 +71,17 @@ module AppMap
322
- end
323
-
324
- class << self
325
- - def build_from_methods(methods, options = {})
326
- + def build_from_methods(methods)
327
- root = Types::Root.new
328
- methods.each do |method|
329
- - add_function root, method, options
330
- + add_function root, method
331
- end
332
- root.children.map(&:to_h)
333
- end
334
-
335
- protected
336
-
337
- - def add_function(root, method, include_source: true)
338
- + def add_function(root, method)
339
- package = method.package
340
- static = method.static
341
-
342
- @@ -113,16 +113,13 @@ module AppMap
343
- [ method.defined_class, static ? '.' : '#', method.name ].join
344
- end
345
-
346
- - source, comment = begin
347
- - [ method.source, method.comment ]
348
- + comment = begin
349
- + method.comment
350
- rescue MethodSource::SourceNotFoundError
351
- - [ nil, nil, ]
352
- + nil
353
- end
354
-
355
- - if include_source
356
- - function_info[:source] = source unless source.blank?
357
- - function_info[:comment] = comment unless comment.blank?
358
- - end
359
- + function_info[:comment] = comment unless comment.blank?
360
-
361
- function_info[:labels] = parse_labels(comment) + (package.labels || [])
362
- object_infos << function_info
363
- diff --git a/lib/appmap/command/record.rb b/lib/appmap/command/record.rb
364
- index 5f22903..d683f63 100644
365
- --- a/lib/appmap/command/record.rb
366
- +++ b/lib/appmap/command/record.rb
367
- @@ -27,7 +27,7 @@ module AppMap
368
- event_thread.join
369
- yield AppMap::APPMAP_FORMAT_VERSION,
370
- AppMap.detect_metadata,
371
- - AppMap.class_map(tracer.event_methods, include_source: AppMap.include_source?),
372
- + AppMap.class_map(tracer.event_methods),
373
- events
374
- end
375
-
376
- diff --git a/lib/appmap/config.rb b/lib/appmap/config.rb
377
- index aa208d6..b4c8841 100644
378
- --- a/lib/appmap/config.rb
379
- +++ b/lib/appmap/config.rb
380
- @@ -49,44 +49,89 @@ module AppMap
381
- end
382
- end
383
-
384
- - Hook = Struct.new(:method_names, :package) do
385
- + Function = Struct.new(:package, :cls, :labels, :function_names) do
386
- + def to_h
387
- + {
388
- + package: package,
389
- + class: cls,
390
- + labels: labels,
391
- + functions: function_names.map(&:to_sym)
392
- + }.compact
393
- + end
394
- end
395
-
396
- - OPENSSL_PACKAGES = Package.build_from_path('openssl', package_name: 'openssl', labels: %w[security crypto])
397
- + class Hook
398
- + attr_reader :method_names, :package
399
- +
400
- + def initialize(method_names, package)
401
- + @method_names = method_names
402
- + @package = package
403
- + end
404
- +
405
- + def to_h
406
- + {
407
- + package: package.name,
408
- + method_names: method_names
409
- + }
410
- + end
411
- + end
412
- +
413
- + OPENSSL_PACKAGES = ->(labels) { Package.build_from_path('openssl', package_name: 'openssl', labels: labels) }
414
-
415
- # Methods that should always be hooked, with their containing
416
- # package and labels that should be applied to them.
417
- HOOKED_METHODS = {
418
- - 'ActiveSupport::SecurityUtils' => Hook.new(:secure_compare, Package.build_from_path('active_support', labels: %w[provider.secure_compare])),
419
- + 'ActiveSupport::SecurityUtils' => Hook.new(:secure_compare, Package.build_from_path('active_support', labels: %w[crypto.secure_compare])),
420
- 'ActionView::Renderer' => Hook.new(:render, Package.build_from_path('action_view', labels: %w[mvc.view])),
421
- - 'ActionDispatch::Cookies::CookieJar' => Hook.new(%i[[]= clear update delete recycle], Package.build_from_path('action_pack', labels: %w[provider.http.cookie])),
422
- - 'ActionDispatch::Cookies::EncryptedCookieJar' => Hook.new(%i[[]=], Package.build_from_path('action_pack', labels: %w[provider.http.cookie crypto])),
423
- - 'CanCan::ControllerAdditions' => Hook.new(%i[authorize! can? cannot?], Package.build_from_path('cancancan', labels: %w[provider.authorization])),
424
- - 'CanCan::Ability' => Hook.new(%i[authorize!], Package.build_from_path('cancancan', labels: %w[provider.authorization])),
425
- + 'ActionDispatch::Request::Session' => Hook.new(%i[destroy [] dig values []= clear update delete fetch merge], Package.build_from_path('action_pack', labels: %w[http.session])),
426
- + 'ActionDispatch::Cookies::CookieJar' => Hook.new(%i[[]= clear update delete recycle], Package.build_from_path('action_pack', labels: %w[http.cookie])),
427
- + 'ActionDispatch::Cookies::EncryptedCookieJar' => Hook.new(%i[[]=], Package.build_from_path('action_pack', labels: %w[http.cookie crypto.encrypt])),
428
- + 'CanCan::ControllerAdditions' => Hook.new(%i[authorize! can? cannot?], Package.build_from_path('cancancan', labels: %w[security.authorization])),
429
- + 'CanCan::Ability' => Hook.new(%i[authorize!], Package.build_from_path('cancancan', labels: %w[security.authorization])),
430
- + 'ActionController::Instrumentation' => [
431
- + Hook.new(%i[process_action send_file send_data redirect_to], Package.build_from_path('action_view', labels: %w[mvc.controller])),
432
- + Hook.new(%i[render], Package.build_from_path('action_view', labels: %w[mvc.view])),
433
- + ]
434
- }.freeze
435
-
436
- BUILTIN_METHODS = {
437
- - 'OpenSSL::PKey::PKey' => Hook.new(:sign, OPENSSL_PACKAGES),
438
- - 'OpenSSL::X509::Request' => Hook.new(%i[sign verify], OPENSSL_PACKAGES),
439
- - 'OpenSSL::PKCS5' => Hook.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGES),
440
- - 'OpenSSL::Cipher' => Hook.new(%i[encrypt decrypt final], OPENSSL_PACKAGES),
441
- - 'OpenSSL::X509::Certificate' => Hook.new(:sign, OPENSSL_PACKAGES),
442
- - 'Net::HTTP' => Hook.new(:request, Package.build_from_path('net/http', package_name: 'net/http', labels: %w[protocol.http io])),
443
- - 'Net::SMTP' => Hook.new(:send, Package.build_from_path('net/smtp', package_name: 'net/smtp', labels: %w[protocol.smtp protocol.email io])),
444
- - 'Net::POP3' => Hook.new(:mails, Package.build_from_path('net/pop3', package_name: 'net/pop', labels: %w[protocol.pop protocol.email io])),
445
- - 'Net::IMAP' => Hook.new(:send_command, Package.build_from_path('net/imap', package_name: 'net/imap', labels: %w[protocol.imap protocol.email io])),
446
- - 'Marshal' => Hook.new(%i[dump load], Package.build_from_path('marshal', labels: %w[format.marshal provider.serialization])),
447
- - 'Psych' => Hook.new(%i[dump dump_stream load load_stream parse parse_stream], Package.build_from_path('yaml', package_name: 'psych', labels: %w[format.yaml provider.serialization])),
448
- - 'JSON::Ext::Parser' => Hook.new(:parse, Package.build_from_path('json', package_name: 'json', labels: %w[format.json provider.serialization])),
449
- - 'JSON::Ext::Generator::State' => Hook.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json provider.serialization])),
450
- + 'OpenSSL::PKey::PKey' => Hook.new(:sign, OPENSSL_PACKAGES.(%w[crypto.pkey])),
451
- + 'OpenSSL::X509::Request' => Hook.new(%i[sign verify], OPENSSL_PACKAGES.(%w[crypto.x509])),
452
- + 'OpenSSL::PKCS5' => Hook.new(%i[pbkdf2_hmac_sha1 pbkdf2_hmac], OPENSSL_PACKAGES.(%w[crypto.pkcs5])),
453
- + 'OpenSSL::Cipher' => [
454
- + Hook.new(%i[encrypt], OPENSSL_PACKAGES.(%w[crypto.encrypt])),
455
- + Hook.new(%i[decrypt], OPENSSL_PACKAGES.(%w[crypto.decrypt]))
456
- + ],
457
- + 'ActiveSupport::Callbacks::CallbackSequence' => [
458
- + Hook.new(:invoke_before, Package.build_from_path('active_support', package_name: 'active_support', labels: %w[mvc.before_action])),
459
- + Hook.new(:invoke_after, Package.build_from_path('active_support', package_name: 'active_support', labels: %w[mvc.after_action])),
460
- + ],
461
- + 'OpenSSL::X509::Certificate' => Hook.new(:sign, OPENSSL_PACKAGES.(%w[crypto.x509])),
462
- + 'Net::HTTP' => Hook.new(:request, Package.build_from_path('net/http', package_name: 'net/http', labels: %w[protocol.http])),
463
- + 'Net::SMTP' => Hook.new(:send, Package.build_from_path('net/smtp', package_name: 'net/smtp', labels: %w[protocol.email.smtp])),
464
- + 'Net::POP3' => Hook.new(:mails, Package.build_from_path('net/pop3', package_name: 'net/pop', labels: %w[protocol.email.pop])),
465
- + 'Net::IMAP' => Hook.new(:send_command, Package.build_from_path('net/imap', package_name: 'net/imap', labels: %w[protocol.email.imap])),
466
- + 'Marshal' => Hook.new(%i[dump load], Package.build_from_path('marshal', labels: %w[format.marshal])),
467
- + 'Psych' => Hook.new(%i[dump dump_stream load load_stream parse parse_stream], Package.build_from_path('yaml', package_name: 'psych', labels: %w[format.yaml])),
468
- + 'JSON::Ext::Parser' => Hook.new(:parse, Package.build_from_path('json', package_name: 'json', labels: %w[format.json])),
469
- + 'JSON::Ext::Generator::State' => Hook.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json])),
470
- }.freeze
471
-
472
- - attr_reader :name, :packages, :exclude
473
- + attr_reader :name, :packages, :exclude, :builtin_methods
474
-
475
- - def initialize(name, packages = [], exclude = [])
476
- + def initialize(name, packages, exclude: [], functions: [])
477
- @name = name
478
- @packages = packages
479
- @exclude = exclude
480
- + @builtin_methods = BUILTIN_METHODS
481
- + @functions = functions
482
- + @hooked_methods = HOOKED_METHODS.dup
483
- + functions.each do |func|
484
- + package_options = {}
485
- + package_options[:labels] = func.labels if func.labels
486
- + @hooked_methods[func.cls] ||= []
487
- + @hooked_methods[func.cls] << Hook.new(func.function_names, Package.build_from_path(func.package, package_options))
488
- + end
489
- end
490
-
491
- class << self
492
- @@ -98,6 +143,16 @@ module AppMap
493
-
494
- # Loads configuration from a Hash.
495
- def load(config_data)
496
- + functions = (config_data['functions'] || []).map do |function_data|
497
- + package = function_data['package']
498
- + cls = function_data['class']
499
- + functions = function_data['function'] || function_data['functions']
500
- + raise 'AppMap class configuration should specify package, class and function(s)' unless package && cls && functions
501
- + functions = Array(functions).map(&:to_sym)
502
- + labels = function_data['label'] || function_data['labels']
503
- + labels = Array(labels).map(&:to_s) if labels
504
- + Function.new(package, cls, labels, functions)
505
- + end
506
- packages = (config_data['packages'] || []).map do |package|
507
- gem = package['gem']
508
- path = package['path']
509
- @@ -112,7 +167,8 @@ module AppMap
510
- Package.build_from_path(path, exclude: package['exclude'] || [], shallow: package['shallow'])
511
- end
512
- end.compact
513
- - Config.new config_data['name'], packages, config_data['exclude'] || []
514
- + exclude = config_data['exclude'] || []
515
- + Config.new config_data['name'], packages, exclude: exclude, functions: functions
516
- end
517
- end
518
-
519
- @@ -120,6 +176,7 @@ module AppMap
520
- {
521
- name: name,
522
- packages: packages.map(&:to_h),
523
- + functions: @functions.map(&:to_h),
524
- exclude: exclude
525
- }
526
- end
527
- @@ -164,14 +221,17 @@ module AppMap
528
- end
529
-
530
- def find_package(defined_class, method_name)
531
- - hook = find_hook(defined_class)
532
- - return nil unless hook
533
- + hooks = find_hooks(defined_class)
534
- + return nil unless hooks
535
-
536
- - Array(hook.method_names).include?(method_name) ? hook.package : nil
537
- + hook = Array(hooks).find do |hook|
538
- + Array(hook.method_names).include?(method_name)
539
- + end
540
- + hook ? hook.package : nil
541
- end
542
-
543
- - def find_hook(defined_class)
544
- - HOOKED_METHODS[defined_class] || BUILTIN_METHODS[defined_class]
545
- + def find_hooks(defined_class)
546
- + Array(@hooked_methods[defined_class] || @builtin_methods[defined_class])
547
- end
548
- end
549
- end
550
- diff --git a/lib/appmap/cucumber.rb b/lib/appmap/cucumber.rb
551
- index 7b59c0a..eaf4ac3 100644
552
- --- a/lib/appmap/cucumber.rb
553
- +++ b/lib/appmap/cucumber.rb
554
- @@ -50,7 +50,7 @@ module AppMap
555
- appmap['metadata'] = update_metadata(scenario, appmap['metadata'])
556
- scenario_filename = AppMap::Util.scenario_filename(appmap['metadata']['name'])
557
-
558
- - File.write(File.join(APPMAP_OUTPUT_DIR, scenario_filename), JSON.generate(appmap))
559
- + AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, scenario_filename), JSON.generate(appmap))
560
- end
561
-
562
- def enabled?
563
- diff --git a/lib/appmap/hook.rb b/lib/appmap/hook.rb
564
- index dd919d9..f141ac7 100644
565
- --- a/lib/appmap/hook.rb
566
- +++ b/lib/appmap/hook.rb
567
- @@ -32,6 +32,7 @@ module AppMap
568
- end
569
-
570
- attr_reader :config
571
- +
572
- def initialize(config)
573
- @config = config
574
- end
575
- @@ -59,6 +60,10 @@ module AppMap
576
-
577
- hook = lambda do |hook_cls|
578
- lambda do |method_id|
579
- + # Don't try and trace the AppMap methods or there will be
580
- + # a stack overflow in the defined hook method.
581
- + return if (hook_cls&.name || '').split('::')[0] == AppMap.name
582
- +
583
- method = begin
584
- hook_cls.public_instance_method(method_id)
585
- rescue NameError
586
- @@ -78,11 +83,9 @@ module AppMap
587
- config.always_hook?(hook_cls, method.name) ||
588
- config.included_by_location?(method)
589
-
590
- - hook_method = Hook::Method.new(config.package_for_method(method), hook_cls, method)
591
- + package = config.package_for_method(method)
592
-
593
- - # Don't try and trace the AppMap methods or there will be
594
- - # a stack overflow in the defined hook method.
595
- - next if /\AAppMap[:\.]/.match?(hook_method.method_display_name)
596
- + hook_method = Hook::Method.new(package, hook_cls, method)
597
-
598
- hook_method.activate
599
- end
600
- @@ -112,25 +115,27 @@ module AppMap
601
- end
602
- end
603
-
604
- - Config::BUILTIN_METHODS.each do |class_name, hook|
605
- - require hook.package.package_name if hook.package.package_name
606
- - Array(hook.method_names).each do |method_name|
607
- - method_name = method_name.to_sym
608
- + config.builtin_methods.each do |class_name, hooks|
609
- + Array(hooks).each do |hook|
610
- + require hook.package.package_name if hook.package.package_name
611
- + Array(hook.method_names).each do |method_name|
612
- + method_name = method_name.to_sym
613
-
614
- - cls = class_from_string.(class_name)
615
- - method = \
616
- - begin
617
- - cls.instance_method(method_name)
618
- - rescue NameError
619
- - cls.method(method_name) rescue nil
620
- - end
621
- + cls = class_from_string.(class_name)
622
- + method = \
623
- + begin
624
- + cls.instance_method(method_name)
625
- + rescue NameError
626
- + cls.method(method_name) rescue nil
627
- + end
628
-
629
- - next if config.never_hook?(method)
630
- + next if config.never_hook?(method)
631
-
632
- - if method
633
- - Hook::Method.new(hook.package, cls, method).activate
634
- - else
635
- - warn "Method #{method_name} not found on #{cls.name}"
636
- + if method
637
- + Hook::Method.new(hook.package, cls, method).activate
638
- + else
639
- + warn "Method #{method_name} not found on #{cls.name}"
640
- + end
641
- end
642
- end
643
- end
644
- diff --git a/lib/appmap/middleware/remote_recording.rb b/lib/appmap/middleware/remote_recording.rb
645
- index 83affc0..f695d25 100644
646
- --- a/lib/appmap/middleware/remote_recording.rb
647
- +++ b/lib/appmap/middleware/remote_recording.rb
648
- @@ -67,7 +67,7 @@ module AppMap
649
-
650
- response = JSON.generate \
651
- version: AppMap::APPMAP_FORMAT_VERSION,
652
- - classMap: AppMap.class_map(tracer.event_methods, include_source: AppMap.include_source?),
653
- + classMap: AppMap.class_map(tracer.event_methods),
654
- metadata: metadata,
655
- events: @events
656
-
657
- diff --git a/lib/appmap/minitest.rb b/lib/appmap/minitest.rb
658
- index dc88bac..cf4a4d2 100644
659
- --- a/lib/appmap/minitest.rb
660
- +++ b/lib/appmap/minitest.rb
661
- @@ -26,8 +26,9 @@ module AppMap
662
- end
663
-
664
-
665
- - def finish
666
- + def finish(exception)
667
- warn "Finishing recording of test #{test.class}.#{test.name}" if AppMap::Minitest::LOG
668
- + warn "Exception: #{exception}" if exception && AppMap::Minitest::LOG
669
-
670
- events = []
671
- AppMap.tracing.delete @trace
672
- @@ -36,15 +37,17 @@ module AppMap
673
-
674
- AppMap::Minitest.add_event_methods @trace.event_methods
675
-
676
- - class_map = AppMap.class_map(@trace.event_methods, include_source: AppMap.include_source?)
677
- + class_map = AppMap.class_map(@trace.event_methods)
678
-
679
- feature_group = test.class.name.underscore.split('_')[0...-1].join('_').capitalize
680
- feature_name = test.name.split('_')[1..-1].join(' ')
681
- scenario_name = [ feature_group, feature_name ].join(' ')
682
-
683
- - AppMap::Minitest.save scenario_name,
684
- - class_map,
685
- - source_location,
686
- + AppMap::Minitest.save name: scenario_name,
687
- + class_map: class_map,
688
- + source_location: source_location,
689
- + test_status: exception ? 'failed' : 'succeeded',
690
- + exception: exception,
691
- events: events
692
- end
693
- end
694
- @@ -63,11 +66,11 @@ module AppMap
695
- @recordings_by_test[test.object_id] = Recording.new(test, name)
696
- end
697
-
698
- - def end_test(test)
699
- + def end_test(test, exception:)
700
- recording = @recordings_by_test.delete(test.object_id)
701
- return warn "No recording found for #{test}" unless recording
702
-
703
- - recording.finish
704
- + recording.finish exception
705
- end
706
-
707
- def config
708
- @@ -78,9 +81,9 @@ module AppMap
709
- @event_methods += event_methods
710
- end
711
-
712
- - def save(example_name, class_map, source_location, events: nil, labels: nil)
713
- + def save(name:, class_map:, source_location:, test_status:, exception:, events:)
714
- metadata = AppMap::Minitest.metadata.tap do |m|
715
- - m[:name] = example_name
716
- + m[:name] = name
717
- m[:source_location] = source_location
718
- m[:app] = AppMap.configuration.name
719
- m[:frameworks] ||= []
720
- @@ -91,6 +94,13 @@ module AppMap
721
- m[:recorder] = {
722
- name: 'minitest'
723
- }
724
- + m[:test_status] = test_status
725
- + if exception
726
- + m[:exception] = {
727
- + class: exception.class.name,
728
- + message: exception.to_s
729
- + }
730
- + end
731
- end
732
-
733
- appmap = {
734
- @@ -99,14 +109,9 @@ module AppMap
735
- classMap: class_map,
736
- events: events
737
- }.compact
738
- - fname = AppMap::Util.scenario_filename(example_name)
739
- + fname = AppMap::Util.scenario_filename(name)
740
-
741
- - File.write(File.join(APPMAP_OUTPUT_DIR, fname), JSON.generate(appmap))
742
- - end
743
- -
744
- - def print_inventory
745
- - class_map = AppMap.class_map(@event_methods)
746
- - save 'Inventory', class_map, labels: %w[inventory]
747
- + AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, fname), JSON.generate(appmap))
748
- end
749
-
750
- def enabled?
751
- @@ -115,9 +120,6 @@ module AppMap
752
-
753
- def run
754
- init
755
- - at_exit do
756
- - print_inventory
757
- - end
758
- end
759
- end
760
- end
761
- @@ -135,7 +137,7 @@ if AppMap::Minitest.enabled?
762
- begin
763
- run_without_hook
764
- ensure
765
- - AppMap::Minitest.end_test self
766
- + AppMap::Minitest.end_test self, exception: $!
767
- end
768
- end
769
- end
770
- diff --git a/lib/appmap/record.rb b/lib/appmap/record.rb
771
- index f42da60..bb3ea94 100644
772
- --- a/lib/appmap/record.rb
773
- +++ b/lib/appmap/record.rb
774
- @@ -23,5 +23,5 @@ at_exit do
775
- 'classMap' => AppMap.class_map(tracer.event_methods),
776
- 'events' => events
777
- }
778
- - File.write 'appmap.json', JSON.generate(appmap)
779
- + AppMap::Util.write_appmap('appmap.json', JSON.generate(appmap))
780
- end
781
- diff --git a/lib/appmap/rspec.rb b/lib/appmap/rspec.rb
782
- index bbc3781..79c0c66 100644
783
- --- a/lib/appmap/rspec.rb
784
- +++ b/lib/appmap/rspec.rb
785
- @@ -94,8 +94,9 @@ module AppMap
786
- result
787
- end
788
-
789
- - def finish
790
- + def finish(exception)
791
- warn "Finishing recording of example #{example}" if AppMap::RSpec::LOG
792
- + warn "Exception: #{exception}" if exception && AppMap::RSpec::LOG
793
-
794
- events = []
795
- AppMap.tracing.delete @trace
796
- @@ -104,7 +105,7 @@ module AppMap
797
-
798
- AppMap::RSpec.add_event_methods @trace.event_methods
799
-
800
- - class_map = AppMap.class_map(@trace.event_methods, include_source: AppMap.include_source?)
801
- + class_map = AppMap.class_map(@trace.event_methods)
802
-
803
- description = []
804
- scope = ScopeExample.new(example)
805
- @@ -127,9 +128,11 @@ module AppMap
806
-
807
- full_description = normalize.call(description.join(' '))
808
-
809
- - AppMap::RSpec.save full_description,
810
- - class_map,
811
- - source_location,
812
- + AppMap::RSpec.save name: full_description,
813
- + class_map: class_map,
814
- + source_location: source_location,
815
- + test_status: exception ? 'failed' : 'succeeded',
816
- + exception: exception,
817
- events: events
818
- end
819
- end
820
- @@ -148,11 +151,11 @@ module AppMap
821
- @recordings_by_example[example.object_id] = Recording.new(example)
822
- end
823
-
824
- - def end_spec(example)
825
- + def end_spec(example, exception:)
826
- recording = @recordings_by_example.delete(example.object_id)
827
- return warn "No recording found for #{example}" unless recording
828
-
829
- - recording.finish
830
- + recording.finish exception
831
- end
832
-
833
- def config
834
- @@ -163,12 +166,11 @@ module AppMap
835
- @event_methods += event_methods
836
- end
837
-
838
- - def save(example_name, class_map, source_location, events: nil, labels: nil)
839
- + def save(name:, class_map:, source_location:, test_status:, exception:, events:)
840
- metadata = AppMap::RSpec.metadata.tap do |m|
841
- - m[:name] = example_name
842
- + m[:name] = name
843
- m[:source_location] = source_location
844
- m[:app] = AppMap.configuration.name
845
- - m[:labels] = labels if labels
846
- m[:frameworks] ||= []
847
- m[:frameworks] << {
848
- name: 'rspec',
849
- @@ -177,6 +179,13 @@ module AppMap
850
- m[:recorder] = {
851
- name: 'rspec'
852
- }
853
- + m[:test_status] = test_status
854
- + if exception
855
- + m[:exception] = {
856
- + class: exception.class.name,
857
- + message: exception.to_s
858
- + }
859
- + end
860
- end
861
-
862
- appmap = {
863
- @@ -185,14 +194,9 @@ module AppMap
864
- classMap: class_map,
865
- events: events
866
- }.compact
867
- - fname = AppMap::Util.scenario_filename(example_name)
868
- -
869
- - File.write(File.join(APPMAP_OUTPUT_DIR, fname), JSON.generate(appmap))
870
- - end
871
- + fname = AppMap::Util.scenario_filename(name)
872
-
873
- - def print_inventory
874
- - class_map = AppMap.class_map(@event_methods)
875
- - save 'Inventory', class_map, labels: %w[inventory]
876
- + AppMap::Util.write_appmap(File.join(APPMAP_OUTPUT_DIR, fname), JSON.generate(appmap))
877
- end
878
-
879
- def enabled?
880
- @@ -201,9 +205,6 @@ module AppMap
881
-
882
- def run
883
- init
884
- - at_exit do
885
- - print_inventory
886
- - end
887
- end
888
- end
889
- end
890
- @@ -225,7 +226,7 @@ if AppMap::RSpec.enabled?
891
- begin
892
- instance_exec(&fn)
893
- ensure
894
- - AppMap::RSpec.end_spec example
895
- + AppMap::RSpec.end_spec example, exception: $!
896
- end
897
- end
898
- end
899
- diff --git a/lib/appmap/util.rb b/lib/appmap/util.rb
900
- index 133d54a..cd08ded 100644
901
- --- a/lib/appmap/util.rb
902
- +++ b/lib/appmap/util.rb
903
- @@ -71,6 +71,22 @@ module AppMap
904
-
905
- event
906
- end
907
- +
908
- + # Atomically writes AppMap data to +filename+.
909
- + def write_appmap(filename, appmap)
910
- + require 'fileutils'
911
- + require 'tmpdir'
912
- +
913
- + # This is what Ruby Tempfile does; but we don't want the file to be unlinked.
914
- + mode = File::RDWR | File::CREAT | File::EXCL
915
- + ::Dir::Tmpname.create([ 'appmap_', '.json' ]) do |tmpname|
916
- + tempfile = File.open(tmpname, mode)
917
- + tempfile.write(appmap)
918
- + tempfile.close
919
- + # Atomically move the tempfile into place.
920
- + FileUtils.mv tempfile.path, filename
921
- + end
922
- + end
923
- end
924
- end
925
- end
926
- diff --git a/lib/appmap/version.rb b/lib/appmap/version.rb
927
- index ff7d53b..8471d09 100644
928
- --- a/lib/appmap/version.rb
929
- +++ b/lib/appmap/version.rb
930
- @@ -3,7 +3,7 @@
931
- module AppMap
932
- URL = 'https://github.com/applandinc/appmap-ruby'
933
-
934
- - VERSION = '0.43.0'
935
- + VERSION = '0.44.0'
936
-
937
- APPMAP_FORMAT_VERSION = '1.4'
938
- end
939
- diff --git a/spec/abstract_controller_base_spec.rb b/spec/abstract_controller_base_spec.rb
940
- index 26e58b1..2aed976 100644
941
- --- a/spec/abstract_controller_base_spec.rb
942
- +++ b/spec/abstract_controller_base_spec.rb
943
- @@ -27,6 +27,8 @@ describe 'Rails' do
944
- end
945
-
946
- let(:appmap) { JSON.parse File.read File.join tmpdir, 'appmap/rspec', appmap_json_file }
947
- + let(:appmap_json_path) { File.join(tmpdir, 'appmap/rspec', appmap_json_file) }
948
- + let(:appmap) { JSON.parse File.read(appmap_json_path) }
949
- let(:events) { appmap['events'] }
950
-
951
- describe 'an API route' do
952
- @@ -35,10 +37,6 @@ describe 'Rails' do
953
- 'Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json'
954
- end
955
-
956
- - it 'inventory file is printed' do
957
- - expect(File).to exist(File.join(tmpdir, 'appmap/rspec/Inventory.appmap.json'))
958
- - end
959
- -
960
- it 'http_server_request is recorded in the appmap' do
961
- expect(events).to include(
962
- hash_including(
963
- diff --git a/spec/class_map_spec.rb b/spec/class_map_spec.rb
964
- index 343c8b9..4f60708 100644
965
- --- a/spec/class_map_spec.rb
966
- +++ b/spec/class_map_spec.rb
967
- @@ -4,18 +4,10 @@ require 'spec_helper'
968
-
969
- describe 'AppMap::ClassMap' do
970
- describe '.build_from_methods' do
971
- - it 'includes source code if available' do
972
- - map = AppMap.class_map([scoped_method(method(:test_method))])
973
- + it 'includes method comment' do
974
- + map = AppMap.class_map([scoped_method((method :test_method))])
975
- function = dig_map(map, 5)[0]
976
- - expect(function[:source]).to include 'test method body'
977
- - expect(function[:comment]).to include 'test method comment'
978
- - end
979
- -
980
- - it 'can omit source code even if available' do
981
- - map = AppMap.class_map([scoped_method((method :test_method))], include_source: false)
982
- - function = dig_map(map, 5)[0]
983
- - expect(function).to_not include(:source)
984
- - expect(function).to_not include(:comment)
985
- + expect(function).to include(:comment)
986
- end
987
-
988
- # test method comment
989
- diff --git a/spec/config_spec.rb b/spec/config_spec.rb
990
- index 5eeaac6..6657f1a 100644
991
- --- a/spec/config_spec.rb
992
- +++ b/spec/config_spec.rb
993
- @@ -17,10 +17,40 @@ describe AppMap::Config, docker: false do
994
- path: 'path-2',
995
- exclude: [ 'exclude-1' ]
996
- }
997
- + ],
998
- + functions: [
999
- + {
1000
- + package: 'pkg',
1001
- + class: 'cls',
1002
- + function: 'fn',
1003
- + label: 'lbl'
1004
- + }
1005
- ]
1006
- }.deep_stringify_keys!
1007
- config = AppMap::Config.load(config_data)
1008
-
1009
- - expect(config.to_h.deep_stringify_keys!).to eq(config_data)
1010
- + config_expectation = {
1011
- + exclude: [],
1012
- + name: 'test',
1013
- + packages: [
1014
- + {
1015
- + path: 'path-1'
1016
- + },
1017
- + {
1018
- + path: 'path-2',
1019
- + exclude: [ 'exclude-1' ]
1020
- + }
1021
- + ],
1022
- + functions: [
1023
- + {
1024
- + package: 'pkg',
1025
- + class: 'cls',
1026
- + functions: [ :fn ],
1027
- + labels: ['lbl']
1028
- + }
1029
- + ]
1030
- + }.deep_stringify_keys!
1031
- +
1032
- + expect(config.to_h.deep_stringify_keys!).to eq(config_expectation)
1033
- end
1034
- end
1035
- diff --git a/spec/fixtures/hook/custom_instance_method.rb b/spec/fixtures/hook/custom_instance_method.rb
1036
- new file mode 100644
1037
- index 0000000..285db81
1038
- --- /dev/null
1039
- +++ b/spec/fixtures/hook/custom_instance_method.rb
1040
- @@ -0,0 +1,11 @@
1041
- +# frozen_string_literal: true
1042
- +
1043
- +class CustomInstanceMethod
1044
- + def to_s
1045
- + 'CustomInstance Method fixture'
1046
- + end
1047
- +
1048
- + def say_default
1049
- + 'default'
1050
- + end
1051
- +end
1052
- diff --git a/spec/fixtures/hook/method_named_call.rb b/spec/fixtures/hook/method_named_call.rb
1053
- new file mode 100644
1054
- index 0000000..69a2cc5
1055
- --- /dev/null
1056
- +++ b/spec/fixtures/hook/method_named_call.rb
1057
- @@ -0,0 +1,11 @@
1058
- +# frozen_string_literal: true
1059
- +
1060
- +class MethodNamedCall
1061
- + def to_s
1062
- + 'MethodNamedCall'
1063
- + end
1064
- +
1065
- + def call(a, b, c, d, e)
1066
- + [ a, b, c, d, e ].join(' ')
1067
- + end
1068
- +end
1069
- diff --git a/spec/hook_spec.rb b/spec/hook_spec.rb
1070
- index e4cbc99..8afb9f1 100644
1071
- --- a/spec/hook_spec.rb
1072
- +++ b/spec/hook_spec.rb
1073
- @@ -64,13 +64,144 @@ describe 'AppMap class Hooking', docker: false do
1074
- it 'excludes named classes and methods' do
1075
- load 'spec/fixtures/hook/exclude.rb'
1076
- package = AppMap::Config::Package.build_from_path('spec/fixtures/hook/exclude.rb')
1077
- - config = AppMap::Config.new('hook_spec', [ package ], %w[ExcludeTest])
1078
- + config = AppMap::Config.new('hook_spec', [ package ], exclude: %w[ExcludeTest])
1079
- AppMap.configuration = config
1080
-
1081
- expect(config.never_hook?(ExcludeTest.new.method(:instance_method))).to be_truthy
1082
- expect(config.never_hook?(ExcludeTest.method(:cls_method))).to be_truthy
1083
- end
1084
-
1085
- + it "handles an instance method named 'call' without issues" do
1086
- + events_yaml = <<~YAML
1087
- + ---
1088
- + - :id: 1
1089
- + :event: :call
1090
- + :defined_class: MethodNamedCall
1091
- + :method_id: call
1092
- + :path: spec/fixtures/hook/method_named_call.rb
1093
- + :lineno: 8
1094
- + :static: false
1095
- + :parameters:
1096
- + - :name: :a
1097
- + :class: Integer
1098
- + :value: '1'
1099
- + :kind: :req
1100
- + - :name: :b
1101
- + :class: Integer
1102
- + :value: '2'
1103
- + :kind: :req
1104
- + - :name: :c
1105
- + :class: Integer
1106
- + :value: '3'
1107
- + :kind: :req
1108
- + - :name: :d
1109
- + :class: Integer
1110
- + :value: '4'
1111
- + :kind: :req
1112
- + - :name: :e
1113
- + :class: Integer
1114
- + :value: '5'
1115
- + :kind: :req
1116
- + :receiver:
1117
- + :class: MethodNamedCall
1118
- + :value: MethodNamedCall
1119
- + - :id: 2
1120
- + :event: :return
1121
- + :parent_id: 1
1122
- + :return_value:
1123
- + :class: String
1124
- + :value: 1 2 3 4 5
1125
- + YAML
1126
- +
1127
- + _, tracer = test_hook_behavior 'spec/fixtures/hook/method_named_call.rb', events_yaml do
1128
- + expect(MethodNamedCall.new.call(1, 2, 3, 4, 5)).to eq('1 2 3 4 5')
1129
- + end
1130
- + class_map = AppMap.class_map(tracer.event_methods)
1131
- + expect(Diffy::Diff.new(<<~CLASSMAP, YAML.dump(class_map)).to_s).to eq('')
1132
- + ---
1133
- + - :name: spec/fixtures/hook/method_named_call.rb
1134
- + :type: package
1135
- + :children:
1136
- + - :name: MethodNamedCall
1137
- + :type: class
1138
- + :children:
1139
- + - :name: call
1140
- + :type: function
1141
- + :location: spec/fixtures/hook/method_named_call.rb:8
1142
- + :static: false
1143
- + CLASSMAP
1144
- + end
1145
- +
1146
- + it 'can custom hook and label a function' do
1147
- + events_yaml = <<~YAML
1148
- + ---
1149
- + - :id: 1
1150
- + :event: :call
1151
- + :defined_class: CustomInstanceMethod
1152
- + :method_id: say_default
1153
- + :path: spec/fixtures/hook/custom_instance_method.rb
1154
- + :lineno: 8
1155
- + :static: false
1156
- + :parameters: []
1157
- + :receiver:
1158
- + :class: CustomInstanceMethod
1159
- + :value: CustomInstance Method fixture
1160
- + - :id: 2
1161
- + :event: :return
1162
- + :parent_id: 1
1163
- + :return_value:
1164
- + :class: String
1165
- + :value: default
1166
- + YAML
1167
- +
1168
- + config = AppMap::Config.load({
1169
- + functions: [
1170
- + {
1171
- + package: 'hook_spec',
1172
- + class: 'CustomInstanceMethod',
1173
- + functions: [ :say_default ],
1174
- + labels: ['cowsay']
1175
- + }
1176
- + ]
1177
- + }.deep_stringify_keys)
1178
- +
1179
- + load 'spec/fixtures/hook/custom_instance_method.rb'
1180
- + hook_cls = CustomInstanceMethod
1181
- + method = hook_cls.instance_method(:say_default)
1182
- +
1183
- + require 'appmap/hook/method'
1184
- + hook_method = AppMap::Hook::Method.new(config.package_for_method(method), hook_cls, method)
1185
- + hook_method.activate
1186
- +
1187
- + tracer = AppMap.tracing.trace
1188
- + AppMap::Event.reset_id_counter
1189
- + begin
1190
- + expect(CustomInstanceMethod.new.say_default).to eq('default')
1191
- + ensure
1192
- + AppMap.tracing.delete(tracer)
1193
- + end
1194
- +
1195
- + events = collect_events(tracer).to_yaml
1196
- +
1197
- + expect(Diffy::Diff.new(events_yaml, events).to_s).to eq('')
1198
- + class_map = AppMap.class_map(tracer.event_methods)
1199
- + expect(Diffy::Diff.new(<<~CLASSMAP, YAML.dump(class_map)).to_s).to eq('')
1200
- + ---
1201
- + - :name: hook_spec
1202
- + :type: package
1203
- + :children:
1204
- + - :name: CustomInstanceMethod
1205
- + :type: class
1206
- + :children:
1207
- + - :name: say_default
1208
- + :type: function
1209
- + :location: spec/fixtures/hook/custom_instance_method.rb:8
1210
- + :static: false
1211
- + :labels:
1212
- + - cowsay
1213
- + CLASSMAP
1214
- + end
1215
- +
1216
- it 'parses labels from comments' do
1217
- _, tracer = invoke_test_file 'spec/fixtures/hook/labels.rb' do
1218
- ClassWithLabel.new.fn_with_label
1219
- @@ -91,9 +222,6 @@ describe 'AppMap class Hooking', docker: false do
1220
- :labels:
1221
- - has-fn-label
1222
- :comment: "# @label has-fn-label\\n"
1223
- - :source: |2
1224
- - def fn_with_label
1225
- - end
1226
- YAML
1227
- end
1228
-
1229
- @@ -148,10 +276,6 @@ describe 'AppMap class Hooking', docker: false do
1230
- :type: function
1231
- :location: spec/fixtures/hook/instance_method.rb:8
1232
- :static: false
1233
- - :source: |2
1234
- - def say_default
1235
- - 'default'
1236
- - end
1237
- YAML
1238
- end
1239
-
1240
- @@ -746,6 +870,7 @@ describe 'AppMap class Hooking', docker: false do
1241
- end
1242
- secure_compare_event = YAML.load(events).find { |evt| evt[:defined_class] == 'ActiveSupport::SecurityUtils' }
1243
- secure_compare_event.delete(:lineno)
1244
- + secure_compare_event.delete(:path)
1245
-
1246
- expect(Diffy::Diff.new(<<~YAML, secure_compare_event.to_yaml).to_s).to eq('')
1247
- ---
1248
- @@ -753,7 +878,6 @@ describe 'AppMap class Hooking', docker: false do
1249
- :event: :call
1250
- :defined_class: ActiveSupport::SecurityUtils
1251
- :method_id: secure_compare
1252
- - :path: lib/active_support/security_utils.rb
1253
- :static: true
1254
- :parameters:
1255
- - :name: :a
1256
- @@ -837,7 +961,7 @@ describe 'AppMap class Hooking', docker: false do
1257
- entry = cm[1][:children][0][:children][0][:children][0]
1258
- # Sanity check, make sure we got the right one
1259
- expect(entry[:name]).to eq('secure_compare')
1260
- - expect(entry[:labels]).to eq(%w[provider.secure_compare])
1261
- + expect(entry[:labels]).to eq(%w[crypto.secure_compare])
1262
- end
1263
- end
1264
-
1265
- diff --git a/test/cli_test.rb b/test/cli_test.rb
1266
- deleted file mode 100755
1267
- index 2ea654c..0000000
1268
- --- a/test/cli_test.rb
1269
- +++ /dev/null
1270
- @@ -1,116 +0,0 @@
1271
- -#!/usr/bin/env ruby
1272
- -# frozen_string_literal: true
1273
- -
1274
- -require 'test_helper'
1275
- -require 'English'
1276
- -
1277
- -class CLITest < Minitest::Test
1278
- - OUTPUT_FILENAME = File.expand_path('../tmp/appmap.json', __dir__)
1279
- - STATS_OUTPUT_FILENAME = File.expand_path('../tmp/stats.txt', __dir__)
1280
- -
1281
- - def setup
1282
- - FileUtils.rm_f OUTPUT_FILENAME
1283
- - FileUtils.rm_f STATS_OUTPUT_FILENAME
1284
- - end
1285
- -
1286
- - def test_record
1287
- - output = Dir.chdir 'test/fixtures/cli_record_test' do
1288
- - `#{File.expand_path '../exe/appmap', __dir__} record -o #{OUTPUT_FILENAME} ./lib/cli_record_test/main.rb`.strip
1289
- - end
1290
- -
1291
- - assert_equal 0, $CHILD_STATUS.exitstatus
1292
- - assert File.file?(OUTPUT_FILENAME), "#{OUTPUT_FILENAME} does not exist"
1293
- - assert_equal 'Hello', output
1294
- - output = JSON.parse(File.read(OUTPUT_FILENAME))
1295
- - assert output['classMap'], 'Output should contain classMap'
1296
- - assert output['events'], 'Output should contain events'
1297
- - end
1298
- -
1299
- - def test_stats_to_file
1300
- - Dir.chdir 'test/fixtures/cli_record_test' do
1301
- - `#{File.expand_path '../exe/appmap', __dir__} record -o #{OUTPUT_FILENAME} ./lib/cli_record_test/main.rb`.strip
1302
- - end
1303
- - assert_equal 0, $CHILD_STATUS.exitstatus
1304
- -
1305
- - output = Dir.chdir 'test/fixtures/cli_record_test' do
1306
- - `#{File.expand_path '../exe/appmap', __dir__} stats -o #{STATS_OUTPUT_FILENAME} #{OUTPUT_FILENAME}`.strip
1307
- - end
1308
- - assert_equal 0, $CHILD_STATUS.exitstatus
1309
- - assert_equal '', output
1310
- - assert File.file?(OUTPUT_FILENAME), "#{OUTPUT_FILENAME} does not exist"
1311
- - end
1312
- -
1313
- -
1314
- - def test_stats_text
1315
- - Dir.chdir 'test/fixtures/cli_record_test' do
1316
- - `#{File.expand_path '../exe/appmap', __dir__} record -o #{OUTPUT_FILENAME} ./lib/cli_record_test/main.rb`.strip
1317
- - end
1318
- - assert_equal 0, $CHILD_STATUS.exitstatus
1319
- -
1320
- - output = Dir.chdir 'test/fixtures/cli_record_test' do
1321
- - `#{File.expand_path '../exe/appmap', __dir__} stats -o - #{OUTPUT_FILENAME}`.strip
1322
- - end
1323
- -
1324
- - assert_equal 0, $CHILD_STATUS.exitstatus
1325
- - assert_equal <<~OUTPUT.strip, output.strip
1326
- - Class frequency:
1327
- - ----------------
1328
- - 1 Main
1329
- -
1330
- - Method frequency:
1331
- - ----------------
1332
- - 1 Main.say_hello
1333
- - OUTPUT
1334
- - end
1335
- -
1336
- - def test_stats_json
1337
- - Dir.chdir 'test/fixtures/cli_record_test' do
1338
- - `#{File.expand_path '../exe/appmap', __dir__} record -o #{OUTPUT_FILENAME} ./lib/cli_record_test/main.rb`.strip
1339
- - end
1340
- - assert_equal 0, $CHILD_STATUS.exitstatus
1341
- -
1342
- - output = Dir.chdir 'test/fixtures/cli_record_test' do
1343
- - `#{File.expand_path '../exe/appmap', __dir__} stats -f json -o - #{OUTPUT_FILENAME}`.strip
1344
- - end
1345
- -
1346
- - assert_equal 0, $CHILD_STATUS.exitstatus
1347
- - assert_equal <<~OUTPUT.strip, output.strip
1348
- - {
1349
- - "class_frequency": [
1350
- - {
1351
- - "name": "Main",
1352
- - "count": 1
1353
- - }
1354
- - ],
1355
- - "method_frequency": [
1356
- - {
1357
- - "name": "Main.say_hello",
1358
- - "count": 1
1359
- - }
1360
- - ]
1361
- - }
1362
- - OUTPUT
1363
- - end
1364
- -
1365
- - def test_record_to_default_location
1366
- - Dir.chdir 'test/fixtures/cli_record_test' do
1367
- - system({ 'APPMAP_FILE' => OUTPUT_FILENAME }, "#{File.expand_path '../exe/appmap', __dir__} record ./lib/cli_record_test/main.rb")
1368
- - end
1369
- -
1370
- - assert_equal 0, $CHILD_STATUS.exitstatus
1371
- - assert File.file?(OUTPUT_FILENAME), 'appmap.json does not exist'
1372
- - end
1373
- -
1374
- - def test_record_to_stdout
1375
- - output = Dir.chdir 'test/fixtures/cli_record_test' do
1376
- - `#{File.expand_path '../exe/appmap', __dir__} record -o - ./lib/cli_record_test/main.rb`
1377
- - end
1378
- -
1379
- - assert_equal 0, $CHILD_STATUS.exitstatus
1380
- - # Event path
1381
- - assert_includes output, %("path":"lib/cli_record_test/main.rb")
1382
- - # Function location
1383
- - assert_includes output, %("location":"lib/cli_record_test/main.rb:3")
1384
- - assert !File.file?(OUTPUT_FILENAME), "#{OUTPUT_FILENAME} should not exist"
1385
- - end
1386
- -end
1387
- diff --git a/test/expectations/openssl_test_key_sign1.json b/test/expectations/openssl_test_key_sign1.json
1388
- index 6489b47..0613a69 100644
1389
- --- a/test/expectations/openssl_test_key_sign1.json
1390
- +++ b/test/expectations/openssl_test_key_sign1.json
1391
- @@ -11,8 +11,7 @@
1392
- "name": "sign",
1393
- "type": "function",
1394
- "location": "lib/openssl_key_sign.rb:10",
1395
- - "static": true,
1396
- - "source": " def Example.sign\n key = OpenSSL::PKey::RSA.new 2048\n\n document = 'the document'\n\n digest = OpenSSL::Digest::SHA256.new\n key.sign digest, document\n end\n"
1397
- + "static": true
1398
- }
1399
- ]
1400
- }
1401
- @@ -40,8 +39,7 @@
1402
- "location": "OpenSSL::PKey::PKey#sign",
1403
- "static": false,
1404
- "labels": [
1405
- - "security",
1406
- - "crypto"
1407
- + "crypto.pkey"
1408
- ]
1409
- }
1410
- ]
1411
- diff --git a/test/gem_test.rb b/test/gem_test.rb
1412
- index 6cae910..1342c2a 100644
1413
- --- a/test/gem_test.rb
1414
- +++ b/test/gem_test.rb
1415
- @@ -26,7 +26,7 @@ class MinitestTest < Minitest::Test
1416
- assert_equal 2, events.size
1417
- assert_equal 'call', events.first['event']
1418
- assert_equal 'default_parser', events.first['method_id']
1419
- - assert_equal "#{Gem.loaded_specs['parser'].gem_dir}/lib/parser/base.rb", events.first['path']
1420
- + assert_match /\lib\/parser\/base\.rb$/, events.first['path']
1421
- assert_equal 'return', events.second['event']
1422
- assert_equal 1, events.second['parent_id']
1423
- end
1424
- diff --git a/test/rspec_test.rb b/test/rspec_test.rb
1425
- index 72ed029..b30618b 100644
1426
- --- a/test/rspec_test.rb
1427
- +++ b/test/rspec_test.rb
1428
- @@ -18,19 +18,6 @@ class RSpecTest < Minitest::Test
1429
- end
1430
- end
1431
-
1432
- - def test_inventory
1433
- - perform_test 'plain_hello_spec' do
1434
- - appmap_file = 'tmp/appmap/rspec/Inventory.appmap.json'
1435
- -
1436
- - assert File.file?(appmap_file), 'appmap output file does not exist'
1437
- - appmap = JSON.parse(File.read(appmap_file))
1438
- - assert_equal AppMap::APPMAP_FORMAT_VERSION, appmap['version']
1439
- - assert_includes appmap.keys, 'metadata'
1440
- - metadata = appmap['metadata']
1441
- - assert_equal 'Inventory', metadata['name']
1442
- - end
1443
- - end
1444
- -
1445
- def test_record_decorated_rspec
1446
- perform_test 'decorated_hello_spec' do
1447
- appmap_file = 'tmp/appmap/rspec/Hello_says_hello.appmap.json'