ruby-trello 0.2.1 → 0.3.0

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/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