appmap 0.31.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 (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