Skip to content

Commit

Permalink
test: add daemon and fetch cli flag tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kylehuntsman authored and hannahhoward committed Jun 22, 2023
1 parent 903b161 commit 7eab5e7
Show file tree
Hide file tree
Showing 6 changed files with 664 additions and 84 deletions.
61 changes: 37 additions & 24 deletions cmd/lassie/daemon.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"

"github.com/filecoin-project/lassie/pkg/aggregateeventrecorder"
Expand Down Expand Up @@ -79,38 +80,40 @@ var daemonCmd = &cli.Command{
Name: "daemon",
Usage: "Starts a lassie daemon, accepting http requests",
Before: before,
After: after,
Flags: daemonFlags,
Action: daemonCommand,
Action: daemonAction,
}

// daemonCommand is the action for the daemon command. It sets up the
// lassie daemon and starts the http server. It is intentionally not
// performing any logic itself, but delegates to the DaemonCommandHandler
// function for testability.
func daemonCommand(cctx *cli.Context) error {
address := cctx.String("address")
port := cctx.Uint("port")
tempDir := cctx.String("tempdir")
// daemonAction is the cli action for the daemon command. This function is
// called by the cli framework when the daemon command is invoked. It translates
// the cli context into the appropriate config objects and then calls the
// daemonRun function.
func daemonAction(cctx *cli.Context) error {
// lassie config
libp2pLowWater := cctx.Int("libp2p-conns-lowwater")
libp2pHighWater := cctx.Int("libp2p-conns-highwater")
concurrentSPRetrievals := cctx.Uint("concurrent-sp-retrievals")
maxBlocks := cctx.Uint64("maxblocks")

eventRecorderURL := cctx.String("event-recorder-url")
authToken := cctx.String("event-recorder-auth")
instanceID := cctx.String("event-recorder-instance-id")

lassieCfg, err := getLassieConfigForDaemon(cctx, libp2pLowWater, libp2pHighWater, concurrentSPRetrievals)
if err != nil {
return cli.Exit(err, 1)
}

// http server config
address := cctx.String("address")
port := cctx.Uint("port")
tempDir := cctx.String("tempdir")
maxBlocks := cctx.Uint64("maxblocks")
httpServerCfg := getHttpServerConfigForDaemon(address, port, tempDir, maxBlocks)

// event recorder config
eventRecorderURL := cctx.String("event-recorder-url")
authToken := cctx.String("event-recorder-auth")
instanceID := cctx.String("event-recorder-instance-id")
eventRecorderCfg := getEventRecorderConfig(eventRecorderURL, authToken, instanceID)

err = daemonCommandHandler(
cctx,
err = daemonRun(
cctx.Context,
lassieCfg,
httpServerCfg,
eventRecorderCfg,
Expand All @@ -122,18 +125,28 @@ func daemonCommand(cctx *cli.Context) error {
return nil
}

// DeamonCommandHandler is the handler for the daemon command.
// This abstraction allows the daemon to be invoked programmatically
// for testing.
func daemonCommandHandler(
cctx *cli.Context,
// daemonRunFunc is the function signature for the daemonRun function.
type daemonRunFunc func(
ctx context.Context,
lassieCfg *lassie.LassieConfig,
httpServerCfg httpserver.HttpServerConfig,
eventRecorderCfg *aggregateeventrecorder.EventRecorderConfig,
) error

// daemonRun is the instance of a daemonRunFunc function that will
// execute when running the daemon command. It is set to
// defaultDaemonRun by default, but can be replaced for testing.
var daemonRun daemonRunFunc = defaultDaemonRun

// defaultDaemonRun is the default implementation for the daemonRun function.
func defaultDaemonRun(
ctx context.Context,
lassieCfg *lassie.LassieConfig,
httpServerCfg httpserver.HttpServerConfig,
eventRecorderCfg *aggregateeventrecorder.EventRecorderConfig,
) error {
ctx := cctx.Context

lassie, err := lassie.NewLassieWithConfig(cctx.Context, lassieCfg)
lassie, err := lassie.NewLassieWithConfig(ctx, lassieCfg)
if err != nil {
return nil
}
Expand Down
216 changes: 216 additions & 0 deletions cmd/lassie/daemon_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package main

import (
"context"
"os"
"testing"
"time"

a "github.com/filecoin-project/lassie/pkg/aggregateeventrecorder"
l "github.com/filecoin-project/lassie/pkg/lassie"
h "github.com/filecoin-project/lassie/pkg/server/http"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/net/connmgr"
"github.com/multiformats/go-multicodec"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
)

func TestDaemonCommandFlags(t *testing.T) {
tests := []struct {
name string
args []string
assert daemonRunFunc
}{
{
name: "with default args",
args: []string{"daemon"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
// lassie config
require.Equal(t, nil, lCfg.Finder)
require.NotNil(t, lCfg.Host, "host should not be nil")
require.Equal(t, 20*time.Second, lCfg.ProviderTimeout)
require.Equal(t, uint(0), lCfg.ConcurrentSPRetrievals)
require.Equal(t, 0*time.Second, lCfg.GlobalTimeout)
require.Equal(t, 0, len(lCfg.Libp2pOptions))
require.Equal(t, 0, len(lCfg.Protocols))
require.Equal(t, 0, len(lCfg.ProviderBlockList))
require.Equal(t, 0, len(lCfg.ProviderAllowList))
require.Equal(t, os.TempDir(), lCfg.TempDir)
require.Equal(t, 6, lCfg.BitswapConcurrency)

// http server config
require.Equal(t, "127.0.0.1", hCfg.Address)
require.Equal(t, uint(0), hCfg.Port)
require.Equal(t, "/tmp", hCfg.TempDir)
require.Equal(t, uint64(0), hCfg.MaxBlocksPerRequest)

// event recorder config
require.Equal(t, "", erCfg.EndpointURL)
require.Equal(t, "", erCfg.EndpointAuthorization)
require.Equal(t, "", erCfg.InstanceID)
return nil
},
},
{
name: "with libp2p low connection threshold and concurrent sp retrievals",
args: []string{"daemon", "--libp2p-conns-lowwater", "10", "--concurrent-sp-retrievals", "10"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, 1, len(lCfg.Libp2pOptions))
// Should only be set when libp2p connection threshold options are also provided
require.Equal(t, uint(10), lCfg.ConcurrentSPRetrievals)
return nil
},
},
{
name: "with libp2p high connection threshold and concurrent sp retrievals",
args: []string{"daemon", "--libp2p-conns-highwater", "10", "--concurrent-sp-retrievals", "10"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, 1, len(lCfg.Libp2pOptions))
// Should only be set when libp2p connection threshold options are also provided
require.Equal(t, uint(10), lCfg.ConcurrentSPRetrievals)
return nil
},
},
{
name: "with libp2p low and high connection thresholds and concurrent sp retrievals",
args: []string{"daemon", "--libp2p-conns-lowwater", "10", "--libp2p-conns-highwater", "20"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.NotNil(t, lCfg.Host, "host should not be nil")
cmgr, ok := lCfg.Host.ConnManager().(*connmgr.BasicConnMgr)
require.True(t, ok)
cmInfo := cmgr.GetInfo()
require.Equal(t, cmInfo.LowWater, 10)
require.Equal(t, cmInfo.HighWater, 10)
return nil
},
},
{
name: "with concurrent sp retrievals",
args: []string{"daemon", "--concurrent-sp-retrievals", "10"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, uint(10), lCfg.ConcurrentSPRetrievals)
return nil
},
},
{
name: "with temp directory",
args: []string{"daemon", "--tempdir", "/mytmpdir"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, "/mytmpdir", lCfg.TempDir)
require.Equal(t, "/mytmpdir", hCfg.TempDir)
return nil
},
},
{
name: "with provider timeout",
args: []string{"daemon", "--provider-timeout", "30s"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, 30*time.Second, lCfg.ProviderTimeout)
return nil
},
},
{
name: "with global timeout",
args: []string{"daemon", "--global-timeout", "30s"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, 30*time.Second, lCfg.GlobalTimeout)
return nil
},
},
{
name: "with protocols",
args: []string{"daemon", "--protocols", "bitswap,graphsync"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, []multicodec.Code{multicodec.TransportBitswap, multicodec.TransportGraphsyncFilecoinv1}, lCfg.Protocols)
return nil
},
},
{
name: "with exclude providers",
args: []string{"daemon", "--exclude-providers", "12D3KooWBSTEYMLSu5FnQjshEVah9LFGEZoQt26eacCEVYfedWA4,12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
p1, err := peer.Decode("12D3KooWBSTEYMLSu5FnQjshEVah9LFGEZoQt26eacCEVYfedWA4")
require.NoError(t, err)
p2, err := peer.Decode("12D3KooWPNbkEgjdBNeaCGpsgCrPRETe4uBZf1ShFXStobdN18ys")
require.NoError(t, err)

require.Equal(t, true, lCfg.ProviderBlockList[p1])
require.Equal(t, true, lCfg.ProviderBlockList[p2])
return nil
},
},
{
name: "with bitswap concurrency",
args: []string{"daemon", "--bitswap-concurrency", "10"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, 10, lCfg.BitswapConcurrency)
return nil
},
},
{
name: "with address",
args: []string{"daemon", "--address", "0.0.0.0"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, "0.0.0.0", hCfg.Address)
return nil
},
},
{
name: "with port",
args: []string{"daemon", "--port", "1234"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, uint(1234), hCfg.Port)
return nil
},
},
{
name: "with max blocks",
args: []string{"daemon", "--maxblocks", "10"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, uint64(10), hCfg.MaxBlocksPerRequest)
return nil
},
},
{
name: "with event recorder url",
args: []string{"daemon", "--event-recorder-url", "https://myeventrecorder.com/v1/retrieval-events"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, "https://myeventrecorder.com/v1/retrieval-events", erCfg.EndpointURL)
return nil
},
},
{
name: "with event recorder auth",
args: []string{"daemon", "--event-recorder-auth", "secret"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, "secret", erCfg.EndpointAuthorization)
return nil
},
},
{
name: "with event recorder instance ID",
args: []string{"daemon", "--event-recorder-instance-id", "myinstanceid"},
assert: func(ctx context.Context, lCfg *l.LassieConfig, hCfg h.HttpServerConfig, erCfg *a.EventRecorderConfig) error {
require.Equal(t, "myinstanceid", erCfg.InstanceID)
return nil
},
},
}

for _, test := range tests {
daemonRun = test.assert
app := &cli.App{
Name: "cli-test",
Flags: daemonFlags,
Commands: []*cli.Command{daemonCmd},
}

t.Run(test.name, func(t *testing.T) {
err := app.Run(append([]string{"cli-test"}, test.args...))
if err != nil {
t.Fatal(err)
}
})
}
}
Loading

0 comments on commit 7eab5e7

Please sign in to comment.