Skip to content

Commit 8f0c042

Browse files
committed
TestWorkflowAndJobConcurrency
1 parent 5932c14 commit 8f0c042

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

tests/integration/actions_concurrency_test.go

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,178 @@ jobs:
593593
})
594594
}
595595

596+
func TestWorkflowAndJobConcurrency(t *testing.T) {
597+
onGiteaRun(t, func(t *testing.T, u *url.URL) {
598+
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
599+
session := loginUser(t, user2.Name)
600+
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
601+
602+
apiRepo := createActionsTestRepo(t, token, "actions-concurrency", false)
603+
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID})
604+
runner1 := newMockRunner()
605+
runner1.registerAsRepoRunner(t, user2.Name, repo.Name, "mock-runner-1", []string{"runner1"})
606+
runner2 := newMockRunner()
607+
runner2.registerAsRepoRunner(t, user2.Name, repo.Name, "mock-runner-2", []string{"runner2"})
608+
runner3 := newMockRunner()
609+
runner3.registerAsRepoRunner(t, user2.Name, repo.Name, "mock-runner-3", []string{"runner3"})
610+
611+
wf1TreePath := ".gitea/workflows/concurrent-workflow-1.yml"
612+
wf1FileContent := `name: concurrent-workflow-1
613+
on:
614+
push:
615+
paths:
616+
- '.gitea/workflows/concurrent-workflow-1.yml'
617+
concurrency:
618+
group: workflow-group-1
619+
jobs:
620+
wf1-job1:
621+
runs-on: runner1
622+
concurrency:
623+
group: job-group-1
624+
steps:
625+
- run: echo 'wf1-job1'
626+
wf1-job2:
627+
runs-on: runner2
628+
concurrency:
629+
group: job-group-2
630+
steps:
631+
- run: echo 'wf1-job2'
632+
`
633+
wf2TreePath := ".gitea/workflows/concurrent-workflow-2.yml"
634+
wf2FileContent := `name: concurrent-workflow-2
635+
on:
636+
push:
637+
paths:
638+
- '.gitea/workflows/concurrent-workflow-2.yml'
639+
concurrency:
640+
group: workflow-group-1
641+
jobs:
642+
wf2-job1:
643+
runs-on: runner1
644+
concurrency:
645+
group: job-group-1
646+
steps:
647+
- run: echo 'wf2-job2'
648+
wf2-job2:
649+
runs-on: runner2
650+
concurrency:
651+
group: job-group-2
652+
steps:
653+
- run: echo 'wf2-job2'
654+
`
655+
wf3TreePath := ".gitea/workflows/concurrent-workflow-3.yml"
656+
wf3FileContent := `name: concurrent-workflow-3
657+
on:
658+
push:
659+
paths:
660+
- '.gitea/workflows/concurrent-workflow-3.yml'
661+
concurrency:
662+
group: workflow-group-2
663+
jobs:
664+
wf3-job1:
665+
runs-on: runner1
666+
concurrency:
667+
group: job-group-1
668+
steps:
669+
- run: echo 'wf3-job1'
670+
`
671+
672+
wf4TreePath := ".gitea/workflows/concurrent-workflow-4.yml"
673+
wf4FileContent := `name: concurrent-workflow-4
674+
on:
675+
push:
676+
paths:
677+
- '.gitea/workflows/concurrent-workflow-4.yml'
678+
concurrency:
679+
group: workflow-group-2
680+
jobs:
681+
wf4-job1:
682+
runs-on: runner2
683+
concurrency:
684+
group: job-group-2
685+
cancel-in-progress: true
686+
steps:
687+
- run: echo 'wf4-job1'
688+
`
689+
690+
// push workflow 1, 2 and 3
691+
opts1 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, fmt.Sprintf("create %s", wf1TreePath), wf1FileContent)
692+
createWorkflowFile(t, token, user2.Name, repo.Name, wf1TreePath, opts1)
693+
opts2 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, fmt.Sprintf("create %s", wf2TreePath), wf2FileContent)
694+
createWorkflowFile(t, token, user2.Name, repo.Name, wf2TreePath, opts2)
695+
opts3 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, fmt.Sprintf("create %s", wf3TreePath), wf3FileContent)
696+
createWorkflowFile(t, token, user2.Name, repo.Name, wf3TreePath, opts3)
697+
// fetch wf1-job1 and wf1-job2
698+
w1j1Task := runner1.fetchTask(t)
699+
w1j2Task := runner2.fetchTask(t)
700+
// cannot fetch wf2-job1 and wf2-job2 because workflow-2 is blocked by workflow-1's concurrency group "workflow-group-1"
701+
// cannot fetch wf3-job1 because it is blocked by wf1-job1's concurrency group "job-group-1"
702+
runner1.fetchNoTask(t)
703+
runner2.fetchNoTask(t)
704+
_, w1j1Job, w1Run := getTaskAndJobAndRunByTaskID(t, w1j1Task.Id)
705+
assert.Equal(t, "job-group-1", w1j1Job.ConcurrencyGroup)
706+
assert.Equal(t, "workflow-group-1", w1Run.ConcurrencyGroup)
707+
assert.Equal(t, "concurrent-workflow-1.yml", w1Run.WorkflowID)
708+
_, w1j2Job, _ := getTaskAndJobAndRunByTaskID(t, w1j2Task.Id)
709+
assert.Equal(t, "job-group-2", w1j2Job.ConcurrencyGroup)
710+
// exec wf1-job1
711+
runner1.execTask(t, w1j1Task, &mockTaskOutcome{
712+
result: runnerv1.Result_RESULT_SUCCESS,
713+
})
714+
// fetch wf3-job1
715+
w3j1Task := runner1.fetchTask(t)
716+
// cannot fetch wf2-job1 and wf2-job2 because workflow-2 is blocked by workflow-1's concurrency group "workflow-group-1"
717+
runner1.fetchNoTask(t)
718+
runner2.fetchNoTask(t)
719+
_, w3j1Job, w3Run := getTaskAndJobAndRunByTaskID(t, w3j1Task.Id)
720+
assert.Equal(t, "job-group-1", w3j1Job.ConcurrencyGroup)
721+
assert.Equal(t, "workflow-group-2", w3Run.ConcurrencyGroup)
722+
assert.Equal(t, "concurrent-workflow-3.yml", w3Run.WorkflowID)
723+
// push workflow-4
724+
opts4 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, fmt.Sprintf("create %s", wf4TreePath), wf4FileContent)
725+
createWorkflowFile(t, token, user2.Name, repo.Name, wf4TreePath, opts4)
726+
// exec wf1-job2
727+
runner2.execTask(t, w1j2Task, &mockTaskOutcome{
728+
result: runnerv1.Result_RESULT_SUCCESS,
729+
})
730+
// wf2-job2
731+
w2j2Task := runner2.fetchTask(t)
732+
// cannot fetch wf2-job1 because it is blocked by wf3-job1's concurrency group "job-group-1"
733+
// cannot fetch wf4-job1 because it is blocked by workflow-3's concurrency group "workflow-group-2"
734+
runner1.fetchNoTask(t)
735+
runner2.fetchNoTask(t)
736+
_, w2j2Job, w2Run := getTaskAndJobAndRunByTaskID(t, w2j2Task.Id)
737+
assert.Equal(t, "job-group-2", w2j2Job.ConcurrencyGroup)
738+
assert.Equal(t, "workflow-group-1", w2Run.ConcurrencyGroup)
739+
assert.Equal(t, "concurrent-workflow-2.yml", w2Run.WorkflowID)
740+
// exec wf3-job1
741+
runner1.execTask(t, w3j1Task, &mockTaskOutcome{
742+
result: runnerv1.Result_RESULT_SUCCESS,
743+
})
744+
// fetch wf2-job1
745+
w2j1Task := runner1.fetchTask(t)
746+
// fetch wf4-job1
747+
w4j1Task := runner2.fetchTask(t)
748+
// all tasks have been fetched
749+
runner1.fetchNoTask(t)
750+
runner2.fetchNoTask(t)
751+
_, w2j1Job, _ := getTaskAndJobAndRunByTaskID(t, w2j1Task.Id)
752+
assert.Equal(t, "job-group-1", w2j1Job.ConcurrencyGroup)
753+
assert.Equal(t, actions_model.StatusRunning, w2j2Job.Status)
754+
_, w2j2Job, w2Run = getTaskAndJobAndRunByTaskID(t, w2j2Task.Id)
755+
// wf2-job2 is cancelled because wf4-job1's cancel-in-progress is true
756+
assert.Equal(t, actions_model.StatusCancelled, w2j2Job.Status)
757+
assert.Equal(t, actions_model.StatusCancelled, w2Run.Status)
758+
_, w4j1Job, w4Run := getTaskAndJobAndRunByTaskID(t, w4j1Task.Id)
759+
assert.Equal(t, "job-group-2", w4j1Job.ConcurrencyGroup)
760+
assert.Equal(t, "workflow-group-2", w4Run.ConcurrencyGroup)
761+
assert.Equal(t, "concurrent-workflow-4.yml", w4Run.WorkflowID)
762+
763+
httpContext := NewAPITestContext(t, user2.Name, repo.Name, auth_model.AccessTokenScopeWriteRepository)
764+
doAPIDeleteRepository(httpContext)(t)
765+
})
766+
}
767+
596768
func getTaskAndJobAndRunByTaskID(t *testing.T, taskID int64) (*actions_model.ActionTask, *actions_model.ActionRunJob, *actions_model.ActionRun) {
597769
actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: taskID})
598770
actionRunJob := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask.JobID})

0 commit comments

Comments
 (0)