Files
coder/coderd/workspaces_internal_test.go
Ehab Younes 9974294ca9 feat: report arbitrary workspace agent session types (#28338)
Report session counts as a dynamic app-name map from the agent, the SSH CLI, and the workspace usage API, so a new IDE flows end to end without a schema, proto, or server change.

- Report through `Stats.session_counts` on Agent API v2.11. Older agents keep reporting through the deprecated count fields.
- Accept arbitrary names from `coder ssh --usage-app` and the workspace usage API. A name the registry does not recognize keeps its identity and is attributed to the `unknown` family.
- Add reconnecting PTY counts to the map without overwriting the counts SSH reported.
- Normalize and merge names before applying the deterministic 64-name cap, ordered by known apps, then count, then name. Overflow sums into `unknown`, and non-positive counts cannot cancel valid activity.
- Strip control characters, treat whitespace-only HTTP app names as absent, and require the exact environment variable prefix when you extract an SSH session type.
- Count overflow entries in `coderd_agentstats_session_counts_overflow_total` and keep raw payloads out of logs.
- Change the usage API's `app_name` to a string, and update the SDK types and API reference.

closes #27410
2026-09-19 00:32:51 +02:00

36 lines
893 B
Go

package coderd
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestNormalizeUsageAppName(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
name string
appName string
want string
}{
{"Empty", "", ""},
{"Whitespace", " \t\n ", ""},
{"NullBytes", "\x00\x00", ""},
// Control characters carry no name, so they must read as an absent
// app name rather than a session under the unknown family.
{"ControlOnly", "\x1b\x07\x01", ""},
{"ControlAndWhitespace", " \x1b \x07\t", ""},
{"EscapeSequenceKeepsPrintableText", "\x1b[31m", "[31m"},
{"Normalized", "Some-Future-IDE", "some_future_ide"},
{"ControlStripped", "cur\x1bsor", "cursor"},
{"LongWhitespace", strings.Repeat(" ", 300), ""},
} {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
require.Equal(t, tc.want, normalizeUsageAppName(tc.appName))
})
}
}