appmap 0.65.1 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30c93c7dbd38cd355d2512f43d177243bba4c184e81c588bf2f99e3b7d2426f4
4
- data.tar.gz: 3dd70314c48d4df781dcda082fb293260d04725228e66c4c3323ebdcb09ea35a
3
+ metadata.gz: 4209d3f9422b61ba07ca1776597eac220374e8308a303cdf001604c90903dd31
4
+ data.tar.gz: 55a755af5bd85255ce882633d3089a0ca308d137b15945e0a1fff4d5479c4994
5
5
  SHA512:
6
- metadata.gz: bea8dc7d3e1f05cca6ae264b7b0cf8ab6cdddfd366c59f09131c9c98cd12989e2878f276fc01360166ccee6c16b040b6ecd3aa8c6e913407bbd93d4bb1928862
7
- data.tar.gz: 5a798b37f59f39f70e69398e0d64353f66baf4b55000b45dc951be27830b04f36d17c2fe58bc4f5e86fdab368c056b90834c15a21f438535f8403ec437758d8d
6
+ metadata.gz: 4a7ce04424eac8292b0457c99bc3b6f699c0e80a6222450e52f37071e078c2c574c33e8a89249c584412c50da5b26d07f98864f50ecc13e0318da6272fafb879
7
+ data.tar.gz: 6c8ba9b9a67f09ce662d1bdf0569238537087709cff6f9be2562d50fe06d8ca4199268a2bc3c0d9136dd8a6ab6ff0e66f0d85683b4d3c15e95ba5e10dbcdeb71
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
+ dist: bionic
2
3
 
3
4
  rbenv:
4
5
  - 2.6
@@ -15,6 +16,7 @@ services:
15
16
  - docker
16
17
 
17
18
  before_install:
19
+ - sudo apt-get update && sudo apt-get install apt-transport-https ca-certificates -y && sudo update-ca-certificates
18
20
  # see https://blog.travis-ci.com/docker-rate-limits
19
21
  # and also https://www.docker.com/blog/what-you-need-to-know-about-upcoming-docker-hub-rate-limiting/
20
22
  # if we do not use authorized account,
