appmap 0.23.0 → 0.25.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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +17 -8
  4. data/.travis.yml +6 -0
  5. data/CHANGELOG.md +19 -0
  6. data/README.md +29 -12
  7. data/Rakefile +3 -3
  8. data/appmap.gemspec +3 -1
  9. data/exe/appmap +6 -18
  10. data/lib/appmap.rb +47 -6
  11. data/lib/appmap/algorithm/prune_class_map.rb +2 -0
  12. data/lib/appmap/algorithm/stats.rb +4 -2
  13. data/lib/appmap/class_map.rb +143 -0
  14. data/lib/appmap/command/record.rb +8 -6
  15. data/lib/appmap/command/stats.rb +2 -0
  16. data/lib/appmap/command/upload.rb +4 -2
  17. data/lib/appmap/event.rb +168 -0
  18. data/lib/appmap/hook.rb +151 -0
  19. data/lib/appmap/middleware/remote_recording.rb +14 -20
  20. data/lib/appmap/rails/action_handler.rb +10 -6
  21. data/lib/appmap/rails/sql_handler.rb +10 -8
  22. data/lib/appmap/railtie.rb +31 -18
  23. data/lib/appmap/rspec.rb +238 -261
  24. data/lib/appmap/trace.rb +88 -0
  25. data/lib/appmap/version.rb +1 -1
  26. data/package-lock.json +90 -92
  27. data/spec/abstract_controller4_base_spec.rb +1 -1
  28. data/spec/abstract_controller_base_spec.rb +7 -3
  29. data/spec/config_spec.rb +25 -0
  30. data/spec/fixtures/hook/attr_accessor.rb +5 -0
  31. data/spec/fixtures/hook/class_method.rb +17 -0
  32. data/spec/fixtures/hook/constructor.rb +7 -0
  33. data/spec/fixtures/hook/exception_method.rb +11 -0
  34. data/spec/fixtures/hook/instance_method.rb +23 -0
  35. data/spec/fixtures/rails4_users_app/app/controllers/api/users_controller.rb +3 -3
  36. data/spec/fixtures/rails4_users_app/config/database.yml +2 -1
  37. data/spec/fixtures/rails4_users_app/docker-compose.yml +2 -0
  38. data/spec/fixtures/rails_users_app/.ruby-version +1 -1
  39. data/spec/fixtures/rails_users_app/app/controllers/api/users_controller.rb +2 -2
  40. data/spec/fixtures/rails_users_app/config/database.yml +2 -1
  41. data/spec/fixtures/rails_users_app/create_app +1 -0
  42. data/spec/fixtures/rails_users_app/docker-compose.yml +4 -0
  43. data/spec/fixtures/rails_users_app/spec/models/user_spec.rb +1 -1
  44. data/spec/hook_spec.rb +357 -0
  45. data/spec/rails_spec_helper.rb +25 -16
  46. data/spec/railtie_spec.rb +1 -1
  47. data/spec/record_sql_rails_pg_spec.rb +1 -2
  48. data/spec/remote_recording_spec.rb +117 -0
  49. data/spec/spec_helper.rb +1 -0
  50. data/test/cli_test.rb +7 -36
  51. data/test/fixtures/cli_record_test/appmap.yml +2 -1
  52. data/test/fixtures/cli_record_test/lib/cli_record_test/main.rb +4 -2
  53. data/test/test_helper.rb +0 -42
  54. metadata +46 -62
  55. data/exe/_appmap-record-self +0 -49
  56. data/lib/appmap/command/inspect.rb +0 -14
  57. data/lib/appmap/config.rb +0 -65
  58. data/lib/appmap/config/directory.rb +0 -65
  59. data/lib/appmap/config/file.rb +0 -13
  60. data/lib/appmap/config/named_function.rb +0 -21
  61. data/lib/appmap/config/package_dir.rb +0 -52
  62. data/lib/appmap/config/path.rb +0 -25
  63. data/lib/appmap/feature.rb +0 -262
  64. data/lib/appmap/inspect.rb +0 -91
  65. data/lib/appmap/inspect/inspector.rb +0 -99
  66. data/lib/appmap/inspect/parse_node.rb +0 -170
  67. data/lib/appmap/inspect/parser.rb +0 -15
  68. data/lib/appmap/parser.rb +0 -60
  69. data/lib/appmap/rspec/parse_node.rb +0 -41
  70. data/lib/appmap/rspec/parser.rb +0 -15
  71. data/lib/appmap/trace/event_handler/rack_handler_webrick.rb +0 -65
  72. data/lib/appmap/trace/tracer.rb +0 -356
  73. data/spec/fixtures/rails_users_app/bin/_appmap-record-self +0 -29
  74. data/spec/rack_handler_webrick_spec.rb +0 -59
  75. data/test/config_test.rb +0 -149
  76. data/test/explict_inspect_test.rb +0 -29
  77. data/test/fixtures/active_record_like/active_record.rb +0 -2
  78. data/test/fixtures/active_record_like/active_record/aggregations.rb +0 -4
  79. data/test/fixtures/active_record_like/active_record/association.rb +0 -4
  80. data/test/fixtures/active_record_like/active_record/associations/join_dependency.rb +0 -6
  81. data/test/fixtures/active_record_like/active_record/associations/join_dependency/join_base.rb +0 -8
  82. data/test/fixtures/active_record_like/active_record/associations/join_dependency/join_part.rb +0 -8
  83. data/test/fixtures/active_record_like/active_record/caps/caps.rb +0 -4
  84. data/test/fixtures/ignore_non_ruby_file/class.rb +0 -3
  85. data/test/fixtures/ignore_non_ruby_file/non-ruby.txt +0 -1
  86. data/test/fixtures/includes_excludes/lib/a/a_1.rb +0 -6
  87. data/test/fixtures/includes_excludes/lib/a/a_2.rb +0 -6
  88. data/test/fixtures/includes_excludes/lib/a/x/x_1.rb +0 -8
  89. data/test/fixtures/includes_excludes/lib/b/b_1.rb +0 -6
  90. data/test/fixtures/includes_excludes/lib/root_1.rb +0 -4
  91. data/test/fixtures/inspect_multiple_subdirs/module_a.rb +0 -2
  92. data/test/fixtures/inspect_multiple_subdirs/module_a/class_a.rb +0 -5
  93. data/test/fixtures/inspect_multiple_subdirs/module_b.rb +0 -2
  94. data/test/fixtures/inspect_multiple_subdirs/module_b/class_b.rb +0 -5
  95. data/test/fixtures/inspect_multiple_subdirs/module_b/class_c.rb +0 -5
  96. data/test/fixtures/inspect_package/module_a/module_b/class_in_module.rb +0 -6
  97. data/test/fixtures/parse_file/defs_static_function.rb +0 -96
  98. data/test/fixtures/parse_file/function_within_class.rb +0 -36
  99. data/test/fixtures/parse_file/include_public_methods.rb +0 -127
  100. data/test/fixtures/parse_file/instance_function.rb +0 -17
  101. data/test/fixtures/parse_file/modules.rb +0 -71
  102. data/test/fixtures/parse_file/sclass_static_function.rb +0 -88
  103. data/test/fixtures/parse_file/toplevel_class.rb +0 -13
  104. data/test/fixtures/parse_file/toplevel_function.rb +0 -14
  105. data/test/fixtures/trace_test/trace_program_1.rb +0 -44
  106. data/test/implicit_inspect_test.rb +0 -33
  107. data/test/include_exclude_test.rb +0 -48
  108. data/test/prerecorded_trace_test.rb +0 -76
  109. data/test/trace_test.rb +0 -92
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'appmap/config'
5
-
6
- class IncludeExcludeTest < Minitest::Test
7
- include FixtureFile
8
-
9
- INCLUDE_EXCLUDE_FIXTURE_DIR = File.join(FIXTURE_DIR, 'includes_excludes')
10
-
11
- def setup
12
- @package_dir = AppMap::Config::PackageDir.new(File.join(INCLUDE_EXCLUDE_FIXTURE_DIR, 'lib')).tap do |c|
13
- c.package_name = 'include_exclude'
14
- end
15
- end
16
-
17
- def test_exclude_dir
18
- @package_dir.exclude = %w[b]
19
- assert_equal %w[lib/root_1.rb lib/a], normalized_children
20
- end
21
-
22
- def test_exclude_file
23
- @package_dir.exclude = %w[root_1.rb]
24
- assert_equal %w[lib/a lib/b], normalized_children
25
- end
26
-
27
- def test_exclude_subfile
28
- @package_dir.exclude = %w[a/a_1.rb root_1.rb b]
29
- assert_equal %w[lib/a], normalized_children
30
- assert_equal %w[lib/a/a_2.rb lib/a/x], normalize_paths(@package_dir.children.first.children.map(&:path))
31
- end
32
-
33
- def test_exclude_subdir
34
- @package_dir.exclude = %w[a/a_1.rb root_1.rb b a/x]
35
- assert_equal %w[lib/a], normalized_children
36
- assert_equal %w[lib/a/a_2.rb], normalize_paths(@package_dir.children.first.children.map(&:path))
37
- end
38
-
39
- protected
40
-
41
- def normalized_children
42
- normalize_paths(@package_dir.children.map(&:path))
43
- end
44
-
45
- def normalize_paths(paths)
46
- paths.map { |p| Pathname.new(p).to_s.gsub("#{INCLUDE_EXCLUDE_FIXTURE_DIR}/", '') }
47
- end
48
- end
@@ -1,76 +0,0 @@
1
- require 'test_helper'
2
- require 'appmap'
3
- require 'appmap/config'
4
- require 'appmap/inspect'
5
- require 'appmap/trace/tracer'
6
-
7
- class PrerecordedTraceTest < Minitest::Test
8
- # Runs a sequence of pre-recorded events.
9
- def test_trace_web_request
10
- config_yaml = <<-CONFIG
11
- lib/appmap:
12
- type: package
13
- package_name: appmap
14
- exclude:
15
- - appmap/server
16
-
17
- examples:
18
- type: package
19
- package_name: examples
20
- CONFIG
21
-
22
- events = %q(
23
- {"id":1,"event":"call","defined_class":"#<Class:MockWebapp::Controller>","method_id":"instance","path":"/Users/kgilpin/Documents/appland/appmap-ruby/examples/mock_webapp/controller.rb","lineno":11,"static":true,"thread_id":70232530171540,"self":{"class":"Class","value":"MockWebapp::Controller","object_id":70232551211420},"parameters":{}}
24
- {"id":2,"event":"return","defined_class":"#<Class:MockWebapp::Controller>","method_id":"instance","path":"/Users/kgilpin/Documents/appland/appmap-ruby/examples/mock_webapp/controller.rb","lineno":13,"static":true,"thread_id":70232530171540,"return_value":{"class":"MockWebapp::Controller","value":"#\u003cMockWebapp::Controller:0x00007fc094883a18\u003e","object_id":70232551202060},"parent_id":1,"elapsed":7.0e-06}
25
- {"id":3,"event":"call","defined_class":"MockWebapp::Request","method_id":"initialize","path":"/Users/kgilpin/Documents/appland/appmap-ruby/examples/mock_webapp/request.rb","lineno":8,"static":false,"thread_id":70232530171540,"self":{"class":"MockWebapp::Request","value":"#\u003cstruct MockWebapp::Request params=nil\u003e","object_id":70232551201560},"parameters":{"args":{"class":"Array","value":"[{:id=\u003e\"alice\"}]","object_id":70232551201520}}}
26
- {"id":4,"event":"return","defined_class":"MockWebapp::Request","method_id":"initialize","path":"/Users/kgilpin/Documents/appland/appmap-ruby/examples/mock_webapp/request.rb","lineno":10,"static":false,"thread_id":70232530171540,"return_value":{"class":"NilClass","value":null,"object_id":8},"parent_id":3,"elapsed":3.0e-06}
27
- {"id":5,"event":"call","defined_class":"MockWebapp::Controller","method_id":"process","path":"/Users/kgilpin/Documents/appland/appmap-ruby/examples/mock_webapp/controller.rb","lineno":17,"static":false,"thread_id":70232530171540,"self":{"class":"MockWebapp::Controller","value":"#\u003cMockWebapp::Controller:0x00007fc094883a18\u003e","object_id":70232551202060},"parameters":{"request":{"class":"MockWebapp::Request","value":"#\u003cstruct MockWebapp::Request params={:id=\u003e\"alice\"}\u003e","object_id":70232551201560}}}
28
- {"id":6,"event":"call","defined_class":"MockWebapp::User","method_id":"find","path":"/Users/kgilpin/Documents/appland/appmap-ruby/examples/mock_webapp/user.rb","lineno":13,"static":true,"thread_id":70232530171540,"self":{"class":"Class","value":"MockWebapp::User","object_id":70232551218320},"parameters":{"id":{"class":"String","value":"alice","object_id":70232551201600}}}
29
- {"id":7,"event":"return","defined_class":"MockWebapp::User","method_id":"find","path":"/Users/kgilpin/Documents/appland/appmap-ruby/examples/mock_webapp/user.rb","lineno":15,"static":true,"thread_id":70232530171540,"return_value":{"class":"MockWebapp::User","value":"#\u003cstruct MockWebapp::User login=\"alice\"\u003e","object_id":70232551218180},"parent_id":6,"elapsed":3.0e-06}
30
- {"id":8,"event":"return","defined_class":"MockWebapp::Controller","method_id":"process","path":"/Users/kgilpin/Documents/appland/appmap-ruby/examples/mock_webapp/controller.rb","lineno":21,"static":false,"thread_id":70232530171540,"return_value":{"class":"Hash","value":"{:login=\u003e\"alice\"}","object_id":70232551198060},"parent_id":5,"elapsed":0.000251}
31
- )
32
-
33
- require 'yaml'
34
- config = AppMap::Config.load YAML.safe_load(config_yaml)
35
- features = config.source_locations.map(&AppMap::Inspect.method(:detect_features)).flatten
36
- methods = features.map(&:collect_functions).flatten
37
-
38
- def method_call_from_event(evt)
39
- AppMap::Trace::MethodCall.new(evt.id, evt.event.intern, evt.defined_class, evt.method_id, evt.path, evt.lineno,
40
- evt.static, evt.thread_id, evt.self, evt.parameters)
41
- end
42
-
43
- def method_return_from_event(evt, parent_id, elapsed)
44
- AppMap::Trace::MethodReturn.new(evt.id, evt.event.intern, evt.defined_class, evt.method_id, evt.path, evt.lineno,
45
- evt.static, evt.thread_id, nil, nil, evt.return_value).tap do |mr|
46
- assert_equal parent_id, evt.parent_id
47
- mr.parent_id = evt.parent_id
48
- mr.elapsed = evt.elapsed
49
- end
50
- end
51
-
52
- tracer = AppMap::Trace::Tracer.new(methods)
53
- handler = AppMap::Trace::TracePointHandler.new(tracer)
54
- handler.call_constructor = method(:method_call_from_event)
55
- handler.return_constructor = method(:method_return_from_event)
56
-
57
- events = events
58
- .split("\n")
59
- .map(&:strip)
60
- .reject(&:empty?)
61
- .map(&JSON.method(:parse))
62
-
63
- events.each do |evt_hash|
64
- evt = OpenStruct.new(evt_hash.dup)
65
- evt['event'] = evt['event'].intern
66
- handler.handle evt
67
- end
68
-
69
- i = 0
70
- while tracer.event?
71
- event = tracer.next_event
72
- assert_equal events[i], JSON.parse(event.to_h.to_json)
73
- i += 1
74
- end
75
- end
76
- end
data/test/trace_test.rb DELETED
@@ -1,92 +0,0 @@
1
- require 'test_helper'
2
-
3
- class TraceTest < Minitest::Test
4
- class << self
5
- def trace(program_file_path, &block)
6
- require 'appmap/inspect'
7
- features = AppMap::Inspect.inspect_file(:implicit, file_path: program_file_path).flatten
8
- functions = features.map(&:collect_functions).flatten
9
- require 'appmap/trace/tracer'
10
- tracer = AppMap::Trace.tracers.trace(functions)
11
- begin
12
- load program_file_path
13
-
14
- yield tracer
15
- ensure
16
- AppMap::Trace.tracers.delete(tracer)
17
- end
18
- end
19
- end
20
-
21
- def test_print_to_stdout
22
- program_file_path = 'test/fixtures/trace_test/trace_program_1.rb'
23
- self.class.trace(program_file_path) do |tracer|
24
- printer = Fixtures::TraceTest::TraceProgram1::Printer::Stdout.new
25
- Fixtures::TraceTest::TraceProgram1::Main.new(printer).say("hello")
26
-
27
- events = []
28
- while tracer.event?
29
- events << tracer.next_event
30
- end
31
-
32
- assert_equal JSON.pretty_generate(JSON.parse(<<-JSON)), JSON.pretty_generate(extract_summary(events))
33
- [
34
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Main","method_id":"initialize","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":5,"static":false},
35
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Main","method_id":"say","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":9,"static":false},
36
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Printer::Stdout","method_id":"say","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":17,"static":false}
37
- ]
38
- JSON
39
- end
40
- end
41
-
42
- def test_print_to_stderr
43
- program_file_path = 'test/fixtures/trace_test/trace_program_1.rb'
44
- self.class.trace(program_file_path) do |tracer|
45
- # printer = Fixtures::TraceTest::TraceProgram1::Printer.make_stderr_printer
46
- printer = Fixtures::TraceTest::TraceProgram1::Printer::Stderr
47
- Fixtures::TraceTest::TraceProgram1::Main.new(printer).say("hello")
48
-
49
- events = []
50
- while tracer.event?
51
- events << tracer.next_event
52
- end
53
-
54
- assert_equal JSON.pretty_generate(JSON.parse(<<-JSON)), JSON.pretty_generate(extract_summary(events))
55
- [
56
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Main","method_id":"initialize","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":5,"static":false},
57
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Main","method_id":"say","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":9,"static":false},
58
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Printer::Stderr","method_id":"say","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":25,"static":true}
59
- ]
60
- JSON
61
- end
62
- end
63
-
64
- def test_print_to_stderr_via_instance_sclass
65
- program_file_path = 'test/fixtures/trace_test/trace_program_1.rb'
66
- self.class.trace(program_file_path) do |tracer|
67
- printer = Fixtures::TraceTest::TraceProgram1::Printer.make_stderr_printer
68
-
69
- Fixtures::TraceTest::TraceProgram1::Main.new(printer).say("hello")
70
-
71
- events = []
72
- while tracer.event?
73
- events << tracer.next_event
74
- end
75
-
76
- assert_equal JSON.pretty_generate(JSON.parse(<<-JSON)), JSON.pretty_generate(extract_summary(events))
77
- [
78
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Printer","method_id":"make_stderr_printer","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":32,"static":true},
79
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Main","method_id":"initialize","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":5,"static":false},
80
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Main","method_id":"say","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":9,"static":false},
81
- {"defined_class":"Fixtures::TraceTest::TraceProgram1::Printer::Stdout","method_id":"say","path":"test/fixtures/trace_test/trace_program_1.rb","lineno":35,"static":true}
82
- ]
83
- JSON
84
- end
85
- end
86
-
87
- def extract_summary(events)
88
- events.select { |e| e.event == :call }
89
- .map(&:to_h)
90
- .map { |h| h.keep_if { |k, _| %i[defined_class method_id path lineno static].member?(k) } }
91
- end
92
- end