appmap 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (259) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.gitignore +17 -0
  4. data/.rubocop.yml +27 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +44 -0
  7. data/CHANGELOG.md +199 -0
  8. data/Dockerfile.appmap +5 -0
  9. data/Gemfile +5 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +300 -0
  12. data/Rakefile +132 -0
  13. data/appmap.gemspec +44 -0
  14. data/appmap.yml +8 -0
  15. data/examples/install.rb +76 -0
  16. data/examples/mock_webapp/Gemfile +1 -0
  17. data/examples/mock_webapp/appmap.yml +2 -0
  18. data/examples/mock_webapp/exe/mock_webapp_request +12 -0
  19. data/examples/mock_webapp/lib/mock_webapp/controller.rb +23 -0
  20. data/examples/mock_webapp/lib/mock_webapp/request.rb +12 -0
  21. data/examples/mock_webapp/lib/mock_webapp/user.rb +18 -0
  22. data/exe/appmap +154 -0
  23. data/lib/appmap.rb +87 -0
  24. data/lib/appmap/algorithm/prune_class_map.rb +67 -0
  25. data/lib/appmap/algorithm/stats.rb +91 -0
  26. data/lib/appmap/class_map.rb +135 -0
  27. data/lib/appmap/command/record.rb +38 -0
  28. data/lib/appmap/command/stats.rb +14 -0
  29. data/lib/appmap/config.rb +91 -0
  30. data/lib/appmap/cucumber.rb +89 -0
  31. data/lib/appmap/event.rb +168 -0
  32. data/lib/appmap/hook.rb +130 -0
  33. data/lib/appmap/metadata.rb +62 -0
  34. data/lib/appmap/middleware/remote_recording.rb +114 -0
  35. data/lib/appmap/minitest.rb +141 -0
  36. data/lib/appmap/rails/action_handler.rb +91 -0
  37. data/lib/appmap/rails/sql_handler.rb +145 -0
  38. data/lib/appmap/railtie.rb +45 -0
  39. data/lib/appmap/record.rb +27 -0
  40. data/lib/appmap/rspec.rb +301 -0
  41. data/lib/appmap/trace.rb +96 -0
  42. data/lib/appmap/util.rb +40 -0
  43. data/lib/appmap/version.rb +9 -0
  44. data/lore/pages/2019-05-21-install-and-record/index.pug +51 -0
  45. data/lore/pages/2019-05-21-install-and-record/install_example_appmap.png +0 -0
  46. data/lore/pages/2019-05-21-install-and-record/metadata.yml +5 -0
  47. data/lore/pages/layout.pug +66 -0
  48. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap-grid.css +1912 -0
  49. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap-grid.css.map +1 -0
  50. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap-grid.min.css +7 -0
  51. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap-grid.min.css.map +1 -0
  52. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap-reboot.css +331 -0
  53. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap-reboot.css.map +1 -0
  54. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap-reboot.min.css +8 -0
  55. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap-reboot.min.css.map +1 -0
  56. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap.css +9030 -0
  57. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap.css.map +1 -0
  58. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap.min.css +7 -0
  59. data/lore/public/lib/bootstrap-4.1.3/css/bootstrap.min.css.map +1 -0
  60. data/lore/public/stylesheets/style.css +8 -0
  61. data/package-lock.json +1064 -0
  62. data/package.json +24 -0
  63. data/spec/abstract_controller4_base_spec.rb +67 -0
  64. data/spec/abstract_controller_base_spec.rb +72 -0
  65. data/spec/config_spec.rb +25 -0
  66. data/spec/fixtures/hook/attr_accessor.rb +5 -0
  67. data/spec/fixtures/hook/compare.rb +7 -0
  68. data/spec/fixtures/hook/constructor.rb +7 -0
  69. data/spec/fixtures/hook/exception_method.rb +11 -0
  70. data/spec/fixtures/hook/instance_method.rb +23 -0
  71. data/spec/fixtures/hook/openssl_sign.rb +87 -0
  72. data/spec/fixtures/hook/singleton_method.rb +54 -0
  73. data/spec/fixtures/rack_users_app/.dockerignore +2 -0
  74. data/spec/fixtures/rack_users_app/.gitignore +2 -0
  75. data/spec/fixtures/rack_users_app/Dockerfile +32 -0
  76. data/spec/fixtures/rack_users_app/Gemfile +10 -0
  77. data/spec/fixtures/rack_users_app/appmap.yml +3 -0
  78. data/spec/fixtures/rack_users_app/config.ru +2 -0
  79. data/spec/fixtures/rack_users_app/docker-compose.yml +9 -0
  80. data/spec/fixtures/rack_users_app/lib/app.rb +36 -0
  81. data/spec/fixtures/rails4_users_app/.gitignore +13 -0
  82. data/spec/fixtures/rails4_users_app/.rbenv-gemsets +2 -0
  83. data/spec/fixtures/rails4_users_app/.ruby-version +1 -0
  84. data/spec/fixtures/rails4_users_app/Dockerfile +30 -0
  85. data/spec/fixtures/rails4_users_app/Dockerfile.pg +3 -0
  86. data/spec/fixtures/rails4_users_app/Gemfile +77 -0
  87. data/spec/fixtures/rails4_users_app/README.rdoc +28 -0
  88. data/spec/fixtures/rails4_users_app/Rakefile +6 -0
  89. data/spec/fixtures/rails4_users_app/app/assets/images/.keep +0 -0
  90. data/spec/fixtures/rails4_users_app/app/assets/javascripts/application.js +16 -0
  91. data/spec/fixtures/rails4_users_app/app/assets/stylesheets/application.css +15 -0
  92. data/spec/fixtures/rails4_users_app/app/controllers/api/users_controller.rb +27 -0
  93. data/spec/fixtures/rails4_users_app/app/controllers/application_controller.rb +5 -0
  94. data/spec/fixtures/rails4_users_app/app/controllers/concerns/.keep +0 -0
  95. data/spec/fixtures/rails4_users_app/app/controllers/health_controller.rb +5 -0
  96. data/spec/fixtures/rails4_users_app/app/controllers/users_controller.rb +5 -0
  97. data/spec/fixtures/rails4_users_app/app/helpers/application_helper.rb +2 -0
  98. data/spec/fixtures/rails4_users_app/app/mailers/.keep +0 -0
  99. data/spec/fixtures/rails4_users_app/app/models/.keep +0 -0
  100. data/spec/fixtures/rails4_users_app/app/models/concerns/.keep +0 -0
  101. data/spec/fixtures/rails4_users_app/app/models/user.rb +18 -0
  102. data/spec/fixtures/rails4_users_app/app/views/layouts/application.html.haml +7 -0
  103. data/spec/fixtures/rails4_users_app/app/views/users/index.html.haml +7 -0
  104. data/spec/fixtures/rails4_users_app/appmap.yml +3 -0
  105. data/spec/fixtures/rails4_users_app/bin/rails +9 -0
  106. data/spec/fixtures/rails4_users_app/bin/setup +29 -0
  107. data/spec/fixtures/rails4_users_app/bin/spring +17 -0
  108. data/spec/fixtures/rails4_users_app/config.ru +4 -0
  109. data/spec/fixtures/rails4_users_app/config/application.rb +26 -0
  110. data/spec/fixtures/rails4_users_app/config/boot.rb +3 -0
  111. data/spec/fixtures/rails4_users_app/config/database.yml +18 -0
  112. data/spec/fixtures/rails4_users_app/config/environment.rb +5 -0
  113. data/spec/fixtures/rails4_users_app/config/environments/development.rb +41 -0
  114. data/spec/fixtures/rails4_users_app/config/environments/production.rb +79 -0
  115. data/spec/fixtures/rails4_users_app/config/environments/test.rb +42 -0
  116. data/spec/fixtures/rails4_users_app/config/initializers/assets.rb +11 -0
  117. data/spec/fixtures/rails4_users_app/config/initializers/backtrace_silencers.rb +7 -0
  118. data/spec/fixtures/rails4_users_app/config/initializers/cookies_serializer.rb +3 -0
  119. data/spec/fixtures/rails4_users_app/config/initializers/filter_parameter_logging.rb +4 -0
  120. data/spec/fixtures/rails4_users_app/config/initializers/inflections.rb +16 -0
  121. data/spec/fixtures/rails4_users_app/config/initializers/mime_types.rb +4 -0
  122. data/spec/fixtures/rails4_users_app/config/initializers/session_store.rb +3 -0
  123. data/spec/fixtures/rails4_users_app/config/initializers/to_time_preserves_timezone.rb +10 -0
  124. data/spec/fixtures/rails4_users_app/config/initializers/wrap_parameters.rb +14 -0
  125. data/spec/fixtures/rails4_users_app/config/locales/en.yml +23 -0
  126. data/spec/fixtures/rails4_users_app/config/routes.rb +12 -0
  127. data/spec/fixtures/rails4_users_app/config/secrets.yml +22 -0
  128. data/spec/fixtures/rails4_users_app/create_app +23 -0
  129. data/spec/fixtures/rails4_users_app/db/migrate/20191127112304_create_users.rb +10 -0
  130. data/spec/fixtures/rails4_users_app/db/schema.rb +26 -0
  131. data/spec/fixtures/rails4_users_app/db/seeds.rb +7 -0
  132. data/spec/fixtures/rails4_users_app/docker-compose.yml +26 -0
  133. data/spec/fixtures/rails4_users_app/lib/assets/.keep +0 -0
  134. data/spec/fixtures/rails4_users_app/lib/tasks/.keep +0 -0
  135. data/spec/fixtures/rails4_users_app/log/.keep +0 -0
  136. data/spec/fixtures/rails4_users_app/public/404.html +67 -0
  137. data/spec/fixtures/rails4_users_app/public/422.html +67 -0
  138. data/spec/fixtures/rails4_users_app/public/500.html +66 -0
  139. data/spec/fixtures/rails4_users_app/public/favicon.ico +0 -0
  140. data/spec/fixtures/rails4_users_app/public/robots.txt +5 -0
  141. data/spec/fixtures/rails4_users_app/spec/controllers/users_controller_api_spec.rb +49 -0
  142. data/spec/fixtures/rails4_users_app/spec/rails_helper.rb +95 -0
  143. data/spec/fixtures/rails4_users_app/spec/spec_helper.rb +96 -0
  144. data/spec/fixtures/rails4_users_app/test/fixtures/users.yml +9 -0
  145. data/spec/fixtures/rails_users_app/.dockerignore +1 -0
  146. data/spec/fixtures/rails_users_app/.gitignore +39 -0
  147. data/spec/fixtures/rails_users_app/.rspec +1 -0
  148. data/spec/fixtures/rails_users_app/.ruby-version +1 -0
  149. data/spec/fixtures/rails_users_app/Dockerfile +29 -0
  150. data/spec/fixtures/rails_users_app/Dockerfile.pg +3 -0
  151. data/spec/fixtures/rails_users_app/Gemfile +52 -0
  152. data/spec/fixtures/rails_users_app/Rakefile +6 -0
  153. data/spec/fixtures/rails_users_app/app/controllers/api/users_controller.rb +27 -0
  154. data/spec/fixtures/rails_users_app/app/controllers/application_controller.rb +2 -0
  155. data/spec/fixtures/rails_users_app/app/controllers/concerns/.keep +0 -0
  156. data/spec/fixtures/rails_users_app/app/controllers/health_controller.rb +5 -0
  157. data/spec/fixtures/rails_users_app/app/controllers/users_controller.rb +5 -0
  158. data/spec/fixtures/rails_users_app/app/models/activerecord/user.rb +18 -0
  159. data/spec/fixtures/rails_users_app/app/models/concerns/.keep +0 -0
  160. data/spec/fixtures/rails_users_app/app/models/sequel/user.rb +25 -0
  161. data/spec/fixtures/rails_users_app/app/views/layouts/application.html.haml +7 -0
  162. data/spec/fixtures/rails_users_app/app/views/users/index.html.haml +7 -0
  163. data/spec/fixtures/rails_users_app/appmap.yml +3 -0
  164. data/spec/fixtures/rails_users_app/bin/appmap +29 -0
  165. data/spec/fixtures/rails_users_app/bin/byebug +29 -0
  166. data/spec/fixtures/rails_users_app/bin/gli +29 -0
  167. data/spec/fixtures/rails_users_app/bin/htmldiff +29 -0
  168. data/spec/fixtures/rails_users_app/bin/ldiff +29 -0
  169. data/spec/fixtures/rails_users_app/bin/nokogiri +29 -0
  170. data/spec/fixtures/rails_users_app/bin/rackup +29 -0
  171. data/spec/fixtures/rails_users_app/bin/rails +4 -0
  172. data/spec/fixtures/rails_users_app/bin/rake +29 -0
  173. data/spec/fixtures/rails_users_app/bin/rspec +29 -0
  174. data/spec/fixtures/rails_users_app/bin/ruby-parse +29 -0
  175. data/spec/fixtures/rails_users_app/bin/ruby-rewrite +29 -0
  176. data/spec/fixtures/rails_users_app/bin/sequel +29 -0
  177. data/spec/fixtures/rails_users_app/bin/setup +25 -0
  178. data/spec/fixtures/rails_users_app/bin/sprockets +29 -0
  179. data/spec/fixtures/rails_users_app/bin/thor +29 -0
  180. data/spec/fixtures/rails_users_app/bin/update +25 -0
  181. data/spec/fixtures/rails_users_app/config.ru +5 -0
  182. data/spec/fixtures/rails_users_app/config/application.rb +51 -0
  183. data/spec/fixtures/rails_users_app/config/boot.rb +3 -0
  184. data/spec/fixtures/rails_users_app/config/credentials.yml.enc +1 -0
  185. data/spec/fixtures/rails_users_app/config/database.yml +18 -0
  186. data/spec/fixtures/rails_users_app/config/environment.rb +5 -0
  187. data/spec/fixtures/rails_users_app/config/environments/development.rb +40 -0
  188. data/spec/fixtures/rails_users_app/config/environments/production.rb +68 -0
  189. data/spec/fixtures/rails_users_app/config/environments/test.rb +36 -0
  190. data/spec/fixtures/rails_users_app/config/initializers/application_controller_renderer.rb +8 -0
  191. data/spec/fixtures/rails_users_app/config/initializers/backtrace_silencers.rb +7 -0
  192. data/spec/fixtures/rails_users_app/config/initializers/cors.rb +16 -0
  193. data/spec/fixtures/rails_users_app/config/initializers/filter_parameter_logging.rb +4 -0
  194. data/spec/fixtures/rails_users_app/config/initializers/inflections.rb +16 -0
  195. data/spec/fixtures/rails_users_app/config/initializers/mime_types.rb +4 -0
  196. data/spec/fixtures/rails_users_app/config/initializers/record_button.rb +3 -0
  197. data/spec/fixtures/rails_users_app/config/initializers/wrap_parameters.rb +9 -0
  198. data/spec/fixtures/rails_users_app/config/locales/en.yml +33 -0
  199. data/spec/fixtures/rails_users_app/config/routes.rb +11 -0
  200. data/spec/fixtures/rails_users_app/create_app +27 -0
  201. data/spec/fixtures/rails_users_app/db/migrate/20190728211408_create_users.rb +9 -0
  202. data/spec/fixtures/rails_users_app/db/schema.rb +23 -0
  203. data/spec/fixtures/rails_users_app/docker-compose.yml +28 -0
  204. data/spec/fixtures/rails_users_app/features/api_users.feature +13 -0
  205. data/spec/fixtures/rails_users_app/features/support/env.rb +4 -0
  206. data/spec/fixtures/rails_users_app/features/support/hooks.rb +11 -0
  207. data/spec/fixtures/rails_users_app/features/support/steps.rb +18 -0
  208. data/spec/fixtures/rails_users_app/lib/tasks/.keep +0 -0
  209. data/spec/fixtures/rails_users_app/log/.keep +0 -0
  210. data/spec/fixtures/rails_users_app/public/robots.txt +1 -0
  211. data/spec/fixtures/rails_users_app/spec/controllers/users_controller_api_spec.rb +29 -0
  212. data/spec/fixtures/rails_users_app/spec/models/user_spec.rb +39 -0
  213. data/spec/fixtures/rails_users_app/spec/rails_helper.rb +66 -0
  214. data/spec/fixtures/rails_users_app/spec/spec_helper.rb +96 -0
  215. data/spec/fixtures/rails_users_app/users_app/.gitignore +20 -0
  216. data/spec/hook_spec.rb +576 -0
  217. data/spec/rails_spec_helper.rb +60 -0
  218. data/spec/railtie_spec.rb +44 -0
  219. data/spec/record_sql_rails4_pg_spec.rb +76 -0
  220. data/spec/record_sql_rails_pg_spec.rb +68 -0
  221. data/spec/remote_recording_spec.rb +117 -0
  222. data/spec/rspec_feature_metadata_spec.rb +32 -0
  223. data/spec/spec_helper.rb +15 -0
  224. data/spec/util_spec.rb +21 -0
  225. data/test/cli_test.rb +116 -0
  226. data/test/cucumber_test.rb +72 -0
  227. data/test/fixtures/cli_record_test/appmap.yml +3 -0
  228. data/test/fixtures/cli_record_test/lib/cli_record_test/main.rb +9 -0
  229. data/test/fixtures/cucumber4_recorder/Gemfile +5 -0
  230. data/test/fixtures/cucumber4_recorder/appmap.yml +3 -0
  231. data/test/fixtures/cucumber4_recorder/features/say_hello.feature +5 -0
  232. data/test/fixtures/cucumber4_recorder/features/support/env.rb +5 -0
  233. data/test/fixtures/cucumber4_recorder/features/support/hooks.rb +11 -0
  234. data/test/fixtures/cucumber4_recorder/features/support/steps.rb +9 -0
  235. data/test/fixtures/cucumber4_recorder/lib/hello.rb +7 -0
  236. data/test/fixtures/cucumber_recorder/Gemfile +5 -0
  237. data/test/fixtures/cucumber_recorder/appmap.yml +3 -0
  238. data/test/fixtures/cucumber_recorder/features/say_hello.feature +5 -0
  239. data/test/fixtures/cucumber_recorder/features/support/env.rb +5 -0
  240. data/test/fixtures/cucumber_recorder/features/support/hooks.rb +11 -0
  241. data/test/fixtures/cucumber_recorder/features/support/steps.rb +9 -0
  242. data/test/fixtures/cucumber_recorder/lib/hello.rb +7 -0
  243. data/test/fixtures/minitest_recorder/Gemfile +5 -0
  244. data/test/fixtures/minitest_recorder/appmap.yml +3 -0
  245. data/test/fixtures/minitest_recorder/lib/hello.rb +5 -0
  246. data/test/fixtures/minitest_recorder/test/hello_test.rb +12 -0
  247. data/test/fixtures/process_recorder/appmap.yml +3 -0
  248. data/test/fixtures/process_recorder/hello.rb +9 -0
  249. data/test/fixtures/rspec_recorder/Gemfile +5 -0
  250. data/test/fixtures/rspec_recorder/appmap.yml +3 -0
  251. data/test/fixtures/rspec_recorder/lib/hello.rb +5 -0
  252. data/test/fixtures/rspec_recorder/spec/decorated_hello_spec.rb +21 -0
  253. data/test/fixtures/rspec_recorder/spec/labeled_hello_spec.rb +9 -0
  254. data/test/fixtures/rspec_recorder/spec/plain_hello_spec.rb +9 -0
  255. data/test/minitest_test.rb +38 -0
  256. data/test/record_process_test.rb +35 -0
  257. data/test/rspec_test.rb +82 -0
  258. data/test/test_helper.rb +4 -0
  259. metadata +525 -0
