moose-inventory 1.0.8 → 2.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.
Files changed (104) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +49 -0
  3. data/.github/workflows/release.yml +58 -0
  4. data/.gitignore +1 -1
  5. data/.gitleaks.toml +9 -0
  6. data/.rubocop.yml +19 -784
  7. data/BACKLOG.md +290 -0
  8. data/Gemfile.lock +95 -0
  9. data/README.md +38 -9
  10. data/Rakefile +1 -1
  11. data/bin/moose-inventory +1 -1
  12. data/docs/release/publishing.md +109 -0
  13. data/docs/release/release-readiness.md +55 -0
  14. data/docs/security-audit-2026-05-21.md +71 -0
  15. data/docs/security-audit-2026-05-26-rerun.md +75 -0
  16. data/docs/security-audit-2026-05-26.md +63 -0
  17. data/lib/moose_inventory/cli/formatter.rb +16 -17
  18. data/lib/moose_inventory/cli/group.rb +4 -1
  19. data/lib/moose_inventory/cli/group_add.rb +89 -75
  20. data/lib/moose_inventory/cli/group_addchild.rb +84 -71
  21. data/lib/moose_inventory/cli/group_addhost.rb +78 -69
  22. data/lib/moose_inventory/cli/group_addvar.rb +37 -37
  23. data/lib/moose_inventory/cli/group_get.rb +23 -26
  24. data/lib/moose_inventory/cli/group_list.rb +12 -15
  25. data/lib/moose_inventory/cli/group_listvars.rb +12 -14
  26. data/lib/moose_inventory/cli/group_rm.rb +104 -76
  27. data/lib/moose_inventory/cli/group_rmchild.rb +99 -54
  28. data/lib/moose_inventory/cli/group_rmhost.rb +64 -60
  29. data/lib/moose_inventory/cli/group_rmvar.rb +5 -5
  30. data/lib/moose_inventory/cli/helpers.rb +76 -0
  31. data/lib/moose_inventory/cli/host.rb +4 -1
  32. data/lib/moose_inventory/cli/host_add.rb +51 -66
  33. data/lib/moose_inventory/cli/host_addgroup.rb +77 -68
  34. data/lib/moose_inventory/cli/host_addvar.rb +6 -6
  35. data/lib/moose_inventory/cli/host_get.rb +15 -18
  36. data/lib/moose_inventory/cli/host_list.rb +3 -3
  37. data/lib/moose_inventory/cli/host_listvars.rb +21 -23
  38. data/lib/moose_inventory/cli/host_rm.rb +9 -9
  39. data/lib/moose_inventory/cli/host_rmgroup.rb +63 -60
  40. data/lib/moose_inventory/cli/host_rmvar.rb +3 -3
  41. data/lib/moose_inventory/config/config.rb +43 -40
  42. data/lib/moose_inventory/db/db.rb +92 -52
  43. data/lib/moose_inventory/db/models.rb +11 -12
  44. data/lib/moose_inventory/inventory_context.rb +50 -0
  45. data/lib/moose_inventory/operations/add_associations.rb +127 -0
  46. data/lib/moose_inventory/operations/add_groups.rb +115 -0
  47. data/lib/moose_inventory/operations/add_hosts.rb +110 -0
  48. data/lib/moose_inventory/operations/group_child_relations.rb +118 -0
  49. data/lib/moose_inventory/operations/group_cleanup.rb +55 -0
  50. data/lib/moose_inventory/operations/remove_associations.rb +101 -0
  51. data/lib/moose_inventory/operations/remove_groups.rb +79 -0
  52. data/lib/moose_inventory/version.rb +1 -1
  53. data/moose-inventory.gemspec +38 -20
  54. data/scripts/check.sh +10 -0
  55. data/scripts/ci/check_permissions.sh +35 -0
  56. data/scripts/ci/check_rubocop.sh +28 -0
  57. data/scripts/ci/check_secrets.sh +26 -0
  58. data/scripts/ci/check_security.sh +68 -0
  59. data/scripts/ci/install_security_tools.sh +47 -0
  60. data/scripts/ci/package_sanity.sh +46 -0
  61. data/scripts/files.rb +1 -4
  62. data/scripts/install_dependencies.sh +19 -0
  63. data/scripts/reports.sh +2 -2
  64. data/spec/lib/moose_inventory/cli/cli_spec.rb +13 -14
  65. data/spec/lib/moose_inventory/cli/group_add_spec.rb +118 -119
  66. data/spec/lib/moose_inventory/cli/group_addchild_spec.rb +49 -51
  67. data/spec/lib/moose_inventory/cli/group_addhost_spec.rb +80 -83
  68. data/spec/lib/moose_inventory/cli/group_addvar_spec.rb +91 -91
  69. data/spec/lib/moose_inventory/cli/group_get_spec.rb +22 -23
  70. data/spec/lib/moose_inventory/cli/group_list_spec.rb +19 -20
  71. data/spec/lib/moose_inventory/cli/group_listvar_spec.rb +35 -36
  72. data/spec/lib/moose_inventory/cli/group_rm_spec.rb +115 -78
  73. data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +86 -45
  74. data/spec/lib/moose_inventory/cli/group_rmhost_spec.rb +43 -46
  75. data/spec/lib/moose_inventory/cli/group_rmvar_spec.rb +131 -131
  76. data/spec/lib/moose_inventory/cli/group_spec.rb +9 -9
  77. data/spec/lib/moose_inventory/cli/host_add_spec.rb +103 -43
  78. data/spec/lib/moose_inventory/cli/host_addgroup_spec.rb +78 -80
  79. data/spec/lib/moose_inventory/cli/host_addvar_spec.rb +122 -122
  80. data/spec/lib/moose_inventory/cli/host_get_spec.rb +16 -16
  81. data/spec/lib/moose_inventory/cli/host_list_spec.rb +8 -8
  82. data/spec/lib/moose_inventory/cli/host_listvar_spec.rb +50 -52
  83. data/spec/lib/moose_inventory/cli/host_rm_spec.rb +12 -12
  84. data/spec/lib/moose_inventory/cli/host_rmgroup_spec.rb +48 -51
  85. data/spec/lib/moose_inventory/cli/host_rmvar_spec.rb +136 -136
  86. data/spec/lib/moose_inventory/config/config_spec.rb +16 -3
  87. data/spec/lib/moose_inventory/db/db_spec.rb +386 -2
  88. data/spec/lib/moose_inventory/db/models_spec.rb +10 -11
  89. data/spec/lib/moose_inventory/operations/add_associations_spec.rb +77 -0
  90. data/spec/lib/moose_inventory/operations/add_groups_spec.rb +65 -0
  91. data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +69 -0
  92. data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +76 -0
  93. data/spec/lib/moose_inventory/operations/remove_associations_spec.rb +78 -0
  94. data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +57 -0
  95. data/spec/shared/shared_config_setup.rb +2 -2
  96. data/spec/spec_helper.rb +7 -8
  97. metadata +157 -105
  98. data/.coveralls.yml +0 -0
  99. data/Guardfile +0 -38
  100. data/config/dotfiles/coveralls.yml +0 -0
  101. data/config/dotfiles/gitignore +0 -20
  102. data/config/dotfiles/rubocop.yml +0 -793
  103. data/scripts/guard_quality.sh +0 -3
  104. data/scripts/guard_test.sh +0 -2
