mercy 1.3.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 +7 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +88 -0
- data/LICENSE +22 -0
- data/README.md +100 -0
- data/Rakefile +7 -0
- data/circle.yml +16 -0
- data/lib/bidu.rb +3 -0
- data/lib/bidu/mercy.rb +18 -0
- data/lib/bidu/mercy/class_methods.rb +19 -0
- data/lib/bidu/mercy/concern.rb +10 -0
- data/lib/bidu/mercy/report.rb +44 -0
- data/lib/bidu/mercy/report/active_record.rb +28 -0
- data/lib/bidu/mercy/report/error.rb +62 -0
- data/lib/bidu/mercy/report/multiple.rb +29 -0
- data/lib/bidu/mercy/report/range.rb +54 -0
- data/lib/bidu/mercy/report_builder.rb +24 -0
- data/lib/bidu/mercy/report_config.rb +37 -0
- data/lib/bidu/mercy/status.rb +27 -0
- data/lib/bidu/mercy/status_builder.rb +35 -0
- data/lib/bidu/mercy/version.rb +5 -0
- data/lib/bidu/period_parser.rb +32 -0
- data/lib/json_parser/type_cast_ext.rb +7 -0
- data/mercy.gemspec +33 -0
- data/spec/lib/bidu/mercy/report/error_spec.rb +385 -0
- data/spec/lib/bidu/mercy/report/multiple_spec.rb +122 -0
- data/spec/lib/bidu/mercy/report/range_spec.rb +302 -0
- data/spec/lib/bidu/mercy/report/report_config_spec.rb +39 -0
- data/spec/lib/bidu/mercy/report_builder_spec.rb +72 -0
- data/spec/lib/bidu/mercy/report_spec.rb +44 -0
- data/spec/lib/bidu/mercy/status_builder_spec.rb +84 -0
- data/spec/lib/bidu/mercy/status_spec.rb +135 -0
- data/spec/lib/bidu/period_parser_spec.rb +27 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/fixture_helpers.rb +19 -0
- data/spec/support/models/document.rb +6 -0
- data/spec/support/report/dummy.rb +17 -0
- data/spec/support/schema.rb +11 -0
- metadata +236 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Bidu::Mercy::ReportBuilder do
|
|
4
|
+
let(:errors) { 1 }
|
|
5
|
+
let(:successes) { 3 }
|
|
6
|
+
let(:old_errors) { 2 }
|
|
7
|
+
let(:key) { :errors }
|
|
8
|
+
let(:threshold) { 0.02 }
|
|
9
|
+
let(:period) { 1.day }
|
|
10
|
+
let(:external_key) { :external_id }
|
|
11
|
+
let(:config) do
|
|
12
|
+
{
|
|
13
|
+
period: period,
|
|
14
|
+
threshold: threshold,
|
|
15
|
+
external_key: :external_id,
|
|
16
|
+
scope: :with_error,
|
|
17
|
+
id: key,
|
|
18
|
+
clazz: Document
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
let(:parameters) { {} }
|
|
22
|
+
let(:report) { subject.build(key, parameters) }
|
|
23
|
+
before do
|
|
24
|
+
subject.add_config(key, config)
|
|
25
|
+
Document.all.each(&:destroy)
|
|
26
|
+
successes.times { |i| Document.create status: :success, external_id: 30+i }
|
|
27
|
+
errors.times { |i| Document.create status: :error, external_id: 10+i }
|
|
28
|
+
old_errors.times do |i|
|
|
29
|
+
Document.create status: :error, external_id: 20+i, created_at: 2.days.ago, updated_at: 2.days.ago
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe '#build' do
|
|
34
|
+
let(:ids) { [ 10 ] }
|
|
35
|
+
it do
|
|
36
|
+
expect(report).to be_a(Bidu::Mercy::Report::Error)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'builds the report using the given configuration' do
|
|
40
|
+
expect(report.as_json).to eq( ids: ids, percentage: 0.25, status: :error )
|
|
41
|
+
expect(report.error?).to be_truthy
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'when passing a custom threshold parameter' do
|
|
45
|
+
let(:parameters) { { threshold: 1 } }
|
|
46
|
+
|
|
47
|
+
it 'uses custom threshold parameter' do
|
|
48
|
+
expect(report.error?).to be_falsey
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context 'when passing a custom period parameter' do
|
|
53
|
+
let(:parameters) { { threshold: 0.4, period: 10.days, status: :error } }
|
|
54
|
+
|
|
55
|
+
it 'uses custom period parameter' do
|
|
56
|
+
expect(report.error?).to be_truthy
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'when passing a custom other parameters' do
|
|
61
|
+
let(:parameters) do
|
|
62
|
+
{ scope: :with_success, clazz: Bidu::Mercy::Report::Error, external_key: :id, id: :failures }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'ignores the non customizable parameters' do
|
|
66
|
+
expect(report.as_json).to eq( ids: ids, percentage: 0.25, status: :error )
|
|
67
|
+
expect(report.error?).to be_truthy
|
|
68
|
+
expect(report.id).to eq(:errors)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Bidu::Mercy::Report do
|
|
4
|
+
class Bidu::Mercy::Report::Dummy1 < Bidu::Mercy::Report
|
|
5
|
+
DEFAULT_OPTION = {
|
|
6
|
+
option_value: 1,
|
|
7
|
+
other_option: 10
|
|
8
|
+
}
|
|
9
|
+
json_parse :option_value, :other_option, case: :snake
|
|
10
|
+
end
|
|
11
|
+
class Bidu::Mercy::Report::Dummy2 < Bidu::Mercy::Report::Dummy1; end
|
|
12
|
+
class Bidu::Mercy::Report::Dummy3 < Bidu::Mercy::Report::Dummy1
|
|
13
|
+
DEFAULT_OPTION = { option_value: 5 }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe 'default_options' do
|
|
17
|
+
let(:report_class) { described_class::Dummy1 }
|
|
18
|
+
let(:subject) { report_class.new }
|
|
19
|
+
|
|
20
|
+
it 'setup the attributes using class default options' do
|
|
21
|
+
expect(subject.option_value).to eq(1)
|
|
22
|
+
expect(subject.other_option).to eq(10)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'when class inherit options' do
|
|
26
|
+
let(:report_class) { described_class::Dummy2 }
|
|
27
|
+
|
|
28
|
+
it 'setup the attributes using superclass default options' do
|
|
29
|
+
expect(subject.option_value).to eq(1)
|
|
30
|
+
expect(subject.other_option).to eq(10)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'when class inherit options but overrides some' do
|
|
35
|
+
let(:report_class) { described_class::Dummy3 }
|
|
36
|
+
|
|
37
|
+
it 'setup the attributes using superclass default options' do
|
|
38
|
+
expect(subject.option_value).to eq(5)
|
|
39
|
+
expect(subject.other_option).to eq(10)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Bidu::Mercy::StatusBuilder do
|
|
4
|
+
let(:errors) { 1 }
|
|
5
|
+
let(:successes) { 3 }
|
|
6
|
+
let(:old_errors) { 2 }
|
|
7
|
+
let(:key) { :errors }
|
|
8
|
+
let(:threshold) { 0.02 }
|
|
9
|
+
let(:period) { 1.day }
|
|
10
|
+
let(:external_key) { :external_id }
|
|
11
|
+
let(:config) do
|
|
12
|
+
{
|
|
13
|
+
period: period,
|
|
14
|
+
threshold: threshold,
|
|
15
|
+
scope: :with_error,
|
|
16
|
+
clazz: Document,
|
|
17
|
+
id: :failures,
|
|
18
|
+
external_key: :external_id,
|
|
19
|
+
on: key
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
let(:parameters) { {} }
|
|
23
|
+
let(:status) { subject.build(key, parameters) }
|
|
24
|
+
before do
|
|
25
|
+
subject.add_report_config(key, config)
|
|
26
|
+
Document.all.each(&:destroy)
|
|
27
|
+
successes.times { |i| Document.create status: :success, external_id: 30+i }
|
|
28
|
+
errors.times { |i| Document.create status: :error, external_id: 10+i }
|
|
29
|
+
old_errors.times do |i|
|
|
30
|
+
Document.create status: :error, external_id: 20+i, created_at: 2.days.ago, updated_at: 2.days.ago
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#build' do
|
|
35
|
+
let(:ids) { [ 10 ] }
|
|
36
|
+
let(:status_expected) { :error }
|
|
37
|
+
let(:percentage) { 0.25 }
|
|
38
|
+
let(:json_expected) do
|
|
39
|
+
{
|
|
40
|
+
status: status_expected,
|
|
41
|
+
failures: {
|
|
42
|
+
ids: ids,
|
|
43
|
+
percentage: percentage,
|
|
44
|
+
status: status_expected
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it do
|
|
50
|
+
expect(status).to be_a(Bidu::Mercy::Status)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context 'when not specifying where to report' do
|
|
54
|
+
let(:key) {}
|
|
55
|
+
|
|
56
|
+
it 'register report under default' do
|
|
57
|
+
expect(subject.build(:default).as_json).to eq(json_expected)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'builds the report using the given configuration' do
|
|
62
|
+
expect(status.as_json).to eq(json_expected)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context 'when passing a custom threshold parameter' do
|
|
66
|
+
let(:parameters) { { threshold: 1 } }
|
|
67
|
+
let(:status_expected) { :ok }
|
|
68
|
+
|
|
69
|
+
it 'uses custom threshold parameter' do
|
|
70
|
+
expect(status.as_json).to eq(json_expected)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context 'when passing a custom period parameter' do
|
|
75
|
+
let(:ids) { [ 10, 20, 21 ] }
|
|
76
|
+
let(:percentage) { 0.5 }
|
|
77
|
+
let(:parameters) { { threshold: 0.4, period: 10.days } }
|
|
78
|
+
|
|
79
|
+
it 'uses custom period parameter' do
|
|
80
|
+
expect(status.as_json).to eq(json_expected)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Bidu::Mercy::Status do
|
|
4
|
+
let(:threshold) { 0.02 }
|
|
5
|
+
let(:period) { 1.day }
|
|
6
|
+
let(:report_options) do
|
|
7
|
+
{
|
|
8
|
+
period: period,
|
|
9
|
+
threshold: threshold,
|
|
10
|
+
scope: :with_error,
|
|
11
|
+
clazz: Document,
|
|
12
|
+
id: :errors
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
let(:success_options) do
|
|
16
|
+
report_options.merge(
|
|
17
|
+
scope: :with_success,
|
|
18
|
+
id: :success
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
let(:errors) { 0 }
|
|
22
|
+
let(:successes) { 1 }
|
|
23
|
+
let(:error_report) { Bidu::Mercy::Report::Error.new(report_options) }
|
|
24
|
+
let(:success_report) do
|
|
25
|
+
Bidu::Mercy::Report::Error.new(success_options)
|
|
26
|
+
end
|
|
27
|
+
let(:reports) { [ error_report ] }
|
|
28
|
+
let(:subject) { described_class.new(reports) }
|
|
29
|
+
before do
|
|
30
|
+
Document.all.each(&:destroy)
|
|
31
|
+
errors.times { Document.create status: :error }
|
|
32
|
+
successes.times { Document.create status: :success }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe '#as_json' do
|
|
36
|
+
let(:status_json) { subject.as_json }
|
|
37
|
+
let(:status) { status_json[:status] }
|
|
38
|
+
|
|
39
|
+
context 'when report is ok' do
|
|
40
|
+
it 'returns a json with ok' do
|
|
41
|
+
expect(status).to eq(:ok)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'returns the report json' do
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'when report is not ok' do
|
|
50
|
+
let(:errors) { 1 }
|
|
51
|
+
|
|
52
|
+
it 'returns a json with error' do
|
|
53
|
+
expect(status).to eq(:error)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'when there are both success and error reports' do
|
|
58
|
+
let(:success_report) do
|
|
59
|
+
Bidu::Mercy::Report::Error.new(report_options.merge(scope: :with_success))
|
|
60
|
+
end
|
|
61
|
+
let(:reports) { [ success_report, error_report ] }
|
|
62
|
+
|
|
63
|
+
it 'returns a json with error' do
|
|
64
|
+
expect(status).to eq(:error)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe '#status' do
|
|
70
|
+
context 'when report is ok' do
|
|
71
|
+
it do
|
|
72
|
+
expect(subject.status).to eq(:ok)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context 'when report is not ok' do
|
|
77
|
+
let(:errors) { 1 }
|
|
78
|
+
|
|
79
|
+
it do
|
|
80
|
+
expect(subject.status).to eq(:error)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context 'when there are both success and error reports' do
|
|
85
|
+
let(:reports) { [ success_report, error_report ] }
|
|
86
|
+
|
|
87
|
+
it do
|
|
88
|
+
expect(subject.status).to eq(:error)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe '#as_json' do
|
|
94
|
+
let(:errors) { 3 }
|
|
95
|
+
let(:ids) { Document.with_error.map(&:id) }
|
|
96
|
+
let(:expected) do
|
|
97
|
+
{
|
|
98
|
+
status: :error,
|
|
99
|
+
errors: {
|
|
100
|
+
ids: ids,
|
|
101
|
+
percentage: 0.75,
|
|
102
|
+
status: :error
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'creates a summary of the reports' do
|
|
108
|
+
expect(subject.as_json).to eq(expected)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
context 'when there are both success and error reports' do
|
|
112
|
+
let(:success_ids) { Document.with_success.map(&:id) }
|
|
113
|
+
let(:expected) do
|
|
114
|
+
{
|
|
115
|
+
status: :error,
|
|
116
|
+
errors: {
|
|
117
|
+
ids: ids,
|
|
118
|
+
percentage: 0.75,
|
|
119
|
+
status: :error
|
|
120
|
+
},
|
|
121
|
+
success: {
|
|
122
|
+
ids: success_ids,
|
|
123
|
+
percentage: 0.25,
|
|
124
|
+
status: :error
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
end
|
|
128
|
+
let(:reports) { [ success_report, error_report ] }
|
|
129
|
+
|
|
130
|
+
it 'creates a summary of all the reports' do
|
|
131
|
+
expect(subject.as_json).to eq(expected)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Bidu::PeriodParser do
|
|
4
|
+
shared_examples 'a class who knows how to parse time' do |tests|
|
|
5
|
+
tests.each do |string, expected|
|
|
6
|
+
it "parses #{string} into #{expected} seconds" do
|
|
7
|
+
expect(described_class.parse(string)).to eq(expected)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it_behaves_like 'a class who knows how to parse time', {
|
|
13
|
+
'3' => 3.seconds,
|
|
14
|
+
'3seconds' => 3.seconds,
|
|
15
|
+
'3minutes' => 3.minutes,
|
|
16
|
+
'3hours' => 3.hours,
|
|
17
|
+
'3days' => 3.days,
|
|
18
|
+
'3months' => 3.months,
|
|
19
|
+
'3years' => 3.years
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
context 'when value is already a period' do
|
|
23
|
+
it 'returns the value itself' do
|
|
24
|
+
expect(described_class.parse(3.minutes)).to eq(3.minutes)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'simplecov'
|
|
2
|
+
SimpleCov.profiles.define 'gem' do
|
|
3
|
+
add_filter '/spec/'
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
if ENV['CODECLIMATE_REPO_TOKEN']
|
|
7
|
+
require "codeclimate-test-reporter"
|
|
8
|
+
CodeClimate::TestReporter.start
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
SimpleCov.start 'gem'
|
|
12
|
+
|
|
13
|
+
require 'pry-nav'
|
|
14
|
+
require 'bidu/mercy'
|
|
15
|
+
|
|
16
|
+
require 'active_record'
|
|
17
|
+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
|
|
18
|
+
|
|
19
|
+
support_files = File.expand_path("spec/support/**/*.rb")
|
|
20
|
+
Dir[support_files].each { |file| require file }
|
|
21
|
+
|
|
22
|
+
RSpec.configure do |config|
|
|
23
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
24
|
+
config.run_all_when_everything_filtered = true
|
|
25
|
+
config.filter_run :focus
|
|
26
|
+
config.filter_run_excluding :integration unless ENV['ALL']
|
|
27
|
+
|
|
28
|
+
config.order = 'random'
|
|
29
|
+
|
|
30
|
+
config.before do
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
|
|
3
|
+
module FixtureHelpers
|
|
4
|
+
def load_fixture_file(filename)
|
|
5
|
+
File.read (['./spec/', 'fixtures', filename].join('/'))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def load_json_fixture_file(filename)
|
|
9
|
+
cached_json_fixture_file(filename)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def cached_json_fixture_file(filename)
|
|
15
|
+
ActiveSupport::JSON.decode(load_fixture_file(filename))
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
RSpec.configuration.include FixtureHelpers
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Bidu
|
|
2
|
+
module Mercy
|
|
3
|
+
class Report
|
|
4
|
+
class Dummy < Report
|
|
5
|
+
ALLOWED_PARAMETERS=[:period, :threshold]
|
|
6
|
+
def initialize(options)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class Dummy
|
|
14
|
+
ALLOWED_PARAMETERS=[:period, :threshold]
|
|
15
|
+
def initialize(options)
|
|
16
|
+
end
|
|
17
|
+
end
|