mcollective-client 2.2.4 → 2.4.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.
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
|