pivotal-tracker 0.5.1 → 0.5.3

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.
@@ -2,6 +2,8 @@
2
2
  <project>
3
3
  <id>102622</id>
4
4
  <name>Pivotal Tracker API Gem</name>
5
+ <first_iteration_start_time type="datetime">2011/12/05 06:00:00 UTC</first_iteration_start_time>
6
+ <current_iteration_number type="integer">4</current_iteration_number>
5
7
  <iteration_length type="integer">1</iteration_length>
6
8
  <week_start_day>Monday</week_start_day>
7
9
  <point_scale>0,1,2,3</point_scale>
@@ -5,6 +5,8 @@
5
5
  <name>Pivotal Tracker API Gem</name>
6
6
  <iteration_length type="integer">1</iteration_length>
7
7
  <week_start_day>Monday</week_start_day>
8
+ <first_iteration_start_time type="datetime">2011/12/05 06:00:00 UTC</first_iteration_start_time>
9
+ <current_iteration_number type="integer">4</current_iteration_number>
8
10
  <point_scale>0,1,2,3</point_scale>
9
11
  <account>Jon</account>
10
12
  <velocity_scheme>Average of 3 iterations</velocity_scheme>
@@ -55,6 +57,8 @@
55
57
  <name>Pivotal Tracker API Gem Target Project</name>
56
58
  <iteration_length type="integer">1</iteration_length>
57
59
  <week_start_day>Monday</week_start_day>
60
+ <first_iteration_start_time type="datetime">2011/12/05 06:00:00 UTC</first_iteration_start_time>
61
+ <current_iteration_number type="integer">4</current_iteration_number>
58
62
  <point_scale>0,1,2,3</point_scale>
59
63
  <account>Jon</account>
60
64
  <velocity_scheme>Average of 3 iterations</velocity_scheme>
@@ -112,6 +112,13 @@
112
112
  request_type: GET
113
113
  update_method: StaleFishFixtures.update_iterations_backlog_fixture
114
114
  last_updated_at: 2010-07-29T20:15:15+01:00
115
+ - iterations_current_backlog:
116
+ file: 'iterations_current_backlog.xml'
117
+ update_interval: 2.weeks
118
+ check_against: http://www.pivotaltracker.com/services/v3/projects/102622/iterations/current_backlog
119
+ request_type: GET
120
+ update_method: StaleFishFixtures.update_iterations_current_backlog_fixture
121
+ last_updated_at: 2010-07-29T20:15:14+01:00
115
122
  - iterations_all:
116
123
  file: 'iterations_all.xml'
117
124
  update_interval: 2.weeks
@@ -133,3 +140,15 @@
133
140
  request_type: POST
134
141
  update_method: StaleFishFixtures.create_new_story
135
142
  last_updated_at: 2010-07-29T20:15:17+01:00
143
+ - bugs:
144
+ file: 'bugs.xml'
145
+ update_interval: nil
146
+ check_against: http://www.pivotaltracker.com/services/v3/projects/102622/stories?filter=story_type%3Abug
147
+ request_type: GET
148
+ last_updated_at:
149
+ - features:
150
+ file: 'features.xml'
151
+ update_interval: nil
152
+ check_against: http://www.pivotaltracker.com/services/v3/projects/102622/stories?filter=story_type%3Afeature
153
+ request_type: GET
154
+ last_updated_at:
@@ -23,8 +23,8 @@ describe PivotalTracker::Activity do
23
23
  context "with a specified occurred since date filter" do
24
24
  it "should correctly url encode the occurred since date filter in the API call" do
25
25
  PivotalTracker::Client.stub!(:connection).and_return connection = double("Client Connection")
26
- connection.should_receive(:[]).with("/activities?limit=100&occurred_since_date=2010/07/29%2019:13:00%20+00:00")
27
- .and_return double("Connection", :get => '<blah></blah>')
26
+ url = "/activities?limit=100&occurred_since_date=2010/07/29%2019:13:00%20+00:00"
27
+ connection.should_receive(:[]).with(url).and_return double("Connection", :get => '<blah></blah>')
28
28
  PivotalTracker::Activity.all nil, :limit => 100, :occurred_since_date => DateTime.parse("2010/7/29 19:13:00 UTC")
