Skip to content

Commit

Permalink
Add Actuator TC tests
Browse files Browse the repository at this point in the history
Signed-off-by: Adrian Chiris <[email protected]>
  • Loading branch information
adrianchiris committed Aug 4, 2022
1 parent 55d1b33 commit e609d67
Showing 1 changed file with 280 additions and 0 deletions.
280 changes: 280 additions & 0 deletions pkg/tc/actuator_tc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
package tc_test

import (
"flag"

"github.com/pkg/errors"
"k8s.io/klog/v2"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/mock"

"github.com/Mellanox/multi-networkpolicy-tc/pkg/tc"
tctypes "github.com/Mellanox/multi-networkpolicy-tc/pkg/tc/types"

tcmocks "github.com/Mellanox/multi-networkpolicy-tc/pkg/tc/mocks"
)

func ingressQdiscMatch() func(q tctypes.QDisc) bool {
return func(q tctypes.QDisc) bool {
return q.Type() == tctypes.QDiscIngressType
}
}

func filterMatch(filter tctypes.Filter) func(f tctypes.Filter) bool {
return func(f tctypes.Filter) bool {
return filter.Equals(f)
}
}

func filterAttrMatch(filterAttr *tctypes.FilterAttrs) func(f *tctypes.FilterAttrs) bool {
return func(f *tctypes.FilterAttrs) bool {
return filterAttr.Equals(f)
}
}

func chainMatch(chain uint16) func(c tctypes.Chain) bool {
// Note(adrianc): ATM we are not needed to match on parent. it may change...
return func(c tctypes.Chain) bool {
return chain == *c.Attrs().Chain
}
}

