@@ -67,6 +67,8 @@ func TestHelpCmds(t *testing.T) {
6767 cmdStr : "open" ,
6868 helpSubStr : "Usage:\n open [flags] path\n " ,
6969 },
70+ // TODO(follow-up PR): Add help tests for the remaining commands.
71+ // Use runHelpCmd(t, "<cmd>", "Usage:\n <cmd>") following the same pattern.
7072 } {
7173 t .Run (name , func (t * testing.T ) {
7274 runHelpCmd (t , tc .cmdStr , tc .helpSubStr )
@@ -80,6 +82,11 @@ func TestCmds(t *testing.T) {
8082 setup func ()
8183 expStdout []string
8284 expErr error
85+ // skipCmdLine skips the command-line sub-test with a message. Use when
86+ // a flag is shared between the CLI layer and the grumble command: go-flags
87+ // consumes it before grumble can see it, making a clean command-line test
88+ // impossible for that particular flag.
89+ skipCmdLine string
8390 }{
8491 "ls invalid options" : {
8592 args : []string {"ls" , "--bar" },
@@ -180,6 +187,183 @@ func TestCmds(t *testing.T) {
180187 },
181188 expStdout : []string {"ls called" },
182189 },
190+
191+ // --- open command ---
192+ // Note: the -w/--write_mode and -p/--db_path flags of the grumble 'open'
193+ // command share names with CLI-level flags that are consumed by go-flags
194+ // before reaching grumble in command-line mode. The command-line test for
195+ // those flags would silently test wrong values. They are correctly exercised
196+ // in command-file mode; see TestRun for CLI-level flag coverage.
197+ "open default" : {
198+ args : []string {"open" , "/path/to/vos-0" },
199+ setup : func () {
200+ ddb_run_open_Fn = func (path , dbPath string , writeMode bool ) error {
201+ fmt .Println ("open called" )
202+ if err := isArgEqual ("/path/to/vos-0" , path , "path" ); err != nil {
203+ return err
204+ }
205+ if err := isArgEqual ("" , dbPath , "db_path" ); err != nil {
206+ return err
207+ }
208+ if err := isArgEqual (false , writeMode , "write_mode" ); err != nil {
209+ return err
210+ }
211+ return nil
212+ }
213+ },
214+ expStdout : []string {"open called" },
215+ },
216+ "open write mode" : {
217+ args : []string {"open" , "-w" , "/path/to/vos-0" },
218+ skipCmdLine : "-w is consumed by the CLI write_mode flag before reaching grumble" ,
219+ setup : func () {
220+ ddb_run_open_Fn = func (path , dbPath string , writeMode bool ) error {
221+ fmt .Println ("open called" )
222+ if err := isArgEqual (true , writeMode , "write_mode" ); err != nil {
223+ return err
224+ }
225+ return nil
226+ }
227+ },
228+ expStdout : []string {"open called" },
229+ },
230+ "open with db path" : {
231+ args : []string {"open" , "-p" , "/sysdb" , "/path/to/vos-0" },
232+ skipCmdLine : "-p is consumed by the CLI db_path flag before reaching grumble" ,
233+ setup : func () {
234+ ddb_run_open_Fn = func (path , dbPath string , writeMode bool ) error {
235+ fmt .Println ("open called" )
236+ if err := isArgEqual ("/path/to/vos-0" , path , "path" ); err != nil {
237+ return err
238+ }
239+ if err := isArgEqual ("/sysdb" , dbPath , "db_path" ); err != nil {
240+ return err
241+ }
242+ return nil
243+ }
244+ },
245+ expStdout : []string {"open called" },
246+ },
247+
248+ // --- feature command ---
249+ // feature --show: verifies the show flag is forwarded to the C layer.
250+ "feature show" : {
251+ args : []string {"feature" , "--show" },
252+ setup : func () {
253+ ddb_run_feature_Fn = func (path , dbPath , enable , disable string , show bool ) error {
254+ fmt .Println ("feature called" )
255+ if err := isArgEqual (true , show , "show" ); err != nil {
256+ return err
257+ }
258+ return nil
259+ }
260+ },
261+ expStdout : []string {"feature called" },
262+ },
263+ // feature --enable: verifies that the enable string reaches ddb_feature_string2flags.
264+ "feature enable" : {
265+ args : []string {"feature" , "--enable=myflag" },
266+ setup : func () {
267+ var capturedFlag string
268+ ddb_feature_string2flags_Fn = func (s string ) (uint64 , uint64 , error ) {
269+ capturedFlag = s
270+ return 0 , 0 , nil
271+ }
272+ ddb_run_feature_Fn = func (path , dbPath , enable , disable string , show bool ) error {
273+ fmt .Println ("feature called" )
274+ if err := isArgEqual ("myflag" , capturedFlag , "enable flag string" ); err != nil {
275+ return err
276+ }
277+ return nil
278+ }
279+ },
280+ expStdout : []string {"feature called" },
281+ },
282+ // feature --disable: verifies that the disable string reaches ddb_feature_string2flags.
283+ "feature disable" : {
284+ args : []string {"feature" , "--disable=otherflag" },
285+ setup : func () {
286+ var capturedFlag string
287+ ddb_feature_string2flags_Fn = func (s string ) (uint64 , uint64 , error ) {
288+ capturedFlag = s
289+ return 0 , 0 , nil
290+ }
291+ ddb_run_feature_Fn = func (path , dbPath , enable , disable string , show bool ) error {
292+ fmt .Println ("feature called" )
293+ if err := isArgEqual ("otherflag" , capturedFlag , "disable flag string" ); err != nil {
294+ return err
295+ }
296+ return nil
297+ }
298+ },
299+ expStdout : []string {"feature called" },
300+ },
301+
302+ // --- dtx_aggr command ---
303+ // The Run handler in ddb_commands.go enforces that exactly one of --cmt_time or
304+ // --cmt_date is provided. These tests exercise that Go-layer validation.
305+ "dtx_aggr both cmt_time and cmt_date" : {
306+ args : []string {"dtx_aggr" , "--cmt_time=0" , "--cmt_date=2024-01-01" },
307+ expErr : ddbTestErr ("mutually exclusive" ),
308+ },
309+ "dtx_aggr neither cmt_time nor cmt_date" : {
310+ args : []string {"dtx_aggr" },
311+ expErr : ddbTestErr ("has to be defined" ),
312+ },
313+ "dtx_aggr cmt_time" : {
314+ args : []string {"dtx_aggr" , "--cmt_time=1000" },
315+ setup : func () {
316+ ddb_run_dtx_aggr_Fn = func (path string , cmtTime uint64 , cmtDate string ) error {
317+ fmt .Println ("dtx_aggr called" )
318+ if err := isArgEqual (uint64 (1000 ), cmtTime , "cmtTime" ); err != nil {
319+ return err
320+ }
321+ if err := isArgEqual ("" , cmtDate , "cmtDate" ); err != nil {
322+ return err
323+ }
324+ return nil
325+ }
326+ },
327+ expStdout : []string {"dtx_aggr called" },
328+ },
329+ "dtx_aggr cmt_date" : {
330+ args : []string {"dtx_aggr" , "--cmt_date=2024-01-01" },
331+ setup : func () {
332+ ddb_run_dtx_aggr_Fn = func (path string , cmtTime uint64 , cmtDate string ) error {
333+ fmt .Println ("dtx_aggr called" )
334+ if err := isArgEqual ("2024-01-01" , cmtDate , "cmtDate" ); err != nil {
335+ return err
336+ }
337+ return nil
338+ }
339+ },
340+ expStdout : []string {"dtx_aggr called" },
341+ },
342+ "dtx_aggr with path" : {
343+ args : []string {"dtx_aggr" , "--cmt_time=0" , "[0]" },
344+ setup : func () {
345+ ddb_run_dtx_aggr_Fn = func (path string , cmtTime uint64 , cmtDate string ) error {
346+ fmt .Println ("dtx_aggr called" )
347+ if err := isArgEqual ("[0]" , path , "path" ); err != nil {
348+ return err
349+ }
350+ if err := isArgEqual (uint64 (0 ), cmtTime , "cmtTime" ); err != nil {
351+ return err
352+ }
353+ return nil
354+ }
355+ },
356+ expStdout : []string {"dtx_aggr called" },
357+ },
358+
359+ // TODO(follow-up PR): Add TestCmds cases for the remaining commands.
360+ // Each new test case follows the same pattern as the cases above: set the
361+ // corresponding ddb_run_<cmd>_Fn hook in setup() to verify argument passing,
362+ // then add the case to this table.
363+ // Commands still to be covered: close, superblock_dump, value_dump, rm,
364+ // value_load, ilog_dump, ilog_commit, ilog_clear, dtx_dump, dtx_cmt_clear,
365+ // smd_sync, vea_dump, vea_update, dtx_act_commit, dtx_act_abort, rm_pool,
366+ // dtx_act_discard_invalid, dev_list, dev_replace, dtx_stat, prov_mem.
183367 } {
184368 t .Run (name , func (t * testing.T ) {
185369 checkCmd := func (t * testing.T , stdout string , err error ) {
@@ -195,6 +379,9 @@ func TestCmds(t *testing.T) {
195379 }
196380
197381 t .Run ("command-line" , func (t * testing.T ) {
382+ if tc .skipCmdLine != "" {
383+ t .Skipf ("skipping command-line mode: %s" , tc .skipCmdLine )
384+ }
198385 ctx := newTestContext (t )
199386 if tc .setup != nil {
200387 tc .setup ()
0 commit comments