appmap 0.26.1 → 0.32.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/.gitignore +1 -3
- data/CHANGELOG.md +37 -0
- data/README.md +170 -29
- data/Rakefile +1 -1
- data/exe/appmap +3 -1
- data/lib/appmap.rb +56 -35
- data/lib/appmap/algorithm/stats.rb +2 -1
- data/lib/appmap/class_map.rb +21 -28
- data/lib/appmap/command/record.rb +2 -61
- data/lib/appmap/config.rb +89 -0
- data/lib/appmap/cucumber.rb +89 -0
- data/lib/appmap/event.rb +28 -19
- data/lib/appmap/hook.rb +56 -128
- data/lib/appmap/hook/method.rb +78 -0
- data/lib/appmap/metadata.rb +62 -0
- data/lib/appmap/middleware/remote_recording.rb +2 -6
- data/lib/appmap/minitest.rb +141 -0
- data/lib/appmap/rails/action_handler.rb +7 -7
- data/lib/appmap/rails/sql_handler.rb +10 -8
- data/lib/appmap/railtie.rb +2 -2
- data/lib/appmap/record.rb +27 -0
- data/lib/appmap/rspec.rb +20 -38
- data/lib/appmap/trace.rb +19 -11
- data/lib/appmap/util.rb +59 -0
- data/lib/appmap/version.rb +1 -1
- data/package-lock.json +3 -3
- data/spec/abstract_controller4_base_spec.rb +1 -1
- data/spec/abstract_controller_base_spec.rb +9 -2
- data/spec/config_spec.rb +3 -3
- data/spec/fixtures/hook/compare.rb +7 -0
- data/spec/fixtures/hook/singleton_method.rb +54 -0
- data/spec/fixtures/rails_users_app/Gemfile +1 -0
- data/spec/fixtures/rails_users_app/features/api_users.feature +13 -0
- data/spec/fixtures/rails_users_app/features/support/env.rb +4 -0
- data/spec/fixtures/rails_users_app/features/support/hooks.rb +11 -0
- data/spec/fixtures/rails_users_app/features/support/steps.rb +18 -0
- data/spec/hook_spec.rb +228 -53
- data/spec/rails_spec_helper.rb +2 -0
- data/spec/record_sql_rails_pg_spec.rb +56 -33
- data/spec/rspec_feature_metadata_spec.rb +2 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/util_spec.rb +21 -0
- data/test/cli_test.rb +4 -4
- data/test/cucumber_test.rb +72 -0
- data/test/fixtures/cucumber4_recorder/Gemfile +5 -0
- data/test/fixtures/cucumber4_recorder/appmap.yml +3 -0
- data/test/fixtures/cucumber4_recorder/features/say_hello.feature +5 -0
- data/test/fixtures/cucumber4_recorder/features/support/env.rb +5 -0
- data/test/fixtures/cucumber4_recorder/features/support/hooks.rb +11 -0
- data/test/fixtures/cucumber4_recorder/features/support/steps.rb +9 -0
- data/test/fixtures/cucumber4_recorder/lib/hello.rb +7 -0
- data/test/fixtures/cucumber_recorder/Gemfile +5 -0
- data/test/fixtures/cucumber_recorder/appmap.yml +3 -0
- data/test/fixtures/cucumber_recorder/features/say_hello.feature +5 -0
- data/test/fixtures/cucumber_recorder/features/support/env.rb +5 -0
- data/test/fixtures/cucumber_recorder/features/support/hooks.rb +11 -0
- data/test/fixtures/cucumber_recorder/features/support/steps.rb +9 -0
- data/test/fixtures/cucumber_recorder/lib/hello.rb +7 -0
- data/test/fixtures/minitest_recorder/Gemfile +5 -0
- data/test/fixtures/minitest_recorder/appmap.yml +3 -0
- data/test/fixtures/minitest_recorder/lib/hello.rb +5 -0
- data/test/fixtures/minitest_recorder/test/hello_test.rb +12 -0
- data/test/fixtures/process_recorder/appmap.yml +3 -0
- data/test/fixtures/process_recorder/hello.rb +9 -0
- data/test/minitest_test.rb +38 -0
- data/test/record_process_test.rb +35 -0
- data/test/test_helper.rb +1 -0
- metadata +39 -3
- data/spec/fixtures/hook/class_method.rb +0 -17
data/spec/rails_spec_helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rails_spec_helper'
|
2
2
|
|
3
|
-
describe '
|
3
|
+
describe 'SQL events' do
|
4
4
|
before(:all) { @fixture_dir = 'spec/fixtures/rails_users_app' }
|
5
5
|
include_context 'Rails app pg database'
|
6
6
|
|
@@ -14,54 +14,77 @@ describe 'Record SQL queries in a Rails app' do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
let(:tmpdir) { "tmp/spec/record_sql_rails_pg_spec" }
|
17
|
-
let(:appmap) { JSON.parse(File.read(appmap_json)).to_yaml }
|
18
17
|
|
19
|
-
|
18
|
+
describe 'fields' do
|
20
19
|
let(:test_line_number) { 8 }
|
21
20
|
let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json') }
|
21
|
+
let(:orm_module) { 'sequel' }
|
22
|
+
let(:appmap) { JSON.parse(File.read(appmap_json)) }
|
23
|
+
describe 'on a call event' do
|
24
|
+
let(:event) do
|
25
|
+
appmap['events'].find do |event|
|
26
|
+
event['event'] == 'call' &&
|
27
|
+
event.keys.include?('sql_query')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
it 'do not include function-only fields' do
|
31
|
+
expect(event.keys).to_not include('defined_class')
|
32
|
+
expect(event.keys).to_not include('method_id')
|
33
|
+
expect(event.keys).to_not include('path')
|
34
|
+
expect(event.keys).to_not include('lineno')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'in a Rails app' do
|
40
|
+
let(:appmap) { JSON.parse(File.read(appmap_json)).to_yaml }
|
41
|
+
context 'while creating a new record' do
|
42
|
+
let(:test_line_number) { 8 }
|
43
|
+
let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json') }
|
22
44
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
45
|
+
context 'using Sequel ORM' do
|
46
|
+
let(:orm_module) { 'sequel' }
|
47
|
+
it 'detects the sql INSERT' do
|
48
|
+
expect(appmap).to include(<<-SQL_QUERY.strip)
|
27
49
|
sql_query:
|
28
50
|
sql: INSERT INTO "users" ("login") VALUES ('alice') RETURNING *
|
29
|
-
|
51
|
+
SQL_QUERY
|
52
|
+
end
|
30
53
|
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
expect(appmap).to include(<<-SQL_QUERY.strip)
|
54
|
+
context 'using ActiveRecord ORM' do
|
55
|
+
let(:orm_module) { 'activerecord' }
|
56
|
+
it 'detects the sql INSERT' do
|
57
|
+
expect(appmap).to include(<<-SQL_QUERY.strip)
|
36
58
|
sql_query:
|
37
59
|
sql: INSERT INTO "users" ("login") VALUES ($1) RETURNING "id"
|
38
|
-
|
60
|
+
SQL_QUERY
|
61
|
+
end
|
39
62
|
end
|
40
63
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
expect(appmap).to include(<<-SQL_QUERY.strip)
|
64
|
+
|
65
|
+
context 'while listing records' do
|
66
|
+
let(:test_line_number) { 23 }
|
67
|
+
let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_GET_api_users_lists_the_users.appmap.json') }
|
68
|
+
|
69
|
+
context 'using Sequel ORM' do
|
70
|
+
let(:orm_module) { 'sequel' }
|
71
|
+
it 'detects the sql SELECT' do
|
72
|
+
expect(appmap).to include(<<-SQL_QUERY.strip)
|
51
73
|
sql_query:
|
52
74
|
sql: SELECT * FROM "users"
|
53
|
-
|
54
|
-
|
55
|
-
|
75
|
+
SQL_QUERY
|
76
|
+
|
77
|
+
expect(appmap).to include('sql:')
|
78
|
+
end
|
56
79
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
expect(appmap).to include(<<-SQL_QUERY.strip)
|
80
|
+
context 'using ActiveRecord ORM' do
|
81
|
+
let(:orm_module) { 'activerecord' }
|
82
|
+
it 'detects the sql SELECT' do
|
83
|
+
expect(appmap).to include(<<-SQL_QUERY.strip)
|
62
84
|
sql_query:
|
63
85
|
sql: SELECT "users".* FROM "users"
|
64
|
-
|
86
|
+
SQL_QUERY
|
87
|
+
end
|
65
88
|
end
|
66
89
|
end
|
67
90
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/util_spec.rb
ADDED
@@ -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
|
data/test/cli_test.rb
CHANGED
@@ -55,11 +55,11 @@ class CLITest < Minitest::Test
|
|
55
55
|
assert_equal <<~OUTPUT.strip, output.strip
|
56
56
|
Class frequency:
|
57
57
|
----------------
|
58
|
-
|
58
|
+
1 Main
|
59
59
|
|
60
60
|
Method frequency:
|
61
61
|
----------------
|
62
|
-
|
62
|
+
1 Main.say_hello
|
63
63
|
OUTPUT
|
64
64
|
end
|
65
65
|
|
@@ -79,13 +79,13 @@ class CLITest < Minitest::Test
|
|
79
79
|
"class_frequency": [
|
80
80
|
{
|
81
81
|
"name": "Main",
|
82
|
-
"count":
|
82
|
+
"count": 1
|
83
83
|
}
|
84
84
|
],
|
85
85
|
"method_frequency": [
|
86
86
|
{
|
87
87
|
"name": "Main.say_hello",
|
88
|
-
"count":
|
88
|
+
"count": 1
|
89
89
|
}
|
90
90
|
]
|
91
91
|
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
require 'English'
|
6
|
+
|
7
|
+
class CucumberTest < Minitest::Test
|
8
|
+
def perform_test(dir)
|
9
|
+
Bundler.with_clean_env do
|
10
|
+
Dir.chdir "test/fixtures/#{dir}" do
|
11
|
+
FileUtils.rm_rf 'tmp'
|
12
|
+
system 'bundle config --local local.appmap ../../..'
|
13
|
+
system 'bundle'
|
14
|
+
system({ 'APPMAP' => 'true' }, %(bundle exec cucumber))
|
15
|
+
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_cucumber
|
22
|
+
perform_test 'cucumber_recorder' do
|
23
|
+
appmap_file = 'tmp/appmap/cucumber/Say_hello.appmap.json'
|
24
|
+
|
25
|
+
assert File.file?(appmap_file),
|
26
|
+
%(appmap output file does not exist in #{Dir.new('tmp/appmap/cucumber').entries.join(', ')})
|
27
|
+
appmap = JSON.parse(File.read(appmap_file))
|
28
|
+
assert_equal AppMap::APPMAP_FORMAT_VERSION, appmap['version']
|
29
|
+
assert_includes appmap.keys, 'metadata'
|
30
|
+
metadata = appmap['metadata']
|
31
|
+
|
32
|
+
assert_equal 'say_hello', metadata['feature_group']
|
33
|
+
assert_equal 'I can say hello', metadata['feature']
|
34
|
+
assert_equal 'Say hello', metadata['name']
|
35
|
+
assert_includes metadata.keys, 'client'
|
36
|
+
assert_equal({ name: 'appmap', url: AppMap::URL, version: AppMap::VERSION }.stringify_keys, metadata['client'])
|
37
|
+
assert_includes metadata.keys, 'recorder'
|
38
|
+
assert_equal({ name: 'cucumber' }.stringify_keys, metadata['recorder'])
|
39
|
+
|
40
|
+
assert_includes metadata.keys, 'frameworks'
|
41
|
+
cucumber = metadata['frameworks'].select {|f| f['name'] == 'cucumber'}
|
42
|
+
assert_equal 1, cucumber.count
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_cucumber4
|
47
|
+
perform_test 'cucumber4_recorder' do
|
48
|
+
appmap_file = 'tmp/appmap/cucumber/Say_hello.appmap.json'
|
49
|
+
|
50
|
+
assert File.file?(appmap_file),
|
51
|
+
%(appmap output file does not exist in #{Dir.new('tmp/appmap/cucumber').entries.join(', ')})
|
52
|
+
appmap = JSON.parse(File.read(appmap_file))
|
53
|
+
assert_equal AppMap::APPMAP_FORMAT_VERSION, appmap['version']
|
54
|
+
assert_includes appmap.keys, 'metadata'
|
55
|
+
metadata = appmap['metadata']
|
56
|
+
|
57
|
+
assert_equal 'say_hello', metadata['feature_group']
|
58
|
+
# In cucumber4, there's no access to the feature name from within the executing scenario
|
59
|
+
# (as far as I can tell).
|
60
|
+
assert_equal 'Say hello', metadata['feature']
|
61
|
+
assert_equal 'Say hello', metadata['name']
|
62
|
+
assert_includes metadata.keys, 'client'
|
63
|
+
assert_equal({ name: 'appmap', url: AppMap::URL, version: AppMap::VERSION }.stringify_keys, metadata['client'])
|
64
|
+
assert_includes metadata.keys, 'recorder'
|
65
|
+
assert_equal({ name: 'cucumber' }.stringify_keys, metadata['recorder'])
|
66
|
+
|
67
|
+
assert_includes metadata.keys, 'frameworks'
|
68
|
+
cucumber = metadata['frameworks'].select {|f| f['name'] == 'cucumber'}
|
69
|
+
assert_equal 1, cucumber.count
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'test_helper'
|
5
|
+
require 'English'
|
6
|
+
|
7
|
+
class MinitestTest < Minitest::Test
|
8
|
+
def perform_test(test_name)
|
9
|
+
Bundler.with_clean_env do
|
10
|
+
Dir.chdir 'test/fixtures/minitest_recorder' do
|
11
|
+
FileUtils.rm_rf 'tmp'
|
12
|
+
system 'bundle config --local local.appmap ../../..'
|
13
|
+
system 'bundle'
|
14
|
+
system({ 'APPMAP' => 'true' }, %(bundle exec ruby -Ilib -Itest test/#{test_name}_test.rb))
|
15
|
+
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_hello
|
22
|
+
perform_test 'hello' do
|
23
|
+
appmap_file = 'tmp/appmap/minitest/Hello_hello.appmap.json'
|
24
|
+
|
25
|
+
assert File.file?(appmap_file), 'appmap output file does not exist'
|
26
|
+
appmap = JSON.parse(File.read(appmap_file))
|
27
|
+
assert_equal AppMap::APPMAP_FORMAT_VERSION, appmap['version']
|
28
|
+
assert_includes appmap.keys, 'metadata'
|
29
|
+
metadata = appmap['metadata']
|
30
|
+
assert_equal 'minitest_recorder', metadata['app']
|
31
|
+
assert_equal 'minitest', metadata['recorder']['name']
|
32
|
+
assert_equal 'ruby', metadata['language']['name']
|
33
|
+
assert_equal 'Hello', metadata['feature_group']
|
34
|
+
assert_equal 'hello', metadata['feature']
|
35
|
+
assert_equal 'Hello hello', metadata['name']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|