chef-rewind 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/CHANGELOG +17 -0
  2. data/Gemfile +42 -2
  3. data/README.md +2 -0
  4. data/chef-rewind.gemspec +1 -1
  5. data/lib/chef/rewind.rb +7 -0
  6. data/spec/data/cookbooks/angrybash/recipes/default.rb +8 -0
  7. data/spec/data/cookbooks/apache2/files/default/apache2_module_conf_generate.pl +2 -0
  8. data/spec/data/cookbooks/apache2/recipes/default.rb +3 -0
  9. data/spec/data/cookbooks/borken/recipes/default.rb +2 -0
  10. data/spec/data/cookbooks/borken/templates/default/borken.erb +2 -0
  11. data/spec/data/cookbooks/chefignore +6 -0
  12. data/spec/data/cookbooks/java/files/default/java.response +2 -0
  13. data/spec/data/cookbooks/openldap/attributes/default.rb +16 -0
  14. data/spec/data/cookbooks/openldap/attributes/smokey.rb +1 -0
  15. data/spec/data/cookbooks/openldap/definitions/client.rb +5 -0
  16. data/spec/data/cookbooks/openldap/definitions/server.rb +5 -0
  17. data/spec/data/cookbooks/openldap/files/default/.dotfile +1 -0
  18. data/spec/data/cookbooks/openldap/files/default/.ssh/id_rsa +1 -0
  19. data/spec/data/cookbooks/openldap/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir +1 -0
  20. data/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file1.txt +3 -0
  21. data/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file2.txt +3 -0
  22. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/.a_dotfile +1 -0
  23. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file1.txt +3 -0
  24. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file2.txt +3 -0
  25. data/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/some_file.txt +3 -0
  26. data/spec/data/cookbooks/openldap/recipes/default.rb +3 -0
  27. data/spec/data/cookbooks/openldap/recipes/gigantor.rb +3 -0
  28. data/spec/data/cookbooks/openldap/recipes/one.rb +15 -0
  29. data/spec/data/cookbooks/openldap/templates/default/openldap_stuff.conf.erb +1 -0
  30. data/spec/data/cookbooks/openldap/templates/default/openldap_variable_stuff.conf.erb +1 -0
  31. data/spec/data/cookbooks/openldap/templates/default/test.erb +1 -0
  32. data/spec/rewind_recipe_spec.rb +62 -0
  33. data/spec/rewind_resource_spec.rb +34 -0
  34. data/spec/spec_helper.rb +81 -0
  35. data/spec/support/chef_helpers.rb +52 -0
  36. data/spec/support/lib/chef/provider/easy.rb +35 -0
  37. data/spec/support/lib/chef/provider/snakeoil.rb +40 -0
  38. data/spec/support/lib/chef/resource/cat.rb +41 -0
  39. data/spec/support/lib/chef/resource/one_two_three_four.rb +43 -0
  40. data/spec/support/lib/chef/resource/zen_master.rb +46 -0
  41. data/spec/support/matchers/leak.rb +96 -0
  42. data/spec/support/mock/constant.rb +52 -0
  43. data/spec/support/mock/platform.rb +18 -0
  44. data/spec/support/platform_helpers.rb +31 -0
  45. data/spec/support/platforms/prof/gc.rb +54 -0
  46. data/spec/support/platforms/prof/win32.rb +46 -0
  47. data/spec/support/shared/functional/directory_resource.rb +85 -0
  48. data/spec/support/shared/functional/file_resource.rb +173 -0
  49. data/spec/support/shared/functional/knife.rb +37 -0
  50. data/spec/support/shared/functional/securable_resource.rb +394 -0
  51. data/spec/support/shared/unit/api_error_inspector.rb +192 -0
  52. data/spec/support/shared/unit/platform_introspector.rb +162 -0
  53. metadata +99 -4
