blood_contracts-instrumentation 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a1ff83954224dfbb24664768832c7db0e4b621364a92de707c3b1774fbc9e30
4
- data.tar.gz: e271b417bdd7082067d91faf6826d91c0f13f5e2f3f01068ddba0a23af3edf8c
3
+ metadata.gz: 1799124ca3d91ee88f459ab3052a28317a65d84175f551ea48bedec9a2fc2d5c
4
+ data.tar.gz: b50de2922484d0e36dac0a72f4f92a4a895504c1f31cc56e42444ce213533122
5
5
  SHA512:
6
- metadata.gz: d6c19029329fbf97adbea0fe440b0951c2ac6f9dd251ba4bf0c2e93d40421e9a823e9f5445c3483f4b78a4f3f23a5827bfa42406757d27f8d82264dbb660a66d
7
- data.tar.gz: bdb1e16379fd159cff96592bff34fd0ed43182bf8da38720acc3a0bf4e759ee0fe78ba746f84a7fcdf7f5dea2f19463c32f68b11e1c5589c776b8abcb56a51f3
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
- TBD
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)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = 'blood_contracts-instrumentation'
5
- gem.version = '0.1.0'
5
+ gem.version = '0.1.1'
6
6
  gem.authors = ['Sergey Dolganov (sclinede)']
7
7
  gem.email = ['sclinede@evilmartians.com']
8
8
 
@@ -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
 
@@ -29,7 +29,7 @@ module BloodContracts
29
29
  instance = instrument_from_proc(proto)
30
30
 
31
31
  if before.respond_to?(:call)
32
- inst.define_singleton_method(:before, &before)
32
+ instance.define_singleton_method(:before, &before)
33
33
  end
34
34
 
35
35
  define_stub(instance, :before)
@@ -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 { is_expected.to match_array([kind_of(described_class::Instrument)]) }
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.0
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 00:00:00.000000000 Z
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