appmap 0.41.1 → 0.44.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +17 -2
  3. data/CHANGELOG.md +31 -0
  4. data/README.md +54 -22
  5. data/appmap.gemspec +0 -2
  6. data/lib/appmap.rb +3 -2
  7. data/lib/appmap/class_map.rb +7 -10
  8. data/lib/appmap/config.rb +94 -34
  9. data/lib/appmap/cucumber.rb +1 -1
  10. data/lib/appmap/event.rb +18 -0
  11. data/lib/appmap/hook.rb +42 -22
  12. data/lib/appmap/hook/method.rb +1 -1
  13. data/lib/appmap/minitest.rb +35 -30
  14. data/lib/appmap/rails/request_handler.rb +41 -10
  15. data/lib/appmap/record.rb +1 -1
  16. data/lib/appmap/rspec.rb +32 -96
  17. data/lib/appmap/util.rb +16 -0
  18. data/lib/appmap/version.rb +1 -1
  19. data/patch +1447 -0
  20. data/spec/abstract_controller_base_spec.rb +69 -26
  21. data/spec/class_map_spec.rb +3 -11
  22. data/spec/config_spec.rb +31 -1
  23. data/spec/fixtures/hook/custom_instance_method.rb +11 -0
  24. data/spec/fixtures/hook/method_named_call.rb +11 -0
  25. data/spec/fixtures/rails5_users_app/Gemfile +7 -3
  26. data/spec/fixtures/rails5_users_app/app/controllers/api/users_controller.rb +2 -0
  27. data/spec/fixtures/rails5_users_app/app/controllers/users_controller.rb +9 -1
  28. data/spec/fixtures/rails5_users_app/config/application.rb +2 -0
  29. data/spec/fixtures/rails5_users_app/create_app +8 -2
  30. data/spec/fixtures/rails5_users_app/docker-compose.yml +3 -0
  31. data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_api_spec.rb +16 -3
  32. data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_spec.rb +2 -2
  33. data/spec/fixtures/rails5_users_app/spec/models/user_spec.rb +2 -12
  34. data/spec/fixtures/rails5_users_app/spec/rails_helper.rb +3 -9
  35. data/spec/fixtures/rails6_users_app/Gemfile +5 -4
  36. data/spec/fixtures/rails6_users_app/app/controllers/api/users_controller.rb +1 -0
  37. data/spec/fixtures/rails6_users_app/app/controllers/users_controller.rb +9 -1
  38. data/spec/fixtures/rails6_users_app/config/application.rb +2 -0
  39. data/spec/fixtures/rails6_users_app/create_app +8 -2
  40. data/spec/fixtures/rails6_users_app/docker-compose.yml +3 -0
  41. data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_api_spec.rb +16 -3
  42. data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_spec.rb +2 -2
  43. data/spec/fixtures/rails6_users_app/spec/models/user_spec.rb +2 -12
  44. data/spec/fixtures/rails6_users_app/spec/rails_helper.rb +3 -9
  45. data/spec/hook_spec.rb +134 -10
  46. data/spec/record_sql_rails_pg_spec.rb +1 -1
  47. data/spec/spec_helper.rb +6 -0
  48. data/test/expectations/openssl_test_key_sign1.json +2 -4
  49. data/test/fixtures/rspec_recorder/spec/decorated_hello_spec.rb +3 -3
  50. data/test/fixtures/rspec_recorder/spec/plain_hello_spec.rb +1 -1
  51. data/test/gem_test.rb +1 -1
  52. data/test/minitest_test.rb +1 -2
  53. data/test/rspec_test.rb +1 -20
  54. metadata +7 -8
  55. data/exe/appmap +0 -154
  56. data/spec/rspec_feature_metadata_spec.rb +0 -31
  57. data/test/cli_test.rb +0 -116
@@ -1,12 +1,11 @@
1
1
  require 'rails_spec_helper'
2
2
 
3
- describe 'AbstractControllerBase' do
3
+ describe 'Rails' do
4
4
  %w[5 6].each do |rails_major_version| # rubocop:disable Metrics/BlockLength
