Skip to content

Commit 0f45585

Browse files
committed
make tasks list more interactive
1 parent 326d38b commit 0f45585

File tree

6 files changed

+796
-436
lines changed

6 files changed

+796
-436
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package api
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"strconv"
7+
"time"
8+
9+
"github.com/ethpandaops/assertoor/pkg/coordinator/types"
10+
"github.com/gorilla/mux"
11+
"gopkg.in/yaml.v3"
12+
)
13+
14+
// GetTestRunTaskDetails godoc
15+
// @Id getTestRunTaskDetails
16+
// @Summary Get detailed task of a given test run
17+
// @Tags TestRun
18+
// @Description Returns the task details with given run ID and task index. Includes full log, configuration and result variables (unless security trimmed).
19+
// @Produce json
20+
// @Param runId path string true "ID of the test run"
21+
// @Param taskIndex path string true "Index of the task to get details for"
22+
// @Success 200 {object} Response{data=GetTestRunDetailedTask} "Success"
23+
// @Failure 400 {object} Response "Bad Request"
24+
// @Failure 404 {object} Response "Not Found"
25+
// @Failure 500 {object} Response "Server Error"
26+
// @Router /api/v1/test_run/{runId}/task/{taskIndex}/details [get]
27+
func (ah *APIHandler) GetTestRunTaskDetails(w http.ResponseWriter, r *http.Request) {
28+
w.Header().Set("Content-Type", contentTypeJSON)
29+
30+
vars := mux.Vars(r)
31+
32+
runID, err := strconv.ParseUint(vars["runId"], 10, 64)
33+
if err != nil {
34+
ah.sendErrorResponse(w, r.URL.String(), "invalid runId provided", http.StatusBadRequest)
35+
return
36+
}
37+
38+
taskIdx, err := strconv.ParseUint(vars["taskIndex"], 10, 64)
39+
if err != nil {
40+
ah.sendErrorResponse(w, r.URL.String(), "invalid taskIndex provided", http.StatusBadRequest)
41+
return
42+
}
43+
44+
testInstance := ah.coordinator.GetTestByRunID(runID)
45+
if testInstance == nil {
46+
ah.sendErrorResponse(w, r.URL.String(), "test run not found", http.StatusNotFound)
47+
return
48+
}
49+
50+
taskScheduler := testInstance.GetTaskScheduler()
51+
if taskScheduler == nil {
52+
ah.sendErrorResponse(w, r.URL.String(), "task scheduler not found", http.StatusNotFound)
53+
return
54+
}
55+
56+
// Get task state by index
57+
taskState := taskScheduler.GetTaskState(types.TaskIndex(taskIdx))
58+
if taskState == nil {
59+
ah.sendErrorResponse(w, r.URL.String(), "task not found", http.StatusNotFound)
60+
return
61+
}
62+
63+
taskStatus := taskState.GetTaskStatus()
64+
65+
// build response similar to GetTestRunDetails logic
66+
taskData := &GetTestRunDetailedTask{
67+
Index: uint64(taskState.Index()),
68+
ParentIndex: uint64(taskState.ParentIndex()),
69+
Name: taskState.Name(),
70+
Title: taskState.Title(),
71+
Started: taskStatus.IsStarted,
72+
Completed: taskStatus.IsStarted && !taskStatus.IsRunning,
73+
Timeout: uint64(taskState.Timeout().Seconds()),
74+
}
75+
76+
switch {
77+
case !taskStatus.IsStarted:
78+
taskData.Status = "pending"
79+
case taskStatus.IsRunning:
80+
taskData.Status = "running"
81+
taskData.StartTime = taskStatus.StartTime.UnixMilli()
82+
taskData.RunTime = uint64(time.Since(taskStatus.StartTime).Round(1 * time.Millisecond).Milliseconds()) //nolint:gosec // no overflow possible
83+
default:
84+
taskData.Status = "complete"
85+
taskData.StartTime = taskStatus.StartTime.UnixMilli()
86+
taskData.StopTime = taskStatus.StopTime.UnixMilli()
87+
taskData.RunTime = uint64(taskStatus.StopTime.Sub(taskStatus.StartTime).Round(1 * time.Millisecond).Milliseconds()) //nolint:gosec // no overflow possible
88+
}
89+
90+
switch taskStatus.Result {
91+
case types.TaskResultNone:
92+
taskData.Result = "none"
93+
case types.TaskResultSuccess:
94+
taskData.Result = "success"
95+
case types.TaskResultFailure:
96+
taskData.Result = "failure"
97+
}
98+
99+
if taskStatus.Error != nil {
100+
taskData.ResultError = taskStatus.Error.Error()
101+
}
102+
103+
// logs (limit 100 entries)
104+
logCount := taskStatus.Logger.GetLogEntryCount()
105+
logStart := uint64(0)
106+
logLimit := uint64(100)
107+
if logCount > logLimit {
108+
logStart = logCount - logLimit
109+
}
110+
111+
taskLog := taskStatus.Logger.GetLogEntries(logStart, logLimit)
112+
taskData.Log = make([]*GetTestRunDetailedTaskLog, len(taskLog))
113+
for i, log := range taskLog {
114+
logData := &GetTestRunDetailedTaskLog{
115+
Time: time.Unix(0, log.LogTime*int64(time.Millisecond)),
116+
Level: uint64(log.LogLevel),
117+
Message: log.LogMessage,
118+
Data: map[string]string{},
119+
}
120+
121+
if log.LogFields != "" {
122+
err := yaml.Unmarshal([]byte(log.LogFields), &logData.Data)
123+
if err == nil {
124+
logData.DataLen = uint64(len(logData.Data))
125+
}
126+
}
127+
128+
taskData.Log[i] = logData
129+
}
130+
131+
// config yaml
132+
if cfgData, err := yaml.Marshal(taskState.Config()); err == nil {
133+
taskData.ConfigYaml = string(cfgData)
134+
} else {
135+
taskData.ConfigYaml = fmt.Sprintf("failed marshalling config: %v", err)
136+
}
137+
138+
// result yaml
139+
if resData, err := yaml.Marshal(taskState.GetTaskStatusVars().GetVarsMap(nil, false)); err == nil {
140+
taskData.ResultYaml = string(resData)
141+
} else {
142+
taskData.ResultYaml = fmt.Sprintf("failed marshalling result: %v", err)
143+
}
144+
145+
ah.sendOKResponse(w, r.URL.String(), taskData)
146+
}

