plow 0.1.0
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.
- data/.gitignore +9 -0
- data/.yardopts +6 -0
- data/HISTORY +39 -0
- data/LICENSE +20 -0
- data/README.markdown +152 -0
- data/ROAD-MAP +10 -0
- data/Rakefile +52 -0
- data/SECURITY +14 -0
- data/VERSION +1 -0
- data/bin/plow +10 -0
- data/bin/plow1.9 +10 -0
- data/lib/plow/application.rb +66 -0
- data/lib/plow/binding_struct.rb +15 -0
- data/lib/plow/core_ext/object.rb +8 -0
- data/lib/plow/errors.rb +27 -0
- data/lib/plow/generator.rb +57 -0
- data/lib/plow/strategy/ubuntu_hardy/templates/README.txt +19 -0
- data/lib/plow/strategy/ubuntu_hardy/templates/apache2-vhost.conf +14 -0
- data/lib/plow/strategy/ubuntu_hardy/user_home_web_app.rb +304 -0
- data/lib/plow.rb +18 -0
- data/spec/fixtures/passwd.txt +27 -0
- data/spec/fixtures/vhost.conf +3 -0
- data/spec/plow/application_spec.rb +241 -0
- data/spec/plow/binding_struct_spec.rb +38 -0
- data/spec/plow/errors_spec.rb +36 -0
- data/spec/plow/generator_spec.rb +160 -0
- data/spec/plow/strategy/ubuntu_hardy/user_home_web_app_spec.rb +561 -0
- data/spec/plow_spec.rb +19 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +29 -0
- metadata +121 -0
@@ -0,0 +1,304 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class Plow
|
4
|
+
class Strategy
|
5
|
+
class UbuntuHardy
|
6
|
+
|
7
|
+
##
|
8
|
+
# Plowing strategy, compatible with the Linux Ubuntu Hardy Heron distribution, for generating
|
9
|
+
# a web-site within a user home directory.
|
10
|
+
class UserHomeWebApp
|
11
|
+
attr_reader :context, :users_file_path, :vhost_file_name, :vhost_file_path, :vhost_template_file_path
|
12
|
+
attr_reader :user_home_path, :sites_home_path, :app_root_path, :app_public_path, :app_log_path
|
13
|
+
|
14
|
+
##
|
15
|
+
# @param [Plow::Generator] context A context reference to the generator controller. (i.e. Strategy pattern)
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# class Plow
|
19
|
+
# class Generator
|
20
|
+
# def initialize
|
21
|
+
# @strategy = Plow::Strategy::UbuntuHardy::UserHomeWebApp.new(self)
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
def initialize(context)
|
26
|
+
@context = context
|
27
|
+
@users_file_path = "/etc/passwd"
|
28
|
+
@vhost_file_name = "#{context.site_name}.conf"
|
29
|
+
@vhost_file_path = "/etc/apache2/sites-available/#{vhost_file_name}"
|
30
|
+
|
31
|
+
@vhost_template_file_path = "#{File.dirname(__FILE__)}/templates/apache2-vhost.conf"
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Begins executing this strategy. In addition to the following exceptions, this method may
|
36
|
+
# also raise exceptions found in private methods of this class.
|
37
|
+
#
|
38
|
+
# @raise [Plow::AppRootAlreadyExistsError] Raised if the web-app root path directory
|
39
|
+
# aleady exists
|
40
|
+
# @raise [Plow::ConfigFileAlreadyExistsError] Raised if a apache2 vhost configuration file
|
41
|
+
# cannot be found
|
42
|
+
def execute
|
43
|
+
if user_exists?
|
44
|
+
say "existing #{context.user_name} user"
|
45
|
+
else
|
46
|
+
say "creating #{context.user_name} user"
|
47
|
+
create_user
|
48
|
+
end
|
49
|
+
|
50
|
+
if user_home_exists?
|
51
|
+
say "existing #{user_home_path}"
|
52
|
+
else
|
53
|
+
say "creating #{user_home_path}"
|
54
|
+
create_user_home
|
55
|
+
end
|
56
|
+
|
57
|
+
if sites_home_exists?
|
58
|
+
say "existing #{sites_home_path}"
|
59
|
+
else
|
60
|
+
say "creating #{sites_home_path}"
|
61
|
+
create_sites_home
|
62
|
+
end
|
63
|
+
|
64
|
+
if app_root_exists?
|
65
|
+
raise(Plow::AppRootAlreadyExistsError, app_root_path)
|
66
|
+
else
|
67
|
+
say "creating #{app_root_path}"
|
68
|
+
create_app_root
|
69
|
+
end
|
70
|
+
|
71
|
+
@app_public_path = "#{app_root_path}/public"
|
72
|
+
say "creating #{@app_public_path}"
|
73
|
+
create_app_public
|
74
|
+
|
75
|
+
@app_log_path = "#{app_root_path}/log"
|
76
|
+
say "creating #{app_log_path}"
|
77
|
+
create_app_logs
|
78
|
+
|
79
|
+
if vhost_config_exists?
|
80
|
+
raise(Plow::ConfigFileAlreadyExistsError, vhost_file_path)
|
81
|
+
else
|
82
|
+
say "creating #{vhost_file_path}"
|
83
|
+
create_vhost_config
|
84
|
+
end
|
85
|
+
|
86
|
+
say "installing #{vhost_file_path}"
|
87
|
+
install_vhost_config
|
88
|
+
end
|
89
|
+
|
90
|
+
############################################################################################################
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
##
|
95
|
+
# Proxy method to +Plow::Generator#say+
|
96
|
+
# @param [String] message A user output message
|
97
|
+
def say(message)
|
98
|
+
context.say(message)
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Proxy method to +Plow::Generator#shell+
|
103
|
+
# @param [String] commands Shell commands with multi-line support.
|
104
|
+
def shell(commands)
|
105
|
+
context.shell(commands)
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Reads the file at +users_file_path+ and yields each user iteratively.
|
110
|
+
#
|
111
|
+
#
|
112
|
+
# @yield [Hash] Each user account
|
113
|
+
# @example
|
114
|
+
# users do |user|
|
115
|
+
# user[:name] #=> [String] The name
|
116
|
+
# user[:password] #=> [String] The bogus password
|
117
|
+
# user[:id] #=> [Number] The uid number
|
118
|
+
# user[:group_ip] #=> [Number] The gid number
|
119
|
+
# user[:info] #=> [String] General account info
|
120
|
+
# user[:home_path] #=> [String] The path to the home directory
|
121
|
+
# user[:shell_path] #=> [String] The path to the default shell
|
122
|
+
# end
|
123
|
+
def users(&block)
|
124
|
+
File.readlines(users_file_path).each do |user_line|
|
125
|
+
user_line = user_line.chomp.split(':')
|
126
|
+
user = {
|
127
|
+
:name => user_line[0],
|
128
|
+
:password => user_line[1],
|
129
|
+
:id => user_line[2].to_i,
|
130
|
+
:group_id => user_line[3].to_i,
|
131
|
+
:info => user_line[4],
|
132
|
+
:home_path => user_line[5],
|
133
|
+
:shell_path => user_line[6]
|
134
|
+
}
|
135
|
+
yield user
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
############################################################################################################
|
140
|
+
|
141
|
+
##
|
142
|
+
# Determines if the context.user_name already exists or not
|
143
|
+
#
|
144
|
+
# @return [Boolean] +true+ if found otherwise +false+
|
145
|
+
# @raise [Plow::ReservedSystemUserNameError] Raised if the +context.user_name+ is a reserved
|
146
|
+
# system user name
|
147
|
+
def user_exists?
|
148
|
+
users do |user|
|
149
|
+
if user[:name] == context.user_name
|
150
|
+
unless user[:id] >= 1000 && user[:id] != 65534
|
151
|
+
raise(Plow::ReservedSystemUserNameError, context.user_name)
|
152
|
+
end
|
153
|
+
return true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
return false
|
158
|
+
end
|
159
|
+
|
160
|
+
##
|
161
|
+
# Creates a system user account for +context.user_name+
|
162
|
+
def create_user
|
163
|
+
shell "adduser #{context.user_name}"
|
164
|
+
end
|
165
|
+
|
166
|
+
############################################################################################################
|
167
|
+
|
168
|
+
##
|
169
|
+
# Determines if a home path for the +context.user_name+ already exists
|
170
|
+
#
|
171
|
+
# @return [Boolean] +true+ if the path already exists, otherwise +false+
|
172
|
+
# @raise [Plow::SystemUserNameNotFoundError] Raised if the +context.user_name+ is not found
|
173
|
+
# even after it has been created
|
174
|
+
def user_home_exists?
|
175
|
+
users do |user|
|
176
|
+
if user[:name] == context.user_name
|
177
|
+
@user_home_path = user[:home_path]
|
178
|
+
return Dir.exists?(user[:home_path])
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
raise(Plow::SystemUserNameNotFoundError, context.user_name)
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Creates a +user_home_path+
|
187
|
+
def create_user_home
|
188
|
+
shell <<-RUN
|
189
|
+
mkdir #{user_home_path}
|
190
|
+
chown #{context.user_name}:#{context.user_name} #{user_home_path}
|
191
|
+
RUN
|
192
|
+
end
|
193
|
+
|
194
|
+
############################################################################################################
|
195
|
+
|
196
|
+
##
|
197
|
+
# Determines if the +sites_home_path+ already exists. As a side-effect, also correctly
|
198
|
+
# sets the +@sites_home_path+ variable.
|
199
|
+
# @return [Boolean] +true+ if the path already exists, otherwise +false+
|
200
|
+
def sites_home_exists?
|
201
|
+
@sites_home_path = "#{user_home_path}/sites"
|
202
|
+
Dir.exists?(sites_home_path)
|
203
|
+
end
|
204
|
+
|
205
|
+
##
|
206
|
+
# Creates the +site_home_path+
|
207
|
+
def create_sites_home
|
208
|
+
shell <<-RUN
|
209
|
+
mkdir #{sites_home_path}
|
210
|
+
chown #{context.user_name}:#{context.user_name} #{sites_home_path}
|
211
|
+
RUN
|
212
|
+
end
|
213
|
+
|
214
|
+
############################################################################################################
|
215
|
+
|
216
|
+
##
|
217
|
+
# Determines if the +app_root_path+ already exists. As a side-effect, also correctly
|
218
|
+
# sets the +@app_root_path+ variable.
|
219
|
+
# @return [Boolean] +true+ if the path exists, otherwise +false+
|
220
|
+
def app_root_exists?
|
221
|
+
@app_root_path = "#{sites_home_path}/#{context.site_name}"
|
222
|
+
Dir.exists?(app_root_path)
|
223
|
+
end
|
224
|
+
|
225
|
+
##
|
226
|
+
# Creates the +app_root_path+
|
227
|
+
def create_app_root
|
228
|
+
shell <<-RUN
|
229
|
+
mkdir #{app_root_path}
|
230
|
+
chown #{context.user_name}:#{context.user_name} #{app_root_path}
|
231
|
+
RUN
|
232
|
+
end
|
233
|
+
|
234
|
+
############################################################################################################
|
235
|
+
|
236
|
+
##
|
237
|
+
# Creates the app public structure at +app_public_path+
|
238
|
+
def create_app_public
|
239
|
+
shell <<-RUN
|
240
|
+
mkdir #{app_public_path}
|
241
|
+
touch #{app_public_path}/index.html
|
242
|
+
chown -R #{context.user_name}:#{context.user_name} #{app_public_path}
|
243
|
+
RUN
|
244
|
+
end
|
245
|
+
|
246
|
+
############################################################################################################
|
247
|
+
|
248
|
+
##
|
249
|
+
# Creates the app log structure at +app_log_path+
|
250
|
+
def create_app_logs
|
251
|
+
shell <<-RUN
|
252
|
+
mkdir #{app_log_path}
|
253
|
+
mkdir #{app_log_path}/apache2
|
254
|
+
chmod 750 #{app_log_path}/apache2
|
255
|
+
|
256
|
+
touch #{app_log_path}/apache2/access.log
|
257
|
+
touch #{app_log_path}/apache2/error.log
|
258
|
+
|
259
|
+
chmod 640 #{app_log_path}/apache2/*.log
|
260
|
+
chown -R #{context.user_name}:#{context.user_name} #{app_log_path}
|
261
|
+
chown root -R #{app_log_path}/apache2
|
262
|
+
RUN
|
263
|
+
end
|
264
|
+
|
265
|
+
############################################################################################################
|
266
|
+
|
267
|
+
##
|
268
|
+
# Determines if the apache2 vhost config file already exists
|
269
|
+
# @return [Boolean] +true+ if the file exists, otherwise +false+
|
270
|
+
def vhost_config_exists?
|
271
|
+
Dir.exists?(vhost_file_path)
|
272
|
+
end
|
273
|
+
|
274
|
+
##
|
275
|
+
# Creates an apache2 vhost config file from a template file to a +vhost_file_path+
|
276
|
+
def create_vhost_config
|
277
|
+
File.open(vhost_file_path, 'wt') do |file|
|
278
|
+
template_context = {
|
279
|
+
:site_name => context.site_name,
|
280
|
+
:site_aliases => context.site_aliases,
|
281
|
+
:app_public_path => app_public_path,
|
282
|
+
:app_log_path => app_log_path
|
283
|
+
}
|
284
|
+
|
285
|
+
config = context.evaluate_template(vhost_template_file_path, template_context)
|
286
|
+
file.write(config)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
############################################################################################################
|
291
|
+
|
292
|
+
##
|
293
|
+
# Installs the apache2 vhost config file by enabling the site and restarting the web server
|
294
|
+
def install_vhost_config
|
295
|
+
shell <<-RUN
|
296
|
+
a2ensite #{vhost_file_name}
|
297
|
+
apache2ctl graceful
|
298
|
+
RUN
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
data/lib/plow.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
unless RUBY_VERSION >= '1.9.1'
|
4
|
+
abort <<-ERROR
|
5
|
+
Incompatible ruby version error in #{__FILE__} near line #{__LINE__}
|
6
|
+
This library requires at least ruby v1.9.1 but you're using ruby v#{RUBY_VERSION}
|
7
|
+
Please see http://www.ruby-lang.org/
|
8
|
+
ERROR
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'plow/core_ext/object'
|
12
|
+
|
13
|
+
require 'plow/errors'
|
14
|
+
require 'plow/application'
|
15
|
+
|
16
|
+
class Plow
|
17
|
+
VERSION = "0.1.0"
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
root:x:0:0:root:/root:/bin/bash
|
2
|
+
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
|
3
|
+
bin:x:2:2:bin:/bin:/bin/sh
|
4
|
+
sys:x:3:3:sys:/dev:/bin/sh
|
5
|
+
sync:x:4:65534:sync:/bin:/bin/sync
|
6
|
+
games:x:5:60:games:/usr/games:/bin/sh
|
7
|
+
man:x:6:12:man:/var/cache/man:/bin/sh
|
8
|
+
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
|
9
|
+
mail:x:8:8:mail:/var/mail:/bin/sh
|
10
|
+
news:x:9:9:news:/var/spool/news:/bin/sh
|
11
|
+
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
|
12
|
+
proxy:x:13:13:proxy:/bin:/bin/sh
|
13
|
+
www-data:x:33:33:www-data:/var/www:/bin/sh
|
14
|
+
backup:x:34:34:backup:/var/backups:/bin/sh
|
15
|
+
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
|
16
|
+
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
|
17
|
+
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
|
18
|
+
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
|
19
|
+
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
|
20
|
+
dhcp:x:101:102::/nonexistent:/bin/false
|
21
|
+
syslog:x:102:103::/home/syslog:/bin/false
|
22
|
+
klog:x:103:104::/home/klog:/bin/false
|
23
|
+
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
|
24
|
+
Debian-exim:x:105:109::/var/spool/exim4:/bin/false
|
25
|
+
sadmin:x:1000:1000:,,,:/home/sadmin:/bin/bash
|
26
|
+
mysql:x:106:111:MySQL Server,,,:/var/lib/mysql:/bin/false
|
27
|
+
steve:x:1001:1001:,,,:/home/steve:/bin/bash
|
@@ -0,0 +1,241 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
3
|
+
|
4
|
+
describe Plow::Application do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@expected_version_stamp = "Plow v0.1.0. Copyright (c) 2009 Ryan Sobol. Licensed under the MIT license."
|
8
|
+
end
|
9
|
+
|
10
|
+
##################################################################################################
|
11
|
+
|
12
|
+
describe ".version_stamp" do
|
13
|
+
it "should create a version stamp as a String" do
|
14
|
+
Plow::Application.send(:version_stamp).should == @expected_version_stamp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
##################################################################################################
|
19
|
+
|
20
|
+
describe ".launch when failing" do
|
21
|
+
before(:each) do
|
22
|
+
@expected_message = <<MESSAGE
|
23
|
+
Usage: plow USER_NAME SITE_NAME [SITE_ALIAS ...]
|
24
|
+
|
25
|
+
Arguments:
|
26
|
+
USER_NAME Name of a Linux system account user (e.g. steve)
|
27
|
+
SITE_NAME Name of the web-site (e.g. www.apple.com)
|
28
|
+
SITE_ALIAS (Optional) List of alias names of the web-site (e.g. apple.com)
|
29
|
+
|
30
|
+
Summary:
|
31
|
+
Plows the fertile soil of your filesystem into neatly organized plots of web-site templates
|
32
|
+
|
33
|
+
Description:
|
34
|
+
1. Sharpens it's blade by ensuring that both a Linux system user account and it's home path exist
|
35
|
+
2. Penetrates the soil by forming the web-site root path within the user home
|
36
|
+
3. Seeds the web-site with an index page and web server log files
|
37
|
+
4. Fertilizes the web-site by installing a virtual host configuration into the web server
|
38
|
+
|
39
|
+
Example:
|
40
|
+
plow steve www.apple.com apple.com
|
41
|
+
MESSAGE
|
42
|
+
$stdout = StringIO.new
|
43
|
+
$stderr = StringIO.new
|
44
|
+
end
|
45
|
+
|
46
|
+
after(:each) do
|
47
|
+
$stdout = STDOUT
|
48
|
+
$stderr = STDERR
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should output the version stamp" do
|
52
|
+
lambda { Plow::Application.launch }.should raise_error
|
53
|
+
$stdout.string.should == @expected_version_stamp + "\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should abort with usage message with 0 arguments" do
|
57
|
+
lambda { Plow::Application.launch }.should raise_error(SystemExit, @expected_message)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should abort with usage message with 1 argument" do
|
61
|
+
lambda { Plow::Application.launch('marco') }.should raise_error(SystemExit, @expected_message)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
##################################################################################################
|
66
|
+
|
67
|
+
describe ".launch when passing" do
|
68
|
+
before(:each) do
|
69
|
+
$stdout = StringIO.new
|
70
|
+
end
|
71
|
+
|
72
|
+
after(:each) do
|
73
|
+
$stdout = STDOUT
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should output the version stamp" do
|
77
|
+
argv = ['steve', 'www.apple.com']
|
78
|
+
generator = mock('generator')
|
79
|
+
|
80
|
+
Plow::Generator.should_receive(:new)
|
81
|
+
.with(*argv)
|
82
|
+
.and_return(generator)
|
83
|
+
generator.should_receive(:run!)
|
84
|
+
|
85
|
+
Plow::Application.launch(*argv)
|
86
|
+
|
87
|
+
$stdout.string.should == @expected_version_stamp + "\n"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should start the generator with 2 arguments" do
|
91
|
+
argv = ['steve', 'www.apple.com']
|
92
|
+
generator = mock('generator')
|
93
|
+
|
94
|
+
Plow::Generator.should_receive(:new)
|
95
|
+
.with(*argv)
|
96
|
+
.and_return(generator)
|
97
|
+
generator.should_receive(:run!)
|
98
|
+
|
99
|
+
Plow::Application.launch(*argv).should == 0
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should start the generator with 3 arguments" do
|
103
|
+
argv = ['marco-polo', 'www.marcopolo.com', 'marcopolo.com']
|
104
|
+
generator = mock('generator')
|
105
|
+
|
106
|
+
Plow::Generator.should_receive(:new)
|
107
|
+
.with(*argv)
|
108
|
+
.and_return(generator)
|
109
|
+
generator.should_receive(:run!)
|
110
|
+
|
111
|
+
Plow::Application.launch(*argv).should == 0
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should start the generator with 4 arguments" do
|
115
|
+
argv = ['marco-polo', 'www.marcopolo.com', 'marcopolo.com', 'asia.marcopolo.com']
|
116
|
+
generator = mock('generator')
|
117
|
+
|
118
|
+
Plow::Generator.should_receive(:new)
|
119
|
+
.with(*argv)
|
120
|
+
.and_return(generator)
|
121
|
+
generator.should_receive(:run!)
|
122
|
+
|
123
|
+
Plow::Application.launch(*argv).should == 0
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
##################################################################################################
|
128
|
+
|
129
|
+
describe "when handling errors from Plow::Generator.new" do
|
130
|
+
before(:each) do
|
131
|
+
@bad_argv = ['bad user name', 'bad site name', 'bad site alias']
|
132
|
+
$stdout = StringIO.new
|
133
|
+
$stderr = StringIO.new
|
134
|
+
end
|
135
|
+
|
136
|
+
after(:each) do
|
137
|
+
$stdout = STDOUT
|
138
|
+
$stderr = STDERR
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should render error message to the user for raised Plow::InvalidSystemUserNameError" do
|
142
|
+
expected_error = Plow::InvalidSystemUserNameError.new(@bad_argv[0])
|
143
|
+
Plow::Generator.should_receive(:new).and_raise(expected_error)
|
144
|
+
|
145
|
+
expected_message = "ERROR: #{@bad_argv[0]} is an invalid system user name"
|
146
|
+
lambda { Plow::Application.launch(*@bad_argv) }.should raise_error(SystemExit, expected_message)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should render error message to the user for raised Plow::InvalidWebSiteNameError" do
|
150
|
+
expected_error = Plow::InvalidWebSiteNameError.new(@bad_argv[1])
|
151
|
+
Plow::Generator.should_receive(:new).and_raise(expected_error)
|
152
|
+
|
153
|
+
expected_message = "ERROR: #{@bad_argv[1]} is an invalid web-site name"
|
154
|
+
lambda { Plow::Application.launch(*@bad_argv) }.should raise_error(SystemExit, expected_message)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should render error message to the user for raised Plow::InvalidWebSiteAliasError" do
|
158
|
+
expected_error = Plow::InvalidWebSiteAliasError.new(@bad_argv[2])
|
159
|
+
Plow::Generator.should_receive(:new).and_raise(expected_error)
|
160
|
+
|
161
|
+
expected_message = "ERROR: #{@bad_argv[2]} is an invalid web-site alias"
|
162
|
+
lambda { Plow::Application.launch(*@bad_argv) }.should raise_error(SystemExit, expected_message)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "when handing errors from Plow::Generator.run!" do
|
167
|
+
before(:each) do
|
168
|
+
$stdout = StringIO.new
|
169
|
+
$stderr = StringIO.new
|
170
|
+
@argv = ['steve', 'www.apple.com', 'apple.com']
|
171
|
+
@generator = mock('generator')
|
172
|
+
end
|
173
|
+
|
174
|
+
after(:each) do
|
175
|
+
$stdout = STDOUT
|
176
|
+
$stderr = STDERR
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should render error message to the user for raised Plow::NonRootProcessOwnerError" do
|
180
|
+
expected_error = Plow::NonRootProcessOwnerError
|
181
|
+
|
182
|
+
Plow::Generator.should_receive(:new)
|
183
|
+
.with(*@argv)
|
184
|
+
.and_return(@generator)
|
185
|
+
@generator.should_receive(:run!).and_raise(expected_error)
|
186
|
+
|
187
|
+
expected_message = "ERROR: This process must be owned or executed by root"
|
188
|
+
lambda { Plow::Application.launch(*@argv) }.should raise_error(SystemExit, expected_message)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should render error message to the user for raised Plow::ReservedSystemUserNameError" do
|
192
|
+
expected_error = Plow::ReservedSystemUserNameError.new(@argv[0])
|
193
|
+
|
194
|
+
Plow::Generator.should_receive(:new)
|
195
|
+
.with(*@argv)
|
196
|
+
.and_return(@generator)
|
197
|
+
@generator.should_receive(:run!).and_raise(expected_error)
|
198
|
+
|
199
|
+
expected_message = "ERROR: #{@argv[0]} is a reserved system user name"
|
200
|
+
lambda { Plow::Application.launch(*@argv) }.should raise_error(SystemExit, expected_message)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should render error message to the user for raised Plow::SystemUserNameNotFoundError" do
|
204
|
+
expected_error = Plow::SystemUserNameNotFoundError.new(@argv[0])
|
205
|
+
|
206
|
+
Plow::Generator.should_receive(:new)
|
207
|
+
.with(*@argv)
|
208
|
+
.and_return(@generator)
|
209
|
+
@generator.should_receive(:run!).and_raise(expected_error)
|
210
|
+
|
211
|
+
expected_message = "ERROR: System user name #{@argv[0]} cannot be found when it should exist"
|
212
|
+
lambda { Plow::Application.launch(*@argv) }.should raise_error(SystemExit, expected_message)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should render error message to the user for raised Plow::AppRootAlreadyExistsError" do
|
216
|
+
app_home_path = "/home/#{@argv[0]}/sites/#{@argv[1]}"
|
217
|
+
expected_error = Plow::AppRootAlreadyExistsError.new(app_home_path)
|
218
|
+
|
219
|
+
Plow::Generator.should_receive(:new)
|
220
|
+
.with(*@argv)
|
221
|
+
.and_return(@generator)
|
222
|
+
@generator.should_receive(:run!).and_raise(expected_error)
|
223
|
+
|
224
|
+
expected_message = "ERROR: Application root path #{app_home_path} already exists"
|
225
|
+
lambda { Plow::Application.launch(*@argv) }.should raise_error(SystemExit, expected_message)
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should render error message to the user for raised Plow::AppRootAlreadyExistsError" do
|
229
|
+
config_file_path = '/etc/apache2/sites_available/vhost.conf'
|
230
|
+
expected_error = Plow::ConfigFileAlreadyExistsError.new(config_file_path)
|
231
|
+
|
232
|
+
Plow::Generator.should_receive(:new)
|
233
|
+
.with(*@argv)
|
234
|
+
.and_return(@generator)
|
235
|
+
@generator.should_receive(:run!).and_raise(expected_error)
|
236
|
+
|
237
|
+
expected_message = "ERROR: Configuration file #{config_file_path} already exists"
|
238
|
+
lambda { Plow::Application.launch(*@argv) }.should raise_error(SystemExit, expected_message)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
4
|
+
|
5
|
+
describe Plow::BindingStruct do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@arguments = { first_name: 'Carl', last_name: 'Sagan' }
|
9
|
+
@struct = Plow::BindingStruct.new(@arguments)
|
10
|
+
end
|
11
|
+
|
12
|
+
##################################################################################################
|
13
|
+
|
14
|
+
describe ".new" do
|
15
|
+
it "should create instance variables for all keys of a parameter Hash" do
|
16
|
+
@struct.instance_variables.sort.should == @arguments.keys.sort.map { |key| "@#{key}".to_sym }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should initialze all instance variables with the values of a parameter Hash" do
|
20
|
+
@struct.instance_variables.each do |ivar|
|
21
|
+
@struct.instance_variable_get(ivar).should == @arguments[ivar.to_s.gsub("@", '').to_sym]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
##################################################################################################
|
27
|
+
|
28
|
+
describe "\#get_binding" do
|
29
|
+
it "should return a Binding object of the instance" do
|
30
|
+
ivars = @arguments.keys.sort.map { |key| "@#{key}".to_sym }
|
31
|
+
ivars.each do |ivar|
|
32
|
+
actual = eval(ivar.to_s, @struct.get_binding)
|
33
|
+
actual.should == @arguments[ivar.to_s.gsub("@", '').to_sym]
|
34
|
+
actual.should == @struct.instance_variable_get(ivar)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
3
|
+
|
4
|
+
describe "Custom Application Errors" do
|
5
|
+
it "Plow::NonRootProcessOwnerError should be a kind of StandardError" do
|
6
|
+
Plow::NonRootProcessOwnerError.new.should be_a_kind_of(StandardError)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "Plow::InvalidSystemUserNameError should be a kind of StandardError" do
|
10
|
+
Plow::InvalidSystemUserNameError.new.should be_a_kind_of(StandardError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "Plow::InvalidWebSiteNameError should be a kind of StandardError" do
|
14
|
+
Plow::InvalidWebSiteNameError.new.should be_a_kind_of(StandardError)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "Plow::InvalidWebSiteAliasError should be a kind of StandardError" do
|
18
|
+
Plow::InvalidWebSiteAliasError.new.should be_a_kind_of(StandardError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "Plow::ReservedSystemUserNameError should be a kind of StandardError" do
|
22
|
+
Plow::ReservedSystemUserNameError.new.should be_a_kind_of(StandardError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Plow::SystemUserNameNotFoundError should be a kind of StandardError" do
|
26
|
+
Plow::SystemUserNameNotFoundError.new.should be_a_kind_of(StandardError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "Plow::AppRootAlreadyExistsError should be a kind of StandardError" do
|
30
|
+
Plow::AppRootAlreadyExistsError.new.should be_a_kind_of(StandardError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "Plow::ConfigFileAlreadyExistsError should be a kind of StandardError" do
|
34
|
+
Plow::ConfigFileAlreadyExistsError.new.should be_a_kind_of(StandardError)
|
35
|
+
end
|
36
|
+
end
|