passenger 5.0.0.beta3 → 5.0.0.rc1

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 (218) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +11 -5
  5. data/CHANGELOG +38 -0
  6. data/CONTRIBUTING.md +1 -4
  7. data/Gemfile +0 -1
  8. data/Gemfile.lock +0 -2
  9. data/Rakefile +33 -33
  10. data/bin/passenger +1 -1
  11. data/bin/passenger-config +1 -1
  12. data/bin/passenger-install-apache2-module +800 -800
  13. data/bin/passenger-install-nginx-module +592 -592
  14. data/bin/passenger-memory-stats +127 -127
  15. data/bin/passenger-status +216 -216
  16. data/build/agents.rb +127 -127
  17. data/build/apache2.rb +87 -87
  18. data/build/basics.rb +60 -60
  19. data/build/common_library.rb +165 -165
  20. data/build/cplusplus_support.rb +51 -51
  21. data/build/cxx_tests.rb +268 -268
  22. data/build/debian.rb +143 -143
  23. data/build/documentation.rb +58 -58
  24. data/build/integration_tests.rb +81 -81
  25. data/build/misc.rb +132 -132
  26. data/build/nginx.rb +20 -20
  27. data/build/node_tests.rb +7 -7
  28. data/build/oxt_tests.rb +14 -14
  29. data/build/packaging.rb +570 -570
  30. data/build/preprocessor.rb +260 -260
  31. data/build/rake_extensions.rb +71 -71
  32. data/build/ruby_extension.rb +29 -29
  33. data/build/ruby_tests.rb +6 -6
  34. data/build/test_basics.rb +37 -37
  35. data/debian.template/control.template +3 -5
  36. data/dev/copy_boost_headers +134 -134
  37. data/dev/install_scripts_bootstrap_code.rb +25 -25
  38. data/dev/list_tests +20 -20
  39. data/dev/ruby_server.rb +223 -223
  40. data/dev/runner +18 -18
  41. data/doc/ServerOptimizationGuide.txt.md +55 -2
  42. data/doc/Users guide Nginx.txt +0 -26
  43. data/doc/Users guide Standalone.txt +5 -1
  44. data/doc/users_guide_snippets/tips.txt +9 -0
  45. data/ext/common/ApplicationPool2/Group.h +23 -11
  46. data/ext/common/ApplicationPool2/Implementation.cpp +32 -7
  47. data/ext/common/ApplicationPool2/Pool.h +22 -17
  48. data/ext/common/ApplicationPool2/SmartSpawner.h +4 -1
  49. data/ext/common/ApplicationPool2/Spawner.h +1 -1
  50. data/ext/common/Constants.h +1 -1
  51. data/ext/common/agents/Base.cpp +35 -20
  52. data/ext/common/agents/HelperAgent/Main.cpp +8 -1
  53. data/ext/common/agents/HelperAgent/OptionParser.h +18 -4
  54. data/ext/common/agents/HelperAgent/RequestHandler.h +2 -83
  55. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +54 -1
  56. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +7 -4
  57. data/ext/common/agents/Main.cpp +1 -1
  58. data/ext/common/agents/Watchdog/Main.cpp +54 -19
  59. data/ext/nginx/Configuration.c +7 -0
  60. data/ext/nginx/ContentHandler.c +9 -1
  61. data/helper-scripts/backtrace-sanitizer.rb +106 -87
  62. data/helper-scripts/crash-watch.rb +32 -0
  63. data/helper-scripts/download_binaries/extconf.rb +38 -38
  64. data/helper-scripts/meteor-loader.rb +107 -107
  65. data/helper-scripts/prespawn +101 -101
  66. data/helper-scripts/rack-loader.rb +96 -96
  67. data/helper-scripts/rack-preloader.rb +137 -137
  68. data/lib/phusion_passenger.rb +292 -292
  69. data/lib/phusion_passenger/abstract_installer.rb +438 -438
  70. data/lib/phusion_passenger/active_support3_extensions/init.rb +168 -170
  71. data/lib/phusion_passenger/admin_tools.rb +20 -20
  72. data/lib/phusion_passenger/admin_tools/instance.rb +178 -178
  73. data/lib/phusion_passenger/admin_tools/instance_registry.rb +61 -61
  74. data/lib/phusion_passenger/admin_tools/memory_stats.rb +267 -267
  75. data/lib/phusion_passenger/apache2/config_options.rb +182 -182
  76. data/lib/phusion_passenger/common_library.rb +479 -485
  77. data/lib/phusion_passenger/config/about_command.rb +161 -161
  78. data/lib/phusion_passenger/config/admin_command_command.rb +129 -129
  79. data/lib/phusion_passenger/config/agent_compiler.rb +121 -121
  80. data/lib/phusion_passenger/config/build_native_support_command.rb +43 -43
  81. data/lib/phusion_passenger/config/command.rb +25 -25
  82. data/lib/phusion_passenger/config/compile_agent_command.rb +62 -62
  83. data/lib/phusion_passenger/config/compile_nginx_engine_command.rb +88 -73
  84. data/lib/phusion_passenger/config/detach_process_command.rb +72 -72
  85. data/lib/phusion_passenger/config/download_agent_command.rb +246 -227
  86. data/lib/phusion_passenger/config/download_nginx_engine_command.rb +245 -224
  87. data/lib/phusion_passenger/config/install_agent_command.rb +144 -132
  88. data/lib/phusion_passenger/config/install_standalone_runtime_command.rb +205 -185
  89. data/lib/phusion_passenger/config/installation_utils.rb +204 -204
  90. data/lib/phusion_passenger/config/list_instances_command.rb +64 -64
  91. data/lib/phusion_passenger/config/main.rb +152 -152
  92. data/lib/phusion_passenger/config/nginx_engine_compiler.rb +319 -300
  93. data/lib/phusion_passenger/config/reopen_logs_command.rb +67 -67
  94. data/lib/phusion_passenger/config/restart_app_command.rb +155 -155
  95. data/lib/phusion_passenger/config/system_metrics_command.rb +13 -13
  96. data/lib/phusion_passenger/config/utils.rb +95 -95
  97. data/lib/phusion_passenger/config/validate_install_command.rb +198 -198
  98. data/lib/phusion_passenger/console_text_template.rb +25 -25
  99. data/lib/phusion_passenger/constants.rb +90 -90
  100. data/lib/phusion_passenger/debug_logging.rb +106 -106
  101. data/lib/phusion_passenger/loader_shared_helpers.rb +447 -432
  102. data/lib/phusion_passenger/message_channel.rb +312 -312
  103. data/lib/phusion_passenger/message_client.rb +176 -176
  104. data/lib/phusion_passenger/native_support.rb +369 -369
  105. data/lib/phusion_passenger/nginx/config_options.rb +297 -297
  106. data/lib/phusion_passenger/packaging.rb +131 -131
  107. data/lib/phusion_passenger/platform_info.rb +360 -360
  108. data/lib/phusion_passenger/platform_info/apache.rb +767 -767
  109. data/lib/phusion_passenger/platform_info/apache_detector.rb +199 -199
  110. data/lib/phusion_passenger/platform_info/binary_compatibility.rb +107 -107
  111. data/lib/phusion_passenger/platform_info/compiler.rb +570 -570
  112. data/lib/phusion_passenger/platform_info/curl.rb +32 -32
  113. data/lib/phusion_passenger/platform_info/cxx_portability.rb +188 -188
  114. data/lib/phusion_passenger/platform_info/depcheck.rb +372 -372
  115. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +109 -109
  116. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +4 -4
  117. data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +10 -34
  118. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +101 -101
  119. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +5 -5
  120. data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +13 -13
  121. data/lib/phusion_passenger/platform_info/linux.rb +55 -55
  122. data/lib/phusion_passenger/platform_info/operating_system.rb +149 -149
  123. data/lib/phusion_passenger/platform_info/ruby.rb +468 -448
  124. data/lib/phusion_passenger/platform_info/zlib.rb +9 -9
  125. data/lib/phusion_passenger/plugin.rb +66 -66
  126. data/lib/phusion_passenger/preloader_shared_helpers.rb +126 -126
  127. data/lib/phusion_passenger/public_api.rb +191 -191
  128. data/lib/phusion_passenger/rack/out_of_band_gc.rb +93 -94
  129. data/lib/phusion_passenger/rack/thread_handler_extension.rb +231 -227
  130. data/lib/phusion_passenger/request_handler.rb +567 -577
  131. data/lib/phusion_passenger/request_handler/thread_handler.rb +379 -381
  132. data/lib/phusion_passenger/ruby_core_enhancements.rb +86 -86
  133. data/lib/phusion_passenger/ruby_core_io_enhancements.rb +74 -74
  134. data/lib/phusion_passenger/simple_benchmarking.rb +25 -25
  135. data/lib/phusion_passenger/standalone/app_finder.rb +153 -150
  136. data/lib/phusion_passenger/standalone/command.rb +44 -40
  137. data/lib/phusion_passenger/standalone/config_utils.rb +53 -53
  138. data/lib/phusion_passenger/standalone/control_utils.rb +38 -59
  139. data/lib/phusion_passenger/standalone/main.rb +73 -73
  140. data/lib/phusion_passenger/standalone/start_command.rb +697 -685
  141. data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +193 -155
  142. data/lib/phusion_passenger/standalone/start_command/nginx_engine.rb +162 -133
  143. data/lib/phusion_passenger/standalone/status_command.rb +64 -64
  144. data/lib/phusion_passenger/standalone/stop_command.rb +72 -72
  145. data/lib/phusion_passenger/standalone/version_command.rb +9 -9
  146. data/lib/phusion_passenger/union_station/connection.rb +32 -32
  147. data/lib/phusion_passenger/union_station/core.rb +251 -251
  148. data/lib/phusion_passenger/union_station/transaction.rb +126 -126
  149. data/lib/phusion_passenger/utils.rb +199 -167
  150. data/lib/phusion_passenger/utils/ansi_colors.rb +128 -128
  151. data/lib/phusion_passenger/utils/download.rb +196 -196
  152. data/lib/phusion_passenger/utils/file_system_watcher.rb +158 -158
  153. data/lib/phusion_passenger/utils/hosts_file_parser.rb +101 -101
  154. data/lib/phusion_passenger/utils/lock.rb +31 -31
  155. data/lib/phusion_passenger/utils/native_support_utils.rb +31 -31
  156. data/lib/phusion_passenger/utils/progress_bar.rb +26 -26
  157. data/lib/phusion_passenger/utils/shellwords.rb +20 -20
  158. data/lib/phusion_passenger/utils/terminal_choice_menu.rb +206 -206
  159. data/lib/phusion_passenger/utils/unseekable_socket.rb +272 -272
  160. data/lib/phusion_passenger/vendor/crash_watch/app.rb +129 -0
  161. data/lib/phusion_passenger/vendor/crash_watch/gdb_controller.rb +341 -0
  162. data/lib/phusion_passenger/vendor/crash_watch/version.rb +24 -0
  163. data/lib/phusion_passenger/vendor/daemon_controller.rb +877 -0
  164. data/lib/phusion_passenger/vendor/daemon_controller/lock_file.rb +127 -0
  165. data/lib/phusion_passenger/vendor/daemon_controller/spawn.rb +26 -0
  166. data/lib/phusion_passenger/vendor/daemon_controller/version.rb +29 -0
  167. data/packaging/rpm/passenger_spec/passenger.spec.template +0 -1
  168. data/passenger.gemspec +0 -1
  169. data/resources/templates/config/nginx_engine_compiler/possible_solutions_for_download_and_extraction_problems.txt.erb +27 -0
  170. data/resources/templates/standalone/config.erb +19 -15
  171. data/test/integration_tests/apache2_tests.rb +566 -566
  172. data/test/integration_tests/downloaded_binaries_tests.rb +126 -125
  173. data/test/integration_tests/native_packaging_spec.rb +296 -296
  174. data/test/integration_tests/nginx_tests.rb +393 -393
  175. data/test/integration_tests/shared/example_webapp_tests.rb +282 -280
  176. data/test/integration_tests/source_packaging_test.rb +138 -138
  177. data/test/integration_tests/spec_helper.rb +5 -5
  178. data/test/integration_tests/standalone_tests.rb +367 -367
  179. data/test/ruby/debug_logging_spec.rb +133 -133
  180. data/test/ruby/message_channel_spec.rb +186 -186
  181. data/test/ruby/rack/loader_spec.rb +28 -28
  182. data/test/ruby/rack/preloader_spec.rb +34 -34
  183. data/test/ruby/rails3.0/loader_spec.rb +12 -12
  184. data/test/ruby/rails3.0/preloader_spec.rb +18 -18
  185. data/test/ruby/rails3.1/loader_spec.rb +12 -12
  186. data/test/ruby/rails3.1/preloader_spec.rb +18 -18
  187. data/test/ruby/rails3.2/loader_spec.rb +12 -12
  188. data/test/ruby/rails3.2/preloader_spec.rb +18 -18
  189. data/test/ruby/rails4.0/loader_spec.rb +12 -12
  190. data/test/ruby/rails4.0/preloader_spec.rb +18 -18
  191. data/test/ruby/rails4.1/loader_spec.rb +12 -12
  192. data/test/ruby/rails4.1/preloader_spec.rb +18 -18
  193. data/test/ruby/request_handler_spec.rb +730 -730
  194. data/test/ruby/shared/loader_sharedspec.rb +224 -224
  195. data/test/ruby/shared/rails/union_station_extensions_sharedspec.rb +327 -327
  196. data/test/ruby/shared/ruby_loader_sharedspec.rb +47 -47
  197. data/test/ruby/spec_helper.rb +65 -65
  198. data/test/ruby/standalone/runtime_installer_spec.rb +384 -384
  199. data/test/ruby/union_station_spec.rb +276 -276
  200. data/test/ruby/utils/file_system_watcher_spec.rb +220 -220
  201. data/test/ruby/utils/hosts_file_parser.rb +248 -248
  202. data/test/ruby/utils/tee_input_spec.rb +215 -215
  203. data/test/ruby/utils/unseekable_socket_spec.rb +57 -57
  204. data/test/ruby/utils_spec.rb +21 -21
  205. data/test/stub/rack/config.ru +87 -87
  206. data/test/stub/rack/library.rb +8 -8
  207. data/test/stub/rack/start.rb +30 -30
  208. data/test/support/apache2_controller.rb +191 -191
  209. data/test/support/nginx_controller.rb +90 -99
  210. data/test/support/placebo-preloader.rb +57 -57
  211. data/test/support/test_helper.rb +435 -435
  212. metadata +11 -21
  213. metadata.gz.asc +7 -7
  214. data/lib/phusion_passenger/standalone/command2.rb +0 -292
  215. data/lib/phusion_passenger/standalone/start2_command.rb +0 -799
  216. data/resources/templates/standalone/download_tool_missing.txt.erb +0 -18
  217. data/resources/templates/standalone/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -17
  218. data/resources/templates/standalone/run_installer_as_root.txt.erb +0 -8
