From 1d43b72a1480127b3b8fd4336958c58075af57f3 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 21 Feb 2020 15:20:44 +0100 Subject: [PATCH 1/7] Fix parsing VPP version info strings Signed-off-by: Ondrej Fabry --- plugins/govppmux/vppcalls/vpp2001/vpe_vppcalls.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/govppmux/vppcalls/vpp2001/vpe_vppcalls.go b/plugins/govppmux/vppcalls/vpp2001/vpe_vppcalls.go index 375ff673e8..f1202a8058 100644 --- a/plugins/govppmux/vppcalls/vpp2001/vpe_vppcalls.go +++ b/plugins/govppmux/vppcalls/vpp2001/vpe_vppcalls.go @@ -39,10 +39,10 @@ func (h *VpeHandler) GetVersion(ctx context.Context) (*vppcalls.VersionInfo, err return nil, err } info := &vppcalls.VersionInfo{ - Program: version.Program, - Version: version.Version, - BuildDate: version.BuildDate, - BuildDirectory: version.BuildDirectory, + Program: strings.TrimRight(version.Program, "\x00"), + Version: strings.TrimRight(version.Version, "\x00"), + BuildDate: strings.TrimRight(version.BuildDate, "\x00"), + BuildDirectory: strings.TrimRight(version.BuildDirectory, "\x00"), } return info, nil } From 4ea9e98dab2f7e11788fc15eea6db3d74fa03086 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 21 Feb 2020 15:21:10 +0100 Subject: [PATCH 2/7] Update integration tests Signed-off-by: Ondrej Fabry --- tests/e2e/010_interfaces_test.go | 2 +- tests/e2e/e2e_test.go | 3 ++ tests/e2e/microservice_test.go | 2 + tests/integration/vpp/000_initial_test.go | 37 +++++++++++-------- tests/integration/vpp/001_telemetry_test.go | 4 +- tests/integration/vpp/010_interfaces_test.go | 24 ++++++------ tests/integration/vpp/020_routes_test.go | 16 ++++---- tests/integration/vpp/021_l3xc_test.go | 14 +++---- tests/integration/vpp/022_ip_neighbor_test.go | 2 +- tests/integration/vpp/080_gre_test.go | 4 +- tests/integration/vpp/090_vxlan_gpe_test.go | 4 +- tests/integration/vpp/100_gtpu_test.go | 4 +- tests/integration/vpp/integration_test.go | 4 +- tests/integration/vpp/utils.go | 37 +++++++++++++++++++ 14 files changed, 103 insertions(+), 54 deletions(-) create mode 100644 tests/integration/vpp/utils.go diff --git a/tests/e2e/010_interfaces_test.go b/tests/e2e/010_interfaces_test.go index 9625f70e75..1b2dfe5569 100644 --- a/tests/e2e/010_interfaces_test.go +++ b/tests/e2e/010_interfaces_test.go @@ -399,4 +399,4 @@ func TestAfPacketWithLogicalReference(t *testing.T) { Eventually(ctx.pingFromVPPClb(veth2IP)).Should(Succeed()) Expect(ctx.pingFromMs(msName, afPacketIP)).To(Succeed()) Expect(ctx.agentInSync()).To(BeTrue()) -} \ No newline at end of file +} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 1292cef7f0..22710345ba 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -297,6 +297,7 @@ func (ctx *testCtx) agentInSync() bool { // execCmd executes command and returns stdout, stderr as strings and error. func (ctx *testCtx) execCmd(cmd string, args ...string) (string, string, error) { + ctx.t.Helper() ctx.t.Logf("exec: %s %s", cmd, strings.Join(args, " ")) var stdout, stderr bytes.Buffer c := exec.Command(cmd, args...) @@ -308,6 +309,7 @@ func (ctx *testCtx) execCmd(cmd string, args ...string) (string, string, error) // execVppctl returns output from vppctl for given action and arguments. func (ctx *testCtx) execVppctl(action string, args ...string) (string, error) { + ctx.t.Helper() command := append([]string{action}, args...) stdout, _, err := ctx.execCmd("vppctl", command...) if err != nil { @@ -356,6 +358,7 @@ func (ctx *testCtx) pingFromMsClb(msName, dstAddress string) func() error { // pingFromVPP pings from inside the VPP. func (ctx *testCtx) pingFromVPP(destAddress string) error { + ctx.t.Helper() // run ping on VPP using vppctl stdout, err := ctx.execVppctl("ping", destAddress) if err != nil { diff --git a/tests/e2e/microservice_test.go b/tests/e2e/microservice_test.go index a7f7453b92..6e12e983d2 100644 --- a/tests/e2e/microservice_test.go +++ b/tests/e2e/microservice_test.go @@ -164,6 +164,8 @@ func (ms *microservice) enterNetNs() (exitNetNs func()) { // ping from inside of the microservice. func (ms *microservice) ping(destAddress string, allowedLoss ...int) error { + ms.t.Helper() + stdout, err := ms.exec("ping", "-w", "4", destAddress) if err != nil { return err diff --git a/tests/integration/vpp/000_initial_test.go b/tests/integration/vpp/000_initial_test.go index 42dfefe593..51b0d1a53f 100644 --- a/tests/integration/vpp/000_initial_test.go +++ b/tests/integration/vpp/000_initial_test.go @@ -15,9 +15,10 @@ package vpp import ( - "context" "testing" + . "github.com/onsi/gomega" + "go.ligato.io/vpp-agent/v3/plugins/govppmux/vppcalls" ) @@ -27,9 +28,11 @@ func TestPing(t *testing.T) { vpp := vppcalls.CompatibleHandler(test.vppClient) - if err := vpp.Ping(context.Background()); err != nil { - t.Fatalf("control ping failed: %v", err) - } + Expect(vpp.Ping(test.Ctx)).To(Succeed()) + + session, err := vpp.GetSession(test.Ctx) + Expect(err).ToNot(HaveOccurred()) + Expect(session.PID).To(BeEquivalentTo(test.vppCmd.Process.Pid)) } func TestGetVersion(t *testing.T) { @@ -38,12 +41,12 @@ func TestGetVersion(t *testing.T) { vpp := vppcalls.CompatibleHandler(test.vppClient) - versionInfo, err := vpp.GetVersion(context.Background()) - if err != nil { - t.Fatalf("getting version failed: %v", err) - } - - t.Logf("version: %v", versionInfo.Version) + info, err := vpp.GetVersion(test.Ctx) + Expect(err).ToNot(HaveOccurred()) + Expect(info.Version).To(BePrintable()) + Expect(info.Program).To(BePrintable()) + Expect(info.BuildDate).To(BePrintable()) + Expect(info.BuildDirectory).To(BePrintable()) } func TestGetPlugins(t *testing.T) { @@ -52,10 +55,14 @@ func TestGetPlugins(t *testing.T) { vpp := vppcalls.CompatibleHandler(test.vppClient) - plugins, err := vpp.GetPlugins(context.Background()) - if err != nil { - t.Fatalf("getting pluggins failed: %v", err) - } - + plugins, err := vpp.GetPlugins(test.Ctx) + Expect(err).ToNot(HaveOccurred()) t.Logf("%d plugins: %v", len(plugins), plugins) + Expect(plugins).ToNot(BeEmpty()) + + // GetModules return empty list with VPP 20.01 + /*modules, err := vpp.GetModules(test.Ctx) + Expect(err).ToNot(HaveOccurred()) + t.Logf("%d modules: %v", len(modules), modules) + Expect(modules).ToNot(BeEmpty())*/ } diff --git a/tests/integration/vpp/001_telemetry_test.go b/tests/integration/vpp/001_telemetry_test.go index bb3c6becb0..a91b4e280f 100644 --- a/tests/integration/vpp/001_telemetry_test.go +++ b/tests/integration/vpp/001_telemetry_test.go @@ -32,7 +32,7 @@ func TestTelemetryNodeCounters(t *testing.T) { h := vppcalls.CompatibleTelemetryHandler(test.vppClient) - nodeCounters, err := h.GetNodeCounters(test.Context) + nodeCounters, err := h.GetNodeCounters(test.Ctx) if err != nil { t.Fatalf("getting node counters failed: %v", err) } @@ -51,7 +51,7 @@ func TestTelemetryInterfaceStats(t *testing.T) { h := vppcalls.CompatibleTelemetryHandler(test.vppClient) - ifStats, err := h.GetInterfaceStats(test.Context) + ifStats, err := h.GetInterfaceStats(test.Ctx) if err != nil { t.Fatalf("getting interface stats failed: %v", err) } else { diff --git a/tests/integration/vpp/010_interfaces_test.go b/tests/integration/vpp/010_interfaces_test.go index 65ab21a6f6..53ff710347 100644 --- a/tests/integration/vpp/010_interfaces_test.go +++ b/tests/integration/vpp/010_interfaces_test.go @@ -67,7 +67,7 @@ func TestInterfaceEnabledFieldWithLoopback(t *testing.T) { } // Test after creation - ifaces, err := h.DumpInterfaces(test.Context) + ifaces, err := h.DumpInterfaces(test.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -83,11 +83,11 @@ func TestInterfaceEnabledFieldWithLoopback(t *testing.T) { } // Set AdminUp and test again - err = h.InterfaceAdminUp(test.Context, ifIdx0) + err = h.InterfaceAdminUp(test.Ctx, ifIdx0) if err != nil { t.Fatalf("enabling interface failed: %v", err) } - ifaces, err = h.DumpInterfaces(test.Context) + ifaces, err = h.DumpInterfaces(test.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -103,11 +103,11 @@ func TestInterfaceEnabledFieldWithLoopback(t *testing.T) { } // Set AdminDown and test again - err = h.InterfaceAdminDown(test.Context, ifIdx0) + err = h.InterfaceAdminDown(test.Ctx, ifIdx0) if err != nil { t.Fatalf("disabling interface failed: %v", err) } - ifaces, err = h.DumpInterfaces(test.Context) + ifaces, err = h.DumpInterfaces(test.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -148,7 +148,7 @@ func TestInterfaceEnabledFieldWithMemif(t *testing.T) { } // Test after creation - ifaces, err := h.DumpInterfaces(test.Context) + ifaces, err := h.DumpInterfaces(test.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -164,11 +164,11 @@ func TestInterfaceEnabledFieldWithMemif(t *testing.T) { } // Set AdminUp and test again - err = h.InterfaceAdminUp(test.Context, memifIdx) + err = h.InterfaceAdminUp(test.Ctx, memifIdx) if err != nil { t.Fatalf("enabling interface failed: %v", err) } - ifaces, err = h.DumpInterfaces(test.Context) + ifaces, err = h.DumpInterfaces(test.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -184,11 +184,11 @@ func TestInterfaceEnabledFieldWithMemif(t *testing.T) { } // Set AdminDown and test again - err = h.InterfaceAdminDown(test.Context, memifIdx) + err = h.InterfaceAdminDown(test.Ctx, memifIdx) if err != nil { t.Fatalf("disabling interface failed: %v", err) } - ifaces, err = h.DumpInterfaces(test.Context) + ifaces, err = h.DumpInterfaces(test.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -260,7 +260,7 @@ func TestLoopbackInterface(t *testing.T) { } t.Logf("loopback index: %+v", ifIdx) - ifaces, err := h.DumpInterfaces(test.Context) + ifaces, err := h.DumpInterfaces(test.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -305,7 +305,7 @@ func TestMemifInterface(t *testing.T) { } t.Logf("memif index: %+v", ifIdx) - ifaces, err := h.DumpInterfaces(test.Context) + ifaces, err := h.DumpInterfaces(test.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } diff --git a/tests/integration/vpp/020_routes_test.go b/tests/integration/vpp/020_routes_test.go index 613875e379..4af4050d8e 100644 --- a/tests/integration/vpp/020_routes_test.go +++ b/tests/integration/vpp/020_routes_test.go @@ -100,7 +100,7 @@ func TestCRUDIPv4Route(t *testing.T) { t.Logf("%d routes dumped", routesCnt) newRoute := vpp_l3.Route{VrfId: 0, DstNetwork: "192.168.10.0/24", NextHopAddr: "192.168.30.1", OutgoingInterface: ifName} - err = h.VppAddRoute(test.Context, &newRoute) + err = h.VppAddRoute(test.Ctx, &newRoute) if err != nil { t.Fatalf("adding route failed: %v", err) } @@ -128,7 +128,7 @@ func TestCRUDIPv4Route(t *testing.T) { t.Error("Added route is not present in route dump") } - err = h.VppDelRoute(test.Context, &newRoute) + err = h.VppDelRoute(test.Ctx, &newRoute) if err != nil { t.Fatalf("deleting route failed: %v", err) } @@ -166,7 +166,7 @@ func TestCRUDIPv4Route(t *testing.T) { t.Logf("%d routes dumped", routesCnt) newRoute = vpp_l3.Route{VrfId: 2, DstNetwork: "192.168.10.0/24", NextHopAddr: "192.168.30.1", OutgoingInterface: ifName} - err = h.VppAddRoute(test.Context, &newRoute) + err = h.VppAddRoute(test.Ctx, &newRoute) if err != nil { t.Fatalf("adding route failed: %v", err) } @@ -194,7 +194,7 @@ func TestCRUDIPv4Route(t *testing.T) { t.Error("Added route is not present in route dump") } - err = h.VppDelRoute(test.Context, &newRoute) + err = h.VppDelRoute(test.Ctx, &newRoute) if err != nil { t.Fatalf("deleting route failed: %v", err) } @@ -249,7 +249,7 @@ func TestCRUDIPv6Route(t *testing.T) { t.Logf("%d routes dumped", routesCnt) newRoute := vpp_l3.Route{VrfId: 0, DstNetwork: "fd30:0:0:1::/64", NextHopAddr: "fd31::1:1:0:0:1", OutgoingInterface: ifName} - err = h.VppAddRoute(test.Context, &newRoute) + err = h.VppAddRoute(test.Ctx, &newRoute) if err != nil { t.Fatalf("adding route failed: %v", err) } @@ -276,7 +276,7 @@ func TestCRUDIPv6Route(t *testing.T) { t.Error("Added route is not present in route dump") } - err = h.VppDelRoute(test.Context, &newRoute) + err = h.VppDelRoute(test.Ctx, &newRoute) if err != nil { t.Fatalf("deleting route failed: %v", err) } @@ -314,7 +314,7 @@ func TestCRUDIPv6Route(t *testing.T) { t.Logf("%d routes dumped", routesCnt) newRoute = vpp_l3.Route{VrfId: 2, DstNetwork: "fd30:0:0:1::/64", NextHopAddr: "fd31::1:1:0:0:1", OutgoingInterface: ifName} - err = h.VppAddRoute(test.Context, &newRoute) + err = h.VppAddRoute(test.Ctx, &newRoute) if err != nil { t.Fatalf("adding route failed: %v", err) } @@ -341,7 +341,7 @@ func TestCRUDIPv6Route(t *testing.T) { t.Error("Added route is not present in route dump") } - err = h.VppDelRoute(test.Context, &newRoute) + err = h.VppDelRoute(test.Ctx, &newRoute) if err != nil { t.Fatalf("deleting route failed: %v", err) } diff --git a/tests/integration/vpp/021_l3xc_test.go b/tests/integration/vpp/021_l3xc_test.go index 75cb75e8fb..d92cd1cca1 100644 --- a/tests/integration/vpp/021_l3xc_test.go +++ b/tests/integration/vpp/021_l3xc_test.go @@ -61,7 +61,7 @@ func TestL3XC(t *testing.T) { if err := ih.AddInterfaceIP(ifIdx1, &ipNet1); err != nil { t.Fatalf("adding interface IP failed: %v", err) } - if err := ih.InterfaceAdminUp(test.Context, ifIdx1); err != nil { + if err := ih.InterfaceAdminUp(test.Ctx, ifIdx1); err != nil { t.Fatalf("setting interface admin up failed: %v", err) } @@ -78,7 +78,7 @@ func TestL3XC(t *testing.T) { if err := ih.AddInterfaceIP(ifIdx2, &ipNet2); err != nil { t.Fatalf("adding interface IP failed: %v", err) } - if err := ih.InterfaceAdminUp(test.Context, ifIdx2); err != nil { + if err := ih.InterfaceAdminUp(test.Ctx, ifIdx2); err != nil { t.Fatalf("setting interface admin up failed: %v", err) } @@ -86,14 +86,14 @@ func TestL3XC(t *testing.T) { l3Handler := l3plugin_vppcalls.CompatibleL3VppHandler(test.vppClient, ifIndexes, vrfIndexes, netalloc_mock.NewMockNetAlloc(), logrus.NewLogger("test")) - l3xcs, err := l3Handler.DumpL3XC(test.Context, math.MaxUint32) + l3xcs, err := l3Handler.DumpL3XC(test.Ctx, math.MaxUint32) if err != nil { t.Fatalf("dumping l3xcs failed: %v", err) } else if len(l3xcs) != 0 { t.Fatalf("expected empty dump, but got: %+v", l3xcs) } - err = l3Handler.UpdateL3XC(test.Context, &l3plugin_vppcalls.L3XC{ + err = l3Handler.UpdateL3XC(test.Ctx, &l3plugin_vppcalls.L3XC{ SwIfIndex: ifIdx1, IsIPv6: false, Paths: []l3plugin_vppcalls.Path{ @@ -107,7 +107,7 @@ func TestL3XC(t *testing.T) { t.Fatalf("unexpected error on updating l3xcs: %v", err) } - l3xcs, err = l3Handler.DumpL3XC(test.Context, math.MaxUint32) + l3xcs, err = l3Handler.DumpL3XC(test.Ctx, math.MaxUint32) if err != nil { t.Fatalf("dumping l3xcs failed: %v", err) } else if n := len(l3xcs); n != 1 { @@ -128,12 +128,12 @@ func TestL3XC(t *testing.T) { t.Fatalf("expected path Nh to be %v, but got %v", ipNet2.IP, path.NextHop) } - err = l3Handler.DeleteL3XC(test.Context, ifIdx1, false) + err = l3Handler.DeleteL3XC(test.Ctx, ifIdx1, false) if err != nil { t.Fatalf("deleting l3xc failed: %v", err) } - l3xcs, err = l3Handler.DumpL3XC(test.Context, math.MaxUint32) + l3xcs, err = l3Handler.DumpL3XC(test.Ctx, math.MaxUint32) if err != nil { t.Fatalf("dumping l3xcs failed: %v", err) } else if len(l3xcs) != 0 { diff --git a/tests/integration/vpp/022_ip_neighbor_test.go b/tests/integration/vpp/022_ip_neighbor_test.go index 5c1dc86665..2c2a18df4a 100644 --- a/tests/integration/vpp/022_ip_neighbor_test.go +++ b/tests/integration/vpp/022_ip_neighbor_test.go @@ -51,7 +51,7 @@ func TestIPNeighbor(t *testing.T) { ) cliShowConfig := func() { - out, err := vpp.RunCli(test.Context, "show ip scan-neighbor") + out, err := vpp.RunCli(test.Ctx, "show ip scan-neighbor") if err != nil { t.Fatal(err) } diff --git a/tests/integration/vpp/080_gre_test.go b/tests/integration/vpp/080_gre_test.go index 5225c3ca49..b018b83527 100644 --- a/tests/integration/vpp/080_gre_test.go +++ b/tests/integration/vpp/080_gre_test.go @@ -123,7 +123,7 @@ func TestGre(t *testing.T) { } } - ifaces, err := h.DumpInterfaces(ctx.Context) + ifaces, err := h.DumpInterfaces(ctx.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -155,7 +155,7 @@ func TestGre(t *testing.T) { t.Fatalf("delete GRE tunnel failed: %v\n", err) } - ifaces, err = h.DumpInterfaces(ctx.Context) + ifaces, err = h.DumpInterfaces(ctx.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } diff --git a/tests/integration/vpp/090_vxlan_gpe_test.go b/tests/integration/vpp/090_vxlan_gpe_test.go index 7663ace1cb..ffaa6db47c 100644 --- a/tests/integration/vpp/090_vxlan_gpe_test.go +++ b/tests/integration/vpp/090_vxlan_gpe_test.go @@ -114,7 +114,7 @@ func TestVxlanGpe(t *testing.T) { } } - ifaces, err := h.DumpInterfaces(ctx.Context) + ifaces, err := h.DumpInterfaces(ctx.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -148,7 +148,7 @@ func TestVxlanGpe(t *testing.T) { t.Fatalf("delete VxLAN-GPE tunnel failed: %v\n", err) } - ifaces, err = h.DumpInterfaces(ctx.Context) + ifaces, err = h.DumpInterfaces(ctx.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } diff --git a/tests/integration/vpp/100_gtpu_test.go b/tests/integration/vpp/100_gtpu_test.go index 7819e4c902..5b2fa27ec4 100644 --- a/tests/integration/vpp/100_gtpu_test.go +++ b/tests/integration/vpp/100_gtpu_test.go @@ -152,7 +152,7 @@ func TestGtpu(t *testing.T) { } if dumpAPIOk { - ifaces, err := h.DumpInterfaces(ctx.Context) + ifaces, err := h.DumpInterfaces(ctx.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } @@ -198,7 +198,7 @@ func TestGtpu(t *testing.T) { } if dumpAPIOk { - ifaces, err := h.DumpInterfaces(ctx.Context) + ifaces, err := h.DumpInterfaces(ctx.Ctx) if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } diff --git a/tests/integration/vpp/integration_test.go b/tests/integration/vpp/integration_test.go index 7162b4f9ca..1b418ecbd0 100644 --- a/tests/integration/vpp/integration_test.go +++ b/tests/integration/vpp/integration_test.go @@ -69,7 +69,7 @@ const ( type TestCtx struct { t *testing.T - Context context.Context + Ctx context.Context vppCmd *exec.Cmd stderr, stdout *bytes.Buffer Conn *govppcore.Connection @@ -225,7 +225,7 @@ func setupVPP(t *testing.T) *TestCtx { return &TestCtx{ t: t, - Context: ctx, + Ctx: ctx, versionInfo: versionInfo, vpp: vpeHandler, vppCmd: vppCmd, diff --git a/tests/integration/vpp/utils.go b/tests/integration/vpp/utils.go new file mode 100644 index 0000000000..d2d9192d27 --- /dev/null +++ b/tests/integration/vpp/utils.go @@ -0,0 +1,37 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package vpp + +import ( + "unicode" + + "github.com/onsi/gomega" + "github.com/onsi/gomega/types" +) + +func BePrintable() types.GomegaMatcher { + return gomega.WithTransform(func(s string) bool { + return isAsciiPrintable(s) + }, gomega.BeTrue()) +} + +func isAsciiPrintable(s string) bool { + for _, r := range s { + if r > unicode.MaxASCII || !unicode.IsPrint(r) { + return false + } + } + return true +} From d8dffb7bc1d00ec1aa4d165d9b3685503c785593 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 21 Feb 2020 15:22:12 +0100 Subject: [PATCH 3/7] Fix race condition related to retrieving stats Signed-off-by: Ondrej Fabry --- cmd/vpp-agent/app/vpp_agent.go | 2 +- plugins/govppmux/client_stats.go | 10 ++++++++++ plugins/govppmux/plugin_impl_govppmux.go | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/cmd/vpp-agent/app/vpp_agent.go b/cmd/vpp-agent/app/vpp_agent.go index ff977c2d76..7304d84461 100644 --- a/cmd/vpp-agent/app/vpp_agent.go +++ b/cmd/vpp-agent/app/vpp_agent.go @@ -162,7 +162,7 @@ func (a *VPPAgent) AfterInit() error { } // Close could close used resources. -func (VPPAgent) Close() error { +func (a *VPPAgent) Close() error { return nil } diff --git a/plugins/govppmux/client_stats.go b/plugins/govppmux/client_stats.go index d9e13bae23..4e7d5f19d5 100644 --- a/plugins/govppmux/client_stats.go +++ b/plugins/govppmux/client_stats.go @@ -40,6 +40,8 @@ func (p *Plugin) GetSystemStats(stats *govppapi.SystemStats) error { if p.statsConn == nil { return nil } + p.statsMu.Lock() + defer p.statsMu.Unlock() return p.statsConn.GetSystemStats(stats) } @@ -48,6 +50,8 @@ func (p *Plugin) GetNodeStats(stats *govppapi.NodeStats) error { if p.statsConn == nil { return nil } + p.statsMu.Lock() + defer p.statsMu.Unlock() return p.statsConn.GetNodeStats(stats) } @@ -56,6 +60,8 @@ func (p *Plugin) GetInterfaceStats(stats *govppapi.InterfaceStats) error { if p.statsConn == nil { return nil } + p.statsMu.Lock() + defer p.statsMu.Unlock() return p.statsConn.GetInterfaceStats(stats) } @@ -64,6 +70,8 @@ func (p *Plugin) GetErrorStats(stats *govppapi.ErrorStats) error { if p.statsConn == nil { return nil } + p.statsMu.Lock() + defer p.statsMu.Unlock() return p.statsConn.GetErrorStats(stats) } @@ -72,5 +80,7 @@ func (p *Plugin) GetBufferStats(stats *govppapi.BufferStats) error { if p.statsConn == nil { return nil } + p.statsMu.Lock() + defer p.statsMu.Unlock() return p.statsConn.GetBufferStats(stats) } diff --git a/plugins/govppmux/plugin_impl_govppmux.go b/plugins/govppmux/plugin_impl_govppmux.go index 41ab5f7056..1ae14fa4f4 100644 --- a/plugins/govppmux/plugin_impl_govppmux.go +++ b/plugins/govppmux/plugin_impl_govppmux.go @@ -62,6 +62,7 @@ type Plugin struct { lastConnErr error vppapiChan govppapi.Channel + statsMu sync.Mutex statsAdapter adapter.StatsAPI statsConn *govpp.StatsConnection From d47e0aea5d1a4f38128c9b196364813449b1489b Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 21 Feb 2020 15:22:39 +0100 Subject: [PATCH 4/7] Update version package Signed-off-by: Ondrej Fabry --- cmd/vpp-agent/main.go | 24 ++++++++++++++++-------- pkg/version/version.go | 32 +++++++++++++++++++------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/cmd/vpp-agent/main.go b/cmd/vpp-agent/main.go index 2f4d061a85..77615db6f0 100644 --- a/cmd/vpp-agent/main.go +++ b/cmd/vpp-agent/main.go @@ -19,6 +19,7 @@ package main import ( "flag" "fmt" + "io/ioutil" "log" "os" "time" @@ -34,7 +35,7 @@ import ( ) const logo = ` __ - _ _____ ___ _______ ____ ____ ___ / /_ + _ _____ ___ _______ ____ ____ ___ / /_ %s | |/ / _ \/ _ /___/ _ '/ _ '/ -_/ _ / __/ %s |___/ .__/ .__/ \_'_/\_' /\__/_//_\__/ %s /_/ /_/ /___/ %s @@ -42,25 +43,32 @@ const logo = ` __ ` func parseVersion() { - ver, rev, date := version.Data() - agent.BuildVersion = ver - agent.CommitHash = rev - agent.BuildDate = date s := flag.NewFlagSet("version", flag.ContinueOnError) - v := s.Bool("version", false, "Print version info and exit.") s.Usage = func() {} + s.SetOutput(ioutil.Discard) + var ( + v = s.Bool("V", false, "Print version and exit.") + vv = s.Bool("version", false, "Print version info and exit.") + ) if err := s.Parse(os.Args[1:]); err == nil { if *v { + fmt.Fprintln(os.Stdout, version.Version()) + os.Exit(0) + } + if *vv { fmt.Fprintln(os.Stdout, version.Info()) os.Exit(0) } } + ver, rev, date := version.Data() + agent.BuildVersion = ver + agent.CommitHash = rev + agent.BuildDate = date } func main() { parseVersion() - - fmt.Fprintf(os.Stderr, logo, version.Short(), version.BuiltStamp(), version.BuiltBy()) + fmt.Fprintf(os.Stderr, logo, version.App(), version.Version(), version.BuiltOn(), version.BuiltBy()) if debug.IsEnabled() { logging.DefaultLogger.SetLevel(logging.DebugLevel) diff --git a/pkg/version/version.go b/pkg/version/version.go index 4f56ff8c9c..e9163ed4ac 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -36,11 +36,10 @@ var buildTime time.Time var revision string func init() { - buildstampInt64, _ := strconv.ParseInt(buildDate, 10, 64) - if buildstampInt64 == 0 { - buildstampInt64 = time.Now().Unix() + if buildDate != "" { + buildstampInt64, _ := strconv.ParseInt(buildDate, 10, 64) + buildTime = time.Unix(buildstampInt64, 0) } - buildTime = time.Unix(buildstampInt64, 0) revision = gitCommit if len(revision) > 7 { revision = revision[:7] @@ -50,8 +49,13 @@ func init() { } } -// String returns version string. -func String() string { +// App returns app name. +func App() string { + return app +} + +// Version returns version string. +func Version() string { return version } @@ -64,22 +68,24 @@ func Short() string { return fmt.Sprintf(`%s %s`, app, version) } -func BuiltStamp() string { - return fmt.Sprintf("%s (%s)", buildTime.Format(time.UnixDate), timeAgo(buildTime)) +func BuiltOn() string { + stamp := fmt.Sprintf("%s", buildTime.Format(time.UnixDate)) + if !buildTime.IsZero() { + stamp += fmt.Sprintf(" (%s)", timeAgo(buildTime)) + } + return stamp } func BuiltBy() string { return fmt.Sprintf("%s@%s (%s %s/%s)", - buildUser, buildHost, - runtime.Version(), runtime.GOOS, runtime.GOARCH, + buildUser, buildHost, runtime.Version(), runtime.GOOS, runtime.GOARCH, ) } // Info returns string with complete version info on single line. func Info() string { - return fmt.Sprintf(`%s %s (%s) built by %s@%s on %v (%s)`, - app, version, revision, - buildUser, buildHost, buildTime.Format(time.Stamp), timeAgo(buildTime), + return fmt.Sprintf(`%s %s (%s) built by %s@%s on %v`, + app, version, revision, buildUser, buildHost, BuiltOn(), ) } From 3bfe2e7dbf9ba2ba7c24abf8eeb8ffc9b45292fb Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 21 Feb 2020 15:23:03 +0100 Subject: [PATCH 5/7] Add prometheus metrics to govppmux Signed-off-by: Ondrej Fabry --- plugins/govppmux/client_binapi.go | 60 ++++------- plugins/govppmux/metrics.go | 167 ++++++++++++++++++++++++++++++ plugins/govppmux/stats.go | 25 +++-- plugins/telemetry/metrics.go | 43 ++++++++ 4 files changed, 245 insertions(+), 50 deletions(-) create mode 100644 plugins/govppmux/metrics.go create mode 100644 plugins/telemetry/metrics.go diff --git a/plugins/govppmux/client_binapi.go b/plugins/govppmux/client_binapi.go index 89d62541c1..4076df3ef3 100644 --- a/plugins/govppmux/client_binapi.go +++ b/plugins/govppmux/client_binapi.go @@ -17,7 +17,6 @@ package govppmux import ( "context" "runtime/trace" - "sync/atomic" "time" govppapi "git.fd.io/govpp.git/api" @@ -27,10 +26,6 @@ import ( // NewAPIChannel returns a new API channel for communication with VPP via govpp core. // It uses default buffer sizes for the request and reply Go channels. -// -// Example of binary API call from some plugin using GOVPP: -// ch, _ := govpp_mux.NewAPIChannel() -// ch.SendRequest(req).ReceiveReply func (p *Plugin) NewAPIChannel() (govppapi.Channel, error) { ch, err := p.vppConn.NewAPIChannel() if err != nil { @@ -45,10 +40,6 @@ func (p *Plugin) NewAPIChannel() (govppapi.Channel, error) { // NewAPIChannelBuffered returns a new API channel for communication with VPP via govpp core. // It allows to specify custom buffer sizes for the request and reply Go channels. -// -// Example of binary API call from some plugin using GOVPP: -// ch, _ := govpp_mux.NewAPIChannelBuffered(100, 100) -// ch.SendRequest(req).ReceiveReply func (p *Plugin) NewAPIChannelBuffered(reqChanBufSize, replyChanBufSize int) (govppapi.Channel, error) { ch, err := p.vppConn.NewAPIChannelBuffered(reqChanBufSize, replyChanBufSize) if err != nil { @@ -75,14 +66,13 @@ func newGovppChan(ch govppapi.Channel, retryCfg retryConfig) *goVppChan { Channel: ch, retry: retryCfg, } - atomic.AddUint64(&stats.ChannelsCreated, 1) - atomic.AddUint64(&stats.ChannelsOpen, 1) + reportChannelsOpened() return govppChan } func (c *goVppChan) Close() { c.Channel.Close() - atomic.AddUint64(&stats.ChannelsOpen, ^uint64(0)) // decrement + reportChannelsClosed() } // helper struct holding info about retry configuration @@ -130,7 +120,7 @@ func (c *goVppChan) SendRequest(request govppapi.Message) govppapi.RequestCtx { // Send request now and wait for context requestCtx := c.Channel.SendRequest(request) - atomic.AddUint64(&stats.RequestsSent, 1) + reportRequestSent(request) // Return context with value and function which allows to send request again if needed return &govppRequestCtx{ @@ -149,37 +139,30 @@ func (r *govppRequestCtx) ReceiveReply(reply govppapi.Message) error { defer r.task.End() var timeout time.Duration - maxRetries := r.retry.attempts + attempts := r.retry.attempts if r.retry.timeout > 0 { // Default value is 500ms timeout = r.retry.timeout } - // Receive reply from original send err := r.requestCtx.ReceiveReply(reply) - for retry := 1; err == core.ErrNotConnected; retry++ { - if retry > maxRetries { - // retrying failed - break + if retry > attempts { + break // max attempts exceeded } - logging.Warnf("Govppmux: request retry (%d/%d), message %s in %v", - retry, maxRetries, r.requestMsg.GetMessageName(), timeout) + logging.Warnf("govppmux: request retry (%d/%d), message %s in %v", + retry, attempts, r.requestMsg.GetMessageName(), timeout) // Wait before next attempt time.Sleep(timeout) // Retry request - trace.Logf(r.ctx, "requestRetry", "%d/%d", retry, maxRetries) + trace.Logf(r.ctx, "requestRetry", "%d/%d", retry, attempts) err = r.sendRequest(r.requestMsg).ReceiveReply(reply) } - - atomic.AddUint64(&stats.RequestsDone, 1) if err != nil { - trackError(err.Error()) - atomic.AddUint64(&stats.RequestsFail, 1) + reportRequestFailed(reply, err) + } else { + reportRequestSuccess(r.requestMsg, r.start) + reportRepliesReceived(reply) } - - took := time.Since(r.start) - trackMsgRequestDur(r.requestMsg.GetMessageName(), took) - return err } @@ -192,7 +175,7 @@ func (c *goVppChan) SendMultiRequest(request govppapi.Message) govppapi.MultiReq // Send request now and wait for context requestCtx := c.Channel.SendMultiRequest(request) - atomic.AddUint64(&stats.RequestsSent, 1) + reportRequestSent(request) // Return context with value and function which allows to send request again if needed return &govppMultirequestCtx{ @@ -209,19 +192,14 @@ func (r *govppMultirequestCtx) ReceiveReply(reply govppapi.Message) (bool, error // Receive reply from original send last, err := r.requestCtx.ReceiveReply(reply) if last || err != nil { - took := time.Since(r.start) - trackMsgRequestDur(r.requestMsg.GetMessageName(), took) - - atomic.AddUint64(&stats.RequestsDone, 1) + defer r.task.End() if err != nil { - trackError(err.Error()) - atomic.AddUint64(&stats.RequestsFail, 1) + reportRequestFailed(r.requestMsg, err) + } else { + reportRequestSuccess(r.requestMsg, r.start) } - - defer r.task.End() } else { - atomic.AddUint64(&stats.RequestReplies, 1) - trackMsgReply(reply.GetMessageName()) + reportRepliesReceived(reply) } return last, err } diff --git a/plugins/govppmux/metrics.go b/plugins/govppmux/metrics.go new file mode 100644 index 0000000000..f8cf4551dc --- /dev/null +++ b/plugins/govppmux/metrics.go @@ -0,0 +1,167 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package govppmux + +import ( + "sync/atomic" + "time" + + govppapi "git.fd.io/govpp.git/api" + "github.com/prometheus/client_golang/prometheus" +) + +// Set of raw Prometheus metrics. +// Labels +// * message +// * +// Do not increment directly, use Report* methods. +var ( + channelsCreated = prometheus.NewCounter(prometheus.CounterOpts{ + Namespace: "ligato", + Subsystem: "govppmux", + Name: "channels_created_total", + Help: "The total number of created channels.", + }) + channelsCount = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "ligato", + Subsystem: "govppmux", + Name: "channels", + Help: "The current number of opened channels.", + }) + requestsSent = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "ligato", + Subsystem: "govppmux", + Name: "requests_total", + Help: "The total number of sent requests.", + }, + []string{"message"}, + ) + requestsCount = prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "ligato", + Subsystem: "govppmux", + Name: "requests", + Help: "The current number of in-flight requests.", + }) + requestsFailed = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "ligato", + Subsystem: "govppmux", + Name: "requests_failed_total", + Help: "The total number of failed requests.", + }, + []string{"message", "error"}, + ) + requestsDone = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "ligato", + Subsystem: "govppmux", + Name: "requests_done_total", + Help: "The total number of done requests.", + }, + []string{"message"}, + ) + repliesReceived = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "ligato", + Subsystem: "govppmux", + Name: "replies_received_total", + Help: "The total number of received replies.", + }, + []string{"message"}, + ) + successfulRequestHandlingSec = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "ligato", + Subsystem: "govppmux", + Name: "successful_request_duration_seconds", + Help: "Bucketed histogram of processing time of successfully handled requests by message name.", + // lowest bucket start of upper bound 0.0005 sec (0.5 ms) with factor 2 + // highest bucket start of 0.0005 sec * 2^12 == 2.048 sec + Buckets: prometheus.ExponentialBuckets(0.0005, 2, 13), + }, + []string{"message"}, + ) +) + +func init() { + prometheus.MustRegister(channelsCreated) + prometheus.MustRegister(channelsCount) + prometheus.MustRegister(requestsSent) + prometheus.MustRegister(requestsCount) + prometheus.MustRegister(requestsDone) + prometheus.MustRegister(requestsFailed) + prometheus.MustRegister(repliesReceived) + prometheus.MustRegister(successfulRequestHandlingSec) +} + +func reportChannelsOpened() { + channelsCreated.Inc() + channelsCount.Inc() + + if DisableOldStats { + return + } + atomic.AddUint64(&stats.ChannelsCreated, 1) + atomic.AddUint64(&stats.ChannelsOpen, 1) +} + +func reportChannelsClosed() { + channelsCount.Dec() + + if DisableOldStats { + return + } + atomic.AddUint64(&stats.ChannelsOpen, ^uint64(0)) // decrement +} + +func reportRequestSent(request govppapi.Message) { + requestsCount.Inc() + requestsSent.WithLabelValues(request.GetMessageName()).Inc() + + if DisableOldStats { + return + } + atomic.AddUint64(&stats.RequestsSent, 1) +} + +func reportRequestFailed(request govppapi.Message, err error) { + requestsCount.Dec() + requestsFailed.WithLabelValues(request.GetMessageName(), err.Error()).Inc() + + if DisableOldStats { + return + } + trackError(err.Error()) + atomic.AddUint64(&stats.RequestsFail, 1) +} + +func reportRequestSuccess(request govppapi.Message, startTime time.Time) { + took := time.Since(startTime) + requestsCount.Dec() + requestsDone.WithLabelValues(request.GetMessageName()).Inc() + successfulRequestHandlingSec.WithLabelValues(request.GetMessageName()).Observe(took.Seconds()) + + if DisableOldStats { + return + } + atomic.AddUint64(&stats.RequestsDone, 1) + trackMsgRequestDur(request.GetMessageName(), took) +} + +func reportRepliesReceived(reply govppapi.Message) { + repliesReceived.WithLabelValues(reply.GetMessageName()).Inc() + + if DisableOldStats { + return + } + atomic.AddUint64(&stats.RequestReplies, 1) + trackMsgReply(reply.GetMessageName()) +} diff --git a/plugins/govppmux/stats.go b/plugins/govppmux/stats.go index 0135a69f3b..91208ad3b2 100644 --- a/plugins/govppmux/stats.go +++ b/plugins/govppmux/stats.go @@ -16,6 +16,7 @@ package govppmux import ( "expvar" + "os" "sync" "time" @@ -23,18 +24,33 @@ import ( "go.ligato.io/vpp-agent/v3/proto/ligato/govppmux" ) +// DisableOldStats is used to disabled old way of collecting stats. +var DisableOldStats = os.Getenv("GOVPPMUX_OLDSTATS_DISABLED") != "" + var ( stats Stats statsMu sync.RWMutex ) func init() { + if DisableOldStats { + return + } stats.Errors = make(metrics.Calls) stats.Messages = make(metrics.Calls) stats.Replies = make(metrics.Calls) + metrics.Register(&govppmux.Metrics{}, func() interface{} { + return &GetStats().Metrics + }) + expvar.Publish("govppmux.stats", expvar.Func(func() interface{} { + return &GetStats().Metrics + })) } func GetStats() *Stats { + if DisableOldStats { + return nil + } s := new(Stats) statsMu.RLock() *s = stats @@ -114,12 +130,3 @@ func trackError(m string) { ms.Increment(0) statsMu.Unlock() } - -func init() { - metrics.Register(&govppmux.Metrics{}, func() interface{} { - return &GetStats().Metrics - }) - expvar.Publish("govppmux.stats", expvar.Func(func() interface{} { - return &GetStats().Metrics - })) -} diff --git a/plugins/telemetry/metrics.go b/plugins/telemetry/metrics.go new file mode 100644 index 0000000000..613949ce67 --- /dev/null +++ b/plugins/telemetry/metrics.go @@ -0,0 +1,43 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package telemetry + +import ( + "github.com/prometheus/client_golang/prometheus" + + "go.ligato.io/vpp-agent/v3/pkg/version" +) + +var ( + currentVersion = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "ligato", + Subsystem: "build", + Name: "info", + Help: "Which version is running. 1 for 'agent_version' label with current version.", + }, + []string{"version", "revision", "build_date", "built_by"}, + ) + processMetrics = prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{ + Namespace: "ligato", + }) +) + +func init() { + prometheus.MustRegister(currentVersion) + prometheus.MustRegister(processMetrics) + + ver, rev, date := version.Data() + currentVersion.WithLabelValues(ver, rev, date, version.BuiltBy()).Set(1) +} From 1b585bfa4e90f0ff41caf7903221a521858de169 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 21 Feb 2020 16:46:13 +0100 Subject: [PATCH 6/7] Address linter review Signed-off-by: Ondrej Fabry --- pkg/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/version/version.go b/pkg/version/version.go index e9163ed4ac..c6ad9f8c44 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -69,7 +69,7 @@ func Short() string { } func BuiltOn() string { - stamp := fmt.Sprintf("%s", buildTime.Format(time.UnixDate)) + stamp := buildTime.Format(time.UnixDate) if !buildTime.IsZero() { stamp += fmt.Sprintf(" (%s)", timeAgo(buildTime)) } From 66f83a4f4c2674a9c430fe3eeb47be57c1bb339f Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 21 Feb 2020 17:43:02 +0100 Subject: [PATCH 7/7] Fix integration test Signed-off-by: Ondrej Fabry --- plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go | 8 ++++---- tests/integration/vpp/000_initial_test.go | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go b/plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go index 1a9a70f4a9..39ff3dbcfb 100644 --- a/plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go +++ b/plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go @@ -40,10 +40,10 @@ func (h *VpeHandler) GetVersion(ctx context.Context) (*vppcalls.VersionInfo, err return nil, err } info := &vppcalls.VersionInfo{ - Program: version.Program, - Version: version.Version, - BuildDate: version.BuildDate, - BuildDirectory: version.BuildDirectory, + Program: strings.TrimRight(version.Program, "\x00"), + Version: strings.TrimRight(version.Version, "\x00"), + BuildDate: strings.TrimRight(version.BuildDate, "\x00"), + BuildDirectory: strings.TrimRight(version.BuildDirectory, "\x00"), } return info, nil } diff --git a/tests/integration/vpp/000_initial_test.go b/tests/integration/vpp/000_initial_test.go index 51b0d1a53f..8102aab884 100644 --- a/tests/integration/vpp/000_initial_test.go +++ b/tests/integration/vpp/000_initial_test.go @@ -43,10 +43,7 @@ func TestGetVersion(t *testing.T) { info, err := vpp.GetVersion(test.Ctx) Expect(err).ToNot(HaveOccurred()) - Expect(info.Version).To(BePrintable()) - Expect(info.Program).To(BePrintable()) - Expect(info.BuildDate).To(BePrintable()) - Expect(info.BuildDirectory).To(BePrintable()) + Expect(info.Version).To(BePrintable(), "Version should be printable string:\n\t%#v", info) } func TestGetPlugins(t *testing.T) {