koala 0.9.0 → 1.0.0.beta
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.
- data/CHANGELOG +33 -7
- data/Manifest +6 -14
- data/Rakefile +4 -3
- data/koala.gemspec +13 -8
- data/lib/koala/graph_api.rb +16 -3
- data/lib/koala/http_services.rb +100 -16
- data/lib/koala/rest_api.rb +73 -6
- data/lib/koala/test_users.rb +72 -0
- data/lib/koala.rb +101 -71
- data/readme.md +14 -13
- data/spec/facebook_data.yml +14 -8
- data/spec/koala/api_base_tests.rb +7 -0
- data/spec/koala/assets/beach.jpg +0 -0
- data/spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb +5 -1
- data/spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb +9 -4
- data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +10 -61
- data/spec/koala/graph_api/graph_api_tests.rb +86 -0
- data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +130 -126
- data/spec/koala/graph_api/graph_collection_tests.rb +2 -2
- data/spec/koala/live_testing_data_helper.rb +40 -12
- data/spec/koala/net_http_service_tests.rb +401 -152
- data/spec/koala/oauth/oauth_tests.rb +41 -72
- data/spec/koala/rest_api/rest_api_no_access_token_tests.rb +7 -76
- data/spec/koala/rest_api/rest_api_tests.rb +118 -0
- data/spec/koala/rest_api/rest_api_with_access_token_tests.rb +6 -4
- data/spec/koala/test_users/test_users_tests.rb +208 -0
- data/spec/koala/typhoeus_service_tests.rb +156 -0
- data/spec/koala_spec_helper.rb +43 -4
- data/spec/koala_spec_without_mocks.rb +4 -4
- data/spec/mock_facebook_responses.yml +69 -3
- data/spec/mock_http_service.rb +16 -1
- metadata +49 -23
- data/examples/oauth_playground/Capfile +0 -2
- data/examples/oauth_playground/LICENSE +0 -22
- data/examples/oauth_playground/Rakefile +0 -4
- data/examples/oauth_playground/config/deploy.rb +0 -39
- data/examples/oauth_playground/config/facebook.yml +0 -13
- data/examples/oauth_playground/config.ru +0 -27
- data/examples/oauth_playground/lib/load_facebook.rb +0 -3
- data/examples/oauth_playground/lib/oauth_playground.rb +0 -187
- data/examples/oauth_playground/readme.md +0 -8
- data/examples/oauth_playground/spec/oauth_playground_spec.rb +0 -35
- data/examples/oauth_playground/spec/spec_helper.rb +0 -36
- data/examples/oauth_playground/tmp/restart.txt +0 -0
- data/examples/oauth_playground/views/index.erb +0 -206
- data/examples/oauth_playground/views/layout.erb +0 -39
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
shared_examples_for "Koala GraphAPI" do
|
|
2
|
+
# all Graph API instances should pass these tests, regardless of configuration
|
|
3
|
+
|
|
4
|
+
# API
|
|
5
|
+
it "should never use the rest api server" do
|
|
6
|
+
Koala.should_receive(:make_request).with(
|
|
7
|
+
anything,
|
|
8
|
+
anything,
|
|
9
|
+
anything,
|
|
10
|
+
hash_not_including(:rest_api => true)
|
|
11
|
+
).and_return(Koala::Response.new(200, "", {}))
|
|
12
|
+
|
|
13
|
+
@api.api("anything")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# GRAPH CALL
|
|
17
|
+
describe "graph_call" do
|
|
18
|
+
it "should pass all arguments to the api method" do
|
|
19
|
+
args = ["koppel", {}, "get", {:a => :b}]
|
|
20
|
+
|
|
21
|
+
@api.should_receive(:api).with(*args)
|
|
22
|
+
|
|
23
|
+
@api.graph_call(*args)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should throw an APIError if the result hash has an error key" do
|
|
27
|
+
Koala.stub(:make_request).and_return(Koala::Response.new(500, {"error" => "An error occurred!"}, {}))
|
|
28
|
+
lambda { @api.graph_call("koppel", {}) }.should raise_exception(Koala::Facebook::APIError)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# SEARCH
|
|
33
|
+
it "should be able to search" do
|
|
34
|
+
result = @api.search("facebook")
|
|
35
|
+
result.length.should be_an(Integer)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# DATA
|
|
39
|
+
# access public info
|
|
40
|
+
|
|
41
|
+
it "should get public data about a user" do
|
|
42
|
+
result = @api.get_object("koppel")
|
|
43
|
+
# the results should have an ID and a name, among other things
|
|
44
|
+
(result["id"] && result["name"]).should_not be_nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should get public data about a Page" do
|
|
48
|
+
result = @api.get_object("contextoptional")
|
|
49
|
+
# the results should have an ID and a name, among other things
|
|
50
|
+
(result["id"] && result["name"]).should
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should be able to get multiple objects" do
|
|
54
|
+
results = @api.get_objects(["contextoptional", "naitik"])
|
|
55
|
+
results.length.should == 2
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should be able to access a user's picture" do
|
|
59
|
+
@api.get_picture("chris.baclig").should =~ /http\:\/\//
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should be able to access a user's picture, given a picture type" do
|
|
63
|
+
@api.get_picture("chris.baclig", {:type => 'large'}).should =~ /^http\:\/\//
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "should be able to access connections from public Pages" do
|
|
67
|
+
result = @api.get_connections("contextoptional", "photos")
|
|
68
|
+
result.should be_a(Array)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# SEARCH
|
|
72
|
+
it "should be able to search" do
|
|
73
|
+
result = @api.search("facebook")
|
|
74
|
+
result.length.should be_an(Integer)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# PAGING THROUGH COLLECTIONS
|
|
78
|
+
# see also graph_collection_tests
|
|
79
|
+
it "should make a request for a page when provided a specific set of page params" do
|
|
80
|
+
query = [1, 2]
|
|
81
|
+
@api.should_receive(:graph_call).with(*query)
|
|
82
|
+
@api.get_page(query)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
end
|
|
@@ -1,150 +1,154 @@
|
|
|
1
1
|
shared_examples_for "Koala GraphAPI with an access token" do
|
|
2
|
-
it "should get public data about a user" do
|
|
3
|
-
result = @api.get_object("koppel")
|
|
4
|
-
# the results should have an ID and a name, among other things
|
|
5
|
-
(result["id"] && result["name"]).should_not be_nil
|
|
6
|
-
end
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
it "should get private data about a user" do
|
|
4
|
+
result = @api.get_object("koppel")
|
|
5
|
+
# updated_time should be a pretty fixed test case
|
|
6
|
+
result["updated_time"].should_not be_nil
|
|
7
|
+
end
|
|
13
8
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
9
|
+
it "should get data about 'me'" do
|
|
10
|
+
result = @api.get_object("me")
|
|
11
|
+
result["updated_time"].should
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should be able to get multiple objects" do
|
|
15
|
+
result = @api.get_objects(["contextoptional", "naitik"])
|
|
16
|
+
result.length.should == 2
|
|
17
|
+
end
|
|
18
|
+
it "should be able to access connections from users" do
|
|
19
|
+
result = @api.get_connections("lukeshepard", "likes")
|
|
20
|
+
result.length.should > 0
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# PUT
|
|
24
|
+
it "should be able to write an object to the graph" do
|
|
25
|
+
result = @api.put_wall_post("Hello, world, from the test suite!")
|
|
26
|
+
@temporary_object_id = result["id"]
|
|
27
|
+
@temporary_object_id.should_not be_nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# DELETE
|
|
31
|
+
it "should be able to delete posts" do
|
|
32
|
+
result = @api.put_wall_post("Hello, world, from the test suite delete method!")
|
|
33
|
+
object_id_to_delete = result["id"]
|
|
34
|
+
delete_result = @api.delete_object(object_id_to_delete)
|
|
35
|
+
delete_result.should == true
|
|
36
|
+
end
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
it "should be able to delete likes" do
|
|
39
|
+
result = @api.put_wall_post("Hello, world, from the test suite delete method!")
|
|
40
|
+
@temporary_object_id = result["id"]
|
|
41
|
+
@api.put_like(@temporary_object_id)
|
|
42
|
+
delete_like_result = @api.delete_like(@temporary_object_id)
|
|
43
|
+
delete_like_result.should == true
|
|
44
|
+
end
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
# additional put tests
|
|
47
|
+
it "should be able to verify messages posted to a wall" do
|
|
48
|
+
message = "the cats are asleep"
|
|
49
|
+
put_result = @api.put_wall_post(message)
|
|
50
|
+
@temporary_object_id = put_result["id"]
|
|
51
|
+
get_result = @api.get_object(@temporary_object_id)
|
|
52
|
+
|
|
53
|
+
# make sure the message we sent is the message that got posted
|
|
54
|
+
get_result["message"].should == message
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should be able to post a message with an attachment to a feed" do
|
|
58
|
+
result = @api.put_wall_post("Hello, world, from the test suite again!", {:name => "Context Optional", :link => "http://www.contextoptional.com/"})
|
|
59
|
+
@temporary_object_id = result["id"]
|
|
60
|
+
@temporary_object_id.should_not be_nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should be able to post photos to the user's wall with an open file object" do
|
|
64
|
+
file_hash = {
|
|
65
|
+
"content_type" => "image/jpg",
|
|
66
|
+
"path" => File.join(File.dirname(__FILE__), "..", "assets", "beach.jpg"),
|
|
67
|
+
"file" => File.open(File.join(File.dirname(__FILE__), "..", "assets", "beach.jpg"))
|
|
68
|
+
}
|
|
69
|
+
result = @api.put_picture(file_hash)
|
|
70
|
+
@temporary_object_id = result["id"]
|
|
71
|
+
@temporary_object_id.should_not be_nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should be able to post photos to the user's wall without an open file object" do
|
|
75
|
+
file_hash = {
|
|
76
|
+
"content_type" => "image/jpg",
|
|
77
|
+
"path" => File.join(File.dirname(__FILE__), "..", "assets", "beach.jpg")
|
|
78
|
+
}
|
|
79
|
+
result = @api.put_picture(file_hash)
|
|
80
|
+
@temporary_object_id = result["id"]
|
|
81
|
+
@temporary_object_id.should_not be_nil
|
|
82
|
+
end
|
|
47
83
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
end
|
|
84
|
+
it "should be able to verify a photo posted to a user's wall" do
|
|
85
|
+
file_hash = {
|
|
86
|
+
"content_type" => "image/jpg",
|
|
87
|
+
"path" => File.join(File.dirname(__FILE__), "..", "assets", "beach.jpg")
|
|
88
|
+
}
|
|
89
|
+
expected_message = "This is the test message"
|
|
55
90
|
|
|
91
|
+
result = @api.put_picture(file_hash, :message => expected_message)
|
|
92
|
+
@temporary_object_id = result["id"]
|
|
93
|
+
@temporary_object_id.should_not be_nil
|
|
56
94
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
result = @api.put_wall_post("Hello, world, from the test suite delete method!")
|
|
67
|
-
object_id_to_delete = result["id"]
|
|
68
|
-
delete_result = @api.delete_object(object_id_to_delete)
|
|
69
|
-
delete_result.should == true
|
|
70
|
-
end
|
|
95
|
+
get_result = @api.get_object(@temporary_object_id)
|
|
96
|
+
get_result["name"].should == expected_message
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "should be able to verify a message with an attachment posted to a feed" do
|
|
100
|
+
attachment = {"name" => "Context Optional", "link" => "http://www.contextoptional.com/"}
|
|
101
|
+
result = @api.put_wall_post("Hello, world, from the test suite again!", attachment)
|
|
102
|
+
@temporary_object_id = result["id"]
|
|
103
|
+
get_result = @api.get_object(@temporary_object_id)
|
|
71
104
|
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
@temporary_object_id = put_result["id"]
|
|
77
|
-
get_result = @api.get_object(@temporary_object_id)
|
|
78
|
-
|
|
79
|
-
# make sure the message we sent is the message that got posted
|
|
80
|
-
get_result["message"].should == message
|
|
81
|
-
end
|
|
105
|
+
# make sure the result we fetch includes all the parameters we sent
|
|
106
|
+
it_matches = attachment.inject(true) {|valid, param| valid && (get_result[param[0]] == attachment[param[0]])}
|
|
107
|
+
it_matches.should == true
|
|
108
|
+
end
|
|
82
109
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@temporary_object_id.should_not be_nil
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it "should be able to verify a message with an attachment posted to a feed" do
|
|
90
|
-
attachment = {"name" => "Context Optional", "link" => "http://www.contextoptional.com/"}
|
|
91
|
-
result = @api.put_wall_post("Hello, world, from the test suite again!", attachment)
|
|
92
|
-
@temporary_object_id = result["id"]
|
|
93
|
-
get_result = @api.get_object(@temporary_object_id)
|
|
94
|
-
|
|
95
|
-
# make sure the result we fetch includes all the parameters we sent
|
|
96
|
-
it_matches = attachment.inject(true) {|valid, param| valid && (get_result[param[0]] == attachment[param[0]])}
|
|
97
|
-
it_matches.should == true
|
|
98
|
-
end
|
|
110
|
+
it "should be able to comment on an object" do
|
|
111
|
+
result = @api.put_wall_post("Hello, world, from the test suite, testing comments!")
|
|
112
|
+
@temporary_object_id = result["id"]
|
|
99
113
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
# this will be deleted when the post gets deleted
|
|
105
|
-
comment_result = @api.put_comment(@temporary_object_id, "it's my comment!")
|
|
106
|
-
comment_result.should_not be_nil
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it "should be able to verify a comment posted about an object" do
|
|
110
|
-
message_text = "Hello, world, from the test suite, testing comments!"
|
|
111
|
-
result = @api.put_wall_post(message_text)
|
|
112
|
-
@temporary_object_id = result["id"]
|
|
113
|
-
|
|
114
|
-
# this will be deleted when the post gets deleted
|
|
115
|
-
comment_text = "it's my comment!"
|
|
116
|
-
comment_result = @api.put_comment(@temporary_object_id, comment_text)
|
|
117
|
-
get_result = @api.get_object(comment_result["id"])
|
|
118
|
-
|
|
119
|
-
# make sure the text of the comment matches what we sent
|
|
120
|
-
get_result["message"].should == comment_text
|
|
121
|
-
end
|
|
114
|
+
# this will be deleted when the post gets deleted
|
|
115
|
+
comment_result = @api.put_comment(@temporary_object_id, "it's my comment!")
|
|
116
|
+
comment_result.should_not be_nil
|
|
117
|
+
end
|
|
122
118
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
end
|
|
119
|
+
it "should be able to verify a comment posted about an object" do
|
|
120
|
+
message_text = "Hello, world, from the test suite, testing comments!"
|
|
121
|
+
result = @api.put_wall_post(message_text)
|
|
122
|
+
@temporary_object_id = result["id"]
|
|
128
123
|
|
|
129
|
-
#
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
end
|
|
124
|
+
# this will be deleted when the post gets deleted
|
|
125
|
+
comment_text = "it's my comment!"
|
|
126
|
+
comment_result = @api.put_comment(@temporary_object_id, comment_text)
|
|
127
|
+
get_result = @api.get_object(comment_result["id"])
|
|
134
128
|
|
|
135
|
-
#
|
|
136
|
-
|
|
129
|
+
# make sure the text of the comment matches what we sent
|
|
130
|
+
get_result["message"].should == comment_text
|
|
131
|
+
end
|
|
137
132
|
|
|
138
|
-
|
|
133
|
+
it "should be able to like an object" do
|
|
134
|
+
result = @api.put_wall_post("Hello, world, from the test suite, testing comments!")
|
|
135
|
+
@temporary_object_id = result["id"]
|
|
136
|
+
like_result = @api.put_like(@temporary_object_id)
|
|
137
|
+
like_result.should be_true
|
|
138
|
+
end
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
class FacebookWithAccessTokenTests < Test::Unit::TestCase
|
|
142
142
|
describe "Koala GraphAPI with an access token" do
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
include LiveTestingDataHelper
|
|
144
|
+
|
|
146
145
|
before :each do
|
|
147
146
|
@api = Koala::Facebook::GraphAPI.new(@token)
|
|
148
147
|
end
|
|
148
|
+
|
|
149
|
+
it_should_behave_like "Koala GraphAPI"
|
|
150
|
+
it_should_behave_like "Koala GraphAPI with an access token"
|
|
151
|
+
it_should_behave_like "Koala GraphAPI with GraphCollection"
|
|
152
|
+
|
|
149
153
|
end
|
|
150
154
|
end
|
|
@@ -65,7 +65,7 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
|
|
|
65
65
|
@api.should_receive(:graph_call).with(@base, @args).and_return(@second_page)
|
|
66
66
|
Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
|
|
67
67
|
|
|
68
|
-
@result.previous_page
|
|
68
|
+
@result.previous_page.should == @page_of_results
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
it "should return the next page of results" do
|
|
@@ -79,7 +79,7 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
|
|
|
79
79
|
it "should return nil it there are no other pages" do
|
|
80
80
|
%w{next previous}.each do |this|
|
|
81
81
|
@result.should_receive("#{this}_page_params".to_sym).and_return(nil)
|
|
82
|
-
@result.send("#{this}_page"
|
|
82
|
+
@result.send("#{this}_page").should == nil
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
end
|
|
@@ -1,15 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
module LiveTestingDataHelper
|
|
2
|
+
# in RSpec 2, included example groups no longer share any hooks or state with outside examples
|
|
3
|
+
# even if in the same block
|
|
4
|
+
# so we have to use a module to provide setup and teardown hooks for live testing
|
|
5
|
+
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.class_eval do
|
|
8
|
+
before :each do
|
|
9
|
+
@token = $testing_data["oauth_token"]
|
|
10
|
+
raise Exception, "Must supply access token to run FacebookWithAccessTokenTests!" unless @token
|
|
11
|
+
# track temporary objects created
|
|
12
|
+
@temporary_object_ids = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
after :each do
|
|
16
|
+
# clean up any temporary objects
|
|
17
|
+
@temporary_object_ids << @temporary_object_id if @temporary_object_id
|
|
18
|
+
count = @temporary_object_ids.length
|
|
19
|
+
errors = []
|
|
20
|
+
|
|
21
|
+
if count > 0
|
|
22
|
+
print "\nCleaning up #{count} temporary #{count > 1 ? "objects" : "object (#{@temporary_object_ids.first})"}..."
|
|
23
|
+
@temporary_object_ids.each do |id|
|
|
24
|
+
# get our API
|
|
25
|
+
api = @api || (@test_users ? @test_users.graph_api : nil)
|
|
26
|
+
raise "Unable to locate API when passed temporary object to delete!" unless api
|
|
27
|
+
|
|
28
|
+
# delete the object
|
|
29
|
+
result = (api.delete_object(id) rescue false)
|
|
30
|
+
# if we errored out or Facebook returned false, track that
|
|
31
|
+
errors << id unless result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if errors.length == 0
|
|
35
|
+
puts "done."
|
|
36
|
+
else
|
|
37
|
+
puts "cleaned up #{count - errors.length} objects, but errored out on the following:\n #{errors.join(", ")}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
13
40
|
end
|
|
14
41
|
end
|
|
42
|
+
end
|
|
15
43
|
end
|