Skip to content
1 change: 1 addition & 0 deletions ovsnl/client_linux_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
)

func TestLinuxClientIntegration(t *testing.T) {

c, err := ovsnl.New()
if err != nil {
if os.IsNotExist(err) {
Expand Down
11 changes: 6 additions & 5 deletions ovsnl/client_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ import (
"golang.org/x/sys/unix"
)

// newTestClient creates a test client with a mock genetlink connection
func newTestClient(conn *genetlink.Conn) (*Client, error) {
c := &Client{}
c.c = conn

// Initialize services.
families, err := c.c.ListFamilies()
if err != nil {
return nil, err
Expand All @@ -45,10 +43,13 @@ func newTestClient(conn *genetlink.Conn) (*Client, error) {
return nil, err
}

// For testing, we'll skip the aggregator initialization
// since it requires actual kernel conntrack support
c.Agg = nil
// Inject our mock connection directly into the datapath service
if c.Datapath != nil {
c.Datapath.c = c
c.c = conn
}

c.Agg = nil
return c, nil
}

Expand Down
52 changes: 52 additions & 0 deletions ovsnl/datapath_linux_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2017 DigitalOcean.
//
// 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.

//go:build linux && integration
// +build linux,integration

package ovsnl

import (
"testing"
)

// TestClientDatapathListIntegration tests datapath listing with real Open vSwitch
func TestClientDatapathListIntegration(t *testing.T) {
// Skip if not running in integration test environment
if testing.Short() {
t.Skip("skipping integration test")
}

c, err := New()
if err != nil {
t.Skipf("skipping integration test: %v", err)
}
defer c.Close()

dps, err := c.Datapath.List()
if err != nil {
t.Fatalf("failed to list datapaths: %v", err)
}

if len(dps) == 0 {
t.Log("no datapaths found (Open vSwitch may not be running)")
return
}

// Verify we can list datapaths
t.Logf("found %d datapaths", len(dps))
for _, dp := range dps {
t.Logf("datapath: %s (index: %d)", dp.Name, dp.Index)
}
}
37 changes: 22 additions & 15 deletions ovsnl/datapath_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,17 @@ import (

func TestClientDatapathListShortHeader(t *testing.T) {
conn := genltest.Dial(ovsFamilies(func(greq genetlink.Message, nreq netlink.Message) ([]genetlink.Message, error) {
// Not enough data for ovsh.Header.
return []genetlink.Message{
{
Data: []byte{0xff, 0xff},
},
}, nil

// Check if this is the datapath list command
if greq.Header.Command == ovsh.DpCmdGet {
// Return deliberately short data for datapath list
shortData := []byte{0xff, 0xff}
return []genetlink.Message{
{Data: shortData},
}, nil
}

return []genetlink.Message{}, nil
}))

c, err := newTestClient(conn)
Expand All @@ -46,8 +51,9 @@ func TestClientDatapathListShortHeader(t *testing.T) {
}
defer c.Close()

_, err = c.Datapath.List()
if err == nil {
_, errDatapath := c.Datapath.List()
if errDatapath == nil {

t.Fatalf("expected an error, but none occurred")
}

Expand All @@ -59,12 +65,12 @@ func TestClientDatapathListBadStats(t *testing.T) {
// Valid header; not enough data for ovsh.DPStats.
return []genetlink.Message{{
Data: append(
// ovsh.Header.
// ovsh.Header (4 bytes).
[]byte{0xff, 0xff, 0xff, 0xff},
// netlink attributes.
mustMarshalAttributes([]netlink.Attribute{{
Type: ovsh.DpAttrStats,
Data: []byte{0xff},
Data: []byte{0xff}, // Only 1 byte, but sizeofDPStats is 32 bytes
}})...,
),
}}, nil
Expand All @@ -89,12 +95,12 @@ func TestClientDatapathListBadMegaflowStats(t *testing.T) {
// Valid header; not enough data for ovsh.DPMegaflowStats.
return []genetlink.Message{{
Data: append(
// ovsh.Header.
// ovsh.Header (4 bytes).
[]byte{0xff, 0xff, 0xff, 0xff},
// netlink attributes.
mustMarshalAttributes([]netlink.Attribute{{
Type: ovsh.DpAttrMegaflowStats,
Data: []byte{0xff},
Data: []byte{0xff}, // Only 1 byte, but sizeofDPMegaflowStats is 32 bytes
}})...,
),
}}, nil
Expand Down Expand Up @@ -223,14 +229,15 @@ func mustMarshalDatapath(dp Datapath) []byte {
// ovsFamilies creates a test handler that returns OVS family messages
func ovsFamilies(handler func(genetlink.Message, netlink.Message) ([]genetlink.Message, error)) func(genetlink.Message, netlink.Message) ([]genetlink.Message, error) {
return func(greq genetlink.Message, nreq netlink.Message) ([]genetlink.Message, error) {
// Handle family listing requests
if greq.Header.Command == unix.CTRL_CMD_GETFAMILY {

// Handle family listing requests (CTRL family)
if nreq.Header.Type == unix.GENL_ID_CTRL && greq.Header.Command == unix.CTRL_CMD_GETFAMILY {
return familyMessages([]string{
ovsh.DatapathFamily,
}), nil
}

// Handle actual datapath requests
// Handle actual datapath requests (OVS datapath family)
return handler(greq, nreq)
}
}