1 package helper
2
3 import (
4 "bufio"
5 "context"
6 "encoding/json"
7 "fmt"
8 "os"
9 "path/filepath"
10 "regexp"
11 "runtime"
12 "strconv"
13 "strings"
14 "testing"
15 "time"
16
17 "github.com/onsi/gomega/types"
18
19 "github.com/tidwall/gjson"
20
21 "github.com/redhat-developer/odo/pkg/config"
22 envcontext "github.com/redhat-developer/odo/pkg/config/context"
23 "github.com/redhat-developer/odo/pkg/preference"
24 "github.com/redhat-developer/odo/pkg/segment"
25 "github.com/redhat-developer/odo/tests/helper/registry_server"
26
27 dfutil "github.com/devfile/library/v2/pkg/util"
28
29 . "github.com/onsi/ginkgo/v2"
30 . "github.com/onsi/gomega"
31 "github.com/onsi/gomega/gexec"
32 )
33
34
35 func RandString(n int) string {
36 return dfutil.GenerateRandomString(n)
37 }
38
39
40
41
42
43
44
45
46
47
48 func WaitForCmdOut(program string, args []string, timeoutInMinutes int, errOnFail bool, check func(output string) bool, includeStdErr ...bool) bool {
49 pingTimeout := time.After(time.Duration(timeoutInMinutes) * time.Minute)
50
51
52 tick := time.Tick(time.Second)
53 for {
54 select {
55 case <-pingTimeout:
56 Fail(fmt.Sprintf("Timeout after %v minutes", timeoutInMinutes))
57
58 case <-tick:
59 session := CmdRunner(program, args...)
60 if errOnFail {
61 Eventually(session).Should(gexec.Exit(0), runningCmd(session.Command))
62 } else {
63 Eventually(session).Should(gexec.Exit(), runningCmd(session.Command))
64 }
65 session.Wait()
66 output := string(session.Out.Contents())
67
68 if len(includeStdErr) > 0 && includeStdErr[0] {
69 output += "\n"
70 output += string(session.Err.Contents())
71 }
72 if check(strings.TrimSpace(output)) {
73 return true
74 }
75 }
76 }
77 }
78
79
80 func MatchAllInOutput(output string, tomatch []string) {
81 for _, i := range tomatch {
82 Expect(output).To(ContainSubstring(i))
83 }
84 }
85
86
87 func DontMatchAllInOutput(output string, tonotmatch []string) {
88 for _, i := range tonotmatch {
89 Expect(output).ToNot(ContainSubstring(i))
90 }
91 }
92
93
94 func Unindented(jsonStr string) (string, error) {
95 var tmpMap map[string]interface{}
96 err := json.Unmarshal([]byte(jsonStr), &tmpMap)
97 if err != nil {
98 return "", err
99 }
100
101 obj, err := json.Marshal(tmpMap)
102 if err != nil {
103 return "", err
104 }
105 return string(obj), err
106 }
107
108
109 func ExtractLines(output string) ([]string, error) {
110 scanner := bufio.NewScanner(strings.NewReader(output))
111 lines := make([]string, 0)
112 for scanner.Scan() {
113 lines = append(lines, scanner.Text())
114 }
115 return lines, scanner.Err()
116 }
117
118
119 func FindFirstElementIndexByPredicate(slice []string, predicate func(string) bool) (int, bool) {
120 for i, s := range slice {
121 if predicate(s) {
122 return i, true
123 }
124 }
125 return 0, false
126 }
127
128
129
130 func FindFirstElementIndexMatchingRegExp(slice []string, regularExpression string) (int, bool) {
131 return FindFirstElementIndexByPredicate(slice, func(s string) bool {
132 matched, err := regexp.MatchString(regularExpression, s)
133 Expect(err).To(BeNil(), func() string {
134 return fmt.Sprintf("regular expression error: %v", err)
135 })
136 return matched
137 })
138 }
139
140
141 func GetUserHomeDir() string {
142 homeDir, err := os.UserHomeDir()
143 Expect(err).NotTo(HaveOccurred())
144 return homeDir
145 }
146
147
148 func LocalKubeconfigSet(context string) {
149 originalKubeCfg := os.Getenv("KUBECONFIG")
150 if originalKubeCfg == "" {
151 homeDir := GetUserHomeDir()
152 originalKubeCfg = filepath.Join(homeDir, ".kube", "config")
153 }
154 copyKubeConfigFile(originalKubeCfg, filepath.Join(context, "config"))
155 }
156
157
158 func GetCliRunner() CliRunner {
159 if IsKubernetesCluster() {
160 return NewKubectlRunner("kubectl")
161 }
162 return NewOcRunner("oc")
163 }
164
165
166 func IsJSON(s string) bool {
167 var js interface{}
168 return json.Unmarshal([]byte(s), &js) == nil
169 }
170
171 type CommonVar struct {
172
173 Project string
174
175 Context string
176
177 ConfigDir string
178
179 CliRunner CliRunner
180
181 OriginalWorkingDirectory string
182 OriginalKubeconfig string
183 registryServer RegistryServer
184 registryUrl string
185
186 testFileName string
187 testCase string
188 testFailed bool
189 testDuration float64
190 }
191
192
193
194 func CommonBeforeEach() CommonVar {
195 SetDefaultEventuallyTimeout(10 * time.Minute)
196 SetDefaultConsistentlyDuration(30 * time.Second)
197
198 commonVar := CommonVar{}
199 commonVar.Context = CreateNewContext()
200 commonVar.ConfigDir = CreateNewContext()
201 commonVar.CliRunner = GetCliRunner()
202 commonVar.OriginalKubeconfig = os.Getenv("KUBECONFIG")
203 specLabels := CurrentSpecReport().Labels()
204 if NeedsCluster(specLabels) {
205 LocalKubeconfigSet(commonVar.ConfigDir)
206 if IsAuth(specLabels) {
207 commonVar.Project = commonVar.CliRunner.CreateAndSetRandNamespaceProject()
208 } else {
209 commonVar.CliRunner.AssertNonAuthenticated()
210 }
211 } else {
212
213 os.Unsetenv("KUBERNETES_SERVICE_HOST")
214
215 kubeconfig, err := os.CreateTemp(commonVar.ConfigDir, "kubeconfig")
216 Expect(err).To(BeNil())
217 err = kubeconfig.Close()
218 Expect(err).To(BeNil())
219 os.Setenv("KUBECONFIG", kubeconfig.Name())
220
221 if NeedsPodman(specLabels) {
222 originalPodmanCmdInitTimeout, present := os.LookupEnv("PODMAN_CMD_INIT_TIMEOUT")
223 DeferCleanup(func() {
224 var resetErr error
225 if present {
226 resetErr = os.Setenv("PODMAN_CMD_INIT_TIMEOUT", originalPodmanCmdInitTimeout)
227 } else {
228 resetErr = os.Unsetenv("PODMAN_CMD_INIT_TIMEOUT")
229 }
230 Expect(resetErr).ShouldNot(HaveOccurred())
231 })
232 Expect(os.Setenv("PODMAN_CMD_INIT_TIMEOUT", "30s")).ShouldNot(HaveOccurred())
233
234
235 GenerateAndSetContainersConf(commonVar.ConfigDir)
236 }
237 }
238 commonVar.OriginalWorkingDirectory = Getwd()
239 Chdir(commonVar.Context)
240
241 configPath := filepath.Join(commonVar.ConfigDir, "preference.yaml")
242 os.Setenv("GLOBALODOCONFIG", configPath)
243
244
245 ctx := context.Background()
246 envConfig, err := config.GetConfiguration()
247 Expect(err).To(BeNil())
248 ctx = envcontext.WithEnvConfig(ctx, *envConfig)
249
250
251 cfg, _ := preference.NewClient(ctx)
252 err = cfg.SetConfiguration(preference.ConsentTelemetrySetting, "false")
253 Expect(err).To(BeNil())
254
255
256 err = cfg.SetConfiguration(preference.UpdateNotificationSetting, "false")
257 Expect(err).To(BeNil())
258
259
260 err = cfg.SetConfiguration(preference.EphemeralSetting, "true")
261 Expect(err).To(BeNil())
262 SetDefaultDevfileRegistry(&commonVar)
263 return commonVar
264 }
265
266
267 func CommonAfterEach(commonVar CommonVar) {
268
269
270 commonVar.testFileName = CurrentSpecReport().ContainerHierarchyLocations[0].FileName
271 commonVar.testCase = CurrentSpecReport().FullText()
272 commonVar.testFailed = CurrentSpecReport().Failed()
273 commonVar.testDuration = CurrentSpecReport().RunTime.Seconds()
274
275 var prNum string
276 var resultsRow string
277 prNum = os.Getenv("GIT_PR_NUMBER")
278 passedOrFailed := "PASSED"
279 if commonVar.testFailed {
280 passedOrFailed = "FAILED"
281 }
282 clusterType := "OCP"
283 if IsKubernetesCluster() {
284 clusterType = "KUBERNETES"
285 }
286 testDate := strings.Split(time.Now().Format(time.RFC3339), "T")[0]
287 resultsRow = prNum + "," + testDate + "," + clusterType + "," + commonVar.testFileName + "," + commonVar.testCase + "," + passedOrFailed + "," + strconv.FormatFloat(commonVar.testDuration, 'E', -1, 64) + "\n"
288 testResultsFile := filepath.Join("/", "tmp", "testResults.txt")
289 if runtime.GOOS == "windows" {
290 testResultsFile = filepath.Join(os.Getenv("TEMP"), "testResults.txt")
291 }
292 f, err := os.OpenFile(testResultsFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
293 if err != nil {
294 fmt.Println("Error when opening file: ", err)
295 } else {
296 _, err = f.WriteString(resultsRow)
297 if err != nil {
298 fmt.Println("Error when writing to file: ", err)
299 }
300 if err = f.Close(); err != nil {
301 fmt.Println("Error when closing file: ", err)
302 }
303 }
304
305 if commonVar.registryServer != nil {
306 err = commonVar.registryServer.Stop()
307 if err != nil {
308 fmt.Fprintf(GinkgoWriter, "[warn] failed to stop mock registry server at %q: %v\n", commonVar.registryServer.GetUrl(), err)
309 }
310 commonVar.registryServer = nil
311 commonVar.registryUrl = ""
312 }
313
314 if commonVar.Project != "" && commonVar.CliRunner.HasNamespaceProject(commonVar.Project) {
315
316 commonVar.CliRunner.DeleteNamespaceProject(commonVar.Project, false)
317 }
318
319 Chdir(commonVar.OriginalWorkingDirectory)
320 err = os.Setenv("KUBECONFIG", commonVar.OriginalKubeconfig)
321 Expect(err).NotTo(HaveOccurred())
322
323
324 DeleteDir(commonVar.Context)
325 DeleteDir(commonVar.ConfigDir)
326
327 os.Unsetenv("GLOBALODOCONFIG")
328 }
329
330
331 func JsonPathContentIs(json string, path string, value string) {
332 result := gjson.Get(json, path)
333 Expect(result.String()).To(Equal(value), fmt.Sprintf("content of path %q should be %q but is %q", path, value, result.String()))
334 }
335
336
337 func JsonPathContentContain(json string, path string, value string) {
338 result := gjson.Get(json, path)
339 Expect(result.String()).To(ContainSubstring(value), fmt.Sprintf("content of path %q should contain %q but is %q", path, value, result.String()))
340 }
341
342
343 func JsonPathSatisfiesAll(json string, path string, matchers ...types.GomegaMatcher) {
344 result := gjson.Get(json, path)
345 Expect(result.String()).Should(SatisfyAll(matchers...))
346 }
347
348
349 func JsonPathDoesNotExist(json string, path string) {
350 result := gjson.Get(json, path)
351 Expect(result.Exists()).To(BeFalse(),
352 fmt.Sprintf("content should not contain %q but is %q", path, result.String()))
353 }
354
355
356 func JsonPathExist(json string, path string) {
357 result := gjson.Get(json, path)
358 Expect(result.Exists()).To(BeTrue(),
359 fmt.Sprintf("content should contain %q", path))
360 }
361 func JsonPathContentIsValidUserPort(json string, path string) {
362 result := gjson.Get(json, path)
363 intVal, err := strconv.Atoi(result.String())
364 Expect(err).ToNot(HaveOccurred())
365 Expect(intVal).To(SatisfyAll(
366 BeNumerically(">=", 1024),
367 BeNumerically("<=", 65535),
368 ))
369 }
370
371 func JsonPathContentHasLen(json string, path string, len int) {
372 result := gjson.Get(json, path+".#")
373 intVal, err := strconv.Atoi(result.String())
374 Expect(err).ToNot(HaveOccurred())
375 Expect(intVal).To(Equal(len), fmt.Sprintf("%q should contain exactly %d elements", path, len))
376 }
377
378
379 func GenerateProjectName() string {
380
381 currGinkgoTestFileName := strings.Replace(strings.Split(strings.Split(CurrentSpecReport().
382 ContainerHierarchyLocations[0].FileName, "/")[len(strings.Split(CurrentSpecReport().ContainerHierarchyLocations[0].FileName, "/"))-1], ".")[0], "_", "-", -1)
383 currGinkgoTestLineNum := fmt.Sprint(CurrentSpecReport().LineNumber())
384 projectName := currGinkgoTestFileName + currGinkgoTestLineNum + RandString(3)
385 return projectName
386 }
387
388
389 func RunTestSpecs(t *testing.T, description string) {
390 os.Setenv(segment.TrackingConsentEnv, "no")
391 RegisterFailHandler(Fail)
392 RunSpecs(t, description)
393 }
394
395 func IsKubernetesCluster() bool {
396 k8s, err := strconv.ParseBool(os.Getenv("KUBERNETES"))
397 if err != nil {
398 return false
399 }
400 return k8s
401 }
402
403 type ResourceInfo struct {
404 ResourceType string
405 ResourceName string
406 Namespace string
407 }
408
409 func SetDefaultDevfileRegistry(commonVar *CommonVar) {
410 commonVar.registryUrl = os.Getenv("DEVFILE_REGISTRY")
411 if commonVar.registryUrl == "" {
412 commonVar.registryServer = registry_server.NewMockRegistryServer()
413 var err error
414 commonVar.registryUrl, err = commonVar.registryServer.Start()
415 Expect(err).ShouldNot(HaveOccurred())
416 }
417 fmt.Printf("Using Devfile Registry URL at: %q\n", commonVar.registryUrl)
418
419 const registryName string = "DefaultDevfileRegistry"
420 Cmd("odo", "preference", "remove", "registry", registryName, "-f").ShouldPass()
421 Cmd("odo", "preference", "add", "registry", registryName, commonVar.registryUrl).ShouldPass()
422 }
423
424 func (c CommonVar) GetDevfileRegistryURL() string {
425 return c.registryUrl
426 }
427
428 func GetOdoVersion() (version string, gitCommit string) {
429 odoVersion := Cmd("odo", "version", "--client", "-o", "json").ShouldPass().Out()
430 return gjson.Get(odoVersion, "version").String(), gjson.Get(odoVersion, "gitCommit").String()
431 }
432
View as plain text