blood_contracts-instrumentation 0.1.0 → 0.1.1
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/CHANGELOG.md +11 -1
- data/blood_contracts-instrumentation.gemspec +1 -1
- data/lib/blood_contracts/instrumentation.rb +8 -0
- data/lib/blood_contracts/instrumentation/instrument.rb +1 -1
- data/spec/blood_contracts/instrumentation/config_spec.rb +105 -0
- data/spec/blood_contracts/instrumentation/failed_match_spec.rb +22 -0
- data/spec/blood_contracts/instrumentation/instrument_spec.rb +102 -0
- data/spec/blood_contracts/instrumentation/session_finalizer_spec.rb +18 -0
- data/spec/blood_contracts/instrumentation/session_recording_spec.rb +40 -0
- data/spec/blood_contracts/instrumentation/session_spec.rb +82 -0
- data/spec/blood_contracts/instrumentation_spec.rb +5 -1
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1799124ca3d91ee88f459ab3052a28317a65d84175f551ea48bedec9a2fc2d5c
|
4
|
+
data.tar.gz: b50de2922484d0e36dac0a72f4f92a4a895504c1f31cc56e42444ce213533122
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fecb3bc14257121f2fb7f183e0db21184b60af47b7aa30511c927ad2404e9bc98738a89c354779bb27fc2dab5d17ddd7e7ff5393443e6758167ef4135aac079
|
7
|
+
data.tar.gz: f829a2f03ea9ebfc23e0b4394604aa867e59521fa3f5f42600b3a0d97ae371b22c7feba29b02dc0f6743e5122c6e487deb3dc27968519639b9fae2ff5ad1d77a
|
data/CHANGELOG.md
CHANGED
@@ -5,8 +5,18 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
7
7
|
|
8
|
+
## [0.1.1] - [2019-07-25]
|
9
|
+
|
10
|
+
Fixes NoMethodError in Instrument.build
|
11
|
+
|
12
|
+
Adds specs
|
13
|
+
|
8
14
|
## [0.1.0] - [2019-07-05]
|
9
15
|
|
10
16
|
This is a first public release marked in change log with features extracted from production app.
|
11
17
|
Includes:
|
12
|
-
|
18
|
+
- Configuration for instruments (proc or a callable object)
|
19
|
+
- Automatic detection of existing Refined types
|
20
|
+
- Assignment of instruments to types
|
21
|
+
- #match wrapper to handle before, after and finalize of call
|
22
|
+
- 3 strategies of finalization (basic, threads and fibers)
|
@@ -56,6 +56,14 @@ module BloodContracts
|
|
56
56
|
@config ||= Config.new
|
57
57
|
end
|
58
58
|
|
59
|
+
# Resets current instance of Config
|
60
|
+
#
|
61
|
+
# @return [Nothig]
|
62
|
+
#
|
63
|
+
def reset_config!
|
64
|
+
@config = nil
|
65
|
+
end
|
66
|
+
|
59
67
|
require_relative "./instrumentation/failed_match.rb"
|
60
68
|
require_relative "./instrumentation/session.rb"
|
61
69
|
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe BloodContracts::Instrumentation::Config do
|
4
|
+
before do
|
5
|
+
module Test
|
6
|
+
require "json"
|
7
|
+
|
8
|
+
class EmailType < BC::Refined
|
9
|
+
REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
|
10
|
+
def match
|
11
|
+
context[:email_input] = value.to_s
|
12
|
+
return failure(:invalid_email) if context[:email_input] !~ REGEX
|
13
|
+
context[:email] = context[:email_input]
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class JsonType < BC::Refined
|
19
|
+
def match
|
20
|
+
context[:parsed] = JSON.parse(value.to_s)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
subject { described_class.new }
|
28
|
+
|
29
|
+
describe "defaults on new instance" do
|
30
|
+
let(:default_pool_size) { BCI::SessionFinalizer::DEFAULT_POOL_SIZE }
|
31
|
+
|
32
|
+
it do
|
33
|
+
expect(subject.instruments).to be_empty
|
34
|
+
expect(subject.types).to be_empty
|
35
|
+
expect(subject.finalizer_pool_size).to eq(default_pool_size)
|
36
|
+
expect(subject.session_finalizer).to eq(:basic)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#instrument" do
|
41
|
+
subject { BCI.configure { |config| config.send(:reset_types!) } }
|
42
|
+
|
43
|
+
before do
|
44
|
+
subject.types << Test::EmailType << Test::JsonType
|
45
|
+
|
46
|
+
subject.instrument "Json", lambda { |session|
|
47
|
+
puts "[SID:#{session.id}] #{session.result_type_name}"
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:instruments) { { /Json/i => [kind_of(BCI::Instrument)] } }
|
52
|
+
let(:json_instruments) { [kind_of(BCI::Instrument)] }
|
53
|
+
|
54
|
+
it do
|
55
|
+
expect(subject.instruments).to match(instruments)
|
56
|
+
expect(subject.types).to match_array([Test::EmailType, Test::JsonType])
|
57
|
+
expect(Test::EmailType.instruments).to be_empty
|
58
|
+
expect(Test::JsonType.instruments).to match_array(json_instruments)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#finalizer_pool_size=" do
|
63
|
+
before do
|
64
|
+
# Pool is only relevant for Fibers finalizer right now
|
65
|
+
subject.session_finalizer = :fibers
|
66
|
+
old_finalizer
|
67
|
+
|
68
|
+
subject.finalizer_pool_size = new_pool_size
|
69
|
+
new_finalizer
|
70
|
+
end
|
71
|
+
|
72
|
+
let(:old_finalizer) { BCI::SessionFinalizer.instance }
|
73
|
+
let(:new_finalizer) { BCI::SessionFinalizer.instance }
|
74
|
+
let(:new_pool_size) { 2 }
|
75
|
+
|
76
|
+
it do
|
77
|
+
expect(old_finalizer).not_to eq(new_finalizer)
|
78
|
+
expect(new_finalizer.fibers.size).to eq(new_pool_size)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#session_finalizer=" do
|
83
|
+
before do
|
84
|
+
# Pool is only relevant for Fibers finalizer right now
|
85
|
+
config = BCI::Config.new
|
86
|
+
default_finalizer
|
87
|
+
|
88
|
+
config.session_finalizer = :fibers
|
89
|
+
fibers_finalizer
|
90
|
+
|
91
|
+
config.session_finalizer = :threads
|
92
|
+
threads_finalizer
|
93
|
+
end
|
94
|
+
|
95
|
+
let(:default_finalizer) { BCI::SessionFinalizer.instance }
|
96
|
+
let(:fibers_finalizer) { BCI::SessionFinalizer.instance }
|
97
|
+
let(:threads_finalizer) { BCI::SessionFinalizer.instance }
|
98
|
+
|
99
|
+
it do
|
100
|
+
expect(default_finalizer).to eq(BCI::SessionFinalizer::Basic)
|
101
|
+
expect(fibers_finalizer).to match(kind_of(BCI::SessionFinalizer::Fibers))
|
102
|
+
expect(threads_finalizer).to eq(BCI::SessionFinalizer::Threads)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe BloodContracts::Instrumentation::FailedMatch do
|
4
|
+
subject do
|
5
|
+
begin
|
6
|
+
1 / 0
|
7
|
+
rescue StandardError => ex
|
8
|
+
described_class.new(ex, context: validation_context)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:validation_context) do
|
13
|
+
{ some: "data", exception: kind_of(ZeroDivisionError) }
|
14
|
+
end
|
15
|
+
|
16
|
+
it do
|
17
|
+
is_expected.to be_invalid
|
18
|
+
expect(subject.match).to eq(subject)
|
19
|
+
expect(subject.exception).to match(kind_of(ZeroDivisionError))
|
20
|
+
expect(subject.context).to match(validation_context)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe BloodContracts::Instrumentation::Instrument do
|
4
|
+
before do
|
5
|
+
module Test
|
6
|
+
Instrument = BloodContracts::Instrumentation::Instrument.build(
|
7
|
+
->(session) { "[SID:#{session.id}] #{session.result_type_name}" },
|
8
|
+
before: ->(session) { session.extras[:started] = true },
|
9
|
+
after: ->(session) { session.extras[:finished] = true }
|
10
|
+
)
|
11
|
+
|
12
|
+
class CustomInstrument
|
13
|
+
def call(session)
|
14
|
+
"[SID:#{session.id}] #{session.result_type_name}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def before(session)
|
18
|
+
session.extras[:started] = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def after(session)
|
22
|
+
session.extras[:finished] = true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
let!(:session) { BloodContracts::Instrumentation::Session.new("SomeType") }
|
29
|
+
|
30
|
+
describe ".build" do
|
31
|
+
# FIXME: add case when after and before are not defined on custom instrument
|
32
|
+
subject { BCI::Instrument.build(Test::CustomInstrument.new) }
|
33
|
+
|
34
|
+
let(:message) do
|
35
|
+
"[SID:#{session.id}] BloodContracts::Core::ContractFailure"
|
36
|
+
end
|
37
|
+
|
38
|
+
it do
|
39
|
+
expect(subject).to match(kind_of(Test::CustomInstrument))
|
40
|
+
|
41
|
+
session.start
|
42
|
+
subject.before(session)
|
43
|
+
expect(session.extras).to include(started: true)
|
44
|
+
|
45
|
+
session.finish(BC::ContractFailure.new({ SomeType: :damn }))
|
46
|
+
subject.after(session)
|
47
|
+
|
48
|
+
expect(session.extras).to include(finished: true)
|
49
|
+
|
50
|
+
expect(subject.call(session)).to eq(message)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#before" do
|
55
|
+
before do
|
56
|
+
session.start
|
57
|
+
Test::Instrument.before(session)
|
58
|
+
end
|
59
|
+
|
60
|
+
it do
|
61
|
+
expect(session.extras).to include(started: true)
|
62
|
+
expect(session.extras).not_to include(finished: true)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#after" do
|
67
|
+
before do
|
68
|
+
session.start
|
69
|
+
Test::Instrument.before(session)
|
70
|
+
|
71
|
+
session.finish(BC::ContractFailure.new({ SomeType: :damn }))
|
72
|
+
Test::Instrument.after(session)
|
73
|
+
end
|
74
|
+
|
75
|
+
it do
|
76
|
+
expect(session.extras).to include(started: true)
|
77
|
+
expect(session.extras).to include(finished: true)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#call" do
|
82
|
+
before do
|
83
|
+
session.start
|
84
|
+
Test::Instrument.before(session)
|
85
|
+
|
86
|
+
session.finish(BC::ContractFailure.new({ SomeType: :damn }))
|
87
|
+
Test::Instrument.after(session)
|
88
|
+
end
|
89
|
+
|
90
|
+
subject { Test::Instrument.call(session) }
|
91
|
+
|
92
|
+
let(:message) do
|
93
|
+
"[SID:#{session.id}] BloodContracts::Core::ContractFailure"
|
94
|
+
end
|
95
|
+
|
96
|
+
it do
|
97
|
+
is_expected.to eq(message)
|
98
|
+
expect(session.extras).to include(started: true)
|
99
|
+
expect(session.extras).to include(finished: true)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe BloodContracts::Instrumentation::SessionFinalizer do
|
4
|
+
before do
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "defaults on new instance" do
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "Basic finalizer" do
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Threads finalizer" do
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Fibers finalizer" do
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe BloodContracts::Instrumentation::SessionRecording do
|
4
|
+
before do
|
5
|
+
BCI.reset_config!
|
6
|
+
module Test
|
7
|
+
class PhoneType < BC::Refined
|
8
|
+
REGEX = /\A(\+7|8)(9|8)\d{9}\z/i
|
9
|
+
def match
|
10
|
+
context[:phone_input] = value.to_s
|
11
|
+
return failure(:invalid_phone) if context[:phone_input] !~ REGEX
|
12
|
+
context[:phone] = context[:phone_input]
|
13
|
+
self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class CustomInstrument
|
18
|
+
def call(session)
|
19
|
+
"[SID:#{session.id}] #{session.result_type_name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def before(session)
|
23
|
+
session.extras[:started] = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def after(session)
|
27
|
+
session.extras[:finished] = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
BCI.configure { |cfg| cfg.instrument "Phone", custom_instrument }
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:custom_instrument) { Test::CustomInstrument.new }
|
36
|
+
|
37
|
+
it do
|
38
|
+
expect(Test::PhoneType.instruments).to match_array([custom_instrument])
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe BloodContracts::Instrumentation::Session do
|
4
|
+
before do
|
5
|
+
module Test
|
6
|
+
class PhoneType < BC::Refined
|
7
|
+
REGEX = /\A(\+7|8)(9|8)\d{9}\z/i
|
8
|
+
def match
|
9
|
+
context[:phone_input] = value.to_s
|
10
|
+
return failure(:invalid_phone) if context[:phone_input] !~ REGEX
|
11
|
+
context[:phone] = context[:phone_input]
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
subject { described_class.new(Test::PhoneType.name) }
|
19
|
+
|
20
|
+
describe "defaults on new instance" do
|
21
|
+
it do
|
22
|
+
expect(subject.extras).to be_empty
|
23
|
+
|
24
|
+
expect(subject.context).to be_empty
|
25
|
+
expect(subject.matcher_type_name).to eq(Test::PhoneType.name)
|
26
|
+
|
27
|
+
expect(subject.result_type_name).to be_nil
|
28
|
+
expect(subject.id.size).to eq(20)
|
29
|
+
|
30
|
+
expect(subject.started_at).to be_nil
|
31
|
+
expect(subject.finished_at).to be_nil
|
32
|
+
|
33
|
+
expect(subject.scope).to be_nil
|
34
|
+
expect(subject.path).to be_nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#start" do
|
39
|
+
before { subject.start }
|
40
|
+
|
41
|
+
it do
|
42
|
+
expect(subject.extras).to be_empty
|
43
|
+
expect(subject.context).to be_empty
|
44
|
+
|
45
|
+
expect(subject.matcher_type_name).to eq(Test::PhoneType.name)
|
46
|
+
expect(subject.result_type_name).to be_nil
|
47
|
+
|
48
|
+
expect(subject.id.size).to eq(20)
|
49
|
+
|
50
|
+
expect(subject.started_at).to match(kind_of(Time))
|
51
|
+
expect(subject.finished_at).to be_nil
|
52
|
+
|
53
|
+
expect(subject.scope).to be_nil
|
54
|
+
expect(subject.path).to be_nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#finish" do
|
59
|
+
before do
|
60
|
+
subject.start
|
61
|
+
subject.finish(invalid_match)
|
62
|
+
end
|
63
|
+
|
64
|
+
let(:invalid_match) { Test::PhoneType.match("asdasdsdas") }
|
65
|
+
|
66
|
+
it do
|
67
|
+
expect(subject.extras).to be_empty
|
68
|
+
expect(subject.context).to match(invalid_match.context)
|
69
|
+
|
70
|
+
expect(subject.matcher_type_name).to eq(Test::PhoneType.name)
|
71
|
+
expect(subject.result_type_name).to eq(BC::ContractFailure.name)
|
72
|
+
|
73
|
+
expect(subject.id.size).to eq(20)
|
74
|
+
|
75
|
+
expect(subject.started_at).to match(kind_of(Time))
|
76
|
+
expect(subject.finished_at).to match(kind_of(Time))
|
77
|
+
|
78
|
+
expect(subject.scope).to eq(described_class::NO_SCOPE)
|
79
|
+
expect(subject.path).to eq(described_class::NO_VALIDATION_PATH)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
RSpec.describe BloodContracts::Instrumentation do
|
4
4
|
before do
|
5
|
+
BCI.configure { |config| config.send(:reset_types!) }
|
6
|
+
|
5
7
|
module Test
|
6
8
|
require "json"
|
7
9
|
|
@@ -57,7 +59,9 @@ RSpec.describe BloodContracts::Instrumentation do
|
|
57
59
|
context "when type matches instruments condition" do
|
58
60
|
let(:type) { Test::JsonType.name }
|
59
61
|
|
60
|
-
it
|
62
|
+
it do
|
63
|
+
is_expected.to match_array([kind_of(BCI::Instrument)])
|
64
|
+
end
|
61
65
|
end
|
62
66
|
|
63
67
|
context "when type doesn't match instruments condition" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blood_contracts-instrumentation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergey Dolganov (sclinede)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: blood_contracts-core
|
@@ -128,6 +128,12 @@ files:
|
|
128
128
|
- lib/blood_contracts/instrumentation/session_finalizer/fibers.rb
|
129
129
|
- lib/blood_contracts/instrumentation/session_finalizer/threads.rb
|
130
130
|
- lib/blood_contracts/instrumentation/session_recording.rb
|
131
|
+
- spec/blood_contracts/instrumentation/config_spec.rb
|
132
|
+
- spec/blood_contracts/instrumentation/failed_match_spec.rb
|
133
|
+
- spec/blood_contracts/instrumentation/instrument_spec.rb
|
134
|
+
- spec/blood_contracts/instrumentation/session_finalizer_spec.rb
|
135
|
+
- spec/blood_contracts/instrumentation/session_recording_spec.rb
|
136
|
+
- spec/blood_contracts/instrumentation/session_spec.rb
|
131
137
|
- spec/blood_contracts/instrumentation_spec.rb
|
132
138
|
- spec/spec_helper.rb
|
133
139
|
homepage: https://github.com/sclinede/blood_contracts-core
|
@@ -154,5 +160,11 @@ signing_key:
|
|
154
160
|
specification_version: 4
|
155
161
|
summary: Adds instrumentation to BloodContracts refinement types
|
156
162
|
test_files:
|
163
|
+
- spec/blood_contracts/instrumentation/config_spec.rb
|
164
|
+
- spec/blood_contracts/instrumentation/failed_match_spec.rb
|
165
|
+
- spec/blood_contracts/instrumentation/instrument_spec.rb
|
166
|
+
- spec/blood_contracts/instrumentation/session_finalizer_spec.rb
|
167
|
+
- spec/blood_contracts/instrumentation/session_recording_spec.rb
|
168
|
+
- spec/blood_contracts/instrumentation/session_spec.rb
|
157
169
|
- spec/blood_contracts/instrumentation_spec.rb
|
158
170
|
- spec/spec_helper.rb
|