hammer_cli 0.0.9 → 0.0.10
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.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/doc/creating_apipie_commands.md +296 -0
- data/doc/creating_commands.md +547 -0
- data/doc/developer_docs.md +5 -926
- data/doc/development_tips.md +30 -0
- data/doc/writing_a_plugin.md +90 -0
- data/lib/hammer_cli/abstract.rb +31 -11
- data/lib/hammer_cli/apipie/resource.rb +14 -6
- data/lib/hammer_cli/apipie/write_command.rb +14 -5
- data/lib/hammer_cli/exception_handler.rb +7 -4
- data/lib/hammer_cli/options/normalizers.rb +27 -0
- data/lib/hammer_cli/output/adapter/abstract.rb +8 -8
- data/lib/hammer_cli/output/adapter/csv.rb +37 -4
- data/lib/hammer_cli/output/adapter/silent.rb +2 -2
- data/lib/hammer_cli/output/dsl.rb +3 -1
- data/lib/hammer_cli/output/output.rb +24 -19
- data/lib/hammer_cli/utils.rb +18 -0
- data/lib/hammer_cli/version.rb +1 -1
- data/lib/hammer_cli.rb +1 -0
- data/test/unit/abstract_test.rb +296 -0
- data/test/unit/apipie/command_test.rb +270 -0
- data/test/unit/apipie/fake_api.rb +101 -0
- data/test/unit/apipie/read_command_test.rb +34 -0
- data/test/unit/apipie/write_command_test.rb +38 -0
- data/test/unit/exception_handler_test.rb +45 -0
- data/test/unit/main_test.rb +47 -0
- data/test/unit/options/normalizers_test.rb +148 -0
- data/test/unit/options/option_definition_test.rb +43 -0
- data/test/unit/output/adapter/abstract_test.rb +96 -0
- data/test/unit/output/adapter/base_test.rb +27 -0
- data/test/unit/output/adapter/csv_test.rb +75 -0
- data/test/unit/output/adapter/table_test.rb +58 -0
- data/test/unit/output/definition_test.rb +27 -0
- data/test/unit/output/dsl_test.rb +119 -0
- data/test/unit/output/fields_test.rb +97 -0
- data/test/unit/output/formatters_test.rb +83 -0
- data/test/unit/output/output_test.rb +104 -0
- data/test/unit/settings_test.rb +106 -0
- data/test/unit/test_helper.rb +20 -0
- data/test/unit/utils_test.rb +35 -0
- data/test/unit/validator_test.rb +142 -0
- metadata +112 -35
- data/LICENSE +0 -5
- data/hammer_cli_complete +0 -13
@@ -0,0 +1,296 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
|
5
|
+
describe HammerCLI::AbstractCommand do
|
6
|
+
|
7
|
+
context "output" do
|
8
|
+
|
9
|
+
let(:cmd_class) { Class.new(HammerCLI::AbstractCommand) }
|
10
|
+
let(:cmd) { cmd_class.new("", { :adapter => :silent }) }
|
11
|
+
it "should define adapter" do
|
12
|
+
cmd.adapter.must_equal :base
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should provide instance of output with default adapter set" do
|
16
|
+
cmd.output.default_adapter.must_equal cmd.adapter
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should hold instance of output definition" do
|
20
|
+
cmd.output_definition.must_be_instance_of HammerCLI::Output::Definition
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can append existing definition" do
|
24
|
+
definition = HammerCLI::Output::Definition.new
|
25
|
+
definition.fields << Fields::Field.new
|
26
|
+
definition.fields << Fields::Field.new
|
27
|
+
|
28
|
+
cmd_class.output(definition) do
|
29
|
+
end
|
30
|
+
cmd_class.output_definition.fields.length.must_equal definition.fields.length
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can append existing definition without passing a block" do
|
34
|
+
definition = HammerCLI::Output::Definition.new
|
35
|
+
definition.fields << Fields::Field.new
|
36
|
+
definition.fields << Fields::Field.new
|
37
|
+
|
38
|
+
cmd_class.output(definition)
|
39
|
+
cmd_class.output_definition.fields.length.must_equal definition.fields.length
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can define fields" do
|
43
|
+
cmd_class.output do
|
44
|
+
field :test_1, "test 1"
|
45
|
+
field :test_2, "test 2"
|
46
|
+
end
|
47
|
+
cmd_class.output_definition.fields.length.must_equal 2
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "exception handler" do
|
52
|
+
|
53
|
+
class Handler
|
54
|
+
def initialize(options={})
|
55
|
+
end
|
56
|
+
def handle_exception(e)
|
57
|
+
raise e
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module ModA
|
62
|
+
module ModB
|
63
|
+
class TestCmd < HammerCLI::AbstractCommand
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should return instance of hammer cli exception handler by default" do
|
69
|
+
cmd = ModA::ModB::TestCmd.new ""
|
70
|
+
cmd.exception_handler.must_be_instance_of HammerCLI::ExceptionHandler
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should return instance of exception handler class defined in a module" do
|
74
|
+
ModA::ModB.expects(:exception_handler_class).returns(Handler)
|
75
|
+
cmd = ModA::ModB::TestCmd.new ""
|
76
|
+
cmd.exception_handler.must_be_instance_of Handler
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should return instance of exception handler class defined deeper in a module hierrarchy" do
|
80
|
+
ModA.expects(:exception_handler_class).returns(Handler)
|
81
|
+
cmd = ModA::ModB::TestCmd.new ""
|
82
|
+
cmd.exception_handler.must_be_instance_of Handler
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "logging" do
|
87
|
+
|
88
|
+
before :each do
|
89
|
+
@log_output = Logging::Appenders['__test__']
|
90
|
+
@log_output.reset
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should log what has been executed" do
|
94
|
+
test_command = Class.new(HammerCLI::AbstractCommand).new("")
|
95
|
+
test_command.run []
|
96
|
+
@log_output.readline.strip.must_equal "INFO HammerCLI::AbstractCommand : Called with options: {}"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "password should be hidden in logs" do
|
100
|
+
test_command_class = Class.new(HammerCLI::AbstractCommand)
|
101
|
+
test_command_class.option(['--password'], 'PASSWORD', 'Password')
|
102
|
+
test_command = test_command_class.new("")
|
103
|
+
test_command.run ['--password=pass']
|
104
|
+
@log_output.readline.strip.must_equal "INFO HammerCLI::AbstractCommand : Called with options: {\"password\"=>\"***\"}"
|
105
|
+
end
|
106
|
+
|
107
|
+
class TestLogCmd < HammerCLI::AbstractCommand
|
108
|
+
def execute
|
109
|
+
logger.error "Test"
|
110
|
+
0
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should have logger named by the class by default" do
|
115
|
+
test_command = Class.new(TestLogCmd).new("")
|
116
|
+
test_command.run []
|
117
|
+
@log_output.read.must_include "ERROR TestLogCmd : Test"
|
118
|
+
end
|
119
|
+
|
120
|
+
class TestLogCmd2 < HammerCLI::AbstractCommand
|
121
|
+
def execute
|
122
|
+
logger('My logger').error "Test"
|
123
|
+
0
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should have logger that accepts custom name" do
|
128
|
+
test_command = Class.new(TestLogCmd2).new("")
|
129
|
+
test_command.run []
|
130
|
+
@log_output.read.must_include "ERROR My logger : Test"
|
131
|
+
end
|
132
|
+
|
133
|
+
class TestLogCmd3 < HammerCLI::AbstractCommand
|
134
|
+
def execute
|
135
|
+
logger.watch "Test", {}
|
136
|
+
0
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should have logger that can inspect object" do
|
141
|
+
test_command = Class.new(TestLogCmd3).new("")
|
142
|
+
test_command.run []
|
143
|
+
@log_output.read.must_include "DEBUG TestLogCmd3 : Test\n{}"
|
144
|
+
end
|
145
|
+
|
146
|
+
class TestLogCmd4 < HammerCLI::AbstractCommand
|
147
|
+
def execute
|
148
|
+
logger.watch "Test", { :a => 'a' }, { :plain => true }
|
149
|
+
0
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should have logger.watch output without colors" do
|
154
|
+
test_command = Class.new(TestLogCmd4).new("")
|
155
|
+
test_command.run []
|
156
|
+
@log_output.read.must_include "DEBUG TestLogCmd4 : Test\n{\n :a => \"a\"\n}"
|
157
|
+
end
|
158
|
+
|
159
|
+
class TestLogCmd5 < HammerCLI::AbstractCommand
|
160
|
+
def execute
|
161
|
+
logger.watch "Test", { :a => 'a' }
|
162
|
+
0
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should have logger.watch colorized output switch in settings" do
|
167
|
+
test_command = Class.new(TestLogCmd5).new("")
|
168
|
+
HammerCLI::Settings.clear
|
169
|
+
HammerCLI::Settings.load(:watch_plain => true)
|
170
|
+
test_command.run []
|
171
|
+
@log_output.read.must_include "DEBUG TestLogCmd5 : Test\n{\n :a => \"a\"\n}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "subcommand behavior" do
|
176
|
+
|
177
|
+
class Subcommand1 < HammerCLI::AbstractCommand; end
|
178
|
+
class Subcommand2 < HammerCLI::AbstractCommand; end
|
179
|
+
|
180
|
+
let(:main_cmd) { HammerCLI::AbstractCommand.dup }
|
181
|
+
|
182
|
+
before :each do
|
183
|
+
@log_output = Logging::Appenders['__test__']
|
184
|
+
@log_output.reset
|
185
|
+
|
186
|
+
main_cmd.recognised_subcommands.clear
|
187
|
+
main_cmd.subcommand("some_command", "description", Subcommand1)
|
188
|
+
main_cmd.subcommand("ping", "description", Subcommand1)
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "subcommand!" do
|
192
|
+
|
193
|
+
it "should replace commands with the same name" do
|
194
|
+
main_cmd.subcommand!("ping", "description", Subcommand2)
|
195
|
+
main_cmd.find_subcommand("some_command").wont_be_nil
|
196
|
+
main_cmd.find_subcommand("ping").wont_be_nil
|
197
|
+
main_cmd.find_subcommand("ping").subcommand_class.must_equal Subcommand2
|
198
|
+
main_cmd.recognised_subcommands.count.must_equal 2
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should write a message to log when replacing subcommand" do
|
202
|
+
main_cmd.subcommand!("ping", "description", Subcommand2)
|
203
|
+
@log_output.readline.strip.must_equal "INFO Clamp::Command : subcommand ping (Subcommand1) was removed."
|
204
|
+
@log_output.readline.strip.must_equal "INFO Clamp::Command : subcommand ping (Subcommand2) was created."
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should add the subcommand" do
|
208
|
+
main_cmd.subcommand!("new_command", "description", Subcommand2)
|
209
|
+
main_cmd.find_subcommand("new_command").wont_be_nil
|
210
|
+
main_cmd.find_subcommand("some_command").wont_be_nil
|
211
|
+
main_cmd.find_subcommand("ping").wont_be_nil
|
212
|
+
main_cmd.recognised_subcommands.count.must_equal 3
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
describe "subcommand" do
|
219
|
+
|
220
|
+
it "should throw an exception for conflicting commands" do
|
221
|
+
proc do
|
222
|
+
main_cmd.subcommand("ping", "description", Subcommand2)
|
223
|
+
end.must_raise HammerCLI::CommandConflict
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should add the subcommand" do
|
227
|
+
main_cmd.subcommand("new_command", "description", Subcommand2)
|
228
|
+
main_cmd.find_subcommand("new_command").wont_be_nil
|
229
|
+
main_cmd.find_subcommand("some_command").wont_be_nil
|
230
|
+
main_cmd.find_subcommand("ping").wont_be_nil
|
231
|
+
main_cmd.recognised_subcommands.count.must_equal 3
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
describe "remove_subcommand" do
|
237
|
+
it "should remove the subcommand" do
|
238
|
+
main_cmd.remove_subcommand('ping')
|
239
|
+
main_cmd.find_subcommand("ping").must_be_nil
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should write a message to log when removing subcommand" do
|
243
|
+
main_cmd.remove_subcommand('ping')
|
244
|
+
@log_output.readline.strip.must_equal "INFO Clamp::Command : subcommand ping (Subcommand1) was removed."
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe "options" do
|
251
|
+
|
252
|
+
class TestOptionCmd < HammerCLI::AbstractCommand
|
253
|
+
option "--test", "TEST", "Test option"
|
254
|
+
option "--test-format", "TEST_FORMAT", "Test option with a formatter",
|
255
|
+
:format => HammerCLI::Options::Normalizers::List.new
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should create instances of hammer options" do
|
259
|
+
opt = TestOptionCmd.find_option("--test")
|
260
|
+
opt.kind_of?(HammerCLI::Options::OptionDefinition).must_equal true
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should set options' formatters" do
|
264
|
+
opt = TestOptionCmd.find_option("--test-format")
|
265
|
+
opt.value_formatter.kind_of?(HammerCLI::Options::Normalizers::List).must_equal true
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should inherit command_name" do
|
271
|
+
class CmdName1 < HammerCLI::AbstractCommand
|
272
|
+
command_name 'cmd'
|
273
|
+
end
|
274
|
+
|
275
|
+
class CmdName2 < CmdName1
|
276
|
+
end
|
277
|
+
|
278
|
+
CmdName2.command_name.must_equal 'cmd'
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should inherit output definition" do
|
282
|
+
class CmdOD1 < HammerCLI::AbstractCommand
|
283
|
+
output do
|
284
|
+
label 'Label' do
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
class CmdOD2 < CmdOD1
|
290
|
+
end
|
291
|
+
|
292
|
+
CmdOD2.output_definition.fields.length.must_equal 1
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
@@ -0,0 +1,270 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), 'fake_api')
|
3
|
+
|
4
|
+
|
5
|
+
describe HammerCLI::Apipie::Command do
|
6
|
+
|
7
|
+
class ParentCommand < HammerCLI::Apipie::Command
|
8
|
+
action :show
|
9
|
+
end
|
10
|
+
|
11
|
+
class CommandA < HammerCLI::Apipie::Command
|
12
|
+
resource FakeApi::Resources::Architecture, :index
|
13
|
+
|
14
|
+
class CommandB < ParentCommand
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class CommandC < CommandA
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
let(:cmd_class) { HammerCLI::Apipie::Command.dup }
|
23
|
+
let(:cmd) { cmd_class.new("") }
|
24
|
+
|
25
|
+
context "setting identifiers" do
|
26
|
+
|
27
|
+
let(:option_switches) { cmd_class.declared_options.map(&:switches).sort }
|
28
|
+
let(:option_attribute_names) { cmd_class.declared_options.map(&:attribute_name).sort }
|
29
|
+
|
30
|
+
class Cmd1 < HammerCLI::Apipie::Command
|
31
|
+
identifiers :id, :name, :label
|
32
|
+
end
|
33
|
+
|
34
|
+
class Cmd2 < Cmd1
|
35
|
+
identifiers :id
|
36
|
+
end
|
37
|
+
|
38
|
+
it "must not set any option by default" do
|
39
|
+
cmd
|
40
|
+
cmd_class.declared_options.must_equal []
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can set option --id" do
|
44
|
+
cmd_class.identifiers :id
|
45
|
+
cmd
|
46
|
+
option_switches.must_equal [["--id"]]
|
47
|
+
option_attribute_names.must_equal ["id"]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can set option --name" do
|
51
|
+
cmd_class.identifiers :name
|
52
|
+
cmd
|
53
|
+
option_switches.must_equal [["--name"]]
|
54
|
+
option_attribute_names.must_equal ["name"]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can set option --label" do
|
58
|
+
cmd_class.identifiers :label
|
59
|
+
cmd
|
60
|
+
option_switches.must_equal [["--label"]]
|
61
|
+
option_attribute_names.must_equal ["label"]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "can set multiple identifiers" do
|
65
|
+
cmd_class.identifiers :id, :name, :label
|
66
|
+
cmd
|
67
|
+
option_switches.must_equal [["--id"], ["--label"], ["--name"]]
|
68
|
+
option_attribute_names.must_equal ["id", "label", "name"]
|
69
|
+
end
|
70
|
+
|
71
|
+
it "can change option reader" do
|
72
|
+
cmd_class.identifiers :name, :id => :id_read_method
|
73
|
+
cmd
|
74
|
+
option_switches.must_equal [["--id"], ["--name"]]
|
75
|
+
option_attribute_names.must_equal ["id_read_method", "name"]
|
76
|
+
end
|
77
|
+
|
78
|
+
it "can override inentifiers in inherrited classes" do
|
79
|
+
Cmd2.new("").class.declared_options.map(&:switches).must_equal [["--id"]]
|
80
|
+
end
|
81
|
+
|
82
|
+
context "require identifiers" do
|
83
|
+
|
84
|
+
it "must require one of declared identifiers" do
|
85
|
+
cmd_class.identifiers :id, :name
|
86
|
+
cmd.run(["--id=1"]).must_equal HammerCLI::EX_OK
|
87
|
+
end
|
88
|
+
|
89
|
+
it "must raise exception when no attribute is passed" do
|
90
|
+
cmd_class.identifiers :id, :name
|
91
|
+
proc { cmd.run([]) }.must_raise Clamp::UsageError
|
92
|
+
end
|
93
|
+
|
94
|
+
it "must run without error when no identifiers are declared" do
|
95
|
+
cmd.run([]).must_equal HammerCLI::EX_OK
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
context "setting resources" do
|
103
|
+
|
104
|
+
it "should set resource and action together" do
|
105
|
+
cmd_class.resource FakeApi::Resources::Architecture, :index
|
106
|
+
|
107
|
+
cmd.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
108
|
+
cmd_class.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
109
|
+
|
110
|
+
cmd.action.must_equal :index
|
111
|
+
cmd_class.action.must_equal :index
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should set resource alone" do
|
115
|
+
cmd_class.resource FakeApi::Resources::Architecture
|
116
|
+
|
117
|
+
cmd.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
118
|
+
cmd_class.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
119
|
+
|
120
|
+
cmd.action.must_equal nil
|
121
|
+
cmd_class.action.must_equal nil
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should set resource and action alone" do
|
125
|
+
cmd_class.resource FakeApi::Resources::Architecture
|
126
|
+
cmd_class.action :index
|
127
|
+
|
128
|
+
cmd.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
129
|
+
cmd_class.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
130
|
+
|
131
|
+
cmd.action.must_equal :index
|
132
|
+
cmd_class.action.must_equal :index
|
133
|
+
end
|
134
|
+
|
135
|
+
it "inherits action from a parent class" do
|
136
|
+
cmd_b = CommandA::CommandB.new("")
|
137
|
+
cmd_b.action.must_equal :show
|
138
|
+
cmd_b.class.action.must_equal :show
|
139
|
+
end
|
140
|
+
|
141
|
+
it "looks up resource in the class' modules" do
|
142
|
+
cmd_b = CommandA::CommandB.new("")
|
143
|
+
cmd_b.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
144
|
+
cmd_b.class.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
145
|
+
end
|
146
|
+
|
147
|
+
it "looks up resource in the superclass" do
|
148
|
+
cmd_c = CommandC.new("")
|
149
|
+
cmd_c.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
150
|
+
cmd_c.class.resource.resource_class.must_equal FakeApi::Resources::Architecture
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "apipie generated options" do
|
155
|
+
|
156
|
+
context "with one simple param" do
|
157
|
+
|
158
|
+
let(:option) { cmd_class.declared_options[0] }
|
159
|
+
|
160
|
+
before :each do
|
161
|
+
cmd_class.resource FakeApi::Resources::Documented, :index
|
162
|
+
cmd_class.apipie_options
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should create an option for the parameter" do
|
166
|
+
cmd_class.declared_options.length.must_equal 1
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should set correct switch" do
|
170
|
+
option.switches.must_be :include?, '--se-arch-val-ue'
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should set correct attribute name" do
|
174
|
+
option.attribute_name.must_equal 'se_arch_val_ue'
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should set description with html tags stripped" do
|
178
|
+
option.description.must_equal 'filter results'
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context "required options" do
|
183
|
+
before :each do
|
184
|
+
cmd_class.resource FakeApi::Resources::Documented, :create
|
185
|
+
cmd_class.apipie_options
|
186
|
+
end
|
187
|
+
|
188
|
+
let(:required_options) { cmd_class.declared_options.reject{|opt| !opt.required?} }
|
189
|
+
|
190
|
+
it "should set required flag for the required options" do
|
191
|
+
required_options.map(&:attribute_name).sort.must_equal ["array_param"]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context "with hash params" do
|
196
|
+
before :each do
|
197
|
+
cmd_class.resource FakeApi::Resources::Documented, :create
|
198
|
+
cmd_class.apipie_options
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should create options for all parameters except the hash" do
|
202
|
+
cmd_class.declared_options.map(&:attribute_name).sort.must_equal ["array_param", "name", "provider"]
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should name the options correctly" do
|
206
|
+
cmd_class.declared_options.map(&:attribute_name).sort.must_equal ["array_param", "name", "provider"]
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
context "array params" do
|
211
|
+
before :each do
|
212
|
+
cmd_class.resource FakeApi::Resources::Documented, :create
|
213
|
+
cmd_class.apipie_options
|
214
|
+
end
|
215
|
+
|
216
|
+
let(:cmd) do
|
217
|
+
cmd_class.new("").tap do |cmd|
|
218
|
+
cmd.stubs(:execute).returns(0)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should parse comma separated string to array" do
|
223
|
+
cmd.run(["--array-param=valA,valB,valC"])
|
224
|
+
cmd.array_param.must_equal ['valA', 'valB', 'valC']
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should parse string to array of length 1" do
|
228
|
+
cmd.run(["--array-param=valA"])
|
229
|
+
cmd.array_param.must_equal ['valA']
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should parse empty string to empty array" do
|
233
|
+
cmd.run(['--array-param='])
|
234
|
+
cmd.array_param.must_equal []
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
context "filtering options" do
|
241
|
+
before :each do
|
242
|
+
cmd_class.resource FakeApi::Resources::Documented, :create
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should skip filtered options" do
|
246
|
+
cmd_class.apipie_options :without => ["provider", "name"]
|
247
|
+
cmd_class.declared_options.map(&:attribute_name).sort.must_equal ["array_param"]
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should skip filtered options defined as symbols" do
|
251
|
+
cmd_class.apipie_options :without => [:provider, :name]
|
252
|
+
cmd_class.declared_options.map(&:attribute_name).sort.must_equal ["array_param"]
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should skip single filtered option in array" do
|
256
|
+
cmd_class.apipie_options :without => ["provider"]
|
257
|
+
cmd_class.declared_options.map(&:attribute_name).sort.must_equal ["array_param", "name"]
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should skip single filtered option" do
|
261
|
+
cmd_class.apipie_options :without => "provider"
|
262
|
+
cmd_class.declared_options.map(&:attribute_name).sort.must_equal ["array_param", "name"]
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module FakeApi
|
2
|
+
module Resources
|
3
|
+
class Architecture
|
4
|
+
def initialize(attrs=nil)
|
5
|
+
end
|
6
|
+
def self.doc
|
7
|
+
{
|
8
|
+
"name"=>"Architecture",
|
9
|
+
"methods"=>[
|
10
|
+
{
|
11
|
+
"name"=>"some_action",
|
12
|
+
"examples"=>[],
|
13
|
+
"errors"=>[],
|
14
|
+
"params"=>[]
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
class CamelCaseName
|
21
|
+
def initialize(attrs=nil)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.doc
|
25
|
+
{
|
26
|
+
"name"=>"CamelCaseName",
|
27
|
+
"methods"=>[]
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
class Documented
|
32
|
+
def initialize(attrs=nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.doc
|
36
|
+
{
|
37
|
+
"name"=>"Documented",
|
38
|
+
"api_url"=>"/api",
|
39
|
+
"version"=>"v2",
|
40
|
+
"short_description"=>nil,
|
41
|
+
"full_description"=>nil,
|
42
|
+
"doc_url"=>"/apidoc/v2/documented",
|
43
|
+
"methods"=>[
|
44
|
+
{
|
45
|
+
"name"=>"index",
|
46
|
+
"examples"=>[],
|
47
|
+
"errors"=>[],
|
48
|
+
"params"=>
|
49
|
+
[{"allow_nil"=>false,
|
50
|
+
"name"=>"se_arch_val-ue",
|
51
|
+
"full_name"=>"se_arch_val-ue_full_name",
|
52
|
+
"validator"=>"Must be String",
|
53
|
+
"description"=>"<p>filter results</p>",
|
54
|
+
"expected_type"=>"string",
|
55
|
+
"required"=>false}],
|
56
|
+
"full_description"=>""},
|
57
|
+
{
|
58
|
+
|
59
|
+
"name"=>"create",
|
60
|
+
"examples"=>[],
|
61
|
+
"errors"=>[],
|
62
|
+
"params"=>
|
63
|
+
[{"allow_nil"=>false,
|
64
|
+
"name"=>"documented",
|
65
|
+
"full_name"=>"documented",
|
66
|
+
"validator"=>"Must be a Hash",
|
67
|
+
"description"=>"",
|
68
|
+
"expected_type"=>"hash",
|
69
|
+
"required"=>true,
|
70
|
+
"params"=>
|
71
|
+
[{"name"=>"name",
|
72
|
+
"allow_nil"=>false,
|
73
|
+
"full_name"=>"documented[name]",
|
74
|
+
"validator"=>"Must be String",
|
75
|
+
"expected_type"=>"string",
|
76
|
+
"description"=>"",
|
77
|
+
"required"=>false},
|
78
|
+
{"name"=>"provider",
|
79
|
+
"allow_nil"=>false,
|
80
|
+
"full_name"=>"documented[provider]",
|
81
|
+
"validator"=>"Must be String",
|
82
|
+
"expected_type"=>"string",
|
83
|
+
"description"=>
|
84
|
+
"<p>Providers include Libvirt, Ovirt, EC2, Vmware, Openstack, Rackspace</p>",
|
85
|
+
"required"=>false},
|
86
|
+
{"name"=>"array_param",
|
87
|
+
"allow_nil"=>false,
|
88
|
+
"full_name"=>"documented[array_param]",
|
89
|
+
"validator"=>"Must be Array",
|
90
|
+
"expected_type"=>"string",
|
91
|
+
"description"=>"",
|
92
|
+
"required"=>true},]
|
93
|
+
}],
|
94
|
+
"full_description"=>""
|
95
|
+
}
|
96
|
+
]
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), 'fake_api')
|
3
|
+
|
4
|
+
|
5
|
+
describe HammerCLI::Apipie::ReadCommand do
|
6
|
+
|
7
|
+
let(:cmd_class) { HammerCLI::Apipie::ReadCommand.dup }
|
8
|
+
let(:cmd) { cmd_class.new("", { :adapter => :silent }) }
|
9
|
+
let(:cmd_run) { cmd.run([]) }
|
10
|
+
|
11
|
+
it "should raise exception when no action is defined" do
|
12
|
+
cmd.stubs(:handle_exception).returns(HammerCLI::EX_SOFTWARE)
|
13
|
+
cmd_run.must_equal HammerCLI::EX_SOFTWARE
|
14
|
+
end
|
15
|
+
|
16
|
+
context "resource defined" do
|
17
|
+
|
18
|
+
before :each do
|
19
|
+
cmd_class.resource FakeApi::Resources::Architecture, "some_action"
|
20
|
+
|
21
|
+
arch = FakeApi::Resources::Architecture.new
|
22
|
+
arch.expects(:some_action).returns([])
|
23
|
+
FakeApi::Resources::Architecture.stubs(:new).returns(arch)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should perform a call to api when resource is defined" do
|
27
|
+
cmd_run.must_equal 0
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
|