api_resource 0.6.18 → 0.6.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,7 +15,7 @@ describe "Should put callbacks around save, create, update, and destroy by defau
15
15
  before_create :bc_cb; after_create :ac_cb
16
16
  before_update :bu_cb; after_update :au_cb
17
17
  before_destroy :bd_cb; after_destroy :ad_cb
18
-
18
+
19
19
  def bs_cb
20
20
  @s_val = 1
21
21
  end
@@ -42,7 +42,7 @@ describe "Should put callbacks around save, create, update, and destroy by defau
42
42
  end
43
43
  EOE
44
44
  end
45
-
45
+
46
46
  it "should fire save and create callbacks when saving a new record" do
47
47
  tr = TestResource.new(:name => "Ethan", :age => 20)
48
48
  tr.save.should be_true
@@ -50,7 +50,7 @@ describe "Should put callbacks around save, create, update, and destroy by defau
50
50
  tr.c_val.should eql(2)
51
51
  tr.u_val.should be_nil
52
52
  end
53
-
53
+
54
54
  it "should fire save and update callbacks when updating a record" do
55
55
  tr = TestResource.new(:name => "Ethan", :age => 20)
56
56
  tr.stubs(:id => 1)
@@ -61,13 +61,13 @@ describe "Should put callbacks around save, create, update, and destroy by defau
61
61
  tr.c_val.should be_nil
62
62
  tr.u_val.should eql(2)
63
63
  end
64
-
64
+
65
65
  it "should only fire destroy callbacks when destroying a record" do
66
66
  tr = TestResource.new(:name => "Ethan", :age => 20)
67
67
  tr.stubs(:id => 1)
68
68
  tr.destroy.should be_true
69
69
  tr.d_val.should eql(2)
70
- tr.s_val.should be_nil
70
+ tr.s_val.should be_nil
71
71
  end
72
-
72
+
73
73
  end
@@ -3,21 +3,21 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
3
  include ApiResource
4
4
 
5
5
  describe Connection do
6
-
6
+
7
7
  it "should be able to set the token directly on ApiResource" do
8
8
  ApiResource.token = "123"
9
9
  ApiResource::Base.token.should eql "123"
10
10
  end
11
-
11
+
12
12
  it "should be able to set a default token value, which is passed through each request" do
13
- ApiResource::Mocks::Connection.expects(:get).with("/test_resources/1.json", {"Accept"=>"application/json", "Lifebooker-Token" => "abc"}).returns(ApiResource::Mocks::MockResponse.new({}))
13
+ ApiResource::Mocks::Connection.expects(:get).with("/test_resources/1.json", {}, {"Accept"=>"application/json", "Lifebooker-Token" => "abc"}).returns(ApiResource::Mocks::MockResponse.new({}))
14
14
  ApiResource::Base.token = "abc"
15
15
  TestResource.find(1)
16
16
  end
17
17
 
18
18
  it "should set the Lifebooker-Token if one is present for GET requests" do
19
19
  token = Kernel.rand(100000).to_s
