orchestrate 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+