diff --git a/go.mod b/go.mod index 5174b63..684adb4 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/khirono/go-rtnlroute v1.0.1 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.8.1 + github.com/smartystreets/goconvey v1.8.1 github.com/stretchr/testify v1.8.3 github.com/urfave/cli v1.22.5 github.com/wmnsk/go-pfcp v0.0.23-0.20231009074152-d5a9c1f47114 @@ -21,6 +22,8 @@ require ( ) require ( + github.com/agiledragon/gomonkey v2.0.2+incompatible // indirect + github.com/agiledragon/gomonkey/v2 v2.11.0 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect @@ -31,7 +34,9 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect @@ -41,6 +46,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/smarty/assertions v1.15.0 // indirect github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect diff --git a/go.sum b/go.sum index d7ebe87..df446a9 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= +github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= +github.com/agiledragon/gomonkey/v2 v2.11.0 h1:5oxSgA+tC1xuGsrIorR+sYiziYltmJyEZ9qA25b6l5U= +github.com/agiledragon/gomonkey/v2 v2.11.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= @@ -35,10 +39,15 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/khirono/go-genl v1.0.1 h1:9/7V52C/lkifC0zjZZaAN6GghQSLZkuNz87vxemyzeY= github.com/khirono/go-genl v1.0.1/go.mod h1:EQ4XpG8LUJTtozdrgcsAgJm++r3l94/LwCia4Rq4Scs= github.com/khirono/go-nl v1.0.4/go.mod h1:PzYeSjD38fzV7mX5DuaCZvnwx2kD/o7XgHyzuJxoi7U= @@ -74,6 +83,12 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= +github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= +github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -99,17 +114,22 @@ github.com/wmnsk/go-pfcp v0.0.23-0.20231009074152-d5a9c1f47114/go.mod h1:C93sXfS golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/internal/pfcp/node_test.go b/internal/pfcp/node_test.go index 7f13b2b..587ce11 100644 --- a/internal/pfcp/node_test.go +++ b/internal/pfcp/node_test.go @@ -3,145 +3,109 @@ package pfcp import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/free5gc/go-upf/internal/forwarder" "github.com/free5gc/go-upf/internal/logger" logger_util "github.com/free5gc/util/logger" ) -func TestNode(t *testing.T) { - n := NewRemoteNode( - "smf1", - nil, - &LocalNode{}, - forwarder.Empty{}, - logger.PfcpLog.WithField(logger_util.FieldControlPlaneNodeID, "smf1"), - ) - t.Run("delete 0 no effect", func(t *testing.T) { - n.DeleteSess(0) - }) - t.Run("sess 0 is not found", func(t *testing.T) { - _, err := n.Sess(0) - if err == nil { - t.Errorf("want false; but got %v\n", err) - } - }) - t.Run("sess 1 is not found", func(t *testing.T) { - _, err := n.Sess(1) - if err == nil { - t.Errorf("want false; but got %v\n", err) - } - }) - t.Run("sess 2 is not found", func(t *testing.T) { - _, err := n.Sess(2) - if err == nil { - t.Errorf("want false; but got %v\n", err) - } - }) - t.Run("new 1", func(t *testing.T) { - sess := n.NewSess(10) - if sess.LocalID != 1 { - t.Errorf("want 1; but got %v\n", sess.LocalID) - } - if sess.RemoteID != 10 { - t.Errorf("want 10; but got %v\n", sess.RemoteID) +func TestRemoteNode(t *testing.T) { + t.Run("sess is not found before create", func(t *testing.T) { + n := NewRemoteNode( + "smf1", + nil, + &LocalNode{}, + forwarder.Empty{}, + logger.PfcpLog.WithField(logger_util.FieldControlPlaneNodeID, "smf1"), + ) + for i := 0; i < 3; i++ { + _, err := n.Sess(uint64(i)) + assert.NotNil(t, err) } }) - t.Run("new 2", func(t *testing.T) { - sess := n.NewSess(20) - if sess.LocalID != 2 { - t.Errorf("want 2; but got %v\n", sess.LocalID) - } - if sess.RemoteID != 20 { - t.Errorf("want 20; but got %v\n", sess.RemoteID) - } - }) - t.Run("new 3", func(t *testing.T) { - sess := n.NewSess(30) - if sess.LocalID != 3 { - t.Errorf("want 3; but got %v\n", sess.LocalID) - } - if sess.RemoteID != 30 { - t.Errorf("want 30; but got %v\n", sess.RemoteID) - } - }) - t.Run("sess 1", func(t *testing.T) { - sess, err := n.Sess(1) - if err != nil { - t.Fatalf("want true; but got %v\n", err) - } - if sess.LocalID != 1 { - t.Errorf("want 1; but got %v\n", sess.LocalID) - } - if sess.RemoteID != 10 { - t.Errorf("want 10; but got %v\n", sess.RemoteID) - } - }) - t.Run("sess 2", func(t *testing.T) { - sess, err := n.Sess(2) - if err != nil { - t.Fatalf("want true; but got %v\n", err) - } - if sess.LocalID != 2 { - t.Errorf("want 2; but got %v\n", sess.LocalID) - } - if sess.RemoteID != 20 { - t.Errorf("want 20; but got %v\n", sess.RemoteID) - } - }) - t.Run("sess 3", func(t *testing.T) { - sess, err := n.Sess(3) - if err != nil { - t.Fatalf("want true; but got %v\n", err) + + t.Run("new multiple session", func(t *testing.T) { + n := NewRemoteNode( + "smf1", + nil, + &LocalNode{}, + forwarder.Empty{}, + logger.PfcpLog.WithField(logger_util.FieldControlPlaneNodeID, "smf1"), + ) + + testcases := []struct { + localID uint64 + remoteID uint64 + }{ + {1, 10}, {2, 20}, {3, 30}, } - if sess.LocalID != 3 { - t.Errorf("want 3; but got %v\n", sess.LocalID) + + for _, tc := range testcases { + sess := n.NewSess(tc.remoteID) + assert.Equal(t, tc.localID, sess.LocalID) + assert.Equal(t, tc.remoteID, sess.RemoteID) } - if sess.RemoteID != 30 { - t.Errorf("want 30; but got %v\n", sess.RemoteID) + + // assure the session stored in the node + for _, tc := range testcases { + sess, err := n.Sess(tc.localID) + assert.Nil(t, err) + assert.Equal(t, tc.localID, sess.LocalID) + assert.Equal(t, tc.remoteID, sess.RemoteID) } }) - t.Run("sess 4 is not found", func(t *testing.T) { - _, err := n.Sess(4) - if err == nil { - t.Errorf("want false; but got %v\n", err) + + t.Run("delete 0 no effect before create", func(t *testing.T) { + n := NewRemoteNode( + "smf1", + nil, + &LocalNode{}, + forwarder.Empty{}, + logger.PfcpLog.WithField(logger_util.FieldControlPlaneNodeID, "smf1"), + ) + report := n.DeleteSess(0) + assert.Nil(t, report) + }) + t.Run("delete should success after create", func(t *testing.T) { + n := NewRemoteNode( + "smf1", + nil, + &LocalNode{}, + forwarder.Empty{}, + logger.PfcpLog.WithField(logger_util.FieldControlPlaneNodeID, "smf1"), + ) + + testcases := []struct { + localID uint64 + remoteID uint64 + }{ + {1, 10}, {2, 20}, {3, 30}, } - }) - t.Run("delete 2", func(t *testing.T) { - n.DeleteSess(2) - }) - t.Run("sess 2 is not found", func(t *testing.T) { - _, err := n.Sess(2) - if err == nil { - t.Errorf("want false; but got %v\n", err) + + for _, tc := range testcases { + n.NewSess(tc.remoteID) } - }) - t.Run("delete 1", func(t *testing.T) { - n.DeleteSess(1) - }) - t.Run("sess 1 is not found", func(t *testing.T) { - _, err := n.Sess(1) - if err == nil { - t.Errorf("want false; but got %v\n", err) + + for _, tc := range testcases { + n.DeleteSess(tc.localID) } - }) - t.Run("delete 1 no effect", func(t *testing.T) { - n.DeleteSess(1) - }) - t.Run("delete 4 no effect", func(t *testing.T) { - n.DeleteSess(4) - }) - t.Run("new 4", func(t *testing.T) { - sess := n.NewSess(40) - if sess.LocalID != 1 { - t.Errorf("want 1; but got %v\n", sess.LocalID) + + // assure the session is deleted + for _, tc := range testcases { + _, err := n.Sess(tc.localID) + assert.NotNil(t, err) } - if sess.RemoteID != 40 { - t.Errorf("want 40; but got %v\n", sess.RemoteID) + + // delete again should have no effect + for _, tc := range testcases { + report := n.DeleteSess(tc.localID) + assert.Nil(t, report) } }) } -func TestNode_multipleSMF(t *testing.T) { +func TestRemoteNode_multipleSMF(t *testing.T) { var lnode LocalNode n1 := NewRemoteNode( "smf1", @@ -254,3 +218,23 @@ func TestNode_multipleSMF(t *testing.T) { } }) } + +func TestLocalNode(t *testing.T) { + t.Run("new session", func(t *testing.T) { + lnode := LocalNode{} + sess := lnode.NewSess(10, BUFFQ_LEN) + assert.Equal(t, uint64(1), sess.LocalID) + assert.Equal(t, uint64(10), sess.RemoteID) + }) + + t.Run("recycle LocalID", func(t *testing.T) { + lnode := LocalNode{ + sess: []*Sess{}, + free: []uint64{}, + } + sess := lnode.NewSess(10, BUFFQ_LEN) + recycleLocalID := 1 + assert.Equal(t, uint64(recycleLocalID), sess.LocalID) + assert.Equal(t, uint64(10), sess.RemoteID) + }) +} diff --git a/internal/pfcp/pfcp_test.go b/internal/pfcp/pfcp_test.go new file mode 100644 index 0000000..37d23dd --- /dev/null +++ b/internal/pfcp/pfcp_test.go @@ -0,0 +1,162 @@ +package pfcp + +import ( + "net" + "sync" + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + + "github.com/free5gc/go-upf/internal/forwarder" + "github.com/free5gc/go-upf/internal/report" + logger_util "github.com/free5gc/util/logger" +) + +type PfcpServerMock struct { + PfcpServer +} + +func (p *PfcpServerMock) GetRNodes() map[string]*RemoteNode { + return p.rnodes +} + +func (p *PfcpServerMock) AddRNode(rnodeid string, node *RemoteNode) { + p.rnodes[rnodeid] = node +} + +func TestStart(t *testing.T) { +} + +func TestStop(t *testing.T) { + s := &PfcpServer{ + log: logrus.WithField(logger_util.FieldControlPlaneNodeID, "127.0.0.1"), + } + + addr, err := net.ResolveUDPAddr("udp4", "127.0.0.1:0") + if err != nil { + t.Errorf("failed to resolve UDP address: %v", err) + return + } + s.conn, err = net.ListenUDP("udp4", addr) + if err != nil { + t.Errorf("expected err to be nil, but got %v", err) + } + + if s.conn == nil { + t.Errorf("expected s.conn not to be nil") + return + } + + s.Stop() + + if !isConnClosed(s.conn) { + t.Errorf("expected connection to be closed") + } +} + +func TestNewNode(t *testing.T) { + s := &PfcpServer{ + log: logrus.WithField(logger_util.FieldControlPlaneNodeID, "127.0.0.1"), + } + + id := "smf1" + driver := forwarder.Empty{} + addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8805") + if err != nil { + t.Errorf("failed to resolve UDP address: %v", err) + return + } + + newNode := s.NewNode(id, addr, driver) + + assert.NotNil(t, newNode) + assert.Equal(t, id, newNode.ID) +} + +func TestUpdateNodeID(t *testing.T) { + s := &PfcpServerMock{ + PfcpServer: PfcpServer{ + log: logrus.WithField(logger_util.FieldControlPlaneNodeID, "127.0.0.1"), + rnodes: make(map[string]*RemoteNode), + }, + } + + origNodeId := "127.0.0.1" + node := s.NewNode(origNodeId, nil, nil) + s.AddRNode(origNodeId, node) + + newNodeId := "192.168.56.101" + s.UpdateNodeID(node, newNodeId) + + assert.Nil(t, s.GetRNodes()[origNodeId]) + assert.NotNil(t, s.GetRNodes()[newNodeId]) +} + +func TestNotifySessReport(t *testing.T) { + s := &PfcpServer{ + srCh: make(chan report.SessReport), + } + + reports := []report.Report{} + + sr := report.SessReport{ + SEID: 1, + Reports: reports, + } + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + receivedSr := <-s.srCh + assert.EqualValues(t, sr, receivedSr) + }() + + s.NotifySessReport(sr) + + wg.Wait() +} + +func TestNotifyTransTimeout(t *testing.T) { + s := &PfcpServer{ + trToCh: make(chan TransactionTimeout), + } + txId := "127.0.0.1-1" + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + receivedSeid := <-s.trToCh + assert.EqualValues(t, TransactionTimeout{TrType: TX, TrID: txId}, receivedSeid) + }() + + s.NotifyTransTimeout(TX, txId) + + wg.Wait() +} + +func isConnClosed(conn *net.UDPConn) bool { + oneByte := make([]byte, 1) + err := conn.SetReadDeadline(time.Now()) + if err != nil { + return true + } + _, err = conn.Read(oneByte) + if err != nil { + netErr, ok := err.(net.Error) + if ok && netErr.Timeout() { + // The read timed out, which means the connection is still open + return false + } + // Any other error means the connection is closed + return true + } + + // If we were able to read a byte, the connection is definitely open + return false +}