mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 02:44:59 +00:00
FB-1766: cleaning up the CmdIO objects passing alternate stdin/
stdout/stderr around A lot of functions in the cmd and ctl packages were passing these around and barely using them. Replaced them with a logger for most functions. Some functions get an io.Writer instead so that their tests can find the output they're looking for. More cleanup on fb-1766: reworked the tests that were using io.Pipe or os.Pipe to check their results so they now use a bytes.Buffer. Unexported some variables that didn't need to be exported. Fixed NewConfigCommand to use the provided stderr, not os.Stderr. Added tests for rbf_dump, rbf_page, and keygen, since those weren't being tested at all. Added chksum_test, final cleanup.
This commit is contained in:
parent
a98b9144cb
commit
f627199acb
63 changed files with 553 additions and 417 deletions
31
cmd.go
31
cmd.go
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright 2021 Molecula Corp. All rights reserved.
|
||||
package pilosa
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
// CmdIO holds standard unix inputs and outputs.
|
||||
type CmdIO struct {
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// NewCmdIO returns a new instance of CmdIO with inputs and outputs set to the
|
||||
// arguments.
|
||||
func NewCmdIO(stdin io.Reader, stdout, stderr io.Writer) *CmdIO {
|
||||
return &CmdIO{
|
||||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
logger: logger.NewStandardLogger(stderr),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CmdIO) Logger() logger.Logger {
|
||||
return c.logger
|
||||
}
|
||||
|
|
@ -2,14 +2,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newAuthTokenCommand(stdin io.Reader, stdout io.Writer, stderr io.Writer) *cobra.Command {
|
||||
cmd := ctl.NewAuthTokenCommand(stdin, stdout, stderr)
|
||||
func newAuthTokenCommand(logdest logger.Logger) *cobra.Command {
|
||||
cmd := ctl.NewAuthTokenCommand(logdest)
|
||||
ccmd := &cobra.Command{
|
||||
Use: "auth-token",
|
||||
Short: "Get an auth-token",
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newBackupCommand(stdin io.Reader, stdout io.Writer, stderr io.Writer) *cobra.Command {
|
||||
cmd := ctl.NewBackupCommand(stdin, stdout, stderr)
|
||||
func newBackupCommand(logdest logger.Logger) *cobra.Command {
|
||||
cmd := ctl.NewBackupCommand(logdest)
|
||||
ccmd := &cobra.Command{
|
||||
Use: "backup",
|
||||
Short: "Back up FeatureBase server",
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newBackupTarCommand(stdin io.Reader, stdout io.Writer, stderr io.Writer) *cobra.Command {
|
||||
cmd := ctl.NewBackupTarCommand(stdin, stdout, stderr)
|
||||
func newBackupTarCommand(logdest logger.Logger) *cobra.Command {
|
||||
cmd := ctl.NewBackupTarCommand(logdest)
|
||||
ccmd := &cobra.Command{
|
||||
Use: "backuptar",
|
||||
Short: "Back up FeatureBase server in tar format",
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newChkSumCommand(stdin io.Reader, stdout io.Writer, stderr io.Writer) *cobra.Command {
|
||||
cmd := ctl.NewChkSumCommand(stdin, stdout, stderr)
|
||||
func newChkSumCommand(logdest logger.Logger) *cobra.Command {
|
||||
cmd := ctl.NewChkSumCommand(logdest)
|
||||
ccmd := &cobra.Command{
|
||||
Use: "chksum",
|
||||
Short: "Digital signature of FeatureBase data",
|
||||
|
|
|
|||
|
|
@ -2,17 +2,16 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var cli *ctl.CLICommand
|
||||
|
||||
// newCLICommand runs the FeatureBase CLI subcommand for ingesting bulk data.
|
||||
func newCLICommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
cli = ctl.NewCLICommand(stdin, stdout, stderr)
|
||||
func newCLICommand(logdest logger.Logger) *cobra.Command {
|
||||
cli = ctl.NewCLICommand(logdest)
|
||||
cliCmd := &cobra.Command{
|
||||
Use: "cli",
|
||||
Short: "Query FB with SQL3 from the command line",
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ import (
|
|||
|
||||
var conf *ctl.ConfigCommand
|
||||
|
||||
func newConfigCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
conf = ctl.NewConfigCommand(stdin, stdout, stderr)
|
||||
Server := server.NewCommand(stdin, stdout, stderr)
|
||||
func newConfigCommand(stderr io.Writer) *cobra.Command {
|
||||
conf = ctl.NewConfigCommand(stderr)
|
||||
Server := server.NewCommand(stderr)
|
||||
confCmd := &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Print the current configuration.",
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import (
|
|||
)
|
||||
|
||||
// newDAXCommand runs the FeatureBase CLI subcommand for ingesting bulk data.
|
||||
func newDAXCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
server := server.NewCommand(stdin, stdout, stderr)
|
||||
func newDAXCommand(stderr io.Writer) *cobra.Command {
|
||||
server := server.NewCommand(stderr)
|
||||
daxCmd := &cobra.Command{
|
||||
Use: "dax",
|
||||
Short: "Run a collection of DAX services",
|
||||
|
|
|
|||
|
|
@ -2,17 +2,16 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
var Exporter *ctl.ExportCommand
|
||||
|
||||
func newExportCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
Exporter = ctl.NewExportCommand(stdin, stdout, stderr)
|
||||
func newExportCommand(logdest logger.Logger) *cobra.Command {
|
||||
Exporter = ctl.NewExportCommand(logdest)
|
||||
exportCmd := &cobra.Command{
|
||||
Use: "export",
|
||||
Short: "Export data from FeatureBase.",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
func main() {
|
||||
defer monitor.CaptureMessage("Session:Ended")
|
||||
rootCmd := cmd.NewRootCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
rootCmd := cmd.NewRootCommand(os.Stderr)
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
|
|
|
|||
|
|
@ -2,17 +2,16 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
var generateConf *ctl.GenerateConfigCommand
|
||||
|
||||
func newGenerateConfigCommand(stdin io.Reader, stdout io.Writer, stderr io.Writer) *cobra.Command {
|
||||
generateConf = ctl.NewGenerateConfigCommand(stdin, stdout, stderr)
|
||||
func newGenerateConfigCommand(logdest logger.Logger) *cobra.Command {
|
||||
generateConf = ctl.NewGenerateConfigCommand(logdest)
|
||||
confCmd := &cobra.Command{
|
||||
Use: "generate-config",
|
||||
Short: "Print the default configuration.",
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ package cmd
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/pql"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -43,8 +43,8 @@ func (dfv *DecimalFlagValue) Type() string {
|
|||
}
|
||||
|
||||
// newImportCommand runs the FeatureBase import subcommand for ingesting bulk data.
|
||||
func newImportCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
Importer = ctl.NewImportCommand(stdin, stdout, stderr)
|
||||
func newImportCommand(logdest logger.Logger) *cobra.Command {
|
||||
Importer = ctl.NewImportCommand(logdest)
|
||||
importCmd := &cobra.Command{
|
||||
Use: "import",
|
||||
Short: "Bulk load data into FeatureBase.",
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newKeygenCommand(stdin io.Reader, stdout io.Writer, stderr io.Writer) *cobra.Command {
|
||||
cmd := ctl.NewKeygenCommand(stdin, stdout, stderr)
|
||||
func newKeygenCommand(logdest logger.Logger) *cobra.Command {
|
||||
cmd := ctl.NewKeygenCommand(logdest)
|
||||
ccmd := &cobra.Command{
|
||||
Use: "keygen",
|
||||
Short: "Generate secret key for authentication.",
|
||||
|
|
|
|||
28
cmd/rbf.go
28
cmd/rbf.go
|
|
@ -4,14 +4,14 @@ package cmd
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newRBFCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
func newRBFCommand(logdest logger.Logger) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "rbf",
|
||||
Short: "Inspect RBF data files.",
|
||||
|
|
@ -19,15 +19,15 @@ func newRBFCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
|||
Provides a set of commands for inspecting RBF data files.
|
||||
`,
|
||||
}
|
||||
cmd.AddCommand(newRBFCheckCommand(stdin, stdout, stderr))
|
||||
cmd.AddCommand(newRBFDumpCommand(stdin, stdout, stderr))
|
||||
cmd.AddCommand(newRBFPagesCommand(stdin, stdout, stderr))
|
||||
cmd.AddCommand(newRBFPageCommand(stdin, stdout, stderr))
|
||||
cmd.AddCommand(newRBFCheckCommand(logdest))
|
||||
cmd.AddCommand(newRBFDumpCommand(logdest))
|
||||
cmd.AddCommand(newRBFPagesCommand(logdest))
|
||||
cmd.AddCommand(newRBFPageCommand(logdest))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newRBFCheckCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
c := ctl.NewRBFCheckCommand(stdin, stdout, stderr)
|
||||
func newRBFCheckCommand(logdest logger.Logger) *cobra.Command {
|
||||
c := ctl.NewRBFCheckCommand(logdest)
|
||||
cmd := &cobra.Command{
|
||||
Use: "check [flags] PATH",
|
||||
Short: "Run consistency check on RBF data.",
|
||||
|
|
@ -48,8 +48,8 @@ Executes a consistency check on an RBF data directory.
|
|||
return cmd
|
||||
}
|
||||
|
||||
func newRBFDumpCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
c := ctl.NewRBFDumpCommand(stdin, stdout, stderr)
|
||||
func newRBFDumpCommand(logdest logger.Logger) *cobra.Command {
|
||||
c := ctl.NewRBFDumpCommand(logdest)
|
||||
cmd := &cobra.Command{
|
||||
Use: "dump [flags] PATH PGNO [PGNO...]",
|
||||
Short: "Prints RBF raw page data",
|
||||
|
|
@ -80,8 +80,8 @@ Dumps the raw hex data for one or more RBF pages.
|
|||
return cmd
|
||||
}
|
||||
|
||||
func newRBFPagesCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
c := ctl.NewRBFPagesCommand(stdin, stdout, stderr)
|
||||
func newRBFPagesCommand(logdest logger.Logger) *cobra.Command {
|
||||
c := ctl.NewRBFPagesCommand(logdest)
|
||||
cmd := &cobra.Command{
|
||||
Use: "pages [flags] PATH",
|
||||
Short: "Prints metadata for the list of all pages",
|
||||
|
|
@ -105,8 +105,8 @@ Prints a line for every page in the database with its type/status.
|
|||
return cmd
|
||||
}
|
||||
|
||||
func newRBFPageCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
c := ctl.NewRBFPageCommand(stdin, stdout, stderr)
|
||||
func newRBFPageCommand(logdest logger.Logger) *cobra.Command {
|
||||
c := ctl.NewRBFPageCommand(logdest)
|
||||
cmd := &cobra.Command{
|
||||
Use: "page [flags] PATH PGNO [PGNO...]",
|
||||
Short: "Prints data for a page(s)",
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newRestoreCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
cmd := ctl.NewRestoreCommand(stdin, stdout, stderr)
|
||||
func newRestoreCommand(logdest logger.Logger) *cobra.Command {
|
||||
cmd := ctl.NewRestoreCommand(logdest)
|
||||
restoreCmd := &cobra.Command{
|
||||
Use: "restore",
|
||||
Short: "Restore from a backup",
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newRestoreTarCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
cmd := ctl.NewRestoreTarCommand(stdin, stdout, stderr)
|
||||
func newRestoreTarCommand(logdest logger.Logger) *cobra.Command {
|
||||
cmd := ctl.NewRestoreTarCommand(logdest)
|
||||
restoreCmd := &cobra.Command{
|
||||
Use: "restoretar",
|
||||
Short: "Restore from a backup in tar format",
|
||||
|
|
|
|||
36
cmd/root.go
36
cmd/root.go
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
|
|
@ -45,7 +46,8 @@ func considerUsageError(cmd *cobra.Command, err error) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func NewRootCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
func NewRootCommand(stderr io.Writer) *cobra.Command {
|
||||
logdest := logger.NewStandardLogger(stderr)
|
||||
rc := &cobra.Command{
|
||||
Use: "featurebase",
|
||||
// TODO: These short/long descriptions could use some updating.
|
||||
|
|
@ -87,22 +89,22 @@ at https://docs.molecula.cloud/.
|
|||
_ = rc.PersistentFlags().MarkHidden("dry-run")
|
||||
rc.PersistentFlags().StringP("config", "c", "", "Configuration file to read from.")
|
||||
|
||||
rc.AddCommand(newChkSumCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newBackupCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newRestoreCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newBackupTarCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newRestoreTarCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newConfigCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newExportCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newGenerateConfigCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newImportCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newAuthTokenCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newRBFCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newServeCmd(stdin, stdout, stderr))
|
||||
rc.AddCommand(newHolderCmd(stdin, stdout, stderr))
|
||||
rc.AddCommand(newKeygenCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newCLICommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newDAXCommand(stdin, stdout, stderr))
|
||||
rc.AddCommand(newChkSumCommand(logdest))
|
||||
rc.AddCommand(newBackupCommand(logdest))
|
||||
rc.AddCommand(newRestoreCommand(logdest))
|
||||
rc.AddCommand(newBackupTarCommand(logdest))
|
||||
rc.AddCommand(newRestoreTarCommand(logdest))
|
||||
rc.AddCommand(newConfigCommand(stderr))
|
||||
rc.AddCommand(newExportCommand(logdest))
|
||||
rc.AddCommand(newGenerateConfigCommand(logdest))
|
||||
rc.AddCommand(newImportCommand(logdest))
|
||||
rc.AddCommand(newAuthTokenCommand(logdest))
|
||||
rc.AddCommand(newRBFCommand(logdest))
|
||||
rc.AddCommand(newServeCmd(stderr))
|
||||
rc.AddCommand(newHolderCmd(stderr))
|
||||
rc.AddCommand(newKeygenCommand(logdest))
|
||||
rc.AddCommand(newCLICommand(logdest))
|
||||
rc.AddCommand(newDAXCommand(stderr))
|
||||
|
||||
rc.SetOutput(stderr)
|
||||
return rc
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package cmd_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
|
@ -9,8 +10,6 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/molecula/featurebase/v3/cmd"
|
||||
"github.com/molecula/featurebase/v3/testhook"
|
||||
"github.com/spf13/cobra"
|
||||
|
|
@ -25,43 +24,15 @@ func failErr(t *testing.T, err error, context ...string) {
|
|||
}
|
||||
}
|
||||
|
||||
// tExec executes the given `cmd`, which will be writing its output to `w`, and
|
||||
// can be read from `out`. It will fail the test if the command does not return
|
||||
// within 1 second. Useful for testing help messages and such.
|
||||
func tExec(t *testing.T, cmd *cobra.Command, out io.Reader, w io.WriteCloser) (output []byte, err error) {
|
||||
done := make(chan struct{})
|
||||
var readErr error
|
||||
go func() {
|
||||
output, readErr = io.ReadAll(out)
|
||||
close(done)
|
||||
}()
|
||||
err = cmd.Execute()
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
return output, fmt.Errorf("closing cmd's stdout: %v", err)
|
||||
}
|
||||
|
||||
// NOTE: if cmd.Execute doesn't return, then this select (and
|
||||
// therefore the one-second timeout, won't be reached)
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(time.Second * 1):
|
||||
t.Fatal("Test failed due to command execution timeout")
|
||||
}
|
||||
return output, readErr
|
||||
}
|
||||
|
||||
// ExecNewRootCommand executes the pilosa root command with the given arguments
|
||||
// and returns its output. It will fail if the command does not complete within
|
||||
// 1 second.
|
||||
func ExecNewRootCommand(t *testing.T, args ...string) (string, error) {
|
||||
out, w := io.Pipe()
|
||||
rc := cmd.NewRootCommand(os.Stdin, w, w)
|
||||
buf := &bytes.Buffer{}
|
||||
rc := cmd.NewRootCommand(buf)
|
||||
rc.SetArgs(args)
|
||||
output, err := tExec(t, rc, out, w)
|
||||
return string(output), err
|
||||
err := rc.Execute()
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
// validator is a simple helper to avoid repeated `if err != nil` checks in
|
||||
|
|
@ -141,7 +112,7 @@ func (ct *commandTest) setupCommand(t *testing.T) *cobra.Command {
|
|||
os.Setenv("PILOSA_POSTGRES_BIND", "")
|
||||
|
||||
// make command and set args
|
||||
rc := cmd.NewRootCommand(strings.NewReader(""), io.Discard, io.Discard)
|
||||
rc := cmd.NewRootCommand(io.Discard)
|
||||
rc.SetArgs(ct.args)
|
||||
|
||||
err = cfgFile.Close()
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ var holder *server.Command
|
|||
|
||||
// newHolderCmd creates a FeatureBase server for just long enough to open the
|
||||
// holder, then shuts it down again.
|
||||
func newHolderCmd(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
holder = server.NewCommand(stdin, stdout, stderr)
|
||||
func newHolderCmd(stderr io.Writer) *cobra.Command {
|
||||
holder = server.NewCommand(stderr)
|
||||
serveCmd := &cobra.Command{
|
||||
Use: "holder",
|
||||
Short: "Load FeatureBase.",
|
||||
|
|
@ -45,8 +45,8 @@ This is only useful for diagnostic use.
|
|||
}
|
||||
|
||||
// newServeCmd creates a FeatureBase server and runs it with command line flags.
|
||||
func newServeCmd(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
|
||||
Server = server.NewCommand(stdin, stdout, stderr)
|
||||
func newServeCmd(stderr io.Writer) *cobra.Command {
|
||||
Server = server.NewCommand(stderr)
|
||||
serveCmd := &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "Run FeatureBase.",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"time"
|
||||
|
||||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
|
@ -31,13 +32,18 @@ type AuthTokenCommand struct { // nolint: maligned
|
|||
client *pilosa.InternalClient
|
||||
|
||||
// Standard input/output.
|
||||
*pilosa.CmdIO
|
||||
logDest logger.Logger
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *AuthTokenCommand) Logger() logger.Logger {
|
||||
return cmd.logDest
|
||||
}
|
||||
|
||||
// NewAuthTokenCommand returns a new instance of AuthTokenCommand.
|
||||
func NewAuthTokenCommand(stdin io.Reader, stdout, stderr io.Writer) *AuthTokenCommand {
|
||||
func NewAuthTokenCommand(logdest logger.Logger) *AuthTokenCommand {
|
||||
return &AuthTokenCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/molecula/featurebase/v3/authn"
|
||||
"github.com/molecula/featurebase/v3/disco"
|
||||
"github.com/molecula/featurebase/v3/encoding/proto"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
"github.com/ricochet2200/go-disk-usage/du"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
|
@ -58,7 +59,7 @@ type BackupCommand struct { // nolint: maligned
|
|||
client *pilosa.InternalClient
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
logDest logger.Logger
|
||||
|
||||
TLS server.TLSConfig
|
||||
|
||||
|
|
@ -66,10 +67,15 @@ type BackupCommand struct { // nolint: maligned
|
|||
IgnoreSpaceCheck bool
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *BackupCommand) Logger() logger.Logger {
|
||||
return cmd.logDest
|
||||
}
|
||||
|
||||
// NewBackupCommand returns a new instance of BackupCommand.
|
||||
func NewBackupCommand(stdin io.Reader, stdout, stderr io.Writer) *BackupCommand {
|
||||
func NewBackupCommand(logdest logger.Logger) *BackupCommand {
|
||||
return &BackupCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
logDest: logdest,
|
||||
Concurrency: 1,
|
||||
RetryPeriod: time.Minute,
|
||||
HeaderTimeout: time.Second * 3,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/molecula/featurebase/v3/authn"
|
||||
"github.com/molecula/featurebase/v3/disco"
|
||||
"github.com/molecula/featurebase/v3/encoding/proto"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
"github.com/molecula/featurebase/v3/vprint"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -51,17 +52,22 @@ type BackupTarCommand struct { // nolint: maligned
|
|||
client *pilosa.InternalClient
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
logDest logger.Logger
|
||||
|
||||
TLS server.TLSConfig
|
||||
|
||||
AuthToken string
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *BackupTarCommand) Logger() logger.Logger {
|
||||
return cmd.logDest
|
||||
}
|
||||
|
||||
// NewBackupTarCommand returns a new instance of BackupCommand.
|
||||
func NewBackupTarCommand(stdin io.Reader, stdout, stderr io.Writer) *BackupTarCommand {
|
||||
func NewBackupTarCommand(logdest logger.Logger) *BackupTarCommand {
|
||||
return &BackupTarCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
logDest: logdest,
|
||||
RetryPeriod: time.Minute,
|
||||
HeaderTimeout: time.Second * 3,
|
||||
Pprof: "localhost:0",
|
||||
|
|
@ -130,7 +136,7 @@ func (cmd *BackupTarCommand) Run(ctx context.Context) (err error) {
|
|||
// Create output file in temporary location, or send to stdout if a dash is specified.
|
||||
var w io.Writer
|
||||
if useStdout {
|
||||
w = cmd.Stdout
|
||||
w = os.Stdout
|
||||
} else {
|
||||
f, err := os.Create(cmd.OutputPath + ".tmp")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package ctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/test"
|
||||
)
|
||||
|
||||
|
|
@ -15,12 +17,12 @@ func TestBackupTarCommand_Run(t *testing.T) {
|
|||
defer cluster.Close()
|
||||
cmd := cluster.GetNode(0)
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewBackupTarCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewBackupTarCommand(cmLog)
|
||||
hostport := cmd.API.Node().URI.HostPort()
|
||||
cm.Host = hostport
|
||||
cm.OutputPath = "-"
|
||||
dir := t.TempDir()
|
||||
cm.OutputPath = filepath.Join(dir, "backuptest.tar")
|
||||
|
||||
resp, err := http.DefaultClient.Do(test.MustNewHTTPRequest("POST", "http://"+hostport+"/index/i", strings.NewReader("")))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,15 @@ package ctl
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
func TestBackupCommand_Run(t *testing.T) {
|
||||
cm := NewBackupCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewBackupCommand(cmLog)
|
||||
cm.OutputDir = ""
|
||||
err := cm.Run(context.Background())
|
||||
if !errors.Is(err, UsageError) {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ import (
|
|||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/cespare/xxhash"
|
||||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
)
|
||||
|
||||
|
|
@ -23,15 +25,22 @@ type ChkSumCommand struct { // nolint: maligned
|
|||
client *pilosa.InternalClient
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
stdout io.Writer
|
||||
logDest logger.Logger
|
||||
|
||||
TLS server.TLSConfig
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *ChkSumCommand) Logger() logger.Logger {
|
||||
return cmd.logDest
|
||||
}
|
||||
|
||||
// NewChkSumCommand returns a new instance of BackupCommand.
|
||||
func NewChkSumCommand(stdin io.Reader, stdout, stderr io.Writer) *ChkSumCommand {
|
||||
func NewChkSumCommand(logdest logger.Logger) *ChkSumCommand {
|
||||
return &ChkSumCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
stdout: os.Stdout,
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +135,7 @@ func (cmd *ChkSumCommand) Run(ctx context.Context) (err error) {
|
|||
}
|
||||
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "hash:%x\n", h.Sum(nil))
|
||||
fmt.Fprintf(cmd.stdout, "hash:%x\n", h.Sum(nil))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
31
ctl/chksum_test.go
Normal file
31
ctl/chksum_test.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2022 Molecula Corp. All rights reserved.
|
||||
package ctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/test"
|
||||
)
|
||||
|
||||
func TestChkSumCommand_Run(t *testing.T) {
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cm := NewChkSumCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cm.stdout = buf
|
||||
|
||||
cluster := test.MustRunCluster(t, 1)
|
||||
defer cluster.Close()
|
||||
cmd := cluster.GetNode(0)
|
||||
cm.Host = cmd.API.Node().URI.HostPort()
|
||||
|
||||
err := cm.Run(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("ChkSum Run doesn't work: %s", err)
|
||||
}
|
||||
//ChkSumCommand is only used in executor_test.go, so for now we're just
|
||||
//making sure that it runs at all, not checking output.
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/molecula/featurebase/v3/dax"
|
||||
queryerhttp "github.com/molecula/featurebase/v3/dax/queryer/http"
|
||||
"github.com/molecula/featurebase/v3/fbcloud"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ type CLICommand struct {
|
|||
queryer FBQueryer
|
||||
}
|
||||
|
||||
func NewCLICommand(stdin io.Reader, stdout, stderr io.Writer) *CLICommand {
|
||||
func NewCLICommand(logdest logger.Logger) *CLICommand {
|
||||
historyPath := ""
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -5,22 +5,26 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
toml "github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
// ConfigCommand represents a command for printing a default config.
|
||||
type ConfigCommand struct {
|
||||
*pilosa.CmdIO
|
||||
// this exists so we can override it in tests
|
||||
stdout io.Writer
|
||||
// this actually gets overridden more generally by different tests
|
||||
stderr io.Writer
|
||||
Config *server.Config
|
||||
}
|
||||
|
||||
// NewConfigCommand returns a new instance of ConfigCommand.
|
||||
func NewConfigCommand(stdin io.Reader, stdout, stderr io.Writer) *ConfigCommand {
|
||||
func NewConfigCommand(stderr io.Writer) *ConfigCommand {
|
||||
return &ConfigCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
stdout: os.Stdout,
|
||||
stderr: stderr,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -30,6 +34,6 @@ func (cmd *ConfigCommand) Run(_ context.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(cmd.Stdout, string(buf))
|
||||
fmt.Fprintln(cmd.stdout, string(buf))
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ package ctl
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -13,22 +12,15 @@ import (
|
|||
)
|
||||
|
||||
func TestConfigCommand_Run(t *testing.T) {
|
||||
rder := []byte{}
|
||||
stdin := bytes.NewReader(rder)
|
||||
r, w, _ := os.Pipe()
|
||||
cm := NewConfigCommand(stdin, w, os.Stderr)
|
||||
cm := NewConfigCommand(os.Stderr)
|
||||
cm.Config = server.NewConfig()
|
||||
buf := &bytes.Buffer{}
|
||||
cm.stdout = buf
|
||||
|
||||
err := cm.Run(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("Config Run doesn't work: %s", err)
|
||||
}
|
||||
w.Close()
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, r)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !strings.Contains(buf.String(), ":10101") {
|
||||
t.Fatalf("Unexpected config: \n%s", buf.String())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"os"
|
||||
|
||||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
@ -25,15 +26,20 @@ type ExportCommand struct {
|
|||
Path string
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
logDest logger.Logger
|
||||
|
||||
TLS server.TLSConfig
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *ExportCommand) Logger() logger.Logger {
|
||||
return cmd.logDest
|
||||
}
|
||||
|
||||
// NewExportCommand returns a new instance of ExportCommand.
|
||||
func NewExportCommand(stdin io.Reader, stdout, stderr io.Writer) *ExportCommand {
|
||||
func NewExportCommand(logdest logger.Logger) *ExportCommand {
|
||||
return &ExportCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,7 +56,7 @@ func (cmd *ExportCommand) Run(ctx context.Context) error {
|
|||
|
||||
// Use output file, if specified.
|
||||
// Otherwise use STDOUT.
|
||||
var w io.Writer = cmd.Stdout
|
||||
var w io.Writer = os.Stdout
|
||||
if cmd.Path != "" {
|
||||
f, err := os.Create(cmd.Path)
|
||||
if err != nil {
|
||||
|
|
@ -81,13 +87,6 @@ func (cmd *ExportCommand) Run(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Close writer, if applicable.
|
||||
if w, ok := w.(io.Closer); ok {
|
||||
if err := w.Close(); err != nil {
|
||||
return errors.Wrap(err, "closing")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,21 +2,22 @@
|
|||
package ctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/test"
|
||||
)
|
||||
|
||||
func TestExportCommand_Validation(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
|
||||
cm := NewExportCommand(stdin, stdout, stderr)
|
||||
cm := NewExportCommand(cmLog)
|
||||
|
||||
err := cm.Run(context.Background())
|
||||
if !errContains(err, pilosa.ErrIndexRequired) {
|
||||
|
|
@ -35,9 +36,8 @@ func TestExportCommand_Run(t *testing.T) {
|
|||
defer cluster.Close()
|
||||
cmd := cluster.GetNode(0)
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewExportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewExportCommand(cmLog)
|
||||
hostport := cmd.API.Node().URI.HostPort()
|
||||
cm.Host = hostport
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
"github.com/pelletier/go-toml"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -14,13 +15,15 @@ import (
|
|||
|
||||
// GenerateConfigCommand represents a command for printing a default config.
|
||||
type GenerateConfigCommand struct {
|
||||
*pilosa.CmdIO
|
||||
stdout io.Writer
|
||||
logDest logger.Logger
|
||||
}
|
||||
|
||||
// NewGenerateConfigCommand returns a new instance of GenerateConfigCommand.
|
||||
func NewGenerateConfigCommand(stdin io.Reader, stdout, stderr io.Writer) *GenerateConfigCommand {
|
||||
func NewGenerateConfigCommand(logdest logger.Logger) *GenerateConfigCommand {
|
||||
return &GenerateConfigCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
stdout: os.Stdout,
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +34,6 @@ func (cmd *GenerateConfigCommand) Run(_ context.Context) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "unmarshalling default config")
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "%s\n", ret)
|
||||
fmt.Fprintf(cmd.stdout, "%s\n", ret)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,27 +4,22 @@ package ctl
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
func TestGenerateConfigCommand_Run(t *testing.T) {
|
||||
rder := []byte{}
|
||||
stdin := bytes.NewReader(rder)
|
||||
r, w, _ := os.Pipe()
|
||||
cm := NewGenerateConfigCommand(stdin, w, os.Stderr)
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cm := NewGenerateConfigCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cm.stdout = buf
|
||||
err := cm.Run(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("Config Run doesn't work: %s", err)
|
||||
}
|
||||
w.Close()
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, r)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !strings.Contains(buf.String(), ":10101") {
|
||||
t.Fatalf("Unexpected config: %s", buf.String())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/authn"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/pql"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -57,17 +58,22 @@ type ImportCommand struct { // nolint: maligned
|
|||
client *pilosa.InternalClient
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
logDest logger.Logger
|
||||
|
||||
TLS server.TLSConfig
|
||||
|
||||
AuthToken string
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *ImportCommand) Logger() logger.Logger {
|
||||
return cmd.logDest
|
||||
}
|
||||
|
||||
// NewImportCommand returns a new instance of ImportCommand.
|
||||
func NewImportCommand(stdin io.Reader, stdout, stderr io.Writer) *ImportCommand {
|
||||
func NewImportCommand(logdest logger.Logger) *ImportCommand {
|
||||
return &ImportCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
logDest: logdest,
|
||||
BufferSize: 10000000,
|
||||
}
|
||||
}
|
||||
|
|
@ -184,7 +190,7 @@ func (cmd *ImportCommand) bufferBits(ctx context.Context, useColumnKeys, useRowK
|
|||
// Read rows as bits.
|
||||
r = csv.NewReader(f)
|
||||
} else {
|
||||
r = csv.NewReader(cmd.Stdin)
|
||||
r = csv.NewReader(os.Stdin)
|
||||
}
|
||||
|
||||
r.FieldsPerRecord = -1
|
||||
|
|
@ -306,7 +312,7 @@ func (cmd *ImportCommand) bufferValues(ctx context.Context, useColumnKeys, parse
|
|||
// Read rows as bits.
|
||||
r = csv.NewReader(f)
|
||||
} else {
|
||||
r = csv.NewReader(cmd.Stdin)
|
||||
r = csv.NewReader(os.Stdin)
|
||||
}
|
||||
|
||||
r.FieldsPerRecord = -1
|
||||
|
|
|
|||
|
|
@ -33,10 +33,7 @@ import (
|
|||
// and a non-nil error does not contain a nil error.
|
||||
func errContains(err error, expected error) bool {
|
||||
if err == nil {
|
||||
if expected == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return expected == nil
|
||||
}
|
||||
if expected == nil {
|
||||
return false
|
||||
|
|
@ -48,9 +45,8 @@ func errContains(err error, expected error) bool {
|
|||
return strings.Contains(e1, e2)
|
||||
}
|
||||
func TestImportCommand_Validation(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
err := cm.Run(context.Background())
|
||||
if !errContains(err, pilosa.ErrIndexRequired) {
|
||||
t.Fatalf("wrong error: expected %q, got: '%v'", pilosa.ErrIndexRequired, err)
|
||||
|
|
@ -72,9 +68,8 @@ func TestImportCommand_Validation(t *testing.T) {
|
|||
|
||||
func TestImportCommand_Basic(t *testing.T) {
|
||||
t.Run("set", func(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import.csv")
|
||||
if err != nil {
|
||||
t.Fatalf("creating tempfile: %v", err)
|
||||
|
|
@ -104,9 +99,8 @@ func TestImportCommand_Basic(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("clear", func(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import.csv")
|
||||
if err != nil {
|
||||
t.Fatalf("creating tempfile: %v", err)
|
||||
|
|
@ -137,9 +131,8 @@ func TestImportCommand_Basic(t *testing.T) {
|
|||
// Ensure that the ImportValue path runs.
|
||||
func TestImportCommand_RunValue(t *testing.T) {
|
||||
t.Run("set", func(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import-value.csv")
|
||||
if err != nil {
|
||||
t.Fatalf("creating tempfile: %v", err)
|
||||
|
|
@ -176,9 +169,8 @@ func TestImportCommand_RunValue(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("clear", func(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import-value.csv")
|
||||
if err != nil {
|
||||
t.Fatalf("creating tempfile: %v", err)
|
||||
|
|
@ -221,9 +213,8 @@ func TestImportCommand_RunValue(t *testing.T) {
|
|||
|
||||
// Ensure that import with keys runs.
|
||||
func TestImportCommand_RunKeys(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import-key.csv")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -261,9 +252,8 @@ func TestImportCommand_RunKeys(t *testing.T) {
|
|||
|
||||
// Ensure that import with keys runs with key replication.
|
||||
func TestImportCommand_KeyReplication(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import-key.csv")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -339,9 +329,8 @@ func TestImportCommand_KeyReplication(t *testing.T) {
|
|||
|
||||
// Ensure that integer import with keys runs.
|
||||
func TestImportCommand_RunValueKeys(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import-key.csv")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -382,9 +371,8 @@ func TestImportCommand_InvalidFile(t *testing.T) {
|
|||
defer cluster.Close()
|
||||
cmd := cluster.GetNode(0)
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
cm.Host = cmd.API.Node().URI.HostPort()
|
||||
cm.Index = "i"
|
||||
cm.Field = "f"
|
||||
|
|
@ -470,9 +458,8 @@ func TestImportCommand_BugOverwriteValue(t *testing.T) {
|
|||
defer cluster.Close()
|
||||
cmd := cluster.GetNode(0)
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import-value.csv")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -537,9 +524,8 @@ func TestImportCommand_BugOverwriteValue(t *testing.T) {
|
|||
|
||||
// Ensure that import into bool field runs.
|
||||
func TestImportCommand_RunBool(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
ctx := context.Background()
|
||||
|
||||
cluster := test.MustRunCluster(t, 1)
|
||||
|
|
@ -717,9 +703,8 @@ func TestImport_AuthOn(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run("set", func(t *testing.T) {
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewImportCommand(cmLog)
|
||||
file, err := testhook.TempFile(t, "import.csv")
|
||||
if err != nil {
|
||||
t.Fatalf("creating tempfile: %v", err)
|
||||
|
|
|
|||
|
|
@ -5,26 +5,29 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/securecookie"
|
||||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
// Keygen represents a command for generating a cryptographic key.
|
||||
type KeygenCommand struct {
|
||||
CmdIO *pilosa.CmdIO
|
||||
stdout io.Writer
|
||||
logDest logger.Logger
|
||||
KeyLength int
|
||||
}
|
||||
|
||||
// NewKeygen returns a new instance of Keygen.
|
||||
func NewKeygenCommand(stdin io.Reader, stdout, stderr io.Writer) *KeygenCommand {
|
||||
func NewKeygenCommand(logdest logger.Logger) *KeygenCommand {
|
||||
return &KeygenCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
stdout: os.Stdout,
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
// Run keygen to obtain key to use for authentication .
|
||||
func (kg *KeygenCommand) Run(_ context.Context) error {
|
||||
fmt.Printf("secret-key = \"%+x\"\n", securecookie.GenerateRandomKey(kg.KeyLength))
|
||||
fmt.Fprintf(kg.stdout, "secret-key = \"%+x\"\n", securecookie.GenerateRandomKey(kg.KeyLength))
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
26
ctl/keygen_test.go
Normal file
26
ctl/keygen_test.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2022 Molecula Corp. All rights reserved.
|
||||
package ctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
func TestKeygenCommand_Run(t *testing.T) {
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cm := NewKeygenCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cm.stdout = buf
|
||||
err := cm.Run(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("Keygen Run doesn't work: %s", err)
|
||||
}
|
||||
if !strings.Contains(buf.String(), "secret-key =") {
|
||||
t.Fatalf("Unexpected output: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,9 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/rbf"
|
||||
)
|
||||
|
||||
|
|
@ -16,13 +17,15 @@ type RBFCheckCommand struct {
|
|||
Path string
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
stdout io.Writer
|
||||
logDest logger.Logger
|
||||
}
|
||||
|
||||
// NewRBFCheckCommand returns a new instance of RBFCheckCommand.
|
||||
func NewRBFCheckCommand(stdin io.Reader, stdout, stderr io.Writer) *RBFCheckCommand {
|
||||
func NewRBFCheckCommand(logdest logger.Logger) *RBFCheckCommand {
|
||||
return &RBFCheckCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
stdout: os.Stdout,
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,16 +43,16 @@ func (cmd *RBFCheckCommand) Run(ctx context.Context) error {
|
|||
switch err := err.(type) {
|
||||
case rbf.ErrorList:
|
||||
for i := range err {
|
||||
fmt.Fprintln(cmd.Stdout, err[i])
|
||||
fmt.Fprintln(cmd.stdout, err[i])
|
||||
}
|
||||
default:
|
||||
fmt.Fprintln(cmd.Stdout, err)
|
||||
fmt.Fprintln(cmd.stdout, err)
|
||||
}
|
||||
return fmt.Errorf("check failed")
|
||||
}
|
||||
|
||||
// If successful, print a success message.
|
||||
fmt.Fprintln(cmd.Stdout, "ok")
|
||||
fmt.Fprintln(cmd.stdout, "ok")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,29 +4,36 @@ package ctl
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
func TestRBFCheckCommand_Run(t *testing.T) {
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := NewRBFCheckCommand(bytes.NewReader(nil), &stdout, &stderr)
|
||||
cmd.Path = filepath.Join("testdata", "rbf-check", "ok")
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cmd := NewRBFCheckCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.stdout = buf
|
||||
cmd.Path = filepath.Join("testdata", "ok")
|
||||
if err := cmd.Run(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if got, want := stdout.String(), `ok`+"\n"; got != want {
|
||||
} else if got, want := buf.String(), `ok`+"\n"; got != want {
|
||||
t.Fatalf("got:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ErrInvalidPageType", func(t *testing.T) {
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := NewRBFCheckCommand(bytes.NewReader(nil), &stdout, &stderr)
|
||||
cmd.Path = filepath.Join("testdata", "rbf-check", "err-invalid-page-type")
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cmd := NewRBFCheckCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.stdout = buf
|
||||
cmd.Path = filepath.Join("testdata", "err-invalid-page-type")
|
||||
if err := cmd.Run(context.Background()); err == nil || err.Error() != `check failed` {
|
||||
t.Fatal(err)
|
||||
} else if got, want := stdout.String(), `page not in-use & not free: pgno=4`+"\n"; got != want {
|
||||
} else if got, want := buf.String(), `page not in-use & not free: pgno=4`+"\n"; got != want {
|
||||
t.Fatalf("got:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/rbf"
|
||||
)
|
||||
|
||||
|
|
@ -21,13 +22,15 @@ type RBFDumpCommand struct {
|
|||
Pgnos []uint32
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
stdout io.Writer
|
||||
logDest logger.Logger
|
||||
}
|
||||
|
||||
// NewRBFDumpCommand returns a new instance of RBFDumpCommand.
|
||||
func NewRBFDumpCommand(stdin io.Reader, stdout, stderr io.Writer) *RBFDumpCommand {
|
||||
func NewRBFDumpCommand(logdest logger.Logger) *RBFDumpCommand {
|
||||
return &RBFDumpCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
stdout: os.Stdout,
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,9 +57,9 @@ func (cmd *RBFDumpCommand) Run(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(cmd.Stdout, "## PAGE %d\n", pgno)
|
||||
fmt.Fprintln(cmd.Stdout, compressedHexDump(buf))
|
||||
fmt.Fprintln(cmd.Stdout, "")
|
||||
fmt.Fprintf(cmd.stdout, "## PAGE %d\n", pgno)
|
||||
fmt.Fprintln(cmd.stdout, compressedHexDump(buf))
|
||||
fmt.Fprintln(cmd.stdout, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
45
ctl/rbf_dump_test.go
Normal file
45
ctl/rbf_dump_test.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2022 Molecula Corp. All rights reserved.
|
||||
package ctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
func TestRBFDumpCommand_Run(t *testing.T) {
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cmd := NewRBFDumpCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.stdout = buf
|
||||
cmd.Path = filepath.Join("testdata", "ok")
|
||||
cmd.Pgnos = []uint32{0}
|
||||
if err := cmd.Run(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if got, want := buf.String(), "## PAGE 0"; !strings.Contains(got, want) {
|
||||
t.Fatalf("got:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ErrInvalidPageType", func(t *testing.T) {
|
||||
t.Skip("Need to figure out how to get an error and what the error message will be.")
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cmd := NewRBFDumpCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.stdout = buf
|
||||
cmd.Path = filepath.Join("testdata", "err-invalid-page-type")
|
||||
cmd.Pgnos = []uint32{4}
|
||||
if err := cmd.Run(context.Background()); err == nil || err.Error() != `check failed` {
|
||||
t.Fatal(err)
|
||||
//this part is still from rbf_check_test til i figure out what the actual error output should be
|
||||
} else if got, want := buf.String(), `page not in-use & not free: pgno=4`+"\n"; got != want {
|
||||
t.Fatalf("got:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -5,8 +5,9 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/rbf"
|
||||
)
|
||||
|
||||
|
|
@ -19,13 +20,15 @@ type RBFPageCommand struct {
|
|||
Pgnos []uint32
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
stdout io.Writer
|
||||
logDest logger.Logger
|
||||
}
|
||||
|
||||
// NewRBFPageCommand returns a new instance of RBFPageCommand.
|
||||
func NewRBFPageCommand(stdin io.Reader, stdout, stderr io.Writer) *RBFPageCommand {
|
||||
func NewRBFPageCommand(logdest logger.Logger) *RBFPageCommand {
|
||||
return &RBFPageCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
stdout: os.Stdout,
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,60 +71,60 @@ func (cmd *RBFPageCommand) Run(ctx context.Context) error {
|
|||
default:
|
||||
return fmt.Errorf("unexpected page type %T", page)
|
||||
}
|
||||
fmt.Fprintln(cmd.Stdout, "")
|
||||
fmt.Fprintln(cmd.stdout, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cmd *RBFPageCommand) printMetaPage(page *rbf.MetaPage) {
|
||||
fmt.Fprintf(cmd.Stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.Stdout, "Type: meta\n")
|
||||
fmt.Fprintf(cmd.Stdout, "PageN: %d\n", page.PageN)
|
||||
fmt.Fprintf(cmd.Stdout, "WALID: %d\n", page.WALID)
|
||||
fmt.Fprintf(cmd.Stdout, "Root Record Pgno: %d\n", page.RootRecordPageNo)
|
||||
fmt.Fprintf(cmd.Stdout, "Freelist Pgno: %d\n", page.FreelistPageNo)
|
||||
fmt.Fprintf(cmd.stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "Type: meta\n")
|
||||
fmt.Fprintf(cmd.stdout, "PageN: %d\n", page.PageN)
|
||||
fmt.Fprintf(cmd.stdout, "WALID: %d\n", page.WALID)
|
||||
fmt.Fprintf(cmd.stdout, "Root Record Pgno: %d\n", page.RootRecordPageNo)
|
||||
fmt.Fprintf(cmd.stdout, "Freelist Pgno: %d\n", page.FreelistPageNo)
|
||||
}
|
||||
|
||||
func (cmd *RBFPageCommand) printRootRecordPage(page *rbf.RootRecordPage) {
|
||||
fmt.Fprintf(cmd.Stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.Stdout, "Type: root record\n")
|
||||
fmt.Fprintf(cmd.Stdout, "Next: %d\n", page.Next)
|
||||
fmt.Fprintf(cmd.Stdout, "Records: n=%d\n", len(page.Records))
|
||||
fmt.Fprintf(cmd.stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "Type: root record\n")
|
||||
fmt.Fprintf(cmd.stdout, "Next: %d\n", page.Next)
|
||||
fmt.Fprintf(cmd.stdout, "Records: n=%d\n", len(page.Records))
|
||||
for i, rec := range page.Records {
|
||||
fmt.Fprintf(cmd.Stdout, "[%d]: name=%q pgno=%d\n", i, rec.Name, rec.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "[%d]: name=%q pgno=%d\n", i, rec.Name, rec.Pgno)
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *RBFPageCommand) printLeafPage(page *rbf.LeafPage) {
|
||||
fmt.Fprintf(cmd.Stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.Stdout, "Type: leaf\n")
|
||||
fmt.Fprintf(cmd.Stdout, "Cells: n=%d\n", len(page.Cells))
|
||||
fmt.Fprintf(cmd.stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "Type: leaf\n")
|
||||
fmt.Fprintf(cmd.stdout, "Cells: n=%d\n", len(page.Cells))
|
||||
for i, cell := range page.Cells {
|
||||
if cell.Type == rbf.ContainerTypeBitmapPtr {
|
||||
fmt.Fprintf(cmd.Stdout, "[%d]: key=%d type=%s pgno=%d\n", i, cell.Key, cell.Type, cell.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "[%d]: key=%d type=%s pgno=%d\n", i, cell.Key, cell.Type, cell.Pgno)
|
||||
} else {
|
||||
fmt.Fprintf(cmd.Stdout, "[%d]: key=%d type=%s values=%v\n", i, cell.Key, cell.Type, cell.Values)
|
||||
fmt.Fprintf(cmd.stdout, "[%d]: key=%d type=%s values=%v\n", i, cell.Key, cell.Type, cell.Values)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *RBFPageCommand) printBranchPage(page *rbf.BranchPage) {
|
||||
fmt.Fprintf(cmd.Stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.Stdout, "Type: branch\n")
|
||||
fmt.Fprintf(cmd.Stdout, "Cells: n=%d\n", len(page.Cells))
|
||||
fmt.Fprintf(cmd.stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "Type: branch\n")
|
||||
fmt.Fprintf(cmd.stdout, "Cells: n=%d\n", len(page.Cells))
|
||||
for i, cell := range page.Cells {
|
||||
fmt.Fprintf(cmd.Stdout, "[%d]: key=%d flags=%d pgno=%d\n", i, cell.Key, cell.Flags, cell.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "[%d]: key=%d flags=%d pgno=%d\n", i, cell.Key, cell.Flags, cell.Pgno)
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *RBFPageCommand) printBitmapPage(page *rbf.BitmapPage) {
|
||||
fmt.Fprintf(cmd.Stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.Stdout, "Type: bitmap\n")
|
||||
fmt.Fprintf(cmd.Stdout, "Values: %v\n", page.Values)
|
||||
fmt.Fprintf(cmd.stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "Type: bitmap\n")
|
||||
fmt.Fprintf(cmd.stdout, "Values: %v\n", page.Values)
|
||||
}
|
||||
|
||||
func (cmd *RBFPageCommand) printFreePage(page *rbf.FreePage) {
|
||||
fmt.Fprintf(cmd.Stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.Stdout, "Type: free\n")
|
||||
fmt.Fprintf(cmd.stdout, "Pgno: %d\n", page.Pgno)
|
||||
fmt.Fprintf(cmd.stdout, "Type: free\n")
|
||||
}
|
||||
|
|
|
|||
44
ctl/rbf_page_test.go
Normal file
44
ctl/rbf_page_test.go
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2022 Molecula Corp. All rights reserved.
|
||||
package ctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
func TestRBFPageCommand_Run(t *testing.T) {
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cmd := NewRBFPageCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.stdout = buf
|
||||
cmd.Path = filepath.Join("testdata", "ok")
|
||||
cmd.Pgnos = []uint32{0}
|
||||
if err := cmd.Run(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if got, want := buf.String(), "Type: meta"; !strings.Contains(got, want) {
|
||||
t.Fatalf("got:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ErrInvalidPageType", func(t *testing.T) {
|
||||
t.Skip("RBF panics if we do this")
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cmd := NewRBFPageCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.stdout = buf
|
||||
cmd.Path = filepath.Join("testdata", "err-invalid-page-type")
|
||||
cmd.Pgnos = []uint32{4}
|
||||
if err := cmd.Run(context.Background()); err == nil || err.Error() != `check failed` {
|
||||
t.Fatal(err)
|
||||
} else if got, want := buf.String(), `page not in-use & not free: pgno=4`+"\n"; got != want {
|
||||
t.Fatalf("got:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -5,8 +5,9 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/rbf"
|
||||
"github.com/molecula/featurebase/v3/txkey"
|
||||
)
|
||||
|
|
@ -20,13 +21,15 @@ type RBFPagesCommand struct {
|
|||
WithTree bool
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
stdout io.Writer
|
||||
logDest logger.Logger
|
||||
}
|
||||
|
||||
// NewRBFPagesCommand returns a new instance of RBFPagesCommand.
|
||||
func NewRBFPagesCommand(stdin io.Reader, stdout, stderr io.Writer) *RBFPagesCommand {
|
||||
func NewRBFPagesCommand(logdest logger.Logger) *RBFPagesCommand {
|
||||
return &RBFPagesCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
stdout: os.Stdout,
|
||||
logDest: logdest,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,81 +52,81 @@ func (cmd *RBFPagesCommand) Run(ctx context.Context) error {
|
|||
// Iterate over each page and grab info.
|
||||
infos, err := tx.PageInfos()
|
||||
if err != nil {
|
||||
fmt.Fprintln(cmd.Stdout, "ERRORS:")
|
||||
fmt.Fprintln(cmd.stdout, "ERRORS:")
|
||||
switch err := err.(type) {
|
||||
case rbf.ErrorList:
|
||||
for i := range err {
|
||||
fmt.Fprintln(cmd.Stdout, err[i])
|
||||
fmt.Fprintln(cmd.stdout, err[i])
|
||||
}
|
||||
default:
|
||||
fmt.Fprintln(cmd.Stdout, err)
|
||||
fmt.Fprintln(cmd.stdout, err)
|
||||
}
|
||||
fmt.Fprintln(cmd.Stdout, "")
|
||||
fmt.Fprintln(cmd.stdout, "")
|
||||
}
|
||||
|
||||
// Write header.
|
||||
fmt.Fprint(cmd.Stdout, "ID ")
|
||||
fmt.Fprint(cmd.Stdout, "TYPE ")
|
||||
fmt.Fprint(cmd.stdout, "ID ")
|
||||
fmt.Fprint(cmd.stdout, "TYPE ")
|
||||
if cmd.WithTree {
|
||||
fmt.Fprint(cmd.Stdout, "TREE ")
|
||||
fmt.Fprint(cmd.stdout, "TREE ")
|
||||
}
|
||||
fmt.Fprintln(cmd.Stdout, "EXTRA")
|
||||
fmt.Fprintln(cmd.stdout, "EXTRA")
|
||||
|
||||
fmt.Fprint(cmd.Stdout, "======== ")
|
||||
fmt.Fprint(cmd.Stdout, "========== ")
|
||||
fmt.Fprint(cmd.stdout, "======== ")
|
||||
fmt.Fprint(cmd.stdout, "========== ")
|
||||
if cmd.WithTree {
|
||||
fmt.Fprint(cmd.Stdout, "============================== ")
|
||||
fmt.Fprint(cmd.stdout, "============================== ")
|
||||
}
|
||||
fmt.Fprintln(cmd.Stdout, "====================")
|
||||
fmt.Fprintln(cmd.stdout, "====================")
|
||||
|
||||
// Print one line for each page.
|
||||
for pgno, info := range infos {
|
||||
fmt.Fprintf(cmd.Stdout, "%-8d ", pgno)
|
||||
fmt.Fprintf(cmd.stdout, "%-8d ", pgno)
|
||||
switch info := info.(type) {
|
||||
case *rbf.MetaPageInfo:
|
||||
fmt.Fprintf(cmd.Stdout, "%-10s ", "meta")
|
||||
fmt.Fprintf(cmd.stdout, "%-10s ", "meta")
|
||||
if cmd.WithTree {
|
||||
fmt.Fprintf(cmd.Stdout, "%-30q ", "")
|
||||
fmt.Fprintf(cmd.stdout, "%-30q ", "")
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "pageN=%d,walid=%d,rootrec=%d,freelist=%d\n", info.PageN, info.WALID, info.RootRecordPageNo, info.FreelistPageNo)
|
||||
fmt.Fprintf(cmd.stdout, "pageN=%d,walid=%d,rootrec=%d,freelist=%d\n", info.PageN, info.WALID, info.RootRecordPageNo, info.FreelistPageNo)
|
||||
|
||||
case *rbf.RootRecordPageInfo:
|
||||
fmt.Fprintf(cmd.Stdout, "%-10s ", "rootrec")
|
||||
fmt.Fprintf(cmd.stdout, "%-10s ", "rootrec")
|
||||
if cmd.WithTree {
|
||||
fmt.Fprintf(cmd.Stdout, "%-30q ", "")
|
||||
fmt.Fprintf(cmd.stdout, "%-30q ", "")
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "next=%d\n", info.Next)
|
||||
fmt.Fprintf(cmd.stdout, "next=%d\n", info.Next)
|
||||
|
||||
case *rbf.LeafPageInfo:
|
||||
fmt.Fprintf(cmd.Stdout, "%-10s ", "leaf")
|
||||
fmt.Fprintf(cmd.stdout, "%-10s ", "leaf")
|
||||
if cmd.WithTree {
|
||||
fmt.Fprintf(cmd.Stdout, "%-30q ", prefixToString(info.Tree))
|
||||
fmt.Fprintf(cmd.stdout, "%-30q ", prefixToString(info.Tree))
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "flags=x%x,celln=%d\n", info.Flags, info.CellN)
|
||||
fmt.Fprintf(cmd.stdout, "flags=x%x,celln=%d\n", info.Flags, info.CellN)
|
||||
|
||||
case *rbf.BranchPageInfo:
|
||||
fmt.Fprintf(cmd.Stdout, "%-10s ", "branch")
|
||||
fmt.Fprintf(cmd.stdout, "%-10s ", "branch")
|
||||
if cmd.WithTree {
|
||||
fmt.Fprintf(cmd.Stdout, "%-30q ", prefixToString(info.Tree))
|
||||
fmt.Fprintf(cmd.stdout, "%-30q ", prefixToString(info.Tree))
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "flags=x%x,celln=%d\n", info.Flags, info.CellN)
|
||||
fmt.Fprintf(cmd.stdout, "flags=x%x,celln=%d\n", info.Flags, info.CellN)
|
||||
|
||||
case *rbf.BitmapPageInfo:
|
||||
fmt.Fprintf(cmd.Stdout, "%-10s ", "bitmap")
|
||||
fmt.Fprintf(cmd.stdout, "%-10s ", "bitmap")
|
||||
if cmd.WithTree {
|
||||
fmt.Fprintf(cmd.Stdout, "%-30q ", prefixToString(info.Tree))
|
||||
fmt.Fprintf(cmd.stdout, "%-30q ", prefixToString(info.Tree))
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "-\n")
|
||||
fmt.Fprintf(cmd.stdout, "-\n")
|
||||
|
||||
case *rbf.FreePageInfo:
|
||||
fmt.Fprintf(cmd.Stdout, "%-10s ", "free")
|
||||
fmt.Fprintf(cmd.stdout, "%-10s ", "free")
|
||||
if cmd.WithTree {
|
||||
fmt.Fprintf(cmd.Stdout, "%-30q ", "")
|
||||
fmt.Fprintf(cmd.stdout, "%-30q ", "")
|
||||
}
|
||||
fmt.Fprintf(cmd.Stdout, "-\n")
|
||||
fmt.Fprintf(cmd.stdout, "-\n")
|
||||
|
||||
default:
|
||||
fmt.Fprintf(cmd.Stdout, "unknown [%T]\n", info)
|
||||
fmt.Fprintf(cmd.stdout, "unknown [%T]\n", info)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,11 @@ package ctl
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
func TestRBFPagesCommand_Run(t *testing.T) {
|
||||
|
|
@ -19,12 +22,14 @@ ID TYPE EXTRA
|
|||
3 leaf flags=x2,celln=1
|
||||
`[1:]
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := NewRBFPagesCommand(bytes.NewReader(nil), &stdout, &stderr)
|
||||
cmd.Path = filepath.Join("testdata", "rbf-pages", "ok")
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cmd := NewRBFPagesCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.stdout = buf
|
||||
cmd.Path = filepath.Join("testdata", "ok")
|
||||
if err := cmd.Run(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if got := stdout.String(); got != want {
|
||||
} else if got := buf.String(); got != want {
|
||||
t.Fatalf("got:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
|
|
@ -40,12 +45,14 @@ ID TYPE EXTRA
|
|||
4 unknown [<nil>]
|
||||
`[1:]
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := NewRBFPagesCommand(bytes.NewReader(nil), &stdout, &stderr)
|
||||
cmd.Path = filepath.Join("testdata", "rbf-pages", "err-invalid-page-type")
|
||||
cmLog := logger.NewStandardLogger(os.Stderr)
|
||||
cmd := NewRBFPagesCommand(cmLog)
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.stdout = buf
|
||||
cmd.Path = filepath.Join("testdata", "err-invalid-page-type")
|
||||
if err := cmd.Run(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if got := stdout.String(); got != want {
|
||||
} else if got := buf.String(); got != want {
|
||||
t.Fatalf("got:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -49,17 +49,22 @@ type RestoreCommand struct {
|
|||
client *pilosa.InternalClient
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
logDest logger.Logger
|
||||
|
||||
TLS server.TLSConfig
|
||||
|
||||
AuthToken string
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *RestoreCommand) Logger() logger.Logger {
|
||||
return cmd.logDest
|
||||
}
|
||||
|
||||
// NewRestoreCommand returns a new instance of RestoreCommand.
|
||||
func NewRestoreCommand(stdin io.Reader, stdout, stderr io.Writer) *RestoreCommand {
|
||||
func NewRestoreCommand(logdest logger.Logger) *RestoreCommand {
|
||||
return &RestoreCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
logDest: logdest,
|
||||
RetryPeriod: time.Second * 30,
|
||||
Concurrency: 1,
|
||||
Pprof: "localhost:0",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/authn"
|
||||
"github.com/molecula/featurebase/v3/disco"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
|
@ -42,17 +43,22 @@ type RestoreTarCommand struct {
|
|||
client *pilosa.InternalClient
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
logDest logger.Logger
|
||||
|
||||
TLS server.TLSConfig
|
||||
|
||||
AuthToken string
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *RestoreTarCommand) Logger() logger.Logger {
|
||||
return cmd.logDest
|
||||
}
|
||||
|
||||
// NewRestoreTarCommand returns a new instance of RestoreTarCommand.
|
||||
func NewRestoreTarCommand(stdin io.Reader, stdout, stderr io.Writer) *RestoreTarCommand {
|
||||
func NewRestoreTarCommand(logdest logger.Logger) *RestoreTarCommand {
|
||||
return &RestoreTarCommand{
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
logDest: logdest,
|
||||
RetryPeriod: time.Second * 30,
|
||||
Pprof: "localhost:0",
|
||||
}
|
||||
|
|
@ -76,7 +82,7 @@ func (cmd *RestoreTarCommand) Run(ctx context.Context) (err error) {
|
|||
var f io.Reader
|
||||
// read from Stdin if path specified as -
|
||||
if useStdin {
|
||||
f = cmd.Stdin
|
||||
f = os.Stdin
|
||||
} else {
|
||||
file, err := os.Open(cmd.Path)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
package ctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/test"
|
||||
)
|
||||
|
||||
|
|
@ -17,9 +18,8 @@ func TestRestoreTarCommand_Run(t *testing.T) {
|
|||
defer cluster.Close()
|
||||
cmd := cluster.GetNode(0)
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewRestoreTarCommand(stdin, stdout, stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewRestoreTarCommand(cmLog)
|
||||
hostport := cmd.API.Node().URI.HostPort()
|
||||
cm.Host = hostport
|
||||
cm.Path = ""
|
||||
|
|
|
|||
|
|
@ -4,12 +4,15 @@ package ctl
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
)
|
||||
|
||||
func TestRestoreCommand_Run(t *testing.T) {
|
||||
cm := NewRestoreCommand(os.Stdin, os.Stdout, os.Stderr)
|
||||
cmLog := logger.NewStandardLogger(io.Discard)
|
||||
cm := NewRestoreCommand(cmLog)
|
||||
cm.Path = ""
|
||||
err := cm.Run(context.Background())
|
||||
if !errors.Is(err, UsageError) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
package ctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
|
|
@ -11,9 +11,7 @@ import (
|
|||
|
||||
func TestBuildServerFlags(t *testing.T) {
|
||||
cm := &cobra.Command{}
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
Server := server.NewCommand(stdin, stdout, stderr)
|
||||
Server := server.NewCommand(os.Stderr)
|
||||
BuildServerFlags(cm, Server)
|
||||
if cm.Flags().Lookup("data-dir").Name == "" {
|
||||
t.Fatal("data-dir flag is required")
|
||||
|
|
|
|||
BIN
ctl/testdata/rbf-pages/err-invalid-page-type/data
vendored
BIN
ctl/testdata/rbf-pages/err-invalid-page-type/data
vendored
Binary file not shown.
BIN
ctl/testdata/rbf-pages/ok/data
vendored
BIN
ctl/testdata/rbf-pages/ok/data
vendored
Binary file not shown.
0
ctl/testdata/rbf-pages/ok/wal
vendored
0
ctl/testdata/rbf-pages/ok/wal
vendored
|
|
@ -53,7 +53,7 @@ type Command struct {
|
|||
done chan struct{}
|
||||
|
||||
// Standard input/output
|
||||
*featurebase.CmdIO
|
||||
stderr io.Writer
|
||||
|
||||
ln net.Listener
|
||||
listenURI *fbnet.URI
|
||||
|
|
@ -94,11 +94,11 @@ func OptCommandConfig(config *Config) CommandOption {
|
|||
}
|
||||
|
||||
// NewCommand returns a new instance of Command.
|
||||
func NewCommand(stdin io.Reader, stdout, stderr io.Writer, opts ...CommandOption) *Command {
|
||||
func NewCommand(stderr io.Writer, opts ...CommandOption) *Command {
|
||||
c := &Command{
|
||||
Config: NewConfig(),
|
||||
|
||||
CmdIO: featurebase.NewCmdIO(stdin, stdout, stderr),
|
||||
stderr: stderr,
|
||||
|
||||
registerFns: make([]registerFn, 0),
|
||||
|
||||
|
|
@ -415,7 +415,7 @@ func (m *Command) setupServer() error {
|
|||
m.logger.Warnf("No snapshotter configured.")
|
||||
}
|
||||
|
||||
fbcmd := featurebaseserver.NewCommand(m.CmdIO.Stdin, m.CmdIO.Stdout, m.CmdIO.Stderr,
|
||||
fbcmd := featurebaseserver.NewCommand(m.stderr,
|
||||
featurebaseserver.OptCommandSetConfig(&m.Config.Computer.Config),
|
||||
featurebaseserver.OptCommandServerOptions(
|
||||
featurebase.OptServerIsComputeNode(true),
|
||||
|
|
@ -465,7 +465,7 @@ func (m *Command) setupLogger() error {
|
|||
var f *logger.FileWriter
|
||||
var err error
|
||||
if m.Config.LogPath == "" {
|
||||
m.logOutput = m.Stderr
|
||||
m.logOutput = os.Stderr
|
||||
} else {
|
||||
f, err = logger.NewFileWriter(m.Config.LogPath)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
pilosa "github.com/molecula/featurebase/v3"
|
||||
"github.com/molecula/featurebase/v3/ctl"
|
||||
"github.com/molecula/featurebase/v3/disco"
|
||||
"github.com/molecula/featurebase/v3/logger"
|
||||
"github.com/molecula/featurebase/v3/pql"
|
||||
"github.com/molecula/featurebase/v3/proto"
|
||||
"github.com/molecula/featurebase/v3/server"
|
||||
|
|
@ -7398,8 +7399,8 @@ func backupTest(t *testing.T, c *test.Cluster, index string) {
|
|||
|
||||
func chkSumCluster(t *testing.T, c *test.Cluster) string {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
chkSum := ctl.NewChkSumCommand(nil, buf, buf)
|
||||
chkSumLog := logger.NewStandardLogger(buf)
|
||||
chkSum := ctl.NewChkSumCommand(chkSumLog)
|
||||
chkSum.Host = c.Nodes[len(c.Nodes)-1].URL()
|
||||
if err := chkSum.Run(context.Background()); err != nil {
|
||||
t.Fatalf("running checksum: %v", err)
|
||||
|
|
@ -7416,7 +7417,8 @@ func backupCluster(t *testing.T, c *test.Cluster, index string) (backupDir strin
|
|||
td = td + "/backupTest"
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
backupCommand := ctl.NewBackupCommand(nil, buf, buf)
|
||||
backupLog := logger.NewStandardLogger(buf)
|
||||
backupCommand := ctl.NewBackupCommand(backupLog)
|
||||
backupCommand.Host = c.Nodes[len(c.Nodes)-1].URL() // don't pick node 0 so we don't always get primary (better code coverage)
|
||||
backupCommand.Index = index
|
||||
backupCommand.OutputDir = td
|
||||
|
|
@ -7430,8 +7432,8 @@ func backupCluster(t *testing.T, c *test.Cluster, index string) (backupDir strin
|
|||
|
||||
func restoreCluster(t *testing.T, backupDir string, c *test.Cluster) {
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
restore := ctl.NewRestoreCommand(nil, buf, buf)
|
||||
restoreLog := logger.NewStandardLogger(buf)
|
||||
restore := ctl.NewRestoreCommand(restoreLog)
|
||||
restore.Host = c.Nodes[len(c.Nodes)-1].URL()
|
||||
restore.Path = backupDir
|
||||
if err := restore.Run(context.Background()); err != nil {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
package clustertest
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
|
@ -251,12 +250,8 @@ func TestClusterStuff(t *testing.T) {
|
|||
// replicas=3 and the backup command will retry on replicas.
|
||||
// featurebase backup cmd can't be used for a test expected to fail
|
||||
// because code coverage report won't be generated.
|
||||
buf := bytes.Buffer{}
|
||||
rder := []byte{}
|
||||
stdin := bytes.NewReader(rder)
|
||||
stdout := bufio.NewWriter(&buf)
|
||||
stderr := bufio.NewWriter(&buf)
|
||||
backup := ctl.NewBackupCommand(stdin, stdout, stderr)
|
||||
backuplog := logger.NewStandardLogger(os.Stderr)
|
||||
backup := ctl.NewBackupCommand(backuplog)
|
||||
backup.Host = "--host=pilosa1:10101"
|
||||
backup.OutputDir = tmpdir + "/backuptest2"
|
||||
backup.RetryPeriod = time.Millisecond * 200
|
||||
|
|
|
|||
|
|
@ -66,9 +66,6 @@ type Command struct {
|
|||
// Configuration.
|
||||
Config *Config
|
||||
|
||||
// Standard input/output
|
||||
*pilosa.CmdIO
|
||||
|
||||
// Started will be closed once Command.Start is finished.
|
||||
Started chan struct{}
|
||||
// done will be closed when Command.Close() is called
|
||||
|
|
@ -101,6 +98,11 @@ type Command struct {
|
|||
isComputeNode bool
|
||||
}
|
||||
|
||||
// Logger returns the command's associated Logger to maintain CommandWithTLSSupport interface compatibility
|
||||
func (cmd *Command) Logger() logger.Logger {
|
||||
return cmd.logger
|
||||
}
|
||||
|
||||
type CommandOption func(c *Command) error
|
||||
|
||||
func OptCommandServerOptions(opts ...pilosa.ServerOption) CommandOption {
|
||||
|
|
@ -169,11 +171,11 @@ type Injections struct {
|
|||
}
|
||||
|
||||
// NewCommand returns a new instance of Main.
|
||||
func NewCommand(stdin io.Reader, stdout, stderr io.Writer, opts ...CommandOption) *Command {
|
||||
func NewCommand(stderr io.Writer, opts ...CommandOption) *Command {
|
||||
c := &Command{
|
||||
Config: NewConfig(),
|
||||
|
||||
CmdIO: pilosa.NewCmdIO(stdin, stdout, stderr),
|
||||
logOutput: stderr,
|
||||
|
||||
Started: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
|
|
@ -730,9 +732,7 @@ func (m *Command) HTTPHandler() http.Handler {
|
|||
func (m *Command) setupLogger() error {
|
||||
var f *logger.FileWriter
|
||||
var err error
|
||||
if m.Config.LogPath == "" {
|
||||
m.logOutput = m.Stderr
|
||||
} else {
|
||||
if m.Config.LogPath != "" {
|
||||
f, err = logger.NewFileWriter(m.Config.LogPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "opening file")
|
||||
|
|
|
|||
|
|
@ -47,7 +47,11 @@ func newCommand(tb DirCleaner, opts ...server.CommandOption) *Command {
|
|||
}, opts...)
|
||||
|
||||
m := &Command{commandOptions: opts}
|
||||
m.Command = server.NewCommand(bytes.NewReader(nil), io.Discard, io.Discard, opts...)
|
||||
output := io.Discard
|
||||
if testing.Verbose() {
|
||||
output = os.Stderr
|
||||
}
|
||||
m.Command = server.NewCommand(output, opts...)
|
||||
// pick etcd ports using a socket rather than a real port
|
||||
err := GetPortsGenConfigs(tb, []*Command{m})
|
||||
if err != nil {
|
||||
|
|
@ -67,11 +71,6 @@ func newCommand(tb DirCleaner, opts ...server.CommandOption) *Command {
|
|||
m.Config.Translation.MapSize = 140000
|
||||
m.Config.WorkerPoolSize = 2
|
||||
|
||||
if testing.Verbose() {
|
||||
m.Command.Stdout = os.Stdout
|
||||
m.Command.Stderr = os.Stderr
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +108,11 @@ func (m *Command) Reopen() error {
|
|||
|
||||
// Create new main with the same config.
|
||||
config := m.Command.Config
|
||||
m.Command = server.NewCommand(bytes.NewReader(nil), io.Discard, io.Discard, m.commandOptions...)
|
||||
output := io.Discard
|
||||
if testing.Verbose() {
|
||||
output = os.Stderr
|
||||
}
|
||||
m.Command = server.NewCommand(output, m.commandOptions...)
|
||||
m.Command.Config = config
|
||||
|
||||
// Run new program.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue