php_fpm_docker 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,277 @@
1
+ require 'spec_helper'
2
+ require 'php_fpm_docker/pool'
3
+
4
+ LAUNCHER_WEB_PATH = '/var/webpath'
5
+ LAUNCHER_BIND_MOUNTS = ['/mnt/bind']
6
+ LAUNCHER_SPAWN_FCGI = '/usr/bin/fcgi-bin'
7
+ LAUNCHER_PHP = '/usr/bin/php'
8
+
9
+ describe PhpFpmDocker::Pool do
10
+
11
+ # Default config
12
+ let(:default_config) {
13
+ {
14
+ 'listen' => '/tmp/name2.sock',
15
+ 'listen.owner' => 'user1',
16
+ 'listen.group' => 'group1',
17
+ 'listen.mode' => '0660',
18
+ 'user' => 'user2',
19
+ 'group' => 'group2',
20
+ 'php_admin_value[open_basedir]' => [
21
+ '/mnt/invalid/not_me_test',
22
+ File.join(LAUNCHER_WEB_PATH,'test123','web'),
23
+ File.join(LAUNCHER_WEB_PATH,'clients','client123','web2','web'),
24
+ ].join(':'),
25
+ }
26
+ }
27
+
28
+ # Mock Etc (getuid and getpwdid)
29
+ before (:example) {
30
+ # mock users
31
+ user1 = double
32
+ allow(user1).to receive(:uid).and_return(1001)
33
+ user2 = double
34
+ allow(user2).to receive(:uid).and_return(1002)
35
+ allow(Etc).to receive(:getpwnam).with('user1').and_return(user1)
36
+ allow(Etc).to receive(:getpwnam).with('user2').and_return(user2)
37
+ # mock groups
38
+ group1 = double
39
+ allow(group1).to receive(:gid).and_return(1001)
40
+ group2 = double
41
+ allow(group2).to receive(:gid).and_return(1002)
42
+ allow(Etc).to receive(:getgrnam).with('group1').and_return(group1)
43
+ allow(Etc).to receive(:getgrnam).with('group2').and_return(group2)
44
+ }
45
+
46
+ # Mock Docker
47
+ before (:example){
48
+ @dbl_docker = class_double('Docker').as_stubbed_const()
49
+ @dbl_docker_container = class_double('Docker::Container').as_stubbed_const()
50
+ }
51
+
52
+ # Mock launcher
53
+ let(:launcher) {
54
+ l = double
55
+
56
+ # respond with global bind mounts
57
+ allow(l).to receive(:bind_mounts).and_return(LAUNCHER_BIND_MOUNTS)
58
+
59
+ # respond with webpath
60
+ allow(l).to receive(:web_path).and_return(LAUNCHER_WEB_PATH)
61
+
62
+ ## Mock docker image
63
+ i = double
64
+ allow(i).to receive(:id).and_return('deadbeef')
65
+ # respond with image
66
+ allow(l).to receive(:docker_image).and_return(i)
67
+
68
+ # respond spwan fcgi path
69
+ allow(l).to receive(:spawn_cmd_path).and_return(LAUNCHER_SPAWN_FCGI)
70
+
71
+ # respond php path
72
+ allow(l).to receive(:php_cmd_path).and_return(LAUNCHER_PHP)
73
+
74
+ l
75
+ }
76
+
77
+ describe 'pool1 with default values' do
78
+ let (:p) {
79
+ p = described_class.new({
80
+ :name => 'pool1',
81
+ :config => default_config,
82
+ :launcher => launcher,
83
+ })
84
+ }
85
+ it "parse correct uid" do
86
+ expect(p.uid).to eq(1002)
87
+ end
88
+ it "parse correct gid" do
89
+ expect(p.gid).to eq(1002)
90
+ end
91
+ it "parse correct listen_uid" do
92
+ expect(p.listen_uid).to eq(1001)
93
+ end
94
+ it "parse correct listen_gid" do
95
+ expect(p.listen_gid).to eq(1001)
96
+ end
97
+ describe "#spawn_command" do
98
+ before (:example) {
99
+ @list = p.spawn_command
100
+ }
101
+ it 'list include spawn_fcgi' do
102
+ expect(@list).to include(LAUNCHER_SPAWN_FCGI)
103
+ end
104
+ it 'list include socket path' do
105
+ expect(@list).to include(default_config['listen'])
106
+ end
107
+ it 'list is flat' do
108
+ expect(@list.flatten).to eq(@list)
109
+ end
110
+ it 'list is string only' do
111
+ @list.each do |elem|
112
+ expect(elem).to be_a(String)
113
+ end
114
+ end
115
+ end
116
+ describe "#bind_mounts" do
117
+ let (:bind_mounts) {
118
+ p.bind_mounts
119
+ }
120
+ it "not raise error" do
121
+ expect{bind_mounts}.not_to raise_error
122
+ end
123
+ it "include socket directory" do
124
+ expect(bind_mounts).to include(File.dirname(default_config['listen']))
125
+ end
126
+ it "include web root directories" do
127
+ # get valid open_base_dirs
128
+ default_config['php_admin_value[open_basedir]'].split(':')[1..-1].each do |dir|
129
+ expect(bind_mounts).to include(File.dirname(dir))
130
+ end
131
+ end
132
+ it "not include fake directories" do
133
+ dir = default_config['php_admin_value[open_basedir]'].split(':').first
134
+ expect(bind_mounts).not_to include(dir)
135
+ expect(bind_mounts).not_to include(File.dirname(dir))
136
+ end
137
+ end
138
+ describe "#php_command" do
139
+ before (:example) {
140
+ @list = p.php_command
141
+ }
142
+ it 'list include php cmd' do
143
+ expect(@list).to include(LAUNCHER_PHP)
144
+ end
145
+ it 'list is flat' do
146
+ expect(@list.flatten).to eq(@list)
147
+ end
148
+ it 'list is string only' do
149
+ @list.each do |elem|
150
+ expect(elem).to be_a(String)
151
+ end
152
+ end
153
+ end
154
+ describe "#docker_create_opts" do
155
+ let (:docker_create_opts) {
156
+ p.docker_create_opts
157
+ }
158
+ it "not raise error" do
159
+ expect{docker_create_opts}.not_to raise_error
160
+ end
161
+ it "include php" do
162
+ expect(docker_create_opts['Image']).to eq('deadbeef')
163
+ end
164
+ end
165
+ describe "#start" do
166
+ let (:method) {
167
+ p.start
168
+ }
169
+ before (:example) {
170
+ # catch upstream calls
171
+ @spawn_list = ['spawn','spawn_args']
172
+ @php_list = ['php','php_args']
173
+ allow(p).to receive(:spawn_command).and_return(@spawn_list)
174
+ allow(p).to receive(:php_command).and_return(@php_list)
175
+ allow(p).to receive(:docker_create_opts).and_return({})
176
+ allow(p).to receive(:docker_start_opts).and_return({})
177
+ }
178
+ it "starts container" do
179
+ # container instance
180
+ dbl_c_inst = double
181
+ expect(dbl_c_inst).to receive(:start).with({})
182
+ expect(@dbl_docker_container).to receive(:create).and_return(dbl_c_inst)
183
+ method
184
+ end
185
+ it "build cmd correctly" do
186
+ # container instance
187
+ dbl_c_inst = double
188
+ allow(dbl_c_inst).to receive(:start).with({})
189
+ hash = hash_including('Cmd' => (@spawn_list + ['--'] + @php_list))
190
+ expect(@dbl_docker_container).to receive(:create).with(hash).and_return(dbl_c_inst)
191
+ method
192
+ end
193
+ it 'enables the pool' do
194
+ # container instance
195
+ dbl_c_inst = double
196
+ expect(dbl_c_inst).to receive(:start).with({})
197
+ expect(@dbl_docker_container).to receive(:create).and_return(dbl_c_inst)
198
+ method
199
+ # container class
200
+ expect(p.enabled).to eq(true)
201
+ end
202
+ end
203
+ describe "#stop" do
204
+ it "stops existing container" do
205
+ # container instance
206
+ dbl_c_inst = double
207
+ allow(dbl_c_inst).to receive(:delete).with(hash_including(force: true))
208
+ p.instance_variable_set(:@container, dbl_c_inst)
209
+ p.stop
210
+ expect(p.enabled).to eq(false)
211
+ end
212
+ it "doesn't stop non-existing container" do
213
+ p.instance_variable_set(:@container, nil)
214
+ p.stop
215
+ expect(p.enabled).to eq(false)
216
+ end
217
+ end
218
+ describe "#container_name" do
219
+ let(:method) {
220
+ p.instance_variable_set(:@name, 'myname')
221
+ p.container_name
222
+ }
223
+ it '@container_name not set' do
224
+ p.instance_variable_set(:@container_name, nil)
225
+ name = method
226
+ expect(name).to a_string_matching(/^myname_[a-f0-9]+$/)
227
+ expect(p.instance_variable_get(:@container_name)).to eq (name)
228
+ end
229
+ it '@container_name set' do
230
+ p.instance_variable_set(:@container_name, 'myname_cafe')
231
+ name = method
232
+ expect(name).to eq ('myname_cafe')
233
+ expect(p.instance_variable_get(:@container_name)).to eq (name)
234
+ end
235
+ end
236
+ describe "#container_running?" do
237
+ it "container is nil" do
238
+ expect(p.container_running?).to eq(false)
239
+ end
240
+ it "container is running" do
241
+ dbl_c_inst = double
242
+ allow(dbl_c_inst).to receive(:info).and_return({'State' => { 'Running' => true }})
243
+ p.instance_variable_set(:@container, dbl_c_inst)
244
+ expect(p.container_running?).to eq(true)
245
+ end
246
+ it "container is not running" do
247
+ dbl_c_inst = double
248
+ allow(dbl_c_inst).to receive(:info).and_return({'State' => { 'Running' => false }})
249
+ p.instance_variable_set(:@container, dbl_c_inst)
250
+ expect(p.container_running?).to eq(false)
251
+ end
252
+ end
253
+ describe "#check" do
254
+ [ # enabled, running, restart
255
+ [true,true,false],
256
+ [false,true,false],
257
+ [false,false,false],
258
+ [true,false,true],
259
+ ].each do |enabled,running,restart|
260
+ it "enabled=#{enabled} and running=#{running} -> restart=#{restart}" do
261
+ allow(p).to receive(:'container_running?').and_return(running)
262
+ p.instance_variable_set(:@enabled, enabled)
263
+
264
+ # container
265
+ dbl_c_inst = double
266
+ p.instance_variable_set(:@container, dbl_c_inst)
267
+
268
+ if restart
269
+ expect(p).to receive(:stop)
270
+ expect(p).to receive(:start)
271
+ end
272
+ p.check
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: php_fpm_docker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Christian Simon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: docker-api
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: inifile
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: coveralls
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Use docker containers for PHP from FPM config
112
+ email:
113
+ - simon@swine.de
114
+ executables:
115
+ - php_fpm_docker
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".rspec"
121
+ - ".rubocop.yml"
122
+ - ".travis.yml"
123
+ - Gemfile
124
+ - Gemfile.lock
125
+ - LICENSE.txt
126
+ - README.md
127
+ - Rakefile
128
+ - bin/php_fpm_docker
129
+ - doc/graphs/structure/structure.gliffy
130
+ - doc/graphs/structure/structure.png
131
+ - doc/graphs/structure/structure.svg
132
+ - lib/php_fpm_docker.rb
133
+ - lib/php_fpm_docker/application.rb
134
+ - lib/php_fpm_docker/launcher.rb
135
+ - lib/php_fpm_docker/pool.rb
136
+ - lib/php_fpm_docker/version.rb
137
+ - php_fpm_docker.gemspec
138
+ - spec/helper.rb
139
+ - spec/spec_helper.rb
140
+ - spec/unit/application_spec.rb
141
+ - spec/unit/launcher_spec.rb
142
+ - spec/unit/pool_spec.rb
143
+ homepage: https://github.com/simonswine/php_fpm_docker
144
+ licenses:
145
+ - GPLv3
146
+ metadata: {}
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubyforge_project:
163
+ rubygems_version: 2.4.3
164
+ signing_key:
165
+ specification_version: 4
166
+ summary: Use docker containers for PHP from FPM config
167
+ test_files:
168
+ - spec/helper.rb
169
+ - spec/spec_helper.rb
170
+ - spec/unit/application_spec.rb
171
+ - spec/unit/launcher_spec.rb
172
+ - spec/unit/pool_spec.rb