chef-dk 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/chef-dk/builtin_commands.rb +10 -0
  4. data/lib/chef-dk/command/base.rb +2 -2
  5. data/lib/chef-dk/command/clean_policy_cookbooks.rb +116 -0
  6. data/lib/chef-dk/command/clean_policy_revisions.rb +113 -0
  7. data/lib/chef-dk/command/delete_policy.rb +122 -0
  8. data/lib/chef-dk/command/delete_policy_group.rb +122 -0
  9. data/lib/chef-dk/command/export.rb +3 -3
  10. data/lib/chef-dk/command/generate.rb +8 -0
  11. data/lib/chef-dk/command/generator_commands/app.rb +1 -1
  12. data/lib/chef-dk/command/generator_commands/cookbook.rb +1 -1
  13. data/lib/chef-dk/command/generator_commands/policyfile.rb +1 -1
  14. data/lib/chef-dk/command/generator_commands/repo.rb +1 -1
  15. data/lib/chef-dk/command/install.rb +22 -5
  16. data/lib/chef-dk/command/provision.rb +0 -4
  17. data/lib/chef-dk/command/push.rb +1 -2
  18. data/lib/chef-dk/command/shell_init.rb +65 -6
  19. data/lib/chef-dk/command/show_policy.rb +1 -2
  20. data/lib/chef-dk/command/undelete.rb +155 -0
  21. data/lib/chef-dk/command/update.rb +5 -5
  22. data/lib/chef-dk/command/verify.rb +61 -17
  23. data/lib/chef-dk/completions/bash.sh.erb +5 -0
  24. data/lib/chef-dk/completions/chef.fish.erb +10 -0
  25. data/lib/chef-dk/completions/zsh.zsh.erb +21 -0
  26. data/lib/chef-dk/exceptions.rb +12 -0
  27. data/lib/chef-dk/helpers.rb +17 -0
  28. data/lib/chef-dk/policyfile/community_cookbook_source.rb +0 -3
  29. data/lib/chef-dk/policyfile/lister.rb +3 -1
  30. data/lib/chef-dk/policyfile/undo_record.rb +142 -0
  31. data/lib/chef-dk/policyfile/undo_stack.rb +130 -0
  32. data/lib/chef-dk/policyfile_lock.rb +30 -0
  33. data/lib/chef-dk/policyfile_services/clean_policies.rb +5 -4
  34. data/lib/chef-dk/policyfile_services/clean_policy_cookbooks.rb +125 -0
  35. data/lib/chef-dk/policyfile_services/rm_policy.rb +142 -0
  36. data/lib/chef-dk/policyfile_services/rm_policy_group.rb +86 -0
  37. data/lib/chef-dk/policyfile_services/show_policy.rb +1 -1
  38. data/lib/chef-dk/policyfile_services/undelete.rb +108 -0
  39. data/lib/chef-dk/service_exceptions.rb +11 -0
  40. data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +6 -2
  41. data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +1 -1
  42. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +1 -1
  43. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +1 -1
  44. data/lib/chef-dk/version.rb +1 -1
  45. data/lib/kitchen/provisioner/policyfile_zero.rb +4 -1
  46. data/spec/unit/command/base_spec.rb +26 -1
  47. data/spec/unit/command/clean_policy_cookbooks_spec.rb +181 -0
  48. data/spec/unit/command/clean_policy_revisions_spec.rb +181 -0
  49. data/spec/unit/command/delete_policy_group_spec.rb +207 -0
  50. data/spec/unit/command/delete_policy_spec.rb +207 -0
  51. data/spec/unit/command/generate_spec.rb +41 -1
  52. data/spec/unit/command/generator_commands/cookbook_spec.rb +1 -1
  53. data/spec/unit/command/generator_commands/policyfile_spec.rb +1 -1
  54. data/spec/unit/command/install_spec.rb +24 -0
  55. data/spec/unit/command/shell_init_spec.rb +176 -5
  56. data/spec/unit/command/undelete_spec.rb +246 -0
  57. data/spec/unit/helpers_spec.rb +24 -0
  58. data/spec/unit/policyfile/lister_spec.rb +16 -0
  59. data/spec/unit/policyfile/undo_record_spec.rb +260 -0
  60. data/spec/unit/policyfile/undo_stack_spec.rb +266 -0
  61. data/spec/unit/policyfile_lock_serialization_spec.rb +41 -0
  62. data/spec/unit/policyfile_services/clean_policy_cookbooks_spec.rb +275 -0
  63. data/spec/unit/policyfile_services/rm_policy_group_spec.rb +241 -0
  64. data/spec/unit/policyfile_services/rm_policy_spec.rb +266 -0
  65. data/spec/unit/policyfile_services/show_policy_spec.rb +52 -2
  66. data/spec/unit/policyfile_services/undelete_spec.rb +304 -0
  67. metadata +43 -91
