UDP support
Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
This commit is contained in:
parent
8988c8f9af
commit
115d42e0f0
72 changed files with 4730 additions and 321 deletions
123
pkg/server/server_entrypoint_udp_test.go
Normal file
123
pkg/server/server_entrypoint_udp_test.go
Normal file
|
@ -0,0 +1,123 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/v2/pkg/config/static"
|
||||
"github.com/containous/traefik/v2/pkg/types"
|
||||
"github.com/containous/traefik/v2/pkg/udp"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestShutdownUDPConn(t *testing.T) {
|
||||
entryPoint, err := NewUDPEntryPoint(&static.EntryPoint{
|
||||
Address: ":0",
|
||||
Transport: &static.EntryPointsTransport{
|
||||
LifeCycle: &static.LifeCycle{
|
||||
GraceTimeOut: types.Duration(5 * time.Second),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
go entryPoint.Start(context.Background())
|
||||
entryPoint.Switch(udp.HandlerFunc(func(conn *udp.Conn) {
|
||||
for {
|
||||
b := make([]byte, 1024*1024)
|
||||
n, err := conn.Read(b)
|
||||
require.NoError(t, err)
|
||||
// We control the termination, otherwise we would block on the Read above, until
|
||||
// conn is closed by a timeout. Which means we would get an error, and even though
|
||||
// we are in a goroutine and the current test might be over, go test would still
|
||||
// yell at us if this happens while other tests are still running.
|
||||
if string(b[:n]) == "CLOSE" {
|
||||
return
|
||||
}
|
||||
_, err = conn.Write(b[:n])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}))
|
||||
|
||||
conn, err := net.Dial("udp", entryPoint.listener.Addr().String())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Start sending packets, to create a "session" with the server.
|
||||
requireEcho(t, "TEST", conn, time.Second)
|
||||
|
||||
doneChan := make(chan struct{})
|
||||
go func() {
|
||||
entryPoint.Shutdown(context.Background())
|
||||
close(doneChan)
|
||||
}()
|
||||
|
||||
// Make sure that our session is still live even after the shutdown.
|
||||
requireEcho(t, "TEST2", conn, time.Second)
|
||||
|
||||
// And make sure that on the other hand, opening new sessions is not possible anymore.
|
||||
conn2, err := net.Dial("udp", entryPoint.listener.Addr().String())
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = conn2.Write([]byte("TEST"))
|
||||
// Packet is accepted, but dropped
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that our session is yet again still live. This is specifically to
|
||||
// make sure we don't create a regression in listener's readLoop, i.e. that we only
|
||||
// terminate the listener's readLoop goroutine by closing its pConn.
|
||||
requireEcho(t, "TEST3", conn, time.Second)
|
||||
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
defer close(done)
|
||||
b := make([]byte, 1024*1024)
|
||||
n, err := conn2.Read(b)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, 0, n)
|
||||
}()
|
||||
|
||||
conn2.Close()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.Tick(time.Second):
|
||||
t.Fatal("Timeout")
|
||||
}
|
||||
|
||||
_, err = conn.Write([]byte("CLOSE"))
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
case <-doneChan:
|
||||
case <-time.Tick(time.Second * 5):
|
||||
// In case we introduce a regression that would make the test wait forever.
|
||||
t.Fatal("Timeout during shutdown")
|
||||
}
|
||||
}
|
||||
|
||||
// requireEcho tests that the conn session is live and functional, by writing
|
||||
// data through it, and expecting the same data as a response when reading on it.
|
||||
// It fatals if the read blocks longer than timeout, which is useful to detect
|
||||
// regressions that would make a test wait forever.
|
||||
func requireEcho(t *testing.T, data string, conn io.ReadWriter, timeout time.Duration) {
|
||||
_, err := conn.Write([]byte(data))
|
||||
require.NoError(t, err)
|
||||
|
||||
doneChan := make(chan struct{})
|
||||
go func() {
|
||||
b := make([]byte, 1024*1024)
|
||||
n, err := conn.Read(b)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, data, string(b[:n]))
|
||||
close(doneChan)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-doneChan:
|
||||
case <-time.Tick(timeout):
|
||||
t.Fatalf("Timeout during echo for: %s", data)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue