mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-04-25 04:57:31 +00:00

Some checks are pending
/ release (push) Waiting to run
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
This PR depends on https://codeberg.org/forgejo/forgejo/pulls/7510 This PR renames UpdateRunJob to UpdateRunJobWithoutNotification and UpdateRun to UpdateRunWithoutNotification and implements wrapper functions that also call the new ActionRunNowDone notification when needed. This PR can be reviewed commit-by-commit. # Things to Test - [x] GetRunBefore - [ ] integration test for sendActionRunNowDoneNotificationIfNeeded, UpdateRun and UpdateRunJob ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests - I added test coverage for Go changes... - [x] in their respective `*_test.go` for unit tests. - [x] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. ### Release notes - [ ] I do not want this change to show in the release notes. - [ ] I want the title to show in the release notes with a link to this pull request. - [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title. Co-authored-by: nobody <nobody@example.com> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7491 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Co-authored-by: christopher-besch <mail@chris-besch.com> Co-committed-by: christopher-besch <mail@chris-besch.com>
176 lines
5.4 KiB
Go
176 lines
5.4 KiB
Go
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package integration
|
|
|
|
import (
|
|
"context"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
actions_model "forgejo.org/models/actions"
|
|
"forgejo.org/models/db"
|
|
unit_model "forgejo.org/models/unit"
|
|
"forgejo.org/models/unittest"
|
|
user_model "forgejo.org/models/user"
|
|
"forgejo.org/modules/gitrepo"
|
|
"forgejo.org/modules/setting"
|
|
actions_service "forgejo.org/services/actions"
|
|
notify_service "forgejo.org/services/notify"
|
|
files_service "forgejo.org/services/repository/files"
|
|
"forgejo.org/tests"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type mockNotifier struct {
|
|
notify_service.NullNotifier
|
|
testIdx int
|
|
t *testing.T
|
|
runID int64
|
|
lastRunID int64
|
|
}
|
|
|
|
var _ notify_service.Notifier = &mockNotifier{}
|
|
|
|
func (m *mockNotifier) ActionRunNowDone(ctx context.Context, run *actions_model.ActionRun, priorStatus actions_model.Status, lastRun *actions_model.ActionRun) {
|
|
switch m.testIdx {
|
|
case 0:
|
|
// we accept the first id as okay and just check that the following ones make sense
|
|
m.runID = run.ID
|
|
assert.Equal(m.t, actions_model.StatusSuccess, run.Status)
|
|
assert.Equal(m.t, actions_model.StatusRunning, priorStatus)
|
|
assert.Nil(m.t, lastRun)
|
|
case 1:
|
|
assert.Equal(m.t, m.runID, run.ID)
|
|
assert.Equal(m.t, actions_model.StatusFailure, run.Status)
|
|
assert.Equal(m.t, actions_model.StatusRunning, priorStatus)
|
|
assert.Equal(m.t, m.lastRunID, lastRun.ID)
|
|
assert.Equal(m.t, actions_model.StatusSuccess, lastRun.Status)
|
|
case 2:
|
|
assert.Equal(m.t, m.runID, run.ID)
|
|
assert.Equal(m.t, actions_model.StatusCancelled, run.Status)
|
|
assert.Equal(m.t, actions_model.StatusRunning, priorStatus)
|
|
assert.Equal(m.t, m.lastRunID, lastRun.ID)
|
|
assert.Equal(m.t, actions_model.StatusFailure, lastRun.Status)
|
|
case 3:
|
|
assert.Equal(m.t, m.runID, run.ID)
|
|
assert.Equal(m.t, actions_model.StatusSuccess, run.Status)
|
|
assert.Equal(m.t, actions_model.StatusRunning, priorStatus)
|
|
assert.Equal(m.t, m.lastRunID, lastRun.ID)
|
|
assert.Equal(m.t, actions_model.StatusCancelled, lastRun.Status)
|
|
case 4:
|
|
assert.Equal(m.t, m.runID, run.ID)
|
|
assert.Equal(m.t, actions_model.StatusSuccess, run.Status)
|
|
assert.Equal(m.t, actions_model.StatusRunning, priorStatus)
|
|
assert.Equal(m.t, m.lastRunID, lastRun.ID)
|
|
assert.Equal(m.t, actions_model.StatusSuccess, lastRun.Status)
|
|
default:
|
|
assert.Fail(m.t, "too many notifications")
|
|
}
|
|
m.lastRunID = m.runID
|
|
m.runID++
|
|
m.testIdx++
|
|
}
|
|
|
|
// ensure all tests have been run
|
|
func (m *mockNotifier) complete() {
|
|
assert.Equal(m.t, 5, m.testIdx)
|
|
}
|
|
|
|
func TestActionNowDoneNotification(t *testing.T) {
|
|
if !setting.Database.Type.IsSQLite3() {
|
|
t.Skip()
|
|
}
|
|
|
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
|
notifier := mockNotifier{t: t, testIdx: 0, lastRunID: -1, runID: -1}
|
|
notify_service.RegisterNotifier(¬ifier)
|
|
|
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
|
|
// create the repo
|
|
repo, sha, f := tests.CreateDeclarativeRepo(t, user2, "repo-workflow-dispatch",
|
|
[]unit_model.Type{unit_model.TypeActions}, nil,
|
|
[]*files_service.ChangeRepoFile{
|
|
{
|
|
Operation: "create",
|
|
TreePath: ".forgejo/workflows/dispatch.yml",
|
|
ContentReader: strings.NewReader(
|
|
"name: test\n" +
|
|
"on: [workflow_dispatch]\n" +
|
|
"jobs:\n" +
|
|
" test:\n" +
|
|
" runs-on: ubuntu-latest\n" +
|
|
" steps:\n" +
|
|
" - run: echo helloworld\n",
|
|
),
|
|
},
|
|
},
|
|
)
|
|
defer f()
|
|
|
|
gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, repo)
|
|
require.NoError(t, err)
|
|
defer gitRepo.Close()
|
|
|
|
workflow, err := actions_service.GetWorkflowFromCommit(gitRepo, "main", "dispatch.yml")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "refs/heads/main", workflow.Ref)
|
|
assert.Equal(t, sha, workflow.Commit.ID.String())
|
|
|
|
inputGetter := func(key string) string {
|
|
return ""
|
|
}
|
|
|
|
runner := newMockRunner()
|
|
runner.registerAsRepoRunner(t, user2.Name, repo.Name, "mock-runner", []string{"ubuntu-latest"})
|
|
|
|
// 0: first successful run
|
|
_, _, err = workflow.Dispatch(db.DefaultContext, inputGetter, repo, user2)
|
|
require.NoError(t, err)
|
|
task := runner.fetchTask(t)
|
|
runner.succeedAtTask(t, task)
|
|
|
|
// we can't differentiate different runs without a delay
|
|
time.Sleep(time.Millisecond * 2000)
|
|
|
|
// 1: failed run
|
|
_, _, err = workflow.Dispatch(db.DefaultContext, inputGetter, repo, user2)
|
|
require.NoError(t, err)
|
|
task = runner.fetchTask(t)
|
|
runner.failAtTask(t, task)
|
|
|
|
// we can't differentiate different runs without a delay
|
|
time.Sleep(time.Millisecond * 2000)
|
|
|
|
// 2: canceled run
|
|
_, _, err = workflow.Dispatch(db.DefaultContext, inputGetter, repo, user2)
|
|
require.NoError(t, err)
|
|
task = runner.fetchTask(t)
|
|
require.NoError(t, actions_service.StopTask(db.DefaultContext, task.Id, actions_model.StatusCancelled))
|
|
|
|
// we can't differentiate different runs without a delay
|
|
time.Sleep(time.Millisecond * 2000)
|
|
|
|
// 3: successful run after failure
|
|
_, _, err = workflow.Dispatch(db.DefaultContext, inputGetter, repo, user2)
|
|
require.NoError(t, err)
|
|
task = runner.fetchTask(t)
|
|
runner.succeedAtTask(t, task)
|
|
|
|
// we can't differentiate different runs without a delay
|
|
time.Sleep(time.Millisecond * 2000)
|
|
|
|
// 4: successful run after success
|
|
_, _, err = workflow.Dispatch(db.DefaultContext, inputGetter, repo, user2)
|
|
require.NoError(t, err)
|
|
task = runner.fetchTask(t)
|
|
runner.succeedAtTask(t, task)
|
|
|
|
notifier.complete()
|
|
})
|
|
}
|