cfoundry 0.4.21 → 0.5.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/Rakefile +47 -24
- data/lib/cfoundry/auth_token.rb +48 -0
- data/lib/cfoundry/baseclient.rb +96 -277
- data/lib/cfoundry/client.rb +2 -0
- data/lib/cfoundry/concerns/login_helpers.rb +13 -0
- data/lib/cfoundry/errors.rb +21 -13
- data/lib/cfoundry/rest_client.rb +290 -0
- data/lib/cfoundry/test_support.rb +3 -0
- data/lib/cfoundry/trace_helpers.rb +9 -9
- data/lib/cfoundry/uaaclient.rb +66 -74
- data/lib/cfoundry/upload_helpers.rb +2 -0
- data/lib/cfoundry/v1/app.rb +2 -2
- data/lib/cfoundry/v1/base.rb +4 -51
- data/lib/cfoundry/v1/client.rb +7 -30
- data/lib/cfoundry/v1/model.rb +22 -5
- data/lib/cfoundry/v1/model_magic.rb +30 -15
- data/lib/cfoundry/v2/app.rb +2 -5
- data/lib/cfoundry/v2/base.rb +10 -74
- data/lib/cfoundry/v2/client.rb +19 -30
- data/lib/cfoundry/v2/domain.rb +1 -4
- data/lib/cfoundry/v2/model.rb +1 -3
- data/lib/cfoundry/v2/model_magic.rb +13 -23
- data/lib/cfoundry/version.rb +1 -1
- data/lib/cfoundry/zip.rb +1 -1
- data/spec/cfoundry/auth_token_spec.rb +77 -0
- data/spec/cfoundry/baseclient_spec.rb +54 -30
- data/spec/cfoundry/errors_spec.rb +10 -13
- data/spec/cfoundry/rest_client_spec.rb +238 -0
- data/spec/cfoundry/trace_helpers_spec.rb +10 -5
- data/spec/cfoundry/uaaclient_spec.rb +141 -114
- data/spec/cfoundry/upload_helpers_spec.rb +129 -0
- data/spec/cfoundry/v1/base_spec.rb +2 -2
- data/spec/cfoundry/v1/client_spec.rb +17 -0
- data/spec/cfoundry/v1/model_magic_spec.rb +43 -0
- data/spec/cfoundry/v2/base_spec.rb +256 -33
- data/spec/cfoundry/v2/client_spec.rb +68 -0
- data/spec/cfoundry/v2/model_magic_spec.rb +49 -0
- data/spec/fixtures/apps/with_vmcignore/ignored_dir/file_in_ignored_dir.txt +1 -0
- data/spec/fixtures/apps/with_vmcignore/ignored_file.txt +1 -0
- data/spec/fixtures/apps/with_vmcignore/non_ignored_dir/file_in_non_ignored_dir.txt +1 -0
- data/spec/fixtures/apps/with_vmcignore/non_ignored_dir/ignored_file.txt +1 -0
- data/spec/fixtures/apps/with_vmcignore/non_ignored_file.txt +1 -0
- data/spec/fixtures/empty_file +0 -0
- data/spec/spec_helper.rb +4 -4
- data/spec/support/randoms.rb +3 -0
- data/spec/support/shared_examples/client_login_examples.rb +46 -0
- data/spec/support/{summaries.rb → shared_examples/model_summary_examples.rb} +0 -0
- data/spec/support/v1_fake_helper.rb +144 -0
- metadata +101 -37
- data/lib/cfoundry/spec_helper.rb +0 -1
@@ -0,0 +1,129 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CFoundry::UploadHelpers do
|
4
|
+
describe '#upload' do
|
5
|
+
let(:base) { Object.new }
|
6
|
+
let(:guid) { "123" }
|
7
|
+
let(:path) { "#{SPEC_ROOT}/fixtures/apps/with_vmcignore" }
|
8
|
+
let(:check_resources) { false }
|
9
|
+
let(:tmpdir) { "#{SPEC_ROOT}/tmp/fake_tmpdir" }
|
10
|
+
|
11
|
+
let(:client) do
|
12
|
+
client = Object.new
|
13
|
+
stub(client).base { base }
|
14
|
+
client
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:fake_model) do
|
18
|
+
class FakeModel
|
19
|
+
include CFoundry::UploadHelpers
|
20
|
+
|
21
|
+
def initialize(client, guid)
|
22
|
+
@client = client
|
23
|
+
@guid = guid
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
FakeModel.new(client, guid)
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
stub(Dir).tmpdir do
|
32
|
+
FileUtils.mkdir_p tmpdir
|
33
|
+
tmpdir
|
34
|
+
end
|
35
|
+
stub(base).upload_app.with_any_args
|
36
|
+
end
|
37
|
+
|
38
|
+
after { FileUtils.rm_rf tmpdir }
|
39
|
+
|
40
|
+
subject { fake_model.upload(path, check_resources) }
|
41
|
+
|
42
|
+
def relative_glob(dir)
|
43
|
+
base_pathname = Pathname.new(dir)
|
44
|
+
Dir["#{dir}/**/{*,.[^\.]*}"].map do |file|
|
45
|
+
Pathname.new(file).relative_path_from(base_pathname).to_s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def mock_zip(*args, &block)
|
50
|
+
if args.empty?
|
51
|
+
mock(CFoundry::Zip).pack.with_any_args(&block)
|
52
|
+
else
|
53
|
+
mock(CFoundry::Zip).pack(*args, &block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'zips the app and uploads the zip file' do
|
58
|
+
zip_path = "#{tmpdir}/#{guid}.zip"
|
59
|
+
mock_zip(anything, zip_path) { true }
|
60
|
+
mock(base).upload_app(guid, zip_path, [])
|
61
|
+
subject
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'uploads an app with the right guid' do
|
65
|
+
mock_zip
|
66
|
+
mock(base).upload_app(guid, anything, anything)
|
67
|
+
subject
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'uses a unique directory name when it copies the app' do
|
71
|
+
mock_zip(/#{tmpdir}.*#{guid}.*/, anything)
|
72
|
+
subject
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'cleans up after itself correctly' do
|
76
|
+
subject
|
77
|
+
expect(relative_glob(tmpdir)).to be_empty
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'includes the source files of the app in the zip file' do
|
81
|
+
mock_zip do |src, _|
|
82
|
+
files = relative_glob(src)
|
83
|
+
expect(files).to include "non_ignored_dir"
|
84
|
+
expect(files).to include "non_ignored_file.txt"
|
85
|
+
expect(files).to include "non_ignored_dir/file_in_non_ignored_dir.txt"
|
86
|
+
end
|
87
|
+
subject
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'includes hidden files (though stager ignores them currently)' do
|
91
|
+
mock_zip do |src, _|
|
92
|
+
expect(relative_glob(src)).to include ".hidden_file"
|
93
|
+
end
|
94
|
+
subject
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'does not include files and directories specified in the vmcignore (including glob patterns)' do
|
98
|
+
mock_zip do |src, _|
|
99
|
+
files = relative_glob(src)
|
100
|
+
expect(files).not_to include "ignored_dir"
|
101
|
+
expect(files).not_to include "ignored_file.txt"
|
102
|
+
expect(files).not_to include "non_ignored_dir/ignored_file.txt" # glob pattern **/ignored_file.txt
|
103
|
+
end
|
104
|
+
subject
|
105
|
+
end
|
106
|
+
|
107
|
+
%w(.git _darcs .svn).each do |source_control_dir_name|
|
108
|
+
context "when there is a #{source_control_dir_name} directory in the app" do
|
109
|
+
before { FileUtils.mkdir_p("#{path}/#{source_control_dir_name}") }
|
110
|
+
|
111
|
+
it "ignores that directory" do
|
112
|
+
mock_zip do |src, _|
|
113
|
+
expect(relative_glob(src)).not_to include source_control_dir_name
|
114
|
+
end
|
115
|
+
subject
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'when there are no files to zip' do
|
121
|
+
before { mock_zip { false } }
|
122
|
+
|
123
|
+
it 'passes `false` to #upload_app' do
|
124
|
+
mock(base).upload_app(guid, false, [])
|
125
|
+
subject
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -3,9 +3,9 @@ require "spec_helper"
|
|
3
3
|
describe CFoundry::V1::Base do
|
4
4
|
let(:base) { CFoundry::V1::Base.new("https://api.cloudfoundry.com") }
|
5
5
|
|
6
|
-
describe '#
|
6
|
+
describe '#get' do
|
7
7
|
let(:options) { {} }
|
8
|
-
subject { base.
|
8
|
+
subject { base.get("foo", options) }
|
9
9
|
|
10
10
|
context 'when successful' do
|
11
11
|
context 'and the accept type is JSON' do
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CFoundry::V1::Client do
|
4
|
+
let(:client) { CFoundry::V1::Client.new }
|
5
|
+
|
6
|
+
describe "#version" do
|
7
|
+
its(:version) { should eq 1 }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#login" do
|
11
|
+
include_examples "client login"
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#login_prompts" do
|
15
|
+
include_examples "client login prompts"
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CFoundry::V1::ModelMagic do
|
4
|
+
let(:client) { v1_fake_client }
|
5
|
+
let(:mymodel) { v1_fake_model }
|
6
|
+
let(:guid) { random_string("my-object-guid") }
|
7
|
+
let(:myobject) { mymodel.new(guid, client) }
|
8
|
+
|
9
|
+
describe "#read_manifest" do
|
10
|
+
context "with an attribute with different read/write locations" do
|
11
|
+
let(:mymodel) do
|
12
|
+
v1_fake_model do
|
13
|
+
attribute :foo, :string, :read => :x, :write => [:y, :z]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
before do
|
18
|
+
stub(client.base).my_fake_model { { :x => "abc" } }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "reads from the write location" do
|
22
|
+
expect {
|
23
|
+
myobject.foo = "def"
|
24
|
+
}.to change { myobject.read_manifest[:foo] }.from("abc").to("def")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#write_manifest" do
|
30
|
+
context "with a read-only attribute" do
|
31
|
+
let(:mymodel) do
|
32
|
+
v1_fake_model do
|
33
|
+
attribute :foo, :string, :read_only => true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not include the attribute" do
|
38
|
+
myobject.fake(:foo => "bar")
|
39
|
+
expect(myobject.write_manifest).to_not include :foo
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,58 +1,281 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe CFoundry::V2::Base do
|
4
|
-
let(:
|
4
|
+
let(:target) { "https://api.cloudfoundry.com" }
|
5
|
+
let(:base) { CFoundry::V2::Base.new(target) }
|
5
6
|
|
6
|
-
describe
|
7
|
-
let(:
|
8
|
-
|
7
|
+
describe "helper methods for HTTP verbs" do
|
8
|
+
let(:rest_client) { base.rest_client }
|
9
|
+
let(:path) { "some-path" }
|
10
|
+
let(:options) { { :some => :option} }
|
11
|
+
let(:url) { target + "/" + path }
|
12
|
+
let(:args) { [path, options] }
|
9
13
|
|
10
|
-
|
11
|
-
context '
|
12
|
-
|
14
|
+
shared_examples "handling responses" do |verb|
|
15
|
+
context 'when successful' do
|
16
|
+
context 'and the accept type is JSON' do
|
17
|
+
let(:options) { {:accept => :json} }
|
13
18
|
|
14
|
-
|
15
|
-
|
16
|
-
|
19
|
+
it 'returns the parsed JSON' do
|
20
|
+
stub_request(:any, 'https://api.cloudfoundry.com/some-path').to_return(:status => 200, :body => "{\"hello\": \"there\"}")
|
21
|
+
expect(subject).to eq(:hello => "there")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'and the accept type is not JSON' do
|
26
|
+
let(:options) { {:accept => :form} }
|
27
|
+
|
28
|
+
it 'returns the body' do
|
29
|
+
stub_request(:any, 'https://api.cloudfoundry.com/some-path').to_return :status => 200, :body => "body"
|
30
|
+
expect(subject).to eq "body"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when an error occurs' do
|
36
|
+
let(:response_code) { 404 }
|
37
|
+
|
38
|
+
it 'raises the correct error if JSON is parsed successfully' do
|
39
|
+
stub_request(:any, 'https://api.cloudfoundry.com/some-path').to_return(
|
40
|
+
:status => response_code,
|
41
|
+
:body => "{\"code\": 111, \"description\": \"Something bad happened\"}"
|
42
|
+
)
|
43
|
+
expect {subject}.to raise_error(CFoundry::SystemError, "111: Something bad happened")
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'raises the correct error if code is missing from response' do
|
47
|
+
stub_request(:any, 'https://api.cloudfoundry.com/some-path').to_return(
|
48
|
+
:status => response_code,
|
49
|
+
:body => "{\"description\": \"Something bad happened\"}"
|
50
|
+
)
|
51
|
+
expect {subject}.to raise_error CFoundry::NotFound
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'raises the correct error if response body is not JSON' do
|
55
|
+
stub_request(:any, 'https://api.cloudfoundry.com/some-path').to_return(
|
56
|
+
:status => response_code,
|
57
|
+
:body => "Error happened"
|
58
|
+
)
|
59
|
+
expect {subject}.to raise_error CFoundry::NotFound
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raises a generic APIError if code is not recognized' do
|
63
|
+
stub_request(:any, 'https://api.cloudfoundry.com/some-path').to_return :status => response_code,
|
64
|
+
:body => "{\"code\": 6932, \"description\": \"Something bad happened\"}"
|
65
|
+
expect {subject}.to raise_error CFoundry::APIError, "6932: Something bad happened"
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when a timeout exception occurs' do
|
69
|
+
before { stub_request(:any, url).to_raise(::Timeout::Error) }
|
70
|
+
|
71
|
+
it 'raises the correct error' do
|
72
|
+
expect { subject }.to raise_error CFoundry::Timeout, /#{url} timed out/
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when an HTTPNotFound error occurs' do
|
77
|
+
before { stub_request(:any, url).to_return(:status => 404, :body => "NOT FOUND") }
|
78
|
+
|
79
|
+
it 'raises the correct error' do
|
80
|
+
expect {subject}.to raise_error CFoundry::NotFound, "404: NOT FOUND"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when an HTTPForbidden error occurs' do
|
85
|
+
before { stub_request(:any, url).to_return(:status => 403, :body => "NONE SHALL PASS") }
|
86
|
+
|
87
|
+
it 'raises the correct error' do
|
88
|
+
expect { subject }.to raise_error CFoundry::Denied, "403: NONE SHALL PASS"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when any other type of error occurs" do
|
93
|
+
before { stub_request(:any, url).to_return(:status => 411, :body => "NOT LONG ENOUGH") }
|
94
|
+
|
95
|
+
it 'raises the correct error' do
|
96
|
+
expect { subject }.to raise_error CFoundry::BadResponse, "411: NOT LONG ENOUGH"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'includes the request and response hashes when it raises errors' do
|
101
|
+
stub_request(:any, url).to_return(:status => 411, :body => "NOT LONG ENOUGH")
|
102
|
+
|
103
|
+
begin
|
104
|
+
subject
|
105
|
+
rescue CFoundry::BadResponse => e
|
106
|
+
expect(e.response).to eq({
|
107
|
+
:status => "411",
|
108
|
+
:headers => {},
|
109
|
+
:body => "NOT LONG ENOUGH"
|
110
|
+
})
|
111
|
+
expect(e.request).to eq({
|
112
|
+
:headers => { "Content-Length" => 0 },
|
113
|
+
:method => verb,
|
114
|
+
:body => nil,
|
115
|
+
:url => "https://api.cloudfoundry.com/some-path"
|
116
|
+
})
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
shared_examples "normalizing arguments" do |verb|
|
123
|
+
context "when multiple path segments are passed" do
|
124
|
+
let(:segments) { ["first-segment", "next-segment"] }
|
125
|
+
|
126
|
+
context "when an options hash is not supplied" do
|
127
|
+
let(:args) { segments }
|
128
|
+
|
129
|
+
it "makes a request with the correct url and options" do
|
130
|
+
mock(rest_client).request(verb, "first-segment/next-segment", {}) { [request, response] }
|
131
|
+
subject
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "when an options has is supplied" do
|
136
|
+
let(:args) { segments + [options] }
|
137
|
+
|
138
|
+
it "makes a request with the correct url and options" do
|
139
|
+
mock(rest_client).request(verb, "first-segment/next-segment", options) { [request, response] }
|
140
|
+
subject
|
141
|
+
end
|
17
142
|
end
|
18
143
|
end
|
19
144
|
|
20
|
-
context
|
21
|
-
|
145
|
+
context "when a single path segment is passed" do
|
146
|
+
context "when an options hash is not supplied" do
|
147
|
+
let(:args) { ["first-segment"] }
|
22
148
|
|
23
|
-
|
24
|
-
|
25
|
-
|
149
|
+
it "makes a request with the correct url and options" do
|
150
|
+
mock(rest_client).request(verb, "first-segment", {}) { [request, response] }
|
151
|
+
subject
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "when an options has is supplied" do
|
156
|
+
let(:args) { ["first-segment", options] }
|
157
|
+
|
158
|
+
it "makes a request with the correct url and options" do
|
159
|
+
mock(rest_client).request(verb, "first-segment", options) { [request, response] }
|
160
|
+
subject
|
161
|
+
end
|
26
162
|
end
|
27
163
|
end
|
164
|
+
end
|
28
165
|
|
166
|
+
let(:response) { { :status => "201", :headers => { "some-header-key" => "some-header-value" }, :body => "some-body" } }
|
167
|
+
let(:request) do
|
168
|
+
{
|
169
|
+
:method => "GET",
|
170
|
+
:url => "http://api.cloudfoundry.com/some-path",
|
171
|
+
:headers => { "some-header-key" => "some-header-value" },
|
172
|
+
:body => "some-body"
|
173
|
+
}
|
29
174
|
end
|
30
175
|
|
31
|
-
|
32
|
-
|
176
|
+
describe "#get" do
|
177
|
+
subject { base.get(*args) }
|
33
178
|
|
34
|
-
it
|
35
|
-
|
36
|
-
|
37
|
-
expect {subject}.to raise_error CFoundry::SystemError, "111: Something bad happened"
|
179
|
+
it "makes a GET request" do
|
180
|
+
mock(rest_client).request("GET", "some-path", options) { [request, response] }
|
181
|
+
subject
|
38
182
|
end
|
39
183
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
184
|
+
include_examples "handling responses", "GET"
|
185
|
+
include_examples "normalizing arguments", "GET"
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "#post" do
|
189
|
+
subject { base.post(*args) }
|
190
|
+
|
191
|
+
it "makes a POST request" do
|
192
|
+
mock(rest_client).request("POST", "some-path", options) { [request, response] }
|
193
|
+
subject
|
194
|
+
end
|
195
|
+
|
196
|
+
include_examples "handling responses", "POST"
|
197
|
+
include_examples "normalizing arguments", "POST"
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "#put" do
|
201
|
+
subject { base.put(*args) }
|
202
|
+
|
203
|
+
it "makes a PUT request" do
|
204
|
+
mock(rest_client).request("PUT", "some-path", options) { [request, response] }
|
205
|
+
subject
|
44
206
|
end
|
45
207
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
208
|
+
include_examples "handling responses", "PUT"
|
209
|
+
include_examples "normalizing arguments", "PUT"
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "#delete" do
|
213
|
+
subject { base.delete(*args) }
|
214
|
+
|
215
|
+
it "makes a DELETE request" do
|
216
|
+
mock(rest_client).request("DELETE", "some-path", options) { [request, response] }
|
217
|
+
subject
|
50
218
|
end
|
51
219
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
220
|
+
include_examples "handling responses", "DELETE"
|
221
|
+
include_examples "normalizing arguments", "DELETE"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "#resource_match" do
|
226
|
+
let(:fingerprints) { "some-fingerprints" }
|
227
|
+
|
228
|
+
it "makes a PUT request to the resource_match endpoint with the correct payload" do
|
229
|
+
stub = stub_request(:put, "https://api.cloudfoundry.com/v2/resource_match").
|
230
|
+
with(:body => fingerprints).
|
231
|
+
to_return(:body => "{}")
|
232
|
+
base.resource_match(fingerprints)
|
233
|
+
expect(stub).to have_been_requested
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "#upload_app" do
|
238
|
+
let(:guid) { "some-guid" }
|
239
|
+
let(:bits) { "some-bits" }
|
240
|
+
let(:fake_zipfile) { File.new("#{SPEC_ROOT}/fixtures/empty_file") }
|
241
|
+
|
242
|
+
it "makes a PUT request to the app bits endpoint with the correct payload" do
|
243
|
+
stub = stub_request(:put, "https://api.cloudfoundry.com/v2/apps/#{guid}/bits").to_return(:body => "{}")
|
244
|
+
base.upload_app(guid, fake_zipfile)
|
245
|
+
expect(stub).to have_been_requested
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
describe "#stream_file" do
|
250
|
+
let(:app_guid) { "1234" }
|
251
|
+
let(:instance_guid) { "3456" }
|
252
|
+
let(:api_url) { "https://api.cloudfoundry.com/v2/apps/#{app_guid}/instances/#{instance_guid}/files/some/path/segments" }
|
253
|
+
let(:file_url) { "http://api.cloudfoundry.com/static/path/to/some/file" }
|
254
|
+
|
255
|
+
before do
|
256
|
+
stub(base).token { CFoundry::AuthToken.new("bearer foo") }
|
257
|
+
end
|
258
|
+
|
259
|
+
it "follows the redirect returned by the files endpoint" do
|
260
|
+
stub_request(:get, api_url).to_return(
|
261
|
+
:status => 301,
|
262
|
+
:headers => { "location" => file_url },
|
263
|
+
:body => ""
|
264
|
+
)
|
265
|
+
|
266
|
+
request =
|
267
|
+
stub_request(
|
268
|
+
:get, file_url + "&tail"
|
269
|
+
).with(
|
270
|
+
:headers => { "Accept" => "*/*", "Authorization" => "bearer foo" }
|
271
|
+
).to_return(
|
272
|
+
:status => 200,
|
273
|
+
:body => "some body chunks"
|
274
|
+
)
|
275
|
+
|
276
|
+
base.stream_file(app_guid, instance_guid, "some", "path", "segments") do |body|
|
277
|
+
expect(request).to have_been_made
|
278
|
+
expect(body).to eql("some body chunks")
|
56
279
|
end
|
57
280
|
end
|
58
281
|
end
|