orchestrate 0.6.3 → 0.7.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.
@@ -1,3 +1,4 @@
1
1
  module Orchestrate
2
- VERSION = "0.6.3"
2
+ # @return [String] The version number of the Orchestrate Gem
3
+ VERSION = "0.7.0"
3
4
  end
data/orchestrate.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.require_paths = ["lib"]
19
19
 
20
20
  s.add_dependency "faraday", "~> 0.9"
21
- s.add_dependency "faraday_middleware", "~> 0.9", ">= 0.9.1"
21
+ s.add_dependency "net-http-persistent", "~> 2.9"
22
22
  s.add_development_dependency "bundler", "~> 1.6"
23
23
  s.add_development_dependency "rake"
24
24
  s.add_development_dependency "typhoeus"
@@ -1,6 +1,6 @@
1
1
  require_relative '../../test_helper'
2
2
 
3
- class CollectionTest < MiniTest::Unit::TestCase
3
+ class CollectionAPITest < MiniTest::Unit::TestCase
4
4
  def setup
5
5
  @collection = 'test'
6
6
  @client, @stubs, @basic_auth = make_client_and_artifacts
@@ -8,10 +8,7 @@ class ExceptionsTest < MiniTest::Unit::TestCase
8
8
  def test_raises_on_unauthroized
9
9
  @stubs.get("/v0/foo") do |env|
10
10
  assert_authorization @basic_auth, env
11
- [ 401, response_headers, {
12
- "message" => "Valid credentials are required.",
13
- "code" => "security_unauthorized"
14
- }.to_json ]
11
+ error_response(:unauthorized)
15
12
  end
16
13
  assert_raises Orchestrate::API::Unauthorized do
17
14
  @client.list(:foo)
@@ -19,92 +16,49 @@ class ExceptionsTest < MiniTest::Unit::TestCase
19
16
  end
20
17
 
21
18
  def test_raises_on_bad_request
22
- message = "Invalid value for header 'If-Match'."
23
- @stubs.put("/v0/foo/bar") do |env|
24
- [400, response_headers, {
25
- message: message,
26
- code: "api_bad_request"
27
- }.to_json ]
28
- end
29
- err = assert_raises Orchestrate::API::BadRequest do
19
+ @stubs.put("/v0/foo/bar") { error_response(:bad_request) }
20
+ assert_raises Orchestrate::API::BadRequest do
30
21
  @client.put(:foo, "bar", {}, "'foo'")
31
22
  end
32
- assert_equal message, err.message
33
23
  end
34
24
 
35
25
  def test_raises_on_malformed_search_query
36
- @stubs.get("/v0/foo") do |env|
37
- [ 400, response_headers, {
38
- message: "The search query provided is invalid.",
39
- code: "search_query_malformed"
40
- }.to_json ]
41
- end
26
+ @stubs.get("/v0/foo") { error_response(:search_query_malformed) }
42
27
  assert_raises Orchestrate::API::MalformedSearch do
43
28
  @client.search(:foo, "foo=\"no")
44
29
  end
45
30
  end
46
31
 
47
32
  def test_raises_on_invalid_search_param
48
- @stubs.get("/v0/foo") do |env|
49
- [ 400, response_headers, {
50
- message: "A provided search query param is invalid.",
51
- details: { query: "Query is empty." },
52
- code: "search_param_invalid"
53
- }.to_json ]
54
- end
33
+ @stubs.get("/v0/foo") { error_response(:invalid_search_param) }
55
34
  assert_raises Orchestrate::API::InvalidSearchParam do
56
35
  @client.search(:foo, '')
57
36
  end
58
37
  end
59
38
 
60
39
  def test_raises_on_malformed_ref
61
- @stubs.put("/v0/foo/bar") do |env|
62
- [ 400, response_headers, {
63
- message: "The provided Item Ref is malformed.",
64
- details: { ref: "blerg" },
65
- code: "item_ref_malformed"
66
- }.to_json ]
67
- end
40
+ @stubs.put("/v0/foo/bar") { error_response(:malformed_ref) }
68
41
  assert_raises Orchestrate::API::MalformedRef do
69
42
  @client.put(:foo, "bar", {:blerg => 'blerg'}, "blerg")
70
43
  end
71
44
  end
72
45
 
73
46
  def test_raises_on_indexing_conflict
