From ca0125e6acea2cb0239ac5effca4dc1f4bb802aa Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Thu, 20 Apr 2023 22:44:25 +0000 Subject: [PATCH 1/6] chore: skip timing-sensistive AgentMetadata test in the standard suite --- agent/agent_test.go | 141 +++++++++++++++++++++++++++----------------- testutil/timing.go | 21 +++++++ 2 files changed, 109 insertions(+), 53 deletions(-) create mode 100644 testutil/timing.go diff --git a/agent/agent_test.go b/agent/agent_test.go index adc85ffe2f4c4..38a70a7b912bb 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1011,78 +1011,113 @@ func TestAgent_Metadata(t *testing.T) { }) t.Run("Many", func(t *testing.T) { + t.Parallel() + script := "echo -n hello" if runtime.GOOS == "windows" { - // Shell scripting in Windows is a pain, and we have already tested - // that the OS logic works in the simpler "Once" test above. - t.Skip() + script = "powershell " + script } - t.Parallel() - - dir := t.TempDir() - - const reportInterval = 2 - const intervalUnit = 100 * time.Millisecond - var ( - greetingPath = filepath.Join(dir, "greeting") - script = "echo hello | tee -a " + greetingPath - ) + //nolint:dogsled _, client, _, _, _ := setupAgent(t, agentsdk.Manifest{ Metadata: []codersdk.WorkspaceAgentMetadataDescription{ { Key: "greeting", - Interval: reportInterval, + Interval: 1, Script: script, }, - { - Key: "bad", - Interval: reportInterval, - Script: "exit 1", - }, }, }, 0) + var gotMd map[string]agentsdk.PostMetadataRequest require.Eventually(t, func() bool { - return len(client.getMetadata()) == 2 + gotMd = client.getMetadata() + return len(gotMd) == 1 }, testutil.WaitShort, testutil.IntervalMedium) - for start := time.Now(); time.Since(start) < testutil.WaitMedium; time.Sleep(testutil.IntervalMedium) { - md := client.getMetadata() - if len(md) != 2 { - panic("unexpected number of metadata entries") - } + collectedAt1 := gotMd["greeting"].CollectedAt + assert.Equal(t, "hello", gotMd["greeting"].Value) - require.Equal(t, "hello\n", md["greeting"].Value) - require.Equal(t, "exit status 1", md["bad"].Error) + if !assert.Eventually(t, func() bool { + gotMd = client.getMetadata() + return gotMd["greeting"].CollectedAt.After(collectedAt1) + }, testutil.WaitShort, testutil.IntervalMedium) { + t.Fatalf("expected metadata to be collected again") + } + }) +} - greetingByt, err := os.ReadFile(greetingPath) - require.NoError(t, err) +func TestAgentMetadata_Timing(t *testing.T) { + if runtime.GOOS == "windows" { + // Shell scripting in Windows is a pain, and we have already tested + // that the OS logic works in the simpler tests. + t.Skip() + } + testutil.SkipIfNotTiming(t) + t.Parallel() - var ( - numGreetings = bytes.Count(greetingByt, []byte("hello")) - idealNumGreetings = time.Since(start) / (reportInterval * intervalUnit) - // We allow a 50% error margin because the report loop may backlog - // in CI and other toasters. In production, there is no hard - // guarantee on timing either, and the frontend gives similar - // wiggle room to the staleness of the value. - upperBound = int(idealNumGreetings) + 1 - lowerBound = (int(idealNumGreetings) / 2) - ) - - if idealNumGreetings < 50 { - // There is an insufficient sample size. - continue - } + dir := t.TempDir() - t.Logf("numGreetings: %d, idealNumGreetings: %d", numGreetings, idealNumGreetings) - // The report loop may slow down on load, but it should never, ever - // speed up. - if numGreetings > upperBound { - t.Fatalf("too many greetings: %d > %d in %v", numGreetings, upperBound, time.Since(start)) - } else if numGreetings < lowerBound { - t.Fatalf("too few greetings: %d < %d", numGreetings, lowerBound) - } + const reportInterval = 2 + const intervalUnit = 100 * time.Millisecond + var ( + greetingPath = filepath.Join(dir, "greeting") + script = "echo hello | tee -a " + greetingPath + ) + _, client, _, _, _ := setupAgent(t, agentsdk.Manifest{ + Metadata: []codersdk.WorkspaceAgentMetadataDescription{ + { + Key: "greeting", + Interval: reportInterval, + Script: script, + }, + { + Key: "bad", + Interval: reportInterval, + Script: "exit 1", + }, + }, + }, 0) + + require.Eventually(t, func() bool { + return len(client.getMetadata()) == 2 + }, testutil.WaitShort, testutil.IntervalMedium) + + for start := time.Now(); time.Since(start) < testutil.WaitMedium; time.Sleep(testutil.IntervalMedium) { + md := client.getMetadata() + if len(md) != 2 { + panic("unexpected number of metadata entries") } - }) + + require.Equal(t, "hello\n", md["greeting"].Value) + require.Equal(t, "exit status 1", md["bad"].Error) + + greetingByt, err := os.ReadFile(greetingPath) + require.NoError(t, err) + + var ( + numGreetings = bytes.Count(greetingByt, []byte("hello")) + idealNumGreetings = time.Since(start) / (reportInterval * intervalUnit) + // We allow a 50% error margin because the report loop may backlog + // in CI and other toasters. In production, there is no hard + // guarantee on timing either, and the frontend gives similar + // wiggle room to the staleness of the value. + upperBound = int(idealNumGreetings) + 1 + lowerBound = (int(idealNumGreetings) / 2) + ) + + if idealNumGreetings < 50 { + // There is an insufficient sample size. + continue + } + + t.Logf("numGreetings: %d, idealNumGreetings: %d", numGreetings, idealNumGreetings) + // The report loop may slow down on load, but it should never, ever + // speed up. + if numGreetings > upperBound { + t.Fatalf("too many greetings: %d > %d in %v", numGreetings, upperBound, time.Since(start)) + } else if numGreetings < lowerBound { + t.Fatalf("too few greetings: %d < %d", numGreetings, lowerBound) + } + } } func TestAgent_Lifecycle(t *testing.T) { diff --git a/testutil/timing.go b/testutil/timing.go new file mode 100644 index 0000000000000..857798ad45ce5 --- /dev/null +++ b/testutil/timing.go @@ -0,0 +1,21 @@ +package testutil + +import ( + "flag" + "testing" +) + +// We can't run timing-sensitive tests in CI because of the +// great variance in runner performance. Instead of not testing timing at all, +// we relegate it to humans manually running certain tests with the "-timing" +// flag from time to time. +// +// Eventually, we should run all timing tests in a self-hosted runner. + +var timingFlag = flag.Bool("timing", false, "run timing-sensitive tests") + +func SkipIfNotTiming(t *testing.T) { + if !*timingFlag { + t.Skip("skipping timing-sensitive test") + } +} From ba6f151a5882da3144d6b2f2df5d8f455a3ef033 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Fri, 21 Apr 2023 19:58:01 +0000 Subject: [PATCH 2/6] Add test-timing target --- Makefile | 20 ++++++++++++++++++++ agent/agent_test.go | 1 + 2 files changed, 21 insertions(+) diff --git a/Makefile b/Makefile index 62c2a612e009f..cfbf28dec4e05 100644 --- a/Makefile +++ b/Makefile @@ -639,6 +639,26 @@ test-postgres-docker: done .PHONY: test-postgres-docker +build/go_tests.json: $(GO_SRC_FILES) + go test ./... -list="." -json > "$@" + +test-timing: build/go_tests.json + # The timing tests intentionally run without parallelism to avoid flakiness. + function test_cmds { + cat "$<" \ + | jq -r ' + select(.Action == "output" and (.Output | test("_Timing\n"))) + | "go test \(.Package) -run=^\(.Output)" + ' \ + | grep -v ^$$ + } + while read cmd; do + echo "running $$cmd" + $$cmd + done < <(test_cmds) + +.PHONY: test-timing + test-clean: go clean -testcache .PHONY: test-clean diff --git a/agent/agent_test.go b/agent/agent_test.go index 38a70a7b912bb..0b6529b971bb9 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1062,6 +1062,7 @@ func TestAgentMetadata_Timing(t *testing.T) { greetingPath = filepath.Join(dir, "greeting") script = "echo hello | tee -a " + greetingPath ) + //nolint:dogsled _, client, _, _, _ := setupAgent(t, agentsdk.Manifest{ Metadata: []codersdk.WorkspaceAgentMetadataDescription{ { From 56a45cc1acdbfe84e14663afa15843e2df34dcf1 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Fri, 21 Apr 2023 20:45:38 +0000 Subject: [PATCH 3/6] fix windows? --- agent/agent.go | 61 ++++++++++++++++++++++++++++++++++++++++----- agent/agent_test.go | 21 ++++++++-------- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index efd57e5db29db..3f08155ab4d75 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -14,9 +14,11 @@ import ( "net/http" "net/netip" "os" + "os/exec" "os/user" "path/filepath" "reflect" + "runtime" "sort" "strconv" "strings" @@ -35,6 +37,7 @@ import ( "cdr.dev/slog" "github.com/coder/coder/agent/agentssh" + "github.com/coder/coder/agent/usershell" "github.com/coder/coder/buildinfo" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/gitauth" @@ -202,7 +205,36 @@ func (a *agent) runLoop(ctx context.Context) { } } -func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMetadataDescription) *codersdk.WorkspaceAgentMetadataResult { +func createMetadataCommand(ctx context.Context, script string) (*exec.Cmd, error) { + // This is largely copied from agentssh, but for some reason the command + // generated there always returns exit status 1 in Windows. + currentUser, err := user.Current() + if err != nil { + return nil, xerrors.Errorf("get current user: %w", err) + } + username := currentUser.Username + + shell, err := usershell.Get(username) + if err != nil { + return nil, xerrors.Errorf("get user shell: %w", err) + } + + var caller string + switch { + case filepath.Base(shell) == "pwsh.exe": + caller = "-Command" + case runtime.GOOS == "windows": + caller = "/c" + default: + caller = "-c" + } + // args := []string{caller, "Get-Process"} + args := []string{"-NoProfile", "-NonInteractive"} + _ = caller + return exec.CommandContext(ctx, "powershell", args...), nil +} + +func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMetadataDescription) *codersdk.WorkspaceAgentMetadataResult { var out bytes.Buffer result := &codersdk.WorkspaceAgentMetadataResult{ // CollectedAt is set here for testing purposes and overrode by @@ -213,18 +245,33 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM // if it is certain the clocks are in sync. CollectedAt: time.Now(), } - cmd, err := a.sshServer.CreateCommand(ctx, md.Script, nil) + cmd, err := createMetadataCommand(ctx, md.Script) if err != nil { - result.Error = err.Error() + result.Error = fmt.Sprintf("create cmd: %+v", err) return result } + // execPath, err := exec.LookPath("cmd.exe") + // if err != nil { + // result.Error = fmt.Sprintf("look path: %+v", err) + // return result + // } + + // cmd = exec.CommandContext(ctx, execPath, "/c", "echo hello") + cmd.Stdout = &out cmd.Stderr = &out + cmd.Stdin = io.LimitReader(nil, 0) - // The error isn't mutually exclusive with useful output. - err = cmd.Run() + // We split up Start and Wait so that we can return a more useful error. + err = cmd.Start() + if err != nil { + result.Error = fmt.Sprintf("start cmd: %+v", err) + return result + } + // This error isn't mutually exclusive with useful output. + err = cmd.Wait() const bufLimit = 10 << 10 if out.Len() > bufLimit { err = errors.Join( @@ -234,8 +281,10 @@ func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentM out.Truncate(bufLimit) } + fmt.Printf("ran %+v %+q: %v\n", cmd.Path, cmd.Args, err) + if err != nil { - result.Error = err.Error() + result.Error = fmt.Sprintf("run cmd: %+v", err) } result.Value = out.String() return result diff --git a/agent/agent_test.go b/agent/agent_test.go index 0b6529b971bb9..a58d0f0ba64d3 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -976,19 +976,20 @@ func TestAgent_StartupScript(t *testing.T) { func TestAgent_Metadata(t *testing.T) { t.Parallel() + echoHello := "echo hello" + if runtime.GOOS == "windows" { + echoHello = "echo 'hello'" + } + t.Run("Once", func(t *testing.T) { t.Parallel() - script := "echo -n hello" - if runtime.GOOS == "windows" { - script = "powershell " + script - } //nolint:dogsled _, client, _, _, _ := setupAgent(t, agentsdk.Manifest{ Metadata: []codersdk.WorkspaceAgentMetadataDescription{ { Key: "greeting", Interval: 0, - Script: script, + Script: echoHello, }, }, }, 0) @@ -1012,17 +1013,13 @@ func TestAgent_Metadata(t *testing.T) { t.Run("Many", func(t *testing.T) { t.Parallel() - script := "echo -n hello" - if runtime.GOOS == "windows" { - script = "powershell " + script - } //nolint:dogsled _, client, _, _, _ := setupAgent(t, agentsdk.Manifest{ Metadata: []codersdk.WorkspaceAgentMetadataDescription{ { Key: "greeting", Interval: 1, - Script: script, + Script: echoHello, }, }, }, 0) @@ -1034,7 +1031,9 @@ func TestAgent_Metadata(t *testing.T) { }, testutil.WaitShort, testutil.IntervalMedium) collectedAt1 := gotMd["greeting"].CollectedAt - assert.Equal(t, "hello", gotMd["greeting"].Value) + if !assert.Equal(t, "hello\n", gotMd["greeting"].Value) { + t.Logf("got: %+v", gotMd) + } if !assert.Eventually(t, func() bool { gotMd = client.getMetadata() From cae381f88aeaccde5f65dd23bed7b348d6dfba4c Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Fri, 21 Apr 2023 20:31:15 -0500 Subject: [PATCH 4/6] Works on my Windows desktop? --- agent/agent.go | 49 ++++++++++++++++++++------------------------- agent/agent_test.go | 9 +++------ 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 3f08155ab4d75..4be86a2ae447a 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -18,7 +18,7 @@ import ( "os/user" "path/filepath" "reflect" - "runtime" + "regexp" "sort" "strconv" "strings" @@ -205,9 +205,17 @@ func (a *agent) runLoop(ctx context.Context) { } } +var ( + isCmdExeRe = regexp.MustCompile(`^(cmd|cmd\.exe)$`) +) + func createMetadataCommand(ctx context.Context, script string) (*exec.Cmd, error) { // This is largely copied from agentssh, but for some reason the command - // generated there always returns exit status 1 in Windows. + // generated there always returns exit status 1 in Windows powershell. + // + // This function puts special PowerShell branching in place that fixes the issue, + // but I'm hesitant on porting it to agentssh before understanding exactly what's + // happening. currentUser, err := user.Current() if err != nil { return nil, xerrors.Errorf("get current user: %w", err) @@ -218,31 +226,28 @@ func createMetadataCommand(ctx context.Context, script string) (*exec.Cmd, error if err != nil { return nil, xerrors.Errorf("get user shell: %w", err) } + shellBase := filepath.Base(shell) - var caller string + var args []string switch { - case filepath.Base(shell) == "pwsh.exe": - caller = "-Command" - case runtime.GOOS == "windows": - caller = "/c" + case isCmdExeRe.MatchString(shellBase): + args = append(args, "/c") default: - caller = "-c" + // -c works for powershell and sh variants. + args = append(args, "-c") } - // args := []string{caller, "Get-Process"} - args := []string{"-NoProfile", "-NonInteractive"} - _ = caller - return exec.CommandContext(ctx, "powershell", args...), nil + args = append(args, script) + return exec.CommandContext(ctx, shell, args...), nil } func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMetadataDescription) *codersdk.WorkspaceAgentMetadataResult { var out bytes.Buffer result := &codersdk.WorkspaceAgentMetadataResult{ // CollectedAt is set here for testing purposes and overrode by - // the server to the time the server received the result to protect - // against clock skew. + // coderd to the time of server receipt to solve clock skew. // // In the future, the server may accept the timestamp from the agent - // if it is certain the clocks are in sync. + // if it can guarantee the clocks are synchronized. CollectedAt: time.Now(), } cmd, err := createMetadataCommand(ctx, md.Script) @@ -251,19 +256,11 @@ func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMet return result } - // execPath, err := exec.LookPath("cmd.exe") - // if err != nil { - // result.Error = fmt.Sprintf("look path: %+v", err) - // return result - // } - - // cmd = exec.CommandContext(ctx, execPath, "/c", "echo hello") - cmd.Stdout = &out cmd.Stderr = &out cmd.Stdin = io.LimitReader(nil, 0) - // We split up Start and Wait so that we can return a more useful error. + // We split up Start and Wait instead of calling Run so that we can return a more precise error. err = cmd.Start() if err != nil { result.Error = fmt.Sprintf("start cmd: %+v", err) @@ -281,10 +278,8 @@ func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMet out.Truncate(bufLimit) } - fmt.Printf("ran %+v %+q: %v\n", cmd.Path, cmd.Args, err) - if err != nil { - result.Error = fmt.Sprintf("run cmd: %+v", err) + result.Error = fmt.Sprintf("run cmd (shell %v): %+v", cmd.Path, err) } result.Value = out.String() return result diff --git a/agent/agent_test.go b/agent/agent_test.go index a58d0f0ba64d3..8098149e8af78 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -976,10 +976,7 @@ func TestAgent_StartupScript(t *testing.T) { func TestAgent_Metadata(t *testing.T) { t.Parallel() - echoHello := "echo hello" - if runtime.GOOS == "windows" { - echoHello = "echo 'hello'" - } + echoHello := "echo 'hello'" t.Run("Once", func(t *testing.T) { t.Parallel() @@ -1031,8 +1028,8 @@ func TestAgent_Metadata(t *testing.T) { }, testutil.WaitShort, testutil.IntervalMedium) collectedAt1 := gotMd["greeting"].CollectedAt - if !assert.Equal(t, "hello\n", gotMd["greeting"].Value) { - t.Logf("got: %+v", gotMd) + if !assert.Equal(t, "hello", strings.TrimSpace(gotMd["greeting"].Value)) { + t.Errorf("got: %+v", gotMd) } if !assert.Eventually(t, func() bool { From 05127e6c0f8bb739b413fb4807712cec1a8afe20 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Sat, 22 Apr 2023 22:22:52 +0000 Subject: [PATCH 5/6] Use tag system --- Makefile | 20 ---------------- agent/agent.go | 48 ++++++--------------------------------- agent/agent_test.go | 3 ++- testutil/enable_timing.go | 8 +++++++ testutil/timing.go | 5 ++-- 5 files changed, 19 insertions(+), 65 deletions(-) create mode 100644 testutil/enable_timing.go diff --git a/Makefile b/Makefile index cfbf28dec4e05..62c2a612e009f 100644 --- a/Makefile +++ b/Makefile @@ -639,26 +639,6 @@ test-postgres-docker: done .PHONY: test-postgres-docker -build/go_tests.json: $(GO_SRC_FILES) - go test ./... -list="." -json > "$@" - -test-timing: build/go_tests.json - # The timing tests intentionally run without parallelism to avoid flakiness. - function test_cmds { - cat "$<" \ - | jq -r ' - select(.Action == "output" and (.Output | test("_Timing\n"))) - | "go test \(.Package) -run=^\(.Output)" - ' \ - | grep -v ^$$ - } - while read cmd; do - echo "running $$cmd" - $$cmd - done < <(test_cmds) - -.PHONY: test-timing - test-clean: go clean -testcache .PHONY: test-clean diff --git a/agent/agent.go b/agent/agent.go index 4be86a2ae447a..c3207de0fa885 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -14,11 +14,9 @@ import ( "net/http" "net/netip" "os" - "os/exec" "os/user" "path/filepath" "reflect" - "regexp" "sort" "strconv" "strings" @@ -37,7 +35,6 @@ import ( "cdr.dev/slog" "github.com/coder/coder/agent/agentssh" - "github.com/coder/coder/agent/usershell" "github.com/coder/coder/buildinfo" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/gitauth" @@ -205,42 +202,7 @@ func (a *agent) runLoop(ctx context.Context) { } } -var ( - isCmdExeRe = regexp.MustCompile(`^(cmd|cmd\.exe)$`) -) - -func createMetadataCommand(ctx context.Context, script string) (*exec.Cmd, error) { - // This is largely copied from agentssh, but for some reason the command - // generated there always returns exit status 1 in Windows powershell. - // - // This function puts special PowerShell branching in place that fixes the issue, - // but I'm hesitant on porting it to agentssh before understanding exactly what's - // happening. - currentUser, err := user.Current() - if err != nil { - return nil, xerrors.Errorf("get current user: %w", err) - } - username := currentUser.Username - - shell, err := usershell.Get(username) - if err != nil { - return nil, xerrors.Errorf("get user shell: %w", err) - } - shellBase := filepath.Base(shell) - - var args []string - switch { - case isCmdExeRe.MatchString(shellBase): - args = append(args, "/c") - default: - // -c works for powershell and sh variants. - args = append(args, "-c") - } - args = append(args, script) - return exec.CommandContext(ctx, shell, args...), nil -} - -func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMetadataDescription) *codersdk.WorkspaceAgentMetadataResult { +func (a *agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMetadataDescription) *codersdk.WorkspaceAgentMetadataResult { var out bytes.Buffer result := &codersdk.WorkspaceAgentMetadataResult{ // CollectedAt is set here for testing purposes and overrode by @@ -250,7 +212,7 @@ func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMet // if it can guarantee the clocks are synchronized. CollectedAt: time.Now(), } - cmd, err := createMetadataCommand(ctx, md.Script) + cmd, err := a.sshServer.CreateCommand(ctx, md.Script, nil) if err != nil { result.Error = fmt.Sprintf("create cmd: %+v", err) return result @@ -278,8 +240,12 @@ func (*agent) collectMetadata(ctx context.Context, md codersdk.WorkspaceAgentMet out.Truncate(bufLimit) } + // Important: if the command times out, we may see a misleading error like + // "exit status 1", so it's important to include the context error. + err = errors.Join(err, ctx.Err()) + if err != nil { - result.Error = fmt.Sprintf("run cmd (shell %v): %+v", cmd.Path, err) + result.Error = fmt.Sprintf("run cmd: %+v", err) } result.Value = out.String() return result diff --git a/agent/agent_test.go b/agent/agent_test.go index 8098149e8af78..6c409102d993e 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1016,6 +1016,7 @@ func TestAgent_Metadata(t *testing.T) { { Key: "greeting", Interval: 1, + Timeout: 100, Script: echoHello, }, }, @@ -1085,7 +1086,7 @@ func TestAgentMetadata_Timing(t *testing.T) { } require.Equal(t, "hello\n", md["greeting"].Value) - require.Equal(t, "exit status 1", md["bad"].Error) + require.Equal(t, "run cmd: exit status 1", md["bad"].Error) greetingByt, err := os.ReadFile(greetingPath) require.NoError(t, err) diff --git a/testutil/enable_timing.go b/testutil/enable_timing.go new file mode 100644 index 0000000000000..d9fffafd95c42 --- /dev/null +++ b/testutil/enable_timing.go @@ -0,0 +1,8 @@ +//go:build timing + +package testutil + +var _ = func() any { + timing = true + return nil +}() diff --git a/testutil/timing.go b/testutil/timing.go index 857798ad45ce5..9cdd3bd8f64d2 100644 --- a/testutil/timing.go +++ b/testutil/timing.go @@ -1,7 +1,6 @@ package testutil import ( - "flag" "testing" ) @@ -12,10 +11,10 @@ import ( // // Eventually, we should run all timing tests in a self-hosted runner. -var timingFlag = flag.Bool("timing", false, "run timing-sensitive tests") +var timing bool func SkipIfNotTiming(t *testing.T) { - if !*timingFlag { + if !timing { t.Skip("skipping timing-sensitive test") } } From 8d710fb53edaed128595314b657cf619deb386d3 Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Mon, 24 Apr 2023 09:19:59 +0000 Subject: [PATCH 6/6] fixup! Use tag system --- agent/agent_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/agent/agent_test.go b/agent/agent_test.go index 6c409102d993e..3c66518acb9fb 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -1081,9 +1081,7 @@ func TestAgentMetadata_Timing(t *testing.T) { for start := time.Now(); time.Since(start) < testutil.WaitMedium; time.Sleep(testutil.IntervalMedium) { md := client.getMetadata() - if len(md) != 2 { - panic("unexpected number of metadata entries") - } + require.Len(t, md, 2, "got: %+v", md) require.Equal(t, "hello\n", md["greeting"].Value) require.Equal(t, "run cmd: exit status 1", md["bad"].Error)