bosh_cli 0.18 → 0.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,10 @@ module Bosh::Cli
6
6
  def self.create_for_log_type(log_type)
7
7
  if log_type == "event"
8
8
  EventLogRenderer.new
9
+ elsif log_type == "result"
10
+ # Null renderer doesn't output anything to screen, so it fits well
11
+ # in case we need to fetch task result log only, without rendering it
12
+ NullRenderer.new
9
13
  else
10
14
  TaskLogRenderer.new
11
15
  end
@@ -20,6 +24,11 @@ module Bosh::Cli
20
24
  @lock = Mutex.new
21
25
  @output = ""
22
26
  @time_adjustment = 0
27
+ @duration = nil
28
+ end
29
+
30
+ def duration_known?
31
+ false # TODO: make it available for basic renderer
23
32
  end
24
33
 
25
34
  def add_output(output)
@@ -0,0 +1,168 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh
4
+ module Cli
5
+ # This class is responsible for tracking director tasks
6
+ class TaskTracker
7
+
8
+ MAX_POLLS = nil # not limited
9
+ POLL_INTERVAL = 1 # second
10
+
11
+ attr_reader :output
12
+
13
+ # @param [Bosh::Cli::Director] director
14
+ # @param [Integer] task_id
15
+ # @param [Hash] options
16
+ def initialize(director, task_id, options = {})
17
+ @director = director
18
+ @task_id = task_id
19
+ @options = options
20
+
21
+ @log_type = options[:log_type] || "event"
22
+ @use_cache = options.key?(:use_cache) ? @options[:use_cache] : true
23
+
24
+ @output = nil
25
+ @cache = Config.cache
26
+ @task = Bosh::Cli::DirectorTask.new(@director, @task_id, @log_type)
27
+
28
+ if options[:raw_output]
29
+ @renderer = Bosh::Cli::TaskLogRenderer.new
30
+ else
31
+ @renderer = Bosh::Cli::TaskLogRenderer.create_for_log_type(@log_type)
32
+ end
33
+ end
34
+
35
+ # Tracks director task. Blocks until task is in one of the 'finished'
36
+ # states (done, error, cancelled). Handles Ctrl+C by prompting to cancel
37
+ # task.
38
+ # @return [Symbol] Task status
39
+ def track
40
+ nl
41
+ @renderer.time_adjustment = @director.get_time_difference
42
+ say("Director task #{@task_id.to_s.yellow}")
43
+
44
+ cached_output = get_cached_task_output
45
+
46
+ if cached_output
47
+ task_status = @task.state.to_sym
48
+ output_received(cached_output)
49
+ @renderer.refresh
50
+ else
51
+ task_status = poll
52
+ end
53
+
54
+ if task_status == :error && interactive? && @log_type != "debug"
55
+ prompt_for_debug_log
56
+ else
57
+ print_task_summary(task_status)
58
+ end
59
+
60
+ save_task_output unless cached_output
61
+ task_status
62
+ end
63
+
64
+ def poll
65
+ polls = 0
66
+
67
+ while true
68
+ polls += 1
69
+ state = @task.state
70
+ output = @task.output
71
+
72
+ output_received(output)
73
+ @renderer.refresh
74
+
75
+ if finished?(state)
76
+ return state.to_sym
77
+ elsif MAX_POLLS && polls >= MAX_POLLS
78
+ return :track_timeout
79
+ end
80
+
81
+ sleep(POLL_INTERVAL)
82
+ end
83
+
84
+ :unknown
85
+ rescue Interrupt # Local ctrl-c handler
86
+ prompt_for_task_cancel
87
+ end
88
+
89
+ def prompt_for_debug_log
90
+ return unless interactive?
91
+ nl
92
+ confirm = ask("The task has returned an error status, " +
93
+ "do you want to see debug log? [Yn]: ")
94
+ if confirm.empty? || confirm =~ /y(es)?/i
95
+ self.class.new(@director, @task_id,
96
+ @options.merge(:log_type => "debug")).track
97
+ else
98
+ say("Please use 'bosh task #{@task_id}' command ".red +
99
+ "to see the debug log".red)
100
+ end
101
+ end
102
+
103
+ def prompt_for_task_cancel
104
+ return unless interactive?
105
+ nl
106
+ confirm = ask("Do you want to cancel task #{@task_id}? [yN] " +
107
+ "(^C again to detach): ")
108
+
109
+ if confirm =~ /y(es)?/i
110
+ say("Cancelling task #{@task_id}...")
111
+ @director.cancel_task(@task_id)
112
+ end
113
+
114
+ poll
115
+ rescue Interrupt
116
+ nl
117
+ err("Task #{@task_id} is still running")
118
+ end
119
+
120
+ def print_task_summary(task_status)
121
+ output_received(@task.flush_output)
122
+ @renderer.finish(task_status)
123
+
124
+ nl
125
+ say("Task #{@task_id} #{task_status.to_s.yellow}")
126
+
127
+ if task_status == :done && @renderer.duration_known?
128
+ say("Started\t\t#{@renderer.started_at.utc.to_s}")
129
+ say("Finished\t#{@renderer.finished_at.utc.to_s}")
130
+ say("Duration\t#{format_time(@renderer.duration).yellow}")
131
+ end
132
+ end
133
+
134
+ private
135
+
136
+ # @param [String] output Output received from director task
137
+ def output_received(output)
138
+ return if output.nil?
139
+ @output ||= ""
140
+ @output << output
141
+ @renderer.add_output(output)
142
+ end
143
+
144
+ def finished?(state)
145
+ %(done error cancelled).include?(state)
146
+ end
147
+
148
+ def interactive?
149
+ Bosh::Cli::Config.interactive
150
+ end
151
+
152
+ def get_cached_task_output
153
+ return nil unless @use_cache
154
+ @cache.read(task_cache_key)
155
+ end
156
+
157
+ def save_task_output
158
+ return nil unless @output && @use_cache
159
+ @cache.write(task_cache_key, @output)
160
+ end
161
+
162
+ def task_cache_key
163
+ "task/#{@director.uuid}/#{@task_id}/#{@log_type}"
164
+ end
165
+
166
+ end
167
+ end
168
+ end
@@ -36,6 +36,7 @@ Job management
36
36
  <%= command_usage(:stop_job) %>
