...

Source file src/github.com/redhat-developer/odo/tests/helper/helper_run.go

Documentation: github.com/redhat-developer/odo/tests/helper

     1  package helper
     2  
     3  import (
     4  	"fmt"
     5  	"os/exec"
     6  	"path/filepath"
     7  	"strings"
     8  	"time"
     9  
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  	"github.com/onsi/gomega/gexec"
    13  	"github.com/onsi/gomega/types"
    14  
    15  	"github.com/redhat-developer/odo/pkg/labels"
    16  )
    17  
    18  const (
    19  	TelemetryCaller = "TELEMETRY_CALLER"
    20  )
    21  
    22  func runningCmd(cmd *exec.Cmd) string {
    23  	prog := filepath.Base(cmd.Path)
    24  	var env []string
    25  	for _, e := range cmd.Env {
    26  		if strings.HasPrefix(e, "ODO_") || e == TelemetryCaller {
    27  			env = append(env, e)
    28  		}
    29  	}
    30  	return fmt.Sprintf("Running %s with args %v and odo env: %v", prog, cmd.Args, env)
    31  }
    32  
    33  func CmdRunner(program string, args ...string) *gexec.Session {
    34  	// prefix ginkgo verbose output with program name
    35  	prefix := fmt.Sprintf("[%s] ", filepath.Base(program))
    36  	prefixWriter := gexec.NewPrefixedWriter(prefix, GinkgoWriter)
    37  	command := exec.Command(program, args...)
    38  	setSysProcAttr(command)
    39  	fmt.Fprintln(GinkgoWriter, runningCmd(command))
    40  	session, err := gexec.Start(command, prefixWriter, prefixWriter)
    41  	Expect(err).NotTo(HaveOccurred())
    42  	return session
    43  }
    44  
    45  // WaitForOutputToContain waits for the session stdout output to contain a particular substring;
    46  // if the session exits, it checks for the substring and returns early
    47  func WaitForOutputToContain(substring string, timeoutInSeconds int, intervalInSeconds int, session *gexec.Session) {
    48  	Eventually(func() string {
    49  		if session.ExitCode() != -1 {
    50  			Expect(string(session.Out.Contents())).To(ContainSubstring(substring), "session exited, but substring not found")
    51  		}
    52  		contents := string(session.Out.Contents())
    53  		return contents
    54  	}, timeoutInSeconds, intervalInSeconds).Should(ContainSubstring(substring))
    55  
    56  }
    57  
    58  func WaitForOutputToContainOne(substrings []string, timeoutInSeconds int, intervalInSeconds int, session *gexec.Session) {
    59  
    60  	matchers := make([]types.GomegaMatcher, 0, len(substrings))
    61  	for _, substring := range substrings {
    62  		matchers = append(matchers, ContainSubstring(substring))
    63  	}
    64  	Eventually(func() string {
    65  		if session.ExitCode() != -1 {
    66  			Expect(string(session.Out.Contents())).To(SatisfyAny(matchers...), "session exited, but substring not found")
    67  		}
    68  		contents := string(session.Out.Contents())
    69  		return contents
    70  	}, timeoutInSeconds, intervalInSeconds).Should(SatisfyAny(matchers...))
    71  }
    72  
    73  // WaitForErroutToContain waits for the session stdout output to contain a particular substring
    74  // if the session exits, it checks for the substring and returns early
    75  func WaitForErroutToContain(substring string, timeoutInSeconds int, intervalInSeconds int, session *gexec.Session) {
    76  
    77  	Eventually(func() string {
    78  		if session.ExitCode() != -1 {
    79  			Expect(string(session.Err.Contents())).To(ContainSubstring(substring), "session exited, but substring not found")
    80  		}
    81  		contents := string(session.Err.Contents())
    82  		return contents
    83  	}, timeoutInSeconds, intervalInSeconds).Should(ContainSubstring(substring))
    84  
    85  }
    86  
    87  // WaitAndCheckForTerminatingState waits for the given interval
    88  // and checks if the given resource type has been deleted on the cluster or is in the terminating state
    89  // path is the path to the program's binary
    90  func WaitAndCheckForTerminatingState(path, resourceType, namespace string, timeoutMinutes int) bool {
    91  	pingTimeout := time.After(time.Duration(timeoutMinutes) * time.Minute)
    92  	// this is a test package so time.Tick() is acceptable
    93  	// nolint
    94  	tick := time.Tick(time.Second)
    95  	for {
    96  		select {
    97  		case <-pingTimeout:
    98  			Fail(fmt.Sprintf("Timeout after %d minutes", timeoutMinutes))
    99  
   100  		case <-tick:
   101  			session := CmdRunner(path, "get", resourceType, "--namespace", namespace)
   102  			Eventually(session).Should(gexec.Exit(0))
   103  			// https://github.com/kubernetes/kubectl/issues/847
   104  			outputStdErr := string(session.Wait().Err.Contents())
   105  			outputStdOut := string(session.Wait().Out.Contents())
   106  
   107  			// if the resource gets deleted before the check, we won't get the `terminating` state output
   108  			// thus we also check and exit when the resource has been deleted on the cluster.
   109  			if strings.Contains(strings.ToLower(outputStdErr), "no resources found") || strings.Contains(strings.ToLower(outputStdOut), "terminating") {
   110  				return true
   111  			}
   112  		}
   113  	}
   114  }
   115  
   116  // GetAnnotationsDeployment gets the annotations from the deployment
   117  // belonging to the given component, app and project
   118  func GetAnnotationsDeployment(path, componentName, appName, projectName string) map[string]string {
   119  	var mapOutput = make(map[string]string)
   120  	selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag()
   121  	output := Cmd(path, "get", "deployment", selector, "--namespace", projectName,
   122  		"-o", "go-template='{{ range $k, $v := (index .items 0).metadata.annotations}}{{$k}}:{{$v}}{{\"\\n\"}}{{end}}'").ShouldPass().Out()
   123  
   124  	for _, line := range strings.Split(output, "\n") {
   125  		line = strings.TrimPrefix(line, "'")
   126  		splits := strings.Split(line, ":")
   127  		if len(splits) < 2 {
   128  			continue
   129  		}
   130  		name := splits[0]
   131  		value := strings.Join(splits[1:], ":")
   132  		mapOutput[name] = value
   133  	}
   134  	return mapOutput
   135  }
   136  
   137  // GetSecrets gets all the secrets belonging to the project
   138  func GetSecrets(path, project string) string {
   139  	session := CmdRunner(path, "get", "secrets", "--namespace", project)
   140  	Eventually(session).Should(gexec.Exit(0))
   141  	output := string(session.Wait().Out.Contents())
   142  	return output
   143  }
   144  
   145  // GetEnvRefNames gets the ref values from the envFroms of the deployment belonging to the given data
   146  func GetEnvRefNames(path, componentName, appName, projectName string) []string {
   147  	selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag()
   148  	output := Cmd(path, "get", "deployment", selector, "--namespace", projectName,
   149  		"-o", "jsonpath='{range .items[0].spec.template.spec.containers[0].envFrom[*]}{.secretRef.name}{\"\\n\"}{end}'").ShouldPass().Out()
   150  
   151  	var result []string
   152  	for _, line := range strings.Split(output, "\n") {
   153  		line = strings.TrimPrefix(line, "'")
   154  		result = append(result, strings.TrimSpace(line))
   155  	}
   156  	return result
   157  }
   158  
   159  // GetEnvFromEntry returns envFrom entry of the deployment
   160  func GetEnvFromEntry(path string, componentName string, appName string, projectName string) string {
   161  	envFromOut := Cmd(path, "get", "deployment", componentName+"-"+appName, "--namespace", projectName,
   162  		"-o", "jsonpath='{.spec.template.spec.containers[0].envFrom}'").ShouldPass().Out()
   163  	return strings.TrimSpace(envFromOut)
   164  }
   165  
   166  // GetVolumeNamesFromDeployment gets the volumes from the deployment belonging to the given data
   167  func GetVolumeNamesFromDeployment(path, componentName, appName, projectName string) map[string]string {
   168  	var mapOutput = make(map[string]string)
   169  	selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag()
   170  	output := Cmd(path, "get", "deployment", selector, "--namespace", projectName,
   171  		"-o", "jsonpath='{range .items[0].spec.template.spec.volumes[*]}{.name}{\":\"}{.persistentVolumeClaim.claimName}{\"\\n\"}{end}'").ShouldPass().Out()
   172  
   173  	for _, line := range strings.Split(output, "\n") {
   174  		line = strings.TrimPrefix(line, "'")
   175  		splits := strings.Split(line, ":")
   176  		if splits[0] == "" {
   177  			continue
   178  		}
   179  		name := splits[0]
   180  
   181  		// if there is no persistent volume claim for the volume
   182  		// we mark it as emptyDir
   183  		value := "emptyDir"
   184  		if len(splits) > 1 && splits[1] != "" {
   185  			value = splits[1]
   186  		}
   187  		mapOutput[name] = value
   188  	}
   189  	return mapOutput
   190  }
   191  

View as plain text