appmap 0.23.0 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
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