37
37
  <%= command_usage(:restart_job) %>
38
38
  <%= command_usage(:recreate_job) %>
39
+ <%= command_usage(:rename_job) %>
39
40
 
40
41
  Log management
41
42
  <%= command_usage(:fetch_logs) %>
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bosh
4
4
  module Cli
5
- VERSION = "0.18"
5
+ VERSION = "0.19"
6
6
  end
7
7
  end
@@ -38,14 +38,14 @@ module Bosh::Cli
38
38
 
39
39
  return nil if builds.empty?
40
40
 
41
- sorted = builds.sort { |build1, build2|
41
+ sorted = builds.sort do |build1, build2|
42
42
  cmp = version_cmp(build2["version"], build1["version"])
43
43
  if cmp == 0
44
44
  raise "There is a duplicate version `#{build1["version"]}' " +
45
- "in index `#{@index_file}'"
45
+ "in index `#{@index_file}'"
46
46
  end
47
47
  cmp
48
- }
48
+ end
49
49
 
50
50
  sorted[0]["version"]
51
51
  end
@@ -110,6 +110,11 @@ describe Bosh::Cli::Command::Biff do
110
110
  @biff.find_in("path1.path2.path3", obj).should == 3
111
111
  end
112
112
 
113
+ it "finds the object(boolean) path" do
114
+ obj = { "path1" => {"path2" => {"path3" => false}} }
115
+ @biff.find_in("path1.path2.path3", obj).should == false
116
+ end
117
+
113
118
  it "finds the object path in an array by the name key" do
114
119
  obj = { "by_key" => 1, "arr" => [{"name" => "by_name"}]}
115
120
  @biff.find_in("arr.by_name", obj).should == {"name" => "by_name"}
