Skip to content

Commit e038ed2

Browse files
committed
improve test
1 parent 25efcaa commit e038ed2

File tree

1 file changed

+120
-85
lines changed

1 file changed

+120
-85
lines changed

Diff for: tests/integration/actions_concurrency_test.go

+120-85
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package integration
22

33
import (
4+
"encoding/base64"
45
"fmt"
56
"net/http"
67
"net/url"
78
"slices"
89
"testing"
10+
"time"
911

1012
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
1113
actions_model "code.gitea.io/gitea/models/actions"
@@ -14,6 +16,7 @@ import (
1416
"code.gitea.io/gitea/models/unittest"
1517
user_model "code.gitea.io/gitea/models/user"
1618
api "code.gitea.io/gitea/modules/structs"
19+
"code.gitea.io/gitea/modules/util"
1720

1821
"github.com/stretchr/testify/assert"
1922
)
@@ -29,6 +32,7 @@ func TestWorkflowConcurrency_NoCancellation(t *testing.T) {
2932
runner := newMockRunner()
3033
runner.registerAsRepoRunner(t, user2.Name, repo.Name, "mock-runner", []string{"ubuntu-latest"})
3134

35+
// add a variable for test
3236
req := NewRequestWithJSON(t, "POST",
3337
fmt.Sprintf("/api/v1/repos/%s/%s/actions/variables/qwe", user2.Name, repo.Name), &api.CreateVariableOption{
3438
Value: "abc123",
@@ -87,11 +91,9 @@ jobs:
8791

8892
// fetch and exec workflow1, workflow2 and workflow3 are blocked
8993
task := runner.fetchTask(t)
90-
actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: task.Id})
91-
actionRunJob := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask.JobID})
92-
actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob.RunID})
93-
assert.Equal(t, "workflow-main-abc123", actionRun.ConcurrencyGroup)
94-
assert.Equal(t, "concurrent-workflow-1.yml", actionRun.WorkflowID)
94+
_, _, run := getTaskAndJobAndRunByTaskID(t, task.Id)
95+
assert.Equal(t, "workflow-main-abc123", run.ConcurrencyGroup)
96+
assert.Equal(t, "concurrent-workflow-1.yml", run.WorkflowID)
9597
runner.fetchNoTask(t)
9698
runner.execTask(t, task, &mockTaskOutcome{
9799
result: runnerv1.Result_RESULT_SUCCESS,
@@ -100,24 +102,20 @@ jobs:
100102
// fetch workflow2 or workflow3
101103
workflowNames := []string{"concurrent-workflow-2.yml", "concurrent-workflow-3.yml"}
102104
task = runner.fetchTask(t)
103-
actionTask = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: task.Id})
104-
actionRunJob = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask.JobID})
105-
actionRun = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob.RunID})
106-
assert.Contains(t, workflowNames, actionRun.WorkflowID)
107-
workflowNames = slices.DeleteFunc(workflowNames, func(wfn string) bool { return wfn == actionRun.WorkflowID })
108-
assert.Equal(t, "workflow-main-abc123", actionRun.ConcurrencyGroup)
105+
_, _, run = getTaskAndJobAndRunByTaskID(t, task.Id)
106+
assert.Contains(t, workflowNames, run.WorkflowID)
107+
workflowNames = slices.DeleteFunc(workflowNames, func(wfn string) bool { return wfn == run.WorkflowID })
108+
assert.Equal(t, "workflow-main-abc123", run.ConcurrencyGroup)
109109
runner.fetchNoTask(t)
110110
runner.execTask(t, task, &mockTaskOutcome{
111111
result: runnerv1.Result_RESULT_SUCCESS,
112112
})
113113

