Skip to content

Commit 2f92f14

Browse files
authored
NETOBSERV-2113 CLI Integration tests (netobserv#212)
* integration tests for CLI * go mod vendor * use inline struct
1 parent ce87678 commit 2f92f14

File tree

458 files changed

+222088
-5392
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

458 files changed

+222088
-5392
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
build
1+
build/*
22
output
33
tmp
44
cover.out

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ linters:
1616
- stylecheck
1717
- typecheck
1818
- unused
19+
- ginkgolinter
1920
run:
2021
go: "1.22"
2122
linters-settings:

e2e/integration-tests/cli.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package integrationtests
2+
3+
import (
4+
"context"
5+
"io/fs"
6+
"os"
7+
"time"
8+
9+
"k8s.io/apimachinery/pkg/api/errors"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/util/wait"
12+
"k8s.io/client-go/kubernetes"
13+
)
14+
15+
func isCLIReady(clientset *kubernetes.Clientset, cliNS string) (bool, error) {
16+
var collectorReady, cliDaemonsetReady bool
17+
err := wait.PollUntilContextTimeout(context.Background(), 30*time.Second, 300*time.Second, false, func(context.Context) (done bool, err error) {
18+
if !collectorReady {
19+
collectorPod, err := getNamespacePods(clientset, cliNS, &metav1.ListOptions{FieldSelector: "status.phase=Running", LabelSelector: "run=collector"})
20+
if err != nil {
21+
return false, err
22+
}
23+
24+
if len(collectorPod) > 0 {
25+
collectorReady = true
26+
}
27+
}
28+
29+
daemonset := "netobserv-cli"
30+
cliDaemonset, err := getDaemonSet(clientset, daemonset, cliNS)
31+
32+
if err != nil {
33+
if errors.IsNotFound(err) {
34+
return false, nil
35+
}
36+
return false, err
37+
}
38+
if cliDaemonset.Status.DesiredNumberScheduled == cliDaemonset.Status.NumberReady {
39+
cliDaemonsetReady = true
40+
}
41+
return collectorReady && cliDaemonsetReady, nil
42+
})
43+
if err != nil {
44+
return false, err
45+
}
46+
return true, nil
47+
}
48+
49+
// get latest flows.json file
50+
func getFlowsJSONFile() (string, error) {
51+
// var files []fs.DirEntry
52+
var files []string
53+
outputDir := "./output/flow/"
54+
dirFS := os.DirFS(outputDir)
55+
files, err := fs.Glob(dirFS, "*.json")
56+
if err != nil {
57+
return "", err
58+
}
59+
// this could be problematic if two tests are running in parallel with --copy=true
60+
var mostRecentFile fs.FileInfo
61+
for _, file := range files {
62+
fileInfo, err := os.Stat(outputDir + file)
63+
if err != nil {
64+
return "", nil
65+
}
66+
if mostRecentFile == nil || fileInfo.ModTime().After(mostRecentFile.ModTime()) {
67+
mostRecentFile = fileInfo
68+
}
69+
}
70+
return outputDir + mostRecentFile.Name(), nil
71+
}

e2e/integration-tests/cluster.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package integrationtests
2+
3+
import (
4+
"context"
5+
"os"
6+
7+
appsv1 "k8s.io/api/apps/v1"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/client-go/kubernetes"
10+
"k8s.io/client-go/tools/clientcmd"
11+
)
12+
13+
func getNewClient() (*kubernetes.Clientset, error) {
14+
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
15+
if err != nil {
16+
return nil, err
17+
}
18+
clientset, err := kubernetes.NewForConfig(config)
19+
20+
if err != nil {
21+
return nil, err
22+
}
23+
24+
return clientset, nil
25+
}
26+
27+
func getClusterNodes(clientset *kubernetes.Clientset, options *metav1.ListOptions) ([]string, error) {
28+
nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), *options)
29+
var allNodes []string
30+
if err != nil {
31+
return allNodes, err
32+
}
33+
for i := range nodes.Items {
34+
allNodes = append(allNodes, nodes.Items[i].Name)
35+
}
36+
return allNodes, nil
37+
}
38+
39+
func getDaemonSet(clientset *kubernetes.Clientset, daemonset string, ns string) (*appsv1.DaemonSet, error) {
40+
ds, err := clientset.AppsV1().DaemonSets(ns).Get(context.TODO(), daemonset, metav1.GetOptions{})
41+
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
return ds, nil
47+
}
48+
49+
func getNamespacePods(clientset *kubernetes.Clientset, namespace string, options *metav1.ListOptions) ([]string, error) {
50+
pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), *options)
51+
var allPods []string
52+
if err != nil {
53+
return allPods, err
54+
}
55+
for i := range pods.Items {
56+
allPods = append(allPods, pods.Items[i].Name)
57+
}
58+
return allPods, nil
59+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package integrationtests
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
9+
g "github.com/onsi/ginkgo/v2"
10+
o "github.com/onsi/gomega"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
)
13+
14+
var _ = g.Describe("NetObserv CLI e2e integration test suite", g.Serial, func() {
15+
cliNS := "netobserv-cli"
16+
17+
g.It("Verify all CLI pods are deployed", g.Label("Sanity"), func() {
18+
cliArgs := []string{"flows", "--copy=false"}
19+
cmd := exec.Command(ocNetObservBinPath, cliArgs...)
20+
err := cmd.Start()
21+
o.Expect(err).NotTo(o.HaveOccurred())
22+
// cleanup()
23+
defer func() {
24+
cliArgs := []string{"cleanup"}
25+
cmd := exec.Command(ocNetObservBinPath, cliArgs...)
26+
err := cmd.Run()
27+
o.Expect(err).NotTo(o.HaveOccurred())
28+
}()
29+
var allPods []string
30+
clientset, err := getNewClient()
31+
o.Expect(err).NotTo(o.HaveOccurred())
32+
nodes, err := getClusterNodes(clientset, &metav1.ListOptions{})
33+
// agent pods + collector pods
34+
totalExpectedPods := len(nodes) + 1
35+
o.Expect(err).NotTo(o.HaveOccurred())
36+
_, err = isCLIReady(clientset, cliNS)
37+
o.Expect(err).NotTo(o.HaveOccurred(), "CLI didn't come ready")
38+
allPods, err = getNamespacePods(clientset, cliNS, &metav1.ListOptions{})
39+
o.Expect(err).NotTo(o.HaveOccurred())
40+
o.Expect(allPods).To(o.HaveLen(totalExpectedPods), fmt.Sprintf("Number of CLI pods are not as expected %d", totalExpectedPods))
41+
})
42+
43+
g.It("Verify regexes filters are applied", func() {
44+
// capture upto 500KB
45+
nsfilter := "openshift-monitoring"
46+
cliArgs := []string{"flows", "--regexes=SrcK8S_Namespace~" + nsfilter, "--copy=true", "--max-bytes=500000"}
47+
cmd := exec.Command(ocNetObservBinPath, cliArgs...)
48+
err := cmd.Run()
49+
o.Expect(err).NotTo(o.HaveOccurred())
50+
// cleanup()
51+
defer func() {
52+
cliArgs := []string{"cleanup"}
53+
cmd := exec.Command(ocNetObservBinPath, cliArgs...)
54+
err := cmd.Run()
55+
o.Expect(err).NotTo(o.HaveOccurred())
56+
}()
57+
o.Expect(cmd.ProcessState.ExitCode()).To(o.BeNumerically("==", 0), "oc-netobserv returned non-zero exit code")
58+
flowsJsonfile, err := getFlowsJSONFile()
59+
o.Expect(err).NotTo(o.HaveOccurred())
60+
flowsFile, err := os.Open(flowsJsonfile)
61+
o.Expect(err).NotTo(o.HaveOccurred())
62+
defer flowsFile.Close()
63+
decoder := json.NewDecoder(flowsFile)
64+
_, err = decoder.Token()
65+
o.Expect(err).NotTo(o.HaveOccurred())
66+
var flow struct {
67+
SrcK8sNamespace string `json:"SrcK8S_Namespace"`
68+
}
69+
for decoder.More() {
70+
err := decoder.Decode(&flow)
71+
o.Expect(err).NotTo(o.HaveOccurred())
72+
if flow.SrcK8sNamespace != nsfilter {
73+
o.Expect(true).To(o.BeFalse(), fmt.Sprintf("Flow %v does not meet regexes condition SrcK8S_Namespace~%s", flow, nsfilter))
74+
}
75+
}
76+
})
77+
})
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package integrationtests
2+
3+
import (
4+
"os"
5+
"os/exec"
6+
"strings"
7+
"testing"
8+
9+
g "github.com/onsi/ginkgo/v2"
10+
o "github.com/onsi/gomega"
11+
)
12+
13+
var ocNetObservBinPath string
14+
15+
func TestIntegrationTests(t *testing.T) {
16+
o.RegisterFailHandler(g.Fail)
17+
g.RunSpecs(t, "IntegrationTests Suite")
18+
}
19+
20+
var _ = g.BeforeSuite(func() {
21+
// kubeconfig env var and see if the cluster is reachable.
22+
if kubeconfig := os.Getenv("KUBECONFIG"); kubeconfig == "" {
23+
g.Skip("Set KUBECONFIG env variable")
24+
}
25+
26+
cmd := exec.Command("which", "oc-netobserv")
27+
out, err := cmd.Output()
28+
o.Expect(err).NotTo(o.HaveOccurred())
29+
ocNetObservBinPath = strings.TrimSuffix(string(out), "\n")
30+
})

go.mod

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ require (
1212
github.com/mattn/go-sqlite3 v1.14.24
1313
github.com/netobserv/flowlogs-pipeline v1.7.0-community.0.20241217113023-fa0540a1658e
1414
github.com/netobserv/netobserv-ebpf-agent v1.7.0-community.0.20250220123714-ff37a09f6232
15+
github.com/onsi/ginkgo/v2 v2.23.0
16+
github.com/onsi/gomega v1.36.2
1517
github.com/rodaine/table v1.3.0
1618
github.com/ryankurte/go-pcapng v0.0.0-20170712041429-73fd1a63fab4
1719
github.com/sirupsen/logrus v1.9.3
@@ -21,45 +23,52 @@ require (
2123
sigs.k8s.io/e2e-framework v0.6.0
2224
)
2325

26+
require (
27+
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
28+
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e // indirect
29+
github.com/ovn-org/ovn-kubernetes/go-controller v0.0.0-20250215040159-dd2a70c928d3 // indirect
30+
golang.org/x/tools v0.31.0 // indirect
31+
sigs.k8s.io/randfill v1.0.0 // indirect
32+
)
33+
2434
require (
2535
github.com/beorn7/perks v1.0.1 // indirect
2636
github.com/blang/semver/v4 v4.0.0 // indirect
2737
github.com/cespare/xxhash/v2 v2.3.0 // indirect
2838
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
29-
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
30-
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
39+
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
40+
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
3141
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
3242
github.com/go-logr/logr v1.4.2 // indirect
33-
github.com/go-openapi/jsonpointer v0.21.0 // indirect
43+
github.com/go-openapi/jsonpointer v0.21.1 // indirect
3444
github.com/go-openapi/jsonreference v0.21.0 // indirect
35-
github.com/go-openapi/swag v0.23.0 // indirect
45+
github.com/go-openapi/swag v0.23.1 // indirect
3646
github.com/gogo/protobuf v1.3.2 // indirect
3747
github.com/golang/protobuf v1.5.4 // indirect
38-
github.com/google/gnostic-models v0.6.8 // indirect
39-
github.com/google/go-cmp v0.6.0 // indirect
48+
github.com/google/gnostic-models v0.6.9 // indirect
49+
github.com/google/go-cmp v0.7.0 // indirect
4050
github.com/google/gofuzz v1.2.0 // indirect
4151
github.com/google/uuid v1.6.0 // indirect
42-
github.com/gorilla/websocket v1.5.0 // indirect
52+
github.com/gorilla/websocket v1.5.3 // indirect
4353
github.com/inconshreveable/mousetrap v1.1.0 // indirect
4454
github.com/josharian/intern v1.0.0 // indirect
4555
github.com/jpillora/backoff v1.0.0 // indirect
4656
github.com/json-iterator/go v1.1.12 // indirect
47-
github.com/klauspost/compress v1.17.11 // indirect
48-
github.com/mailru/easyjson v0.7.7 // indirect
49-
github.com/mattn/go-colorable v0.1.13 // indirect
57+
github.com/klauspost/compress v1.18.0 // indirect
58+
github.com/mailru/easyjson v0.9.0 // indirect
59+
github.com/mattn/go-colorable v0.1.14 // indirect
5060
github.com/mattn/go-isatty v0.0.20 // indirect
5161
github.com/moby/spdystream v0.5.0 // indirect
5262
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
5363
github.com/modern-go/reflect2 v1.0.2 // indirect
5464
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
5565
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
5666
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
57-
github.com/ovn-org/ovn-kubernetes/go-controller v0.0.0-20250215040159-dd2a70c928d3 // indirect
5867
github.com/pkg/errors v0.9.1 // indirect
5968
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
60-
github.com/prometheus/client_golang v1.20.5 // indirect
69+
github.com/prometheus/client_golang v1.21.1 // indirect
6170
github.com/prometheus/client_model v0.6.1 // indirect
62-
github.com/prometheus/common v0.59.1 // indirect
71+
github.com/prometheus/common v0.63.0 // indirect
6372
github.com/prometheus/procfs v0.15.1 // indirect
6473
github.com/segmentio/kafka-go v0.4.47 // indirect
6574
github.com/spf13/pflag v1.0.6 // indirect
@@ -68,29 +77,29 @@ require (
6877
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
6978
github.com/xdg-go/scram v1.1.2 // indirect
7079
github.com/xdg-go/stringprep v1.0.4 // indirect
71-
go.opentelemetry.io/otel v1.32.0 // indirect
72-
go.opentelemetry.io/otel/trace v1.32.0 // indirect
73-
golang.org/x/net v0.36.0 // indirect
74-
golang.org/x/oauth2 v0.24.0 // indirect
75-
golang.org/x/sys v0.30.0 // indirect
76-
golang.org/x/term v0.29.0 // indirect
77-
golang.org/x/text v0.22.0 // indirect
78-
golang.org/x/time v0.7.0 // indirect
79-
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
80-
google.golang.org/grpc v1.70.0 // indirect
81-
google.golang.org/protobuf v1.36.6
80+
go.opentelemetry.io/otel v1.35.0 // indirect
81+
go.opentelemetry.io/otel/trace v1.35.0 // indirect
82+
golang.org/x/net v0.37.0 // indirect
83+
golang.org/x/oauth2 v0.28.0 // indirect
84+
golang.org/x/sys v0.31.0 // indirect
85+
golang.org/x/term v0.30.0 // indirect
86+
golang.org/x/text v0.23.0 // indirect
87+
golang.org/x/time v0.11.0 // indirect
88+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
89+
google.golang.org/grpc v1.71.0 // indirect
90+
google.golang.org/protobuf v1.36.5
8291
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
8392
gopkg.in/inf.v0 v0.9.1 // indirect
8493
gopkg.in/yaml.v2 v2.4.0 // indirect
85-
k8s.io/api v0.32.2 // indirect
86-
k8s.io/apimachinery v0.32.2 // indirect
87-
k8s.io/client-go v0.32.2 // indirect
88-
k8s.io/component-base v0.32.1 // indirect
94+
k8s.io/api v0.32.3
95+
k8s.io/apimachinery v0.32.3
96+
k8s.io/client-go v0.32.3
97+
k8s.io/component-base v0.32.3 // indirect
8998
k8s.io/klog/v2 v2.130.1 // indirect
90-
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
91-
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
92-
sigs.k8s.io/controller-runtime v0.20.0 // indirect
93-
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
94-
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
99+
k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 // indirect
100+
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
101+
sigs.k8s.io/controller-runtime v0.20.3 // indirect
102+
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
103+
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
95104
sigs.k8s.io/yaml v1.4.0 // indirect
96105
)

0 commit comments

Comments
 (0)