@@ -13,30 +13,30 @@ describe Bosh::Cli::Director do
13
13
  describe "fetching status" do
14
14
  it "tells if user is authenticated" do
15
15
  @director.should_receive(:get).with("/info", "application/json").
16
- and_return([200, JSON.generate("user" => "adam")])
16
+ and_return([200, JSON.generate("user" => "adam")])
17
17
  @director.authenticated?.should == true
18
18
  end
19
19
 
20
20
  it "tells if user not authenticated" do
21
21
  @director.should_receive(:get).with("/info", "application/json").
22
- and_return([403, "Forbidden"])
22
+ and_return([403, "Forbidden"])
23
23
  @director.authenticated?.should == false
24
24
 
25
25
  @director.should_receive(:get).with("/info", "application/json").
26
- and_return([500, "Error"])
26
+ and_return([500, "Error"])
27
27
  @director.authenticated?.should == false
28
28
 
29
29
  @director.should_receive(:get).with("/info", "application/json").
30
- and_return([404, "Not Found"])
30
+ and_return([404, "Not Found"])
31
31
  @director.authenticated?.should == false
32
32
 
33
33
  @director.should_receive(:get).with("/info", "application/json").
34
- and_return([200, JSON.generate("user" => nil, "version" => 1)])
34
+ and_return([200, JSON.generate("user" => nil, "version" => 1)])
35
35
  @director.authenticated?.should == false
36
36
 
37
37
  # Backward compatibility
38
38
  @director.should_receive(:get).with("/info", "application/json").
39
- and_return([200, JSON.generate("status" => "ZB")])
39
+ and_return([200, JSON.generate("status" => "ZB")])
40
40
  @director.authenticated?.should == true
41
41
  end
42
42
  end
@@ -53,157 +53,144 @@ describe Bosh::Cli::Director do
53
53
  describe "API calls" do
54
54
  it "creates user" do
55
55
  @director.should_receive(:post).
56
- with("/users", "application/json",
57
- JSON.generate("username" => "joe", "password" => "pass")).
58
- and_return(true)
56
+ with("/users", "application/json",
57
+ JSON.generate("username" => "joe", "password" => "pass")).
58
+ and_return(true)
59
59
  @director.create_user("joe", "pass")
60
60
  end
61
61
 
62
62
  it "uploads stemcell" do
63
63
  @director.should_receive(:upload_and_track).
64
- with("/stemcells", "application/x-compressed",
65
- "/path", :log_type=>"event").and_return(true)
64
+ with("/stemcells", "application/x-compressed", "/path").
65
+ and_return(true)
66
66
  @director.upload_stemcell("/path")
67
67
  end
68
68
 
69
69
  it "lists stemcells" do
70
70
  @director.should_receive(:get).with("/stemcells", "application/json").
71
- and_return([200, JSON.generate([]), {}])
71
+ and_return([200, JSON.generate([]), {}])
72
72
  @director.list_stemcells
73
73
  end
74
74
 
75
75
  it "lists releases" do
76
76
  @director.should_receive(:get).with("/releases", "application/json").
77
- and_return([200, JSON.generate([]), {}])
77
+ and_return([200, JSON.generate([]), {}])
78
78
  @director.list_releases
79
79
  end
80
80
 
81
81
  it "lists deployments" do
82
82
  @director.should_receive(:get).with("/deployments", "application/json").
83
- and_return([200, JSON.generate([]), {}])
83
+ and_return([200, JSON.generate([]), {}])
84
84
  @director.list_deployments
85
85
  end
86
86
 
87
87
  it "lists currently running tasks (director version < 0.3.5)" do
88
88
  @director.should_receive(:get).with("/info", "application/json").
89
- and_return([200, JSON.generate({ :version => "0.3.2"})])
89
+ and_return([200, JSON.generate({ :version => "0.3.2"})])
90
90
  @director.should_receive(:get).
91
- with("/tasks?state=processing", "application/json").
92
- and_return([200, JSON.generate([]), {}])
91
+ with("/tasks?state=processing", "application/json").
92
+ and_return([200, JSON.generate([]), {}])
93
93
  @director.list_running_tasks
