github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/internal/dep/dep.go (about)

     1  // Copyright 2020 The ChromiumOS Authors
     2  // Use of this source code is governed by a BSD-style license that can be
     3  // found in the LICENSE file.
     4  
     5  // Package dep deals with dependencies of tests.
     6  package dep
     7  
     8  import (
     9  	"fmt"
    10  	"regexp"
    11  	"strings"
    12  
    13  	"go.chromium.org/tast/core/errors"
    14  	"go.chromium.org/tast/core/internal/protocol"
    15  
    16  	frameworkprotocol "go.chromium.org/tast/core/framework/protocol"
    17  )
    18  
    19  // Deps contains all information about dependencies tests have.
    20  type Deps struct {
    21  	Test     string
    22  	Var      []string
    23  	Software map[string]SoftwareDeps
    24  	Hardware map[string]HardwareDeps
    25  }
    26  
    27  // Check performs dependency checks according to given features.
    28  // On success, it returns a list of reasons for which a test should be skipped.
    29  // If reasons is empty, a test should be run.
    30  func (d *Deps) Check(f *protocol.Features) (reasons []string, err error) {
    31  	if reason, skip := f.GetForceSkips()[d.Test]; skip {
    32  		return []string{reason.Reason}, nil
    33  	}
    34  
    35  	if !f.GetCheckDeps() {
    36  		return nil, nil
    37  	}
    38  
    39  	for role, swDep := range d.Software {
    40  		var dut *frameworkprotocol.DUTFeatures
    41  		if role != "" {
    42  			var valid bool
    43  			if dut, valid = f.GetCompanionFeatures()[role]; !valid {
    44  				continue
    45  			}
    46  		} else {
    47  			dut = f.GetDut()
    48  		}
    49  
    50  		missing, unknown := missingSoftwareDeps(swDep, dut.GetSoftware())
    51  
    52  		if len(unknown) > 0 {
    53  			return nil, errors.Errorf("unknown SoftwareDeps: %v", strings.Join(unknown, ", "))
    54  		}
    55  		if len(missing) > 0 {
    56  			reasons = append(reasons, fmt.Sprintf("missing SoftwareDeps: %s", strings.Join(missing, ", ")))
    57  		}
    58  	}
    59  
    60  	for role, hwDep := range d.Hardware {
    61  		var dut *frameworkprotocol.DUTFeatures
    62  		if role != "" {
    63  			var valid bool
    64  			dut, valid = f.GetCompanionFeatures()[role]
    65  			if !valid {
    66  				continue
    67  			}
    68  		} else {
    69  			dut = f.GetDut()
    70  		}
    71  
    72  		sat, err := hwDep.Satisfied(dut.GetHardware())
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  		for _, r := range sat {
    77  			reasons = append(reasons, r)
    78  		}
    79  	}
    80  
    81  	if len(reasons) != 0 {
    82  		return reasons, nil
    83  	}
    84  
    85  	// If f.MaybeMissingVars is empty, no variables are considered as missing.
    86  	maybeMissingVars, err := regexp.Compile("^" + f.GetInfra().GetMaybeMissingVars() + "$")
    87  	if err != nil {
    88  		return nil, errors.Errorf("regex %v is invalid: %v", f.GetInfra().GetMaybeMissingVars(), err)
    89  	}
    90  
    91  	vars := f.GetInfra().GetVars()
    92  	for _, v := range d.Var {
    93  		if _, ok := vars[v]; ok {
    94  			continue
    95  		}
    96  		if maybeMissingVars.MatchString(v) {
    97  			reasons = append(reasons, fmt.Sprintf("runtime variable %v is missing and matches with %v", v, maybeMissingVars))
    98  			continue
    99  		}
   100  		if f.GetInfra().GetMaybeMissingVars() == "" {
   101  			return nil, errors.Errorf("runtime variable %v is missing", v)
   102  		}
   103  		return nil, errors.Errorf("runtime variable %v is missing and doesn't match with %v", v, maybeMissingVars)
   104  	}
   105  
   106  	return reasons, nil
   107  }