pkg/coordinator/web/api/get_test_run_api.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,20 @@ func (ah *APIHandler) GetTestRun(w http.ResponseWriter, r *http.Request) {
120120
Title: taskState.Title(),
121121
Started: taskStatus.IsStarted,
122122
Completed: taskStatus.IsStarted && !taskStatus.IsRunning,
123-
Timeout: uint64(taskState.Timeout().Seconds()),
123+
Timeout: uint64(taskState.Timeout().Milliseconds()),
124124
}
125125

126126
switch {
127127
case !taskStatus.IsStarted:
128128
taskData.Status = "pending"
129129
case taskStatus.IsRunning:
130130
taskData.Status = "running"
131-
taskData.StartTime = taskStatus.StartTime.Unix()
131+
taskData.StartTime = taskStatus.StartTime.UnixMilli()
132132
taskData.RunTime = uint64(time.Since(taskStatus.StartTime).Round(1 * time.Millisecond).Milliseconds()) //nolint:gosec // no overflow possible
133133
default:
134134
taskData.Status = "complete"
135-
taskData.StartTime = taskStatus.StartTime.Unix()
136-
taskData.StopTime = taskStatus.StopTime.Unix()
135+
taskData.StartTime = taskStatus.StartTime.UnixMilli()
136+
taskData.StopTime = taskStatus.StopTime.UnixMilli()
137137
taskData.RunTime = uint64(taskStatus.StopTime.Sub(taskStatus.StartTime).Round(1 * time.Millisecond).Milliseconds()) //nolint:gosec // no overflow possible
138138
}
139139

pkg/coordinator/web/api/get_test_run_details_api.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,20 @@ func (ah *APIHandler) GetTestRunDetails(w http.ResponseWriter, r *http.Request)
109109
Title: taskState.Title(),
110110
Started: taskStatus.IsStarted,
111111
Completed: taskStatus.IsStarted && !taskStatus.IsRunning,
112-
Timeout: uint64(taskState.Timeout().Seconds()),
112+
Timeout: uint64(taskState.Timeout().Milliseconds()),
113113
}
114114

115115
switch {
116116
case !taskStatus.IsStarted:
117117
taskData.Status = "pending"
118118
case taskStatus.IsRunning:
119119
taskData.Status = "running"
120-
taskData.StartTime = taskStatus.StartTime.Unix()
120+
taskData.StartTime = taskStatus.StartTime.UnixMilli()
121121
taskData.RunTime = uint64(time.Since(taskStatus.StartTime).Round(1 * time.Millisecond).Milliseconds()) //nolint:gosec // no overflow possible
122122
default:
123123
taskData.Status = "complete"
124-
taskData.StartTime = taskStatus.StartTime.Unix()
125-
taskData.StopTime = taskStatus.StopTime.Unix()
124+
taskData.StartTime = taskStatus.StartTime.UnixMilli()
125+
taskData.StopTime = taskStatus.StopTime.UnixMilli()
126126
taskData.RunTime = uint64(taskStatus.StopTime.Sub(taskStatus.StartTime).Round(1 * time.Millisecond).Milliseconds()) //nolint:gosec // no overflow possible
127127
}
128128

0 commit comments

Comments
 (0)