94
94
  end
95
95
 
96
96
  it "lists currently running tasks (director version >= 0.3.5)" do
97
97
  @director.should_receive(:get).
98
- with("/info", "application/json").
99
- and_return([200, JSON.generate({ :version => "0.3.5"})])
98
+ with("/info", "application/json").
99
+ and_return([200, JSON.generate({ :version => "0.3.5"})])
100
100
  @director.should_receive(:get).
101
- with("/tasks?state=processing,cancelling,queued", "application/json").
102
- and_return([200, JSON.generate([]), {}])
101
+ with("/tasks?state=processing,cancelling,queued", "application/json").
102
+ and_return([200, JSON.generate([]), {}])
103
103
  @director.list_running_tasks
104
104
  end
105
105
 
106
106
  it "lists recent tasks" do
107
107
  @director.should_receive(:get).
108
- with("/tasks?limit=30", "application/json").
109
- and_return([200, JSON.generate([]), {}])
108
+ with("/tasks?limit=30", "application/json").
109
+ and_return([200, JSON.generate([]), {}])
110
110
  @director.list_recent_tasks
111
111
 
112
112
  @director.should_receive(:get).
113
- with("/tasks?limit=100", "application/json").
114
- and_return([200, JSON.generate([]), {}])
113
+ with("/tasks?limit=100", "application/json").
114
+ and_return([200, JSON.generate([]), {}])
115
115
  @director.list_recent_tasks(100000)
116
116
  end
117
117
 
118
118
  it "uploads release" do
119
119
  @director.should_receive(:upload_and_track).
120
- with("/releases", "application/x-compressed",
121
- "/path", :log_type => "event").
122
- and_return(true)
120
+ with("/releases", "application/x-compressed", "/path").
121
+ and_return(true)
123
122
  @director.upload_release("/path")
124
123
  end
125
124
 
126
125
  it "gets release info" do
127
126
  @director.should_receive(:get).
128
- with("/releases/foo", "application/json").
129
- and_return([200, JSON.generate([]), { }])
127
+ with("/releases/foo", "application/json").
128
+ and_return([200, JSON.generate([]), { }])
130
129
  @director.get_release("foo")
131
130
  end
132
131
 
133
132
  it "gets deployment info" do
134
133
  @director.should_receive(:get).
135
- with("/deployments/foo", "application/json").
136
- and_return([200, JSON.generate([]), { }])
134
+ with("/deployments/foo", "application/json").
135
+ and_return([200, JSON.generate([]), { }])
137
136
  @director.get_deployment("foo")
138
137
  end
139
138
 
140
139
  it "deletes stemcell" do
141
140
  @director.should_receive(:request_and_track).
142
- with(:delete, "/stemcells/ubuntu/123",
143
- nil, nil, :log_type => "event").
144
- and_return(true)
141
+ with(:delete, "/stemcells/ubuntu/123").and_return(true)
145
142
  @director.delete_stemcell("ubuntu", "123")
146
143
  end
147
144
 
148
145
  it "deletes deployment" do
149
146
  @director.should_receive(:request_and_track).
150
- with(:delete, "/deployments/foo",
151
- nil, nil, :log_type => "event").
152
- and_return(true)
147
+ with(:delete, "/deployments/foo").and_return(true)
153
148
  @director.delete_deployment("foo")
154
149
  end
155
150
 
156
151
  it "deletes release (non-force)" do
157
152
  @director.should_receive(:request_and_track).
158
- with(:delete, "/releases/za",
159
- nil, nil, :log_type => "event").
160
- and_return(true)
153
+ with(:delete, "/releases/za").and_return(true)
161
154
  @director.delete_release("za")
162
155
  end
163
156
 
164
157
  it "deletes release (force)" do
165
158
  @director.should_receive(:request_and_track).
166
- with(:delete, "/releases/zb?force=true",
167
- nil, nil, :log_type => "event").
168
- and_return(true)
159
+ with(:delete, "/releases/zb?force=true").and_return(true)
169
160
  @director.delete_release("zb", :force => true)
