mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
179 lines
4.5 KiB
Go
179 lines
4.5 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
package test
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/molecula/featurebase/v3/etcd"
|
|
"github.com/molecula/featurebase/v3/server"
|
|
"github.com/molecula/featurebase/v3/testhook"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type Ports struct {
|
|
LsnC *net.TCPListener
|
|
PortC int
|
|
|
|
LsnP *net.TCPListener
|
|
PortP int
|
|
|
|
LsnG *net.TCPListener
|
|
Grpc int
|
|
}
|
|
|
|
func (ports *Ports) Close() error {
|
|
err := ports.LsnC.Close()
|
|
err2 := ports.LsnP.Close()
|
|
err3 := ports.LsnG.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err2 != nil {
|
|
return err2
|
|
}
|
|
return err3
|
|
}
|
|
|
|
// listenerWithURL builds a TCP listener and corresponding http://localhost:%d
|
|
// URL, and returns those.
|
|
func listenerWithURL() (listener *net.TCPListener, url string, err error) {
|
|
l, err := net.Listen("tcp", ":0")
|
|
if err != nil {
|
|
return listener, url, err
|
|
}
|
|
listener = l.(*net.TCPListener)
|
|
port := listener.Addr().(*net.TCPAddr).Port
|
|
url = fmt.Sprintf("http://localhost:%d", port)
|
|
return listener, url, err
|
|
}
|
|
|
|
// GetPortsGenConfigs creates listener ports, and updates the configurations
|
|
// of servers to match these created ports, including cross-references
|
|
// like updating the InitCluster values in the Etcd configs.
|
|
func GetPortsGenConfigs(tb testing.TB, nodes []*Command) error {
|
|
peerUrls := make([]string, len(nodes))
|
|
for i := range nodes {
|
|
if nodes[i].Config == nil {
|
|
nodes[i].Config = &server.Config{}
|
|
}
|
|
config := nodes[i].Config
|
|
name := fmt.Sprintf("server%d", i)
|
|
clusterName := fmt.Sprintf("cluster-%s", tb.Name())
|
|
discoDir, err := testhook.TempDir(tb, "disco.")
|
|
if err != nil {
|
|
return errors.Wrap(err, "creating temp directory")
|
|
}
|
|
clientListener, clientURL, err := listenerWithURL()
|
|
if err != nil {
|
|
return errors.Wrap(err, "creating client listener")
|
|
}
|
|
peerListener, peerURL, err := listenerWithURL()
|
|
if err != nil {
|
|
return errors.Wrap(err, "creating peer listener")
|
|
}
|
|
grpcListener, grpcUrl, err := listenerWithURL()
|
|
if err != nil {
|
|
return errors.Wrap(err, "creating gRPC listener")
|
|
}
|
|
// for grpc, we don't want the http part...
|
|
colon := strings.LastIndexByte(grpcUrl, ':')
|
|
if colon != -1 {
|
|
grpcUrl = grpcUrl[colon:]
|
|
}
|
|
config.Name = name
|
|
config.Cluster.Name = clusterName
|
|
config.BindGRPC = grpcUrl
|
|
config.GRPCListener = grpcListener
|
|
config.Etcd = etcd.Options{
|
|
Dir: discoDir,
|
|
LClientURL: clientURL,
|
|
AClientURL: clientURL,
|
|
LPeerURL: peerURL,
|
|
APeerURL: peerURL,
|
|
HeartbeatTTL: 60,
|
|
LPeerSocket: []*net.TCPListener{peerListener},
|
|
LClientSocket: []*net.TCPListener{clientListener},
|
|
BootstrapTimeout: 50 * time.Millisecond,
|
|
UnsafeNoFsync: true,
|
|
}
|
|
peerUrls[i] = fmt.Sprintf("%s=%s", name, peerURL)
|
|
}
|
|
allPeerUrls := strings.Join(peerUrls, ",")
|
|
for i := range nodes {
|
|
nodes[i].Config.Etcd.InitCluster = allPeerUrls
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//GenPortsConfig creates specific configuration for etcd.
|
|
func GenPortsConfig(tb testing.TB, ports []Ports) []*server.Config {
|
|
cfgs := make([]*server.Config, len(ports))
|
|
clusterURLs := make([]string, len(ports))
|
|
for i := range cfgs {
|
|
name := fmt.Sprintf("server%d", i)
|
|
clusterName := "cluster-abc123"
|
|
|
|
lsnC, portC := ports[i].LsnC, ports[i].PortC
|
|
lClientURL := fmt.Sprintf("http://localhost:%d", portC)
|
|
lsnP, portP := ports[i].LsnP, ports[i].PortP
|
|
lPeerURL := fmt.Sprintf("http://localhost:%d", portP)
|
|
|
|
discoDir := ""
|
|
if d, err := testhook.TempDir(tb, "disco."); err == nil {
|
|
discoDir = d
|
|
}
|
|
|
|
cfgs[i] = &server.Config{
|
|
Name: name,
|
|
BindGRPC: fmt.Sprintf(":%d", ports[i].Grpc),
|
|
GRPCListener: ports[i].LsnG,
|
|
Etcd: etcd.Options{
|
|
Dir: discoDir,
|
|
LClientURL: lClientURL,
|
|
AClientURL: lClientURL,
|
|
LPeerURL: lPeerURL,
|
|
APeerURL: lPeerURL,
|
|
HeartbeatTTL: 5,
|
|
LPeerSocket: []*net.TCPListener{lsnP},
|
|
LClientSocket: []*net.TCPListener{lsnC},
|
|
BootstrapTimeout: 50 * time.Millisecond,
|
|
UnsafeNoFsync: true,
|
|
},
|
|
}
|
|
cfgs[i].Cluster.Name = clusterName
|
|
|
|
clusterURLs[i] = fmt.Sprintf("%s=%s", name, lPeerURL)
|
|
}
|
|
for i := range cfgs {
|
|
cfgs[i].Etcd.InitCluster = strings.Join(clusterURLs, ",")
|
|
}
|
|
|
|
return cfgs
|
|
}
|
|
|
|
func NewPorts(lsn []*net.TCPListener) []Ports {
|
|
var out []Ports
|
|
|
|
n := len(lsn)
|
|
ports := make([]int, n)
|
|
for i := 0; i < n; i++ {
|
|
ports[i] = lsn[i].Addr().(*net.TCPAddr).Port
|
|
}
|
|
|
|
for i := 0; i < n; i = i + 3 {
|
|
out = append(out, Ports{
|
|
LsnC: lsn[i],
|
|
PortC: ports[i],
|
|
LsnP: lsn[i+1],
|
|
PortP: ports[i+1],
|
|
Grpc: ports[i+2],
|
|
LsnG: lsn[i+2],
|
|
})
|
|
}
|
|
|
|
return out
|
|
}
|