29
29
  end
30
30
  end
@@ -53,7 +53,7 @@ describe PivotalTracker::Attachment do
53
53
 
54
54
  it "should return an attachment object with a pending status" do
55
55
  FakeWeb.allow_net_connect = true
56
- resource = @target_story.upload_attachment(File.dirname(__FILE__) + '/../../../LICENSE')
56
+ resource = @target_story.upload_attachment(File.dirname(__FILE__) + '/../../LICENSE')
57
57
  FakeWeb.allow_net_connect = @orig_net_lock
58
58
  resource.should be_a(PivotalTracker::Attachment)
59
59
  resource.status.should == 'Pending'
@@ -0,0 +1,148 @@
1
+ require "spec_helper"
2
+
3
+ describe PivotalTracker::Client do
4
+
5
+ describe ".connection" do
6
+
7
+ context "with no existing token" do
8
+
9
+ before do
10
+ PivotalTracker::Client.token = nil
11
+ end
12
+
13
+ it "raises a NoToken exception" do
14
+ lambda { PivotalTracker::Client.connection }.should raise_error(PivotalTracker::Client::NoToken)
15
+ end
16
+
17
+ describe "after setting a new token" do
18
+
19
+ before do
20
+ PivotalTracker::Client.token = "anewtoken"
21
+ end
22
+
23
+ it "called to RestClient::Resource using the new token" do
24
+ RestClient::Resource.should_receive(:new).
25
+ with(PivotalTracker::Client.api_url, :headers => { 'X-TrackerToken' => "anewtoken", 'Content-Type' => 'application/xml' })
26
+
27
+ PivotalTracker::Client.connection
28
+ end
29
+
30
+ it "returned the connection for the new token" do
31
+ @resource = Object.new
32
+
33
+ RestClient::Resource.should_receive(:new).
34
+ with(PivotalTracker::Client.api_url, :headers => { 'X-TrackerToken' => "anewtoken", 'Content-Type' => 'application/xml' }).
35
+ and_return(@resource)
36
+
37
+ PivotalTracker::Client.connection.should == @resource
38
+
39
+ # We need to clear the connections or it causes later spec failures
40
+ PivotalTracker::Client.clear_connections
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ context "with an existing token" do
48
+
49
+ before do
50
+ PivotalTracker::Client.token = "abc123"
51
+ end
52
+
53
+ it "returned a RestClient::Resource using the token" do
54
+ @resource = Object.new
55
+
56
+ RestClient::Resource.should_receive(:new).
57
+ with(PivotalTracker::Client.api_url, :headers => { 'X-TrackerToken' => "abc123", 'Content-Type' => 'application/xml' }).
58
+ and_return(@resource)
59
+
60
+ PivotalTracker::Client.connection.should == @resource
61
+ end
62
+
63
+ describe "after setting a new token" do
64
+
65
+ before do
66
+ PivotalTracker::Client.token = "anewtoken"
67
+ end
68
+
69
+ it "called to RestClient::Resource using the new token" do
70
+ RestClient::Resource.should_receive(:new).
71
+ with(PivotalTracker::Client.api_url, :headers => { 'X-TrackerToken' => "anewtoken", 'Content-Type' => 'application/xml' })
72
+
73
+ PivotalTracker::Client.connection
74
+ end
75
+
76
+ it "returned the connection for the new token" do
77
+ @resource = Object.new
78
+
79
+ RestClient::Resource.should_receive(:new).
80
+ with(PivotalTracker::Client.api_url, :headers => { 'X-TrackerToken' => "anewtoken", 'Content-Type' => 'application/xml' }).
81
+ and_return(@resource)
82
+
83
+ PivotalTracker::Client.connection.should == @resource
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+ end
90
+
91
+ describe ".tracker_host" do
92
+ it "returns www.pivotaltracker.com by default" do
93
+ PivotalTracker::Client.tracker_host.should == 'www.pivotaltracker.com'
94
+ end
95
+ end
96
+
97
+ describe ".tracker_host=" do
98
+ it "sets the tracker_host" do
99
+ tracker_host_url = 'http://some_other_tracker_tracker_host_url'
100
+ PivotalTracker::Client.tracker_host = tracker_host_url
101
+ PivotalTracker::Client.tracker_host.should == tracker_host_url
102
+ PivotalTracker::Client.tracker_host = nil
103
+ end
104
+ end
105
+
106
+ describe "#api_ssl_url" do
107
+ context "when not passed a username and password" do
108
+ before do
109
+ PivotalTracker::Client.tracker_host = nil
110
+ PivotalTracker::Client.use_ssl = true
111
+ end
112
+ it "returns https://www.pivotaltracker.com/services/v3" do
113
+ PivotalTracker::Client.api_ssl_url.should == 'https://www.pivotaltracker.com/services/v3'
114
+ end
115
+ end
116
+ context "when passed a username and password" do
117
+ before do
118
+ PivotalTracker::Client.tracker_host = nil
119
+ PivotalTracker::Client.use_ssl = false
120
+ end
121
+ it "returns https://USER:PASSWORD@www.pivotaltracker.com/services/v3" do
122
+ PivotalTracker::Client.api_ssl_url('USER', 'PASSWORD').should == 'https://USER:PASSWORD@www.pivotaltracker.com/services/v3'
123
+ end
124
+ end
125
+ end
126
+
127
+ describe "#api_url" do
128
+ context "when not passed a username and password" do
129
+ before do
130
+ PivotalTracker::Client.tracker_host = nil
131
+ PivotalTracker::Client.use_ssl = true
132
+ end
133
+ it "returns https://www.pivotaltracker.com/services/v3" do
134
+ PivotalTracker::Client.api_ssl_url.should == 'https://www.pivotaltracker.com/services/v3'
135
+ end
136
+ end
137
+ context "when passed a username and password" do
138
+ before do
139
+ PivotalTracker::Client.tracker_host = nil
140
+ PivotalTracker::Client.use_ssl = false
141
+ end
142
+ it "returns https://www.pivotaltracker.com/services/v3" do
143
+ PivotalTracker::Client.api_ssl_url('user', 'password').should == 'https://user:password@www.pivotaltracker.com/services/v3'
144
+ end
145
+ end
146
+ end
147
+
148
+ end
@@ -48,6 +48,18 @@ describe PivotalTracker::Iteration do
48
48
  @iterations.first.should be_a(PivotalTracker::Iteration)