170
161
  end
171
162
 
172
163
  it "deploys" do
173
164
  @director.should_receive(:request_and_track).
174
- with(:post, "/deployments", "text/yaml",
175
- "manifest", :log_type => "event").
176
- and_return(true)
165
+ with(:post, "/deployments", "text/yaml", "manifest").and_return(true)
177
166
  @director.deploy("manifest")
178
167
  end
179
168
 
180
169
  it "changes job state" do
181
170
  @director.should_receive(:request_and_track).
182
- with(:put, "/deployments/foo/jobs/dea?state=stopped",
183
- "text/yaml", "manifest", :log_type => "event").
184
- and_return(true)
171
+ with(:put, "/deployments/foo/jobs/dea?state=stopped",
172
+ "text/yaml", "manifest").and_return(true)
185
173
  @director.change_job_state("foo", "manifest", "dea", nil, "stopped")
186
174
  end
187
175
 
188
176
  it "changes job instance state" do
189
177
  @director.should_receive(:request_and_track).
190
- with(:put, "/deployments/foo/jobs/dea/0?state=detached",
191
- "text/yaml", "manifest", :log_type => "event").
192
- and_return(true)
178
+ with(:put, "/deployments/foo/jobs/dea/0?state=detached",
179
+ "text/yaml", "manifest").and_return(true)
193
180
  @director.change_job_state("foo", "manifest", "dea", 0, "detached")
194
181
  end
195
182
 
196
183
  it "gets task state" do
197
184
  @director.should_receive(:get).
198
- with("/tasks/232").
199
- and_return([200, JSON.generate({ "state" => "done" })])
185
+ with("/tasks/232").
186
+ and_return([200, JSON.generate({ "state" => "done" })])
200
187
  @director.get_task_state(232).should == "done"
201
188
  end
202
189
 
203
190
  it "whines on missing task" do
204
191
  @director.should_receive(:get).
205
- with("/tasks/232").
206
- and_return([404, "Not Found"])
192
+ with("/tasks/232").
193
+ and_return([404, "Not Found"])
207
194
  lambda {
208
195
  @director.get_task_state(232).should
209
196
  }.should raise_error(Bosh::Cli::MissingTask)
@@ -211,17 +198,17 @@ describe Bosh::Cli::Director do
211
198
 
212
199
  it "gets task output" do
213
200
  @director.should_receive(:get).
214
- with("/tasks/232/output", nil,
215
- nil, { "Range" => "bytes=42-" }).
216
- and_return([206, "test", { :content_range => "bytes 42-56/100" }])
201
+ with("/tasks/232/output", nil,
202
+ nil, { "Range" => "bytes=42-" }).
203
+ and_return([206, "test", { :content_range => "bytes 42-56/100" }])
217
204
  @director.get_task_output(232, 42).should == ["test", 57]
218
205
  end
219
206
 
220
207
  it "doesn't set task output new offset if it wasn't a partial response" do
221
208
  @director.should_receive(:get).
222
- with("/tasks/232/output", nil, nil,
223
- { "Range" => "bytes=42-" }).
224
- and_return([200, "test"])
209
+ with("/tasks/232/output", nil, nil,
210
+ { "Range" => "bytes=42-" }).
211
+ and_return([200, "test"])
225
212
  @director.get_task_output(232, 42).should == ["test", nil]
226
213
  end
227
214
 
@@ -231,8 +218,8 @@ describe Bosh::Cli::Director do
231
218
  Time.stub!(:now).and_return(now)
232
219
 
233
220
  @director.should_receive(:get).with("/info").
234
- and_return([200, JSON.generate("version" => 1),
235
- { :date => server_time.rfc822 }])
221
+ and_return([200, JSON.generate("version" => 1),
222
+ { :date => server_time.rfc822 }])
236
223
  @director.get_time_difference.to_i.should == 100
237
224
  end
238
225
 
@@ -241,59 +228,65 @@ describe Bosh::Cli::Director do
241
228
  describe "checking status" do
242
229
  it "considers target valid if it responds with 401 (for compatibility)" do