@@ -4,226 +4,226 @@ PhusionPassenger.require_passenger_lib 'utils/file_system_watcher'
4
4
  module PhusionPassenger
5
5
 
6
6
  describe Utils::FileSystemWatcher do
7
- before :each do
8
- @tmpdir = "tmp.fs_watcher"
9
- @tmpdir2 = "tmp.fs_watcher2"
10
- @tmpdir3 = "tmp.fs_watcher3"
11
- @term_pipe = IO.pipe
12
- [@tmpdir, @tmpdir2, @tmpdir3].each do |dir|
13
- remove_dir_tree(dir)
14
- Dir.mkdir(dir)
15
- end
16
- end
17
-
18
- after :each do
19
- if @thread
20
- @term_pipe[1].write("x")
21
- @thread.join
22
- end
23
- @watcher.close if @watcher
24
- @term_pipe[0].close
25
- @term_pipe[1].close
26
- [@tmpdir, @tmpdir2, @tmpdir3].each do |dir|
27
- remove_dir_tree(dir)
28
- end
29
- end
30
-
31
- def create(*args)
32
- @watcher = Utils::FileSystemWatcher.new(*args)
33
- @watcher.poll_interval = 0.1 if @watcher.respond_to?(:poll_interval=)
34
- return @watcher
35
- end
36
-
37
- describe "#wait_for_change blocks until" do
38
- def test_block(filenames)
39
- create(filenames, @term_pipe[0])
40
- result = nil
41
- thread = Thread.new do
42
- result = @watcher.wait_for_change
43
- end
44
- yield if block_given?
45
- eventually do
46
- !thread.alive?
47
- end
48
- return result
49
- ensure
50
- if thread
51
- @term_pipe[1].write("x")
52
- thread.join
53
- end
54
- @watcher.close
55
- end
56
-
57
- specify "a subdirectory has been created in one of the watched directories" do
58
- result = test_block([@tmpdir, @tmpdir2]) do
59
- Dir.mkdir("#{@tmpdir}/foo")
60
- end
61
- result.should be_true
62
- end
63
-
64
- specify "a subdirectory has been removed in one of the watched directories" do
65
- Dir.mkdir("#{@tmpdir2}/foo")
66
- result = test_block([@tmpdir, @tmpdir2]) do
67
- Dir.rmdir("#{@tmpdir2}/foo")
68
- end
69
- result.should be_true
70
- end
71
-
72
- specify "a subdirectory has been renamed in one of the watched directories" do
73
- Dir.mkdir("#{@tmpdir}/foo")
74
- result = test_block([@tmpdir, @tmpdir2]) do
75
- File.rename("#{@tmpdir}/foo", "#{@tmpdir3}/bar")
76
- end
77
- result.should be_true
78
- end
79
-
80
- specify "a file has been created in one of the watched directories" do
81
- result = test_block([@tmpdir, @tmpdir2]) do
82
- File.touch("#{@tmpdir}/foo")
83
- end
84
- result.should be_true
85
- end
86
-
87
- specify "a file has been removed in one of the watched directories" do
88
- File.touch("#{@tmpdir2}/foo")
89
- result = test_block([@tmpdir, @tmpdir2]) do
90
- File.unlink("#{@tmpdir2}/foo")
91
- end
92
- result.should be_true
93
- end
94
-
95
- specify "a file has been renamed in one of the watched directories" do
96
- File.touch("#{@tmpdir}/foo")
97
- result = test_block([@tmpdir, @tmpdir2]) do
98
- File.rename("#{@tmpdir}/foo", "#{@tmpdir3}/bar")
99
- end
100
- result.should be_true
101
- end
102
-
103
- specify "a watched file has been written to" do
104
- File.touch("#{@tmpdir}/foo")
105
- result = test_block(["#{@tmpdir}/foo"]) do
106
- File.write("#{@tmpdir}/foo", "bar")
107
- end
108
- end
109
-
110
- specify "a watched file has been truncated" do
111
- File.write("#{@tmpdir}/foo", "contents")
112
- result = test_block(["#{@tmpdir}/foo"]) do
113
- if RUBY_PLATFORM =~ /darwin/
114
- # OS X kernel bug in kqueue... sigh...
115
- File.open("#{@tmpdir}/foo", "w") do |f|
116
- f.write("a")
117
- f.truncate(0)
118
- end
119
- else
120
- File.open("#{@tmpdir}/foo", "w").close
121
- end
122
- end
123
- end
124
-
125
- specify "a watched file has been removed" do
126
- File.touch("#{@tmpdir}/foo")
127
- result = test_block(["#{@tmpdir}/foo"]) do
128
- File.unlink("#{@tmpdir}/foo")
129
- end
130
- end
131
-
132
- specify "a watched file has been renamed" do
133
- File.touch("#{@tmpdir}/foo")
134
- result = test_block(["#{@tmpdir}/foo"]) do
135
- File.rename("#{@tmpdir}/foo", "#{@tmpdir}/bar")
136
- end
137
- end
138
-
139
- specify "the termination pipe became readable" do
140
- result = test_block([@tmpdir]) do
141
- @term_pipe[1].write("x")
142
- end
143
- result.should be_nil
144
- end
145
-
146
- specify "one of the watched files or directories could not be statted while constructing the object" do
147
- test_block([@tmpdir, "#{@tmpdir}/foo"]).should be_false
148
-
149
- when_not_running_as_root do
150
- Dir.mkdir("#{@tmpdir}/foo")
151
- File.touch("#{@tmpdir}/foo/file")
152
- Dir.mkdir("#{@tmpdir}/foo/dir")
153
- File.chmod(0000, "#{@tmpdir}/foo")
154
-
155
- test_block([@tmpdir, "#{@tmpdir}/foo/file"]).should be_false
156
- test_block([@tmpdir, "#{@tmpdir}/foo/dir"]).should be_false
157
- end
158
- end
159
-
160
- if Utils::FileSystemWatcher.opens_files?
161
- when_not_running_as_root do
162
- specify "one of the watched files or directories could not be opened while constructing the object" do
163
- File.touch("#{@tmpdir}/file")
164
- File.chmod(0000, "#{@tmpdir}/file")
165
- test_block([@tmpdir, "#{@tmpdir}/file"]).should be_false
166
-
167
- Dir.mkdir("#{@tmpdir}/dir")
168
- File.chmod(0000, "#{@tmpdir}/dir")
169
- test_block([@tmpdir, "#{@tmpdir}/dir"]).should be_false
170
- end
171
- end
172
- end # if
173
- end
174
-
175
- describe "#wait_for_change does not return if" do
176
- def test_block(filenames)
177
- create(filenames, @term_pipe[0])
178
- @thread = Thread.new do
179
- @watcher.wait_for_change
180
- end
181
- yield
182
- should_never_happen(0.4) do
183
- !@thread.alive?
184
- end
185
- end
186
-
187
- specify "nothing happened in one of its watched files or directories" do
188
- test_block([@tmpdir, @tmpdir2]) do
189
- File.touch("#{@tmpdir3}/file")
190
- Dir.mkdir("#{@tmpdir3}/dir")
191
- end
192
- end
193
-
194
- specify "something happened in a subdirectory that isn't on the watch list" do
195
- # In other words it does not watch subdirectories recursively.
196
- Dir.mkdir("#{@tmpdir}/subdir")
197
- test_block([@tmpdir, @tmpdir2]) do
198
- File.touch("#{@tmpdir}/subdir/file")
199
- end
200
- end
201
-
202
- specify "a file in a watched directory is merely modified" do
203
- File.touch("#{@tmpdir}/hello", 10)
204
- test_block([@tmpdir, @tmpdir2]) do
205
- File.touch("#{@tmpdir}/hello", 4567)
206
- File.write("#{@tmpdir}/hello", "foobar")
207
- end
208
- end
209
- end
210
-
211
- specify "#wait_for_change notices events that have occurred after object construction but before #wait_for_change has been called" do
212
- create([@tmpdir, @tmpdir2], @term_pipe[0])
213
- @thread = Thread.new do
214
- @watcher.wait_for_change
215
- end
216
- File.touch("#{@tmpdir}/foo", Time.now - 10)
217
- eventually do
218
- !@thread.alive?
219
- end
220
- end
221
-
222
- it "can be closed multiple times" do
223
- create([@tmpdir])
224
- @watcher.close
225
- @watcher.close
226
- end
7
+ before :each do
8
+ @tmpdir = "tmp.fs_watcher"
9
+ @tmpdir2 = "tmp.fs_watcher2"
10
+ @tmpdir3 = "tmp.fs_watcher3"
11
+ @term_pipe = IO.pipe
12
+ [@tmpdir, @tmpdir2, @tmpdir3].each do |dir|
13
+ remove_dir_tree(dir)
14
+ Dir.mkdir(dir)
15
+ end
16
+ end
17
+
18
+ after :each do
19
+ if @thread
20
+ @term_pipe[1].write("x")
21
+ @thread.join
22
+ end
23
+ @watcher.close if @watcher
24
+ @term_pipe[0].close
25
+ @term_pipe[1].close
26
+ [@tmpdir, @tmpdir2, @tmpdir3].each do |dir|
27
+ remove_dir_tree(dir)
28
+ end
29
+ end
30
+
31
+ def create(*args)
32
+ @watcher = Utils::FileSystemWatcher.new(*args)
33
+ @watcher.poll_interval = 0.1 if @watcher.respond_to?(:poll_interval=)
34
+ return @watcher
35
+ end
36
+
37
+ describe "#wait_for_change blocks until" do
38
+ def test_block(filenames)
39
+ create(filenames, @term_pipe[0])
40
+ result = nil
41
+ thread = Thread.new do
42
+ result = @watcher.wait_for_change
43
+ end
44
+ yield if block_given?
45
+ eventually do
46
+ !thread.alive?
47
+ end
48
+ return result
49
+ ensure
50
+ if thread
51
+ @term_pipe[1].write("x")
52
+ thread.join
53
+ end
54
+ @watcher.close
55
+ end
56
+
57
+ specify "a subdirectory has been created in one of the watched directories" do
58
+ result = test_block([@tmpdir, @tmpdir2]) do
59
+ Dir.mkdir("#{@tmpdir}/foo")
60
+ end
61
+ result.should be_true
62
+ end
63
+
64
+ specify "a subdirectory has been removed in one of the watched directories" do
65
+ Dir.mkdir("#{@tmpdir2}/foo")
66
+ result = test_block([@tmpdir, @tmpdir2]) do
67
+ Dir.rmdir("#{@tmpdir2}/foo")
68
+ end
69
+ result.should be_true
70
+ end
71
+
72
+ specify "a subdirectory has been renamed in one of the watched directories" do
73
+ Dir.mkdir("#{@tmpdir}/foo")
74
+ result = test_block([@tmpdir, @tmpdir2]) do
75
+ File.rename("#{@tmpdir}/foo", "#{@tmpdir3}/bar")
76
+ end
77
+ result.should be_true
78
+ end
79
+
80
+ specify "a file has been created in one of the watched directories" do
81
+ result = test_block([@tmpdir, @tmpdir2]) do
82
+ File.touch("#{@tmpdir}/foo")
83
+ end
84
+ result.should be_true
85
+ end
86
+
87
+ specify "a file has been removed in one of the watched directories" do
88
+ File.touch("#{@tmpdir2}/foo")
89
+ result = test_block([@tmpdir, @tmpdir2]) do
90
+ File.unlink("#{@tmpdir2}/foo")
91
+ end
92
+ result.should be_true
93
+ end
94
+
95
+ specify "a file has been renamed in one of the watched directories" do
96
+ File.touch("#{@tmpdir}/foo")
97
+ result = test_block([@tmpdir, @tmpdir2]) do
98
+ File.rename("#{@tmpdir}/foo", "#{@tmpdir3}/bar")
99
+ end
100
+ result.should be_true
101
+ end
102
+
103
+ specify "a watched file has been written to" do
104
+ File.touch("#{@tmpdir}/foo")
105
+ result = test_block(["#{@tmpdir}/foo"]) do
106
+ File.write("#{@tmpdir}/foo", "bar")
107
+ end
108
+ end
109
+
110
+ specify "a watched file has been truncated" do
111
+ File.write("#{@tmpdir}/foo", "contents")
112
+ result = test_block(["#{@tmpdir}/foo"]) do
113
+ if RUBY_PLATFORM =~ /darwin/
114
+ # OS X kernel bug in kqueue... sigh...
115
+ File.open("#{@tmpdir}/foo", "w") do |f|
116
+ f.write("a")
117
+ f.truncate(0)
118
+ end
119
+ else
120
+ File.open("#{@tmpdir}/foo", "w").close
121
+ end
122
+ end
123
+ end
124
+
125
+ specify "a watched file has been removed" do
126
+ File.touch("#{@tmpdir}/foo")
127
+ result = test_block(["#{@tmpdir}/foo"]) do
128
+ File.unlink("#{@tmpdir}/foo")
129
+ end
130
+ end
131
+
132
+ specify "a watched file has been renamed" do
133
+ File.touch("#{@tmpdir}/foo")
134
+ result = test_block(["#{@tmpdir}/foo"]) do
135
+ File.rename("#{@tmpdir}/foo", "#{@tmpdir}/bar")
136
+ end
137
+ end
138
+
139
+ specify "the termination pipe became readable" do
140
+ result = test_block([@tmpdir]) do
141
+ @term_pipe[1].write("x")
142
+ end
143
+ result.should be_nil
144
+ end
145
+
146
+ specify "one of the watched files or directories could not be statted while constructing the object" do
147
+ test_block([@tmpdir, "#{@tmpdir}/foo"]).should be_false
148
+
149
+ when_not_running_as_root do
150
+ Dir.mkdir("#{@tmpdir}/foo")
151
+ File.touch("#{@tmpdir}/foo/file")
152
+ Dir.mkdir("#{@tmpdir}/foo/dir")
153
+ File.chmod(0000, "#{@tmpdir}/foo")
154
+
155
+ test_block([@tmpdir, "#{@tmpdir}/foo/file"]).should be_false
156
+ test_block([@tmpdir, "#{@tmpdir}/foo/dir"]).should be_false
157
+ end
158
+ end
159
+
160
+ if Utils::FileSystemWatcher.opens_files?
161
+ when_not_running_as_root do
162
+ specify "one of the watched files or directories could not be opened while constructing the object" do
163
+ File.touch("#{@tmpdir}/file")
164
+ File.chmod(0000, "#{@tmpdir}/file")
165
+ test_block([@tmpdir, "#{@tmpdir}/file"]).should be_false
166
+
167
+ Dir.mkdir("#{@tmpdir}/dir")
168
+ File.chmod(0000, "#{@tmpdir}/dir")
169
+ test_block([@tmpdir, "#{@tmpdir}/dir"]).should be_false
170
+ end
171
+ end
172
+ end # if
173
+ end
174
+
175
+ describe "#wait_for_change does not return if" do
176
+ def test_block(filenames)
177
+ create(filenames, @term_pipe[0])
178
+ @thread = Thread.new do
179
+ @watcher.wait_for_change
180
+ end
181
+ yield
182
+ should_never_happen(0.4) do
183
+ !@thread.alive?
184
+ end
185
+ end
186
+
187
+ specify "nothing happened in one of its watched files or directories" do
188
+ test_block([@tmpdir, @tmpdir2]) do
189
+ File.touch("#{@tmpdir3}/file")
190
+ Dir.mkdir("#{@tmpdir3}/dir")
191
+ end
192
+ end
193
+
194
+ specify "something happened in a subdirectory that isn't on the watch list" do
195
+ # In other words it does not watch subdirectories recursively.
196
+ Dir.mkdir("#{@tmpdir}/subdir")
197
+ test_block([@tmpdir, @tmpdir2]) do
198
+ File.touch("#{@tmpdir}/subdir/file")
199
+ end
200
+ end
201
+
202
+ specify "a file in a watched directory is merely modified" do
203
+ File.touch("#{@tmpdir}/hello", 10)
204
+ test_block([@tmpdir, @tmpdir2]) do
205
+ File.touch("#{@tmpdir}/hello", 4567)
206
+ File.write("#{@tmpdir}/hello", "foobar")
207
+ end
208
+ end
209
+ end
210
+
211
+ specify "#wait_for_change notices events that have occurred after object construction but before #wait_for_change has been called" do
212
+ create([@tmpdir, @tmpdir2], @term_pipe[0])
213
+ @thread = Thread.new do
214
+ @watcher.wait_for_change
215
+ end
216
+ File.touch("#{@tmpdir}/foo", Time.now - 10)
217
+ eventually do
218
+ !@thread.alive?
219
+ end
220
+ end
221
+
222
+ it "can be closed multiple times" do
223
+ create([@tmpdir])
224
+ @watcher.close
225
+ @watcher.close
226
+ end
227
227
  end
