passenger 5.0.4 → 5.0.5
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.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/.editorconfig +10 -0
- data/CHANGELOG +21 -0
- data/build/agents.rb +2 -2
- data/build/apache2.rb +6 -5
- data/build/common_library.rb +22 -7
- data/build/cxx_tests.rb +0 -3
- data/build/misc.rb +1 -1
- data/dev/parse_file_descriptor_log +119 -0
- data/doc/CloudLicensingConfiguration.html +387 -0
- data/doc/Design and Architecture.html +2430 -0
- data/doc/Packaging.html +488 -0
- data/doc/Security of user switching support.html +1833 -0
- data/doc/ServerOptimizationGuide.html +659 -0
- data/doc/ServerOptimizationGuide.txt.md +8 -0
- data/doc/Users guide Apache.html +9116 -0
- data/doc/Users guide Apache.idmap.txt +6 -2
- data/doc/Users guide Apache.txt +26 -7
- data/doc/Users guide Nginx.html +9025 -0
- data/doc/Users guide Nginx.idmap.txt +7 -3
- data/doc/Users guide Nginx.txt +29 -6
- data/doc/Users guide Standalone.html +3983 -0
- data/doc/Users guide.html +1748 -0
- data/doc/users_guide_snippets/installation.txt +4 -4
- data/ext/apache2/Configuration.cpp +16 -5
- data/ext/apache2/Configuration.hpp +4 -2
- data/ext/apache2/Hooks.cpp +44 -19
- data/ext/boost/libs/thread/src/pthread/once.cpp +2 -0
- data/ext/boost/libs/thread/src/pthread/once_atomic.cpp +6 -0
- data/ext/common/AgentsStarter.h +3 -2
- data/ext/common/ApplicationPool2/DirectSpawner.h +14 -4
- data/ext/common/ApplicationPool2/DummySpawner.h +12 -7
- data/ext/common/ApplicationPool2/Implementation.cpp +1 -1
- data/ext/common/ApplicationPool2/Process.h +2 -1
- data/ext/common/ApplicationPool2/Session.h +6 -6
- data/ext/common/ApplicationPool2/SmartSpawner.h +19 -4
- data/ext/common/ApplicationPool2/Socket.h +59 -27
- data/ext/common/ApplicationPool2/Spawner.h +2 -2
- data/ext/common/BackgroundEventLoop.cpp +6 -1
- data/ext/common/Constants.h +1 -1
- data/ext/common/EventedClient.h +1 -1
- data/ext/common/EventedServer.h +2 -2
- data/ext/common/FileDescriptor.h +25 -6
- data/ext/common/Logging.cpp +107 -52
- data/ext/common/Logging.h +146 -19
- data/ext/common/MessageClient.h +2 -2
- data/ext/common/MessageServer.h +3 -2
- data/ext/common/RandomGenerator.h +8 -7
- data/ext/common/SafeLibev.h +5 -1
- data/ext/common/ServerKit/AcceptLoadBalancer.h +9 -4
- data/ext/common/ServerKit/FdSinkChannel.h +5 -2
- data/ext/common/ServerKit/FdSourceChannel.h +5 -2
- data/ext/common/ServerKit/FileBufferedChannel.h +2 -0
- data/ext/common/ServerKit/FileBufferedFdSinkChannel.h +7 -2
- data/ext/common/ServerKit/HttpServer.h +6 -0
- data/ext/common/ServerKit/Server.h +40 -3
- data/ext/common/StaticString.h +20 -0
- data/ext/common/UnionStation/Connection.h +3 -1
- data/ext/common/UnionStation/Core.h +6 -4
- data/ext/common/Utils.cpp +4 -3
- data/ext/common/Utils/DateParsing.h +19 -5
- data/ext/common/Utils/FastStringStream.h +183 -0
- data/ext/common/Utils/IOUtils.cpp +47 -28
- data/ext/common/Utils/IOUtils.h +56 -12
- data/ext/common/Utils/MessagePassing.h +3 -3
- data/ext/common/Utils/ProcessMetricsCollector.h +2 -2
- data/ext/common/Utils/ScopeGuard.h +16 -5
- data/ext/common/Utils/SpeedMeter.h +2 -2
- data/ext/common/Utils/StrIntUtils.cpp +6 -6
- data/ext/common/Utils/StrIntUtils.h +2 -1
- data/ext/common/agents/Base.cpp +56 -4
- data/ext/common/agents/Base.h +2 -1
- data/ext/common/agents/HelperAgent/AdminServer.h +122 -11
- data/ext/common/agents/HelperAgent/Main.cpp +16 -5
- data/ext/common/agents/HelperAgent/OptionParser.h +7 -1
- data/ext/common/agents/HelperAgent/RequestHandler.h +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +10 -1
- data/ext/common/agents/HelperAgent/RequestHandler/Request.h +8 -0
- data/ext/common/agents/HelperAgent/RequestHandler/TurboCaching.h +4 -3
- data/ext/common/agents/LoggingAgent/AdminServer.h +57 -11
- data/ext/common/agents/LoggingAgent/LoggingServer.h +3 -3
- data/ext/common/agents/LoggingAgent/Main.cpp +11 -3
- data/ext/common/agents/Watchdog/AdminServer.h +53 -11
- data/ext/common/agents/Watchdog/AgentWatcher.cpp +3 -3
- data/ext/common/agents/Watchdog/Main.cpp +13 -6
- data/ext/libeio/ecb.h +1 -1
- data/ext/libev/ev.c +13 -1
- data/ext/libev/ev.h +3 -0
- data/ext/nginx/Configuration.c +28 -6
- data/ext/nginx/Configuration.h +2 -1
- data/ext/nginx/ngx_http_passenger_module.c +5 -4
- data/ext/oxt/dynamic_thread_group.hpp +38 -5
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/common_library.rb +9 -5
- data/lib/phusion_passenger/config/reopen_logs_command.rb +2 -2
- data/lib/phusion_passenger/packaging.rb +23 -37
- data/passenger.gemspec +21 -21
- metadata +4 -453
- metadata.gz.asc +7 -7
- data/.gitignore +0 -68
- data/.travis.yml +0 -16
- data/Gemfile +0 -17
- data/Gemfile.lock +0 -39
- data/Vagrantfile +0 -54
- data/debian.template/README.Debian +0 -15
- data/debian.template/changelog +0 -316
- data/debian.template/compat +0 -1
- data/debian.template/control.erb +0 -91
- data/debian.template/copyright +0 -385
- data/debian.template/libapache2-mod-passenger.install +0 -3
- data/debian.template/libapache2-mod-passenger.postinst +0 -36
- data/debian.template/libapache2-mod-passenger.prerm +0 -15
- data/debian.template/locations.ini.erb +0 -14
- data/debian.template/passenger-dev.install.erb +0 -3
- data/debian.template/passenger-doc.install.erb +0 -2
- data/debian.template/passenger.conf +0 -6
- data/debian.template/passenger.docs +0 -4
- data/debian.template/passenger.install.erb +0 -14
- data/debian.template/passenger.load +0 -3
- data/debian.template/passenger.manpages +0 -3
- data/debian.template/patches/series +0 -0
- data/debian.template/rules.erb +0 -76
- data/debian.template/source/format +0 -1
- data/ext/common/EventedBufferedInput.h +0 -458
- data/packaging/rpm/LICENSE.txt +0 -19
- data/packaging/rpm/Makefile +0 -13
- data/packaging/rpm/README.md +0 -41
- data/packaging/rpm/Vagrantfile +0 -38
- data/packaging/rpm/Vagrantfile.centos +0 -30
- data/packaging/rpm/build +0 -170
- data/packaging/rpm/create_project +0 -41
- data/packaging/rpm/git_update +0 -88
- data/packaging/rpm/image/Dockerfile +0 -37
- data/packaging/rpm/image/Gemfile +0 -3
- data/packaging/rpm/image/Gemfile.lock +0 -12
- data/packaging/rpm/image/RPM-GPG-KEY-amazon-ga +0 -19
- data/packaging/rpm/image/amazon2014-i386.cfg +0 -96
- data/packaging/rpm/image/amazon2014-x86_64.cfg +0 -96
- data/packaging/rpm/image/site-defaults.cfg +0 -168
- data/packaging/rpm/internal/build_tasks.rb +0 -238
- data/packaging/rpm/internal/dummygpg +0 -11
- data/packaging/rpm/internal/exec_build +0 -42
- data/packaging/rpm/internal/get_distro_arch +0 -14
- data/packaging/rpm/internal/get_distro_id +0 -10
- data/packaging/rpm/internal/git_update +0 -27
- data/packaging/rpm/internal/inituidgid +0 -17
- data/packaging/rpm/internal/my_init +0 -344
- data/packaging/rpm/internal/python27 +0 -3
- data/packaging/rpm/internal/repo_update +0 -46
- data/packaging/rpm/internal/setuser +0 -26
- data/packaging/rpm/internal/tracking_helper +0 -40
- data/packaging/rpm/jenkins_release +0 -99
- data/packaging/rpm/lib/build_tasks_support.rb +0 -402
- data/packaging/rpm/lib/preprocessor.rb +0 -341
- data/packaging/rpm/nginx_spec/404.html +0 -119
- data/packaging/rpm/nginx_spec/50x.html +0 -119
- data/packaging/rpm/nginx_spec/index.html +0 -116
- data/packaging/rpm/nginx_spec/nginx-auto-cc-gcc.patch +0 -13
- data/packaging/rpm/nginx_spec/nginx-logo.png +0 -0
- data/packaging/rpm/nginx_spec/nginx-upgrade +0 -13
- data/packaging/rpm/nginx_spec/nginx-upgrade.8 +0 -151
- data/packaging/rpm/nginx_spec/nginx.conf +0 -131
- data/packaging/rpm/nginx_spec/nginx.init +0 -144
- data/packaging/rpm/nginx_spec/nginx.logrotate +0 -13
- data/packaging/rpm/nginx_spec/nginx.service +0 -15
- data/packaging/rpm/nginx_spec/nginx.spec.template +0 -560
- data/packaging/rpm/nginx_spec/nginx.sysconfig +0 -4
- data/packaging/rpm/nginx_spec/passenger.conf +0 -9
- data/packaging/rpm/nginx_spec/poweredby.png +0 -0
- data/packaging/rpm/passenger_spec/apache-passenger.conf.in +0 -26
- data/packaging/rpm/passenger_spec/config.json +0 -30
- data/packaging/rpm/passenger_spec/passenger.logrotate +0 -7
- data/packaging/rpm/passenger_spec/passenger.spec.template +0 -478
- data/packaging/rpm/passenger_spec/passenger_dynamic_thread_group.patch +0 -16
- data/packaging/rpm/passenger_spec/passenger_tests_default_config_example.patch +0 -44
- data/packaging/rpm/passenger_spec/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +0 -21
- data/packaging/rpm/repo_update +0 -114
- data/packaging/rpm/setup-system +0 -61
- data/packaging/rpm/shell +0 -10
- data/test/.rspec +0 -4
- data/test/config.json.example +0 -42
- data/test/config.json.rpm-automation +0 -15
- data/test/config.json.travis +0 -15
- data/test/config.json.vagrant +0 -30
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +0 -124
- data/test/cxx/ApplicationPool2/OptionsTest.cpp +0 -30
- data/test/cxx/ApplicationPool2/PoolTest.cpp +0 -2062
- data/test/cxx/ApplicationPool2/ProcessTest.cpp +0 -130
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +0 -243
- data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +0 -823
- data/test/cxx/BufferedIOTest.cpp +0 -364
- data/test/cxx/CachedFileStatTest.cpp +0 -402
- data/test/cxx/CxxTestMain.cpp +0 -181
- data/test/cxx/DataStructures/LStringTest.cpp +0 -275
- data/test/cxx/DataStructures/StringKeyTableTest.cpp +0 -199
- data/test/cxx/DateParsingTest.cpp +0 -75
- data/test/cxx/DechunkerTest.cpp +0 -250
- data/test/cxx/EventedBufferedInputTest.cpp +0 -758
- data/test/cxx/EventedClientTest.cpp +0 -523
- data/test/cxx/FileChangeCheckerTest.cpp +0 -331
- data/test/cxx/FileDescriptorTest.cpp +0 -69
- data/test/cxx/FilterSupportTest.cpp +0 -433
- data/test/cxx/IOUtilsTest.cpp +0 -861
- data/test/cxx/MemoryKit/MbufTest.cpp +0 -213
- data/test/cxx/MessageIOTest.cpp +0 -360
- data/test/cxx/MessagePassingTest.cpp +0 -81
- data/test/cxx/MessageReadersWritersTest.cpp +0 -576
- data/test/cxx/MessageServerTest.cpp +0 -393
- data/test/cxx/ProcessMetricsCollectorTest.cpp +0 -123
- data/test/cxx/RequestHandlerTest.cpp +0 -1463
- data/test/cxx/ResponseCacheTest.cpp +0 -322
- data/test/cxx/ServerKit/ChannelTest.cpp +0 -1467
- data/test/cxx/ServerKit/CookieUtilsTest.cpp +0 -274
- data/test/cxx/ServerKit/FileBufferedChannelTest.cpp +0 -992
- data/test/cxx/ServerKit/HeaderTableTest.cpp +0 -177
- data/test/cxx/ServerKit/HttpServerTest.cpp +0 -1580
- data/test/cxx/ServerKit/ServerTest.cpp +0 -408
- data/test/cxx/StaticStringTest.cpp +0 -220
- data/test/cxx/StringMapTest.cpp +0 -131
- data/test/cxx/SystemTimeTest.cpp +0 -37
- data/test/cxx/TemplateTest.cpp +0 -118
- data/test/cxx/TestSupport.cpp +0 -207
- data/test/cxx/TestSupport.h +0 -333
- data/test/cxx/UnionStationTest.cpp +0 -741
- data/test/cxx/Utils/StrIntUtilsTest.cpp +0 -39
- data/test/cxx/UtilsTest.cpp +0 -672
- data/test/cxx/VariantMapTest.cpp +0 -191
- data/test/gdbinit.example +0 -34
- data/test/integration_tests/apache2_tests.rb +0 -585
- data/test/integration_tests/downloaded_binaries_tests.rb +0 -185
- data/test/integration_tests/native_packaging_spec.rb +0 -368
- data/test/integration_tests/nginx_tests.rb +0 -402
- data/test/integration_tests/shared/example_webapp_tests.rb +0 -289
- data/test/integration_tests/source_packaging_test.rb +0 -201
- data/test/integration_tests/spec_helper.rb +0 -22
- data/test/integration_tests/standalone_tests.rb +0 -392
- data/test/node/line_reader_spec.js +0 -338
- data/test/node/spec_helper.js +0 -65
- data/test/oxt/backtrace_test.cpp +0 -88
- data/test/oxt/counter.hpp +0 -55
- data/test/oxt/dynamic_thread_group_test.cpp +0 -131
- data/test/oxt/oxt_test_main.cpp +0 -27
- data/test/oxt/spin_lock_test.cpp +0 -59
- data/test/oxt/syscall_interruption_test.cpp +0 -39
- data/test/ruby/debug_logging_spec.rb +0 -145
- data/test/ruby/message_channel_spec.rb +0 -196
- data/test/ruby/rack/loader_spec.rb +0 -42
- data/test/ruby/rack/preloader_spec.rb +0 -48
- data/test/ruby/rails3.0/loader_spec.rb +0 -26
- data/test/ruby/rails3.0/preloader_spec.rb +0 -32
- data/test/ruby/rails3.1/loader_spec.rb +0 -26
- data/test/ruby/rails3.1/preloader_spec.rb +0 -32
- data/test/ruby/rails3.2/loader_spec.rb +0 -26
- data/test/ruby/rails3.2/preloader_spec.rb +0 -32
- data/test/ruby/rails4.0/loader_spec.rb +0 -28
- data/test/ruby/rails4.0/preloader_spec.rb +0 -34
- data/test/ruby/rails4.1/loader_spec.rb +0 -28
- data/test/ruby/rails4.1/preloader_spec.rb +0 -34
- data/test/ruby/request_handler_spec.rb +0 -747
- data/test/ruby/shared/loader_sharedspec.rb +0 -247
- data/test/ruby/shared/rails/union_station_extensions_sharedspec.rb +0 -357
- data/test/ruby/shared/ruby_loader_sharedspec.rb +0 -55
- data/test/ruby/spec_helper.rb +0 -114
- data/test/ruby/standalone/runtime_installer_spec.rb +0 -402
- data/test/ruby/union_station_spec.rb +0 -288
- data/test/ruby/utils/file_system_watcher_spec.rb +0 -229
- data/test/ruby/utils/hosts_file_parser.rb +0 -258
- data/test/ruby/utils/tee_input_spec.rb +0 -235
- data/test/ruby/utils/unseekable_socket_spec.rb +0 -66
- data/test/ruby/utils_spec.rb +0 -41
- data/test/stub/apache2/httpd.conf.erb +0 -122
- data/test/stub/apache2/mime.types +0 -748
- data/test/stub/garbage1.dat +0 -0
- data/test/stub/garbage2.dat +0 -0
- data/test/stub/garbage3.dat +0 -0
- data/test/stub/http_request.yml +0 -23
- data/test/stub/index.html +0 -1
- data/test/stub/nginx/koi-utf +0 -109
- data/test/stub/nginx/koi-win +0 -103
- data/test/stub/nginx/mime.types +0 -70
- data/test/stub/nginx/nginx.conf.erb +0 -70
- data/test/stub/nginx/win-utf +0 -126
- data/test/stub/node/app.js +0 -133
- data/test/stub/node/public/.gitignore +0 -0
- data/test/stub/node/tmp/.gitignore +0 -0
- data/test/stub/rack/config.ru +0 -95
- data/test/stub/rack/library.rb +0 -16
- data/test/stub/rack/public/.gitignore +0 -0
- data/test/stub/rack/start.rb +0 -52
- data/test/stub/rack/tmp/.gitignore +0 -0
- data/test/stub/rails3.0/.gitignore +0 -4
- data/test/stub/rails3.0/Gemfile +0 -22
- data/test/stub/rails3.0/Gemfile.lock +0 -80
- data/test/stub/rails3.0/Rakefile +0 -10
- data/test/stub/rails3.0/app/controllers/application_controller.rb +0 -4
- data/test/stub/rails3.0/app/helpers/application_helper.rb +0 -2
- data/test/stub/rails3.0/app/views/layouts/application.html.erb +0 -14
- data/test/stub/rails3.0/config.ru +0 -4
- data/test/stub/rails3.0/config/application.rb +0 -48
- data/test/stub/rails3.0/config/boot.rb +0 -13
- data/test/stub/rails3.0/config/database.yml +0 -22
- data/test/stub/rails3.0/config/environment.rb +0 -5
- data/test/stub/rails3.0/config/environments/development.rb +0 -19
- data/test/stub/rails3.0/config/environments/production.rb +0 -48
- data/test/stub/rails3.0/config/environments/test.rb +0 -32
- data/test/stub/rails3.0/config/initializers/backtrace_silencers.rb +0 -7
- data/test/stub/rails3.0/config/initializers/inflections.rb +0 -10
- data/test/stub/rails3.0/config/initializers/mime_types.rb +0 -5
- data/test/stub/rails3.0/config/initializers/passenger.rb +0 -2
- data/test/stub/rails3.0/config/initializers/secret_token.rb +0 -7
- data/test/stub/rails3.0/config/initializers/session_store.rb +0 -8
- data/test/stub/rails3.0/config/locales/en.yml +0 -5
- data/test/stub/rails3.0/config/routes.rb +0 -58
- data/test/stub/rails3.0/db/seeds.rb +0 -7
- data/test/stub/rails3.0/doc/README_FOR_APP +0 -2
- data/test/stub/rails3.0/lib/tasks/.gitkeep +0 -0
- data/test/stub/rails3.0/log/.gitignore +0 -0
- data/test/stub/rails3.0/public/404.html +0 -26
- data/test/stub/rails3.0/public/422.html +0 -26
- data/test/stub/rails3.0/public/500.html +0 -26
- data/test/stub/rails3.0/public/favicon.ico +0 -0
- data/test/stub/rails3.0/public/index.html +0 -279
- data/test/stub/rails3.0/public/robots.txt +0 -5
- data/test/stub/rails3.0/public/stylesheets/.gitkeep +0 -0
- data/test/stub/rails3.0/script/rails +0 -9
- data/test/stub/rails3.0/test/performance/browsing_test.rb +0 -9
- data/test/stub/rails3.0/test/test_helper.rb +0 -13
- data/test/stub/rails3.0/vendor/plugins/.gitkeep +0 -0
- data/test/stub/rails3.1/.gitignore +0 -15
- data/test/stub/rails3.1/Gemfile +0 -37
- data/test/stub/rails3.1/Gemfile.lock +0 -115
- data/test/stub/rails3.1/README +0 -261
- data/test/stub/rails3.1/Rakefile +0 -7
- data/test/stub/rails3.1/app/assets/images/rails.png +0 -0
- data/test/stub/rails3.1/app/assets/stylesheets/application.css +0 -7
- data/test/stub/rails3.1/app/controllers/application_controller.rb +0 -3
- data/test/stub/rails3.1/app/helpers/application_helper.rb +0 -2
- data/test/stub/rails3.1/app/mailers/.gitkeep +0 -0
- data/test/stub/rails3.1/app/models/.gitkeep +0 -0
- data/test/stub/rails3.1/app/views/layouts/application.html.erb +0 -14
- data/test/stub/rails3.1/config.ru +0 -4
- data/test/stub/rails3.1/config/application.rb +0 -48
- data/test/stub/rails3.1/config/boot.rb +0 -6
- data/test/stub/rails3.1/config/database.yml +0 -25
- data/test/stub/rails3.1/config/environment.rb +0 -5
- data/test/stub/rails3.1/config/environments/development.rb +0 -30
- data/test/stub/rails3.1/config/environments/production.rb +0 -60
- data/test/stub/rails3.1/config/environments/test.rb +0 -39
- data/test/stub/rails3.1/config/initializers/backtrace_silencers.rb +0 -7
- data/test/stub/rails3.1/config/initializers/inflections.rb +0 -10
- data/test/stub/rails3.1/config/initializers/mime_types.rb +0 -5
- data/test/stub/rails3.1/config/initializers/passenger.rb +0 -2
- data/test/stub/rails3.1/config/initializers/secret_token.rb +0 -7
- data/test/stub/rails3.1/config/initializers/session_store.rb +0 -8
- data/test/stub/rails3.1/config/initializers/wrap_parameters.rb +0 -14
- data/test/stub/rails3.1/config/locales/en.yml +0 -5
- data/test/stub/rails3.1/config/routes.rb +0 -58
- data/test/stub/rails3.1/db/seeds.rb +0 -7
- data/test/stub/rails3.1/doc/README_FOR_APP +0 -2
- data/test/stub/rails3.1/lib/assets/.gitkeep +0 -0
- data/test/stub/rails3.1/lib/tasks/.gitkeep +0 -0
- data/test/stub/rails3.1/log/.gitkeep +0 -0
- data/test/stub/rails3.1/public/404.html +0 -26
- data/test/stub/rails3.1/public/422.html +0 -26
- data/test/stub/rails3.1/public/500.html +0 -26
- data/test/stub/rails3.1/public/favicon.ico +0 -0
- data/test/stub/rails3.1/public/index.html +0 -241
- data/test/stub/rails3.1/public/robots.txt +0 -5
- data/test/stub/rails3.1/script/rails +0 -6
- data/test/stub/rails3.1/test/fixtures/.gitkeep +0 -0
- data/test/stub/rails3.1/test/functional/.gitkeep +0 -0
- data/test/stub/rails3.1/test/integration/.gitkeep +0 -0
- data/test/stub/rails3.1/test/performance/browsing_test.rb +0 -12
- data/test/stub/rails3.1/test/test_helper.rb +0 -13
- data/test/stub/rails3.1/test/unit/.gitkeep +0 -0
- data/test/stub/rails3.1/vendor/assets/stylesheets/.gitkeep +0 -0
- data/test/stub/rails3.1/vendor/plugins/.gitkeep +0 -0
- data/test/stub/rails3.2/.gitignore +0 -15
- data/test/stub/rails3.2/Gemfile +0 -39
- data/test/stub/rails3.2/Gemfile.lock +0 -113
- data/test/stub/rails3.2/Rakefile +0 -7
- data/test/stub/rails3.2/app/assets/images/rails.png +0 -0
- data/test/stub/rails3.2/app/assets/stylesheets/application.css +0 -13
- data/test/stub/rails3.2/app/controllers/application_controller.rb +0 -3
- data/test/stub/rails3.2/app/helpers/application_helper.rb +0 -2
- data/test/stub/rails3.2/app/mailers/.gitkeep +0 -0
- data/test/stub/rails3.2/app/models/.gitkeep +0 -0
- data/test/stub/rails3.2/app/views/layouts/application.html.erb +0 -14
- data/test/stub/rails3.2/config.ru +0 -4
- data/test/stub/rails3.2/config/application.rb +0 -62
- data/test/stub/rails3.2/config/boot.rb +0 -6
- data/test/stub/rails3.2/config/database.yml +0 -25
- data/test/stub/rails3.2/config/environment.rb +0 -5
- data/test/stub/rails3.2/config/environments/development.rb +0 -37
- data/test/stub/rails3.2/config/environments/production.rb +0 -67
- data/test/stub/rails3.2/config/environments/test.rb +0 -37
- data/test/stub/rails3.2/config/initializers/backtrace_silencers.rb +0 -7
- data/test/stub/rails3.2/config/initializers/inflections.rb +0 -15
- data/test/stub/rails3.2/config/initializers/mime_types.rb +0 -5
- data/test/stub/rails3.2/config/initializers/passenger.rb +0 -2
- data/test/stub/rails3.2/config/initializers/secret_token.rb +0 -7
- data/test/stub/rails3.2/config/initializers/session_store.rb +0 -8
- data/test/stub/rails3.2/config/initializers/wrap_parameters.rb +0 -14
- data/test/stub/rails3.2/config/locales/en.yml +0 -5
- data/test/stub/rails3.2/config/routes.rb +0 -58
- data/test/stub/rails3.2/db/seeds.rb +0 -7
- data/test/stub/rails3.2/doc/README_FOR_APP +0 -2
- data/test/stub/rails3.2/lib/assets/.gitkeep +0 -0
- data/test/stub/rails3.2/lib/tasks/.gitkeep +0 -0
- data/test/stub/rails3.2/log/.gitkeep +0 -0
- data/test/stub/rails3.2/public/404.html +0 -26
- data/test/stub/rails3.2/public/422.html +0 -26
- data/test/stub/rails3.2/public/500.html +0 -25
- data/test/stub/rails3.2/public/favicon.ico +0 -0
- data/test/stub/rails3.2/public/index.html +0 -241
- data/test/stub/rails3.2/public/robots.txt +0 -5
- data/test/stub/rails3.2/script/rails +0 -6
- data/test/stub/rails3.2/test/fixtures/.gitkeep +0 -0
- data/test/stub/rails3.2/test/functional/.gitkeep +0 -0
- data/test/stub/rails3.2/test/integration/.gitkeep +0 -0
- data/test/stub/rails3.2/test/performance/browsing_test.rb +0 -12
- data/test/stub/rails3.2/test/test_helper.rb +0 -13
- data/test/stub/rails3.2/test/unit/.gitkeep +0 -0
- data/test/stub/rails3.2/vendor/assets/stylesheets/.gitkeep +0 -0
- data/test/stub/rails3.2/vendor/plugins/.gitkeep +0 -0
- data/test/stub/rails4.0/.gitignore +0 -16
- data/test/stub/rails4.0/Gemfile +0 -45
- data/test/stub/rails4.0/Gemfile.lock +0 -126
- data/test/stub/rails4.0/README.rdoc +0 -28
- data/test/stub/rails4.0/Rakefile +0 -6
- data/test/stub/rails4.0/app/assets/images/.keep +0 -0
- data/test/stub/rails4.0/app/assets/javascripts/application.js +0 -16
- data/test/stub/rails4.0/app/assets/stylesheets/application.css +0 -13
- data/test/stub/rails4.0/app/controllers/application_controller.rb +0 -5
- data/test/stub/rails4.0/app/controllers/concerns/.keep +0 -0
- data/test/stub/rails4.0/app/helpers/application_helper.rb +0 -2
- data/test/stub/rails4.0/app/mailers/.keep +0 -0
- data/test/stub/rails4.0/app/models/.keep +0 -0
- data/test/stub/rails4.0/app/models/concerns/.keep +0 -0
- data/test/stub/rails4.0/app/views/layouts/application.html.erb +0 -14
- data/test/stub/rails4.0/bin/bundle +0 -3
- data/test/stub/rails4.0/bin/rails +0 -4
- data/test/stub/rails4.0/bin/rake +0 -4
- data/test/stub/rails4.0/config.ru +0 -4
- data/test/stub/rails4.0/config/application.rb +0 -23
- data/test/stub/rails4.0/config/boot.rb +0 -4
- data/test/stub/rails4.0/config/database.yml +0 -25
- data/test/stub/rails4.0/config/environment.rb +0 -5
- data/test/stub/rails4.0/config/environments/development.rb +0 -29
- data/test/stub/rails4.0/config/environments/production.rb +0 -80
- data/test/stub/rails4.0/config/environments/test.rb +0 -36
- data/test/stub/rails4.0/config/initializers/backtrace_silencers.rb +0 -7
- data/test/stub/rails4.0/config/initializers/filter_parameter_logging.rb +0 -4
- data/test/stub/rails4.0/config/initializers/inflections.rb +0 -16
- data/test/stub/rails4.0/config/initializers/mime_types.rb +0 -5
- data/test/stub/rails4.0/config/initializers/passenger.rb +0 -2
- data/test/stub/rails4.0/config/initializers/secret_token.rb +0 -12
- data/test/stub/rails4.0/config/initializers/session_store.rb +0 -3
- data/test/stub/rails4.0/config/initializers/wrap_parameters.rb +0 -14
- data/test/stub/rails4.0/config/locales/en.yml +0 -23
- data/test/stub/rails4.0/config/routes.rb +0 -57
- data/test/stub/rails4.0/db/seeds.rb +0 -7
- data/test/stub/rails4.0/lib/assets/.keep +0 -0
- data/test/stub/rails4.0/lib/tasks/.keep +0 -0
- data/test/stub/rails4.0/log/.keep +0 -0
- data/test/stub/rails4.0/public/404.html +0 -58
- data/test/stub/rails4.0/public/422.html +0 -58
- data/test/stub/rails4.0/public/500.html +0 -57
- data/test/stub/rails4.0/public/favicon.ico +0 -0
- data/test/stub/rails4.0/public/robots.txt +0 -5
- data/test/stub/rails4.0/test/controllers/.keep +0 -0
- data/test/stub/rails4.0/test/fixtures/.keep +0 -0
- data/test/stub/rails4.0/test/helpers/.keep +0 -0
- data/test/stub/rails4.0/test/integration/.keep +0 -0
- data/test/stub/rails4.0/test/mailers/.keep +0 -0
- data/test/stub/rails4.0/test/models/.keep +0 -0
- data/test/stub/rails4.0/test/test_helper.rb +0 -15
- data/test/stub/rails4.0/vendor/assets/javascripts/.keep +0 -0
- data/test/stub/rails4.0/vendor/assets/stylesheets/.keep +0 -0
- data/test/stub/rails4.1/.gitignore +0 -16
- data/test/stub/rails4.1/Gemfile +0 -45
- data/test/stub/rails4.1/Gemfile.lock +0 -129
- data/test/stub/rails4.1/README.rdoc +0 -28
- data/test/stub/rails4.1/Rakefile +0 -6
- data/test/stub/rails4.1/app/assets/images/.keep +0 -0
- data/test/stub/rails4.1/app/assets/javascripts/application.js +0 -16
- data/test/stub/rails4.1/app/assets/stylesheets/application.css +0 -13
- data/test/stub/rails4.1/app/controllers/application_controller.rb +0 -5
- data/test/stub/rails4.1/app/controllers/concerns/.keep +0 -0
- data/test/stub/rails4.1/app/helpers/application_helper.rb +0 -2
- data/test/stub/rails4.1/app/mailers/.keep +0 -0
- data/test/stub/rails4.1/app/models/.keep +0 -0
- data/test/stub/rails4.1/app/models/concerns/.keep +0 -0
- data/test/stub/rails4.1/app/views/layouts/application.html.erb +0 -14
- data/test/stub/rails4.1/bin/bundle +0 -3
- data/test/stub/rails4.1/bin/rails +0 -4
- data/test/stub/rails4.1/bin/rake +0 -4
- data/test/stub/rails4.1/config.ru +0 -4
- data/test/stub/rails4.1/config/application.rb +0 -23
- data/test/stub/rails4.1/config/boot.rb +0 -4
- data/test/stub/rails4.1/config/database.yml +0 -25
- data/test/stub/rails4.1/config/environment.rb +0 -5
- data/test/stub/rails4.1/config/environments/development.rb +0 -29
- data/test/stub/rails4.1/config/environments/production.rb +0 -80
- data/test/stub/rails4.1/config/environments/test.rb +0 -36
- data/test/stub/rails4.1/config/initializers/backtrace_silencers.rb +0 -7
- data/test/stub/rails4.1/config/initializers/filter_parameter_logging.rb +0 -4
- data/test/stub/rails4.1/config/initializers/inflections.rb +0 -16
- data/test/stub/rails4.1/config/initializers/mime_types.rb +0 -5
- data/test/stub/rails4.1/config/initializers/passenger.rb +0 -5
- data/test/stub/rails4.1/config/initializers/secret_token.rb +0 -12
- data/test/stub/rails4.1/config/initializers/session_store.rb +0 -3
- data/test/stub/rails4.1/config/initializers/wrap_parameters.rb +0 -14
- data/test/stub/rails4.1/config/locales/en.yml +0 -23
- data/test/stub/rails4.1/config/routes.rb +0 -57
- data/test/stub/rails4.1/db/seeds.rb +0 -7
- data/test/stub/rails4.1/lib/assets/.keep +0 -0
- data/test/stub/rails4.1/lib/tasks/.keep +0 -0
- data/test/stub/rails4.1/log/.keep +0 -0
- data/test/stub/rails4.1/public/404.html +0 -58
- data/test/stub/rails4.1/public/422.html +0 -58
- data/test/stub/rails4.1/public/500.html +0 -57
- data/test/stub/rails4.1/public/favicon.ico +0 -0
- data/test/stub/rails4.1/public/robots.txt +0 -5
- data/test/stub/rails4.1/test/controllers/.keep +0 -0
- data/test/stub/rails4.1/test/fixtures/.keep +0 -0
- data/test/stub/rails4.1/test/helpers/.keep +0 -0
- data/test/stub/rails4.1/test/integration/.keep +0 -0
- data/test/stub/rails4.1/test/mailers/.keep +0 -0
- data/test/stub/rails4.1/test/models/.keep +0 -0
- data/test/stub/rails4.1/test/test_helper.rb +0 -15
- data/test/stub/rails4.1/vendor/assets/javascripts/.keep +0 -0
- data/test/stub/rails4.1/vendor/assets/stylesheets/.keep +0 -0
- data/test/stub/start_error.pl +0 -24
- data/test/stub/upload_data.txt +0 -494
- data/test/stub/wsgi/passenger_wsgi.py +0 -212
- data/test/stub/wsgi/public/.gitignore +0 -0
- data/test/stub/wsgi/tmp/.gitignore +0 -0
- data/test/support/allocate_memory.c +0 -14
- data/test/support/apache2_controller.rb +0 -258
- data/test/support/multipart.rb +0 -62
- data/test/support/nginx_controller.rb +0 -97
- data/test/support/placebo-preloader.rb +0 -88
- data/test/support/test_helper.rb +0 -455
- data/test/support/valgrind.h +0 -2539
- data/test/tut/tut.h +0 -1310
- data/test/tut/tut_reporter.h +0 -256
- data/test/valgrind-osx.supp +0 -7
@@ -1,30 +0,0 @@
|
|
1
|
-
#include <TestSupport.h>
|
2
|
-
#include <ApplicationPool2/Process.h>
|
3
|
-
|
4
|
-
using namespace Passenger;
|
5
|
-
using namespace Passenger::ApplicationPool2;
|
6
|
-
using namespace std;
|
7
|
-
|
8
|
-
namespace tut {
|
9
|
-
struct ApplicationPool2_OptionsTest {
|
10
|
-
ApplicationPool2_OptionsTest() {
|
11
|
-
}
|
12
|
-
};
|
13
|
-
|
14
|
-
DEFINE_TEST_GROUP(ApplicationPool2_OptionsTest);
|
15
|
-
|
16
|
-
TEST_METHOD(1) {
|
17
|
-
// Test persist().
|
18
|
-
char appRoot[] = "appRoot";
|
19
|
-
char processTitle[] = "processTitle";
|
20
|
-
|
21
|
-
Options options;
|
22
|
-
options.appRoot = appRoot;
|
23
|
-
options.processTitle = processTitle;
|
24
|
-
|
25
|
-
Options options2 = options.copyAndPersist();
|
26
|
-
appRoot[0] = processTitle[0] = 'x';
|
27
|
-
ensure_equals(options2.appRoot, "appRoot");
|
28
|
-
ensure_equals(options2.processTitle, "processTitle");
|
29
|
-
}
|
30
|
-
}
|
@@ -1,2062 +0,0 @@
|
|
1
|
-
#include <TestSupport.h>
|
2
|
-
#include <ApplicationPool2/Pool.h>
|
3
|
-
#include <Utils/IOUtils.h>
|
4
|
-
#include <Utils/StrIntUtils.h>
|
5
|
-
#include <Utils/json.h>
|
6
|
-
#include <MessageReadersWriters.h>
|
7
|
-
#include <map>
|
8
|
-
#include <vector>
|
9
|
-
#include <cerrno>
|
10
|
-
#include <signal.h>
|
11
|
-
|
12
|
-
using namespace std;
|
13
|
-
using namespace Passenger;
|
14
|
-
using namespace Passenger::ApplicationPool2;
|
15
|
-
|
16
|
-
namespace tut {
|
17
|
-
struct ApplicationPool2_PoolTest {
|
18
|
-
SpawnerConfigPtr spawnerConfig;
|
19
|
-
SpawnerFactoryPtr spawnerFactory;
|
20
|
-
PoolPtr pool;
|
21
|
-
Pool::DebugSupportPtr debug;
|
22
|
-
Ticket ticket;
|
23
|
-
GetCallback callback;
|
24
|
-
SessionPtr currentSession;
|
25
|
-
ExceptionPtr currentException;
|
26
|
-
AtomicInt number;
|
27
|
-
boost::mutex syncher;
|
28
|
-
list<SessionPtr> sessions;
|
29
|
-
bool retainSessions;
|
30
|
-
|
31
|
-
ApplicationPool2_PoolTest() {
|
32
|
-
retainSessions = false;
|
33
|
-
spawnerConfig = boost::make_shared<SpawnerConfig>();
|
34
|
-
spawnerConfig->resourceLocator = resourceLocator;
|
35
|
-
spawnerConfig->finalize();
|
36
|
-
spawnerFactory = boost::make_shared<SpawnerFactory>(spawnerConfig);
|
37
|
-
pool = boost::make_shared<Pool>(spawnerFactory);
|
38
|
-
pool->initialize();
|
39
|
-
callback.func = _callback;
|
40
|
-
callback.userData = this;
|
41
|
-
setLogLevel(LVL_ERROR); // TODO: change to LVL_WARN
|
42
|
-
setPrintAppOutputAsDebuggingMessages(true);
|
43
|
-
}
|
44
|
-
|
45
|
-
~ApplicationPool2_PoolTest() {
|
46
|
-
// Explicitly destroy these here because they can run
|
47
|
-
// additional code that depend on other fields in this
|
48
|
-
// class.
|
49
|
-
TRACE_POINT();
|
50
|
-
clearAllSessions();
|
51
|
-
UPDATE_TRACE_POINT();
|
52
|
-
pool->destroy();
|
53
|
-
UPDATE_TRACE_POINT();
|
54
|
-
pool.reset();
|
55
|
-
setLogLevel(DEFAULT_LOG_LEVEL);
|
56
|
-
setPrintAppOutputAsDebuggingMessages(false);
|
57
|
-
SystemTime::releaseAll();
|
58
|
-
}
|
59
|
-
|
60
|
-
void initPoolDebugging() {
|
61
|
-
pool->initDebugging();
|
62
|
-
debug = pool->debugSupport;
|
63
|
-
}
|
64
|
-
|
65
|
-
void clearAllSessions() {
|
66
|
-
SessionPtr myCurrentSession;
|
67
|
-
list<SessionPtr> mySessions;
|
68
|
-
{
|
69
|
-
LockGuard l(syncher);
|
70
|
-
myCurrentSession = currentSession;
|
71
|
-
mySessions = sessions;
|
72
|
-
currentSession.reset();
|
73
|
-
sessions.clear();
|
74
|
-
}
|
75
|
-
myCurrentSession.reset();
|
76
|
-
mySessions.clear();
|
77
|
-
}
|
78
|
-
|
79
|
-
Options createOptions() {
|
80
|
-
Options options;
|
81
|
-
options.spawnMethod = "dummy";
|
82
|
-
options.appRoot = "stub/rack";
|
83
|
-
options.startCommand = "ruby\t" "start.rb";
|
84
|
-
options.startupFile = "start.rb";
|
85
|
-
options.loadShellEnvvars = false;
|
86
|
-
options.user = testConfig["normal_user_1"].asCString();
|
87
|
-
options.defaultUser = testConfig["default_user"].asCString();
|
88
|
-
options.defaultGroup = testConfig["default_group"].asCString();
|
89
|
-
return options;
|
90
|
-
}
|
91
|
-
|
92
|
-
static void _callback(const SessionPtr &session, const ExceptionPtr &e,
|
93
|
-
void *userData)
|
94
|
-
{
|
95
|
-
ApplicationPool2_PoolTest *self = (ApplicationPool2_PoolTest *) userData;
|
96
|
-
SessionPtr oldSession;
|
97
|
-
{
|
98
|
-
LockGuard l(self->syncher);
|
99
|
-
oldSession = self->currentSession;
|
100
|
-
self->currentSession = session;
|
101
|
-
self->currentException = e;
|
102
|
-
self->number++;
|
103
|
-
if (self->retainSessions && session != NULL) {
|
104
|
-
self->sessions.push_back(session);
|
105
|
-
}
|
106
|
-
}
|
107
|
-
// destroy old session object outside the lock.
|
108
|
-
}
|
109
|
-
|
110
|
-
void sendHeaders(int connection, ...) {
|
111
|
-
va_list ap;
|
112
|
-
const char *arg;
|
113
|
-
vector<StaticString> args;
|
114
|
-
|
115
|
-
va_start(ap, connection);
|
116
|
-
while ((arg = va_arg(ap, const char *)) != NULL) {
|
117
|
-
args.push_back(StaticString(arg, strlen(arg) + 1));
|
118
|
-
}
|
119
|
-
va_end(ap);
|
120
|
-
|
121
|
-
shared_array<StaticString> args_array(new StaticString[args.size() + 1]);
|
122
|
-
unsigned int totalSize = 0;
|
123
|
-
for (unsigned int i = 0; i < args.size(); i++) {
|
124
|
-
args_array[i + 1] = args[i];
|
125
|
-
totalSize += args[i].size();
|
126
|
-
}
|
127
|
-
char sizeHeader[sizeof(uint32_t)];
|
128
|
-
Uint32Message::generate(sizeHeader, totalSize);
|
129
|
-
args_array[0] = StaticString(sizeHeader, sizeof(uint32_t));
|
130
|
-
|
131
|
-
gatheredWrite(connection, args_array.get(), args.size() + 1, NULL);
|
132
|
-
}
|
133
|
-
|
134
|
-
string stripHeaders(const string &str) {
|
135
|
-
string::size_type pos = str.find("\r\n\r\n");
|
136
|
-
if (pos == string::npos) {
|
137
|
-
return str;
|
138
|
-
} else {
|
139
|
-
string result = str;
|
140
|
-
result.erase(0, pos + 4);
|
141
|
-
return result;
|
142
|
-
}
|
143
|
-
}
|
144
|
-
|
145
|
-
string sendRequest(const Options &options, const char *path) {
|
146
|
-
int oldNumber = number;
|
147
|
-
pool->asyncGet(options, callback);
|
148
|
-
EVENTUALLY(5,
|
149
|
-
result = number == oldNumber + 1;
|
150
|
-
);
|
151
|
-
if (currentException != NULL) {
|
152
|
-
P_ERROR("get() exception: " << currentException->what());
|
153
|
-
abort();
|
154
|
-
}
|
155
|
-
currentSession->initiate();
|
156
|
-
sendHeaders(currentSession->fd(),
|
157
|
-
"PATH_INFO", path,
|
158
|
-
"REQUEST_METHOD", "GET",
|
159
|
-
NULL);
|
160
|
-
shutdown(currentSession->fd(), SHUT_WR);
|
161
|
-
string body = stripHeaders(readAll(currentSession->fd()));
|
162
|
-
ProcessPtr process = currentSession->getProcess()->shared_from_this();
|
163
|
-
currentSession.reset();
|
164
|
-
EVENTUALLY(5,
|
165
|
-
result = process->busyness() == 0;
|
166
|
-
);
|
167
|
-
return body;
|
168
|
-
}
|
169
|
-
|
170
|
-
// Ensure that n processes exist.
|
171
|
-
Options ensureMinProcesses(unsigned int n) {
|
172
|
-
Options options = createOptions();
|
173
|
-
options.minProcesses = n;
|
174
|
-
pool->asyncGet(options, callback);
|
175
|
-
EVENTUALLY(5,
|
176
|
-
result = number == 1;
|
177
|
-
);
|
178
|
-
EVENTUALLY(5,
|
179
|
-
result = pool->getProcessCount() == n;
|
180
|
-
);
|
181
|
-
currentSession.reset();
|
182
|
-
return options;
|
183
|
-
}
|
184
|
-
|
185
|
-
void disableProcess(ProcessPtr process, AtomicInt *result) {
|
186
|
-
*result = (int) pool->disableProcess(StaticString(process->gupid,
|
187
|
-
process->gupidSize));
|
188
|
-
}
|
189
|
-
};
|
190
|
-
|
191
|
-
DEFINE_TEST_GROUP_WITH_LIMIT(ApplicationPool2_PoolTest, 100);
|
192
|
-
|
193
|
-
TEST_METHOD(1) {
|
194
|
-
// Test initial state.
|
195
|
-
ensure(!pool->atFullCapacity());
|
196
|
-
}
|
197
|
-
|
198
|
-
|
199
|
-
/*********** Test asyncGet() behavior on a single SuperGroup and Group ***********/
|
200
|
-
|
201
|
-
TEST_METHOD(2) {
|
202
|
-
// asyncGet() actions on empty pools cannot be immediately satisfied.
|
203
|
-
// Instead a new process will be spawned. In the mean time get()
|
204
|
-
// actions are put on a wait list which will be processed as soon
|
205
|
-
// as the new process is done spawning.
|
206
|
-
Options options = createOptions();
|
207
|
-
|
208
|
-
ScopedLock l(pool->syncher);
|
209
|
-
pool->asyncGet(options, callback, false);
|
210
|
-
ensure_equals(number, 0);
|
211
|
-
ensure(pool->getWaitlist.empty());
|
212
|
-
ensure(!pool->superGroups.empty());
|
213
|
-
l.unlock();
|
214
|
-
|
215
|
-
EVENTUALLY(5,
|
216
|
-
result = pool->getProcessCount() == 1;
|
217
|
-
);
|
218
|
-
ensure_equals(number, 1);
|
219
|
-
ensure(currentSession != NULL);
|
220
|
-
ensure(currentException == NULL);
|
221
|
-
}
|
222
|
-
|
223
|
-
TEST_METHOD(3) {
|
224
|
-
// If one matching process already exists and it's not at full
|
225
|
-
// capacity then asyncGet() will immediately use it.
|
226
|
-
Options options = createOptions();
|
227
|
-
|
228
|
-
// Spawn a process and opens a session with it.
|
229
|
-
pool->asyncGet(options, callback);
|
230
|
-
EVENTUALLY(5,
|
231
|
-
result = number == 1;
|
232
|
-
);
|
233
|
-
|
234
|
-
// Close the session so that the process is now idle.
|
235
|
-
ProcessPtr process = currentSession->getProcess()->shared_from_this();
|
236
|
-
currentSession.reset();
|
237
|
-
ensure_equals(process->busyness(), 0);
|
238
|
-
ensure(!process->isTotallyBusy());
|
239
|
-
|
240
|
-
// Verify test assertion.
|
241
|
-
ScopedLock l(pool->syncher);
|
242
|
-
pool->asyncGet(options, callback, false);
|
243
|
-
ensure_equals("callback is immediately called", number, 2);
|
244
|
-
}
|
245
|
-
|
246
|
-
TEST_METHOD(4) {
|
247
|
-
// If one matching process already exists but it's at full capacity,
|
248
|
-
// and the limits prevent spawning of a new process,
|
249
|
-
// then asyncGet() will put the get action on the group's wait
|
250
|
-
// queue. When the process is no longer at full capacity it will
|
251
|
-
// process the request.
|
252
|
-
|
253
|
-
// Spawn a process and verify that it's at full capacity.
|
254
|
-
// Keep its session open.
|
255
|
-
Options options = createOptions();
|
256
|
-
options.appGroupName = "test";
|
257
|
-
pool->setMax(1);
|
258
|
-
pool->asyncGet(options, callback);
|
259
|
-
EVENTUALLY(5,
|
260
|
-
result = number == 1;
|
261
|
-
);
|
262
|
-
SessionPtr session1 = currentSession;
|
263
|
-
ProcessPtr process = session1->getProcess()->shared_from_this();
|
264
|
-
currentSession.reset();
|
265
|
-
ensure_equals(process->sessions, 1);
|
266
|
-
ensure(process->isTotallyBusy());
|
267
|
-
|
268
|
-
// Now call asyncGet() again.
|
269
|
-
pool->asyncGet(options, callback);
|
270
|
-
ensure_equals("callback is not yet called", number, 1);
|
271
|
-
ensure_equals("the get action has been put on the wait list",
|
272
|
-
pool->superGroups.lookupCopy("test")->defaultGroup->getWaitlist.size(), 1u);
|
273
|
-
|
274
|
-
session1.reset();
|
275
|
-
ensure_equals("callback is called after the process becomes idle",
|
276
|
-
number, 2);
|
277
|
-
ensure_equals("the get wait list has been processed",
|
278
|
-
pool->superGroups.lookupCopy("test")->defaultGroup->getWaitlist.size(), 0u);
|
279
|
-
ensure_equals(process->sessions, 1);
|
280
|
-
}
|
281
|
-
|
282
|
-
TEST_METHOD(5) {
|
283
|
-
// If one matching process already exists but it's at full utilization,
|
284
|
-
// and the limits and pool capacity allow spawning of a new process,
|
285
|
-
// then get() will put the get action on the group's wait
|
286
|
-
// queue while spawning a process in the background.
|
287
|
-
// Either the existing process or the newly spawned process
|
288
|
-
// will process the action, whichever becomes first available.
|
289
|
-
|
290
|
-
// Here we test the case in which the existing process becomes
|
291
|
-
// available first.
|
292
|
-
initPoolDebugging();
|
293
|
-
|
294
|
-
// Spawn a regular process and keep its session open.
|
295
|
-
Options options = createOptions();
|
296
|
-
debug->messages->send("Proceed with spawn loop iteration 1");
|
297
|
-
SessionPtr session1 = pool->get(options, &ticket);
|
298
|
-
ProcessPtr process1 = session1->getProcess()->shared_from_this();
|
299
|
-
|
300
|
-
// Now spawn a process that never finishes.
|
301
|
-
pool->asyncGet(options, callback);
|
302
|
-
|
303
|
-
// Release the session on the first process.
|
304
|
-
session1.reset();
|
305
|
-
|
306
|
-
EVENTUALLY(1,
|
307
|
-
result = number == 1;
|
308
|
-
);
|
309
|
-
ensure_equals("The first process handled the second asyncGet() request",
|
310
|
-
currentSession->getProcess(), process1.get());
|
311
|
-
|
312
|
-
debug->messages->send("Proceed with spawn loop iteration 2");
|
313
|
-
EVENTUALLY(5,
|
314
|
-
result = number == 1;
|
315
|
-
);
|
316
|
-
}
|
317
|
-
|
318
|
-
TEST_METHOD(6) {
|
319
|
-
// Here we test the case in which the new process becomes
|
320
|
-
// available first.
|
321
|
-
|
322
|
-
// Spawn a regular process.
|
323
|
-
Options options = createOptions();
|
324
|
-
pool->asyncGet(options, callback);
|
325
|
-
EVENTUALLY(5,
|
326
|
-
result = number == 1;
|
327
|
-
);
|
328
|
-
SessionPtr session1 = currentSession;
|
329
|
-
ProcessPtr process1 = currentSession->getProcess()->shared_from_this();
|
330
|
-
currentSession.reset();
|
331
|
-
|
332
|
-
// As long as we don't release process1 the following get
|
333
|
-
// action will be processed by the newly spawned process.
|
334
|
-
pool->asyncGet(options, callback);
|
335
|
-
EVENTUALLY(5,
|
336
|
-
result = pool->getProcessCount() == 2;
|
337
|
-
);
|
338
|
-
ensure_equals(number, 2);
|
339
|
-
ensure(currentSession->getProcess() != process1.get());
|
340
|
-
}
|
341
|
-
|
342
|
-
TEST_METHOD(7) {
|
343
|
-
// If multiple matching processes exist, and one of them is idle,
|
344
|
-
// then asyncGet() will use that.
|
345
|
-
|
346
|
-
// Spawn 3 processes and keep a session open with 1 of them.
|
347
|
-
Options options = createOptions();
|
348
|
-
options.minProcesses = 3;
|
349
|
-
pool->asyncGet(options, callback);
|
350
|
-
EVENTUALLY(5,
|
351
|
-
result = number == 1;
|
352
|
-
);
|
353
|
-
EVENTUALLY(5,
|
354
|
-
result = pool->getProcessCount() == 3;
|
355
|
-
);
|
356
|
-
SessionPtr session1 = currentSession;
|
357
|
-
ProcessPtr process1 = currentSession->getProcess()->shared_from_this();
|
358
|
-
currentSession.reset();
|
359
|
-
|
360
|
-
// Now open another session. It should complete immediately
|
361
|
-
// and should not use the first process.
|
362
|
-
ScopedLock l(pool->syncher);
|
363
|
-
pool->asyncGet(options, callback, false);
|
364
|
-
ensure_equals("asyncGet() completed immediately", number, 2);
|
365
|
-
SessionPtr session2 = currentSession;
|
366
|
-
ProcessPtr process2 = currentSession->getProcess()->shared_from_this();
|
367
|
-
l.unlock();
|
368
|
-
currentSession.reset();
|
369
|
-
ensure(process2 != process1);
|
370
|
-
|
371
|
-
// Now open yet another session. It should also complete immediately
|
372
|
-
// and should not use the first or the second process.
|
373
|
-
l.lock();
|
374
|
-
pool->asyncGet(options, callback, false);
|
375
|
-
ensure_equals("asyncGet() completed immediately", number, 3);
|
376
|
-
SessionPtr session3 = currentSession;
|
377
|
-
ProcessPtr process3 = currentSession->getProcess()->shared_from_this();
|
378
|
-
l.unlock();
|
379
|
-
currentSession.reset();
|
380
|
-
ensure(process3 != process1);
|
381
|
-
ensure(process3 != process2);
|
382
|
-
}
|
383
|
-
|
384
|
-
TEST_METHOD(8) {
|
385
|
-
// If multiple matching processes exist, then asyncGet() will use
|
386
|
-
// the one with the smallest utilization number.
|
387
|
-
|
388
|
-
// Spawn 2 processes, each with a concurrency of 2.
|
389
|
-
Options options = createOptions();
|
390
|
-
options.minProcesses = 2;
|
391
|
-
pool->setMax(2);
|
392
|
-
GroupPtr group = pool->findOrCreateGroup(options);
|
393
|
-
spawnerConfig->concurrency = 2;
|
394
|
-
{
|
395
|
-
LockGuard l(pool->syncher);
|
396
|
-
group->spawn();
|
397
|
-
}
|
398
|
-
EVENTUALLY(5,
|
399
|
-
result = pool->getProcessCount() == 2;
|
400
|
-
);
|
401
|
-
|
402
|
-
// asyncGet() selects some process.
|
403
|
-
pool->asyncGet(options, callback);
|
404
|
-
ensure_equals(number, 1);
|
405
|
-
SessionPtr session1 = currentSession;
|
406
|
-
ProcessPtr process1 = currentSession->getProcess()->shared_from_this();
|
407
|
-
currentSession.reset();
|
408
|
-
|
409
|
-
// The first process now has 1 session, so next asyncGet() should
|
410
|
-
// select the other process.
|
411
|
-
pool->asyncGet(options, callback);
|
412
|
-
ensure_equals(number, 2);
|
413
|
-
SessionPtr session2 = currentSession;
|
414
|
-
ProcessPtr process2 = currentSession->getProcess()->shared_from_this();
|
415
|
-
currentSession.reset();
|
416
|
-
ensure("(1)", process1 != process2);
|
417
|
-
|
418
|
-
// Both processes now have an equal number of sessions. Next asyncGet()
|
419
|
-
// can select either.
|
420
|
-
pool->asyncGet(options, callback);
|
421
|
-
ensure_equals(number, 3);
|
422
|
-
SessionPtr session3 = currentSession;
|
423
|
-
ProcessPtr process3 = currentSession->getProcess()->shared_from_this();
|
424
|
-
currentSession.reset();
|
425
|
-
|
426
|
-
// One process now has the lowest number of sessions. Next
|
427
|
-
// asyncGet() should select that one.
|
428
|
-
pool->asyncGet(options, callback);
|
429
|
-
ensure_equals(number, 4);
|
430
|
-
SessionPtr session4 = currentSession;
|
431
|
-
ProcessPtr process4 = currentSession->getProcess()->shared_from_this();
|
432
|
-
currentSession.reset();
|
433
|
-
ensure(process3 != process4);
|
434
|
-
}
|
435
|
-
|
436
|
-
TEST_METHOD(9) {
|
437
|
-
// If multiple matching processes exist, and all of them are at full capacity,
|
438
|
-
// and no more processes may be spawned,
|
439
|
-
// then asyncGet() will put the action on the group's wait queue.
|
440
|
-
// The process that first becomes not at full capacity will process the action.
|
441
|
-
|
442
|
-
// Spawn 2 processes and open 4 sessions.
|
443
|
-
Options options = createOptions();
|
444
|
-
options.appGroupName = "test";
|
445
|
-
options.minProcesses = 2;
|
446
|
-
pool->setMax(2);
|
447
|
-
spawnerConfig->concurrency = 2;
|
448
|
-
|
449
|
-
vector<SessionPtr> sessions;
|
450
|
-
int expectedNumber = 1;
|
451
|
-
for (int i = 0; i < 4; i++) {
|
452
|
-
pool->asyncGet(options, callback);
|
453
|
-
EVENTUALLY(5,
|
454
|
-
result = number == expectedNumber;
|
455
|
-
);
|
456
|
-
expectedNumber++;
|
457
|
-
sessions.push_back(currentSession);
|
458
|
-
currentSession.reset();
|
459
|
-
}
|
460
|
-
EVENTUALLY(5,
|
461
|
-
result = pool->getProcessCount() == 2;
|
462
|
-
);
|
463
|
-
|
464
|
-
SuperGroupPtr superGroup = pool->superGroups.lookupCopy("test");
|
465
|
-
ensure_equals(superGroup->groups[0]->getWaitlist.size(), 0u);
|
466
|
-
ensure(pool->atFullCapacity());
|
467
|
-
|
468
|
-
// Now try to open another session.
|
469
|
-
pool->asyncGet(options, callback);
|
470
|
-
ensure_equals("The get request has been put on the wait list",
|
471
|
-
pool->superGroups.lookupCopy("test")->groups[0]->getWaitlist.size(), 1u);
|
472
|
-
|
473
|
-
// Close an existing session so that one process is no
|
474
|
-
// longer at full utilization.
|
475
|
-
sessions[0].reset();
|
476
|
-
ensure_equals("The get request has been removed from the wait list",
|
477
|
-
pool->superGroups.lookupCopy("test")->groups[0]->getWaitlist.size(), 0u);
|
478
|
-
ensure(pool->atFullCapacity());
|
479
|
-
}
|
480
|
-
|
481
|
-
TEST_METHOD(10) {
|
482
|
-
// If multiple matching processes exist, and all of them are at full utilization,
|
483
|
-
// and a new process may be spawned,
|
484
|
-
// then asyncGet() will put the action on the group's wait queue and spawn the
|
485
|
-
// new process.
|
486
|
-
// The process that first becomes not at full utilization
|
487
|
-
// or the newly spawned process
|
488
|
-
// will process the action, whichever is earlier.
|
489
|
-
// Here we test the case where an existing process is earlier.
|
490
|
-
|
491
|
-
// Spawn 2 processes and open 4 sessions.
|
492
|
-
Options options = createOptions();
|
493
|
-
options.minProcesses = 2;
|
494
|
-
pool->setMax(3);
|
495
|
-
GroupPtr group = pool->findOrCreateGroup(options);
|
496
|
-
spawnerConfig->concurrency = 2;
|
497
|
-
|
498
|
-
vector<SessionPtr> sessions;
|
499
|
-
int expectedNumber = 1;
|
500
|
-
for (int i = 0; i < 4; i++) {
|
501
|
-
pool->asyncGet(options, callback);
|
502
|
-
EVENTUALLY(5,
|
503
|
-
result = number == expectedNumber;
|
504
|
-
);
|
505
|
-
expectedNumber++;
|
506
|
-
sessions.push_back(currentSession);
|
507
|
-
currentSession.reset();
|
508
|
-
}
|
509
|
-
EVENTUALLY(5,
|
510
|
-
result = pool->getProcessCount() == 2;
|
511
|
-
);
|
512
|
-
|
513
|
-
// The next asyncGet() should spawn a new process and the action should be queued.
|
514
|
-
ScopedLock l(pool->syncher);
|
515
|
-
spawnerConfig->spawnTime = 5000000;
|
516
|
-
pool->asyncGet(options, callback, false);
|
517
|
-
ensure(group->spawning());
|
518
|
-
ensure_equals(group->getWaitlist.size(), 1u);
|
519
|
-
l.unlock();
|
520
|
-
|
521
|
-
// Close one of the sessions. Now it will process the action.
|
522
|
-
ProcessPtr process = sessions[0]->getProcess()->shared_from_this();
|
523
|
-
sessions[0].reset();
|
524
|
-
ensure_equals(number, 5);
|
525
|
-
ensure_equals(currentSession->getProcess(), process.get());
|
526
|
-
ensure_equals(group->getWaitlist.size(), 0u);
|
527
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
528
|
-
}
|
529
|
-
|
530
|
-
TEST_METHOD(11) {
|
531
|
-
// Here we test the case where the newly spawned process is earlier.
|
532
|
-
|
533
|
-
// Spawn 2 processes and open 4 sessions.
|
534
|
-
Options options = createOptions();
|
535
|
-
options.minProcesses = 2;
|
536
|
-
pool->setMax(3);
|
537
|
-
GroupPtr group = pool->findOrCreateGroup(options);
|
538
|
-
spawnerConfig->concurrency = 2;
|
539
|
-
|
540
|
-
vector<SessionPtr> sessions;
|
541
|
-
int expectedNumber = 1;
|
542
|
-
for (int i = 0; i < 4; i++) {
|
543
|
-
pool->asyncGet(options, callback);
|
544
|
-
EVENTUALLY(5,
|
545
|
-
result = number == expectedNumber;
|
546
|
-
);
|
547
|
-
expectedNumber++;
|
548
|
-
sessions.push_back(currentSession);
|
549
|
-
currentSession.reset();
|
550
|
-
}
|
551
|
-
EVENTUALLY(5,
|
552
|
-
result = pool->getProcessCount() == 2;
|
553
|
-
);
|
554
|
-
|
555
|
-
// The next asyncGet() should spawn a new process. After it's done
|
556
|
-
// spawning it will process the action.
|
557
|
-
pool->asyncGet(options, callback);
|
558
|
-
EVENTUALLY(5,
|
559
|
-
result = pool->getProcessCount() == 3;
|
560
|
-
);
|
561
|
-
EVENTUALLY(5,
|
562
|
-
result = number == 5;
|
563
|
-
);
|
564
|
-
ensure_equals(currentSession->getProcess()->pid, 3);
|
565
|
-
ensure_equals(group->getWaitlist.size(), 0u);
|
566
|
-
}
|
567
|
-
|
568
|
-
TEST_METHOD(12) {
|
569
|
-
// Test shutting down.
|
570
|
-
ensureMinProcesses(2);
|
571
|
-
ensure(pool->detachSuperGroupByName("stub/rack"));
|
572
|
-
ensure_equals(pool->getSuperGroupCount(), 0u);
|
573
|
-
}
|
574
|
-
|
575
|
-
TEST_METHOD(13) {
|
576
|
-
// Test shutting down while Group is restarting.
|
577
|
-
initPoolDebugging();
|
578
|
-
debug->messages->send("Proceed with spawn loop iteration 1");
|
579
|
-
ensureMinProcesses(1);
|
580
|
-
|
581
|
-
ensure(pool->restartGroupByName("stub/rack#default"));
|
582
|
-
debug->debugger->recv("About to end restarting");
|
583
|
-
ensure(pool->detachSuperGroupByName("stub/rack"));
|
584
|
-
ensure_equals(pool->getSuperGroupCount(), 0u);
|
585
|
-
}
|
586
|
-
|
587
|
-
TEST_METHOD(14) {
|
588
|
-
// Test shutting down while Group is spawning.
|
589
|
-
initPoolDebugging();
|
590
|
-
Options options = createOptions();
|
591
|
-
|
592
|
-
pool->asyncGet(options, callback);
|
593
|
-
debug->debugger->recv("Begin spawn loop iteration 1");
|
594
|
-
ensure(pool->detachSuperGroupByName("stub/rack"));
|
595
|
-
ensure_equals(pool->getSuperGroupCount(), 0u);
|
596
|
-
}
|
597
|
-
|
598
|
-
TEST_METHOD(15) {
|
599
|
-
// Test shutting down while SuperGroup is initializing.
|
600
|
-
initPoolDebugging();
|
601
|
-
debug->spawning = false;
|
602
|
-
debug->superGroup = true;
|
603
|
-
Options options = createOptions();
|
604
|
-
|
605
|
-
pool->asyncGet(options, callback);
|
606
|
-
debug->debugger->recv("About to finish SuperGroup initialization");
|
607
|
-
ensure(pool->detachSuperGroupByName("stub/rack"));
|
608
|
-
ensure_equals(pool->getSuperGroupCount(), 0u);
|
609
|
-
}
|
610
|
-
|
611
|
-
TEST_METHOD(16) {
|
612
|
-
// Test shutting down while SuperGroup is restarting.
|
613
|
-
initPoolDebugging();
|
614
|
-
debug->spawning = false;
|
615
|
-
debug->superGroup = true;
|
616
|
-
debug->messages->send("Proceed with initializing SuperGroup");
|
617
|
-
ensureMinProcesses(1);
|
618
|
-
|
619
|
-
ensure_equals(pool->restartSuperGroupsByAppRoot("stub/rack"), 1u);
|
620
|
-
debug->debugger->recv("About to finish SuperGroup restart");
|
621
|
-
ensure(pool->detachSuperGroupByName("stub/rack"));
|
622
|
-
ensure_equals(pool->getSuperGroupCount(), 0u);
|
623
|
-
}
|
624
|
-
|
625
|
-
TEST_METHOD(17) {
|
626
|
-
// Test that restartGroupByName() spawns more processes to ensure
|
627
|
-
// that minProcesses and other constraints are met.
|
628
|
-
ensureMinProcesses(1);
|
629
|
-
ensure(pool->restartGroupByName("stub/rack#default"));
|
630
|
-
EVENTUALLY(5,
|
631
|
-
result = pool->getProcessCount() == 1;
|
632
|
-
);
|
633
|
-
}
|
634
|
-
|
635
|
-
TEST_METHOD(18) {
|
636
|
-
// Test getting from an app for which minProcesses is set to 0,
|
637
|
-
// and restart.txt already existed.
|
638
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
639
|
-
Options options = createOptions();
|
640
|
-
options.appRoot = "tmp.wsgi";
|
641
|
-
options.appType = "wsgi";
|
642
|
-
options.startupFile = "passenger_wsgi.py";
|
643
|
-
options.spawnMethod = "direct";
|
644
|
-
options.minProcesses = 0;
|
645
|
-
initPoolDebugging();
|
646
|
-
debug->spawning = false;
|
647
|
-
|
648
|
-
SystemTime::forceAll(1000000);
|
649
|
-
pool->get(options, &ticket);
|
650
|
-
SystemTime::forceAll(20000000);
|
651
|
-
touchFile("tmp.wsgi/tmp/restart.txt", 1);
|
652
|
-
pool->asyncGet(options, callback);
|
653
|
-
debug->debugger->recv("About to end restarting");
|
654
|
-
debug->messages->send("Finish restarting");
|
655
|
-
EVENTUALLY(5,
|
656
|
-
result = number == 1;
|
657
|
-
);
|
658
|
-
ensure_equals(pool->getProcessCount(), 1u);
|
659
|
-
}
|
660
|
-
|
661
|
-
|
662
|
-
/*********** Test asyncGet() behavior on multiple SuperGroups,
|
663
|
-
each with a single Group ***********/
|
664
|
-
|
665
|
-
TEST_METHOD(20) {
|
666
|
-
// If the pool is full, and one tries to asyncGet() from a nonexistant group,
|
667
|
-
// then it will kill the oldest idle process and spawn a new process.
|
668
|
-
Options options = createOptions();
|
669
|
-
pool->setMax(2);
|
670
|
-
|
671
|
-
// Get from /foo and close its session immediately.
|
672
|
-
options.appRoot = "/foo";
|
673
|
-
pool->asyncGet(options, callback);
|
674
|
-
EVENTUALLY(5,
|
675
|
-
result = number == 1;
|
676
|
-
);
|
677
|
-
ProcessPtr process1 = currentSession->getProcess()->shared_from_this();
|
678
|
-
GroupPtr group1 = process1->getGroup()->shared_from_this();
|
679
|
-
SuperGroupPtr superGroup1 = group1->getSuperGroup()->shared_from_this();
|
680
|
-
currentSession.reset();
|
681
|
-
|
682
|
-
// Get from /bar and keep its session open.
|
683
|
-
options.appRoot = "/bar";
|
684
|
-
pool->asyncGet(options, callback);
|
685
|
-
EVENTUALLY(5,
|
686
|
-
result = number == 2;
|
687
|
-
);
|
688
|
-
SessionPtr session2 = currentSession;
|
689
|
-
currentSession.reset();
|
690
|
-
|
691
|
-
// Get from /baz. The process for /foo should be killed now.
|
692
|
-
options.appRoot = "/baz";
|
693
|
-
pool->asyncGet(options, callback);
|
694
|
-
EVENTUALLY(5,
|
695
|
-
result = number == 3;
|
696
|
-
);
|
697
|
-
|
698
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
699
|
-
ensure_equals(superGroup1->getProcessCount(), 0u);
|
700
|
-
}
|
701
|
-
|
702
|
-
TEST_METHOD(21) {
|
703
|
-
// If the pool is full, and one tries to asyncGet() from a nonexistant group,
|
704
|
-
// and all existing processes are non-idle, then it will
|
705
|
-
// kill the oldest process and spawn a new process.
|
706
|
-
Options options = createOptions();
|
707
|
-
pool->setMax(2);
|
708
|
-
|
709
|
-
// Get from /foo and close its session immediately.
|
710
|
-
options.appRoot = "/foo";
|
711
|
-
pool->asyncGet(options, callback);
|
712
|
-
EVENTUALLY(5,
|
713
|
-
result = number == 1;
|
714
|
-
);
|
715
|
-
ProcessPtr process1 = currentSession->getProcess()->shared_from_this();
|
716
|
-
GroupPtr group1 = process1->getGroup()->shared_from_this();
|
717
|
-
SuperGroupPtr superGroup1 = group1->getSuperGroup()->shared_from_this();
|
718
|
-
|
719
|
-
// Get from /bar and keep its session open.
|
720
|
-
options.appRoot = "/bar";
|
721
|
-
pool->asyncGet(options, callback);
|
722
|
-
EVENTUALLY(5,
|
723
|
-
result = number == 2;
|
724
|
-
);
|
725
|
-
SessionPtr session2 = currentSession;
|
726
|
-
currentSession.reset();
|
727
|
-
|
728
|
-
// Get from /baz. The process for /foo should be killed now.
|
729
|
-
options.appRoot = "/baz";
|
730
|
-
pool->asyncGet(options, callback);
|
731
|
-
EVENTUALLY(5,
|
732
|
-
result = number == 3;
|
733
|
-
);
|
734
|
-
|
735
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
736
|
-
ensure_equals(superGroup1->getProcessCount(), 0u);
|
737
|
-
}
|
738
|
-
|
739
|
-
TEST_METHOD(22) {
|
740
|
-
// Suppose the pool is at full capacity, and one tries to asyncGet() from an
|
741
|
-
// existant group that does not have any processes. It should kill a process
|
742
|
-
// from another group, and the request should succeed.
|
743
|
-
Options options = createOptions();
|
744
|
-
SessionPtr session;
|
745
|
-
pid_t pid1, pid2;
|
746
|
-
pool->setMax(1);
|
747
|
-
|
748
|
-
// Create a group /foo.
|
749
|
-
options.appRoot = "/foo";
|
750
|
-
SystemTime::force(1);
|
751
|
-
session = pool->get(options, &ticket);
|
752
|
-
pid1 = session->getPid();
|
753
|
-
session.reset();
|
754
|
-
|
755
|
-
// Create a group /bar.
|
756
|
-
options.appRoot = "/bar";
|
757
|
-
SystemTime::force(2);
|
758
|
-
session = pool->get(options, &ticket);
|
759
|
-
pid2 = session->getPid();
|
760
|
-
session.reset();
|
761
|
-
|
762
|
-
// Sleep for a short while to give Pool a chance to shutdown
|
763
|
-
// the first process.
|
764
|
-
usleep(300000);
|
765
|
-
ensure_equals("(1)", pool->getProcessCount(), 1u);
|
766
|
-
|
767
|
-
// Get from /foo.
|
768
|
-
options.appRoot = "/foo";
|
769
|
-
SystemTime::force(3);
|
770
|
-
session = pool->get(options, &ticket);
|
771
|
-
ensure("(2)", session->getPid() != pid1);
|
772
|
-
ensure("(3)", session->getPid() != pid2);
|
773
|
-
ensure_equals("(4)", pool->getProcessCount(), 1u);
|
774
|
-
}
|
775
|
-
|
776
|
-
TEST_METHOD(23) {
|
777
|
-
// Suppose the pool is at full capacity, and one tries to asyncGet() from an
|
778
|
-
// existant group that does not have any processes, and that happens to need
|
779
|
-
// restarting. It should kill a process from another group and the request
|
780
|
-
// should succeed.
|
781
|
-
Options options1 = createOptions();
|
782
|
-
Options options2 = createOptions();
|
783
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
784
|
-
SessionPtr session;
|
785
|
-
pid_t pid1, pid2;
|
786
|
-
pool->setMax(1);
|
787
|
-
|
788
|
-
// Create a group tmp.wsgi.
|
789
|
-
options1.appRoot = "tmp.wsgi";
|
790
|
-
options1.appType = "wsgi";
|
791
|
-
options1.startupFile = "passenger_wsgi.py";
|
792
|
-
options1.spawnMethod = "direct";
|
793
|
-
SystemTime::force(1);
|
794
|
-
session = pool->get(options1, &ticket);
|
795
|
-
pid1 = session->getPid();
|
796
|
-
session.reset();
|
797
|
-
|
798
|
-
// Create a group bar.
|
799
|
-
options2.appRoot = "bar";
|
800
|
-
SystemTime::force(2);
|
801
|
-
session = pool->get(options2, &ticket);
|
802
|
-
pid2 = session->getPid();
|
803
|
-
session.reset();
|
804
|
-
|
805
|
-
// Sleep for a short while to give Pool a chance to shutdown
|
806
|
-
// the first process.
|
807
|
-
usleep(300000);
|
808
|
-
ensure_equals("(1)", pool->getProcessCount(), 1u);
|
809
|
-
|
810
|
-
// Get from tmp.wsgi.
|
811
|
-
SystemTime::force(3);
|
812
|
-
touchFile("tmp.wsgi/tmp/restart.txt", 4);
|
813
|
-
session = pool->get(options1, &ticket);
|
814
|
-
ensure("(2)", session->getPid() != pid1);
|
815
|
-
ensure("(3)", session->getPid() != pid2);
|
816
|
-
ensure_equals("(4)", pool->getProcessCount(), 1u);
|
817
|
-
}
|
818
|
-
|
819
|
-
TEST_METHOD(24) {
|
820
|
-
// Suppose the pool is at full capacity, with two groups:
|
821
|
-
// - one that is spawning a process.
|
822
|
-
// - one with no processes.
|
823
|
-
// When one tries to asyncGet() from the second group, there should
|
824
|
-
// be no process to kill, but when the first group is done spawning
|
825
|
-
// it should throw away that process immediately to allow the second
|
826
|
-
// group to spawn.
|
827
|
-
Options options1 = createOptions();
|
828
|
-
Options options2 = createOptions();
|
829
|
-
initPoolDebugging();
|
830
|
-
debug->restarting = false;
|
831
|
-
pool->setMax(1);
|
832
|
-
|
833
|
-
// Create a group foo.
|
834
|
-
options1.appRoot = "foo";
|
835
|
-
options1.noop = true;
|
836
|
-
SystemTime::force(1);
|
837
|
-
pool->get(options1, &ticket);
|
838
|
-
|
839
|
-
// Create a group bar, but don't let it finish spawning.
|
840
|
-
options2.appRoot = "bar";
|
841
|
-
options2.noop = true;
|
842
|
-
SystemTime::force(2);
|
843
|
-
GroupPtr barGroup = pool->get(options2, &ticket)->getGroup()->shared_from_this();
|
844
|
-
{
|
845
|
-
LockGuard l(pool->syncher);
|
846
|
-
ensure_equals("(1)", barGroup->spawn(), SR_OK);
|
847
|
-
}
|
848
|
-
debug->debugger->recv("Begin spawn loop iteration 1");
|
849
|
-
|
850
|
-
// Now get from foo again and let the request be queued.
|
851
|
-
options1.noop = false;
|
852
|
-
SystemTime::force(3);
|
853
|
-
pool->asyncGet(options1, callback);
|
854
|
-
|
855
|
-
// Nothing should happen while bar is spawning.
|
856
|
-
SHOULD_NEVER_HAPPEN(100,
|
857
|
-
result = number > 0;
|
858
|
-
);
|
859
|
-
ensure_equals("(2)", pool->getProcessCount(), 0u);
|
860
|
-
|
861
|
-
// Now let bar finish spawning. Eventually there should
|
862
|
-
// only be one process: the one for foo.
|
863
|
-
debug->messages->send("Proceed with spawn loop iteration 1");
|
864
|
-
debug->debugger->recv("Spawn loop done");
|
865
|
-
debug->messages->send("Proceed with spawn loop iteration 2");
|
866
|
-
debug->debugger->recv("Spawn loop done");
|
867
|
-
EVENTUALLY(5,
|
868
|
-
LockGuard l(pool->syncher);
|
869
|
-
vector<ProcessPtr> processes = pool->getProcesses(false);
|
870
|
-
if (processes.size() == 1) {
|
871
|
-
GroupPtr group = processes[0]->getGroup()->shared_from_this();
|
872
|
-
result = group->name == "foo#default";
|
873
|
-
} else {
|
874
|
-
result = false;
|
875
|
-
}
|
876
|
-
);
|
877
|
-
}
|
878
|
-
|
879
|
-
TEST_METHOD(25) {
|
880
|
-
// Suppose the pool is at full capacity, with two groups:
|
881
|
-
// - one that is spawning a process, and has a queued request.
|
882
|
-
// - one with no processes.
|
883
|
-
// When one tries to asyncGet() from the second group, there should
|
884
|
-
// be no process to kill, but when the first group is done spawning
|
885
|
-
// it should throw away that process immediately to allow the second
|
886
|
-
// group to spawn.
|
887
|
-
Options options1 = createOptions();
|
888
|
-
Options options2 = createOptions();
|
889
|
-
initPoolDebugging();
|
890
|
-
debug->restarting = false;
|
891
|
-
pool->setMax(1);
|
892
|
-
|
893
|
-
// Create a group foo.
|
894
|
-
options1.appRoot = "foo";
|
895
|
-
options1.noop = true;
|
896
|
-
SystemTime::force(1);
|
897
|
-
pool->get(options1, &ticket);
|
898
|
-
|
899
|
-
// Create a group bar with a queued request, but don't let it finish spawning.
|
900
|
-
options2.appRoot = "bar";
|
901
|
-
SystemTime::force(2);
|
902
|
-
pool->asyncGet(options2, callback);
|
903
|
-
debug->debugger->recv("Begin spawn loop iteration 1");
|
904
|
-
|
905
|
-
// Now get from foo again and let the request be queued.
|
906
|
-
options1.noop = false;
|
907
|
-
SystemTime::force(3);
|
908
|
-
pool->asyncGet(options1, callback);
|
909
|
-
|
910
|
-
// Nothing should happen while bar is spawning.
|
911
|
-
SHOULD_NEVER_HAPPEN(100,
|
912
|
-
result = number > 0;
|
913
|
-
);
|
914
|
-
ensure_equals("(1)", pool->getProcessCount(), 0u);
|
915
|
-
|
916
|
-
// Now let bar finish spawning. The request for bar should be served.
|
917
|
-
debug->messages->send("Proceed with spawn loop iteration 1");
|
918
|
-
debug->debugger->recv("Spawn loop done");
|
919
|
-
EVENTUALLY(5,
|
920
|
-
result = number == 1;
|
921
|
-
);
|
922
|
-
ensure_equals(currentSession->getGroup()->name, "bar#default");
|
923
|
-
|
924
|
-
// When that request is done, the process for bar should be killed,
|
925
|
-
// and a process for foo should be spawned.
|
926
|
-
currentSession.reset();
|
927
|
-
debug->messages->send("Proceed with spawn loop iteration 2");
|
928
|
-
debug->debugger->recv("Spawn loop done");
|
929
|
-
EVENTUALLY(5,
|
930
|
-
LockGuard l(pool->syncher);
|
931
|
-
vector<ProcessPtr> processes = pool->getProcesses(false);
|
932
|
-
if (processes.size() == 1) {
|
933
|
-
GroupPtr group = processes[0]->getGroup()->shared_from_this();
|
934
|
-
result = group->name == "foo#default";
|
935
|
-
} else {
|
936
|
-
result = false;
|
937
|
-
}
|
938
|
-
);
|
939
|
-
|
940
|
-
EVENTUALLY(5,
|
941
|
-
result = number == 2;
|
942
|
-
);
|
943
|
-
}
|
944
|
-
|
945
|
-
|
946
|
-
/*********** Test detachProcess() ***********/
|
947
|
-
|
948
|
-
TEST_METHOD(30) {
|
949
|
-
// detachProcess() detaches the process from the group. The pool
|
950
|
-
// will restore the minimum number of processes afterwards.
|
951
|
-
Options options = createOptions();
|
952
|
-
options.appGroupName = "test";
|
953
|
-
options.minProcesses = 2;
|
954
|
-
pool->asyncGet(options, callback);
|
955
|
-
EVENTUALLY(5,
|
956
|
-
result = pool->getProcessCount() == 2;
|
957
|
-
);
|
958
|
-
EVENTUALLY(5,
|
959
|
-
result = number == 1;
|
960
|
-
);
|
961
|
-
|
962
|
-
ProcessPtr process = currentSession->getProcess()->shared_from_this();
|
963
|
-
pool->detachProcess(process);
|
964
|
-
{
|
965
|
-
LockGuard l(pool->syncher);
|
966
|
-
ensure(process->enabled == Process::DETACHED);
|
967
|
-
}
|
968
|
-
EVENTUALLY(5,
|
969
|
-
result = pool->getProcessCount() == 2;
|
970
|
-
);
|
971
|
-
currentSession.reset();
|
972
|
-
EVENTUALLY(5,
|
973
|
-
result = process->isDead();
|
974
|
-
);
|
975
|
-
}
|
976
|
-
|
977
|
-
TEST_METHOD(31) {
|
978
|
-
// If the containing group had waiters on it, and detachProcess()
|
979
|
-
// detaches the only process in the group, then a new process
|
980
|
-
// is automatically spawned to handle the waiters.
|
981
|
-
Options options = createOptions();
|
982
|
-
options.appGroupName = "test";
|
983
|
-
pool->setMax(1);
|
984
|
-
spawnerConfig->spawnTime = 1000000;
|
985
|
-
|
986
|
-
pool->asyncGet(options, callback);
|
987
|
-
EVENTUALLY(5,
|
988
|
-
result = number == 1;
|
989
|
-
);
|
990
|
-
SessionPtr session1 = currentSession;
|
991
|
-
currentSession.reset();
|
992
|
-
|
993
|
-
pool->asyncGet(options, callback);
|
994
|
-
|
995
|
-
{
|
996
|
-
LockGuard l(pool->syncher);
|
997
|
-
ensure_equals(pool->superGroups.lookupCopy("test")->defaultGroup->getWaitlist.size(), 1u);
|
998
|
-
}
|
999
|
-
|
1000
|
-
pool->detachProcess(session1->getProcess()->shared_from_this());
|
1001
|
-
{
|
1002
|
-
LockGuard l(pool->syncher);
|
1003
|
-
ensure(pool->superGroups.lookupCopy("test")->defaultGroup->spawning());
|
1004
|
-
ensure_equals(pool->superGroups.lookupCopy("test")->defaultGroup->enabledCount, 0);
|
1005
|
-
ensure_equals(pool->superGroups.lookupCopy("test")->defaultGroup->getWaitlist.size(), 1u);
|
1006
|
-
}
|
1007
|
-
|
1008
|
-
EVENTUALLY(5,
|
1009
|
-
result = number == 2;
|
1010
|
-
);
|
1011
|
-
}
|
1012
|
-
|
1013
|
-
TEST_METHOD(32) {
|
1014
|
-
// If the pool had waiters on it then detachProcess() will
|
1015
|
-
// automatically create the SuperGroups that were requested
|
1016
|
-
// by the waiters.
|
1017
|
-
Options options = createOptions();
|
1018
|
-
options.appGroupName = "test";
|
1019
|
-
options.minProcesses = 0;
|
1020
|
-
pool->setMax(1);
|
1021
|
-
spawnerConfig->spawnTime = 30000;
|
1022
|
-
|
1023
|
-
// Begin spawning a process.
|
1024
|
-
pool->asyncGet(options, callback);
|
1025
|
-
ensure(pool->atFullCapacity());
|
1026
|
-
|
1027
|
-
// asyncGet() on another group should now put it on the waiting list.
|
1028
|
-
Options options2 = createOptions();
|
1029
|
-
options2.appGroupName = "test2";
|
1030
|
-
options2.minProcesses = 0;
|
1031
|
-
spawnerConfig->spawnTime = 90000;
|
1032
|
-
pool->asyncGet(options2, callback);
|
1033
|
-
{
|
1034
|
-
LockGuard l(pool->syncher);
|
1035
|
-
ensure_equals(pool->getWaitlist.size(), 1u);
|
1036
|
-
}
|
1037
|
-
|
1038
|
-
// Eventually the dummy process for "test" is now done spawning.
|
1039
|
-
// We then detach it.
|
1040
|
-
EVENTUALLY(5,
|
1041
|
-
result = number == 1;
|
1042
|
-
);
|
1043
|
-
SessionPtr session1 = currentSession;
|
1044
|
-
currentSession.reset();
|
1045
|
-
pool->detachProcess(session1->getProcess()->shared_from_this());
|
1046
|
-
{
|
1047
|
-
LockGuard l(pool->syncher);
|
1048
|
-
ensure(pool->superGroups.lookupCopy("test2") != NULL);
|
1049
|
-
ensure_equals(pool->getWaitlist.size(), 0u);
|
1050
|
-
}
|
1051
|
-
EVENTUALLY(5,
|
1052
|
-
result = number == 2;
|
1053
|
-
);
|
1054
|
-
}
|
1055
|
-
|
1056
|
-
TEST_METHOD(33) {
|
1057
|
-
// A SuperGroup does not become garbage collectable
|
1058
|
-
// after detaching all its processes.
|
1059
|
-
Options options = createOptions();
|
1060
|
-
pool->asyncGet(options, callback);
|
1061
|
-
EVENTUALLY(5,
|
1062
|
-
result = number == 1;
|
1063
|
-
);
|
1064
|
-
ProcessPtr process = currentSession->getProcess()->shared_from_this();
|
1065
|
-
currentSession.reset();
|
1066
|
-
SuperGroupPtr superGroup = process->getSuperGroup()->shared_from_this();
|
1067
|
-
pool->detachProcess(process);
|
1068
|
-
LockGuard l(pool->syncher);
|
1069
|
-
ensure_equals(pool->superGroups.size(), 1u);
|
1070
|
-
ensure(superGroup->isAlive());
|
1071
|
-
ensure(!superGroup->garbageCollectable());
|
1072
|
-
}
|
1073
|
-
|
1074
|
-
TEST_METHOD(34) {
|
1075
|
-
// When detaching a process, it waits until all sessions have
|
1076
|
-
// finished before telling the process to shut down.
|
1077
|
-
Options options = createOptions();
|
1078
|
-
options.spawnMethod = "direct";
|
1079
|
-
options.minProcesses = 0;
|
1080
|
-
SessionPtr session = pool->get(options, &ticket);
|
1081
|
-
ProcessPtr process = session->getProcess()->shared_from_this();
|
1082
|
-
|
1083
|
-
ensure(pool->detachProcess(process));
|
1084
|
-
{
|
1085
|
-
LockGuard l(pool->syncher);
|
1086
|
-
ensure_equals(process->enabled, Process::DETACHED);
|
1087
|
-
}
|
1088
|
-
SHOULD_NEVER_HAPPEN(100,
|
1089
|
-
LockGuard l(pool->syncher);
|
1090
|
-
result = !process->isAlive()
|
1091
|
-
|| !process->osProcessExists();
|
1092
|
-
);
|
1093
|
-
|
1094
|
-
session.reset();
|
1095
|
-
EVENTUALLY(1,
|
1096
|
-
LockGuard l(pool->syncher);
|
1097
|
-
result = process->enabled == Process::DETACHED
|
1098
|
-
&& !process->osProcessExists()
|
1099
|
-
&& process->isDead();
|
1100
|
-
);
|
1101
|
-
}
|
1102
|
-
|
1103
|
-
TEST_METHOD(35) {
|
1104
|
-
// When detaching a process, it waits until the OS processes
|
1105
|
-
// have exited before cleaning up the in-memory data structures.
|
1106
|
-
Options options = createOptions();
|
1107
|
-
options.spawnMethod = "direct";
|
1108
|
-
options.minProcesses = 0;
|
1109
|
-
ProcessPtr process = pool->get(options, &ticket)->getProcess()->shared_from_this();
|
1110
|
-
|
1111
|
-
ScopeGuard g(boost::bind(::kill, process->pid, SIGCONT));
|
1112
|
-
kill(process->pid, SIGSTOP);
|
1113
|
-
|
1114
|
-
ensure(pool->detachProcess(process));
|
1115
|
-
{
|
1116
|
-
LockGuard l(pool->syncher);
|
1117
|
-
ensure_equals(process->enabled, Process::DETACHED);
|
1118
|
-
}
|
1119
|
-
EVENTUALLY(1,
|
1120
|
-
result = process->getLifeStatus() == Process::SHUTDOWN_TRIGGERED;
|
1121
|
-
);
|
1122
|
-
|
1123
|
-
SHOULD_NEVER_HAPPEN(100,
|
1124
|
-
LockGuard l(pool->syncher);
|
1125
|
-
result = process->isDead()
|
1126
|
-
|| !process->osProcessExists();
|
1127
|
-
);
|
1128
|
-
|
1129
|
-
kill(process->pid, SIGCONT);
|
1130
|
-
g.clear();
|
1131
|
-
|
1132
|
-
EVENTUALLY(1,
|
1133
|
-
LockGuard l(pool->syncher);
|
1134
|
-
result = process->enabled == Process::DETACHED
|
1135
|
-
&& !process->osProcessExists()
|
1136
|
-
&& process->isDead();
|
1137
|
-
);
|
1138
|
-
}
|
1139
|
-
|
1140
|
-
TEST_METHOD(36) {
|
1141
|
-
// Detaching a process that is already being detached, works.
|
1142
|
-
Options options = createOptions();
|
1143
|
-
options.appGroupName = "test";
|
1144
|
-
options.minProcesses = 0;
|
1145
|
-
|
1146
|
-
initPoolDebugging();
|
1147
|
-
debug->restarting = false;
|
1148
|
-
debug->spawning = false;
|
1149
|
-
debug->detachedProcessesChecker = true;
|
1150
|
-
|
1151
|
-
pool->asyncGet(options, callback);
|
1152
|
-
EVENTUALLY(5,
|
1153
|
-
result = pool->getProcessCount() == 1;
|
1154
|
-
);
|
1155
|
-
EVENTUALLY(5,
|
1156
|
-
result = number == 1;
|
1157
|
-
);
|
1158
|
-
|
1159
|
-
ProcessPtr process = currentSession->getProcess()->shared_from_this();
|
1160
|
-
pool->detachProcess(process);
|
1161
|
-
debug->debugger->recv("About to start detached processes checker");
|
1162
|
-
{
|
1163
|
-
LockGuard l(pool->syncher);
|
1164
|
-
ensure(process->enabled == Process::DETACHED);
|
1165
|
-
}
|
1166
|
-
|
1167
|
-
// detachProcess() will spawn a new process. Prevent it from being
|
1168
|
-
// spawned too soon.
|
1169
|
-
debug->spawning = true;
|
1170
|
-
|
1171
|
-
pool->detachProcess(process);
|
1172
|
-
debug->messages->send("Proceed with starting detached processes checker");
|
1173
|
-
debug->messages->send("Proceed with starting detached processes checker");
|
1174
|
-
debug->messages->send("Proceed with spawn loop iteration 2");
|
1175
|
-
|
1176
|
-
EVENTUALLY(5,
|
1177
|
-
result = pool->getProcessCount() == 0;
|
1178
|
-
);
|
1179
|
-
currentSession.reset();
|
1180
|
-
EVENTUALLY(5,
|
1181
|
-
result = process->isDead();
|
1182
|
-
);
|
1183
|
-
}
|
1184
|
-
|
1185
|
-
|
1186
|
-
/*********** Test disabling and enabling processes ***********/
|
1187
|
-
|
1188
|
-
TEST_METHOD(40) {
|
1189
|
-
// Disabling a process under idle conditions should succeed immediately.
|
1190
|
-
ensureMinProcesses(2);
|
1191
|
-
vector<ProcessPtr> processes = pool->getProcesses();
|
1192
|
-
ensure_equals("Disabling succeeds",
|
1193
|
-
pool->disableProcess(StaticString(processes[0]->gupid,
|
1194
|
-
processes[0]->gupidSize)), DR_SUCCESS);
|
1195
|
-
|
1196
|
-
LockGuard l(pool->syncher);
|
1197
|
-
ensure(processes[0]->isAlive());
|
1198
|
-
ensure_equals("Process is disabled",
|
1199
|
-
processes[0]->enabled,
|
1200
|
-
Process::DISABLED);
|
1201
|
-
ensure("Other processes are not affected",
|
1202
|
-
processes[1]->isAlive());
|
1203
|
-
ensure_equals("Other processes are not affected",
|
1204
|
-
processes[1]->enabled, Process::ENABLED);
|
1205
|
-
}
|
1206
|
-
|
1207
|
-
TEST_METHOD(41) {
|
1208
|
-
// Disabling the sole process in a group, in case the pool settings allow
|
1209
|
-
// spawning another process, should trigger a new process spawn.
|
1210
|
-
ensureMinProcesses(1);
|
1211
|
-
Options options = createOptions();
|
1212
|
-
SessionPtr session = pool->get(options, &ticket);
|
1213
|
-
|
1214
|
-
ensure_equals(pool->getProcessCount(), 1u);
|
1215
|
-
ensure(!pool->isSpawning());
|
1216
|
-
|
1217
|
-
spawnerConfig->spawnTime = 60000;
|
1218
|
-
AtomicInt code = -1;
|
1219
|
-
TempThread thr(boost::bind(&ApplicationPool2_PoolTest::disableProcess,
|
1220
|
-
this, session->getProcess()->shared_from_this(), &code));
|
1221
|
-
EVENTUALLY2(100, 1,
|
1222
|
-
result = pool->isSpawning();
|
1223
|
-
);
|
1224
|
-
EVENTUALLY(1,
|
1225
|
-
result = pool->getProcessCount() == 2u;
|
1226
|
-
);
|
1227
|
-
ensure_equals((int) code, -1);
|
1228
|
-
session.reset();
|
1229
|
-
EVENTUALLY(1,
|
1230
|
-
result = code == (int) DR_SUCCESS;
|
1231
|
-
);
|
1232
|
-
}
|
1233
|
-
|
1234
|
-
TEST_METHOD(42) {
|
1235
|
-
// Disabling the sole process in a group, in case pool settings don't allow
|
1236
|
-
// spawning another process, should fail.
|
1237
|
-
pool->setMax(1);
|
1238
|
-
ensureMinProcesses(1);
|
1239
|
-
|
1240
|
-
vector<ProcessPtr> processes = pool->getProcesses();
|
1241
|
-
ensure_equals("(1)", processes.size(), 1u);
|
1242
|
-
|
1243
|
-
DisableResult result = pool->disableProcess(StaticString(
|
1244
|
-
processes[0]->gupid, processes[0]->gupidSize));
|
1245
|
-
ensure_equals("(2)", result, DR_ERROR);
|
1246
|
-
ensure_equals("(3)", pool->getProcessCount(), 1u);
|
1247
|
-
}
|
1248
|
-
|
1249
|
-
TEST_METHOD(43) {
|
1250
|
-
// If there are no enabled processes in the group, then disabling should
|
1251
|
-
// succeed after the new process has been spawned.
|
1252
|
-
initPoolDebugging();
|
1253
|
-
debug->messages->send("Proceed with spawn loop iteration 1");
|
1254
|
-
debug->messages->send("Proceed with spawn loop iteration 2");
|
1255
|
-
|
1256
|
-
Options options = createOptions();
|
1257
|
-
SessionPtr session1 = pool->get(options, &ticket);
|
1258
|
-
SessionPtr session2 = pool->get(options, &ticket);
|
1259
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
1260
|
-
GroupPtr group = session1->getGroup()->shared_from_this();
|
1261
|
-
ProcessPtr process1 = session1->getProcess()->shared_from_this();
|
1262
|
-
ProcessPtr process2 = session2->getProcess()->shared_from_this();
|
1263
|
-
|
1264
|
-
AtomicInt code1 = -1, code2 = -2;
|
1265
|
-
TempThread thr(boost::bind(&ApplicationPool2_PoolTest::disableProcess,
|
1266
|
-
this, process1, &code1));
|
1267
|
-
TempThread thr2(boost::bind(&ApplicationPool2_PoolTest::disableProcess,
|
1268
|
-
this, process2, &code2));
|
1269
|
-
EVENTUALLY(5,
|
1270
|
-
LockGuard l(pool->syncher);
|
1271
|
-
result = group->enabledCount == 0
|
1272
|
-
&& group->disablingCount == 2
|
1273
|
-
&& group->disabledCount == 0;
|
1274
|
-
);
|
1275
|
-
session1.reset();
|
1276
|
-
session2.reset();
|
1277
|
-
SHOULD_NEVER_HAPPEN(20,
|
1278
|
-
result = code1 != -1 || code2 != -2;
|
1279
|
-
);
|
1280
|
-
|
1281
|
-
debug->messages->send("Proceed with spawn loop iteration 3");
|
1282
|
-
EVENTUALLY(5,
|
1283
|
-
result = code1 == DR_SUCCESS;
|
1284
|
-
);
|
1285
|
-
EVENTUALLY(5,
|
1286
|
-
result = code2 == DR_SUCCESS;
|
1287
|
-
);
|
1288
|
-
{
|
1289
|
-
LockGuard l(pool->syncher);
|
1290
|
-
ensure_equals(group->enabledCount, 1);
|
1291
|
-
ensure_equals(group->disablingCount, 0);
|
1292
|
-
ensure_equals(group->disabledCount, 2);
|
1293
|
-
}
|
1294
|
-
}
|
1295
|
-
|
1296
|
-
TEST_METHOD(44) {
|
1297
|
-
// Suppose that a previous disable command triggered a new process spawn,
|
1298
|
-
// and the spawn fails. Then any disabling processes should become enabled
|
1299
|
-
// again, and the callbacks for the previous disable commands should be called.
|
1300
|
-
initPoolDebugging();
|
1301
|
-
debug->messages->send("Proceed with spawn loop iteration 1");
|
1302
|
-
debug->messages->send("Proceed with spawn loop iteration 2");
|
1303
|
-
|
1304
|
-
Options options = createOptions();
|
1305
|
-
options.minProcesses = 2;
|
1306
|
-
SessionPtr session1 = pool->get(options, &ticket);
|
1307
|
-
SessionPtr session2 = pool->get(options, &ticket);
|
1308
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
1309
|
-
|
1310
|
-
AtomicInt code1 = -1, code2 = -1;
|
1311
|
-
TempThread thr(boost::bind(&ApplicationPool2_PoolTest::disableProcess,
|
1312
|
-
this, session1->getProcess()->shared_from_this(), &code1));
|
1313
|
-
TempThread thr2(boost::bind(&ApplicationPool2_PoolTest::disableProcess,
|
1314
|
-
this, session2->getProcess()->shared_from_this(), &code2));
|
1315
|
-
EVENTUALLY(2,
|
1316
|
-
GroupPtr group = session1->getGroup()->shared_from_this();
|
1317
|
-
LockGuard l(pool->syncher);
|
1318
|
-
result = group->enabledCount == 0
|
1319
|
-
&& group->disablingCount == 2
|
1320
|
-
&& group->disabledCount == 0;
|
1321
|
-
);
|
1322
|
-
SHOULD_NEVER_HAPPEN(20,
|
1323
|
-
result = code1 != -1 || code2 != -1;
|
1324
|
-
);
|
1325
|
-
|
1326
|
-
setLogLevel(LVL_CRIT);
|
1327
|
-
debug->messages->send("Fail spawn loop iteration 3");
|
1328
|
-
EVENTUALLY(5,
|
1329
|
-
result = code1 == DR_ERROR;
|
1330
|
-
);
|
1331
|
-
EVENTUALLY(5,
|
1332
|
-
result = code2 == DR_ERROR;
|
1333
|
-
);
|
1334
|
-
{
|
1335
|
-
GroupPtr group = session1->getGroup()->shared_from_this();
|
1336
|
-
LockGuard l(pool->syncher);
|
1337
|
-
ensure_equals(group->enabledCount, 2);
|
1338
|
-
ensure_equals(group->disablingCount, 0);
|
1339
|
-
ensure_equals(group->disabledCount, 0);
|
1340
|
-
}
|
1341
|
-
}
|
1342
|
-
|
1343
|
-
// TODO: asyncGet() should not select a disabling process if there are enabled processes.
|
1344
|
-
// TODO: asyncGet() should not select a disabling process when non-rolling restarting.
|
1345
|
-
// TODO: asyncGet() should select a disabling process if there are no enabled processes
|
1346
|
-
// in the group. If this happens then asyncGet() will also spawn a new process.
|
1347
|
-
// TODO: asyncGet() should not select a disabled process.
|
1348
|
-
|
1349
|
-
// TODO: If there are no enabled processes and all disabling processes are at full
|
1350
|
-
// utilization, and the process that was being spawned becomes available
|
1351
|
-
// earlier than any of the disabling processes, then the newly spawned process
|
1352
|
-
// should handle the request.
|
1353
|
-
|
1354
|
-
// TODO: A disabling process becomes disabled as soon as it's done with
|
1355
|
-
// all its request.
|
1356
|
-
|
1357
|
-
TEST_METHOD(50) {
|
1358
|
-
// Disabling a process that's already being disabled should result in the
|
1359
|
-
// callback being called after disabling is done.
|
1360
|
-
ensureMinProcesses(2);
|
1361
|
-
Options options = createOptions();
|
1362
|
-
SessionPtr session = pool->get(options, &ticket);
|
1363
|
-
|
1364
|
-
AtomicInt code = -1;
|
1365
|
-
TempThread thr(boost::bind(&ApplicationPool2_PoolTest::disableProcess,
|
1366
|
-
this, session->getProcess()->shared_from_this(), &code));
|
1367
|
-
SHOULD_NEVER_HAPPEN(100,
|
1368
|
-
result = code != -1;
|
1369
|
-
);
|
1370
|
-
session.reset();
|
1371
|
-
EVENTUALLY(5,
|
1372
|
-
result = code != -1;
|
1373
|
-
);
|
1374
|
-
ensure_equals(code, (int) DR_SUCCESS);
|
1375
|
-
}
|
1376
|
-
|
1377
|
-
// TODO: Enabling a process that's disabled succeeds immediately.
|
1378
|
-
// TODO: Enabling a process that's disabling succeeds immediately. The disable
|
1379
|
-
// callbacks will be called with DR_CANCELED.
|
1380
|
-
|
1381
|
-
TEST_METHOD(51) {
|
1382
|
-
// If the number of processes is already at maximum, then disabling
|
1383
|
-
// a process will cause that process to be disabled, without spawning
|
1384
|
-
// a new process.
|
1385
|
-
pool->setMax(2);
|
1386
|
-
ensureMinProcesses(2);
|
1387
|
-
|
1388
|
-
vector<ProcessPtr> processes = pool->getProcesses();
|
1389
|
-
ensure_equals(processes.size(), 2u);
|
1390
|
-
DisableResult result = pool->disableProcess(
|
1391
|
-
StaticString(processes[0]->gupid, processes[0]->gupidSize));
|
1392
|
-
ensure_equals(result, DR_SUCCESS);
|
1393
|
-
|
1394
|
-
{
|
1395
|
-
ScopedLock l(pool->syncher);
|
1396
|
-
GroupPtr group = processes[0]->getGroup()->shared_from_this();
|
1397
|
-
ensure_equals(group->enabledCount, 1);
|
1398
|
-
ensure_equals(group->disablingCount, 0);
|
1399
|
-
ensure_equals(group->disabledCount, 1);
|
1400
|
-
}
|
1401
|
-
}
|
1402
|
-
|
1403
|
-
|
1404
|
-
/*********** Other tests ***********/
|
1405
|
-
|
1406
|
-
TEST_METHOD(60) {
|
1407
|
-
// The pool is considered to be at full capacity if and only
|
1408
|
-
// if all SuperGroups are at full capacity.
|
1409
|
-
Options options = createOptions();
|
1410
|
-
Options options2 = createOptions();
|
1411
|
-
options2.appGroupName = "test";
|
1412
|
-
|
1413
|
-
pool->setMax(2);
|
1414
|
-
pool->asyncGet(options, callback);
|
1415
|
-
EVENTUALLY(5,
|
1416
|
-
result = number == 1;
|
1417
|
-
);
|
1418
|
-
|
1419
|
-
pool->asyncGet(options2, callback);
|
1420
|
-
EVENTUALLY(5,
|
1421
|
-
result = number == 2;
|
1422
|
-
);
|
1423
|
-
|
1424
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
1425
|
-
ensure(pool->atFullCapacity());
|
1426
|
-
clearAllSessions();
|
1427
|
-
pool->detachSuperGroupByName("test");
|
1428
|
-
ensure(!pool->atFullCapacity());
|
1429
|
-
}
|
1430
|
-
|
1431
|
-
TEST_METHOD(61) {
|
1432
|
-
// If the pool is at full capacity, then increasing 'max' will cause
|
1433
|
-
// new processes to be spawned. Any queued get requests are processed
|
1434
|
-
// as those new processes become available or as existing processes
|
1435
|
-
// become available.
|
1436
|
-
Options options = createOptions();
|
1437
|
-
retainSessions = true;
|
1438
|
-
pool->setMax(1);
|
1439
|
-
|
1440
|
-
pool->asyncGet(options, callback);
|
1441
|
-
pool->asyncGet(options, callback);
|
1442
|
-
pool->asyncGet(options, callback);
|
1443
|
-
EVENTUALLY(5,
|
1444
|
-
result = number == 1;
|
1445
|
-
);
|
1446
|
-
|
1447
|
-
pool->setMax(4);
|
1448
|
-
EVENTUALLY(5,
|
1449
|
-
result = number == 3;
|
1450
|
-
);
|
1451
|
-
ensure_equals(pool->getProcessCount(), 3u);
|
1452
|
-
}
|
1453
|
-
|
1454
|
-
TEST_METHOD(62) {
|
1455
|
-
// Each spawned process has a GUPID, which can be looked up
|
1456
|
-
// through findProcessByGupid().
|
1457
|
-
Options options = createOptions();
|
1458
|
-
pool->asyncGet(options, callback);
|
1459
|
-
EVENTUALLY(5,
|
1460
|
-
result = number == 1;
|
1461
|
-
);
|
1462
|
-
string gupid(currentSession->getProcess()->gupid,
|
1463
|
-
currentSession->getProcess()->gupidSize);
|
1464
|
-
ensure(!gupid.empty());
|
1465
|
-
ensure_equals(currentSession->getProcess(),
|
1466
|
-
pool->findProcessByGupid(gupid).get());
|
1467
|
-
}
|
1468
|
-
|
1469
|
-
TEST_METHOD(63) {
|
1470
|
-
// findProcessByGupid() returns a NULL pointer if there is
|
1471
|
-
// no matching process.
|
1472
|
-
ensure(pool->findProcessByGupid("none") == NULL);
|
1473
|
-
}
|
1474
|
-
|
1475
|
-
TEST_METHOD(64) {
|
1476
|
-
// Test process idle cleaning.
|
1477
|
-
Options options = createOptions();
|
1478
|
-
pool->setMaxIdleTime(50000);
|
1479
|
-
SessionPtr session1 = pool->get(options, &ticket);
|
1480
|
-
SessionPtr session2 = pool->get(options, &ticket);
|
1481
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
1482
|
-
|
1483
|
-
session2.reset();
|
1484
|
-
|
1485
|
-
// One of the processes still has a session open and should
|
1486
|
-
// not be idle cleaned.
|
1487
|
-
EVENTUALLY(2,
|
1488
|
-
result = pool->getProcessCount() == 1;
|
1489
|
-
);
|
1490
|
-
SHOULD_NEVER_HAPPEN(150,
|
1491
|
-
result = pool->getProcessCount() == 0;
|
1492
|
-
);
|
1493
|
-
|
1494
|
-
// It shouldn't clean more processes than minInstances allows.
|
1495
|
-
sessions.clear();
|
1496
|
-
SHOULD_NEVER_HAPPEN(150,
|
1497
|
-
result = pool->getProcessCount() == 0;
|
1498
|
-
);
|
1499
|
-
}
|
1500
|
-
|
1501
|
-
TEST_METHOD(65) {
|
1502
|
-
// Test spawner idle cleaning.
|
1503
|
-
Options options = createOptions();
|
1504
|
-
options.appGroupName = "test1";
|
1505
|
-
Options options2 = createOptions();
|
1506
|
-
options2.appGroupName = "test2";
|
1507
|
-
|
1508
|
-
retainSessions = true;
|
1509
|
-
pool->setMaxIdleTime(50000);
|
1510
|
-
pool->asyncGet(options, callback);
|
1511
|
-
pool->asyncGet(options2, callback);
|
1512
|
-
EVENTUALLY(2,
|
1513
|
-
result = number == 2;
|
1514
|
-
);
|
1515
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
1516
|
-
|
1517
|
-
EVENTUALLY(2,
|
1518
|
-
SpawnerPtr spawner = pool->getSuperGroup("test1")->defaultGroup->spawner;
|
1519
|
-
result = static_pointer_cast<DummySpawner>(spawner)->cleanCount >= 1;
|
1520
|
-
);
|
1521
|
-
EVENTUALLY(2,
|
1522
|
-
SpawnerPtr spawner = pool->getSuperGroup("test2")->defaultGroup->spawner;
|
1523
|
-
result = static_pointer_cast<DummySpawner>(spawner)->cleanCount >= 1;
|
1524
|
-
);
|
1525
|
-
}
|
1526
|
-
|
1527
|
-
TEST_METHOD(66) {
|
1528
|
-
// It should restart the app if restart.txt is created or updated.
|
1529
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1530
|
-
Options options = createOptions();
|
1531
|
-
options.appRoot = "tmp.wsgi";
|
1532
|
-
options.appType = "wsgi";
|
1533
|
-
options.startupFile = "passenger_wsgi.py";
|
1534
|
-
options.spawnMethod = "direct";
|
1535
|
-
options.statThrottleRate = 0;
|
1536
|
-
pool->setMax(1);
|
1537
|
-
|
1538
|
-
// Send normal request.
|
1539
|
-
ensure_equals(sendRequest(options, "/"), "front page");
|
1540
|
-
|
1541
|
-
// Modify application; it shouldn't have effect yet.
|
1542
|
-
writeFile("tmp.wsgi/passenger_wsgi.py",
|
1543
|
-
"def application(env, start_response):\n"
|
1544
|
-
" start_response('200 OK', [('Content-Type', 'text/html')])\n"
|
1545
|
-
" return ['restarted']\n");
|
1546
|
-
ensure_equals(sendRequest(options, "/"), "front page");
|
1547
|
-
|
1548
|
-
// Create restart.txt and send request again. The change should now be activated.
|
1549
|
-
touchFile("tmp.wsgi/tmp/restart.txt", 1);
|
1550
|
-
ensure_equals(sendRequest(options, "/"), "restarted");
|
1551
|
-
|
1552
|
-
// Modify application again; it shouldn't have effect yet.
|
1553
|
-
writeFile("tmp.wsgi/passenger_wsgi.py",
|
1554
|
-
"def application(env, start_response):\n"
|
1555
|
-
" start_response('200 OK', [('Content-Type', 'text/html')])\n"
|
1556
|
-
" return ['restarted 2']\n");
|
1557
|
-
ensure_equals(sendRequest(options, "/"), "restarted");
|
1558
|
-
|
1559
|
-
// Touch restart.txt and send request again. The change should now be activated.
|
1560
|
-
touchFile("tmp.wsgi/tmp/restart.txt", 2);
|
1561
|
-
ensure_equals(sendRequest(options, "/"), "restarted 2");
|
1562
|
-
}
|
1563
|
-
|
1564
|
-
TEST_METHOD(67) {
|
1565
|
-
// Test spawn exceptions.
|
1566
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1567
|
-
Options options = createOptions();
|
1568
|
-
options.appRoot = "tmp.wsgi";
|
1569
|
-
options.appType = "wsgi";
|
1570
|
-
options.startupFile = "passenger_wsgi.py";
|
1571
|
-
options.spawnMethod = "direct";
|
1572
|
-
|
1573
|
-
writeFile("tmp.wsgi/passenger_wsgi.py",
|
1574
|
-
"import sys\n"
|
1575
|
-
"sys.stderr.write('Something went wrong!')\n"
|
1576
|
-
"exit(1)\n");
|
1577
|
-
|
1578
|
-
setLogLevel(LVL_CRIT);
|
1579
|
-
pool->asyncGet(options, callback);
|
1580
|
-
EVENTUALLY(5,
|
1581
|
-
result = number == 1;
|
1582
|
-
);
|
1583
|
-
|
1584
|
-
ensure(currentException != NULL);
|
1585
|
-
boost::shared_ptr<SpawnException> e = dynamic_pointer_cast<SpawnException>(currentException);
|
1586
|
-
ensure(e->getErrorPage().find("Something went wrong!") != string::npos);
|
1587
|
-
}
|
1588
|
-
|
1589
|
-
TEST_METHOD(68) {
|
1590
|
-
// If a process fails to spawn, then it stops trying to spawn minProcesses processes.
|
1591
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1592
|
-
Options options = createOptions();
|
1593
|
-
options.appRoot = "tmp.wsgi";
|
1594
|
-
options.appType = "wsgi";
|
1595
|
-
options.startupFile = "passenger_wsgi.py";
|
1596
|
-
options.spawnMethod = "direct";
|
1597
|
-
options.minProcesses = 4;
|
1598
|
-
|
1599
|
-
writeFile("tmp.wsgi/counter", "0");
|
1600
|
-
chmod("tmp.wsgi/counter", 0666);
|
1601
|
-
// Our application starts successfully the first two times,
|
1602
|
-
// and fails all the other times.
|
1603
|
-
writeFile("tmp.wsgi/passenger_wsgi.py",
|
1604
|
-
"import sys\n"
|
1605
|
-
|
1606
|
-
"def application(env, start_response):\n"
|
1607
|
-
" pass\n"
|
1608
|
-
|
1609
|
-
"counter = int(open('counter', 'r').read())\n"
|
1610
|
-
"f = open('counter', 'w')\n"
|
1611
|
-
"f.write(str(counter + 1))\n"
|
1612
|
-
"f.close()\n"
|
1613
|
-
"if counter >= 2:\n"
|
1614
|
-
" sys.stderr.write('Something went wrong!')\n"
|
1615
|
-
" exit(1)\n");
|
1616
|
-
|
1617
|
-
setLogLevel(LVL_CRIT);
|
1618
|
-
pool->asyncGet(options, callback);
|
1619
|
-
EVENTUALLY(5,
|
1620
|
-
result = number == 1;
|
1621
|
-
);
|
1622
|
-
EVENTUALLY(5,
|
1623
|
-
result = pool->getProcessCount() == 2;
|
1624
|
-
);
|
1625
|
-
EVENTUALLY(5,
|
1626
|
-
result = !pool->isSpawning();
|
1627
|
-
);
|
1628
|
-
SHOULD_NEVER_HAPPEN(500,
|
1629
|
-
result = pool->getProcessCount() > 2;
|
1630
|
-
);
|
1631
|
-
}
|
1632
|
-
|
1633
|
-
TEST_METHOD(69) {
|
1634
|
-
// It removes the process from the pool if session->initiate() fails.
|
1635
|
-
Options options = createOptions();
|
1636
|
-
options.appRoot = "stub/wsgi";
|
1637
|
-
options.appType = "wsgi";
|
1638
|
-
options.startupFile = "passenger_wsgi.py";
|
1639
|
-
options.spawnMethod = "direct";
|
1640
|
-
|
1641
|
-
pool->asyncGet(options, callback);
|
1642
|
-
EVENTUALLY(5,
|
1643
|
-
result = number == 1;
|
1644
|
-
);
|
1645
|
-
pid_t pid = currentSession->getPid();
|
1646
|
-
|
1647
|
-
kill(pid, SIGTERM);
|
1648
|
-
// Wait until process is gone.
|
1649
|
-
EVENTUALLY(5,
|
1650
|
-
result = kill(pid, 0) == -1 && (errno == ESRCH || errno == EPERM || errno == ECHILD);
|
1651
|
-
);
|
1652
|
-
|
1653
|
-
try {
|
1654
|
-
currentSession->initiate();
|
1655
|
-
fail("Initiate is supposed to fail");
|
1656
|
-
} catch (const SystemException &e) {
|
1657
|
-
ensure_equals(e.code(), ECONNREFUSED);
|
1658
|
-
}
|
1659
|
-
ensure_equals(pool->getProcessCount(), 0u);
|
1660
|
-
}
|
1661
|
-
|
1662
|
-
TEST_METHOD(70) {
|
1663
|
-
// When a process has become idle, and there are waiters on the pool,
|
1664
|
-
// consider detaching it in order to satisfy a waiter.
|
1665
|
-
Options options1 = createOptions();
|
1666
|
-
Options options2 = createOptions();
|
1667
|
-
options2.appRoot = "stub/wsgi";
|
1668
|
-
|
1669
|
-
retainSessions = true;
|
1670
|
-
pool->setMax(2);
|
1671
|
-
pool->asyncGet(options1, callback);
|
1672
|
-
pool->asyncGet(options1, callback);
|
1673
|
-
EVENTUALLY(3,
|
1674
|
-
result = pool->getProcessCount() == 2;
|
1675
|
-
);
|
1676
|
-
pool->asyncGet(options2, callback);
|
1677
|
-
ensure_equals(pool->getWaitlist.size(), 1u);
|
1678
|
-
ensure_equals(number, 2);
|
1679
|
-
|
1680
|
-
currentSession.reset();
|
1681
|
-
sessions.pop_front();
|
1682
|
-
EVENTUALLY(3,
|
1683
|
-
result = number == 3;
|
1684
|
-
);
|
1685
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
1686
|
-
SuperGroupPtr superGroup1 = pool->superGroups.lookupCopy("stub/rack");
|
1687
|
-
SuperGroupPtr superGroup2 = pool->superGroups.lookupCopy("stub/rack");
|
1688
|
-
ensure_equals(superGroup1->defaultGroup->enabledCount, 1);
|
1689
|
-
ensure_equals(superGroup2->defaultGroup->enabledCount, 1);
|
1690
|
-
}
|
1691
|
-
|
1692
|
-
TEST_METHOD(71) {
|
1693
|
-
// A process is detached after processing maxRequests sessions.
|
1694
|
-
Options options = createOptions();
|
1695
|
-
options.minProcesses = 0;
|
1696
|
-
options.maxRequests = 5;
|
1697
|
-
pool->setMax(1);
|
1698
|
-
|
1699
|
-
SessionPtr session = pool->get(options, &ticket);
|
1700
|
-
ensure_equals(pool->getProcessCount(), 1u);
|
1701
|
-
pid_t origPid = session->getPid();
|
1702
|
-
session.reset();
|
1703
|
-
|
1704
|
-
for (int i = 0; i < 3; i++) {
|
1705
|
-
pool->get(options, &ticket).reset();
|
1706
|
-
ensure_equals(pool->getProcessCount(), 1u);
|
1707
|
-
ensure_equals(pool->getProcesses()[0]->pid, origPid);
|
1708
|
-
}
|
1709
|
-
|
1710
|
-
pool->get(options, &ticket).reset();
|
1711
|
-
EVENTUALLY(2,
|
1712
|
-
result = pool->getProcessCount() == 0;
|
1713
|
-
);
|
1714
|
-
}
|
1715
|
-
|
1716
|
-
TEST_METHOD(72) {
|
1717
|
-
// If we restart while spawning is in progress, and the restart
|
1718
|
-
// finishes before the process is done spawning, then that
|
1719
|
-
// process will not be attached and the original spawn loop will
|
1720
|
-
// abort. A new spawn loop will start to ensure that resource
|
1721
|
-
// constraints are met.
|
1722
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1723
|
-
initPoolDebugging();
|
1724
|
-
Options options = createOptions();
|
1725
|
-
options.appRoot = "tmp.wsgi";
|
1726
|
-
options.minProcesses = 3;
|
1727
|
-
options.statThrottleRate = 0;
|
1728
|
-
|
1729
|
-
// Trigger spawn loop and freeze it at the point where it's spawning
|
1730
|
-
// the second process.
|
1731
|
-
pool->asyncGet(options, callback);
|
1732
|
-
debug->debugger->recv("Begin spawn loop iteration 1");
|
1733
|
-
debug->messages->send("Proceed with spawn loop iteration 1");
|
1734
|
-
debug->debugger->recv("Begin spawn loop iteration 2");
|
1735
|
-
ensure_equals("(1)", pool->getProcessCount(), 1u);
|
1736
|
-
|
1737
|
-
// Trigger restart, wait until it's finished.
|
1738
|
-
touchFile("tmp.wsgi/tmp/restart.txt", 1);
|
1739
|
-
pool->asyncGet(options, callback);
|
1740
|
-
debug->messages->send("Finish restarting");
|
1741
|
-
debug->debugger->recv("Restarting done");
|
1742
|
-
ensure_equals("(2)", pool->getProcessCount(), 0u);
|
1743
|
-
|
1744
|
-
// The restarter should have created a new spawn loop and
|
1745
|
-
// instructed the old one to stop.
|
1746
|
-
debug->debugger->recv("Begin spawn loop iteration 3");
|
1747
|
-
|
1748
|
-
// We let the old spawn loop continue, which should drop
|
1749
|
-
// the second process and abort.
|
1750
|
-
debug->messages->send("Proceed with spawn loop iteration 2");
|
1751
|
-
debug->debugger->recv("Spawn loop done");
|
1752
|
-
ensure_equals("(3)", pool->getProcessCount(), 0u);
|
1753
|
-
|
1754
|
-
// We let the new spawn loop continue.
|
1755
|
-
debug->messages->send("Proceed with spawn loop iteration 3");
|
1756
|
-
debug->messages->send("Proceed with spawn loop iteration 4");
|
1757
|
-
debug->messages->send("Proceed with spawn loop iteration 5");
|
1758
|
-
debug->debugger->recv("Spawn loop done");
|
1759
|
-
ensure_equals("(4)", pool->getProcessCount(), 3u);
|
1760
|
-
}
|
1761
|
-
|
1762
|
-
TEST_METHOD(73) {
|
1763
|
-
// If a get() request comes in while the restart is in progress, then
|
1764
|
-
// that get() request will be put into the get waiters list, which will
|
1765
|
-
// be processed after spawning is done.
|
1766
|
-
|
1767
|
-
// Spawn 2 processes.
|
1768
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1769
|
-
Options options = createOptions();
|
1770
|
-
options.appRoot = "tmp.wsgi";
|
1771
|
-
options.minProcesses = 2;
|
1772
|
-
options.statThrottleRate = 0;
|
1773
|
-
pool->asyncGet(options, callback);
|
1774
|
-
EVENTUALLY(2,
|
1775
|
-
result = pool->getProcessCount() == 2;
|
1776
|
-
);
|
1777
|
-
|
1778
|
-
// Trigger a restart. The creation of the new spawner should take a while.
|
1779
|
-
spawnerConfig->spawnerCreationSleepTime = 20000;
|
1780
|
-
touchFile("tmp.wsgi/tmp/restart.txt");
|
1781
|
-
pool->asyncGet(options, callback);
|
1782
|
-
GroupPtr group = pool->findOrCreateGroup(options);
|
1783
|
-
ensure_equals(pool->getProcessCount(), 0u);
|
1784
|
-
ensure_equals(group->getWaitlist.size(), 1u);
|
1785
|
-
|
1786
|
-
// Now that the restart is in progress, perform a get().
|
1787
|
-
pool->asyncGet(options, callback);
|
1788
|
-
ensure_equals(group->getWaitlist.size(), 2u);
|
1789
|
-
EVENTUALLY(2,
|
1790
|
-
result = number == 3;
|
1791
|
-
);
|
1792
|
-
ensure_equals("The restart function respects minProcesses",
|
1793
|
-
pool->getProcessCount(), 2u);
|
1794
|
-
}
|
1795
|
-
|
1796
|
-
TEST_METHOD(74) {
|
1797
|
-
// If a process fails to spawn, it sends a SpawnException result to all get waiters.
|
1798
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1799
|
-
chmod("tmp.wsgi", 0777);
|
1800
|
-
Options options = createOptions();
|
1801
|
-
options.appRoot = "tmp.wsgi";
|
1802
|
-
options.appType = "wsgi";
|
1803
|
-
options.startupFile = "passenger_wsgi.py";
|
1804
|
-
options.spawnMethod = "direct";
|
1805
|
-
pool->setMax(1);
|
1806
|
-
|
1807
|
-
writeFile("tmp.wsgi/passenger_wsgi.py",
|
1808
|
-
"import os, time, sys\n"
|
1809
|
-
"\n"
|
1810
|
-
"def file_exists(filename):\n"
|
1811
|
-
" try:\n"
|
1812
|
-
" os.stat(filename)\n"
|
1813
|
-
" return True\n"
|
1814
|
-
" except OSError:\n"
|
1815
|
-
" return False\n"
|
1816
|
-
"\n"
|
1817
|
-
"f = open('spawned.txt', 'w')\n"
|
1818
|
-
"f.write(str(os.getpid()))\n"
|
1819
|
-
"f.close()\n"
|
1820
|
-
"while not file_exists('continue.txt'):\n"
|
1821
|
-
" time.sleep(0.05)\n"
|
1822
|
-
"sys.stderr.write('Something went wrong!')\n"
|
1823
|
-
"exit(1)\n");
|
1824
|
-
|
1825
|
-
retainSessions = true;
|
1826
|
-
setLogLevel(LVL_CRIT);
|
1827
|
-
pool->asyncGet(options, callback);
|
1828
|
-
pool->asyncGet(options, callback);
|
1829
|
-
pool->asyncGet(options, callback);
|
1830
|
-
pool->asyncGet(options, callback);
|
1831
|
-
|
1832
|
-
EVENTUALLY(5,
|
1833
|
-
result = fileExists("tmp.wsgi/spawned.txt");
|
1834
|
-
);
|
1835
|
-
usleep(20000);
|
1836
|
-
writeFile("tmp.wsgi/passenger_wsgi.py", readAll("stub/wsgi/passenger_wsgi.py"));
|
1837
|
-
pid_t pid = (pid_t) stringToLL(readAll("tmp.wsgi/spawned.txt"));
|
1838
|
-
kill(pid, SIGTERM);
|
1839
|
-
EVENTUALLY(5,
|
1840
|
-
result = number == 4;
|
1841
|
-
);
|
1842
|
-
ensure_equals(pool->getProcessCount(), 0u);
|
1843
|
-
ensure(sessions.empty());
|
1844
|
-
}
|
1845
|
-
|
1846
|
-
TEST_METHOD(75) {
|
1847
|
-
// If a process fails to spawn, the existing processes
|
1848
|
-
// are kept alive.
|
1849
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1850
|
-
Options options = createOptions();
|
1851
|
-
options.appRoot = "tmp.wsgi";
|
1852
|
-
options.appType = "wsgi";
|
1853
|
-
options.startupFile = "passenger_wsgi.py";
|
1854
|
-
options.spawnMethod = "direct";
|
1855
|
-
options.minProcesses = 2;
|
1856
|
-
|
1857
|
-
// Spawn 2 processes.
|
1858
|
-
retainSessions = true;
|
1859
|
-
pool->asyncGet(options, callback);
|
1860
|
-
pool->asyncGet(options, callback);
|
1861
|
-
EVENTUALLY(10,
|
1862
|
-
result = number == 2;
|
1863
|
-
);
|
1864
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
1865
|
-
|
1866
|
-
// Mess up the application and spawn a new one.
|
1867
|
-
writeFile("tmp.wsgi/passenger_wsgi.py",
|
1868
|
-
"import sys\n"
|
1869
|
-
"sys.stderr.write('Something went wrong!')\n"
|
1870
|
-
"exit(1)\n");
|
1871
|
-
try {
|
1872
|
-
setLogLevel(LVL_CRIT);
|
1873
|
-
currentSession = pool->get(options, &ticket);
|
1874
|
-
fail("SpawnException expected");
|
1875
|
-
} catch (const SpawnException &) {
|
1876
|
-
ensure_equals(pool->getProcessCount(), 2u);
|
1877
|
-
}
|
1878
|
-
}
|
1879
|
-
|
1880
|
-
TEST_METHOD(76) {
|
1881
|
-
// No more than maxOutOfBandWorkInstances process will be performing
|
1882
|
-
// out-of-band work at the same time.
|
1883
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
1884
|
-
Options options = createOptions();
|
1885
|
-
options.appRoot = "tmp.wsgi";
|
1886
|
-
options.appType = "wsgi";
|
1887
|
-
options.startupFile = "passenger_wsgi.py";
|
1888
|
-
options.spawnMethod = "direct";
|
1889
|
-
options.maxOutOfBandWorkInstances = 2;
|
1890
|
-
initPoolDebugging();
|
1891
|
-
debug->restarting = false;
|
1892
|
-
debug->spawning = false;
|
1893
|
-
debug->oobw = true;
|
1894
|
-
|
1895
|
-
// Spawn 3 processes and initiate 2 OOBW requests.
|
1896
|
-
SessionPtr session1 = pool->get(options, &ticket);
|
1897
|
-
SessionPtr session2 = pool->get(options, &ticket);
|
1898
|
-
SessionPtr session3 = pool->get(options, &ticket);
|
1899
|
-
session1->requestOOBW();
|
1900
|
-
session1.reset();
|
1901
|
-
session2->requestOOBW();
|
1902
|
-
session2.reset();
|
1903
|
-
|
1904
|
-
// 2 OOBW requests eventually start.
|
1905
|
-
debug->debugger->recv("OOBW request about to start");
|
1906
|
-
debug->debugger->recv("OOBW request about to start");
|
1907
|
-
|
1908
|
-
// Request another OOBW, but this one is not initiated.
|
1909
|
-
session3->requestOOBW();
|
1910
|
-
session3.reset();
|
1911
|
-
SHOULD_NEVER_HAPPEN(100,
|
1912
|
-
result = debug->debugger->peek("OOBW request about to start") != NULL;
|
1913
|
-
);
|
1914
|
-
|
1915
|
-
// Let one OOBW request finish. The third one should eventually
|
1916
|
-
// start.
|
1917
|
-
debug->messages->send("Proceed with OOBW request");
|
1918
|
-
debug->debugger->recv("OOBW request about to start");
|
1919
|
-
|
1920
|
-
debug->messages->send("Proceed with OOBW request");
|
1921
|
-
debug->messages->send("Proceed with OOBW request");
|
1922
|
-
debug->debugger->recv("OOBW request finished");
|
1923
|
-
debug->debugger->recv("OOBW request finished");
|
1924
|
-
debug->debugger->recv("OOBW request finished");
|
1925
|
-
}
|
1926
|
-
|
1927
|
-
TEST_METHOD(77) {
|
1928
|
-
// If the getWaitlist already has maxRequestQueueSize items,
|
1929
|
-
// then an exception is returned.
|
1930
|
-
Options options = createOptions();
|
1931
|
-
options.appGroupName = "test1";
|
1932
|
-
options.maxRequestQueueSize = 3;
|
1933
|
-
GroupPtr group = pool->findOrCreateGroup(options);
|
1934
|
-
spawnerConfig->concurrency = 3;
|
1935
|
-
initPoolDebugging();
|
1936
|
-
pool->setMax(1);
|
1937
|
-
|
1938
|
-
for (int i = 0; i < 3; i++) {
|
1939
|
-
pool->asyncGet(options, callback);
|
1940
|
-
}
|
1941
|
-
ensure_equals(number, 0);
|
1942
|
-
{
|
1943
|
-
LockGuard l(pool->syncher);
|
1944
|
-
ensure_equals(group->getWaitlist.size(),
|
1945
|
-
3u);
|
1946
|
-
}
|
1947
|
-
|
1948
|
-
try {
|
1949
|
-
pool->get(options, &ticket);
|
1950
|
-
fail("Expected RequestQueueFullException");
|
1951
|
-
} catch (const RequestQueueFullException &e) {
|
1952
|
-
// OK
|
1953
|
-
}
|
1954
|
-
|
1955
|
-
debug->messages->send("Proceed with spawn loop iteration 1");
|
1956
|
-
debug->messages->send("Spawn loop done");
|
1957
|
-
EVENTUALLY(5,
|
1958
|
-
result = number == 3;
|
1959
|
-
);
|
1960
|
-
}
|
1961
|
-
|
1962
|
-
TEST_METHOD(78) {
|
1963
|
-
// Test restarting while a previous restart was already being finalized.
|
1964
|
-
// The previous finalization should abort.
|
1965
|
-
Options options = createOptions();
|
1966
|
-
initPoolDebugging();
|
1967
|
-
debug->spawning = false;
|
1968
|
-
pool->get(options, &ticket);
|
1969
|
-
|
1970
|
-
ensure_equals(pool->restartSuperGroupsByAppRoot(options.appRoot), 1u);
|
1971
|
-
debug->debugger->recv("About to end restarting");
|
1972
|
-
ensure_equals(pool->restartSuperGroupsByAppRoot(options.appRoot), 1u);
|
1973
|
-
debug->debugger->recv("About to end restarting");
|
1974
|
-
debug->messages->send("Finish restarting");
|
1975
|
-
debug->messages->send("Finish restarting");
|
1976
|
-
debug->debugger->recv("Restarting done");
|
1977
|
-
debug->debugger->recv("Restarting aborted");
|
1978
|
-
}
|
1979
|
-
|
1980
|
-
TEST_METHOD(79) {
|
1981
|
-
// Test sticky sessions.
|
1982
|
-
|
1983
|
-
// Spawn 2 processes and get their sticky session IDs and PIDs.
|
1984
|
-
ensureMinProcesses(2);
|
1985
|
-
Options options = createOptions();
|
1986
|
-
SessionPtr session1 = pool->get(options, &ticket);
|
1987
|
-
SessionPtr session2 = pool->get(options, &ticket);
|
1988
|
-
int id1 = session1->getStickySessionId();
|
1989
|
-
int id2 = session2->getStickySessionId();
|
1990
|
-
pid_t pid1 = session1->getPid();
|
1991
|
-
pid_t pid2 = session2->getPid();
|
1992
|
-
session1.reset();
|
1993
|
-
session2.reset();
|
1994
|
-
|
1995
|
-
// Make two requests with id1 as sticky session ID. They should
|
1996
|
-
// both go to process pid1.
|
1997
|
-
options.stickySessionId = id1;
|
1998
|
-
session1 = pool->get(options, &ticket);
|
1999
|
-
ensure_equals("Request 1.1 goes to process 1", session1->getPid(), pid1);
|
2000
|
-
// The second request should be queued, and should not finish until
|
2001
|
-
// the first request is finished.
|
2002
|
-
ensure_equals(number, 1);
|
2003
|
-
pool->asyncGet(options, callback);
|
2004
|
-
SHOULD_NEVER_HAPPEN(100,
|
2005
|
-
result = number > 1;
|
2006
|
-
);
|
2007
|
-
session1.reset();
|
2008
|
-
EVENTUALLY(1,
|
2009
|
-
result = number == 2;
|
2010
|
-
);
|
2011
|
-
ensure_equals("Request 1.2 goes to process 1", currentSession->getPid(), pid1);
|
2012
|
-
currentSession.reset();
|
2013
|
-
|
2014
|
-
// Make two requests with id2 as sticky session ID. They should
|
2015
|
-
// both go to process pid2.
|
2016
|
-
options.stickySessionId = id2;
|
2017
|
-
session1 = pool->get(options, &ticket);
|
2018
|
-
ensure_equals("Request 2.1 goes to process 2", session1->getPid(), pid2);
|
2019
|
-
// The second request should be queued, and should not finish until
|
2020
|
-
// the first request is finished.
|
2021
|
-
pool->asyncGet(options, callback);
|
2022
|
-
SHOULD_NEVER_HAPPEN(100,
|
2023
|
-
result = number > 2;
|
2024
|
-
);
|
2025
|
-
session1.reset();
|
2026
|
-
EVENTUALLY(1,
|
2027
|
-
result = number == 3;
|
2028
|
-
);
|
2029
|
-
ensure_equals("Request 2.2 goes to process 2", currentSession->getPid(), pid2);
|
2030
|
-
currentSession.reset();
|
2031
|
-
}
|
2032
|
-
|
2033
|
-
// TODO: Persistent connections.
|
2034
|
-
// TODO: If one closes the session before it has reached EOF, and process's maximum concurrency
|
2035
|
-
// has already been reached, then the pool should ping the process so that it can detect
|
2036
|
-
// when the session's connection has been released by the app.
|
2037
|
-
|
2038
|
-
|
2039
|
-
/*********** Test previously discovered bugs ***********/
|
2040
|
-
|
2041
|
-
TEST_METHOD(85) {
|
2042
|
-
// Test detaching, then restarting. This should not violate any invariants.
|
2043
|
-
TempDirCopy dir("stub/wsgi", "tmp.wsgi");
|
2044
|
-
Options options = createOptions();
|
2045
|
-
options.appRoot = "tmp.wsgi";
|
2046
|
-
options.appType = "wsgi";
|
2047
|
-
options.startupFile = "passenger_wsgi.py";
|
2048
|
-
options.spawnMethod = "direct";
|
2049
|
-
options.statThrottleRate = 0;
|
2050
|
-
|
2051
|
-
SessionPtr session = pool->get(options, &ticket);
|
2052
|
-
string gupid(session->getProcess()->gupid,
|
2053
|
-
session->getProcess()->gupidSize);
|
2054
|
-
session.reset();
|
2055
|
-
pool->detachProcess(gupid);
|
2056
|
-
touchFile("tmp.wsgi/tmp/restart.txt", 1);
|
2057
|
-
pool->get(options, &ticket).reset();
|
2058
|
-
}
|
2059
|
-
|
2060
|
-
|
2061
|
-
/*****************************/
|
2062
|
-
}
|