74
- @stubs.put("/v0/foo/bar") do |env|
75
- [ 409, response_headers, {
76
- message: "The item has been stored but conflicts were detected when indexing. Conflicting fields have not been indexed.",
77
- details: {
78
- conflicts: { name: { type: "string", expected: "long" } },
79
- conflicts_uri: "/v0/test/one/refs/f8a86a25029a907b/conflicts"
80
- },
81
- code: "indexing_conflict"
82
- }.to_json ]
83
- end
47
+ @stubs.put("/v0/foo/bar") { error_response(:indexing_conflict) }
84
48
  assert_raises Orchestrate::API::IndexingConflict do
85
49
  @client.put(:foo, 'bar', {count: "foo"})
86
50
  end
87
51
  end
88
52
 
89
53
  def test_raises_on_version_mismatch
90
- @stubs.put("/v0/foo/bar") do |env|
91
- [ 412, response_headers, {
92
- message: "The version of the item does not match.",
93
- code: "item_version_mismatch"
94
- }.to_json ]
95
- end
54
+ @stubs.put("/v0/foo/bar") { error_response(:version_mismatch) }
96
55
  assert_raises Orchestrate::API::VersionMismatch do
97
56
  @client.put(:foo, 'bar', {foo:'bar'}, "7ae8635207acbb2f")
98
57
  end
99
58
  end
100
59
 
101
60
  def test_raises_on_item_already_present
102
- @stubs.put("/v0/foo/bar") do |env|
103
- [ 412, response_headers, {
104
- message: "The item is already present.",
105
- code: "item_already_present"
106
- }.to_json ]
107
- end
61
+ @stubs.put("/v0/foo/bar") { error_response(:already_present) }
108
62
  assert_raises Orchestrate::API::AlreadyPresent do
109
63
  @client.put_if_absent(:foo, 'bar', {foo:'bar'})
110
64
  end
@@ -1,6 +1,6 @@
1
1
  require_relative "../../test_helper"
2
2
 
3
- class KeyValueTest < MiniTest::Unit::TestCase
3
+ class KeyValueAPITest < MiniTest::Unit::TestCase
4
4
  def setup
5
5
  @collection = 'test'
6
6
  @key = 'keyname'
@@ -0,0 +1,44 @@
1
+ require "test_helper"
2
+
3
+ class ApplicationTest < MiniTest::Unit::TestCase
4
+
5
+ def test_instantianes_with_api_key
6
+ stubs = Faraday::Adapter::Test::Stubs.new
7
+ pinged = false
8
+ stubs.head('/v0') do |env|
9
+ pinged = true
10
+ [200, response_headers, '']
11
+ end
12
+
13
+ app = Orchestrate::Application.new("api_key") do |conn|
14
+ conn.adapter :test, stubs
15
+ end
16
+
17
+ assert_equal "api_key", app.api_key
18
+ assert_kind_of Orchestrate::Client, app.client
19
+ assert pinged, "API wasn't pinged"
20
+ end
21
+
22
+ def test_instantiates_with_client
23
+ client, stubs = make_client_and_artifacts
24
+ pinged = false
25
+ stubs.head('/v0') do |env|
26
+ pinged = true
27
+ [ 200, response_headers, '' ]
28
+ end
29
+
30
+ app = Orchestrate::Application.new(client)
31
+ assert_equal client.api_key, app.api_key
32
+ assert_equal client, app.client
33
+ assert pinged, "API wasn't pinged"
34
+ end
35
+
36
+ def test_collection_accessor
37
+ app, stubs = make_application
38
+ users = app[:users]
39
+ assert_kind_of Orchestrate::Collection, users
40
+ assert_equal app, users.app
41
+ assert_equal 'users', users.name
42
+ end
43
+
44
+ end
@@ -1,34 +1,36 @@
1
1
  require "test_helper"
2
2
 
3
- describe Orchestrate::Client do
3
+ class ClientTest < MiniTest::Unit::TestCase
4
4
 
5
- it "should initialize" do
5
+ def test_initialization
6
6
  client = Orchestrate::Client.new('8c3')
7
- client.must_be_kind_of Orchestrate::Client
7
+ assert_equal '8c3', client.api_key
8
8
  end
9
9
 
10
- it "handles parallel requests" do
11
- client, stubs = make_client_and_artifacts
10
+ def test_parallelism
11
+ thing_body = {"foo" => "bar"}
12
+ list_body = {"count" => 1, "results" => [{"value"=>{"a" => "b"}, "path" => {}, "reftime" => ""}] }
13
+ client, stubs = make_client_and_artifacts(true)
12
14
  stubs.get("/v0/foo") do |env|
