active_rest_client 0.9.58

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.simplecov +4 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +9 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +585 -0
  9. data/Rakefile +3 -0
  10. data/active_rest_client.gemspec +34 -0
  11. data/lib/active_rest_client.rb +23 -0
  12. data/lib/active_rest_client/base.rb +128 -0
  13. data/lib/active_rest_client/caching.rb +84 -0
  14. data/lib/active_rest_client/configuration.rb +69 -0
  15. data/lib/active_rest_client/connection.rb +76 -0
  16. data/lib/active_rest_client/connection_manager.rb +21 -0
  17. data/lib/active_rest_client/headers_list.rb +47 -0
  18. data/lib/active_rest_client/instrumentation.rb +62 -0
  19. data/lib/active_rest_client/lazy_association_loader.rb +95 -0
  20. data/lib/active_rest_client/lazy_loader.rb +23 -0
  21. data/lib/active_rest_client/logger.rb +67 -0
  22. data/lib/active_rest_client/mapping.rb +65 -0
  23. data/lib/active_rest_client/proxy_base.rb +143 -0
  24. data/lib/active_rest_client/recording.rb +24 -0
  25. data/lib/active_rest_client/request.rb +412 -0
  26. data/lib/active_rest_client/request_filtering.rb +52 -0
  27. data/lib/active_rest_client/result_iterator.rb +66 -0
  28. data/lib/active_rest_client/validation.rb +60 -0
  29. data/lib/active_rest_client/version.rb +3 -0
  30. data/spec/lib/base_spec.rb +245 -0
  31. data/spec/lib/caching_spec.rb +179 -0
  32. data/spec/lib/configuration_spec.rb +105 -0
  33. data/spec/lib/connection_manager_spec.rb +36 -0
  34. data/spec/lib/connection_spec.rb +73 -0
  35. data/spec/lib/headers_list_spec.rb +61 -0
  36. data/spec/lib/instrumentation_spec.rb +59 -0
  37. data/spec/lib/lazy_association_loader_spec.rb +118 -0
  38. data/spec/lib/lazy_loader_spec.rb +25 -0
  39. data/spec/lib/logger_spec.rb +63 -0
  40. data/spec/lib/mapping_spec.rb +48 -0
  41. data/spec/lib/proxy_spec.rb +154 -0
  42. data/spec/lib/recording_spec.rb +34 -0
  43. data/spec/lib/request_filtering_spec.rb +72 -0
  44. data/spec/lib/request_spec.rb +471 -0
  45. data/spec/lib/result_iterator_spec.rb +104 -0
  46. data/spec/lib/validation_spec.rb +113 -0
  47. data/spec/spec_helper.rb +22 -0
  48. metadata +265 -0
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRestClient::Configuration do
4
+ before :each do
5
+ Object.send(:remove_const, :ConfigurationExample) if defined?(ConfigurationExample)
6
+ ActiveRestClient::Base._reset_configuration!
7
+
8
+ class ConfigurationExample
9
+ include ActiveRestClient::Configuration
10
+ base_url "http://www.example.com"
11
+ end
12
+
13
+ class ConfigurationExampleBare
14
+ include ActiveRestClient::Configuration
15
+ end
16
+ end
17
+
18
+ it "should default to non-whiny missing methods" do
19
+ class UnusuedConfigurationExample1
20
+ include ActiveRestClient::Configuration
21
+ end
22
+ expect(UnusuedConfigurationExample1.whiny_missing).to be_false
23
+ end
24
+
25
+ it "should allow whiny missing methods to be enabled" do
26
+ ConfigurationExample.whiny_missing true
27
+ expect(ConfigurationExample.whiny_missing).to be_true
28
+ end
29
+
30
+ it "should remember the set base_url" do
31
+ expect(ConfigurationExample.base_url).to eq("http://www.example.com")
32
+ end
33
+
34
+ it "should remember the set base_url on a class, overriding a general one" do
35
+ ActiveRestClient::Base.base_url = "http://general.example.com"
36
+ expect(ConfigurationExample.base_url).to eq("http://www.example.com")
37
+ end
38
+
39
+ it "should remove a trailing slash from a globally configured base_url" do
40
+ ActiveRestClient::Base.base_url = "http://general.example.com/"
41
+ expect(ConfigurationExample.base_url).to eq("http://www.example.com")
42
+ end
43
+
44
+ it "should remember the set base_url on the base class if a more specific one hasn't been set" do
45
+ ActiveRestClient::Base.base_url = "http://general.example.com"
46
+ expect(ConfigurationExampleBare.base_url).to eq("http://general.example.com")
47
+ end
48
+
49
+ it "should remove a trailing slash from a specific class configured base_url" do
50
+ class ConfigurationExample2
51
+ include ActiveRestClient::Configuration
52
+ base_url "http://specific.example.com/"
53
+ end
54
+ expect(ConfigurationExample2.base_url).to eq("http://specific.example.com")
55
+ end
56
+
57
+ it "should default to non-lazy loading" do
58
+ class LazyLoadingConfigurationExample1
59
+ include ActiveRestClient::Configuration
60
+ end
61
+ expect(LazyLoadingConfigurationExample1.lazy_load?).to be_false
62
+ end
63
+
64
+ it "should be able to switch on lazy loading" do
65
+ class LazyLoadingConfigurationExample2
66
+ include ActiveRestClient::Configuration
67
+ lazy_load!
68
+ end
69
+ expect(LazyLoadingConfigurationExample2.lazy_load?).to be_true
70
+ end
71
+
72
+ it "should default to non-verbose loggingg" do
73
+ class VerboseConfigurationExample1
74
+ include ActiveRestClient::Configuration
75
+ end
76
+ expect(VerboseConfigurationExample1.verbose).to be_false
77
+ end
78
+
79
+ it "should be able to switch on verbose logging" do
80
+ class VerboseConfigurationExample2
81
+ include ActiveRestClient::Configuration
82
+ verbose!
83
+ end
84
+ class VerboseConfigurationExample3
85
+ include ActiveRestClient::Configuration
86
+ verbose true
87
+ end
88
+ expect(VerboseConfigurationExample2.verbose).to be_true
89
+ expect(VerboseConfigurationExample3.verbose).to be_true
90
+ end
91
+
92
+ it "should store a translator given" do
93
+ expect{ ConfigurationExample.send(:translator) }.to_not raise_error
94
+ ConfigurationExample.send(:translator, String)
95
+ expect{ ConfigurationExample.translator.respond_to?(:length) }.to be_true
96
+ end
97
+
98
+ it "should store a proxy given" do
99
+ expect{ ConfigurationExample.send(:proxy) }.to_not raise_error
100
+ ConfigurationExample.send(:proxy, String)
101
+ expect{ ConfigurationExample.proxy.respond_to?(:length) }.to be_true
102
+ end
103
+
104
+
105
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRestClient::ConnectionManager do
4
+ before(:each) do
5
+ ActiveRestClient::ConnectionManager.reset!
6
+ end
7
+
8
+ it "should have a get_connection method" do
9
+ expect(ActiveRestClient::ConnectionManager).to respond_to("get_connection")
10
+ end
11
+
12
+ it "should return a connection for a given base url" do
13
+ connection = ActiveRestClient::ConnectionManager.get_connection("http://www.example.com")
14
+ expect(connection).to be_kind_of(ActiveRestClient::Connection)
15
+ end
16
+
17
+ it "should return the same connection for each base url when re-requested" do
18
+ connection = ActiveRestClient::ConnectionManager.get_connection("http://www.example.com")
19
+ expect(ActiveRestClient::ConnectionManager.get_connection("http://www.example.com")).to eq(connection)
20
+ end
21
+
22
+ it "should return different connections for each base url when requested" do
23
+ base_url = "http://www.example.com"
24
+ other_base_url = "http://other.example.com"
25
+ expect(ActiveRestClient::ConnectionManager.get_connection(base_url).base_url).to eq(base_url)
26
+ expect(ActiveRestClient::ConnectionManager.get_connection(other_base_url).base_url).to eq(other_base_url)
27
+ expect(ActiveRestClient::ConnectionManager.instance_variable_get(:@_connections).size).to eq(2)
28
+ end
29
+
30
+ it "should find a connection if you pass in URLs containing an existing connection's base_url" do
31
+ base_url = "http://www.example.com"
32
+ connection = ActiveRestClient::ConnectionManager.get_connection(base_url)
33
+ found_connection = ActiveRestClient::ConnectionManager.find_connection_for_url("#{base_url}:8080/people/test")
34
+ expect(found_connection).to eq(connection)
35
+ end
36
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRestClient::Connection do
4
+ before(:each) do
5
+ @connection = ActiveRestClient::Connection.new("http://www.example.com")
6
+ end
7
+
8
+ it "should contain a patron session" do
9
+ expect(@connection.session).to be_a_kind_of(Patron::Session)
10
+ end
11
+
12
+ it "should set the Base URL for Patron to be the one passed in" do
13
+ expect(@connection.session.base_url).to eq("http://www.example.com")
14
+ end
15
+
16
+ it "should set a user agent for the Patron session" do
17
+ expect(@connection.headers["User-Agent"]).to match(/^ActiveRestClient\/[0-9.]+$/)
18
+ end
19
+
20
+ it "should try to Keep-Alive Patron session connections" do
21
+ expect(@connection.headers["Connection"]).to match(/Keep-Alive/)
22
+ end
23
+
24
+ it "should pass a GET request through to Patron" do
25
+ @connection.session = double(Patron::Session)
26
+ @connection.session.stub(:get).with("/foo", {}).and_return(OpenStruct.new(body:"{result:true}"))
27
+ result = @connection.get("/foo")
28
+ expect(result.body).to eq("{result:true}")
29
+ end
30
+
31
+ it "should pass a PUT request through to Patron" do
32
+ @connection.session = double(Patron::Session)
33
+ @connection.session.stub(:put).with("/foo", "body", {}).and_return(OpenStruct.new(body:"{result:true}"))
34
+ result = @connection.put("/foo", "body")
35
+ expect(result.body).to eq("{result:true}")
36
+ end
37
+
38
+ it "should pass a POST request through to Patron" do
39
+ @connection.session = double(Patron::Session)
40
+ @connection.session.stub(:post).with("/foo", "body", {}).and_return(OpenStruct.new(body:"{result:true}"))
41
+ result = @connection.post("/foo", "body")
42
+ expect(result.body).to eq("{result:true}")
43
+ end
44
+
45
+ it "should pass a DELETE request through to Patron" do
46
+ @connection.session = double(Patron::Session)
47
+ @connection.session.stub(:delete).with("/foo", {}).and_return(OpenStruct.new(body:"{result:true}"))
48
+ result = @connection.delete("/foo")
49
+ expect(result.body).to eq("{result:true}")
50
+ end
51
+
52
+ it "should retry once in the event of a connection failed" do
53
+ @times_called = 0
54
+ Patron::Session.any_instance.stub(:get).and_return do
55
+ raise Patron::ConnectionFailed.new("Foo") if (@times_called += 1) == 1
56
+ end
57
+ expect { @connection.get("/foo") }.to_not raise_error
58
+ end
59
+
60
+ it "should not retry more than once in the event of a connection failed" do
61
+ @times_called = 0
62
+ Patron::Session.any_instance.stub(:get).and_return do
63
+ raise Patron::ConnectionFailed.new("Foo")
64
+ end
65
+ expect { @connection.get("/foo") }.to raise_error(ActiveRestClient::ConnectionFailedException)
66
+ end
67
+
68
+ it "should raise an exception on timeout" do
69
+ Patron::Session.any_instance.stub(:get).and_raise Patron::TimeoutError.new("Foo")
70
+ expect { @connection.get("/foo") }.to raise_error(ActiveRestClient::TimeoutException)
71
+ end
72
+
73
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRestClient::HeadersList do
4
+ let(:headers_list) { ActiveRestClient::HeadersList.new }
5
+
6
+ it "should remember stored headers" do
7
+ url = "http://www.google.com"
8
+ headers_list["X-My-Header"] = url
9
+ expect(headers_list["X-My-Header"]).to eq(url)
10
+ end
11
+
12
+ it "should remember overwrite normal headers" do
13
+ url = "http://www.google.com"
14
+ headers_list["X-My-Header"] = "SHOULD NEVER BE SEEN"
15
+ headers_list["X-My-Header"] = url
16
+ expect(headers_list["X-My-Header"]).to eq(url)
17
+ end
18
+
19
+ it "should append to specific headers, such as Set-cookie" do
20
+ headers_list["Set-Cookie"] = "first_value"
21
+ headers_list["Set-Cookie"] = "second_value"
22
+ expect(headers_list["Set-Cookie"]).to eq(%w{first_value second_value})
23
+ end
24
+
25
+ it "should not be case sensitive on header names when setting headers" do
26
+ url = "http://www.google.com"
27
+ headers_list["X-My-Header"] = "SHOULD NEVER BE SEEN"
28
+ headers_list["X-MY-HEADER"] = url
29
+ expect(headers_list["X-My-Header"]).to eq(url)
30
+ end
31
+
32
+ it "should not be case sensitive on header names when getting headers" do
33
+ url = "http://www.google.com"
34
+ headers_list["X-My-Header"] = url
35
+ expect(headers_list["X-MY-HEADER"]).to eq(url)
36
+ end
37
+
38
+ it "should allow iterating over headers set, by default with array items returned whole" do
39
+ headers_list["X-My-Header"] = "http://www.google.com"
40
+ headers_list["Set-Cookie"] = "first_value"
41
+ headers_list["SET-COOKIE"] = "second_value"
42
+ values = []
43
+ headers_list.each do |name, value|
44
+ values << "#{name}=#{value.to_s}"
45
+ end
46
+ expect(values.size).to eq(2)
47
+ expect(values).to eq(["X-My-Header=http://www.google.com", "Set-Cookie=[\"first_value\", \"second_value\"]"])
48
+ end
49
+
50
+ it "should allow iterating over headers set splitting array headers in to individual ones" do
51
+ headers_list["X-My-Header"] = "http://www.google.com"
52
+ headers_list["Set-Cookie"] = "first_value"
53
+ headers_list["SET-COOKIE"] = "second_value"
54
+ values = []
55
+ headers_list.each(true) do |name, value|
56
+ values << "#{name}=#{value.to_s}"
57
+ end
58
+ expect(values.size).to eq(3)
59
+ expect(values).to eq(["X-My-Header=http://www.google.com", "Set-Cookie=first_value", "Set-Cookie=second_value"])
60
+ end
61
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ class InstrumentationExampleClient < ActiveRestClient::Base
4
+ base_url "http://www.example.com"
5
+ get :fake, "/fake", fake:"{\"result\":true, \"list\":[1,2,3,{\"test\":true}], \"child\":{\"grandchild\":{\"test\":true}}}"
6
+ get :real, "/real"
7
+ end
8
+
9
+ describe ActiveRestClient::Instrumentation do
10
+ it "should save a load hook to include the instrumentation" do
11
+ hook_tester = double("HookTester")
12
+ hook_tester.should_receive(:include).with(ActiveRestClient::ControllerInstrumentation)
13
+ ActiveSupport.run_load_hooks(:action_controller, hook_tester)
14
+ end
15
+
16
+ it "should call ActiveSupport::Notifications.instrument when making any request" do
17
+ ActiveSupport::Notifications.should_receive(:instrument).with("request_call.active_rest_client", {:name=>"InstrumentationExampleClient#fake"})
18
+ InstrumentationExampleClient.fake
19
+ end
20
+
21
+ it "should call ActiveSupport::Notifications#request_call when making any request" do
22
+ ActiveRestClient::Instrumentation.any_instance.should_receive(:request_call).with(an_instance_of(ActiveSupport::Notifications::Event))
23
+ InstrumentationExampleClient.fake
24
+ end
25
+
26
+
27
+ it "should log time spent in each API call" do
28
+ ActiveRestClient::Connection.
29
+ any_instance.
30
+ should_receive(:get).
31
+ with("/real", an_instance_of(Hash)).
32
+ and_return(OpenStruct.new(body:"{\"first_name\":\"John\", \"id\":1234}", headers:{}, status:200))
33
+ ActiveRestClient::Logger.should_receive(:debug).with {|*args| args.first[/ActiveRestClient.*ms\)/]}
34
+ ActiveRestClient::Logger.should_receive(:debug).at_least(:once).with(any_args)
35
+ InstrumentationExampleClient.real
36
+ end
37
+
38
+
39
+ it "should report the total time spent" do
40
+ # Create a couple of classes to fake being part of ActionController (that would normally call this method)
41
+ class InstrumentationTimeSpentExampleClientParent
42
+ def append_info_to_payload(payload) ; {} ; end
43
+ def self.log_process_action(payload) ; [] ; end
44
+ end
45
+
46
+ class InstrumentationTimeSpentExampleClient < InstrumentationTimeSpentExampleClientParent
47
+ include ActiveRestClient::ControllerInstrumentation
48
+
49
+ def test
50
+ payload = {}
51
+ append_info_to_payload(payload)
52
+ self.class.log_process_action(payload)
53
+ end
54
+ end
55
+
56
+ messages = InstrumentationTimeSpentExampleClient.new.test
57
+ expect(messages.first).to match(/ActiveRestClient.*ms.*call/)
58
+ end
59
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRestClient::LazyAssociationLoader do
4
+ let(:url1) { "http://www.example.com/some/url" }
5
+ let(:url2) { "http://www.example.com/some/other" }
6
+ let(:calling_object) { o = double("Object").as_null_object }
7
+ let(:request) { ActiveRestClient::Request.new({:method => :get, url:"http://api.example.com/v1/foo"}, calling_object) }
8
+
9
+ it "should raise an exception if you initialize it with a value that is not a string, hash or array" do
10
+ expect do
11
+ ActiveRestClient::LazyAssociationLoader.new(:person, OpenStruct.new, nil)
12
+ end.to raise_error(ActiveRestClient::InvalidLazyAssociationContentException)
13
+ end
14
+
15
+ it "should store a URL passed as a string to the new object during creation" do
16
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, url1, nil)
17
+ expect(loader.instance_variable_get(:@url)).to eq(url1)
18
+ end
19
+
20
+ it "should store a URL from a hash passed to the new object during creation" do
21
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, {"url" => url1}, nil)
22
+ expect(loader.instance_variable_get(:@url)).to eq(url1)
23
+ end
24
+
25
+ it "should store a list of URLs from an array passed to the new object during creation" do
26
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, [url1, url2], nil)
27
+ array = loader.instance_variable_get(:@subloaders)
28
+ expect(array[0].instance_variable_get(:@url)).to eq(url1)
29
+ expect(array[1].instance_variable_get(:@url)).to eq(url2)
30
+ expect(array[2]).to be_nil
31
+ end
32
+
33
+ it "should store a hash of URLs from a hash passed to the new object during creation" do
34
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, {"main" => url1, "thumb" => url2}, request)
35
+ expect(loader.main.instance_variable_get(:@url)).to eq(url1)
36
+ expect(loader.thumb.instance_variable_get(:@url)).to eq(url2)
37
+ expect(loader.size).to eq(2)
38
+ end
39
+
40
+ it "should still be able to iterate over a hash of URLs from a hash passed to the new object during creation" do
41
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, {"main" => url1, "thumb" => url2}, request)
42
+ output = []
43
+ loader.each do |k, v|
44
+ output << v.instance_variable_get(:@url)
45
+ end
46
+ expect(output.size).to eq(2)
47
+ expect(output[0]).to eq(url1)
48
+ expect(output[1]).to eq(url2)
49
+ expect(output[2]).to be_nil
50
+ end
51
+
52
+ it "should be able to list the keys from a hash passed to the new object during creation" do
53
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, {"main" => url1, "thumb" => url2}, request)
54
+ expect(loader.keys[0]).to eq(:main)
55
+ expect(loader.keys[1]).to eq(:thumb)
56
+ expect(loader.keys.size).to eq(2)
57
+ end
58
+
59
+ it "should report the size of a list of stored URLs" do
60
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, [url1, url2], nil)
61
+ expect(loader.size).to eq(2)
62
+ end
63
+
64
+ it "should respond to each and iterate through the list of stored URLs" do
65
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, [url1, url2], nil)
66
+ output = []
67
+ loader.each do |o|
68
+ output << o.instance_variable_get(:@url)
69
+ end
70
+ expect(output.size).to eq(2)
71
+ expect(output[0]).to eq(url1)
72
+ expect(output[1]).to eq(url2)
73
+ expect(output[2]).to be_nil
74
+ end
75
+
76
+ it "should return a LazyAssociationLoader for each stored URL in a list" do
77
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, [url1, url2], nil)
78
+ output = []
79
+ loader.each do |o|
80
+ expect(o).to be_an_instance_of(ActiveRestClient::LazyAssociationLoader)
81
+ end
82
+ end
83
+
84
+ it "should make the request for a URL if it's accessed" do
85
+ method_data = {options:{url:"foo"}}
86
+ request = double("Request").as_null_object
87
+ request.stub(:method).and_return(method_data)
88
+ request.should_receive(:object).with(any_args).and_return(Array.new)
89
+ request.should_receive(:call).with(any_args).and_return("")
90
+ ActiveRestClient::Request.should_receive(:new).with(any_args).and_return(request)
91
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, url1, request)
92
+ loader.length
93
+ end
94
+
95
+ it "should proxy methods to the underlying object if the request has been made" do
96
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, url1, request)
97
+ object = double("Object")
98
+ object.should_receive(:length).and_return(1)
99
+ loader.instance_variable_set(:@object, object)
100
+ expect(loader.length).to eq(1)
101
+ end
102
+
103
+ it "should be able to iterate underlying object if it's an array" do
104
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, url1, request)
105
+ ActiveRestClient::Request.any_instance.should_receive(:call).with(any_args).and_return([1,2,3])
106
+ test = []
107
+ loader.each do |item|
108
+ test << item
109
+ end
110
+ expect(test).to eq([1,2,3])
111
+ end
112
+
113
+ it "should be able to return the size of the underlying object if it's an array" do
114
+ loader = ActiveRestClient::LazyAssociationLoader.new(:person, url1, request)
115
+ ActiveRestClient::Request.any_instance.should_receive(:call).with(any_args).and_return([1,2,3])
116
+ expect(loader.size).to eq(3)
117
+ end
118
+ end