5
- context "in Rails #{rails_major_version}" do
6
- include_context 'Rails app pg database', "spec/fixtures/rails#{rails_major_version}_users_app"
5
+ context "#{rails_major_version}" do
6
+ include_context 'Rails app pg database', "spec/fixtures/rails#{rails_major_version}_users_app" unless use_existing_data?
7
+
7
8
  def run_spec(spec_name)
8
- FileUtils.rm_rf tmpdir
9
- FileUtils.mkdir_p tmpdir
10
9
  cmd = <<~CMD.gsub "\n", ' '
11
10
  docker-compose run --rm -e RAILS_ENV=test -e APPMAP=true
12
11
  -v #{File.absolute_path tmpdir}:/app/tmp app ./bin/rspec #{spec_name}
@@ -18,25 +17,32 @@ describe 'AbstractControllerBase' do
18
17
  'tmp/spec/AbstractControllerBase'
19
18
  end
20
19
 
20
+ unless use_existing_data?
21
+ before(:all) do
22
+ FileUtils.rm_rf tmpdir
23
+ FileUtils.mkdir_p tmpdir
24
+ run_spec 'spec/controllers/users_controller_spec.rb'
25
+ run_spec 'spec/controllers/users_controller_api_spec.rb'
26
+ end
27
+ end
28
+
21
29
  let(:appmap) { JSON.parse File.read File.join tmpdir, 'appmap/rspec', appmap_json_file }
30
+ let(:appmap_json_path) { File.join(tmpdir, 'appmap/rspec', appmap_json_file) }
31
+ let(:appmap) { JSON.parse File.read(appmap_json_path) }
22
32
  let(:events) { appmap['events'] }
23
33
 
24
- describe 'testing with rspec' do
25
- describe 'creating a user' do
26
- before(:all) { run_spec 'spec/controllers/users_controller_api_spec.rb:8' }
34
+ describe 'an API route' do
35
+ describe 'creating an object' do
27
36
  let(:appmap_json_file) do
28
37
  'Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json'
29
38
  end
30
39
 
31
- it 'inventory file is printed' do
32
- expect(File).to exist(File.join(tmpdir, 'appmap/rspec/Inventory.appmap.json'))
33
- end
34
-
35
- it 'message fields are recorded in the appmap' do
40
+ it 'http_server_request is recorded in the appmap' do
36
41
  expect(events).to include(
37
42
  hash_including(
38
43
  'http_server_request' => hash_including(
39
44
  'request_method' => 'POST',
45
+ 'normalized_path_info' => '/api/users(.:format)',
40
46
  'path_info' => '/api/users'
41
47
  ),
42
48
  'message' => include(
@@ -53,12 +59,17 @@ describe 'AbstractControllerBase' do
53
59
  'object_id' => Integer
54
60
  )
55
61
  )
56
- ),
62
+ )
63
+ )
64
+ end
65
+
66
+ it 'http_server_response is recorded in the appmap' do
67
+ expect(events).to include(
57
68
  hash_including(
58
- 'http_server_response' => {
69
+ 'http_server_response' => hash_including(
59
70
  'status' => 201,
60
71
  'mime_type' => 'application/json; charset=utf-8'
61
- }
72
+ )
62
73
  )
63
74
  )
64
75
  end
@@ -70,7 +81,7 @@ describe 'AbstractControllerBase' do
70
81
  'defined_class' => 'Api::UsersController',
71
82
  'method_id' => 'build_user',
72
83
  'path' => 'app/controllers/api/users_controller.rb',
73
- 'lineno' => 23,
84
+ 'lineno' => Integer,
74
85
  'static' => false,
75
86
  'parameters' => include(
76
87
  'name' => 'params',
@@ -93,10 +104,47 @@ describe 'AbstractControllerBase' do
93
104
  'elapsed' => Numeric
94
105
  )
95
106
  end
