moose-inventory 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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +0 -0
  3. data/.gitignore +17 -0
  4. data/.rubocop.yml +793 -0
  5. data/Gemfile +3 -0
  6. data/Guardfile +38 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +31 -0
  9. data/README.md.orig +35 -0
  10. data/Rakefile +1 -0
  11. data/bin/moose_inventory +10 -0
  12. data/config/dotfiles/coveralls.yml +0 -0
  13. data/config/dotfiles/gitignore +17 -0
  14. data/config/dotfiles/rubocop.yml +793 -0
  15. data/lib/moose/inventory/cli/application.rb +30 -0
  16. data/lib/moose/inventory/cli/formatter.rb +92 -0
  17. data/lib/moose/inventory/cli/group.rb +23 -0
  18. data/lib/moose/inventory/cli/group_add.rb +98 -0
  19. data/lib/moose/inventory/cli/group_addchild.rb +21 -0
  20. data/lib/moose/inventory/cli/group_addhost.rb +97 -0
  21. data/lib/moose/inventory/cli/group_addvar.rb +72 -0
  22. data/lib/moose/inventory/cli/group_get.rb +52 -0
  23. data/lib/moose/inventory/cli/group_list.rb +41 -0
  24. data/lib/moose/inventory/cli/group_rm.rb +77 -0
  25. data/lib/moose/inventory/cli/group_rmchild.rb +20 -0
  26. data/lib/moose/inventory/cli/group_rmhost.rb +89 -0
  27. data/lib/moose/inventory/cli/group_rmvar.rb +65 -0
  28. data/lib/moose/inventory/cli/host.rb +24 -0
  29. data/lib/moose/inventory/cli/host_add.rb +93 -0
  30. data/lib/moose/inventory/cli/host_addgroup.rb +88 -0
  31. data/lib/moose/inventory/cli/host_addvar.rb +76 -0
  32. data/lib/moose/inventory/cli/host_get.rb +59 -0
  33. data/lib/moose/inventory/cli/host_list.rb +40 -0
  34. data/lib/moose/inventory/cli/host_rm.rb +62 -0
  35. data/lib/moose/inventory/cli/host_rmgroup.rb +80 -0
  36. data/lib/moose/inventory/cli/host_rmvar.rb +69 -0
  37. data/lib/moose/inventory/config/config.rb +169 -0
  38. data/lib/moose/inventory/db/db.rb +249 -0
  39. data/lib/moose/inventory/db/exceptions.rb +14 -0
  40. data/lib/moose/inventory/db/models.rb +32 -0
  41. data/lib/moose/inventory/moose_inventory_cli.rb +25 -0
  42. data/lib/moose/inventory/version.rb +7 -0
  43. data/moose-inventory.gemspec +45 -0
  44. data/scripts/guard_quality.sh +3 -0
  45. data/scripts/guard_test.sh +2 -0
  46. data/scripts/reports.sh +4 -0
  47. data/spec/config/config.yml +12 -0
  48. data/spec/lib/moose/inventory/cli/application_spec.rb +15 -0
  49. data/spec/lib/moose/inventory/cli/cli_spec.rb +26 -0
  50. data/spec/lib/moose/inventory/cli/formatter_spec.rb +63 -0
  51. data/spec/lib/moose/inventory/cli/group_add_spec.rb +398 -0
  52. data/spec/lib/moose/inventory/cli/group_addhost_spec.rb +251 -0
  53. data/spec/lib/moose/inventory/cli/group_addvar_spec.rb +235 -0
  54. data/spec/lib/moose/inventory/cli/group_get_spec.rb +107 -0
  55. data/spec/lib/moose/inventory/cli/group_list_spec.rb +79 -0
  56. data/spec/lib/moose/inventory/cli/group_rm_spec.rb +191 -0
  57. data/spec/lib/moose/inventory/cli/group_rmhost_spec.rb +215 -0
  58. data/spec/lib/moose/inventory/cli/group_rmvar_spec.rb +202 -0
  59. data/spec/lib/moose/inventory/cli/group_spec.rb +15 -0
  60. data/spec/lib/moose/inventory/cli/host_add_spec.rb +330 -0
  61. data/spec/lib/moose/inventory/cli/host_addgroup_spec.rb +248 -0
  62. data/spec/lib/moose/inventory/cli/host_addvar_spec.rb +233 -0
  63. data/spec/lib/moose/inventory/cli/host_get_spec.rb +106 -0
  64. data/spec/lib/moose/inventory/cli/host_list_spec.rb +83 -0
  65. data/spec/lib/moose/inventory/cli/host_rm_spec.rb +132 -0
  66. data/spec/lib/moose/inventory/cli/host_rmgroup_spec.rb +245 -0
  67. data/spec/lib/moose/inventory/cli/host_rmvar_spec.rb +206 -0
  68. data/spec/lib/moose/inventory/cli/host_spec.rb +12 -0
  69. data/spec/lib/moose/inventory/config/config_spec.rb +80 -0
  70. data/spec/lib/moose/inventory/db/db_spec.rb +184 -0
  71. data/spec/lib/moose/inventory/db/models_spec.rb +150 -0
  72. data/spec/shared/shared_config_setup.rb +21 -0
  73. data/spec/spec_helper.rb +110 -0
  74. metadata +386 -0
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ # TODO: the usual respond_to? method doesn't seem to work on Thor objects.
4
+ # Why not? For now, we'll check against instance_methods.
5
+
6
+ RSpec.describe Moose::Inventory::Cli::Group do
7
+ before(:all) do
8
+ # Set up the configuration object
9
+ @mockarg_parts = {
10
+ config: File.join(spec_root, 'config/config.yml'),
11
+ format: 'yaml',
12
+ env: 'test'
13
+ }
14
+
15
+ @mockargs = []
16
+ @mockarg_parts.each do |key, val|
17
+ @mockargs << "--#{key}"
18
+ @mockargs << val
19
+ end
20
+
21
+ @config = Moose::Inventory::Config
22
+ @config.init(@mockargs)
23
+ @console = Moose::Inventory::Cli::Formatter
24
+
25
+ @db = Moose::Inventory::DB
26
+ @db.init if @db.db.nil?
27
+
28
+ @group = Moose::Inventory::Cli::Group
29
+ @app = Moose::Inventory::Cli::Application
30
+ end
31
+
32
+ before(:each) do
33
+ @db.reset
34
+ end
35
+
36
+ #=======================
37
+ describe 'get' do
38
+ #---------------------
39
+ it 'should be responsive' do
40
+ result = @group.instance_methods(false).include?(:get)
41
+ expect(result).to eq(true)
42
+ end
43
+
44
+ #---------------------
45
+ it '<missing args> ... should abort with an error' do
46
+ actual = runner { @app.start(%W(group get)) }
47
+
48
+ #@console.out(actual,'y')
49
+
50
+ desired = {aborted: true}
51
+ desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 1 or more\n"
52
+
53
+ expected(actual, desired)
54
+ end
55
+
56
+ #---------------------
57
+ it "GROUP ... should return an empty set when GROUP doesn't exist" do
58
+ group_name = 'does-not-exist'
59
+ actual = runner { @app.start(%W(group get #{ group_name })) }
60
+
61
+ #@console.out(actual, 'y')
62
+
63
+ desired = {}
64
+ desired[:STDOUT] = {}.to_yaml
65
+
66
+ expected(actual, desired)
67
+ end
68
+
69
+ #---------------------
70
+ it 'GROUP ... should get a group from the db' do
71
+ name = 'test_group'
72
+ runner { @app.start(%W(group add #{ name })) }
73
+
74
+ actual = runner { @app.start(%W(group get #{ name })) }
75
+
76
+ mock = {}
77
+ mock[name.to_sym] = {}
78
+ # mock[name.to_sym][:hosts] = [] # TODO: Should this be present or not?
79
+
80
+ desired = { aborted: false, STDOUT: '', STDERR: '' }
81
+ desired[:STDOUT] = mock.to_yaml
82
+
83
+ expected(actual, desired)
84
+ end
85
+
86
+ #---------------------
87
+ it 'GROUP ... should display groupvars, if any are set' do
88
+ name = 'test_group'
89
+ var = 'foo=bar'
90
+ tmp = runner { @app.start(%W(group add #{ name })) }
91
+ tmp = runner { @app.start(%W(group addvar #{ name } #{ var })) }
92
+
93
+ actual = runner { @app.start(%W(group get #{ name })) }
94
+ #@console.out(actual, 'y')
95
+
96
+ mock = {}
97
+ mock[name.to_sym] = {}
98
+ mock[name.to_sym][:groupvars] = {foo: 'bar'}
99
+
100
+ desired = {}
101
+ desired[:STDOUT] = mock.to_yaml
102
+
103
+ expected(actual, desired)
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Moose::Inventory::Cli::Group do
4
+ before(:all) do
5
+ # Set up the configuration object
6
+ @mockarg_parts = {
7
+ config: File.join(spec_root, 'config/config.yml'),
8
+ format: 'yaml',
9
+ env: 'test'
10
+ }
11
+
12
+ @mockargs = []
13
+ @mockarg_parts.each do |key, val|
14
+ @mockargs << "--#{key}"
15
+ @mockargs << val
16
+ end
17
+
18
+ @config = Moose::Inventory::Config
19
+ @config.init(@mockargs)
20
+
21
+ @db = Moose::Inventory::DB
22
+ @db.init if @db.db.nil?
23
+
24
+ @group = Moose::Inventory::Cli::Group
25
+ @app = Moose::Inventory::Cli::Application
26
+ end
27
+
28
+ before(:each) do
29
+ @db.reset
30
+ end
31
+
32
+ #====================
33
+ describe 'list' do
34
+ #---------------------
35
+ it 'should be responsive' do
36
+ result = @group.instance_methods(false).include?(:list)
37
+ expect(result).to eq(true)
38
+ end
39
+
40
+ #---------------------
41
+ it 'should return an empty set when no results' do
42
+ # no items in the db
43
+ actual = runner { @app.start(%W(group list)) }
44
+
45
+ desired = { aborted: false, STDOUT: '', STDERR: '' }
46
+ desired[:STDOUT] = {}.to_yaml
47
+
48
+ expected(actual, desired)
49
+ end
50
+
51
+ #---------------------
52
+ it 'should get a list of group from the db' do
53
+ var = 'foo=bar'
54
+ host_name = 'test_host'
55
+
56
+ mock = {}
57
+ groups = %w(group1 group2 group3)
58
+ groups.each do |name|
59
+ runner { @app.start(%W(group add #{name})) }
60
+ runner { @app.start(%W(group addvar #{ name } #{var})) }
61
+ mock[name.to_sym] = {}
62
+ mock[name.to_sym][:groupvars] = {foo: 'bar'}
63
+ end
64
+
65
+ # items should now be in the db
66
+ actual = runner{ @app.start(%w(group list)) }
67
+
68
+ desired = { aborted: false, STDOUT: '', STDERR: '' }
69
+ desired[:STDOUT] = mock.to_yaml
70
+
71
+ expected(actual, desired)
72
+ end
73
+ # #---------------------
74
+ # it 'host list ... should display hostvars, if any are set' do
75
+ # Covered by 'should get a list of hosts from the db'
76
+ # end
77
+
78
+ end
79
+ end
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+
3
+ # TODO: the usual respond_to? method doesn't seem to work on Thor objects.
4
+ # Why not? For now, we'll check against instance_methods.
5
+
6
+ RSpec.describe Moose::Inventory::Cli::Group do
7
+ before(:all) do
8
+ # Set up the configuration object
9
+ @mockarg_parts = {
10
+ config: File.join(spec_root, 'config/config.yml'),
11
+ format: 'yaml',
12
+ env: 'test'
13
+ }
14
+
15
+ @mockargs = []
16
+ @mockarg_parts.each do |key, val|
17
+ @mockargs << "--#{key}"
18
+ @mockargs << val
19
+ end
20
+
21
+ @config = Moose::Inventory::Config
22
+ @config.init(@mockargs)
23
+
24
+ @console = Moose::Inventory::Cli::Formatter
25
+
26
+ @db = Moose::Inventory::DB
27
+ @db.init if @db.db.nil?
28
+
29
+ @group = Moose::Inventory::Cli::Group
30
+ @host = Moose::Inventory::Cli::Host
31
+ @app = Moose::Inventory::Cli::Application
32
+ end
33
+
34
+ before(:each) do
35
+ @db.reset
36
+ end
37
+
38
+ #======================
39
+ describe 'rm' do
40
+ #---------------
41
+ it 'Group.rm() should be responsive' do
42
+ result = @group.instance_methods(false).include?(:rm)
43
+ expect(result).to eq(true)
44
+ end
45
+
46
+ #---------------
47
+ it '<missing argument> ... should abort with an error' do
48
+ actual = runner { @app.start(%w(host rm)) }
49
+
50
+ # Check output
51
+ desired = { aborted: true, STDERR: '', STDOUT: '' }
52
+ desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 1 or more.\n"
53
+ expected(actual, desired)
54
+ end
55
+
56
+ # --------------------
57
+ it 'ungrouped ... should abort with an error' do
58
+ actual = runner { @app.start(%W(group rm ungrouped)) }
59
+
60
+ # Check output
61
+ desired = {aborted: true}
62
+ desired[:STDERR] =
63
+ "Cannot manually manipulate the automatic group 'ungrouped'\n"
64
+ expected(actual, desired)
65
+ end
66
+
67
+
68
+ #---------------
69
+ it '<non-existent group> ... should warn about non-existent groups' do
70
+ # Rationale:
71
+ # The request implies the desired state is that the group is not present
72
+ # If the group is not present, for whatever reason, then the desired state
73
+ # already exists.
74
+
75
+ # 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')
80
+ desired = {}
81
+ desired[:STDOUT] =
82
+ "Remove group '#{group_name}':\n"\
83
+ " - Retrieve group '#{group_name}'...\n"\
84
+ " - No such group, skipping.\n"\
85
+ " - OK\n"\
86
+ " - All OK\n"\
87
+ "Succeeded, with warnings.\n"
88
+ desired[:STDERR] =
89
+ "WARNING: Group '#{group_name}' does not exist, skipping.\n"
90
+
91
+ expected(actual, desired)
92
+ end
93
+
94
+ #---------------
95
+ it 'GROUP ... should remove a group' do
96
+ group_name = 'test1'
97
+ @db.models[:group].create(name: group_name)
98
+
99
+ actual = runner { @app.start(%W(group rm #{group_name})) }
100
+
101
+ # Check output
102
+ desired = {}
103
+ desired[:STDOUT] =
104
+ "Remove group '#{group_name}':\n"\
105
+ " - Retrieve group '#{group_name}'...\n"\
106
+ " - OK\n"\
107
+ " - Destroy group '#{group_name}'...\n"\
108
+ " - OK\n"\
109
+ " - All OK\n"\
110
+ "Succeeded.\n"
111
+ expected(actual, desired)
112
+
113
+ # Check db
114
+ group = @db.models[:group].find(name: group_name)
115
+ expect(group).to be_nil
116
+ end
117
+
118
+ #---------------
119
+ 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
137
+ desired = {}
138
+ desired[:STDOUT] =
139
+ "Remove group '#{group_name}':\n"\
140
+ " - Retrieve group '#{group_name}'...\n"\
141
+ " - OK\n"\
142
+ " - Adding automatic association {group:ungrouped <-> host:#{host_name}}...\n"\
143
+ " - OK\n"\
144
+ " - Destroy group '#{group_name}'...\n"\
145
+ " - OK\n"\
146
+ " - All OK\n"\
147
+ "Succeeded.\n"
148
+ expected(actual, desired)
149
+
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
160
+
161
+ #---------------
162
+ it 'GROUP1 GROUP2 ... should remove multiple groups' do
163
+ names = %w(group1 group2 group3)
164
+ names.each do |name|
165
+ @db.models[:group].create(name: name)
166
+ end
167
+
168
+ actual = runner { @app.start(%w(group rm) + names) }
169
+
170
+ # Check output
171
+ desired = {STDOUT: ''}
172
+ names.each do |name|
173
+ # Check output
174
+ 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"
181
+ end
182
+ desired[:STDOUT] = desired[:STDOUT] + "Succeeded.\n"
183
+ expected(actual, desired)
184
+
185
+
186
+ # Check db
187
+ hosts = @db.models[:host].all
188
+ expect(hosts.count).to eq(0)
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,215 @@
1
+ require 'spec_helper'
2
+
3
+ # TODO: the usual respond_to? method doesn't seem to work on Thor objects.
4
+ # Why not? For now, we'll check against instance_methods.
5
+
6
+ RSpec.describe Moose::Inventory::Cli::Group do
7
+ before(:all) do
8
+ # Set up the configuration object
9
+ @mockarg_parts = {
10
+ config: File.join(spec_root, 'config/config.yml'),
11
+ format: 'yaml',
12
+ env: 'test'
13
+ }
14
+
15
+ @mockargs = []
16
+ @mockarg_parts.each do |key, val|
17
+ @mockargs << "--#{key}"
18
+ @mockargs << val
19
+ end
20
+
21
+ @console = Moose::Inventory::Cli::Formatter
22
+ @config = Moose::Inventory::Config
23
+ @config.init(@mockargs)
24
+
25
+ @db = Moose::Inventory::DB
26
+ @db.init if @db.db.nil?
27
+
28
+ @group = Moose::Inventory::Cli::Group
29
+ @host = Moose::Inventory::Cli::Host
30
+ @app = Moose::Inventory::Cli::Application
31
+ end
32
+
33
+ before(:each) do
34
+ @db.reset
35
+ end
36
+
37
+ #====================
38
+ describe 'rmgroup' do
39
+ #----------------
40
+ it 'should be responsive' do
41
+ result = @group.instance_methods(false).include?(:rmhost)
42
+ expect(result).to eq(true)
43
+ end
44
+
45
+ #----------------
46
+
47
+ #------------------------
48
+ it '<missing args> ... should abort with an error' do
49
+ actual = runner do
50
+ @app.start(%w(group rmhost)) # <- no group or hosts given
51
+ end
52
+
53
+ # Check output
54
+ desired = { aborted: true}
55
+ desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 2 or more.\n"
56
+ expected(actual, desired)
57
+ end
58
+
59
+ #------------------------
60
+ it 'GROUP GROUP ... should abort if the group does not exist' do
61
+ group_name = 'not-a-group'
62
+ host_name = 'example'
63
+ actual = runner do
64
+ @app.start(%W(group rmhost #{group_name} #{host_name}))
65
+ end
66
+
67
+ # Check output
68
+ desired = { aborted: true}
69
+ desired[:STDOUT] =
70
+ "Dissociate group '#{group_name}' from host(s) '#{host_name}':\n"\
71
+ " - retrieve group '#{group_name}'...\n"
72
+ desired[:STDERR] =
73
+ "ERROR: The group '#{group_name}' does not exist.\n"\
74
+ "An error occurred during a transaction, any changes have been rolled back.\n"
75
+ expected(actual, desired)
76
+ end
77
+
78
+ #------------------------
79
+ it 'GROUP HOST ... should dissociate the group from an existing group' do
80
+ host_name = 'test1'
81
+ group_name = 'group1'
82
+
83
+ runner { @app.start(%W(host add #{host_name})) }
84
+ runner { @app.start(%W(group add #{group_name})) }
85
+ runner { @app.start(%W(group addhost #{group_name} #{host_name} )) }
86
+
87
+ #
88
+ # Dissociate the host
89
+ # 1. expect that the group association is removed
90
+ # 2. expect that no association with ungrouped is made.
91
+
92
+ actual = runner do
93
+ @app.start(%W(group rmhost #{group_name} #{host_name} ))
94
+ end
95
+
96
+ #@console.dump(actual, 'y')
97
+
98
+ # rubocop:disable Metrics/LineLength
99
+ desired = { aborted: false}
100
+ desired[:STDOUT] =
101
+ "Dissociate group '#{group_name}' from host(s) '#{host_name}':\n"\
102
+ " - retrieve group '#{group_name}'...\n"\
103
+ " - OK\n"\
104
+ " - remove association {group:#{group_name} <-> host:#{host_name}}...\n"\
105
+ " - OK\n"\
106
+ " - add automatic association {group:ungrouped <-> host:#{host_name}}...\n"\
107
+ " - OK\n"\
108
+ " - all OK\n"\
109
+ "Succeeded.\n"
110
+ expected(actual, desired)
111
+ # rubocop:enable Metrics/LineLength
112
+
113
+ # We should have the correct group associations
114
+ group = @db.models[:group].find(name: group_name)
115
+ hosts = group.hosts_dataset
116
+ expect(hosts.count).to eq(0)
117
+ end
118
+
119
+ #------------------------
120
+ it 'GROUP HOST ... should warn about non-existing associations' do
121
+ # 1. Should warn that the association doesn't exist.
122
+ # 2. Should complete with success. (desired state == actual state)
123
+
124
+ host_name = 'test_host'
125
+ group_name = 'test_group'
126
+ runner { @app.start(%W(host add #{host_name})) }
127
+ runner { @app.start(%W(group add #{group_name})) }
128
+ runner { @app.start(%W(group addhost #{host_name})) }
129
+
130
+ actual = runner do
131
+ @app.start(%W(group rmhost #{group_name} #{host_name}))
132
+ end
133
+
134
+ # rubocop:disable Metrics/LineLength
135
+ desired = { aborted: false}
136
+ desired[:STDOUT] =
137
+ "Dissociate group '#{group_name}' from host(s) '#{host_name}':\n"\
138
+ " - retrieve group \'#{group_name}\'...\n"\
139
+ " - OK\n"\
140
+ " - remove association {group:#{group_name } <-> host:#{host_name}}...\n"\
141
+ " - doesn't exist, skipping.\n"\
142
+ " - OK\n"\
143
+ " - all OK\n"\
144
+ "Succeeded, with warnings.\n"
145
+ desired[:STDERR] =
146
+ "WARNING: Association {group:#{group_name} <-> host:#{host_name}} "\
147
+ "doesn't exist, skipping.\n"
148
+
149
+ expected(actual, desired)
150
+ end
151
+
152
+ #------------------------
153
+ it '\'ungrouped\' HOST ... should abort with an error' do
154
+
155
+ host_name = 'test_host'
156
+ group_name = 'ungrouped'
157
+
158
+ runner { @app.start(%W(host add #{name})) } # <- auto creates the association with ungrouped
159
+
160
+ actual = runner { @app.start(%W(group rmhost #{group_name} #{host_name} )) }
161
+
162
+ desired = { aborted: true}
163
+ desired[:STDERR] =
164
+ "ERROR: Cannot manually manipulate the automatic group 'ungrouped'.\n"
165
+ expected(actual, desired)
166
+ end
167
+
168
+ #------------------------
169
+ it 'GROUP HOST1 HOST2 ... should dissociate the group from'\
170
+ ' multiple hosts at once' do
171
+ # 1. Should dissociate hosts from the group
172
+ # 2. Should add each host to the 'ungrouped' automatic group
173
+ # if it has no other groups.
174
+
175
+ group_name = 'test_group'
176
+ host_names = %W( test_host1 test_host2 test_host3 )
177
+
178
+ runner { @app.start(%W(group add #{group_name} )) }
179
+ runner { @app.start(%W(group addhost #{group_name}) + host_names) }
180
+
181
+ actual = runner do
182
+ @app.start(%W(group rmhost #{group_name}) + host_names)
183
+ end
184
+
185
+ #@console.out(actual, 'y')
186
+
187
+ # rubocop:disable Metrics/LineLength
188
+ desired = { aborted: false}
189
+ desired[:STDOUT] =
190
+ "Dissociate group '#{group_name}' from host(s) '#{host_names.join(',')}':\n"\
191
+ " - retrieve group \'#{group_name}\'...\n"\
192
+ " - OK\n"
193
+ host_names.each do |host|
194
+ desired[:STDOUT] = desired[:STDOUT] +
195
+ " - remove association {group:#{group_name} <-> host:#{host}}...\n"\
196
+ " - OK\n"\
197
+ " - add automatic association {group:ungrouped <-> host:#{host}}...\n"\
198
+ " - OK\n"\
199
+ end
200
+ desired[:STDOUT] = desired[:STDOUT] +
201
+ " - all OK\n"\
202
+ "Succeeded.\n"
203
+ expected(actual, desired)
204
+ # rubocop:enable Metrics/LineLength
205
+
206
+ # We should have the correct group associations
207
+ group = @db.models[:group].find(name: group_name)
208
+ hosts = group.hosts_dataset
209
+ expect(hosts.count).to eq(0)
210
+ host_names.each do |host|
211
+ expect(hosts[name: host]).to be_nil
212
+ end
213
+ end
214
+ end
215
+ end