appmap 0.54.4 → 0.58.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 +4 -4
- data/CHANGELOG.md +44 -0
- data/exe/appmap-agent-init +2 -2
- data/exe/appmap-agent-status +19 -0
- data/lib/appmap.rb +2 -4
- data/lib/appmap/command/agent_setup/init.rb +8 -22
- data/lib/appmap/command/agent_setup/status.rb +43 -0
- data/lib/appmap/config.rb +2 -1
- data/lib/appmap/event.rb +32 -2
- data/lib/appmap/hook.rb +28 -0
- data/lib/appmap/hook/method.rb +6 -1
- data/lib/appmap/service/config_analyzer.rb +34 -0
- data/lib/appmap/service/integration_test_path_finder.rb +44 -0
- data/lib/appmap/service/test_command_provider.rb +54 -0
- data/lib/appmap/service/test_framework_detector.rb +21 -0
- data/lib/appmap/util.rb +1 -1
- data/lib/appmap/version.rb +1 -1
- data/spec/fixtures/config/incomplete_config.yml +1 -0
- data/spec/fixtures/config/invalid_config.yml +2 -0
- data/spec/fixtures/config/valid_config.yml +3 -0
- data/spec/fixtures/rails6_users_app/test/controllers/functional_calc_test.rb +10 -0
- data/spec/fixtures/rails6_users_app/test/integration/integration_calc_test.rb +12 -0
- data/spec/hook_spec.rb +1 -1
- data/spec/service/config_analyzer_spec.rb +96 -0
- data/test/agent_setup_init_test.rb +16 -16
- data/test/agent_setup_status_test.rb +65 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca5a16a5edc35706d33aa6ec21e45b5641aa9342b6fc5ab03ada141556c2b859
|
4
|
+
data.tar.gz: 7a4b5b6ff0c504814b7eccebba46a739cc4e00fcf6eb1e5492ef7f52d2f887d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5267e3ba0827671d825ca0bb0323965ae0d8b5c0ac772f95721227af2b66a3a2d2843f7813a4f1faff997e49cd83dc4b7d78a57cb3b4852cfd6fbe63290aa223
|
7
|
+
data.tar.gz: cdb60a38a5d9c836a159c9473a7bf42e06589926ec7011b5978add71dca14ef6fd8acc807d7ef745e3d17ab908e38eca49bfbb3094c5b48a97d4084d9a2f34d8
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,47 @@
|
|
1
|
+
# [0.58.0](https://github.com/applandinc/appmap-ruby/compare/v0.57.1...v0.58.0) (2021-07-06)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* Add `test_commands` sections to `appmap-agent-status` executable ([4cd8fe5](https://github.com/applandinc/appmap-ruby/commit/4cd8fe58acb4af72b7818db96de9e479562b9ea0))
|
7
|
+
|
8
|
+
## [0.57.1](https://github.com/applandinc/appmap-ruby/compare/v0.57.0...v0.57.1) (2021-07-02)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* rename agentVersionPorject to agentVersion ([905fc5d](https://github.com/applandinc/appmap-ruby/commit/905fc5dd643411deb94f8a1087bcdb3a562d218a))
|
14
|
+
|
15
|
+
# [0.57.0](https://github.com/applandinc/appmap-ruby/compare/v0.56.0...v0.57.0) (2021-06-29)
|
16
|
+
|
17
|
+
|
18
|
+
### Features
|
19
|
+
|
20
|
+
* Update init command to return JSON ([1f93e89](https://github.com/applandinc/appmap-ruby/commit/1f93e8909684e1018f513d69adfde2a5d0bf6bc9))
|
21
|
+
|
22
|
+
# [0.56.0](https://github.com/applandinc/appmap-ruby/compare/v0.55.0...v0.56.0) (2021-06-28)
|
23
|
+
|
24
|
+
|
25
|
+
### Features
|
26
|
+
|
27
|
+
* add appmap-agent-status executable with config/project properties ([043f845](https://github.com/applandinc/appmap-ruby/commit/043f8453a2533a6e172d1cd23fcde04f19e73173))
|
28
|
+
|
29
|
+
# [0.55.0](https://github.com/applandinc/appmap-ruby/compare/v0.54.4...v0.55.0) (2021-06-28)
|
30
|
+
|
31
|
+
|
32
|
+
### Bug Fixes
|
33
|
+
|
34
|
+
* Avoid calling == ([f30ed9f](https://github.com/applandinc/appmap-ruby/commit/f30ed9f309753252df35e372d925db3b914260d4))
|
35
|
+
* Log dynamic loading of appmap helpers at info level ([15dcd3c](https://github.com/applandinc/appmap-ruby/commit/15dcd3c913fa1c32aea034b28ddae59668efa217))
|
36
|
+
* Remove dynamic loading of rake and rspec helpers ([6790970](https://github.com/applandinc/appmap-ruby/commit/67909702f3c8a52081ef1e23a87c292908883334))
|
37
|
+
|
38
|
+
|
39
|
+
### Features
|
40
|
+
|
41
|
+
* APPMAP_PROFILE_DISPLAY_STRING and APPMAP_OBJECT_STRING ([3f5daa8](https://github.com/applandinc/appmap-ruby/commit/3f5daa890bfbfd39b7f825794d0c43da509b3201))
|
42
|
+
* Package name to require can be specified when hooking a gem ([fcc5eb6](https://github.com/applandinc/appmap-ruby/commit/fcc5eb691a0330444560eb4c2afe7fc3c4c8afa8))
|
43
|
+
* Profile packaging hooking ([c020a31](https://github.com/applandinc/appmap-ruby/commit/c020a312f4545348ec7cc302443269c57a7fc026))
|
44
|
+
|
1
45
|
## [0.54.4](https://github.com/applandinc/appmap-ruby/compare/v0.54.3...v0.54.4) (2021-06-27)
|
2
46
|
|
3
47
|
|
data/exe/appmap-agent-init
CHANGED
@@ -5,10 +5,10 @@ require 'optparse'
|
|
5
5
|
require 'appmap'
|
6
6
|
require 'appmap/command/agent_setup/init'
|
7
7
|
|
8
|
-
@options = {:
|
8
|
+
@options = { config_file: AppMap::DEFAULT_CONFIG_FILE_PATH }
|
9
9
|
|
10
10
|
OptionParser.new do |parser|
|
11
|
-
parser.banner = 'Usage:
|
11
|
+
parser.banner = 'Usage: appmap-agent-init [options]'
|
12
12
|
|
13
13
|
description = "AppMap configuration file path (default: #{AppMap::DEFAULT_CONFIG_FILE_PATH})"
|
14
14
|
parser.on('-c', '--config=FILEPATH', description) do |filepath|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'appmap'
|
6
|
+
require 'appmap/command/agent_setup/status'
|
7
|
+
|
8
|
+
@options = { config_file: AppMap::DEFAULT_CONFIG_FILE_PATH }
|
9
|
+
|
10
|
+
OptionParser.new do |parser|
|
11
|
+
parser.banner = 'Usage: appmap-agent-status [options]'
|
12
|
+
|
13
|
+
description = "AppMap configuration file path (default: #{AppMap::DEFAULT_CONFIG_FILE_PATH})"
|
14
|
+
parser.on('-c', '--config=FILEPATH', description) do |filepath|
|
15
|
+
@options[:config_file] = filepath
|
16
|
+
end
|
17
|
+
end.parse!
|
18
|
+
|
19
|
+
AppMap::Command::AgentSetup::Status.new(@options[:config_file]).perform
|
data/lib/appmap.rb
CHANGED
@@ -28,11 +28,9 @@ lambda do
|
|
28
28
|
INITIALIZERS = {
|
29
29
|
# In a Rails app, Rails is always defined by the time the other gems are loaded. Therefore, we
|
30
30
|
# don't try and trap the loading of Rails itself here.
|
31
|
-
|
31
|
+
# Emperically, Rake and RSpec are also defined before appmap is loaded whenever a Rake task or
|
32
|
+
# RSpec tests are being run. Therefore, the only hook we need here is Minitest.
|
32
33
|
'Minitest::Unit::TestCase' => Initializer.new('AppMap::Minitest', 'appmap/minitest', 'minitest'),
|
33
|
-
'Rake' => [
|
34
|
-
Initializer.new('AppMap::Swagger', 'appmap/swagger', 'rake')
|
35
|
-
]
|
36
34
|
}
|
37
35
|
|
38
36
|
TracePoint.new(:class) do |tp|
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'json'
|
4
4
|
require 'appmap/service/guesser'
|
5
|
-
require 'appmap/util'
|
6
5
|
|
7
6
|
module AppMap
|
8
7
|
module Command
|
@@ -11,32 +10,19 @@ module AppMap
|
|
11
10
|
|
12
11
|
class Init < InitStruct
|
13
12
|
def perform
|
14
|
-
if File.exist?(config_file)
|
15
|
-
puts AppMap::Util.color(%(The AppMap config file #{config_file} already exists.), :magenta)
|
16
|
-
return
|
17
|
-
end
|
18
|
-
|
19
|
-
ensure_directory_exists
|
20
|
-
|
21
13
|
config = {
|
22
14
|
'name' => Service::Guesser.guess_name,
|
23
15
|
'packages' => Service::Guesser.guess_paths.map { |path| { 'path' => path } }
|
24
16
|
}
|
25
|
-
content = YAML.dump(config).gsub("---\n", '')
|
26
17
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
18
|
+
result = {
|
19
|
+
configuration: {
|
20
|
+
filename: config_file,
|
21
|
+
contents: YAML.dump(config)
|
22
|
+
}
|
23
|
+
}
|
36
24
|
|
37
|
-
|
38
|
-
dirname = File.dirname(config_file)
|
39
|
-
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
25
|
+
puts JSON.pretty_generate(result)
|
40
26
|
end
|
41
27
|
end
|
42
28
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'appmap/service/config_analyzer'
|
5
|
+
require 'appmap/service/integration_test_path_finder'
|
6
|
+
require 'appmap/service/test_command_provider'
|
7
|
+
|
8
|
+
module AppMap
|
9
|
+
module Command
|
10
|
+
module AgentSetup
|
11
|
+
StatusStruct = Struct.new(:config_file)
|
12
|
+
|
13
|
+
class Status < StatusStruct
|
14
|
+
def perform
|
15
|
+
status = {
|
16
|
+
test_commands: Service::TestCommandProvider.all,
|
17
|
+
properties: {
|
18
|
+
config: {
|
19
|
+
app: config_analyzer.app_name,
|
20
|
+
present: config_analyzer.present?,
|
21
|
+
valid: config_analyzer.valid?
|
22
|
+
},
|
23
|
+
project: {
|
24
|
+
agentVersion: AppMap::VERSION,
|
25
|
+
language: 'ruby',
|
26
|
+
remoteRecordingCapable: Gem.loaded_specs.has_key?('rails'),
|
27
|
+
integrationTests: Service::IntegrationTestPathFinder.count_paths > 0
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
puts JSON.pretty_generate(status)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def config_analyzer
|
38
|
+
@config_analyzer ||= Service::ConfigAnalyzer.new(config_file)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/appmap/config.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
3
4
|
require 'yaml'
|
4
5
|
require 'appmap/util'
|
5
6
|
require 'appmap/handler/net_http'
|
@@ -343,7 +344,7 @@ module AppMap
|
|
343
344
|
shallow = package['shallow']
|
344
345
|
# shallow is true by default for gems
|
345
346
|
shallow = true if shallow.nil?
|
346
|
-
Package.build_from_gem(gem, exclude: package['exclude'] || [], shallow: shallow)
|
347
|
+
Package.build_from_gem(gem, package_name: package['package'], exclude: package['exclude'] || [], shallow: shallow)
|
347
348
|
else
|
348
349
|
Package.build_from_path(path, exclude: package['exclude'] || [], shallow: package['shallow'])
|
349
350
|
end
|
data/lib/appmap/event.rb
CHANGED
@@ -29,11 +29,31 @@ module AppMap
|
|
29
29
|
|
30
30
|
# Gets a display string for a value. This is not meant to be a machine deserializable value.
|
31
31
|
def display_string(value)
|
32
|
-
return nil
|
32
|
+
return nil if value.equal?(nil)
|
33
33
|
|
34
|
+
# With setting APPMAP_PROFILE_DISPLAY_STRING, stringifying this class is shown to take 9 seconds(!) of a 17 second test run.
|
35
|
+
return nil if best_class_name(value) == 'ActiveSupport::Callbacks::Filters::Environment'
|
36
|
+
|
37
|
+
if @times.nil? && ENV['APPMAP_PROFILE_DISPLAY_STRING'] == 'true'
|
38
|
+
@times = Hash.new {|memo,key| memo[key] = 0}
|
39
|
+
Thread.new do
|
40
|
+
sleep 0.5
|
41
|
+
while true
|
42
|
+
warn @times.to_a.sort{|a,b| b[1] <=> a[1]}[0..9].join("\n")
|
43
|
+
sleep 3
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
start = Time.now
|
34
49
|
value_string = custom_display_string(value) || default_display_string(value)
|
35
50
|
|
36
|
-
|
51
|
+
if @times
|
52
|
+
elapsed = Time.now - start
|
53
|
+
@times[best_class_name(value)] += elapsed
|
54
|
+
end
|
55
|
+
|
56
|
+
encode_dislay_string(value_string)
|
37
57
|
end
|
38
58
|
|
39
59
|
def object_properties(hash_like)
|
@@ -57,8 +77,16 @@ module AppMap
|
|
57
77
|
value_cls.name
|
58
78
|
end
|
59
79
|
|
80
|
+
def encode_dislay_string(value)
|
81
|
+
(value||'')[0...LIMIT].encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
82
|
+
end
|
83
|
+
|
60
84
|
def custom_display_string(value)
|
61
85
|
case value
|
86
|
+
when NilClass, TrueClass, FalseClass, Numeric, Time, Date
|
87
|
+
value.to_s
|
88
|
+
when String
|
89
|
+
value[0...LIMIT].encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
62
90
|
when File
|
63
91
|
"#{value.class}[path=#{value.path}]"
|
64
92
|
when Net::HTTP
|
@@ -71,6 +99,8 @@ module AppMap
|
|
71
99
|
end
|
72
100
|
|
73
101
|
def default_display_string(value)
|
102
|
+
return nil if ENV['APPMAP_OBJECT_STRING'] == 'false'
|
103
|
+
|
74
104
|
last_resort_string = lambda do
|
75
105
|
warn "AppMap encountered an error inspecting a #{value.class.name}: #{$!.message}"
|
76
106
|
'*Error inspecting variable*'
|
data/lib/appmap/hook.rb
CHANGED
@@ -9,6 +9,7 @@ module AppMap
|
|
9
9
|
|
10
10
|
OBJECT_INSTANCE_METHODS = %i[! != !~ <=> == === =~ __id__ __send__ class clone define_singleton_method display dup enum_for eql? equal? extend freeze frozen? hash inspect instance_eval instance_exec instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method methods nil? object_id private_methods protected_methods public_method public_methods public_send remove_instance_variable respond_to? send singleton_class singleton_method singleton_methods taint tainted? tap then to_enum to_s to_h to_a trust untaint untrust untrusted? yield_self].freeze
|
11
11
|
OBJECT_STATIC_METHODS = %i[! != !~ < <= <=> == === =~ > >= __id__ __send__ alias_method allocate ancestors attr attr_accessor attr_reader attr_writer autoload autoload? class class_eval class_exec class_variable_defined? class_variable_get class_variable_set class_variables clone const_defined? const_get const_missing const_set constants define_method define_singleton_method deprecate_constant display dup enum_for eql? equal? extend freeze frozen? hash include include? included_modules inspect instance_eval instance_exec instance_method instance_methods instance_of? instance_variable_defined? instance_variable_get instance_variable_set instance_variables is_a? itself kind_of? method method_defined? methods module_eval module_exec name new nil? object_id prepend private_class_method private_constant private_instance_methods private_method_defined? private_methods protected_instance_methods protected_method_defined? protected_methods public_class_method public_constant public_instance_method public_instance_methods public_method public_method_defined? public_methods public_send remove_class_variable remove_instance_variable remove_method respond_to? send singleton_class singleton_class? singleton_method singleton_methods superclass taint tainted? tap then to_enum to_s trust undef_method untaint untrust untrusted? yield_self].freeze
|
12
|
+
SLOW_PACKAGE_THRESHOLD = 0.05
|
12
13
|
|
13
14
|
@unbound_method_arity = ::UnboundMethod.instance_method(:arity)
|
14
15
|
@method_arity = ::Method.instance_method(:arity)
|
@@ -49,6 +50,27 @@ module AppMap
|
|
49
50
|
@notrace_paths = Set.new
|
50
51
|
# Locations that have already been visited.
|
51
52
|
@trace_locations = Set.new
|
53
|
+
@module_load_times = Hash.new {|memo,k| memo[k] = 0}
|
54
|
+
@slow_packages = Set.new
|
55
|
+
|
56
|
+
if ENV['APPMAP_PROFILE_HOOK'] == 'true'
|
57
|
+
Thread.new do
|
58
|
+
sleep 1
|
59
|
+
while true
|
60
|
+
@module_load_times
|
61
|
+
.keys
|
62
|
+
.select { |key| !@slow_packages.member?(key) }
|
63
|
+
.each do |key|
|
64
|
+
elapsed = @module_load_times[key]
|
65
|
+
if elapsed >= SLOW_PACKAGE_THRESHOLD
|
66
|
+
@slow_packages.add(key)
|
67
|
+
warn "AppMap: Package #{key} took #{@module_load_times[key]} seconds to hook"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
sleep 5
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
52
74
|
|
53
75
|
@trace_end = TracePoint.new(:end, &method(:trace_end))
|
54
76
|
@trace_end.enable(&block)
|
@@ -157,6 +179,7 @@ module AppMap
|
|
157
179
|
end
|
158
180
|
end
|
159
181
|
|
182
|
+
start = Time.now
|
160
183
|
instance_methods.each(&hook.(cls))
|
161
184
|
begin
|
162
185
|
# NoMethodError: private method `singleton_class' called for Rack::MiniProfiler:Class
|
@@ -166,6 +189,11 @@ module AppMap
|
|
166
189
|
# uninitialized constant Faraday::Connection
|
167
190
|
warn "NameError in #{__FILE__}: #{$!.message}"
|
168
191
|
end
|
192
|
+
elapsed = Time.now - start
|
193
|
+
if location.index(Bundler.bundle_path.to_s) == 0
|
194
|
+
package_tokens = location[Bundler.bundle_path.to_s.length + 1..-1].split('/')
|
195
|
+
@module_load_times[package_tokens[1]] += elapsed
|
196
|
+
end
|
169
197
|
end
|
170
198
|
end
|
171
199
|
end
|
data/lib/appmap/hook/method.rb
CHANGED
@@ -49,9 +49,14 @@ module AppMap
|
|
49
49
|
|
50
50
|
hook_method_def = Proc.new do |*args, &block|
|
51
51
|
instance_method = hook_method.bind(self).to_proc
|
52
|
+
|
53
|
+
is_array_containing_empty_hash = ->(obj) {
|
54
|
+
obj.is_a?(Array) && obj.length == 1 && obj[0].is_a?(Hash) && obj[0].size == 0
|
55
|
+
}
|
56
|
+
|
52
57
|
call_instance_method = -> {
|
53
58
|
# https://github.com/applandinc/appmap-ruby/issues/153
|
54
|
-
if Util.ruby_minor_version >= 2.7 && args
|
59
|
+
if Util.ruby_minor_version >= 2.7 && is_array_containing_empty_hash.(args) && hook_method.arity == 1
|
55
60
|
instance_method.call({}, &block)
|
56
61
|
else
|
57
62
|
instance_method.call(*args, &block)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppMap
|
4
|
+
module Service
|
5
|
+
class ConfigAnalyzer
|
6
|
+
attr_reader :config_error
|
7
|
+
|
8
|
+
def initialize(config_file)
|
9
|
+
@config_file = config_file
|
10
|
+
@config = load_config
|
11
|
+
end
|
12
|
+
|
13
|
+
def app_name
|
14
|
+
@config.to_h[:name] if present?
|
15
|
+
end
|
16
|
+
|
17
|
+
def present?
|
18
|
+
File.exist?(@config_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
present? && @config.to_h.key?(:name) && @config.to_h.key?(:packages)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def load_config
|
28
|
+
AppMap::Config.load_from_file @config_file if present?
|
29
|
+
rescue
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'appmap/service/test_framework_detector'
|
4
|
+
|
5
|
+
module AppMap
|
6
|
+
module Service
|
7
|
+
class IntegrationTestPathFinder
|
8
|
+
class << self
|
9
|
+
def find
|
10
|
+
@paths ||= begin
|
11
|
+
paths = { rspec: [], minitest: [], cucumber: [] }
|
12
|
+
paths[:rspec] = find_rspec_paths if TestFrameworkDetector.rspec_present?
|
13
|
+
paths[:minitest] = find_minitest_paths if TestFrameworkDetector.minitest_present?
|
14
|
+
paths[:cucumber] = find_cucumber_paths if TestFrameworkDetector.cucumber_present?
|
15
|
+
paths
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def count_paths
|
20
|
+
find.flatten(2).length - 3
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def find_rspec_paths
|
26
|
+
find_non_empty_paths(%w[spec/controllers spec/requests spec/integration spec/api spec/features spec/system])
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def find_minitest_paths
|
31
|
+
find_non_empty_paths(%w[test/controllers test/integration])
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_cucumber_paths
|
35
|
+
find_non_empty_paths(%w[features])
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_non_empty_paths(paths)
|
39
|
+
paths.select { |path| Dir.exist?(path) && !Dir.empty?(path) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'appmap/service/test_framework_detector'
|
4
|
+
require 'appmap/service/integration_test_path_finder'
|
5
|
+
|
6
|
+
module AppMap
|
7
|
+
module Service
|
8
|
+
class TestCommandProvider
|
9
|
+
class << self
|
10
|
+
def all
|
11
|
+
commands = []
|
12
|
+
|
13
|
+
if TestFrameworkDetector.rspec_present? && !integration_test_paths[:rspec].empty?
|
14
|
+
commands << {
|
15
|
+
framework: :rspec,
|
16
|
+
command: "APPMAP=true bundle exec rspec #{integration_test_paths[:rspec].join(' ')}"
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
if TestFrameworkDetector.minitest_present? && !integration_test_paths[:minitest].empty?
|
21
|
+
commands << {
|
22
|
+
framework: :minitest,
|
23
|
+
command: minitest_command
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
if TestFrameworkDetector.cucumber_present? && !integration_test_paths[:cucumber].empty?
|
28
|
+
commands << {
|
29
|
+
framework: :cucumber,
|
30
|
+
command: 'APPMAP=true bundle exec cucumber'
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
commands
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def minitest_command
|
40
|
+
if Gem.loaded_specs.has_key?('rails')
|
41
|
+
"APPMAP=true bundle exec rails test #{integration_test_paths[:minitest].join(' ')}"
|
42
|
+
else
|
43
|
+
subcommands = integration_test_paths[:minitest].map { |path| "APPMAP=true bundle exec ruby #{path}" }
|
44
|
+
subcommands.join(' && ')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def integration_test_paths
|
49
|
+
@paths ||= Service::IntegrationTestPathFinder.find
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppMap
|
4
|
+
module Service
|
5
|
+
class TestFrameworkDetector
|
6
|
+
class << self
|
7
|
+
def rspec_present?
|
8
|
+
Gem.loaded_specs.has_key?('rspec-core')
|
9
|
+
end
|
10
|
+
|
11
|
+
def minitest_present?
|
12
|
+
Gem.loaded_specs.has_key?('minitest')
|
13
|
+
end
|
14
|
+
|
15
|
+
def cucumber_present?
|
16
|
+
Gem.loaded_specs.has_key?('cucumber')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/appmap/util.rb
CHANGED
data/lib/appmap/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
name: app
|
data/spec/hook_spec.rb
CHANGED
@@ -970,7 +970,7 @@ describe 'AppMap class Hooking', docker: false do
|
|
970
970
|
tz = ENV['TZ']
|
971
971
|
ENV['TZ'] = 'UTC'
|
972
972
|
Timecop.freeze(Time.utc('2020-01-01')) do
|
973
|
-
expect(Time).to receive(:now).
|
973
|
+
expect(Time).to receive(:now).at_least(3).times.and_call_original
|
974
974
|
expect(InstanceMethod.new.say_the_time).to be
|
975
975
|
end
|
976
976
|
ensure
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'appmap/service/config_analyzer'
|
5
|
+
|
6
|
+
describe AppMap::Service::ConfigAnalyzer do
|
7
|
+
subject { described_class.new(config_file) }
|
8
|
+
|
9
|
+
context 'with non-existing config' do
|
10
|
+
let(:config_file) { 'spec/fixtures/config/non_existing_config.yml'}
|
11
|
+
|
12
|
+
describe '.app_name' do
|
13
|
+
it 'returns nil' do
|
14
|
+
expect(subject.app_name).to be_nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.is_valid?' do
|
19
|
+
it 'returns false' do
|
20
|
+
expect(subject.valid?).to be_falsey
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.is_present?' do
|
25
|
+
it 'returns false' do
|
26
|
+
expect(subject.present?).to be_falsey
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with valid config' do
|
32
|
+
let(:config_file) { 'spec/fixtures/config/valid_config.yml'}
|
33
|
+
|
34
|
+
describe '.app_name' do
|
35
|
+
it 'returns app name value from config' do
|
36
|
+
expect(subject.app_name).to eq('appmap')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '.is_valid?' do
|
41
|
+
it 'returns true' do
|
42
|
+
expect(subject.valid?).to be_truthy
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '.is_present?' do
|
47
|
+
it 'returns true' do
|
48
|
+
expect(subject.present?).to be_truthy
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with invalid YAML config' do
|
54
|
+
let(:config_file) { 'spec/fixtures/config/invalid_config.yml'}
|
55
|
+
|
56
|
+
describe '.app_name' do
|
57
|
+
it 'returns app name value from config' do
|
58
|
+
expect(subject.app_name).to be_nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '.is_valid?' do
|
63
|
+
it 'returns false' do
|
64
|
+
expect(subject.valid?).to be_falsey
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '.is_present?' do
|
69
|
+
it 'return true' do
|
70
|
+
expect(subject.present?).to be_truthy
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'with incomplete config' do
|
76
|
+
let(:config_file) { 'spec/fixtures/config/incomplete_config.yml'}
|
77
|
+
|
78
|
+
describe '.app_name' do
|
79
|
+
it 'returns nil' do
|
80
|
+
expect(subject.app_name).to eq('app')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '.is_valid?' do
|
85
|
+
it 'guesses paths and returns true ' do
|
86
|
+
expect(subject.valid?).to be_truthy
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '.is_present?' do
|
91
|
+
it 'returns true' do
|
92
|
+
expect(subject.present?).to be_truthy
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -5,8 +5,8 @@ require 'test_helper'
|
|
5
5
|
|
6
6
|
class AgentSetupInitTest < Minitest::Test
|
7
7
|
CONFIG_FILENAME = '123.yml'
|
8
|
-
|
9
|
-
|
8
|
+
EXPECTED_CONFIG_CONTENT = %(---
|
9
|
+
name: appmap-ruby
|
10
10
|
packages:
|
11
11
|
- path: lib
|
12
12
|
)
|
@@ -14,24 +14,24 @@ packages:
|
|
14
14
|
def test_init_when_config_exists
|
15
15
|
output = `./exe/appmap-agent-init`
|
16
16
|
assert_equal 0, $CHILD_STATUS.exitstatus
|
17
|
-
|
17
|
+
expected = JSON.pretty_generate({
|
18
|
+
configuration: {
|
19
|
+
filename: 'appmap.yml',
|
20
|
+
contents: EXPECTED_CONFIG_CONTENT
|
21
|
+
}
|
22
|
+
})
|
23
|
+
assert_equal expected, output.strip
|
18
24
|
end
|
19
25
|
|
20
26
|
def test_init_with_custom_config_filename
|
21
27
|
output = `./exe/appmap-agent-init -c #{CONFIG_FILENAME}`
|
22
28
|
assert_equal 0, $CHILD_STATUS.exitstatus
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
output = `./exe/appmap-agent-init --config=#{SUBFOLDER_CONFIG_FILEPATH}`
|
31
|
-
assert_equal 0, $CHILD_STATUS.exitstatus
|
32
|
-
assert_includes output, "The following AppMap config file #{SUBFOLDER_CONFIG_FILEPATH} has been created:"
|
33
|
-
assert_equal EXPECTED_CONFIG_CONTENT, File.read(SUBFOLDER_CONFIG_FILEPATH)
|
34
|
-
ensure
|
35
|
-
File.delete(SUBFOLDER_CONFIG_FILEPATH) if File.exist?(SUBFOLDER_CONFIG_FILEPATH)
|
29
|
+
expected = JSON.pretty_generate({
|
30
|
+
configuration: {
|
31
|
+
filename: CONFIG_FILENAME,
|
32
|
+
contents: EXPECTED_CONFIG_CONTENT
|
33
|
+
}
|
34
|
+
})
|
35
|
+
assert_equal expected, output.strip
|
36
36
|
end
|
37
37
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
class AgentSetupInitTest < Minitest::Test
|
7
|
+
def test_status_gem
|
8
|
+
output = `./exe/appmap-agent-status`
|
9
|
+
assert_equal 0, $CHILD_STATUS.exitstatus
|
10
|
+
expected = {
|
11
|
+
test_commands: [],
|
12
|
+
properties: {
|
13
|
+
config: {
|
14
|
+
app: 'AppMap Rubygem',
|
15
|
+
present: true,
|
16
|
+
valid: true
|
17
|
+
},
|
18
|
+
project: {
|
19
|
+
agentVersion: AppMap::VERSION,
|
20
|
+
language: 'ruby',
|
21
|
+
remoteRecordingCapable: false,
|
22
|
+
integrationTests: false
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
assert_equal JSON.pretty_generate(expected), output.strip
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_status_rails_app
|
30
|
+
def test_status
|
31
|
+
output = `cd spec/fixtures/rails6_users_app && bundle exec ../../../exe/appmap-agent-status`
|
32
|
+
assert_equal 0, $CHILD_STATUS.exitstatus
|
33
|
+
expected = {
|
34
|
+
test_commands: [
|
35
|
+
{
|
36
|
+
framework: :rspec,
|
37
|
+
command: 'APPMAP=true bundle exec rspec spec/controllers'
|
38
|
+
},
|
39
|
+
{
|
40
|
+
framework: :minitest,
|
41
|
+
command: 'APPMAP=true bundle exec ruby test/controllers && APPMAP=true bundle exec ruby test/integration'
|
42
|
+
},
|
43
|
+
{
|
44
|
+
framework: :cucumber,
|
45
|
+
command: 'APPMAP=true bundle exec cucumber'
|
46
|
+
}
|
47
|
+
],
|
48
|
+
properties: {
|
49
|
+
config: {
|
50
|
+
app: nil,
|
51
|
+
present: true,
|
52
|
+
valid: true
|
53
|
+
},
|
54
|
+
project: {
|
55
|
+
agentVersion: AppMap::VERSION,
|
56
|
+
language: 'ruby',
|
57
|
+
remoteRecordingCapable: false,
|
58
|
+
integrationTests: true
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
assert_equal JSON.pretty_generate(expected), output.strip
|
63
|
+
end
|
64
|
+
end
|
65
|
+
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.
|
4
|
+
version: 0.58.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-06
|
11
|
+
date: 2021-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -295,6 +295,7 @@ email:
|
|
295
295
|
- kgilpin@gmail.com
|
296
296
|
executables:
|
297
297
|
- appmap-agent-init
|
298
|
+
- appmap-agent-status
|
298
299
|
- appmap-inspect
|
299
300
|
extensions:
|
300
301
|
- ext/appmap/extconf.rb
|
@@ -324,6 +325,7 @@ files:
|
|
324
325
|
- examples/mock_webapp/lib/mock_webapp/request.rb
|
325
326
|
- examples/mock_webapp/lib/mock_webapp/user.rb
|
326
327
|
- exe/appmap-agent-init
|
328
|
+
- exe/appmap-agent-status
|
327
329
|
- exe/appmap-inspect
|
328
330
|
- ext/appmap/appmap.c
|
329
331
|
- ext/appmap/extconf.rb
|
@@ -331,6 +333,7 @@ files:
|
|
331
333
|
- lib/appmap/agent.rb
|
332
334
|
- lib/appmap/class_map.rb
|
333
335
|
- lib/appmap/command/agent_setup/init.rb
|
336
|
+
- lib/appmap/command/agent_setup/status.rb
|
334
337
|
- lib/appmap/command/inspect.rb
|
335
338
|
- lib/appmap/command_error.rb
|
336
339
|
- lib/appmap/config.rb
|
@@ -351,7 +354,11 @@ files:
|
|
351
354
|
- lib/appmap/railtie.rb
|
352
355
|
- lib/appmap/record.rb
|
353
356
|
- lib/appmap/rspec.rb
|
357
|
+
- lib/appmap/service/config_analyzer.rb
|
354
358
|
- lib/appmap/service/guesser.rb
|
359
|
+
- lib/appmap/service/integration_test_path_finder.rb
|
360
|
+
- lib/appmap/service/test_command_provider.rb
|
361
|
+
- lib/appmap/service/test_framework_detector.rb
|
355
362
|
- lib/appmap/swagger.rb
|
356
363
|
- lib/appmap/swagger/configuration.rb
|
357
364
|
- lib/appmap/swagger/markdown_descriptions.rb
|
@@ -364,6 +371,9 @@ files:
|
|
364
371
|
- release.sh
|
365
372
|
- spec/class_map_spec.rb
|
366
373
|
- spec/config_spec.rb
|
374
|
+
- spec/fixtures/config/incomplete_config.yml
|
375
|
+
- spec/fixtures/config/invalid_config.yml
|
376
|
+
- spec/fixtures/config/valid_config.yml
|
367
377
|
- spec/fixtures/hook/.gitignore
|
368
378
|
- spec/fixtures/hook/app/controllers/api/api_keys_controller.rb
|
369
379
|
- spec/fixtures/hook/app/controllers/organizations_controller.rb
|
@@ -536,6 +546,8 @@ files:
|
|
536
546
|
- spec/fixtures/rails6_users_app/spec/models/user_spec.rb
|
537
547
|
- spec/fixtures/rails6_users_app/spec/rails_helper.rb
|
538
548
|
- spec/fixtures/rails6_users_app/spec/spec_helper.rb
|
549
|
+
- spec/fixtures/rails6_users_app/test/controllers/functional_calc_test.rb
|
550
|
+
- spec/fixtures/rails6_users_app/test/integration/integration_calc_test.rb
|
539
551
|
- spec/fixtures/rails6_users_app/users_app/.gitignore
|
540
552
|
- spec/hook_spec.rb
|
541
553
|
- spec/open_spec.rb
|
@@ -545,10 +557,12 @@ files:
|
|
545
557
|
- spec/record_net_http_spec.rb
|
546
558
|
- spec/record_sql_rails_pg_spec.rb
|
547
559
|
- spec/remote_recording_spec.rb
|
560
|
+
- spec/service/config_analyzer_spec.rb
|
548
561
|
- spec/spec_helper.rb
|
549
562
|
- spec/swagger/swagger_spec.rb
|
550
563
|
- spec/util_spec.rb
|
551
564
|
- test/agent_setup_init_test.rb
|
565
|
+
- test/agent_setup_status_test.rb
|
552
566
|
- test/bundle_vendor_test.rb
|
553
567
|
- test/cucumber_test.rb
|
554
568
|
- test/expectations/openssl_test_key_sign1.json
|