ruby-trello 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/client_spec.rb CHANGED
@@ -1,30 +1,131 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
- module Trello
4
- describe Client do
5
- before(:all) do
6
- Client.public_key = 'dummy'
7
- Client.secret = 'dummy'
3
+ include Trello
4
+ include Trello::Authorization
5
+
6
+ describe Client, "and how it handles authorization" do
7
+ let (:fake_ok_response) {
8
+ stub "A fake OK response",
9
+ :code => 200,
10
+ :body => "A fake response body"
11
+ }
12
+
13
+ before do
14
+ TInternet.stub(:execute).and_return fake_ok_response
15
+ Authorization::AuthPolicy.stub(:authorize) do |request|
16
+ request
8
17
  end
18
+ end
19
+
20
+ it "authorizes before it queries the internet" do
21
+ AuthPolicy.should_receive(:authorize).once.ordered
22
+ TInternet.should_receive(:execute).once.ordered
23
+
24
+ Client.get "/xxx"
25
+ end
26
+
27
+ it "queries the internet with expanded earl and query parameters" do
28
+ expected_uri = Addressable::URI.parse("https://api.trello.com/1/xxx?a=1&b=2")
29
+ expected_request = Request.new :get, expected_uri, {}
30
+
31
+ TInternet.should_receive(:execute).once.with expected_request
32
+
33
+ Client.get "/xxx", :a => "1", :b => "2"
34
+ end
35
+
36
+ it "encodes parameters" do
37
+ expected_uri = Addressable::URI.parse("https://api.trello.com/1/xxx?name=Jazz%20Kang")
38
+ expected_request = Request.new :get, expected_uri, {}
39
+
40
+ TInternet.should_receive(:execute).once.with expected_request
9
41
 
10
- context 'keys' do
11
- after do
12
- Client.public_key = 'dummy'
13
- end
42
+ Client.get "/xxx", :name => "Jazz Kang"
43
+ end
44
+
45
+ it "raises an error when response has non-200 status" do
46
+ expected_error_message = "An error response"
47
+ response_with_non_200_status = stub "A fake OK response",
48
+ :code => 201,
49
+ :body => expected_error_message
50
+
51
+ TInternet.stub(:execute).and_return response_with_non_200_status
52
+
53
+ lambda{Client.get "/xxx"}.should raise_error expected_error_message
54
+ end
55
+
56
+ it "uses version 1 of the API" do
57
+ TInternet.should_receive(:execute).once do |request|
58
+ request.uri.to_s.should =~ /1\//
59
+ fake_ok_response
60
+ end
14
61
 
15
- it 'throws an error if the public key is ommitted' do
16
- Client.public_key = ''
17
- lambda { Client.send(:consumer) }.should raise_error(Client::EnterYourPublicKey)
18
- end
62
+ Client.get "/"
63
+ end
19
64
 
20
- after do
21
- Client.secret = 'dummy'
22
- end
65
+ it "omits the \"?\" when no parameters" do
66
+ TInternet.should_receive(:execute).once do |request|
67
+ request.uri.to_s.should_not =~ /\?$/
68
+ fake_ok_response
69
+ end
70
+
71
+ Client.get "/xxx"
72
+ end
73
+
74
+ it "supports post" do
75
+ TInternet.should_receive(:execute).once.and_return fake_ok_response
76
+
77
+ Client.post "/xxx", { :phil => "T' north" }
78
+ end
23
79
 
24
- it 'throws an error if the secret is ommitted' do
25
- Client.secret = ''
26
- lambda { Client.send(:consumer) }.should raise_error(Client::EnterYourSecret)
27
- end
80
+ it "supplies the body for a post" do
81
+ expected_body = { :name => "Phil", :nickname => "The Crack Fox" }
82
+
83
+ TInternet.should_receive(:execute).once do |request|
84
+ request.body.should == expected_body
85
+ fake_ok_response
86
+ end
87
+
88
+ Client.post "/xxx", expected_body
89
+ end
90
+
91
+ it "supplies the path for a post" do
92
+ expected_path = "/xxx"
93
+
94
+ TInternet.should_receive(:execute).once do |request|
95
+ request.uri.path.should =~ /#{expected_path}$/
96
+ fake_ok_response
28
97
  end
