Skip to content

Commit

Permalink
Enrich relevant integration test cases
Browse files Browse the repository at this point in the history
For the sake of both performance and readability,
only the tests that break in the absence of a 'metadata.name'
field in their Devfiles have been updated (to test this specific case).
  • Loading branch information
rm3l committed Aug 29, 2022
1 parent 35a2605 commit 511322a
Show file tree
Hide file tree
Showing 5 changed files with 1,207 additions and 950 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ metadata:
displayName: Node.js Runtime
icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg
language: javascript
name: my-nodejs-app
name: nodejs
projectType: nodejs
tags:
- NodeJS
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
schemaVersion: 2.0.0
metadata:
name: test-devfile
name: nodejs
starterProjects:
- name: nodejs-starter
git:
Expand Down
34 changes: 34 additions & 0 deletions tests/helper/helper_filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"strings"
"time"

"github.com/devfile/library/pkg/devfile/parser"
dfutil "github.com/devfile/library/pkg/util"
"k8s.io/utils/pointer"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -285,3 +287,35 @@ func AppendToFile(filepath string, s string) error {
}
return nil
}

// DevfileUpdater is a helper type that can mutate a Devfile object.
// It is intended to be used in conjunction with the UpdateDevfileContent function.
type DevfileUpdater func(*parser.DevfileObj) error

// DevfileMetadataNameRemover removes the 'metadata.name' field from the given Devfile
var DevfileMetadataNameRemover = func(d *parser.DevfileObj) error {
return d.SetMetadataName("")
}

// UpdateDevfileContent parses the Devfile at the given path, then updates its content using the given handlers, and writes the updated Devfile to the given path.
//
// The handlers are invoked in the order they are provided.
//
// No operation is performed if no handler function is specified.
//
// See DevfileMetadataNameRemover for an example of handler function that can operate on the Devfile content.
func UpdateDevfileContent(path string, handlers []DevfileUpdater) {
if len(handlers) == 0 {
//Nothing to do => skip
return
}

d, err := parser.ParseDevfile(parser.ParserArgs{Path: path, FlattenedDevfile: pointer.BoolPtr(false)})
Expect(err).NotTo(HaveOccurred())
for _, h := range handlers {
err = h(&d)
Expect(err).NotTo(HaveOccurred())
}
err = d.WriteYamlDevfile()
Expect(err).NotTo(HaveOccurred())
}
289 changes: 170 additions & 119 deletions tests/integration/cmd_dev_debug_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,72 +63,98 @@ var _ = Describe("odo dev debug command tests", func() {
})
})

When("a composite command is used as debug command", func() {
const devfileCmpName = "nodejs"
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)
var err error
session, stdout, stderr, ports, err = helper.StartDevMode(nil, "--debug")
Expect(err).ToNot(HaveOccurred())
})
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(nil, "--debug")
Expect(err).ToNot(HaveOccurred())
})

AfterEach(func() {
session.Stop()
session.WaitEnd()
})
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)",
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("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("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("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)
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
Expand Down Expand Up @@ -196,79 +222,104 @@ var _ = Describe("odo dev debug command tests", func() {
})
})

When("running build and debug commands as composite in different containers and a shared volume", func() {
const devfileCmpName = "nodejs"
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)
var err error
session, stdout, stderr, ports, err = helper.StartDevMode(nil, "--debug")
Expect(err).ToNot(HaveOccurred())
})
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(nil, "--debug")
Expect(err).ToNot(HaveOccurred())
})

AfterEach(func() {
session.Stop()
session.WaitEnd()
})
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)",
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("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("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("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)
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() {
Expand Down
Loading

0 comments on commit 511322a

Please sign in to comment.