var _ = Describe("Actuator TC tests", func() {
var actuator tc.Actuator
var tcMock *tcmocks.TC
var logger klog.Logger

BeforeEach(func() {
// init logger
fs := flag.NewFlagSet("test-flag-set", flag.PanicOnError)
klog.InitFlags(fs)
Expect(fs.Set("v", "8")).ToNot(HaveOccurred())
logger = klog.NewKlogr().WithName("actuator-tc-test")
DeferCleanup(klog.Flush)
By("Logger initialized")

tcMock = tcmocks.NewTC(GinkgoT())
actuator = tc.NewActuatorTCImpl(tcMock, logger)
})

Context("Actuate Qdisc Only", func() {
It("fails if listing qdisc fails", func() {
tcObj := &tc.TCObjects{
QDisc: tctypes.NewIngressQdisc(),
}

tcMock.On("QDiscList").Return(nil, errors.New("test error!"))

err := actuator.Actuate(tcObj)
Expect(err).To(HaveOccurred())
})

It("fails if delete qdisc fails", func() {
tcObj := &tc.TCObjects{}

tcMock.On("QDiscList").Return([]tctypes.QDisc{tctypes.NewIngressQdisc()}, nil)
tcMock.On("QDiscDel", mock.Anything).Return(errors.New("test error!"))

err := actuator.Actuate(tcObj)
Expect(err).To(HaveOccurred())
})

When("TCObjects does not contain Qdisc", func() {
It("deletes ingress Qdisc when exists", func() {
tcObj := &tc.TCObjects{}

tcMock.On("QDiscList").Return([]tctypes.QDisc{tctypes.NewIngressQdisc()}, nil)
tcMock.On("QDiscDel", mock.MatchedBy(ingressQdiscMatch())).Return(nil)

err := actuator.Actuate(tcObj)
Expect(err).ToNot(HaveOccurred())
})

It("does nothing if ingress Qdisc does not exists", func() {
tcObj := &tc.TCObjects{}

tcMock.On("QDiscList").Return([]tctypes.QDisc{}, nil)

err := actuator.Actuate(tcObj)
Expect(err).ToNot(HaveOccurred())
})
})

When("TCObjects contain ingress Qdisc", func() {
It("does nothing if ingress Qdisc exist without chain 0", func() {
tcObj := &tc.TCObjects{
QDisc: tctypes.NewIngressQdisc(),
}

tcMock.On("QDiscList").Return([]tctypes.QDisc{}, nil)
tcMock.On("ChainList", mock.Anything).Return([]tctypes.Chain{
tctypes.NewChainBuilder().WithParent(0xfffffff1).WithChain(1).Build()}, nil)

err := actuator.Actuate(tcObj)
Expect(err).ToNot(HaveOccurred())
})

It("deletes chain 0 on ingress qdisc when exists", func() {
tcObj := &tc.TCObjects{
QDisc: tctypes.NewIngressQdisc(),
}

tcMock.On("QDiscList").Return([]tctypes.QDisc{}, nil)
tcMock.On("ChainList", mock.Anything).Return([]tctypes.Chain{
tctypes.NewChainBuilder().WithParent(0xfffffff1).WithChain(0).Build()}, nil)
tcMock.On("ChainDel",
mock.MatchedBy(ingressQdiscMatch()),
mock.MatchedBy(chainMatch(0))).
Return(nil)

err := actuator.Actuate(tcObj)
Expect(err).ToNot(HaveOccurred())
})

It("does nothing if ingress Qdisc exists, chain 0 does not exist", func() {
tcObj := &tc.TCObjects{
QDisc: tctypes.NewIngressQdisc(),
}

tcMock.On("QDiscList").Return([]tctypes.QDisc{tctypes.NewIngressQdisc()}, nil)
tcMock.On("ChainList", mock.Anything).Return([]tctypes.Chain{}, nil)

err := actuator.Actuate(tcObj)
Expect(err).ToNot(HaveOccurred())
})

It("fails if delete chain fails", func() {
tcObj := &tc.TCObjects{
QDisc: tctypes.NewIngressQdisc(),
}

tcMock.On("QDiscList").Return([]tctypes.QDisc{}, nil)
tcMock.On("ChainList", mock.Anything).Return([]tctypes.Chain{
tctypes.NewChainBuilder().WithParent(0xfffffff1).WithChain(0).Build()}, nil)
tcMock.On("ChainDel", mock.Anything, mock.Anything).Return(errors.New("test error!"))

err := actuator.Actuate(tcObj)
Expect(err).To(HaveOccurred())
})
})
})

Context("Actuate with filters", func() {
neededFilters := []tctypes.Filter{
tctypes.NewFlowerFilterBuilder().
WithProtocol(tctypes.FilterProtocolIP).
WithPriority(100).
WithMatchKeyDstIP("10.100.0.0/24").
WithAction(tctypes.NewGenericActionBuiler().WithDrop().Build()).
Build(),
tctypes.NewFlowerFilterBuilder().
WithProtocol(tctypes.FilterProtocolIP).
WithPriority(200).
WithMatchKeyDstIP("10.100.0.0/16").
WithAction(tctypes.NewGenericActionBuiler().WithPass().Build()).
Build(),
}
existingFilters := []tctypes.Filter{
tctypes.NewFlowerFilterBuilder().
WithProtocol(tctypes.FilterProtocolIP).
WithPriority(100).
WithMatchKeyDstIP("10.100.1.0/24").
WithAction(tctypes.NewGenericActionBuiler().WithDrop().Build()).
Build(),
tctypes.NewFlowerFilterBuilder().
WithProtocol(tctypes.FilterProtocolIP).
WithPriority(200).
WithMatchKeyDstIP("10.100.0.0/16").
WithAction(tctypes.NewGenericActionBuiler().WithPass().Build()).
Build(),
}
var tcObj *tc.TCObjects

BeforeEach(func() {
tcObj = &tc.TCObjects{
QDisc: tctypes.NewIngressQdisc(),
Filters: neededFilters,
}
})

When("no ingress qdisc in TCObjects", func() {
It("fails", func() {
tcObj.QDisc = nil

err := actuator.Actuate(tcObj)
Expect(err).To(HaveOccurred())
})
})

When("filters provided in TCObjects, no filters set on ingress qdisc", func() {
BeforeEach(func() {
tcMock.On("QDiscList").Return([]tctypes.QDisc{tctypes.NewIngressQdisc()}, nil)
})

It("adds them to qdisc", func() {
tcMock.On("FilterList", mock.MatchedBy(ingressQdiscMatch())).Return([]tctypes.Filter{}, nil)
for i := range neededFilters {
tcMock.On(
"FilterAdd",
mock.MatchedBy(ingressQdiscMatch()),
mock.MatchedBy(filterMatch(neededFilters[i]))).
Return(nil)
}

err := actuator.Actuate(tcObj)
Expect(err).ToNot(HaveOccurred())
})

It("fails if listing filter on qdisc fails", func() {
tcMock.On("FilterList", mock.Anything).
Return(nil, errors.New("test error!"))

err := actuator.Actuate(tcObj)
Expect(err).To(HaveOccurred())
})

It("fails if adding filter to qdisc fails", func() {
tcMock.On("FilterList", mock.MatchedBy(ingressQdiscMatch())).Return([]tctypes.Filter{}, nil)
tcMock.On("FilterAdd", mock.Anything, mock.Anything).Return(errors.New("test error!"))

err := actuator.Actuate(tcObj)
Expect(err).To(HaveOccurred())
})
})

When("filters provided in TCObjects, and filters set on ingress qdisc", func() {
BeforeEach(func() {
tcMock.On("QDiscList").Return([]tctypes.QDisc{tctypes.NewIngressQdisc()}, nil)
tcMock.On("FilterList", mock.MatchedBy(ingressQdiscMatch())).Return(existingFilters, nil)
})

It("removes un-needed filters and adds needed filters", func() {
tcMock.On(
"FilterDel",
mock.MatchedBy(ingressQdiscMatch()),
mock.MatchedBy(filterAttrMatch(existingFilters[0].Attrs()))).
Return(nil)
tcMock.On(
"FilterAdd",
mock.MatchedBy(ingressQdiscMatch()),
mock.MatchedBy(filterMatch(neededFilters[0]))).
Return(nil)

err := actuator.Actuate(tcObj)
Expect(err).ToNot(HaveOccurred())
})

It("fails if removing filter from qdisc fails", func() {
tcMock.On(
"FilterDel",
mock.MatchedBy(ingressQdiscMatch()),
mock.MatchedBy(filterAttrMatch(existingFilters[0].Attrs()))).
Return(errors.New("test error!"))
err := actuator.Actuate(tcObj)
Expect(err).To(HaveOccurred())
})
})
})
})

0 comments on commit e609d67

Please sign in to comment.