chore: delete dead functions and skip-only or duplicated tests (#29461)

This commit is contained in:
Michael Suchacz
2026-09-17 18:14:08 +02:00
committed by GitHub
parent 7a27db2635
commit d2e94e299a
46 changed files with 154 additions and 2279 deletions
-19
View File
@@ -22,22 +22,3 @@ type ContainerCLI interface {
// Remove removes the container
Remove(ctx context.Context, containerName string) error
}
// noopContainerCLI is a ContainerCLI that does nothing.
type noopContainerCLI struct{}
var _ ContainerCLI = noopContainerCLI{}
func (noopContainerCLI) List(_ context.Context) (codersdk.WorkspaceAgentListContainersResponse, error) {
return codersdk.WorkspaceAgentListContainersResponse{}, nil
}
func (noopContainerCLI) DetectArchitecture(_ context.Context, _ string) (string, error) {
return "<none>", nil
}
func (noopContainerCLI) Copy(_ context.Context, _ string, _ string, _ string) error { return nil }
func (noopContainerCLI) ExecAs(_ context.Context, _ string, _ string, _ ...string) ([]byte, error) {
return nil, nil
}
func (noopContainerCLI) Stop(_ context.Context, _ string) error { return nil }
func (noopContainerCLI) Remove(_ context.Context, _ string) error { return nil }
-9
View File
@@ -177,15 +177,6 @@ type devcontainerCLIReadConfigConfig struct {
stderr io.Writer
}
// WithReadConfigOutput sets additional stdout and stderr writers for logs
// during ReadConfig operations.
func WithReadConfigOutput(stdout, stderr io.Writer) DevcontainerCLIReadConfigOptions {
return func(o *devcontainerCLIReadConfigConfig) {
o.stdout = stdout
o.stderr = stderr
}
}
func applyDevcontainerCLIUpOptions(opts []DevcontainerCLIUpOptions) DevcontainerCLIUpConfig {
conf := DevcontainerCLIUpConfig{Stdout: io.Discard, Stderr: io.Discard}
for _, opt := range opts {
-7
View File
@@ -33,13 +33,6 @@ func WithClock(c quartz.Clock) Option {
}
}
// WithGitBinary overrides the git binary path (for testing).
func WithGitBinary(path string) Option {
return func(h *Handler) {
h.gitBin = path
}
}
const (
// scanCooldown is the minimum interval between successive scans.
scanCooldown = 1 * time.Second
-17
View File
@@ -7,7 +7,6 @@ import (
"net"
"net/http"
"sync"
"time"
"github.com/sony/gobreaker/v2"
"golang.org/x/xerrors"
@@ -187,22 +186,6 @@ func (p *ProviderCircuitBreakers) Execute(endpoint, model string, w http.Respons
return handlerErr
}
// Timeout returns the configured timeout duration for this circuit breaker.
func (p *ProviderCircuitBreakers) Timeout() time.Duration {
return p.config.Timeout
}
// Provider returns the provider name for this circuit breaker.
func (p *ProviderCircuitBreakers) Provider() string {
return p.provider
}
// OpenErrorResponse returns the error response body when the circuit is open.
// This is exposed for handlers to use when responding to rejected requests.
func (p *ProviderCircuitBreakers) OpenErrorResponse() []byte {
return p.openErrBody()
}
// StateToGaugeValue converts gobreaker.State to a gauge value.
// closed=0, half-open=0.5, open=1
func StateToGaugeValue(s gobreaker.State) float64 {
@@ -29,40 +29,6 @@ func newTestAnthropic(t testing.TB, cfg config.Anthropic, bedrockCfg *config.AWS
return p
}
func TestAnthropic_TypeAndName(t *testing.T) {
t.Parallel()
tests := []struct {
name string
cfg config.Anthropic
expectType string
expectName string
}{
{
name: "defaults",
cfg: config.Anthropic{},
expectType: config.ProviderAnthropic,
expectName: config.ProviderAnthropic,
},
{
name: "custom_name",
cfg: config.Anthropic{Name: "anthropic-custom"},
expectType: config.ProviderAnthropic,
expectName: "anthropic-custom",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := newTestAnthropic(t, tc.cfg, nil)
assert.Equal(t, tc.expectType, p.Type())
assert.Equal(t, tc.expectName, p.Name())
})
}
}
func TestNewAnthropic_KeyResolution(t *testing.T) {
t.Parallel()
@@ -482,30 +482,6 @@ func TestBedrock_CircuitBreakerOpenErrorResponse(t *testing.T) {
assert.Equal(t, "service_unavailable", openAIEnvelope.Error.Code)
}
func TestBedrock_TypeAndName(t *testing.T) {
t.Parallel()
p := newTestBedrock(t, config.Anthropic{}, config.AWSBedrock{
Region: "us-west-2",
AccessKey: "test-key",
AccessKeySecret: "test-secret",
Model: "m",
SmallFastModel: "s",
})
assert.Equal(t, config.ProviderBedrock, p.Type())
assert.Equal(t, config.ProviderBedrock, p.Name())
p2 := newTestBedrock(t, config.Anthropic{Name: "bedrock-custom"}, config.AWSBedrock{
Region: "us-west-2",
AccessKey: "test-key",
AccessKeySecret: "test-secret",
Model: "m",
SmallFastModel: "s",
})
assert.Equal(t, config.ProviderBedrock, p2.Type())
assert.Equal(t, "bedrock-custom", p2.Name())
}
func TestBedrock_KeyPool(t *testing.T) {
t.Parallel()
@@ -18,40 +18,6 @@ import (
var testTracer = otel.Tracer("copilot_test")
func TestCopilot_TypeAndName(t *testing.T) {
t.Parallel()
tests := []struct {
name string
cfg config.Copilot
expectType string
expectName string
}{
{
name: "defaults",
cfg: config.Copilot{},
expectType: config.ProviderCopilot,
expectName: config.ProviderCopilot,
},
{
name: "custom_name",
cfg: config.Copilot{Name: "copilot-business"},
expectType: config.ProviderCopilot,
expectName: "copilot-business",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewCopilot(tc.cfg)
assert.Equal(t, tc.expectType, p.Type())
assert.Equal(t, tc.expectName, p.Name())
})
}
}
// TestCopilot_KeyFailoverConfig verifies that Copilot, being BYOK-only,
// returns a zero-value KeyFailoverConfig so that KeyFailoverTransport
// short-circuits and passes the request through unchanged.
-34
View File
@@ -164,40 +164,6 @@ func generateResponsesPayload(payloadSize int, inputCount int, stream bool) []by
return bodyBytes
}
func TestOpenAI_TypeAndName(t *testing.T) {
t.Parallel()
tests := []struct {
name string
cfg config.OpenAI
expectType string
expectName string
}{
{
name: "defaults",
cfg: config.OpenAI{},
expectType: config.ProviderOpenAI,
expectName: config.ProviderOpenAI,
},
{
name: "custom_name",
cfg: config.OpenAI{Name: "openai-custom"},
expectType: config.ProviderOpenAI,
expectName: "openai-custom",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := NewOpenAI(tc.cfg)
assert.Equal(t, tc.expectType, p.Type())
assert.Equal(t, tc.expectName, p.Name())
})
}
}
func TestOpenAI_CreateInterceptor_Credential(t *testing.T) {
t.Parallel()
@@ -0,0 +1,91 @@
package provider
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/coder/coder/v2/aibridge/config"
)
func TestProvider_TypeAndName(t *testing.T) {
t.Parallel()
bedrockCfg := config.AWSBedrock{
Region: "us-west-2",
AccessKey: "test-key",
AccessKeySecret: "test-secret",
Model: "m",
SmallFastModel: "s",
}
tests := []struct {
name string
provider func(t testing.TB) Provider
expectType string
expectName string
}{
{
name: "anthropic_defaults",
provider: func(t testing.TB) Provider { return newTestAnthropic(t, config.Anthropic{}, nil) },
expectType: config.ProviderAnthropic,
expectName: config.ProviderAnthropic,
},
{
name: "anthropic_custom_name",
provider: func(t testing.TB) Provider {
return newTestAnthropic(t, config.Anthropic{Name: "anthropic-custom"}, nil)
},
expectType: config.ProviderAnthropic,
expectName: "anthropic-custom",
},
{
name: "bedrock_defaults",
provider: func(t testing.TB) Provider { return newTestBedrock(t, config.Anthropic{}, bedrockCfg) },
expectType: config.ProviderBedrock,
expectName: config.ProviderBedrock,
},
{
name: "bedrock_custom_name",
provider: func(t testing.TB) Provider {
return newTestBedrock(t, config.Anthropic{Name: "bedrock-custom"}, bedrockCfg)
},
expectType: config.ProviderBedrock,
expectName: "bedrock-custom",
},
{
name: "copilot_defaults",
provider: func(testing.TB) Provider { return NewCopilot(config.Copilot{}) },
expectType: config.ProviderCopilot,
expectName: config.ProviderCopilot,
},
{
name: "copilot_custom_name",
provider: func(testing.TB) Provider { return NewCopilot(config.Copilot{Name: "copilot-business"}) },
expectType: config.ProviderCopilot,
expectName: "copilot-business",
},
{
name: "openai_defaults",
provider: func(testing.TB) Provider { return NewOpenAI(config.OpenAI{}) },
expectType: config.ProviderOpenAI,
expectName: config.ProviderOpenAI,
},
{
name: "openai_custom_name",
provider: func(testing.TB) Provider { return NewOpenAI(config.OpenAI{Name: "openai-custom"}) },
expectType: config.ProviderOpenAI,
expectName: "openai-custom",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
p := tc.provider(t)
assert.Equal(t, tc.expectType, p.Type())
assert.Equal(t, tc.expectName, p.Name())
})
}
}
-9
View File
@@ -77,12 +77,3 @@ func InterceptionAttributesFromContext(ctx context.Context) []attribute.KeyValue
func WithRequestBridgeAttributesInContext(ctx context.Context, traceAttrs []attribute.KeyValue) context.Context {
return context.WithValue(ctx, traceRequestBridgeAttrsContextKey{}, traceAttrs)
}
func RequestBridgeAttributesFromContext(ctx context.Context) []attribute.KeyValue {
attrs, ok := ctx.Value(traceRequestBridgeAttrsContextKey{}).([]attribute.KeyValue)
if !ok {
return nil
}
return attrs
}
-6
View File
@@ -67,12 +67,6 @@ func WithStackdriver(loc string) Option {
}
}
func WithTrace() Option {
return func(b *Builder) {
b.Trace = true
}
}
func WithVerbose() Option {
return func(b *Builder) {
b.Verbose = true
-13
View File
@@ -24,7 +24,6 @@ import (
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/provisioner/echo"
"github.com/coder/coder/v2/testutil"
"github.com/coder/quartz"
"github.com/coder/serpent"
)
@@ -41,18 +40,6 @@ func New(t testing.TB, args ...string) (*serpent.Invocation, config.Root) {
return NewWithCommand(t, cmd, args...)
}
// NewWithClock is like New, but injects the given clock for
// tests that are time-dependent.
func NewWithClock(t testing.TB, clk quartz.Clock, args ...string) (*serpent.Invocation, config.Root) {
var root cli.RootCmd
root.SetClock(clk)
cmd, err := root.Command(root.AGPL())
require.NoError(t, err)
return NewWithCommand(t, cmd, args...)
}
type logWriter struct {
prefix string
log slog.Logger
-5
View File
@@ -151,11 +151,6 @@ func Capture(inv *serpent.Invocation) *Output {
return output
}
// Golden returns the formatted output with lines prefixed by "err: " or "out: ".
func (o *Output) Golden() []byte {
return o.combined.Bytes()
}
// Stdout returns the unprefixed stdout content for parsing (e.g., JSON).
func (o *Output) Stdout() string {
return o.stdout.String()
-71
View File
@@ -4,8 +4,6 @@ import (
"sync"
"golang.org/x/xerrors"
"github.com/coder/coder/v2/codersdk"
)
// Queue is a FIFO queue with a fixed size. If the size is exceeded, the first
@@ -89,72 +87,3 @@ func (q *Queue[T]) Len() int {
defer q.mu.Unlock()
return len(q.items)
}
type reportTask struct {
link string
messageID int64
selfReported bool
state codersdk.WorkspaceAppStatusState
summary string
}
// statusQueue is a Queue that:
// 1. Only pushes items that are not duplicates.
// 2. Preserves the existing message and URI when one a message is not provided.
// 3. Ignores "working" updates from the status watcher.
type StatusQueue struct {
Queue[reportTask]
// lastMessageID is the ID of the last *user* message that we saw. A user
// message only happens when interacting via the API (as opposed to
// interacting with the terminal directly).
lastMessageID int64
}
func (q *StatusQueue) Push(report reportTask) error {
q.mu.Lock()
defer q.mu.Unlock()
if q.closed {
return xerrors.New("queue has been closed")
}
var lastReport reportTask
if len(q.items) > 0 {
lastReport = q.items[len(q.items)-1]
}
// Use "working" status if this is a new user message. If this is not a new
// user message, and the status is "working" and not self-reported (meaning it
// came from the screen watcher), then it means one of two things:
// 1. The LLM is still working, in which case our last status will already
// have been "working", so there is nothing to do.
// 2. The user has interacted with the terminal directly. For now, we are
// ignoring these updates. This risks missing cases where the user
// manually submits a new prompt and the LLM becomes active and does not
// update itself, but it avoids spamming useless status updates as the user
// is typing, so the tradeoff is worth it. In the future, if we can
// reliably distinguish between user and LLM activity, we can change this.
if report.messageID > q.lastMessageID {
report.state = codersdk.WorkspaceAppStatusStateWorking
} else if report.state == codersdk.WorkspaceAppStatusStateWorking && !report.selfReported {
q.mu.Unlock()
return nil
}
// Preserve previous message and URI if there was no message.
if report.summary == "" {
report.summary = lastReport.summary
if report.link == "" {
report.link = lastReport.link
}
}
// Avoid queueing duplicate updates.
if report.state == lastReport.state &&
report.link == lastReport.link &&
report.summary == lastReport.summary {
return nil
}
// Drop the first item if the queue has gotten too big.
if len(q.items) >= q.size {
q.items = q.items[1:]
}
q.items = append(q.items, report)
q.cond.Broadcast()
return nil
}
+1 -7
View File
@@ -602,7 +602,7 @@ type RootCmd struct {
useKeyringWithGlobalConfig bool
// clock is used for time-dependent operations. Initialized to
// quartz.NewReal() in Command() if not set via SetClock.
// quartz.NewReal() in Command() if unset.
clock quartz.Clock
// TLS configuration for custom CA or client certificates.
@@ -612,12 +612,6 @@ type RootCmd struct {
tlsConfig *tls.Config
}
// SetClock sets the clock used for time-dependent operations.
// Must be called before Command() to take effect.
func (r *RootCmd) SetClock(clk quartz.Clock) {
r.clock = clk
}
// ensureClientURL loads the client URL from the config file if it
// wasn't provided via --url or CODER_URL.
func (r *RootCmd) ensureClientURL() error {
-6
View File
@@ -2646,12 +2646,6 @@ func isReplicaRelayRequest(r *http.Request) bool {
return r.Header.Get("X-Coder-Relay-Source-Replica") != ""
}
// IsLocalhost returns true if the host points to the local machine. Intended to
// be called with `u.Hostname()`.
func IsLocalhost(host string) bool {
return host == "localhost" || host == "127.0.0.1" || host == "::1"
}
// PostgresConnectOptions contains options for connecting to Postgres.
type PostgresConnectOptions struct {
MaxOpenConns int
+62 -118
View File
@@ -1750,62 +1750,31 @@ func TestServer(t *testing.T) {
t.Run("Logging", func(t *testing.T) {
t.Parallel()
t.Run("CreatesFile", func(t *testing.T) {
t.Parallel()
fiName := testutil.TempFile(t, "", "coder-logging-test-*")
sinks := []struct {
flag string
file string
}{
{flag: "--log-human", file: testutil.TempFile(t, "", "coder-logging-test-*")},
{flag: "--log-json", file: testutil.TempFile(t, "", "coder-logging-test-*")},
}
args := []string{
"server",
"--log-filter=.*",
dbArg(t),
"--http-address", "127.0.0.1:0",
"--access-url", "http://example.com",
"--provisioner-daemons=3",
"--provisioner-types=echo",
}
for _, sink := range sinks {
args = append(args, sink.flag, sink.file)
}
root, _ := clitest.New(t, args...)
startIgnoringPostgresQueryCancel(t, root)
root, _ := clitest.New(t,
"server",
"--log-filter=.*",
dbArg(t),
"--http-address", "127.0.0.1:0",
"--access-url", "http://example.com",
"--provisioner-daemons=3",
"--provisioner-types=echo",
"--log-human", fiName,
)
startIgnoringPostgresQueryCancel(t, root)
loggingWaitFile(t, fiName, testutil.WaitLong)
})
t.Run("Human", func(t *testing.T) {
t.Parallel()
fi := testutil.TempFile(t, "", "coder-logging-test-*")
root, _ := clitest.New(t,
"server",
"--log-filter=.*",
dbArg(t),
"--http-address", "127.0.0.1:0",
"--access-url", "http://example.com",
"--provisioner-daemons=3",
"--provisioner-types=echo",
"--log-human", fi,
)
startIgnoringPostgresQueryCancel(t, root)
loggingWaitFile(t, fi, testutil.WaitShort)
})
t.Run("JSON", func(t *testing.T) {
t.Parallel()
fi := testutil.TempFile(t, "", "coder-logging-test-*")
root, _ := clitest.New(t,
"server",
"--log-filter=.*",
dbArg(t),
"--http-address", "127.0.0.1:0",
"--access-url", "http://example.com",
"--provisioner-daemons=3",
"--provisioner-types=echo",
"--log-json", fi,
)
startIgnoringPostgresQueryCancel(t, root)
loggingWaitFile(t, fi, testutil.WaitShort)
})
for _, sink := range sinks {
loggingWaitFile(t, sink.file, testutil.WaitLong)
}
})
t.Run("YAML", func(t *testing.T) {
@@ -2110,7 +2079,7 @@ func TestServer_ExternalAuthGitHubDefaultProvider(t *testing.T) {
}
}
//nolint:tparallel,paralleltest // This test sets environment variables.
//nolint:paralleltest // This test sets environment variables.
func TestServer_Logging_NoParallel(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = io.Copy(io.Discard, r.Body)
@@ -2134,73 +2103,48 @@ func TestServer_Logging_NoParallel(t *testing.T) {
// I know; it was made up for the Go package.
t.Setenv("GCE_METADATA_HOST", server.URL)
t.Run("Stackdriver", func(t *testing.T) {
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitSuperLong)
defer cancelFunc()
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitSuperLong)
defer cancelFunc()
fi := testutil.TempFile(t, "", "coder-logging-test-*")
sinks := []struct {
flag string
file string
}{
{flag: "--log-human", file: testutil.TempFile(t, "", "coder-logging-test-*")},
{flag: "--log-json", file: testutil.TempFile(t, "", "coder-logging-test-*")},
{flag: "--log-stackdriver", file: testutil.TempFile(t, "", "coder-logging-test-*")},
}
args := []string{
"server",
"--log-filter=.*",
dbArg(t),
"--http-address", "127.0.0.1:0",
"--access-url", "http://example.com",
"--provisioner-daemons=3",
"--provisioner-types=echo",
}
for _, sink := range sinks {
args = append(args, sink.flag, sink.file)
}
inv, _ := clitest.New(t,
"server",
"--log-filter=.*",
dbArg(t),
"--http-address", "127.0.0.1:0",
"--access-url", "http://example.com",
"--provisioner-daemons=3",
"--provisioner-types=echo",
"--log-stackdriver", fi,
)
// Attach expecter so we get debug output from the command if this test
// fails.
stdout := expecter.NewAttachedToInvocation(t, inv)
// NOTE(mafredri): This test might end up downloading Terraform
// which can take a long time and end up failing the test.
// This is why we wait extra long below for server to listen on
// HTTP.
inv, _ := clitest.New(t, args...)
// Attach expecter so we get debug output from the command if this test
// fails.
stdout := expecter.NewAttachedToInvocation(t, inv)
startIgnoringPostgresQueryCancel(t, inv.WithContext(ctx))
startIgnoringPostgresQueryCancel(t, inv.WithContext(ctx))
// Wait for server to listen on HTTP, this is a good
// starting point for expecting logs.
_ = stdout.ExpectMatch(ctx, "Started HTTP listener at")
// Wait for server to listen on HTTP, this is a good
// starting point for expecting logs.
_ = stdout.ExpectMatch(ctx, "Started HTTP listener at")
loggingWaitFile(t, fi, testutil.WaitSuperLong)
})
t.Run("Multiple", func(t *testing.T) {
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitSuperLong)
defer cancelFunc()
fi1 := testutil.TempFile(t, "", "coder-logging-test-*")
fi2 := testutil.TempFile(t, "", "coder-logging-test-*")
fi3 := testutil.TempFile(t, "", "coder-logging-test-*")
// NOTE(mafredri): This test might end up downloading Terraform
// which can take a long time and end up failing the test.
// This is why we wait extra long below for server to listen on
// HTTP.
inv, _ := clitest.New(t,
"server",
"--log-filter=.*",
dbArg(t),
"--http-address", "127.0.0.1:0",
"--access-url", "http://example.com",
"--provisioner-daemons=3",
"--provisioner-types=echo",
"--log-human", fi1,
"--log-json", fi2,
"--log-stackdriver", fi3,
)
// Attach expecter so we get debug output from the command if this test
// fails.
stdout := expecter.NewAttachedToInvocation(t, inv)
startIgnoringPostgresQueryCancel(t, inv)
// Wait for server to listen on HTTP, this is a good
// starting point for expecting logs.
_ = stdout.ExpectMatch(ctx, "Started HTTP listener at")
loggingWaitFile(t, fi1, testutil.WaitSuperLong)
loggingWaitFile(t, fi2, testutil.WaitSuperLong)
loggingWaitFile(t, fi3, testutil.WaitSuperLong)
})
for _, sink := range sinks {
loggingWaitFile(t, sink.file, testutil.WaitSuperLong)
}
}
func loggingWaitFile(t *testing.T, fiName string, dur time.Duration) {
-11
View File
@@ -97,17 +97,6 @@ func (a RBACAsserter) AssertChecked(t *testing.T, action policy.Action, objects
a.Recorder.AssertOutOfOrder(t, a.Subject, pairs...)
}
// AssertInOrder must be called in the correct order of authz checks. If the objects
// or actions are not in the correct order, the test will fail.
func (a RBACAsserter) AssertInOrder(t *testing.T, action policy.Action, objects ...interface{}) {
converted := a.convertObjects(t, objects...)
pairs := make([]ActionObjectPair, 0, len(converted))
for _, obj := range converted {
pairs = append(pairs, a.Recorder.Pair(action, obj))
}
a.Recorder.AssertActor(t, a.Subject, pairs...)
}
// convertObjects converts the codersdk types to rbac.Object. Unfortunately
// does not have type safety, and instead uses a t.Fatal to enforce types.
func (RBACAsserter) convertObjects(t *testing.T, objs ...interface{}) []rbac.Object {
-5
View File
@@ -1417,11 +1417,6 @@ func AgentsReady(agent codersdk.WorkspaceAgent) bool {
return agent.LifecycleState == codersdk.WorkspaceAgentLifecycleReady
}
// AgentsNotReady checks that the latest lifecycle state of an agent is anything except "Ready".
func AgentsNotReady(agent codersdk.WorkspaceAgent) bool {
return !AgentsReady(agent)
}
// WaitFor waits for the given criteria and fails the test if they are not met before the
// waiter's context is canceled.
func (w WorkspaceAgentWaiter) WaitFor(criteria ...WaitForAgentFn) {
-6
View File
@@ -250,12 +250,6 @@ func WithPKCE() func(*FakeIDP) {
}
}
func WithAuthorizedRedirectURL(hook func(redirectURL string) error) func(*FakeIDP) {
return func(f *FakeIDP) {
f.hookValidRedirectURL = hook
}
}
func WithMiddlewares(mws ...func(http.Handler) http.Handler) func(*FakeIDP) {
return func(f *FakeIDP) {
f.middlewares = append(f.middlewares, mws...)
-6
View File
@@ -77,12 +77,6 @@ func WithClock(clock quartz.Clock) RotatorOption {
}
}
func WithKeyDuration(keyDuration time.Duration) RotatorOption {
return func(r *rotator) {
r.keyDuration = keyDuration
}
}
// WithFeatures sets the crypto key features the rotator manages, replacing the
// default set. Use this to opt experiment- or deployment-gated features (such
// as the NATS cluster CA) into rotation only when their owner is active.
-6
View File
@@ -354,12 +354,6 @@ func User(user database.User, organizationIDs []uuid.UUID) codersdk.User {
return convertedUser
}
func Users(users []database.User, organizationIDs map[uuid.UUID][]uuid.UUID) []codersdk.User {
return slice.List(users, func(user database.User) codersdk.User {
return User(user, organizationIDs[user.ID])
})
}
func Group(row database.GetGroupsRow, members []database.GroupMember, totalMemberCount int) codersdk.Group {
return codersdk.Group{
ID: row.Group.ID,
-6
View File
@@ -52,12 +52,6 @@ func (b OrganizationBuilder) Deleted(deleted bool) OrganizationBuilder {
return b
}
func (b OrganizationBuilder) Seed(seed database.Organization) OrganizationBuilder {
//nolint: revive // returns modified struct
b.seed = seed
return b
}
func (b OrganizationBuilder) Members(users ...database.User) OrganizationBuilder {
for _, u := range users {
//nolint: revive // returns modified struct
-80
View File
@@ -38,7 +38,6 @@ import (
"github.com/coder/coder/v2/coderd/x/chatd/chatprompt"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/cryptorand"
"github.com/coder/coder/v2/provisionerd/proto"
"github.com/coder/coder/v2/testutil"
)
@@ -652,18 +651,6 @@ func APIKey(t testing.TB, db database.Store, seed database.APIKey, munge ...func
return key, fmt.Sprintf("%s-%s", key.ID, secret)
}
func WorkspaceAgentPortShare(t testing.TB, db database.Store, orig database.WorkspaceAgentPortShare) database.WorkspaceAgentPortShare {
ps, err := db.UpsertWorkspaceAgentPortShare(genCtx, database.UpsertWorkspaceAgentPortShareParams{
WorkspaceID: takeFirst(orig.WorkspaceID, uuid.New()),
AgentName: takeFirst(orig.AgentName, testutil.GetRandomName(t)),
Port: takeFirst(orig.Port, 8080),
ShareLevel: takeFirst(orig.ShareLevel, database.AppSharingLevelPublic),
Protocol: takeFirst(orig.Protocol, database.PortShareProtocolHttp),
})
require.NoError(t, err, "insert workspace agent")
return ps
}
func WorkspaceAgent(t testing.TB, db database.Store, orig database.WorkspaceAgent) database.WorkspaceAgent {
agt, err := db.InsertWorkspaceAgent(genCtx, database.InsertWorkspaceAgentParams{
ID: takeFirst(orig.ID, uuid.New()),
@@ -830,20 +817,6 @@ func WorkspaceAgentScriptTiming(t testing.TB, db database.Store, orig database.W
panic("failed to insert workspace agent script timing")
}
func WorkspaceAgentDevcontainer(t testing.TB, db database.Store, orig database.WorkspaceAgentDevcontainer) database.WorkspaceAgentDevcontainer {
devcontainers, err := db.InsertWorkspaceAgentDevcontainers(genCtx, database.InsertWorkspaceAgentDevcontainersParams{
WorkspaceAgentID: takeFirst(orig.WorkspaceAgentID, uuid.New()),
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
ID: []uuid.UUID{takeFirst(orig.ID, uuid.New())},
Name: []string{takeFirst(orig.Name, testutil.GetRandomName(t))},
WorkspaceFolder: []string{takeFirst(orig.WorkspaceFolder, "/workspace")},
ConfigPath: []string{takeFirst(orig.ConfigPath, "")},
SubagentID: []uuid.UUID{orig.SubagentID.UUID},
})
require.NoError(t, err, "insert workspace agent devcontainer")
return devcontainers[0]
}
func Workspace(t testing.TB, db database.Store, orig database.WorkspaceTable) database.WorkspaceTable {
t.Helper()
@@ -1446,21 +1419,6 @@ func WorkspaceAppStat(t testing.TB, db database.Store, orig database.WorkspaceAp
return scheme
}
func WorkspaceAppStatus(t testing.TB, db database.Store, orig database.WorkspaceAppStatus) database.WorkspaceAppStatus {
appStatus, err := db.InsertWorkspaceAppStatus(genCtx, database.InsertWorkspaceAppStatusParams{
ID: takeFirst(orig.ID, uuid.New()),
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
WorkspaceID: takeFirst(orig.WorkspaceID, uuid.New()),
AgentID: takeFirst(orig.AgentID, uuid.New()),
AppID: takeFirst(orig.AppID, uuid.New()),
State: takeFirst(orig.State, database.WorkspaceAppStatusStateWorking),
Message: takeFirst(orig.Message, ""),
Uri: takeFirst(orig.Uri, sql.NullString{}),
})
require.NoError(t, err, "insert workspace agent status")
return appStatus
}
func WorkspaceResource(t testing.TB, db database.Store, orig database.WorkspaceResource) database.WorkspaceResource {
resource, err := db.InsertWorkspaceResource(genCtx, database.InsertWorkspaceResourceParams{
ID: takeFirst(orig.ID, uuid.New()),
@@ -1645,16 +1603,6 @@ func TemplateVersionVariable(t testing.TB, db database.Store, orig database.Temp
return version
}
func TemplateVersionWorkspaceTag(t testing.TB, db database.Store, orig database.TemplateVersionWorkspaceTag) database.TemplateVersionWorkspaceTag {
workspaceTag, err := db.InsertTemplateVersionWorkspaceTag(genCtx, database.InsertTemplateVersionWorkspaceTagParams{
TemplateVersionID: takeFirst(orig.TemplateVersionID, uuid.New()),
Key: takeFirst(orig.Key, testutil.GetRandomName(t)),
Value: takeFirst(orig.Value, testutil.GetRandomName(t)),
})
require.NoError(t, err, "insert template version workspace tag")
return workspaceTag
}
func TemplateVersionParameter(t testing.TB, db database.Store, orig database.TemplateVersionParameter) database.TemplateVersionParameter {
t.Helper()
@@ -1682,34 +1630,6 @@ func TemplateVersionParameter(t testing.TB, db database.Store, orig database.Tem
return version
}
func TemplateVersionTerraformValues(t testing.TB, db database.Store, orig database.TemplateVersionTerraformValue) database.TemplateVersionTerraformValue {
t.Helper()
jobID := uuid.New()
if orig.TemplateVersionID != uuid.Nil {
v, err := db.GetTemplateVersionByID(genCtx, orig.TemplateVersionID)
if err == nil {
jobID = v.JobID
}
}
params := database.InsertTemplateVersionTerraformValuesByJobIDParams{
JobID: jobID,
CachedPlan: takeFirstSlice(orig.CachedPlan, []byte("{}")),
CachedModuleFiles: orig.CachedModuleFiles,
UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()),
ProvisionerdVersion: takeFirst(orig.ProvisionerdVersion, proto.CurrentVersion.String()),
}
err := db.InsertTemplateVersionTerraformValuesByJobID(genCtx, params)
require.NoError(t, err, "insert template version parameter")
v, err := db.GetTemplateVersionTerraformValues(genCtx, orig.TemplateVersionID)
require.NoError(t, err, "get template version values")
return v
}
// WorkspaceAgentStat inserts a workspace agent stat row. Seed the
// session_counts column by setting SessionCounts on orig, for example with
// the SessionCounts helper:
-8
View File
@@ -151,14 +151,6 @@ func WithDBFrom(dbFrom string) OpenOption {
}
}
// WithLogDSN sets whether the DSN should be logged during testing.
// This provides an ergonomic way to connect to test databases during debugging.
func WithLogDSN(logDSN bool) OpenOption {
return func(o *OpenOptions) {
o.LogDSN = logDSN
}
}
// TBSubset is a subset of the testing.TB interface.
// It allows to use dbtestutil.Open outside of tests.
type TBSubset interface {
File diff suppressed because it is too large Load Diff
-10
View File
@@ -1,10 +0,0 @@
package httpapi
import "net/http"
// NoopResponseWriter is a response writer that does nothing.
type NoopResponseWriter struct{}
func (NoopResponseWriter) Header() http.Header { return http.Header{} }
func (NoopResponseWriter) Write(p []byte) (int, error) { return len(p), nil }
func (NoopResponseWriter) WriteHeader(int) {}
-21
View File
@@ -31,11 +31,6 @@ func UserParam(r *http.Request) database.User {
return user
}
func UserParamOptional(r *http.Request) (database.User, bool) {
user, ok := r.Context().Value(userParamContextKey{}).(database.User)
return user, ok
}
// ExtractUserParam extracts a user from an ID/username in the {user} URL
// parameter.
func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
@@ -53,22 +48,6 @@ func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
}
}
// ExtractUserParamOptional does not fail if no user is present.
func ExtractUserParamOptional(db database.Store) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
user, ok := ExtractUserContext(ctx, db, &httpapi.NoopResponseWriter{}, r)
if ok {
ctx = context.WithValue(ctx, userParamContextKey{}, user)
}
next.ServeHTTP(rw, r.WithContext(ctx))
})
}
}
// ExtractUserContext queries the database for the parameterized `{user}` from the request URL.
func ExtractUserContext(ctx context.Context, db database.Store, rw http.ResponseWriter, r *http.Request) (user database.User, ok bool) {
// userQuery is either a uuid, a username, or 'me'
-8
View File
@@ -719,14 +719,6 @@ func ConfigWithACL() regosql.ConvertConfig {
}
}
// ConfigWithoutACL is the basic configuration for converting rego to SQL when
// the object has no ACL fields.
func ConfigWithoutACL() regosql.ConvertConfig {
return regosql.ConvertConfig{
VariableConverter: regosql.NoACLConverter(),
}
}
// ConfigChats uses a resource converter so SQL filters qualify chat
// ACL columns consistently with GetChats.
func ConfigChats() regosql.ConvertConfig {
-22
View File
@@ -12,28 +12,6 @@ import (
"github.com/coder/coder/v2/coderd/database"
)
// NoopResolver implements the Resolver interface
var _ Resolver = &NoopResolver{}
// NoopResolver is a useful test device.
type NoopResolver struct{}
func NewNoopResolver() *NoopResolver {
return &NoopResolver{}
}
func (NoopResolver) GetRuntimeConfig(context.Context, string) (string, error) {
return "", ErrEntryNotFound
}
func (NoopResolver) UpsertRuntimeConfig(context.Context, string, string) error {
return ErrEntryNotFound
}
func (NoopResolver) DeleteRuntimeConfig(context.Context, string) error {
return ErrEntryNotFound
}
// StoreResolver implements the Resolver interface
var _ Resolver = &StoreResolver{}
-6
View File
@@ -1027,12 +1027,6 @@ func (r *remoteReporter) collectUserSecretsSummary(ctx context.Context) (*UserSe
}, nil
}
// HashContent returns a SHA256 hash of the content as a hex string.
// This is useful for hashing sensitive content like prompts for telemetry.
func HashContent(content string) string {
return fmt.Sprintf("%x", sha256.Sum256([]byte(content)))
}
// ConvertAPIKey anonymizes an API key.
func ConvertAPIKey(apiKey database.APIKey) APIKey {
a := APIKey{
-6
View File
@@ -202,12 +202,6 @@ func EndHTTPSpan(r *http.Request, status int, span trace.Span, serverName string
type tracerNameKey struct{}
// SetTracerName sets the tracer name that will be used by all spans created
// from the context.
func SetTracerName(ctx context.Context, tracerName string) context.Context {
return context.WithValue(ctx, tracerNameKey{}, tracerName)
}
// GetTracerName returns the tracer name from the context, or TracerName if none
// is set.
func GetTracerName(ctx context.Context) string {
-55
View File
@@ -3048,54 +3048,6 @@ func TestDormantUser(t *testing.T) {
require.Equal(t, codersdk.UserStatusActive, users.Users[0].Status)
}
// TestSuspendedPagination is when the after_id is a suspended record.
// The database query should still return the correct page, as the after_id
// is in a subquery that finds the record regardless of its status.
// This is mainly to confirm the db fake has the same behavior.
func TestSuspendedPagination(t *testing.T) {
t.Parallel()
t.Skip("This fails when two users are created at the exact same time. The reason is unknown... See: https://github.com/coder/coder/actions/runs/3057047622/jobs/4931863163")
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
me, err := client.User(ctx, codersdk.Me)
require.NoError(t, err)
orgID := me.OrganizationIDs[0]
total := 10
users := make([]codersdk.User, 0, total)
// Create users
for i := 0; i < total; i++ {
email := fmt.Sprintf("%d@coder.com", i)
username := fmt.Sprintf("user%d", i)
user, err := client.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
Email: email,
Username: username,
Password: "MySecurePassword!",
OrganizationIDs: []uuid.UUID{orgID},
})
require.NoError(t, err)
users = append(users, user)
}
sortUsers(users)
deletedUser := users[2]
expected := users[3:8]
_, err = client.UpdateUserStatus(ctx, deletedUser.ID.String(), codersdk.UserStatusSuspended)
require.NoError(t, err, "suspend user")
page, err := client.Users(ctx, codersdk.UsersRequest{
Pagination: codersdk.Pagination{
Limit: len(expected),
AfterID: deletedUser.ID,
},
})
require.NoError(t, err)
require.Equal(t, expected, page.Users, "expected page")
}
func TestUserAutofillParameters(t *testing.T) {
t.Parallel()
t.Run("NotSelf", func(t *testing.T) {
@@ -3381,13 +3333,6 @@ func assertPagination(ctx context.Context, t *testing.T, client *codersdk.Client
}
}
// sortUsers sorts by (created_at, id)
func sortUsers(users []codersdk.User) {
slices.SortFunc(users, func(a, b codersdk.User) int {
return slice.Ascending(strings.ToLower(a.Username), strings.ToLower(b.Username))
})
}
func sortDatabaseUsers(users []database.User) {
slices.SortFunc(users, func(a, b database.User) int {
return slice.Ascending(strings.ToLower(a.Username), strings.ToLower(b.Username))
-349
View File
@@ -2080,355 +2080,6 @@ func TestWorkspaceFilterAllStatus(t *testing.T) {
}
}
// TestWorkspaceFilter creates a set of workspaces, users, and organizations
// to run various filters against for testing.
func TestWorkspaceFilter(t *testing.T) {
t.Parallel()
// Manual tests still occur below, so this is safe to disable.
t.Skip("This test is slow and flaky. See: https://github.com/coder/coder/issues/2854")
// nolint:unused
type coderUser struct {
*codersdk.Client
User codersdk.User
Org codersdk.Organization
}
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
first := coderdtest.CreateFirstUser(t, client)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
users := make([]coderUser, 0)
for i := 0; i < 10; i++ {
userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID, rbac.RoleOwner())
if i%3 == 0 {
var err error
user, err = client.UpdateUserProfile(ctx, user.ID.String(), codersdk.UpdateUserProfileRequest{
Username: strings.ToUpper(user.Username),
})
require.NoError(t, err, "uppercase username")
}
org, err := userClient.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
Name: user.Username + "-org",
})
require.NoError(t, err, "create org")
users = append(users, coderUser{
Client: userClient,
User: user,
Org: org,
})
}
type madeWorkspace struct {
Owner codersdk.User
Workspace codersdk.Workspace
Template codersdk.Template
}
availTemplates := make([]codersdk.Template, 0)
allWorkspaces := make([]madeWorkspace, 0)
upperTemplates := make([]string, 0)
// Create some random workspaces
var count int
for i, user := range users {
version := coderdtest.CreateTemplateVersion(t, client, user.Org.ID, nil)
// Create a template & workspace in the user's org
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
var template codersdk.Template
if i%3 == 0 {
template = coderdtest.CreateTemplate(t, client, user.Org.ID, version.ID, func(request *codersdk.CreateTemplateRequest) {
request.Name = strings.ToUpper(request.Name)
})
upperTemplates = append(upperTemplates, template.Name)
} else {
template = coderdtest.CreateTemplate(t, client, user.Org.ID, version.ID)
}
availTemplates = append(availTemplates, template)
workspace := coderdtest.CreateWorkspace(t, user.Client, template.ID, func(request *codersdk.CreateWorkspaceRequest) {
if count%3 == 0 {
request.Name = strings.ToUpper(request.Name)
}
})
allWorkspaces = append(allWorkspaces, madeWorkspace{
Workspace: workspace,
Template: template,
Owner: user.User,
})
// Make a workspace with a random template
idx, _ := cryptorand.Intn(len(availTemplates))
randTemplate := availTemplates[idx]
randWorkspace := coderdtest.CreateWorkspace(t, user.Client, randTemplate.ID)
allWorkspaces = append(allWorkspaces, madeWorkspace{
Workspace: randWorkspace,
Template: randTemplate,
Owner: user.User,
})
}
// Make sure all workspaces are done. Do it after all are made
for i, w := range allWorkspaces {
latest := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, w.Workspace.LatestBuild.ID)
allWorkspaces[i].Workspace.LatestBuild = latest
}
// --- Setup done ---
testCases := []struct {
Name string
Filter codersdk.WorkspaceFilter
// If FilterF is true, we include it in the expected results
FilterF func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool
}{
{
Name: "All",
Filter: codersdk.WorkspaceFilter{},
FilterF: func(_ codersdk.WorkspaceFilter, _ madeWorkspace) bool {
return true
},
},
{
Name: "Owner",
Filter: codersdk.WorkspaceFilter{
Owner: strings.ToUpper(users[2].User.Username),
},
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
return strings.EqualFold(workspace.Owner.Username, f.Owner)
},
},
{
Name: "TemplateName",
Filter: codersdk.WorkspaceFilter{
Template: strings.ToUpper(allWorkspaces[5].Template.Name),
},
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
return strings.EqualFold(workspace.Template.Name, f.Template)
},
},
{
Name: "UpperTemplateName",
Filter: codersdk.WorkspaceFilter{
Template: upperTemplates[0],
},
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
return strings.EqualFold(workspace.Template.Name, f.Template)
},
},
{
Name: "Name",
Filter: codersdk.WorkspaceFilter{
// Use a common letter... one has to have this letter in it
Name: "a",
},
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
return strings.ContainsAny(workspace.Workspace.Name, "Aa")
},
},
{
Name: "Q-Owner/Name",
Filter: codersdk.WorkspaceFilter{
FilterQuery: allWorkspaces[5].Owner.Username + "/" + strings.ToUpper(allWorkspaces[5].Workspace.Name),
},
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
if strings.EqualFold(workspace.Owner.Username, allWorkspaces[5].Owner.Username) &&
strings.Contains(strings.ToLower(workspace.Workspace.Name), strings.ToLower(allWorkspaces[5].Workspace.Name)) {
return true
}
return false
},
},
{
Name: "Many filters",
Filter: codersdk.WorkspaceFilter{
Owner: allWorkspaces[3].Owner.Username,
Template: allWorkspaces[3].Template.Name,
Name: allWorkspaces[3].Workspace.Name,
},
FilterF: func(f codersdk.WorkspaceFilter, workspace madeWorkspace) bool {
if strings.EqualFold(workspace.Owner.Username, f.Owner) &&
strings.Contains(strings.ToLower(workspace.Workspace.Name), strings.ToLower(f.Name)) &&
strings.EqualFold(workspace.Template.Name, f.Template) {
return true
}
return false
},
},
}
for _, c := range testCases {
t.Run(c.Name, func(t *testing.T) {
t.Parallel()
ctx := testutil.Context(t, testutil.WaitShort)
workspaces, err := client.Workspaces(ctx, c.Filter)
require.NoError(t, err, "fetch workspaces")
exp := make([]codersdk.Workspace, 0)
for _, made := range allWorkspaces {
if c.FilterF(c.Filter, made) {
exp = append(exp, made.Workspace)
}
}
require.ElementsMatch(t, exp, workspaces, "expected workspaces returned")
})
}
t.Run("Shared", func(t *testing.T) {
t.Parallel()
dv := coderdtest.DeploymentValues(t)
var (
client, db = coderdtest.NewWithDatabase(t, &coderdtest.Options{
DeploymentValues: dv,
})
orgOwner = coderdtest.CreateFirstUser(t, client)
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OwnerID: workspaceOwner.ID,
OrganizationID: orgOwner.OrganizationID,
}).Do().Workspace
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OwnerID: workspaceOwner.ID,
OrganizationID: orgOwner.OrganizationID,
}).Do().Workspace
_, toShareWithUser = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID)
ctx = testutil.Context(t, testutil.WaitMedium)
)
client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
UserRoles: map[string]codersdk.WorkspaceRole{
toShareWithUser.ID.String(): codersdk.WorkspaceRoleUse,
},
})
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
Shared: ptr.Ref(true),
})
require.NoError(t, err, "fetch workspaces")
require.Equal(t, 1, workspaces.Count, "expected only one workspace")
require.Equal(t, workspaces.Workspaces[0].ID, sharedWorkspace.ID)
})
t.Run("NotShared", func(t *testing.T) {
t.Parallel()
dv := coderdtest.DeploymentValues(t)
var (
client, db = coderdtest.NewWithDatabase(t, &coderdtest.Options{
DeploymentValues: dv,
})
orgOwner = coderdtest.CreateFirstUser(t, client)
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OwnerID: workspaceOwner.ID,
OrganizationID: orgOwner.OrganizationID,
}).Do().Workspace
notSharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OwnerID: workspaceOwner.ID,
OrganizationID: orgOwner.OrganizationID,
}).Do().Workspace
_, toShareWithUser = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID)
ctx = testutil.Context(t, testutil.WaitMedium)
)
client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
UserRoles: map[string]codersdk.WorkspaceRole{
toShareWithUser.ID.String(): codersdk.WorkspaceRoleUse,
},
})
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
Shared: ptr.Ref(false),
})
require.NoError(t, err, "fetch workspaces")
require.Equal(t, 1, workspaces.Count, "expected only one workspace")
require.Equal(t, workspaces.Workspaces[0].ID, notSharedWorkspace.ID)
})
t.Run("SharedWithUserByID", func(t *testing.T) {
t.Parallel()
dv := coderdtest.DeploymentValues(t)
var (
client, db = coderdtest.NewWithDatabase(t, &coderdtest.Options{
DeploymentValues: dv,
})
orgOwner = coderdtest.CreateFirstUser(t, client)
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OwnerID: workspaceOwner.ID,
OrganizationID: orgOwner.OrganizationID,
}).Do().Workspace
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OwnerID: workspaceOwner.ID,
OrganizationID: orgOwner.OrganizationID,
}).Do().Workspace
_, toShareWithUser = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID)
ctx = testutil.Context(t, testutil.WaitMedium)
)
client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
UserRoles: map[string]codersdk.WorkspaceRole{
toShareWithUser.ID.String(): codersdk.WorkspaceRoleUse,
},
})
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
SharedWithUser: toShareWithUser.ID.String(),
})
require.NoError(t, err, "fetch workspaces")
require.Equal(t, 1, workspaces.Count, "expected only one workspace")
require.Equal(t, workspaces.Workspaces[0].ID, sharedWorkspace.ID)
})
t.Run("SharedWithUserByUsername", func(t *testing.T) {
t.Parallel()
dv := coderdtest.DeploymentValues(t)
var (
client, db = coderdtest.NewWithDatabase(t, &coderdtest.Options{
DeploymentValues: dv,
})
orgOwner = coderdtest.CreateFirstUser(t, client)
_, workspaceOwner = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID, rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
sharedWorkspace = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OwnerID: workspaceOwner.ID,
OrganizationID: orgOwner.OrganizationID,
}).Do().Workspace
_ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
OwnerID: workspaceOwner.ID,
OrganizationID: orgOwner.OrganizationID,
}).Do().Workspace
_, toShareWithUser = coderdtest.CreateAnotherUser(t, client, orgOwner.OrganizationID)
ctx = testutil.Context(t, testutil.WaitMedium)
)
client.UpdateWorkspaceACL(ctx, sharedWorkspace.ID, codersdk.UpdateWorkspaceACL{
UserRoles: map[string]codersdk.WorkspaceRole{
toShareWithUser.ID.String(): codersdk.WorkspaceRoleUse,
},
})
workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
SharedWithUser: toShareWithUser.Username,
})
require.NoError(t, err, "fetch workspaces")
require.Equal(t, 1, workspaces.Count, "expected only one workspace")
require.Equal(t, workspaces.Workspaces[0].ID, sharedWorkspace.ID)
})
}
// TestWorkspaceFilterManual runs some specific setups with basic checks.
func TestWorkspaceFilterManual(t *testing.T) {
t.Parallel()
-9
View File
@@ -75,15 +75,6 @@ func TrackerWithLogger(log slog.Logger) TrackerOption {
}
}
// TrackerWithFlushInterval allows configuring the flush interval of Tracker.
func TrackerWithFlushInterval(d time.Duration) TrackerOption {
return func(h *UsageTracker) {
ticker := time.NewTicker(d)
h.tickCh = ticker.C
h.stopTick = ticker.Stop
}
}
// TrackerWithTickFlush allows passing two channels: one that reads
// a time.Time, and one that returns the number of marked workspaces
// every time Tracker flushes.
-9
View File
@@ -94,15 +94,6 @@ type Worker struct {
// WorkerOption configures a Worker.
type WorkerOption func(*Worker)
// WithTickTimeout sets the maximum duration for a single tick.
func WithTickTimeout(d time.Duration) WorkerOption {
return func(w *Worker) {
if d > 0 {
w.tickTimeout = d
}
}
}
// NewWorker creates a Worker with default batch size and interval.
func NewWorker(
store Store,
@@ -259,11 +259,6 @@ func (opts *LicenseOptions) Generate(t *testing.T) string {
return GenerateLicense(t, *opts)
}
// AddFullLicense generates a license with all features enabled.
func AddFullLicense(t *testing.T, client *codersdk.Client) codersdk.License {
return AddLicense(t, client, LicenseOptions{AllFeatures: true})
}
// AddLicense generates a new license with the options provided and inserts it.
func AddLicense(t *testing.T, client *codersdk.Client, options LicenseOptions) codersdk.License {
l, err := client.AddLicense(context.Background(), codersdk.AddLicenseRequest{
@@ -100,14 +100,6 @@ func WithBatchSize(size int) DBBatcherOption {
}
}
// WithFlushInterval sets how frequently the batcher flushes to the
// database.
func WithFlushInterval(d time.Duration) DBBatcherOption {
return func(b *DBBatcher) {
b.interval = d
}
}
// WithClock sets the clock, useful for testing.
func WithClock(clock quartz.Clock) DBBatcherOption {
return func(b *DBBatcher) {
-14
View File
@@ -709,20 +709,6 @@ data "coder_parameter" "{{ .Name }}" {
return buf.String(), err
}
func WithResources(resources []*proto.Resource) *Responses {
return &Responses{
Parse: ParseComplete,
ProvisionInit: InitComplete,
ProvisionApply: []*proto.Response{{Type: &proto.Response_Apply{Apply: &proto.ApplyComplete{}}}},
ProvisionGraph: []*proto.Response{{Type: &proto.Response_Graph{Graph: &proto.GraphComplete{
Resources: resources,
}}}},
ProvisionPlan: []*proto.Response{{Type: &proto.Response_Plan{Plan: &proto.PlanComplete{
Plan: []byte("{}"),
}}}},
}
}
func WithExtraFiles(extraFiles map[string][]byte) *Responses {
return &Responses{
Parse: ParseComplete,
-9
View File
@@ -109,15 +109,6 @@ func (p *PTY) WriteLine(str string) {
require.NoError(p.t, err, "write line failed")
}
// Named sets the PTY name in the logs. Defaults to "cmd". Make sure you set this before anything starts writing to the
// pty, or it may not be named consistently. E.g.
//
// p := New(t).Named("myCmd")
func (p *PTY) Named(name string) *PTY {
p.Rename(name)
return p
}
type PTYCmd struct {
expecter.Expecter
pty.PTYCmd
-100
View File
@@ -1,9 +1,7 @@
package autostart
import (
"encoding/json"
"fmt"
"io"
"sort"
"time"
@@ -92,104 +90,6 @@ func percentile(sorted []time.Duration, p float64) time.Duration {
return sorted[index]
}
// PrintText writes the results in a human-readable text format.
func (r RunResults) PrintText(w io.Writer) {
_, _ = fmt.Fprintf(w, "Autostart Scale Test Results\n")
_, _ = fmt.Fprintf(w, "=============================\n\n")
_, _ = fmt.Fprintf(w, "Total Runs: %d\n", r.TotalRuns)
_, _ = fmt.Fprintf(w, "Successful: %d\n", r.SuccessfulRuns)
_, _ = fmt.Fprintf(w, "Failed: %d\n\n", r.FailedRuns)
if r.SuccessfulRuns > 0 {
_, _ = fmt.Fprintf(w, "End-to-End Latency (Config → Completion)\n")
_, _ = fmt.Fprintf(w, "-----------------------------------------\n")
_, _ = fmt.Fprintf(w, "P50: %v\n", r.EndToEndLatencyP50.Round(time.Millisecond))
_, _ = fmt.Fprintf(w, "P95: %v\n", r.EndToEndLatencyP95.Round(time.Millisecond))
_, _ = fmt.Fprintf(w, "P99: %v\n\n", r.EndToEndLatencyP99.Round(time.Millisecond))
_, _ = fmt.Fprintf(w, "Trigger to Completion Latency (Scheduled Time → Completion)\n")
_, _ = fmt.Fprintf(w, "------------------------------------------------------------\n")
_, _ = fmt.Fprintf(w, "P50: %v\n", r.TriggerToCompletionP50.Round(time.Millisecond))
_, _ = fmt.Fprintf(w, "P95: %v\n", r.TriggerToCompletionP95.Round(time.Millisecond))
_, _ = fmt.Fprintf(w, "P99: %v\n\n", r.TriggerToCompletionP99.Round(time.Millisecond))
}
if r.FailedRuns > 0 {
_, _ = fmt.Fprintf(w, "Failed Runs\n")
_, _ = fmt.Fprintf(w, "-----------\n")
for _, run := range r.Runs {
if !run.Success {
_, _ = fmt.Fprintf(w, "- %s (%s): %s\n", run.WorkspaceName, run.WorkspaceID, run.Error)
}
}
}
}
// MarshalJSON implements json.Marshaler to provide custom JSON output.
func (r RunResults) MarshalJSON() ([]byte, error) {
// Convert durations to milliseconds for JSON output.
type jsonResults struct {
TotalRuns int `json:"total_runs"`
SuccessfulRuns int `json:"successful_runs"`
FailedRuns int `json:"failed_runs"`
EndToEndLatencyP50MS int64 `json:"end_to_end_latency_p50_ms"`
EndToEndLatencyP95MS int64 `json:"end_to_end_latency_p95_ms"`
EndToEndLatencyP99MS int64 `json:"end_to_end_latency_p99_ms"`
TriggerToCompletionP50MS int64 `json:"trigger_to_completion_p50_ms"`
TriggerToCompletionP95MS int64 `json:"trigger_to_completion_p95_ms"`
TriggerToCompletionP99MS int64 `json:"trigger_to_completion_p99_ms"`
Runs []struct {
WorkspaceID string `json:"workspace_id"`
WorkspaceName string `json:"workspace_name"`
Success bool `json:"success"`
Error string `json:"error,omitempty"`
EndToEndLatencyMS int64 `json:"end_to_end_latency_ms"`
TriggerToCompletionMS int64 `json:"trigger_to_completion_ms"`
} `json:"runs"`
}
jr := jsonResults{
TotalRuns: r.TotalRuns,
SuccessfulRuns: r.SuccessfulRuns,
FailedRuns: r.FailedRuns,
EndToEndLatencyP50MS: r.EndToEndLatencyP50.Milliseconds(),
EndToEndLatencyP95MS: r.EndToEndLatencyP95.Milliseconds(),
EndToEndLatencyP99MS: r.EndToEndLatencyP99.Milliseconds(),
TriggerToCompletionP50MS: r.TriggerToCompletionP50.Milliseconds(),
TriggerToCompletionP95MS: r.TriggerToCompletionP95.Milliseconds(),
TriggerToCompletionP99MS: r.TriggerToCompletionP99.Milliseconds(),
}
for _, run := range r.Runs {
jr.Runs = append(jr.Runs, struct {
WorkspaceID string `json:"workspace_id"`
WorkspaceName string `json:"workspace_name"`
Success bool `json:"success"`
Error string `json:"error,omitempty"`
EndToEndLatencyMS int64 `json:"end_to_end_latency_ms"`
TriggerToCompletionMS int64 `json:"trigger_to_completion_ms"`
}{
WorkspaceID: run.WorkspaceID.String(),
WorkspaceName: run.WorkspaceName,
Success: run.Success,
Error: run.Error,
EndToEndLatencyMS: run.EndToEndLatency().Milliseconds(),
TriggerToCompletionMS: run.TriggerToCompletionLatency().Milliseconds(),
})
}
return json.Marshal(jr)
}
// ToHarnessResults converts autostart-specific results into the standard
// harness.Results format for use with existing output functions.
func (r RunResults) ToHarnessResults() harness.Results {
-6
View File
@@ -1500,12 +1500,6 @@ func NewController(logger slog.Logger, dialer ControlProtocolDialer, opts ...Con
type ControllerOpt func(*Controller)
func WithTestClock(clock quartz.Clock) ControllerOpt {
return func(c *Controller) {
c.clock = clock
}
}
func WithGracefulTimeout(timeout time.Duration) ControllerOpt {
return func(c *Controller) {
c.gracefulTimeout = timeout
-21
View File
@@ -79,27 +79,6 @@ func SoftTryReceive[A any](ctx context.Context, t testing.TB, c <-chan A) (A, bo
}
}
// AssertReceive will receive a value from the chan and return it. If the
// context expires or the channel is closed before a value can be received,
// it will mark the test as failed but continue execution.
// The second return value indicates whether the receive was successful.
//
// Safety: can be called from any goroutine.
func AssertReceive[A any](ctx context.Context, t testing.TB, c <-chan A) (A, bool) {
t.Helper()
select {
case <-ctx.Done():
assert.Fail(t, "AssertReceive: context expired")
var a A
return a, false
case a, ok := <-c:
if !ok {
assert.Fail(t, "AssertReceive: channel closed")
}
return a, ok
}
}
// AssertSend will send the given value over the chan and then return. If
// the context expires before the send succeeds, it will mark the test as failed
// but continue execution.
-18
View File
@@ -284,24 +284,6 @@ func (e *Expecter) Peek(ctx context.Context, n int) []byte {
return slices.Clone(out)
}
//nolint:govet // We don't care about conforming to ReadRune() (rune, int, error).
func (e *Expecter) ReadRune(ctx context.Context) rune {
e.t.Helper()
var r rune
err := e.doMatchWithDeadline(ctx, "ReadRune", func(rd *bufio.Reader) error {
var err error
r, _, err = rd.ReadRune()
return err
})
if err != nil {
e.fatalf("read error", "%v (wanted rune; got %q)", err, r)
return 0
}
e.Logf("matched rune = %q", r)
return r
}
func (e *Expecter) ReadLine(ctx context.Context) string {
e.t.Helper()
-5
View File
@@ -29,11 +29,6 @@ func PromGaugeAssertion(t testing.TB, metrics []*dto.MetricFamily, assert func(i
return assert(getValue(t, metrics, gaugeKind, name, labels...))
}
func PromCounterAssertion(t testing.TB, metrics []*dto.MetricFamily, assert func(in float64) bool, name string, labels ...string) bool {
t.Helper()
return assert(getValue(t, metrics, counterKind, name, labels...))
}
func PromCounterGathered(t testing.TB, metrics []*dto.MetricFamily, name string, labels ...string) bool {
t.Helper()
return getMetric(t, metrics, name, labels...) != nil
-8
View File
@@ -47,14 +47,6 @@ func NewWriterAttachedToSSHSession(t *testing.T, l slog.Logger, session *ssh.Ses
}
}
func (w *Writer) Write(r rune) {
w.t.Helper()
_, err := w.w.Write([]byte{byte(r)})
if assert.NoError(w.t, err, "write failed") {
w.l.Debug(context.Background(), "wrote rune", slog.F("rune", r))
}
}
func (w *Writer) WriteLine(str string) {
w.t.Helper()