@@ -0,0 +1,46 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/win32/process'
20
+
21
+ module RSpec
22
+ module Prof
23
+ module Win32
24
+ class Profiler
25
+
26
+ def start
27
+ GC.start
28
+ end
29
+
30
+ def stop
31
+ GC.start
32
+ end
33
+
34
+ def working_set_size
35
+ Chef::ReservedNames::Win32::Process.get_current_process.memory_info[:WorkingSetSize]
36
+ end
37
+
38
+ def handle_count
39
+ Chef::ReservedNames::Win32::Process.get_current_process.handle_count
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,85 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ shared_examples_for "a directory resource" do
20
+ context "when the target directory does not exist" do
21
+ it "creates the directory when the :create action is run" do
22
+ resource.run_action(:create)
23
+ File.should exist(path)
24
+ end
25
+
26
+ it "recursively creates required directories if requested" do
27
+ resource.recursive(true)
28
+ recursive_path = File.join(path, 'red-headed-stepchild')
29
+ resource.path(recursive_path)
30
+ resource.run_action(:create)
31
+ File.should exist(path)
32
+ File.should exist(recursive_path)
33
+ end
34
+ end
35
+
36
+ context "when the target directory exists" do
37
+ before(:each) do
38
+ FileUtils.mkdir(path)
39
+ end
40
+
41
+ it "does not re-create the directory" do
42
+ resource.run_action(:create)
43
+ File.should exist(path)
44
+ end
45
+
46
+ it "deletes the directory when the :delete action is run" do
47
+ resource.run_action(:delete)
48
+ File.should_not exist(path)
49
+ end
50
+
51
+ it "recursively deletes directories if requested" do
52
+ FileUtils.mkdir(File.join(path, 'red-headed-stepchild'))
53
+ resource.recursive(true)
54
+ resource.run_action(:delete)
55
+ File.should_not exist(path)
56
+ end
57
+ end
58
+
59
+ # Set up the context for security tests
60
+ def allowed_acl(sid, expected_perms)
61
+ [
62
+ ACE.access_allowed(sid, expected_perms[:specific]),
63
+ ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE))
64
+ ]
65
+ end
66
+
67
+ def denied_acl(sid, expected_perms)
68
+ [
69
+ ACE.access_denied(sid, expected_perms[:specific]),
70
+ ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE))
71
+ ]
72
+ end
73
+
74
+ it_behaves_like "a securable resource"
75
+ end
76
+
77
+ shared_context Chef::Resource::Directory do
78
+ let(:path) do
79
+ File.join(Dir.tmpdir, make_tmpname(directory_base, nil))
80
+ end
81
+
82
+ after(:each) do
83
+ FileUtils.rm_r(path) if File.exists?(path)
84
+ end
85
+ end
@@ -0,0 +1,173 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ shared_examples_for "a file with the wrong content" do
20
+ it "overwrites the file with the updated content when the :create action is run" do
21
+ Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH
22
+ sleep 1
23
+ resource.run_action(:create)
24
+ File.stat(path).mtime.should > @expected_mtime
25
+ sha256_checksum(path).should_not == @expected_checksum
26
+ end
27
+
28
+ it "doesn't overwrite the file when the :create_if_missing action is run" do
29
+ sleep 1
30
+ resource.run_action(:create_if_missing)
31
+ File.stat(path).mtime.should == @expected_mtime
32
+ sha256_checksum(path).should == @expected_checksum
33
+ end
34
+
35
+ it "should backup the existing file" do
36
+ Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH
37
+ resource.run_action(:create)
38
+ Dir.glob(backup_glob).size.should equal(1)
39
+ end
40
+
41
+ it "should not attempt to backup the existing file if :backup == 0" do
42
+ Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH
43
+ resource.backup(0)
44
+ resource.run_action(:create)
45
+ Dir.glob(backup_glob).size.should equal(0)
46
+ end
47
+
48
+ it "deletes the file when the :delete action is run" do
49
+ resource.run_action(:delete)
50
+ File.should_not exist(path)
51
+ end
52
+ end
53
+
54
+ shared_examples_for "a file with the correct content" do
55
+ it "does not overwrite the original when the :create action is run" do
56
+ resource.run_action(:create)
57
+ sha256_checksum(path).should == @expected_checksum
58
+ end
59
+
60
+ it "does not update the mtime/atime of the file when the :create action is run" do
61
+ sleep 1
62
+ File.stat(path).mtime.should == @expected_mtime
63
+ File.stat(path).atime.should be_within(2).of(@expected_atime)
64
+ end
65
+
66
+ it "doesn't overwrite the file when the :create_if_missing action is run" do
67
+ resource.run_action(:create_if_missing)
68
+ sha256_checksum(path).should == @expected_checksum
69
+ end
70
+
71
+ it "deletes the file when the :delete action is run" do
72
+ resource.run_action(:delete)
73
+ File.should_not exist(path)
74
+ end
75
+ end
76
+
77
+ shared_examples_for "a file resource" do
78
+ # note the stripping of the drive letter from the tmpdir on windows
79
+ let(:backup_glob) { File.join(CHEF_SPEC_BACKUP_PATH, Dir.tmpdir.sub(/^([A-Za-z]:)/, ""), "#{file_base}*") }
80
+
81
+ context "when the target file does not exist" do
82
+ it "creates the file when the :create action is run" do
83
+ resource.run_action(:create)
84
+ File.should exist(path)
85
+ end
86
+
87
+ it "creates the file with the correct content when the :create action is run" do
88
+ resource.run_action(:create)
89
+ IO.read(path).should == expected_content
90
+ end
91
+
92
+ it "creates the file with the correct content when the :create_if_missing action is run" do
93
+ resource.run_action(:create_if_missing)
94
+ IO.read(path).should == expected_content
95
+ end
96
+
97
+ it "deletes the file when the :delete action is run" do
98
+ resource.run_action(:delete)
99
+ File.should_not exist(path)
100
+ end
101
+ end
102
+
103
+ # Set up the context for security tests
104
+ def allowed_acl(sid, expected_perms)
105
+ [ ACE.access_allowed(sid, expected_perms[:specific]) ]
106
+ end
107
+
108
+ def denied_acl(sid, expected_perms)
109
+ [ ACE.access_denied(sid, expected_perms[:specific]) ]
110
+ end
111
+
112
+
113
+ context "when the target file has the wrong content" do
114
+ before(:each) do
115
+ File.open(path, "w") { |f| f.print "This is so wrong!!!" }
116
+ @expected_mtime = File.stat(path).mtime
117
+ @expected_checksum = sha256_checksum(path)
118
+ end
119
+
120
+ describe "and the target file has the correct permissions" do
121
+ include_context "setup correct permissions"
122
+
123
+ it_behaves_like "a file with the wrong content"
124
+
125
+ it_behaves_like "a securable resource"
126
+ end
127
+
128
+ context "and the target file has incorrect permissions" do
129
+ include_context "setup broken permissions"
130
+
131
+ it_behaves_like "a file with the wrong content"
132
+
133
+ it_behaves_like "a securable resource"
134
+ end
135
+ end
136
+
137
+ context "when the target file has the correct content" do
138
+ before(:each) do
139
+ File.open(path, "w") { |f| f.print expected_content }
140
+ @expected_mtime = File.stat(path).mtime
141
+ @expected_atime = File.stat(path).atime
142
+ @expected_checksum = sha256_checksum(path)
143
+ end
144
+
145
+ describe "and the target file has the correct permissions" do
146
+ include_context "setup correct permissions"
147
+
148
+ it_behaves_like "a file with the correct content"
149
+
150
+ it_behaves_like "a securable resource"
151
+ end
152
+
153
+ context "and the target file has incorrect permissions" do
154
+ include_context "setup broken permissions"
155
+
156
+ it_behaves_like "a file with the correct content"
157
+
158
+ it_behaves_like "a securable resource"
159
+ end
160
+ end
161
+
162
+ end
163
+
164
+ shared_context Chef::Resource::File do
165
+ let(:path) do
166
+ File.join(Dir.tmpdir, make_tmpname(file_base, nil))
167
+ end
168
+
169
+ after(:each) do
170
+ FileUtils.rm_r(path) if File.exists?(path)
171
+ FileUtils.rm_r(CHEF_SPEC_BACKUP_PATH) if File.exists?(CHEF_SPEC_BACKUP_PATH)
172
+ end
173
+ end
@@ -0,0 +1,37 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: AJ Christensen (<aj@junglist.gen.nz>)
4
+ # Author:: Ho-Sheng Hsiao (<hosh@opscode.com>)
5
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ module SpecHelpers
21
+ module Knife
22
+ def redefine_argv(value)
23
+ Object.send(:remove_const, :ARGV)
24
+ Object.send(:const_set, :ARGV, value)
25
+ end
26
+
27
+ def with_argv(*argv)
28
+ original_argv = ARGV
29
+ redefine_argv(argv.flatten)
30
+ begin
31
+ yield
32
+ ensure
33
+ redefine_argv(original_argv)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,394 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Author:: Mark Mzyk (<mmzyk@opscode.com>)
4
+ # Author:: John Keiser (<jkeiser@opscode.com>)
5
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ # TODO test that these work when you are logged on as a user joined to a domain (rather than local computer)
22
+ # TODO test that you can set users from other domains
23
+
24
+ require 'etc'
25
+
26
+ shared_context "setup correct permissions" do
27
+ context "on unix", :unix_only do
28
+ context "with root", :requires_root do
29
+ before :each do
30
+ File.chown(Etc.getpwnam('nobody').uid, 1337, path)
31
+ File.chmod(0776, path)
32
+ end
33
+ end
34
+
35
+ context "without root", :requires_unprivileged_user do
36
+ before :each do
37
+ File.chmod(0776, path)
38
+ end
39
+ end
40
+ end
41
+
42
+ # FIXME: windows
43
+ end
44
+
45
+ shared_context "setup broken permissions" do
46
+ context "on unix", :unix_only do
47
+ context "with root", :requires_root do
48
+ before :each do
49
+ File.chown(0, 0, path)
50
+ File.chmod(0644, path)
51
+ end
52
+ end
53
+
54
+ context "without root", :requires_unprivileged_user do
55
+ before :each do
56
+ File.chmod(0644, path)
57
+ end
58
+ end
59
+ end
60
+
61
+ # FIXME: windows
62
+ end
63
+
64
+ shared_examples_for "a securable resource" do
65
+ context "on Unix", :unix_only do
66
+ let(:expected_user_name) { 'nobody' }
67
+ let(:expected_uid) { Etc.getpwnam(expected_user_name).uid }
68
+ let(:desired_gid) { 1337 }
69
+ let(:expected_gid) { 1337 }
70
+
71
+ pending "should set an owner (Rerun specs under root)", :requires_unprivileged_user => true
72
+ pending "should set a group (Rerun specs under root)", :requires_unprivileged_user => true
73
+
74
+ it "should set an owner", :requires_root do
75
+ resource.owner expected_user_name
76
+ resource.run_action(:create)
77
+ File.lstat(path).uid.should == expected_uid
78
+ end
79
+
80
+ it "should set a group", :requires_root do
81
+ resource.group desired_gid
82
+ resource.run_action(:create)
83
+ File.lstat(path).gid.should == expected_gid
84
+ end
85
+
86
+ it "should set permissions in string form as an octal number" do
87
+ mode_string = '776'
88
+ resource.mode mode_string
89
+ resource.run_action(:create)
90
+ pending('Linux does not support lchmod', :if => resource.instance_of?(Chef::Resource::Link) && !os_x? && !freebsd?) do
91
+ (File.lstat(path).mode & 007777).should == (mode_string.oct & 007777)
92
+ end
93
+ end
94
+
95
+ it "should set permissions in numeric form as a ruby-interpreted octal" do
96
+ mode_integer = 0776
97
+ resource.mode mode_integer
98
+ resource.run_action(:create)
99
+ pending('Linux does not support lchmod', :if => resource.instance_of?(Chef::Resource::Link) && !os_x? && !freebsd?) do
100
+ (File.lstat(path).mode & 007777).should == (mode_integer & 007777)
101
+ end
102
+ end
103
+ end
104
+
105
+ context "on Windows", :windows_only do
106
+
107
+ if windows?
108
+ SID = Chef::ReservedNames::Win32::Security::SID
109
+ ACE = Chef::ReservedNames::Win32::Security::ACE
110
+ end
111
+
112
+ def get_security_descriptor(path)
113
+ Chef::ReservedNames::Win32::Security.get_named_security_info(path)
114
+ end
115
+
116
+ def explicit_aces
117
+ descriptor.dacl.select { |ace| ace.explicit? }
118
+ end
119
+
120
+ def extract_ace_properties(aces)
121
+ hashes = []
122
+ aces.each do |ace|
123
+ hashes << { :mask => ace.mask, :type => ace.type, :flags => ace.flags }
124
+ end
125
+ hashes
126
+ end
127
+
128
+ # Standard expected rights
129
+ let(:expected_read_perms) do
130
+ {
131
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ,
132
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ,
133
+ }
134
+ end
135
+
136
+ let(:expected_read_execute_perms) do
137
+ {
138
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE,
139
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE
140
+ }
141
+ end
142
+
143
+ let(:expected_write_perms) do
144
+ {
145
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE,
146
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE
147
+ }
148
+ end
149
+
150
+ let(:expected_modify_perms) do
151
+ {
152
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE,
153
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE
154
+ }
155
+ end
156
+
157
+ let(:expected_full_control_perms) do
158
+ {
159
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_ALL,
160
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS
161
+ }
162
+ end
163
+
164
+ RSpec::Matchers.define :have_expected_properties do |mask, type, flags|
165
+ match do |ace|
166
+ ace.mask == mask
167
+ ace.type == type
168
+ ace.flags == flags
169
+ end
170
+ end
171
+
172
+ def descriptor
173
+ get_security_descriptor(path)
174
+ end
175
+
176
+ before(:each) do
177
+ resource.run_action(:delete)
178
+ end
179
+
180
+ it "sets owner to Administrators on create if owner is not specified" do
181
+ File.exist?(path).should == false
182
+ resource.run_action(:create)
183
+ descriptor.owner.should == SID.Administrators
184
+ end
185
+
186
+ it "sets owner when owner is specified" do
187
+ resource.owner 'Guest'
188
+ resource.run_action(:create)
189
+ descriptor.owner.should == SID.Guest
190
+ end
191
+
192
+ it "fails to set owner when owner has invalid characters" do
193
+ lambda { resource.owner 'Lance "The Nose" Glindenberry III' }.should raise_error#(Chef::Exceptions::ValidationFailed)
194
+ end
195
+
196
+ it "sets owner when owner is specified with a \\" do
197
+ resource.owner "#{ENV['USERDOMAIN']}\\Guest"
198
+ resource.run_action(:create)
199
+ descriptor.owner.should == SID.Guest
200
+ end
201
+
202
+ it "leaves owner alone if owner is not specified and resource already exists" do
203
+ # Set owner to Guest so it's not the same as the current user (which is the default on create)
204
+ resource.owner 'Guest'
205
+ resource.run_action(:create)
206
+ descriptor.owner.should == SID.Guest
207
+
208
+ new_resource = create_resource
209
+ new_resource.owner.should == nil
210
+ new_resource.run_action(:create)
211
+ descriptor.owner.should == SID.Guest
212
+ end
213
+
214
+ it "sets group to None on create if group is not specified" do
215
+ resource.group.should == nil
216
+ File.exist?(path).should == false
217
+ resource.run_action(:create)
218
+ descriptor.group.should == SID.None
219
+ end
220
+
221
+ it "sets group when group is specified" do
222
+ resource.group 'Everyone'
223
+ resource.run_action(:create)
224
+ descriptor.group.should == SID.Everyone
225
+ end
226
+
227
+ it "fails to set group when group has invalid characters" do
228
+ lambda { resource.group 'Lance "The Nose" Glindenberry III' }.should raise_error(Chef::Exceptions::ValidationFailed)
229
+ end
230
+
231
+ it "sets group when group is specified with a \\" do
232
+ pending "Need to find a group containing a backslash that is on most peoples' machines" do
233
+ resource.group "#{ENV['COMPUTERNAME']}\\Administrators"
234
+ resource.run_action(:create)
235
+ descriptor.group.should == SID.Everyone
236
+ end
237
+ end
238
+
239
+ it "leaves group alone if group is not specified and resource already exists" do
240
+ # Set group to Everyone so it's not the default (None)
241
+ resource.group 'Everyone'
242
+ resource.run_action(:create)
243
+ descriptor.group.should == SID.Everyone
244
+
245
+ new_resource = create_resource
246
+ new_resource.group.should == nil
247
+ new_resource.run_action(:create)
248
+ descriptor.group.should == SID.Everyone
249
+ end
250
+
251
+ describe "with rights and deny_rights attributes" do
252
+
253
+ it "correctly sets :read rights" do
254
+ resource.rights(:read, 'Guest')
255
+ resource.run_action(:create)
256
+ explicit_aces.should == allowed_acl(SID.Guest, expected_read_perms)
257
+ end
258
+
259
+ it "correctly sets :read_execute rights" do
260
+ resource.rights(:read_execute, 'Guest')
261
+ resource.run_action(:create)
262
+ explicit_aces.should == allowed_acl(SID.Guest, expected_read_execute_perms)
263
+ end
264
+
265
+ it "correctly sets :write rights" do
266
+ resource.rights(:write, 'Guest')
267
+ resource.run_action(:create)
268
+ explicit_aces.should == allowed_acl(SID.Guest, expected_write_perms)
269
+ end
270
+
271
+ it "correctly sets :modify rights" do
272
+ resource.rights(:modify, 'Guest')
273
+ resource.run_action(:create)
274
+ explicit_aces.should == allowed_acl(SID.Guest, expected_modify_perms)
275
+ end
276
+
277
+ it "correctly sets :full_control rights" do
278
+ resource.rights(:full_control, 'Guest')
279
+ resource.run_action(:create)
280
+ explicit_aces.should == allowed_acl(SID.Guest, expected_full_control_perms)
281
+ end
282
+
283
+ it "correctly sets deny_rights" do
284
+ # deny is an ACE with full rights, but is a deny type ace, not an allow type
285
+ resource.deny_rights(:full_control, 'Guest')
286
+ resource.run_action(:create)
287
+ explicit_aces.should == denied_acl(SID.Guest, expected_full_control_perms)
288
+ end
289
+
290
+ it "Sets multiple rights" do
291
+ resource.rights(:read, 'Everyone')
292
+ resource.rights(:modify, 'Guest')
293
+ resource.run_action(:create)
294
+
295
+ explicit_aces.should ==
296
+ allowed_acl(SID.Everyone, expected_read_perms) +
297
+ allowed_acl(SID.Guest, expected_modify_perms)
298
+ end
299
+
300
+ it "Sets deny_rights ahead of rights" do
301
+ resource.rights(:read, 'Everyone')
302
+ resource.deny_rights(:modify, 'Guest')
303
+ resource.run_action(:create)
304
+
305
+ explicit_aces.should ==
306
+ denied_acl(SID.Guest, expected_modify_perms) +
307
+ allowed_acl(SID.Everyone, expected_read_perms)
308
+ end
309
+
310
+ it "Sets deny_rights ahead of rights when specified in reverse order" do
311
+ resource.deny_rights(:modify, 'Guest')
312
+ resource.rights(:read, 'Everyone')
313
+ resource.run_action(:create)
314
+
315
+ explicit_aces.should ==
316
+ denied_acl(SID.Guest, expected_modify_perms) +
317
+ allowed_acl(SID.Everyone, expected_read_perms)
318
+ end
319
+
320
+ end
321
+
322
+ context "with a mode attribute" do
323
+ if windows?
324
+ Security = Chef::ReservedNames::Win32::API::Security
325
+ end
326
+
327
+ it "respects mode in string form as an octal number" do
328
+ #on windows, mode cannot modify owner and/or group permissons
329
+ #unless the owner and/or group as appropriate is specified
330
+ resource.mode '400'
331
+ resource.owner 'Guest'
332
+ resource.group 'Everyone'
333
+ resource.run_action(:create)
334
+
335
+ explicit_aces.should == [ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ) ]
336
+ end
337
+
338
+ it "respects mode in numeric form as a ruby-interpreted octal" do
339
+ resource.mode 0700
340
+ resource.owner 'Guest'
341
+ resource.run_action(:create)
342
+
343
+ explicit_aces.should == [ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE) ]
344
+ end
345
+
346
+ it "respects the owner, group and everyone bits of mode" do
347
+ resource.mode 0754
348
+ resource.owner 'Guest'
349
+ resource.group 'Administrators'
350
+ resource.run_action(:create)
351
+
352
+ explicit_aces.should == [
353
+ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE),
354
+ ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_EXECUTE),
355
+ ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_READ)
356
+ ]
357
+ end
358
+
359
+ it "respects the individual read, write and execute bits of mode" do
360
+ resource.mode 0421
361
+ resource.owner 'Guest'
362
+ resource.group 'Administrators'
363
+ resource.run_action(:create)
364
+
365
+ explicit_aces.should == [
366
+ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ),
367
+ ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_WRITE | Security::DELETE),
368
+ ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_EXECUTE)
369
+ ]
370
+ end
371
+
372
+ it 'warns when mode tries to set owner bits but owner is not specified' do
373
+ @warn = []
374
+ Chef::Log.stub!(:warn) { |msg| @warn << msg }
375
+
376
+ resource.mode 0400
377
+ resource.run_action(:create)
378
+
379
+ @warn.include?("Mode 400 includes bits for the owner, but owner is not specified").should be_true
380
+ end
381
+
382
+ it 'warns when mode tries to set group bits but group is not specified' do
383
+ @warn = []
384
+ Chef::Log.stub!(:warn) { |msg| @warn << msg }
385
+
386
+ resource.mode 0040
387
+ resource.run_action(:create)
388
+
389
+ @warn.include?("Mode 040 includes bits for the group, but group is not specified").should be_true
390
+ end
391
+ end
392
+
393
+ end
394
+ end