Squashed 'livekit-server/' content from commit 154b4d26
git-subtree-dir: livekit-server git-subtree-split: 154b4d26b769c68a03c096124094b97bf61a996f
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
// Copyright 2023 LiveKit, 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
|
||||
//
|
||||
// http://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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/livekit/protocol/auth"
|
||||
"github.com/livekit/protocol/utils"
|
||||
"github.com/livekit/protocol/utils/guid"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
"github.com/livekit/livekit-server/pkg/routing"
|
||||
"github.com/livekit/livekit-server/pkg/service"
|
||||
)
|
||||
|
||||
func generateKeys(_ *cli.Context) error {
|
||||
apiKey := guid.New(utils.APIKeyPrefix)
|
||||
secret := utils.RandomSecret()
|
||||
fmt.Println("API Key: ", apiKey)
|
||||
fmt.Println("API Secret: ", secret)
|
||||
return nil
|
||||
}
|
||||
|
||||
func printPorts(c *cli.Context) error {
|
||||
conf, err := getConfig(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
udpPorts := make([]string, 0)
|
||||
tcpPorts := make([]string, 0)
|
||||
|
||||
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - HTTP service", conf.Port))
|
||||
if conf.RTC.TCPPort != 0 {
|
||||
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - ICE/TCP", conf.RTC.TCPPort))
|
||||
}
|
||||
if conf.RTC.UDPPort.Valid() {
|
||||
portStr, _ := conf.RTC.UDPPort.MarshalYAML()
|
||||
udpPorts = append(udpPorts, fmt.Sprintf("%s - ICE/UDP", portStr))
|
||||
} else {
|
||||
udpPorts = append(udpPorts, fmt.Sprintf("%d-%d - ICE/UDP range", conf.RTC.ICEPortRangeStart, conf.RTC.ICEPortRangeEnd))
|
||||
}
|
||||
|
||||
if conf.TURN.Enabled {
|
||||
if conf.TURN.TLSPort > 0 {
|
||||
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - TURN/TLS", conf.TURN.TLSPort))
|
||||
}
|
||||
if conf.TURN.UDPPort > 0 {
|
||||
udpPorts = append(udpPorts, fmt.Sprintf("%d - TURN/UDP", conf.TURN.UDPPort))
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("TCP Ports")
|
||||
for _, p := range tcpPorts {
|
||||
fmt.Println(p)
|
||||
}
|
||||
|
||||
fmt.Println("UDP Ports")
|
||||
for _, p := range udpPorts {
|
||||
fmt.Println(p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func helpVerbose(c *cli.Context) error {
|
||||
generatedFlags, err := config.GenerateCLIFlags(baseFlags, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.App.Flags = append(baseFlags, generatedFlags...)
|
||||
return cli.ShowAppHelp(c)
|
||||
}
|
||||
|
||||
func createToken(c *cli.Context) error {
|
||||
room := c.String("room")
|
||||
identity := c.String("identity")
|
||||
|
||||
conf, err := getConfig(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// use the first API key from config
|
||||
if len(conf.Keys) == 0 {
|
||||
// try to load from file
|
||||
if _, err := os.Stat(conf.KeyFile); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Open(conf.KeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = f.Close()
|
||||
}()
|
||||
decoder := yaml.NewDecoder(f)
|
||||
if err = decoder.Decode(conf.Keys); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(conf.Keys) == 0 {
|
||||
return fmt.Errorf("keys are not configured")
|
||||
}
|
||||
}
|
||||
|
||||
var apiKey string
|
||||
var apiSecret string
|
||||
for k, v := range conf.Keys {
|
||||
apiKey = k
|
||||
apiSecret = v
|
||||
break
|
||||
}
|
||||
|
||||
grant := &auth.VideoGrant{
|
||||
RoomJoin: true,
|
||||
Room: room,
|
||||
}
|
||||
if c.Bool("recorder") {
|
||||
grant.Hidden = true
|
||||
grant.Recorder = true
|
||||
grant.SetCanPublish(false)
|
||||
grant.SetCanPublishData(false)
|
||||
}
|
||||
|
||||
at := auth.NewAccessToken(apiKey, apiSecret).
|
||||
AddGrant(grant).
|
||||
SetIdentity(identity).
|
||||
SetValidFor(30 * 24 * time.Hour)
|
||||
|
||||
token, err := at.ToJWT()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Token:", token)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func listNodes(c *cli.Context) error {
|
||||
conf, err := getConfig(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
currentNode, err := routing.NewLocalNode(conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
router, err := service.InitializeRouter(conf, currentNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := router.ListNodes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetRowLine(true)
|
||||
table.SetAutoWrapText(false)
|
||||
table.SetHeader([]string{
|
||||
"ID", "IP Address", "Region",
|
||||
"CPUs", "CPU Usage\nLoad Avg",
|
||||
"Memory Used/Total",
|
||||
"Rooms", "Clients\nTracks In/Out",
|
||||
"Bytes/s In/Out\nBytes Total", "Packets/s In/Out\nPackets Total", "System Dropped Pkts/s\nPkts/s Out/Dropped",
|
||||
"Nack/s\nNack Total", "Retrans/s\nRetrans Total",
|
||||
"Started At\nUpdated At",
|
||||
})
|
||||
table.SetColumnAlignment([]int{
|
||||
tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER,
|
||||
tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_RIGHT,
|
||||
tablewriter.ALIGN_RIGHT,
|
||||
tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_RIGHT,
|
||||
tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_RIGHT,
|
||||
tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_RIGHT,
|
||||
tablewriter.ALIGN_CENTER,
|
||||
})
|
||||
|
||||
for _, node := range nodes {
|
||||
stats := node.Stats
|
||||
|
||||
// Id and state
|
||||
idAndState := fmt.Sprintf("%s\n(%s)", node.Id, node.State.Enum().String())
|
||||
|
||||
// System stats
|
||||
cpus := strconv.Itoa(int(stats.NumCpus))
|
||||
cpuUsageAndLoadAvg := fmt.Sprintf("%.2f %%\n%.2f %.2f %.2f", stats.CpuLoad*100,
|
||||
stats.LoadAvgLast1Min, stats.LoadAvgLast5Min, stats.LoadAvgLast15Min)
|
||||
memUsage := fmt.Sprintf("%s / %s", humanize.Bytes(stats.MemoryUsed), humanize.Bytes(stats.MemoryTotal))
|
||||
|
||||
// Room stats
|
||||
rooms := strconv.Itoa(int(stats.NumRooms))
|
||||
clientsAndTracks := fmt.Sprintf("%d\n%d / %d", stats.NumClients, stats.NumTracksIn, stats.NumTracksOut)
|
||||
|
||||
// Packet stats
|
||||
bytes := fmt.Sprintf("%sps / %sps\n%s / %s", humanize.Bytes(uint64(stats.BytesInPerSec)), humanize.Bytes(uint64(stats.BytesOutPerSec)),
|
||||
humanize.Bytes(stats.BytesIn), humanize.Bytes(stats.BytesOut))
|
||||
packets := fmt.Sprintf("%s / %s\n%s / %s", humanize.Comma(int64(stats.PacketsInPerSec)), humanize.Comma(int64(stats.PacketsOutPerSec)),
|
||||
strings.TrimSpace(humanize.SIWithDigits(float64(stats.PacketsIn), 2, "")), strings.TrimSpace(humanize.SIWithDigits(float64(stats.PacketsOut), 2, "")))
|
||||
sysPackets := fmt.Sprintf("%.2f %%\n%v / %v", stats.SysPacketsDroppedPctPerSec*100, float64(stats.SysPacketsOutPerSec), float64(stats.SysPacketsDroppedPerSec))
|
||||
nacks := fmt.Sprintf("%.2f\n%s", stats.NackPerSec, strings.TrimSpace(humanize.SIWithDigits(float64(stats.NackTotal), 2, "")))
|
||||
retransmit := fmt.Sprintf("%.2f\n%s", stats.RetransmitPacketsOutPerSec, strings.TrimSpace(humanize.SIWithDigits(float64(stats.RetransmitPacketsOut), 2, "")))
|
||||
|
||||
// Date
|
||||
startedAndUpdated := fmt.Sprintf("%s\n%s", time.Unix(stats.StartedAt, 0).UTC().UTC().Format("2006-01-02 15:04:05"),
|
||||
time.Unix(stats.UpdatedAt, 0).UTC().Format("2006-01-02 15:04:05"))
|
||||
|
||||
table.Append([]string{
|
||||
idAndState, node.Ip, node.Region,
|
||||
cpus, cpuUsageAndLoadAvg,
|
||||
memUsage,
|
||||
rooms, clientsAndTracks,
|
||||
bytes, packets, sysPackets,
|
||||
nacks, retransmit,
|
||||
startedAndUpdated,
|
||||
})
|
||||
}
|
||||
table.Render()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
// Copyright 2023 LiveKit, 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
|
||||
//
|
||||
// http://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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/rtc"
|
||||
"github.com/livekit/livekit-server/pkg/telemetry/prometheus"
|
||||
"github.com/livekit/protocol/logger"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
"github.com/livekit/livekit-server/pkg/routing"
|
||||
"github.com/livekit/livekit-server/pkg/service"
|
||||
"github.com/livekit/livekit-server/version"
|
||||
)
|
||||
|
||||
var baseFlags = []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "bind",
|
||||
Usage: "IP address to listen on, use flag multiple times to specify multiple addresses",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Usage: "path to LiveKit config file",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config-body",
|
||||
Usage: "LiveKit config in YAML, typically passed in as an environment var in a container",
|
||||
EnvVars: []string{"LIVEKIT_CONFIG"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "key-file",
|
||||
Usage: "path to file that contains API keys/secrets",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "keys",
|
||||
Usage: "api keys (key: secret\\n)",
|
||||
EnvVars: []string{"LIVEKIT_KEYS"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "region",
|
||||
Usage: "region of the current node. Used by regionaware node selector",
|
||||
EnvVars: []string{"LIVEKIT_REGION"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "node-ip",
|
||||
Usage: "IP address of the current node, used to advertise to clients. Automatically determined by default",
|
||||
EnvVars: []string{"NODE_IP"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "udp-port",
|
||||
Usage: "UDP port(s) to use for WebRTC traffic",
|
||||
EnvVars: []string{"UDP_PORT"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "redis-host",
|
||||
Usage: "host (incl. port) to redis server",
|
||||
EnvVars: []string{"REDIS_HOST"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "redis-password",
|
||||
Usage: "password to redis",
|
||||
EnvVars: []string{"REDIS_PASSWORD"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "turn-cert",
|
||||
Usage: "tls cert file for TURN server",
|
||||
EnvVars: []string{"LIVEKIT_TURN_CERT"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "turn-key",
|
||||
Usage: "tls key file for TURN server",
|
||||
EnvVars: []string{"LIVEKIT_TURN_KEY"},
|
||||
},
|
||||
// debugging flags
|
||||
&cli.StringFlag{
|
||||
Name: "memprofile",
|
||||
Usage: "write memory profile to `file`",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "dev",
|
||||
Usage: "sets log-level to debug, console formatter, and /debug/pprof. insecure for production",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "disable-strict-config",
|
||||
Usage: "disables strict config parsing",
|
||||
Hidden: true,
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
if rtc.Recover(logger.GetLogger()) != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
generatedFlags, err := config.GenerateCLIFlags(baseFlags, true)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
Name: "livekit-server",
|
||||
Usage: "High performance WebRTC server",
|
||||
Description: "run without subcommands to start the server",
|
||||
Flags: append(baseFlags, generatedFlags...),
|
||||
Action: startServer,
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "generate-keys",
|
||||
Usage: "generates an API key and secret pair",
|
||||
Action: generateKeys,
|
||||
},
|
||||
{
|
||||
Name: "ports",
|
||||
Usage: "print ports that server is configured to use",
|
||||
Action: printPorts,
|
||||
},
|
||||
{
|
||||
// this subcommand is deprecated, token generation is provided by CLI
|
||||
Name: "create-join-token",
|
||||
Hidden: true,
|
||||
Usage: "create a room join token for development use",
|
||||
Action: createToken,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "room",
|
||||
Usage: "name of room to join",
|
||||
Required: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "identity",
|
||||
Usage: "identity of participant that holds the token",
|
||||
Required: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "recorder",
|
||||
Usage: "creates a hidden participant that can only subscribe",
|
||||
Required: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "list-nodes",
|
||||
Usage: "list all nodes",
|
||||
Action: listNodes,
|
||||
},
|
||||
{
|
||||
Name: "help-verbose",
|
||||
Usage: "prints app help, including all generated configuration flags",
|
||||
Action: helpVerbose,
|
||||
},
|
||||
},
|
||||
Version: version.Version,
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getConfig(c *cli.Context) (*config.Config, error) {
|
||||
confString, err := getConfigString(c.String("config"), c.String("config-body"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
strictMode := true
|
||||
if c.Bool("disable-strict-config") {
|
||||
strictMode = false
|
||||
}
|
||||
|
||||
conf, err := config.NewConfig(confString, strictMode, c, baseFlags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.InitLoggerFromConfig(&conf.Logging)
|
||||
|
||||
if conf.Development {
|
||||
logger.Infow("starting in development mode")
|
||||
|
||||
if len(conf.Keys) == 0 {
|
||||
logger.Infow("no keys provided, using placeholder keys",
|
||||
"API Key", "devkey",
|
||||
"API Secret", "secret",
|
||||
)
|
||||
conf.Keys = map[string]string{
|
||||
"devkey": "secret",
|
||||
}
|
||||
shouldMatchRTCIP := false
|
||||
// when dev mode and using shared keys, we'll bind to localhost by default
|
||||
if conf.BindAddresses == nil {
|
||||
conf.BindAddresses = []string{
|
||||
"127.0.0.1",
|
||||
"::1",
|
||||
}
|
||||
} else {
|
||||
// if non-loopback addresses are provided, then we'll match RTC IP to bind address
|
||||
// our IP discovery ignores loopback addresses
|
||||
for _, addr := range conf.BindAddresses {
|
||||
ip := net.ParseIP(addr)
|
||||
if ip != nil && !ip.IsLoopback() && !ip.IsUnspecified() {
|
||||
shouldMatchRTCIP = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if shouldMatchRTCIP {
|
||||
for _, bindAddr := range conf.BindAddresses {
|
||||
conf.RTC.IPs.Includes = append(conf.RTC.IPs.Includes, bindAddr+"/24")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func startServer(c *cli.Context) error {
|
||||
conf, err := getConfig(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// validate API key length
|
||||
err = conf.ValidateKeys()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if memProfile := c.String("memprofile"); memProfile != "" {
|
||||
if f, err := os.Create(memProfile); err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer func() {
|
||||
// run memory profile at termination
|
||||
runtime.GC()
|
||||
_ = pprof.WriteHeapProfile(f)
|
||||
_ = f.Close()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
currentNode, err := routing.NewLocalNode(conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := prometheus.Init(string(currentNode.NodeID()), currentNode.NodeType()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server, err := service.InitializeServer(conf, currentNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 2; i++ {
|
||||
sig := <-sigChan
|
||||
force := i > 0
|
||||
logger.Infow("exit requested, shutting down", "signal", sig, "force", force)
|
||||
go server.Stop(force)
|
||||
}
|
||||
}()
|
||||
|
||||
return server.Start()
|
||||
}
|
||||
|
||||
func getConfigString(configFile string, inConfigBody string) (string, error) {
|
||||
if inConfigBody != "" || configFile == "" {
|
||||
return inConfigBody, nil
|
||||
}
|
||||
|
||||
outConfigBody, err := os.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(outConfigBody), nil
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2023 LiveKit, 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
|
||||
//
|
||||
// http://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 main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testStruct struct {
|
||||
configFileName string
|
||||
configBody string
|
||||
|
||||
expectedError error
|
||||
expectedConfigBody string
|
||||
}
|
||||
|
||||
func TestGetConfigString(t *testing.T) {
|
||||
tests := []testStruct{
|
||||
{"", "", nil, ""},
|
||||
{"", "configBody", nil, "configBody"},
|
||||
{"file", "configBody", nil, "configBody"},
|
||||
{"file", "", nil, "fileContent"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
func() {
|
||||
writeConfigFile(test, t)
|
||||
defer os.Remove(test.configFileName)
|
||||
|
||||
configBody, err := getConfigString(test.configFileName, test.configBody)
|
||||
require.Equal(t, test.expectedError, err)
|
||||
require.Equal(t, test.expectedConfigBody, configBody)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldReturnErrorIfConfigFileDoesNotExist(t *testing.T) {
|
||||
configBody, err := getConfigString("notExistingFile", "")
|
||||
require.Error(t, err)
|
||||
require.Empty(t, configBody)
|
||||
}
|
||||
|
||||
func writeConfigFile(test testStruct, t *testing.T) {
|
||||
if test.configFileName != "" {
|
||||
d1 := []byte(test.expectedConfigBody)
|
||||
err := os.WriteFile(test.configFileName, d1, 0o644)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user