114114
// fetch the last workflow (workflow2 or workflow3)
115115
task = runner.fetchTask(t)
116-
actionTask = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: task.Id})
117-
actionRunJob = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask.JobID})
118-
actionRun = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob.RunID})
119-
assert.Equal(t, "workflow-main-abc123", actionRun.ConcurrencyGroup)
120-
assert.Equal(t, workflowNames[0], actionRun.WorkflowID)
116+
_, _, run = getTaskAndJobAndRunByTaskID(t, task.Id)
117+
assert.Equal(t, "workflow-main-abc123", run.ConcurrencyGroup)
118+
assert.Equal(t, workflowNames[0], run.WorkflowID)
121119
runner.fetchNoTask(t)
122120
runner.execTask(t, task, &mockTaskOutcome{
123121
result: runnerv1.Result_RESULT_SUCCESS,
@@ -130,84 +128,121 @@ jobs:
130128

131129
func TestWorkflowConcurrency_WithCancellation(t *testing.T) {
132130
onGiteaRun(t, func(t *testing.T, u *url.URL) {
131+
// user2 is the owner of the base repo
133132
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
134-
session := loginUser(t, user2.Name)
135-
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
133+
user2Session := loginUser(t, user2.Name)
134+
user2Token := getTokenForLoggedInUser(t, user2Session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
135+
// user4 is the owner of the forked repo
136+
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
137+
user4Token := getTokenForLoggedInUser(t, loginUser(t, user4.Name), auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
136138

137-
apiRepo := createActionsTestRepo(t, token, "actions-concurrency", false)
138-
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID})
139-
runner := newMockRunner()
140-
runner.registerAsRepoRunner(t, user2.Name, repo.Name, "mock-runner", []string{"ubuntu-latest"})
139+
apiBaseRepo := createActionsTestRepo(t, user2Token, "actions-concurrency", false)
140+
baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiBaseRepo.ID})
141+
user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository)
141142

142-
req := NewRequestWithJSON(t, "POST",
143-
fmt.Sprintf("/api/v1/repos/%s/%s/actions/variables/qwe", user2.Name, repo.Name), &api.CreateVariableOption{
144-
Value: "abc123",
145-
}).
146-
AddTokenAuth(token)
147-
MakeRequest(t, req, http.StatusNoContent)
143+
runner := newMockRunner()
144+
runner.registerAsRepoRunner(t, baseRepo.OwnerName, baseRepo.Name, "mock-runner", []string{"ubuntu-latest"})
148145

149-
wf1TreePath := ".gitea/workflows/concurrent-workflow-1.yml"
150-
wf1FileContent := `name: concurrent-workflow-1
151-
on:
152-
push:
153-
paths:
154-
- '.gitea/workflows/concurrent-workflow-1.yml'
146+
// init the workflow
147+
wfTreePath := ".gitea/workflows/pull.yml"
148+
wfFileContent := `name: Pull Request
149+
on: pull_request
155150
concurrency:
156-
group: workflow-main-abc123
151+
group: pull-request-test
152+
cancel-in-progress: ${{ !startsWith(github.ref_name, 'dev-pub/') }}
157153
jobs:
158154
wf1-job:
159155
runs-on: ubuntu-latest
160156
steps:
161-
- run: echo 'job from workflow1'
157+
- run: echo 'test the pull'
162158
`
163-
wf2TreePath := ".gitea/workflows/concurrent-workflow-2.yml"
164-
wf2FileContent := `name: concurrent-workflow-2
165-
on:
166-
push:
167-
paths:
168-
- '.gitea/workflows/concurrent-workflow-2.yml'
169-
concurrency:
170-
group: workflow-${{ github.ref_name }}-${{ vars.qwe }}
171-
cancel-in-progress: ${{ github.ref_name == 'main' }}
172-
jobs:
173-
wf2-job:
174-
runs-on: ubuntu-latest
175-
steps:
176-
- run: echo 'job from workflow2'
177-
`
178-
179-
// push workflow1
180-
opts1 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, fmt.Sprintf("create %s", wf1TreePath), wf1FileContent)
181-
createWorkflowFile(t, token, user2.Name, repo.Name, wf1TreePath, opts1)
182-
// fetch the task of workflow1
183-
task1 := runner.fetchTask(t)
184-
actionTask1 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: task1.Id})
185-
actionRunJob1 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask1.JobID})
186-
actionRun1 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob1.RunID})
187-
assert.Equal(t, "workflow-main-abc123", actionRun1.ConcurrencyGroup)
188-
assert.Equal(t, "concurrent-workflow-1.yml", actionRun1.WorkflowID)
189-
assert.False(t, actionRun1.ConcurrencyCancel)
190-
assert.True(t, actionRun1.Status.IsRunning())
191-
192-
// push workflow2
193-
opts2 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, fmt.Sprintf("create %s", wf2TreePath), wf2FileContent)
194-
createWorkflowFile(t, token, user2.Name, repo.Name, wf2TreePath, opts2)
195-
// fetch the task of workflow2
196-
task2 := runner.fetchTask(t)
197-
actionTask2 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: task2.Id})
198-
actionRunJob2 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask2.JobID})
199-
actionRun2 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob2.RunID})
200-
assert.Equal(t, "workflow-main-abc123", actionRun2.ConcurrencyGroup)
201-
assert.Equal(t, "concurrent-workflow-2.yml", actionRun2.WorkflowID)
202-
assert.True(t, actionRun2.ConcurrencyCancel)
203-
assert.True(t, actionRun2.Status.IsRunning())
204-
205-
// after pushing workflow2, the status of the run of workflow1 should be "cancelled"
206-
// fetch the last workflow (workflow2 or workflow3)
207-
actionRun1 = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob1.RunID})
208-
assert.True(t, actionRun1.Status.IsCancelled())
209-
210-
httpContext := NewAPITestContext(t, user2.Name, repo.Name, auth_model.AccessTokenScopeWriteRepository)
211-
doAPIDeleteRepository(httpContext)(t)
159+
opts1 := getWorkflowCreateFileOptions(user2, baseRepo.DefaultBranch, fmt.Sprintf("create %s", wfTreePath), wfFileContent)
160+
createWorkflowFile(t, user2Token, baseRepo.OwnerName, baseRepo.Name, wfTreePath, opts1)
161+
// user2 creates a pull request
162+
doAPICreateFile(user2APICtx, "user2-fix.txt", &api.CreateFileOptions{
163+
FileOptions: api.FileOptions{
164+
NewBranchName: "bugfix/aaa",
165+
Message: "create user2-fix.txt",
166+
Author: api.Identity{
167+
Name: user4.Name,
168+
Email: user4.Email,
169+
},
170+
Committer: api.Identity{
171+
Name: user4.Name,
172+
Email: user4.Email,
173+
},
174+
Dates: api.CommitDateOptions{
175+
Author: time.Now(),
176+
Committer: time.Now(),
177+
},
178+
},
179+
ContentBase64: base64.StdEncoding.EncodeToString([]byte("user2-fix")),
180+
})(t)
181+
doAPICreatePullRequest(user2APICtx, baseRepo.OwnerName, baseRepo.Name, baseRepo.DefaultBranch, "bugfix/aaa")(t)
182+
pr1Task1 := runner.fetchTask(t)
183+
_, _, pr1Run1 := getTaskAndJobAndRunByTaskID(t, pr1Task1.Id)
184+
assert.Equal(t, "pull-request-test", pr1Run1.ConcurrencyGroup)
185+
assert.True(t, pr1Run1.ConcurrencyCancel)
186+
assert.True(t, pr1Run1.Status.IsRunning())
187+
188+
// user4 forks the repo
189+
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/forks", baseRepo.OwnerName, baseRepo.Name),
190+
&api.CreateForkOption{
191+
Name: util.ToPointer("actions-concurrency-fork"),
192+
}).AddTokenAuth(user4Token)
193+
resp := MakeRequest(t, req, http.StatusAccepted)
194+
var apiForkRepo api.Repository
195+
DecodeJSON(t, resp, &apiForkRepo)
196+
forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiForkRepo.ID})
197+
user4APICtx := NewAPITestContext(t, user4.Name, forkRepo.Name, auth_model.AccessTokenScopeWriteRepository)
198+
// user4 creates a pull request
199+
doAPICreateFile(user4APICtx, "user4-fix.txt", &api.CreateFileOptions{
200+
FileOptions: api.FileOptions{
201+
NewBranchName: "bugfix/bbb",
202+
Message: "create user4-fix.txt",
203+
Author: api.Identity{
204+
Name: user4.Name,
205+
Email: user4.Email,
206+
},
207+
Committer: api.Identity{
208+
Name: user4.Name,
209+
Email: user4.Email,
210+
},
211+
Dates: api.CommitDateOptions{
212+
Author: time.Now(),
213+
Committer: time.Now(),
214+
},
215+
},
216+
ContentBase64: base64.StdEncoding.EncodeToString([]byte("user4-fix")),
217+
})(t)
218+
doAPICreatePullRequest(user4APICtx, baseRepo.OwnerName, baseRepo.Name, baseRepo.DefaultBranch, fmt.Sprintf("%s:bugfix/bbb", user4.Name))(t)
219+
// cannot fetch the task because an approval is required
220+
runner.fetchNoTask(t)
221+
// user2 approves the run
222+
pr2Run1 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{RepoID: baseRepo.ID, TriggerUserID: user4.ID})
223+
req = NewRequestWithValues(t, "POST",
224+
fmt.Sprintf("/%s/%s/actions/runs/%d/approve", baseRepo.OwnerName, baseRepo.Name, pr2Run1.Index),
225+
map[string]string{
226+
"_csrf": GetUserCSRFToken(t, user2Session),
227+
})
228+
user2Session.MakeRequest(t, req, http.StatusOK)
229+
// fetch the task and the previous task has been cancelled
230+
runner.fetchTask(t)
231+
pr2Run1 = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: pr2Run1.ID})
232+
assert.Equal(t, "pull-request-test", pr2Run1.ConcurrencyGroup)
233+
assert.True(t, pr2Run1.ConcurrencyCancel)
234+
assert.True(t, pr2Run1.Status.IsRunning())
235+
pr1Run1 = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: pr1Run1.ID})
236+
assert.True(t, pr1Run1.Status.IsCancelled())
237+
238+
doAPIDeleteRepository(user4APICtx)(t)
239+
doAPIDeleteRepository(user2APICtx)(t)
212240
})
213241
}
242+
243+
func getTaskAndJobAndRunByTaskID(t *testing.T, taskID int64) (*actions_model.ActionTask, *actions_model.ActionRunJob, *actions_model.ActionRun) {
244+
actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: taskID})
245+
actionRunJob := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask.JobID})
246+
actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob.RunID})
247+
return actionTask, actionRunJob, actionRun
248+
}

0 commit comments

Comments
 (0)