hover-ruby-client 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ruby.yml +30 -0
- data/.gitignore +64 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +161 -0
- data/README.md +50 -0
- data/Rakefile +14 -0
- data/hover-ruby-client.gemspec +38 -0
- data/lib/hover/client/basic_auth.rb +18 -0
- data/lib/hover/client/hmac.rb +20 -0
- data/lib/hover/client/hover.rb +29 -0
- data/lib/hover/client/http.rb +141 -0
- data/lib/hover/client/manowar.rb +17 -0
- data/lib/hover/client/midas.rb +120 -0
- data/lib/hover/client/static.rb +89 -0
- data/lib/hover/decoder/json_stream.rb +25 -0
- data/lib/hover/encoder/json_stream.rb +35 -0
- data/lib/hover/importer/active_record.rb +134 -0
- data/lib/hover/jobs/concerns/retry_network_errors.rb +45 -0
- data/lib/hover/version.rb +3 -0
- data/test/app/Gemfile +1 -0
- data/test/files/archive.zip +0 -0
- data/test/files/encoded.json +106 -0
- data/test/test_helper.rb +80 -0
- data/test/unit/client/basic_auth_test.rb +21 -0
- data/test/unit/client/hmac_test.rb +277 -0
- data/test/unit/client/hover_test.rb +62 -0
- data/test/unit/client/manowar_test.rb +34 -0
- data/test/unit/client/midas_test.rb +187 -0
- data/test/unit/client/static_test.rb +169 -0
- data/test/unit/decoder/json_stream_test.rb +8 -0
- data/test/unit/encoder/json_stream_test.rb +135 -0
- data/test/unit/importer/active_record_test.rb +354 -0
- data/test/unit/jobs/concerns/retry_network_errors_test.rb +23 -0
- metadata +286 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
require 'hover/client/hover'
|
4
|
+
|
5
|
+
describe Hover::Client::Hover do
|
6
|
+
let(:client) { Hover::Client::Hover.new('access_id', 'secret_key') }
|
7
|
+
|
8
|
+
it "inits" do
|
9
|
+
assert client.is_a?(Hover::Client::Hover)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "json_get" do
|
13
|
+
arguments = ['orders.json', {}]
|
14
|
+
|
15
|
+
response = mock
|
16
|
+
parsed_response = mock
|
17
|
+
client.expects(:get).with(*arguments).returns(response)
|
18
|
+
client.expects(:parse_response).with(response).returns(parsed_response)
|
19
|
+
|
20
|
+
client.json_get(*arguments).must_equal(parsed_response)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "json_put" do
|
24
|
+
arguments = ['orders/1.json', {'order[address]' => 'kansas'}]
|
25
|
+
|
26
|
+
response = mock
|
27
|
+
parsed_response = mock
|
28
|
+
client.expects(:put).with(*arguments).returns(response)
|
29
|
+
client.expects(:parse_response).with(response).returns(parsed_response)
|
30
|
+
|
31
|
+
client.json_put(*arguments).must_equal(parsed_response)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "json_post" do
|
35
|
+
response = mock
|
36
|
+
parsed_response = mock
|
37
|
+
client.expects(:post).with('orders.json', {'order[address]' => 'elsewhere'}).returns(response)
|
38
|
+
client.expects(:parse_response).with(response).returns(parsed_response)
|
39
|
+
|
40
|
+
client.json_post('orders.json', {'order[address]' => 'elsewhere'}).must_equal(parsed_response)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "json_patch" do
|
44
|
+
arguments = ['orders/1.json', {'order[address]' => 'san francisco'}]
|
45
|
+
|
46
|
+
response = mock
|
47
|
+
parsed_response = mock
|
48
|
+
client.expects(:patch).with(*arguments).returns(response)
|
49
|
+
client.expects(:parse_response).with(response).returns(parsed_response)
|
50
|
+
|
51
|
+
client.json_patch(*arguments).must_equal(parsed_response)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "json_delete" do
|
55
|
+
response = mock
|
56
|
+
parsed_response = mock
|
57
|
+
client.expects(:delete).with('orders/1.json').returns(response)
|
58
|
+
client.expects(:parse_response).with(response).returns(parsed_response)
|
59
|
+
|
60
|
+
client.json_delete('orders/1.json').must_equal(parsed_response)
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
require 'hover/client/manowar'
|
4
|
+
|
5
|
+
describe Hover::Client::Manowar do
|
6
|
+
before do
|
7
|
+
@client = Hover::Client::Manowar.new('access_id', 'secret_key')
|
8
|
+
end
|
9
|
+
|
10
|
+
it "inits" do
|
11
|
+
assert @client.is_a?(Hover::Client::Manowar)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "submit_order" do
|
15
|
+
it "submits" do
|
16
|
+
parameters = {
|
17
|
+
"order[midas_identifier]" => 1,
|
18
|
+
"order[images_attributes][0][id]" => 1,
|
19
|
+
"order[images_attributes][1][id]" => 2
|
20
|
+
}
|
21
|
+
|
22
|
+
@client.expects(:json_post).with("orders.json", parameters)
|
23
|
+
|
24
|
+
@client.submit_order(parameters)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "order_results" do
|
29
|
+
it "gets results" do
|
30
|
+
@client.expects(:json_get).with("orders/1/results.json")
|
31
|
+
@client.order_results(1)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
require 'hover/client/midas'
|
4
|
+
|
5
|
+
describe Hover::Client::Midas do
|
6
|
+
before do
|
7
|
+
@client = Hover::Client::Midas.new('access_id', 'secret_key', 'http://localhost:3000')
|
8
|
+
end
|
9
|
+
|
10
|
+
it "inits" do
|
11
|
+
assert @client.is_a?(Hover::Client::Midas)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "user" do
|
15
|
+
it "gets user info" do
|
16
|
+
@client.expects(:json_get).with("me.json")
|
17
|
+
@client.me
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "orders" do
|
22
|
+
|
23
|
+
describe "index" do
|
24
|
+
it "gets index" do
|
25
|
+
@client.expects(:json_get).with("orders.json", {})
|
26
|
+
@client.orders
|
27
|
+
end
|
28
|
+
|
29
|
+
it "gets second page of index" do
|
30
|
+
@client.expects(:json_get).with("orders.json", {page: 2})
|
31
|
+
@client.orders(page: 2)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "show" do
|
36
|
+
it "shows" do
|
37
|
+
@client.expects(:json_get).with("orders/1.json", {})
|
38
|
+
@client.order(1)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "create" do
|
43
|
+
it "creates" do
|
44
|
+
@client.expects(:json_post).with("orders.json", {})
|
45
|
+
@client.create_order
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "complete upload" do
|
50
|
+
it "completes" do
|
51
|
+
@client.expects(:patch).with("orders/1/archive_uploading_complete.json")
|
52
|
+
@client.complete_order_upload(1)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "complete work" do
|
57
|
+
it "completes" do
|
58
|
+
@client.expects(:put).with("orders/1/work_complete.json")
|
59
|
+
@client.order_complete_work(1)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "images" do
|
65
|
+
describe "index" do
|
66
|
+
it "gets index" do
|
67
|
+
@client.expects(:json_get).with("images.json", {})
|
68
|
+
@client.images
|
69
|
+
end
|
70
|
+
|
71
|
+
it "gets second page of index" do
|
72
|
+
@client.expects(:json_get).with("images.json", {page: 2})
|
73
|
+
@client.images(page: 2)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "gets images for order" do
|
77
|
+
@client.expects(:json_get).with("images.json", {order_id: 1})
|
78
|
+
@client.images(order_id: 1)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "show" do
|
83
|
+
it "shows" do
|
84
|
+
@client.expects(:json_get).with("images/1.json")
|
85
|
+
@client.image(1)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "download_image" do
|
90
|
+
before do
|
91
|
+
@client.expects(:get_redirect_location).with("images/1.jpg", {}).once.returns("http://example.com/usr/to/s3")
|
92
|
+
end
|
93
|
+
|
94
|
+
it "contains the correct contents" do
|
95
|
+
chunk = "testing 1 2 3"
|
96
|
+
uri_mock = mock
|
97
|
+
uri_mock.expects(:read).once.returns(chunk)
|
98
|
+
Kernel.expects(:open).once.returns(uri_mock)
|
99
|
+
|
100
|
+
@client.download_image({"id" => 1}) do |file|
|
101
|
+
file.read.must_equal(chunk)
|
102
|
+
file.must_be_kind_of(File)
|
103
|
+
File.exist?(file.path).must_equal(true)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "upload_image" do
|
109
|
+
it "uploads" do
|
110
|
+
file = File.new("/tmp/test", "w")
|
111
|
+
|
112
|
+
image = {
|
113
|
+
"id" => 1,
|
114
|
+
"image" => {"upload_url" => "http://localhost/v1/images.json"}
|
115
|
+
}
|
116
|
+
|
117
|
+
file = mock
|
118
|
+
file.expects(:size).returns(1).once
|
119
|
+
|
120
|
+
request = mock
|
121
|
+
request.expects(:body_stream=).with(file).once
|
122
|
+
request.expects(:content_length=).with(1).once
|
123
|
+
|
124
|
+
request.expects(:[]=).with('Content-Type', '') # otherwise the signature is invalid!
|
125
|
+
|
126
|
+
Net::HTTP::Put.expects(:new)
|
127
|
+
.with(URI.parse(image["image"]["upload_url"]).request_uri)
|
128
|
+
.returns(request)
|
129
|
+
.once
|
130
|
+
|
131
|
+
Net::HTTP.any_instance.expects(:use_ssl=).with(true).once
|
132
|
+
Net::HTTP.any_instance.expects(:request).with(request).once
|
133
|
+
|
134
|
+
@client.upload_image(image, file)
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "upload images for order" do
|
140
|
+
it "fails if there are too many images" do
|
141
|
+
collection = [{"id" => 1}]
|
142
|
+
file_name_list = %w(1.jpg 2.jpg 3.jpg 4.jpg)
|
143
|
+
|
144
|
+
Dir.expects(:glob).once.returns(file_name_list)
|
145
|
+
|
146
|
+
@client.expects(:json_get).with("images/upload_urls.json", order_id: 1).returns(collection)
|
147
|
+
@client.expects(:upload_image).never
|
148
|
+
|
149
|
+
Proc.new {
|
150
|
+
@client.upload_images_for_order(1, "/tmp/testing_upload_images_for_order")
|
151
|
+
}.must_raise RuntimeError
|
152
|
+
end
|
153
|
+
|
154
|
+
it "uploads images for order" do
|
155
|
+
collection = (1 .. 5).inject([]) { |a, n| a << {"id" => n} }
|
156
|
+
file_name_list = %w(1.jpg 2.jpg 3.jpg 4.jpg)
|
157
|
+
|
158
|
+
Dir.expects(:glob).once.returns(file_name_list)
|
159
|
+
|
160
|
+
@client.expects(:json_get).with("images/upload_urls.json", order_id: 1).returns(collection)
|
161
|
+
@client.expects(:upload_image).at_most(file_name_list.size).at_least(file_name_list.size)
|
162
|
+
|
163
|
+
@client.upload_images_for_order(1, "/tmp/testing_upload_images_for_order")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "upload prometheus export" do
|
168
|
+
it "uploads export" do
|
169
|
+
path = File.join(File.dirname(__FILE__), '..', '..', 'files', 'archive.zip')
|
170
|
+
|
171
|
+
Zip::Entry.any_instance.expects(:extract).twice
|
172
|
+
@client.expects(:upload_images_for_order).once
|
173
|
+
|
174
|
+
@client.upload_images_from_prometheus_export(1, path)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "upload_image_urls" do
|
179
|
+
it "requests urls" do
|
180
|
+
@client.expects(:json_get).with("images/upload_urls.json", order_id: 1).once
|
181
|
+
@client.image_upload_urls(1)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require './test/test_helper'
|
2
|
+
|
3
|
+
require 'hover/client/static'
|
4
|
+
|
5
|
+
describe Hover::Client::Static do
|
6
|
+
let(:application) { 'hyperion' }
|
7
|
+
let(:environment) { 'development' }
|
8
|
+
|
9
|
+
before do
|
10
|
+
@client = Hover::Client::Static.new(application, environment, 'access_id', 'secret_key')
|
11
|
+
end
|
12
|
+
|
13
|
+
it "inits" do
|
14
|
+
assert @client.is_a?(Hover::Client::Static)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "param_name" do
|
18
|
+
it "metric value" do
|
19
|
+
Hover::Client::Static.param_name('metric', 'value').must_equal('metric[value]')
|
20
|
+
end
|
21
|
+
|
22
|
+
it "metric tags->order->practice" do
|
23
|
+
Hover::Client::Static.param_name('metric', 'tags', 'order', 'practice').must_equal('metric[tags][order][practice]')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "tags order->practice" do
|
27
|
+
Hover::Client::Static.param_name('tags', 'order', 'practice').must_equal('tags[order][practice]')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "tags_to_parameter" do
|
32
|
+
it "flat hash" do
|
33
|
+
input = {
|
34
|
+
modeler: 'yanis@hover.to',
|
35
|
+
server: 'production',
|
36
|
+
order: 1234
|
37
|
+
}
|
38
|
+
|
39
|
+
output = {
|
40
|
+
'metric[tags][modeler]' => 'yanis@hover.to',
|
41
|
+
'metric[tags][server]' => 'production',
|
42
|
+
'metric[tags][order]' => 1234
|
43
|
+
}
|
44
|
+
|
45
|
+
Hover::Client::Static.tags_to_params(input).must_equal(output)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "nested" do
|
49
|
+
input = {
|
50
|
+
a: 1,
|
51
|
+
b: 2,
|
52
|
+
c: {
|
53
|
+
d: 4,
|
54
|
+
e: ['a', 'b', 'c']
|
55
|
+
},
|
56
|
+
}
|
57
|
+
|
58
|
+
output = {
|
59
|
+
'metric[tags][a]' => 1,
|
60
|
+
'metric[tags][b]' => 2,
|
61
|
+
'metric[tags][c][d]' => 4,
|
62
|
+
'metric[tags][c][e][]' => ['a', 'b', 'c']
|
63
|
+
}
|
64
|
+
|
65
|
+
Hover::Client::Static.tags_to_params(input).must_equal(output)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "metrics" do
|
70
|
+
describe "create" do
|
71
|
+
let(:happened_at) { Time.now.utc }
|
72
|
+
|
73
|
+
it "reports to alooma" do
|
74
|
+
@client.expects(:alooma_url).returns("https://localhost").at_least(1)
|
75
|
+
|
76
|
+
http = mock
|
77
|
+
Net::HTTP.expects(:new).returns(http)
|
78
|
+
http.expects(:use_ssl=).with(true)
|
79
|
+
response = mock
|
80
|
+
response.expects(:code).returns(200)
|
81
|
+
http.expects(:request).returns(response)
|
82
|
+
|
83
|
+
@client.create_metric(name: 'foo', value: 1)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "raises AloomaReportingError if alooma returns an error" do
|
87
|
+
@client.expects(:alooma_url).returns("https://localhost").at_least(1)
|
88
|
+
|
89
|
+
http = mock
|
90
|
+
Net::HTTP.expects(:new).returns(http)
|
91
|
+
http.expects(:use_ssl=).with(true)
|
92
|
+
response = mock
|
93
|
+
response.expects(:code).returns(503)
|
94
|
+
http.expects(:request).returns(response)
|
95
|
+
|
96
|
+
err = Proc.new { @client.create_metric(name: 'foo', value: 1) }.must_raise(Hover::Client::AloomaReportingError)
|
97
|
+
err.message.must_match(/Error reporting to alooma/)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "creates metric" do
|
101
|
+
parameters = {
|
102
|
+
"metric[name]" => 'state_waiting_labeling',
|
103
|
+
'metric[value]' => 133.2,
|
104
|
+
'metric[happened_at]' => happened_at.to_s,
|
105
|
+
'metric[environment]' => environment,
|
106
|
+
'metric[application]' => application,
|
107
|
+
'metric[tags][order_id]' => 2
|
108
|
+
}
|
109
|
+
|
110
|
+
sorted_array = parameters.to_a.sort_by(&:first)
|
111
|
+
metric_identifier = Digest::SHA256.hexdigest(sorted_array.to_json)
|
112
|
+
parameters['metric[identifier]'] = metric_identifier
|
113
|
+
|
114
|
+
@client.expects(:alooma_url).returns("https://localhost").at_least(1)
|
115
|
+
@client.expects(:post_to_alooma).with(parameters, 'https://localhost')
|
116
|
+
|
117
|
+
@client.create_metric(name: 'state_waiting_labeling', value: 133.2, happened_at: happened_at, tags: {order_id: 2})
|
118
|
+
end
|
119
|
+
|
120
|
+
it "includes remote_record_id parameter" do
|
121
|
+
parameters = {
|
122
|
+
"metric[name]" => 'name',
|
123
|
+
'metric[value]' => 1,
|
124
|
+
'metric[happened_at]' => 'foo',
|
125
|
+
'metric[environment]' => environment,
|
126
|
+
'metric[application]' => application,
|
127
|
+
'metric[remote_record_id]' => 7
|
128
|
+
}
|
129
|
+
|
130
|
+
sorted_array = parameters.to_a.sort_by(&:first)
|
131
|
+
metric_identifier = Digest::SHA256.hexdigest(sorted_array.to_json)
|
132
|
+
parameters['metric[identifier]'] = metric_identifier
|
133
|
+
|
134
|
+
@client.expects(:alooma_url).returns("https://localhost").at_least(1)
|
135
|
+
@client.expects(:post_to_alooma).with(parameters, 'https://localhost')
|
136
|
+
|
137
|
+
@client.create_metric(name: 'name', value: 1, remote_record_id: 7, happened_at: 'foo')
|
138
|
+
end
|
139
|
+
|
140
|
+
it "creates metric with nested tags" do
|
141
|
+
parameters = {
|
142
|
+
"metric[name]" => 'state_labeling',
|
143
|
+
'metric[value]' => 3449,
|
144
|
+
'metric[happened_at]' => happened_at.to_s,
|
145
|
+
'metric[environment]' => environment,
|
146
|
+
'metric[application]' => application,
|
147
|
+
'metric[tags][order][id]' => 2,
|
148
|
+
'metric[tags][order][practice]' => false,
|
149
|
+
'metric[tags][user][email]' => 'modeler@hover.to',
|
150
|
+
'metric[tags][a][b][c][]' => [11, 27],
|
151
|
+
}
|
152
|
+
|
153
|
+
sorted_array = parameters.to_a.sort_by(&:first)
|
154
|
+
metric_identifier = Digest::SHA256.hexdigest(sorted_array.to_json)
|
155
|
+
parameters['metric[identifier]'] = metric_identifier
|
156
|
+
|
157
|
+
@client.expects(:alooma_url).returns("https://localhost").at_least(1)
|
158
|
+
@client.expects(:post_to_alooma).with(parameters, 'https://localhost')
|
159
|
+
|
160
|
+
@client.create_metric(name: 'state_labeling', value: 3449, happened_at: happened_at, tags: {
|
161
|
+
order: {id: 2, practice: false},
|
162
|
+
user: {email: 'modeler@hover.to'},
|
163
|
+
a: {b: {c: [11, 27]}}
|
164
|
+
})
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|