Skip to content

Commit

Permalink
Add details page for individual test runs
Browse files Browse the repository at this point in the history
Rate limit · GitHub

Access has been restricted

You have triggered a rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

tvrg committed Dec 1, 2022
1 parent 497e403 commit 200d089
Showing 11 changed files with 259 additions and 43 deletions.
26 changes: 20 additions & 6 deletions api/api.go
Original file line number Diff line number Diff line change
@@ -40,7 +40,8 @@ func New(db *sqlx.DB, token string) *echo.Echo {
})
app.POST("/report/:commit", secure(token, wrapper.AddReport))
app.GET("/flakes", wrapper.GetFlakyTests)
app.GET("/test/:name/fails", wrapper.GetFailedBuilds)
app.GET("/test/:id/fails", wrapper.GetFailedBuilds)
app.GET("/test/:test_id/upload/:upload_id/output", wrapper.GetTestResult)
app.GET("/ui", func(c echo.Context) error {
flakes, err := api.flakyTests()
if err != nil {
@@ -51,15 +52,28 @@ func New(db *sqlx.DB, token string) *echo.Echo {
"Flakes": flakes,
})
})
app.GET("/ui/test/:name/fails", func(c echo.Context) error {
name := c.Param("name")
fails, err := api.failedBuilds(name)
app.GET("/ui/test/:id/fails", func(c echo.Context) error {
testID := c.Param("id")
test, err := api.failedBuilds(testID)
if err != nil {
return err
}
return c.Render(http.StatusOK, "fails.html", map[string]interface{}{
"Title": "Failed Builds " + name,
"Fails": fails,
"Title": "Failed Builds " + test.Name,
"TestId": testID,
"Results": test.Results,
})
})
app.GET("/ui/test/:test_id/upload/:upload_id", func(c echo.Context) error {
testID := c.Param("test_id")
uploadID := c.Param("upload_id")
result, err := api.testResult(testID, uploadID)
if err != nil {
return err
}
return c.Render(http.StatusOK, "result.html", map[string]interface{}{
"Title": "Test result for " + result.Name,
"Result": result,
})
})
app.StaticFS("/ui", asset.Static)
43 changes: 33 additions & 10 deletions api/fails.go
Original file line number Diff line number Diff line change
@@ -2,36 +2,59 @@ package api

import (
"net/http"
"strconv"
"time"

"github.com/FACT-Finder/noflake/database"
"github.com/labstack/echo/v4"
)

func (a *api) GetFailedBuilds(ctx echo.Context, name string) error {
flakes, err := a.failedBuilds(name)
func (a *api) GetFailedBuilds(ctx echo.Context, testID string) error {
flakes, err := a.failedBuilds(testID)
if err != nil {
return err
}
return ctx.JSON(http.StatusOK, flakes)
}

func (a *api) failedBuilds(name string) ([]FailedBuild, error) {
failures, err := database.GetFailures(a.db, name)
func (a *api) failedBuilds(id string) (TestResults, error) {
testID, err := strconv.Atoi(id)
if err != nil {
return nil, err
return TestResults{}, err
}

result := []FailedBuild{}
testName, err := database.GetTestName(a.db, testID)
if err != nil {
return TestResults{}, err
}

failures, err := database.GetFailures(a.db, testID)
if err != nil {
return TestResults{}, err
}

results := []TestResult{}

for _, fail := range failures {
uploadID := strconv.Itoa(fail.UploadID)
commitSHA := fail.CommitSHA
output := fail.Output
url := fail.URL
lastFailStr := fail.Date.UTC().Format(time.RFC3339)
result = append(result,
FailedBuild{CommitSHA: commitSHA, Date: lastFailStr, Output: output, Url: url})
results = append(results,
TestResult{
TestId: id,
UploadId: uploadID,
Name: testName,
CommitSHA: commitSHA,
Date: lastFailStr,
Success: false,
Url: url,
})
}

return result, nil
return TestResults{
TestId: id,
Name: testName,
Results: results,
}, nil
}
5 changes: 4 additions & 1 deletion api/flakes.go
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ package api

import (
"net/http"
"strconv"
"time"

"github.com/FACT-Finder/noflake/database"
@@ -17,11 +18,13 @@ func (a *api) flakyTests() ([]FlakyTest, error) {
flakes := []FlakyTest{}

for _, test := range tests {
name := test.Name
totalFails := test.TotalFails
lastFail := test.LastFail
lastFailStr := lastFail.UTC().Format(time.RFC3339)
idStr := strconv.Itoa(test.ID)
flakes = append(flakes,
FlakyTest{Test: test.Name, TotalFails: &totalFails, LastFail: &lastFailStr})
FlakyTest{Id: idStr, Name: name, TotalFails: &totalFails, LastFail: &lastFailStr})
}

return flakes, nil
4 changes: 2 additions & 2 deletions api/report.go
Original file line number Diff line number Diff line change
@@ -80,9 +80,9 @@ func (a *api) AddReport(ctx echo.Context, commitSha string, params AddReportPara
fmt.Sprintf("couldn't store test results: %s", err))
}

err = database.UpdateFlakyTests(a.db, *commit)
err = database.UpdateFlakyTests(a.db, *commit.ID)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest,
return echo.NewHTTPError(http.StatusInternalServerError,
fmt.Sprintf("couldn't update flaky tests: %s", err))
}

44 changes: 44 additions & 0 deletions api/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package api

import (
"net/http"
"strconv"

"github.com/FACT-Finder/noflake/database"
"github.com/labstack/echo/v4"
)

func (a *api) GetTestResult(ctx echo.Context, testID, uploadID string) error {
output, err := a.testResult(testID, uploadID)
if err != nil {
return err
}
return ctx.JSON(http.StatusOK, output)
}

func (a *api) testResult(testIDStr, uploadIDStr string) (TestResult, error) {
testID, err := strconv.Atoi(testIDStr)
if err != nil {
return TestResult{}, err
}

uploadID, err := strconv.Atoi(uploadIDStr)
if err != nil {
return TestResult{}, err
}

testResult, err := database.GetTestResult(a.db, testID, uploadID)
if err != nil {
return TestResult{}, err
}

return TestResult{
TestId: testIDStr,
UploadId: uploadIDStr,
Name: testResult.Name,
CommitSHA: testResult.CommitSHA,
Url: testResult.URL,
Success: testResult.Success,
Output: testResult.Output,
}, nil
}
4 changes: 3 additions & 1 deletion asset/fails.html
Original file line number Diff line number Diff line change
@@ -5,12 +5,14 @@
<th>Commit</th>
<th></th>
</tr>
{{ range .Fails }}
{{ range .Results }}
<tr>
<td>{{.Date}}</td>
<td>{{.CommitSHA}}</td>
<td><a href="{{.Url}}">Build</a></td>
<td><a href="/ui/test/{{$.TestId}}/upload/{{.UploadId}}">Details</a></td>
</tr>
{{ end }}
</table>
{{template "end" .}}
{{.Output}}
2 changes: 1 addition & 1 deletion asset/index.html
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
<tr>
<td>{{.LastFail}}</td>
<td>{{.TotalFails}}</td>
<td><a href="/ui/test/{{.Test}}/fails">{{.Test}}</a></td>
<td><a href="/ui/test/{{.Id}}/fails">{{.Name}}</a></td>
</tr>
{{ end }}
</table>
20 changes: 20 additions & 0 deletions asset/result.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{{template "start" .}}
<div>
<a href="/ui/test/{{.Result.TestId}}/fails">Show all failures for this test</a>
</div>
<br />
<table>
<tr><td>Name</td><td>{{.Result.Name}}</td></tr>
<tr><td>Commit</td><td>{{.Result.CommitSHA}}</td></tr>
<tr><td>Success</td><td>{{.Result.Success}}</td>
<tr><td>Build</td><td><a href="{{.Result.Url}}">{{.Result.Url}}</a></td>
</table>
<br />
<div>
<div><b>Output:</b></div>
<pre>
{{.Result.Output}}
</pre>
</div>
{{template "end" .}}
{{.Output}}
12 changes: 6 additions & 6 deletions database/fails.go
Original file line number Diff line number Diff line change
@@ -7,27 +7,27 @@ import (
)

type TestFailure struct {
UploadID int `db:"upload_id"`
Date time.Time `db:"last_fail"`
Output *string `db:"output"`
CommitSHA string `db:"commit_sha"`
URL *string `db:"url"`
}

func GetFailures(db *sqlx.DB, name string) ([]TestFailure, error) {
func GetFailures(db *sqlx.DB, testID int) ([]TestFailure, error) {
rows, err := db.Queryx(`
SELECT
uploads.id as upload_id,
commits.commit_sha,
uploads.url,
results.output,
uploads.time
from results
LEFT JOIN commits on commits.id = results.commit_id
LEFT JOIN uploads on uploads.id = results.upload_id
LEFT JOIN tests on tests.id = results.test_id
WHERE
tests.name = ? and results.success = 0
tests.id = ? and results.success = 0
ORDER BY uploads.time desc
`, name)
`, testID)
if err != nil {
return nil, err
}
@@ -36,7 +36,7 @@ func GetFailures(db *sqlx.DB, name string) ([]TestFailure, error) {
for rows.Next() {
var failure TestFailure
var dateTimestamp int64
err = rows.Scan(&failure.CommitSHA, &failure.URL, &failure.Output, &dateTimestamp)
err = rows.Scan(&failure.UploadID, &failure.CommitSHA, &failure.URL, &dateTimestamp)
if err != nil {
return nil, err
}
49 changes: 46 additions & 3 deletions database/test.go
Original file line number Diff line number Diff line change
@@ -80,7 +80,7 @@ func InsertTests(db *sqlx.DB, tests []model.TestResult, upload model.Upload) err
return nil
}

func UpdateFlakyTests(db *sqlx.DB, commit model.Commit) error {
func UpdateFlakyTests(db *sqlx.DB, commitID int) error {
stmt, err := db.Preparex(`
UPDATE tests SET flaky = true
WHERE tests.id in (
@@ -95,13 +95,14 @@ func UpdateFlakyTests(db *sqlx.DB, commit model.Commit) error {
return err
}

_, err = stmt.Exec(commit.ID)
_, err = stmt.Exec(commitID)
return err
}

func GetFlakyTests(db *sqlx.DB) ([]FlakyTest, error) {
rows, err := db.Queryx(`
SELECT
tests.id AS test_id,
tests.name AS name,
count(results.success) as total_fails,
MAX(uploads.time) as last_fail
@@ -120,7 +121,7 @@ func GetFlakyTests(db *sqlx.DB) ([]FlakyTest, error) {
for rows.Next() {
var test FlakyTest
var lastFailTimestamp int64
err = rows.Scan(&test.Name, &test.TotalFails, &lastFailTimestamp)
err = rows.Scan(&test.ID, &test.Name, &test.TotalFails, &lastFailTimestamp)
if err != nil {
return nil, err
}
@@ -131,7 +132,49 @@ func GetFlakyTests(db *sqlx.DB) ([]FlakyTest, error) {
return tests, nil
}

func GetTestName(db *sqlx.DB, testID int) (string, error) {
name := ""
err := db.QueryRowx(
`SELECT tests.name from tests WHERE tests.id = ?
`, testID).Scan(&name)

return name, err
}

type TestResult struct {
UploadID int `db:"upload_id"`
TestID int `db:"test_id"`
Name string `db:"test_name"`
CommitSHA string `db:"commit_sha"`
URL *string `db:"url"`
Success bool `db:"success"`
Output *string `db:"test_output"`
Date string `db:"time"`
}

func GetTestResult(db *sqlx.DB, testID, uploadID int) (TestResult, error) {
output := TestResult{UploadID: uploadID, TestID: testID}
err := db.QueryRowx(`
SELECT
tests.name as test_name,
commits.commit_sha,
uploads.url,
results.success,
results.output as test_output,
uploads.time
from results
LEFT JOIN commits on commits.id = results.commit_id
LEFT JOIN tests on tests.id = results.test_id
LEFT JOIN uploads on uploads.id = results.upload_id
WHERE
results.test_id = ? and results.upload_id = ?
`, testID, uploadID).StructScan(&output)

return output, err
}

type FlakyTest struct {
ID int `db:"test_id"`
Name string `db:"name"`
TotalFails int `db:"total_fails"`
LastFail time.Time `db:"last_fail"`
Rate limit · GitHub

Access has been restricted

You have triggered a rate limit.

Please wait a few minutes before you try again;
in some cases this may take up to an hour.

0 comments on commit 200d089

Please sign in to comment.