liveqa 1.8.3 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -2
- data/.travis.yml +0 -1
- data/LICENCE +21 -0
- data/README.md +10 -117
- data/lib/liveqa/api_resource.rb +7 -3
- data/lib/liveqa/batch.rb +18 -0
- data/lib/liveqa/config.rb +13 -21
- data/lib/liveqa/event.rb +1 -1
- data/lib/liveqa/formated_logger.rb +45 -0
- data/lib/liveqa/message.rb +3 -3
- data/lib/liveqa/plugins/rack/middleware.rb +3 -3
- data/lib/liveqa/plugins/sidekiq/server_middleware.rb +1 -1
- data/lib/liveqa/processor/async.rb +48 -0
- data/lib/liveqa/processor/batch.rb +81 -0
- data/lib/liveqa/processor/worker.rb +66 -0
- data/lib/liveqa/util.rb +3 -3
- data/lib/liveqa/version.rb +1 -1
- data/lib/liveqa.rb +66 -33
- data/liveqa.gemspec +3 -3
- data/spec/lib/liveqa/api_resource_spec.rb +8 -8
- data/spec/lib/liveqa/batch_spec.rb +14 -0
- data/spec/lib/liveqa/config_spec.rb +9 -15
- data/spec/lib/liveqa/formated_logger_spec.rb +99 -0
- data/spec/lib/liveqa/processor/async_spec.rb +19 -0
- data/spec/lib/liveqa/processor/batch_spec.rb +48 -0
- data/spec/lib/liveqa/processor/worker_spec.rb +25 -0
- data/spec/lib/liveqa_spec.rb +133 -40
- metadata +26 -16
- data/lib/liveqa/async_handlers/base.rb +0 -15
- data/lib/liveqa/async_handlers/sidekiq.rb +0 -33
- data/spec/lib/liveqa/async_handlers/base_spec.rb +0 -29
- data/spec/lib/liveqa/async_handlers/sidekiq_spec.rb +0 -40
data/lib/liveqa.rb
CHANGED
@@ -5,12 +5,11 @@ require 'ostruct'
|
|
5
5
|
require 'json'
|
6
6
|
require 'time'
|
7
7
|
require 'cgi'
|
8
|
-
|
9
|
-
# Async
|
10
|
-
require 'liveqa/async_handlers/base'
|
8
|
+
require 'logger'
|
11
9
|
|
12
10
|
# Base
|
13
11
|
require 'liveqa/version'
|
12
|
+
require 'liveqa/formated_logger'
|
14
13
|
require 'liveqa/library_name'
|
15
14
|
require 'liveqa/util'
|
16
15
|
require 'liveqa/config'
|
@@ -21,6 +20,11 @@ require 'liveqa/api_resource'
|
|
21
20
|
require 'liveqa/store'
|
22
21
|
require 'liveqa/message'
|
23
22
|
|
23
|
+
# Processor
|
24
|
+
require 'liveqa/processor/async'
|
25
|
+
require 'liveqa/processor/worker'
|
26
|
+
require 'liveqa/processor/batch'
|
27
|
+
|
24
28
|
# Operations
|
25
29
|
require 'liveqa/api_operation/save'
|
26
30
|
require 'liveqa/api_operation/delete'
|
@@ -30,6 +34,7 @@ require 'liveqa/event'
|
|
30
34
|
require 'liveqa/group'
|
31
35
|
require 'liveqa/identity'
|
32
36
|
require 'liveqa/watcher'
|
37
|
+
require 'liveqa/batch'
|
33
38
|
|
34
39
|
# Plugins
|
35
40
|
require 'liveqa/plugins'
|
@@ -39,6 +44,11 @@ require 'liveqa/plugins'
|
|
39
44
|
module LiveQA
|
40
45
|
class << self
|
41
46
|
|
47
|
+
EVENTS_CREATE_ACTION = 'events:create'.freeze
|
48
|
+
GROUPS_UPDATE_ACTION = 'groups:update'.freeze
|
49
|
+
IDENTITIES_UPDATE_ACTION = 'identities:update'.freeze
|
50
|
+
WATCHERS_CREATE_ACTION = 'watchers:create'.freeze
|
51
|
+
|
42
52
|
##
|
43
53
|
# @return [LiveQA::Config] configurations
|
44
54
|
attr_reader :configurations
|
@@ -65,8 +75,8 @@ module LiveQA
|
|
65
75
|
# @param [Hash] payload to be send
|
66
76
|
# @param [Hash] options for the request
|
67
77
|
#
|
68
|
-
# @return [
|
69
|
-
def track(name, payload = {},
|
78
|
+
# @return [Boolean] status of the request
|
79
|
+
def track(name, payload = {}, options = {})
|
70
80
|
return true unless configurations.enabled
|
71
81
|
|
72
82
|
payload[:type] = 'track'
|
@@ -75,12 +85,15 @@ module LiveQA
|
|
75
85
|
|
76
86
|
payload = Message.extended.merge(payload)
|
77
87
|
|
78
|
-
if configurations.
|
79
|
-
return
|
88
|
+
if configurations.async
|
89
|
+
return processor.enqueue(
|
90
|
+
action: EVENTS_CREATE_ACTION,
|
91
|
+
payload: payload,
|
92
|
+
options: options.select { |k, _v| %i[space_name environment_name].include?(k) },
|
93
|
+
)
|
80
94
|
end
|
81
95
|
|
82
|
-
event = Event.create(payload,
|
83
|
-
|
96
|
+
event = Event.create(payload, options)
|
84
97
|
event.successful?
|
85
98
|
end
|
86
99
|
|
@@ -91,8 +104,8 @@ module LiveQA
|
|
91
104
|
# @param [Hash] payload to be send
|
92
105
|
# @param [Hash] options for the request
|
93
106
|
#
|
94
|
-
# @return [
|
95
|
-
def identify(user_id, payload = {},
|
107
|
+
# @return [Boolean] status of the request
|
108
|
+
def identify(user_id, payload = {}, options = {})
|
96
109
|
return true unless configurations.enabled
|
97
110
|
|
98
111
|
payload[:type] = 'identify'
|
@@ -101,12 +114,15 @@ module LiveQA
|
|
101
114
|
|
102
115
|
payload = Message.extended.merge(payload)
|
103
116
|
|
104
|
-
if configurations.
|
105
|
-
return
|
117
|
+
if configurations.async
|
118
|
+
return processor.enqueue(
|
119
|
+
action: EVENTS_CREATE_ACTION,
|
120
|
+
payload: payload,
|
121
|
+
options: options.select { |k, _v| %i[space_name environment_name].include?(k) },
|
122
|
+
)
|
106
123
|
end
|
107
124
|
|
108
|
-
event = Event.create(payload,
|
109
|
-
|
125
|
+
event = Event.create(payload, options)
|
110
126
|
event.successful?
|
111
127
|
end
|
112
128
|
|
@@ -117,18 +133,22 @@ module LiveQA
|
|
117
133
|
# @param [Hash] payload to be send
|
118
134
|
# @param [Hash] options for the request
|
119
135
|
#
|
120
|
-
# @return [
|
121
|
-
def set_group(group_id, payload = {},
|
136
|
+
# @return [Boolean] status of the request
|
137
|
+
def set_group(group_id, payload = {}, options = {})
|
122
138
|
return true unless configurations.enabled
|
123
139
|
|
124
140
|
payload = Message.base.merge(payload)
|
125
141
|
|
126
|
-
if configurations.
|
127
|
-
return
|
142
|
+
if configurations.async
|
143
|
+
return processor.enqueue(
|
144
|
+
action: GROUPS_UPDATE_ACTION,
|
145
|
+
id: group_id,
|
146
|
+
payload: payload,
|
147
|
+
options: options.select { |k, _v| %i[space_name environment_name].include?(k) },
|
148
|
+
)
|
128
149
|
end
|
129
150
|
|
130
|
-
group = Group.update(group_id, payload,
|
131
|
-
|
151
|
+
group = Group.update(group_id, payload, options)
|
132
152
|
group.successful?
|
133
153
|
end
|
134
154
|
|
@@ -139,18 +159,22 @@ module LiveQA
|
|
139
159
|
# @param [Hash] payload to be send
|
140
160
|
# @param [Hash] options for the request
|
141
161
|
#
|
142
|
-
# @return [
|
143
|
-
def set_identity(user_id, payload = {},
|
162
|
+
# @return [Boolean] status of the request
|
163
|
+
def set_identity(user_id, payload = {}, options = {})
|
144
164
|
return true unless configurations.enabled
|
145
165
|
|
146
166
|
payload = Message.base.merge(payload)
|
147
167
|
|
148
|
-
if configurations.
|
149
|
-
return
|
168
|
+
if configurations.async
|
169
|
+
return processor.enqueue(
|
170
|
+
action: IDENTITIES_UPDATE_ACTION,
|
171
|
+
id: user_id,
|
172
|
+
payload: payload,
|
173
|
+
options: options.select { |k, _v| %i[space_name environment_name].include?(k) },
|
174
|
+
)
|
150
175
|
end
|
151
176
|
|
152
|
-
identity = Identity.update(user_id, payload,
|
153
|
-
|
177
|
+
identity = Identity.update(user_id, payload, options)
|
154
178
|
identity.successful?
|
155
179
|
end
|
156
180
|
|
@@ -161,8 +185,8 @@ module LiveQA
|
|
161
185
|
# @param [Hash] payload to be send
|
162
186
|
# @param [Hash] options for the request
|
163
187
|
#
|
164
|
-
# @return [
|
165
|
-
def watch(id_or_name, payload = {},
|
188
|
+
# @return [Boolean] status of the request
|
189
|
+
def watch(id_or_name, payload = {}, options = {})
|
166
190
|
return true unless configurations.enabled
|
167
191
|
|
168
192
|
payload[:template_flow] = id_or_name
|
@@ -170,14 +194,23 @@ module LiveQA
|
|
170
194
|
|
171
195
|
payload.delete(:session_tracker_id) if payload.delete(:without_session)
|
172
196
|
|
173
|
-
if configurations.
|
174
|
-
return
|
197
|
+
if configurations.async
|
198
|
+
return processor.enqueue(
|
199
|
+
action: WATCHERS_CREATE_ACTION,
|
200
|
+
payload: payload,
|
201
|
+
options: options.select { |k, _v| %i[space_name environment_name].include?(k) },
|
202
|
+
)
|
175
203
|
end
|
176
204
|
|
177
|
-
watcher = Watcher.create(payload,
|
178
|
-
|
205
|
+
watcher = Watcher.create(payload, options)
|
179
206
|
watcher.successful?
|
180
207
|
end
|
181
208
|
|
209
|
+
private
|
210
|
+
|
211
|
+
def processor
|
212
|
+
@processor ||= Processor::Async.new
|
213
|
+
end
|
214
|
+
|
182
215
|
end
|
183
216
|
end
|
data/liveqa.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
lib = File.expand_path('
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
require 'liveqa/version'
|
4
4
|
require 'liveqa/library_name'
|
@@ -19,8 +19,8 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
20
20
|
|
21
21
|
s.add_development_dependency 'faker', '~> 1.8.4'
|
22
|
-
s.add_development_dependency 'rake', '>= 0.9.0'
|
23
22
|
s.add_development_dependency 'pry'
|
23
|
+
s.add_development_dependency 'rake', '>= 0.9.0'
|
24
24
|
s.add_development_dependency 'rspec', '~> 3.5'
|
25
|
-
s.add_development_dependency 'rubocop', '= 0.
|
25
|
+
s.add_development_dependency 'rubocop', '= 0.58.2'
|
26
26
|
end
|
@@ -12,7 +12,7 @@ describe LiveQA::APIResource do
|
|
12
12
|
let(:expected_payload) {{
|
13
13
|
method: :post,
|
14
14
|
url: 'http://localhost:4003/test',
|
15
|
-
payload: '
|
15
|
+
payload: match(''),
|
16
16
|
use_ssl: false,
|
17
17
|
headers: {
|
18
18
|
accept: 'application/json',
|
@@ -20,7 +20,7 @@ describe LiveQA::APIResource do
|
|
20
20
|
x_account_token: 'acc_xx',
|
21
21
|
x_space_name: 'LiveQA',
|
22
22
|
x_environment_name: 'test'
|
23
|
-
}
|
23
|
+
},
|
24
24
|
}}
|
25
25
|
|
26
26
|
after { resource }
|
@@ -32,7 +32,7 @@ describe LiveQA::APIResource do
|
|
32
32
|
let(:expected_payload) {{
|
33
33
|
method: :post,
|
34
34
|
url: 'http://localhost:4003/test',
|
35
|
-
payload: "
|
35
|
+
payload: match("\"test\":true"),
|
36
36
|
use_ssl: false,
|
37
37
|
headers: {
|
38
38
|
accept: 'application/json',
|
@@ -51,8 +51,8 @@ describe LiveQA::APIResource do
|
|
51
51
|
context 'with body and get' do
|
52
52
|
let(:expected_payload) {{
|
53
53
|
method: :get,
|
54
|
-
url:
|
55
|
-
payload: "
|
54
|
+
url: match("http://localhost:4003/test\\?test=true"),
|
55
|
+
payload: match("\"test\":true"),
|
56
56
|
use_ssl: false,
|
57
57
|
headers: {
|
58
58
|
accept: 'application/json',
|
@@ -71,8 +71,8 @@ describe LiveQA::APIResource do
|
|
71
71
|
context 'with overwrite headers tokens' do
|
72
72
|
let(:expected_payload) {{
|
73
73
|
method: :post,
|
74
|
-
url: 'http://localhost:4003/test',
|
75
|
-
payload: '
|
74
|
+
url: match('http://localhost:4003/test'),
|
75
|
+
payload: match(''),
|
76
76
|
use_ssl: false,
|
77
77
|
headers: {
|
78
78
|
accept: 'application/json',
|
@@ -101,7 +101,7 @@ describe LiveQA::APIResource do
|
|
101
101
|
context 'with Net::HTTPBadRequest' do
|
102
102
|
let(:response) { double('response', code: '400', code_type: Net::HTTPBadRequest, body: {}.to_json, message: 'failed') }
|
103
103
|
|
104
|
-
it { expect { resource }.
|
104
|
+
it { expect { resource }.to raise_error(LiveQA::RequestError) }
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LiveQA::Batch do
|
4
|
+
|
5
|
+
describe '.create' do
|
6
|
+
let(:response) { double('LiveQA::Request', body: "{\"object\":\"event\",\"id\":41}") }
|
7
|
+
before { allow(LiveQA::Request).to receive(:execute).and_return(response) }
|
8
|
+
|
9
|
+
subject(:create) { LiveQA::Batch.create(data: []) }
|
10
|
+
|
11
|
+
it { is_expected.to be_successful }
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -10,7 +10,15 @@ describe LiveQA::Config do
|
|
10
10
|
|
11
11
|
%i[account_token environment_name api_host api_version].each do |field|
|
12
12
|
context "validate #{field}" do
|
13
|
-
let(:params) {
|
13
|
+
let(:params) {
|
14
|
+
{
|
15
|
+
account_token: 'acc_xx',
|
16
|
+
space_name: 'LiveQA',
|
17
|
+
environment_name: 'test',
|
18
|
+
api_host: 'host',
|
19
|
+
api_version: 'v1',
|
20
|
+
}.merge(field => '')
|
21
|
+
}
|
14
22
|
|
15
23
|
it { expect { config.valid! }.to raise_error(LiveQA::ConfigurationError, "#{field} can't be blank") }
|
16
24
|
end
|
@@ -24,19 +32,5 @@ describe LiveQA::Config do
|
|
24
32
|
it { expect(config.obfuscated_fields).to match_array(%w[another_password password_confirmation password access_token api_key authenticity_token ccv credit_card_number cvv secret secret_token token]) }
|
25
33
|
end
|
26
34
|
|
27
|
-
context 'async_handler' do
|
28
|
-
context 'sidekiq' do
|
29
|
-
let(:params) {{
|
30
|
-
account_token: 'acc_xx',
|
31
|
-
space_name: 'LiveQA',
|
32
|
-
environment_name: 'test',
|
33
|
-
async_handler: :sidekiq
|
34
|
-
}}
|
35
|
-
before { config.valid! }
|
36
|
-
|
37
|
-
it { expect(config.async_handler).to be_a(LiveQA::AsyncHandlers::Sidekiq) }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
35
|
end
|
42
36
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LiveQA::FormatedLogger do
|
4
|
+
let(:default_logger) { Logger.new(STDOUT) }
|
5
|
+
let(:logger) { LiveQA::FormatedLogger.build(default_logger) }
|
6
|
+
|
7
|
+
describe 'debug' do
|
8
|
+
|
9
|
+
context 'active' do
|
10
|
+
before do
|
11
|
+
allow(default_logger).to receive(:debug)
|
12
|
+
logger.debug('test')
|
13
|
+
end
|
14
|
+
|
15
|
+
it { expect(default_logger).to have_received(:debug).with('[LiveQA] test') }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'inactive' do
|
19
|
+
before do
|
20
|
+
LiveQA.configurations.log = false
|
21
|
+
allow(default_logger).to receive(:debug)
|
22
|
+
logger.debug('test')
|
23
|
+
end
|
24
|
+
|
25
|
+
it { expect(default_logger).to_not have_received(:debug) }
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'info' do
|
31
|
+
|
32
|
+
context 'active' do
|
33
|
+
before do
|
34
|
+
allow(default_logger).to receive(:info)
|
35
|
+
logger.info('test')
|
36
|
+
end
|
37
|
+
|
38
|
+
it { expect(default_logger).to have_received(:info).with('[LiveQA] test') }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'inactive' do
|
42
|
+
before do
|
43
|
+
LiveQA.configurations.log = false
|
44
|
+
allow(default_logger).to receive(:info)
|
45
|
+
logger.info('test')
|
46
|
+
end
|
47
|
+
|
48
|
+
it { expect(default_logger).to_not have_received(:info) }
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'info' do
|
54
|
+
|
55
|
+
context 'active' do
|
56
|
+
before do
|
57
|
+
allow(default_logger).to receive(:info)
|
58
|
+
logger.info('test')
|
59
|
+
end
|
60
|
+
|
61
|
+
it { expect(default_logger).to have_received(:info).with('[LiveQA] test') }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'inactive' do
|
65
|
+
before do
|
66
|
+
LiveQA.configurations.log = false
|
67
|
+
allow(default_logger).to receive(:info)
|
68
|
+
logger.info('test')
|
69
|
+
end
|
70
|
+
|
71
|
+
it { expect(default_logger).to_not have_received(:info) }
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'error' do
|
77
|
+
|
78
|
+
context 'active' do
|
79
|
+
before do
|
80
|
+
allow(default_logger).to receive(:error)
|
81
|
+
logger.error('test')
|
82
|
+
end
|
83
|
+
|
84
|
+
it { expect(default_logger).to have_received(:error).with('[LiveQA] test') }
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'inactive' do
|
88
|
+
before do
|
89
|
+
LiveQA.configurations.log = false
|
90
|
+
allow(default_logger).to receive(:error)
|
91
|
+
logger.error('test')
|
92
|
+
end
|
93
|
+
|
94
|
+
it { expect(default_logger).to_not have_received(:error) }
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LiveQA::Processor::Async do
|
4
|
+
|
5
|
+
let(:processor) { LiveQA::Processor::Async.new }
|
6
|
+
|
7
|
+
context 'enqueue a message' do
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(processor).to receive(:ensure_worker_running)
|
11
|
+
processor.enqueue({ test: 'hello' })
|
12
|
+
end
|
13
|
+
|
14
|
+
it { expect(processor).to have_received(:ensure_worker_running) }
|
15
|
+
it { expect(processor.instance_variable_get(:@queue).length).to eq(1) }
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LiveQA::Processor::Batch do
|
4
|
+
let(:batch) { LiveQA::Processor::Batch.new }
|
5
|
+
|
6
|
+
context 'set defaults' do
|
7
|
+
it { expect(batch.messages).to eq([]) }
|
8
|
+
it { expect(batch.can_run?).to be_truthy }
|
9
|
+
it { expect(batch.can_retry?).to be_truthy }
|
10
|
+
it { expect(batch.full?).to be_falsey }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'add message' do
|
14
|
+
before { batch << { test: 'hello' }}
|
15
|
+
|
16
|
+
it { expect(batch.messages).to eq([{ test: 'hello' }]) }
|
17
|
+
it { expect(batch.full?).to be_falsey }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with extended task' do
|
21
|
+
before { batch.update_retry }
|
22
|
+
|
23
|
+
it { expect(batch.can_run?).to be_falsey }
|
24
|
+
it { expect(batch.can_retry?).to be_truthy }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with extended task' do
|
28
|
+
before do
|
29
|
+
11.times { batch.update_retry }
|
30
|
+
end
|
31
|
+
|
32
|
+
it { expect(batch.can_run?).to be_falsey }
|
33
|
+
it { expect(batch.can_retry?).to be_falsey }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with max number of messages reached' do
|
37
|
+
before { 100.times { batch << { test: 'hello' }}}
|
38
|
+
|
39
|
+
it { expect(batch.full?).to be_truthy }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with max size reached' do
|
43
|
+
before { 20.times { batch << 1000.times.map {{ test: 'hello' }}}}
|
44
|
+
|
45
|
+
it { expect(batch.full?).to be_truthy }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LiveQA::Processor::Worker do
|
4
|
+
let(:queue) { Queue.new }
|
5
|
+
let(:worker) { LiveQA::Processor::Worker.new(queue) }
|
6
|
+
|
7
|
+
context 'do nothing' do
|
8
|
+
before do
|
9
|
+
allow(worker).to receive(:send_batches)
|
10
|
+
worker.run
|
11
|
+
end
|
12
|
+
|
13
|
+
it { expect(worker).not_to have_received(:send_batches) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with something in the queue' do
|
17
|
+
before do
|
18
|
+
queue << { test: true }
|
19
|
+
allow(LiveQA::Batch).to receive(:create)
|
20
|
+
worker.run
|
21
|
+
end
|
22
|
+
|
23
|
+
it { expect(LiveQA::Batch).to have_received(:create) }
|
24
|
+
end
|
25
|
+
end
|