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,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'open3'
5
+
6
+ def wait_for_container(app_name)
7
+ start_time = Time.now
8
+ until `docker-compose ps -q --filter health=healthy #{app_name}`.strip != ''
9
+ elapsed = Time.now - start_time
10
+ raise "Timeout waiting for container #{app_name} to be ready" if elapsed > 10
11
+
12
+ $stderr.write '.' if elapsed > 3
13
+ sleep 0.25
14
+ end
15
+ end
16
+
17
+ def run_cmd(*cmd, &failed)
18
+ out, status = Open3.capture2e(*cmd)
19
+ return [ out, status ] if status.success?
20
+
21
+ warn <<~WARNING
22
+ Command failed:
23
+ #{cmd}
24
+ <<< Output:
25
+ #{out}
26
+ >>> End of output
27
+ WARNING
28
+ failed&.call
29
+ raise 'Command failed'
30
+ end
31
+
32
+ shared_context 'Rails app pg database' do
33
+ before(:all) do
34
+ raise 'you must set @fixure_dir' unless @fixture_dir
35
+
36
+ print_pg_logs = lambda do
37
+ logs, = run_cmd 'docker-compose logs pg'
38
+ puts "docker-compose logs for pg:"
39
+ puts
40
+ puts logs
41
+ end
42
+
43
+ Dir.chdir @fixture_dir do
44
+ run_cmd 'docker-compose down -v'
45
+ cmd = 'docker-compose up -d pg'
46
+ run_cmd cmd
47
+ wait_for_container 'pg'
48
+
49
+ cmd = 'docker-compose run --rm app ./create_app'
50
+ run_cmd cmd, &print_pg_logs
51
+ end
52
+ end
53
+
54
+ after(:all) do
55
+ if ENV['NOKILL'] != 'true'
56
+ cmd = 'docker-compose down -v'
57
+ run_cmd cmd, chdir: @fixture_dir
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,44 @@
1
+ require 'rails_spec_helper'
2
+
3
+ describe 'AppMap tracer via Railtie' do
4
+ before(:all) { @fixture_dir = 'spec/fixtures/rails_users_app' }
5
+ include_context 'Rails app pg database'
6
+
7
+ let(:env) { {} }
8
+
9
+ let(:cmd) { %(docker-compose run --rm -e RAILS_ENV -e APPMAP app ./bin/rails r "puts Rails.configuration.appmap.enabled.inspect") }
10
+ let(:command_capture2) do
11
+ require 'open3'
12
+ Open3.capture3(env, cmd, chdir: @fixture_dir).tap do |result|
13
+ unless result[2] == 0
14
+ $stderr.puts <<~END
15
+ Failed to run rails_users_app container
16
+ <<< Output:
17
+ #{result[0]}
18
+ #{result[1]}
19
+ >>> End of output
20
+ END
21
+ raise 'Failed to run rails_users_app container'
22
+ end
23
+ end
24
+ end
25
+ let(:command_output) { command_capture2[0].strip }
26
+ let(:command_result) { command_capture2[2] }
27
+
28
+ it 'is disabled by default' do
29
+ expect(command_output).to eq('nil')
30
+ end
31
+
32
+ describe 'with APPMAP=true' do
33
+ let(:env) { { 'APPMAP' => 'true' } }
34
+ it 'is enabled' do
35
+ expect(command_output.split("\n")).to include('true')
36
+ end
37
+ context 'and RAILS_ENV=test' do
38
+ let(:env) { { 'APPMAP' => 'true', 'RAILS_ENV' => 'test' } }
39
+ it 'is disabled' do
40
+ expect(command_output).to eq('nil')
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,76 @@
1
+ require 'rails_spec_helper'
2
+
3
+ describe 'Record SQL queries in a Rails4 app' do
4
+ before(:all) { @fixture_dir = 'spec/fixtures/rails4_users_app' }
5
+ include_context 'Rails app pg database'
6
+
7
+ around(:each) do |example|
8
+ FileUtils.rm_rf tmpdir
9
+ FileUtils.mkdir_p tmpdir
10
+ cmd = "docker-compose run --rm -e ORM_MODULE=#{orm_module} -e APPMAP=true -v #{File.absolute_path tmpdir}:/app/tmp app ./bin/rspec spec/controllers/users_controller_api_spec.rb:#{test_line_number}"
11
+ run_cmd cmd, chdir: @fixture_dir
12
+
13
+ example.run
14
+ end
15
+
16
+ let(:tmpdir) { "tmp/spec/record_sql_rails_pg_spec" }
17
+ let(:appmap) { JSON.parse(File.read(appmap_json)).to_yaml }
18
+
19
+ context 'when running specs' do
20
+ let(:test_line_number) { 31 }
21
+ let(:orm_module) { 'activerecord' }
22
+
23
+ it { is_expected.to be }
24
+ end
25
+
26
+ context 'while creating a new record' do
27
+ let(:test_line_number) { 8 }
28
+ let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json') }
29
+
30
+ xcontext 'using Sequel ORM' do
31
+ let(:orm_module) { 'sequel' }
32
+ it 'detects the sql INSERT' do
33
+ expect(appmap).to include(<<-SQL_QUERY.strip)
34
+ sql_query:
35
+ sql: INSERT INTO "users" ("login") VALUES ('alice') RETURNING *
36
+ SQL_QUERY
37
+ end
38
+ end
39
+ context 'using ActiveRecord ORM' do
40
+ let(:orm_module) { 'activerecord' }
41
+ it 'detects the sql INSERT' do
42
+ expect(appmap).to include(<<-SQL_QUERY.strip)
43
+ sql_query:
44
+ sql: INSERT INTO "users" ("login", "created_at", "updated_at") VALUES ($1, $2,
45
+ $3) RETURNING "id"
46
+ SQL_QUERY
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'while listing records' do
52
+ let(:test_line_number) { 23 }
53
+ let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_GET_api_users_lists_the_users.appmap.json') }
54
+
55
+ xcontext 'using Sequel ORM' do
56
+ let(:orm_module) { 'sequel' }
57
+ it 'detects the sql SELECT' do
58
+ expect(appmap).to include(<<-SQL_QUERY.strip)
59
+ sql_query:
60
+ sql: SELECT * FROM "users"
61
+ SQL_QUERY
62
+
63
+ expect(appmap).to include('sql:')
64
+ end
65
+ end
66
+ context 'using ActiveRecord ORM' do
67
+ let(:orm_module) { 'activerecord' }
68
+ it 'detects the sql SELECT' do
69
+ expect(appmap).to include(<<-SQL_QUERY.strip)
70
+ sql_query:
71
+ sql: SELECT "users".* FROM "users"
72
+ SQL_QUERY
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,68 @@
1
+ require 'rails_spec_helper'
2
+
3
+ describe 'Record SQL queries in a Rails app' do
4
+ before(:all) { @fixture_dir = 'spec/fixtures/rails_users_app' }
5
+ include_context 'Rails app pg database'
6
+
7
+ around(:each) do |example|
8
+ FileUtils.rm_rf tmpdir
9
+ FileUtils.mkdir_p tmpdir
10
+ cmd = "docker-compose run --rm -e ORM_MODULE=#{orm_module} -e APPMAP=true -v #{File.absolute_path tmpdir}:/app/tmp app ./bin/rspec spec/controllers/users_controller_api_spec.rb:#{test_line_number}"
11
+ run_cmd cmd, chdir: @fixture_dir
12
+
13
+ example.run
14
+ end
15
+
16
+ let(:tmpdir) { "tmp/spec/record_sql_rails_pg_spec" }
17
+ let(:appmap) { JSON.parse(File.read(appmap_json)).to_yaml }
18
+
19
+ context 'while creating a new record' do
20
+ let(:test_line_number) { 8 }
21
+ let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json') }
22
+
23
+ context 'using Sequel ORM' do
24
+ let(:orm_module) { 'sequel' }
25
+ it 'detects the sql INSERT' do
26
+ expect(appmap).to include(<<-SQL_QUERY.strip)
27
+ sql_query:
28
+ sql: INSERT INTO "users" ("login") VALUES ('alice') RETURNING *
29
+ SQL_QUERY
30
+ end
31
+ end
32
+ context 'using ActiveRecord ORM' do
33
+ let(:orm_module) { 'activerecord' }
34
+ it 'detects the sql INSERT' do
35
+ expect(appmap).to include(<<-SQL_QUERY.strip)
36
+ sql_query:
37
+ sql: INSERT INTO "users" ("login") VALUES ($1) RETURNING "id"
38
+ SQL_QUERY
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'while listing records' do
44
+ let(:test_line_number) { 23 }
45
+ let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_GET_api_users_lists_the_users.appmap.json') }
46
+
47
+ context 'using Sequel ORM' do
48
+ let(:orm_module) { 'sequel' }
49
+ it 'detects the sql SELECT' do
50
+ expect(appmap).to include(<<-SQL_QUERY.strip)
51
+ sql_query:
52
+ sql: SELECT * FROM "users"
53
+ SQL_QUERY
54
+
55
+ expect(appmap).to include('sql:')
56
+ end
57
+ end
58
+ context 'using ActiveRecord ORM' do
59
+ let(:orm_module) { 'activerecord' }
60
+ it 'detects the sql SELECT' do
61
+ expect(appmap).to include(<<-SQL_QUERY.strip)
62
+ sql_query:
63
+ sql: SELECT "users".* FROM "users"
64
+ SQL_QUERY
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,117 @@
1
+ require 'rails_spec_helper'
2
+ require 'net/http'
3
+ require 'socket'
4
+
5
+ describe 'remote recording', :order => :defined do
6
+ before(:all) { @fixture_dir = 'spec/fixtures/rails_users_app' }
7
+ include_context 'Rails app pg database'
8
+
9
+ before(:all) do
10
+ start_cmd = 'docker-compose up -d app'
11
+ run_cmd({ 'ORM_MODULE' => 'sequel', 'APPMAP' => 'true' }, start_cmd, chdir: @fixture_dir)
12
+ Dir.chdir @fixture_dir do
13
+ wait_for_container 'app'
14
+ end
15
+
16
+ port_cmd = 'docker-compose port app 3000'
17
+ port_out, = run_cmd port_cmd, chdir: @fixture_dir
18
+ @service_port = port_out.strip.split(':')[1]
19
+
20
+ service_running = false
21
+ retry_count = 0
22
+ uri = URI("http://localhost:#{@service_port}/health")
23
+
24
+ until service_running
25
+ sleep(0.25)
26
+ begin
27
+ res = Net::HTTP.start(uri.hostname, uri.port) do |http|
28
+ http.request(Net::HTTP::Get.new(uri))
29
+ end
30
+
31
+ status = res.response.code.to_i
32
+ service_running = true if status >= 200 && status < 300
33
+
34
+ # give up after a certain error threshold is met
35
+ # we don't want to wait forever if there's an unrecoverable issue
36
+ raise 'gave up waiting on fixture service' if (retry_count += 1) == 10
37
+ rescue Errno::ETIMEDOUT, Errno::ECONNRESET, EOFError
38
+ $stderr.print('.')
39
+ end
40
+ end
41
+ end
42
+
43
+ def json_body(res)
44
+ JSON.parse(res.body).deep_symbolize_keys
45
+ end
46
+
47
+ after(:all) do
48
+ run_cmd 'docker-compose rm -fs app', chdir: @fixture_dir
49
+ end
50
+
51
+ let(:service_address) { URI("http://localhost:#{@service_port}") }
52
+ let(:users_path) { '/users' }
53
+ let(:record_path) { '/_appmap/record' }
54
+
55
+ it 'returns the recording status' do
56
+ res = Net::HTTP.start(service_address.hostname, service_address.port) { |http|
57
+ http.request(Net::HTTP::Get.new(record_path))
58
+ }
59
+
60
+ expect(res).to be_a(Net::HTTPOK)
61
+ expect(res['Content-Type']).to eq('application/json')
62
+ expect(json_body(res)).to eq(enabled: false)
63
+ end
64
+
65
+ it 'starts a new recording session' do
66
+ res = Net::HTTP.start(service_address.hostname, service_address.port) { |http|
67
+ http.request(Net::HTTP::Post.new(record_path))
68
+ }
69
+
70
+ expect(res).to be_a(Net::HTTPOK)
71
+ end
72
+
73
+ it 'reflects the recording status' do
74
+ res = Net::HTTP.start(service_address.hostname, service_address.port) { |http|
75
+ http.request(Net::HTTP::Get.new(record_path))
76
+ }
77
+
78
+ expect(res).to be_a(Net::HTTPOK)
79
+ expect(res['Content-Type']).to eq('application/json')
80
+ expect(json_body(res)).to eq(enabled: true)
81
+ end
82
+
83
+ it 'fails to start a new recording session while recording is already active' do
84
+ res = Net::HTTP.start(service_address.hostname, service_address.port) { |http|
85
+ http.request(Net::HTTP::Post.new(record_path))
86
+ }
87
+
88
+ expect(res).to be_a(Net::HTTPConflict)
89
+ end
90
+
91
+ it 'stops recording' do
92
+ # Generate some events
93
+ Net::HTTP.start(service_address.hostname, service_address.port) { |http|
94
+ http.request(Net::HTTP::Get.new(users_path) )
95
+ }
96
+
97
+ res = Net::HTTP.start(service_address.hostname, service_address.port) { |http|
98
+ http.request(Net::HTTP::Delete.new(record_path))
99
+ }
100
+
101
+ expect(res).to be_a(Net::HTTPOK)
102
+ expect(res['Content-Type']).to eq('application/json')
103
+
104
+ data = json_body(res)
105
+ expect(data[:metadata]).to be_truthy
106
+ expect(data[:classMap].length).to be > 0
107
+ expect(data[:events].length).to be > 0
108
+ end
109
+
110
+ it 'fails to stop recording if there is no active recording session' do
111
+ res = Net::HTTP.start(service_address.hostname, service_address.port) { |http|
112
+ http.request(Net::HTTP::Delete.new(record_path))
113
+ }
114
+
115
+ expect(res).to be_a(Net::HTTPNotFound)
116
+ end
117
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_spec_helper'
4
+
5
+ describe 'RSpec feature and feature group metadata' do
6
+ before(:all) { @fixture_dir = 'spec/fixtures/rails_users_app' }
7
+ include_examples 'Rails app pg database'
8
+
9
+ around(:each) do |example|
10
+ FileUtils.rm_rf tmpdir
11
+ FileUtils.mkdir_p tmpdir
12
+ cmd = "docker-compose run --rm -e APPMAP=true -v #{File.absolute_path(tmpdir).shellescape}:/app/tmp app ./bin/rspec spec/models/user_spec.rb"
13
+ run_cmd cmd, chdir: @fixture_dir
14
+
15
+ example.run
16
+ end
17
+
18
+ let(:tmpdir) { 'tmp/spec/RSpec feature and feature group metadata' }
19
+ let(:appmap_json) { File.join(tmpdir, %(appmap/rspec/User_creation_creates_charles.appmap.json)) }
20
+
21
+ describe do
22
+ it 'are recorded in the appmap' do
23
+ expect(File).to exist(appmap_json)
24
+ appmap = JSON.parse(File.read(appmap_json)).to_yaml
25
+
26
+ expect(appmap).to include(<<-METADATA.strip)
27
+ feature: Create a user
28
+ feature_group: User
29
+ METADATA
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ require 'rspec'
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'yaml'
5
+ require 'English'
6
+ require 'webdrivers/chromedriver'
7
+
8
+ # Disable default initialization of AppMap
9
+ ENV['APPMAP_INITIALIZE'] = 'false'
10
+
11
+ require 'appmap'
12
+
13
+ RSpec.configure do |config|
14
+ config.example_status_persistence_file_path = "tmp/rspec_failed_examples.txt"
15
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'appmap/util'
5
+
6
+ describe AppMap::Util, docker: false do
7
+ let(:subject) { AppMap::Util.method(:scenario_filename) }
8
+ describe 'scenario_filename' do
9
+ it 'leaves short names alone' do
10
+ expect(subject.call('foobar')).to eq('foobar.appmap.json')
11
+ end
12
+ it 'has a customizable suffix' do
13
+ expect(subject.call('foobar', extension: '.json')).to eq('foobar.json')
14
+ end
15
+ it 'limits the filename length' do
16
+ fname = (0...104).map { |i| ((i % 26) + 97).chr }.join
17
+
18
+ expect(subject.call(fname, max_length: 50)).to eq('abcdefghijklmno-RAd_SFbH1sUZ_OXfwPsfzw.appmap.json')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'test_helper'
5
+ require 'English'
6
+
7
+ class CLITest < Minitest::Test
8
+ OUTPUT_FILENAME = File.expand_path('../tmp/appmap.json', __dir__)
9
+ STATS_OUTPUT_FILENAME = File.expand_path('../tmp/stats.txt', __dir__)
10
+
11
+ def setup
12
+ FileUtils.rm_f OUTPUT_FILENAME
13
+ FileUtils.rm_f STATS_OUTPUT_FILENAME
14
+ end
15
+
16
+ def test_record
17
+ output = Dir.chdir 'test/fixtures/cli_record_test' do
18
+ `#{File.expand_path '../exe/appmap', __dir__} record -o #{OUTPUT_FILENAME} ./lib/cli_record_test/main.rb`.strip
19
+ end
20
+
21
+ assert_equal 0, $CHILD_STATUS.exitstatus
22
+ assert File.file?(OUTPUT_FILENAME), "#{OUTPUT_FILENAME} does not exist"
23
+ assert_equal 'Hello', output
24
+ output = JSON.parse(File.read(OUTPUT_FILENAME))
25
+ assert output['classMap'], 'Output should contain classMap'
26
+ assert output['events'], 'Output should contain events'
27
+ end
28
+
29
+ def test_stats_to_file
30
+ Dir.chdir 'test/fixtures/cli_record_test' do
31
+ `#{File.expand_path '../exe/appmap', __dir__} record -o #{OUTPUT_FILENAME} ./lib/cli_record_test/main.rb`.strip
32
+ end
33
+ assert_equal 0, $CHILD_STATUS.exitstatus
34
+
35
+ output = Dir.chdir 'test/fixtures/cli_record_test' do
36
+ `#{File.expand_path '../exe/appmap', __dir__} stats -o #{STATS_OUTPUT_FILENAME} #{OUTPUT_FILENAME}`.strip
37
+ end
38
+ assert_equal 0, $CHILD_STATUS.exitstatus
39
+ assert_equal '', output
40
+ assert File.file?(OUTPUT_FILENAME), "#{OUTPUT_FILENAME} does not exist"
41
+ end
42
+
43
+
44
+ def test_stats_text
45
+ Dir.chdir 'test/fixtures/cli_record_test' do
46
+ `#{File.expand_path '../exe/appmap', __dir__} record -o #{OUTPUT_FILENAME} ./lib/cli_record_test/main.rb`.strip
47
+ end
48
+ assert_equal 0, $CHILD_STATUS.exitstatus
49
+
50
+ output = Dir.chdir 'test/fixtures/cli_record_test' do
51
+ `#{File.expand_path '../exe/appmap', __dir__} stats -o - #{OUTPUT_FILENAME}`.strip
52
+ end
53
+
54
+ assert_equal 0, $CHILD_STATUS.exitstatus
55
+ assert_equal <<~OUTPUT.strip, output.strip
56
+ Class frequency:
57
+ ----------------
58
+ 2 Main
59
+
60
+ Method frequency:
61
+ ----------------
62
+ 1 Main.say_hello
63
+ OUTPUT
64
+ end
65
+
66
+ def test_stats_json
67
+ Dir.chdir 'test/fixtures/cli_record_test' do
68
+ `#{File.expand_path '../exe/appmap', __dir__} record -o #{OUTPUT_FILENAME} ./lib/cli_record_test/main.rb`.strip
69
+ end
70
+ assert_equal 0, $CHILD_STATUS.exitstatus
71
+
72
+ output = Dir.chdir 'test/fixtures/cli_record_test' do
73
+ `#{File.expand_path '../exe/appmap', __dir__} stats -f json -o - #{OUTPUT_FILENAME}`.strip
74
+ end
75
+
76
+ assert_equal 0, $CHILD_STATUS.exitstatus
77
+ assert_equal <<~OUTPUT.strip, output.strip
78
+ {
79
+ "class_frequency": [
80
+ {
81
+ "name": "Main",
82
+ "count": 2
83
+ }
84
+ ],
85
+ "method_frequency": [
86
+ {
87
+ "name": "Main.say_hello",
88
+ "count": 1
89
+ }
90
+ ]
91
+ }
92
+ OUTPUT
93
+ end
94
+
95
+ def test_record_to_default_location
96
+ Dir.chdir 'test/fixtures/cli_record_test' do
97
+ system({ 'APPMAP_FILE' => OUTPUT_FILENAME }, "#{File.expand_path '../exe/appmap', __dir__} record ./lib/cli_record_test/main.rb")
98
+ end
99
+
100
+ assert_equal 0, $CHILD_STATUS.exitstatus
101
+ assert File.file?(OUTPUT_FILENAME), 'appmap.json does not exist'
102
+ end
103
+
104
+ def test_record_to_stdout
105
+ output = Dir.chdir 'test/fixtures/cli_record_test' do
106
+ `#{File.expand_path '../exe/appmap', __dir__} record -o - ./lib/cli_record_test/main.rb`
107
+ end
108
+
109
+ assert_equal 0, $CHILD_STATUS.exitstatus
110
+ # Event path
111
+ assert_includes output, %("path":"lib/cli_record_test/main.rb")
112
+ # Function location
113
+ assert_includes output, %("location":"lib/cli_record_test/main.rb:3")
114
+ assert !File.file?(OUTPUT_FILENAME), "#{OUTPUT_FILENAME} should not exist"
115
+ end
116
+ end