feat(site): add agent connection timings (#15276)

Local preview:

<img width="1260" alt="Screenshot 2024-10-29 at 16 16 01"
src="https://github.com/user-attachments/assets/10fdb20d-1f2a-4b0a-a8a1-171050ee620d">


Close https://github.com/coder/internal/issues/116

---------

Co-authored-by: Danny Kopping <danny@coder.com>
This commit is contained in:
Bruno Quaresma
2024-11-01 13:29:00 -03:00
committed by GitHub
co-authored by Danny Kopping
parent 18ef954a03
commit e232aee011
22 changed files with 747 additions and 304 deletions
+95 -22
View File
@@ -1183,8 +1183,9 @@ func TestPostWorkspaceBuild(t *testing.T) {
})
}
//nolint:paralleltest
func TestWorkspaceBuildTimings(t *testing.T) {
t.Parallel()
// Setup the test environment with a template and version
db, pubsub := dbtestutil.NewDB(t)
client := coderdtest.New(t, &coderdtest.Options{
@@ -1237,10 +1238,13 @@ func TestWorkspaceBuildTimings(t *testing.T) {
})
}
//nolint:paralleltest
t.Run("NonExistentBuild", func(t *testing.T) {
// When: fetching an inexistent build
t.Parallel()
// Given: a non-existent build
buildID := uuid.New()
// When: fetching timings for the build
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
_, err := client.WorkspaceBuildTimings(ctx, buildID)
@@ -1250,10 +1254,13 @@ func TestWorkspaceBuildTimings(t *testing.T) {
require.Contains(t, err.Error(), "not found")
})
//nolint:paralleltest
t.Run("EmptyTimings", func(t *testing.T) {
// When: fetching timings for a build with no timings
t.Parallel()
// Given: a build with no timings
build := makeBuild()
// When: fetching timings for the build
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
res, err := client.WorkspaceBuildTimings(ctx, build.ID)
@@ -1264,25 +1271,27 @@ func TestWorkspaceBuildTimings(t *testing.T) {
require.Empty(t, res.AgentScriptTimings)
})
//nolint:paralleltest
t.Run("ProvisionerTimings", func(t *testing.T) {
// When: fetching timings for a build with provisioner timings
t.Parallel()
// Given: a build with provisioner timings
build := makeBuild()
provisionerTimings := dbgen.ProvisionerJobTimings(t, db, build, 5)
// Then: return a response with the expected timings
// When: fetching timings for the build
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
res, err := client.WorkspaceBuildTimings(ctx, build.ID)
require.NoError(t, err)
require.Len(t, res.ProvisionerTimings, 5)
// Then: return a response with the expected timings
require.Len(t, res.ProvisionerTimings, 5)
for i := range res.ProvisionerTimings {
timingRes := res.ProvisionerTimings[i]
genTiming := provisionerTimings[i]
require.Equal(t, genTiming.Resource, timingRes.Resource)
require.Equal(t, genTiming.Action, timingRes.Action)
require.Equal(t, string(genTiming.Stage), timingRes.Stage)
require.Equal(t, string(genTiming.Stage), string(timingRes.Stage))
require.Equal(t, genTiming.JobID.String(), timingRes.JobID.String())
require.Equal(t, genTiming.Source, timingRes.Source)
require.Equal(t, genTiming.StartedAt.UnixMilli(), timingRes.StartedAt.UnixMilli())
@@ -1290,9 +1299,10 @@ func TestWorkspaceBuildTimings(t *testing.T) {
}
})
//nolint:paralleltest
t.Run("AgentScriptTimings", func(t *testing.T) {
// When: fetching timings for a build with agent script timings
t.Parallel()
// Given: a build with agent script timings
build := makeBuild()
resource := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{
JobID: build.JobID,
@@ -1305,27 +1315,31 @@ func TestWorkspaceBuildTimings(t *testing.T) {
})
agentScriptTimings := dbgen.WorkspaceAgentScriptTimings(t, db, script, 5)
// Then: return a response with the expected timings
// When: fetching timings for the build
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
res, err := client.WorkspaceBuildTimings(ctx, build.ID)
require.NoError(t, err)
require.Len(t, res.AgentScriptTimings, 5)
// Then: return a response with the expected timings
require.Len(t, res.AgentScriptTimings, 5)
for i := range res.AgentScriptTimings {
timingRes := res.AgentScriptTimings[i]
genTiming := agentScriptTimings[i]
require.Equal(t, genTiming.ExitCode, timingRes.ExitCode)
require.Equal(t, string(genTiming.Status), timingRes.Status)
require.Equal(t, string(genTiming.Stage), timingRes.Stage)
require.Equal(t, string(genTiming.Stage), string(timingRes.Stage))
require.Equal(t, genTiming.StartedAt.UnixMilli(), timingRes.StartedAt.UnixMilli())
require.Equal(t, genTiming.EndedAt.UnixMilli(), timingRes.EndedAt.UnixMilli())
require.Equal(t, agent.ID.String(), timingRes.WorkspaceAgentID)
require.Equal(t, agent.Name, timingRes.WorkspaceAgentName)
}
})
//nolint:paralleltest
t.Run("NoAgentScripts", func(t *testing.T) {
// When: fetching timings for a build with no agent scripts
t.Parallel()
// Given: a build with no agent scripts
build := makeBuild()
resource := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{
JobID: build.JobID,
@@ -1334,29 +1348,88 @@ func TestWorkspaceBuildTimings(t *testing.T) {
ResourceID: resource.ID,
})
// Then: return a response with empty agent script timings
// When: fetching timings for the build
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
res, err := client.WorkspaceBuildTimings(ctx, build.ID)
require.NoError(t, err)
// Then: return a response with empty agent script timings
require.Empty(t, res.AgentScriptTimings)
})
// Some workspaces might not have agents. It is improbable, but possible.
//nolint:paralleltest
t.Run("NoAgents", func(t *testing.T) {
// When: fetching timings for a build with no agents
t.Parallel()
// Given: a build with no agents
build := makeBuild()
dbgen.WorkspaceResource(t, db, database.WorkspaceResource{
JobID: build.JobID,
})
// Then: return a response with empty agent script timings
// trigger build
// When: fetching timings for the build
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
res, err := client.WorkspaceBuildTimings(ctx, build.ID)
require.NoError(t, err)
// Then: return a response with empty agent script timings
require.Empty(t, res.AgentScriptTimings)
require.Empty(t, res.AgentConnectionTimings)
})
t.Run("AgentConnectionTimings", func(t *testing.T) {
t.Parallel()
// Given: a build with an agent
build := makeBuild()
resource := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{
JobID: build.JobID,
})
agent := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{
ResourceID: resource.ID,
})
// When: fetching timings for the build
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
res, err := client.WorkspaceBuildTimings(ctx, build.ID)
require.NoError(t, err)
// Then: return a response with the expected timings
require.Len(t, res.AgentConnectionTimings, 1)
for i := range res.ProvisionerTimings {
timingRes := res.AgentConnectionTimings[i]
require.Equal(t, agent.ID.String(), timingRes.WorkspaceAgentID)
require.Equal(t, agent.Name, timingRes.WorkspaceAgentName)
require.NotEmpty(t, timingRes.StartedAt)
require.NotEmpty(t, timingRes.EndedAt)
}
})
t.Run("MultipleAgents", func(t *testing.T) {
t.Parallel()
// Given: a build with multiple agents
build := makeBuild()
resource := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{
JobID: build.JobID,
})
agents := make([]database.WorkspaceAgent, 5)
for i := range agents {
agents[i] = dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{
ResourceID: resource.ID,
})
}
// When: fetching timings for the build
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
t.Cleanup(cancel)
res, err := client.WorkspaceBuildTimings(ctx, build.ID)
require.NoError(t, err)
// Then: return a response with the expected timings
require.Len(t, res.AgentConnectionTimings, 5)
})
}