pg_rails 7.0.8.pre.alpha.82 → 7.0.8.pre.alpha.84
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/pg_engine/app/admin/email_logs.rb +37 -0
- data/pg_engine/app/controllers/admin/email_logs_controller.rb +50 -0
- data/pg_engine/app/controllers/pg_engine/base_controller.rb +3 -0
- data/pg_engine/app/controllers/public/webhooks_controller.rb +77 -0
- data/pg_engine/app/decorators/email_log_decorator.rb +16 -0
- data/pg_engine/app/models/email.rb +16 -2
- data/pg_engine/app/models/email_log.rb +59 -0
- data/pg_engine/app/policies/email_log_policy.rb +31 -0
- data/pg_engine/app/views/admin/email_logs/_email_log.html.slim +1 -0
- data/pg_engine/app/views/admin/email_logs/_form.html.slim +16 -0
- data/pg_engine/app/views/admin/email_logs/show.html.slim +18 -0
- data/pg_engine/app/views/admin/emails/show.html.slim +20 -4
- data/pg_engine/app/views/pg_engine/base/index.html.slim +2 -0
- data/pg_engine/config/locales/es.yml +1 -0
- data/pg_engine/config/routes.rb +26 -0
- data/pg_engine/db/migrate/20240523183651_create_email_logs.rb +19 -0
- data/pg_engine/lib/pg_engine/email_observer.rb +4 -2
- data/pg_engine/lib/pg_engine/mailgun/log_sync.rb +36 -35
- data/pg_engine/lib/pg_engine/utils/check_invalid_records.rb +39 -0
- data/pg_engine/lib/pg_engine/utils/pg_logger.rb +20 -2
- data/pg_engine/spec/controllers/admin/email_logs_controller_spec.rb +179 -0
- data/pg_engine/spec/controllers/pg_engine/base_controller_spec.rb +11 -0
- data/pg_engine/spec/controllers/public/webhooks_controller_spec.rb +142 -0
- data/pg_engine/spec/factories/email_logs.rb +20 -0
- data/pg_engine/spec/lib/pg_engine/mailgun/log_sync_spec.rb +81 -7
- data/pg_engine/spec/models/email_log_spec.rb +48 -0
- data/pg_engine/spec/models/email_spec.rb +35 -0
- data/pg_layout/app/views/layouts/pg_layout/base.html.slim +11 -0
- data/pg_rails/lib/pg_rails/rspec_logger_matchers.rb +62 -0
- data/pg_rails/lib/version.rb +1 -1
- metadata +18 -2
@@ -5,7 +5,14 @@ require 'rainbow'
|
|
5
5
|
# TODO: poder pasar blocks
|
6
6
|
|
7
7
|
def pg_err(*args)
|
8
|
-
|
8
|
+
if ENV.fetch('RAISE_ERRORS', false)
|
9
|
+
# :nocov:
|
10
|
+
raise args.first if args.first.is_a?(Exception)
|
11
|
+
|
12
|
+
raise StandardError, args
|
13
|
+
|
14
|
+
# :nocov:
|
15
|
+
end
|
9
16
|
|
10
17
|
byebug if ENV.fetch('BYEBUG_ERRORS', false) # rubocop:disable Lint/Debugger
|
11
18
|
|
@@ -30,6 +37,10 @@ end
|
|
30
37
|
|
31
38
|
module PgEngine
|
32
39
|
class PgLogger
|
40
|
+
def self.test_logged_messages
|
41
|
+
@test_logged_messages ||= []
|
42
|
+
end
|
43
|
+
|
33
44
|
class << self
|
34
45
|
def log(type, *args)
|
35
46
|
notify_all(build_msg(*args), type)
|
@@ -41,6 +52,7 @@ module PgEngine
|
|
41
52
|
send_to_logger(mensaje, type)
|
42
53
|
send_to_rollbar(mensaje, type)
|
43
54
|
send_to_stdout(mensaje, type) if ENV.fetch('LOG_TO_STDOUT', nil)
|
55
|
+
save_internal(mensaje, type) if Rails.env.test?
|
44
56
|
nil
|
45
57
|
end
|
46
58
|
|
@@ -61,6 +73,10 @@ module PgEngine
|
|
61
73
|
Rails.logger.send(type, rainbow_wrap(mensaje, type))
|
62
74
|
end
|
63
75
|
|
76
|
+
def save_internal(mensaje, type)
|
77
|
+
PgEngine::PgLogger.test_logged_messages << [type, mensaje]
|
78
|
+
end
|
79
|
+
|
64
80
|
# Format
|
65
81
|
|
66
82
|
# TODO: loguear time
|
@@ -110,7 +126,9 @@ module PgEngine
|
|
110
126
|
|
111
127
|
def cleaner
|
112
128
|
bc = ActiveSupport::BacktraceCleaner.new
|
113
|
-
bc.
|
129
|
+
bc.remove_silencers!
|
130
|
+
pattern = %r{\A[^/]+ \([\w.]+\) }
|
131
|
+
bc.add_silencer { |line| pattern.match?(line) && !line.match?(/pg_contable|pg_rails/) }
|
114
132
|
bc.add_silencer { |line| /pg_logger/.match?(line) }
|
115
133
|
bc
|
116
134
|
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# generado con pg_rails
|
4
|
+
|
5
|
+
require 'rails_helper'
|
6
|
+
|
7
|
+
# This spec was generated by rspec-rails when you ran the scaffold generator.
|
8
|
+
# It demonstrates how one might use RSpec to specify the controller code that
|
9
|
+
# was generated by Rails when you ran the scaffold generator.
|
10
|
+
#
|
11
|
+
# It assumes that the implementation code is generated by the rails scaffold
|
12
|
+
# generator. If you are using any extension libraries to generate different
|
13
|
+
# controller code, this generated spec may or may not pass.
|
14
|
+
#
|
15
|
+
# It only uses APIs available in rails and/or rspec-rails. There are a number
|
16
|
+
# of tools you can use to make these specs even more expressive, but we're
|
17
|
+
# sticking to rails and rspec-rails APIs to keep things simple and stable.
|
18
|
+
#
|
19
|
+
# Compared to earlier versions of this generator, there is very limited use of
|
20
|
+
# stubs and message expectations in this spec. Stubs are only used when there
|
21
|
+
# is no simpler way to get a handle on the object needed for the example.
|
22
|
+
# Message expectations are only used when there is no simpler way to specify
|
23
|
+
# that an instance is receiving a specific message.
|
24
|
+
#
|
25
|
+
# Also compared to earlier versions of this generator, there are no longer any
|
26
|
+
# expectations of assigns and templates rendered. These features have been
|
27
|
+
# removed from Rails core in Rails 5, but can be added back in via the
|
28
|
+
# `rails-controller-testing` gem.
|
29
|
+
|
30
|
+
RSpec.describe Admin::EmailLogsController do
|
31
|
+
render_views
|
32
|
+
# This should return the minimal set of attributes required to create a valid
|
33
|
+
# EmailLog. As you add validations to EmailLog, be sure to
|
34
|
+
# adjust the attributes here as well.
|
35
|
+
let(:valid_attributes) do
|
36
|
+
attributes_for(:email_log)
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:logged_user) { create :user, :developer }
|
40
|
+
|
41
|
+
before do
|
42
|
+
sign_in logged_user if logged_user.present?
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#mailgun_sync' do
|
46
|
+
subject do
|
47
|
+
post :mailgun_sync
|
48
|
+
end
|
49
|
+
|
50
|
+
before do
|
51
|
+
allow(PgEngine::Mailgun::LogSync).to receive(:download).and_return([])
|
52
|
+
end
|
53
|
+
|
54
|
+
it do
|
55
|
+
subject
|
56
|
+
expect(response).to have_http_status(:redirect)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'routing' do
|
61
|
+
it 'routes GET index correctly' do
|
62
|
+
route = { get: '/a/email_logs' }
|
63
|
+
expect(route).to route_to(controller: 'admin/email_logs', action: 'index')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'GET #index' do
|
68
|
+
subject do
|
69
|
+
get :index, params: {}
|
70
|
+
end
|
71
|
+
|
72
|
+
before { create :email_log }
|
73
|
+
|
74
|
+
it 'returns a success response' do
|
75
|
+
subject
|
76
|
+
expect(response).to be_successful
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when user is not logged in' do
|
80
|
+
let(:logged_user) { nil }
|
81
|
+
|
82
|
+
it 'redirects to login path' do
|
83
|
+
subject
|
84
|
+
expect(response).to redirect_to(new_user_session_path)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when se pide el excel' do
|
89
|
+
subject do
|
90
|
+
get :index, params: {}, format: 'xlsx'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns a success response' do
|
94
|
+
subject
|
95
|
+
expect(response).to be_successful
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'GET #show' do
|
101
|
+
it 'returns a success response' do
|
102
|
+
email_log = create(:email_log)
|
103
|
+
get :show, params: { id: email_log.to_param }
|
104
|
+
expect(response).to be_successful
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe 'GET #new' do
|
109
|
+
it 'returns a success response' do
|
110
|
+
get :new, params: {}
|
111
|
+
expect(response).to be_successful
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe 'GET #edit' do
|
116
|
+
it 'returns a success response' do
|
117
|
+
email_log = create(:email_log)
|
118
|
+
get :edit, params: { id: email_log.to_param }
|
119
|
+
expect(response).to be_successful
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'POST #create' do
|
124
|
+
context 'with valid params' do
|
125
|
+
it 'creates a new EmailLog' do
|
126
|
+
expect do
|
127
|
+
post :create, params: { email_log: valid_attributes }
|
128
|
+
end.to change(EmailLog, :count).by(1)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'redirects to the created email_log' do
|
132
|
+
post :create, params: { email_log: valid_attributes }
|
133
|
+
expect(response).to redirect_to([:admin, EmailLog.last])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe 'PUT #update' do
|
139
|
+
context 'with valid params' do
|
140
|
+
let(:new_attributes) do
|
141
|
+
attributes_for(:email_log)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'redirects to the email_log' do
|
145
|
+
email_log = create(:email_log)
|
146
|
+
put :update, params: { id: email_log.to_param, email_log: valid_attributes }
|
147
|
+
expect(response).to redirect_to([:admin, email_log])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe 'DELETE #destroy' do
|
153
|
+
subject do
|
154
|
+
request.headers['Accept'] = 'text/vnd.turbo-stream.html,text/html'
|
155
|
+
delete :destroy, params: { id: email_log.to_param, redirect_to: redirect_url }
|
156
|
+
end
|
157
|
+
|
158
|
+
let!(:email_log) { create :email_log }
|
159
|
+
let(:redirect_url) { nil }
|
160
|
+
|
161
|
+
it 'destroys the requested email_log' do
|
162
|
+
expect { subject }.to change(EmailLog, :count).by(-1)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'quita el elemento de la lista' do
|
166
|
+
subject
|
167
|
+
expect(response.body).to include('turbo-stream action="remove"')
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'si hay redirect_to' do
|
171
|
+
let(:redirect_url) { admin_email_logs_url }
|
172
|
+
|
173
|
+
it 'redirects to the email_logs list' do
|
174
|
+
subject
|
175
|
+
expect(response).to redirect_to(admin_email_logs_url)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -60,6 +60,17 @@ describe DummyBaseController do
|
|
60
60
|
expect(response.body).to include '<turbo-stream action="remove" targets=".modal">'
|
61
61
|
end
|
62
62
|
end
|
63
|
+
|
64
|
+
context 'cuando acepta json' do
|
65
|
+
before do
|
66
|
+
request.headers['Accept'] = 'application/json'
|
67
|
+
end
|
68
|
+
|
69
|
+
fit do
|
70
|
+
subject
|
71
|
+
expect(response).to have_http_status(:internal_server_error)
|
72
|
+
end
|
73
|
+
end
|
63
74
|
end
|
64
75
|
|
65
76
|
describe 'not_authorized' do
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec::Matchers.define_negated_matcher :not_change, :change
|
4
|
+
|
5
|
+
def build_body(log_id, signature, timestamp)
|
6
|
+
<<~JSON
|
7
|
+
{
|
8
|
+
"signature": {
|
9
|
+
"timestamp": "#{timestamp}",
|
10
|
+
"token": "6fcc81a280a2458de8c83bf22dde8c71485be1d51333d3427e",
|
11
|
+
"signature": "#{signature}"
|
12
|
+
},
|
13
|
+
"event-data": {
|
14
|
+
"timestamp": 1715014542.2477064,
|
15
|
+
"ip": "66.102.8.333",
|
16
|
+
"event": "delivered",
|
17
|
+
"id": "#{log_id}",
|
18
|
+
"severity":"temporary",
|
19
|
+
"log-level": "info",
|
20
|
+
"message": {
|
21
|
+
"headers": { "message-id": "msgid@fakeapp2024.mail" }
|
22
|
+
},
|
23
|
+
"recipient": "natprobel@fakemail.com"
|
24
|
+
}
|
25
|
+
}
|
26
|
+
JSON
|
27
|
+
end
|
28
|
+
|
29
|
+
fdescribe Public::WebhooksController do
|
30
|
+
include ActiveSupport::Testing::TimeHelpers
|
31
|
+
|
32
|
+
before { travel_to Time.zone.at(1_716_564_587) }
|
33
|
+
|
34
|
+
describe '#mailgun' do
|
35
|
+
subject do
|
36
|
+
post :mailgun, body:, as: :json
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:signature) { 'c524037907046276117758afae8a340e77a43a6e48eb35a9521426e7a3ff675b' }
|
40
|
+
let(:log_id) { 'log_2' }
|
41
|
+
let(:timestamp) { '1716564587' }
|
42
|
+
|
43
|
+
let(:body) do
|
44
|
+
build_body(log_id, signature, timestamp)
|
45
|
+
end
|
46
|
+
|
47
|
+
it do
|
48
|
+
subject
|
49
|
+
expect(response).to have_http_status(:ok)
|
50
|
+
end
|
51
|
+
|
52
|
+
it do
|
53
|
+
expect { subject }.to change(EmailLog, :count).by(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'cuando tira internal server error' do
|
57
|
+
let(:body) { '{ "este json": "no me sirve" }' }
|
58
|
+
|
59
|
+
it do
|
60
|
+
subject
|
61
|
+
expect(response).to have_http_status(:internal_server_error)
|
62
|
+
end
|
63
|
+
|
64
|
+
fit do
|
65
|
+
expect { subject }.to have_errored('internal server error')
|
66
|
+
.and(have_errored('no me sirve'))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'cuando no es un json' do
|
71
|
+
let(:body) { 'mal json' }
|
72
|
+
|
73
|
+
it do
|
74
|
+
subject
|
75
|
+
expect(response).to have_http_status(:bad_request)
|
76
|
+
end
|
77
|
+
|
78
|
+
fit do
|
79
|
+
expect { subject }.to have_warned('parser error').and(have_warned('mal json'))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'cuando ya existe un log con ese ID' do
|
84
|
+
before do
|
85
|
+
create(:email_log, log_id:)
|
86
|
+
end
|
87
|
+
|
88
|
+
it do
|
89
|
+
expect { subject }.to have_warned('ya existía un log con ese id')
|
90
|
+
.and(not_change(EmailLog, :count))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
shared_context 'todo bien pero no guarda el log' do
|
95
|
+
it 'responds ok' do
|
96
|
+
subject
|
97
|
+
expect(response).to have_http_status(:ok)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'no guarda el log ;)' do
|
101
|
+
expect { subject }.not_to change(EmailLog, :count)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'si la signature no es válida' do
|
106
|
+
let(:signature) { 'no válida' }
|
107
|
+
|
108
|
+
it_behaves_like 'todo bien pero no guarda el log'
|
109
|
+
|
110
|
+
fit do
|
111
|
+
expect { subject }.to have_warned('refusing invalid signature')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'cuando ya se usó el token' do
|
116
|
+
subject do
|
117
|
+
post :mailgun, body: build_body('otro id', signature, timestamp), as: :json
|
118
|
+
end
|
119
|
+
|
120
|
+
before do
|
121
|
+
post :mailgun, body: build_body(log_id, signature, timestamp), as: :json
|
122
|
+
end
|
123
|
+
|
124
|
+
it_behaves_like 'todo bien pero no guarda el log'
|
125
|
+
|
126
|
+
fit do
|
127
|
+
expect { subject }.to have_warned('refusing used token')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'cuando la timestamp está muy lejos' do
|
132
|
+
let(:timestamp) { '1111111' }
|
133
|
+
let(:signature) { '869c06cea4be27321a6a7c6a8e3d0668bb9c2b5b3de5532f644dba181a157d9a' }
|
134
|
+
|
135
|
+
it_behaves_like 'todo bien pero no guarda el log'
|
136
|
+
|
137
|
+
fit do
|
138
|
+
expect { subject }.to have_warned('refusing due to timestamp')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# generado con pg_rails
|
4
|
+
|
5
|
+
FactoryBot.define do
|
6
|
+
factory :email_log do
|
7
|
+
email
|
8
|
+
log_id { Faker::Lorem.sentence }
|
9
|
+
event { %w[accepted delivered failed opened].sample }
|
10
|
+
log_level { %w[info warn error].sample }
|
11
|
+
severity { %w[permanent temporary].sample }
|
12
|
+
timestamp { '' }
|
13
|
+
message_id { Faker::Lorem.sentence }
|
14
|
+
|
15
|
+
trait :email_existente do
|
16
|
+
email { nil }
|
17
|
+
email_id { Email.pluck(:id).sample }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,25 +1,99 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
|
-
describe PgEngine::Mailgun::LogSync
|
4
|
+
describe PgEngine::Mailgun::LogSync, vcr: { cassette_name: 'mailgun/log_sync_download',
|
5
|
+
match_requests_on: %i[method host] } do
|
5
6
|
let(:instancia) { described_class }
|
6
7
|
|
7
|
-
describe '#download'
|
8
|
-
vcr: { cassette_name: 'mailgun/log_sync_download',
|
9
|
-
match_requests_on: %i[method host] } do
|
8
|
+
describe '#download' do
|
10
9
|
subject do
|
11
10
|
instancia.download
|
12
|
-
instancia.sync_redis
|
13
11
|
end
|
14
12
|
|
15
13
|
after do
|
16
|
-
|
14
|
+
FileUtils.rm_r(instancia.log_dir)
|
17
15
|
end
|
18
16
|
|
19
17
|
let!(:email) { create :email, message_id: '66393f1bc7d4_47a5108ec1628f@notebook.mail' }
|
20
18
|
|
21
19
|
it do
|
22
|
-
expect { subject }.to change { email.
|
20
|
+
expect { subject }.to change { email.email_logs.count }.from(0).to(3)
|
21
|
+
.and(change(EmailLog, :count).to(8))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#digest' do
|
26
|
+
subject do
|
27
|
+
instancia.digest(JSON.parse(log_data))
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:log_data) do
|
31
|
+
<<~JSON
|
32
|
+
{
|
33
|
+
"timestamp": 1715014542.2477064,
|
34
|
+
"ip": "66.102.8.333",
|
35
|
+
"event": "delivered",
|
36
|
+
"id": "log_2",
|
37
|
+
"severity":"temporary",
|
38
|
+
"log-level": "info",
|
39
|
+
"message": {
|
40
|
+
"headers": { "message-id": "msgid@fakeapp2024.mail" }
|
41
|
+
},
|
42
|
+
"recipient": "natprobel@fakemail.com"
|
43
|
+
}
|
44
|
+
JSON
|
45
|
+
end
|
46
|
+
|
47
|
+
let(:expected_attributes) do
|
48
|
+
{
|
49
|
+
log_id: 'log_2',
|
50
|
+
event: 'delivered',
|
51
|
+
log_level: 'info',
|
52
|
+
severity: 'temporary',
|
53
|
+
timestamp: 1_715_014_542,
|
54
|
+
message_id: 'msgid@fakeapp2024.mail'
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
it do
|
59
|
+
expect { subject }.to change(EmailLog, :count).by(1)
|
60
|
+
end
|
61
|
+
|
62
|
+
it do
|
63
|
+
expect(subject).to have_attributes(expected_attributes)
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'ya existe el log' do
|
67
|
+
subject do
|
68
|
+
instancia.digest(JSON.parse(log_data))
|
69
|
+
instancia.digest(JSON.parse(log_data))
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'solo lo crea una vez' do
|
73
|
+
expect { subject }.to change(EmailLog, :count).by(1)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'cuando se asocia a un email' do
|
78
|
+
let!(:email) { create :email, message_id: 'msgid@fakeapp2024.mail' }
|
79
|
+
|
80
|
+
it do
|
81
|
+
expect(subject.email).to eq email
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'changes email status' do
|
85
|
+
expect { subject }.to change { email.reload.status }.to 'delivered'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'cuando hay errores' do
|
90
|
+
subject do
|
91
|
+
instancia.digest({})
|
92
|
+
end
|
93
|
+
|
94
|
+
it do
|
95
|
+
expect { subject }.to raise_error(NoMethodError)
|
96
|
+
end
|
23
97
|
end
|
24
98
|
end
|
25
99
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# generado con pg_rails
|
4
|
+
|
5
|
+
require 'rails_helper'
|
6
|
+
|
7
|
+
RSpec.describe EmailLog do
|
8
|
+
let(:email_log) { create(:email_log) }
|
9
|
+
|
10
|
+
it 'se persiste' do
|
11
|
+
expect(email_log).to be_persisted
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'status_for_email' do
|
15
|
+
subject do
|
16
|
+
email_log.status_for_email
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:email_log) { create(:email_log, event:, severity:) }
|
20
|
+
let(:severity) { nil }
|
21
|
+
|
22
|
+
context 'cuando es accepted' do
|
23
|
+
let(:event) { 'accepted' }
|
24
|
+
|
25
|
+
it { is_expected.to eq 'accepted' }
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'cuando es delivered' do
|
29
|
+
let(:event) { 'delivered' }
|
30
|
+
|
31
|
+
it { is_expected.to eq 'delivered' }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'cuando hay un fallo temporario' do
|
35
|
+
let(:event) { 'failed' }
|
36
|
+
let(:severity) { 'temporary' }
|
37
|
+
|
38
|
+
it { is_expected.to eq 'accepted' }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'cuando hay un fallo permanente' do
|
42
|
+
let(:event) { 'failed' }
|
43
|
+
let(:severity) { 'permanent' }
|
44
|
+
|
45
|
+
it { is_expected.to eq 'rejected' }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -10,4 +10,39 @@ RSpec.describe Email do
|
|
10
10
|
it 'se persiste' do
|
11
11
|
expect(email).to be_persisted
|
12
12
|
end
|
13
|
+
|
14
|
+
describe 'update_status!' do
|
15
|
+
context 'cuando hay accepted y delivered' do
|
16
|
+
subject do
|
17
|
+
create :email_log, email: email.reload, event: 'accepted'
|
18
|
+
create :email_log, email: email.reload, event: 'delivered'
|
19
|
+
end
|
20
|
+
|
21
|
+
it do
|
22
|
+
expect { subject }.to change { email.reload.status }.to 'delivered'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'cuando hay accepted y fallo temporario' do
|
27
|
+
subject do
|
28
|
+
create :email_log, email: email.reload, event: 'failed', severity: 'temporary'
|
29
|
+
create :email_log, email: email.reload, event: 'accepted'
|
30
|
+
end
|
31
|
+
|
32
|
+
it do
|
33
|
+
expect { subject }.to change { email.reload.status }.to 'accepted'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'cuando hay accepted y fallo permanente' do
|
38
|
+
subject do
|
39
|
+
create :email_log, email: email.reload, event: 'accepted'
|
40
|
+
create :email_log, email: email.reload, event: 'failed', severity: 'permanent'
|
41
|
+
end
|
42
|
+
|
43
|
+
it do
|
44
|
+
expect { subject }.to change { email.reload.status }.to 'rejected'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
13
48
|
end
|
@@ -33,6 +33,17 @@ html
|
|
33
33
|
- if @rollbar_token.present?
|
34
34
|
meta name="rollbar-token" content="#{@rollbar_token}"
|
35
35
|
meta name="rollbar-env" content="#{Rails.env}"
|
36
|
+
|
37
|
+
link rel="preconnect" href="https://fonts.googleapis.com"
|
38
|
+
link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="crossorigin"
|
39
|
+
link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap" rel="stylesheet"
|
40
|
+
css:
|
41
|
+
body {
|
42
|
+
font-family: "Ubuntu", sans-serif;
|
43
|
+
font-weight: 400;
|
44
|
+
font-style: normal;
|
45
|
+
}
|
46
|
+
|
36
47
|
body
|
37
48
|
= render partial: 'pg_layout/sidebar_mobile'
|
38
49
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# :nocov:
|
2
|
+
module PgEngine
|
3
|
+
module Matchers
|
4
|
+
module PgLogger
|
5
|
+
class Base < RSpec::Rails::Matchers::BaseMatcher
|
6
|
+
def initialize(text, level)
|
7
|
+
super()
|
8
|
+
@text = text
|
9
|
+
@level = level
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class PgHaveLogged < Base
|
14
|
+
def matches?(proc)
|
15
|
+
msg = 'have_logged only support block expectations'
|
16
|
+
raise ArgumentError, msg unless proc.is_a?(Proc)
|
17
|
+
|
18
|
+
original_messages = Set.new(PgEngine::PgLogger.test_logged_messages)
|
19
|
+
proc.call
|
20
|
+
logged_messages = Set.new(PgEngine::PgLogger.test_logged_messages)
|
21
|
+
|
22
|
+
@new_messages = logged_messages - original_messages
|
23
|
+
@new_messages.any? do |level, message|
|
24
|
+
if @text.present? && @level.present?
|
25
|
+
level == @level && message.include?(@text)
|
26
|
+
elsif @text.present?
|
27
|
+
message.include? @text
|
28
|
+
elsif @level.present?
|
29
|
+
level == @level
|
30
|
+
else
|
31
|
+
true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def failure_message
|
37
|
+
msg = "expected to #{@level || log}"
|
38
|
+
msg << "with text: #{@text}" if @text.present?
|
39
|
+
return unless @new_messages.any?
|
40
|
+
|
41
|
+
msg << "\nLogged messages:"
|
42
|
+
@new_messages.each do |level, message|
|
43
|
+
msg << "\n #{level}: #{message[0..200]}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def supports_block_expectations?
|
48
|
+
true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def have_errored(text = nil) # rubocop:disable Naming/PredicateName
|
54
|
+
PgLogger::PgHaveLogged.new(text, :error)
|
55
|
+
end
|
56
|
+
|
57
|
+
def have_warned(text = nil) # rubocop:disable Naming/PredicateName
|
58
|
+
PgLogger::PgHaveLogged.new(text, :warn)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
# :nocov:
|
data/pg_rails/lib/version.rb
CHANGED