107
+
108
+ context 'with an object-style message' do
109
+ let(:appmap_json_file) { 'Api_UsersController_POST_api_users_with_required_parameters_with_object-style_parameters_creates_a_user.appmap.json' }
110
+
111
+ it 'message properties are recorded in the appmap' do
112
+ expect(events).to include(
113
+ hash_including(
114
+ 'message' => include(
115
+ hash_including(
116
+ 'name' => 'user',
117
+ 'properties' => [
118
+ { 'name' => 'login', 'class' => 'String' },
119
+ { 'name' => 'password', 'class' => 'String' }
120
+ ]
121
+ )
122
+ )
123
+ )
124
+ )
125
+ end
126
+ end
127
+ end
128
+
129
+ describe 'listing objects' do
130
+ context 'with a custom header' do
131
+ let(:appmap_json_file) { 'Api_UsersController_GET_api_users_with_a_custom_header_lists_the_users.appmap.json' }
132
+
133
+ it 'custom header is recorded in the appmap' do
134
+ expect(events).to include(
135
+ hash_including(
136
+ 'http_server_request' => hash_including(
137
+ 'headers' => hash_including('X-Sandwich' => 'turkey')
138
+ )
139
+ )
140
+ )
141
+ end
142
+ end
96
143
  end
144
+ end
97
145
 
98
- describe 'showing a user' do
99
- before(:all) { run_spec 'spec/controllers/users_controller_spec.rb:22' }
146
+ describe 'a UI route' do
147
+ describe 'rendering a page' do
100
148
  let(:appmap_json_file) do
101
149
  'UsersController_GET_users_login_shows_the_user.appmap.json'
102
150
  end
@@ -112,11 +160,6 @@ describe 'AbstractControllerBase' do
112
160
  )
113
161
  )
114
162
  end
115
- end
116
-
117
- describe 'listing users' do
118
- before(:all) { run_spec 'spec/controllers/users_controller_spec.rb:11' }
119
- let(:appmap_json_file) { 'UsersController_GET_users_lists_the_users.appmap.json' }
120
163
 
121
164
  it 'records and labels view rendering' do
122
165
  expect(events).to include hash_including(
@@ -128,7 +171,7 @@ describe 'AbstractControllerBase' do
128
171
  'lineno' => Integer,
129
172
  'static' => false
130
173
  )
131
-
174
+
132
175
  expect(appmap['classMap']).to include hash_including(
133
176
  'name' => 'action_view',
134
177
  'children' => include(hash_including(
@@ -142,7 +185,7 @@ describe 'AbstractControllerBase' do
142
185
  ))
143
186
  ))
144
187
  )
145
- end
188
+ end
146
189
  end
147
190
  end
148
191
  end
@@ -4,18 +4,10 @@ require 'spec_helper'
4
4
 
5
5
  describe 'AppMap::ClassMap' do
6
6
  describe '.build_from_methods' do
7
- it 'includes source code if available' do
8
- map = AppMap.class_map([scoped_method(method(:test_method))])
7
+ it 'includes method comment' do
8
+ map = AppMap.class_map([scoped_method((method :test_method))])
9
9
  function = dig_map(map, 5)[0]
10
- expect(function[:source]).to include 'test method body'
11
- expect(function[:comment]).to include 'test method comment'
12
- end
13
-
14
- it 'can omit source code even if available' do
15
- map = AppMap.class_map([scoped_method((method :test_method))], include_source: false)
16
- function = dig_map(map, 5)[0]
17
- expect(function).to_not include(:source)
18
- expect(function).to_not include(:comment)
10
+ expect(function).to include(:comment)
19
11
  end
20
12
 
21
13
  # test method comment
data/spec/config_spec.rb CHANGED
@@ -17,10 +17,40 @@ describe AppMap::Config, docker: false do
17
17
  path: 'path-2',
18
18
  exclude: [ 'exclude-1' ]
19
19
  }
20
+ ],
21
+ functions: [
22
+ {
23
+ package: 'pkg',
24
+ class: 'cls',
25
+ function: 'fn',
26
+ label: 'lbl'
27
+ }
20
28
  ]
21
29
  }.deep_stringify_keys!
22
30
  config = AppMap::Config.load(config_data)
23
31
 
24
- expect(config.to_h.deep_stringify_keys!).to eq(config_data)
32
+ config_expectation = {
33
+ exclude: [],
34
+ name: 'test',
35
+ packages: [
36
+ {
37
+ path: 'path-1'
38
+ },
39
+ {
40
+ path: 'path-2',
41
+ exclude: [ 'exclude-1' ]
42
+ }
43
+ ],
44
+ functions: [
45
+ {
46
+ package: 'pkg',
47
+ class: 'cls',
48
+ functions: [ :fn ],
49
+ labels: ['lbl']
50
+ }
51
+ ]
52
+ }.deep_stringify_keys!
53
+
54
+ expect(config.to_h.deep_stringify_keys!).to eq(config_expectation)
25
55
  end