98
+
99
+ Client.post "/xxx", {}
100
+ end
101
+
102
+ it "supports put" do
103
+ expected_path = "/xxx"
104
+
105
+ TInternet.should_receive(:execute).once.and_return fake_ok_response
106
+
107
+ Client.put "/xxx", { :phil => "T' north" }
108
+ end
109
+
110
+ it "supplies the body for a put" do
111
+ expected_body = { :name => "Phil", :nickname => "The Crack Fox" }
112
+
113
+ TInternet.should_receive(:execute).once do |request|
114
+ request.body.should == expected_body
115
+ fake_ok_response
116
+ end
117
+
118
+ Client.put "/xxx", expected_body
119
+ end
120
+
121
+ it "supplies the path for a put" do
122
+ expected_path = "/xxx"
123
+
124
+ TInternet.should_receive(:execute).once do |request|
125
+ request.uri.path.should =~ /#{expected_path}$/
126
+ fake_ok_response
127
+ end
128
+
129
+ Client.put "/xxx", {}
29
130
  end
30
- end
131
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ require 'integration/integration_test'
3
+
4
+ describe "Authorizing read-only requests", :broken => true do
5
+ include IntegrationTest
6
+
7
+ it "Reading public resources requires just a developer public key" do
8
+ uri = Addressable::URI.parse("https://api.trello.com/1/boards/4ed7e27fe6abb2517a21383d")
9
+ uri.query_values = {
10
+ :key => @developer_public_key
11
+ }
12
+
13
+ get(uri).code.should === 200
14
+ end
15
+
16
+ it "Reading private resources requires developer public key AND a member token" do
17
+ uri = Addressable::URI.parse("https://api.trello.com/1/boards/#{@welcome_board}")
18
+ uri.query_values = {
19
+ :key => @developer_public_key,
20
+ :token => @member_token
21
+ }
22
+
23
+ get(uri).code.should === 200
24
+ end
25
+
26
+ it "can fetch the welcome board" do
27
+ BasicAuthPolicy.developer_public_key = @developer_public_key
28
+ BasicAuthPolicy.member_token = @member_token
29
+
30
+ Container.set Trello::Authorization, "AuthPolicy", BasicAuthPolicy
31
+
32
+ welcome_board = Board.find @welcome_board
33
+ welcome_board.name.should === "Welcome Board"
34
+ welcome_board.id.should === @welcome_board
35
+ end
36
+ end
37
+
38
+ describe "OAuth", :broken => true do
39
+ include IntegrationTest
40
+
41
+ before do
42
+ Container.set Trello::Authorization, "AuthPolicy", OAuthPolicy
43
+ end
44
+
45
+ it "[!] actually does not enforce signature at all, only the keys are required" do
46
+ OAuthPolicy.consumer_credential = OAuthCredential.new @developer_public_key, nil
47
+ OAuthPolicy.token = OAuthCredential.new @access_token_key, nil
48
+
49
+ pending "I would expect this to fail because I have signed with nil secrets" do
50
+ lambda{Client.get("/boards/#{@welcome_board}/")}.should raise_error
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'integration/integration_test'
3
+
4
+ describe "how to use boards", :broken => true do
5
+ include IntegrationTest
6
+
7
+ context "given a valid access token" do
8
+ before :all do
9
+ OAuthPolicy.consumer_credential = OAuthCredential.new @developer_public_key, @developer_secret
10
+ OAuthPolicy.token = OAuthCredential.new @access_token_key, @access_token_secret
11
+ Container.set Trello::Authorization, "AuthPolicy", OAuthPolicy
12
+ end
13
+
14
+ after do
15
+ if @new_board and false == @new_board.closed?
16
+ @new_board.update_fields 'closed' => true
17
+ @new_board.save!
18
+ end
19
+ end
20
+
21
+ it "can add a board" do
22
+ @new_board = Board.create(:name => "An example")
23
+ @new_board.should_not be_nil
24
+ @new_board.id.should_not be_nil
25
+ @new_board.name.should == "An example"
26
+ @new_board.should_not be_closed
27
+ end
28
+
29
+ it "can read the welcome board" do
30
+ welcome_board = Board.find @welcome_board
31
+ welcome_board.name.should === "Welcome Board"
32
+ welcome_board.id.should === @welcome_board
33
+ end
34
+
35
+ it "can close a board" do
36
+ @new_board = Board.create(:name => "[#{Time.now}, CLOSED] An example")
37
+
38
+ @new_board.update_fields 'closed' => true
39
+ @new_board.save!
40
+
41
+ Board.find(@new_board.id).should be_closed
42
+ end
43
+
44
+ it "can list all boards" do
45
+ Client.get("/members/me/boards/").json_into(Board).should be_an Array
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,40 @@
1
+ module IntegrationTest
2
+ include Trello
3
+ include Trello::Authorization
4
+
5
+ class Container
6
+ class << self
7
+ def set(parent, name, value)
8
+ parent.send :remove_const, name
9
+ parent.const_set name, value
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.included(klass)
15
+ klass.class_eval do
16
+ before :all do
17
+ # Getting developer/member key
18
+ # 1. https://trello.com/1/appKey/generate
19
+ # 2. https://trello.com/1/connect?key=<public_key_here>&name=RubyTrelloIntegrationTests&response_type=token
20
+ # See: https://trello.com/board/trello-public-api/4ed7e27fe6abb2517a21383d
21
+
22
+ @developer_public_key = ENV["DEVELOPER_PUBLIC_KEY"]
23
+ @developer_secret = ENV["DEVELOPER_SECRET"]
24
+ @member_token = ENV["MEMBER_TOKEN"]
25
+ @welcome_board = ENV["WELCOME_BOARD"]
26
+ @access_token_key = ENV["ACCESS_TOKEN_KEY"]
27
+ @access_token_secret = ENV["ACCESS_TOKEN_SECRET"]
28
+
29
+ WebMock.disable!
30
+ end
31
+ end
32
+ end
33
+
34
+ protected
35
+
36
+ def get(uri)
37
+ require "rest_client"
38
+ RestClient.get uri.to_s
39
+ end
40
+ end
data/spec/list_spec.rb CHANGED
@@ -4,14 +4,9 @@ module Trello
4
4
  describe List do