13
- [ 200, response_headers, {}.to_json ]
15
+ [ 200, response_headers, list_body.to_json ]
14
16
  end
15
- stubs.get("/v0/users/mattly") do |env|
16
- [ 200, response_headers, {}.to_json ]
17
+ stubs.get("/v0/things/foo") do |env|
18
+ [ 200, response_headers, thing_body.to_json ]
17
19
  end
18
20
  responses = nil
19
- capture_warnings do
20
- responses = client.in_parallel do |r|
21
- r[:list] = client.list(:foo)
22
- r[:user] = client.get(:users, "mattly")
23
- end
21
+ responses = client.in_parallel do |r|
22
+ r[:list] = client.list(:foo)
23
+ r[:thing] = client.get(:things, "foo")
24
24
  end
25
25
  assert responses[:list]
26
26
  assert_equal 200, responses[:list].status
27
- assert responses[:user]
28
- assert_equal 200, responses[:user].status
27
+ assert_equal list_body, responses[:list].body
28
+ assert responses[:thing]
29
+ assert_equal 200, responses[:thing].status
30
+ assert_equal thing_body, responses[:thing].body
29
31
  end
30
32
 
31
- it "handles ping request" do
33
+ def test_ping_request_success
32
34
  client, stubs = make_client_and_artifacts
33
35
  stubs.head("/v0") do |env|
34
36
  [ 200, response_headers, '' ]
@@ -36,7 +38,7 @@ describe Orchestrate::Client do
36
38
  client.ping
37
39
  end
38
40
 
39
- it "handles ping with invalid api_key and raises Unauthorized" do
41
+ def test_ping_request_unauthorized
40
42
  client, stubs = make_client_and_artifacts
41
43
  headers = response_headers
42
44
  stubs.head("/v0") { [ 401, headers, '' ] }