20
- ApiResource::Mocks::Connection.expects(:get).with("/test_resources/1.json", {"Accept"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
20
+ ApiResource::Mocks::Connection.expects(:get).with("/test_resources/1.json", {}, {"Accept"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
21
21
 
22
22
  ApiResource::Base.token = token
23
23
 
@@ -44,7 +44,7 @@ describe Connection do
44
44
 
45
45
  it "should set the Lifebooker-Token if one is present for POST requests" do
46
46
  token = Kernel.rand(100000).to_s
47
- ApiResource::Mocks::Connection.expects(:post).with("/test_resources/1.json", {}, {"Content-Type"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
47
+ ApiResource::Mocks::Connection.expects(:post).with("/test_resources/1.json", '{}', {"Content-Type"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
48
48
 
49
49
  ApiResource::Base.token = token
50
50
 
@@ -53,7 +53,7 @@ describe Connection do
53
53
 
54
54
  it "should set the Lifebooker-Token if one is present for PUT requests" do
55
55
  token = Kernel.rand(100000).to_s
56
- ApiResource::Mocks::Connection.expects(:put).with("/test_resources/1.json", {}, {"Content-Type"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
56
+ ApiResource::Mocks::Connection.expects(:put).with("/test_resources/1.json", '{}', {"Content-Type"=>"application/json", 'Lifebooker-Token' => "#{token}"}).returns(ApiResource::Mocks::MockResponse.new({}))
57
57
 
58
58
  ApiResource::Base.token = token
59
59
 
@@ -75,7 +75,7 @@ describe Connection do
75
75
  TestResource.connection.headers.include?("Lifebooker-Token").should eql true
76
76
  TestResource.connection.headers["Lifebooker-Token"] = token
77
77
  end
78
-
78
+
79
79
  it "should be able to set a token for a given block" do
80
80
  ApiResource::Base.token = "123456"
81
81
  begin
@@ -88,14 +88,14 @@ describe Connection do
88
88
  end
89
89
  ApiResource::Base.token.should eql "123456"
90
90
  end
91
-
91
+
92
92
  it "should provider a method to regenerate its connection" do
93
93
  conn = ApiResource::Base.connection
94
94
  conn.should be ApiResource::Base.connection
95
95
  ApiResource.reset_connection
96
96
  conn.should_not be ApiResource::Base.connection
97
97
  end
98
-
98
+
99
99
  context "No Mocks" do
100
100
  before(:all) do
101
101
  ApiResource::Mocks.remove
@@ -111,25 +111,25 @@ describe Connection do
111
111
  ApiResource.open_timeout = 1
112
112
  ApiResource.open_timeout.should eql 1
113
113
 
114
- ApiResource::Base.connection.send(:http, "/test").options[:timeout].should eql 1
115
- ApiResource::Base.connection.send(:http, "/test").options[:open_timeout].should eql 1
116
-
114
+ ApiResource::Base.connection.send(:http).receive_timeout.should eql 1
115
+ ApiResource::Base.connection.send(:http).connect_timeout.should eql 1
116
+
117
117
  ApiResource.timeout = 100
118
- ApiResource::Base.connection.send(:http, "/test").options[:timeout].should eql 100
118
+ ApiResource::Base.connection.send(:http).receive_timeout.should eql 100
119
119
 
120
120
  end
121
-
122
- it "should time out if RestClient takes too long" do
123
-
121
+
122
+ it "should time out if HttpClient takes too long" do
123
+
124
124
  # hopefully google won't actually respond this fast :)
125
125
  ApiResource.timeout = 0.001
126
126
  ApiResource::Base.site = "http://www.google.com"
127
127
  lambda{
128
128
  ApiResource::Base.connection.get("/")
129
129
  }.should raise_error(ApiResource::RequestTimeout)
130
-
130
+
131
131
  end
132
-
132
+
133
133
  end
134
134
 
135
135
  context "headers" do
@@ -150,7 +150,7 @@ describe Connection do
150
150
  end
151
151
 
152
152
  end
153
-
154
153
 
155
-
154
+
155
+
156
156
  end
@@ -79,6 +79,20 @@ describe ApiResource::Finders do
79
79
  TestResource.includes(:has_many_objects).find(1)
80
80
  end
81
81
 
82
+ it "should be able to chain find on top of an includes call and a scope" do
83
+ TestResource.connection.expects(:get).with("/test_resources.json?birthday%5Bdate%5D=5&find%5Bids%5D=1").returns({"id" => 1, "has_many_object_ids" => [1,2]})
84
+ HasManyObject.connection.expects(:get).with("/has_many_objects.json?ids%5B%5D=1&ids%5B%5D=2").returns([])
85
+
86
+ TestResource.includes(:has_many_objects).birthday(5).find(1)
87
+ end
88
+
89
+ it "should disregard condition order" do
90
+ TestResource.connection.expects(:get).with("/test_resources.json?birthday%5Bdate%5D=5&find%5Bids%5D=1").returns({"id" => 1, "has_many_object_ids" => [1,2]})
91
+ HasManyObject.connection.expects(:get).with("/has_many_objects.json?ids%5B%5D=1&ids%5B%5D=2").returns([])
92
+
93
+ TestResource.birthday(5).includes(:has_many_objects).find(1)
94
+ end
95
+
82
96
  it "should be able to use a scope with arguments" do
83
97
  TestResource.connection.expects(:get)
84
98
  .with("/test_resources.json?active=true&birthday%5Bdate%5D=5").returns([{"id" => 10}])
@@ -4,7 +4,7 @@ require 'json'
4
4
  include ApiResource
5
5
 
6
6
  describe Mocks do
7
-
7
+
8
8
  # we set up the mocks in spec helper, so we can just assert this
9
9
  it "should hijack the connection" do
10
10
  ApiResource::Mocks::Interface.any_instance.expects(:get).once.returns(
@@ -12,29 +12,29 @@ describe Mocks do
12
12
  )
13
13
  TestResource.reload_class_attributes
14
14
  end
15
-
15
+
16
16
  it "should allow the user to raise errors for invalid responsed" do
17
- old_err_status = ApiResource.raise_missing_definition_error
17
+ old_err_status = ApiResource.raise_missing_definition_error
18
18
  ApiResource::Base.raise_missing_definition_error = true
19
-
19
+
20
20
  lambda {
21
21
  class MyNewInvalidResource < ApiResource::Base; end
22
- MyNewInvalidResource.new
22
+ MyNewInvalidResource.new
23
23
  }.should raise_error(ApiResource::ResourceNotFound)
24
-
24
+
25
25
  ApiResource.raise_missing_definition_error = old_err_status
26
26
  end
27
27
 
28
28
  it "should merge params for a request" do
29
29
  resp = ApiResource::Base.connection.get(
30
- "/mock_with_block/1?#{{:test => "abc"}.to_query}"
30
+ "/mock_with_block/1.json?#{{:test => "abc"}.to_query}"
31
31
  )
32
32
  resp["id"].should eql "1"
33
33
  resp["test"].should eql "abc"
34
34
  end
35
35
 
36
36
  context "Mock Request" do
37
- context "Initialize" do
37
+ context "Initialize" do
38
38
  it "should correctly assign blank params" do
39
39
  request = ApiResource::Mocks::MockRequest.new(:get, "/authenticate.json?token=")
40
40
  request.params.should eql({"token" => ""})
@@ -70,5 +70,5 @@ describe Mocks do
70
70
 
71
71
  end
72
72
  end
73
-
73
+
74
74
  end
@@ -36,8 +36,8 @@ describe "With Prefixes" do
36
36
  it "should use the prefix to create a new record" do
37
37
  prefix_model.send(:connection).expects(:post)
38
38
  .with(
39
- "/foreign/123/prefix_models.json",
40
- {"prefix_model" => {"name" => "test"}}.to_json,
39
+ "/foreign/123/prefix_models.json",
40
+ has_entry(:prefix_model, has_entry('name', 'test')),
41
41
  instance_of(Hash)
42
42
  )
43
43
  prefix_model.save
@@ -90,9 +90,8 @@ describe "With Prefixes" do
90
90
  prefix_model.name = "changed name"
91
91
  prefix_model.send(:connection).expects(:put)
92
92
  .with(
93
-
94
- "/foreign/123/prefix_models/456.json",
95
- {"prefix_model" => {"name" => "changed name"}}.to_json,
93
+ "/foreign/123/prefix_models/456.json",
94
+ has_entry(:prefix_model, has_entry('name', 'changed name')),
96
95
  instance_of(Hash)
97
96
  )
98
97
  prefix_model.save
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApiResource::Scopes do
4
+
5
+ before(:all) do
6
+ ScopeResource.class_eval do
7
+ scope :no_arg, {}
8
+ scope :one_arg, {id: :req}
9
+ scope :one_array_arg, {ids: :req}
10
+ scope :two_args, {page: :req, per_page: :req}
11
+ scope :opt_args, {arg1: :opt}
12
+ scope :req_and_opt_args, {arg1: :req, arg2: :opt}
13
+ scope :var_args, {ids: :rest}
14
+ scope :mix_args, {id: :req, vararg: :rest}
15
+ end
16
+ end
17
+
18
+ context "Constructing arguments" do
19
+
20
+ it "should be able to query scopes on the current model" do
21
+ ScopeResource.no_arg.to_query.should eql(
22
+ "no_arg=true"
23
+ )
24
+ ScopeResource.one_arg(5).to_query.should eql(
25
+ "one_arg[id]=5"
26
+ )
27
+ ScopeResource.one_array_arg([3, 5]).to_query.should eql(
28
+ "one_array_arg[ids][]=3&one_array_arg[ids][]=5"
29
+ )
30
+ ScopeResource.two_args(1, 20).to_query.should eql(
31
+ "two_args[page]=1&two_args[per_page]=20"
32
+ )
33
+ $DEB = true
34
+ ScopeResource.opt_args.to_query.should eql(
35
+ "opt_args=true"
36
+ )
37
+ ScopeResource.opt_args(3).to_query.should eql(
38
+ "opt_args[arg1]=3"
39
+ )
40
+ ScopeResource.var_args(1, 2).to_query.should eql(
41
+ "var_args[ids][]=1&var_args[ids][]=2"
42
+ )
43
+ args = ["a", {opt1: 1}, {opt2: 2}]
44
+ ScopeResource.mix_args(*args).to_query.should eql(
45
+ "mix_args[id]=a&mix_args[vararg][][opt1]=1&mix_args[vararg][][opt2]=2"
46
+ )
47
+ end
48
+ end
49
+
50
+ context '#add_scopes' do
51
+
52
+ it 'applies static scopes' do
53
+ ScopeResource.expects(:no_arg).returns(ScopeResource)
54
+ ScopeResource.add_scopes(no_arg: 1)
55
+ end
56
+
57
+ it 'applies scopes with one argument' do
58
+ ScopeResource.expects(:one_arg).with(5).returns(ScopeResource)
59
+ ScopeResource.add_scopes(one_arg: {id: 5})
60
+ end
61
+
62
+ it 'applies scopes with an array argument' do
63
+ ScopeResource.expects(:one_array_arg).with([5]).returns(ScopeResource)
64
+ ScopeResource.add_scopes(one_array_arg: {ids: [5]})
65
+ end
66
+
67
+ it 'applies scopes with two arguments' do
68
+ ScopeResource.expects(:two_args).with(7,9).returns(ScopeResource)
69
+ ScopeResource.add_scopes(two_args: {page: 7, per_page: 9})
70
+ end
71
+
72
+ it 'applies scopes with optional arguments when those arguments are supplied' do
73
+ ScopeResource.expects(:opt_args).with(5).returns(ScopeResource)
74
+ ScopeResource.add_scopes(opt_args: {arg1: 5})
75
+ end
76
+
77
+ it "doesn't apply scopes with only optional arguments when there are no supplied args" do
78
+ ScopeResource.expects(:opt_args).never
79
+ ScopeResource.add_scopes(opt_args: {})
80
+ end
81
+
82
+ it "applies scopes that have both optional and required args with only the required args if the optional args are not passed in" do
83
+ ScopeResource.expects(:req_and_opt_args).with(5).returns(ScopeResource)
84
+ ScopeResource.add_scopes(req_and_opt_args: {arg1: 5})
85
+ end
86
+
87
+ it "applies scopes with variable arg lists" do
88
+ ScopeResource.expects(:var_args).with([5,6,7]).returns(ScopeResource)
89
+ ScopeResource.add_scopes(var_args: {ids: [5,6,7]})
90
+ end
91
+
92
+ it "applies scopes with mixed arg lists" do
93
+ ScopeResource.expects(:mix_args).with(4,[5,6,7]).returns(ScopeResource)
94
+ ScopeResource.add_scopes(mix_args: {id: 4, vararg: [5,6,7]})
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ module ApiResource
4
+
5
+ describe Serializer do
6
+
7
+ before(:each) do
8
+ TestResource.reload_resource_definition
9
+ TestResource.has_many :has_many_objects
10
+ TestResource.define_attributes :attr1, :attr2
11
+ TestResource.include_root_in_json = false
12
+ end
13
+
14
+ after(:all) do
15
+ TestResource.include_root_in_json = true
16
+ end
17
+
18
+ subject {
19
+ Serializer.new(instance)
20
+ }
21
+
22
+ let(:instance){
23
+ TestResource.new({
24
+ attr1: "attr1",
25
+ attr2: "attr2",
26
+ has_many_objects: []
27
+ })
28
+ }
29
+
30
+ context "#to_hash" do
31
+
32
+ it 'includes attributes' do
33
+
34
+ subject.to_hash["attr1"].should_not be_nil
35
+
36
+ end
37
+
38
+ it "should not include associations by default if
39
+ they have not changed" do
40
+
41
+ subject.to_hash["has_many_objects"].should be_nil
42
+ end
43
+
44
+ it "should include associations passed given in the include_associations array" do
45
+
46
+ subject = Serializer.new(
47
+ instance,
48
+ include_associations: [:has_many_objects]
49
+ )
50
+
51
+ subject.to_hash["has_many_objects"].should_not be_nil
52
+ end
53
+
54
+ it "should include associations by default if they have changed" do
55
+ instance.has_many_objects = [{name: "test"}]
56
+ hash = subject.to_hash
57
+ hash["has_many_objects"].should_not be_nil
58
+ end
59
+
60
+ it "should not include unknown attributes unless they
61
+ are passed in via the include_extras array" do
62
+
63
+ TestResource.class_eval do
64
+ define_attributes :attr3, access_level: :protected
65
+ end
66
+
67
+ instance = TestResource.instantiate_record({
68
+ attr1: "attr1",
69
+ attr2: "attr2",
70
+ attr3: "attr3"
71
+ })
72
+
73
+ subject = Serializer.new(instance)
74
+ subject.to_hash["attr3"].should be_nil
75
+
76
+ subject = Serializer.new(instance, include_extras: [:attr3])
77
+ subject.to_hash["attr3"].should_not be_nil
78
+ end
79
+
80
+ it "should ignore fields set under the except option" do
81
+ tst = TestResource.new({
82
+ attr1: "attr1",
83
+ attr2: "attr2"
84
+ })
85
+ hash = JSON.parse(tst.to_json(except: [:attr1]))
86
+ hash["attr1"].should be_nil
87
+ hash["attr2"].should be_present
88
+ end
89
+
90
+ context "Nested Objects" do
91
+
92
+ before(:all) do
93
+ TestResource.has_many(:has_many_objects)
94
+ end
95
+
96
+ after(:all) do
97
+ TestResource.reload_resource_definition
98
+ end
99
+
100
+ it "should include the id of nested objects in the serialization" do
101
+ instance.has_many_objects = [
102
+ {name: "123", id: "1"}
103
+ ]
104
+ subject = Serializer.new(
105
+ instance,
106
+ include_associations: [:has_many_objects]
107
+ )
108
+ subject.to_hash["has_many_objects"].first["id"].should_not be_nil
109
+ end
110
+
111
+ it "should exclude include the id of new nested objects in the
112
+ serialization" do
113
+ instance.has_many_objects = [
114
+ {name: "123"}
115
+ ]
116
+ subject = Serializer.new(
117
+ instance,
118
+ include_associations: [:has_many_objects]
119
+ )
120
+ object_hash = subject.to_hash["has_many_objects"].first
121
+ object_hash.keys.should_not include "id"
122
+ end
123
+
124
+ end
125
+
126
+ context 'Foreign keys' do
127
+
128
+ context 'Prefixed' do
129
+
130
+ before(:all) do
131
+ TestResource.prefix =
132
+ "/belongs_to_objects/:belongs_to_object_id/"
133
+ end
134
+
135
+ after(:all) do
136
+ TestResource.prefix = "/"
137
+ end
138
+
139
+ it 'excludes the foreign key when it is nested in the prefix' do
140
+ instance.belongs_to_object_id = 123
141
+ subject.to_hash["belongs_to_object_id"].should be_blank
142
+ end
143
+
144
+ end
145
+
146
+ it "should include the foreign_key_id when saving" do
147
+ instance.stubs(:id => 123)
148
+ instance.has_many_object_ids = [4]
149
+ subject.to_hash[:has_many_object_ids].should eql([4])
150
+ end
151
+
152
+ end
153
+
154
+ end
155
+ end
156
+ end