5
5
  include Helpers
6
6
 
7
- before(:all) do
8
- Client.public_key = 'dummy'
9
- Client.secret = 'dummy'
10
- end
11
-
12
7
  before(:each) do
13
- stub_trello_request!(:get, "/lists/abcdef123456789123456789?", nil, JSON.generate(lists_details.first))
14
- stub_trello_request!(:get, "/boards/abcdef123456789123456789?", nil, JSON.generate(boards_details.first))
8
+ Client.stub(:get).with("/lists/abcdef123456789123456789").and_return JSON.generate(lists_details.first)
9
+ Client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
15
10
 
16
11
  @list = List.find("abcdef123456789123456789")
17
12
  end
@@ -34,11 +29,22 @@ module Trello
34
29
  end
35
30
  end
36
31
 
32
+ context "actions" do
33
+ it "has a list of actions" do
34
+ Client.stub(:get).with("/lists/abcdef123456789123456789/actions").and_return actions_payload
35
+ @list.actions.count.should be > 0
36
+ end
37
+ end
38
+
37
39
  context "cards" do
38
40
  it "has a list of cards" do
39
- stub_trello_request!(:get, "/lists/abcdef123456789123456789/cards?", { :filter => :open }, cards_payload)
41
+ Client.stub(:get).with("/lists/abcdef123456789123456789/cards", { :filter => :open }).and_return cards_payload
40
42
  @list.cards.count.should be > 0
41
43
  end
42
44
  end
45
+
46
+ it "is not closed" do
47
+ @list.closed?.should_not be_true
48
+ end
43
49
  end
44
- end
50
+ end
data/spec/member_spec.rb CHANGED
@@ -6,35 +6,38 @@ module Trello
6
6
  describe Member do
7
7
  include Helpers
8
8
 
9
- before(:all) do
10
- Client.public_key = 'dummy'
11
- Client.secret = 'dummy'
12
- end
13
-
14
9
  before(:each) do
15
- stub_trello_request!(:get, '/members/me?', nil, user_payload)
10
+ Client.stub(:get).with("/members/me").and_return user_payload
16
11
 
17
12
  @member = Member.find('me')
18
13
  end
19
14
 
20
15
  context "actions" do
21
- it "retrieves a list of actions" do
22
- stub_trello_request!(:get, '/members/me/actions?', nil, actions_payload)
16
+ it "retrieves a list of actions", :refactor => true do
17
+ Client.stub(:get).with("/members/me/actions").and_return actions_payload
23
18
  @member.actions.count.should be > 0
24
19
  end
25
20
  end
26
21
 
27
22
  context "boards" do
28
23
  it "has a list of boards" do
29
- stub_trello_request!(:get, '/members/me/boards?', { :filter => :all }, boards_payload)
24
+ Client.stub(:get).with("/members/me/boards", { :filter => :all }).and_return boards_payload
30
25
  boards = @member.boards
31
26
  boards.count.should be > 0
32
27
  end
33
28
  end
34
29
 
