mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
Folds groups of near-identical test bodies (same parent, same parallel flag, differing only in inputs and expected values) into table-driven tests in eight packages: `coderd/templatebuilder`, `scripts/develop`, `agent/agentfiles`, `coderd/x/chatd/chatloop`, `coderd/x/chatd/chatdebug`, `enterprise/aibridgeproxyd`, `cli`, and `coderd/database/db2sdk`. One commit per package. Every case keeps its previous subtest name, `t.Parallel()` placement is unchanged, and the set of `=== RUN` names is identical except where standalone `TestX_Y` funcs became `TestX/Y` subtests (chatloop: 9 funcs into `TestExecuteLocalTools_BatchRuntime`; chatdebug: 15 funcs into two tables). Members whose bodies differ in more than data stayed as they were (listed per package in the commit messages). In `agent/agentfiles` the four `TestFuzzyReplace_*` funcs were already tables, so the shared request plumbing was hoisted into one helper instead of merging the funcs and losing their per-rule docs. Net -1035 lines across 9 test files; runtime is unchanged (all sub-100ms unit tests). | Package | Diff | Funcs removed | Subtests | RUN lines | |---|---|---|---|---| | coderd/templatebuilder | +237 / -291 | 0 | 31 -> 31 | 33 -> 33 | | scripts/develop | +194 / -246 | 0 | 27 -> 27 | 28 -> 28 | | agent/agentfiles | +117 / -260 | 0 | unchanged | 58 -> 58 | | coderd/x/chatd/chatloop | +224 / -306 | 9 | 3 -> 12 | 14 -> 15 | | coderd/x/chatd/chatdebug | +251 / -537 | 13 | 0 -> 15 | 42 -> 44 | | enterprise/aibridgeproxyd | +287 / -419 | 0 | 31 -> 31 | 32 -> 32 | | cli | +143 / -326 | 0 | 15 -> 15 | 16 -> 16 | | coderd/database/db2sdk | +130 / -233 | 0 | 9 -> 9 | 10 -> 10 | ## Validation - Per package: `go test -count=1 -tags=testsmallbatch -parallel=8 ./<pkg>/ -run <regex> -v` before and after, with the `=== RUN` name sets diffed - `go test -race -count=2 -shuffle=on` on each converted test: pass - `golangci-lint run ./<pkg>/...` with a fresh cache: 0 issues in all eight packages - Repository pre-commit hook (including lint/go) passed on every commit Part of the test-suite speedup series (see #29457); independent of the other PRs. ## Remote validation Remote run on a dogfood workspace (separate compute), chat https://dogfood.cdr.dev/agents/5bbe73d0-866a-4841-9cc3-c5e5b4d97e44, tested head `d7c55d6b0e8` against base `9d973372774`: all eight packages pass on the head and under `-race -count=3 -shuffle=on`; package times are sub-second on both sides (unchanged). `=== RUN` name sets: chatloop 15 to 16 lines with all nine `TestExecuteLocalTools_<X>` leaves surviving as `TestExecuteLocalTools_BatchRuntime/<X>`; chatdebug 42 to 44; `aibridgeproxyd` `TestNew` 32 to 32, byte-identical sorted list. One correction to the text above: seven chatdebug leaves are renamed, not preserved verbatim (`TestRecordingTransport_*UnknownLength*` became `TestRecordingTransport_UnknownLengthClose/<name without "UnknownLength">`), so `-run` filters keyed on those old names need updating. Endorsed verdict: PASS. > Xum (an AI agent) authored this PR on behalf of @ibetitsmike.
326 lines
8.2 KiB
Go
326 lines
8.2 KiB
Go
package templatebuilder
|
|
|
|
import (
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestParseBasesFromFS(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("ValidManifest", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fsys := fstest.MapFS{
|
|
"bases/docker/base.json": &fstest.MapFile{
|
|
Data: []byte(`{
|
|
"id": "docker",
|
|
"display_name": "Docker",
|
|
"os": "linux",
|
|
"default_context": {
|
|
"container_image": "codercom/enterprise-base:ubuntu"
|
|
}
|
|
}`),
|
|
},
|
|
"bases/docker/main.tf.tmpl": &fstest.MapFile{
|
|
Data: []byte(`image = "{{ .ContainerImage }}"`),
|
|
},
|
|
"bases/docker/README.md": &fstest.MapFile{
|
|
Data: []byte("# Docker\n"),
|
|
},
|
|
}
|
|
|
|
bases, err := parseBasesFromFS(fsys)
|
|
require.NoError(t, err)
|
|
require.Len(t, bases, 1)
|
|
|
|
b := bases["docker"]
|
|
require.NotNil(t, b)
|
|
require.Equal(t, "docker", b.Manifest.ID)
|
|
require.Equal(t, "Docker", b.Manifest.DisplayName)
|
|
require.Equal(t, "linux", b.Manifest.OS)
|
|
require.Equal(t, "codercom/enterprise-base:ubuntu", b.Manifest.DefaultContext.ContainerImage)
|
|
require.Contains(t, b.Templates, "main.tf.tmpl")
|
|
})
|
|
|
|
t.Run("MultipleBases", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fsys := fstest.MapFS{
|
|
"bases/alpha/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "alpha", "os": "linux"}`),
|
|
},
|
|
"bases/alpha/main.tf.tmpl": &fstest.MapFile{
|
|
Data: []byte(`resource "alpha" {}`),
|
|
},
|
|
"bases/alpha/README.md": &fstest.MapFile{
|
|
Data: []byte("# Alpha\n"),
|
|
},
|
|
"bases/beta/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "beta", "os": "linux"}`),
|
|
},
|
|
"bases/beta/main.tf.tmpl": &fstest.MapFile{
|
|
Data: []byte(`resource "beta" {}`),
|
|
},
|
|
"bases/beta/README.md": &fstest.MapFile{
|
|
Data: []byte("# Beta\n"),
|
|
},
|
|
}
|
|
|
|
bases, err := parseBasesFromFS(fsys)
|
|
require.NoError(t, err)
|
|
require.Len(t, bases, 2)
|
|
require.NotNil(t, bases["alpha"])
|
|
require.NotNil(t, bases["beta"])
|
|
})
|
|
|
|
t.Run("EmptyCatalog", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fsys := fstest.MapFS{
|
|
"bases/.keep": &fstest.MapFile{Data: []byte{}},
|
|
}
|
|
|
|
bases, err := parseBasesFromFS(fsys)
|
|
require.NoError(t, err)
|
|
require.Empty(t, bases)
|
|
})
|
|
|
|
t.Run("PreParsesTemplates", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fsys := fstest.MapFS{
|
|
"bases/mybase/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "mybase", "os": "linux"}`),
|
|
},
|
|
"bases/mybase/main.tf.tmpl": &fstest.MapFile{
|
|
Data: []byte(`image = "{{ .ContainerImage }}"`),
|
|
},
|
|
// .tftpl files are Terraform templatefile() inputs, not Go templates.
|
|
"bases/mybase/cloud-init/config.yaml.tftpl": &fstest.MapFile{
|
|
Data: []byte(`${some_terraform_var}`),
|
|
},
|
|
"bases/mybase/README.md": &fstest.MapFile{
|
|
Data: []byte("# My Base\n"),
|
|
},
|
|
}
|
|
|
|
bases, err := parseBasesFromFS(fsys)
|
|
require.NoError(t, err)
|
|
|
|
b := bases["mybase"]
|
|
require.NotNil(t, b)
|
|
require.Contains(t, b.Templates, "main.tf.tmpl")
|
|
// .tftpl files should not be pre-parsed as Go templates.
|
|
require.NotContains(t, b.Templates, "cloud-init/config.yaml.tftpl")
|
|
})
|
|
|
|
t.Run("AllowsEmptyOS", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fsys := fstest.MapFS{
|
|
"bases/nospec/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "nospec"}`),
|
|
},
|
|
"bases/nospec/README.md": &fstest.MapFile{
|
|
Data: []byte("# No Spec\n"),
|
|
},
|
|
}
|
|
|
|
bases, err := parseBasesFromFS(fsys)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "", bases["nospec"].Manifest.OS)
|
|
})
|
|
|
|
t.Run("AcceptsWindowsOS", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fsys := fstest.MapFS{
|
|
"bases/winbox/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "winbox", "os": "windows"}`),
|
|
},
|
|
"bases/winbox/main.tf.tmpl": &fstest.MapFile{
|
|
Data: []byte(`resource "coder_agent" "main" {}`),
|
|
},
|
|
"bases/winbox/README.md": &fstest.MapFile{
|
|
Data: []byte("# Windows\n"),
|
|
},
|
|
}
|
|
|
|
bases, err := parseBasesFromFS(fsys)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "windows", bases["winbox"].Manifest.OS)
|
|
require.Equal(t, BaseOSWindows, validBaseOS[bases["winbox"].Manifest.OS])
|
|
})
|
|
|
|
t.Run("ParsesAgents", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fsys := fstest.MapFS{
|
|
"bases/multi/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "multi", "os": "linux", "agents": [{"name": "main"}, {"name": "gpu", "default": true}]}`),
|
|
},
|
|
"bases/multi/main.tf.tmpl": &fstest.MapFile{
|
|
Data: []byte(`resource "coder_agent" "main" {}
|
|
resource "coder_agent" "gpu" {}`),
|
|
},
|
|
"bases/multi/README.md": &fstest.MapFile{
|
|
Data: []byte("# Multi\n"),
|
|
},
|
|
}
|
|
|
|
bases, err := parseBasesFromFS(fsys)
|
|
require.NoError(t, err)
|
|
agents := bases["multi"].Manifest.Agents
|
|
require.Equal(t, []BaseAgent{{Name: "main"}, {Name: "gpu", Default: true}}, agents)
|
|
})
|
|
|
|
rejects := []struct {
|
|
name string
|
|
fsys fstest.MapFS
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "RejectsMissingReadme",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "bad", "os": "linux"}`),
|
|
},
|
|
"bases/bad/main.tf.tmpl": &fstest.MapFile{
|
|
Data: []byte(`resource {}`),
|
|
},
|
|
},
|
|
wantErr: "read README.md for base",
|
|
},
|
|
{
|
|
name: "RejectsDirWithoutManifest",
|
|
fsys: fstest.MapFS{
|
|
"bases/nobase/readme.txt": &fstest.MapFile{Data: []byte("hi")},
|
|
},
|
|
wantErr: "read nobase/base.json",
|
|
},
|
|
{
|
|
name: "RejectsEmptyID",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "", "os": "linux"}`),
|
|
},
|
|
},
|
|
wantErr: "empty id",
|
|
},
|
|
{
|
|
name: "RejectsDuplicateID",
|
|
fsys: fstest.MapFS{
|
|
"bases/a/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "dupe", "os": "linux"}`),
|
|
},
|
|
"bases/a/README.md": &fstest.MapFile{
|
|
Data: []byte("# A\n"),
|
|
},
|
|
"bases/b/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "dupe", "os": "linux"}`),
|
|
},
|
|
"bases/b/README.md": &fstest.MapFile{
|
|
Data: []byte("# B\n"),
|
|
},
|
|
},
|
|
wantErr: "duplicate base id",
|
|
},
|
|
{
|
|
name: "RejectsUnknownOS",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "bad", "os": "beos"}`),
|
|
},
|
|
},
|
|
wantErr: `unknown os "beos"`,
|
|
},
|
|
{
|
|
name: "RejectsUnknownField",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "bad", "os": "linux", "dispaly_name": "typo"}`),
|
|
},
|
|
},
|
|
wantErr: "decode",
|
|
},
|
|
{
|
|
name: "RejectsInvalidJSON",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{not json`),
|
|
},
|
|
},
|
|
wantErr: "decode",
|
|
},
|
|
{
|
|
name: "RejectsInvalidTemplate",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "bad", "os": "linux"}`),
|
|
},
|
|
"bases/bad/main.tf.tmpl": &fstest.MapFile{
|
|
Data: []byte(`{{ .Broken`),
|
|
},
|
|
},
|
|
wantErr: "parse templates",
|
|
},
|
|
{
|
|
name: "RejectsEmptyAgentName",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "bad", "os": "linux", "agents": [{"name": ""}]}`),
|
|
},
|
|
},
|
|
wantErr: "empty name",
|
|
},
|
|
{
|
|
name: "RejectsDuplicateAgentName",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "bad", "os": "linux", "agents": [{"name": "main"}, {"name": "main"}]}`),
|
|
},
|
|
},
|
|
wantErr: "duplicate agent name",
|
|
},
|
|
{
|
|
name: "RejectsMultipleDefaultAgents",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "bad", "os": "linux", "agents": [{"name": "a", "default": true}, {"name": "b", "default": true}]}`),
|
|
},
|
|
},
|
|
wantErr: "exactly one required",
|
|
},
|
|
{
|
|
name: "RejectsMultiAgentWithoutDefault",
|
|
fsys: fstest.MapFS{
|
|
"bases/bad/base.json": &fstest.MapFile{
|
|
Data: []byte(`{"id": "bad", "os": "linux", "agents": [{"name": "a"}, {"name": "b"}]}`),
|
|
},
|
|
},
|
|
wantErr: "exactly one required",
|
|
},
|
|
}
|
|
for _, tc := range rejects {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := parseBasesFromFS(tc.fsys)
|
|
require.ErrorContains(t, err, tc.wantErr)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDefaultAgentName(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
require.Equal(t, "", defaultAgentName(nil))
|
|
require.Equal(t, "main", defaultAgentName([]BaseAgent{{Name: "main"}, {Name: "gpu"}}),
|
|
"first agent is the default when none is marked")
|
|
require.Equal(t, "gpu", defaultAgentName([]BaseAgent{{Name: "main"}, {Name: "gpu", Default: true}}),
|
|
"the marked agent is the default")
|
|
}
|