Files
odo/tests/integration/cmd_dev_debug_test.go
Philippe Martin 120920f868 Integration tests for odo dev running on podman (#6332)
* Change signature of StartDevMode to use options structure

* Add tests for odo dev on podman

* Uncomment commented code

* Update Makefile

Co-authored-by: Armel Soro <armel@rm3l.org>

Co-authored-by: Armel Soro <armel@rm3l.org>
2022-11-24 08:24:00 -05:00

342 lines
13 KiB
Go

package integration
import (
"fmt"
"path/filepath"
"strings"
"github.com/redhat-developer/odo/tests/helper"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("odo dev debug command tests", func() {
var cmpName string
var commonVar helper.CommonVar
// This is run before every Spec (It)
var _ = BeforeEach(func() {
commonVar = helper.CommonBeforeEach()
cmpName = helper.RandString(6)
helper.Chdir(commonVar.Context)
Expect(helper.VerifyFileExists(".odo/env/env.yaml")).To(BeFalse())
})
// This is run after every Spec (It)
var _ = AfterEach(func() {
helper.CommonAfterEach(commonVar)
})
When("a component is bootstrapped", func() {
BeforeEach(func() {
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-debugrun.yaml")).ShouldPass()
Expect(helper.VerifyFileExists(".odo/env/env.yaml")).To(BeFalse())
})
When("running odo dev with debug flag", func() {
var devSession helper.DevSession
var ports map[string]string
BeforeEach(func() {
var err error
devSession, _, _, ports, err = helper.StartDevMode(helper.DevSessionOpts{
CmdlineArgs: []string{"--debug"},
})
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
devSession.Kill()
devSession.WaitEnd()
})
It("should expect a ws connection when tried to connect on default debug port locally", func() {
// 400 response expected because the endpoint expects a websocket request and we are doing a HTTP GET
// We are just using this to validate if nodejs agent is listening on the other side
helper.HttpWaitForWithStatus("http://"+ports["5858"], "WebSockets request was expected", 12, 5, 400)
})
// #6056
It("should not add a DEBUG_PORT variable to the container", func() {
podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project)
stdout := commonVar.CliRunner.Exec(podName, commonVar.Project, "--", "sh", "-c", "echo -n ${DEBUG_PORT}")
Expect(stdout).To(BeEmpty())
})
})
})
for _, devfileHandlerCtx := range []struct {
name string
cmpName string
devfileHandler func(path string)
}{
{
name: "with metadata.name",
// cmpName from Devfile
cmpName: "nodejs",
},
{
name: "without metadata.name",
// cmpName is returned by alizer.DetectName
cmpName: "nodejs-starter",
devfileHandler: func(path string) {
helper.UpdateDevfileContent(path, []helper.DevfileUpdater{helper.DevfileMetadataNameRemover})
},
},
} {
devfileHandlerCtx := devfileHandlerCtx
When("a composite command is used as debug command - "+devfileHandlerCtx.name, func() {
var devfileCmpName string
var session helper.DevSession
var stdout []byte
var stderr []byte
var ports map[string]string
BeforeEach(func() {
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfileCompositeRunAndDebug.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
devfileCmpName = devfileHandlerCtx.cmpName
if devfileHandlerCtx.devfileHandler != nil {
devfileHandlerCtx.devfileHandler(filepath.Join(commonVar.Context, "devfile.yaml"))
}
var err error
session, stdout, stderr, ports, err = helper.StartDevMode(helper.DevSessionOpts{
CmdlineArgs: []string{"--debug"},
})
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
session.Stop()
session.WaitEnd()
})
It("should run successfully", func() {
By("verifying from the output that all commands have been executed", func() {
helper.MatchAllInOutput(string(stdout), []string{
"Building your application in container on cluster",
"Executing the application (command: mkdir)",
"Executing the application (command: echo)",
"Executing the application (command: install)",
"Executing the application (command: start-debug)",
})
})
By("verifying that any command that did not succeed in the middle has logged such information correctly", func() {
helper.MatchAllInOutput(string(stderr), []string{
"Devfile command \"echo\" exited with an error status",
"intentional-error-message",
})
})
By("building the application only once", func() {
// Because of the Spinner, the "Building your application in container on cluster" is printed twice in the captured stdout.
// The bracket allows to match the last occurrence with the command execution timing information.
Expect(strings.Count(string(stdout), "Building your application in container on cluster (command: install) [")).
To(BeNumerically("==", 1), "\nOUTPUT: "+string(stdout)+"\n")
})
By("verifying that the command did run successfully", func() {
// Verify the command executed successfully
podName := commonVar.CliRunner.GetRunningPodNameByComponent(devfileCmpName, commonVar.Project)
res := commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
podName,
"runtime",
commonVar.Project,
[]string{"stat", "/projects/testfolder"},
func(cmdOp string, err error) bool {
return err == nil
},
)
Expect(res).To(BeTrue())
})
By("expecting a ws connection when tried to connect on default debug port locally", func() {
// 400 response expected because the endpoint expects a websocket request and we are doing a HTTP GET
// We are just using this to validate if nodejs agent is listening on the other side
helper.HttpWaitForWithStatus("http://"+ports["5858"], "WebSockets request was expected", 12, 5, 400)
})
})
})
}
When("a composite apply command is used as debug command", func() {
deploymentName := "my-component"
var session helper.DevSession
var sessionOut []byte
var err error
var ports map[string]string
const (
DEVFILE_DEBUG_PORT = "5858"
)
BeforeEach(func() {
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-composite-apply-commands.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
session, sessionOut, _, ports, err = helper.StartDevMode(helper.DevSessionOpts{
EnvVars: []string{"PODMAN_CMD=echo"},
CmdlineArgs: []string{"--debug"},
})
Expect(err).ToNot(HaveOccurred())
})
It("should execute the composite apply commands successfully", func() {
checkDeploymentExists := func() {
out := commonVar.CliRunner.Run("get", "deployments", deploymentName).Out.Contents()
Expect(out).To(ContainSubstring(deploymentName))
}
checkImageBuilt := func() {
Expect(string(sessionOut)).To(ContainSubstring("Building & Pushing Container"))
Expect(string(sessionOut)).To(ContainSubstring("build -t quay.io/unknown-account/myimage -f " + filepath.Join(commonVar.Context, "Dockerfile ") + commonVar.Context))
Expect(string(sessionOut)).To(ContainSubstring("push quay.io/unknown-account/myimage"))
}
checkWSConnection := func() {
// 400 response expected because the endpoint expects a websocket request and we are doing a HTTP GET
// We are just using this to validate if nodejs agent is listening on the other side
helper.HttpWaitForWithStatus("http://"+ports[DEVFILE_DEBUG_PORT], "WebSockets request was expected", 12, 5, 400)
}
By("expecting a ws connection when tried to connect on default debug port locally", func() {
checkWSConnection()
})
By("checking is the image was successfully built", func() {
checkImageBuilt()
})
By("checking the deployment was created successfully", func() {
checkDeploymentExists()
})
By("checking odo dev watches correctly", func() {
// making changes to the project again
helper.ReplaceString(filepath.Join(commonVar.Context, "server.js"), "from Node.js Starter Application", "from the new Node.js Starter Application")
_, _, _, err = session.WaitSync()
Expect(err).ToNot(HaveOccurred())
checkDeploymentExists()
checkImageBuilt()
checkWSConnection()
})
By("cleaning up the resources on ending the session", func() {
session.Stop()
session.WaitEnd()
out := commonVar.CliRunner.Run("get", "deployments").Out.Contents()
Expect(out).ToNot(ContainSubstring(deploymentName))
})
})
})
for _, devfileHandlerCtx := range []struct {
name string
cmpName string
devfileHandler func(path string)
}{
{
name: "with metadata.name",
// cmpName from Devfile
cmpName: "nodejs",
},
{
name: "without metadata.name",
// cmpName is returned by alizer.DetectName
cmpName: "nodejs-starter",
devfileHandler: func(path string) {
helper.UpdateDevfileContent(path, []helper.DevfileUpdater{helper.DevfileMetadataNameRemover})
},
},
} {
devfileHandlerCtx := devfileHandlerCtx
When("running build and debug commands as composite in different containers and a shared volume - "+devfileHandlerCtx.name, func() {
var devfileCmpName string
var session helper.DevSession
var stdout []byte
var stderr []byte
var ports map[string]string
BeforeEach(func() {
helper.CopyExampleDevFile(
filepath.Join("source", "devfiles", "nodejs", "devfileCompositeBuildRunDebugInMultiContainersAndSharedVolume.yaml"),
filepath.Join(commonVar.Context, "devfile.yaml"))
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
devfileCmpName = devfileHandlerCtx.cmpName
if devfileHandlerCtx.devfileHandler != nil {
devfileHandlerCtx.devfileHandler(filepath.Join(commonVar.Context, "devfile.yaml"))
}
var err error
session, stdout, stderr, ports, err = helper.StartDevMode(helper.DevSessionOpts{
CmdlineArgs: []string{"--debug"},
})
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
session.Stop()
session.WaitEnd()
})
It("should run successfully", func() {
By("verifying from the output that all commands have been executed", func() {
helper.MatchAllInOutput(string(stdout), []string{
"Building your application in container on cluster (command: mkdir)",
"Building your application in container on cluster (command: sleep-cmd-build)",
"Building your application in container on cluster (command: build-cmd)",
"Executing the application (command: sleep-cmd-run)",
"Executing the application (command: echo-with-error)",
"Executing the application (command: check-build-result)",
"Executing the application (command: start-debug)",
})
})
By("verifying that any command that did not succeed in the middle has logged such information correctly", func() {
helper.MatchAllInOutput(string(stderr), []string{
"Devfile command \"echo-with-error\" exited with an error status",
"intentional-error-message",
})
})
By("building the application only once per exec command in the build command", func() {
// Because of the Spinner, the "Building your application in container on cluster" is printed twice in the captured stdout.
// The bracket allows to match the last occurrence with the command execution timing information.
out := string(stdout)
for _, cmd := range []string{"mkdir", "sleep-cmd-build", "build-cmd"} {
Expect(strings.Count(out, fmt.Sprintf("Building your application in container on cluster (command: %s) [", cmd))).
To(BeNumerically("==", 1), "\nOUTPUT: "+string(stdout)+"\n")
}
})
By("verifying that the command did run successfully", func() {
// Verify the command executed successfully
podName := commonVar.CliRunner.GetRunningPodNameByComponent(devfileCmpName, commonVar.Project)
res := commonVar.CliRunner.CheckCmdOpInRemoteDevfilePod(
podName,
"runtime",
commonVar.Project,
[]string{"stat", "/projects/testfolder"},
func(cmdOp string, err error) bool {
return err == nil
},
)
Expect(res).To(BeTrue())
})
By("expecting a ws connection when tried to connect on default debug port locally", func() {
// 400 response expected because the endpoint expects a websocket request and we are doing a HTTP GET
// We are just using this to validate if nodejs agent is listening on the other side
helper.HttpWaitForWithStatus("http://"+ports["5858"], "WebSockets request was expected", 12, 5, 400)
})
})
})
}
When("a component without debug command is bootstrapped", func() {
BeforeEach(func() {
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context)
helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-without-debugrun.yaml")).ShouldPass()
Expect(helper.VerifyFileExists(".odo/env/env.yaml")).To(BeFalse())
})
It("should fail running odo dev --debug", func() {
output := helper.Cmd("odo", "dev", "--debug").ShouldFail().Err()
Expect(output).To(ContainSubstring("no command of kind \"debug\" found in the devfile"))
})
})
})