etre-client 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +97 -0
- data/README.md +74 -0
- data/Rakefile +4 -0
- data/etre-client.gemspec +26 -0
- data/lib/etre-client.rb +264 -0
- data/lib/etre-client/errors.rb +13 -0
- data/lib/etre-client/version.rb +5 -0
- data/spec/client_spec.rb +328 -0
- data/spec/unit_helper.rb +8 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d7ee88bbc4eaef62c80b7fe886975cc09f6fe3fa
|
4
|
+
data.tar.gz: 474060e882a53a6274772f2b21854651295d43f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e3ec873dbc34c866833116196fce1b87a463a9f45360786bb48e6afb5c306bc1d7911a3c1d944736e81dee8dba6679793bf31afbeb63a2ad406b91930ea49d9
|
7
|
+
data.tar.gz: b993c6f228ac3bc21f941d4a2cbd2b86eb0f43058a8e3e9a27da4082555507668312bcf446a257ce7eb0b9d1b19bb8cdbbd2fa3fee9fadbd19c38fef80e0413d
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionpack (5.1.4)
|
5
|
+
actionview (= 5.1.4)
|
6
|
+
activesupport (= 5.1.4)
|
7
|
+
rack (~> 2.0)
|
8
|
+
rack-test (>= 0.6.3)
|
9
|
+
rails-dom-testing (~> 2.0)
|
10
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
11
|
+
actionview (5.1.4)
|
12
|
+
activesupport (= 5.1.4)
|
13
|
+
builder (~> 3.1)
|
14
|
+
erubi (~> 1.4)
|
15
|
+
rails-dom-testing (~> 2.0)
|
16
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
17
|
+
activesupport (5.1.4)
|
18
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
19
|
+
i18n (~> 0.7)
|
20
|
+
minitest (~> 5.1)
|
21
|
+
tzinfo (~> 1.1)
|
22
|
+
builder (3.2.3)
|
23
|
+
concurrent-ruby (1.0.5)
|
24
|
+
crass (1.0.2)
|
25
|
+
diff-lcs (1.3)
|
26
|
+
domain_name (0.5.20170404)
|
27
|
+
unf (>= 0.0.5, < 1.0.0)
|
28
|
+
erubi (1.7.0)
|
29
|
+
http-cookie (1.0.3)
|
30
|
+
domain_name (~> 0.5)
|
31
|
+
i18n (0.9.0)
|
32
|
+
concurrent-ruby (~> 1.0)
|
33
|
+
loofah (2.1.1)
|
34
|
+
crass (~> 1.0.2)
|
35
|
+
nokogiri (>= 1.5.9)
|
36
|
+
method_source (0.9.0)
|
37
|
+
mime-types (3.1)
|
38
|
+
mime-types-data (~> 3.2015)
|
39
|
+
mime-types-data (3.2016.0521)
|
40
|
+
mini_portile2 (2.3.0)
|
41
|
+
minitest (5.10.3)
|
42
|
+
netrc (0.11.0)
|
43
|
+
nokogiri (1.8.1)
|
44
|
+
mini_portile2 (~> 2.3.0)
|
45
|
+
rack (2.0.3)
|
46
|
+
rack-test (0.7.0)
|
47
|
+
rack (>= 1.0, < 3)
|
48
|
+
rails-dom-testing (2.0.3)
|
49
|
+
activesupport (>= 4.2.0)
|
50
|
+
nokogiri (>= 1.6)
|
51
|
+
rails-html-sanitizer (1.0.3)
|
52
|
+
loofah (~> 2.0)
|
53
|
+
railties (5.1.4)
|
54
|
+
actionpack (= 5.1.4)
|
55
|
+
activesupport (= 5.1.4)
|
56
|
+
method_source
|
57
|
+
rake (>= 0.8.7)
|
58
|
+
thor (>= 0.18.1, < 2.0)
|
59
|
+
rake (12.2.1)
|
60
|
+
rest-client (2.0.2)
|
61
|
+
http-cookie (>= 1.0.2, < 2.0)
|
62
|
+
mime-types (>= 1.16, < 4.0)
|
63
|
+
netrc (~> 0.8)
|
64
|
+
rspec-core (3.7.0)
|
65
|
+
rspec-support (~> 3.7.0)
|
66
|
+
rspec-expectations (3.7.0)
|
67
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
68
|
+
rspec-support (~> 3.7.0)
|
69
|
+
rspec-mocks (3.7.0)
|
70
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
71
|
+
rspec-support (~> 3.7.0)
|
72
|
+
rspec-rails (3.7.1)
|
73
|
+
actionpack (>= 3.0)
|
74
|
+
activesupport (>= 3.0)
|
75
|
+
railties (>= 3.0)
|
76
|
+
rspec-core (~> 3.7.0)
|
77
|
+
rspec-expectations (~> 3.7.0)
|
78
|
+
rspec-mocks (~> 3.7.0)
|
79
|
+
rspec-support (~> 3.7.0)
|
80
|
+
rspec-support (3.7.0)
|
81
|
+
thor (0.20.0)
|
82
|
+
thread_safe (0.3.6)
|
83
|
+
tzinfo (1.2.4)
|
84
|
+
thread_safe (~> 0.1)
|
85
|
+
unf (0.1.4)
|
86
|
+
unf_ext
|
87
|
+
unf_ext (0.0.7.4)
|
88
|
+
|
89
|
+
PLATFORMS
|
90
|
+
ruby
|
91
|
+
|
92
|
+
DEPENDENCIES
|
93
|
+
rest-client
|
94
|
+
rspec-rails
|
95
|
+
|
96
|
+
BUNDLED WITH
|
97
|
+
1.15.4
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
Description
|
2
|
+
------
|
3
|
+
etre-client is a gem that can be used to interact with an [Etre](https://github.com/square/etre) instance.
|
4
|
+
|
5
|
+
Installation
|
6
|
+
------
|
7
|
+
etre-client is hosted on rubygems.org. To install it
|
8
|
+
1. Add "etre-client" to your Gemfile
|
9
|
+
2. Run "bunndle install"
|
10
|
+
|
11
|
+
Alternatively, you can just "gem install etre-client".
|
12
|
+
|
13
|
+
Usage
|
14
|
+
------
|
15
|
+
Create a new client
|
16
|
+
```
|
17
|
+
e = Etre::Client.new(entity_type: "node", url: "http://127.0.0.1:8080")
|
18
|
+
```
|
19
|
+
|
20
|
+
Insert entities
|
21
|
+
```
|
22
|
+
entities = [{"foo" => "bar"}, {"foo" => "abc"}]
|
23
|
+
e.insert(entities)
|
24
|
+
=> [{"id"=>"59f90caadd1b176f02eddcd8", "uri"=>"127.0.0.1:8080/api/v1/entity/59f90caadd1b176f02eddcd8"}, {"id"=>"59f90caadd1b176f02eddcda", "uri"=>"127.0.0.1:8080/api/v1/entity/59f90caadd1b176f02eddcda"}]
|
25
|
+
```
|
26
|
+
|
27
|
+
Update entities
|
28
|
+
```
|
29
|
+
query = "foo=bar"
|
30
|
+
patch = {"foo" => "newbar"}
|
31
|
+
e.update(query, patch)
|
32
|
+
=> [{"id"=>"59f90caadd1b176f02eddcd8", "uri"=>"127.0.0.1:8080/api/v1/entity/59f90caadd1b176f02eddcd8", "diff"=>{"_id"=>"59f90caadd1b176f02eddcd8", "_rev"=>0, "_type"=>"node", "foo"=>"bar"}}]
|
33
|
+
```
|
34
|
+
|
35
|
+
Update a single entity
|
36
|
+
```
|
37
|
+
id = "59f90caadd1b176f02eddcda"
|
38
|
+
patch = {"foo" => "newbar"}
|
39
|
+
e.update_one(id, patch)
|
40
|
+
|
41
|
+
=> {"id"=>"59f90caadd1b176f02eddcda", "uri"=>"127.0.0.1:8080/api/v1/entity/59f90caadd1b176f02eddcda", "diff"=>{"_id"=>"59f90caadd1b176f02eddcda", "_rev"=>0, "_type"=>"node", "foo"=>"abc"}}
|
42
|
+
```
|
43
|
+
|
44
|
+
Delete entities
|
45
|
+
```
|
46
|
+
query = "foo=bar"
|
47
|
+
e.delete(query)
|
48
|
+
```
|
49
|
+
|
50
|
+
Delete a single entity
|
51
|
+
```
|
52
|
+
id = "abc"
|
53
|
+
e.delete_one(id)
|
54
|
+
=> {"_id" => "abc", "foo" => "bar"}
|
55
|
+
```
|
56
|
+
|
57
|
+
List the labels for an entity
|
58
|
+
```
|
59
|
+
id = "abc"
|
60
|
+
e.labels(id)
|
61
|
+
=> ["foo"]
|
62
|
+
```
|
63
|
+
|
64
|
+
Development
|
65
|
+
------
|
66
|
+
Run the tests
|
67
|
+
```
|
68
|
+
bundle exec rake spec
|
69
|
+
```
|
70
|
+
|
71
|
+
## License
|
72
|
+
|
73
|
+
Copyright (c) 2017 Square Inc. Distributed under the Apache 2.0 License.
|
74
|
+
See LICENSE file for further details.
|
data/Rakefile
ADDED
data/etre-client.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'etre-client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'etre-client'
|
8
|
+
spec.version = Etre::Client::VERSION
|
9
|
+
spec.version = '0.8.0'
|
10
|
+
spec.license = 'Apache-2.0'
|
11
|
+
spec.authors = ['Michael Finch']
|
12
|
+
spec.email = ['mfinch@squareup.com']
|
13
|
+
spec.summary = 'Client gem for interacting with Etre'
|
14
|
+
spec.homepage = 'https://github.com/square/etre-client-ruby'
|
15
|
+
spec.required_ruby_version = '>= 2.3.0'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'json'
|
22
|
+
spec.add_runtime_dependency 'rest-client', '~> 2.0'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'rake', '~> 12.2', '>= 12.2.0'
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
|
+
end
|
data/lib/etre-client.rb
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
require 'etre-client/errors'
|
2
|
+
require 'rest-client'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Etre
|
6
|
+
class Client
|
7
|
+
attr_reader :entity_type, :url
|
8
|
+
|
9
|
+
API_ROOT = "/api/v1"
|
10
|
+
META_LABEL_ID = "_id"
|
11
|
+
META_LABEL_TYPE = "_type"
|
12
|
+
|
13
|
+
def initialize(entity_type:, url:, ssl_cert: nil, ssl_key: nil, ssl_ca: nil, insecure: true)
|
14
|
+
@entity_type = entity_type
|
15
|
+
@url = url
|
16
|
+
|
17
|
+
@ssl_cert = ssl_cert
|
18
|
+
@ssl_key = ssl_key
|
19
|
+
@ssl_ca = ssl_ca
|
20
|
+
@insecure = insecure
|
21
|
+
end
|
22
|
+
|
23
|
+
# query returns an array of entities that satisfy a query.
|
24
|
+
def query(query, filter = nil)
|
25
|
+
if query.nil? || query.empty?
|
26
|
+
raise QueryNotProvided
|
27
|
+
end
|
28
|
+
|
29
|
+
# @todo: translate filter to query params
|
30
|
+
|
31
|
+
# Do the normal GET /entities?query unless the query is ~2k characters
|
32
|
+
# becuase that brings the entire URL length close to the max supported
|
33
|
+
# limit across most HTTP servers. In that case, switch to alternate
|
34
|
+
# endpoint to POST the long query.
|
35
|
+
if query.length < 2000
|
36
|
+
# Always escape the query.
|
37
|
+
query = CGI::escape(query)
|
38
|
+
|
39
|
+
resp = etre_get("/entities/#{@entity_type}?query=#{query}")
|
40
|
+
else
|
41
|
+
# DO NOT ESCAPE THE QUERY! It's not sent via URL, so no escaping needed.
|
42
|
+
resp = etre_post("/query/#{@entity_type}", query)
|
43
|
+
end
|
44
|
+
|
45
|
+
if resp.code != 200
|
46
|
+
raise UnexpectedResponseCode, "expected 200, got #{resp.code}"
|
47
|
+
end
|
48
|
+
|
49
|
+
return JSON.parse(resp.body)
|
50
|
+
end
|
51
|
+
|
52
|
+
# insert inserts an array of entities.
|
53
|
+
def insert(entities)
|
54
|
+
if entities.nil? || !entities.any?
|
55
|
+
raise EntityNotProvided
|
56
|
+
end
|
57
|
+
|
58
|
+
entities.each do |e|
|
59
|
+
if e.key?(META_LABEL_ID)
|
60
|
+
raise EntityIdSet, "entity: #{e}"
|
61
|
+
end
|
62
|
+
|
63
|
+
if e.key?(META_LABEL_TYPE) && e[META_LABEL_TYPE] != @entity_type
|
64
|
+
raise EntityTypeMismatch, "only valid type is '#{@entity_type}', but " +
|
65
|
+
"entity has type '#{e[META_LABEL_TYPE]}'"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
resp = etre_post("/entities/#{@entity_type}", entities)
|
70
|
+
if ![200, 201].include?(resp.code)
|
71
|
+
raise UnexpectedResponseCode, "expected 200 or 201, got #{resp.code}"
|
72
|
+
end
|
73
|
+
|
74
|
+
return JSON.parse(resp.body)
|
75
|
+
end
|
76
|
+
|
77
|
+
# update updates entities with the given patch that satisfy the given query.
|
78
|
+
def update(query, patch)
|
79
|
+
if query.nil? || query.empty?
|
80
|
+
raise QueryNotProvided
|
81
|
+
end
|
82
|
+
|
83
|
+
# Always escape the query.
|
84
|
+
query = CGI::escape(query)
|
85
|
+
|
86
|
+
if patch.nil? || !patch.any?
|
87
|
+
raise PatchNotProvided
|
88
|
+
end
|
89
|
+
|
90
|
+
if patch.key?(META_LABEL_ID)
|
91
|
+
raise PatchIdSet, "patch: #{patch}"
|
92
|
+
end
|
93
|
+
|
94
|
+
if patch.key?(META_LABEL_TYPE) && patch[META_LABEL_TYPE] != @entity_type
|
95
|
+
raise EntityTypeMismatch, "only valid type is '#{@entity_type}', but " +
|
96
|
+
"patch has type '#{patch[META_LABEL_TYPE]}'"
|
97
|
+
end
|
98
|
+
|
99
|
+
resp = etre_put("/entities/#{@entity_type}?query=#{query}", patch)
|
100
|
+
if ![200, 201].include?(resp.code)
|
101
|
+
raise UnexpectedResponseCode, "expected 200 or 201, got #{resp.code}"
|
102
|
+
end
|
103
|
+
|
104
|
+
return JSON.parse(resp.body)
|
105
|
+
end
|
106
|
+
|
107
|
+
# update_one updates the given entity id with the provided patch.
|
108
|
+
def update_one(id, patch)
|
109
|
+
if id.nil? || id.empty?
|
110
|
+
raise IdNotProvided
|
111
|
+
end
|
112
|
+
|
113
|
+
if patch.nil? || !patch.any?
|
114
|
+
raise PatchNotProvided
|
115
|
+
end
|
116
|
+
|
117
|
+
if patch.key?(META_LABEL_ID)
|
118
|
+
raise PatchIdSet, "patch: #{patch}"
|
119
|
+
end
|
120
|
+
|
121
|
+
if patch.key?(META_LABEL_TYPE) && patch[META_LABEL_TYPE] != @entity_type
|
122
|
+
raise EntityTypeMismatch, "only valid type is '#{@entity_type}', but " +
|
123
|
+
"patch has type '#{patch[META_LABEL_TYPE]}'"
|
124
|
+
end
|
125
|
+
|
126
|
+
resp = etre_put("/entity/#{@entity_type}/#{id}", patch)
|
127
|
+
if ![200, 201].include?(resp.code)
|
128
|
+
raise UnexpectedResponseCode, "expected 200 or 201, got #{resp.code}"
|
129
|
+
end
|
130
|
+
|
131
|
+
return JSON.parse(resp.body)
|
132
|
+
end
|
133
|
+
|
134
|
+
# delete deletes the entities that satisfy the given query.
|
135
|
+
def delete(query)
|
136
|
+
if query.nil? || query.empty?
|
137
|
+
raise QueryNotProvided
|
138
|
+
end
|
139
|
+
|
140
|
+
# Always escape the query.
|
141
|
+
query = CGI::escape(query)
|
142
|
+
|
143
|
+
resp = etre_delete("/entities/#{@entity_type}?query=#{query}")
|
144
|
+
if resp.code != 200
|
145
|
+
raise UnexpectedResponseCode, "expected 200, got #{resp.code}"
|
146
|
+
end
|
147
|
+
|
148
|
+
return JSON.parse(resp.body)
|
149
|
+
end
|
150
|
+
|
151
|
+
# delete_one deletes the entity with the given id.
|
152
|
+
def delete_one(id)
|
153
|
+
if id.nil? || id.empty?
|
154
|
+
raise IdNotProvided
|
155
|
+
end
|
156
|
+
|
157
|
+
resp = etre_delete("/entity/#{@entity_type}/#{id}")
|
158
|
+
if resp.code != 200
|
159
|
+
raise UnexpectedResponseCode, "expected 200, got #{resp.code}"
|
160
|
+
end
|
161
|
+
|
162
|
+
return JSON.parse(resp.body)
|
163
|
+
end
|
164
|
+
|
165
|
+
# labels returns an array of labels for the given entity id.
|
166
|
+
def labels(id)
|
167
|
+
if id.nil? || id.empty?
|
168
|
+
raise IdNotProvided
|
169
|
+
end
|
170
|
+
|
171
|
+
resp = etre_get("/entity/#{@entity_type}/#{id}/labels")
|
172
|
+
|
173
|
+
if resp.code != 200
|
174
|
+
raise UnexpectedResponseCode, "expected 200, got #{resp.code}"
|
175
|
+
end
|
176
|
+
|
177
|
+
return JSON.parse(resp.body)
|
178
|
+
end
|
179
|
+
|
180
|
+
# delete_label deletes the given label on the provided entity id.
|
181
|
+
def delete_label(id, label)
|
182
|
+
if id.nil? || id.empty?
|
183
|
+
raise IdNotProvided
|
184
|
+
end
|
185
|
+
|
186
|
+
if label.nil? || label.empty?
|
187
|
+
raise LabelNotSet
|
188
|
+
end
|
189
|
+
|
190
|
+
resp = etre_delete("/entity/#{@entity_type}/#{id}/labels/#{label}")
|
191
|
+
if resp.code != 200
|
192
|
+
raise UnexpectedResponseCode, "expected 200, got #{resp.code}"
|
193
|
+
end
|
194
|
+
|
195
|
+
return JSON.parse(resp.body)
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
def etre_get(route)
|
201
|
+
resource_for_route(route).get(
|
202
|
+
get_headers,
|
203
|
+
)
|
204
|
+
end
|
205
|
+
|
206
|
+
def etre_post(route, params = nil)
|
207
|
+
resource_for_route(route).post(
|
208
|
+
params.to_json,
|
209
|
+
post_headers,
|
210
|
+
)
|
211
|
+
end
|
212
|
+
|
213
|
+
def etre_put(route, params = nil)
|
214
|
+
resource_for_route(route).put(
|
215
|
+
params.to_json,
|
216
|
+
put_headers,
|
217
|
+
)
|
218
|
+
end
|
219
|
+
|
220
|
+
def etre_delete(route)
|
221
|
+
resource_for_route(route).delete(
|
222
|
+
delete_headers,
|
223
|
+
)
|
224
|
+
end
|
225
|
+
|
226
|
+
def get_headers
|
227
|
+
{:accept => 'application/json'}
|
228
|
+
end
|
229
|
+
|
230
|
+
def post_headers
|
231
|
+
get_headers.merge!(:content_type => 'application/json')
|
232
|
+
end
|
233
|
+
|
234
|
+
def put_headers
|
235
|
+
post_headers
|
236
|
+
end
|
237
|
+
|
238
|
+
def delete_headers
|
239
|
+
get_headers
|
240
|
+
end
|
241
|
+
|
242
|
+
def resource_for_route(route)
|
243
|
+
opts = {}
|
244
|
+
opts.merge!(ssl_options) unless @insecure
|
245
|
+
RestClient::Resource.new(
|
246
|
+
@url + API_ROOT + route,
|
247
|
+
opts
|
248
|
+
)
|
249
|
+
end
|
250
|
+
|
251
|
+
def ssl_options
|
252
|
+
{
|
253
|
+
:ssl_client_cert => OpenSSL::X509::Certificate.new(File.read(@ssl_cert)),
|
254
|
+
:ssl_client_key => OpenSSL::PKey::RSA.new(File.read(@ssl_key)),
|
255
|
+
:ssl_ca_file => @ssl_ca,
|
256
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_PEER,
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
def parse_response(response)
|
261
|
+
JSON.parse(response)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Etre
|
2
|
+
class Client
|
3
|
+
class EntityIdSet < StandardError; end
|
4
|
+
class EntityNotProvided < StandardError; end
|
5
|
+
class EntityTypeMismatch < StandardError; end
|
6
|
+
class IdNotProvided < StandardError; end
|
7
|
+
class LabelNotSet < StandardError; end
|
8
|
+
class PatchIdSet < StandardError; end
|
9
|
+
class PatchNotProvided < StandardError; end
|
10
|
+
class QueryNotProvided < StandardError; end
|
11
|
+
class UnexpectedResponseCode < StandardError; end
|
12
|
+
end
|
13
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,328 @@
|
|
1
|
+
require 'etre-client'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe Etre::Client do
|
5
|
+
let(:etre_client) { Etre::Client.new(entity_type: "node", url: "http://localhost:3000", insecure: true) }
|
6
|
+
let(:get_headers) { {:accept => "application/json"} }
|
7
|
+
let(:post_headers) { get_headers.merge({:content_type => "application/json"}) }
|
8
|
+
let(:put_headers) { post_headers }
|
9
|
+
let(:delete_headers) { get_headers }
|
10
|
+
let(:migration_id) { 3 }
|
11
|
+
let(:cluster) { "cluster-001" }
|
12
|
+
let(:entity1) { {"_id" => "abc", "foo" => "bar"} }
|
13
|
+
let(:entity2) { {"oof" => "rab"} }
|
14
|
+
let(:entity3) { {"blah" => "slug"} }
|
15
|
+
let(:entity4) { {"_type" => "host", "a" => "b"} }
|
16
|
+
let(:response_double) { instance_double(RestClient::Response) }
|
17
|
+
let(:resource_double) { instance_double(RestClient::Resource) }
|
18
|
+
|
19
|
+
describe '#query' do
|
20
|
+
it "makes GET request when query is short" do
|
21
|
+
q = "foo=bar"
|
22
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entities/#{etre_client.entity_type}?query=#{CGI::escape(q)}"
|
23
|
+
|
24
|
+
expect(response_double).to receive(:code).and_return(200)
|
25
|
+
expect(response_double).to receive(:body).and_return([entity1].to_json)
|
26
|
+
expect(resource_double).to receive(:get).with(get_headers).and_return(response_double)
|
27
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
28
|
+
expect(etre_client.query(q)).to eq([entity1])
|
29
|
+
end
|
30
|
+
|
31
|
+
it "makes POST request when query is too long" do
|
32
|
+
q = "foo=bar," * 300
|
33
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/query/#{etre_client.entity_type}"
|
34
|
+
|
35
|
+
expect(response_double).to receive(:code).and_return(200)
|
36
|
+
expect(response_double).to receive(:body).and_return([entity1].to_json)
|
37
|
+
expect(resource_double).to receive(:post).with(q.to_json, post_headers).and_return(response_double)
|
38
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
39
|
+
expect(etre_client.query(q)).to eq([entity1])
|
40
|
+
end
|
41
|
+
|
42
|
+
it "raises if query is empty" do
|
43
|
+
q = ""
|
44
|
+
|
45
|
+
expect{etre_client.query(q)}.to raise_error(Etre::Client::QueryNotProvided)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "raises if it gets an unexpected response code" do
|
49
|
+
q = "foo=bar"
|
50
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entities/#{etre_client.entity_type}?query=#{CGI::escape(q)}"
|
51
|
+
|
52
|
+
expect(response_double).to receive(:code).twice.and_return(400)
|
53
|
+
expect(resource_double).to receive(:get).with(get_headers).and_return(response_double)
|
54
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
55
|
+
expect{etre_client.query(q)}.to raise_error(Etre::Client::UnexpectedResponseCode)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#insert" do
|
60
|
+
before :each do
|
61
|
+
@path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entities/#{etre_client.entity_type}"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "inserts entities" do
|
65
|
+
entities = [entity2, entity3]
|
66
|
+
|
67
|
+
expect(response_double).to receive(:code).and_return(200)
|
68
|
+
expect(response_double).to receive(:body).and_return(entities.to_json)
|
69
|
+
expect(resource_double).to receive(:post).with(entities.to_json, post_headers).and_return(response_double)
|
70
|
+
expect(RestClient::Resource).to receive(:new).with(@path, {}).and_return(resource_double)
|
71
|
+
expect(etre_client.insert(entities)).to eq(entities)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "raises if an entity has _id set" do
|
75
|
+
entities = [entity1, entity2]
|
76
|
+
|
77
|
+
expect{etre_client.insert(entities)}.to raise_error(Etre::Client::EntityIdSet)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "raises if an entity has the wrong _type set" do
|
81
|
+
entities = [entity2, entity4]
|
82
|
+
|
83
|
+
expect{etre_client.insert(entities)}.to raise_error(Etre::Client::EntityTypeMismatch)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "raises if it gets an unexpected response code" do
|
87
|
+
entities = [entity2, entity3]
|
88
|
+
|
89
|
+
expect(response_double).to receive(:code).twice.and_return(400)
|
90
|
+
expect(resource_double).to receive(:post).with(entities.to_json, post_headers).and_return(response_double)
|
91
|
+
expect(RestClient::Resource).to receive(:new).with(@path, {}).and_return(resource_double)
|
92
|
+
expect{etre_client.insert(entities)}.to raise_error(Etre::Client::UnexpectedResponseCode)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#update" do
|
97
|
+
it "updates entities" do
|
98
|
+
query = "foo=bar"
|
99
|
+
patch = {"foo" => "new"}
|
100
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entities/#{etre_client.entity_type}?query=#{CGI::escape(query)}"
|
101
|
+
|
102
|
+
expect(response_double).to receive(:code).and_return(200)
|
103
|
+
expect(response_double).to receive(:body).and_return({}.to_json)
|
104
|
+
expect(resource_double).to receive(:put).with(patch.to_json, put_headers).and_return(response_double)
|
105
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
106
|
+
expect(etre_client.update(query, patch)).to eq({})
|
107
|
+
end
|
108
|
+
|
109
|
+
it "raises if query is empty" do
|
110
|
+
query = ""
|
111
|
+
patch = {"foo" => "new"}
|
112
|
+
|
113
|
+
expect{etre_client.update(query, patch)}.to raise_error(Etre::Client::QueryNotProvided)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "raises if patch is empty" do
|
117
|
+
query = "foo=bar"
|
118
|
+
patch = {}
|
119
|
+
|
120
|
+
expect{etre_client.update(query, patch)}.to raise_error(Etre::Client::PatchNotProvided)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "raises if _id is set in patch" do
|
124
|
+
query = "foo=bar"
|
125
|
+
patch = {"_id" => "abc"}
|
126
|
+
|
127
|
+
expect{etre_client.update(query, patch)}.to raise_error(Etre::Client::PatchIdSet)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "raises if patch has the wrong _type set" do
|
131
|
+
query = "foo=bar"
|
132
|
+
patch = {"_type" => "host"}
|
133
|
+
|
134
|
+
expect{etre_client.update(query, patch)}.to raise_error(Etre::Client::EntityTypeMismatch)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "raises if it gets an unexpected response code" do
|
138
|
+
query = "foo=bar"
|
139
|
+
patch = {"foo" => "new"}
|
140
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entities/#{etre_client.entity_type}?query=#{CGI::escape(query)}"
|
141
|
+
|
142
|
+
expect(response_double).to receive(:code).twice.and_return(400)
|
143
|
+
expect(resource_double).to receive(:put).with(patch.to_json, put_headers).and_return(response_double)
|
144
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
145
|
+
expect{etre_client.update(query, patch)}.to raise_error(Etre::Client::UnexpectedResponseCode)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "#update_one" do
|
150
|
+
it "updates an entity" do
|
151
|
+
id = "abc"
|
152
|
+
patch = {"foo" => "new"}
|
153
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entity/#{etre_client.entity_type}/#{id}"
|
154
|
+
|
155
|
+
expect(response_double).to receive(:code).and_return(200)
|
156
|
+
expect(response_double).to receive(:body).and_return({}.to_json)
|
157
|
+
expect(resource_double).to receive(:put).with(patch.to_json, put_headers).and_return(response_double)
|
158
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
159
|
+
expect(etre_client.update_one(id, patch)).to eq({})
|
160
|
+
end
|
161
|
+
|
162
|
+
it "raises if id is empty" do
|
163
|
+
id = ""
|
164
|
+
patch = {"foo" => "new"}
|
165
|
+
|
166
|
+
expect{etre_client.update_one(id, patch)}.to raise_error(Etre::Client::IdNotProvided)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "raises if patch is empty" do
|
170
|
+
id = "abc"
|
171
|
+
patch = {}
|
172
|
+
|
173
|
+
expect{etre_client.update_one(id, patch)}.to raise_error(Etre::Client::PatchNotProvided)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "raises if _id is set in patch" do
|
177
|
+
id = "abc"
|
178
|
+
patch = {"_id" => "abc"}
|
179
|
+
|
180
|
+
expect{etre_client.update_one(id, patch)}.to raise_error(Etre::Client::PatchIdSet)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "raises if patch has the wrong _type set" do
|
184
|
+
id = "abc"
|
185
|
+
patch = {"_type" => "host"}
|
186
|
+
|
187
|
+
expect{etre_client.update_one(id, patch)}.to raise_error(Etre::Client::EntityTypeMismatch)
|
188
|
+
end
|
189
|
+
|
190
|
+
it "raises if it gets an unexpected response code" do
|
191
|
+
id = "abc"
|
192
|
+
patch = {"foo" => "new"}
|
193
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entity/#{etre_client.entity_type}/#{id}"
|
194
|
+
|
195
|
+
expect(response_double).to receive(:code).twice.and_return(400)
|
196
|
+
expect(resource_double).to receive(:put).with(patch.to_json, put_headers).and_return(response_double)
|
197
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
198
|
+
expect{etre_client.update_one(id, patch)}.to raise_error(Etre::Client::UnexpectedResponseCode)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe "#delete" do
|
203
|
+
it "deletes entities" do
|
204
|
+
query = "foo=bar"
|
205
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entities/#{etre_client.entity_type}?query=#{CGI::escape(query)}"
|
206
|
+
|
207
|
+
expect(response_double).to receive(:code).and_return(200)
|
208
|
+
expect(response_double).to receive(:body).and_return({}.to_json)
|
209
|
+
expect(resource_double).to receive(:delete).with(delete_headers).and_return(response_double)
|
210
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
211
|
+
expect(etre_client.delete(query)).to eq({})
|
212
|
+
end
|
213
|
+
|
214
|
+
it "raises if query is empty" do
|
215
|
+
query = ""
|
216
|
+
|
217
|
+
expect{etre_client.delete(query)}.to raise_error(Etre::Client::QueryNotProvided)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "raises if it gets an unexpected response code" do
|
221
|
+
query = "foo=bar"
|
222
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entities/#{etre_client.entity_type}?query=#{CGI::escape(query)}"
|
223
|
+
|
224
|
+
expect(response_double).to receive(:code).twice.and_return(400)
|
225
|
+
expect(resource_double).to receive(:delete).with(delete_headers).and_return(response_double)
|
226
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
227
|
+
expect{etre_client.delete(query)}.to raise_error(Etre::Client::UnexpectedResponseCode)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe "#delete_one" do
|
232
|
+
it "deletes an entity" do
|
233
|
+
id = "abc"
|
234
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entity/#{etre_client.entity_type}/#{id}"
|
235
|
+
|
236
|
+
expect(response_double).to receive(:code).and_return(200)
|
237
|
+
expect(response_double).to receive(:body).and_return({}.to_json)
|
238
|
+
expect(resource_double).to receive(:delete).with(delete_headers).and_return(response_double)
|
239
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
240
|
+
expect(etre_client.delete_one(id)).to eq({})
|
241
|
+
end
|
242
|
+
|
243
|
+
it "raises if id is empty" do
|
244
|
+
id = ""
|
245
|
+
|
246
|
+
expect{etre_client.delete_one(id)}.to raise_error(Etre::Client::IdNotProvided)
|
247
|
+
end
|
248
|
+
|
249
|
+
it "raises if it gets an unexpected response code" do
|
250
|
+
id = "abc"
|
251
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entity/#{etre_client.entity_type}/#{id}"
|
252
|
+
|
253
|
+
expect(response_double).to receive(:code).twice.and_return(400)
|
254
|
+
expect(resource_double).to receive(:delete).with(delete_headers).and_return(response_double)
|
255
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
256
|
+
expect{etre_client.delete_one(id)}.to raise_error(Etre::Client::UnexpectedResponseCode)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe "#labels" do
|
261
|
+
it "lists the lables for an entity" do
|
262
|
+
id = "abc"
|
263
|
+
labels = ["foo1", "foo2"]
|
264
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entity/#{etre_client.entity_type}/#{id}/labels"
|
265
|
+
|
266
|
+
expect(response_double).to receive(:code).and_return(200)
|
267
|
+
expect(response_double).to receive(:body).and_return(labels.to_json)
|
268
|
+
expect(resource_double).to receive(:get).with(get_headers).and_return(response_double)
|
269
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
270
|
+
expect(etre_client.labels(id)).to eq(labels)
|
271
|
+
end
|
272
|
+
|
273
|
+
it "raises if id is empty" do
|
274
|
+
id = ""
|
275
|
+
|
276
|
+
expect{etre_client.labels(id)}.to raise_error(Etre::Client::IdNotProvided)
|
277
|
+
end
|
278
|
+
|
279
|
+
it "raises if it gets an unexpected response code" do
|
280
|
+
id = "abc"
|
281
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entity/#{etre_client.entity_type}/#{id}/labels"
|
282
|
+
|
283
|
+
expect(response_double).to receive(:code).twice.and_return(400)
|
284
|
+
expect(resource_double).to receive(:get).with(get_headers).and_return(response_double)
|
285
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
286
|
+
expect{etre_client.labels(id)}.to raise_error(Etre::Client::UnexpectedResponseCode)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe "#delete_label" do
|
291
|
+
it "deletes the label on an entity" do
|
292
|
+
id = "abc"
|
293
|
+
label = "foo"
|
294
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entity/#{etre_client.entity_type}/#{id}/labels/#{label}"
|
295
|
+
|
296
|
+
expect(response_double).to receive(:code).and_return(200)
|
297
|
+
expect(response_double).to receive(:body).and_return({}.to_json)
|
298
|
+
expect(resource_double).to receive(:delete).with(delete_headers).and_return(response_double)
|
299
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
300
|
+
expect(etre_client.delete_label(id, label)).to eq({})
|
301
|
+
end
|
302
|
+
|
303
|
+
it "raises if id is empty" do
|
304
|
+
id = ""
|
305
|
+
label = "foo"
|
306
|
+
|
307
|
+
expect{etre_client.delete_label(id, label)}.to raise_error(Etre::Client::IdNotProvided)
|
308
|
+
end
|
309
|
+
|
310
|
+
it "raises if label is empty" do
|
311
|
+
id = ""
|
312
|
+
label = ""
|
313
|
+
|
314
|
+
expect{etre_client.delete_label(id, label)}.to raise_error(Etre::Client::IdNotProvided)
|
315
|
+
end
|
316
|
+
|
317
|
+
it "raises if it gets an unexpected response code" do
|
318
|
+
id = "abc"
|
319
|
+
label = "foo"
|
320
|
+
path = "#{etre_client.url}#{Etre::Client::API_ROOT}/entity/#{etre_client.entity_type}/#{id}/labels/#{label}"
|
321
|
+
|
322
|
+
expect(response_double).to receive(:code).twice.and_return(400)
|
323
|
+
expect(resource_double).to receive(:delete).with(delete_headers).and_return(response_double)
|
324
|
+
expect(RestClient::Resource).to receive(:new).with(path, {}).and_return(resource_double)
|
325
|
+
expect{etre_client.delete_label(id, label)}.to raise_error(Etre::Client::UnexpectedResponseCode)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
data/spec/unit_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: etre-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Finch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-10-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '12.2'
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 12.2.0
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '12.2'
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 12.2.0
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.0'
|
75
|
+
description:
|
76
|
+
email:
|
77
|
+
- mfinch@squareup.com
|
78
|
+
executables: []
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- ".gitignore"
|
83
|
+
- Gemfile
|
84
|
+
- Gemfile.lock
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- etre-client.gemspec
|
88
|
+
- lib/etre-client.rb
|
89
|
+
- lib/etre-client/errors.rb
|
90
|
+
- lib/etre-client/version.rb
|
91
|
+
- spec/client_spec.rb
|
92
|
+
- spec/unit_helper.rb
|
93
|
+
homepage: https://github.com/square/etre-client-ruby
|
94
|
+
licenses:
|
95
|
+
- Apache-2.0
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: 2.3.0
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.5.2
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: Client gem for interacting with Etre
|
117
|
+
test_files:
|
118
|
+
- spec/client_spec.rb
|
119
|
+
- spec/unit_helper.rb
|