mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
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:
co-authored by
Danny Kopping
parent
18ef954a03
commit
e232aee011
Generated
+60
-2
@@ -9020,6 +9020,28 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AgentConnectionTiming": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ended_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"stage": {
|
||||
"$ref": "#/definitions/codersdk.TimingStage"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"workspace_agent_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_agent_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AgentScriptTiming": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -9034,7 +9056,7 @@ const docTemplate = `{
|
||||
"type": "integer"
|
||||
},
|
||||
"stage": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/codersdk.TimingStage"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
@@ -9042,6 +9064,12 @@ const docTemplate = `{
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_agent_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_agent_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12170,7 +12198,7 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
},
|
||||
"stage": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/codersdk.TimingStage"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
@@ -13473,6 +13501,29 @@ const docTemplate = `{
|
||||
"TemplateVersionWarningUnsupportedWorkspaces"
|
||||
]
|
||||
},
|
||||
"codersdk.TimingStage": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"init",
|
||||
"plan",
|
||||
"graph",
|
||||
"apply",
|
||||
"start",
|
||||
"stop",
|
||||
"cron",
|
||||
"connect"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"TimingStageInit",
|
||||
"TimingStagePlan",
|
||||
"TimingStageGraph",
|
||||
"TimingStageApply",
|
||||
"TimingStageStart",
|
||||
"TimingStageStop",
|
||||
"TimingStageCron",
|
||||
"TimingStageConnect"
|
||||
]
|
||||
},
|
||||
"codersdk.TokenConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -14806,7 +14857,14 @@ const docTemplate = `{
|
||||
"codersdk.WorkspaceBuildTimings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent_connection_timings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.AgentConnectionTiming"
|
||||
}
|
||||
},
|
||||
"agent_script_timings": {
|
||||
"description": "TODO: Consolidate agent-related timing metrics into a single struct when\nupdating the API version",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.AgentScriptTiming"
|
||||
|
||||
Generated
+60
-2
@@ -7992,6 +7992,28 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AgentConnectionTiming": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ended_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"stage": {
|
||||
"$ref": "#/definitions/codersdk.TimingStage"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"workspace_agent_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_agent_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AgentScriptTiming": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8006,7 +8028,7 @@
|
||||
"type": "integer"
|
||||
},
|
||||
"stage": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/codersdk.TimingStage"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
@@ -8014,6 +8036,12 @@
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_agent_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_agent_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -10986,7 +11014,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"stage": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/codersdk.TimingStage"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
@@ -12228,6 +12256,29 @@
|
||||
"enum": ["UNSUPPORTED_WORKSPACES"],
|
||||
"x-enum-varnames": ["TemplateVersionWarningUnsupportedWorkspaces"]
|
||||
},
|
||||
"codersdk.TimingStage": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"init",
|
||||
"plan",
|
||||
"graph",
|
||||
"apply",
|
||||
"start",
|
||||
"stop",
|
||||
"cron",
|
||||
"connect"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"TimingStageInit",
|
||||
"TimingStagePlan",
|
||||
"TimingStageGraph",
|
||||
"TimingStageApply",
|
||||
"TimingStageStart",
|
||||
"TimingStageStop",
|
||||
"TimingStageCron",
|
||||
"TimingStageConnect"
|
||||
]
|
||||
},
|
||||
"codersdk.TokenConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -13475,7 +13526,14 @@
|
||||
"codersdk.WorkspaceBuildTimings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent_connection_timings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.AgentConnectionTiming"
|
||||
}
|
||||
},
|
||||
"agent_script_timings": {
|
||||
"description": "TODO: Consolidate agent-related timing metrics into a single struct when\nupdating the API version",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/codersdk.AgentScriptTiming"
|
||||
|
||||
@@ -2894,13 +2894,15 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
||||
})
|
||||
rows := []database.GetWorkspaceAgentScriptTimingsByBuildIDRow{
|
||||
{
|
||||
StartedAt: timing.StartedAt,
|
||||
EndedAt: timing.EndedAt,
|
||||
Stage: timing.Stage,
|
||||
ScriptID: timing.ScriptID,
|
||||
ExitCode: timing.ExitCode,
|
||||
Status: timing.Status,
|
||||
DisplayName: script.DisplayName,
|
||||
StartedAt: timing.StartedAt,
|
||||
EndedAt: timing.EndedAt,
|
||||
Stage: timing.Stage,
|
||||
ScriptID: timing.ScriptID,
|
||||
ExitCode: timing.ExitCode,
|
||||
Status: timing.Status,
|
||||
DisplayName: script.DisplayName,
|
||||
WorkspaceAgentID: agent.ID,
|
||||
WorkspaceAgentName: agent.Name,
|
||||
},
|
||||
}
|
||||
check.Args(build.ID).Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(rows)
|
||||
|
||||
@@ -5899,15 +5899,31 @@ func (q *FakeQuerier) GetWorkspaceAgentScriptTimingsByBuildID(ctx context.Contex
|
||||
break
|
||||
}
|
||||
}
|
||||
if script.ID == uuid.Nil {
|
||||
return nil, xerrors.Errorf("script with ID %s not found", t.ScriptID)
|
||||
}
|
||||
|
||||
var agent database.WorkspaceAgent
|
||||
for _, a := range agents {
|
||||
if a.ID == script.WorkspaceAgentID {
|
||||
agent = a
|
||||
break
|
||||
}
|
||||
}
|
||||
if agent.ID == uuid.Nil {
|
||||
return nil, xerrors.Errorf("agent with ID %s not found", t.ScriptID)
|
||||
}
|
||||
|
||||
rows = append(rows, database.GetWorkspaceAgentScriptTimingsByBuildIDRow{
|
||||
ScriptID: t.ScriptID,
|
||||
StartedAt: t.StartedAt,
|
||||
EndedAt: t.EndedAt,
|
||||
ExitCode: t.ExitCode,
|
||||
Stage: t.Stage,
|
||||
Status: t.Status,
|
||||
DisplayName: script.DisplayName,
|
||||
ScriptID: t.ScriptID,
|
||||
StartedAt: t.StartedAt,
|
||||
EndedAt: t.EndedAt,
|
||||
ExitCode: t.ExitCode,
|
||||
Stage: t.Stage,
|
||||
Status: t.Status,
|
||||
DisplayName: script.DisplayName,
|
||||
WorkspaceAgentID: agent.ID,
|
||||
WorkspaceAgentName: agent.Name,
|
||||
})
|
||||
}
|
||||
return rows, nil
|
||||
|
||||
@@ -11454,7 +11454,11 @@ func (q *sqlQuerier) GetWorkspaceAgentMetadata(ctx context.Context, arg GetWorks
|
||||
}
|
||||
|
||||
const getWorkspaceAgentScriptTimingsByBuildID = `-- name: GetWorkspaceAgentScriptTimingsByBuildID :many
|
||||
SELECT workspace_agent_script_timings.script_id, workspace_agent_script_timings.started_at, workspace_agent_script_timings.ended_at, workspace_agent_script_timings.exit_code, workspace_agent_script_timings.stage, workspace_agent_script_timings.status, workspace_agent_scripts.display_name
|
||||
SELECT
|
||||
workspace_agent_script_timings.script_id, workspace_agent_script_timings.started_at, workspace_agent_script_timings.ended_at, workspace_agent_script_timings.exit_code, workspace_agent_script_timings.stage, workspace_agent_script_timings.status,
|
||||
workspace_agent_scripts.display_name,
|
||||
workspace_agents.id as workspace_agent_id,
|
||||
workspace_agents.name as workspace_agent_name
|
||||
FROM workspace_agent_script_timings
|
||||
INNER JOIN workspace_agent_scripts ON workspace_agent_scripts.id = workspace_agent_script_timings.script_id
|
||||
INNER JOIN workspace_agents ON workspace_agents.id = workspace_agent_scripts.workspace_agent_id
|
||||
@@ -11464,13 +11468,15 @@ WHERE workspace_builds.id = $1
|
||||
`
|
||||
|
||||
type GetWorkspaceAgentScriptTimingsByBuildIDRow struct {
|
||||
ScriptID uuid.UUID `db:"script_id" json:"script_id"`
|
||||
StartedAt time.Time `db:"started_at" json:"started_at"`
|
||||
EndedAt time.Time `db:"ended_at" json:"ended_at"`
|
||||
ExitCode int32 `db:"exit_code" json:"exit_code"`
|
||||
Stage WorkspaceAgentScriptTimingStage `db:"stage" json:"stage"`
|
||||
Status WorkspaceAgentScriptTimingStatus `db:"status" json:"status"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
ScriptID uuid.UUID `db:"script_id" json:"script_id"`
|
||||
StartedAt time.Time `db:"started_at" json:"started_at"`
|
||||
EndedAt time.Time `db:"ended_at" json:"ended_at"`
|
||||
ExitCode int32 `db:"exit_code" json:"exit_code"`
|
||||
Stage WorkspaceAgentScriptTimingStage `db:"stage" json:"stage"`
|
||||
Status WorkspaceAgentScriptTimingStatus `db:"status" json:"status"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"`
|
||||
WorkspaceAgentName string `db:"workspace_agent_name" json:"workspace_agent_name"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceAgentScriptTimingsByBuildID(ctx context.Context, id uuid.UUID) ([]GetWorkspaceAgentScriptTimingsByBuildIDRow, error) {
|
||||
@@ -11490,6 +11496,8 @@ func (q *sqlQuerier) GetWorkspaceAgentScriptTimingsByBuildID(ctx context.Context
|
||||
&i.Stage,
|
||||
&i.Status,
|
||||
&i.DisplayName,
|
||||
&i.WorkspaceAgentID,
|
||||
&i.WorkspaceAgentName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -303,7 +303,11 @@ VALUES
|
||||
RETURNING workspace_agent_script_timings.*;
|
||||
|
||||
-- name: GetWorkspaceAgentScriptTimingsByBuildID :many
|
||||
SELECT workspace_agent_script_timings.*, workspace_agent_scripts.display_name
|
||||
SELECT
|
||||
workspace_agent_script_timings.*,
|
||||
workspace_agent_scripts.display_name,
|
||||
workspace_agents.id as workspace_agent_id,
|
||||
workspace_agents.name as workspace_agent_name
|
||||
FROM workspace_agent_script_timings
|
||||
INNER JOIN workspace_agent_scripts ON workspace_agent_scripts.id = workspace_agent_script_timings.script_id
|
||||
INNER JOIN workspace_agents ON workspace_agents.id = workspace_agent_scripts.workspace_agent_id
|
||||
|
||||
@@ -957,15 +957,29 @@ func (api *API) buildTimings(ctx context.Context, build database.WorkspaceBuild)
|
||||
return codersdk.WorkspaceBuildTimings{}, xerrors.Errorf("fetching workspace agent script timings: %w", err)
|
||||
}
|
||||
|
||||
resources, err := api.Database.GetWorkspaceResourcesByJobID(ctx, build.JobID)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return codersdk.WorkspaceBuildTimings{}, xerrors.Errorf("fetching workspace resources: %w", err)
|
||||
}
|
||||
resourceIDs := make([]uuid.UUID, 0, len(resources))
|
||||
for _, resource := range resources {
|
||||
resourceIDs = append(resourceIDs, resource.ID)
|
||||
}
|
||||
agents, err := api.Database.GetWorkspaceAgentsByResourceIDs(ctx, resourceIDs)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return codersdk.WorkspaceBuildTimings{}, xerrors.Errorf("fetching workspace agents: %w", err)
|
||||
}
|
||||
|
||||
res := codersdk.WorkspaceBuildTimings{
|
||||
ProvisionerTimings: make([]codersdk.ProvisionerTiming, 0, len(provisionerTimings)),
|
||||
AgentScriptTimings: make([]codersdk.AgentScriptTiming, 0, len(agentScriptTimings)),
|
||||
ProvisionerTimings: make([]codersdk.ProvisionerTiming, 0, len(provisionerTimings)),
|
||||
AgentScriptTimings: make([]codersdk.AgentScriptTiming, 0, len(agentScriptTimings)),
|
||||
AgentConnectionTimings: make([]codersdk.AgentConnectionTiming, 0, len(agents)),
|
||||
}
|
||||
|
||||
for _, t := range provisionerTimings {
|
||||
res.ProvisionerTimings = append(res.ProvisionerTimings, codersdk.ProvisionerTiming{
|
||||
JobID: t.JobID,
|
||||
Stage: string(t.Stage),
|
||||
Stage: codersdk.TimingStage(t.Stage),
|
||||
Source: t.Source,
|
||||
Action: t.Action,
|
||||
Resource: t.Resource,
|
||||
@@ -975,12 +989,23 @@ func (api *API) buildTimings(ctx context.Context, build database.WorkspaceBuild)
|
||||
}
|
||||
for _, t := range agentScriptTimings {
|
||||
res.AgentScriptTimings = append(res.AgentScriptTimings, codersdk.AgentScriptTiming{
|
||||
StartedAt: t.StartedAt,
|
||||
EndedAt: t.EndedAt,
|
||||
ExitCode: t.ExitCode,
|
||||
Stage: string(t.Stage),
|
||||
Status: string(t.Status),
|
||||
DisplayName: t.DisplayName,
|
||||
StartedAt: t.StartedAt,
|
||||
EndedAt: t.EndedAt,
|
||||
ExitCode: t.ExitCode,
|
||||
Stage: codersdk.TimingStage(t.Stage),
|
||||
Status: string(t.Status),
|
||||
DisplayName: t.DisplayName,
|
||||
WorkspaceAgentID: t.WorkspaceAgentID.String(),
|
||||
WorkspaceAgentName: t.WorkspaceAgentName,
|
||||
})
|
||||
}
|
||||
for _, agent := range agents {
|
||||
res.AgentConnectionTimings = append(res.AgentConnectionTimings, codersdk.AgentConnectionTiming{
|
||||
WorkspaceAgentID: agent.ID.String(),
|
||||
WorkspaceAgentName: agent.Name,
|
||||
StartedAt: agent.CreatedAt,
|
||||
Stage: codersdk.TimingStageConnect,
|
||||
EndedAt: agent.FirstConnectedAt.Time,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user