data/CHANGELOG.md CHANGED
@@ -1,3 +1,43 @@
1
+ # [0.67.0](https://github.com/applandinc/appmap-ruby/compare/v0.66.2...v0.67.0) (2021-10-21)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Ensure rack is available, and handle nil HTTP response ([5e81dc4](https://github.com/applandinc/appmap-ruby/commit/5e81dc4310c9b7f2d81c31339f8490639c845f76))
7
+ * Handle WeakRef ([852ee04](https://github.com/applandinc/appmap-ruby/commit/852ee047880f9d1492be38772ed3f0cc1a670cb5))
8
+
9
+
10
+ ### Features
11
+
12
+ * APPMAP_AUTOREQUIRE and APPMAP_INITIALIZE env vars to customize loading behavior ([369807e](https://github.com/applandinc/appmap-ruby/commit/369807e4c90243e296b324e70805bd09d0f5fc4a))
13
+ * Perform GC before running each test ([84c895e](https://github.com/applandinc/appmap-ruby/commit/84c895e95fe8caa270cc1412e239599bfcc1b467))
14
+
15
+ ## [0.66.2](https://github.com/applandinc/appmap-ruby/compare/v0.66.1...v0.66.2) (2021-10-07)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * fix Travis for Ruby 3.0 ([8ec7359](https://github.com/applandinc/appmap-ruby/commit/8ec7359287f5b204ae9fb0724d8b683adfb79df5))
21
+ * Fix warning of circular import ([84d456d](https://github.com/applandinc/appmap-ruby/commit/84d456d8ac26ef3fc7a81ca6517e4363aac9916d))
22
+ * Properly handle headers which aren't mangled by Rack ([8e78e13](https://github.com/applandinc/appmap-ruby/commit/8e78e138776cb563f984e3592cf5024af16da2b7))
23
+ * replace deprecated File.exists? method ([80ce5b5](https://github.com/applandinc/appmap-ruby/commit/80ce5b59fd010a806ca6320365f453f1e74f095d))
24
+ * Validate presence package configuration ([f478d6b](https://github.com/applandinc/appmap-ruby/commit/f478d6b60a786608c21217755cec9a8185e084d3))
25
+
26
+ ## [0.66.1](https://github.com/applandinc/appmap-ruby/compare/v0.66.0...v0.66.1) (2021-09-29)
27
+
28
+
29
+ ### Bug Fixes
30
+
31
+ * Fix compilation on macOS with Xcode 13 ([8c66e08](https://github.com/applandinc/appmap-ruby/commit/8c66e08393bf8d9efac9635ad7a150329797729d))
32
+
33
+ # [0.66.0](https://github.com/applandinc/appmap-ruby/compare/v0.65.1...v0.66.0) (2021-09-28)
34
+
35
+
36
+ ### Features
37
+
38
+ * Add option for explicit 'require' in function config ([1cf6c2a](https://github.com/applandinc/appmap-ruby/commit/1cf6c2aed8ee2d89c900f2959484b88b6fd3eb93))
39
+ * Builtin code such as Ruby Logger can be hooked via appmap.yml ([779c9e5](https://github.com/applandinc/appmap-ruby/commit/779c9e5e4177d58ea7b63e663e7c5a0810a78c60))
40
+
1
41
  ## [0.65.1](https://github.com/applandinc/appmap-ruby/compare/v0.65.0...v0.65.1) (2021-09-16)
2
42
 
3
43
 
@@ -1,6 +1,17 @@
1
1
  require "mkmf"
2
2
 
3
+
3
4
  $CFLAGS='-Werror'
5
+
6
+ # Per https://bugs.ruby-lang.org/issues/17865,
7
+ # compound-token-split-by-macro was added in clang 12 and broke
8
+ # compilation with some of the ruby headers. If the current compiler
9
+ # supports the new warning, turn it off.
10
+ new_warning = '-Wno-error=compound-token-split-by-macro'
11
+ if try_cflags(new_warning)
12
+ $CFLAGS += ' ' + new_warning
13
+ end
14
+
4
15
  extension_name = "appmap"
5
16
  dir_config(extension_name)
6
17
  create_makefile(File.join(extension_name, extension_name))
data/lib/appmap/config.rb CHANGED
@@ -117,13 +117,15 @@ module AppMap
117
117
  # entry in appmap.yml. When the Config is initialized, each Function is converted into
118
118
  # a Package and TargetMethods. It's called a Function rather than a Method, because Function
119
119
  # is the AppMap terminology.
120
- Function = Struct.new(:package, :cls, :labels, :function_names) do # :nodoc:
120
+ Function = Struct.new(:package, :cls, :labels, :function_names, :builtin, :package_name) do # :nodoc:
121
121
  def to_h
122
122
  {
123
123
  package: package,
124
+ package_name: package_name,
124
125
  class: cls,
125
126
  labels: labels,
126
- functions: function_names.map(&:to_sym)
127
+ functions: function_names.map(&:to_sym),
128
+ builtin: builtin
127
129
  }.compact
128
130
  end
129
131
  end
@@ -174,8 +176,8 @@ module AppMap
174
176
  package_hooks('actionpack',
175
177
  [
176
178
  method_hook('ActionDispatch::Request::Session', %i[[] dig values fetch], %w[http.session.read]),
177
- method_hook('ActionDispatch::Request::Session', %i[destroy[]= clear update delete merge], %w[http.session.write]),
178
- method_hook('ActionDispatch::Cookies::CookieJar', %i[[]= clear update delete recycle], %w[http.session.read]),
179
+ method_hook('ActionDispatch::Request::Session', %i[destroy []= clear update delete merge], %w[http.session.write]),
180
+ method_hook('ActionDispatch::Cookies::CookieJar', %i[[] fetch], %w[http.session.read]),
179
181
  method_hook('ActionDispatch::Cookies::CookieJar', %i[[]= clear update delete recycle], %w[http.session.write]),
180
182
  method_hook('ActionDispatch::Cookies::EncryptedCookieJar', %i[[]= clear update delete recycle], %w[http.cookie crypto.encrypt])
181
183
  ],
@@ -244,7 +246,7 @@ module AppMap
244
246
  @depends_config = depends_config
245
247
  @hook_paths = Set.new(packages.map(&:path))
246
248
  @exclude = exclude
247
- @builtin_hooks = BUILTIN_HOOKS
249
+ @builtin_hooks = BUILTIN_HOOKS.dup
248
250
  @functions = functions
249
251
 
250
252
  @hooked_methods = METHOD_HOOKS.each_with_object(Hash.new { |h,k| h[k] = [] }) do |cls_target_methods, hooked_methods|
@@ -254,7 +256,15 @@ module AppMap
254
256
  functions.each do |func|
255
257
  package_options = {}
256
258
  package_options[:labels] = func.labels if func.labels
257
- @hooked_methods[func.cls] << TargetMethods.new(func.function_names, Package.build_from_path(func.package, **package_options))
259
+ package_options[:package_name] = func.package_name
260
+ package_options[:package_name] ||= func.package if func.builtin
261
+ hook = TargetMethods.new(func.function_names, Package.build_from_path(func.package, **package_options))
262
+ if func.builtin
263
+ @builtin_hooks[func.cls] ||= []
264
+ @builtin_hooks[func.cls] << hook
265
+ else
266
+ @hooked_methods[func.cls] << hook
267
+ end
258
268
  end
259
269
 
260
270
  @hooked_methods.each_value do |hooks|
@@ -277,7 +287,7 @@ module AppMap
277
287
  LOGO
278
288
  end
279
289
 
280
- config_present = true if File.exists?(config_file_name)
290
+ config_present = true if File.exist?(config_file_name)
281
291
 
282
292
  config_data = if config_present
283
293
  YAML.safe_load(::File.read(config_file_name))
@@ -300,6 +310,7 @@ module AppMap
300
310
  MISSING_FILE_MSG
301
311
  {}
302
312
  end
313
+
303
314
  load(config_data).tap do |config|
304
315
  config_yaml = {
305
316
  'name' => config.name,
@@ -324,15 +335,22 @@ module AppMap
324
335
 
325
336
  if config_data['functions']
326
337
  config_params[:functions] = config_data['functions'].map do |function_data|
327
- package = function_data['package']
328
- cls = function_data['class']
329
- functions = function_data['function'] || function_data['functions']
330
- raise %q(AppMap config 'function' element should specify 'package', 'class' and 'function' or 'functions') unless package && cls && functions
338
+ function_name = function_data['name']
339
+ package, cls, functions = []
340
+ if function_name
341
+ package, cls, _, function = Util.parse_function_name(function_name)
342
+ functions = Array(function)
343
+ else
344
+ package = function_data['package']
345
+ cls = function_data['class']
346
+ functions = function_data['function'] || function_data['functions']
347
+ raise %q(AppMap config 'function' element should specify 'package', 'class' and 'function' or 'functions') unless package && cls && functions
348
+ end
331
349
 
332
350
  functions = Array(functions).map(&:to_sym)
333
351
  labels = function_data['label'] || function_data['labels']
334
352
  labels = Array(labels).map(&:to_s) if labels
335
- Function.new(package, cls, labels, functions)
353
+ Function.new(package, cls, labels, functions, function_data['builtin'], function_data['require'])
336
354
  end
337
355
  end
338
356
 
@@ -342,6 +360,7 @@ module AppMap
342
360
  gem = package['gem']
343
361
  path = package['path']
344
362
  raise %q(AppMap config 'package' element should specify 'gem' or 'path', not both) if gem && path
363
+ raise %q(AppMap config 'package' element should specify 'gem' or 'path') unless gem || path
345
364
 
346
365
  if gem
347
366
  shallow = package['shallow']
@@ -63,7 +63,7 @@ module AppMap
63
63
  removed = []
64
64
  out_of_date_appmaps.each do |appmap_path|
65
65
  mtime_path = File.join(appmap_path, 'mtime')
66
- next unless File.exists?(mtime_path)
66
+ next unless File.exist?(mtime_path)
67
67
 
68
68
  appmap_mtime = File.read(mtime_path).to_i
69
69
  if appmap_mtime < since_ms
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'appmap'
4
-
5
3
  module AppMap
6
4
  module Depends
7
5
  class Configuration
@@ -16,7 +16,7 @@ module AppMap
16
16
  def delete_appmap(appmap_path)
17
17
  FileUtils.rm_rf(appmap_path)
18
18
  appmap_file_path = [ appmap_path, 'appmap.json' ].join('.')
19
- File.unlink(appmap_file_path) if File.exists?(appmap_file_path)
19
+ File.unlink(appmap_file_path) if File.exist?(appmap_file_path)
20
20
  rescue
21
21
  warn "Unable to delete AppMap: #{$!}"
22
22
  end
data/lib/appmap/event.rb CHANGED
@@ -111,10 +111,12 @@ module AppMap
111
111
  rescue NoMethodError
112
112
  begin
113
113
  value.inspect
114
- rescue StandardError
114
+ rescue
115
115
  last_resort_string.call
116
116
  end
117
- rescue StandardError
117
+ rescue WeakRef::RefError
118
+ nil
119
+ rescue
118
120
  last_resort_string.call
119
121
  end
120
122
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'appmap/event'
4
4
  require 'appmap/util'
5
+ require 'rack'
5
6
 
6
7
  module AppMap
7
8
  module Handler
@@ -27,7 +28,7 @@ module AppMap
27
28
 
28
29
  self.request_method = request.method
29
30
  self.url = url
30
- self.headers = AppMap::Util.select_headers(NetHTTP.request_headers(request))
31
+ self.headers = NetHTTP.copy_headers(request)
31
32
  self.params = Rack::Utils.parse_nested_query(query)
32
33
  end
33
34
 
@@ -55,22 +56,25 @@ module AppMap
55
56
  end
56
57
 
57
58
  class HTTPClientResponse < AppMap::Event::MethodReturnIgnoreValue
58
- attr_accessor :status, :mime_type, :headers
59
+ attr_accessor :status, :headers
59
60
 
60
61
  def initialize(response, parent_id, elapsed)
61
62
  super AppMap::Event.next_id_counter, :return, Thread.current.object_id
62
63
 
63
- self.status = response.code.to_i
64
+ if response
65
+ self.status = response.code.to_i
66
+ self.headers = NetHTTP.copy_headers(response)
67
+ else
68
+ self.headers = {}
69
+ end
64
70
  self.parent_id = parent_id
65
71
  self.elapsed = elapsed
66
- self.headers = AppMap::Util.select_headers(NetHTTP.response_headers(response))
67
72
  end
68
73
 
69
74
  def to_h
70
75
  super.tap do |h|
71
76
  h[:http_client_response] = {
72
77
  status_code: status,
73
- mime_type: mime_type,
74
78
  headers: headers
75
79
  }.compact
76
80
  end
@@ -79,17 +83,15 @@ module AppMap
79
83
 
80
84
  class NetHTTP
81
85
  class << self
82
- def request_headers(request)
86
+ def copy_headers(obj)
83
87
  {}.tap do |headers|
84
- request.each_header do |k,v|
85
- key = [ 'HTTP', Util.underscore(k).upcase ].join('_')
86
- headers[key] = v
88
+ obj.each_header do |key, value|
89
+ key = key.split('-').map(&:capitalize).join('-')
90
+ headers[key] = value
87
91
  end
88
92
  end
89
93
  end
90
-
91
- alias response_headers request_headers
92
-
94
+
93
95
  def handle_call(defined_class, hook_method, receiver, args)
94
96
  # request will call itself again in a start block if it's not already started.
95
97
  return unless receiver.started?
@@ -9,16 +9,14 @@ module AppMap
9
9
  module Rails
10
10
  module RequestHandler
11
11
  class HTTPServerRequest < AppMap::Event::MethodEvent
12
- attr_accessor :normalized_path_info, :request_method, :path_info, :params, :mime_type, :headers, :authorization
12
+ attr_accessor :normalized_path_info, :request_method, :path_info, :params, :headers
13
13
 
14
14
  def initialize(request)
15
15
  super AppMap::Event.next_id_counter, :call, Thread.current.object_id
16
16
 
17
17
  self.request_method = request.request_method
18
18
  self.normalized_path_info = normalized_path(request)
19
- self.mime_type = request.headers['Content-Type']
20
- self.headers = AppMap::Util.select_headers(request.env)
21
- self.authorization = request.headers['Authorization']
19
+ self.headers = AppMap::Util.select_rack_headers(request.env)
22
20
  self.path_info = request.path_info.split('?')[0]
23
21
  # ActionDispatch::Http::ParameterFilter is deprecated
24
22
  parameter_filter_cls = \
@@ -35,9 +33,7 @@ module AppMap
35
33
  h[:http_server_request] = {
36
34
  request_method: request_method,
37
35
  path_info: path_info,
38
- mime_type: mime_type,
39
36
  normalized_path_info: normalized_path_info,
40
- authorization: authorization,
41
37
  headers: headers,
42
38
  }.compact
43
39
 
@@ -72,23 +68,21 @@ module AppMap
72
68
  end
73
69
 
74
70
  class HTTPServerResponse < AppMap::Event::MethodReturnIgnoreValue
75
- attr_accessor :status, :mime_type, :headers
71
+ attr_accessor :status, :headers
76
72
 
77
73
  def initialize(response, parent_id, elapsed)
78
74
  super AppMap::Event.next_id_counter, :return, Thread.current.object_id
79
75
 
80
76
  self.status = response.status
81
- self.mime_type = response.headers['Content-Type']
82
77
  self.parent_id = parent_id
83
78
  self.elapsed = elapsed
84
- self.headers = AppMap::Util.select_headers(response.headers)
79
+ self.headers = response.headers.dup
85
80
  end
86
81
 
87
82
  def to_h
88
83
  super.tap do |h|
89
84
  h[:http_server_response] = {
90
85
  status_code: status,
91
- mime_type: mime_type,
92
86
  headers: headers
93
87
  }.compact
94
88
  end
data/lib/appmap/hook.rb CHANGED
@@ -89,7 +89,7 @@ module AppMap
89
89
 
90
90
  config.builtin_hooks.each do |class_name, hooks|
91
91
  Array(hooks).each do |hook|
92
- require hook.package.package_name if hook.package.package_name
92
+ require hook.package.package_name if hook.package.package_name && hook.package.package_name != 'ruby'
93
93
  Array(hook.method_names).each do |method_name|
94
94
  method_name = method_name.to_sym
95
95
  base_cls = class_from_string.(class_name)
@@ -142,6 +142,7 @@ if AppMap::Minitest.enabled?
142
142
  alias run_without_hook run
143
143
 
144
144
  def run
145
+ GC.start
145
146
  AppMap::Minitest.begin_test self, name
146
147
  begin
147
148
  run_without_hook
data/lib/appmap/rspec.rb CHANGED
@@ -87,6 +87,7 @@ module AppMap
87
87
  end
88
88
 
89
89
  warn "Starting recording of example #{example}@#{source_location}" if AppMap::RSpec::LOG
90
+ GC.start
90
91
  @trace = AppMap.tracing.trace
91
92
  @webdriver_port = webdriver_port.()
92
93
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
 
3
5
  module AppMap
data/lib/appmap/util.rb CHANGED
@@ -21,6 +21,16 @@ module AppMap
21
21
  WHITE = "\e[37m"
22
22
 
23
23
  class << self
24
+ def parse_function_name(name)
25
+ package_tokens = name.split('/')
26
+
27
+ class_and_name = package_tokens.pop
28
+ class_name, function_name, static = class_and_name.include?('.') ? class_and_name.split('.', 2) + [ true ] : class_and_name.split('#', 2) + [ false ]
29
+
30
+ raise "Malformed fully-qualified function name #{name}" unless function_name
31
+ [ package_tokens.empty? ? 'ruby' : package_tokens.join('/'), class_name, static, function_name ]
32
+ end
33
+
24
34
  # scenario_filename builds a suitable file name from a scenario name.
25
35
  # Special characters are removed, and the file name is truncated to fit within
26
36
  # shell limitations.
@@ -98,8 +108,18 @@ module AppMap
98
108
  event
99
109
  end
100
110
 
101
- def select_headers(env)
111
+ def select_rack_headers(env)
112
+ finalize_headers = lambda do |headers|
113
+ blank?(headers) ? nil : headers
114
+ end
115
+
102
116
  # Rack prepends HTTP_ to all client-sent headers.
117
+
118
+ if !env['rack.version']
119
+ warn "Request headers does not contain rack.version. HTTP_ prefix is not expected."
120
+ return finalize_headers.call(env.dup)
121
+ end
122
+
103
123
  matching_headers = env
104
124
  .select { |k,v| k.start_with? 'HTTP_'}
105
125
  .reject { |k,v| blank?(v) }
@@ -108,7 +128,7 @@ module AppMap
108
128
  value = kv[1]
109
129
  memo[key] = value
110
130
  end
111
- blank?(matching_headers) ? nil : matching_headers
131
+ finalize_headers.call(matching_headers)
112
132
  end
113
133
 
114
134
  def normalize_path(path)
@@ -3,7 +3,7 @@
3
3
  module AppMap
4
4
  URL = 'https://github.com/applandinc/appmap-ruby'
5
5
 
6
- VERSION = '0.65.1'
6
+ VERSION = '0.67.0'
7
7
 
8
8
  APPMAP_FORMAT_VERSION = '1.5.1'
9
9
 
data/lib/appmap.rb CHANGED
@@ -74,6 +74,6 @@ lambda do
74
74
  require 'appmap/depends'
75
75
  end
76
76
 
77
- end.call
77
+ end.call unless ENV['APPMAP_AUTOREQUIRE'] == 'false'
78
78
 
79
- AppMap.initialize_configuration if ENV['APPMAP'] == 'true'
79
+ AppMap.initialize_configuration if ENV['APPMAP'] == 'true' && ENV['APPMAP_INITIALIZE'] != 'false'
data/spec/config_spec.rb CHANGED
@@ -55,6 +55,34 @@ describe AppMap::Config, docker: false do
55
55
  expect(config.to_h.deep_stringify_keys!).to eq(config_expectation)
56
56
  end
57
57
 
58
+ it 'interprets a function in canonical name format' do
59
+ config_data = {
60
+ name: 'test',
61
+ packages: [],
62
+ functions: [
63
+ {
64
+ name: 'pkg/cls#fn',
65
+ }
66
+ ]
67
+ }.deep_stringify_keys!
68
+ config = AppMap::Config.load(config_data)
69
+
70
+ config_expectation = {
71
+ exclude: [],
72
+ name: 'test',
73
+ packages: [],
74
+ functions: [
75
+ {
76
+ package: 'pkg',
77
+ class: 'cls',
78
+ functions: [ :fn ],
79
+ }
80
+ ]
81
+ }.deep_stringify_keys!
82
+
83
+ expect(config.to_h.deep_stringify_keys!).to eq(config_expectation)
84
+ end
85
+
58
86
  context do
59
87
  let(:warnings) { @warnings ||= [] }
60
88
  let(:warning) { warnings.join }
@@ -93,9 +93,9 @@ describe 'Depends API' do
93
93
 
94
94
  test_report.clean_appmaps
95
95
 
96
- expect(File.exists?(new_spec_file)).to be_falsey
96
+ expect(File.exist?(new_spec_file)).to be_falsey
97
97
  ensure
98
- FileUtils.rm_f new_spec_file if File.exists?(new_spec_file)
98
+ FileUtils.rm_f new_spec_file if File.exist?(new_spec_file)
99
99
  FileUtils.rm_rf new_spec_file.split('.')[0]
100
100
  end
101
101
  end
@@ -0,0 +1,3 @@
1
+ name: name
2
+ packages:
3
+ - dogs: are friendly
@@ -5,3 +5,7 @@ packages:
5
5
  - path: app/controllers
6
6
  labels: [ mvc.controller ]
7
7
  - gem: sequel
8
+ functions:
9
+ - name: logger/Logger::LogDevice#write
10
+ builtin: true
11
+ label: log
@@ -5,6 +5,10 @@ packages:
5
5
  - path: app/controllers
6
6
  labels: [ mvc.controller ]
7
7
  - gem: sequel
8
+ functions:
9
+ - name: logger/Logger::LogDevice#write
10
+ builtin: true
11
+ label: log
8
12
  swagger:
9
13
  project_version: 1.1.0
10
14
  output_dir: tmp/swagger
@@ -1,7 +1,11 @@
1
1
  require 'rails_spec_helper'
2
2
 
3
+ def default_rails_versions
4
+ ruby_2? ? [ 5, 6 ] : [ 6 ]
5
+ end
6
+
3
7
  # Rails5 doesn't work with Ruby 3.x
4
- RailsVersions = ruby_2? ? [ 5, 6 ] : [ 6 ]
8
+ RailsVersions = ENV['RAILS_VERSIONS'] || default_rails_versions
5
9
 
6
10
  describe 'Rails' do
7
11
  RailsVersions.each do |rails_major_version| # rubocop:disable Metrics/BlockLength
@@ -54,7 +58,7 @@ describe 'Rails' do
54
58
  hash_including(
55
59
  'http_server_response' => hash_including(
56
60
  'status_code' => 201,
57
- 'mime_type' => 'application/json; charset=utf-8',
61
+ 'headers' => hash_including('Content-Type' => 'application/json; charset=utf-8'),
58
62
  )
59
63
  )
60
64
  )
@@ -91,6 +95,15 @@ describe 'Rails' do
91
95
  )
92
96
  end
93
97
 
98
+ it 'captures log events' do
99
+ expect(events).to include hash_including(
100
+ 'event' => 'call',
101
+ 'defined_class' => 'Logger::LogDevice',
102
+ 'method_id' => 'write',
103
+ 'static' => false
104
+ )
105
+ end
106
+
94
107
  context 'with an object-style message' do
95
108
  let(:appmap_json_file) { 'Api_UsersController_POST_api_users_with_required_parameters_with_object-style_parameters_creates_a_user.appmap.json' }
96
109
 
@@ -6,6 +6,7 @@ class AgentSetupValidateTest < Minitest::Test
6
6
  NON_EXISTING_CONFIG_FILENAME = '123.yml'
7
7
  INVALID_YAML_CONFIG_FILENAME = 'spec/fixtures/config/invalid_yaml_config.yml'
8
8
  INVALID_CONFIG_FILENAME = 'spec/fixtures/config/invalid_config.yml'
9
+ MISSING_PATH_OR_GEM_CONFIG_FILENAME = 'spec/fixtures/config/missing_path_or_gem.yml'
9
10
 
10
11
  def test_init_when_config_exists
11
12
  output = `./exe/appmap-agent-validate`
@@ -72,4 +73,22 @@ class AgentSetupValidateTest < Minitest::Test
72
73
  ])
73
74
  assert_equal expected, output.strip
74
75
  end
76
+
77
+ def test_init_with_missing_package_key
78
+ output = `./exe/appmap-agent-validate -c #{MISSING_PATH_OR_GEM_CONFIG_FILENAME}`
79
+ assert_equal 0, $CHILD_STATUS.exitstatus
80
+ expected = JSON.pretty_generate([
81
+ {
82
+ level: :error,
83
+ message: 'AppMap auto-configuration is currently not available for non Rails projects'
84
+ },
85
+ {
86
+ level: :error,
87
+ filename: MISSING_PATH_OR_GEM_CONFIG_FILENAME,
88
+ message: "AppMap configuration #{MISSING_PATH_OR_GEM_CONFIG_FILENAME} could not be loaded",
89
+ detailed_message: "AppMap config 'package' element should specify 'gem' or 'path'"
90
+ }
91
+ ])
92
+ assert_equal expected, output.strip
93
+ end
75
94
  end
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'appmap', git: 'applandinc/appmap-ruby', branch: `git rev-parse --abbrev-ref HEAD`.strip
4
+ gem 'minitest'
5
+ gem 'mocha'
@@ -0,0 +1,5 @@
1
+ name: mocha_mock_app
2
+ packages:
3
+ - path: lib
4
+ - gem: mocha
5
+ shallow: false
@@ -0,0 +1,5 @@
1
+ class Sheep
2
+ def baa
3
+ 'baa'
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
2
+
3
+ require 'minitest/autorun'
4
+
5
+ require 'appmap'
6
+ require 'appmap/minitest' if ENV['APPMAP_AUTOREQUIRE'] == 'false'
7
+
8
+ require 'sheep'
9
+ require 'mocha/minitest'
10
+
11
+ class SheepTest < Minitest::Test
12
+ def test_sheep
13
+ sheep = mock('sheep')
14
+ sheep.responds_like(Sheep.new)
15
+ sheep.expects(:baa).returns('baa')
16
+ sheep.baa
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'test_helper'
5
+
6
+ class MockCompatibilityTest < Minitest::Test
7
+ def perform_minitest_test(test_name, env = {})
8
+ Bundler.with_clean_env do
9
+ Dir.chdir 'test/fixtures/mocha_mock_app' do
10
+ FileUtils.rm_rf 'tmp'
11
+ system 'bundle config --local local.appmap ../../..'
12
+ system 'bundle'
13
+ system(env.merge({ 'APPMAP' => 'true' }), %(bundle exec ruby -Ilib -Itest test/#{test_name}_test.rb))
14
+
15
+ yield
16
+ end
17
+ end
18
+ end
19
+
20
+ def test_expectation
21
+ perform_minitest_test('sheep') do
22
+ appmap_file = 'tmp/appmap/minitest/Sheep_sheep.appmap.json'
23
+
24
+ assert File.file?(appmap_file), 'appmap output file does not exist'
25
+ appmap = JSON.parse(File.read(appmap_file))
26
+ assert_equal AppMap::APPMAP_FORMAT_VERSION, appmap['version']
27
+ assert_includes appmap.keys, 'metadata'
28
+ metadata = appmap['metadata']
29
+ assert_equal 'succeeded', metadata['test_status']
30
+ end
31
+ end
32
+
33
+ def test_expectation_without_autorequire
34
+ perform_minitest_test('sheep', 'APPMAP_AUTOREQUIRE' => 'false') do
35
+ appmap_file = 'tmp/appmap/minitest/Sheep_sheep.appmap.json'
36
+
37
+ assert File.file?(appmap_file), 'appmap output file does not exist'
38
+ appmap = JSON.parse(File.read(appmap_file))
39
+ assert_equal AppMap::APPMAP_FORMAT_VERSION, appmap['version']
40
+ assert_includes appmap.keys, 'metadata'
41
+ metadata = appmap['metadata']
42
+ assert_equal 'succeeded', metadata['test_status']
43
+ end
44
+ end
45
+ 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.65.1
4
+ version: 0.67.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: 2021-09-16 00:00:00.000000000 Z
11
+ date: 2021-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -3462,6 +3462,7 @@ files:
3462
3462
  - spec/fixtures/config/incomplete_config.yml
3463
3463
  - spec/fixtures/config/invalid_config.yml
3464
3464
  - spec/fixtures/config/invalid_yaml_config.yml
3465
+ - spec/fixtures/config/missing_path_or_gem.yml
3465
3466
  - spec/fixtures/config/valid_config.yml
3466
3467
  - spec/fixtures/depends/.gitignore
3467
3468
  - spec/fixtures/depends/app/controllers/api/api_keys_controller.rb
@@ -3698,6 +3699,10 @@ files:
3698
3699
  - test/fixtures/minitest_recorder/appmap.yml
3699
3700
  - test/fixtures/minitest_recorder/lib/hello.rb
3700
3701
  - test/fixtures/minitest_recorder/test/hello_test.rb
3702
+ - test/fixtures/mocha_mock_app/Gemfile
3703
+ - test/fixtures/mocha_mock_app/appmap.yml
3704
+ - test/fixtures/mocha_mock_app/lib/sheep.rb
3705
+ - test/fixtures/mocha_mock_app/test/sheep_test.rb
3701
3706
  - test/fixtures/openssl_recorder/Gemfile
3702
3707
  - test/fixtures/openssl_recorder/appmap.yml
3703
3708
  - test/fixtures/openssl_recorder/lib/openssl_cert_sign.rb
@@ -3714,6 +3719,7 @@ files:
3714
3719
  - test/gem_test.rb
3715
3720
  - test/inspect_cli_test.rb
3716
3721
  - test/minitest_test.rb
3722
+ - test/mock_compatibility_test.rb
3717
3723
  - test/openssl_test.rb
3718
3724
  - test/record_process_test.rb
3719
3725
  - test/rspec_test.rb
@@ -3738,7 +3744,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
3738
3744
  - !ruby/object:Gem::Version
3739
3745
  version: '0'
3740
3746
  requirements: []
3741
- rubygems_version: 3.0.8
3747
+ rubygems_version: 3.0.6
3742
3748
  signing_key:
3743
3749
  specification_version: 4
3744
3750
  summary: Record the operation of a Ruby program, using the AppLand 'AppMap' format.