243
230
  @director.stub(:get).
244
- with("/info", "application/json").
245
- and_return([401, "Not authorized"])
231
+ with("/info", "application/json").
232
+ and_return([401, "Not authorized"])
246
233
  @director.exists?.should be_true
247
234
  end
248
235
 
249
236
  it "considers target valid if it responds with 200" do
250
237
  @director.stub(:get).
251
- with("/info", "application/json").
252
- and_return([200, JSON.generate("name" => "Director is your friend")])
238
+ with("/info", "application/json").
239
+ and_return([200, JSON.generate("name" => "Director is your friend")])
253
240
  @director.exists?.should be_true
254
241
  end
255
242
  end
256
243
 
257
244
  describe "tracking request" do
258
245
  it "starts polling task if request responded with a redirect to task URL" do
246
+ options = { :arg1 => 1, :arg2 => 2 }
247
+
259
248
  @director.should_receive(:request).
260
- with(:get, "/stuff", "text/plain", "abc").
261
- and_return([302, "body", { :location => "/tasks/502" }])
262
- @director.should_receive(:poll_task).
263
- with("502", :arg1 => 1, :arg2 => 2).
264
- and_return("polling result")
249
+ with(:get, "/stuff", "text/plain", "abc").
250
+ and_return([302, "body", { :location => "/tasks/502" }])
251
+
252
+ tracker = mock("tracker", :track => "polling result", :output => "foo")
253
+
254
+ Bosh::Cli::TaskTracker.should_receive(:new).
255
+ with(@director, "502", options).
256
+ and_return(tracker)
257
+
265
258
  @director.request_and_track(:get, "/stuff", "text/plain",
266
- "abc", :arg1 => 1, :arg2 => 2).
267
- should == ["polling result", "502"]
259
+ "abc", options).
260
+ should == ["polling result", "502", "foo"]
268
261
  end
269
262
 
270
- it "considers all reponses but 302 a failure" do
263
+ it "considers all responses but 302 a failure" do
271
264
  [200, 404, 403].each do |code|
272
265
  @director.should_receive(:request).
273
- with(:get, "/stuff", "text/plain", "abc").
274
- and_return([code, "body", { }])
266
+ with(:get, "/stuff", "text/plain", "abc").
267
+ and_return([code, "body", {}])
275
268
  @director.request_and_track(:get, "/stuff", "text/plain",
276
269
  "abc", :arg1 => 1, :arg2 => 2).
277
- should == [:failed, nil]
270
+ should == [:failed, nil, nil]
278
271
  end
279
272
  end
280
273
 
281
- it "reports task as non trackable if its URL is unfamiliar" do
274
+ it "reports task as non-trackable if its URL is unfamiliar" do
282
275
  @director.should_receive(:request).
283
- with(:get, "/stuff", "text/plain", "abc").
284
- and_return([302, "body", { :location => "/track-task/502" }])
276
+ with(:get, "/stuff", "text/plain", "abc").
277
+ and_return([302, "body", { :location => "/track-task/502" }])
285
278
  @director.request_and_track(:get, "/stuff", "text/plain",
286
279
  "abc", :arg1 => 1, :arg2 => 2).
287
- should == [:non_trackable, nil]
280
+ should == [:non_trackable, nil, nil]
288
281
  end
289
282
 
290
- it "suppports uploading with progress bar" do
283
+ it "supports uploading with progress bar" do
291
284
  file = spec_asset("valid_release.tgz")
292
285
  f = Bosh::Cli::FileWithProgressBar.open(file, "r")
293
286
 
294
287
  Bosh::Cli::FileWithProgressBar.stub!(:open).with(file, "r").and_return(f)
295
288
  @director.should_receive(:request_and_track).
296
- with(:post, "/stuff", "application/x-compressed", f, { })
289
+ with(:post, "/stuff", "application/x-compressed", f, { })
297
290
  @director.upload_and_track("/stuff", "application/x-compressed", file)
298
291
  f.progress_bar.finished?.should be_true
299
292
  end
