@@ -22,6 +22,13 @@ func mountpointMetrics(diskUsed, diskLimit, inodesUsed, inodesLimit float64) map
2222 }
2323}
2424
25+ // objectStorageMetrics has no inodes limit, like the API.
26+ var objectStorageMetrics = map [string ]any {
27+ "disk_used" : map [string ]any {"avg" : 400 },
28+ "disk_limit" : map [string ]any {"max" : 1000 },
29+ "inodes_used" : map [string ]any {"avg" : 25 },
30+ }
31+
2532// filterServices applies the services[] query filter, like the API.
2633func filterServices (req * http.Request , services map [string ]any ) map [string ]any {
2734 var names []string
@@ -42,7 +49,14 @@ func filterServices(req *http.Request, services map[string]any) map[string]any {
4249 return filtered
4350}
4451
45- func setupMetricsTest (t * testing.T , withStorage , withStorageMount bool ) (
52+ type metricsTestOptions struct {
53+ storage bool // Services report network storage.
54+ storageMount bool // The app has a storage mount.
55+ objectStorage map [string ]any // The app's object storage metrics, if any.
56+ objectQuota int // The app's object storage quota (MB).
57+ }
58+
59+ func setupMetricsTest (t * testing.T , opts metricsTestOptions ) (
4660 f * cmdFactory , apiHandler * mockapi.Handler , projectID string ,
4761) {
4862 authServer := mockapi .NewAuthServer (t )
@@ -63,9 +77,12 @@ func setupMetricsTest(t *testing.T, withStorage, withStorageMount bool) (
6377 main := makeEnv (projectID , "main" , "production" , "active" , nil )
6478 obsPath := "/projects/" + projectID + "/environments/main/observability"
6579 app := mockapi.App {Name : "app" , Type : "php:8.4" , Size : "AUTO" }
66- if withStorageMount {
80+ if opts . storageMount {
6781 app .Mounts = map [string ]mockapi.Mount {"/files" : {Source : "storage" , SourcePath : "files" }}
6882 }
83+ if opts .objectQuota > 0 {
84+ app .Resources = map [string ]any {"disk" : map [string ]any {"object" : opts .objectQuota }}
85+ }
6986 main .SetCurrentDeployment (& mockapi.Deployment {
7087 WebApps : map [string ]mockapi.App {
7188 "app" : app ,
@@ -106,7 +123,7 @@ func setupMetricsTest(t *testing.T, withStorage, withStorageMount bool) (
106123 "/mnt" : mountpointMetrics (250 , 1000 , 5 , 1000 ),
107124 "/tmp" : mountpointMetrics (10 , 1000 , 1 , 1000 ),
108125 }
109- if withStorage {
126+ if opts . storage {
110127 appMounts ["storage" ] = mountpointMetrics (920 , 1000 , 30 , 100 )
111128 // Storage with a partial set of inode metrics.
112129 dbMounts ["storage" ] = map [string ]any {
@@ -115,6 +132,9 @@ func setupMetricsTest(t *testing.T, withStorage, withStorageMount bool) (
115132 "inodes_limit" : map [string ]any {"max" : 100 },
116133 }
117134 }
135+ if opts .objectStorage != nil {
136+ appMounts ["object storage" ] = opts .objectStorage
137+ }
118138 _ = json .NewEncoder (w ).Encode (map [string ]any {
119139 "_grain" : 60 ,
120140 "_from" : 1790189400 ,
@@ -135,78 +155,138 @@ func setupMetricsTest(t *testing.T, withStorage, withStorageMount bool) (
135155func TestMetricsStorage (t * testing.T ) {
136156 t .Parallel ()
137157 cases := []struct {
138- name string
139- withStorage bool
140- withStorageMount bool
141- env []string
142- args []string
143- want string
144- notWant string
158+ name string
159+ opts metricsTestOptions
160+ env []string
161+ args []string
162+ want string
163+ notWant string
145164 }{
146165 {
147- name : "all storage columns" ,
148- withStorage : true ,
166+ name : "all storage columns" ,
167+ opts : metricsTestOptions { storage : true } ,
149168 args : []string {"metrics:all" , "-1" , "--no-header" , "--format" , "plain" ,
150169 "-c" , "service,disk_percent,storage_percent,storage_inodes_percent" },
151170 want : "app\t 10.0%\t 92.0%\t 30.0%\n db\t 25.0%\t 50.0%\t \n " ,
152171 },
153172 {
154- name : "all table shows storage when present" ,
155- withStorage : true ,
156- args : []string {"metrics:all" , "-1" },
157- want : "Storage %" ,
173+ name : "all table shows storage when present" ,
174+ opts : metricsTestOptions { storage : true } ,
175+ args : []string {"metrics:all" , "-1" },
176+ want : "Storage %" ,
158177 },
159178 {
160179 name : "all table hides storage when absent" ,
161180 args : []string {"metrics:all" , "-1" },
162181 notWant : "Storage" ,
163182 },
164183 {
165- name : "all table shows storage when the deployment has storage mounts" ,
166- withStorageMount : true ,
167- args : []string {"metrics:all" , "-1" },
168- want : "Storage %" ,
184+ name : "all table shows storage when the deployment has storage mounts" ,
185+ opts : metricsTestOptions { storageMount : true } ,
186+ args : []string {"metrics:all" , "-1" },
187+ want : "Storage %" ,
169188 },
170189 {
171- name : "all table ignores storage mounts of filtered-out apps" ,
172- withStorageMount : true ,
173- args : []string {"metrics:all" , "-1" , "-s" , "db" },
174- notWant : "Storage" ,
190+ name : "all table ignores storage mounts of filtered-out apps" ,
191+ opts : metricsTestOptions { storageMount : true } ,
192+ args : []string {"metrics:all" , "-1" , "-s" , "db" },
193+ notWant : "Storage" ,
175194 },
176195 {
177196 name : "all csv always includes storage" ,
178197 args : []string {"metrics:all" , "-1" , "--format" , "csv" },
179- want : "/tmp inodes %,Storage %,Storage inodes %\n " ,
198+ want : "/tmp inodes %,Storage %,Storage inodes %,Object storage % \n " ,
180199 },
181200 {
182- name : "disk-usage storage columns" ,
183- withStorage : true ,
201+ name : "all object storage columns" ,
202+ opts : metricsTestOptions {objectStorage : objectStorageMetrics },
203+ args : []string {"metrics:all" , "-1" , "--no-header" , "-B" , "--format" , "plain" ,
204+ "-c" , "service,object_storage_used,object_storage_limit,object_storage_percent,object_storage_count" },
205+ want : "app\t 400\t 1000\t 40.0%\t 25\n db\t \t \t \t \n " ,
206+ },
207+ {
208+ name : "all object storage without a quota" ,
209+ opts : metricsTestOptions {objectStorage : map [string ]any {
210+ "disk_used" : map [string ]any {"avg" : 400 },
211+ "inodes_used" : map [string ]any {"avg" : 25 },
212+ }},
213+ args : []string {"metrics:all" , "-1" , "--no-header" , "-B" , "--format" , "plain" , "-s" , "app" ,
214+ "-c" , "service,object_storage_used,object_storage_limit,object_storage_percent,object_storage_count" },
215+ want : "app\t 400\t \t \t 25\n " ,
216+ },
217+ {
218+ name : "all table shows object storage when present" ,
219+ opts : metricsTestOptions {objectStorage : objectStorageMetrics },
220+ args : []string {"metrics:all" , "-1" },
221+ want : "Object storage %" ,
222+ },
223+ {
224+ name : "all table hides object storage when absent" ,
225+ args : []string {"metrics:all" , "-1" },
226+ notWant : "Object" ,
227+ },
228+ {
229+ name : "all table shows object storage when the app has a quota" ,
230+ opts : metricsTestOptions {objectQuota : 1024 },
231+ args : []string {"metrics:all" , "-1" },
232+ want : "Object storage %" ,
233+ },
234+ {
235+ name : "all table ignores object storage quotas of filtered-out apps" ,
236+ opts : metricsTestOptions {objectQuota : 1024 },
237+ args : []string {"metrics:all" , "-1" , "-s" , "db" },
238+ notWant : "Object" ,
239+ },
240+ {
241+ name : "disk-usage storage columns" ,
242+ opts : metricsTestOptions {storage : true },
184243 args : []string {"disk" , "-1" , "--no-header" , "-B" , "--format" , "plain" ,
185244 "-c" , "service,storage_used,storage_limit,storage_percent,storage_ipercent" },
186245 want : "app\t 920\t 1000\t 92.0%\t 30.0%\n db\t 500\t 1000\t 50.0%\t \n " ,
187246 },
188247 {
189- name : "disk-usage table shows storage when present" ,
190- withStorage : true ,
191- args : []string {"disk" , "-1" },
192- want : "Storage used" ,
248+ name : "disk-usage table shows storage when present" ,
249+ opts : metricsTestOptions { storage : true } ,
250+ args : []string {"disk" , "-1" },
251+ want : "Storage used" ,
193252 },
194253 {
195254 name : "disk-usage csv always includes storage" ,
196255 args : []string {"disk" , "-1" , "--format" , "csv" },
197- want : "/tmp %,Storage used,Storage limit,Storage %,Storage inodes %\n " ,
256+ want : "/tmp %,Storage used,Storage limit,Storage %,Storage inodes %," +
257+ "Object storage used,Object storage limit,Object storage %\n " ,
258+ },
259+ {
260+ name : "disk-usage object storage columns" ,
261+ opts : metricsTestOptions {objectStorage : objectStorageMetrics },
262+ args : []string {"disk" , "-1" , "--no-header" , "-B" , "--format" , "plain" , "-s" , "app" ,
263+ "-c" , "service,object_used,object_limit,object_percent,object_count" },
264+ want : "app\t 400\t 1000\t 40.0%\t 25\n " ,
265+ },
266+ {
267+ name : "disk-usage table shows object storage when present" ,
268+ opts : metricsTestOptions {objectStorage : objectStorageMetrics },
269+ args : []string {"disk" , "-1" },
270+ want : "Object storage used" ,
198271 },
199272 {
200- name : "disabled" ,
201- withStorage : true ,
202- env : []string {"TEST_CLI_API_METRICS_STORAGE=0" },
203- args : []string {"metrics:all" , "-1" , "--format" , "csv" },
204- notWant : "Storage" ,
273+ name : "disabled" ,
274+ opts : metricsTestOptions {storage : true },
275+ env : []string {"TEST_CLI_API_METRICS_STORAGE=0" },
276+ args : []string {"metrics:all" , "-1" , "--format" , "csv" },
277+ notWant : "Storage" ,
278+ },
279+ {
280+ name : "disabled object storage" ,
281+ opts : metricsTestOptions {objectStorage : objectStorageMetrics },
282+ env : []string {"TEST_CLI_API_METRICS_STORAGE=0" },
283+ args : []string {"disk" , "-1" , "--format" , "csv" },
284+ notWant : "Object" ,
205285 },
206286 }
207287 for _ , c := range cases {
208288 t .Run (c .name , func (t * testing.T ) {
209- f , _ , projectID := setupMetricsTest (t , c .withStorage , c . withStorageMount )
289+ f , _ , projectID := setupMetricsTest (t , c .opts )
210290 // The terminal is wide enough for headers not to wrap.
211291 f .extraEnv = append ([]string {"COLUMNS=500" }, c .env ... )
212292 args := append ([]string {}, c .args ... )
@@ -226,10 +306,12 @@ func TestMetricsStorage(t *testing.T) {
226306
227307func TestMetricsStorageDisabledColumn (t * testing.T ) {
228308 t .Parallel ()
229- f , _ , projectID := setupMetricsTest (t , true , false )
309+ f , _ , projectID := setupMetricsTest (t , metricsTestOptions { storage : true , objectStorage : objectStorageMetrics } )
230310 f .extraEnv = []string {"TEST_CLI_API_METRICS_STORAGE=0" }
231311
232- _ , stderr , err := f .RunCombinedOutput ("disk" , "-1" , "-c" , "storage_used" , "-p" , projectID , "-e" , "main" )
233- assert .Error (t , err )
234- assert .Contains (t , stderr , "Column not found: storage_used" )
312+ for _ , col := range []string {"storage_used" , "object_used" } {
313+ _ , stderr , err := f .RunCombinedOutput ("disk" , "-1" , "-c" , col , "-p" , projectID , "-e" , "main" )
314+ assert .Error (t , err )
315+ assert .Contains (t , stderr , "Column not found: " + col )
316+ }
235317}
0 commit comments