228
228
 
229
229
  end # module PhusionPassenger
@@ -5,254 +5,254 @@ require 'stringio'
5
5
  module PhusionPassenger
6
6
 
7
7
  describe Utils::HostsFileParser do
8
- before :each do
9
- @io = StringIO.new
10
- end
11
-
12
- def create
13
- @io.rewind
14
- @parser = Utils::HostsFileParser.new(@io)
15
- end
16
-
17
- describe "parsing" do
18
- it "ignores comments" do
19
- @io.puts("# 127.0.0.1 foo.com")
20
- create
21
- @parser.ip_count.should == 0
22
- @parser.host_count.should == 0
23
- end
24
-
25
- it "ignores comments that come after leading spaces" do
26
- @io.puts(" # 127.0.0.1 foo.com")
27
- create
28
- @parser.ip_count.should == 0
29
- @parser.host_count.should == 0
30
- end
31
-
32
- it "ignores comments that come after leading tabs" do
33
- @io.puts("\t# 127.0.0.1 foo.com")
34
- create
35
- @parser.ip_count.should == 0
36
- @parser.host_count.should == 0
37
- end
38
-
39
- it "ignores empty lines" do
40
- @io.puts("127.0.0.1 foo.com")
41
- @io.puts
42
- @io.puts("127.0.0.1 bar.com")
43
- @io.puts("127.0.0.2 baz.com")
44
- create
45
- @parser.ip_count.should == 2
46
- @parser.host_count.should == 3
47
- end
48
-
49
- it "ignores leading and trailing spaces" do
50
- @io.puts(" 127.0.0.1 foo.com")
51
- @io.puts
52
- @io.puts(" 127.0.0.1 bar.com ")
53
- @io.puts("127.0.0.2 baz.com ")
54
- create
55
- @parser.ip_count.should == 2
56
- @parser.host_count.should == 3
57
- @parser.resolve("foo.com").should == "127.0.0.1"
58
- @parser.resolve("bar.com").should == "127.0.0.1"
59
- @parser.resolve("baz.com").should == "127.0.0.2"
60
- end
61
-
62
- it "ignores leading and trailing tabs" do
63
- @io.puts("\t\t127.0.0.1 foo.com")
64
- @io.puts
65
- @io.puts("\t127.0.0.1 bar.com\t")
66
- @io.puts("127.0.0.2 baz.com\t\t")
67
- create
68
- @parser.ip_count.should == 2
69
- @parser.host_count.should == 3
70
- @parser.resolve("foo.com").should == "127.0.0.1"
71
- @parser.resolve("bar.com").should == "127.0.0.1"
72
- @parser.resolve("baz.com").should == "127.0.0.2"
73
- end
74
-
75
- it "correctly handles spaces as seperators" do
76
- @io.puts("127.0.0.1 foo.com bar.com baz.com")
77
- create
78
- @parser.ip_count.should == 1
79
- @parser.host_count.should == 3
80
- @parser.resolve("foo.com").should == "127.0.0.1"
81
- @parser.resolve("bar.com").should == "127.0.0.1"
82
- @parser.resolve("baz.com").should == "127.0.0.1"
83
- end
84
-
85
- it "correctly handles tabs as seperators" do
86
- @io.puts("127.0.0.1\tfoo.com\t\tbar.com baz.com")
87
- create
88
- @parser.ip_count.should == 1
89
- @parser.host_count.should == 3
90
- @parser.resolve("foo.com").should == "127.0.0.1"
91
- @parser.resolve("bar.com").should == "127.0.0.1"
92
- @parser.resolve("baz.com").should == "127.0.0.1"
93
- end
94
- end
95
-
96
- describe "#resolve" do
97
- it "returns nil if the host name is not in the file" do
98
- @io.puts("127.0.0.1 foo.com")
99
- create
100
- @parser.resolve("bar.com").should be_nil
101
- end
102
-
103
- it "returns the IP address associated with the host name if it exists" do
104
- @io.puts("255.255.255.255 foo.com")
105
- create
106
- @parser.resolve("foo.com").should == "255.255.255.255"
107
- end
108
-
109
- it "is case-insensitive" do
110
- @io.puts("255.255.255.255 fOO.com")
111
- create
112
- @parser.resolve("foo.COM").should == "255.255.255.255"
113
- end
114
-
115
- it "correctly handles lines that contain multiple host names" do
116
- @io.puts("255.255.255.255 foo.com bar.com")
117
- create
118
- @parser.resolve("foo.com").should == "255.255.255.255"
119
- @parser.resolve("bar.com").should == "255.255.255.255"
120
- @parser.resolve("baz.com").should be_nil
121
- end
122
-
123
- it "always returns 127.0.0.1 for localhost" do
124
- create
125
- @parser.resolve("localhost").should == "127.0.0.1"
126
- @parser.resolve("localHOST").should == "127.0.0.1"
127
- end
128
- end
129
-
130
- describe "#resolves_to_localhost?" do
131
- before :each do
132
- @io.puts "127.0.0.1 kotori"
133
- @io.puts "192.168.0.1 kanako"
134
- @io.puts "::1 ageha"
135
- @io.puts "::2 sawako"
136
- @io.puts "0.0.0.0 mizusawa"
137
- create
138
- end
139
-
140
- it "returns true if the host name resolves to 127.0.0.1" do
141
- @parser.resolves_to_localhost?("kotori").should be_true
142
- end
143
-
144
- it "returns true if the host name resolves to ::1" do
145
- @parser.resolves_to_localhost?("ageha").should be_true
146
- end
147
-
148
- it "returns true if the host name resolves to 0.0.0.0" do
149
- @parser.resolves_to_localhost?("mizusawa").should be_true
150
- end
151
-
152
- it "returns false if the host name resolves to something else" do
153
- @parser.resolves_to_localhost?("sawako").should be_false
154
- @parser.resolves_to_localhost?("kanako").should be_false
155
- end
156
-
157
- it "returns false if the host name does not resolve" do
158
- @parser.resolves_to_localhost?("foo.com").should be_false
159
- end
160
- end
161
-
162
- describe "#add_group_data" do
163
- before :each do
164
- @standard_entries =
165
- "127.0.0.1 kotori hazuki\n" +
166
- " 192.168.0.1 kanako\n\n" +
167
- "\t::1 ageha sawako\n" +
168
- "0.0.0.0 mizusawa naru\n"
169
- @target = StringIO.new
170
- end
171
-
172
- it "adds the group data if it doesn't exist" do
173
- @io.puts @standard_entries
174
- create
175
-
176
- @parser.add_group_data("some marker",
177
- "# a comment\n" +
178
- "127.0.0.1 foo\n")
179
- @parser.write(@target)
180
- @target.string.should ==
181
- @standard_entries +
182
- "###### BEGIN some marker ######\n" +
183
- "# a comment\n" +
184
- "127.0.0.1 foo\n" +
185
- "###### END some marker ######\n"
186
- end
187
-
188
- it "replaces the existing group data if it does exist" do
189
- @io.puts "###### BEGIN some marker ######\n" +
190
- "# another comment\n" +
191
- "127.0.0.1 bar\n" +
192
- "###### END some marker ######\n" +
193
- "\n" +
194
- @standard_entries +
195
- "###### BEGIN some other marker ######\n" +
196
- "# another comment\n" +
197
- "127.0.0.1 bar\n" +
198
- "###### END some other marker ######\n"
199
- create
200
-
201
- @parser.add_group_data("some marker", "127.0.0.1 foo\n")
202
- @parser.write(@target)
203
- @target.string.should ==
204
- "###### BEGIN some marker ######\n" +
205
- "127.0.0.1 foo\n" +
206
- "###### END some marker ######\n" +
207
- "\n" +
208
- @standard_entries +
209
- "###### BEGIN some other marker ######\n" +
210
- "# another comment\n" +
211
- "127.0.0.1 bar\n" +
212
- "###### END some other marker ######\n"
213
- end
214
-
215
- it "correctly handles the lack of a terminating newline in the group data" do
216
- @io.puts @standard_entries
217
- create
218
-
219
- @parser.add_group_data("some marker",
220
- "# a comment\n" +
221
- "127.0.0.1 foo")
222
- @parser.write(@target)
223
- @target.string.should ==
224
- @standard_entries +
225
- "###### BEGIN some marker ######\n" +
226
- "# a comment\n" +
227
- "127.0.0.1 foo\n" +
228
- "###### END some marker ######\n"
229
- end
230
-
231
- it "ensures that the group data starts at a new line" do
232
- @io.write "127.0.0.1 foo.com"
233
- create
234
- @parser.add_group_data("some marker", "127.0.0.1 bar.com")
235
- @parser.write(@target)
236
- @target.string.should ==
237
- "127.0.0.1 foo.com\n" +
238
- "###### BEGIN some marker ######\n" +
239
- "127.0.0.1 bar.com\n" +
240
- "###### END some marker ######\n"
241
- end
242
- end
243
-
244
- describe "#write" do
245
- it "preserves all comments and leading and trailing whitespaces" do
246
- @io.puts "127.0.0.1 foo.com "
247
- @io.puts "# a comment"
248
- @io.puts "\t127.0.0.1 bar.com\t"
249
- create
250
- original_data = @io.string
251
- target = StringIO.new
252
- @parser.write(target)
253
- target.string.should == original_data
254
- end
255
- end
8
+ before :each do
9
+ @io = StringIO.new
10
+ end
11
+
12
+ def create
13
+ @io.rewind
14
+ @parser = Utils::HostsFileParser.new(@io)
15
+ end
16
+
17
+ describe "parsing" do
18
+ it "ignores comments" do
19
+ @io.puts("# 127.0.0.1 foo.com")
20
+ create
21
+ @parser.ip_count.should == 0
22
+ @parser.host_count.should == 0
23
+ end
24
+
25
+ it "ignores comments that come after leading spaces" do
26
+ @io.puts(" # 127.0.0.1 foo.com")
27
+ create
28
+ @parser.ip_count.should == 0
29
+ @parser.host_count.should == 0
30
+ end
31
+
32
+ it "ignores comments that come after leading tabs" do
33
+ @io.puts("\t# 127.0.0.1 foo.com")
34
+ create
35
+ @parser.ip_count.should == 0
36
+ @parser.host_count.should == 0
37
+ end
38
+
39
+ it "ignores empty lines" do
40
+ @io.puts("127.0.0.1 foo.com")
41
+ @io.puts
42
+ @io.puts("127.0.0.1 bar.com")
43
+ @io.puts("127.0.0.2 baz.com")
44
+ create
45
+ @parser.ip_count.should == 2
46
+ @parser.host_count.should == 3
47
+ end
48
+
49
+ it "ignores leading and trailing spaces" do
50
+ @io.puts(" 127.0.0.1 foo.com")
51
+ @io.puts
52
+ @io.puts(" 127.0.0.1 bar.com ")
53
+ @io.puts("127.0.0.2 baz.com ")
54
+ create
55
+ @parser.ip_count.should == 2
56
+ @parser.host_count.should == 3
57
+ @parser.resolve("foo.com").should == "127.0.0.1"
58
+ @parser.resolve("bar.com").should == "127.0.0.1"
59
+ @parser.resolve("baz.com").should == "127.0.0.2"
60
+ end
61
+
62
+ it "ignores leading and trailing tabs" do
63
+ @io.puts("\t\t127.0.0.1 foo.com")
64
+ @io.puts
65
+ @io.puts("\t127.0.0.1 bar.com\t")
66
+ @io.puts("127.0.0.2 baz.com\t\t")
67
+ create
68
+ @parser.ip_count.should == 2
69
+ @parser.host_count.should == 3
70
+ @parser.resolve("foo.com").should == "127.0.0.1"
71
+ @parser.resolve("bar.com").should == "127.0.0.1"
72
+ @parser.resolve("baz.com").should == "127.0.0.2"
73
+ end
74
+
75
+ it "correctly handles spaces as seperators" do
76
+ @io.puts("127.0.0.1 foo.com bar.com baz.com")
77
+ create
78
+ @parser.ip_count.should == 1
79
+ @parser.host_count.should == 3
80
+ @parser.resolve("foo.com").should == "127.0.0.1"
81
+ @parser.resolve("bar.com").should == "127.0.0.1"
82
+ @parser.resolve("baz.com").should == "127.0.0.1"
83
+ end
84
+
85
+ it "correctly handles tabs as seperators" do
86
+ @io.puts("127.0.0.1\tfoo.com\t\tbar.com baz.com")
87
+ create
88
+ @parser.ip_count.should == 1
89
+ @parser.host_count.should == 3
90
+ @parser.resolve("foo.com").should == "127.0.0.1"
91
+ @parser.resolve("bar.com").should == "127.0.0.1"
92
+ @parser.resolve("baz.com").should == "127.0.0.1"
93
+ end
94
+ end
95
+
96
+ describe "#resolve" do
97
+ it "returns nil if the host name is not in the file" do
98
+ @io.puts("127.0.0.1 foo.com")
99
+ create
100
+ @parser.resolve("bar.com").should be_nil
101
+ end
102
+
103
+ it "returns the IP address associated with the host name if it exists" do
104
+ @io.puts("255.255.255.255 foo.com")
105
+ create
106
+ @parser.resolve("foo.com").should == "255.255.255.255"
107
+ end
108
+
109
+ it "is case-insensitive" do
110
+ @io.puts("255.255.255.255 fOO.com")
111
+ create
112
+ @parser.resolve("foo.COM").should == "255.255.255.255"
113
+ end
114
+
115
+ it "correctly handles lines that contain multiple host names" do
116
+ @io.puts("255.255.255.255 foo.com bar.com")
117
+ create
118
+ @parser.resolve("foo.com").should == "255.255.255.255"
119
+ @parser.resolve("bar.com").should == "255.255.255.255"
120
+ @parser.resolve("baz.com").should be_nil
121
+ end
122
+
123
+ it "always returns 127.0.0.1 for localhost" do
124
+ create
125
+ @parser.resolve("localhost").should == "127.0.0.1"
126
+ @parser.resolve("localHOST").should == "127.0.0.1"
127
+ end
128
+ end
129
+
130
+ describe "#resolves_to_localhost?" do
131
+ before :each do
132
+ @io.puts "127.0.0.1 kotori"
133
+ @io.puts "192.168.0.1 kanako"
134
+ @io.puts "::1 ageha"
135
+ @io.puts "::2 sawako"
136
+ @io.puts "0.0.0.0 mizusawa"
137
+ create
138
+ end
139
+
140
+ it "returns true if the host name resolves to 127.0.0.1" do
141
+ @parser.resolves_to_localhost?("kotori").should be_true
142
+ end
143
+
144
+ it "returns true if the host name resolves to ::1" do
145
+ @parser.resolves_to_localhost?("ageha").should be_true
146
+ end
147
+
148
+ it "returns true if the host name resolves to 0.0.0.0" do
149
+ @parser.resolves_to_localhost?("mizusawa").should be_true
150
+ end
151
+
152
+ it "returns false if the host name resolves to something else" do
153
+ @parser.resolves_to_localhost?("sawako").should be_false
154
+ @parser.resolves_to_localhost?("kanako").should be_false
155
+ end
156
+
157
+ it "returns false if the host name does not resolve" do
158
+ @parser.resolves_to_localhost?("foo.com").should be_false
159
+ end
160
+ end
161
+
162
+ describe "#add_group_data" do
163
+ before :each do
164
+ @standard_entries =
165
+ "127.0.0.1 kotori hazuki\n" +
166
+ " 192.168.0.1 kanako\n\n" +
167
+ "\t::1 ageha sawako\n" +
168
+ "0.0.0.0 mizusawa naru\n"
169
+ @target = StringIO.new
170
+ end
171
+
172
+ it "adds the group data if it doesn't exist" do
173
+ @io.puts @standard_entries
174
+ create
175
+
176
+ @parser.add_group_data("some marker",
177
+ "# a comment\n" +
178
+ "127.0.0.1 foo\n")
179
+ @parser.write(@target)
180
+ @target.string.should ==
181
+ @standard_entries +
182
+ "###### BEGIN some marker ######\n" +
183
+ "# a comment\n" +
184
+ "127.0.0.1 foo\n" +
185
+ "###### END some marker ######\n"
186
+ end
187
+
188
+ it "replaces the existing group data if it does exist" do
189
+ @io.puts "###### BEGIN some marker ######\n" +
190
+ "# another comment\n" +
191
+ "127.0.0.1 bar\n" +
192
+ "###### END some marker ######\n" +
193
+ "\n" +
194
+ @standard_entries +
195
+ "###### BEGIN some other marker ######\n" +
196
+ "# another comment\n" +
197
+ "127.0.0.1 bar\n" +
198
+ "###### END some other marker ######\n"
199
+ create
200
+
201
+ @parser.add_group_data("some marker", "127.0.0.1 foo\n")
202
+ @parser.write(@target)
203
+ @target.string.should ==
204
+ "###### BEGIN some marker ######\n" +
205
+ "127.0.0.1 foo\n" +
206
+ "###### END some marker ######\n" +
207
+ "\n" +
208
+ @standard_entries +
209
+ "###### BEGIN some other marker ######\n" +
210
+ "# another comment\n" +
211
+ "127.0.0.1 bar\n" +
212
+ "###### END some other marker ######\n"
213
+ end
214
+
215
+ it "correctly handles the lack of a terminating newline in the group data" do
216
+ @io.puts @standard_entries
217
+ create
218
+
219
+ @parser.add_group_data("some marker",
220
+ "# a comment\n" +
221
+ "127.0.0.1 foo")
222
+ @parser.write(@target)
223
+ @target.string.should ==
224
+ @standard_entries +
225
+ "###### BEGIN some marker ######\n" +
226
+ "# a comment\n" +
227
+ "127.0.0.1 foo\n" +
228
+ "###### END some marker ######\n"
229
+ end
230
+
231
+ it "ensures that the group data starts at a new line" do
232
+ @io.write "127.0.0.1 foo.com"
233
+ create
234
+ @parser.add_group_data("some marker", "127.0.0.1 bar.com")
235
+ @parser.write(@target)
236
+ @target.string.should ==
237
+ "127.0.0.1 foo.com\n" +
238
+ "###### BEGIN some marker ######\n" +
239
+ "127.0.0.1 bar.com\n" +
240
+ "###### END some marker ######\n"
241
+ end
242
+ end
243
+
244
+ describe "#write" do
245
+ it "preserves all comments and leading and trailing whitespaces" do
246
+ @io.puts "127.0.0.1 foo.com "
247
+ @io.puts "# a comment"
248
+ @io.puts "\t127.0.0.1 bar.com\t"
249
+ create
250
+ original_data = @io.string
251
+ target = StringIO.new
252
+ @parser.write(target)
253
+ target.string.should == original_data
254
+ end
255
+ end
256
256
  end
257
257
 
258
258
  end # module PhusionPassenger