mirror of
https://github.com/fatedier/frp.git
synced 2025-07-27 07:35:07 +00:00
frpc: consider include configs for verify and reload command (#2424)
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/fatedier/frp/test/e2e/framework"
|
||||
"github.com/fatedier/frp/test/e2e/framework/consts"
|
||||
"github.com/fatedier/frp/test/e2e/mock/server"
|
||||
"github.com/fatedier/frp/test/e2e/pkg/port"
|
||||
"github.com/fatedier/frp/test/e2e/pkg/request"
|
||||
|
||||
@@ -80,7 +81,7 @@ var _ = Describe("[Feature: Basic]", func() {
|
||||
|
||||
for _, test := range tests {
|
||||
framework.NewRequestExpect(f).
|
||||
Request(framework.SetRequestProtocol(protocol)).
|
||||
RequestModify(framework.SetRequestProtocol(protocol)).
|
||||
PortName(test.portName).
|
||||
Explain(test.proxyName).
|
||||
Ensure()
|
||||
@@ -185,7 +186,7 @@ var _ = Describe("[Feature: Basic]", func() {
|
||||
|
||||
for _, test := range tests {
|
||||
framework.NewRequestExpect(f).
|
||||
Request(framework.SetRequestProtocol(protocol)).
|
||||
RequestModify(framework.SetRequestProtocol(protocol)).
|
||||
PortName(test.bindPortName).
|
||||
Explain(test.proxyName).
|
||||
ExpectError(test.expectError).
|
||||
@@ -213,12 +214,11 @@ var _ = Describe("[Feature: Basic]", func() {
|
||||
multiplexer = httpconnect
|
||||
local_port = {{ .%s }}
|
||||
custom_domains = %s
|
||||
`+extra, proxyName, framework.TCPEchoServerPort, proxyName)
|
||||
`+extra, proxyName, port.GenName(proxyName), proxyName)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
proxyName string
|
||||
portName string
|
||||
extraConfig string
|
||||
}{
|
||||
{
|
||||
@@ -244,7 +244,11 @@ var _ = Describe("[Feature: Basic]", func() {
|
||||
// build all client config
|
||||
for _, test := range tests {
|
||||
clientConf += getProxyConf(test.proxyName, test.extraConfig) + "\n"
|
||||
|
||||
localServer := server.New(server.TCP, server.WithBindPort(f.AllocPort()), server.WithRespContent([]byte(test.proxyName)))
|
||||
f.RunServer(port.GenName(test.proxyName), localServer)
|
||||
}
|
||||
|
||||
// run frps and frpc
|
||||
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
||||
|
||||
@@ -257,15 +261,15 @@ var _ = Describe("[Feature: Basic]", func() {
|
||||
|
||||
proxyURL := fmt.Sprintf("http://127.0.0.1:%d", f.PortByName(tcpmuxHTTPConnectPortName))
|
||||
// Request with incorrect connect hostname
|
||||
framework.NewRequestExpect(f).Request(func(r *request.Request) {
|
||||
framework.NewRequestExpect(f).RequestModify(func(r *request.Request) {
|
||||
r.Proxy(proxyURL, "invalid")
|
||||
}).ExpectError(true).Explain("request without HTTP connect expect error").Ensure()
|
||||
|
||||
// Request with correct connect hostname
|
||||
for _, test := range tests {
|
||||
framework.NewRequestExpect(f).Request(func(r *request.Request) {
|
||||
framework.NewRequestExpect(f).RequestModify(func(r *request.Request) {
|
||||
r.Proxy(proxyURL, test.proxyName)
|
||||
}).Explain(test.proxyName).Ensure()
|
||||
}).ExpectResp([]byte(test.proxyName)).Explain(test.proxyName).Ensure()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@@ -49,7 +49,7 @@ func defineClientServerTest(desc string, f *framework.Framework, configures *gen
|
||||
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
||||
|
||||
framework.NewRequestExpect(f).PortName(tcpPortName).ExpectError(configures.expectError).Explain("tcp proxy").Ensure()
|
||||
framework.NewRequestExpect(f).Request(framework.SetRequestProtocol("udp")).
|
||||
framework.NewRequestExpect(f).RequestModify(framework.SetRequestProtocol("udp")).
|
||||
PortName(udpPortName).ExpectError(configures.expectError).Explain("udp proxy").Ensure()
|
||||
})
|
||||
}
|
||||
|
@@ -62,17 +62,17 @@ var _ = Describe("[Feature: Server Manager]", func() {
|
||||
framework.NewRequestExpect(f).PortName(tcpPortName).Ensure()
|
||||
|
||||
// Not Allowed
|
||||
framework.NewRequestExpect(f).Request(framework.SetRequestPort(20001)).ExpectError(true).Ensure()
|
||||
framework.NewRequestExpect(f).RequestModify(framework.SetRequestPort(20001)).ExpectError(true).Ensure()
|
||||
|
||||
// Unavailable, already bind by frps
|
||||
framework.NewRequestExpect(f).PortName(consts.PortServerName).ExpectError(true).Ensure()
|
||||
|
||||
// UDP
|
||||
// Allowed in range
|
||||
framework.NewRequestExpect(f).Request(framework.SetRequestProtocol("udp")).PortName(udpPortName).Ensure()
|
||||
framework.NewRequestExpect(f).RequestModify(framework.SetRequestProtocol("udp")).PortName(udpPortName).Ensure()
|
||||
|
||||
// Not Allowed
|
||||
framework.NewRequestExpect(f).Request(func(r *request.Request) {
|
||||
framework.NewRequestExpect(f).RequestModify(func(r *request.Request) {
|
||||
r.UDP().Port(20003)
|
||||
}).ExpectError(true).Ensure()
|
||||
})
|
||||
|
@@ -49,7 +49,6 @@ func RunE2ETests(t *testing.T) {
|
||||
// accepting the byte array.
|
||||
func setupSuite() {
|
||||
// Run only on Ginkgo node 1
|
||||
// TODO
|
||||
}
|
||||
|
||||
// setupSuitePerGinkgoNode is the boilerplate that can be used to setup ginkgo test suites, on the SynchronizedBeforeSuite step.
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/fatedier/frp/test/e2e/mock/server"
|
||||
"github.com/fatedier/frp/test/e2e/pkg/port"
|
||||
"github.com/fatedier/frp/test/e2e/pkg/process"
|
||||
|
||||
@@ -32,7 +33,7 @@ type Framework struct {
|
||||
// portAllocator to alloc port for this test case.
|
||||
portAllocator *port.Allocator
|
||||
|
||||
// Multiple mock servers used for e2e testing.
|
||||
// Multiple default mock servers used for e2e testing.
|
||||
mockServers *MockServers
|
||||
|
||||
// To make sure that this framework cleans up after itself, no matter what,
|
||||
@@ -47,6 +48,9 @@ type Framework struct {
|
||||
serverProcesses []*process.Process
|
||||
clientConfPaths []string
|
||||
clientProcesses []*process.Process
|
||||
|
||||
// Manual registered mock servers.
|
||||
servers []*server.Server
|
||||
}
|
||||
|
||||
func NewDefaultFramework() *Framework {
|
||||
@@ -62,6 +66,7 @@ func NewDefaultFramework() *Framework {
|
||||
func NewFramework(opt Options) *Framework {
|
||||
f := &Framework{
|
||||
portAllocator: port.NewAllocator(opt.FromPortIndex, opt.ToPortIndex, opt.TotalParallelNode, opt.CurrentNodeIndex-1),
|
||||
usedPorts: make(map[string]int),
|
||||
}
|
||||
|
||||
ginkgo.BeforeEach(f.BeforeEach)
|
||||
@@ -110,9 +115,14 @@ func (f *Framework) AfterEach() {
|
||||
f.serverProcesses = nil
|
||||
f.clientProcesses = nil
|
||||
|
||||
// close mock servers
|
||||
// close default mock servers
|
||||
f.mockServers.Close()
|
||||
|
||||
// close manual registered mock servers
|
||||
for _, s := range f.servers {
|
||||
s.Close()
|
||||
}
|
||||
|
||||
// clean directory
|
||||
os.RemoveAll(f.TempDirectory)
|
||||
f.TempDirectory = ""
|
||||
@@ -123,7 +133,7 @@ func (f *Framework) AfterEach() {
|
||||
for _, port := range f.usedPorts {
|
||||
f.portAllocator.Release(port)
|
||||
}
|
||||
f.usedPorts = nil
|
||||
f.usedPorts = make(map[string]int)
|
||||
}
|
||||
|
||||
var portRegex = regexp.MustCompile(`{{ \.Port.*? }}`)
|
||||
@@ -161,7 +171,6 @@ func (f *Framework) genPortsFromTemplates(templates []string) (ports map[string]
|
||||
ports[name] = port
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// RenderTemplates alloc all ports for port names placeholder.
|
||||
@@ -176,6 +185,10 @@ func (f *Framework) RenderTemplates(templates []string) (outs []string, ports ma
|
||||
params[name] = port
|
||||
}
|
||||
|
||||
for name, port := range f.usedPorts {
|
||||
params[name] = port
|
||||
}
|
||||
|
||||
for _, t := range templates {
|
||||
tmpl, err := template.New("").Parse(t)
|
||||
if err != nil {
|
||||
@@ -193,3 +206,22 @@ func (f *Framework) RenderTemplates(templates []string) (outs []string, ports ma
|
||||
func (f *Framework) PortByName(name string) int {
|
||||
return f.usedPorts[name]
|
||||
}
|
||||
|
||||
func (f *Framework) AllocPort() int {
|
||||
port := f.portAllocator.Get()
|
||||
ExpectTrue(port > 0, "alloc port failed")
|
||||
return port
|
||||
}
|
||||
|
||||
func (f *Framework) ReleasePort(port int) {
|
||||
f.portAllocator.Release(port)
|
||||
}
|
||||
|
||||
func (f *Framework) RunServer(portName string, s *server.Server) {
|
||||
f.servers = append(f.servers, s)
|
||||
if s.BindPort() > 0 {
|
||||
f.usedPorts[portName] = s.BindPort()
|
||||
}
|
||||
err := s.Run()
|
||||
ExpectNoError(err, portName)
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/fatedier/frp/test/e2e/mock/echoserver"
|
||||
"github.com/fatedier/frp/test/e2e/mock/server"
|
||||
"github.com/fatedier/frp/test/e2e/pkg/port"
|
||||
)
|
||||
|
||||
@@ -15,36 +15,22 @@ const (
|
||||
)
|
||||
|
||||
type MockServers struct {
|
||||
tcpEchoServer *echoserver.Server
|
||||
udpEchoServer *echoserver.Server
|
||||
udsEchoServer *echoserver.Server
|
||||
tcpEchoServer *server.Server
|
||||
udpEchoServer *server.Server
|
||||
udsEchoServer *server.Server
|
||||
}
|
||||
|
||||
func NewMockServers(portAllocator *port.Allocator) *MockServers {
|
||||
s := &MockServers{}
|
||||
tcpPort := portAllocator.Get()
|
||||
udpPort := portAllocator.Get()
|
||||
s.tcpEchoServer = echoserver.New(echoserver.Options{
|
||||
Type: echoserver.TCP,
|
||||
BindAddr: "127.0.0.1",
|
||||
BindPort: int32(tcpPort),
|
||||
RepeatNum: 1,
|
||||
})
|
||||
s.udpEchoServer = echoserver.New(echoserver.Options{
|
||||
Type: echoserver.UDP,
|
||||
BindAddr: "127.0.0.1",
|
||||
BindPort: int32(udpPort),
|
||||
RepeatNum: 1,
|
||||
})
|
||||
s.tcpEchoServer = server.New(server.TCP, server.WithBindPort(tcpPort), server.WithEchoMode(true))
|
||||
s.udpEchoServer = server.New(server.UDP, server.WithBindPort(udpPort), server.WithEchoMode(true))
|
||||
|
||||
udsIndex := portAllocator.Get()
|
||||
udsAddr := fmt.Sprintf("%s/frp_echo_server_%d.sock", os.TempDir(), udsIndex)
|
||||
os.Remove(udsAddr)
|
||||
s.udsEchoServer = echoserver.New(echoserver.Options{
|
||||
Type: echoserver.Unix,
|
||||
BindAddr: udsAddr,
|
||||
RepeatNum: 1,
|
||||
})
|
||||
s.udsEchoServer = server.New(server.Unix, server.WithBindAddr(udsAddr), server.WithEchoMode(true))
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -65,14 +51,14 @@ func (m *MockServers) Close() {
|
||||
m.tcpEchoServer.Close()
|
||||
m.udpEchoServer.Close()
|
||||
m.udsEchoServer.Close()
|
||||
os.Remove(m.udsEchoServer.GetOptions().BindAddr)
|
||||
os.Remove(m.udsEchoServer.BindAddr())
|
||||
}
|
||||
|
||||
func (m *MockServers) GetTemplateParams() map[string]interface{} {
|
||||
ret := make(map[string]interface{})
|
||||
ret[TCPEchoServerPort] = m.tcpEchoServer.GetOptions().BindPort
|
||||
ret[UDPEchoServerPort] = m.udpEchoServer.GetOptions().BindPort
|
||||
ret[UDSEchoServerAddr] = m.udsEchoServer.GetOptions().BindAddr
|
||||
ret[TCPEchoServerPort] = m.tcpEchoServer.BindPort()
|
||||
ret[UDPEchoServerPort] = m.udpEchoServer.BindPort()
|
||||
ret[UDSEchoServerAddr] = m.udsEchoServer.BindAddr()
|
||||
return ret
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,9 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str
|
||||
ExpectNoError(err)
|
||||
ExpectTrue(len(templates) > 0)
|
||||
|
||||
f.usedPorts = ports
|
||||
for name, port := range ports {
|
||||
f.usedPorts[name] = port
|
||||
}
|
||||
|
||||
for i := range serverTemplates {
|
||||
path := filepath.Join(f.TempDirectory, fmt.Sprintf("frp-e2e-server-%d", i))
|
||||
|
@@ -54,7 +54,7 @@ func NewRequestExpect(f *Framework) *RequestExpect {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *RequestExpect) Request(f func(r *request.Request)) *RequestExpect {
|
||||
func (e *RequestExpect) RequestModify(f func(r *request.Request)) *RequestExpect {
|
||||
f(e.req)
|
||||
return e
|
||||
}
|
||||
@@ -66,6 +66,11 @@ func (e *RequestExpect) PortName(name string) *RequestExpect {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *RequestExpect) ExpectResp(resp []byte) *RequestExpect {
|
||||
e.expectResp = resp
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *RequestExpect) ExpectError(expectErr bool) *RequestExpect {
|
||||
e.expectError = expectErr
|
||||
return e
|
||||
|
@@ -1,111 +0,0 @@
|
||||
package echoserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
fnet "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
type ServerType string
|
||||
|
||||
const (
|
||||
TCP ServerType = "tcp"
|
||||
UDP ServerType = "udp"
|
||||
Unix ServerType = "unix"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Type ServerType
|
||||
BindAddr string
|
||||
BindPort int32
|
||||
RepeatNum int
|
||||
SpecifiedResponse string
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
opt Options
|
||||
|
||||
l net.Listener
|
||||
}
|
||||
|
||||
func New(opt Options) *Server {
|
||||
if opt.Type == "" {
|
||||
opt.Type = TCP
|
||||
}
|
||||
if opt.BindAddr == "" {
|
||||
opt.BindAddr = "127.0.0.1"
|
||||
}
|
||||
if opt.RepeatNum <= 0 {
|
||||
opt.RepeatNum = 1
|
||||
}
|
||||
return &Server{
|
||||
opt: opt,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) GetOptions() Options {
|
||||
return s.opt
|
||||
}
|
||||
|
||||
func (s *Server) Run() error {
|
||||
if err := s.initListener(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
c, err := s.l.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go s.handle(c)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
if s.l != nil {
|
||||
return s.l.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) initListener() (err error) {
|
||||
switch s.opt.Type {
|
||||
case TCP:
|
||||
s.l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", s.opt.BindAddr, s.opt.BindPort))
|
||||
case UDP:
|
||||
s.l, err = fnet.ListenUDP(s.opt.BindAddr, int(s.opt.BindPort))
|
||||
case Unix:
|
||||
s.l, err = net.Listen("unix", s.opt.BindAddr)
|
||||
default:
|
||||
return fmt.Errorf("unknown server type: %s", s.opt.Type)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handle(c net.Conn) {
|
||||
defer c.Close()
|
||||
|
||||
buf := make([]byte, 2048)
|
||||
for {
|
||||
n, err := c.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var response string
|
||||
if len(s.opt.SpecifiedResponse) > 0 {
|
||||
response = s.opt.SpecifiedResponse
|
||||
} else {
|
||||
response = strings.Repeat(string(buf[:n]), s.opt.RepeatNum)
|
||||
}
|
||||
c.Write([]byte(response))
|
||||
}
|
||||
}
|
142
test/e2e/mock/server/server.go
Normal file
142
test/e2e/mock/server/server.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
libnet "github.com/fatedier/frp/pkg/util/net"
|
||||
)
|
||||
|
||||
type ServerType string
|
||||
|
||||
const (
|
||||
TCP ServerType = "tcp"
|
||||
UDP ServerType = "udp"
|
||||
Unix ServerType = "unix"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
netType ServerType
|
||||
bindAddr string
|
||||
bindPort int
|
||||
respContent []byte
|
||||
bufSize int64
|
||||
|
||||
echoMode bool
|
||||
|
||||
l net.Listener
|
||||
}
|
||||
|
||||
type Option func(*Server) *Server
|
||||
|
||||
func New(netType ServerType, options ...Option) *Server {
|
||||
s := &Server{
|
||||
netType: netType,
|
||||
bindAddr: "127.0.0.1",
|
||||
bufSize: 2048,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
s = option(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func WithBindAddr(addr string) Option {
|
||||
return func(s *Server) *Server {
|
||||
s.bindAddr = addr
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
func WithBindPort(port int) Option {
|
||||
return func(s *Server) *Server {
|
||||
s.bindPort = port
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
func WithRespContent(content []byte) Option {
|
||||
return func(s *Server) *Server {
|
||||
s.respContent = content
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
func WithBufSize(bufSize int64) Option {
|
||||
return func(s *Server) *Server {
|
||||
s.bufSize = bufSize
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
func WithEchoMode(echoMode bool) Option {
|
||||
return func(s *Server) *Server {
|
||||
s.echoMode = echoMode
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Run() error {
|
||||
if err := s.initListener(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
c, err := s.l.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go s.handle(c)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
if s.l != nil {
|
||||
return s.l.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) initListener() (err error) {
|
||||
switch s.netType {
|
||||
case TCP:
|
||||
s.l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", s.bindAddr, s.bindPort))
|
||||
case UDP:
|
||||
s.l, err = libnet.ListenUDP(s.bindAddr, s.bindPort)
|
||||
case Unix:
|
||||
s.l, err = net.Listen("unix", s.bindAddr)
|
||||
default:
|
||||
return fmt.Errorf("unknown server type: %s", s.netType)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) handle(c net.Conn) {
|
||||
defer c.Close()
|
||||
|
||||
buf := make([]byte, s.bufSize)
|
||||
for {
|
||||
n, err := c.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if s.echoMode {
|
||||
c.Write(buf[:n])
|
||||
} else {
|
||||
c.Write(s.respContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) BindAddr() string {
|
||||
return s.bindAddr
|
||||
}
|
||||
|
||||
func (s *Server) BindPort() int {
|
||||
return s.bindPort
|
||||
}
|
@@ -56,7 +56,6 @@ func (pa *Allocator) GetByName(portName string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// TODO: Distinguish between TCP and UDP
|
||||
l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
||||
if err != nil {
|
||||
// Maybe not controlled by us, mark it used.
|
||||
|
@@ -59,9 +59,11 @@ func WithRangePorts(from, to int) NameOption {
|
||||
}
|
||||
|
||||
func GenName(name string, options ...NameOption) string {
|
||||
name = strings.ReplaceAll(name, "-", "")
|
||||
name = strings.ReplaceAll(name, "_", "")
|
||||
builder := &nameBuilder{name: name}
|
||||
for _, option := range options {
|
||||
option(builder)
|
||||
builder = option(builder)
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
@@ -6,11 +6,9 @@ package e2e
|
||||
// and then the function that only runs on the first Ginkgo node.
|
||||
func CleanupSuite() {
|
||||
// Run on all Ginkgo nodes
|
||||
// TODO
|
||||
}
|
||||
|
||||
// AfterSuiteActions are actions that are run on ginkgo's SynchronizedAfterSuite
|
||||
func AfterSuiteActions() {
|
||||
// Run only Ginkgo on node 1
|
||||
// TODO
|
||||
}
|
||||
|
Reference in New Issue
Block a user