test/cxx/ApplicationPool2/SmartSpawnerTest.cpp in passenger-4.0.60 vs test/cxx/ApplicationPool2/SmartSpawnerTest.cpp in passenger-5.0.0.beta1

- old
+ new

@@ -11,19 +11,16 @@ using namespace Passenger; using namespace Passenger::ApplicationPool2; namespace tut { struct ApplicationPool2_SmartSpawnerTest { - ServerInstanceDirPtr serverInstanceDir; - ServerInstanceDir::GenerationPtr generation; - ProcessPtr process; + SpawnObject object; PipeWatcher::DataCallback gatherOutput; string gatheredOutput; boost::mutex gatheredOutputSyncher; ApplicationPool2_SmartSpawnerTest() { - createServerInstanceDirAndGeneration(serverInstanceDir, generation); PipeWatcher::onData = PipeWatcher::DataCallback(); gatherOutput = boost::bind(&ApplicationPool2_SmartSpawnerTest::_gatherOutput, this, _1, _2); setLogLevel(LVL_ERROR); // TODO: should be LVL_WARN setPrintAppOutputAsDebuggingMessages(true); } @@ -44,17 +41,21 @@ command.push_back(string(buf) + "/support/placebo-preloader.rb"); if (exitImmediately) { command.push_back("exit-immediately"); } - return boost::make_shared<SmartSpawner>( - generation, - command, - options, - make_shared<SpawnerConfig>(*resourceLocator)); + return boost::make_shared<SmartSpawner>(command, + options, createSpawnerConfig()); } + SpawnerConfigPtr createSpawnerConfig() { + SpawnerConfigPtr config = boost::make_shared<SpawnerConfig>(); + config->resourceLocator = resourceLocator; + config->finalize(); + return config; + } + Options createOptions() { Options options; options.spawnMethod = "smart"; options.loadShellEnvvars = false; return options; @@ -77,20 +78,20 @@ options.appRoot = "stub/rack"; options.startCommand = "ruby\t" "start.rb"; options.startupFile = "start.rb"; boost::shared_ptr<SmartSpawner> spawner = createSpawner(options); setLogLevel(LVL_CRIT); - process = spawner->spawn(options); - process->requiresShutdown = false; + object = spawner->spawn(options); + object.process->requiresShutdown = false; kill(spawner->getPreloaderPid(), SIGTERM); // Give it some time to exit. usleep(300000); // No exception at next spawn. - process = spawner->spawn(options); - process->requiresShutdown = false; + object = spawner->spawn(options); + object.process->requiresShutdown = false; } TEST_METHOD(81) { // If the preloader still crashes after the restart then // SmartSpawner will throw an exception. @@ -99,12 +100,12 @@ options.startCommand = "ruby\t" "start.rb"; options.startupFile = "start.rb"; setLogLevel(LVL_CRIT); boost::shared_ptr<SmartSpawner> spawner = createSpawner(options, true); try { - process = spawner->spawn(options); - process->requiresShutdown = false; + object = spawner->spawn(options); + object.process->requiresShutdown = false; fail("SpawnException expected"); } catch (const SpawnException &) { // Pass. } } @@ -115,31 +116,43 @@ // whatever stderr output as error page. Options options = createOptions(); options.appRoot = "stub/rack"; options.startCommand = "ruby\t" "start.rb"; options.startupFile = "start.rb"; - options.startTimeout = 300; + options.startTimeout = 100; vector<string> preloaderCommand; preloaderCommand.push_back("bash"); preloaderCommand.push_back("-c"); preloaderCommand.push_back("echo hello world >&2; sleep 60"); - SmartSpawner spawner( - generation, - preloaderCommand, - options, - make_shared<SpawnerConfig>(*resourceLocator)); + SmartSpawner spawner(preloaderCommand, options, createSpawnerConfig()); setLogLevel(LVL_CRIT); try { - process = spawner.spawn(options); - process->requiresShutdown = false; + object = spawner.spawn(options); + object.process->requiresShutdown = false; fail("SpawnException expected"); } catch (const SpawnException &e) { ensure_equals(e.getErrorKind(), SpawnException::PRELOADER_STARTUP_TIMEOUT); - ensure(e.getErrorPage().find("hello world\n") != string::npos); + if (e.getErrorPage().find("hello world\n") == string::npos) { + // This might be caused by the machine being too slow. + // Try again with a higher timeout. + options.startTimeout = 1000; + SmartSpawner spawner2(preloaderCommand, options, createSpawnerConfig()); + try { + object = spawner2.spawn(options); + object.process->requiresShutdown = false; + fail("SpawnException expected"); + } catch (const SpawnException &e2) { + ensure_equals(e2.getErrorKind(), + SpawnException::PRELOADER_STARTUP_TIMEOUT); + if (e2.getErrorPage().find("hello world\n") == string::npos) { + fail(("Unexpected error page:\n" + e2.getErrorPage()).c_str()); + } + } + } } } TEST_METHOD(83) { // If the preloader crashed during startup without returning @@ -152,20 +165,16 @@ vector<string> preloaderCommand; preloaderCommand.push_back("bash"); preloaderCommand.push_back("-c"); preloaderCommand.push_back("echo hello world >&2"); - SmartSpawner spawner( - generation, - preloaderCommand, - options, - make_shared<SpawnerConfig>(*resourceLocator)); + SmartSpawner spawner(preloaderCommand, options, createSpawnerConfig()); setLogLevel(LVL_CRIT); try { - process = spawner.spawn(options); - process->requiresShutdown = false; + object = spawner.spawn(options); + object.process->requiresShutdown = false; fail("SpawnException expected"); } catch (const SpawnException &e) { ensure_equals(e.getErrorKind(), SpawnException::PRELOADER_STARTUP_ERROR); ensure(e.getErrorPage().find("hello world\n") != string::npos); @@ -173,30 +182,28 @@ } TEST_METHOD(84) { // If the preloader encountered an error, then the resulting SpawnException // takes note of the process's environment variables. + string envvars = modp::b64_encode("PASSENGER_FOO\0foo\0", + sizeof("PASSENGER_FOO\0foo\0") - 1); Options options = createOptions(); options.appRoot = "stub/rack"; options.startCommand = "ruby\t" "start.rb"; options.startupFile = "start.rb"; - options.environmentVariables.push_back(make_pair("PASSENGER_FOO", "foo")); + options.environmentVariables = envvars; vector<string> preloaderCommand; preloaderCommand.push_back("bash"); preloaderCommand.push_back("-c"); preloaderCommand.push_back("echo hello world >&2"); - SmartSpawner spawner( - generation, - preloaderCommand, - options, - make_shared<SpawnerConfig>(*resourceLocator)); + SmartSpawner spawner(preloaderCommand, options, createSpawnerConfig()); setLogLevel(LVL_CRIT); try { - process = spawner.spawn(options); - process->requiresShutdown = false; + object = spawner.spawn(options); + object.process->requiresShutdown = false; fail("SpawnException expected"); } catch (const SpawnException &e) { ensure(containsSubstring(e["envvars"], "PASSENGER_FOO=foo\n")); } } @@ -211,31 +218,22 @@ { vector<string> preloaderCommand; preloaderCommand.push_back("ruby"); preloaderCommand.push_back(resourceLocator->getHelperScriptsDir() + "/rack-preloader.rb"); - SmartSpawner spawner( - generation, - preloaderCommand, - options, - make_shared<SpawnerConfig>(*resourceLocator)); - process = spawner.spawn(options); - process->requiresShutdown = false; + SmartSpawner spawner(preloaderCommand, options, createSpawnerConfig()); + object = spawner.spawn(options); + object.process->requiresShutdown = false; } - SessionPtr session = process->newSession(); + SessionPtr session = object.process->newSession(); session->initiate(); const char header[] = "REQUEST_METHOD\0GET\0" "PATH_INFO\0/print_stderr\0"; - string data(header, sizeof(header) - 1); - data.append("PASSENGER_CONNECT_PASSWORD"); - data.append(1, '\0'); - data.append(process->connectPassword); - data.append(1, '\0'); - writeScalarMessage(session->fd(), data); + writeScalarMessage(session->fd(), header, sizeof(header) - 1); shutdown(session->fd(), SHUT_WR); readAll(session->fd()); EVENTUALLY(2, boost::lock_guard<boost::mutex> l(gatheredOutputSyncher); result = gatheredOutput.find("hello world!\n") != string::npos;