orchestrate 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +64 -27
- data/lib/orchestrate.rb +6 -1
- data/lib/orchestrate/api.rb +1 -0
- data/lib/orchestrate/api/errors.rb +3 -1
- data/lib/orchestrate/api/helpers.rb +1 -0
- data/lib/orchestrate/api/response.rb +43 -10
- data/lib/orchestrate/application.rb +55 -0
- data/lib/orchestrate/client.rb +5 -24
- data/lib/orchestrate/collection.rb +310 -0
- data/lib/orchestrate/key_value.rb +232 -0
- data/lib/orchestrate/version.rb +2 -1
- data/orchestrate.gemspec +1 -1
- data/test/orchestrate/api/{collections_test.rb → collections_api_test.rb} +1 -1
- data/test/orchestrate/api/exceptions_test.rb +9 -55
- data/test/orchestrate/api/{key_value_test.rb → key_value_api_test.rb} +1 -1
- data/test/orchestrate/application_test.rb +44 -0
- data/test/orchestrate/client_test.rb +19 -17
- data/test/orchestrate/collection_enumeration_test.rb +116 -0
- data/test/orchestrate/collection_kv_accessors_test.rb +145 -0
- data/test/orchestrate/collection_test.rb +63 -0
- data/test/orchestrate/key_value_persistence_test.rb +161 -0
- data/test/orchestrate/key_value_test.rb +116 -0
- data/test/test_helper.rb +134 -8
- metadata +24 -15
@@ -0,0 +1,63 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CollectionTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_instantiates_with_app_and_name
|
6
|
+
app, stubs = make_application
|
7
|
+
users = Orchestrate::Collection.new(app, :users)
|
8
|
+
assert_equal app, users.app
|
9
|
+
assert_equal 'users', users.name
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_instantiates_with_client_and_name
|
13
|
+
client, stubs = make_client_and_artifacts
|
14
|
+
stubs.head("/v0") { [200, response_headers, ''] }
|
15
|
+
users = Orchestrate::Collection.new(client, :users)
|
16
|
+
assert_equal client, users.app.client
|
17
|
+
assert_equal 'users', users.name
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_destroy
|
21
|
+
app, stubs = make_application
|
22
|
+
users = Orchestrate::Collection.new(app, :users)
|
23
|
+
stubs.delete("/v0/users") do |env|
|
24
|
+
assert_equal "true", env.params["force"]
|
25
|
+
[204, response_headers, '']
|
26
|
+
end
|
27
|
+
assert true, users.destroy!
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_equality
|
31
|
+
app, stubs = make_application
|
32
|
+
app2, stubs = make_application
|
33
|
+
items1 = app[:items]
|
34
|
+
items2 = app[:items]
|
35
|
+
other = app[:other]
|
36
|
+
assert_equal items1, items2
|
37
|
+
refute_equal items1, other
|
38
|
+
refute_equal items1, OpenStruct.new({name: 'items'})
|
39
|
+
refute_equal items1, 3
|
40
|
+
refute_equal items1, app2[:items]
|
41
|
+
|
42
|
+
assert items1.eql?(items2)
|
43
|
+
assert items2.eql?(items1)
|
44
|
+
refute items1.eql?(other)
|
45
|
+
refute other.eql?(items1)
|
46
|
+
refute items1.eql?(app2[:items])
|
47
|
+
|
48
|
+
# equal? is for object identity only
|
49
|
+
refute items1.equal?(items2)
|
50
|
+
refute other.equal?(items1)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_sorting
|
54
|
+
app, stubs = make_application
|
55
|
+
app2, stubs = make_application
|
56
|
+
assert_equal(-1, app[:users] <=> app[:items])
|
57
|
+
assert_equal 0, app[:items] <=> app[:items]
|
58
|
+
assert_equal 1, app[:items] <=> app[:users]
|
59
|
+
assert_nil 2 <=> app[:items]
|
60
|
+
assert_nil app2[:items] <=> app[:items]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class KeyValuePersistenceTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@app, @stubs = make_application
|
6
|
+
@items = @app[:items]
|
7
|
+
@kv = make_kv_item(@items, @stubs, :loaded => Time.now - 60)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_save_performs_put_if_match_and_returns_true_on_success
|
11
|
+
@kv[:foo] = "bar"
|
12
|
+
new_ref = nil
|
13
|
+
@stubs.put("/v0/items/#{@kv.key}") do |env|
|
14
|
+
assert_equal @kv.value, JSON.parse(env.body)
|
15
|
+
assert_header 'If-Match', "\"#{@kv.ref}\"", env
|
16
|
+
new_ref = make_ref
|
17
|
+
[ 201, response_headers({'Etag' => new_ref, "Location" => "/v0/items/#{@kv.key}/refs/#{new_ref}"}), '' ]
|
18
|
+
end
|
19
|
+
assert_equal true, @kv.save
|
20
|
+
assert_equal new_ref, @kv.ref
|
21
|
+
assert_in_delta Time.now.to_f, @kv.last_request_time.to_f, 1.1
|
22
|
+
assert_equal "bar", @kv[:foo]
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_save_performs_put_if_match_and_returns_false_on_version_mismatch
|
26
|
+
@stubs.put("/v0/items/#{@kv.key}") do |env|
|
27
|
+
assert_header 'If-Match', "\"#{@kv.ref}\"", env
|
28
|
+
error_response(:version_mismatch)
|
29
|
+
end
|
30
|
+
assert_equal false, @kv.save
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_save_performs_put_if_match_and_returns_true_on_indexing_conflict
|
34
|
+
ref = @kv.ref
|
35
|
+
@stubs.put("/v0/items/#{@kv.key}") do |env|
|
36
|
+
ref = make_ref
|
37
|
+
assert_header 'If-Match', "\"#{@kv.ref}\"", env
|
38
|
+
error_response(:indexing_conflict, {
|
39
|
+
headers: {"Location" => "/v0/items/#{@kv.key}/refs/#{ref}"},
|
40
|
+
conflicts_uri: "/v0/items/#{@kv.key}/refs/#{ref}/conflicts"
|
41
|
+
})
|
42
|
+
end
|
43
|
+
assert_equal true, @kv.save
|
44
|
+
assert_equal ref, @kv.ref
|
45
|
+
assert_in_delta Time.now.to_f, @kv.last_request_time.to_f, 1.1
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_save_returns_false_on_etc_errors
|
49
|
+
@stubs.put("/v0/items/#{@kv.key}") { error_response(:bad_request) }
|
50
|
+
assert_equal false, @kv.save
|
51
|
+
|
52
|
+
@stubs.put("/v0/items/#{@kv.key}") { error_response(:service_error) }
|
53
|
+
assert_equal false, @kv.save
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_save_bang_performs_put_if_match_doesnt_raise_on_success
|
57
|
+
@kv[:foo] = "bar"
|
58
|
+
ref = @kv.ref
|
59
|
+
@stubs.put("/v0/items/#{@kv.key}") do |env|
|
60
|
+
assert_equal @kv.value, JSON.parse(env.body)
|
61
|
+
assert_header 'If-Match', %|"#{ref}"|, env
|
62
|
+
ref = make_ref
|
63
|
+
[201, response_headers({'Etag'=>%|"#{ref}"|, 'Loation'=>"/v0/items/#{@kv.key}/refs/#{ref}"}), '']
|
64
|
+
end
|
65
|
+
@kv.save!
|
66
|
+
assert_equal ref, @kv.ref
|
67
|
+
assert_in_delta Time.now.to_f, @kv.last_request_time.to_f, 1.1
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_save_bang_performs_put_if_match_raises_on_version_mismatch
|
71
|
+
@stubs.put("/v0/items/#{@kv.key}") do |env|
|
72
|
+
assert_header "If-Match", %|"#{@kv.ref}"|, env
|
73
|
+
error_response(:version_mismatch)
|
74
|
+
end
|
75
|
+
assert_raises Orchestrate::API::VersionMismatch do
|
76
|
+
@kv.save!
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_save_bang_performs_put_if_match_doesnt_raise_on_indexing_conflict
|
81
|
+
ref = @kv.ref
|
82
|
+
@stubs.put("/v0/items/#{@kv.key}") do |env|
|
83
|
+
ref = make_ref
|
84
|
+
assert_header "If-Match", %|"#{@kv.ref}"|, env
|
85
|
+
error_response(:indexing_conflict, {
|
86
|
+
headers: {"Location" => "/v0/items/#{@kv.key}/refs/#{ref}"},
|
87
|
+
conflicts_uri: "/v0/items/#{@kv.key}/refs/#{ref}/conflicts"
|
88
|
+
})
|
89
|
+
end
|
90
|
+
@kv.save!
|
91
|
+
assert_equal ref, @kv.ref
|
92
|
+
assert_in_delta Time.now.to_f, @kv.last_request_time.to_f, 1.1
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_save_bang_performs_put_if_match_raises_on_request_error
|
96
|
+
@stubs.put("/v0/items/#{@kv.key}") do |env|
|
97
|
+
assert_header "If-Match", %|"#{@kv.ref}"|, env
|
98
|
+
error_response(:bad_request)
|
99
|
+
end
|
100
|
+
assert_raises Orchestrate::API::BadRequest do
|
101
|
+
@kv.save!
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_save_bang_performs_put_if_match_raises_on_service_error
|
106
|
+
@stubs.put("/v0/items/#{@kv.key}") { error_response(:service_error) }
|
107
|
+
assert_raises Orchestrate::API::ServiceError do
|
108
|
+
@kv.save!
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_destroy_performs_delete_if_match_and_returns_true_on_success
|
113
|
+
@stubs.delete("/v0/items/#{@kv.key}") do |env|
|
114
|
+
assert_header 'If-Match', "\"#{@kv.ref}\"", env
|
115
|
+
[204, response_headers, '']
|
116
|
+
end
|
117
|
+
assert_equal true, @kv.destroy
|
118
|
+
assert_nil @kv.ref
|
119
|
+
assert_in_delta Time.now.to_f, @kv.last_request_time.to_f, 1.1
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_destroy_performs_delete_if_match_and_returns_false_on_error
|
123
|
+
@stubs.delete("/v0/items/#{@kv.key}") { error_response(:version_mismatch) }
|
124
|
+
assert_equal false, @kv.destroy
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_destroy_bang_performs_delete_raises_on_error
|
128
|
+
@stubs.delete("/v0/items/#{@kv.key}") { error_response(:version_mismatch) }
|
129
|
+
assert_raises Orchestrate::API::VersionMismatch do
|
130
|
+
@kv.destroy!
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_purge_performs_purge_if_match_and_returns_true_on_success
|
135
|
+
@stubs.delete("/v0/items/#{@kv.key}") do |env|
|
136
|
+
assert_header 'If-Match', %|"#{@kv.ref}"|, env
|
137
|
+
assert_equal "true", env.params['purge']
|
138
|
+
[ 204, response_headers, '' ]
|
139
|
+
end
|
140
|
+
assert_equal true, @kv.purge
|
141
|
+
assert_nil @kv.ref
|
142
|
+
assert_in_delta Time.now.to_f, @kv.last_request_time.to_f, 1.1
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_purge_performs_purge_if_match_and_returns_false_on_error
|
146
|
+
@stubs.delete("/v0/items/#{@kv.key}") { error_response(:version_mismatch) }
|
147
|
+
assert_equal false, @kv.purge
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_purge_bang_performs_purge_if_match_and_raises_on_error
|
151
|
+
@stubs.delete("/v0/items/#{@kv.key}") do |env|
|
152
|
+
assert_header 'If-Match', %|"#{@kv.ref}"|, env
|
153
|
+
assert_equal "true", env.params['purge']
|
154
|
+
error_response(:version_mismatch)
|
155
|
+
end
|
156
|
+
assert_raises Orchestrate::API::VersionMismatch do
|
157
|
+
@kv.purge!
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class KeyValueTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_load_with_collection_and_key
|
6
|
+
app, stubs = make_application
|
7
|
+
items = app[:items]
|
8
|
+
ref = "123456"
|
9
|
+
body = {"hello" => "world"}
|
10
|
+
kv = make_kv_item(items, stubs, { key: "hello", ref: ref, body: body })
|
11
|
+
assert_equal "hello", kv.key
|
12
|
+
assert_equal ref, kv.ref
|
13
|
+
assert_equal "items/hello", kv.id
|
14
|
+
assert_equal body, kv.value
|
15
|
+
assert kv.loaded?
|
16
|
+
assert_in_delta Time.now.to_f, kv.last_request_time.to_f, 1.1
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_value_accessors
|
20
|
+
app, stubs = make_application
|
21
|
+
items = app[:items]
|
22
|
+
body = {"hello" => "world", "one" => "two"}
|
23
|
+
kv = make_kv_item(items, stubs, {body: body})
|
24
|
+
assert_equal body["hello"], kv["hello"]
|
25
|
+
assert_equal body["hello"], kv[:hello]
|
26
|
+
assert_equal body["one"], kv["one"]
|
27
|
+
assert_equal body["one"], kv[:one]
|
28
|
+
|
29
|
+
kv[:one] = 1
|
30
|
+
assert_equal 1, kv["one"]
|
31
|
+
kv[:two] = "Two"
|
32
|
+
assert_equal "Two", kv[:two]
|
33
|
+
kv["three"] = "Tres"
|
34
|
+
assert_equal "Tres", kv[:three]
|
35
|
+
kv["four"] = "IV"
|
36
|
+
assert_equal "IV", kv["four"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_instantiates_from_parallel_request
|
40
|
+
app, stubs = make_application({parallel: true})
|
41
|
+
items = app[:items]
|
42
|
+
body = {"hello" => "foo"}
|
43
|
+
ref = make_ref
|
44
|
+
stubs.get("/v0/items/foo") { [200, response_headers(ref_headers(:items, :foo, ref)), body.to_json] }
|
45
|
+
stubs.put("/v0/items/bar") { [201, response_headers(ref_headers(:items, :bar, make_ref)), ''] }
|
46
|
+
results = app.in_parallel do |r|
|
47
|
+
r[:foo] = items[:foo]
|
48
|
+
r[:bar] = items.create(:bar, {})
|
49
|
+
end
|
50
|
+
assert_equal 'foo', results[:foo].key
|
51
|
+
assert_equal ref, results[:foo].ref
|
52
|
+
assert_equal body, results[:foo].value
|
53
|
+
assert_equal 'bar', results[:bar].key
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_instantiates_without_loading
|
57
|
+
app, stubs = make_application
|
58
|
+
items = app[:items]
|
59
|
+
kv = Orchestrate::KeyValue.new(items, 'keyname')
|
60
|
+
assert_equal 'keyname', kv.key
|
61
|
+
assert_equal items, kv.collection
|
62
|
+
assert ! kv.loaded?
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_instantiates_from_collection_and_listing
|
66
|
+
app, stubs = make_application
|
67
|
+
listing = make_kv_listing('items', {key: "foo"})
|
68
|
+
kv = Orchestrate::KeyValue.new(app[:items], listing, Time.now)
|
69
|
+
assert_equal 'items', kv.collection_name
|
70
|
+
assert_equal "foo", kv.key
|
71
|
+
assert_equal listing['path']['ref'], kv.ref
|
72
|
+
assert_equal listing['value'], kv.value
|
73
|
+
assert_in_delta Time.at(listing['reftime'] / 1000), kv.reftime, 1.1
|
74
|
+
assert_in_delta Time.now.to_f, kv.last_request_time.to_f, 1.1
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_equality
|
78
|
+
app, stubs = make_application
|
79
|
+
app2, stubs = make_application
|
80
|
+
items = app[:items]
|
81
|
+
|
82
|
+
foo = Orchestrate::KeyValue.new(items, :foo)
|
83
|
+
|
84
|
+
assert_equal foo, Orchestrate::KeyValue.new(items, :foo)
|
85
|
+
refute_equal foo, Orchestrate::KeyValue.new(items, :bar)
|
86
|
+
refute_equal foo, Orchestrate::KeyValue.new(app[:users], :foo)
|
87
|
+
refute_equal foo, Orchestrate::KeyValue.new(app2[:items], :foo)
|
88
|
+
refute_equal foo, :foo
|
89
|
+
|
90
|
+
assert foo.eql?(Orchestrate::KeyValue.new(items, :foo))
|
91
|
+
refute foo.eql?(Orchestrate::KeyValue.new(items, :bar))
|
92
|
+
refute foo.eql?(Orchestrate::KeyValue.new(app[:users], :foo))
|
93
|
+
refute foo.eql?(Orchestrate::KeyValue.new(app2[:items], :foo))
|
94
|
+
refute foo.eql?(:foo)
|
95
|
+
|
96
|
+
# equal? is for Object equality
|
97
|
+
assert foo.equal?(foo)
|
98
|
+
refute foo.equal?(Orchestrate::KeyValue.new(items, :foo))
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_sorting
|
102
|
+
app, stubs = make_application
|
103
|
+
app2, stubs = make_application
|
104
|
+
|
105
|
+
foo = Orchestrate::KeyValue.new(app[:items], :foo)
|
106
|
+
|
107
|
+
assert_equal(-1, foo <=> Orchestrate::KeyValue.new(app[:items], :bar))
|
108
|
+
assert_equal 0, foo <=> Orchestrate::KeyValue.new(app[:items], :foo)
|
109
|
+
assert_equal 1, foo <=> Orchestrate::KeyValue.new(app[:items], :zoo)
|
110
|
+
assert_nil foo <=> Orchestrate::KeyValue.new(app[:users], :foo)
|
111
|
+
assert_nil foo <=> Orchestrate::KeyValue.new(app2[:items], :foo)
|
112
|
+
assert_nil foo <=> :foo
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
data/test/test_helper.rb
CHANGED
@@ -7,6 +7,37 @@ require "securerandom"
|
|
7
7
|
require "time"
|
8
8
|
require "logger"
|
9
9
|
|
10
|
+
class ParallelTest < Faraday::Adapter::Test
|
11
|
+
self.supports_parallel = true
|
12
|
+
extend Faraday::Adapter::Parallelism
|
13
|
+
|
14
|
+
class Manager
|
15
|
+
def initialize
|
16
|
+
@queue = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def queue(env)
|
20
|
+
@queue.push(env)
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
@queue.each {|env| env[:response].finish(env) unless env[:response].finished? }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.setup_parallel_manager(options={})
|
29
|
+
@mgr ||= Manager.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(env)
|
33
|
+
super(env)
|
34
|
+
env[:parallel_manager].queue(env) if env[:parallel_manager]
|
35
|
+
env[:response]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Faraday::Adapter.register_middleware :parallel_test => :ParallelTest
|
40
|
+
|
10
41
|
# Test Helpers ---------------------------------------------------------------
|
11
42
|
|
12
43
|
def output_message(name, msg = nil)
|
@@ -15,17 +46,59 @@ end
|
|
15
46
|
|
16
47
|
# TODO this is a bit messy for now at least but there's a bunch of
|
17
48
|
# intermediate state we'd have to deal with in a bunch of other places
|
18
|
-
def make_client_and_artifacts
|
49
|
+
def make_client_and_artifacts(parallel=false)
|
19
50
|
api_key = SecureRandom.hex(24)
|
20
51
|
basic_auth = "Basic #{Base64.encode64("#{api_key}:").gsub(/\n/,'')}"
|
21
52
|
stubs = Faraday::Adapter::Test::Stubs.new
|
22
53
|
client = Orchestrate::Client.new(api_key) do |f|
|
23
|
-
|
54
|
+
if parallel
|
55
|
+
f.adapter :parallel_test, stubs
|
56
|
+
else
|
57
|
+
f.adapter :test, stubs
|
58
|
+
end
|
24
59
|
f.response :logger, Logger.new(File.join(File.dirname(__FILE__), "test.log"))
|
25
60
|
end
|
26
61
|
[client, stubs, basic_auth]
|
27
62
|
end
|
28
63
|
|
64
|
+
def ref_headers(coll, key, ref)
|
65
|
+
{'Etag' => %|"#{ref}"|, 'Location' => "/v0/#{coll}/#{key}/refs/#{ref}"}
|
66
|
+
end
|
67
|
+
|
68
|
+
def make_application(opts={})
|
69
|
+
client, stubs = make_client_and_artifacts(opts[:parallel])
|
70
|
+
stubs.head("/v0") { [200, response_headers, ''] }
|
71
|
+
app = Orchestrate::Application.new(client)
|
72
|
+
[app, stubs]
|
73
|
+
end
|
74
|
+
|
75
|
+
def make_ref
|
76
|
+
SecureRandom.hex(16)
|
77
|
+
end
|
78
|
+
|
79
|
+
def make_kv_item(collection, stubs, opts={})
|
80
|
+
key = opts[:key] || 'hello'
|
81
|
+
ref = opts[:ref] || "12345"
|
82
|
+
body = opts[:body] || {"hello" => "world"}
|
83
|
+
res_headers = response_headers({
|
84
|
+
'Etag' => "\"#{ref}\"",
|
85
|
+
'Content-Location' => "/v0/#{collection.name}/#{key}/refs/#{ref}"
|
86
|
+
})
|
87
|
+
stubs.get("/v0/items/#{key}") { [200, res_headers, body.to_json] }
|
88
|
+
kv = Orchestrate::KeyValue.load(collection, key)
|
89
|
+
kv.instance_variable_set(:@last_request_time, opts[:loaded]) if opts[:loaded]
|
90
|
+
kv
|
91
|
+
end
|
92
|
+
|
93
|
+
def make_kv_listing(collection, opts={})
|
94
|
+
key = opts[:key] || "item-#{rand(1_000_000)}"
|
95
|
+
ref = opts[:ref] || make_ref
|
96
|
+
reftime = opts[:reftime] || Time.now.to_f - (rand(24) * 3600_000)
|
97
|
+
body = opts[:body] || {"key" => key}
|
98
|
+
{ "path" => { "collection" => collection, "key" => key, "ref" => ref },
|
99
|
+
"reftime" => reftime, "value" => body }
|
100
|
+
end
|
101
|
+
|
29
102
|
def capture_warnings
|
30
103
|
old, $stderr = $stderr, StringIO.new
|
31
104
|
begin
|
@@ -50,12 +123,65 @@ def chunked_encoding_header
|
|
50
123
|
end
|
51
124
|
|
52
125
|
def response_not_found(items)
|
53
|
-
{ "message" => "The requested items could not be found.",
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
}.to_json
|
126
|
+
{ "message" => "The requested items could not be found.",
|
127
|
+
"details" => {
|
128
|
+
"items" => [ items ]
|
129
|
+
},
|
130
|
+
"code" => "items_not_found"
|
131
|
+
}.to_json
|
132
|
+
end
|
133
|
+
|
134
|
+
def error_response(error, etc={})
|
135
|
+
headers = response_headers(etc.fetch(:headers, {}))
|
136
|
+
case error
|
137
|
+
when :bad_request
|
138
|
+
[400, headers, {message: "The API request is malformed.", code: "api_bad_request"}.to_json ]
|
139
|
+
when :search_query_malformed
|
140
|
+
[ 400, headers, {
|
141
|
+
message: "The search query provided is invalid.",
|
142
|
+
code: "search_query_malformed"
|
143
|
+
}.to_json ]
|
144
|
+
when :invalid_search_param
|
145
|
+
[ 400, headers, {
|
146
|
+
message: "A provided search query param is invalid.",
|
147
|
+
details: { query: "Query is empty." },
|
148
|
+
code: "search_param_invalid"
|
149
|
+
}.to_json ]
|
150
|
+
when :malformed_ref
|
151
|
+
[ 400, headers, {
|
152
|
+
message: "The provided Item Ref is malformed.",
|
153
|
+
details: { ref: "blerg" },
|
154
|
+
code: "item_ref_malformed"
|
155
|
+
}.to_json ]
|
156
|
+
when :unauthorized
|
157
|
+
[ 401, headers, {
|
158
|
+
"message" => "Valid credentials are required.",
|
159
|
+
"code" => "security_unauthorized"
|
160
|
+
}.to_json ]
|
161
|
+
when :indexing_conflict
|
162
|
+
[409, headers, {
|
163
|
+
message: "The item has been stored but conflicts were detected when indexing. Conflicting fields have not been indexed.",
|
164
|
+
details: {
|
165
|
+
conflicts: { name: { type: "string", expected: "long" } },
|
166
|
+
conflicts_uri: etc[:conflicts_uri]
|
167
|
+
},
|
168
|
+
code: "indexing_conflict"
|
169
|
+
}.to_json ]
|
170
|
+
when :version_mismatch
|
171
|
+
[412, headers, {
|
172
|
+
message: "The version of the item does not match.",
|
173
|
+
code: "item_version_mismatch"
|
174
|
+
}.to_json]
|
175
|
+
when :already_present
|
176
|
+
[ 412, headers, {
|
177
|
+
message: "The item is already present.",
|
178
|
+
code: "item_already_present"
|
179
|
+
}.to_json ]
|
180
|
+
when :service_error
|
181
|
+
headers.delete("Content-Type")
|
182
|
+
[ 500, headers, '' ]
|
183
|
+
else raise ArgumentError.new("unknown error #{error}")
|
184
|
+
end
|
59
185
|
end
|
60
186
|
|
61
187
|
# Assertion Helpers
|