Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more tests for Podman + write Component abstraction for integration tests #6427

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions tests/helper/component_cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package helper

import (
"fmt"

. "github.com/onsi/gomega"
)

// ClusterComponent is an abstraction for a Devfile Component deployed on a cluster (either Kubernetes or OpenShift)
type ClusterComponent struct {
name string
app string
namespace string
cli CliRunner
}

func NewClusterComponent(name string, app string, namespace string, cli CliRunner) *ClusterComponent {
return &ClusterComponent{
name: name,
app: app,
namespace: namespace,
cli: cli,
}
}

func (o *ClusterComponent) ExpectIsNotDeployed() {
deploymentName := fmt.Sprintf("%s-%s", o.name, o.app)
stdout := o.cli.Run("get", "deployment", "-n", o.namespace).Out.Contents()
Expect(string(stdout)).To(Not(ContainSubstring(deploymentName)))
}

func (o *ClusterComponent) Exec(container string, args ...string) string {
podName := o.cli.GetRunningPodNameByComponent(o.name, o.namespace)
return o.cli.Exec(podName, o.namespace, append([]string{"--"}, args...)...)
}

func (o *ClusterComponent) GetEnvVars() map[string]string {
return o.cli.GetEnvsDevFileDeployment(o.name, o.app, o.namespace)
}
23 changes: 23 additions & 0 deletions tests/helper/component_interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package helper

import (
. "github.com/onsi/ginkgo/v2"
)

// Component is an abstraction for a Devfile Component deployed on a specific platform
type Component interface {
// ExpectIsNotDeployed checks that the component is not deployed
ExpectIsNotDeployed()
// Exec executes the command in specific container of the component
Exec(container string, args ...string) string
// GetEnvVars returns the environment variables defined for the component
GetEnvVars() map[string]string
}

func NewComponent(name string, app string, namespace string, cli CliRunner) Component {
if NeedsCluster(CurrentSpecReport().Labels()) {
return NewClusterComponent(name, app, namespace, cli)
} else {
return NewPodmanComponent(name, app)
}
}
75 changes: 75 additions & 0 deletions tests/helper/component_podman.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package helper

import (
"fmt"
"os/exec"

. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
jsonserializer "k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/kubectl/pkg/scheme"
)

// PodmanComponent is an abstraction for a Devfile Component deployed on podman
type PodmanComponent struct {
name string
app string
}

func NewPodmanComponent(name string, app string) *PodmanComponent {
return &PodmanComponent{
name: name,
app: app,
}
}

func (o *PodmanComponent) ExpectIsNotDeployed() {
podName := fmt.Sprintf("%s-%s", o.name, o.app)
cmd := exec.Command("podman", "pod", "list", "--format", "{{.Name}}", "--noheading")
Copy link
Member

@rm3l rm3l Dec 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to make the path to podman configurable (ideally using the PODMAN_CMD env var just like with the internal PodmanCli client)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. This is used during integration tests only, on a stable environment, I cannot see a reason for the moment to have to configure it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree from the environment perspective.
I thought it would make sense for an odo dev to make sure the same podman binary is used when running the actual odo commands in the tests and when performing the assertions here..
But okay, that's something that can be optimized later on.
/lgtm

stdout, err := cmd.Output()
Expect(err).ToNot(HaveOccurred())
Expect(string(stdout)).ToNot(ContainSubstring(podName))
}

func (o *PodmanComponent) Exec(container string, args ...string) string {
containerName := fmt.Sprintf("%s-%s-%s", o.name, o.app, container)
cmdargs := []string{"exec", "--interactive"}
cmdargs = append(cmdargs, "--tty")
cmdargs = append(cmdargs, containerName)
cmdargs = append(cmdargs, args...)

command := exec.Command("podman", cmdargs...)
fmt.Printf("exec %v\n", cmdargs)
out, err := command.Output()
Expect(err).ToNot(HaveOccurred())
return string(out)
}

func (o *PodmanComponent) GetEnvVars() map[string]string {
podName := fmt.Sprintf("%s-%s", o.name, o.app)
podDef := getPodDef(podName)
res := map[string]string{}
for _, env := range podDef.Spec.Containers[0].Env {
res[env.Name] = env.Value
}
return res
}

func getPodDef(podname string) *corev1.Pod {
serializer := jsonserializer.NewSerializerWithOptions(
jsonserializer.SimpleMetaFactory{},
scheme.Scheme,
scheme.Scheme,
jsonserializer.SerializerOptions{
Yaml: true,
},
)

cmd := exec.Command("podman", "kube", "generate", podname)
resultBytes, err := cmd.Output()
Expect(err).ToNot(HaveOccurred())
var pod corev1.Pod
_, _, err = serializer.Decode(resultBytes, nil, &pod)
Expect(err).ToNot(HaveOccurred())
return &pod
}
8 changes: 3 additions & 5 deletions tests/helper/helper_dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,9 @@ func (o DevSession) CheckNotSynced(timeout time.Duration) {
// RunDevMode runs a dev session and executes the `inside` code when the dev mode is completely started
// The inside handler is passed the internal session pointer, the contents of the standard and error outputs,
// and a slice of strings - ports - giving the redirections in the form localhost:<port_number> to access ports opened by component
func RunDevMode(additionalOpts []string, envvars []string, inside func(session *gexec.Session, outContents []byte, errContents []byte, ports map[string]string)) error {
session, outContents, errContents, urls, err := StartDevMode(DevSessionOpts{
EnvVars: envvars,
CmdlineArgs: additionalOpts,
})
func RunDevMode(options DevSessionOpts, inside func(session *gexec.Session, outContents []byte, errContents []byte, ports map[string]string)) error {

session, outContents, errContents, urls, err := StartDevMode(options)
if err != nil {
return err
}
Expand Down
Loading