Skip to content
This repository has been archived by the owner on Jul 19, 2023. It is now read-only.

Commit

Permalink
simple unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
bensolo-io committed Jul 5, 2023
1 parent af79755 commit 30824ef
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 159 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/hashicorp/go-plugin v1.4.9
github.com/sirupsen/logrus v1.9.0
github.com/solo-io/solo-apis v1.6.32-0.20230623162622-377f95c0a7c7
github.com/stretchr/testify v1.8.2
k8s.io/apimachinery v0.26.4
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
sigs.k8s.io/controller-runtime v0.14.6
Expand All @@ -30,6 +31,7 @@ require (
github.com/go-task/slim-sprig v2.20.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.9 // indirect
Expand All @@ -50,6 +52,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand Down Expand Up @@ -286,6 +287,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
Expand All @@ -296,6 +298,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
Expand Down Expand Up @@ -332,6 +335,7 @@ golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hM
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -361,6 +365,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -411,6 +416,7 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200612220849-54c614fe050c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
12 changes: 8 additions & 4 deletions pkg/mocks/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ import (
)

const (
RouteTableName = "httpbin"
RouteTableNamespace = "httpbin"
RouteTableName = "mock"
RouteTableNamespace = "mock"
DestinationKind = "SERVICE"
DestinationNamespace = "httpbin"
DestinationNamespace = "mock"
StableService = "stable"
CanaryService = "canary"
RolloutNamespace = "mock"
RolloutName = "mock"
)

var RouteTable = networkv2.RouteTable{
Expand All @@ -37,7 +41,7 @@ var RouteTable = networkv2.RouteTable{
},
RefKind: &commonv2.DestinationReference_Ref{
Ref: &commonv2.ObjectReference{
Name: RouteTableName,
Name: StableService,
Namespace: DestinationNamespace,
},
},
Expand Down
39 changes: 26 additions & 13 deletions pkg/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ const (

type RpcPlugin struct {
IsTest bool
LogCtx *logrus.Entry
Client networkv2.Clientset
// temporary hack until mock clienset is fixed (missing some interface methods)
MockRouteTable *networkv2.RouteTable
LogCtx *logrus.Entry
Client networkv2.Clientset
}

type GlooPlatformAPITrafficRouting struct {
Expand All @@ -40,6 +42,10 @@ type GlooPlatformAPITrafficRouting struct {
}

func (r *RpcPlugin) InitPlugin() pluginTypes.RpcError {
if r.MockRouteTable != nil {
return pluginTypes.RpcError{}
}

r.LogCtx = r.LogCtx.WithField("PluginName", PluginName)
k, err := util.NewSoloNetworkV2K8sClient()
if err != nil {
Expand All @@ -64,11 +70,16 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad
}
}

rt, err := r.getRouteTable(ctx, glooplatformConfig)
if err != nil {
return pluginTypes.RpcError{
ErrorString: err.Error(),
var rt *networkv2.RouteTable
if r.MockRouteTable == nil {
rt, err = r.getRouteTable(ctx, glooplatformConfig)
if err != nil {
return pluginTypes.RpcError{
ErrorString: err.Error(),
}
}
} else {
rt = r.MockRouteTable
}

// do we need this (not sure if not found yields an error)?
Expand All @@ -80,7 +91,7 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad
r.LogCtx.Debugf("found RT %s", rt.Name)

// get the stable destination
httpRoute, stableDest, canaryDest, err := r.getHttpRefs(rollout.Spec.Strategy.Canary.StableService, rollout.Spec.Strategy.Canary.CanaryService, glooplatformConfig, rt)
httpRoute, stableDest, canaryDest, err := getHttpRefs(rollout.Spec.Strategy.Canary.StableService, rollout.Spec.Strategy.Canary.CanaryService, glooplatformConfig, rt)
if err != nil {
return pluginTypes.RpcError{
ErrorString: err.Error(),
Expand Down Expand Up @@ -120,11 +131,13 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad

r.LogCtx.Debugf("attempting to set stable=%d, canary=%d", stableDest.Weight, canaryDest.Weight)

err = r.Client.RouteTables().UpdateRouteTable(ctx, rt, &k8sclient.UpdateOptions{})
if err != nil {
r.LogCtx.Error(err.Error())
return pluginTypes.RpcError{
ErrorString: err.Error(),
if r.MockRouteTable == nil {
err = r.Client.RouteTables().UpdateRouteTable(ctx, rt, &k8sclient.UpdateOptions{})
if err != nil {
r.LogCtx.Error(err.Error())
return pluginTypes.RpcError{
ErrorString: err.Error(),
}
}
}

Expand Down Expand Up @@ -170,7 +183,7 @@ func (r *RpcPlugin) getRouteTable(ctx context.Context, trafficConfig *GlooPlatfo
})
}

func (r *RpcPlugin) getHttpRefs(stableServiceName string, canaryServiceName string, trafficConfig *GlooPlatformAPITrafficRouting, rt *networkv2.RouteTable) (route *networkv2.HTTPRoute, stable *solov2.DestinationReference, canary *solov2.DestinationReference, err error) {
func getHttpRefs(stableServiceName string, canaryServiceName string, trafficConfig *GlooPlatformAPITrafficRouting, rt *networkv2.RouteTable) (route *networkv2.HTTPRoute, stable *solov2.DestinationReference, canary *solov2.DestinationReference, err error) {
for _, httpRoute := range rt.Spec.Http {
fw := httpRoute.GetForwardTo()
if fw != nil {
Expand Down
170 changes: 170 additions & 0 deletions pkg/plugin/plugin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package plugin

import (
"context"
"encoding/json"
"testing"
"time"

"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
rolloutsPlugin "github.com/argoproj/argo-rollouts/rollout/trafficrouting/plugin/rpc"
"github.com/bensolo-io/rollouts-plugin-trafficrouter-glooplatform/pkg/mocks"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

log "github.com/sirupsen/logrus"

goPlugin "github.com/hashicorp/go-plugin"
)

var testHandshake = goPlugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "ARGO_ROLLOUTS_RPC_PLUGIN",
MagicCookieValue: "trafficrouter",
}

// func TestRollouts(t *testing.T) {

// err := filepath.Walk("testfiles",
// func(path string, info os.FileInfo, err error) error {
// if err != nil {
// return err
// }

// if !info.IsDir() && filepath.Ext(path) == ".yaml" {
// data, err := ioutil.ReadFile(path)
// if err != nil {
// return fmt.Errorf("failed to read bytes from '%s': %s", path, err)
// }
// }

// return nil
// })

// assert.Empty(t, err)
// }

func TestRunSuccessfully(t *testing.T) {
logCtx := log.WithFields(log.Fields{"plugin": "trafficrouter"})
log.SetLevel(log.DebugLevel)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// this is a better way, but mock clientset is missing ExternalEndpoints func
// mockClient := mocknetworkv2.NewMockRouteTableClient(gomock.NewController(t)) //.GetRouteTable(ctx, &mocks.RouteTable)

rpcPluginImp := &RpcPlugin{
LogCtx: logCtx,
MockRouteTable: &mocks.RouteTable,
}

// pluginMap is the map of plugins we can dispense.
var pluginMap = map[string]goPlugin.Plugin{
"RpcTrafficRouterPlugin": &rolloutsPlugin.RpcTrafficRouterPlugin{Impl: rpcPluginImp},
}

ch := make(chan *goPlugin.ReattachConfig, 1)
closeCh := make(chan struct{})
go goPlugin.Serve(&goPlugin.ServeConfig{
HandshakeConfig: testHandshake,
Plugins: pluginMap,
Test: &goPlugin.ServeTestConfig{
Context: ctx,
ReattachConfigCh: ch,
CloseCh: closeCh,
},
})

// We should get a config
var config *goPlugin.ReattachConfig
select {
case config = <-ch:
case <-time.After(2000 * time.Millisecond):
t.Fatal("should've received reattach")
}
if config == nil {
t.Fatal("config should not be nil")
}

// Connect!
c := goPlugin.NewClient(&goPlugin.ClientConfig{
Cmd: nil,
HandshakeConfig: testHandshake,
Plugins: pluginMap,
Reattach: config,
})
client, err := c.Client()
if err != nil {
t.Fatalf("err: %s", err)
}

// Pinging should work
if err := client.Ping(); err != nil {
t.Fatalf("should not err: %s", err)
}

// Kill which should do nothing
c.Kill()
if err := client.Ping(); err != nil {
t.Fatalf("should not err: %s", err)
}

// Request the plugin
raw, err := client.Dispense("RpcTrafficRouterPlugin")
if err != nil {
t.Fail()
}

pluginInstance := raw.(*rolloutsPlugin.TrafficRouterPluginRPC)
err = pluginInstance.InitPlugin()
if err.Error() != "" {
t.Fail()
}
t.Run("SetWeight", func(t *testing.T) {
var desiredWeight int32 = 30
err := pluginInstance.SetWeight(newMockRollout(), desiredWeight, []v1alpha1.WeightDestination{})

assert.Empty(t, err.Error())
assert.Equal(t, uint32(100-desiredWeight), mocks.RouteTable.Spec.Http[0].GetForwardTo().Destinations[0].Weight)
assert.Equal(t, uint32(desiredWeight), mocks.RouteTable.Spec.Http[0].GetForwardTo().Destinations[1].Weight)
})

// Canceling should cause an exit
cancel()
<-closeCh
}

func newMockRollout() *v1alpha1.Rollout {
pluginConfig := GlooPlatformAPITrafficRouting{
RouteTableName: mocks.RouteTableName,
RouteTableNamespace: mocks.RouteTableNamespace,
DestinationKind: mocks.DestinationKind,
DestinationNamespace: mocks.DestinationNamespace,
}

encoded, err := json.Marshal(pluginConfig)
if err != nil {
log.Fatalf("failed to marshal plugin config: %s", err)
}

return &v1alpha1.Rollout{
ObjectMeta: metav1.ObjectMeta{
Name: mocks.RolloutName,
Namespace: mocks.RolloutNamespace,
},
Spec: v1alpha1.RolloutSpec{
Strategy: v1alpha1.RolloutStrategy{
Canary: &v1alpha1.CanaryStrategy{
StableService: mocks.StableService,
CanaryService: mocks.CanaryService,
TrafficRouting: &v1alpha1.RolloutTrafficRouting{
Plugins: map[string]json.RawMessage{
"solo-io/glooplatformAPI": encoded,
},
},
},
},
},
}
}
Loading

0 comments on commit 30824ef

Please sign in to comment.