@@ -165,6 +165,30 @@ func Test_AppClient_ReadDeployedApps_BrokenAppsJSON(t *testing.T) {
165165 assert .Equal (t , err .(* slackerror.Error ).Code , slackerror .ErrUnableToParseJSON )
166166}
167167
168+ // Test that a zero-byte or whitespace-only apps.json (e.g. from a truncated
169+ // write after a prior process interrupt) is treated as empty state, not a
170+ // parse error. This prevents a hot loop of unable_to_parse_json events on
171+ // every CLI invocation while the file remains empty on disk.
172+ func Test_AppClient_ReadDeployedApps_EmptyAppsJSON (t * testing.T ) {
173+ tests := map [string ]string {
174+ "zero-byte file" : "" ,
175+ "whitespace-only file" : " \n \t \n " ,
176+ }
177+ for name , contents := range tests {
178+ t .Run (name , func (t * testing.T ) {
179+ ac , _ , _ , pathToAppsJSON , _ , teardown := setup (t )
180+ defer teardown (t )
181+ err := afero .WriteFile (ac .fs , pathToAppsJSON , []byte (contents ), 0600 )
182+ require .NoError (t , err )
183+ err = ac .readDeployedApps ()
184+ require .NoError (t , err )
185+ // The empty file should be rewritten as a valid empty apps object.
186+ f , _ := afero .ReadFile (ac .fs , pathToAppsJSON )
187+ assert .Equal (t , "{}" , string (f ))
188+ })
189+ }
190+ }
191+
168192// Test that pre-existing dev app details get read from apps.dev.json
169193func Test_AppClient_ReadDevApps_ExistingAppsJSON (t * testing.T ) {
170194 ac , _ , _ , _ , pathToDevAppsJSON , teardown := setup (t )
@@ -207,6 +231,29 @@ func Test_AppClient_ReadDevApps_BrokenAppsJSON(t *testing.T) {
207231 assert .Equal (t , err .(* slackerror.Error ).Code , slackerror .ErrUnableToParseJSON )
208232}
209233
234+ // Test that a zero-byte or whitespace-only apps.dev.json (e.g. from a
235+ // truncated write after a prior process interrupt) is treated as empty
236+ // state, not a parse error. See Test_AppClient_ReadDeployedApps_EmptyAppsJSON.
237+ func Test_AppClient_ReadDevApps_EmptyAppsJSON (t * testing.T ) {
238+ tests := map [string ]string {
239+ "zero-byte file" : "" ,
240+ "whitespace-only file" : " \n \t \n " ,
241+ }
242+ for name , contents := range tests {
243+ t .Run (name , func (t * testing.T ) {
244+ ac , _ , _ , _ , pathToDevAppsJSON , teardown := setup (t )
245+ defer teardown (t )
246+ err := afero .WriteFile (ac .fs , pathToDevAppsJSON , []byte (contents ), 0600 )
247+ require .NoError (t , err )
248+ err = ac .readLocalApps ()
249+ require .NoError (t , err )
250+ // The empty file should be rewritten as a valid empty apps object.
251+ f , _ := afero .ReadFile (ac .fs , pathToDevAppsJSON )
252+ assert .Equal (t , "{}" , string (f ))
253+ })
254+ }
255+ }
256+
210257// Test that a team flag config defines the default app name in an empty AppClient
211258func Test_AppClient_getDeployedAppTeamDomain_ViaCLIFlag (t * testing.T ) {
212259 ac , _ , _ , _ , _ , teardown := setup (t )
0 commit comments