mtk_framework 0.1.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 (50) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/test.yml +21 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +22 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.rdoc +18 -0
  8. data/Rakefile +50 -0
  9. data/VERSION +1 -0
  10. data/lib/mtk_framework.rb +50 -0
  11. data/lib/mtk_framework/active_interaction_concerns/i18nable.rb +18 -0
  12. data/lib/mtk_framework/active_interaction_concerns/interruptable.rb +32 -0
  13. data/lib/mtk_framework/active_interaction_concerns/loggable.rb +84 -0
  14. data/lib/mtk_framework/active_interaction_concerns/rescuable.rb +27 -0
  15. data/lib/mtk_framework/active_interaction_concerns/updatable_object.rb +32 -0
  16. data/lib/mtk_framework/active_interaction_mocks/interaction_group_mocks_helper.rb +32 -0
  17. data/lib/mtk_framework/active_interaction_mocks/interaction_mocks_helper.rb +61 -0
  18. data/lib/mtk_framework/active_interaction_mocks/mocks_loader.rb +53 -0
  19. data/lib/mtk_framework/active_interaction_params.rb +16 -0
  20. data/lib/mtk_framework/active_interaction_params/parametrize_filter.rb +108 -0
  21. data/lib/mtk_framework/core_extensions/array/except.rb +7 -0
  22. data/lib/mtk_framework/core_extensions/class/virtual_method.rb +11 -0
  23. data/lib/mtk_framework/core_extensions/hash/rename_keys.rb +11 -0
  24. data/lib/mtk_framework/gem_extensions/active_interaction/base.rb +20 -0
  25. data/lib/mtk_framework/gem_extensions/active_interaction/filters/abstract_tz_filter.rb +28 -0
  26. data/lib/mtk_framework/gem_extensions/active_interaction/filters/hash_filter.rb +38 -0
  27. data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_account_filter.rb +23 -0
  28. data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_contract_address_filter.rb +23 -0
  29. data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_operation_filter.rb +23 -0
  30. data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_public_key_filter.rb +23 -0
  31. data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_secret_key_filter.rb +23 -0
  32. data/lib/mtk_framework/gem_extensions/active_interaction/filters/tz_signature_filter.rb +23 -0
  33. data/lib/mtk_framework/locale/active_interaction.fr.yml +8 -0
  34. data/lib/mtk_framework/locale/fr.yml +219 -0
  35. data/lib/mtk_framework/railtie.rb +13 -0
  36. data/mtk_framework.gemspec +114 -0
  37. data/spec/active_interaction_concerns/interruptable_spec.rb +127 -0
  38. data/spec/active_interaction_concerns/loggable_spec.rb +195 -0
  39. data/spec/application_interaction_spec.rb +17 -0
  40. data/spec/fake_app.rb +14 -0
  41. data/spec/gem_extensions/active_interaction/filters/tz_account_filter_spec.rb +7 -0
  42. data/spec/gem_extensions/active_interaction/filters/tz_contract_address_filter_spec.rb +7 -0
  43. data/spec/gem_extensions/active_interaction/filters/tz_operation_filter_spec.rb +7 -0
  44. data/spec/gem_extensions/active_interaction/filters/tz_public_key_filter_spec.rb +7 -0
  45. data/spec/gem_extensions/active_interaction/filters/tz_secret_key_filter_spec.rb +7 -0
  46. data/spec/gem_extensions/active_interaction/filters/tz_signature_filter_spec.rb +7 -0
  47. data/spec/gem_extensions/active_interaction/filters_shared.rb +253 -0
  48. data/spec/gem_extensions/active_interaction/tz_filters_shared.rb +60 -0
  49. data/spec/spec_helper.rb +24 -0
  50. metadata +232 -0
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe MtkFramework::ActiveInteractionConcerns::Loggable do
4
+ let(:logger_output) { StringIO.new }
5
+ let(:logger) { Logger.new(logger_output) }
6
+
7
+ before do
8
+ allow(Rails).to receive(:logger).and_return(logger)
9
+ end
10
+
11
+ describe 'run' do
12
+ before do
13
+ application_interaction = Class.new(ActiveInteraction::Base) do
14
+ include MtkFramework::ActiveInteractionConcerns::Loggable
15
+ include MtkFramework::ActiveInteractionConcerns::Interruptable
16
+ end
17
+
18
+ stub_const('ApplicationInteraction', application_interaction)
19
+ end
20
+ context 'simple interaction' do
21
+ subject { DummyInteraction.run(params) }
22
+
23
+ before do
24
+ dummy_interaction = Class.new(ApplicationInteraction) do
25
+ integer :integer_param
26
+
27
+ validates :integer_param, numericality: { geater_than: 0 }
28
+
29
+ def execute
30
+ errors.add(:integer_param, :invalid) unless integer_param > 10
31
+ end
32
+ end
33
+
34
+ stub_const('DummyInteraction', dummy_interaction)
35
+ end
36
+
37
+ context 'type_check fails' do
38
+ let(:params) { {} }
39
+
40
+ it 'logs errors' do
41
+ expect(subject).not_to be_valid
42
+ expect(logger_output.string)
43
+ .to match %r{Interaction DummyInteraction failed: 'Integer param est obligatoire' called from: spec/active_interaction_concerns/loggable_spec\.rb} # rubocop:disable Layout/LineLength
44
+ end
45
+ end
46
+
47
+ context 'type_check succeeds' do
48
+ context 'validation fails' do
49
+ let(:params) { { integer_param: 0 } }
50
+
51
+ it 'logs errors' do
52
+ expect(subject).not_to be_valid
53
+ expect(logger_output.string)
54
+ end
55
+ end
56
+
57
+ context 'validation succeeds' do
58
+ context 'execution fails' do
59
+ let(:params) { { integer_param: 1 } }
60
+
61
+ it 'logs errors' do
62
+ expect(subject).not_to be_valid
63
+ expect(logger_output.string)
64
+ expect(logger_output.string)
65
+ end
66
+ end
67
+
68
+ context 'execution succeeds' do
69
+ let(:params) { { integer_param: 11 } }
70
+
71
+ it 'logs call' do
72
+ expect(subject).to be_valid
73
+ expect(logger_output.string)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ context 'with compose' do
80
+ subject { DummyWithcompose.run(params) }
81
+
82
+ before do
83
+ dummy_with_compose = Class.new(ApplicationInteraction) do
84
+ integer :integer_param
85
+
86
+ def execute
87
+ compose(DummyInteraction, integer_param: integer_param)
88
+ end
89
+ end
90
+
91
+ stub_const('DummyWithcompose', dummy_with_compose)
92
+ end
93
+
94
+ context 'succeeds' do
95
+ let(:params) { { integer_param: 11 } }
96
+
97
+ it 'works' do
98
+ expect(subject).to be_valid
99
+ expect(logger_output.string)
100
+ expect(logger_output.string)
101
+ .to include 'Interaction DummyInteraction [{:integer_param=>11}] called from spec/active_interaction_concerns/loggable_spec.rb' # rubocop:disable Layout/LineLength
102
+ end
103
+ end
104
+
105
+ context 'compose execution fails' do
106
+ let(:params) { { integer_param: 0 } }
107
+
108
+ it 'logs failures for each interaction' do
109
+ expect(subject).not_to be_valid
110
+ expect(logger_output.string).to include 'Interaction DummyInteraction failed'
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ context 'interrupted' do
117
+ subject { DummyInterrupted.run }
118
+
119
+ before do
120
+ dummy_interaction = Class.new(ApplicationInteraction) do
121
+ def execute
122
+ interrupt_execute! :base, :invalid
123
+ end
124
+ end
125
+
126
+ stub_const('DummyInterrupted', dummy_interaction)
127
+ end
128
+
129
+ it 'works' do
130
+ expect(subject).not_to be_valid
131
+ expect(logger_output.string)
132
+ .to include 'Interaction DummyInterrupted [] called from spec/active_interaction_concerns/loggable_spec.rb' # rubocop:disable Layout/LineLength
133
+ expect(logger_output.string)
134
+ .to include "Interaction DummyInterrupted failed: 'est invalide' called from: spec/active_interaction_concerns/loggable_spec.rb" # rubocop:disable Layout/LineLength
135
+ end
136
+ end
137
+
138
+ context 'run! interrupted' do
139
+ subject { DummyInterrupted.run! }
140
+
141
+ before do
142
+ dummy_interaction = Class.new(ApplicationInteraction) do
143
+ def execute
144
+ interrupt_execute! :base, :invalid
145
+ end
146
+ end
147
+
148
+ stub_const('DummyInterrupted', dummy_interaction)
149
+ end
150
+
151
+ it 'works' do
152
+ expect { subject }.to raise_error ActiveInteraction::InvalidInteractionError, 'est invalide'
153
+ expect(logger_output.string)
154
+ .to include 'Interaction DummyInterrupted [] called from spec/active_interaction_concerns/loggable_spec.rb' # rubocop:disable Layout/LineLength
155
+ expect(logger_output.string)
156
+ .to include "Interaction DummyInterrupted failed: 'est invalide' called from: spec/active_interaction_concerns/loggable_spec.rb" # rubocop:disable Layout/LineLength
157
+ end
158
+ end
159
+
160
+ context 'filtering logs' do
161
+ subject { DummyInteraction.run(params) }
162
+
163
+ let(:params) do
164
+ {
165
+ password: 'super secret',
166
+ bank_account: {
167
+ name: 'name_value'
168
+ },
169
+ not_filtered: 'value'
170
+ }
171
+ end
172
+
173
+ before do
174
+ dummy_interaction = Class.new(ApplicationInteraction) do
175
+ string :password
176
+ hash :bank_account do
177
+ string :name
178
+ end
179
+ string :not_filtered
180
+
181
+ def execute; end
182
+ end
183
+
184
+ stub_const('DummyInteraction', dummy_interaction)
185
+ end
186
+
187
+ it 'logs call filtering params' do
188
+ expect(subject).to be_valid
189
+ x = logger_output.string
190
+ expect(logger_output.string)
191
+ .to include 'Interaction DummyInteraction [{:password=>"[FILTERED]", :bank_account=>{:name=>"[FILTERED]"}, :not_filtered=>"value"}] called from spec/active_interaction_concerns/loggable_spec.rb' # rubocop:disable Layout/LineLength
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require_relative 'spec_helper'
4
+ # require 'active_interaction'
5
+ # require 'mtk_framework'
6
+ # require 'pry'
7
+
8
+ class ApplicationInteraction < ActiveInteraction::Base
9
+ include MtkFramework::ActiveInteractionConcerns::I18nable
10
+ include MtkFramework::ActiveInteractionConcerns::Interruptable
11
+ include MtkFramework::ActiveInteractionConcerns::Loggable
12
+ include MtkFramework::ActiveInteractionConcerns::Rescuable
13
+ include MtkFramework::ActiveInteractionConcerns::UpdatableObject
14
+ end
15
+
16
+ RSpec.describe ApplicationInteraction do
17
+ end
data/spec/fake_app.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dummy
4
+ class Application < Rails::Application
5
+ config.eager_load = false
6
+ config.root = ''
7
+ config.filter_parameters = ['password', 'bank_account.name']
8
+ config.i18n.default_locale = :fr
9
+ end
10
+ end
11
+
12
+ Rails.logger = Logger.new('/dev/null')
13
+
14
+ Rails.application.initialize!
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe ActiveInteraction::TzAccountFilter, :filter do # rubocop: disable RSpec/FilePath
4
+ it_behaves_like "a tz filter",
5
+ valid: [Faker::Blockchain::Tezos.account],
6
+ invalid: ["invalid", Faker::Blockchain::Tezos.secret_key]
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe ActiveInteraction::TzContractAddressFilter, :filter do # rubocop: disable RSpec/FilePath
4
+ it_behaves_like "a tz filter",
5
+ valid: [Faker::Blockchain::Tezos.contract],
6
+ invalid: ["invalid", Faker::Blockchain::Tezos.secret_key]
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe ActiveInteraction::TzOperationFilter, :filter do # rubocop: disable RSpec/FilePath
4
+ it_behaves_like "a tz filter",
5
+ valid: [Faker::Blockchain::Tezos.operation],
6
+ invalid: ["invalid", Faker::Blockchain::Tezos.secret_key]
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe ActiveInteraction::TzPublicKeyFilter, :filter do # rubocop: disable RSpec/FilePath
4
+ it_behaves_like "a tz filter",
5
+ valid: [Faker::Blockchain::Tezos.public_key],
6
+ invalid: ["invalid", Faker::Blockchain::Tezos.secret_key]
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe ActiveInteraction::TzSecretKeyFilter, :filter do # rubocop: disable RSpec/FilePath
4
+ it_behaves_like "a tz filter",
5
+ valid: [Faker::Blockchain::Tezos.secret_key],
6
+ invalid: ["invalid", 10, Faker::Blockchain::Tezos.public_key]
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe ActiveInteraction::TzSignatureFilter, :filter do # rubocop: disable RSpec/FilePath
4
+ it_behaves_like "a tz filter",
5
+ valid: [Faker::Blockchain::Tezos.signature],
6
+ invalid: ["invalid", 10, Faker::Blockchain::Tezos.public_key]
7
+ end
@@ -0,0 +1,253 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_context "filters" do
4
+ subject(:filter) { described_class.new(name, options, &block) }
5
+
6
+ let(:block) { nil }
7
+ let(:name) { SecureRandom.hex.to_sym }
8
+ let(:options) { {} }
9
+
10
+ shared_context "optional" do
11
+ before do
12
+ options[:default] = nil
13
+ end
14
+ end
15
+
16
+ shared_context "required" do
17
+ before do
18
+ options.delete(:default)
19
+ end
20
+ end
21
+ end
22
+
23
+ RSpec.shared_examples_for "a filter" do
24
+ include_context "filters"
25
+
26
+ describe ".factory" do
27
+ context "with an invalid slug" do
28
+ it "raises an error" do
29
+ expect do
30
+ described_class.factory(:invalid)
31
+ end.to raise_error ActiveInteraction::MissingFilterError
32
+ end
33
+ end
34
+
35
+ context "with a valid slug" do
36
+ it "returns a Filter" do
37
+ expect(
38
+ described_class.factory(described_class.slug)
39
+ ).to eql described_class
40
+ end
41
+ end
42
+ end
43
+
44
+ describe ".slug" do
45
+ it "returns a symbol" do
46
+ expect(described_class.slug).to be_a Symbol
47
+ end
48
+ end
49
+
50
+ describe "#cast" do
51
+ let(:value) { nil }
52
+ let(:result) { filter.send(:cast, value, nil) }
53
+
54
+ context "optional" do
55
+ include_context "optional"
56
+
57
+ it "returns nil" do
58
+ expect(result).to be_nil
59
+ end
60
+ end
61
+
62
+ context "required" do
63
+ include_context "required"
64
+
65
+ it "raises an error" do
66
+ expect { result }.to raise_error ActiveInteraction::MissingValueError
67
+ end
68
+
69
+ context "with an invalid default" do
70
+ let(:value) { Object.new }
71
+
72
+ it "raises an error" do
73
+ expect { result }.to raise_error ActiveInteraction::InvalidValueError
74
+ end
75
+ end
76
+ end
77
+
78
+ # BasicObject is missing a lot of methods
79
+ context "with a BasicObject" do
80
+ let(:value) { BasicObject.new }
81
+
82
+ it "raises an error" do
83
+ expect { result }.to raise_error ActiveInteraction::InvalidValueError
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "#clean" do
89
+ let(:value) { nil }
90
+
91
+ context "optional" do
92
+ include_context "optional"
93
+
94
+ it "returns the default" do
95
+ expect(filter.clean(value, nil)).to eql options[:default]
96
+ end
97
+ end
98
+
99
+ context "required" do
100
+ include_context "required"
101
+
102
+ it "raises an error" do
103
+ expect do
104
+ filter.clean(value, nil)
105
+ end.to raise_error ActiveInteraction::MissingValueError
106
+ end
107
+
108
+ context "with an invalid value" do
109
+ let(:value) { Object.new }
110
+
111
+ it "raises an error" do
112
+ expect do
113
+ filter.clean(value, nil)
114
+ end.to raise_error ActiveInteraction::InvalidValueError
115
+ end
116
+ end
117
+ end
118
+
119
+ context "with an invalid default" do
120
+ before do
121
+ options[:default] = Object.new
122
+ end
123
+
124
+ it "raises an error" do
125
+ expect do
126
+ filter.clean(value, nil)
127
+ end.to raise_error ActiveInteraction::InvalidDefaultError
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "#default" do
133
+ context "optional" do
134
+ include_context "optional"
135
+
136
+ it "returns the default" do
137
+ expect(filter.default(nil)).to eql options[:default]
138
+ end
139
+ end
140
+
141
+ context "required" do
142
+ include_context "required"
143
+
144
+ it "raises an error" do
145
+ expect do
146
+ filter.default(nil)
147
+ end.to raise_error ActiveInteraction::NoDefaultError
148
+ end
149
+ end
150
+
151
+ context "with an invalid default" do
152
+ before do
153
+ options[:default] = Object.new
154
+ end
155
+
156
+ it "raises an error" do
157
+ expect do
158
+ filter.default(nil)
159
+ end.to raise_error ActiveInteraction::InvalidDefaultError
160
+ end
161
+ end
162
+
163
+ context "with a callable default" do
164
+ include_context "optional"
165
+
166
+ before do
167
+ default = options[:default]
168
+ options[:default] = -> { default }
169
+ end
170
+
171
+ it "returns the default" do
172
+ expect(filter.default(nil)).to eql options[:default].call
173
+ end
174
+ end
175
+
176
+ context "with a callable default that takes an argument" do
177
+ include_context "optional"
178
+
179
+ it "returns the default" do
180
+ default = options[:default]
181
+
182
+ spec = self
183
+ filter # Necessary to bring into scope for lambda.
184
+ options[:default] = ->(this) do
185
+ spec.expect(this).to be filter
186
+ default
187
+ end
188
+
189
+ expect(filter.default(nil)).to be default
190
+ end
191
+ end
192
+ end
193
+
194
+ describe "#desc" do
195
+ it "returns nil" do
196
+ expect(filter.desc).to be_nil
197
+ end
198
+
199
+ context "with a description" do
200
+ let(:desc) { SecureRandom.hex }
201
+
202
+ before do
203
+ options[:desc] = desc
204
+ end
205
+
206
+ it "returns the description" do
207
+ expect(filter.desc).to eql desc
208
+ end
209
+ end
210
+ end
211
+
212
+ describe "#filters" do
213
+ it "returns Hash" do
214
+ expect(filter.filters).to be_a Hash
215
+ end
216
+ end
217
+
218
+ describe "#default?" do
219
+ context "optional" do
220
+ include_context "optional"
221
+
222
+ it "returns true" do
223
+ expect(filter).to be_default
224
+ end
225
+ end
226
+
227
+ context "required" do
228
+ include_context "required"
229
+
230
+ it "returns false" do
231
+ expect(filter).not_to be_default
232
+ end
233
+ end
234
+ end
235
+
236
+ describe "#name" do
237
+ it "returns the name" do
238
+ expect(filter.name).to eql name
239
+ end
240
+ end
241
+
242
+ describe "#options" do
243
+ it "returns the options" do
244
+ expect(filter.options).to eql options
245
+ end
246
+ end
247
+
248
+ describe "#database_column_type" do
249
+ it "returns a symbol" do
250
+ expect(filter.database_column_type).to be_a Symbol
251
+ end
252
+ end
253
+ end