@@ -0,0 +1,96 @@
1
+ # This file was generated by the `rails generate rspec:install` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+ RSpec.configure do |config|
17
+ # rspec-expectations config goes here. You can use an alternate
18
+ # assertion/expectation library such as wrong or the stdlib/minitest
19
+ # assertions if you prefer.
20
+ config.expect_with :rspec do |expectations|
21
+ # This option will default to `true` in RSpec 4. It makes the `description`
22
+ # and `failure_message` of custom matchers include text for helper methods
23
+ # defined using `chain`, e.g.:
24
+ # be_bigger_than(2).and_smaller_than(4).description
25
+ # # => "be bigger than 2 and smaller than 4"
26
+ # ...rather than:
27
+ # # => "be bigger than 2"
28
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29
+ end
30
+
31
+ # rspec-mocks config goes here. You can use an alternate test double
32
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
33
+ config.mock_with :rspec do |mocks|
34
+ # Prevents you from mocking or stubbing a method that does not exist on
35
+ # a real object. This is generally recommended, and will default to
36
+ # `true` in RSpec 4.
37
+ mocks.verify_partial_doubles = true
38
+ end
39
+
40
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41
+ # have no way to turn it off -- the option exists only for backwards
42
+ # compatibility in RSpec 3). It causes shared context metadata to be
43
+ # inherited by the metadata hash of host groups and examples, rather than
44
+ # triggering implicit auto-inclusion in groups with matching metadata.
45
+ config.shared_context_metadata_behavior = :apply_to_host_groups
46
+
47
+ # The settings below are suggested to provide a good initial experience
48
+ # with RSpec, but feel free to customize to your heart's content.
49
+ =begin
50
+ # This allows you to limit a spec run to individual examples or groups
51
+ # you care about by tagging them with `:focus` metadata. When nothing
52
+ # is tagged with `:focus`, all examples get run. RSpec also provides
53
+ # aliases for `it`, `describe`, and `context` that include `:focus`
54
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
55
+ config.filter_run_when_matching :focus
56
+
57
+ # Allows RSpec to persist some state between runs in order to support
58
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
59
+ # you configure your source control system to ignore this file.
60
+ config.example_status_persistence_file_path = "spec/examples.txt"
61
+
62
+ # Limits the available syntax to the non-monkey patched syntax that is
63
+ # recommended. For more details, see:
64
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
65
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
66
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
67
+ config.disable_monkey_patching!
68
+
69
+ # Many RSpec users commonly either run the entire suite or an individual
70
+ # file, and it's useful to allow more verbose output when running an
71
+ # individual spec file.
72
+ if config.files_to_run.one?
73
+ # Use the documentation formatter for detailed output,
74
+ # unless a formatter has already been configured
75
+ # (e.g. via a command-line flag).
76
+ config.default_formatter = "doc"
77
+ end
78
+
79
+ # Print the 10 slowest examples and example groups at the
80
+ # end of the spec run, to help surface which specs are running
81
+ # particularly slow.
82
+ config.profile_examples = 10
83
+
84
+ # Run specs in random order to surface order dependencies. If you find an
85
+ # order dependency and want to debug it, you can fix the order by providing
86
+ # the seed, which is printed after each run.
87
+ # --seed 1234
88
+ config.order = :random
89
+
90
+ # Seed global randomization in this process using the `--seed` CLI option.
91
+ # Setting this allows you to use `--seed` to deterministically reproduce
92
+ # test failures related to randomization by passing the same `--seed` value
93
+ # as the one that triggered the failure.
94
+ Kernel.srand config.seed
95
+ =end
96
+ end
@@ -0,0 +1,20 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore all logfiles and tempfiles.
11
+ /log/*
12
+ /tmp/*
13
+ !/log/.keep
14
+ !/tmp/.keep
15
+
16
+
17
+ .byebug_history
18
+
19
+ # Ignore master key for decrypting credentials and more.
20
+ /config/master.key
@@ -0,0 +1,576 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_spec_helper'
4
+ require 'appmap/hook'
5
+ require 'appmap/event'
6
+ require 'diffy'
7
+
8
+ # Show nulls as the literal +null+, rather than just leaving the field
9
+ # empty. This make some of the expected YAML below easier to
10
+ # understand.
11
+ module ShowYamlNulls
12
+ def visit_NilClass(o)
13
+ @emitter.scalar('null', nil, 'tag:yaml.org,2002:null', true, false, Psych::Nodes::Scalar::ANY)
14
+ end
15
+ end
16
+ Psych::Visitors::YAMLTree.prepend(ShowYamlNulls)
17
+
18
+ describe 'AppMap class Hooking', docker: false do
19
+ def collect_events(tracer)
20
+ [].tap do |events|
21
+ while tracer.event?
22
+ events << tracer.next_event.to_h
23
+ end
24
+ end.map do |event|
25
+ event.delete(:thread_id)
26
+ event.delete(:elapsed)
27
+ delete_object_id = ->(obj) { (obj || {}).delete(:object_id) }
28
+ delete_object_id.call(event[:receiver])
29
+ delete_object_id.call(event[:return_value])
30
+ (event[:parameters] || []).each(&delete_object_id)
31
+ (event[:exceptions] || []).each(&delete_object_id)
32
+
33
+ case event[:event]
34
+ when :call
35
+ event[:path] = event[:path].gsub(Gem.dir + '/', '')
36
+ when :return
37
+ # These should be removed from the appmap spec
38
+ %i[defined_class method_id path lineno static].each do |obsolete_field|
39
+ event.delete(obsolete_field)
40
+ end
41
+ end
42
+ event
43
+ end.to_yaml
44
+ end
45
+
46
+ def invoke_test_file(file, setup: nil, &block)
47
+ AppMap.configuration = nil
48
+ package = AppMap::Package.new(file, [])
49
+ config = AppMap::Config.new('hook_spec', [ package ])
50
+ AppMap.configuration = config
51
+ tracer = nil
52
+ AppMap::Hook.new(config).enable do
53
+ setup_result = setup.call if setup
54
+
55
+ tracer = AppMap.tracing.trace
56
+ AppMap::Event.reset_id_counter
57
+ begin
58
+ load file
59
+ yield setup_result
60
+ ensure
61
+ AppMap.tracing.delete(tracer)
62
+ end
63
+ end
64
+
65
+ [ config, tracer ]
66
+ end
67
+
68
+ def test_hook_behavior(file, events_yaml, setup: nil, &block)
69
+ config, tracer = invoke_test_file(file, setup: setup, &block)
70
+
71
+ events = collect_events(tracer)
72
+ expect(Diffy::Diff.new(events, events_yaml).to_s).to eq('')
73
+
74
+ [ config, tracer ]
75
+ end
76
+
77
+ after do
78
+ AppMap.configuration = nil
79
+ end
80
+
81
+ it 'hooks an instance method that takes no arguments' do
82
+ events_yaml = <<~YAML
83
+ ---
84
+ - :id: 1
85
+ :event: :call
86
+ :defined_class: InstanceMethod
87
+ :method_id: say_default
88
+ :path: spec/fixtures/hook/instance_method.rb
89
+ :lineno: 8
90
+ :static: false
91
+ :parameters: []
92
+ :receiver:
93
+ :class: InstanceMethod
94
+ :value: Instance Method fixture
95
+ - :id: 2
96
+ :event: :return
97
+ :parent_id: 1
98
+ :return_value:
99
+ :class: String
100
+ :value: default
101
+ YAML
102
+ config, tracer = test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
103
+ expect(InstanceMethod.new.say_default).to eq('default')
104
+ end
105
+ end
106
+
107
+ it 'collects the methods that are invoked' do
108
+ _, tracer = invoke_test_file 'spec/fixtures/hook/instance_method.rb' do
109
+ InstanceMethod.new.say_default
110
+ end
111
+ expect(tracer.event_methods.to_a.map(&:defined_class)).to eq([ 'InstanceMethod' ])
112
+ expect(tracer.event_methods.to_a.map(&:to_s)).to eq([ InstanceMethod.public_instance_method(:say_default).to_s ])
113
+ end
114
+
115
+ it 'builds a class map of invoked methods' do
116
+ _, tracer = invoke_test_file 'spec/fixtures/hook/instance_method.rb' do
117
+ InstanceMethod.new.say_default
118
+ end
119
+ class_map = AppMap.class_map(tracer.event_methods).to_yaml
120
+ expect(Diffy::Diff.new(class_map, <<~YAML).to_s).to eq('')
121
+ ---
122
+ - :name: spec/fixtures/hook/instance_method.rb
123
+ :type: package
124
+ :children:
125
+ - :name: InstanceMethod
126
+ :type: class
127
+ :children:
128
+ - :name: say_default
129
+ :type: function
130
+ :location: spec/fixtures/hook/instance_method.rb:8
131
+ :static: false
132
+ YAML
133
+ end
134
+
135
+ it 'does not hook an attr_accessor' do
136
+ events_yaml = <<~YAML
137
+ --- []
138
+ YAML
139
+ test_hook_behavior 'spec/fixtures/hook/attr_accessor.rb', events_yaml do
140
+ obj = AttrAccessor.new
141
+ obj.value = 'foo'
142
+ expect(obj.value).to eq('foo')
143
+ end
144
+ end
145
+
146
+ it 'does not hook a constructor' do
147
+ events_yaml = <<~YAML
148
+ --- []
149
+ YAML
150
+ test_hook_behavior 'spec/fixtures/hook/constructor.rb', events_yaml do
151
+ Constructor.new('foo')
152
+ end
153
+ end
154
+
155
+ it 'hooks an instance method that takes an argument' do
156
+ events_yaml = <<~YAML
157
+ ---
158
+ - :id: 1
159
+ :event: :call
160
+ :defined_class: InstanceMethod
161
+ :method_id: say_echo
162
+ :path: spec/fixtures/hook/instance_method.rb
163
+ :lineno: 12
164
+ :static: false
165
+ :parameters:
166
+ - :name: :arg
167
+ :class: String
168
+ :value: echo
169
+ :kind: :req
170
+ :receiver:
171
+ :class: InstanceMethod
172
+ :value: Instance Method fixture
173
+ - :id: 2
174
+ :event: :return
175
+ :parent_id: 1
176
+ :return_value:
177
+ :class: String
178
+ :value: echo
179
+ YAML
180
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
181
+ expect(InstanceMethod.new.say_echo('echo')).to eq('echo')
182
+ end
183
+ end
184
+
185
+ it 'hooks an instance method that takes a keyword argument' do
186
+ events_yaml = <<~YAML
187
+ ---
188
+ - :id: 1
189
+ :event: :call
190
+ :defined_class: InstanceMethod
191
+ :method_id: say_kw
192
+ :path: spec/fixtures/hook/instance_method.rb
193
+ :lineno: 16
194
+ :static: false
195
+ :parameters:
196
+ - :name: :kw
197
+ :class: Hash
198
+ :value: '{:kw=>"kw"}'
199
+ :kind: :key
200
+ :receiver:
201
+ :class: InstanceMethod
202
+ :value: Instance Method fixture
203
+ - :id: 2
204
+ :event: :return
205
+ :parent_id: 1
206
+ :return_value:
207
+ :class: String
208
+ :value: kw
209
+ YAML
210
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
211
+ expect(InstanceMethod.new.say_kw(kw: 'kw')).to eq('kw')
212
+ end
213
+ end
214
+
215
+ it 'hooks an instance method that takes a default keyword argument' do
216
+ events_yaml = <<~YAML
217
+ ---
218
+ - :id: 1
219
+ :event: :call
220
+ :defined_class: InstanceMethod
221
+ :method_id: say_kw
222
+ :path: spec/fixtures/hook/instance_method.rb
223
+ :lineno: 16
224
+ :static: false
225
+ :parameters:
226
+ - :name: :kw
227
+ :class: NilClass
228
+ :value: null
229
+ :kind: :key
230
+ :receiver:
231
+ :class: InstanceMethod
232
+ :value: Instance Method fixture
233
+ - :id: 2
234
+ :event: :return
235
+ :parent_id: 1
236
+ :return_value:
237
+ :class: String
238
+ :value: kw
239
+ YAML
240
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
241
+ expect(InstanceMethod.new.say_kw).to eq('kw')
242
+ end
243
+ end
244
+
245
+ it 'hooks an instance method that takes a block argument' do
246
+ events_yaml = <<~YAML
247
+ ---
248
+ - :id: 1
249
+ :event: :call
250
+ :defined_class: InstanceMethod
251
+ :method_id: say_block
252
+ :path: spec/fixtures/hook/instance_method.rb
253
+ :lineno: 20
254
+ :static: false
255
+ :parameters:
256
+ - :name: :block
257
+ :class: NilClass
258
+ :value: null
259
+ :kind: :block
260
+ :receiver:
261
+ :class: InstanceMethod
262
+ :value: Instance Method fixture
263
+ - :id: 2
264
+ :event: :return
265
+ :parent_id: 1
266
+ :return_value:
267
+ :class: String
268
+ :value: albert
269
+ YAML
270
+ test_hook_behavior 'spec/fixtures/hook/instance_method.rb', events_yaml do
271
+ expect(InstanceMethod.new.say_block { 'albert' }).to eq('albert')
272
+ end
273
+ end
274
+
275
+ it 'hooks a singleton method' do
276
+ events_yaml = <<~YAML
277
+ ---
278
+ - :id: 1
279
+ :event: :call
280
+ :defined_class: SingletonMethod
281
+ :method_id: say_default
282
+ :path: spec/fixtures/hook/singleton_method.rb
283
+ :lineno: 5
284
+ :static: true
285
+ :parameters: []
286
+ :receiver:
287
+ :class: Class
288
+ :value: SingletonMethod
289
+ - :id: 2
290
+ :event: :return
291
+ :parent_id: 1
292
+ :return_value:
293
+ :class: String
294
+ :value: default
295
+ YAML
296
+ test_hook_behavior 'spec/fixtures/hook/singleton_method.rb', events_yaml do
297
+ expect(SingletonMethod.say_default).to eq('default')
298
+ end
299
+ end
300
+
301
+ it 'hooks a class method with explicit class name scope' do
302
+ events_yaml = <<~YAML
303
+ ---
304
+ - :id: 1
305
+ :event: :call
306
+ :defined_class: SingletonMethod
307
+ :method_id: say_class_defined
308
+ :path: spec/fixtures/hook/singleton_method.rb
309
+ :lineno: 10
310
+ :static: true
311
+ :parameters: []
312
+ :receiver:
313
+ :class: Class
314
+ :value: SingletonMethod
315
+ - :id: 2
316
+ :event: :return
317
+ :parent_id: 1
318
+ :return_value:
319
+ :class: String
320
+ :value: defined with explicit class scope
321
+ YAML
322
+ test_hook_behavior 'spec/fixtures/hook/singleton_method.rb', events_yaml do
323
+ expect(SingletonMethod.say_class_defined).to eq('defined with explicit class scope')
324
+ end
325
+ end
326
+
327
+ it "hooks a class method with 'self' as the class name scope" do
328
+ events_yaml = <<~YAML
329
+ ---
330
+ - :id: 1
331
+ :event: :call
332
+ :defined_class: SingletonMethod
333
+ :method_id: say_self_defined
334
+ :path: spec/fixtures/hook/singleton_method.rb
335
+ :lineno: 14
336
+ :static: true
337
+ :parameters: []
338
+ :receiver:
339
+ :class: Class
340
+ :value: SingletonMethod
341
+ - :id: 2
342
+ :event: :return
343
+ :parent_id: 1
344
+ :return_value:
345
+ :class: String
346
+ :value: defined with self class scope
347
+ YAML
348
+ test_hook_behavior 'spec/fixtures/hook/singleton_method.rb', events_yaml do
349
+ expect(SingletonMethod.say_self_defined).to eq('defined with self class scope')
350
+ end
351
+ end
352
+
353
+
354
+ it 'hooks an included method' do
355
+ events_yaml = <<~YAML
356
+ ---
357
+ - :id: 1
358
+ :event: :call
359
+ :defined_class: SingletonMethod
360
+ :method_id: added_method
361
+ :path: spec/fixtures/hook/singleton_method.rb
362
+ :lineno: 44
363
+ :static: false
364
+ :parameters: []
365
+ :receiver:
366
+ :class: SingletonMethod
367
+ :value: Singleton Method fixture
368
+ - :id: 2
369
+ :event: :call
370
+ :defined_class: AddMethod
371
+ :method_id: _added_method
372
+ :path: spec/fixtures/hook/singleton_method.rb
373
+ :lineno: 50
374
+ :static: false
375
+ :parameters: []
376
+ :receiver:
377
+ :class: SingletonMethod
378
+ :value: Singleton Method fixture
379
+ - :id: 3
380
+ :event: :return
381
+ :parent_id: 2
382
+ :return_value:
383
+ :class: String
384
+ :value: defined by including a module
385
+ - :id: 4
386
+ :event: :return
387
+ :parent_id: 1
388
+ :return_value:
389
+ :class: String
390
+ :value: defined by including a module
391
+ YAML
392
+
393
+ load 'spec/fixtures/hook/singleton_method.rb'
394
+ setup = -> { SingletonMethod.new.do_include }
395
+ test_hook_behavior 'spec/fixtures/hook/singleton_method.rb', events_yaml, setup: setup do |s|
396
+ expect(s.added_method).to eq('defined by including a module')
397
+ end
398
+ end
399
+
400
+ it "doesn't hook a singleton method defined for an instance" do
401
+ # Ideally, Ruby would fire a TracePoint event when a singleton
402
+ # class gets created by defining a method on an instance. It
403
+ # currently doesn't, though, so there's no way for us to hook such
404
+ # a method.
405
+ #
406
+ # This example will fail if Ruby's behavior changes at some point
407
+ # in the future.
408
+ events_yaml = <<~YAML
409
+ --- []
410
+ YAML
411
+
412
+ load 'spec/fixtures/hook/singleton_method.rb'
413
+ setup = -> { SingletonMethod.new_with_instance_method }
414
+ test_hook_behavior 'spec/fixtures/hook/singleton_method.rb', events_yaml, setup: setup do |s|
415
+ expect(s.say_instance_defined).to eq('defined for an instance')
416
+ end
417
+ end
418
+
419
+ it 'Reports exceptions' do
420
+ events_yaml = <<~YAML
421
+ ---
422
+ - :id: 1
423
+ :event: :call
424
+ :defined_class: ExceptionMethod
425
+ :method_id: raise_exception
426
+ :path: spec/fixtures/hook/exception_method.rb
427
+ :lineno: 8
428
+ :static: false
429
+ :parameters: []
430
+ :receiver:
431
+ :class: ExceptionMethod
432
+ :value: Exception Method fixture
433
+ - :id: 2
434
+ :event: :return
435
+ :parent_id: 1
436
+ :exceptions:
437
+ - :class: RuntimeError
438
+ :message: Exception occurred in raise_exception
439
+ :path: spec/fixtures/hook/exception_method.rb
440
+ :lineno: 9
441
+ YAML
442
+ test_hook_behavior 'spec/fixtures/hook/exception_method.rb', events_yaml do
443
+ begin
444
+ ExceptionMethod.new.raise_exception
445
+ rescue
446
+ # don't let the exception fail the test
447
+ end
448
+ end
449
+ end
450
+
451
+ it 're-raises exceptions' do
452
+ RSpec::Expectations.configuration.on_potential_false_positives = :nothing
453
+
454
+ invoke_test_file 'spec/fixtures/hook/exception_method.rb' do
455
+ expect { ExceptionMethod.new.raise_exception }.to raise_exception
456
+ end
457
+ end
458
+
459
+ context 'OpenSSL::X509::Certificate.sign' do
460
+ # OpenSSL::X509 is not being hooked.
461
+ # This might be because the class is being loaded before AppMap, and so the TracePoint
462
+ # set by AppMap doesn't see it.
463
+ xit 'is hooked' do
464
+ events_yaml = <<~YAML
465
+ ---
466
+ YAML
467
+ test_hook_behavior 'spec/fixtures/hook/openssl_sign.rb', events_yaml do
468
+ expect(OpenSSLExample.example).to be_truthy
469
+ end
470
+ end
471
+ end
472
+
473
+ context 'ActiveSupport::SecurityUtils.secure_compare' do
474
+ it 'is hooked' do
475
+ events_yaml = <<~YAML
476
+ ---
477
+ - :id: 1
478
+ :event: :call
479
+ :defined_class: Compare
480
+ :method_id: compare
481
+ :path: spec/fixtures/hook/compare.rb
482
+ :lineno: 4
483
+ :static: true
484
+ :parameters:
485
+ - :name: :s1
486
+ :class: String
487
+ :value: string
488
+ :kind: :req
489
+ - :name: :s2
490
+ :class: String
491
+ :value: string
492
+ :kind: :req
493
+ :receiver:
494
+ :class: Class
495
+ :value: Compare
496
+ - :id: 2
497
+ :event: :call
498
+ :defined_class: ActiveSupport::SecurityUtils
499
+ :method_id: secure_compare
500
+ :path: gems/activesupport-6.0.3.2/lib/active_support/security_utils.rb
501
+ :lineno: 26
502
+ :static: true
503
+ :parameters:
504
+ - :name: :a
505
+ :class: String
506
+ :value: string
507
+ :kind: :req
508
+ - :name: :b
509
+ :class: String
510
+ :value: string
511
+ :kind: :req
512
+ :receiver:
513
+ :class: Module
514
+ :value: ActiveSupport::SecurityUtils
515
+ - :id: 3
516
+ :event: :return
517
+ :parent_id: 2
518
+ :return_value:
519
+ :class: TrueClass
520
+ :value: 'true'
521
+ - :id: 4
522
+ :event: :return
523
+ :parent_id: 1
524
+ :return_value:
525
+ :class: TrueClass
526
+ :value: 'true'
527
+ YAML
528
+
529
+ test_hook_behavior 'spec/fixtures/hook/compare.rb', events_yaml do
530
+ expect(Compare.compare('string', 'string')).to be_truthy
531
+ end
532
+ end
533
+
534
+ it 'gets labeled in the classmap' do
535
+ classmap_yaml = <<~YAML
536
+ ---
537
+ - :name: spec/fixtures/hook/compare.rb
538
+ :type: package
539
+ :children:
540
+ - :name: Compare
541
+ :type: class
542
+ :children:
543
+ - :name: compare
544
+ :type: function
545
+ :location: spec/fixtures/hook/compare.rb:4
546
+ :static: true
547
+ - :name: active_support
548
+ :type: package
549
+ :children:
550
+ - :name: ActiveSupport
551
+ :type: class
552
+ :children:
553
+ - :name: SecurityUtils
554
+ :type: class
555
+ :children:
556
+ - :name: secure_compare
557
+ :type: function
558
+ :location: gems/activesupport-6.0.3.2/lib/active_support/security_utils.rb:26
559
+ :static: true
560
+ :labels:
561
+ - security
562
+ YAML
563
+
564
+ config, tracer = invoke_test_file 'spec/fixtures/hook/compare.rb' do
565
+ expect(Compare.compare('string', 'string')).to be_truthy
566
+ end
567
+ cm = AppMap::ClassMap.build_from_methods(config, tracer.event_methods)
568
+ entry = cm[1][:children][0][:children][0][:children][0]
569
+ # Sanity check, make sure we got the right one
570
+ expect(entry[:name]).to eq('secure_compare')
571
+ spec = Gem::Specification.find_by_name('activesupport')
572
+ entry[:location].gsub!(spec.base_dir + '/', '')
573
+ expect(Diffy::Diff.new(cm.to_yaml, classmap_yaml).to_s).to eq('')
574
+ end
575
+ end
576
+ end