@@ -0,0 +1,116 @@
1
+ require "test_helper"
2
+
3
+ class CollectionEnumerationTest < MiniTest::Unit::TestCase
4
+
5
+ def test_enumerates_over_all
6
+ app, stubs = make_application
7
+ stubs.get("/v0/items") do |env|
8
+ assert_equal "100", env.params['limit']
9
+ body = case env.params['afterKey']
10
+ when nil
11
+ { "results" => 100.times.map {|x| make_kv_listing(:items, key: "key-#{x}") },
12
+ "next" => "/v0/items?afterKey=key-99&limit=100", "count" => 100 }
13
+ when 'key-99'
14
+ { "results" => 4.times.map {|x| make_kv_listing(:items, key: "key-#{100+x}")},
15
+ "count" => 4 }
16
+ else
17
+ raise ArgumentError.new("unexpected afterKey: #{env.params['afterKey']}")
18
+ end
19
+ [ 200, response_headers, body.to_json ]
20
+ end
21
+ items = app[:items].map {|item| item }
22
+ assert_equal 104, items.length
23
+ items.each_with_index do |item, index|
24
+ assert_equal "key-#{index}", item.key
25
+ assert item.ref
26
+ assert item.reftime
27
+ assert item.value
28
+ assert_equal "key-#{index}", item[:key]
29
+ assert_in_delta Time.now.to_f, item.last_request_time.to_f, 1.1
30
+ end
31
+ end
32
+
33
+ def test_enumerator_in_parallel
34
+ app, stubs = make_application({parallel:true})
35
+ stubs.get("/v0/items") do |env|
36
+ body = case env.params['afterKey']
37
+ when nil
38
+ { "results" => 10.times.map {|x| make_kv_listing(:items, key: "key-#{x}") },
39
+ "next" => "/v0/items?afterKey=key-9", "count" => 10 }
40
+ when 'key-9'
41
+ { "results" => 4.times.map {|x| make_kv_listing(:items, key: "key-#{10+x}")},
42
+ "count" => 4 }
43
+ else
44
+ raise ArgumentError.new("unexpected afterKey: #{env.params['afterKey']}")
45
+ end
46
+ [ 200, response_headers, body.to_json ]
47
+ end
48
+ items=nil
49
+ assert_raises Orchestrate::ResultsNotReady do
50
+ app.in_parallel { app[:items].take(5) }
51
+ end
52
+ if app[:items].respond_to?(:lazy)
53
+ app.in_parallel do
54
+ items = app[:items].lazy.map {|item| item }
55
+ end
56
+ items = items.force
57
+ assert_equal 14, items.length
58
+ items.each_with_index do |item, index|
59
+ assert_equal "key-#{index}", item.key
60
+ assert item.ref
61
+ assert item.reftime
62
+ assert item.value
63
+ assert_equal "key-#{index}", item[:key]
64
+ assert_in_delta Time.now.to_f, item.last_request_time.to_f, 1.1
65
+ end
66
+ end
67
+ end
68
+
69
+ def test_enumerates_as_needed
70
+ app, stubs = make_application
71
+ stubs.get("/v0/items") do |env|
72
+ assert_equal "5", env.params["limit"]
73
+ if env.params['afterKey'] != nil
74
+ raise ArgumentError.new("unexpected afterKey: #{env.params['afterKey']}")
75
+ else
76
+ body = { "results" => 5.times.map {|x| make_kv_listing(:items, key: "key-#{x}")},
77
+ "next" => "/v0/items?afterKey=key-4&limit=5", "count" => 5 }
78
+ [ 200, response_headers, body.to_json ]
79
+ end
80
+ end
81
+ items = app[:items].take(5).map {|item| item }
82
+ assert_equal 5, items.length
83
+ end
84
+
85
+ def test_enumerates_with_range_start_and_end
86
+ keys = %w[bar bat bee cat dog ear foo]
87
+ app, stubs = make_application
88
+ stubs.get("/v0/items") do |env|
89
+ assert_equal "bar", env.params['startKey']
90
+ assert_equal "foo", env.params['endKey']
91
+ body = { "results" => keys.map {|k| make_kv_listing(:items, key: k)},
92
+ "count" => keys.length }
93
+ [ 200, response_headers, body.to_json ]
94
+ end
95
+ items = app[:items].start(:bar).end(:foo).take(5).map {|item| item.key }
96
+ assert_equal 5, items.length
97
+ assert_equal %w[bar bat bee cat dog], items
98
+ end
99
+
100
+ def test_enumerates_with_range_after_and_before
101
+ keys = %w[bar bat bee cat dog ear foo]
102
+ app, stubs = make_application
103
+ stubs.get("/v0/items") do |env|
104
+ assert_equal "bar", env.params['afterKey']
105
+ assert_equal "goo", env.params['beforeKey']
106
+ body = { "results" => keys.drop(1).map {|k| make_kv_listing(:items, key: k)},
107
+ "count" => keys.length }
108
+ [ 200, response_headers, body.to_json ]
109
+ end
110
+ items = app[:items].after(:bar).before(:goo).take(5).map {|item| item.key }
111
+ assert_equal 5, items.length
112
+ assert_equal %w[bat bee cat dog ear], items
113
+ end
114
+
115
+ end
116
+
@@ -0,0 +1,145 @@
1
+ require "test_helper"
2
+
3
+ class Collection_KV_Accessors_Test < MiniTest::Unit::TestCase
4
+ def setup
5
+ @app, @stubs = make_application
6
+ @items = @app[:items]
7
+ end
8
+
9
+ def test_kv_getter_when_present
10
+ body = {"hello" => "world"}
11
+ @stubs.get("/v0/items/hello") do |env|
12
+ [200, response_headers, body.to_json]
13
+ end
14
+ hello = @items[:hello]
15
+ assert_kind_of Orchestrate::KeyValue, hello
16
+ end
17
+
18
+ def test_kv_getter_when_absent
19
+ @stubs.get("/v0/items/absent") do |env|
20
+ [404, response_headers, response_not_found('absent')]
21
+ end
22
+ assert_nil @items[:absent]
23
+ end
24
+
25
+ def test_kv_setter
26
+ body = { "hello" => "world" }
27
+ ref = nil
28
+ @stubs.put("/v0/items/newitem") do |env|
29
+ assert_header "If-Match", nil, env
30
+ assert_header "If-None-Match", nil, env
31
+ assert_equal body, JSON.parse(env.body)
32
+ ref = make_ref
33
+ [ 201, response_headers({'Etag' => %|"#{ref}"|, 'Location' => "/v0/items/newitem/refs/#{ref}"}), '' ]
34
+ end
35
+ @items[:newitem] = body
36
+ assert ref
37
+ end
38
+
39
+ def test_set_performs_put
40
+ body = { "hello" => "world" }
41
+ ref = nil
42
+ @stubs.put("/v0/items/newitem") do |env|
43
+ assert_header "If-Match", nil, env
44
+ assert_header "If-None-Match", nil, env
45
+ assert_equal body, JSON.parse(env.body)
46
+ ref = make_ref
47
+ [ 201, response_headers({'Etag' => %|"#{ref}"|, 'Location' => "/v0/items/newitem/refs/#{ref}"}), '' ]
48
+ end
49
+ kv = @items.set(:newitem, body)
50
+ assert_equal ref, kv.ref
51
+ assert_equal "newitem", kv.key
52
+ assert_equal body, kv.value
53
+ assert kv.loaded?
54
+ assert_in_delta Time.now.to_f, kv.last_request_time.to_f, 1.1
55
+ end
56
+
57
+ def test_append_operator_performs_post
58
+ body = { "hello" => "world" }
59
+ key = nil
60
+ ref = nil
61
+ @stubs.post("/v0/items") do |env|
62
+ assert_header 'Content-Type', 'application/json', env
63
+ assert_equal body, JSON.parse(env.body)
64
+ ref = make_ref
65
+ key = SecureRandom.hex(16)
66
+ [ 201, response_headers({
67
+ 'Etag' => %|"#{ref}"|, "Location" => "/v0/items/#{key}/refs/#{ref}"
68
+ }), '' ]
69
+ end
70
+ kv = @items << body
71
+ assert kv
72
+ assert_equal key, kv.key
73
+ assert_equal ref, kv.ref
74
+ assert_equal body, kv.value
75
+ assert kv.loaded?
76
+ assert_in_delta Time.now.to_f, kv.last_request_time.to_f, 1.1
77
+ end
78
+
79
+ def test_create_performs_post_with_one_arg
80
+ body = { "hello" => "world" }
81
+ key = nil
82
+ ref = nil
83
+ @stubs.post("/v0/items") do |env|
84
+ assert_header 'Content-Type', 'application/json', env
85
+ assert_equal body, JSON.parse(env.body)
86
+ ref = make_ref
87
+ key = SecureRandom.hex(16)
88
+ [ 201, response_headers({
89
+ 'Etag' => %|"#{ref}"|, "Location" => "/v0/items/#{key}/refs/#{ref}"
90
+ }), '' ]
91
+ end
92
+ kv = @items.create(body)
93
+ assert kv
94
+ assert_equal key, kv.key
95
+ assert_equal ref, kv.ref
96
+ assert_equal body, kv.value
97
+ assert kv.loaded?
98
+ assert_in_delta Time.now.to_f, kv.last_request_time.to_f, 1.1
99
+ end
100
+
101
+ def test_create_performs_put_if_absent_with_two_args
102
+ body = { "hello" => "world" }
103
+ ref = nil
104
+ @stubs.put("/v0/items/newitem") do |env|
105
+ assert_header "If-Match", nil, env
106
+ assert_header "If-None-Match", '"*"', env
107
+ assert_equal body, JSON.parse(env.body)
108
+ ref = make_ref
109
+ [ 201, response_headers({"Etag" => %|"#{ref}"|, "Location" => "/v0/items/newitem/refs/#{ref}"}), '' ]
110
+ end
111
+ kv = @items.create(:newitem, body)
112
+ assert_equal @items, kv.collection
113
+ assert_equal "newitem", kv.key
114
+ assert_equal ref, kv.ref
115
+ assert_equal body, kv.value
116
+ assert kv.loaded?
117
+ assert_in_delta Time.now.to_f, kv.last_request_time.to_f, 1.1
118
+ end
119
+
120
+ def test_create_performs_put_if_absent_with_two_args_returns_false_on_already_exists
121
+ @stubs.put("/v0/items/newitem") do |env|
122
+ assert_header "If-Match", nil, env
123
+ assert_header "If-None-Match", '"*"', env
124
+ error_response(:already_present)
125
+ end
126
+ assert_equal false, @items.create(:newitem, {"hello" => "world"})
127
+ end
128
+
129
+ def test_delete_performs_delete
130
+ @stubs.delete("/v0/items/olditem") do |env|
131
+ assert_nil env.params['purge']
132
+ [ 204, response_headers, '' ]
133
+ end
134
+ assert_equal true, @items.delete(:olditem)
135
+ end
136
+
137
+ def test_purge_performs_purge
138
+ @stubs.delete("/v0/items/olditem") do |env|
139
+ assert_equal "true", env.params['purge']
140
+ [ 204, response_headers, '' ]
141
+ end
142
+ assert_equal true, @items.purge(:olditem)
143
+ end
144
+ end
145
+