26
56
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CustomInstanceMethod
4
+ def to_s
5
+ 'CustomInstance Method fixture'
6
+ end
7
+
8
+ def say_default
9
+ 'default'
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MethodNamedCall
4
+ def to_s
5
+ 'MethodNamedCall'
6
+ end
7
+
8
+ def call(a, b, c, d, e)
9
+ [ a, b, c, d, e ].join(' ')
10
+ end
11
+ end
@@ -39,12 +39,16 @@ group :development, :test do
39
39
  gem 'appmap', appmap_options
40
40
  gem 'cucumber-rails', require: false
41
41
  gem 'rspec-rails'
42
- # Required for Sequel, since without ActiveRecord, the Rails transactional fixture support
43
- # isn't activated.
44
- gem 'database_cleaner'
45
42
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
46
43
  gem 'pry-byebug'
47
44
  end
48
45
 
46
+ group :test do
47
+ # Require only one of these.
48
+ # 'database_cleaner' requries 'database_cleaner-active_record', so don't require it.
49
+ gem 'database_cleaner-active_record', require: false
50
+ gem 'database_cleaner-sequel', require: false
51
+ end
52
+
49
53
  group :development do
50
54
  end
@@ -6,6 +6,8 @@ module Api
6
6
  end
7
7
 
8
8
  def create
9
+ params = self.params.key?(:user) ? self.params[:user] : self.params
10
+
9
11
  @user = build_user(params.slice(:login).to_unsafe_h)
10
12
  unless @user.valid?
