Ctrl K
ComunidadGuías…

cli/ping_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package cli_test

import (
	"bytes"
	"context"
	"encoding/json"
	"testing"

	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/coder/coder/v2/agent/agenttest"
	"github.com/coder/coder/v2/cli"
	"github.com/coder/coder/v2/cli/clitest"
	"github.com/coder/coder/v2/coderd/coderdtest"
	sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
	"github.com/coder/coder/v2/testutil"
	"github.com/coder/coder/v2/testutil/expecter"
)

func TestPing_AgentSuggestions(t *testing.T) {
	t.Parallel()

	client, workspace, _ := setupWorkspaceForAgent(t, func(agents []*sdkproto.Agent) []*sdkproto.Agent {
		agents[0].Name = "coder"
		return append(agents, &sdkproto.Agent{
			Id:   uuid.NewString(),
			Name: "dev",
			Auth: &sdkproto.Agent_Token{Token: uuid.NewString()},
		})
	})
	qualifiedName := "myuser/" + workspace.Name
	for _, tc := range []struct {
		name  string
		input string
		want  string
		json  bool
	}{
		{name: "Name", input: workspace.Name, want: workspace.Name},
		{name: "OwnerAndName", input: qualifiedName, want: qualifiedName},
		{name: "UUID", input: workspace.ID.String(), want: qualifiedName},
		{name: "JSON", input: workspace.Name, want: workspace.Name, json: true},
	} {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()
			args := []string{"ping", tc.input}
			if tc.json {
				args = append(args, "--num", "1", "--output", "json")
			}
			inv, root := clitest.New(t, args...)
			clitest.SetupConfig(t, client, root)
			var stdout bytes.Buffer
			inv.Stdout = &stdout
			err := inv.WithContext(testutil.Context(t, testutil.WaitLong)).Run()
			require.ErrorContains(t, err, "multiple agents found")
			require.ErrorContains(t, err, "Try running:")
			assert.Contains(t, err.Error(), "$ coder ping "+tc.want+".coder")
			assert.Contains(t, err.Error(), "$ coder ping "+tc.want+".dev")
			assert.NotContains(t, err.Error(), "$ ssh ")
			assert.Empty(t, stdout.String())
		})
	}
}

func TestPing(t *testing.T) {
	t.Parallel()

	t.Run("OK", func(t *testing.T) {
		t.Parallel()

		client, workspace, agentToken := setupWorkspaceForAgent(t)
		inv, root := clitest.New(t, "ping", workspace.Name)
		clitest.SetupConfig(t, client, root)
		stdout := expecter.NewAttachedToInvocation(t, inv)

		_ = agenttest.New(t, client.URL, agentToken)
		_ = coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)

		ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
		defer cancel()

		cmdDone := tGo(t, func() {
			err := inv.WithContext(ctx).Run()
			assert.NoError(t, err)
		})

		stdout.ExpectMatch(ctx, "pong from "+workspace.Name)
		cancel()
		<-cmdDone
	})

	t.Run("1Ping", func(t *testing.T) {
		t.Parallel()

		client, workspace, agentToken := setupWorkspaceForAgent(t)
		inv, root := clitest.New(t, "ping", "-n", "1", workspace.Name)
		clitest.SetupConfig(t, client, root)
		stdout := expecter.NewAttachedToInvocation(t, inv)

		_ = agenttest.New(t, client.URL, agentToken)
		_ = coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)

		ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
		defer cancel()

		cmdDone := tGo(t, func() {
			err := inv.WithContext(ctx).Run()
			assert.NoError(t, err)
		})

		stdout.ExpectMatch(ctx, "pong from "+workspace.Name)
		// The default table output prints the summary after the last ping.
		stdout.ExpectRegexMatch(ctx, `(?i)successful`)
		cancel()
		<-cmdDone
	})

	t.Run("1PingWithTime", func(t *testing.T) {
		t.Parallel()

		tests := []struct {
			name string
			utc  bool
		}{
			{name: "LocalTime"},      // --time renders the pong response time.
			{name: "UTC", utc: true}, // --utc implies --time, so we expect it to also contain the pong time.
		}

		for _, tc := range tests {
			t.Run(tc.name, func(t *testing.T) {
				t.Parallel()

				client, workspace, agentToken := setupWorkspaceForAgent(t)
				args := []string{"ping", "-n", "1", workspace.Name, "--time"}
				if tc.utc {
					args = append(args, "--utc")
				}

				inv, root := clitest.New(t, args...)
				clitest.SetupConfig(t, client, root)
				stdout := expecter.NewAttachedToInvocation(t, inv)

				_ = agenttest.New(t, client.URL, agentToken)
				_ = coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)

				ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
				defer cancel()

				cmdDone := tGo(t, func() {
					err := inv.WithContext(ctx).Run()
					assert.NoError(t, err)
				})

				// RFC3339 is the format used to render the pong times.
				rfc3339 := `\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?`

				// Validate that dates are rendered as specified.
				if tc.utc {
					rfc3339 += `Z`
				} else {
					rfc3339 += `(?:Z|[+-]\d{2}:\d{2})`
				}

				stdout.ExpectRegexMatch(ctx, `\[`+rfc3339+`\] pong from `+workspace.Name)
				cancel()
				<-cmdDone
			})
		}
	})

	t.Run("JSON", func(t *testing.T) {
		t.Parallel()

		client, workspace, agentToken := setupWorkspaceForAgent(t)
		inv, root := clitest.New(t, "ping", "-n", "1", "-o", "json", workspace.Name)
		clitest.SetupConfig(t, client, root)
		out := bytes.NewBuffer(nil)
		inv.Stdout = out

		_ = agenttest.New(t, client.URL, agentToken)
		_ = coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)

		ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
		defer cancel()

		err := inv.WithContext(ctx).Run()
		require.NoError(t, err)

		// stdout must contain nothing but the JSON document; diagnostic
		// and per-attempt lines are redirected to stderr in JSON mode.
		var result cli.PingJSONOutput
		require.NoError(t, json.Unmarshal(out.Bytes(), &result))
		assert.Equal(t, workspace.Name, result.Workspace)
		require.Len(t, result.Pongs, 1)
		assert.Equal(t, 1, result.Pongs[0].Sequence)
		assert.Empty(t, result.Pongs[0].Error)
		require.NotNil(t, result.Pongs[0].LatencyMS)
		require.NotNil(t, result.Pongs[0].Direct)
		assert.Equal(t, 1, result.Summary.Total)
		assert.Equal(t, 1, result.Summary.Successful)
		require.NotNil(t, result.Summary.MinMS)
		require.NotNil(t, result.Summary.AvgMS)
		require.NotNil(t, result.Summary.MaxMS)
	})

	t.Run("JSONRequiresNum", func(t *testing.T) {
		t.Parallel()

		for _, args := range [][]string{
			{"ping", "-o", "json", "my-workspace"},
			{"ping", "-n", "0", "-o", "json", "my-workspace"},
		} {
			inv, _ := clitest.New(t, args...)
			out := bytes.NewBuffer(nil)
			inv.Stdout = out

			err := inv.Run()
			require.ErrorContains(t, err, "--output json requires --num")
			assert.Empty(t, out.String())
		}
	})
}