bidu-mercy 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +88 -0
  6. data/LICENSE +22 -0
  7. data/README.md +100 -0
  8. data/Rakefile +7 -0
  9. data/circle.yml +16 -0
  10. data/lib/bidu.rb +3 -0
  11. data/lib/bidu/mercy.rb +18 -0
  12. data/lib/bidu/mercy/class_methods.rb +19 -0
  13. data/lib/bidu/mercy/concern.rb +10 -0
  14. data/lib/bidu/mercy/report.rb +44 -0
  15. data/lib/bidu/mercy/report/active_record.rb +28 -0
  16. data/lib/bidu/mercy/report/error.rb +62 -0
  17. data/lib/bidu/mercy/report/multiple.rb +29 -0
  18. data/lib/bidu/mercy/report/range.rb +54 -0
  19. data/lib/bidu/mercy/report_builder.rb +24 -0
  20. data/lib/bidu/mercy/report_config.rb +37 -0
  21. data/lib/bidu/mercy/status.rb +27 -0
  22. data/lib/bidu/mercy/status_builder.rb +35 -0
  23. data/lib/bidu/mercy/version.rb +5 -0
  24. data/lib/bidu/period_parser.rb +32 -0
  25. data/lib/json_parser/type_cast_ext.rb +7 -0
  26. data/mercy.gemspec +33 -0
  27. data/spec/lib/bidu/mercy/report/error_spec.rb +385 -0
  28. data/spec/lib/bidu/mercy/report/multiple_spec.rb +122 -0
  29. data/spec/lib/bidu/mercy/report/range_spec.rb +302 -0
  30. data/spec/lib/bidu/mercy/report/report_config_spec.rb +39 -0
  31. data/spec/lib/bidu/mercy/report_builder_spec.rb +72 -0
  32. data/spec/lib/bidu/mercy/report_spec.rb +44 -0
  33. data/spec/lib/bidu/mercy/status_builder_spec.rb +84 -0
  34. data/spec/lib/bidu/mercy/status_spec.rb +135 -0
  35. data/spec/lib/bidu/period_parser_spec.rb +27 -0
  36. data/spec/spec_helper.rb +32 -0
  37. data/spec/support/fixture_helpers.rb +19 -0
  38. data/spec/support/models/document.rb +6 -0
  39. data/spec/support/report/dummy.rb +17 -0
  40. data/spec/support/schema.rb +11 -0
  41. 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
@@ -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,6 @@
1
+ class Document < ActiveRecord::Base
2
+ scope :with_error, proc { where(status: :error) }
3
+ scope :with_success, proc { where(status: :success) }
4
+ scope :type_a, proc { where(doc_type: :a) }
5
+ scope :type_b, proc { where(doc_type: :b) }
6
+ end
@@ -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