carlos / platform Public

sidecars: surface list truncation in ls

Paul Campbell pushed by paul@keymail.dev 14dcd8b53f6755430db884e5a4dc1574d8a1d8f2 parent 7369fde
2 files changed, +75 −3
  • sidecars_cli.go +9 −1
  • sidecars_cli_test.go +66 −2
diff --git a/sidecars_cli.go b/sidecars_cli.go
index 4ccab29c3..d0b3b29b7 100644
--- a/sidecars_cli.go
+++ b/sidecars_cli.go
@@ -416,8 +416,16 @@ func runSidecarsList(args []string) {
sidecarVersionCell(r.RunningVersion), r.CreatedAt, r.CreatedBy)
}
w.Flush()
+ // The console caps one answer at sidecarListMax (500, apisidecars.go)
+ // and says so honestly via `truncated` — this line is the same honesty
+ // rule as VERSION's "unknown": a list that quietly stops at a prefix
+ // and says nothing is exactly the overclaim the rest of this branch
+ // refuses to make, and it is not hypothetical for the motivating
+ // customer (Eleven: a bot per enrolled member, so exceeding 500 is
+ // growth, not misuse). No pagination here — a cursor is a product
+ // decision, not this fix's job — just the fact that more exist.
if truncated {
- mutedf(stdout, "(truncated at 500 records)")
+ mutedf(stdout, "(showing the first %d sidecars — more exist)", len(recs))
}
}
diff --git a/sidecars_cli_test.go b/sidecars_cli_test.go
index 073f54c38..da55ed25d 100644
--- a/sidecars_cli_test.go
+++ b/sidecars_cli_test.go
@@ -5,12 +5,20 @@
// exists in this package for os.Exit paths). What's tested directly
// instead is sidecarsEnable, the core PutSidecarManifest wrapper;
// parseArgv, the -args flag's whitespace-split helper; parseDurationSeconds,
-// the -idle/-max-run duration-to-seconds conversion; and the two small
-// render helpers `ls`'s VERSION and PLACEMENT columns go through.
+// the -idle/-max-run duration-to-seconds conversion; the two small render
+// helpers `ls`'s VERSION and PLACEMENT columns go through; and
+// TestSidecarsListTruncatedNotice, which drives the real runSidecarsList
+// against a fake console (apimode_test.go's newTestSession/loginTo/
+// apiTestAccount verb-level fixtures) to pin the truncation honesty notice
+// added in review round 1.
package main
import (
"context"
+ "encoding/json"
+ "net/http"
+ "net/http/httptest"
+ "strings"
"testing"
"github.com/carlosframework/platform/internal/provision"
@@ -147,3 +155,59 @@ func TestSidecarPlacementCell(t *testing.T) {
}
}
}
+
+// TestSidecarsListTruncatedNotice pins the truncation honesty rule added in
+// Task 14 review round 1: the console caps one `ls` answer at
+// sidecarListMax (500, internal/console/apisidecars.go) and reports it via
+// the response's `truncated` flag; a caller that prints the records and
+// drops that flag on the floor renders a list that quietly stops at a
+// prefix and says nothing — the same overclaim VERSION's "unknown" exists
+// to prevent, and not hypothetical for the motivating customer (Eleven: a
+// bot per enrolled member, so exceeding 500 is growth, not misuse).
+//
+// This drives the real runSidecarsList — not just the client method —
+// against a fake console built the way apimode_test.go's other verb-level
+// tests are (newTestSession/loginTo/apiTestAccount), asserting the notice
+// appears for a truncated answer and stays silent for a whole one. Those
+// two cases are the mutation check the brief asked for: a change that
+// ignores the flag entirely (always prints it, or never does) fails
+// exactly one of the two subtests.
+func TestSidecarsListTruncatedNotice(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ truncated bool
+ }{
+ {"truncated", true},
+ {"not truncated", false},
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ useTempCredentials(t)
+ clearDeploymentEnv(t)
+ checkNoRegistry := requireNoRegistryTouch(t)
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ json.NewEncoder(w).Encode(map[string]any{
+ "sidecars": []map[string]any{
+ {"name": "bot-acme", "host": "bot-acme.titogo.bab.sidecar.internal", "channel": "stable"},
+ },
+ "truncated": tc.truncated,
+ })
+ }))
+ defer ts.Close()
+ loginTo(t, ts.URL, "vicky@keymail.dev")
+
+ buf := captureStdout(t)
+ runSidecarsList([]string{"-app", "titogo", "-account", apiTestAccount})
+
+ out := buf.String()
+ const notice = "more exist"
+ if tc.truncated && !strings.Contains(out, notice) {
+ t.Fatalf("ls stdout = %q, want a truncation notice containing %q", out, notice)
+ }
+ if !tc.truncated && strings.Contains(out, notice) {
+ t.Fatalf("ls stdout = %q, must NOT claim more exist for a whole (untruncated) answer", out)
+ }
+ checkNoRegistry()
+ })
+ }
+}