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.
- checksums.yaml +4 -4
- data/.travis.yml +17 -2
- data/CHANGELOG.md +31 -0
- data/README.md +54 -22
- data/appmap.gemspec +0 -2
- data/lib/appmap.rb +3 -2
- data/lib/appmap/class_map.rb +7 -10
- data/lib/appmap/config.rb +94 -34
- data/lib/appmap/cucumber.rb +1 -1
- data/lib/appmap/event.rb +18 -0
- data/lib/appmap/hook.rb +42 -22
- data/lib/appmap/hook/method.rb +1 -1
- data/lib/appmap/minitest.rb +35 -30
- data/lib/appmap/rails/request_handler.rb +41 -10
- data/lib/appmap/record.rb +1 -1
- data/lib/appmap/rspec.rb +32 -96
- data/lib/appmap/util.rb +16 -0
- data/lib/appmap/version.rb +1 -1
- data/patch +1447 -0
- data/spec/abstract_controller_base_spec.rb +69 -26
- data/spec/class_map_spec.rb +3 -11
- data/spec/config_spec.rb +31 -1
- data/spec/fixtures/hook/custom_instance_method.rb +11 -0
- data/spec/fixtures/hook/method_named_call.rb +11 -0
- data/spec/fixtures/rails5_users_app/Gemfile +7 -3
- data/spec/fixtures/rails5_users_app/app/controllers/api/users_controller.rb +2 -0
- data/spec/fixtures/rails5_users_app/app/controllers/users_controller.rb +9 -1
- data/spec/fixtures/rails5_users_app/config/application.rb +2 -0
- data/spec/fixtures/rails5_users_app/create_app +8 -2
- data/spec/fixtures/rails5_users_app/docker-compose.yml +3 -0
- data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_api_spec.rb +16 -3
- data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_spec.rb +2 -2
- data/spec/fixtures/rails5_users_app/spec/models/user_spec.rb +2 -12
- data/spec/fixtures/rails5_users_app/spec/rails_helper.rb +3 -9
- data/spec/fixtures/rails6_users_app/Gemfile +5 -4
- data/spec/fixtures/rails6_users_app/app/controllers/api/users_controller.rb +1 -0
- data/spec/fixtures/rails6_users_app/app/controllers/users_controller.rb +9 -1
- data/spec/fixtures/rails6_users_app/config/application.rb +2 -0
- data/spec/fixtures/rails6_users_app/create_app +8 -2
- data/spec/fixtures/rails6_users_app/docker-compose.yml +3 -0
- data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_api_spec.rb +16 -3
- data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_spec.rb +2 -2
- data/spec/fixtures/rails6_users_app/spec/models/user_spec.rb +2 -12
- data/spec/fixtures/rails6_users_app/spec/rails_helper.rb +3 -9
- data/spec/hook_spec.rb +134 -10
- data/spec/record_sql_rails_pg_spec.rb +1 -1
- data/spec/spec_helper.rb +6 -0
- data/test/expectations/openssl_test_key_sign1.json +2 -4
- data/test/fixtures/rspec_recorder/spec/decorated_hello_spec.rb +3 -3
- data/test/fixtures/rspec_recorder/spec/plain_hello_spec.rb +1 -1
- data/test/gem_test.rb +1 -1
- data/test/minitest_test.rb +1 -2
- data/test/rspec_test.rb +1 -20
- metadata +7 -8
- data/exe/appmap +0 -154
- data/spec/rspec_feature_metadata_spec.rb +0 -31
- data/test/cli_test.rb +0 -116
@@ -1,7 +1,6 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
3
|
|
4
|
-
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
5
4
|
gem 'rails', '~> 6'
|
6
5
|
|
7
6
|
gem 'haml-rails'
|
@@ -40,12 +39,14 @@ group :development, :test do
|
|
40
39
|
gem 'appmap', appmap_options
|
41
40
|
gem 'cucumber-rails', require: false
|
42
41
|
gem 'rspec-rails'
|
43
|
-
# Required for Sequel, since without ActiveRecord, the Rails transactional fixture support
|
44
|
-
# isn't activated.
|
45
|
-
gem 'database_cleaner'
|
46
42
|
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
47
43
|
gem 'pry-byebug'
|
48
44
|
end
|
49
45
|
|
46
|
+
group :test do
|
47
|
+
gem 'database_cleaner-active_record', require: false
|
48
|
+
gem 'database_cleaner-sequel', require: false
|
49
|
+
end
|
50
|
+
|
50
51
|
group :development do
|
51
52
|
end
|
@@ -4,7 +4,15 @@ class UsersController < ApplicationController
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def show
|
7
|
-
|
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
|
-
|
20
|
-
|
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
|
|
@@ -1,13 +1,19 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
require 'rack/test'
|
3
3
|
|
4
|
-
RSpec.describe Api::UsersController,
|
5
|
-
describe 'POST /api/users'
|
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'
|
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'
|
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'
|
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
|
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'
|
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
|
-
|
58
|
-
|
59
|
-
|
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
|
data/spec/hook_spec.rb
CHANGED
@@ -64,13 +64,144 @@ describe 'AppMap class Hooking', docker: false do
|
|
64
64
|
it 'excludes named classes and methods' do
|
65
65
|
load 'spec/fixtures/hook/exclude.rb'
|
66
66
|
package = AppMap::Config::Package.build_from_path('spec/fixtures/hook/exclude.rb')
|
67
|
-
config = AppMap::Config.new('hook_spec', [ package ], %w[ExcludeTest])
|
67
|
+
config = AppMap::Config.new('hook_spec', [ package ], exclude: %w[ExcludeTest])
|
68
68
|
AppMap.configuration = config
|
69
69
|
|
70
70
|
expect(config.never_hook?(ExcludeTest.new.method(:instance_method))).to be_truthy
|
71
71
|
expect(config.never_hook?(ExcludeTest.method(:cls_method))).to be_truthy
|
72
72
|
end
|
73
73
|
|
74
|
+
it "handles an instance method named 'call' without issues" do
|
75
|
+
events_yaml = <<~YAML
|
76
|
+
---
|
77
|
+
- :id: 1
|
78
|
+
:event: :call
|
79
|
+
:defined_class: MethodNamedCall
|
80
|
+
:method_id: call
|
81
|
+
:path: spec/fixtures/hook/method_named_call.rb
|
82
|
+
:lineno: 8
|
83
|
+
:static: false
|
84
|
+
:parameters:
|
85
|
+
- :name: :a
|
86
|
+
:class: Integer
|
87
|
+
:value: '1'
|
88
|
+
:kind: :req
|
89
|
+
- :name: :b
|
90
|
+
:class: Integer
|
91
|
+
:value: '2'
|
92
|
+
:kind: :req
|
93
|
+
- :name: :c
|
94
|
+
:class: Integer
|
95
|
+
:value: '3'
|
96
|
+
:kind: :req
|
97
|
+
- :name: :d
|
98
|
+
:class: Integer
|
99
|
+
:value: '4'
|
100
|
+
:kind: :req
|
101
|
+
- :name: :e
|
102
|
+
:class: Integer
|
103
|
+
:value: '5'
|
104
|
+
:kind: :req
|
105
|
+
:receiver:
|
106
|
+
:class: MethodNamedCall
|
107
|
+
:value: MethodNamedCall
|
108
|
+
- :id: 2
|
109
|
+
:event: :return
|
110
|
+
:parent_id: 1
|
111
|
+
:return_value:
|
112
|
+
:class: String
|
113
|
+
:value: 1 2 3 4 5
|
114
|
+
YAML
|
115
|
+
|
116
|
+
_, tracer = test_hook_behavior 'spec/fixtures/hook/method_named_call.rb', events_yaml do
|
117
|
+
expect(MethodNamedCall.new.call(1, 2, 3, 4, 5)).to eq('1 2 3 4 5')
|
118
|
+
end
|
119
|
+
class_map = AppMap.class_map(tracer.event_methods)
|
120
|
+
expect(Diffy::Diff.new(<<~CLASSMAP, YAML.dump(class_map)).to_s).to eq('')
|
121
|
+
---
|
122
|
+
- :name: spec/fixtures/hook/method_named_call.rb
|
123
|
+
:type: package
|
124
|
+
:children:
|
125
|
+
- :name: MethodNamedCall
|
126
|
+
:type: class
|
127
|
+
:children:
|
128
|
+
- :name: call
|
129
|
+
:type: function
|
130
|
+
:location: spec/fixtures/hook/method_named_call.rb:8
|
131
|
+
:static: false
|
132
|
+
CLASSMAP
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'can custom hook and label a function' do
|
136
|
+
events_yaml = <<~YAML
|
137
|
+
---
|
138
|
+
- :id: 1
|
139
|
+
:event: :call
|
140
|
+
:defined_class: CustomInstanceMethod
|
141
|
+
:method_id: say_default
|
142
|
+
:path: spec/fixtures/hook/custom_instance_method.rb
|
143
|
+
:lineno: 8
|
144
|
+
:static: false
|
145
|
+
:parameters: []
|
146
|
+
:receiver:
|
147
|
+
:class: CustomInstanceMethod
|
148
|
+
:value: CustomInstance Method fixture
|
149
|
+
- :id: 2
|
150
|
+
:event: :return
|
151
|
+
:parent_id: 1
|
152
|
+
:return_value:
|
153
|
+
:class: String
|
154
|
+
:value: default
|
155
|
+
YAML
|
156
|
+
|
157
|
+
config = AppMap::Config.load({
|
158
|
+
functions: [
|
159
|
+
{
|
160
|
+
package: 'hook_spec',
|
161
|
+
class: 'CustomInstanceMethod',
|
162
|
+
functions: [ :say_default ],
|
163
|
+
labels: ['cowsay']
|
164
|
+
}
|
165
|
+
]
|
166
|
+
}.deep_stringify_keys)
|
167
|
+
|
168
|
+
load 'spec/fixtures/hook/custom_instance_method.rb'
|
169
|
+
hook_cls = CustomInstanceMethod
|
170
|
+
method = hook_cls.instance_method(:say_default)
|
171
|
+
|
172
|
+
require 'appmap/hook/method'
|
173
|
+
hook_method = AppMap::Hook::Method.new(config.package_for_method(method), hook_cls, method)
|
174
|
+
hook_method.activate
|
175
|
+
|
176
|
+
tracer = AppMap.tracing.trace
|
177
|
+
AppMap::Event.reset_id_counter
|
178
|
+
begin
|
179
|
+
expect(CustomInstanceMethod.new.say_default).to eq('default')
|
180
|
+
ensure
|
181
|
+
AppMap.tracing.delete(tracer)
|
182
|
+
end
|
183
|
+
|
184
|
+
events = collect_events(tracer).to_yaml
|
185
|
+
|
186
|
+
expect(Diffy::Diff.new(events_yaml, events).to_s).to eq('')
|
187
|
+
class_map = AppMap.class_map(tracer.event_methods)
|
188
|
+
expect(Diffy::Diff.new(<<~CLASSMAP, YAML.dump(class_map)).to_s).to eq('')
|
189
|
+
---
|
190
|
+
- :name: hook_spec
|
191
|
+
:type: package
|
192
|
+
:children:
|
193
|
+
- :name: CustomInstanceMethod
|
194
|
+
:type: class
|
195
|
+
:children:
|
196
|
+
- :name: say_default
|
197
|
+
:type: function
|
198
|
+
:location: spec/fixtures/hook/custom_instance_method.rb:8
|
199
|
+
:static: false
|
200
|
+
:labels:
|
201
|
+
- cowsay
|
202
|
+
CLASSMAP
|
203
|
+
end
|
204
|
+
|
74
205
|
it 'parses labels from comments' do
|
75
206
|
_, tracer = invoke_test_file 'spec/fixtures/hook/labels.rb' do
|
76
207
|
ClassWithLabel.new.fn_with_label
|
@@ -91,9 +222,6 @@ describe 'AppMap class Hooking', docker: false do
|
|
91
222
|
:labels:
|
92
223
|
- has-fn-label
|
93
224
|
:comment: "# @label has-fn-label\\n"
|
94
|
-
:source: |2
|
95
|
-
def fn_with_label
|
96
|
-
end
|
97
225
|
YAML
|
98
226
|
end
|
99
227
|
|
@@ -148,10 +276,6 @@ describe 'AppMap class Hooking', docker: false do
|
|
148
276
|
:type: function
|
149
277
|
:location: spec/fixtures/hook/instance_method.rb:8
|
150
278
|
:static: false
|
151
|
-
:source: |2
|
152
|
-
def say_default
|
153
|
-
'default'
|
154
|
-
end
|
155
279
|
YAML
|
156
280
|
end
|
157
281
|
|
@@ -746,6 +870,7 @@ describe 'AppMap class Hooking', docker: false do
|
|
746
870
|
end
|
747
871
|
secure_compare_event = YAML.load(events).find { |evt| evt[:defined_class] == 'ActiveSupport::SecurityUtils' }
|
748
872
|
secure_compare_event.delete(:lineno)
|
873
|
+
secure_compare_event.delete(:path)
|
749
874
|
|
750
875
|
expect(Diffy::Diff.new(<<~YAML, secure_compare_event.to_yaml).to_s).to eq('')
|
751
876
|
---
|
@@ -753,7 +878,6 @@ describe 'AppMap class Hooking', docker: false do
|
|
753
878
|
:event: :call
|
754
879
|
:defined_class: ActiveSupport::SecurityUtils
|
755
880
|
:method_id: secure_compare
|
756
|
-
:path: lib/active_support/security_utils.rb
|
757
881
|
:static: true
|
758
882
|
:parameters:
|
759
883
|
- :name: :a
|
@@ -837,7 +961,7 @@ describe 'AppMap class Hooking', docker: false do
|
|
837
961
|
entry = cm[1][:children][0][:children][0][:children][0]
|
838
962
|
# Sanity check, make sure we got the right one
|
839
963
|
expect(entry[:name]).to eq('secure_compare')
|
840
|
-
expect(entry[:labels]).to eq(%w[
|
964
|
+
expect(entry[:labels]).to eq(%w[crypto.secure_compare])
|
841
965
|
end
|
842
966
|
end
|
843
967
|
|
@@ -61,7 +61,7 @@ describe 'SQL events' do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
context 'while listing records' do
|
64
|
-
let(:test_line_number) {
|
64
|
+
let(:test_line_number) { 29 }
|
65
65
|
let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_GET_api_users_lists_the_users.appmap.json') }
|
66
66
|
|
67
67
|
context 'using Sequel ORM' do
|
data/spec/spec_helper.rb
CHANGED
@@ -14,3 +14,9 @@ require 'appmap'
|
|
14
14
|
RSpec.configure do |config|
|
15
15
|
config.example_status_persistence_file_path = "tmp/rspec_failed_examples.txt"
|
16
16
|
end
|
17
|
+
|
18
|
+
# Re-run the Rails specs without re-generating the data. This is useful for efficiently enhancing and
|
19
|
+
# debugging the test itself.
|
20
|
+
def use_existing_data?
|
21
|
+
ENV['USE_EXISTING_DATA'] == 'true'
|
22
|
+
end
|
@@ -11,8 +11,7 @@
|
|
11
11
|
"name": "sign",
|
12
12
|
"type": "function",
|
13
13
|
"location": "lib/openssl_key_sign.rb:10",
|
14
|
-
"static": true
|
15
|
-
"source": " def Example.sign\n key = OpenSSL::PKey::RSA.new 2048\n\n document = 'the document'\n\n digest = OpenSSL::Digest::SHA256.new\n key.sign digest, document\n end\n"
|
14
|
+
"static": true
|
16
15
|
}
|
17
16
|
]
|
18
17
|
}
|
@@ -40,8 +39,7 @@
|
|
40
39
|
"location": "OpenSSL::PKey::PKey#sign",
|
41
40
|
"static": false,
|
42
41
|
"labels": [
|
43
|
-
"
|
44
|
-
"crypto"
|
42
|
+
"crypto.pkey"
|
45
43
|
]
|
46
44
|
}
|
47
45
|
]
|
@@ -2,7 +2,7 @@ require 'rspec'
|
|
2
2
|
require 'appmap/rspec'
|
3
3
|
require 'hello'
|
4
4
|
|
5
|
-
describe Hello
|
5
|
+
describe Hello do
|
6
6
|
before do
|
7
7
|
# Trick appmap-ruby into thinking we're a Rails app.
|
8
8
|
stub_const('Rails', double('rails', version: 'fake.0'))
|
@@ -11,11 +11,11 @@ describe Hello, feature_group: 'Saying hello' do
|
|
11
11
|
# The order of these examples is important. The tests check the
|
12
12
|
# appmap for 'says hello', and we want another example to get run
|
13
13
|
# before it.
|
14
|
-
it 'does not say goodbye'
|
14
|
+
it 'does not say goodbye' do
|
15
15
|
expect(Hello.new.say_hello).not_to eq('Goodbye!')
|
16
16
|
end
|
17
17
|
|
18
|
-
it 'says hello'
|
18
|
+
it 'says hello' do
|
19
19
|
expect(Hello.new.say_hello).to eq('Hello!')
|
20
20
|
end
|
21
21
|
end
|