@@ -6,7 +6,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
6
6
  @mockarg_parts = {
7
7
  config: File.join(spec_root, 'config/config.yml'),
8
8
  format: 'yaml',
9
- env: 'test'
9
+ env: 'test',
10
10
  }
11
11
 
12
12
  @mockargs = []
@@ -23,7 +23,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
23
23
 
24
24
  @console = Moose::Inventory::Cli::Formatter
25
25
  @group = Moose::Inventory::Cli::Group
26
- @cli = Moose::Inventory::Cli
26
+ @cli = Moose::Inventory::Cli
27
27
  @app = Moose::Inventory::Cli::Application
28
28
  end
29
29
 
@@ -42,7 +42,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
42
42
  #---------------------
43
43
  it 'should return an empty set when no results' do
44
44
  # no items in the db
45
- actual = runner { @app.start(%W(group list)) }
45
+ actual = runner { @app.start(%w(group list)) }
46
46
 
47
47
  desired = { aborted: false, STDOUT: '', STDERR: '' }
48
48
  desired[:STDOUT] = {}.to_yaml
@@ -59,14 +59,14 @@ RSpec.describe Moose::Inventory::Cli::Group do
59
59
  groups = %w(group1 group2 group3)
60
60
  groups.each do |name|
61
61
  runner { @app.start(%W(group add #{name})) }
62
- runner { @app.start(%W(group addvar #{ name } #{var})) }
62
+ runner { @app.start(%W(group addvar #{name} #{var})) }
63
63
  mock[name.to_sym] = {}
64
- mock[name.to_sym][:groupvars] = {foo: 'bar'}
64
+ mock[name.to_sym][:groupvars] = { foo: 'bar' }
65
65
  end
66
66
 
67
67
  # items should now be in the db
68
- actual = runner{ @app.start(%w(group list)) }
69
-
68
+ actual = runner { @app.start(%w(group list)) }
69
+
70
70
  desired = { aborted: false, STDOUT: '', STDERR: '' }
71
71
  desired[:STDOUT] = mock.to_yaml
72
72
 
@@ -75,28 +75,27 @@ RSpec.describe Moose::Inventory::Cli::Group do
75
75
 
76
76
  #---------------------
77
77
  it 'should be an alias of --list (i.e. Ansible parameter)' do
78
-
79
78
  host_name = 'test_host'
80
79
 
81
80
  mock = {}
82
81
  groups = %w(group1 group2 group3)
83
82
  groups.each do |name|
84
83
  runner { @app.start(%W(group add #{name})) }
85
- mock[name.to_sym] = {}
84
+ mock[name.to_sym] = { hosts: [] }
86
85
  end
87
-
86
+
88
87
  args = @mockargs.clone
89
- args << "--list"
90
-
91
- actual = runner{ @cli.start(args) }
92
-
93
- #@console.out(actual, 'y')
94
-
88
+ args << '--list'
89
+
90
+ actual = runner { @cli.start(args) }
91
+
92
+ # @console.out(actual, 'y')
93
+
95
94
  desired = { aborted: false, STDOUT: '', STDERR: '' }
96
95
  desired[:STDOUT] = mock.to_json + "\n"
97
-
96
+
98
97
  expected(actual, desired)
99
- end
100
-
98
+ end
99
+ end
101
100
  end
102
- end
101
+
@@ -6,7 +6,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
6
6
  @mockarg_parts = {
7
7
  config: File.join(spec_root, 'config/config.yml'),
8
8
  format: 'yaml',
9
- env: 'test'
9
+ env: 'test',
10
10
  }
11
11
 
12
12
  @mockargs = []
@@ -23,12 +23,12 @@ RSpec.describe Moose::Inventory::Cli::Group do
23
23
 
24
24
  @console = Moose::Inventory::Cli::Formatter
25
25
  @group = Moose::Inventory::Cli::Group
26
- @cli = Moose::Inventory::Cli
26
+ @cli = Moose::Inventory::Cli
27
27
  @app = Moose::Inventory::Cli::Application
28
28
  end
29
29
 
30
30
  before(:each) do
31
- # We make some @cli calls, which changes config,
31
+ # We make some @cli calls, which changes config,
32
32
  # so we must reset config on each pass
33
33
  @config.init(@mockargs)
34
34
  @db.reset
@@ -41,79 +41,78 @@ RSpec.describe Moose::Inventory::Cli::Group do
41
41
  result = @group.instance_methods(false).include?(:listvars)
42
42
  expect(result).to eq(true)
43
43
  end
44
-
44
+
45
45
  #-----------------
46
46
  it '<missing args> ... should abort with an error' do
47
- actual = runner { @app.start(%w(group listvars)) }
47
+ actual = runner { @app.start(%w(group listvars)) }
48
48
 
49
49
  # Check output
50
- desired = { aborted: true}
50
+ desired = { aborted: true }
51
51
  desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 1 or more.\n"
52
52
  expected(actual, desired)
53
53
  end
54
-
54
+
55
55
  #-----------------
56
56
  it '--ansible <missing args> ... should abort with an error' do
57
-
58
57
  args = @mockargs.clone
59
- args.concat( %w(--ansible group listvars) ).flatten
60
-
61
- actual = runner{ @cli.start(args) }
62
-
58
+ args.concat(%w(--ansible group listvars)).flatten
59
+
60
+ actual = runner { @cli.start(args) }
61
+
63
62
  # Check output
64
- desired = { aborted: true}
63
+ desired = { aborted: true }
65
64
  desired[:STDERR] = "ERROR: Wrong number of arguments for Ansible mode, 0 for 1.\n"
66
65
  expected(actual, desired)
67
66
  end
68
-
67
+
69
68
  #------------------------
70
69
  it 'GROUP ... should return a list of group variables grouped by group' do
71
- group_name ='test_group'
70
+ group_name = 'test_group'
72
71
  group_vars = %w(foo=bar cow=chicken)
73
-
74
- tmp = runner { @app.start(%W(group add #{group_name} )) }
72
+
73
+ tmp = runner { @app.start(%W(group add #{group_name})) }
75
74
  tmp = runner { @app.start(%W(group addvar #{group_name} #{group_vars[0]} #{group_vars[1]})) }
76
-
75
+
77
76
  actual = runner do
78
77
  @app.start(%W(group listvars #{group_name}))
79
78
  end
80
79
 
81
- #@console.out(actual, 'y')
82
-
80
+ # @console.out(actual, 'y')
81
+
83
82
  # Check output
84
83
  mock = {}
85
- mock[group_name.to_sym] = {}
84
+ mock[group_name.to_sym] = {}
86
85
  group_vars.each do |hv|
87
- hv_array = hv.split('=')
88
- mock[group_name.to_sym][hv_array[0].to_sym] = hv_array[1]
86
+ hv_array = hv.split('=')
87
+ mock[group_name.to_sym][hv_array[0].to_sym] = hv_array[1]
89
88
  end
90
-
89
+
91
90
  desired = {}
92
91
  desired[:STDOUT] = mock.to_yaml
93
92
  expected(actual, desired)
94
93
  end
95
-
94
+
96
95
  #------------------------
97
96
  it '--ansible GROUP ... should return a list of group variables, in a style akin to Ansible\'s \'--host HOSTNAME\'' do
98
- group_name ='test_group'
97
+ group_name = 'test_group'
99
98
  group_vars = %w(foo=bar cow=chicken)
100
-
101
- tmp = runner { @app.start(%W(group add #{group_name} )) }
99
+
100
+ tmp = runner { @app.start(%W(group add #{group_name})) }
102
101
  tmp = runner { @app.start(%W(group addvar #{group_name} #{group_vars[0]} #{group_vars[1]})) }
103
-
102
+
104
103
  actual = runner do
105
- @cli.start(%W(--ansible group listvars #{group_name}))
104
+ @cli.start(%W(--config #{@mockarg_parts[:config]} --ansible group listvars #{group_name}))
106
105
  end
107
-
108
- #@console.out(actual, 'y')
109
-
106
+
107
+ # @console.out(actual, 'y')
108
+
110
109
  # Check output
111
110
  mock = {}
112
111
  group_vars.each do |hv|
113
- hv_array = hv.split('=')
114
- mock[hv_array[0].to_sym] = hv_array[1]
112
+ hv_array = hv.split('=')
113
+ mock[hv_array[0].to_sym] = hv_array[1]
115
114
  end
116
-
115
+
117
116
  desired = {}
118
117
  desired[:STDOUT] = mock.to_json + "\n"
119
118
  expected(actual, desired)
@@ -9,7 +9,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
9
9
  @mockarg_parts = {
10
10
  config: File.join(spec_root, 'config/config.yml'),
11
11
  format: 'yaml',
12
- env: 'test'
12
+ env: 'test',
13
13
  }
14
14
 
15
15
  @mockargs = []
@@ -22,7 +22,7 @@ RSpec.describe Moose::Inventory::Cli::Group do
22
22
  @config.init(@mockargs)
23
23
 
24
24
  @console = Moose::Inventory::Cli::Formatter
25
-
25
+
26
26
  @db = Moose::Inventory::DB
27
27
  @db.init if @db.db.nil?
28
28
 
@@ -52,18 +52,17 @@ RSpec.describe Moose::Inventory::Cli::Group do
52
52
  desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 1 or more.\n"
53
53
  expected(actual, desired)
54
54
  end
55
-
55
+
56
56
  # --------------------
57
57
  it 'ungrouped ... should abort with an error' do
58
- actual = runner { @app.start(%W(group rm ungrouped)) }
58
+ actual = runner { @app.start(%w(group rm ungrouped)) }
59
59
 
60
60
  # Check output
61
- desired = {aborted: true}
61
+ desired = { aborted: true }
62
62
  desired[:STDERR] =
63
63
  "Cannot manually manipulate the automatic group 'ungrouped'\n"
64
64
  expected(actual, desired)
65
- end
66
-
65
+ end
67
66
 
68
67
  #---------------
69
68
  it '<non-existent group> ... should warn about non-existent groups' do
@@ -73,10 +72,10 @@ RSpec.describe Moose::Inventory::Cli::Group do
73
72
  # already exists.
74
73
 
75
74
  # no items in the db
76
- group_name = "fake"
77
- actual = runner { @app.start(%W(group rm #{group_name})) }
78
-
79
- #@console.out(actual,'y')
75
+ group_name = 'fake'
76
+ actual = runner { @app.start(%W(group rm #{group_name})) }
77
+
78
+ # @console.out(actual,'y')
80
79
  desired = {}
81
80
  desired[:STDOUT] =
82
81
  "Remove group '#{group_name}':\n"\
@@ -114,26 +113,26 @@ RSpec.describe Moose::Inventory::Cli::Group do
114
113
  group = @db.models[:group].find(name: group_name)
115
114
  expect(group).to be_nil
116
115
  end
117
-
116
+
118
117
  #---------------
119
118
  it "GROUP ... should handle the automatic 'ungrouped' group for associated hosts" do
120
- host_name = 'test-host1'
121
- group_name = 'test-group1'
122
-
123
- tmp = runner { @app.start(%W(group add #{group_name} --hosts #{host_name})) }
124
- expect(tmp[:unexpected]).to eq(false)
125
- expect(tmp[:aborted]).to eq(false)
126
- host = @db.models[:host].find(name: host_name)
127
- groups_ds = host.groups_dataset
128
- expect(groups_ds).not_to be_nil
129
- expect(groups_ds[name: 'ungrouped']).to be_nil # Shouldn't be ungrouped
130
-
131
- # Now do the rm
132
- actual = runner { @app.start(%W(group rm #{group_name})) }
133
-
134
- # @console.out(actual)
135
-
136
- # Check output
119
+ host_name = 'test-host1'
120
+ group_name = 'test-group1'
121
+
122
+ tmp = runner { @app.start(%W(group add #{group_name} --hosts #{host_name})) }
123
+ expect(tmp[:unexpected]).to eq(false)
124
+ expect(tmp[:aborted]).to eq(false)
125
+ host = @db.models[:host].find(name: host_name)
126
+ groups_ds = host.groups_dataset
127
+ expect(groups_ds).not_to be_nil
128
+ expect(groups_ds[name: 'ungrouped']).to be_nil # Shouldn't be ungrouped
129
+
130
+ # Now do the rm
131
+ actual = runner { @app.start(%W(group rm #{group_name})) }
132
+
133
+ # @console.out(actual)
134
+
135
+ # Check output
137
136
  desired = {}
138
137
  desired[:STDOUT] =
139
138
  "Remove group '#{group_name}':\n"\
@@ -147,16 +146,16 @@ RSpec.describe Moose::Inventory::Cli::Group do
147
146
  "Succeeded.\n"
148
147
  expected(actual, desired)
149
148
 
150
- # Check db
151
- group = @db.models[:group].find(name: group_name)
152
- expect(group).to be_nil
153
-
154
- host = @db.models[:host].find(name: host_name)
155
- expect(host).not_to be_nil
156
- groups_ds = host.groups_dataset
157
- expect(groups_ds).not_to be_nil
158
- expect(groups_ds[name: 'ungrouped']).not_to be_nil
159
- end
149
+ # Check db
150
+ group = @db.models[:group].find(name: group_name)
151
+ expect(group).to be_nil
152
+
153
+ host = @db.models[:host].find(name: host_name)
154
+ expect(host).not_to be_nil
155
+ groups_ds = host.groups_dataset
156
+ expect(groups_ds).not_to be_nil
157
+ expect(groups_ds[name: 'ungrouped']).not_to be_nil
158
+ end
160
159
 
161
160
  #---------------
162
161
  it 'GROUP1 GROUP2 ... should remove multiple groups' do
@@ -168,20 +167,19 @@ RSpec.describe Moose::Inventory::Cli::Group do
168
167
  actual = runner { @app.start(%w(group rm) + names) }
169
168
 
170
169
  # Check output
171
- desired = {STDOUT: ''}
170
+ desired = { STDOUT: '' }
172
171
  names.each do |name|
173
172
  # Check output
174
173
  desired[:STDOUT] = desired[:STDOUT] +
175
- "Remove group '#{name}':\n"\
176
- " - Retrieve group '#{name}'...\n"\
177
- " - OK\n"\
178
- " - Destroy group '#{name}'...\n"\
179
- " - OK\n"\
180
- " - All OK\n"
174
+ "Remove group '#{name}':\n"\
175
+ " - Retrieve group '#{name}'...\n"\
176
+ " - OK\n"\
177
+ " - Destroy group '#{name}'...\n"\
178
+ " - OK\n"\
179
+ " - All OK\n"
181
180
  end
182
181
  desired[:STDOUT] = desired[:STDOUT] + "Succeeded.\n"
183
182
  expected(actual, desired)
184
-
185
183
 
186
184
  # Check db
187
185
  groups = @db.models[:group].all
@@ -190,27 +188,27 @@ RSpec.describe Moose::Inventory::Cli::Group do
190
188
 
191
189
  #---------------
192
190
  it 'GROUP ... should remove GROUP, where GROUP has an associated parent.' do
193
- @db.models[:group].create(name: "parent")
194
- runner { @app.start(%w(group addchild parent child) ) }
191
+ @db.models[:group].create(name: 'parent')
192
+ runner { @app.start(%w(group addchild parent child)) }
193
+
194
+ actual = runner { @app.start(%w(group rm child)) }
195
195
 
196
- actual = runner { @app.start(%w(group rm child) ) }
197
-
198
196
  # Check output
199
- desired = {STDOUT: ''}
197
+ desired = { STDOUT: '' }
200
198
  # Check output
201
199
  desired[:STDOUT] = desired[:STDOUT] +
202
- "Remove group 'child':\n"\
203
- " - Retrieve group 'child'...\n"\
204
- " - OK\n"\
205
- " - Remove association {group:child <-> group:parent}...\n"\
206
- " - OK\n"\
207
- " - Destroy group 'child'...\n"\
208
- " - OK\n"\
209
- " - All OK\n"
200
+ "Remove group 'child':\n"\
201
+ " - Retrieve group 'child'...\n"\
202
+ " - OK\n"\
203
+ " - Remove association {group:child <-> group:parent}...\n"\
204
+ " - OK\n"\
205
+ " - Destroy group 'child'...\n"\
206
+ " - OK\n"\
207
+ " - All OK\n"
210
208
 
211
209
  desired[:STDOUT] = desired[:STDOUT] + "Succeeded.\n"
212
210
  expected(actual, desired)
213
-
211
+
214
212
  # Check db
215
213
  groups = @db.models[:group].all
216
214
  expect(groups.count).to eq(1)
@@ -218,31 +216,70 @@ RSpec.describe Moose::Inventory::Cli::Group do
218
216
 
219
217
  #---------------
220
218
  it 'GROUP ... should remove GROUP, where GROUP has an associated child.' do
221
- @db.models[:group].create(name: "parent")
222
- runner { @app.start(%w(group addchild parent child) ) }
223
-
224
- actual = runner { @app.start(%w(group rm parent) ) }
225
-
219
+ @db.models[:group].create(name: 'parent')
220
+ runner { @app.start(%w(group addchild parent child)) }
221
+
222
+ actual = runner { @app.start(%w(group rm parent)) }
223
+
226
224
  # Check output
227
- desired = {STDOUT: ''}
225
+ desired = { STDOUT: '' }
228
226
  # Check output
229
227
  desired[:STDOUT] = desired[:STDOUT] +
230
- "Remove group 'parent':\n"\
231
- " - Retrieve group 'parent'...\n"\
232
- " - OK\n"\
233
- " - Remove association {group:parent <-> group:child}...\n"\
234
- " - OK\n"\
235
- " - Destroy group 'parent'...\n"\
236
- " - OK\n"\
237
- " - All OK\n"
238
-
228
+ "Remove group 'parent':\n"\
229
+ " - Retrieve group 'parent'...\n"\
230
+ " - OK\n"\
231
+ " - Remove association {group:parent <-> group:child}...\n"\
232
+ " - OK\n"\
233
+ " - Destroy group 'parent'...\n"\
234
+ " - OK\n"\
235
+ " - All OK\n"
236
+
239
237
  desired[:STDOUT] = desired[:STDOUT] + "Succeeded.\n"
240
238
  expected(actual, desired)
241
-
239
+
242
240
  # Check db
243
241
  groups = @db.models[:group].all
244
242
  expect(groups.count).to eq(1)
245
243
  end
246
-
244
+
245
+ #---------------
246
+ it 'GROUP --recursive ... should remove orphaned child groups recursively' do
247
+ runner { @app.start(%w(group add parent)) }
248
+ runner { @app.start(%w(group add child --hosts child-host)) }
249
+ runner { @app.start(%w(group add grandchild)) }
250
+ runner { @app.start(%w(group addchild parent child)) }
251
+ runner { @app.start(%w(group addchild child grandchild)) }
252
+
253
+ actual = runner { @app.start(%w(group rm --recursive parent)) }
254
+
255
+ expect(actual[:unexpected]).to eq(false)
256
+ expect(actual[:aborted]).to eq(false)
257
+ expect(actual[:STDOUT]).to include("- Recursively delete orphaned group 'child'...\n")
258
+ expect(actual[:STDOUT]).to include("- Recursively delete orphaned group 'grandchild'...\n")
259
+
260
+ %w(parent child grandchild).each do |name|
261
+ expect(@db.models[:group].find(name: name)).to be_nil
262
+ end
263
+
264
+ host = @db.models[:host].find(name: 'child-host')
265
+ expect(host.groups_dataset[name: 'ungrouped']).not_to be_nil
266
+ end
267
+
268
+ #---------------
269
+ it 'GROUP --recursive ... should not remove child groups with another parent' do
270
+ runner { @app.start(%w(group add parent other-parent)) }
271
+ runner { @app.start(%w(group addchild parent child)) }
272
+ runner { @app.start(%w(group addchild other-parent child)) }
273
+
274
+ actual = runner { @app.start(%w(group rm --recursive parent)) }
275
+
276
+ expect(actual[:unexpected]).to eq(false)
277
+ expect(actual[:aborted]).to eq(false)
278
+ expect(@db.models[:group].find(name: 'parent')).to be_nil
279
+
280
+ child = @db.models[:group].find(name: 'child')
281
+ expect(child).not_to be_nil
282
+ expect(child.parents_dataset[name: 'other-parent']).not_to be_nil
283
+ end
247
284
  end
248
285
  end