49
49
  end
50
50
  end
51
+
52
+ describe ".current_backlog" do
53
+ before do
54
+ @iterations = PivotalTracker::Iteration.current_backlog(@project)
55
+ end
56
+
57
+ it "should return an array of Iterations for the given Project" do
58
+ @iterations.should be_a(Array)
59
+ @iterations.first.should be_a(PivotalTracker::Iteration)
60
+ end
61
+ end
62
+
51
63
 
52
64
  end
53
65
 
@@ -13,7 +13,7 @@ describe PivotalTracker::Project do
13
13
 
14
14
  it "should be a project instance" do
15
15
  @projects.first.should be_a(PivotalTracker::Project)
16
- end
16
+ end
17
17
  end
18
18
 
19
19
  context ".find" do
@@ -32,6 +32,14 @@ describe PivotalTracker::Project do
32
32
  it "should have false for use_https" do
33
33
  @project.use_https.should be_false
34
34
  end
35
+
36
+ it "should have first_iteration_start_time attribute" do
37
+ @project.respond_to?(:first_iteration_start_time).should be_true
38
+ end
39
+
40
+ it "should have current_iteration_number attribute" do
41
+ @project.respond_to?(:current_iteration_number).should be_true
42
+ end
35
43
  end
36
44
 
37
45
  context ".stories" do
@@ -67,7 +75,7 @@ describe PivotalTracker::Project do
67
75
 
68
76
  context "on failure" do
69
77
  before do
