worker/server: add JobDependencyChainErrors() method

Add new `JobDependencyChainErrors()` method for gathering a stack trace
of job errors from the job's dependencies which caused it to fail.

The `JobDependencyChainErrors()` implementation uses job-type specific
`...Status()` methods intentionally, because job-type specific status
methods check the job's result in a slightly different way and set
the result.JobError to a specific value. Due to this reason, it would
not be practical to introduce a generic `JobStatus()` method and get rid
of the `switch` block, because in reality, the new method would have
to implement an equivalent `switch` block as well.

Add unit test covering the method functionality.
This commit is contained in:
Tomas Hozza 2022-05-24 13:59:16 +02:00 committed by Tom Gundersen
parent 5bd02f2f27
commit fa37005a32
2 changed files with 790 additions and 0 deletions

View file

@ -174,6 +174,94 @@ func (s *Server) CheckBuildDependencies(dep uuid.UUID, jobErr *clienterrors.Erro
return nil
}
// DependencyChainErrors recursively gathers all errors from job's dependencies,
// which caused it to fail. If the job didn't fail, `nil` is returned.
func (s *Server) JobDependencyChainErrors(id uuid.UUID) (*clienterrors.Error, error) {
jobType, err := s.JobType(id)
if err != nil {
return nil, err
}
var jobResult *JobResult
var jobDeps []uuid.UUID
switch jobType {
case JobTypeOSBuild:
var osbuildJR OSBuildJobResult
_, jobDeps, err = s.OSBuildJobStatus(id, &osbuildJR)
if err != nil {
return nil, err
}
jobResult = &osbuildJR.JobResult
case JobTypeDepsolve:
var depsolveJR DepsolveJobResult
_, jobDeps, err = s.DepsolveJobStatus(id, &depsolveJR)
if err != nil {
return nil, err
}
jobResult = &depsolveJR.JobResult
case JobTypeManifestIDOnly:
var manifestJR ManifestJobByIDResult
_, jobDeps, err = s.ManifestJobStatus(id, &manifestJR)
if err != nil {
return nil, err
}
jobResult = &manifestJR.JobResult
case JobTypeKojiInit:
var kojiInitJR KojiInitJobResult
_, jobDeps, err = s.KojiInitJobStatus(id, &kojiInitJR)
if err != nil {
return nil, err
}
jobResult = &kojiInitJR.JobResult
case JobTypeOSBuildKoji:
var osbuildKojiJR OSBuildKojiJobResult
_, jobDeps, err = s.OSBuildKojiJobStatus(id, &osbuildKojiJR)
if err != nil {
return nil, err
}
jobResult = &osbuildKojiJR.JobResult
case JobTypeKojiFinalize:
var kojiFinalizeJR KojiFinalizeJobResult
_, jobDeps, err = s.KojiFinalizeJobStatus(id, &kojiFinalizeJR)
if err != nil {
return nil, err
}
jobResult = &kojiFinalizeJR.JobResult
default:
return nil, fmt.Errorf("unexpected job type: %s", jobType)
}
if jobError := jobResult.JobError; jobError != nil {
depErrors := []*clienterrors.Error{}
if jobError.IsDependencyError() {
// check job's dependencies
for _, dep := range jobDeps {
depError, err := s.JobDependencyChainErrors(dep)
if err != nil {
return nil, err
}
if depError != nil {
depErrors = append(depErrors, depError)
}
}
}
if len(depErrors) > 0 {
jobError.Details = depErrors
}
return jobError, nil
}
return nil, nil
}
func (s *Server) OSBuildJobStatus(id uuid.UUID, result *OSBuildJobResult) (*JobStatus, []uuid.UUID, error) {
jobType, _, status, deps, err := s.jobStatus(id, result)
if err != nil {