@@ -308,16 +301,16 @@ describe Bosh::Cli::Director do
308
301
 
309
302
  client = mock("httpclient")
310
303
  client.should_receive(:send_timeout=).
311
- with(Bosh::Cli::Director::API_TIMEOUT)
304
+ with(Bosh::Cli::Director::API_TIMEOUT)
312
305
  client.should_receive(:receive_timeout=).
313
- with(Bosh::Cli::Director::API_TIMEOUT)
306
+ with(Bosh::Cli::Director::API_TIMEOUT)
314
307
  client.should_receive(:connect_timeout=).
315
- with(Bosh::Cli::Director::CONNECT_TIMEOUT)
308
+ with(Bosh::Cli::Director::CONNECT_TIMEOUT)
316
309
  HTTPClient.stub!(:new).and_return(client)
317
310
 
318
311
  client.should_receive(:request).
319
- with(:get, "http://target/stuff", :body => "payload",
320
- :header => headers.merge("Authorization" => auth))
312
+ with(:get, "http://target/stuff", :body => "payload",
313
+ :header => headers.merge("Authorization" => auth))
321
314
  @director.send(:perform_http_request, :get,
322
315
  "http://target/stuff", "payload", headers)
323
316
  end
@@ -351,7 +344,7 @@ describe Bosh::Cli::Director do
351
344
  :headers => {})
352
345
 
353
346
  @director.should_receive(:perform_http_request).
354
- and_return(mock_response)
347
+ and_return(mock_response)
355
348
  @director.request(:get, "/stuff", "application/octet-stream",
356
349
  "payload", { :hdr1 => "a", :hdr2 => "b"})
357
350
  }.should raise_error(Bosh::Cli::DirectorError,
@@ -363,7 +356,7 @@ describe Bosh::Cli::Director do
363
356
  :body => "error message goes here",
364
357
  :headers => {})
365
358
  @director.should_receive(:perform_http_request).
366
- and_return(mock_response)
359
+ and_return(mock_response)
367
360
  @director.request(:get, "/stuff", "application/octet-stream",
368
361
  "payload", { :hdr1 => "a", :hdr2 => "b"})
369
362
  }.should raise_error(Bosh::Cli::DirectorError,
@@ -376,7 +369,7 @@ describe Bosh::Cli::Director do
376
369
  :body => '{"c":"d","a":"b"}',
377
370
  :headers => {})
378
371
  @director.should_receive(:perform_http_request).
379
- and_return(mock_response)
372
+ and_return(mock_response)
380
373
  @director.request(:get, "/stuff", "application/octet-stream",
381
374
  "payload", { :hdr1 => "a", :hdr2 => "b"})
