hawkei 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +48 -0
  5. data/.ruby-version +1 -0
  6. data/.tool-versions +1 -0
  7. data/.travis.yml +11 -0
  8. data/Gemfile +12 -0
  9. data/LICENCE +21 -0
  10. data/Makefile +9 -0
  11. data/README.md +17 -0
  12. data/Rakefile +4 -0
  13. data/hawkei.gemspec +28 -0
  14. data/lib/hawkei/api_operation/delete.rb +38 -0
  15. data/lib/hawkei/api_operation/save.rb +57 -0
  16. data/lib/hawkei/api_resource.rb +130 -0
  17. data/lib/hawkei/batch.rb +18 -0
  18. data/lib/hawkei/config.rb +123 -0
  19. data/lib/hawkei/errors.rb +41 -0
  20. data/lib/hawkei/formated_logger.rb +45 -0
  21. data/lib/hawkei/hawkei_object.rb +179 -0
  22. data/lib/hawkei/library_name.rb +3 -0
  23. data/lib/hawkei/message.rb +79 -0
  24. data/lib/hawkei/plugins/rack/middleware.rb +139 -0
  25. data/lib/hawkei/plugins/rails/data.rb +19 -0
  26. data/lib/hawkei/plugins/rails/middleware_data.rb +28 -0
  27. data/lib/hawkei/plugins/rails/railtie.rb +23 -0
  28. data/lib/hawkei/plugins/sidekiq/client_middleware.rb +19 -0
  29. data/lib/hawkei/plugins/sidekiq/load.rb +14 -0
  30. data/lib/hawkei/plugins/sidekiq/server_middleware.rb +48 -0
  31. data/lib/hawkei/plugins.rb +17 -0
  32. data/lib/hawkei/processor/async.rb +50 -0
  33. data/lib/hawkei/processor/batch.rb +84 -0
  34. data/lib/hawkei/processor/worker.rb +113 -0
  35. data/lib/hawkei/request.rb +134 -0
  36. data/lib/hawkei/store.rb +49 -0
  37. data/lib/hawkei/util.rb +180 -0
  38. data/lib/hawkei/version.rb +3 -0
  39. data/lib/hawkei/watcher.rb +15 -0
  40. data/lib/hawkei.rb +170 -0
  41. data/spec/lib/hawkei/api_resource_spec.rb +109 -0
  42. data/spec/lib/hawkei/batch_spec.rb +14 -0
  43. data/spec/lib/hawkei/config_spec.rb +36 -0
  44. data/spec/lib/hawkei/formated_logger_spec.rb +99 -0
  45. data/spec/lib/hawkei/hawkei_object_spec.rb +123 -0
  46. data/spec/lib/hawkei/message_spec.rb +178 -0
  47. data/spec/lib/hawkei/plugins/rack/middleware_spec.rb +88 -0
  48. data/spec/lib/hawkei/plugins/rails/data_spec.rb +22 -0
  49. data/spec/lib/hawkei/plugins/rails/middleware_data_spec.rb +46 -0
  50. data/spec/lib/hawkei/plugins/sidekiq/client_middleware_spec.rb +15 -0
  51. data/spec/lib/hawkei/plugins/sidekiq/server_middleware_spec.rb +58 -0
  52. data/spec/lib/hawkei/processor/async_spec.rb +36 -0
  53. data/spec/lib/hawkei/processor/batch_spec.rb +51 -0
  54. data/spec/lib/hawkei/processor/worker_spec.rb +100 -0
  55. data/spec/lib/hawkei/store_spec.rb +82 -0
  56. data/spec/lib/hawkei/util_spec.rb +132 -0
  57. data/spec/lib/hawkei/watcher_spec.rb +25 -0
  58. data/spec/lib/hawkei_spec.rb +175 -0
  59. data/spec/spec_helper.rb +33 -0
  60. data/spec/support/rack_app.rb +12 -0
  61. metadata +206 -0
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'rails'
3
+ require 'hawkei/plugins/rails/middleware_data'
4
+
5
+ describe Hawkei::Plugins::Rails::MiddlewareData do
6
+
7
+ let(:middleware) { Hawkei::Plugins::Rails::MiddlewareData }
8
+
9
+ describe '#store_data' do
10
+ let(:request) do
11
+ double('request',
12
+ env: {
13
+ 'action_dispatch.request_id' => '42a'
14
+ }
15
+ )
16
+ end
17
+
18
+ context 'blank store' do
19
+ before { middleware.store_data(request) }
20
+
21
+ let(:expected) {{
22
+ request: {
23
+ id: '42a'
24
+ }
25
+ }}
26
+
27
+ it { expect(Hawkei::Store.store).to match(expected) }
28
+ end
29
+
30
+ context 'update the store' do
31
+ before do
32
+ Hawkei::Store.set(:request, { xhr: false })
33
+ end
34
+ before { middleware.store_data(request) }
35
+
36
+ let(:expected) {{
37
+ request: {
38
+ id: '42a',
39
+ xhr: false
40
+ }
41
+ }}
42
+
43
+ it { expect(Hawkei::Store.store).to match(expected) }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'sidekiq'
3
+ require 'hawkei/plugins/sidekiq/client_middleware'
4
+
5
+ describe Hawkei::Plugins::Sidekiq::ClientMiddleware do
6
+
7
+ let(:middleware) { Hawkei::Plugins::Sidekiq::ClientMiddleware.new }
8
+
9
+ describe '#call' do
10
+ before { Hawkei::Store.set(:tracker_id, 1) }
11
+
12
+ it { expect { middleware.call('MyWorker', {}, 'default', {}) {} }.to_not raise_error }
13
+ end
14
+
15
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'sidekiq'
3
+ require 'hawkei/plugins/sidekiq/server_middleware'
4
+
5
+ describe Hawkei::Plugins::Sidekiq::ServerMiddleware do
6
+
7
+ let(:middleware) { Hawkei::Plugins::Sidekiq::ServerMiddleware.new }
8
+
9
+ describe '#call' do
10
+ let(:job_attr) {{
11
+ 'class' => 'MyWorker',
12
+ 'args' => ['42'],
13
+ 'retry' => 3,
14
+ 'queue' => 'default',
15
+ 'jid' => '24cc849f71325b62ef470901',
16
+ 'created_at' => 1513299839.2563882,
17
+ '_hawkei_stid' => '06a09f70-6219-4860-babc-18aa47a62f7f',
18
+ 'enqueued_at' => 1513300328.8271549,
19
+ 'error_message' => 'exit',
20
+ 'error_class' => 'SystemExit',
21
+ 'failed_at' => 1513300166.646098,
22
+ 'retry_count' => 1,
23
+ 'retried_at' => 1513300238.6037261
24
+ }}
25
+
26
+ context 'expected to be clean at the end' do
27
+ before { middleware.call('MyWorker', job_attr, 'default') {} }
28
+
29
+ it { expect(Hawkei::Store.store).to be_empty }
30
+ end
31
+
32
+ context 'expected to be clean at the end' do
33
+ before { allow(Hawkei::Store).to receive(:clear!).and_return(true) }
34
+ before { middleware.call('MyWorker', job_attr, 'default') {} }
35
+
36
+ let(:expected) {{
37
+ session_tracker_id: '06a09f70-6219-4860-babc-18aa47a62f7f',
38
+ server_software: include("Sidekiq"),
39
+ worker: {
40
+ name: 'sidekiq',
41
+ version: kind_of(String),
42
+ queue: 'default',
43
+ class: 'MyWorker',
44
+ id: '24cc849f71325b62ef470901',
45
+ created_at: '2017-12-15T01:03:59.256Z',
46
+ process_at: '2017-12-15T01:12:08.827Z',
47
+ args: ['42'],
48
+ retried: true,
49
+ retry_number: 1,
50
+ failed_at: '2017-12-15T01:09:26.646Z'
51
+ },
52
+ }}
53
+
54
+ it { expect(Hawkei::Store.store).to match(expected) }
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hawkei::Processor::Async do
4
+
5
+ let(:processor) { Hawkei::Processor::Async.new }
6
+
7
+ context 'enqueue a message' do
8
+ before do
9
+ allow(processor).to receive(:ensure_worker_running)
10
+ processor.enqueue({ test: 'hello' })
11
+ end
12
+
13
+ it { expect(processor).to have_received(:ensure_worker_running) }
14
+ it { expect(processor.instance_variable_get(:@queue).length).to eq(1) }
15
+ end
16
+
17
+ context 'shutting down worker' do
18
+ before do
19
+ allow_message_expectations_on_nil
20
+
21
+ allow(processor.instance_variable_get(:@state_worker)).to receive(:make_false)
22
+ allow(processor.instance_variable_get(:@worker_thread)).to receive(:wait)
23
+ allow(Concurrent.global_io_executor).to receive(:shutdown)
24
+ allow(Concurrent.global_io_executor).to receive(:wait_for_termination)
25
+
26
+ processor.send(:shutdown_worker)
27
+ end
28
+
29
+ it { expect(processor.instance_variable_get(:@state_worker)).to have_received(:make_false) }
30
+ it { expect(processor.instance_variable_get(:@worker_thread)).to have_received(:wait) }
31
+ it { expect(Concurrent.global_io_executor).to have_received(:shutdown) }
32
+ it { expect(Concurrent.global_io_executor).to have_received(:wait_for_termination) }
33
+ it { expect(processor.instance_variable_get(:@queue).length).to eq(1) }
34
+ end
35
+
36
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hawkei::Processor::Batch do
4
+ let(:batch) { Hawkei::Processor::Batch.new }
5
+
6
+ context 'set defaults' do
7
+ it { expect(batch.messages).to eq([]) }
8
+ it { expect(batch.can_retry?).to be_truthy }
9
+ it { expect(batch.full?).to be_falsey }
10
+ it { expect(batch.empty?).to be_truthy }
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
+ it { expect(batch.empty?).to be_falsey }
19
+ end
20
+
21
+ context 'with extended task' do
22
+ before { batch.update_retry }
23
+
24
+ it { expect(batch.can_retry?).to be_truthy }
25
+ it { expect(batch.next_retry).to eq(2) }
26
+ end
27
+
28
+ context 'with extended task' do
29
+ before do
30
+ 11.times { batch.update_retry }
31
+ end
32
+
33
+ it { expect(batch.can_retry?).to be_falsey }
34
+ it { expect(batch.next_retry).to eq(60) }
35
+ end
36
+
37
+ context 'with max number of messages reached' do
38
+ before { 100.times { batch << { test: 'hello' }}}
39
+
40
+ it { expect(batch.full?).to be_truthy }
41
+ it { expect(batch.empty?).to be_falsey }
42
+ end
43
+
44
+ context 'with max size reached' do
45
+ before { 20.times { batch << 1000.times.map {{ test: 'hello' }}}}
46
+
47
+ it { expect(batch.full?).to be_truthy }
48
+ it { expect(batch.empty?).to be_falsey }
49
+ end
50
+
51
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hawkei::Processor::Worker do
4
+ let(:state_worker) { Concurrent::AtomicBoolean.new(true) }
5
+ let(:queue) { Queue.new }
6
+ let(:worker) { Hawkei::Processor::Worker.new(queue, state_worker) }
7
+ let!(:current_batch) { worker.instance_variable_get(:@batch) }
8
+
9
+ describe 'private#add_message_to_batch' do
10
+ context 'add to batch' do
11
+ let(:message) { Object.new }
12
+ before { worker.send(:add_message_to_batch, message) }
13
+
14
+ it { expect(current_batch.messages).to eq([message]) }
15
+ end
16
+
17
+ context 'with batch full' do
18
+ before do
19
+ allow(current_batch).to receive(:full?).and_return(true)
20
+ allow(worker).to receive(:flush)
21
+ worker.send(:add_message_to_batch, Object.new)
22
+ end
23
+
24
+ it { expect(worker).to have_received(:flush) }
25
+ end
26
+
27
+ context 'call flush' do
28
+ before do
29
+ allow(worker).to receive(:flush)
30
+ worker.send(:add_message_to_batch, Hawkei::Processor::Worker::FLUSH_MESSAGE)
31
+ end
32
+
33
+ it { expect(worker).to have_received(:flush) }
34
+ end
35
+ end
36
+
37
+ describe 'private#flush' do
38
+ before do
39
+ allow(current_batch).to receive(:empty?).and_return(batch_status)
40
+ allow(worker).to receive(:send_batch)
41
+ worker.send(:flush)
42
+ end
43
+
44
+ context 'with not empty batch' do
45
+ let(:batch_status) { false }
46
+
47
+ it { expect(worker).to have_received(:send_batch).with(current_batch) }
48
+ it { expect(current_batch).to_not eq(worker.instance_variable_get(:@batch)) }
49
+ end
50
+
51
+ context 'with empty batch' do
52
+ let(:batch_status) { true }
53
+
54
+ it { expect(worker).to_not have_received(:send_batch) }
55
+ it { expect(current_batch).to eq(worker.instance_variable_get(:@batch)) }
56
+ end
57
+ end
58
+
59
+ describe 'private#send_batch' do
60
+ let(:batch) { Hawkei::Processor::Batch.new }
61
+ let(:batch_can_retry) { true }
62
+
63
+ before do
64
+ allow(Hawkei::Request).to receive(:execute).and_return(response)
65
+ allow(batch).to receive(:update_retry)
66
+ allow(batch).to receive(:can_retry?).and_return(batch_can_retry)
67
+ allow(Concurrent::ScheduledTask).to receive(:new)
68
+ worker.send(:send_batch, batch)
69
+ sleep(0.1)
70
+ end
71
+
72
+ context 'with valid request' do
73
+ let(:response) { double('Hawkei::Request', body: "{\"object\":\"batch\",\"id\":41}") }
74
+
75
+ it { expect(Hawkei::Request).to have_received(:execute) }
76
+ it { expect(batch).to_not have_received(:update_retry) }
77
+ it { expect(worker.instance_variable_get(:@promises).size).to eq(0) }
78
+ end
79
+
80
+ context 'with invalid request' do
81
+ let(:response) { nil }
82
+
83
+ it { expect(Hawkei::Request).to have_received(:execute) }
84
+ it { expect(batch).to have_received(:update_retry) }
85
+ it { expect(Concurrent::ScheduledTask).to have_received(:new) }
86
+ it { expect(worker.instance_variable_get(:@promises).size).to eq(1) }
87
+ end
88
+
89
+ context 'with batch exhausted request' do
90
+ let(:batch_can_retry) { false }
91
+ let(:response) { nil }
92
+
93
+ it { expect(Hawkei::Request).to have_received(:execute) }
94
+ it { expect(batch).to have_received(:update_retry) }
95
+ it { expect(Concurrent::ScheduledTask).to_not have_received(:new) }
96
+ it { expect(worker.instance_variable_get(:@promises).size).to eq(0) }
97
+ end
98
+ end
99
+
100
+ end
@@ -0,0 +1,82 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe Hawkei::Store do
5
+
6
+ subject(:store) { Hawkei::Store }
7
+
8
+ describe '.store' do
9
+ it { expect(store.store).to eq({})}
10
+ end
11
+
12
+ describe '.store' do
13
+ before { store.clear! }
14
+ it { expect(store.store).to eq({})}
15
+
16
+ context 'with values' do
17
+ before { store.set(:test, 'value') }
18
+ before { store.clear! }
19
+
20
+ it { expect(store.store).to eq({}) }
21
+ end
22
+ end
23
+
24
+ describe '.load_from_hash' do
25
+ context 'with hash' do
26
+ before { store.load_from_hash('test' => 'value', another: 'another_value') }
27
+
28
+ it { expect(store.store).to match(test: 'value', another: 'another_value') }
29
+ end
30
+
31
+ it { expect { store.load_from_hash(nil) }.to_not raise_error }
32
+ end
33
+
34
+ describe '.set' do
35
+ before { store.set(:test, 'value') }
36
+
37
+ it { expect(store.store).to eq(test: 'value') }
38
+ end
39
+
40
+ describe '[]=' do
41
+ before { store[:test] = 'value' }
42
+
43
+ it { expect(store.store).to eq(test: 'value') }
44
+ end
45
+
46
+ describe '.get' do
47
+ before { store.set(:test, 'value') }
48
+
49
+ it { expect(store.get(:test)).to eq('value') }
50
+ end
51
+
52
+ describe '[]' do
53
+ before { store[:test] = 'value' }
54
+
55
+ it { expect(store[:test]).to eq('value') }
56
+ end
57
+
58
+ describe '.bulk_set' do
59
+ before { store[:test] = 'value' }
60
+ before { store.bulk_set(new_test: 'value', another: 'another_value') }
61
+
62
+ it { expect(store.store).to match(test: 'value', new_test: 'value', another: 'another_value') }
63
+ end
64
+
65
+ describe '.exist?' do
66
+ before { store.set(:test, 'value') }
67
+
68
+ it { expect(store.exist?(:test)).to be_truthy }
69
+ it { expect(store.exist?(:something)).to be_falsey }
70
+ end
71
+
72
+ describe '.exist?' do
73
+ before { store.set(:test, 'value') }
74
+ before { store.delete(:test)}
75
+
76
+ it { expect(store.exist?(:test)).to be_falsey }
77
+
78
+ context 'value does not exist' do
79
+ it { expect { store.delete(:something) }.to_not raise_error }
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hawkei::Util do
4
+
5
+ describe '#camelize' do
6
+ it { expect(Hawkei::Util.except_keys({ a: 1, b: 2 }, :b)).to eq({ a: 1 }) }
7
+ end
8
+
9
+ describe '#camelize' do
10
+ it { expect(Hawkei::Util.camelize('model')).to eq("Model") }
11
+ it { expect(Hawkei::Util.camelize('my_model')).to eq("MyModel") }
12
+ end
13
+
14
+ describe '#compact' do
15
+ it { expect(Hawkei::Util.compact(test: nil, other: 'test')).to eq(other: 'test') }
16
+ end
17
+
18
+ describe '#deep_compact' do
19
+ let(:payload) {{
20
+ my_key: 'test',
21
+ empty_key: nil,
22
+ another_key: {
23
+ last_key: 42,
24
+ valid_key: 'test',
25
+ empty_key: nil,
26
+ yet_another_key: {
27
+ empty_key: nil
28
+ }
29
+ }
30
+ }}
31
+
32
+ let(:expected) {{
33
+ my_key: 'test',
34
+ another_key: {
35
+ last_key: 42,
36
+ valid_key: 'test'
37
+ }
38
+ }}
39
+ it { expect(Hawkei::Util.deep_compact(payload)).to eq(expected) }
40
+ end
41
+
42
+ describe '#encode_parameters' do
43
+ it { expect(Hawkei::Util.encode_parameters(id: 42, other: 'test')).to eq("id=42&other=test") }
44
+ end
45
+
46
+ describe '#underscore' do
47
+ it { expect(Hawkei::Util.underscore('Model')).to eq("model") }
48
+ it { expect(Hawkei::Util.underscore('MyModel')).to eq("my_model") }
49
+ end
50
+
51
+ describe '#deep_underscore_key' do
52
+ let(:payload) {{
53
+ 'MyKey' => 'test',
54
+ 'anotherKey' => {
55
+ 'lastKey' => 'test',
56
+ 'valid_key' => 'test'
57
+ }
58
+ }}
59
+
60
+ let(:expected) {{
61
+ my_key: 'test',
62
+ another_key: {
63
+ last_key: 'test',
64
+ valid_key: 'test'
65
+ }
66
+ }}
67
+
68
+ it { expect(Hawkei::Util.deep_underscore_key(payload)).to eq(expected) }
69
+ end
70
+
71
+ describe '#deep_stringify_key' do
72
+ let(:payload) {{
73
+ my_key: 'test',
74
+ another_key: {
75
+ last_key: 'test',
76
+ valid_key: 'test'
77
+ }
78
+ }}
79
+
80
+ let(:expected) {{
81
+ 'my_key' => 'test',
82
+ 'another_key' => {
83
+ 'last_key' => 'test',
84
+ 'valid_key' => 'test'
85
+ }
86
+ }}
87
+
88
+ it { expect(Hawkei::Util.deep_stringify_key(payload)).to eq(expected) }
89
+ end
90
+
91
+ describe '#deep_symbolize_key' do
92
+ let(:payload) {{
93
+ 'my_key' => 'test',
94
+ 'another_key' => {
95
+ 'last_key' => 'test',
96
+ 'valid_key' => 'test'
97
+ }
98
+ }}
99
+
100
+ let(:expected) {{
101
+ my_key: 'test',
102
+ another_key: {
103
+ last_key: 'test',
104
+ valid_key: 'test'
105
+ }
106
+ }}
107
+
108
+ it { expect(Hawkei::Util.deep_symbolize_key(payload)).to eq(expected) }
109
+ end
110
+
111
+ describe '#deep_obfuscate_value' do
112
+ let(:fields) { ['password', 'credit_card'] }
113
+ let(:payload) {{
114
+ password: 'test',
115
+ another_key: {
116
+ credit_card: '41111111',
117
+ valid_key: 'test'
118
+ }
119
+ }}
120
+
121
+ let(:expected) {{
122
+ password: '[HIDDEN]',
123
+ another_key: {
124
+ credit_card: '[HIDDEN]',
125
+ valid_key: 'test'
126
+ }
127
+ }}
128
+
129
+ it { expect(Hawkei::Util.deep_obfuscate_value(payload, fields)).to eq(expected) }
130
+ end
131
+
132
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hawkei::Watcher do
4
+
5
+ describe '#create' do
6
+ let(:response) { double('Hawkei::Request', body: "{\"object\":\"watcher\",\"id\":1}") }
7
+ before { expect(Hawkei::Request).to receive(:execute).and_return(response) }
8
+
9
+ subject(:create) { Hawkei::Watcher.create(template_flow: 'My Hawkei', expected_times: 42) }
10
+
11
+ it { is_expected.to be_successful }
12
+ it { expect(create.id).to eq(1) }
13
+ end
14
+
15
+ describe '#delete' do
16
+ let(:response) { double('Hawkei::Request', body: "{\"object\":\"watcher\",\"id\":1}") }
17
+ before { expect(Hawkei::Request).to receive(:execute).and_return(response) }
18
+
19
+ subject(:delete) { Hawkei::Watcher.delete(1) }
20
+
21
+ it { is_expected.to be_successful }
22
+ it { expect(delete.id).to eq(1) }
23
+ end
24
+
25
+ end