@@ -64,40 +64,35 @@ func TestStackListCmd(t *testing.T) {
6464 global .Client = origClient
6565 })
6666
67- // Set up a mock client
67+ // Set up a mock client (shared, but stacksToList is updated per subtest)
6868 mockClient := client.GrpcClient {}
6969 mockCtrl := & MockFabricControllerClient {
7070 canIUseResponse : defangv1.CanIUseResponse {},
7171 }
7272 mockClient .SetFabricClient (mockCtrl )
7373 global .Client = & mockClient
7474
75- // Set up a fake RootCmd with required flags
76- RootCmd = & cobra.Command {Use : "defang" }
77- RootCmd .PersistentFlags ().StringVarP (& global .Stack .Name , "stack" , "s" , global .Stack .Name , "stack name" )
78- RootCmd .PersistentFlags ().VarP (& global .Stack .Provider , "provider" , "P" , "provider" )
79- RootCmd .PersistentFlags ().StringP ("project-name" , "p" , "" , "project name" )
80- RootCmd .PersistentFlags ().StringArrayP ("file" , "f" , []string {}, "compose file path(s)" )
81-
82- // Create stackListCmd with manual RunE to avoid configureLoader call during test
83- var stackListCmd = makeStackListCmd ()
84-
85- // Add stackListCmd as a child of RootCmd
86- RootCmd .AddCommand (stackListCmd )
75+ downStackFile := []byte ("DEFANG_PROVIDER=aws\n AWS_REGION=us-test-1\n DEFANG_MODE=affordable" )
76+ upStackFile := []byte ("DEFANG_PROVIDER=gcp\n GOOGLE_REGION=us-central1\n DEFANG_MODE=balanced" )
8777
8878 tests := []struct {
8979 name string
90- stacks []stacks.Parameters
80+ localStacks []stacks.Parameters
81+ remoteStacks []* defangv1.Stack
82+ cmdArgs []string
9183 expectOutput string
84+ containsAll []string
85+ containsNone []string
9286 }{
9387 {
9488 name : "no stacks present" ,
95- stacks : []stacks.Parameters {},
89+ localStacks : []stacks.Parameters {},
90+ cmdArgs : []string {"list" },
9691 expectOutput : " * No Defang stacks found in the current directory.\n " ,
9792 },
9893 {
9994 name : "multiple stacks present" ,
100- stacks : []stacks.Parameters {
95+ localStacks : []stacks.Parameters {
10196 {
10297 Name : "teststack1" ,
10398 Provider : client .ProviderAWS ,
@@ -111,13 +106,57 @@ func TestStackListCmd(t *testing.T) {
111106 Mode : modes .ModeBalanced ,
112107 },
113108 },
109+ cmdArgs : []string {"list" },
114110 expectOutput : "NAME DEFAULT PROVIDER REGION ACCOUNT MODE DEPLOYEDAT\n " +
115111 "teststack1 aws us-test-2 AFFORDABLE \n " +
116112 "teststack2 gcp us-central1 BALANCED \n " ,
117113 },
114+ {
115+ name : "down stack hidden by default" ,
116+ remoteStacks : []* defangv1.Stack {
117+ {Name : "downstack" , Status : defangv1 .StackStatus_STACK_STATUS_DOWN , StackFile : downStackFile },
118+ },
119+ cmdArgs : []string {"list" },
120+ expectOutput : " * All stacks in the current directory are down.\n " ,
121+ },
122+ {
123+ name : "down stack shown with --all" ,
124+ remoteStacks : []* defangv1.Stack {
125+ {Name : "downstack" , Status : defangv1 .StackStatus_STACK_STATUS_DOWN , StackFile : downStackFile },
126+ },
127+ cmdArgs : []string {"list" , "--all" },
128+ containsAll : []string {"downstack" },
129+ },
130+ {
131+ name : "mixed stacks, down hidden without --all" ,
132+ remoteStacks : []* defangv1.Stack {
133+ {Name : "upstack" , Status : defangv1 .StackStatus_STACK_STATUS_UP , StackFile : upStackFile },
134+ {Name : "downstack" , Status : defangv1 .StackStatus_STACK_STATUS_DOWN , StackFile : downStackFile },
135+ },
136+ cmdArgs : []string {"list" },
137+ containsAll : []string {"upstack" },
138+ containsNone : []string {"downstack" },
139+ },
140+ {
141+ name : "mixed stacks, all shown with --all" ,
142+ remoteStacks : []* defangv1.Stack {
143+ {Name : "upstack" , Status : defangv1 .StackStatus_STACK_STATUS_UP , StackFile : upStackFile },
144+ {Name : "downstack" , Status : defangv1 .StackStatus_STACK_STATUS_DOWN , StackFile : downStackFile },
145+ },
146+ cmdArgs : []string {"list" , "--all" },
147+ containsAll : []string {"upstack" , "downstack" },
148+ },
118149 }
119150 for _ , tt := range tests {
120151 t .Run (tt .name , func (t * testing.T ) {
152+ // Recreate RootCmd and stackListCmd per subtest so flag state is fresh
153+ RootCmd = & cobra.Command {Use : "defang" }
154+ RootCmd .PersistentFlags ().StringVarP (& global .Stack .Name , "stack" , "s" , global .Stack .Name , "stack name" )
155+ RootCmd .PersistentFlags ().VarP (& global .Stack .Provider , "provider" , "P" , "provider" )
156+ RootCmd .PersistentFlags ().StringP ("project-name" , "p" , "" , "project name" )
157+ RootCmd .PersistentFlags ().StringArrayP ("file" , "f" , []string {}, "compose file path(s)" )
158+ RootCmd .AddCommand (makeStackListCmd ())
159+
121160 // Setup stacks
122161 t .Chdir (t .TempDir ())
123162 // create a compose file so stackListCmd doesn't error out
@@ -128,18 +167,27 @@ func TestStackListCmd(t *testing.T) {
128167 image: nginx` ),
129168 os .FileMode (0644 ),
130169 )
131- for _ , stack := range tt .stacks {
170+ for _ , stack := range tt .localStacks {
132171 stacks .CreateInDirectory ("." , stack )
133172 }
173+ mockCtrl .stacksToList = tt .remoteStacks
134174
135175 buffer := new (bytes.Buffer )
136176 mockStdin := bytes .NewReader ([]byte {})
137177 MockTerm (t , buffer , mockStdin )
138178
139- RootCmd .SetArgs ([] string { "list" } )
179+ RootCmd .SetArgs (tt . cmdArgs )
140180 err := RootCmd .Execute ()
141181 assert .NoError (t , err )
142- assert .Equal (t , tt .expectOutput , buffer .String ())
182+ if tt .expectOutput != "" {
183+ assert .Equal (t , tt .expectOutput , buffer .String ())
184+ }
185+ for _ , s := range tt .containsAll {
186+ assert .Contains (t , buffer .String (), s )
187+ }
188+ for _ , s := range tt .containsNone {
189+ assert .NotContains (t , buffer .String (), s )
190+ }
143191 })
144192 }
145193}
0 commit comments