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.

Files changed (550) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +10 -0
  5. data/CHANGELOG +21 -0
  6. data/build/agents.rb +2 -2
  7. data/build/apache2.rb +6 -5
  8. data/build/common_library.rb +22 -7
  9. data/build/cxx_tests.rb +0 -3
  10. data/build/misc.rb +1 -1
  11. data/dev/parse_file_descriptor_log +119 -0
  12. data/doc/CloudLicensingConfiguration.html +387 -0
  13. data/doc/Design and Architecture.html +2430 -0
  14. data/doc/Packaging.html +488 -0
  15. data/doc/Security of user switching support.html +1833 -0
  16. data/doc/ServerOptimizationGuide.html +659 -0
  17. data/doc/ServerOptimizationGuide.txt.md +8 -0
  18. data/doc/Users guide Apache.html +9116 -0
  19. data/doc/Users guide Apache.idmap.txt +6 -2
  20. data/doc/Users guide Apache.txt +26 -7
  21. data/doc/Users guide Nginx.html +9025 -0
  22. data/doc/Users guide Nginx.idmap.txt +7 -3
  23. data/doc/Users guide Nginx.txt +29 -6
  24. data/doc/Users guide Standalone.html +3983 -0
  25. data/doc/Users guide.html +1748 -0
  26. data/doc/users_guide_snippets/installation.txt +4 -4
  27. data/ext/apache2/Configuration.cpp +16 -5
  28. data/ext/apache2/Configuration.hpp +4 -2
  29. data/ext/apache2/Hooks.cpp +44 -19
  30. data/ext/boost/libs/thread/src/pthread/once.cpp +2 -0
  31. data/ext/boost/libs/thread/src/pthread/once_atomic.cpp +6 -0
  32. data/ext/common/AgentsStarter.h +3 -2
  33. data/ext/common/ApplicationPool2/DirectSpawner.h +14 -4
  34. data/ext/common/ApplicationPool2/DummySpawner.h +12 -7
  35. data/ext/common/ApplicationPool2/Implementation.cpp +1 -1
  36. data/ext/common/ApplicationPool2/Process.h +2 -1
  37. data/ext/common/ApplicationPool2/Session.h +6 -6
  38. data/ext/common/ApplicationPool2/SmartSpawner.h +19 -4
  39. data/ext/common/ApplicationPool2/Socket.h +59 -27
  40. data/ext/common/ApplicationPool2/Spawner.h +2 -2
  41. data/ext/common/BackgroundEventLoop.cpp +6 -1
  42. data/ext/common/Constants.h +1 -1
  43. data/ext/common/EventedClient.h +1 -1
  44. data/ext/common/EventedServer.h +2 -2
  45. data/ext/common/FileDescriptor.h +25 -6
  46. data/ext/common/Logging.cpp +107 -52
  47. data/ext/common/Logging.h +146 -19
  48. data/ext/common/MessageClient.h +2 -2
  49. data/ext/common/MessageServer.h +3 -2
  50. data/ext/common/RandomGenerator.h +8 -7
  51. data/ext/common/SafeLibev.h +5 -1
  52. data/ext/common/ServerKit/AcceptLoadBalancer.h +9 -4
  53. data/ext/common/ServerKit/FdSinkChannel.h +5 -2
  54. data/ext/common/ServerKit/FdSourceChannel.h +5 -2
  55. data/ext/common/ServerKit/FileBufferedChannel.h +2 -0
  56. data/ext/common/ServerKit/FileBufferedFdSinkChannel.h +7 -2
  57. data/ext/common/ServerKit/HttpServer.h +6 -0
  58. data/ext/common/ServerKit/Server.h +40 -3
  59. data/ext/common/StaticString.h +20 -0
  60. data/ext/common/UnionStation/Connection.h +3 -1
  61. data/ext/common/UnionStation/Core.h +6 -4
  62. data/ext/common/Utils.cpp +4 -3
  63. data/ext/common/Utils/DateParsing.h +19 -5
  64. data/ext/common/Utils/FastStringStream.h +183 -0
  65. data/ext/common/Utils/IOUtils.cpp +47 -28
  66. data/ext/common/Utils/IOUtils.h +56 -12
  67. data/ext/common/Utils/MessagePassing.h +3 -3
  68. data/ext/common/Utils/ProcessMetricsCollector.h +2 -2
  69. data/ext/common/Utils/ScopeGuard.h +16 -5
  70. data/ext/common/Utils/SpeedMeter.h +2 -2
  71. data/ext/common/Utils/StrIntUtils.cpp +6 -6
  72. data/ext/common/Utils/StrIntUtils.h +2 -1
  73. data/ext/common/agents/Base.cpp +56 -4
  74. data/ext/common/agents/Base.h +2 -1
  75. data/ext/common/agents/HelperAgent/AdminServer.h +122 -11
  76. data/ext/common/agents/HelperAgent/Main.cpp +16 -5
  77. data/ext/common/agents/HelperAgent/OptionParser.h +7 -1
  78. data/ext/common/agents/HelperAgent/RequestHandler.h +1 -1
  79. data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +10 -1
  80. data/ext/common/agents/HelperAgent/RequestHandler/Request.h +8 -0
  81. data/ext/common/agents/HelperAgent/RequestHandler/TurboCaching.h +4 -3
  82. data/ext/common/agents/LoggingAgent/AdminServer.h +57 -11
  83. data/ext/common/agents/LoggingAgent/LoggingServer.h +3 -3
  84. data/ext/common/agents/LoggingAgent/Main.cpp +11 -3
  85. data/ext/common/agents/Watchdog/AdminServer.h +53 -11
  86. data/ext/common/agents/Watchdog/AgentWatcher.cpp +3 -3
  87. data/ext/common/agents/Watchdog/Main.cpp +13 -6
  88. data/ext/libeio/ecb.h +1 -1
  89. data/ext/libev/ev.c +13 -1
  90. data/ext/libev/ev.h +3 -0
  91. data/ext/nginx/Configuration.c +28 -6
  92. data/ext/nginx/Configuration.h +2 -1
  93. data/ext/nginx/ngx_http_passenger_module.c +5 -4
  94. data/ext/oxt/dynamic_thread_group.hpp +38 -5
  95. data/lib/phusion_passenger.rb +1 -1
  96. data/lib/phusion_passenger/common_library.rb +9 -5
  97. data/lib/phusion_passenger/config/reopen_logs_command.rb +2 -2
  98. data/lib/phusion_passenger/packaging.rb +23 -37
  99. data/passenger.gemspec +21 -21
  100. metadata +4 -453
  101. metadata.gz.asc +7 -7
  102. data/.gitignore +0 -68
  103. data/.travis.yml +0 -16
  104. data/Gemfile +0 -17
  105. data/Gemfile.lock +0 -39
  106. data/Vagrantfile +0 -54
  107. data/debian.template/README.Debian +0 -15
  108. data/debian.template/changelog +0 -316
  109. data/debian.template/compat +0 -1
  110. data/debian.template/control.erb +0 -91
  111. data/debian.template/copyright +0 -385
  112. data/debian.template/libapache2-mod-passenger.install +0 -3
  113. data/debian.template/libapache2-mod-passenger.postinst +0 -36
  114. data/debian.template/libapache2-mod-passenger.prerm +0 -15
  115. data/debian.template/locations.ini.erb +0 -14
  116. data/debian.template/passenger-dev.install.erb +0 -3
  117. data/debian.template/passenger-doc.install.erb +0 -2
  118. data/debian.template/passenger.conf +0 -6
  119. data/debian.template/passenger.docs +0 -4
  120. data/debian.template/passenger.install.erb +0 -14
  121. data/debian.template/passenger.load +0 -3
  122. data/debian.template/passenger.manpages +0 -3
  123. data/debian.template/patches/series +0 -0
  124. data/debian.template/rules.erb +0 -76
  125. data/debian.template/source/format +0 -1
  126. data/ext/common/EventedBufferedInput.h +0 -458
  127. data/packaging/rpm/LICENSE.txt +0 -19
  128. data/packaging/rpm/Makefile +0 -13
  129. data/packaging/rpm/README.md +0 -41
  130. data/packaging/rpm/Vagrantfile +0 -38
  131. data/packaging/rpm/Vagrantfile.centos +0 -30
  132. data/packaging/rpm/build +0 -170
  133. data/packaging/rpm/create_project +0 -41
  134. data/packaging/rpm/git_update +0 -88
  135. data/packaging/rpm/image/Dockerfile +0 -37
  136. data/packaging/rpm/image/Gemfile +0 -3
  137. data/packaging/rpm/image/Gemfile.lock +0 -12
  138. data/packaging/rpm/image/RPM-GPG-KEY-amazon-ga +0 -19
  139. data/packaging/rpm/image/amazon2014-i386.cfg +0 -96
  140. data/packaging/rpm/image/amazon2014-x86_64.cfg +0 -96
  141. data/packaging/rpm/image/site-defaults.cfg +0 -168
  142. data/packaging/rpm/internal/build_tasks.rb +0 -238
  143. data/packaging/rpm/internal/dummygpg +0 -11
  144. data/packaging/rpm/internal/exec_build +0 -42
  145. data/packaging/rpm/internal/get_distro_arch +0 -14
  146. data/packaging/rpm/internal/get_distro_id +0 -10
  147. data/packaging/rpm/internal/git_update +0 -27
  148. data/packaging/rpm/internal/inituidgid +0 -17
  149. data/packaging/rpm/internal/my_init +0 -344
  150. data/packaging/rpm/internal/python27 +0 -3
  151. data/packaging/rpm/internal/repo_update +0 -46
  152. data/packaging/rpm/internal/setuser +0 -26
  153. data/packaging/rpm/internal/tracking_helper +0 -40
  154. data/packaging/rpm/jenkins_release +0 -99
  155. data/packaging/rpm/lib/build_tasks_support.rb +0 -402
  156. data/packaging/rpm/lib/preprocessor.rb +0 -341
  157. data/packaging/rpm/nginx_spec/404.html +0 -119
  158. data/packaging/rpm/nginx_spec/50x.html +0 -119
  159. data/packaging/rpm/nginx_spec/index.html +0 -116
  160. data/packaging/rpm/nginx_spec/nginx-auto-cc-gcc.patch +0 -13
  161. data/packaging/rpm/nginx_spec/nginx-logo.png +0 -0
  162. data/packaging/rpm/nginx_spec/nginx-upgrade +0 -13
  163. data/packaging/rpm/nginx_spec/nginx-upgrade.8 +0 -151
  164. data/packaging/rpm/nginx_spec/nginx.conf +0 -131
  165. data/packaging/rpm/nginx_spec/nginx.init +0 -144
  166. data/packaging/rpm/nginx_spec/nginx.logrotate +0 -13
  167. data/packaging/rpm/nginx_spec/nginx.service +0 -15
  168. data/packaging/rpm/nginx_spec/nginx.spec.template +0 -560
  169. data/packaging/rpm/nginx_spec/nginx.sysconfig +0 -4
  170. data/packaging/rpm/nginx_spec/passenger.conf +0 -9
  171. data/packaging/rpm/nginx_spec/poweredby.png +0 -0
  172. data/packaging/rpm/passenger_spec/apache-passenger.conf.in +0 -26
  173. data/packaging/rpm/passenger_spec/config.json +0 -30
  174. data/packaging/rpm/passenger_spec/passenger.logrotate +0 -7
  175. data/packaging/rpm/passenger_spec/passenger.spec.template +0 -478
  176. data/packaging/rpm/passenger_spec/passenger_dynamic_thread_group.patch +0 -16
  177. data/packaging/rpm/passenger_spec/passenger_tests_default_config_example.patch +0 -44
  178. data/packaging/rpm/passenger_spec/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +0 -21
  179. data/packaging/rpm/repo_update +0 -114
  180. data/packaging/rpm/setup-system +0 -61
  181. data/packaging/rpm/shell +0 -10
  182. data/test/.rspec +0 -4
  183. data/test/config.json.example +0 -42
  184. data/test/config.json.rpm-automation +0 -15
  185. data/test/config.json.travis +0 -15
  186. data/test/config.json.vagrant +0 -30
  187. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +0 -124
  188. data/test/cxx/ApplicationPool2/OptionsTest.cpp +0 -30
  189. data/test/cxx/ApplicationPool2/PoolTest.cpp +0 -2062
  190. data/test/cxx/ApplicationPool2/ProcessTest.cpp +0 -130
  191. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +0 -243
  192. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +0 -823
  193. data/test/cxx/BufferedIOTest.cpp +0 -364
  194. data/test/cxx/CachedFileStatTest.cpp +0 -402
  195. data/test/cxx/CxxTestMain.cpp +0 -181
  196. data/test/cxx/DataStructures/LStringTest.cpp +0 -275
  197. data/test/cxx/DataStructures/StringKeyTableTest.cpp +0 -199
  198. data/test/cxx/DateParsingTest.cpp +0 -75
  199. data/test/cxx/DechunkerTest.cpp +0 -250
  200. data/test/cxx/EventedBufferedInputTest.cpp +0 -758
  201. data/test/cxx/EventedClientTest.cpp +0 -523
  202. data/test/cxx/FileChangeCheckerTest.cpp +0 -331
  203. data/test/cxx/FileDescriptorTest.cpp +0 -69
  204. data/test/cxx/FilterSupportTest.cpp +0 -433
  205. data/test/cxx/IOUtilsTest.cpp +0 -861
  206. data/test/cxx/MemoryKit/MbufTest.cpp +0 -213
  207. data/test/cxx/MessageIOTest.cpp +0 -360
  208. data/test/cxx/MessagePassingTest.cpp +0 -81
  209. data/test/cxx/MessageReadersWritersTest.cpp +0 -576
  210. data/test/cxx/MessageServerTest.cpp +0 -393
  211. data/test/cxx/ProcessMetricsCollectorTest.cpp +0 -123
  212. data/test/cxx/RequestHandlerTest.cpp +0 -1463
  213. data/test/cxx/ResponseCacheTest.cpp +0 -322
  214. data/test/cxx/ServerKit/ChannelTest.cpp +0 -1467
  215. data/test/cxx/ServerKit/CookieUtilsTest.cpp +0 -274
  216. data/test/cxx/ServerKit/FileBufferedChannelTest.cpp +0 -992
  217. data/test/cxx/ServerKit/HeaderTableTest.cpp +0 -177
  218. data/test/cxx/ServerKit/HttpServerTest.cpp +0 -1580
  219. data/test/cxx/ServerKit/ServerTest.cpp +0 -408
  220. data/test/cxx/StaticStringTest.cpp +0 -220
  221. data/test/cxx/StringMapTest.cpp +0 -131
  222. data/test/cxx/SystemTimeTest.cpp +0 -37
  223. data/test/cxx/TemplateTest.cpp +0 -118
  224. data/test/cxx/TestSupport.cpp +0 -207
  225. data/test/cxx/TestSupport.h +0 -333
  226. data/test/cxx/UnionStationTest.cpp +0 -741
  227. data/test/cxx/Utils/StrIntUtilsTest.cpp +0 -39
  228. data/test/cxx/UtilsTest.cpp +0 -672
  229. data/test/cxx/VariantMapTest.cpp +0 -191
  230. data/test/gdbinit.example +0 -34
  231. data/test/integration_tests/apache2_tests.rb +0 -585
  232. data/test/integration_tests/downloaded_binaries_tests.rb +0 -185
  233. data/test/integration_tests/native_packaging_spec.rb +0 -368
  234. data/test/integration_tests/nginx_tests.rb +0 -402
  235. data/test/integration_tests/shared/example_webapp_tests.rb +0 -289
  236. data/test/integration_tests/source_packaging_test.rb +0 -201
  237. data/test/integration_tests/spec_helper.rb +0 -22
  238. data/test/integration_tests/standalone_tests.rb +0 -392
  239. data/test/node/line_reader_spec.js +0 -338
  240. data/test/node/spec_helper.js +0 -65
  241. data/test/oxt/backtrace_test.cpp +0 -88
  242. data/test/oxt/counter.hpp +0 -55
  243. data/test/oxt/dynamic_thread_group_test.cpp +0 -131
  244. data/test/oxt/oxt_test_main.cpp +0 -27
  245. data/test/oxt/spin_lock_test.cpp +0 -59
  246. data/test/oxt/syscall_interruption_test.cpp +0 -39
  247. data/test/ruby/debug_logging_spec.rb +0 -145
  248. data/test/ruby/message_channel_spec.rb +0 -196
  249. data/test/ruby/rack/loader_spec.rb +0 -42
  250. data/test/ruby/rack/preloader_spec.rb +0 -48
  251. data/test/ruby/rails3.0/loader_spec.rb +0 -26
  252. data/test/ruby/rails3.0/preloader_spec.rb +0 -32
  253. data/test/ruby/rails3.1/loader_spec.rb +0 -26
  254. data/test/ruby/rails3.1/preloader_spec.rb +0 -32
  255. data/test/ruby/rails3.2/loader_spec.rb +0 -26
  256. data/test/ruby/rails3.2/preloader_spec.rb +0 -32
  257. data/test/ruby/rails4.0/loader_spec.rb +0 -28
  258. data/test/ruby/rails4.0/preloader_spec.rb +0 -34
  259. data/test/ruby/rails4.1/loader_spec.rb +0 -28
  260. data/test/ruby/rails4.1/preloader_spec.rb +0 -34
  261. data/test/ruby/request_handler_spec.rb +0 -747
  262. data/test/ruby/shared/loader_sharedspec.rb +0 -247
  263. data/test/ruby/shared/rails/union_station_extensions_sharedspec.rb +0 -357
  264. data/test/ruby/shared/ruby_loader_sharedspec.rb +0 -55
  265. data/test/ruby/spec_helper.rb +0 -114
  266. data/test/ruby/standalone/runtime_installer_spec.rb +0 -402
  267. data/test/ruby/union_station_spec.rb +0 -288
  268. data/test/ruby/utils/file_system_watcher_spec.rb +0 -229
  269. data/test/ruby/utils/hosts_file_parser.rb +0 -258
  270. data/test/ruby/utils/tee_input_spec.rb +0 -235
  271. data/test/ruby/utils/unseekable_socket_spec.rb +0 -66
  272. data/test/ruby/utils_spec.rb +0 -41
  273. data/test/stub/apache2/httpd.conf.erb +0 -122
  274. data/test/stub/apache2/mime.types +0 -748
  275. data/test/stub/garbage1.dat +0 -0
  276. data/test/stub/garbage2.dat +0 -0
  277. data/test/stub/garbage3.dat +0 -0
  278. data/test/stub/http_request.yml +0 -23
  279. data/test/stub/index.html +0 -1
  280. data/test/stub/nginx/koi-utf +0 -109
  281. data/test/stub/nginx/koi-win +0 -103
  282. data/test/stub/nginx/mime.types +0 -70
  283. data/test/stub/nginx/nginx.conf.erb +0 -70
  284. data/test/stub/nginx/win-utf +0 -126
  285. data/test/stub/node/app.js +0 -133
  286. data/test/stub/node/public/.gitignore +0 -0
  287. data/test/stub/node/tmp/.gitignore +0 -0
  288. data/test/stub/rack/config.ru +0 -95
  289. data/test/stub/rack/library.rb +0 -16
  290. data/test/stub/rack/public/.gitignore +0 -0
  291. data/test/stub/rack/start.rb +0 -52
  292. data/test/stub/rack/tmp/.gitignore +0 -0
  293. data/test/stub/rails3.0/.gitignore +0 -4
  294. data/test/stub/rails3.0/Gemfile +0 -22
  295. data/test/stub/rails3.0/Gemfile.lock +0 -80
  296. data/test/stub/rails3.0/Rakefile +0 -10
  297. data/test/stub/rails3.0/app/controllers/application_controller.rb +0 -4
  298. data/test/stub/rails3.0/app/helpers/application_helper.rb +0 -2
  299. data/test/stub/rails3.0/app/views/layouts/application.html.erb +0 -14
  300. data/test/stub/rails3.0/config.ru +0 -4
  301. data/test/stub/rails3.0/config/application.rb +0 -48
  302. data/test/stub/rails3.0/config/boot.rb +0 -13
  303. data/test/stub/rails3.0/config/database.yml +0 -22
  304. data/test/stub/rails3.0/config/environment.rb +0 -5
  305. data/test/stub/rails3.0/config/environments/development.rb +0 -19
  306. data/test/stub/rails3.0/config/environments/production.rb +0 -48
  307. data/test/stub/rails3.0/config/environments/test.rb +0 -32
  308. data/test/stub/rails3.0/config/initializers/backtrace_silencers.rb +0 -7
  309. data/test/stub/rails3.0/config/initializers/inflections.rb +0 -10
  310. data/test/stub/rails3.0/config/initializers/mime_types.rb +0 -5
  311. data/test/stub/rails3.0/config/initializers/passenger.rb +0 -2
  312. data/test/stub/rails3.0/config/initializers/secret_token.rb +0 -7
  313. data/test/stub/rails3.0/config/initializers/session_store.rb +0 -8
  314. data/test/stub/rails3.0/config/locales/en.yml +0 -5
  315. data/test/stub/rails3.0/config/routes.rb +0 -58
  316. data/test/stub/rails3.0/db/seeds.rb +0 -7
  317. data/test/stub/rails3.0/doc/README_FOR_APP +0 -2
  318. data/test/stub/rails3.0/lib/tasks/.gitkeep +0 -0
  319. data/test/stub/rails3.0/log/.gitignore +0 -0
  320. data/test/stub/rails3.0/public/404.html +0 -26
  321. data/test/stub/rails3.0/public/422.html +0 -26
  322. data/test/stub/rails3.0/public/500.html +0 -26
  323. data/test/stub/rails3.0/public/favicon.ico +0 -0
  324. data/test/stub/rails3.0/public/index.html +0 -279
  325. data/test/stub/rails3.0/public/robots.txt +0 -5
  326. data/test/stub/rails3.0/public/stylesheets/.gitkeep +0 -0
  327. data/test/stub/rails3.0/script/rails +0 -9
  328. data/test/stub/rails3.0/test/performance/browsing_test.rb +0 -9
  329. data/test/stub/rails3.0/test/test_helper.rb +0 -13
  330. data/test/stub/rails3.0/vendor/plugins/.gitkeep +0 -0
  331. data/test/stub/rails3.1/.gitignore +0 -15
  332. data/test/stub/rails3.1/Gemfile +0 -37
  333. data/test/stub/rails3.1/Gemfile.lock +0 -115
  334. data/test/stub/rails3.1/README +0 -261
  335. data/test/stub/rails3.1/Rakefile +0 -7
  336. data/test/stub/rails3.1/app/assets/images/rails.png +0 -0
  337. data/test/stub/rails3.1/app/assets/stylesheets/application.css +0 -7
  338. data/test/stub/rails3.1/app/controllers/application_controller.rb +0 -3
  339. data/test/stub/rails3.1/app/helpers/application_helper.rb +0 -2
  340. data/test/stub/rails3.1/app/mailers/.gitkeep +0 -0
  341. data/test/stub/rails3.1/app/models/.gitkeep +0 -0
  342. data/test/stub/rails3.1/app/views/layouts/application.html.erb +0 -14
  343. data/test/stub/rails3.1/config.ru +0 -4
  344. data/test/stub/rails3.1/config/application.rb +0 -48
  345. data/test/stub/rails3.1/config/boot.rb +0 -6
  346. data/test/stub/rails3.1/config/database.yml +0 -25
  347. data/test/stub/rails3.1/config/environment.rb +0 -5
  348. data/test/stub/rails3.1/config/environments/development.rb +0 -30
  349. data/test/stub/rails3.1/config/environments/production.rb +0 -60
  350. data/test/stub/rails3.1/config/environments/test.rb +0 -39
  351. data/test/stub/rails3.1/config/initializers/backtrace_silencers.rb +0 -7
  352. data/test/stub/rails3.1/config/initializers/inflections.rb +0 -10
  353. data/test/stub/rails3.1/config/initializers/mime_types.rb +0 -5
  354. data/test/stub/rails3.1/config/initializers/passenger.rb +0 -2
  355. data/test/stub/rails3.1/config/initializers/secret_token.rb +0 -7
  356. data/test/stub/rails3.1/config/initializers/session_store.rb +0 -8
  357. data/test/stub/rails3.1/config/initializers/wrap_parameters.rb +0 -14
  358. data/test/stub/rails3.1/config/locales/en.yml +0 -5
  359. data/test/stub/rails3.1/config/routes.rb +0 -58
  360. data/test/stub/rails3.1/db/seeds.rb +0 -7
  361. data/test/stub/rails3.1/doc/README_FOR_APP +0 -2
  362. data/test/stub/rails3.1/lib/assets/.gitkeep +0 -0
  363. data/test/stub/rails3.1/lib/tasks/.gitkeep +0 -0
  364. data/test/stub/rails3.1/log/.gitkeep +0 -0
  365. data/test/stub/rails3.1/public/404.html +0 -26
  366. data/test/stub/rails3.1/public/422.html +0 -26
  367. data/test/stub/rails3.1/public/500.html +0 -26
  368. data/test/stub/rails3.1/public/favicon.ico +0 -0
  369. data/test/stub/rails3.1/public/index.html +0 -241
  370. data/test/stub/rails3.1/public/robots.txt +0 -5
  371. data/test/stub/rails3.1/script/rails +0 -6
  372. data/test/stub/rails3.1/test/fixtures/.gitkeep +0 -0
  373. data/test/stub/rails3.1/test/functional/.gitkeep +0 -0
  374. data/test/stub/rails3.1/test/integration/.gitkeep +0 -0
  375. data/test/stub/rails3.1/test/performance/browsing_test.rb +0 -12
  376. data/test/stub/rails3.1/test/test_helper.rb +0 -13
  377. data/test/stub/rails3.1/test/unit/.gitkeep +0 -0
  378. data/test/stub/rails3.1/vendor/assets/stylesheets/.gitkeep +0 -0
  379. data/test/stub/rails3.1/vendor/plugins/.gitkeep +0 -0
  380. data/test/stub/rails3.2/.gitignore +0 -15
  381. data/test/stub/rails3.2/Gemfile +0 -39
  382. data/test/stub/rails3.2/Gemfile.lock +0 -113
  383. data/test/stub/rails3.2/Rakefile +0 -7
  384. data/test/stub/rails3.2/app/assets/images/rails.png +0 -0
  385. data/test/stub/rails3.2/app/assets/stylesheets/application.css +0 -13
  386. data/test/stub/rails3.2/app/controllers/application_controller.rb +0 -3
  387. data/test/stub/rails3.2/app/helpers/application_helper.rb +0 -2
  388. data/test/stub/rails3.2/app/mailers/.gitkeep +0 -0
  389. data/test/stub/rails3.2/app/models/.gitkeep +0 -0
  390. data/test/stub/rails3.2/app/views/layouts/application.html.erb +0 -14
  391. data/test/stub/rails3.2/config.ru +0 -4
  392. data/test/stub/rails3.2/config/application.rb +0 -62
  393. data/test/stub/rails3.2/config/boot.rb +0 -6
  394. data/test/stub/rails3.2/config/database.yml +0 -25
  395. data/test/stub/rails3.2/config/environment.rb +0 -5
  396. data/test/stub/rails3.2/config/environments/development.rb +0 -37
  397. data/test/stub/rails3.2/config/environments/production.rb +0 -67
  398. data/test/stub/rails3.2/config/environments/test.rb +0 -37
  399. data/test/stub/rails3.2/config/initializers/backtrace_silencers.rb +0 -7
  400. data/test/stub/rails3.2/config/initializers/inflections.rb +0 -15
  401. data/test/stub/rails3.2/config/initializers/mime_types.rb +0 -5
  402. data/test/stub/rails3.2/config/initializers/passenger.rb +0 -2
  403. data/test/stub/rails3.2/config/initializers/secret_token.rb +0 -7
  404. data/test/stub/rails3.2/config/initializers/session_store.rb +0 -8
  405. data/test/stub/rails3.2/config/initializers/wrap_parameters.rb +0 -14
  406. data/test/stub/rails3.2/config/locales/en.yml +0 -5
  407. data/test/stub/rails3.2/config/routes.rb +0 -58
  408. data/test/stub/rails3.2/db/seeds.rb +0 -7
  409. data/test/stub/rails3.2/doc/README_FOR_APP +0 -2
  410. data/test/stub/rails3.2/lib/assets/.gitkeep +0 -0
  411. data/test/stub/rails3.2/lib/tasks/.gitkeep +0 -0
  412. data/test/stub/rails3.2/log/.gitkeep +0 -0
  413. data/test/stub/rails3.2/public/404.html +0 -26
  414. data/test/stub/rails3.2/public/422.html +0 -26
  415. data/test/stub/rails3.2/public/500.html +0 -25
  416. data/test/stub/rails3.2/public/favicon.ico +0 -0
  417. data/test/stub/rails3.2/public/index.html +0 -241
  418. data/test/stub/rails3.2/public/robots.txt +0 -5
  419. data/test/stub/rails3.2/script/rails +0 -6
  420. data/test/stub/rails3.2/test/fixtures/.gitkeep +0 -0
  421. data/test/stub/rails3.2/test/functional/.gitkeep +0 -0
  422. data/test/stub/rails3.2/test/integration/.gitkeep +0 -0
  423. data/test/stub/rails3.2/test/performance/browsing_test.rb +0 -12
  424. data/test/stub/rails3.2/test/test_helper.rb +0 -13
  425. data/test/stub/rails3.2/test/unit/.gitkeep +0 -0
  426. data/test/stub/rails3.2/vendor/assets/stylesheets/.gitkeep +0 -0
  427. data/test/stub/rails3.2/vendor/plugins/.gitkeep +0 -0
  428. data/test/stub/rails4.0/.gitignore +0 -16
  429. data/test/stub/rails4.0/Gemfile +0 -45
  430. data/test/stub/rails4.0/Gemfile.lock +0 -126
  431. data/test/stub/rails4.0/README.rdoc +0 -28
  432. data/test/stub/rails4.0/Rakefile +0 -6
  433. data/test/stub/rails4.0/app/assets/images/.keep +0 -0
  434. data/test/stub/rails4.0/app/assets/javascripts/application.js +0 -16
  435. data/test/stub/rails4.0/app/assets/stylesheets/application.css +0 -13
  436. data/test/stub/rails4.0/app/controllers/application_controller.rb +0 -5
  437. data/test/stub/rails4.0/app/controllers/concerns/.keep +0 -0
  438. data/test/stub/rails4.0/app/helpers/application_helper.rb +0 -2
  439. data/test/stub/rails4.0/app/mailers/.keep +0 -0
  440. data/test/stub/rails4.0/app/models/.keep +0 -0
  441. data/test/stub/rails4.0/app/models/concerns/.keep +0 -0
  442. data/test/stub/rails4.0/app/views/layouts/application.html.erb +0 -14
  443. data/test/stub/rails4.0/bin/bundle +0 -3
  444. data/test/stub/rails4.0/bin/rails +0 -4
  445. data/test/stub/rails4.0/bin/rake +0 -4
  446. data/test/stub/rails4.0/config.ru +0 -4
  447. data/test/stub/rails4.0/config/application.rb +0 -23
  448. data/test/stub/rails4.0/config/boot.rb +0 -4
  449. data/test/stub/rails4.0/config/database.yml +0 -25
  450. data/test/stub/rails4.0/config/environment.rb +0 -5
  451. data/test/stub/rails4.0/config/environments/development.rb +0 -29
  452. data/test/stub/rails4.0/config/environments/production.rb +0 -80
  453. data/test/stub/rails4.0/config/environments/test.rb +0 -36
  454. data/test/stub/rails4.0/config/initializers/backtrace_silencers.rb +0 -7
  455. data/test/stub/rails4.0/config/initializers/filter_parameter_logging.rb +0 -4
  456. data/test/stub/rails4.0/config/initializers/inflections.rb +0 -16
  457. data/test/stub/rails4.0/config/initializers/mime_types.rb +0 -5
  458. data/test/stub/rails4.0/config/initializers/passenger.rb +0 -2
  459. data/test/stub/rails4.0/config/initializers/secret_token.rb +0 -12
  460. data/test/stub/rails4.0/config/initializers/session_store.rb +0 -3
  461. data/test/stub/rails4.0/config/initializers/wrap_parameters.rb +0 -14
  462. data/test/stub/rails4.0/config/locales/en.yml +0 -23
  463. data/test/stub/rails4.0/config/routes.rb +0 -57
  464. data/test/stub/rails4.0/db/seeds.rb +0 -7
  465. data/test/stub/rails4.0/lib/assets/.keep +0 -0
  466. data/test/stub/rails4.0/lib/tasks/.keep +0 -0
  467. data/test/stub/rails4.0/log/.keep +0 -0
  468. data/test/stub/rails4.0/public/404.html +0 -58
  469. data/test/stub/rails4.0/public/422.html +0 -58
  470. data/test/stub/rails4.0/public/500.html +0 -57
  471. data/test/stub/rails4.0/public/favicon.ico +0 -0
  472. data/test/stub/rails4.0/public/robots.txt +0 -5
  473. data/test/stub/rails4.0/test/controllers/.keep +0 -0
  474. data/test/stub/rails4.0/test/fixtures/.keep +0 -0
  475. data/test/stub/rails4.0/test/helpers/.keep +0 -0
  476. data/test/stub/rails4.0/test/integration/.keep +0 -0
  477. data/test/stub/rails4.0/test/mailers/.keep +0 -0
  478. data/test/stub/rails4.0/test/models/.keep +0 -0
  479. data/test/stub/rails4.0/test/test_helper.rb +0 -15
  480. data/test/stub/rails4.0/vendor/assets/javascripts/.keep +0 -0
  481. data/test/stub/rails4.0/vendor/assets/stylesheets/.keep +0 -0
  482. data/test/stub/rails4.1/.gitignore +0 -16
  483. data/test/stub/rails4.1/Gemfile +0 -45
  484. data/test/stub/rails4.1/Gemfile.lock +0 -129
  485. data/test/stub/rails4.1/README.rdoc +0 -28
  486. data/test/stub/rails4.1/Rakefile +0 -6
  487. data/test/stub/rails4.1/app/assets/images/.keep +0 -0
  488. data/test/stub/rails4.1/app/assets/javascripts/application.js +0 -16
  489. data/test/stub/rails4.1/app/assets/stylesheets/application.css +0 -13
  490. data/test/stub/rails4.1/app/controllers/application_controller.rb +0 -5
  491. data/test/stub/rails4.1/app/controllers/concerns/.keep +0 -0
  492. data/test/stub/rails4.1/app/helpers/application_helper.rb +0 -2
  493. data/test/stub/rails4.1/app/mailers/.keep +0 -0
  494. data/test/stub/rails4.1/app/models/.keep +0 -0
  495. data/test/stub/rails4.1/app/models/concerns/.keep +0 -0
  496. data/test/stub/rails4.1/app/views/layouts/application.html.erb +0 -14
  497. data/test/stub/rails4.1/bin/bundle +0 -3
  498. data/test/stub/rails4.1/bin/rails +0 -4
  499. data/test/stub/rails4.1/bin/rake +0 -4
  500. data/test/stub/rails4.1/config.ru +0 -4
  501. data/test/stub/rails4.1/config/application.rb +0 -23
  502. data/test/stub/rails4.1/config/boot.rb +0 -4
  503. data/test/stub/rails4.1/config/database.yml +0 -25
  504. data/test/stub/rails4.1/config/environment.rb +0 -5
  505. data/test/stub/rails4.1/config/environments/development.rb +0 -29
  506. data/test/stub/rails4.1/config/environments/production.rb +0 -80
  507. data/test/stub/rails4.1/config/environments/test.rb +0 -36
  508. data/test/stub/rails4.1/config/initializers/backtrace_silencers.rb +0 -7
  509. data/test/stub/rails4.1/config/initializers/filter_parameter_logging.rb +0 -4
  510. data/test/stub/rails4.1/config/initializers/inflections.rb +0 -16
  511. data/test/stub/rails4.1/config/initializers/mime_types.rb +0 -5
  512. data/test/stub/rails4.1/config/initializers/passenger.rb +0 -5
  513. data/test/stub/rails4.1/config/initializers/secret_token.rb +0 -12
  514. data/test/stub/rails4.1/config/initializers/session_store.rb +0 -3
  515. data/test/stub/rails4.1/config/initializers/wrap_parameters.rb +0 -14
  516. data/test/stub/rails4.1/config/locales/en.yml +0 -23
  517. data/test/stub/rails4.1/config/routes.rb +0 -57
  518. data/test/stub/rails4.1/db/seeds.rb +0 -7
  519. data/test/stub/rails4.1/lib/assets/.keep +0 -0
  520. data/test/stub/rails4.1/lib/tasks/.keep +0 -0
  521. data/test/stub/rails4.1/log/.keep +0 -0
  522. data/test/stub/rails4.1/public/404.html +0 -58
  523. data/test/stub/rails4.1/public/422.html +0 -58
  524. data/test/stub/rails4.1/public/500.html +0 -57
  525. data/test/stub/rails4.1/public/favicon.ico +0 -0
  526. data/test/stub/rails4.1/public/robots.txt +0 -5
  527. data/test/stub/rails4.1/test/controllers/.keep +0 -0
  528. data/test/stub/rails4.1/test/fixtures/.keep +0 -0
  529. data/test/stub/rails4.1/test/helpers/.keep +0 -0
  530. data/test/stub/rails4.1/test/integration/.keep +0 -0
  531. data/test/stub/rails4.1/test/mailers/.keep +0 -0
  532. data/test/stub/rails4.1/test/models/.keep +0 -0
  533. data/test/stub/rails4.1/test/test_helper.rb +0 -15
  534. data/test/stub/rails4.1/vendor/assets/javascripts/.keep +0 -0
  535. data/test/stub/rails4.1/vendor/assets/stylesheets/.keep +0 -0
  536. data/test/stub/start_error.pl +0 -24
  537. data/test/stub/upload_data.txt +0 -494
  538. data/test/stub/wsgi/passenger_wsgi.py +0 -212
  539. data/test/stub/wsgi/public/.gitignore +0 -0
  540. data/test/stub/wsgi/tmp/.gitignore +0 -0
  541. data/test/support/allocate_memory.c +0 -14
  542. data/test/support/apache2_controller.rb +0 -258
  543. data/test/support/multipart.rb +0 -62
  544. data/test/support/nginx_controller.rb +0 -97
  545. data/test/support/placebo-preloader.rb +0 -88
  546. data/test/support/test_helper.rb +0 -455
  547. data/test/support/valgrind.h +0 -2539
  548. data/test/tut/tut.h +0 -1310
  549. data/test/tut/tut_reporter.h +0 -256
  550. 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
- }