...

Source file src/github.com/linkerd/linkerd2/testutil/test_helper_check.go

Documentation: github.com/linkerd/linkerd2/testutil

     1  package testutil
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/linkerd/linkerd2/pkg/healthcheck"
    12  	vizHealthcheck "github.com/linkerd/linkerd2/viz/pkg/healthcheck"
    13  )
    14  
    15  var preCategories = []healthcheck.CategoryID{
    16  	healthcheck.KubernetesAPIChecks,
    17  	healthcheck.KubernetesVersionChecks,
    18  	healthcheck.LinkerdPreInstallChecks,
    19  	healthcheck.LinkerdVersionChecks,
    20  }
    21  
    22  var coreCategories = []healthcheck.CategoryID{
    23  	healthcheck.KubernetesAPIChecks,
    24  	healthcheck.KubernetesVersionChecks,
    25  	healthcheck.LinkerdControlPlaneExistenceChecks,
    26  	healthcheck.LinkerdConfigChecks,
    27  	healthcheck.LinkerdIdentity,
    28  	healthcheck.LinkerdWebhooksAndAPISvcTLS,
    29  	healthcheck.LinkerdVersionChecks,
    30  	healthcheck.LinkerdControlPlaneProxyChecks,
    31  }
    32  
    33  var dataPlaneCategories = []healthcheck.CategoryID{
    34  	healthcheck.LinkerdIdentityDataPlane,
    35  	healthcheck.LinkerdControlPlaneProxyChecks,
    36  	healthcheck.LinkerdDataPlaneChecks,
    37  }
    38  
    39  // TestCheckPre runs validates the output of `linkerd check --pre`
    40  func (h *TestHelper) TestCheckPre() error {
    41  	cmd := []string{"check", "--pre", "--output", "json", "--wait", "5m"}
    42  	return h.testCheck(cmd, preCategories)
    43  }
    44  
    45  // TestCheck runs validates the output of `linkerd check`
    46  func (h *TestHelper) TestCheck(extraArgs ...string) error {
    47  	return h.TestCheckWith([]healthcheck.CategoryID{healthcheck.LinkerdControlPlaneVersionChecks, vizHealthcheck.LinkerdVizExtensionCheck}, extraArgs...)
    48  }
    49  
    50  // TestCheckWith validates the output of `linkerd check`. It will validate the
    51  // core categories and any additional categories that the caller provides.
    52  func (h *TestHelper) TestCheckWith(additional []healthcheck.CategoryID, extraArgs ...string) error {
    53  	cmd := []string{"check", "--output", "json", "--wait", "5m"}
    54  	cmd = append(cmd, extraArgs...)
    55  	categories := append(coreCategories, additional...)
    56  	return h.testCheck(cmd, categories)
    57  }
    58  
    59  // TestCheckProxy runs validates the output of `linkerd check --proxy`
    60  func (h *TestHelper) TestCheckProxy(expectedVersion, namespace string) error {
    61  	cmd := []string{"check", "--proxy", "--expected-version", expectedVersion,
    62  		"--namespace", namespace, "--output", "json", "--wait", "5m"}
    63  	categories := append(coreCategories, vizHealthcheck.LinkerdVizExtensionCheck,
    64  		vizHealthcheck.LinkerdVizExtensionDataPlaneCheck)
    65  	categories = append(categories, dataPlaneCategories...)
    66  	return h.testCheck(cmd, categories)
    67  }
    68  
    69  func (h *TestHelper) testCheck(cmd []string, categories []healthcheck.CategoryID) error {
    70  	timeout := time.Minute * 10
    71  	return RetryFor(timeout, func() error {
    72  		res, err := h.LinkerdRun(cmd...)
    73  		if err != nil {
    74  			return fmt.Errorf("'linkerd check' command failed\n%w\n%s", err, res)
    75  		}
    76  
    77  		returnedCats := map[healthcheck.CategoryID]struct{}{}
    78  
    79  		// We can't just use json.Unmarshal() because the check output is formatted as NDJSON
    80  		d := json.NewDecoder(strings.NewReader(res))
    81  		for {
    82  			var out healthcheck.CheckOutput
    83  			err := d.Decode(&out)
    84  			if err != nil {
    85  				// io.EOF is expected at end of stream.
    86  				if !errors.Is(err, io.EOF) {
    87  					return fmt.Errorf("error processing 'linkerd check' output: %w", err)
    88  				}
    89  				break
    90  			}
    91  
    92  			errs := []string{}
    93  			for _, cat := range out.Categories {
    94  				for _, check := range cat.Checks {
    95  					returnedCats[cat.Name] = struct{}{}
    96  					if check.Result == healthcheck.CheckErr {
    97  						errs = append(errs, fmt.Sprintf("%s: %s", cat.Name, check.Error))
    98  					}
    99  				}
   100  			}
   101  			if len(errs) > 0 {
   102  				return errors.New(strings.Join(errs, "\n"))
   103  			}
   104  		}
   105  
   106  		errs := []string{}
   107  		for _, cat := range categories {
   108  			if _, ok := returnedCats[cat]; !ok {
   109  				errs = append(errs, fmt.Sprintf("missing category '%s'", cat))
   110  			}
   111  		}
   112  		if len(errs) > 0 {
   113  			return errors.New(strings.Join(errs, "\n"))
   114  		}
   115  
   116  		return nil
   117  	})
   118  }
   119  

View as plain text