Files
ziti/tests/tunneler_data_flow_test.go
T
Andrew Martinez b562fb5c07 splits API specs into composible modules
- splits Open API 2.0 (swagger) into client/management APIs
- uses go-swaggers flatten capabilities
- uses newer version of go-swagger (v0.27.0)
- introduces /edge/client/v1, /edge/management/v1
- non-prefixed URLs default to /edge/client/v1
- splits some shared management/client API handlers
- renames some REST models to "client" instead of "limited"
- passes all apitests, fails dataflow upd test (main fails this as well)
- updates generate rest script for powershell
- todo: test generate rest script for bash
- todo: use xweb (different branch)
2021-05-04 11:30:32 -04:00

439 lines
11 KiB
Go

// +build dataflow
/*
Copyright NetFoundry, Inc.
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
https://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.
*/
package tests
import (
"bytes"
"fmt"
"github.com/openziti/foundation/util/info"
"github.com/openziti/sdk-golang/ziti/edge"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"io"
"math"
"math/rand"
"net"
"testing"
"time"
)
func Test_TunnelerDataflowTcp(t *testing.T) {
ctx := NewTestContext(t)
defer ctx.Teardown()
ctx.StartServer()
ctx.RequireAdminManagementApiLogin()
ctx.AdminManagementSession.requireNewServicePolicy("Dial", s("#all"), s("#all"), nil)
ctx.AdminManagementSession.requireNewServicePolicy("Bind", s("#all"), s("#all"), nil)
ctx.AdminManagementSession.requireNewEdgeRouterPolicy(s("#all"), s("#all"))
ctx.AdminManagementSession.requireNewServiceEdgeRouterPolicy(s("#all"), s("#all"))
hostConfig := ctx.newConfig("NH5p4FpGR", map[string]interface{}{
"address": "localhost",
"port": 8687,
"forwardProtocol": true,
"allowedProtocols": []string{"tcp", "udp"},
})
hostConfig.Name = "tunnel-host"
ctx.AdminManagementSession.requireCreateEntity(hostConfig)
service := ctx.AdminManagementSession.testContext.newService(nil, s(hostConfig.Id))
service.Name = "tunnel-test-tcp"
ctx.AdminManagementSession.requireCreateEntity(service)
service2 := ctx.AdminManagementSession.testContext.newService(nil, s(hostConfig.Id))
service2.Name = "tunnel-test-udp"
ctx.AdminManagementSession.requireCreateEntity(service2)
ctx.CreateEnrollAndStartTunnelerEdgeRouter()
l, err := net.Listen("tcp", "localhost:8687")
ctx.Req.NoError(err)
time.Sleep(time.Second)
errC := make(chan error, 10)
go acceptConnections(l, errC)
conn, err := net.Dial("tcp", "localhost:8686")
ctx.Req.NoError(err)
_, err = conn.Write([]byte("hello"))
ctx.Req.NoError(err)
fmt.Println("client sent: 'hello'")
var read []string
for {
buf := make([]byte, 1024)
_ = conn.SetDeadline(time.Now().Add(time.Second))
n, err := conn.Read(buf)
if err != nil && errors.Is(err, io.EOF) {
if n > 0 {
fmt.Printf("server responded: '%v'\n", string(buf[:n]))
read = append(read, string(buf[:n]))
}
break
}
ctx.Req.NoError(err)
fmt.Printf("server responded: '%v'\n", string(buf[:n]))
read = append(read, string(buf[:n]))
}
ctx.Req.Equal(1, len(read))
if len(read) > 0 { // goland complaining about potential nil slice
ctx.Req.Equal("goodbye", read[0])
}
var errs []error
done := false
for !done {
select {
case err, ok := <-errC:
if !ok {
done = true
break
}
fmt.Printf("error: %v\n", err)
errs = append(errs, err)
case <-time.After(1 * time.Second):
ctx.Req.Fail("timed out waiting for errors")
}
}
ctx.Req.Equal(0, len(errs))
}
func acceptConnections(l net.Listener, errC chan error) {
defer func() { _ = l.Close() }()
defer close(errC)
conn, err := l.Accept()
if err != nil {
return
}
_ = conn.SetDeadline(time.Now().Add(time.Second))
handleServerConn(conn, errC)
}
func handleServerConn(conn net.Conn, errC chan error) {
var read []string
defer func() {
if len(read) != 1 {
errC <- errors.Errorf("server expected on read result, got %+v", read)
} else if read[0] != "hello" {
errC <- errors.Errorf("server expected on read result of \"hello\", got %+v", read)
}
}()
buf := make([]byte, len([]byte("hello")))
n, err := conn.Read(buf)
if err != nil {
errC <- err
return
}
fmt.Printf("client said: '%v'\n", string(buf[:n]))
read = append(read, string(buf[:n]))
if _, err = conn.Write([]byte("goodbye")); err != nil {
errC <- err
return
}
fmt.Println("server sent: goodbye")
if err = conn.Close(); err != nil {
errC <- err
}
}
func Test_TunnelerDataflowHalfClose(t *testing.T) {
ctx := NewTestContext(t)
defer ctx.Teardown()
ctx.StartServer()
ctx.RequireAdminManagementApiLogin()
ctx.AdminManagementSession.requireNewServicePolicy("Dial", s("#all"), s("#all"), nil)
ctx.AdminManagementSession.requireNewServicePolicy("Bind", s("#all"), s("#all"), nil)
ctx.AdminManagementSession.requireNewEdgeRouterPolicy(s("#all"), s("#all"))
ctx.AdminManagementSession.requireNewServiceEdgeRouterPolicy(s("#all"), s("#all"))
hostConfig := ctx.newConfig("NH5p4FpGR", map[string]interface{}{
"address": "localhost",
"port": 8689,
"forwardProtocol": true,
"allowedProtocols": []string{"tcp", "udp"},
})
hostConfig.Name = "tunnel-host"
ctx.AdminManagementSession.requireCreateEntity(hostConfig)
service := ctx.AdminManagementSession.testContext.newService(nil, s(hostConfig.Id))
service.Name = "tunnel-test-tcp"
ctx.AdminManagementSession.requireCreateEntity(service)
service2 := ctx.AdminManagementSession.testContext.newService(nil, s(hostConfig.Id))
service2.Name = "tunnel-test-udp"
ctx.AdminManagementSession.requireCreateEntity(service2)
ctx.CreateEnrollAndStartTunnelerEdgeRouter()
l, err := net.Listen("tcp", "localhost:8689")
ctx.Req.NoError(err)
time.Sleep(time.Second)
errC := make(chan error, 10)
go acceptConnectionsHalfClose(l, errC)
conn, err := net.Dial("tcp", "localhost:8686")
ctx.Req.NoError(err)
_, err = conn.Write([]byte("hello"))
ctx.Req.NoError(err)
fmt.Println("client sent: 'hello'")
ctx.Req.NoError(conn.(edge.CloseWriter).CloseWrite())
var read []string
for {
buf := make([]byte, 1024)
_ = conn.SetDeadline(time.Now().Add(time.Second))
n, err := conn.Read(buf)
if err != nil && errors.Is(err, io.EOF) {
if n > 0 {
fmt.Printf("server responded: '%v'\n", string(buf[:n]))
read = append(read, string(buf[:n]))
}
break
}
ctx.Req.NoError(err)
fmt.Printf("server responded: '%v'\n", string(buf[:n]))
read = append(read, string(buf[:n]))
}
ctx.Req.Equal(1, len(read))
if len(read) > 0 { // goland complaining about potential nil slice
ctx.Req.Equal("goodbye", read[0])
}
var errs []error
done := false
for !done {
select {
case err, ok := <-errC:
if !ok {
done = true
break
}
fmt.Printf("error: %v\n", err)
errs = append(errs, err)
case <-time.After(1 * time.Second):
ctx.Req.Fail("timed out waiting for errors")
}
}
ctx.Req.Equal(0, len(errs))
}
func acceptConnectionsHalfClose(l net.Listener, errC chan error) {
defer func() { _ = l.Close() }()
defer close(errC)
conn, err := l.Accept()
if err != nil {
return
}
_ = conn.SetDeadline(time.Now().Add(time.Second))
handleServerConnHalfClose(conn, errC)
}
func handleServerConnHalfClose(conn net.Conn, errC chan error) {
var read []string
defer func() {
if len(read) != 1 {
errC <- errors.Errorf("server expected on read result, got %+v", read)
} else if read[0] != "hello" {
errC <- errors.Errorf("server expected on read result of \"hello\", got %+v", read)
}
}()
for {
buf := make([]byte, len([]byte("hello")))
n, err := conn.Read(buf)
if err != nil && errors.Is(err, io.EOF) {
if n > 0 {
read = append(read, string(buf[:n]))
fmt.Printf("client said: '%v'\n", string(buf[:n]))
}
break
}
if err != nil {
errC <- err
return
}
fmt.Printf("client said: '%v'\n", string(buf[:n]))
read = append(read, string(buf[:n]))
}
_, err := conn.Write([]byte("goodbye"))
if err != nil {
errC <- err
return
}
fmt.Println("server sent: goodbye")
if err = conn.(edge.CloseWriter).CloseWrite(); err != nil {
errC <- err
}
}
func Test_TunnelerDataflowUdp(t *testing.T) {
ctx := NewTestContext(t)
defer ctx.Teardown()
ctx.StartServer()
ctx.RequireAdminManagementApiLogin()
ctx.AdminManagementSession.requireNewServicePolicy("Dial", s("#all"), s("#all"), nil)
ctx.AdminManagementSession.requireNewServicePolicy("Bind", s("#all"), s("#all"), nil)
ctx.AdminManagementSession.requireNewEdgeRouterPolicy(s("#all"), s("#all"))
ctx.AdminManagementSession.requireNewServiceEdgeRouterPolicy(s("#all"), s("#all"))
hostConfig := ctx.newConfig("NH5p4FpGR", map[string]interface{}{
"address": "localhost",
"port": 8690,
"forwardProtocol": true,
"allowedProtocols": []string{"tcp", "udp"},
})
hostConfig.Name = "tunnel-host"
ctx.AdminManagementSession.requireCreateEntity(hostConfig)
service := ctx.AdminManagementSession.testContext.newService(nil, s(hostConfig.Id))
service.Name = "tunnel-test-tcp"
ctx.AdminManagementSession.requireCreateEntity(service)
service2 := ctx.AdminManagementSession.testContext.newService(nil, s(hostConfig.Id))
service2.Name = "tunnel-test-udp"
ctx.AdminManagementSession.requireCreateEntity(service2)
ctx.CreateEnrollAndStartTunnelerEdgeRouter()
l, err := net.ListenPacket("udp", "localhost:8690")
ctx.Req.NoError(err)
time.Sleep(time.Second)
errC := make(chan error, 10)
go echoData(l, errC)
conn, err := net.Dial("udp", "localhost:8688")
ctx.Req.NoError(err)
counter := byte(0)
for i := 0; i < 100; i++ {
size := rand.Int31n(info.MaxUdpPacketSize-1) + 1
buf := make([]byte, size)
for idx := range buf {
buf[idx] = counter
counter++
}
time.Sleep(time.Millisecond)
err := conn.SetDeadline(time.Now().Add(time.Second))
ctx.Req.NoError(err)
_, err = conn.Write(buf)
ctx.Req.NoError(err)
logrus.Errorf("%v (CLIENT): wrote %v bytes", i, size)
readBuf := make([]byte, size)
_, err = io.ReadFull(conn, readBuf)
ctx.Req.NoError(err)
logrus.Errorf("%v (CLIENT): read %v bytes", i, size)
ctx.Req.Equal(buf, readBuf)
}
_, err = conn.Write([]byte(endOfData))
ctx.Req.NoError(err)
_ = conn.Close()
var errs []error
done := false
for !done {
select {
case err, ok := <-errC:
if !ok {
done = true
break
}
fmt.Printf("error: %v\n", err)
errs = append(errs, err)
case <-time.After(1 * time.Second):
ctx.Req.Fail("timed out waiting for errors")
}
}
ctx.Req.Equal(0, len(errs))
}
var endOfData = "end-of-data"
func echoData(conn net.PacketConn, errC chan error) {
defer func() { _ = conn.Close() }()
defer close(errC)
counter := byte(0)
buf := make([]byte, math.MaxUint16)
i := 0
for {
size, addr, err := conn.ReadFrom(buf)
if err != nil {
select {
case errC <- err:
default:
}
return
}
logrus.Errorf("%v (SERVER): read %v bytes", i, size)
readBuf := buf[:size]
if bytes.Equal([]byte(endOfData), readBuf) {
return
}
for _, val := range readBuf {
if val != counter {
errC <- errors.Errorf("invalid value %v expected %v", val, counter)
return
}
counter++
}
_, err = conn.WriteTo(readBuf, addr)
if err != nil {
errC <- err
return
}
logrus.Errorf("%v (SERVER): wrote %v bytes", i, size)
i++
}
}