11
13
  error = {
@@ -4,7 +4,15 @@ class UsersController < ApplicationController
4
4
  end
5
5
 
6
6
  def show
7
- if (@user = User[login: params[:id]])
7
+ find_user = lambda do |id|
8
+ if User.respond_to?(:[])
9
+ User[login: id]
10
+ else
11
+ User.find_by_login!(id)
12
+ end
13
+ end
14
+
15
+ if (@user = find_user.(params[:id]))
8
16
  render plain: @user
9
17
  else
10
18
  render plain: 'Not found', status: 404
@@ -15,8 +15,10 @@ case orm_module
15
15
  when 'sequel'
16
16
  require 'sequel-rails'
17
17
  require 'sequel_secure_password'
18
+ require 'database_cleaner-sequel' if Rails.env.test?
18
19
  when 'activerecord'
19
20
  require 'active_record/railtie'
21
+ require 'database_cleaner-active_record' if Rails.env.test?
20
22
  end
21
23
 
22
24
  require 'appmap/railtie' if defined?(AppMap)
@@ -16,11 +16,17 @@ if [[ $? != 0 ]]; then
16
16
  exit 1
17
17
  fi
18
18
 
19
- psql -h pg -U postgres -c "create database app_development"
20
- psql -h pg -U postgres -c "create database app_test"
19
+ # Required for migrations
20
+ export ORM_MODULE=sequel
21
21
 
22
+ set +e
23
+ psql -h pg -U postgres -c "drop database if exists app_development"
24
+ psql -h pg -U postgres -c "drop database if exists app_test"
22
25
  set -e
23
26
 
27
+ psql -h pg -U postgres -c "create database app_development"
28
+ psql -h pg -U postgres -c "create database app_test"
29
+
24
30
  RAILS_ENV=development ./bin/rake db:migrate
25
31
  RAILS_ENV=test ./bin/rake db:migrate
26
32
 
@@ -19,6 +19,9 @@ services:
19
19
  environment:
20
20
  RAILS_ENV:
21
21
  ORM_MODULE:
22
+ PGHOST: pg
23
+ PGPORT: '5432'
24
+ DATABASE_URL: postgres://postgres@pg
22
25
  APPMAP:
23
26
  volumes:
24
27
  - .:/src/app
@@ -1,13 +1,19 @@
1
1
  require 'rails_helper'
2
2
  require 'rack/test'
3
3
 
4
- RSpec.describe Api::UsersController, feature_group: 'Users', type: :controller, appmap: true do
5
- describe 'POST /api/users', feature: 'Create a user' do
4
+ RSpec.describe Api::UsersController, type: :controller do
5
+ describe 'POST /api/users' do
6
6
  describe 'with required parameters' do
7
7
  it 'creates a user' do
8
8
  post :create, params: { login: 'alice', password: 'foobar' }
9
9
  expect(response.status).to eq(201)
10
10
  end
11
+ describe 'with object-style parameters' do
12
+ it 'creates a user' do
13
+ post :create, params: { user: { login: 'alice', password: 'foobar' } }
14
+ expect(response.status).to eq(201)
15
+ end
16
+ end
11
17
  end
12
18
  describe 'with a missing parameter' do
13
19
  it 'reports error 422' do
@@ -16,7 +22,7 @@ RSpec.describe Api::UsersController, feature_group: 'Users', type: :controller,
16
22
  end
17
23
  end
18
24
  end
19
- describe 'GET /api/users', feature: 'List users' do
25
+ describe 'GET /api/users' do
20
26
  before do
21
27
  post :create, params: { login: 'alice' }
22
28
  end
@@ -25,5 +31,12 @@ RSpec.describe Api::UsersController, feature_group: 'Users', type: :controller,
25
31
  users = JSON.parse(response.body)
26
32
  expect(users.map { |r| r['login'] }).to include('alice')
27
33
  end
34
+ describe 'with a custom header' do
35
+ it 'lists the users' do
36
+ request.headers['X-Sandwich'] = 'turkey'
37
+ get :index, params: {}
38
+ expect(response.status).to eq(200)
39
+ end
40
+ end
28
41
  end
29
42
  end
@@ -4,7 +4,7 @@ require 'rack/test'
4
4
  RSpec.describe UsersController, type: :controller do
5
5
  render_views
6
6
 
7
- describe 'GET /users', feature: 'Show all users' do
7
+ describe 'GET /users' do
8
8
  before do
9
9
  User.create login: 'alice'
10
10
  end
@@ -14,7 +14,7 @@ RSpec.describe UsersController, type: :controller do
14
14
  end
15
15
  end
16
16
 
17
- describe 'GET /users/:login', feature: 'Show a user' do
17
+ describe 'GET /users/:login' do
18
18
  before do
19
19
  User.create login: 'alice'
20
20
  end
@@ -1,6 +1,6 @@
1
1
  require 'rails_helper'
2
2
 
3
- describe User, feature_group: 'User', appmap: true do
3
+ describe User do
4
4
  # TODO: appmap/rspec doesn't handle shared_examples_for 100% correctly yet.
5
5
  # In my tests, only one of these two tests will be emitted as an appmap.
6
6
  shared_examples_for 'creates the user' do |username|
@@ -11,17 +11,7 @@ describe User, feature_group: 'User', appmap: true do
11
11
  end
12
12
  end
13
13
 
14
- describe 'creation', feature: 'Create a user' do
15
- context 'using shared_examples_for' do
16
- # AppMap.
17
- # context "with username 'alice'" do
18
- # it_should_behave_like 'creates the user', 'alice'
19
- # end
20
- # context "with username 'bob'" do
21
- # it_should_behave_like 'creates the user', 'bob'
22
- # end
23
- end
24
-
14
+ describe 'creation' do
25
15
  # So, instead of shared_examples_for, let's go with a simple method
26
16
  # containing the assertions. The method can be called from within an example.
27
17
  def save_and_verify
@@ -45,7 +45,6 @@ RSpec.configure do |config|
45
45
  # arbitrary gems may also be filtered via:
46
46
  # config.filter_gems_from_backtrace("gem name")
47
47
 
48
-
49
48
  DatabaseCleaner.allow_remote_database_url = true
50
49
 
51
50
  config.before(:suite) do
@@ -54,13 +53,8 @@ RSpec.configure do |config|
54
53
  end
55
54
 
56
55
  config.around :each do |example|
57
- # Enable the use of 'return' from a guard
58
- -> {
59
- return example.run unless %i[model controller].member?(example.metadata[:type])
60
-
61
- DatabaseCleaner.cleaning do
62
- example.run
63
- end
64
- }.call
56
+ DatabaseCleaner.cleaning do
57
+ example.run
58
+ end
65
59
  end
66
60
  end