@@ -24,6 +24,9 @@ describe ChefDK::PolicyfileLock, "when reading a Policyfile.lock" do
24
24
  {
25
25
  "name" => "example",
26
26
  "run_list" => [ "recipe[cookbook::recipe_name]" ],
27
+ "named_run_lists" => {
28
+ "fast-deploy" => [ "recipe[cookbook::deployit]" ]
29
+ },
27
30
  "cookbook_locks" => {
28
31
  # TODO: add some valid locks
29
32
  },
@@ -50,6 +53,10 @@ describe ChefDK::PolicyfileLock, "when reading a Policyfile.lock" do
50
53
  expect(lockfile.run_list).to eq(["recipe[cookbook::recipe_name]"])
51
54
  end
52
55
 
56
+ it "includes the named run lists" do
57
+ expect(lockfile.named_run_lists).to eq({ "fast-deploy" => [ "recipe[cookbook::deployit]" ] })
58
+ end
59
+
53
60
  it "includes the cookbook locks" do
54
61
  expect(lockfile.cookbook_locks).to eq({})
55
62
  end
@@ -100,6 +107,40 @@ describe ChefDK::PolicyfileLock, "when reading a Policyfile.lock" do
100
107
  expect { lockfile.build_from_lock_data(bad_run_list) }.to raise_error(ChefDK::InvalidLockfile)
101
108
  end
102
109
 
110
+ it "allows the named_run_lists field to be absent" do
111
+ missing_named_run_lists = valid_lock_data.dup
112
+ missing_named_run_lists.delete("named_run_lists")
113
+
114
+ expect { lockfile.build_from_lock_data(missing_named_run_lists) }.to_not raise_error
115
+ end
116
+
117
+ it "requires the named_run_lists field to be a Hash if present" do
118
+ bad_named_run_lists = valid_lock_data.dup
119
+ bad_named_run_lists["named_run_lists"] = false
120
+
121
+ expect { lockfile.build_from_lock_data(bad_named_run_lists) }.to raise_error(ChefDK::InvalidLockfile)
122
+ end
123
+
124
+ it "requires the keys in named_run_lists to be strings" do
125
+ bad_named_run_lists = valid_lock_data.dup
126
+ bad_named_run_lists["named_run_lists"] = { 42 => [] }
127
+
128
+ expect { lockfile.build_from_lock_data(bad_named_run_lists) }.to raise_error(ChefDK::InvalidLockfile)
129
+ end
130
+
131
+ it "requires the values in named_run_lists to be arrays" do
132
+ bad_named_run_lists = valid_lock_data.dup
133
+ bad_named_run_lists["named_run_lists"] = { "bad" => 42 }
134
+
135
+ expect { lockfile.build_from_lock_data(bad_named_run_lists) }.to raise_error(ChefDK::InvalidLockfile)
136
+ end
137
+
138
+ it "requires the values in named_run_lists to be valid run lists" do
139
+ bad_named_run_lists = valid_lock_data.dup
140
+ bad_named_run_lists["named_run_lists"] = { "bad" => [ 42 ] }
141
+
142
+ expect { lockfile.build_from_lock_data(bad_named_run_lists) }.to raise_error(ChefDK::InvalidLockfile)
143
+ end
103
144
  it "requires the `cookbook_locks` section be present and its value is a Hash" do
104
145
  missing_locks = valid_lock_data.dup
105
146
  missing_locks.delete("cookbook_locks")
@@ -0,0 +1,275 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2015 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'spec_helper'
19
+ require 'chef-dk/policyfile_services/clean_policy_cookbooks'
20
+
21
+ describe ChefDK::PolicyfileServices::CleanPolicyCookbooks do
22
+
23
+ let(:cookbook_artifacts_list) do
24
+ {
25
+ "mysql" => {
26
+ "versions" => [
27
+ {
28
+ "identifier" => "6b506252cae939c874bd59b560c339b01c31326b"
29
+ }
30
+ ]
31
+ },
32
+ "build-essential" => {
33
+ "versions" => [
34
+ {
35
+ "identifier" => "2db3df121028894f45497f847de91b91fbf76824"
36
+ },
37
+ {
38
+ "identifier" => "d8ce58401d154378599b0fead81d2c390615602b"
39
+ }
40
+ ]
41
+ }
42
+ }
43
+ end
44
+
45
+ let(:cookbook_ids_by_name) do
46
+ {
47
+ "mysql" => [ "6b506252cae939c874bd59b560c339b01c31326b" ],
48
+ "build-essential" => [ "2db3df121028894f45497f847de91b91fbf76824", "d8ce58401d154378599b0fead81d2c390615602b" ]
49
+ }
50
+ end
51
+
52
+ let(:cookbook_ids_in_sets_by_name) do
53
+ cookbook_ids_by_name.inject({}) do |map, (name, id_list)|
54
+ map[name] = Set.new(id_list)
55
+ map
56
+ end
57
+ end
58
+
59
+ let(:policies_list) do
60
+ {
61
+ "aar" => {
62
+ "revisions" => {
63
+ "37f9b658cdd1d9319bac8920581723efcc2014304b5f3827ee0779e10ffbdcc9" => { }
64
+ }
65
+ },
66
+ "jenkins" => {
67
+ "revisions" => {
68
+ "613f803bdd035d574df7fa6da525b38df45a74ca82b38b79655efed8a189e073" => { },
69
+ "6fe753184c8946052d3231bb4212116df28d89a3a5f7ae52832ad408419dd5eb" => { }
70
+ }
71
+ }
72
+ }
73
+ end
74
+
75
+ let(:http_client) { instance_double(ChefDK::AuthenticatedHTTP) }
76
+
77
+ let(:ui) { TestHelpers::TestUI.new }
78
+
79
+ let(:chef_config) do
80
+ double("Chef::Config",
81
+ chef_server_url: "https://localhost:10443",
82
+ client_key: "/path/to/client/key.pem",
83
+ node_name: "deuce")
84
+ end
85
+
86
+ subject(:clean_policy_cookbooks_service) do
87
+ described_class.new(ui: ui, config: chef_config)
88
+ end
89
+
90
+
91
+ it "configures an HTTP client with the user's credentials" do
92
+ expect(ChefDK::AuthenticatedHTTP).to receive(:new).with("https://localhost:10443",
93
+ signing_key_filename: "/path/to/client/key.pem",
94
+ client_name: "deuce")
95
+ clean_policy_cookbooks_service.http_client
96
+ end
97
+
98
+ context "when an error occurs fetching cookbook data from the server" do
99
+
100
+ let(:response) do
101
+ Net::HTTPResponse.send(:response_class, "500").new("1.0", "500", "Internal Server Error").tap do |r|
102
+ r.instance_variable_set(:@body, "oops")
103
+ end
104
+ end
105
+
106
+ let(:http_exception) do
107
+ begin
108
+ response.error!
109
+ rescue => e
110
+ e
111
+ end
112
+ end
113
+
114
+ before do
115
+ allow(clean_policy_cookbooks_service).to receive(:http_client).and_return(http_client)
116
+ expect(http_client).to receive(:get).with("/policies").and_return({})
117
+ expect(http_client).to receive(:get).with("/cookbook_artifacts").and_raise(http_exception)
118
+ end
119
+
120
+ it "raises a standardized nested exception" do
121
+ expect { clean_policy_cookbooks_service.run }.to raise_error(ChefDK::PolicyCookbookCleanError)
122
+ end
123
+
124
+ end
125
+
126
+ context "when the server returns cookbook data successfully" do
127
+
128
+ before do
129
+ allow(clean_policy_cookbooks_service).to receive(:http_client).and_return(http_client)
130
+
131
+ allow(http_client).to receive(:get).with("/cookbook_artifacts").and_return(cookbook_artifacts_list)
132
+ allow(http_client).to receive(:get).with("/policies").and_return(policies_list)
133
+ end
134
+
135
+ context "when the server has no policy cookbooks" do
136
+
137
+ let(:cookbook_artifacts_list) { {} }
138
+ let(:policies_list) { {} }
139
+
140
+ it "has an empty list for all cookbooks" do
141
+ expect(clean_policy_cookbooks_service.all_cookbooks).to eq({})
142
+ end
143
+
144
+ it "has no in-use cookbook artifacts" do
145
+ expect(clean_policy_cookbooks_service.active_cookbooks).to eq({})
146
+ end
147
+
148
+ it "has no cookbooks to clean" do
149
+ expect(clean_policy_cookbooks_service.cookbooks_to_clean).to eq({})
150
+ end
151
+
152
+ it "does not clean any cookbooks" do
153
+ expect(http_client).to_not receive(:delete)
154
+ clean_policy_cookbooks_service.run
155
+ end
156
+ end
157
+
158
+ context "when the server has policy cookbooks" do
159
+
160
+ let(:policy_aar_37f9b65) do
161
+ {
162
+ "cookbook_locks" => {
163
+ "mysql" => { "identifier" => "6b506252cae939c874bd59b560c339b01c31326b" }
164
+ }
165
+ }
166
+ end
167
+
168
+ let(:policy_jenkins_613f803) do
169
+ {
170
+ "cookbook_locks" => {
171
+ "mysql" => { "identifier" => "6b506252cae939c874bd59b560c339b01c31326b" },
172
+ "build-essential" => { "identifier" => "2db3df121028894f45497f847de91b91fbf76824" }
173
+ }
174
+ }
175
+ end
176
+
177
+ let(:policy_jenkins_6fe7531) do
178
+ {
179
+ "cookbook_locks" => {
180
+ "mysql" => { "identifier" => "6b506252cae939c874bd59b560c339b01c31326b" },
181
+ "build-essential" => { "identifier" => "d8ce58401d154378599b0fead81d2c390615602b" }
182
+ }
183
+ }
184
+ end
185
+
186
+ before do
187
+ allow(http_client).to receive(:get).
188
+ with("/policies/aar/revisions/37f9b658cdd1d9319bac8920581723efcc2014304b5f3827ee0779e10ffbdcc9").
189
+ and_return(policy_aar_37f9b65)
190
+ allow(http_client).to receive(:get).
191
+ with("/policies/jenkins/revisions/613f803bdd035d574df7fa6da525b38df45a74ca82b38b79655efed8a189e073").
192
+ and_return(policy_jenkins_613f803)
193
+ allow(http_client).to receive(:get).
194
+ with("/policies/jenkins/revisions/6fe753184c8946052d3231bb4212116df28d89a3a5f7ae52832ad408419dd5eb").
195
+ and_return(policy_jenkins_6fe7531)
196
+ end
197
+
198
+
199
+ context "and all cookbooks are active" do
200
+
201
+ it "lists all the cookbooks" do
202
+ expect(clean_policy_cookbooks_service.all_cookbooks).to eq(cookbook_ids_by_name)
203
+ end
204
+
205
+ it "lists all active cookbooks" do
206
+ expect(clean_policy_cookbooks_service.active_cookbooks).to eq(cookbook_ids_in_sets_by_name)
207
+ end
208
+
209
+ it "has no cookbooks to clean" do
210
+ expect(clean_policy_cookbooks_service.cookbooks_to_clean).to eq({})
211
+ end
212
+
213
+ it "does not clean any cookbooks" do
214
+ expect(http_client).to_not receive(:delete)
215
+ clean_policy_cookbooks_service.run
216
+ end
217
+ end
218
+
219
+ context "and some cookbooks can be GC'd" do
220
+
221
+ let(:policy_jenkins_6fe7531) do
222
+ {
223
+ "cookbook_locks" => {
224
+ "mysql" => { "identifier" => "6b506252cae939c874bd59b560c339b01c31326b" },
225
+ # this is changed to reference the same cookbook as policy_jenkins_613f803
226
+ "build-essential" => { "identifier" => "2db3df121028894f45497f847de91b91fbf76824" }
227
+ }
228
+ }
229
+ end
230
+
231
+ let(:expected_active_cookbooks) do
232
+ {
233
+ "mysql" => Set.new([ "6b506252cae939c874bd59b560c339b01c31326b" ]),
234
+ "build-essential" => Set.new([ "2db3df121028894f45497f847de91b91fbf76824" ])
235
+ }
236
+ end
237
+
238
+ it "lists all the cookbooks" do
239
+ expect(clean_policy_cookbooks_service.all_cookbooks).to eq(cookbook_ids_by_name)
240
+ end
241
+
242
+ it "lists all active cookbooks" do
243
+ expect(clean_policy_cookbooks_service.active_cookbooks).to eq(expected_active_cookbooks)
244
+ end
245
+
246
+ it "lists non-active cookbooks" do
247
+ expected = { "build-essential" => Set.new([ "d8ce58401d154378599b0fead81d2c390615602b" ]) }
248
+ expect(clean_policy_cookbooks_service.cookbooks_to_clean).to eq(expected)
249
+ end
250
+
251
+ it "deletes the non-active cookbooks" do
252
+ expect(http_client).to receive(:delete).with("/cookbook_artifacts/build-essential/d8ce58401d154378599b0fead81d2c390615602b")
253
+ clean_policy_cookbooks_service.run
254
+ end
255
+
256
+ # Regression test. This was giving us an Argument error for `<Set> - nil`
257
+ context "when there are no active revisions of a given cookbook" do
258
+
259
+ let(:policies_list) { {} }
260
+
261
+ it "deletes the non-active cookbooks" do
262
+ expect(http_client).to receive(:delete).with("/cookbook_artifacts/build-essential/d8ce58401d154378599b0fead81d2c390615602b")
263
+ expect(http_client).to receive(:delete).with("/cookbook_artifacts/build-essential/2db3df121028894f45497f847de91b91fbf76824")
264
+ expect(http_client).to receive(:delete).with("/cookbook_artifacts/mysql/6b506252cae939c874bd59b560c339b01c31326b")
265
+ clean_policy_cookbooks_service.run
266
+ end
267
+
268
+ end
269
+
270
+ end
271
+ end
272
+ end
273
+
274
+ end
275
+
@@ -0,0 +1,241 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2015 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'spec_helper'
19
+ require 'chef-dk/policyfile_services/rm_policy_group'
20
+
21
+ describe ChefDK::PolicyfileServices::RmPolicyGroup do
22
+
23
+ let(:policy_group) { "preprod" }
24
+
25
+ let(:http_client) { instance_double(ChefDK::AuthenticatedHTTP) }
26
+
27
+ let(:ui) { TestHelpers::TestUI.new }
28
+
29
+ let(:non_empty_policy_groups) do
30
+ {
31
+ "dev" => {
32
+ "uri" => "https://chef.example/organizations/testorg/policy_groups/dev",
33
+ "policies" => {
34
+ "appserver" => { "revision_id" => "1111111111111111111111111111111111111111111111111111111111111111" },
35
+ "load-balancer" => { "revision_id" => "5555555555555555555555555555555555555555555555555555555555555555" },
36
+ "db" => { "revision_id" => "9999999999999999999999999999999999999999999999999999999999999999" }
37
+ }
38
+ },
39
+ "preprod" => {
40
+ "uri" => "https://chef.example/organizations/testorg/policy_groups/preprod",
41
+ "policies" => {
42
+ "appserver" => { "revision_id" => "2222222222222222222222222222222222222222222222222222222222222222" },
43
+ "load-balancer" => { "revision_id" => "5555555555555555555555555555555555555555555555555555555555555555" },
44
+ "db" => { "revision_id" => "9999999999999999999999999999999999999999999999999999999999999999" }
45
+ }
46
+ }
47
+ }
48
+ end
49
+
50
+
51
+ let(:empty_policy_groups) do
52
+ {
53
+ "dev" => {
54
+ "uri" => "https://chef.example/organizations/testorg/policy_groups/dev"
55
+ },
56
+ "preprod" => {
57
+ "uri" => "https://chef.example/organizations/testorg/policy_groups/preprod"
58
+ }
59
+ }
60
+ end
61
+
62
+ let(:chef_config) do
63
+ double("Chef::Config",
64
+ chef_server_url: "https://localhost:10443",
65
+ client_key: "/path/to/client/key.pem",
66
+ node_name: "deuce")
67
+ end
68
+
69
+ subject(:rm_policy_group_service) do
70
+ described_class.new(policy_group: policy_group, ui: ui, config: chef_config)
71
+ end
72
+
73
+ let(:undo_record) do
74
+ rm_policy_group_service.undo_record
75
+ end
76
+
77
+ let(:undo_stack) do
78
+ rm_policy_group_service.undo_stack
79
+ end
80
+
81
+
82
+ it "configures an HTTP client" do
83
+ expect(ChefDK::AuthenticatedHTTP).to receive(:new).with("https://localhost:10443",
84
+ signing_key_filename: "/path/to/client/key.pem",
85
+ client_name: "deuce")
86
+ rm_policy_group_service.http_client
87
+ end
88
+
89
+ context "when the server returns an error fetching the policy data" do
90
+
91
+ let(:response) do
92
+ Net::HTTPResponse.send(:response_class, "500").new("1.0", "500", "Internal Server Error").tap do |r|
93
+ r.instance_variable_set(:@body, "oops")
94
+ end
95
+ end
96
+
97
+ let(:http_exception) do
98
+ begin
99
+ response.error!
100
+ rescue => e
101
+ e
102
+ end
103
+ end
104
+
105
+ before do
106
+ allow(rm_policy_group_service).to receive(:http_client).and_return(http_client)
107
+ end
108
+
109
+ describe "when getting an error response fetching the policy group" do
110
+
111
+ before do
112
+ expect(http_client).to receive(:get).with("/policy_groups").and_raise(http_exception)
113
+ end
114
+
115
+ it "re-raises the error with a standardized exception class" do
116
+ expect { rm_policy_group_service.run }.to raise_error(ChefDK::DeletePolicyGroupError)
117
+ end
118
+
119
+ end
120
+
121
+ describe "when getting an error fetching policy revisions" do
122
+
123
+ before do
124
+ expect(http_client).to receive(:get).with("/policy_groups").and_return(non_empty_policy_groups)
125
+ expect(http_client).to receive(:get).
126
+ with("/policies/appserver/revisions/2222222222222222222222222222222222222222222222222222222222222222").
127
+ and_raise(http_exception)
128
+ end
129
+
130
+ it "re-raises the error with a standardized exception class" do
131
+ expect { rm_policy_group_service.run }.to raise_error(ChefDK::DeletePolicyGroupError)
132
+ end
133
+
134
+ end
135
+
136
+
137
+ end
138
+
139
+ context "when the given group doesn't exist" do
140
+
141
+ let(:policy_group) { "incorrect_policy_group_name" }
142
+
143
+ before do
144
+ allow(rm_policy_group_service).to receive(:http_client).and_return(http_client)
145
+ expect(http_client).to receive(:get).with("/policy_groups").and_return(non_empty_policy_groups)
146
+ end
147
+
148
+ it "prints a message stating that the group doesn't exist" do
149
+ expect { rm_policy_group_service.run }.to_not raise_error
150
+ expect(ui.output).to eq("Policy group 'incorrect_policy_group_name' does not exist on the server\n")
151
+ end
152
+
153
+ end
154
+
155
+ context "when the group exists but has no policies assigned to it" do
156
+
157
+ before do
158
+ allow(rm_policy_group_service).to receive(:http_client).and_return(http_client)
159
+ expect(http_client).to receive(:get).with("/policy_groups").and_return(empty_policy_groups)
160
+ expect(http_client).to receive(:delete).with("/policy_groups/preprod")
161
+ expect(undo_stack).to receive(:push).with(undo_record)
162
+ end
163
+
164
+ it "removes the group" do
165
+ rm_policy_group_service.run
166
+ expect(ui.output).to include("Removed policy group 'preprod'.")
167
+ end
168
+
169
+ it "stores the group in the restore file" do
170
+ rm_policy_group_service.run
171
+ expect(undo_record.description).to eq("delete-policy-group preprod")
172
+ expect(undo_record.policy_groups).to eq( [ policy_group ] )
173
+ expect(undo_record.policy_revisions).to be_empty
174
+ end
175
+
176
+ end
177
+
178
+ context "when the group exists and has policies assigned to it" do
179
+
180
+ let(:policy_appserver_2) do
181
+ {
182
+ "name" => "appserver",
183
+ "revision_id" => "2222222222222222222222222222222222222222222222222222222222222222"
184
+ }
185
+ end
186
+
187
+ let(:policy_load_balancer_5) do
188
+ {
189
+ "name" => "load-balancer",
190
+ "revision_id" => "5555555555555555555555555555555555555555555555555555555555555555"
191
+ }
192
+ end
193
+
194
+ let(:policy_db_9) do
195
+ {
196
+ "name" => "db",
197
+ "revision_id" => "9999999999999999999999999999999999999999999999999999999999999999"
198
+ }
199
+ end
200
+
201
+ before do
202
+ allow(rm_policy_group_service).to receive(:http_client).and_return(http_client)
203
+ expect(http_client).to receive(:get).with("/policy_groups").and_return(non_empty_policy_groups)
204
+ expect(http_client).to receive(:get).
205
+ with("/policies/appserver/revisions/2222222222222222222222222222222222222222222222222222222222222222").
206
+ and_return(policy_appserver_2)
207
+ expect(http_client).to receive(:get).
208
+ with("/policies/load-balancer/revisions/5555555555555555555555555555555555555555555555555555555555555555").
209
+ and_return(policy_load_balancer_5)
210
+ expect(http_client).to receive(:get).
211
+ with("/policies/db/revisions/9999999999999999999999999999999999999999999999999999999999999999").
212
+ and_return(policy_db_9)
213
+
214
+ expect(http_client).to receive(:delete).with("/policy_groups/preprod")
215
+ expect(undo_stack).to receive(:push).with(undo_record)
216
+ end
217
+
218
+ it "removes the group" do
219
+ rm_policy_group_service.run
220
+ expect(ui.output).to include("Removed policy group 'preprod'.")
221
+ end
222
+
223
+ it "stores the group and policyfile revision contents in the restore file" do
224
+ rm_policy_group_service.run
225
+ expect(undo_record.description).to eq("delete-policy-group preprod")
226
+ expect(undo_record.policy_groups).to eq( [ policy_group ] )
227
+
228
+ expected_policy_revision_undo_data =
229
+ [
230
+ { policy_name: "appserver", policy_group: "preprod", data: policy_appserver_2},
231
+ { policy_name: "load-balancer", policy_group: "preprod", data: policy_load_balancer_5},
232
+ { policy_name: "db", policy_group: "preprod", data: policy_db_9}
233
+ ]
234
+
235
+ expect(undo_record.policy_revisions.map(&:to_h)).to match_array(expected_policy_revision_undo_data)
236
+ end
237
+
238
+ end
239
+
240
+ end
241
+