382
375
  }.should raise_error(Bosh::Cli::DirectorError,
@@ -388,13 +381,15 @@ describe Bosh::Cli::Director do
388
381
  it "wraps director access exceptions" do
389
382
  [URI::Error, SocketError, Errno::ECONNREFUSED].each do |err|
390
383
  @director.should_receive(:perform_http_request).
391
- and_raise(err.new("err message"))
384
+ and_raise(err.new("err message"))
392
385
  lambda {
393
386
  @director.request(:get, "/stuff", "app/zb", "payload", { })
394
387
  }.should raise_error(Bosh::Cli::DirectorInaccessible)
395
388
  end
389
+
396
390
  @director.should_receive(:perform_http_request).
397
- and_raise(SystemCallError.new("err message"))
391
+ and_raise(SystemCallError.new("err message", 22))
392
+
398
393
  lambda {
399
394
  @director.request(:get, "/stuff", "app/zb", "payload", { })
400
395
  }.should raise_error Bosh::Cli::DirectorError
@@ -404,11 +399,12 @@ describe Bosh::Cli::Director do
404
399
  mock_response = mock("response", :code => 200,
405
400
  :body => "test body", :headers => { })
406
401
  @director.should_receive(:perform_http_request).
407
- and_yield("test body").and_return(mock_response)
402
+ and_yield("test body").and_return(mock_response)
408
403
 
409
- code, filename, headers = @director.request(:get,
410
- "/files/foo", nil, nil,
411
- { }, { :file => true })
404
+ code, filename, headers =
405
+ @director.request(:get,
406
+ "/files/foo", nil, nil,
407
+ { }, { :file => true })
412
408
 
413
409
  code.should == 200
414
410
  File.read(filename).should == "test body"
@@ -416,96 +412,4 @@ describe Bosh::Cli::Director do
416
412
  end
417
413
  end
418
414
 
419
- describe "polling jobs" do
420
- it "polls until success" do
421
- n_calls = 0
422
-
423
- @director.stub!(:get_time_difference).and_return(0)
424
- @director.should_receive(:get).
425
- with("/tasks/1").exactly(5).times.
426
- and_return {
427
- n_calls += 1;
428
- [200,
429
- JSON.generate("state" => n_calls == 5 ? "done" : "processing")
430
- ]
431
- }
432
- @director.should_receive(:get).
433
- with("/tasks/1/output",
434
- nil, nil, "Range" => "bytes=0-").
435
- exactly(5).times.and_return(nil)
436
-
437
- @director.poll_task(1, :poll_interval => 0, :max_polls => 1000).
438
- should == :done
439
- end
440
-
441
- it "respects max polls setting" do
442
- @director.stub!(:get_time_difference).and_return(0)
443
- @director.should_receive(:get).with("/tasks/1").
444
- exactly(10).times.
445
- and_return [200, JSON.generate("state" => "processing")]
446
- @director.should_receive(:get).
447
- with("/tasks/1/output",
448
- nil, nil, "Range" => "bytes=0-").
449
- exactly(10).times.and_return(nil)
450
-
451
- @director.poll_task(1, :poll_interval => 0, :max_polls => 10).
452
- should == :track_timeout
453
- end
454
-
455
- it "respects poll interval setting" do
456
- @director.stub(:get).and_return([200, "processing"])
457
-
458
- @director.should_receive(:get).with("/tasks/1").
459
- exactly(10).times.
460
- and_return([200, JSON.generate("state" => "processing")])
461
- @director.should_receive(:get).
462
- with("/tasks/1/output", nil, nil,
463
- "Range" => "bytes=0-").
464
- exactly(10).times.and_return(nil)
465
- @director.should_receive(:sleep).with(5).exactly(9).times.and_return(nil)
466
-
467
- @director.poll_task(1, :poll_interval => 5, :max_polls => 10).
468
- should == :track_timeout
469
- end
470
-
471
- it "stops polling and returns error if status is not HTTP 200" do
472
- @director.stub!(:get_time_difference).and_return(0)
473
-
474
- @director.should_receive(:get).
475
- with("/tasks/1").
476
- and_return([500, JSON.generate("state" => "processing")])
477
-
478
- lambda {
479
- @director.poll_task(1, :poll_interval => 0, :max_polls => 10)
480
- }.should raise_error(Bosh::Cli::TaskTrackError,
481
- "Got HTTP 500 while tracking task state")
482
- end
483
-
484
- it "stops polling and returns error if task state is error" do
485
- @director.stub!(:get_time_difference).and_return(0)
486
-
487
- @director.stub(:get).
488
- with("/tasks/1/output", nil, nil,
489
- "Range" => "bytes=0-").
490
- and_return([200, ""])
491
-
492
- @director.stub(:get).
493
- with("/tasks/1").
494
- and_return([200, JSON.generate("state" => "error")])
495
-
496
- @director.should_receive(:get).exactly(2).times
497
-
498
- @director.poll_task(1, :poll_interval => 0, :max_polls => 10).
499
- should == :error
500
- end
501
- end
502
-
503
- it "calls cancel_task on the current task when cancel_current is called" do
504
- task_num = 1
505
- @director.stub(:cancel_task).and_return(["body", 200])
506
- @director.should_receive(:cancel_task).once.with(task_num)
507
- @director.should_receive(:say).once.with("Cancelling task ##{task_num}.")
508
- @director.current_running_task = task_num
509
- @director.cancel_current
510
- end
511
415
  end