30
+ context "cards" do
31
+ it "has a list of cards" do
32
+ Client.stub(:get).with("/members/me/cards", { :filter => :open }).and_return cards_payload
33
+ cards = @member.cards
34
+ cards.count.should be > 0
35
+ end
36
+ end
37
+
35
38
  context "organizations" do
36
39
  it "has a list of organizations" do
37
- stub_trello_request!(:get, '/members/me/organizations?', { :filter => :all }, orgs_payload)
40
+ Client.stub(:get).with("/members/me/organizations", { :filter => :all }).and_return orgs_payload
38
41
  orgs = @member.organizations
39
42
  orgs.count.should be > 0
40
43
  end
@@ -62,4 +65,4 @@ module Trello
62
65
  end
63
66
  end
64
67
  end
65
- end
68
+ end
@@ -0,0 +1,83 @@
1
+ require "spec_helper"
2
+
3
+ include Trello::Authorization
4
+ include Trello
5
+
6
+ describe OAuthPolicy do
7
+ before do
8
+ OAuthPolicy.consumer_credential = OAuthCredential.new "xxx", "xxx"
9
+ OAuthPolicy.token = nil
10
+ end
11
+
12
+ it "adds an authorization header" do
13
+ uri = Addressable::URI.parse("https://xxx/")
14
+
15
+ request = Request.new :get, uri
16
+
17
+ authorized_request = OAuthPolicy.authorize request
18
+
19
+ authorized_request.headers.keys.should include "Authorization"
20
+ end
21
+
22
+ it "preserves query parameters" do
23
+ uri = Addressable::URI.parse("https://xxx/?name=Riccardo")
24
+ request = Request.new :get, uri
25
+
26
+ authorized_request = OAuthPolicy.authorize request
27
+
28
+ the_query_parameters = Addressable::URI.parse(authorized_request.uri).query_values
29
+ the_query_parameters.should == {"name" => "Riccardo"}
30
+ end
31
+
32
+ it "adds the correct signature as part of authorization header" do
33
+ Clock.stub(:timestamp).and_return "1327048592"
34
+ Nonce.stub(:next).and_return "b94ff2bf7f0a5e87a326064ae1dbb18f"
35
+
36
+ OAuthPolicy.consumer_credential = OAuthCredential.new "consumer_key", "consumer_secret"
37
+
38
+ request = Request.new :get, Addressable::URI.parse("http://xxx/")
39
+
40
+ authorized_request = OAuthPolicy.authorize request
41
+
42
+ authorized_request.headers["Authorization"].should =~ /oauth_signature="u7CmId4WEDUqPdHnWVf1JVChFmg%3D"/
43
+ end
44
+
45
+ it "adds correct signature for uri with parameters" do
46
+ Clock.stub(:timestamp).and_return "1327351010"
47
+ Nonce.stub(:next).and_return "f5474aaf44ca84df0b09870044f91c69"
48
+
49
+ OAuthPolicy.consumer_credential = OAuthCredential.new "consumer_key", "consumer_secret"
50
+
51
+ request = Request.new :get, Addressable::URI.parse("http://xxx/?a=b")
52
+
53
+ authorized_request = OAuthPolicy.authorize request
54
+
55
+ authorized_request.headers["Authorization"].should =~ /oauth_signature="ABL%2FcOSGJSbvvLt1gW2nV9i%2FDyA%3D"/
56
+ end
57
+
58
+ it "fails if consumer_credential is unset" do
59
+ OAuthPolicy.consumer_credential = nil
60
+
61
+ request = Request.new :get, Addressable::URI.parse("http://xxx/")
62
+
63
+ lambda{OAuthPolicy.authorize request}.should raise_error "The consumer_credential has not been supplied."
64
+ end
65
+
66
+ it "can sign with token" do
67
+ Clock.stub(:timestamp).and_return "1327360530"
68
+ Nonce.stub(:next).and_return "4f610cb28e7aa8711558de5234af1f0e"
69
+
70
+ OAuthPolicy.consumer_credential = OAuthCredential.new "consumer_key", "consumer_secret"
71
+ OAuthPolicy.token = OAuthCredential.new "token_key", "token_secret"
72
+
73
+ request = Request.new :get, Addressable::URI.parse("http://xxx/")
74
+
75
+ authorized_request = OAuthPolicy.authorize request
76
+
77
+ authorized_request.headers["Authorization"].should =~ /oauth_signature="1Boj4fo6KiXA4xGD%2BKF5QOD36PI%3D"/
78
+ end
79
+
80
+ it "adds correct signature for https uri"
81
+ it "adds correct signature for verbs other than get"
82
+ it "can sign with access token too"
83
+ end