mcollective-client 2.2.4 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of mcollective-client might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/lib/mcollective/application.rb +25 -34
- data/lib/mcollective/client.rb +91 -33
- data/lib/mcollective/config.rb +42 -43
- data/lib/mcollective/data/base.rb +1 -1
- data/lib/mcollective/data/result.rb +6 -2
- data/lib/mcollective/ddl/agentddl.rb +28 -1
- data/lib/mcollective/ddl/base.rb +8 -6
- data/lib/mcollective/log.rb +11 -3
- data/lib/mcollective/logger/file_logger.rb +4 -4
- data/lib/mcollective/matcher.rb +9 -1
- data/lib/mcollective/message.rb +14 -23
- data/lib/mcollective/optionparser.rb +9 -1
- data/lib/mcollective/pluginpackager.rb +24 -3
- data/lib/mcollective/pluginpackager/agent_definition.rb +12 -12
- data/lib/mcollective/pluginpackager/standard_definition.rb +12 -12
- data/lib/mcollective/rpc/agent.rb +15 -12
- data/lib/mcollective/rpc/client.rb +67 -31
- data/lib/mcollective/rpc/helpers.rb +7 -1
- data/lib/mcollective/rpc/reply.rb +3 -1
- data/lib/mcollective/shell.rb +45 -8
- data/lib/mcollective/util.rb +37 -1
- data/lib/mcollective/windows_daemon.rb +14 -3
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/application_spec.rb +45 -26
- data/spec/unit/cache_spec.rb +3 -3
- data/spec/unit/client_spec.rb +269 -24
- data/spec/unit/config_spec.rb +89 -26
- data/spec/unit/data/base_spec.rb +1 -0
- data/spec/unit/data/result_spec.rb +19 -1
- data/spec/unit/data_spec.rb +3 -0
- data/spec/unit/ddl/agentddl_spec.rb +32 -0
- data/spec/unit/ddl/base_spec.rb +4 -0
- data/spec/unit/ddl/dataddl_spec.rb +1 -1
- data/spec/unit/log_spec.rb +44 -27
- data/spec/unit/logger/base_spec.rb +1 -1
- data/spec/unit/matcher_spec.rb +14 -0
- data/spec/unit/message_spec.rb +24 -0
- data/spec/unit/optionparser_spec.rb +99 -0
- data/spec/unit/pluginpackager/agent_definition_spec.rb +48 -17
- data/spec/unit/pluginpackager/standard_definition_spec.rb +44 -20
- data/spec/unit/pluginpackager_spec.rb +31 -7
- data/spec/unit/plugins/mcollective/agent/rpcutil_spec.rb +176 -0
- data/spec/unit/plugins/mcollective/application/plugin_spec.rb +81 -0
- data/spec/unit/plugins/mcollective/audit/logfile_spec.rb +44 -0
- data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +118 -27
- data/spec/unit/plugins/mcollective/connector/rabbitmq_spec.rb +168 -34
- data/spec/unit/plugins/mcollective/data/agent_data_spec.rb +1 -0
- data/spec/unit/plugins/mcollective/data/fstat_data_spec.rb +1 -0
- data/spec/unit/plugins/mcollective/discovery/flatfile_spec.rb +10 -0
- data/spec/unit/plugins/mcollective/discovery/stdin_spec.rb +65 -0
- data/spec/unit/plugins/mcollective/facts/yaml_facts_spec.rb +65 -0
- data/spec/unit/plugins/mcollective/packagers/debpackage_packager_spec.rb +240 -219
- data/spec/unit/plugins/mcollective/packagers/modulepackage_packager_spec.rb +209 -0
- data/spec/unit/plugins/mcollective/packagers/rpmpackage_packager_spec.rb +223 -109
- data/spec/unit/rpc/actionrunner_spec.rb +2 -1
- data/spec/unit/rpc/agent_spec.rb +130 -1
- data/spec/unit/rpc/client_spec.rb +169 -3
- data/spec/unit/security/base_spec.rb +0 -1
- data/spec/unit/shell_spec.rb +76 -3
- data/spec/unit/util_spec.rb +69 -1
- data/spec/unit/windows_daemon_spec.rb +30 -9
- metadata +104 -90
- data/spec/unit/plugins/mcollective/connector/stomp/eventlogger_spec.rb +0 -34
- data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +0 -424
- data/spec/unit/plugins/mcollective/validator/any_validator_spec.rb +0 -15
@@ -151,7 +151,8 @@ module MCollective
|
|
151
151
|
if Util.windows?
|
152
152
|
@runner.canrun?(File.join(ENV['SystemRoot'], "explorer.exe")).should == true
|
153
153
|
else
|
154
|
-
|
154
|
+
true_exe = ENV["PATH"].split(File::PATH_SEPARATOR).map {|f| p = File.join(f, "true") ;p if File.exists?(p)}.compact.first
|
155
|
+
@runner.canrun?(true_exe).should == true
|
155
156
|
end
|
156
157
|
end
|
157
158
|
|
data/spec/unit/rpc/agent_spec.rb
CHANGED
@@ -8,6 +8,8 @@ module MCollective
|
|
8
8
|
before do
|
9
9
|
ddl = stub
|
10
10
|
ddl.stubs(:meta).returns({})
|
11
|
+
ddl.stubs(:action).returns([])
|
12
|
+
ddl.stubs(:validate_rpc_request).returns(true)
|
11
13
|
DDL.stubs(:new).returns(ddl)
|
12
14
|
|
13
15
|
@agent = Agent.new
|
@@ -15,9 +17,136 @@ module MCollective
|
|
15
17
|
@agent.request = {}
|
16
18
|
end
|
17
19
|
|
20
|
+
describe "#handlemsg" do
|
21
|
+
before do
|
22
|
+
Reply.any_instance.stubs(:initialize_data)
|
23
|
+
|
24
|
+
@agent.stubs(:respond_to?).with("rspec_action_action").returns(true)
|
25
|
+
@agent.stubs(:respond_to?).with("authorization_hook").returns(false)
|
26
|
+
@agent.stubs(:rspec_action_action).returns(nil)
|
27
|
+
|
28
|
+
@msg = {:msgtime => 1356006671,
|
29
|
+
:senderid => "example.com",
|
30
|
+
:requestid => "55f8abe1442328321667877a08bdc586",
|
31
|
+
:body => {:agent => "rspec_agent",
|
32
|
+
:action => "rspec_action",
|
33
|
+
:data => {}},
|
34
|
+
:caller => "cert=rspec"}
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should or validate the incoming request" do
|
38
|
+
Request.any_instance.expects(:validate!).raises(DDLValidationError, "Failed to validate")
|
39
|
+
|
40
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
41
|
+
|
42
|
+
reply[:statuscode].should == 4
|
43
|
+
reply[:statusmsg].should == "Failed to validate"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should call the authorization hook if set" do
|
47
|
+
@agent.expects(:respond_to?).with("authorization_hook").returns(true)
|
48
|
+
@agent.expects(:authorization_hook).raises("authorization denied")
|
49
|
+
Log.stubs(:error)
|
50
|
+
|
51
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
52
|
+
|
53
|
+
reply[:statuscode].should == 5
|
54
|
+
reply[:statusmsg].should == "authorization denied"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should audit the request" do
|
58
|
+
@agent.expects(:audit_request)
|
59
|
+
|
60
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
61
|
+
reply[:statuscode].should == 0
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should call the before_processing_hook" do
|
65
|
+
@agent.expects(:before_processing_hook)
|
66
|
+
|
67
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
68
|
+
reply[:statuscode].should == 0
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should fail if the action does not exist" do
|
72
|
+
@agent.expects(:respond_to?).with("rspec_action_action").returns(false)
|
73
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
74
|
+
reply[:statuscode].should == 2
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should call the action correctly" do
|
78
|
+
@agent.expects(:rspec_action_action)
|
79
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
80
|
+
reply[:statuscode].should == 0
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should handle RPC Aborted errors" do
|
84
|
+
@agent.expects(:rspec_action_action).raises(RPCAborted, "rspec test")
|
85
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
86
|
+
reply[:statuscode].should == 1
|
87
|
+
reply[:statusmsg].should == "rspec test"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should handle Unknown Action errors" do
|
91
|
+
@agent.stubs(:respond_to?).with("rspec_action_action").returns(false)
|
92
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
93
|
+
reply[:statuscode].should == 2
|
94
|
+
reply[:statusmsg].should == "Unknown action 'rspec_action' for agent 'rspec_agent'"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should handle Missing Data errors" do
|
98
|
+
@agent.expects(:rspec_action_action).raises(MissingRPCData, "rspec test")
|
99
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
100
|
+
reply[:statuscode].should == 3
|
101
|
+
reply[:statusmsg].should == "rspec test"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should handle Invalid Data errors" do
|
105
|
+
@agent.expects(:rspec_action_action).raises(InvalidRPCData, "rspec test")
|
106
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
107
|
+
reply[:statuscode].should == 4
|
108
|
+
reply[:statusmsg].should == "rspec test"
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should handle unknown errors" do
|
112
|
+
@agent.expects(:rspec_action_action).raises(UnknownRPCError, "rspec test")
|
113
|
+
Log.expects(:error).twice
|
114
|
+
|
115
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
116
|
+
reply[:statuscode].should == 5
|
117
|
+
reply[:statusmsg].should == "rspec test"
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should handle arbitrary exceptions" do
|
121
|
+
@agent.expects(:rspec_action_action).raises(Exception, "rspec test")
|
122
|
+
Log.expects(:error).twice
|
123
|
+
|
124
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
125
|
+
reply[:statuscode].should == 5
|
126
|
+
reply[:statusmsg].should == "rspec test"
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should call the after_processing_hook" do
|
130
|
+
@agent.expects(:after_processing_hook)
|
131
|
+
reply = @agent.handlemsg(@msg, DDL.new)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should respond if required" do
|
135
|
+
Request.any_instance.expects(:should_respond?).returns(true)
|
136
|
+
Reply.any_instance.expects(:to_hash).returns({})
|
137
|
+
@agent.handlemsg(@msg, DDL.new).should == {}
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should not respond when not required" do
|
141
|
+
Request.any_instance.expects(:should_respond?).returns(false)
|
142
|
+
Reply.any_instance.expects(:to_hash).never
|
143
|
+
@agent.handlemsg(@msg, DDL.new).should == nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
18
147
|
describe "#meta" do
|
19
148
|
it "should be deprecated" do
|
20
|
-
Log.expects(:warn).with(regexp_matches(/
|
149
|
+
Log.expects(:warn).with(regexp_matches(/Setting metadata in agents has been deprecated/))
|
21
150
|
Agent.metadata("foo")
|
22
151
|
end
|
23
152
|
end
|
@@ -62,6 +62,19 @@ module MCollective
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
+
describe "#validate_request" do
|
66
|
+
it "should fail when a DDL isn't present" do
|
67
|
+
@client.instance_variable_set("@ddl", nil)
|
68
|
+
expect { @client.validate_request("rspec", {}) }.to raise_error("No DDL found for agent foo cannot validate inputs")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should validate the input arguments" do
|
72
|
+
@client.ddl.expects(:set_default_input_arguments).with("rspec", {})
|
73
|
+
@client.ddl.expects(:validate_rpc_request).with("rspec", {})
|
74
|
+
@client.validate_request("rspec", {})
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
65
78
|
describe "#process_results_with_block" do
|
66
79
|
it "should inform the stats object correctly for passed requests" do
|
67
80
|
response = {:senderid => "rspec", :body => {:statuscode => 0}}
|
@@ -215,7 +228,9 @@ module MCollective
|
|
215
228
|
|
216
229
|
describe "#discovery_method=" do
|
217
230
|
it "should set the method" do
|
231
|
+
@client.default_discovery_method.should == true
|
218
232
|
@client.discovery_method = "rspec"
|
233
|
+
@client.default_discovery_method.should == false
|
219
234
|
@client.discovery_method.should == "rspec"
|
220
235
|
end
|
221
236
|
|
@@ -224,6 +239,7 @@ module MCollective
|
|
224
239
|
client.discovery_method = "rspec"
|
225
240
|
client.discovery_method.should == "rspec"
|
226
241
|
client.discovery_options.should == ["rspec"]
|
242
|
+
client.default_discovery_method.should == false
|
227
243
|
end
|
228
244
|
|
229
245
|
it "should clear the options if none are given initially" do
|
@@ -263,6 +279,77 @@ module MCollective
|
|
263
279
|
end
|
264
280
|
end
|
265
281
|
|
282
|
+
describe "#class_filter" do
|
283
|
+
it "should add a class to the filter" do
|
284
|
+
@client.class_filter("rspec")
|
285
|
+
@client.filter["cf_class"].should == ["rspec"]
|
286
|
+
end
|
287
|
+
|
288
|
+
it "should be idempotent" do
|
289
|
+
@client.class_filter("rspec")
|
290
|
+
@client.class_filter("rspec")
|
291
|
+
@client.filter["cf_class"].should == ["rspec"]
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "#fact_filter" do
|
296
|
+
before do
|
297
|
+
Util.stubs(:parse_fact_string).with("rspec=present").returns({:value => "present", :fact => "rspec", :operator => "=="})
|
298
|
+
end
|
299
|
+
|
300
|
+
it "should add a fact to the filter" do
|
301
|
+
@client.fact_filter("rspec", "present", "=")
|
302
|
+
@client.filter["fact"].should == [{:value=>"present", :fact=>"rspec", :operator=>"=="}]
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should be idempotent" do
|
306
|
+
@client.fact_filter("rspec", "present", "=")
|
307
|
+
@client.fact_filter("rspec", "present", "=")
|
308
|
+
@client.filter["fact"].should == [{:value=>"present", :fact=>"rspec", :operator=>"=="}]
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "#agent_filter" do
|
313
|
+
it "should add an agent to the filter" do
|
314
|
+
@client.filter["agent"].should == ["foo"]
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should be idempotent" do
|
318
|
+
@client.agent_filter("foo")
|
319
|
+
@client.filter["agent"].should == ["foo"]
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
describe "#identity_filter" do
|
324
|
+
it "should add a node to the filter" do
|
325
|
+
@client.identity_filter("rspec_node")
|
326
|
+
@client.filter["identity"].should == ["rspec_node"]
|
327
|
+
end
|
328
|
+
|
329
|
+
it "should be idempotent" do
|
330
|
+
@client.identity_filter("rspec_node")
|
331
|
+
@client.identity_filter("rspec_node")
|
332
|
+
@client.filter["identity"].should == ["rspec_node"]
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
describe "#compound_filter" do
|
337
|
+
before do
|
338
|
+
Matcher.stubs(:create_compound_callstack).with("filter").returns("filter")
|
339
|
+
end
|
340
|
+
|
341
|
+
it "should add a compound filter" do
|
342
|
+
@client.compound_filter("filter")
|
343
|
+
@client.filter["compound"].should == ["filter"]
|
344
|
+
end
|
345
|
+
|
346
|
+
it "should be idempotent" do
|
347
|
+
@client.compound_filter("filter")
|
348
|
+
@client.compound_filter("filter")
|
349
|
+
@client.filter["compound"].should == ["filter"]
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
266
353
|
describe "#discovery_timeout" do
|
267
354
|
it "should favour the initial options supplied timeout" do
|
268
355
|
client = Client.new("rspec", {:options => {:disctimeout => 3, :filter => Util.empty_filter, :config => "/nonexisting"}})
|
@@ -321,9 +408,7 @@ module MCollective
|
|
321
408
|
|
322
409
|
client.stubs(:call_agent)
|
323
410
|
|
324
|
-
|
325
|
-
ddl.expects(:validate_rpc_request).with("rspec", {:arg => :val}).raises("validation failed")
|
326
|
-
client.instance_variable_set("@ddl", ddl)
|
411
|
+
client.expects(:validate_request).with("rspec", {:arg => :val}).raises("validation failed")
|
327
412
|
|
328
413
|
expect { client.rspec(:arg => :val) }.to raise_error("validation failed")
|
329
414
|
end
|
@@ -482,6 +567,87 @@ module MCollective
|
|
482
567
|
end
|
483
568
|
end
|
484
569
|
|
570
|
+
describe "#fire_and_forget_request" do
|
571
|
+
before do
|
572
|
+
@client = stub
|
573
|
+
@discoverer = stub
|
574
|
+
@ddl = stub
|
575
|
+
|
576
|
+
@ddl.stubs(:meta).returns({:timeout => 2})
|
577
|
+
|
578
|
+
@discoverer.stubs(:force_direct_mode?).returns(false)
|
579
|
+
@discoverer.stubs(:ddl).returns(@ddl)
|
580
|
+
@discoverer.stubs(:discovery_method).returns("mc")
|
581
|
+
|
582
|
+
@client.stubs("options=")
|
583
|
+
@client.stubs(:collective).returns("mcollective")
|
584
|
+
@client.stubs(:discoverer).returns(@discoverer)
|
585
|
+
@client.stubs(:sendreq)
|
586
|
+
|
587
|
+
Config.instance.stubs(:loadconfig).with("/nonexisting").returns(true)
|
588
|
+
MCollective::Client.expects(:new).returns(@client)
|
589
|
+
Config.instance.stubs(:direct_addressing).returns(true)
|
590
|
+
|
591
|
+
@rpcclient = Client.new("foo", {:options => {:filter => Util.empty_filter, :config => "/nonexisting"}})
|
592
|
+
@rpcclient.stubs(:validate_request)
|
593
|
+
@request = stub
|
594
|
+
@rpcclient.stubs(:new_request).returns(@request)
|
595
|
+
end
|
596
|
+
|
597
|
+
it "should validate the request" do
|
598
|
+
@rpcclient.expects(:validate_request).with("rspec", {:rspec => "test"}).raises("rspec")
|
599
|
+
|
600
|
+
expect {
|
601
|
+
@rpcclient.fire_and_forget_request("rspec", {:rspec => "test"})
|
602
|
+
}.to raise_error("rspec")
|
603
|
+
end
|
604
|
+
|
605
|
+
it "should set the filter if it was specifically supplied" do
|
606
|
+
message = mock
|
607
|
+
Message.expects(:new).with(@request, nil, {:agent => "foo", :type => :request, :collective => "mcollective", :filter => "filter", :options => @rpcclient.options}).returns(message)
|
608
|
+
|
609
|
+
@rpcclient.expects(:identity_filter_discovery_optimization)
|
610
|
+
@rpcclient.fire_and_forget_request("rspec", {:rspec => "test"}, "filter")
|
611
|
+
end
|
612
|
+
|
613
|
+
it "should set reply_to if set" do
|
614
|
+
message = mock
|
615
|
+
Message.expects(:new).with(@request, nil, {:agent => "foo", :type => :request, :collective => "mcollective", :filter => @rpcclient.filter, :options => @rpcclient.options}).returns(message)
|
616
|
+
|
617
|
+
@rpcclient.reply_to = "/reply/to"
|
618
|
+
message.expects(:reply_to=).with("/reply/to")
|
619
|
+
|
620
|
+
@rpcclient.expects(:identity_filter_discovery_optimization)
|
621
|
+
@rpcclient.fire_and_forget_request("rspec", {:rspec => "test"})
|
622
|
+
end
|
623
|
+
|
624
|
+
it "should support direct_requests with discovery data supplied" do
|
625
|
+
message = mock
|
626
|
+
Message.expects(:new).with(@request, nil, {:agent => "foo", :type => :request, :collective => "mcollective", :filter => @rpcclient.filter, :options => @rpcclient.options}).returns(message)
|
627
|
+
|
628
|
+
@rpcclient.discover :nodes => "rspec"
|
629
|
+
message.expects(:discovered_hosts=).with(["rspec"])
|
630
|
+
message.expects(:type=).with(:direct_request)
|
631
|
+
|
632
|
+
@rpcclient.expects(:identity_filter_discovery_optimization)
|
633
|
+
@rpcclient.fire_and_forget_request("rspec", {:rspec => "test"})
|
634
|
+
end
|
635
|
+
|
636
|
+
it "should support direct_requests with discoverers that force direct mode" do
|
637
|
+
message = mock
|
638
|
+
Message.expects(:new).with(@request, nil, {:agent => "foo", :type => :request, :collective => "mcollective", :filter => @rpcclient.filter, :options => @rpcclient.options}).returns(message)
|
639
|
+
|
640
|
+
@discoverer.stubs(:force_direct_mode?).returns(true)
|
641
|
+
@rpcclient.stubs(:discover).returns(["rspec"])
|
642
|
+
|
643
|
+
message.expects(:discovered_hosts=).with(["rspec"])
|
644
|
+
message.expects(:type=).with(:direct_request)
|
645
|
+
|
646
|
+
@rpcclient.expects(:identity_filter_discovery_optimization)
|
647
|
+
@rpcclient.fire_and_forget_request("rspec", {:rspec => "test"})
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
485
651
|
describe "#call_agent_batched" do
|
486
652
|
before do
|
487
653
|
@client = stub
|
data/spec/unit/shell_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env rspec
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
+
require 'pathname'
|
4
5
|
|
5
6
|
module MCollective
|
6
7
|
describe Shell do
|
@@ -79,8 +80,15 @@ module MCollective
|
|
79
80
|
end
|
80
81
|
end
|
81
82
|
|
83
|
+
before :each do
|
84
|
+
@systemu = mock
|
85
|
+
@thread = mock
|
86
|
+
@thread.stubs(:kill)
|
87
|
+
@systemu.stubs(:thread).returns(@thread)
|
88
|
+
end
|
89
|
+
|
82
90
|
it "should run the command" do
|
83
|
-
Shell.any_instance.stubs("systemu").returns(
|
91
|
+
Shell.any_instance.stubs("systemu").returns(@systemu).once.with("date", "stdout" => '', "stderr" => '', "env" => {"LC_ALL" => "C"}, 'cwd' => Dir.tmpdir)
|
84
92
|
s = Shell.new("date")
|
85
93
|
s.runcommand
|
86
94
|
end
|
@@ -127,11 +135,12 @@ module MCollective
|
|
127
135
|
end
|
128
136
|
|
129
137
|
it "should run in the correct cwd" do
|
130
|
-
|
138
|
+
tmpdir = Pathname.new(Dir.tmpdir).realpath.to_s
|
139
|
+
s = Shell.new('ruby -e "puts Dir.pwd"', :cwd => tmpdir)
|
131
140
|
|
132
141
|
s.runcommand
|
133
142
|
|
134
|
-
s.stdout.should == "#{
|
143
|
+
s.stdout.should == "#{tmpdir}#{nl}"
|
135
144
|
end
|
136
145
|
|
137
146
|
it "should send the stdin" do
|
@@ -147,6 +156,70 @@ module MCollective
|
|
147
156
|
|
148
157
|
s.stdout.should == "first line#{nl}#{nl}2nd line#{nl}"
|
149
158
|
end
|
159
|
+
|
160
|
+
it "should quietly catch Errno::ESRCH if the systemu process has completed" do
|
161
|
+
s = Shell.new("echo foo")
|
162
|
+
Thread.any_instance.stubs(:alive?).raises(Errno::ESRCH)
|
163
|
+
s.runcommand
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "timeout has been set" do
|
167
|
+
before do
|
168
|
+
thread = mock
|
169
|
+
thread.stubs(:alive?).returns(false)
|
170
|
+
Thread.stubs(:current).returns(thread)
|
171
|
+
Util.stubs(:windows?).returns(false)
|
172
|
+
Thread.stubs(:alive?).returns(false)
|
173
|
+
Process.expects(:kill).with("TERM", 1234)
|
174
|
+
Process.expects(:waitpid).with(1234)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should terminate the systemu process after the specified timeout is exceeded" do
|
178
|
+
s = Shell.new(%{ruby -e 'sleep 5'}, :timeout => 1)
|
179
|
+
s.stubs(:systemu).yields(1234).returns(@systemu)
|
180
|
+
s.stubs(:sleep).with(2)
|
181
|
+
s.expects(:sleep).with(1)
|
182
|
+
Process.stubs(:kill).with(0, 1234).returns(1, nil)
|
183
|
+
s.runcommand
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should kill an unresponsive systemu process on timeout" do
|
187
|
+
s = Shell.new(%{ruby -e 'sleep 5'}, :timeout => 1)
|
188
|
+
s.stubs(:systemu).yields(1234).returns(@systemu)
|
189
|
+
s.expects(:sleep).with(1)
|
190
|
+
s.stubs(:sleep).with(2)
|
191
|
+
Process.stubs(:kill).with(0, 1234).returns(1)
|
192
|
+
Process.expects(:kill).with("KILL", 1234)
|
193
|
+
s.runcommand
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should kill the systemu process if the parent thread exits and :on_thread_exit is specified" do
|
197
|
+
s = Shell.new(%{ruby -e 'sleep 5'}, :timeout => :on_thread_exit)
|
198
|
+
s.stubs(:systemu).yields(1234).returns(@systemu)
|
199
|
+
s.stubs(:sleep).with(2)
|
200
|
+
Process.stubs(:kill).with(0, 1234).returns(1)
|
201
|
+
Process.expects(:kill).with("KILL", 1234)
|
202
|
+
s.runcommand
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should log a warning if the child process cannot be reaped" do
|
207
|
+
s = Shell.new('ruby -e "sleep 2"', :timeout=> 1)
|
208
|
+
Thread.stubs(:current)
|
209
|
+
s.stubs(:systemu).yields(1234).returns(@systemu)
|
210
|
+
s.stubs(:sleep).with(1).raises(Errno::ECHILD)
|
211
|
+
Log.expects(:warn).with("Could not reap process '1234'.")
|
212
|
+
s.runcommand
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should kill the guard thread when the process returns" do
|
216
|
+
s = Shell.new("echo hello world")
|
217
|
+
Thread.stubs(:current)
|
218
|
+
s.expects(:systemu).returns(@systemu)
|
219
|
+
@thread.expects(:kill)
|
220
|
+
result = s.runcommand
|
221
|
+
result.should == @systemu
|
222
|
+
end
|
150
223
|
end
|
151
224
|
end
|
152
225
|
end
|