70
- FakeWeb.register_uri(:post, "http://www.pivotaltracker.com/services/v3/projects",
78
+ FakeWeb.register_uri(:post, "#{PivotalTracker::Client.api_url}/projects",
71
79
  :body => %{<?xml version="1.0" encoding="UTF-8"?>
72
80
  <errors>
73
81
  <error>error#1 message</error>
@@ -10,6 +10,20 @@ describe PivotalTracker::Story do
10
10
  @project.stories.all.should be_a(Array)
11
11
  @project.stories.all.first.should be_a(PivotalTracker::Story)
12
12
  end
13
+
14
+ it "should allow filtering" do
15
+ @project.stories.all(:story_type => ['bug']).should be_a(Array)
16
+ @project.stories.all(:story_type => ['feature']).should be_a(Array)
17
+ end
18
+
19
+ it "should cache stories" do
20
+ count = @project.stories.all.count
21
+ @project.stories.all.count.should == count
22
+ bugs_count = @project.stories.all(:story_type => ['bug']).count
23
+ bugs_count.should_not == count
24
+ @project.stories.all(:story_type => ['bug']).count.should == bugs_count
25
+ end
26
+
13
27
  end
14
28
 
15
29
  context ".find" do
@@ -25,7 +39,7 @@ describe PivotalTracker::Story do
25
39
 
26
40
  context "on failure" do
27
41
  before do
28
- FakeWeb.register_uri(:post, "http://www.pivotaltracker.com/services/v3/projects/#{@project.id}/stories",
42
+ FakeWeb.register_uri(:post, "#{PivotalTracker::Client.api_url}/projects/#{@project.id}/stories",
29
43
  :body => %{<?xml version="1.0" encoding="UTF-8"?>
30
44
  <errors>
31
45
  <error>error#1 message</error>
@@ -52,43 +66,69 @@ describe PivotalTracker::Story do
52
66
  @story.attachments.first.should be_a(PivotalTracker::Attachment)
53
67
  end
54
68
  end
69
+
70
+ context ".move" do
71
+ let(:project_id) { @project.id }
72
+ let(:top_story_id) {4460598}
73
+ let(:bottom_story_id) {4459994}
74
+ let(:top_story) { @project.stories.find(top_story_id) }
75
+ let(:bottom_story) { @project.stories.find(bottom_story_id) }
76
+
77
+ it "should return the moved story when moved before" do
78
+ expected_uri = "#{PivotalTracker::Client.api_url}/projects/#{project_id}/stories/#{top_story_id}/moves?move\[move\]=before&move\[target\]=#{bottom_story_id}"
79
+ FakeWeb.register_uri(:post, expected_uri, :body => %{<story><id type="integer">#{top_story_id}</id></story>})
80
+ @moved_story = top_story.move(:before, bottom_story)
81
+ @moved_story.should be_a(PivotalTracker::Story)
82
+ @moved_story.id.should be(top_story_id)
83
+ end
84
+
85
+ it "should return the moved story when moved after" do
86
+ expected_uri = "#{PivotalTracker::Client.api_url}/projects/#{project_id}/stories/#{bottom_story_id}/moves?move\[move\]=after&move\[target\]=#{top_story_id}"
87
+ FakeWeb.register_uri(:post, expected_uri, :body => %{<story><id type="integer">#{bottom_story_id}</id></story>})
88
+ @moved_story = bottom_story.move(:after, top_story)
89
+ @moved_story.should be_a(PivotalTracker::Story)
90
+ @moved_story.id.should be(bottom_story_id)
91
+ end
92
+
93
+ it "should raise an error when trying to move in an invalid position" do
94
+ expect { top_story.move(:next_to, bottom_story) }.to raise_error(ArgumentError)
95
+ end
96
+ end
55
97
 
56
98
  context ".move_to_project" do
57
- before(:each) do
58
- pending
59
- @orig_net_lock = FakeWeb.allow_net_connect?
60
- FakeWeb.allow_net_connect = true
61
- @target_project = PivotalTracker::Project.find(103014)
62
- @movable_story = @project.stories.find(4490874)
99
+ let(:expected_uri) {"#{PivotalTracker::Client.api_url}/projects/#{project_id}/stories/#{story_id}"}
100
+ let(:project_id) { @project.id }
101
+ let(:movable_story) { @project.stories.find(4459994) }
102
+ let(:story_id) { movable_story.id }
103
+ let(:target_project) { PivotalTracker::Project.new(:id => 103014) }
104
+
105
+ before do
106
+ FakeWeb.register_uri(:put, expected_uri, :body => %{<?xml version="1.0" encoding="UTF-8"?>
107
+ <story>
108
+ <project_id type="integer">#{target_project.id}</project_id>
109
+ </story>})
63
110
  end
64
111
 
65
112
  it "should return an updated story from the target project when passed a PivotalTracker::Story" do
66
- target_story = @target_project.stories.find(4477972)
67
- response = @movable_story.move_to_project(target_story)
113
+ target_story = PivotalTracker::Story.new(:project_id => target_project.id)
114
+ response = movable_story.move_to_project(target_story)
115
+ response.should_not be_nil
68
116
  response.project_id.should == target_story.project_id
69
117
  end
70
118
 
71
119
  it "should return an updated story from the target project when passed a PivotalTracker::Project" do
72
- response = @movable_story.move_to_project(@target_project)
73
- response.project_id.should == @target_project.id
120
+ response = movable_story.move_to_project(target_project)
121
+ response.project_id.should == target_project.id
74
122
  end
75
123
 
76
124
  it "should return an updated story from the target project when passed a String" do
77
- response = @movable_story.move_to_project('103014')
78
- response.project_id.should == 103014
125
+ response = movable_story.move_to_project(target_project.id.to_s)
126
+ response.project_id.should == target_project.id
79
127
  end
80
128
 
81
129
  it "should return an updated story from the target project when passed an Integer"do
82
- response = @movable_story.move_to_project(103014)
83
- response.project_id.should == 103014
84
- end
85
-
86
- after (:each) do
87
- pending
88
- @movable_story = @target_project.stories.find(4490874)
89
- response = @movable_story.move_to_project(102622)
90
- FakeWeb.allow_net_connect = @orig_net_lock
91
- response.project_id.should == 102622
130
+ response = movable_story.move_to_project(target_project.id.to_i)
131
+ response.project_id.should == target_project.id
92
132
  end
93
133
  end
94
134
 
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'bundler'
2
+ require 'fileutils'
2
3
 
3
4
  Bundler.require(:default, :runtime, :test)
4
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -8,12 +9,13 @@ require 'pivotal-tracker'
8
9
  require 'rspec'
9
10
  require 'rspec/autorun'
10
11
 
11
- PROJECT_ID = ENV['PROJECT_ID'] || "102622"
12
+ PROJECT_ID = ENV['PROJECT_ID'] || 102622
12
13
  TOKEN = '8358666c5a593a3c82cda728c8a62b63'
13
14
 
14
15
  PivotalTracker::Client.token = TOKEN
15
16
 
16
- # tm: hack StaleFish
17
+ # tm: hack StaleFish to prevent it from accessing real API which slows down the test.
18
+ # Fixtures should be upated manually.
17
19
  module StaleFish
18
20
  class Fixture
19
21
  def is_stale?
@@ -26,13 +28,19 @@ end
26
28
  # in ./support/ and its subdirectories.
27
29
  Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
28
30
 
29
- StaleFish.setup(File.join(File.dirname(__FILE__), 'fixtures', 'stale_fish.yml'))
30
31
 
31
32
  RSpec.configure do |config|
32
- # config.include(Rack::Test::Methods)
33
+ # Give StaleFish temporary file which is ignored by git
34
+ org_stale_fish_config = File.join(File.dirname(__FILE__), 'fixtures', 'stale_fish.yml')
35
+ tmp_stale_fish_config = File.join(File.dirname(__FILE__), 'fixtures', 'stale_fish-tmp.yml')
36
+ FileUtils.copy_file org_stale_fish_config, tmp_stale_fish_config, :remove_destination => true
37
+ StaleFish.setup(tmp_stale_fish_config)
33
38
 
34
39
  config.before :suite do
35
40
  StaleFish.update_stale
36
41
  end
37
42
 
43
+ config.before :each do
44
+ PivotalTracker::Client.clear_connections
45
+ end
38
46
  end