passenger 4.0.0.rc6 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- data.tar.gz.asc +7 -7
- data/NEWS +14 -0
- data/build/basics.rb +2 -1
- data/build/packaging.rb +33 -0
- data/dev/run_travis.sh +1 -0
- data/doc/Architectural overview.html +1 -3
- data/doc/Packaging.txt.md +6 -6
- data/doc/Security of user switching support.html +1 -3
- data/doc/Users guide Apache.html +53 -20
- data/doc/Users guide Apache.idmap.txt +4 -0
- data/doc/Users guide Apache.txt +8 -0
- data/doc/Users guide Nginx.html +41 -18
- data/doc/Users guide Standalone.html +1 -3
- data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +11 -5
- data/doc/users_guide_snippets/installation.txt +5 -1
- data/doc/users_guide_snippets/tips.txt +10 -7
- data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +2 -2
- data/ext/apache2/Configuration.cpp +5 -6
- data/ext/apache2/Configuration.hpp +0 -4
- data/ext/common/ApplicationPool2/Group.h +25 -43
- data/ext/common/ApplicationPool2/Implementation.cpp +51 -32
- data/ext/common/ApplicationPool2/Pool.h +6 -7
- data/ext/common/ApplicationPool2/Process.h +61 -44
- data/ext/common/ApplicationPool2/Spawner.h +5 -0
- data/ext/common/BackgroundEventLoop.cpp +5 -11
- data/ext/common/Constants.h +1 -1
- data/ext/common/Utils.cpp +1 -1
- data/ext/common/agents/HelperAgent/AgentOptions.h +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler.h +2 -0
- data/ext/common/agents/LoggingAgent/LoggingServer.h +4 -1
- data/ext/common/agents/LoggingAgent/RemoteSender.h +58 -6
- data/lib/phusion_passenger.rb +2 -2
- data/lib/phusion_passenger/loader_shared_helpers.rb +6 -6
- data/lib/phusion_passenger/platform_info/compiler.rb +16 -0
- data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +1 -1
- data/lib/phusion_passenger/request_handler.rb +1 -0
- data/lib/phusion_passenger/standalone/start_command.rb +0 -4
- data/lib/phusion_passenger/utils/robust_interruption.rb +47 -28
- data/resources/templates/standalone/config.erb +4 -22
- data/test/config.json.example +1 -1
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +5 -3
- data/test/cxx/ApplicationPool2/PoolTest.cpp +75 -2
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +12 -7
- data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +18 -5
- data/test/cxx/RequestHandlerTest.cpp +3 -0
- data/test/ruby/shared/loader_sharedspec.rb +4 -0
- metadata +5 -6
- metadata.gz.asc +7 -7
- data/doc/Users guide Apache.index.sqlite3 +0 -0
data/lib/phusion_passenger.rb
CHANGED
@@ -31,9 +31,9 @@ module PhusionPassenger
|
|
31
31
|
PACKAGE_NAME = 'passenger'
|
32
32
|
|
33
33
|
# Phusion Passenger version number. Don't forget to edit ext/common/Constants.h too.
|
34
|
-
VERSION_STRING = '4.0.
|
34
|
+
VERSION_STRING = '4.0.1'
|
35
35
|
|
36
|
-
PREFERRED_NGINX_VERSION = '1.
|
36
|
+
PREFERRED_NGINX_VERSION = '1.4.0'
|
37
37
|
PREFERRED_PCRE_VERSION = '8.32'
|
38
38
|
STANDALONE_INTERFACE_VERSION = 1
|
39
39
|
|
@@ -81,12 +81,12 @@ module LoaderSharedHelpers
|
|
81
81
|
f.puts "RUBY_PLATFORM = #{RUBY_PLATFORM}"
|
82
82
|
f.puts "RUBY_ENGINE = #{defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'nil'}"
|
83
83
|
end
|
84
|
-
File.open("#{dir}/load_path", "
|
84
|
+
File.open("#{dir}/load_path", "wb") do |f|
|
85
85
|
$LOAD_PATH.each do |path|
|
86
86
|
f.puts path
|
87
87
|
end
|
88
88
|
end
|
89
|
-
File.open("#{dir}/loaded_libs", "
|
89
|
+
File.open("#{dir}/loaded_libs", "wb") do |f|
|
90
90
|
$LOADED_FEATURES.each do |filename|
|
91
91
|
f.puts filename
|
92
92
|
end
|
@@ -94,7 +94,7 @@ module LoaderSharedHelpers
|
|
94
94
|
|
95
95
|
# We write to these files last because the 'require' calls can fail.
|
96
96
|
require 'rbconfig' if !defined?(RbConfig::CONFIG)
|
97
|
-
File.open("#{dir}/rbconfig", "
|
97
|
+
File.open("#{dir}/rbconfig", "wb") do |f|
|
98
98
|
RbConfig::CONFIG.each_pair do |key, value|
|
99
99
|
f.puts "#{key} = #{value}"
|
100
100
|
end
|
@@ -103,7 +103,7 @@ module LoaderSharedHelpers
|
|
103
103
|
File.open("#{dir}/ruby_info", "a") do |f|
|
104
104
|
f.puts "RubyGems version = #{Gem::VERSION}"
|
105
105
|
end
|
106
|
-
File.open("#{dir}/activated_gems", "
|
106
|
+
File.open("#{dir}/activated_gems", "wb") do |f|
|
107
107
|
if Gem.respond_to?(:loaded_specs)
|
108
108
|
Gem.loaded_specs.each_pair do |name, spec|
|
109
109
|
f.puts "#{name} => #{spec.version}"
|
@@ -119,7 +119,7 @@ module LoaderSharedHelpers
|
|
119
119
|
|
120
120
|
def dump_envvars
|
121
121
|
if dir = ENV['PASSENGER_DEBUG_DIR']
|
122
|
-
File.open("#{dir}/envvars", "
|
122
|
+
File.open("#{dir}/envvars", "wb") do |f|
|
123
123
|
ENV.each_pair do |key, value|
|
124
124
|
f.puts "#{key} = #{value}"
|
125
125
|
end
|
@@ -131,7 +131,7 @@ module LoaderSharedHelpers
|
|
131
131
|
|
132
132
|
def dump_system_memory_stats
|
133
133
|
if dir = ENV['PASSENGER_DEBUG_DIR']
|
134
|
-
File.open("#{dir}/sysmemory", "
|
134
|
+
File.open("#{dir}/sysmemory", "wb") do |f|
|
135
135
|
f.write(`"#{PhusionPassenger.helper_scripts_dir}/system-memory-stats.py"`)
|
136
136
|
end
|
137
137
|
end
|
@@ -257,6 +257,22 @@ public
|
|
257
257
|
:c, '', '-Wno-ambiguous-member-template')
|
258
258
|
end
|
259
259
|
memoize :compiler_supports_wno_ambiguous_member_template?, true
|
260
|
+
|
261
|
+
def self.compiler_supports_feliminate_unused_debug?
|
262
|
+
create_temp_file("passenger-compile-check.c") do |filename, f|
|
263
|
+
f.close
|
264
|
+
begin
|
265
|
+
command = create_compiler_command(:c,
|
266
|
+
"-c '#{filename}' -o '#{filename}.o'",
|
267
|
+
'-feliminate-unused-debug-symbols -feliminate-unused-debug-types')
|
268
|
+
result = run_compiler("Checking for C compiler '--feliminate-unused-debug-{symbols,types}' support",
|
269
|
+
command, filename, '', true)
|
270
|
+
return result && result[:output].empty?
|
271
|
+
ensure
|
272
|
+
File.unlink("#{filename}.o") rescue nil
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
260
276
|
|
261
277
|
# Returns whether compiling C++ with -fvisibility=hidden might result
|
262
278
|
# in tons of useless warnings, like this:
|
@@ -109,10 +109,6 @@ private
|
|
109
109
|
require 'fileutils' unless defined?(FileUtils)
|
110
110
|
end
|
111
111
|
|
112
|
-
def require_app_finder
|
113
|
-
require 'phusion_passenger/standalone/app_finder' unless defined?(AppFinder)
|
114
|
-
end
|
115
|
-
|
116
112
|
def parse_my_options
|
117
113
|
description = "Starts Phusion Passenger Standalone and serve one or more Ruby web applications."
|
118
114
|
parse_options!("start [directory]", description) do |opts|
|
@@ -5,6 +5,26 @@ module Utils
|
|
5
5
|
|
6
6
|
module RobustInterruption
|
7
7
|
class Interrupted < StandardError
|
8
|
+
def initialize
|
9
|
+
@origin_thread = Thread.current
|
10
|
+
@origin = caller
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_backtrace(bt)
|
14
|
+
@origin.reverse.each do |line|
|
15
|
+
if bt.last == line
|
16
|
+
bt.pop
|
17
|
+
else
|
18
|
+
break
|
19
|
+
end
|
20
|
+
end
|
21
|
+
bt << "interruption initiator thread: #{RobustInterruption._get_thread_display_name @origin_thread}"
|
22
|
+
bt.concat(@origin)
|
23
|
+
super(bt)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class NotInstalled < StandardError
|
8
28
|
end
|
9
29
|
|
10
30
|
class Data
|
@@ -52,43 +72,29 @@ module RobustInterruption
|
|
52
72
|
RobustInterruption.install
|
53
73
|
end
|
54
74
|
|
55
|
-
def installed?(thread = Thread.current)
|
56
|
-
return !!thread[:robust_interruption]
|
57
|
-
end
|
58
|
-
module_function :installed?
|
59
|
-
|
60
75
|
def interrupted?(thread = Thread.current)
|
61
76
|
if data = thread[:robust_interruption]
|
62
77
|
return data.interrupted?
|
63
78
|
else
|
64
|
-
Kernel.raise "RobustThreadInterruption not installed for #{thread}"
|
79
|
+
Kernel.raise NotInstalled, "RobustThreadInterruption not installed for #{_get_thread_display_name thread}"
|
65
80
|
end
|
66
81
|
end
|
67
82
|
module_function :interrupted?
|
68
83
|
|
69
84
|
def self.raise(thread, exception = Interrupted)
|
70
|
-
if
|
85
|
+
if data = thread[:robust_interruption]
|
71
86
|
RobustInterruption.disable_interruptions(Thread.current) do
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
def self._raise(thread, exception)
|
80
|
-
data = thread[:robust_interruption]
|
81
|
-
if data
|
82
|
-
data.interrupted = true
|
83
|
-
if data.try_lock
|
84
|
-
begin
|
85
|
-
thread.raise(exception)
|
86
|
-
ensure
|
87
|
-
data.unlock
|
87
|
+
data.interrupted = true
|
88
|
+
if data.try_lock
|
89
|
+
begin
|
90
|
+
thread.raise(exception)
|
91
|
+
ensure
|
92
|
+
data.unlock
|
93
|
+
end
|
88
94
|
end
|
89
95
|
end
|
90
96
|
else
|
91
|
-
Kernel.raise "RobustThreadInterruption not installed for #{thread}"
|
97
|
+
Kernel.raise NotInstalled, "RobustThreadInterruption not installed for #{_get_thread_display_name thread}"
|
92
98
|
end
|
93
99
|
end
|
94
100
|
|
@@ -105,7 +111,7 @@ module RobustInterruption
|
|
105
111
|
data.unlock if was_interruptable
|
106
112
|
end
|
107
113
|
else
|
108
|
-
Kernel.raise "RobustThreadInterruption not installed for #{thread}"
|
114
|
+
Kernel.raise NotInstalled, "RobustThreadInterruption not installed for #{_get_thread_display_name thread}"
|
109
115
|
end
|
110
116
|
end
|
111
117
|
module_function :disable_interruptions
|
@@ -123,7 +129,7 @@ module RobustInterruption
|
|
123
129
|
data.pop_interruption_flag
|
124
130
|
end
|
125
131
|
else
|
126
|
-
Kernel.raise "RobustThreadInterruption not installed for #{thread}"
|
132
|
+
Kernel.raise NotInstalled, "RobustThreadInterruption not installed for #{_get_thread_display_name thread}"
|
127
133
|
end
|
128
134
|
end
|
129
135
|
module_function :enable_interruptions
|
@@ -132,7 +138,7 @@ module RobustInterruption
|
|
132
138
|
data = thread[:robust_interruption]
|
133
139
|
if data
|
134
140
|
if data.interruption_flags.size < 2
|
135
|
-
Kernel.raise "Cannot restore interruptions state to previous value - no previous value exists"
|
141
|
+
Kernel.raise NotInstalled, "Cannot restore interruptions state to previous value - no previous value exists"
|
136
142
|
end
|
137
143
|
if data.interruption_flags[-2]
|
138
144
|
enable_interruptions do
|
@@ -144,10 +150,23 @@ module RobustInterruption
|
|
144
150
|
end
|
145
151
|
end
|
146
152
|
else
|
147
|
-
Kernel.raise "RobustThreadInterruption not installed for #{thread}"
|
153
|
+
Kernel.raise NotInstalled, "RobustThreadInterruption not installed for #{_get_thread_display_name thread}"
|
148
154
|
end
|
149
155
|
end
|
150
156
|
module_function :restore_interruptions
|
157
|
+
|
158
|
+
private
|
159
|
+
def _get_thread_display_name(thread)
|
160
|
+
if !(thread_id = thread[:id])
|
161
|
+
thread.to_s =~ /:(0x[0-9a-f]+)/i
|
162
|
+
thread_id = $1 || '?'
|
163
|
+
end
|
164
|
+
if thread_name = thread[:name]
|
165
|
+
thread_name = "(#{thread_name})"
|
166
|
+
end
|
167
|
+
return "#{thread_id}#{thread_name}"
|
168
|
+
end
|
169
|
+
module_function :_get_thread_display_name
|
151
170
|
end
|
152
171
|
|
153
172
|
end # module Utils
|
@@ -1,26 +1,7 @@
|
|
1
1
|
#####################################################
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# The fact that Phusion Passenger uses Nginx
|
7
|
-
# internally is considered to be an implementation
|
8
|
-
# detail that the user should not bother with.
|
9
|
-
# We may arbitrarily replace the Nginx core with
|
10
|
-
# something else in the future.
|
11
|
-
#
|
12
|
-
# As such, we do not support any kind of custom
|
13
|
-
# Nginx configuration in Phusion Passenger Standalone.
|
14
|
-
# If you need additional Nginx modules or if you need
|
15
|
-
# special Nginx configuration or whatever then you
|
16
|
-
# should use Phusion Passenger for Nginx, NOT
|
17
|
-
# Phusion Passenger Standalone.
|
18
|
-
#
|
19
|
-
# You are strongly discouraged from editing this file
|
20
|
-
# and treating Phusion Passenger Standalone as an easy
|
21
|
-
# way to start Nginx. We will not provide any support
|
22
|
-
# for this.
|
23
|
-
#
|
2
|
+
# This file is autogenerated by Phusion Passenger Standalone
|
3
|
+
# from <%= template_filename %>
|
4
|
+
# Please edit that file instead.
|
24
5
|
#####################################################
|
25
6
|
|
26
7
|
|
@@ -96,6 +77,7 @@ http {
|
|
96
77
|
union_station_key <%= app[:union_station_key] %>;
|
97
78
|
<% end %>
|
98
79
|
|
80
|
+
# Rails asset pipeline support.
|
99
81
|
location ~ ^/assets/ {
|
100
82
|
error_page 490 = @static_asset;
|
101
83
|
error_page 491 = @dynamic_request;
|
data/test/config.json.example
CHANGED
@@ -38,5 +38,5 @@
|
|
38
38
|
// If you want to run the Nginx integration tests, then set the following
|
39
39
|
// config option to the full path of the Nginx binary. This Nginx binary *must*
|
40
40
|
// be compiled with Phusion Passenger support!
|
41
|
-
|
41
|
+
"nginx": "/usr/local/sbin/nginx"
|
42
42
|
}
|
@@ -27,7 +27,6 @@ namespace tut {
|
|
27
27
|
~ApplicationPool2_DirectSpawnerTest() {
|
28
28
|
setLogLevel(DEFAULT_LOG_LEVEL);
|
29
29
|
unlink("stub/wsgi/passenger_wsgi.pyc");
|
30
|
-
Process::maybeShutdown(process);
|
31
30
|
PipeWatcher::onData = PipeWatcher::DataCallback();
|
32
31
|
}
|
33
32
|
|
@@ -67,7 +66,8 @@ namespace tut {
|
|
67
66
|
spawner.getConfig()->forwardStderr = false;
|
68
67
|
|
69
68
|
try {
|
70
|
-
spawner.spawn(options);
|
69
|
+
process = spawner.spawn(options);
|
70
|
+
process->requiresShutdown = false;
|
71
71
|
fail("Timeout expected");
|
72
72
|
} catch (const SpawnException &e) {
|
73
73
|
ensure_equals(e.getErrorKind(),
|
@@ -89,7 +89,8 @@ namespace tut {
|
|
89
89
|
spawner.getConfig()->forwardStderr = false;
|
90
90
|
|
91
91
|
try {
|
92
|
-
spawner.spawn(options);
|
92
|
+
process = spawner.spawn(options);
|
93
|
+
process->requiresShutdown = false;
|
93
94
|
fail("SpawnException expected");
|
94
95
|
} catch (const SpawnException &e) {
|
95
96
|
ensure_equals(e.getErrorKind(),
|
@@ -108,6 +109,7 @@ namespace tut {
|
|
108
109
|
options.startupFile = "start.rb";
|
109
110
|
SpawnerPtr spawner = createSpawner(options);
|
110
111
|
process = spawner->spawn(options);
|
112
|
+
process->requiresShutdown = false;
|
111
113
|
ensure_equals(process->sockets->size(), 1u);
|
112
114
|
|
113
115
|
Connection conn = process->sockets->front().checkoutConnection();
|
@@ -732,7 +732,7 @@ namespace tut {
|
|
732
732
|
SessionPtr session3 = pool->get(options, &ticket);
|
733
733
|
{
|
734
734
|
LockGuard l(pool->syncher);
|
735
|
-
ensure("(4)",
|
735
|
+
ensure("(4)", session1->getProcess()->enabled == Process::DETACHED);
|
736
736
|
ensure_equals("(6)", fooGroup->getWaitlist.size(), 1u);
|
737
737
|
ensure_equals("(7)", pool->getWaitlist.size(), 0u);
|
738
738
|
}
|
@@ -763,10 +763,17 @@ namespace tut {
|
|
763
763
|
|
764
764
|
ProcessPtr process = currentSession->getProcess();
|
765
765
|
pool->detachProcess(currentSession->getProcess());
|
766
|
-
|
766
|
+
{
|
767
|
+
LockGuard l(pool->syncher);
|
768
|
+
ensure(process->enabled == Process::DETACHED);
|
769
|
+
}
|
767
770
|
EVENTUALLY(5,
|
768
771
|
result = pool->getProcessCount() == 2;
|
769
772
|
);
|
773
|
+
currentSession.reset();
|
774
|
+
EVENTUALLY(5,
|
775
|
+
result = process->isDead();
|
776
|
+
);
|
770
777
|
}
|
771
778
|
|
772
779
|
TEST_METHOD(31) {
|
@@ -866,6 +873,72 @@ namespace tut {
|
|
866
873
|
ensure(!superGroup->garbageCollectable());
|
867
874
|
}
|
868
875
|
|
876
|
+
TEST_METHOD(34) {
|
877
|
+
// When detaching a process, it waits until all sessions have
|
878
|
+
// finished before telling the process to shut down.
|
879
|
+
Options options = createOptions();
|
880
|
+
options.spawnMethod = "direct";
|
881
|
+
options.minProcesses = 0;
|
882
|
+
SessionPtr session = pool->get(options, &ticket);
|
883
|
+
ProcessPtr process = session->getProcess();
|
884
|
+
|
885
|
+
ensure(pool->detachProcess(process));
|
886
|
+
{
|
887
|
+
LockGuard l(pool->syncher);
|
888
|
+
ensure_equals(process->enabled, Process::DETACHED);
|
889
|
+
}
|
890
|
+
SHOULD_NEVER_HAPPEN(100,
|
891
|
+
LockGuard l(pool->syncher);
|
892
|
+
result = !process->isAlive()
|
893
|
+
|| !process->osProcessExists();
|
894
|
+
);
|
895
|
+
|
896
|
+
session.reset();
|
897
|
+
EVENTUALLY(1,
|
898
|
+
LockGuard l(pool->syncher);
|
899
|
+
result = process->enabled == Process::DETACHED
|
900
|
+
&& !process->osProcessExists()
|
901
|
+
&& process->isDead();
|
902
|
+
);
|
903
|
+
}
|
904
|
+
|
905
|
+
TEST_METHOD(35) {
|
906
|
+
// When detaching a process, it waits until the OS processes
|
907
|
+
// have exited before cleaning up the in-memory data structures.
|
908
|
+
Options options = createOptions();
|
909
|
+
options.spawnMethod = "direct";
|
910
|
+
options.minProcesses = 0;
|
911
|
+
ProcessPtr process = pool->get(options, &ticket)->getProcess();
|
912
|
+
|
913
|
+
ScopeGuard g(boost::bind(::kill, process->pid, SIGCONT));
|
914
|
+
kill(process->pid, SIGSTOP);
|
915
|
+
|
916
|
+
ensure(pool->detachProcess(process));
|
917
|
+
{
|
918
|
+
LockGuard l(pool->syncher);
|
919
|
+
ensure_equals(process->enabled, Process::DETACHED);
|
920
|
+
}
|
921
|
+
EVENTUALLY(1,
|
922
|
+
result = process->getLifeStatus() == Process::SHUTDOWN_TRIGGERED;
|
923
|
+
);
|
924
|
+
|
925
|
+
SHOULD_NEVER_HAPPEN(100,
|
926
|
+
LockGuard l(pool->syncher);
|
927
|
+
result = process->isDead()
|
928
|
+
|| !process->osProcessExists();
|
929
|
+
);
|
930
|
+
|
931
|
+
kill(process->pid, SIGCONT);
|
932
|
+
g.clear();
|
933
|
+
|
934
|
+
EVENTUALLY(1,
|
935
|
+
LockGuard l(pool->syncher);
|
936
|
+
result = process->enabled == Process::DETACHED
|
937
|
+
&& !process->osProcessExists()
|
938
|
+
&& process->isDead();
|
939
|
+
);
|
940
|
+
}
|
941
|
+
|
869
942
|
|
870
943
|
/*********** Test disabling and enabling processes ***********/
|
871
944
|
|
@@ -32,7 +32,6 @@ namespace tut {
|
|
32
32
|
~ApplicationPool2_SmartSpawnerTest() {
|
33
33
|
setLogLevel(DEFAULT_LOG_LEVEL);
|
34
34
|
unlink("stub/wsgi/passenger_wsgi.pyc");
|
35
|
-
Process::maybeShutdown(process);
|
36
35
|
PipeWatcher::onData = PipeWatcher::DataCallback();
|
37
36
|
}
|
38
37
|
|
@@ -79,7 +78,8 @@ namespace tut {
|
|
79
78
|
options.startCommand = "ruby\1" "start.rb";
|
80
79
|
options.startupFile = "start.rb";
|
81
80
|
shared_ptr<SmartSpawner> spawner = createSpawner(options);
|
82
|
-
spawner->spawn(options)
|
81
|
+
process = spawner->spawn(options);
|
82
|
+
process->requiresShutdown = false;
|
83
83
|
|
84
84
|
kill(spawner->getPreloaderPid(), SIGTERM);
|
85
85
|
// Give it some time to exit.
|
@@ -87,7 +87,8 @@ namespace tut {
|
|
87
87
|
|
88
88
|
// No exception at next spawn.
|
89
89
|
setLogLevel(-1);
|
90
|
-
spawner->spawn(options)
|
90
|
+
process = spawner->spawn(options);
|
91
|
+
process->requiresShutdown = false;
|
91
92
|
}
|
92
93
|
|
93
94
|
TEST_METHOD(81) {
|
@@ -100,7 +101,8 @@ namespace tut {
|
|
100
101
|
setLogLevel(-1);
|
101
102
|
shared_ptr<SmartSpawner> spawner = createSpawner(options, true);
|
102
103
|
try {
|
103
|
-
spawner->spawn(options)
|
104
|
+
process = spawner->spawn(options);
|
105
|
+
process->requiresShutdown = false;
|
104
106
|
fail("SpawnException expected");
|
105
107
|
} catch (const SpawnException &) {
|
106
108
|
// Pass.
|
@@ -130,7 +132,8 @@ namespace tut {
|
|
130
132
|
spawner.getConfig()->forwardStderr = false;
|
131
133
|
|
132
134
|
try {
|
133
|
-
spawner.spawn(options)
|
135
|
+
process = spawner.spawn(options);
|
136
|
+
process->requiresShutdown = false;
|
134
137
|
fail("SpawnException expected");
|
135
138
|
} catch (const SpawnException &e) {
|
136
139
|
ensure_equals(e.getErrorKind(),
|
@@ -161,7 +164,8 @@ namespace tut {
|
|
161
164
|
spawner.getConfig()->forwardStderr = false;
|
162
165
|
|
163
166
|
try {
|
164
|
-
spawner.spawn(options)
|
167
|
+
process = spawner.spawn(options);
|
168
|
+
process->requiresShutdown = false;
|
165
169
|
fail("SpawnException expected");
|
166
170
|
} catch (const SpawnException &e) {
|
167
171
|
ensure_equals(e.getErrorKind(),
|
@@ -192,7 +196,8 @@ namespace tut {
|
|
192
196
|
spawner.getConfig()->forwardStderr = false;
|
193
197
|
|
194
198
|
try {
|
195
|
-
spawner.spawn(options)
|
199
|
+
process = spawner.spawn(options);
|
200
|
+
process->requiresShutdown = false;
|
196
201
|
fail("SpawnException expected");
|
197
202
|
} catch (const SpawnException &e) {
|
198
203
|
ensure(containsSubstring(e["envvars"], "PASSENGER_FOO=foo\n"));
|