From 6334854815d40c83bf783b9209a1c7aa63d2f414 Mon Sep 17 00:00:00 2001 From: Orpheus Lummis Date: Fri, 16 Dec 2022 11:41:05 -0600 Subject: [PATCH] WIP --- tests/integration/cli/client_ping_test.go | 71 +++++++++ tests/integration/cli/client_test.go | 24 +++ tests/integration/cli/init_test.go | 74 ++++++++++ tests/integration/cli/log_config_test.go | 41 ++---- tests/integration/cli/root_test.go | 56 +++++++ tests/integration/cli/rpc_test.go | 14 ++ tests/integration/cli/serverdump_test.go | 62 ++++++++ tests/integration/cli/start_test.go | 40 +++++ tests/integration/cli/utils.go | 171 ++++++++++++++++++++++ tests/integration/cli/utils_test.go | 62 ++++++++ tests/integration/cli/version_test.go | 49 +++++++ 11 files changed, 636 insertions(+), 28 deletions(-) create mode 100644 tests/integration/cli/client_ping_test.go create mode 100644 tests/integration/cli/client_test.go create mode 100644 tests/integration/cli/init_test.go create mode 100644 tests/integration/cli/root_test.go create mode 100644 tests/integration/cli/rpc_test.go create mode 100644 tests/integration/cli/serverdump_test.go create mode 100644 tests/integration/cli/start_test.go create mode 100644 tests/integration/cli/utils.go create mode 100644 tests/integration/cli/utils_test.go create mode 100644 tests/integration/cli/version_test.go diff --git a/tests/integration/cli/client_ping_test.go b/tests/integration/cli/client_ping_test.go new file mode 100644 index 0000000000..4e05d28357 --- /dev/null +++ b/tests/integration/cli/client_ping_test.go @@ -0,0 +1,71 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest + +import ( + "context" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/sourcenetwork/defradb/cli" + "github.com/sourcenetwork/defradb/config" +) + +func TestPingCommandToValidHostWithNoNode(t *testing.T) { + logLines := captureStderr(t, func() { + cfg := config.NewWithDefaults() + defraCmd := cli.NewDefraCommand(cfg) + defraCmd.RootCmd.SetArgs([]string{"client", "ping", "--url", "localhost:9876"}) + assert.Error(t, defraCmd.Execute(context.Background())) + }) + gotExpectedError := false + expectedError1 := "{\"Error\": \"failed to send ping: Get \\\"http://localhost:9876/api/v0/ping\\\": dial tcp [::1]:9876: connect: connection refused\"}" + expectedError2 := "{\"Error\": \"failed to send ping: Get \\\"http://localhost:9876/api/v0/ping\\\": dial tcp 127.0.0.1:9876: connect: connection refused\"}" + for _, line := range logLines { + if strings.Contains(line, expectedError1) || strings.Contains(line, expectedError2) { + gotExpectedError = true + break + } + } + assert.True(t, gotExpectedError) +} + +func TestPingCommandToInvalidHost(t *testing.T) { + logLines := captureStderr(t, func() { + cfg := config.NewWithDefaults() + defraCmd := cli.NewDefraCommand(cfg) + defraCmd.RootCmd.SetArgs([]string{"client", "ping", "--url", "'1!2:3!4'"}) + assert.Error(t, defraCmd.Execute(context.Background())) + }) + expectedError := "{\"Error\": \"failed to load config: failed to validate API config: invalid database URL provided\"}" + assert.Contains(t, parseLogLine(logLines[0]), expectedError) +} + +func TestPingCommandToValidLocalhostwithFramework(t *testing.T) { + cfg := config.NewWithDefaults() + testCfg := newRandomTestConfig(t) + cfg.API.Address = testCfg.serialize().APIAddress + cfg.Rootdir = testCfg.serialize().RootDir + defraCmd := cli.NewDefraCommand(cfg) + // defer(releasePortsOfCommand(defraCmd)) + logLines := testFrameworkWithBackgroundNodeExec(t, testCfg, func() { + defraCmd.RootCmd.SetArgs([]string{"client", "ping"}) + err := defraCmd.Execute(context.Background()) + assert.NoError(t, err) + }) + expectedOutput := `{"data":{"response":"pong"}}` + assert.Contains(t, parseLogLine(logLines[0]), expectedOutput) +} diff --git a/tests/integration/cli/client_test.go b/tests/integration/cli/client_test.go new file mode 100644 index 0000000000..2249b5558f --- /dev/null +++ b/tests/integration/cli/client_test.go @@ -0,0 +1,24 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest + +/* + - schema + - add + - blocks + - get + - dump + - peerid + - query +*/ diff --git a/tests/integration/cli/init_test.go b/tests/integration/cli/init_test.go new file mode 100644 index 0000000000..35ad13ea5d --- /dev/null +++ b/tests/integration/cli/init_test.go @@ -0,0 +1,74 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/sourcenetwork/defradb/cli" + "github.com/sourcenetwork/defradb/config" +) + +// Executing init command creates valid config file. +func TestCLIInitCommand(t *testing.T) { + tmpdir := t.TempDir() + logLines := captureStderr(t, func() { + defraCmd := cli.NewDefraCommand(config.NewWithDefaults()) + defraCmd.RootCmd.SetArgs([]string{"init", "--rootdir", tmpdir}) + assert.NoError(t, defraCmd.Execute(context.Background())) + }) + t.Log(logLines) + assert.Contains(t, parseLogLine(logLines[0]), "Initialized configuration file at "+tmpdir+"/"+config.DefaultConfigFileName) + + cfg := config.NewWithDefaults() + cfg.Rootdir = tmpdir + assert.NoError(t, cfg.Load(true)) +} + +// Executing init command twice leads to error. +// func TestCLIInitCommandTwiceErrors(t *testing.T) { +// tmpdir := t.TempDir() +// logLines := captureStderr(t, func() { +// rootCmd := cli.NewDefraCommand(config.NewWithDefaults()).RootCmd +// rootCmd.SetArgs([]string{"init", tmpdir}) +// assert.NoError(t, rootCmd.Execute()) +// }) +// assert.Contains(t, parseLogLine(logLines[0]), "Initialized configuration file at "+tmpdir+"/"+config.DefaultConfigFileName) +// logLines = captureStderr(t, func() { +// rootCmd := cli.NewDefraCommand(config.NewWithDefaults()).RootCmd +// rootCmd.SetArgs([]string{"init", tmpdir}) +// assert.NoError(t, rootCmd.Execute()) // TBD: should this be an error? +// }) +// assert.Contains(t, parseLogLine(logLines[0]), "Configuration file already exists at "+tmpdir+"/"+config.DefaultConfigFileName+". Consider using --reinitialize") +// } + +// Executing init command twice, but second time reinitializing. +// func TestInitCommandTwiceReinitalize(t *testing.T) { +// tmpdir := t.TempDir() +// defraCommand := cli.NewDefraCommand(config.NewWithDefaults()) +// logLines := captureStderr(t, func() { +// defraCommand.RootCmd.SetArgs([]string{"init", "--rootdir", tmpdir}) +// assert.NoError(t, defraCommand.Execute(context.Background())) +// }) +// t.Log(logLines) +// assert.Contains(t, parseLogLine(logLines[0]), "Initialized configuration file at "+tmpdir+"/"+config.DefaultConfigFileName) +// // logLines = captureStderr(t, func() { +// // rootCmd.SetArgs([]string{"init", tmpdir, "--reinitialize"}) +// // assert.NoError(t, rootCmd.Execute()) +// // }) +// // assert.Contains(t, parseLogLine(logLines[0]), "Reinitialized configuration file at "+tmpdir+"/"+config.DefaultConfigFileName) +// } diff --git a/tests/integration/cli/log_config_test.go b/tests/integration/cli/log_config_test.go index fffdcfbef6..2684eb51c3 100644 --- a/tests/integration/cli/log_config_test.go +++ b/tests/integration/cli/log_config_test.go @@ -8,35 +8,18 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -package cli - -import ( - "bufio" - "bytes" - "context" - "fmt" - "io" - "os" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/sourcenetwork/defradb/cli" - "github.com/sourcenetwork/defradb/logging" -) - -const ( - testLogger1 = "testLogger1" - testLogger2 = "testLogger2" - testLogger3 = "testLogger3" -) - -var ( - log1 = logging.MustNewLogger(testLogger1) - log2 = logging.MustNewLogger(testLogger2) - log3 = logging.MustNewLogger(testLogger3) -) +//go:build integrationcli +// +build integrationcli +package clitest + +// const ( +// testLogger1 = "testLogger1" +// testLogger2 = "testLogger2" +// testLogger3 = "testLogger3" +// ) + +/* func TestCLILogsToStderrGivenNamedLogLevel(t *testing.T) { ctx := context.Background() logLines := captureLogLines( @@ -109,3 +92,5 @@ func parseLines(r io.Reader) ([]string, error) { return logLines, nil } + +*/ diff --git a/tests/integration/cli/root_test.go b/tests/integration/cli/root_test.go new file mode 100644 index 0000000000..061ef4ce54 --- /dev/null +++ b/tests/integration/cli/root_test.go @@ -0,0 +1,56 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/sourcenetwork/defradb/cli" + "github.com/sourcenetwork/defradb/config" +) + +func TestRootCommandEmptyRootDir(t *testing.T) { + defraCmd := cli.NewDefraCommand(config.NewWithDefaults()) + tmpdir := t.TempDir() + defraCmd.RootCmd.SetArgs([]string{"--rootdir", tmpdir}) + assert.NoError(t, defraCmd.Execute(context.Background())) + assert.Equal(t, config.NewWithDefaults(), defraCmd.Cfg) +} + +func TestRootCommandRootDirWithDefaultConfig(t *testing.T) { + defraCmd := cli.NewDefraCommand(config.NewWithDefaults()) + tmpdir := t.TempDir() + cfg := config.NewWithDefaults() + cfg.Rootdir = tmpdir + assert.NoError(t, cfg.CreateRootDir()) + defraCmd.RootCmd.SetArgs([]string{"--rootdir", tmpdir}) + assert.NoError(t, defraCmd.Execute(context.Background())) + assert.Equal(t, config.NewWithDefaults(), defraCmd.Cfg) +} + +// loaded config is non-default +func TestRootCommandRootDirWithNonDefaultConfig(t *testing.T) { + tmpdir := t.TempDir() + cfg := config.NewWithDefaults() + cfg.Rootdir = tmpdir + defraCmd := cli.NewDefraCommand(cfg) + defraCmd.Cfg.Datastore.Store = "memory" + assert.NoError(t, defraCmd.Cfg.WriteConfigFile()) + defraCmd.RootCmd.SetArgs([]string{"--rootdir", tmpdir}) + assert.NoError(t, defraCmd.Execute(context.Background())) + assert.Equal(t, "memory", defraCmd.Cfg.Datastore.Store) +} diff --git a/tests/integration/cli/rpc_test.go b/tests/integration/cli/rpc_test.go new file mode 100644 index 0000000000..fb3caef48b --- /dev/null +++ b/tests/integration/cli/rpc_test.go @@ -0,0 +1,14 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest diff --git a/tests/integration/cli/serverdump_test.go b/tests/integration/cli/serverdump_test.go new file mode 100644 index 0000000000..088b253bed --- /dev/null +++ b/tests/integration/cli/serverdump_test.go @@ -0,0 +1,62 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest + +/* + +import ( + "bufio" + "os" + "testing" + + "github.com/sourcenetwork/defradb/cli" +) + +// Execution error, {"Error": "badger store does not exist at /Users/o/.defradb/data. Try with an existing directory"} + +func TestServerDump(t *testing.T) { + lines := capture(t, func() { + cmd := cli.MakeCommandTree() + tmpdir := t.TempDir() + cmd.SetArgs([]string{"init", tmpdir}) + cmd.Execute() + cmd.SetArgs([]string{"--rootdir", tmpdir, "server-dump"}) + cmd.Execute() + + // tmpdir := t.TempDir() + // initCmd := cli.MakeInitCommand() + // initCmd.SetArgs([]string{tmpdir}) + // initCmd.Execute() + + // serverDumpCmd := cli.MakeServerDumpCmd() + // serverDumpCmd.Execute() + }) + t.Log(lines) + t.Fail() + // Dumping DB state + // keys are like + // /db/blocks/ + // /db/data/ + // /db/system/ + // /peers/peers/ + // /providers/ +} + +func TestServerDumpMemoryErrs(t *testing.T) { + // we expect the following error: + // Execution error, {"Error": "server-side dump is only supported for the Badger datastore"} +} + + +*/ diff --git a/tests/integration/cli/start_test.go b/tests/integration/cli/start_test.go new file mode 100644 index 0000000000..bd2b59812b --- /dev/null +++ b/tests/integration/cli/start_test.go @@ -0,0 +1,40 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/sourcenetwork/defradb/cli" + "github.com/sourcenetwork/defradb/config" +) + +func TestWithFrameworkStartDoubleFailsBecauseOfRootdirLock(t *testing.T) { + cfg := config.NewWithDefaults() + testCfg := newRandomTestConfig(t) + cfg.Rootdir = testCfg.RootDir + defraCmd := cli.NewDefraCommand(cfg) + // defer(releasePortsOfCommand(defraCmd)) + logLines := testFrameworkWithBackgroundNodeExec(t, testCfg, func() { + defraCmd.RootCmd.SetArgs([]string{"start"}) + err := defraCmd.Execute(context.Background()) + assert.Error(t, err) + }) + expectedError := fmt.Sprintf("{\"Error\": \"failed to open datastore: Cannot acquire directory lock on \\\"%v/data\\\". Another process is using this Badger database. error: resource temporarily unavailable\"}", testCfg.RootDir) + assert.Contains(t, parseLogLine(logLines[2]), expectedError) +} diff --git a/tests/integration/cli/utils.go b/tests/integration/cli/utils.go new file mode 100644 index 0000000000..5837746d41 --- /dev/null +++ b/tests/integration/cli/utils.go @@ -0,0 +1,171 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +/* +WIP explanatory how the test framework works + +A system to generate unique test configurations. +*/ +package clitest + +import ( + "bufio" + "context" + "crypto/sha256" + "fmt" + "math/rand" + "os" + "os/exec" + "strings" + "testing" + "time" + + "github.com/sourcenetwork/defradb/cli" + "github.com/sourcenetwork/defradb/config" +) + +func execDefraCmdWithArgs(cfg *config.Config, args []string) error { + defraCmd := cli.NewDefraCommand(cfg) + defraCmd.RootCmd.SetArgs(args) + return defraCmd.Execute(context.Background()) +} + +type testConfig struct { + RootDir string + APIPort int + RPCPort int + P2PPort int + TCPPort int + ID string +} + +var testConfigs = make(map[string]testConfig) + +func newTestConfig(t *testing.T) testConfig { + t.Helper() + tc := testConfig{ + RootDir: t.TempDir(), + APIPort: newPort(), + RPCPort: newPort(), + P2PPort: newPort(), + TCPPort: newPort(), + } + tc.ID = tc.selfhash() + testConfigs[tc.ID] = tc + return tc +} + +func (tc testConfig) selfhash() string { + return fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprintf("%v", tc)))) +} + +// serialize testConfig +func (tc testConfig) serialize() string { + return testConfigSerialized{ + RootDir: tc.RootDir, + APIAddress: fmt.Sprintf("localhost:%v", tc.APIPort), + RPCAddress: fmt.Sprintf("localhost:%v", tc.RPCPort), + P2PAddress: fmt.Sprintf("/ip4/127.0.0.1/tcp/%v", tc.P2PPort), + TCPAddress: fmt.Sprintf("/ip4/127.0.0.1/tcp/%v", tc.TCPPort), + } +} + +func releaseTestConfig(tc testConfig) { +} + +var ports = make(map[int]bool) + +func newPort() int { + min := 9999 + max := 65535 + for { + port := rand.Intn(max-min) + min + if _, ok := ports[port]; !ok { + ports[port] = true + return port + } + } +} + +// this works with the PATH setup ... +func testFrameworkWithBackgroundNodeExec(t *testing.T, testCfg testConfig, action func()) []string { + t.Helper() + c := testCfg.serialize() + // potential problem with this + args := []string{"start"} + args = append(args, "--rootdir", c.RootDir) + args = append(args, "--url", c.APIAddress) + args = append(args, "--p2paddr", c.P2PAddress) + args = append(args, "--tcpaddr", c.TCPAddress) + go func() { + cmd := exec.Command("defradb", args...) + // stdout, _ := cmd.StdoutPipe() + // stderr, _ := cmd.StderrPipe() + + err := cmd.Start() + if err != nil { + panic(err) + } + + // time.Sleep(2 * time.Second) + + // scanner := bufio.NewScanner(stdout) + // for scanner.Scan() { + // fmt.Println(scanner.Text()) + // } + + // scanner = bufio.NewScanner(stderr) + // for scanner.Scan() { + // fmt.Println("bg node stderr", scanner.Text()) + // } + }() + // sufficient time for the background node to start + time.Sleep(2 * time.Second) + + // WIP or sstdout ?? + // clarify the thing with piping ... + lines := captureStderr(t, action) + return lines +} + +// Execute an action that writes to Stderr and captures the log output. +func captureStderr(t *testing.T, action func()) []string { + t.Helper() + + stderr := os.Stderr + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + os.Stderr = w + + action() + + _ = w.Close() + scanner := bufio.NewScanner(r) + scanner.Split(bufio.ScanLines) + var lines []string + for scanner.Scan() { + text := scanner.Text() + t.Log(text) + lines = append(lines, text) + } + _ = r.Close() + os.Stderr = stderr + return lines +} + +// parse log line as quasi-csv into a string array +func parseLogLine(line string) []string { + return strings.Split(line, ", ") +} diff --git a/tests/integration/cli/utils_test.go b/tests/integration/cli/utils_test.go new file mode 100644 index 0000000000..65d3de2a03 --- /dev/null +++ b/tests/integration/cli/utils_test.go @@ -0,0 +1,62 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest + +import ( + "context" + "fmt" + "log" + "os" + "reflect" + "testing" + + "github.com/sourcenetwork/defradb/cli" + "github.com/sourcenetwork/defradb/config" + "github.com/stretchr/testify/assert" +) + +func TestCaptureStderr(t *testing.T) { + lines := captureStderr(t, func() { + fmt.Fprintln(os.Stderr, "Test message 1") + log.Println("Test message 2") + fmt.Fprintln(os.Stderr, "Test message 3") + log.Println("Test message 4") + }) + + expectedLines := []string{ + "Test message 1", + "Test message 3", + } + + if !reflect.DeepEqual(lines, expectedLines) { + t.Errorf("expected %q, got %q", expectedLines, lines) + } +} + +func TestBasicStderrCapture(t *testing.T) { + lines := captureStderr(t, func() { + defraCmd := cli.NewDefraCommand(config.NewWithDefaults()) + defraCmd.RootCmd.SetArgs([]string{"129873918269387162"}) + assert.Error(t, defraCmd.Execute(context.Background())) + }) + + t.Log(lines) + + expectedLines := []string{ + "Usage:", + "defradb [command]", + } + + assert.Equal(t, expectedLines, lines) +} diff --git a/tests/integration/cli/version_test.go b/tests/integration/cli/version_test.go new file mode 100644 index 0000000000..f3be5a158b --- /dev/null +++ b/tests/integration/cli/version_test.go @@ -0,0 +1,49 @@ +// Copyright 2022 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +//go:build integrationcli +// +build integrationcli + +package clitest + +import ( + "os/exec" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/sourcenetwork/defradb/config" +) + +func TestExecVersion(t *testing.T) { + cmd := exec.Command("defradb", "version") + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatal(err) + } + assert.Contains(t, string(out), "defradb") + assert.Contains(t, string(out), "built with Go") +} + +func TestWithFrameworkSimpleVersion(t *testing.T) { + var err error + cfg := config.NewWithDefaults() + testCfg := newRandomTestConfig(t) + defer(releaseTestCfg(testCfg)) + cfg.Rootdir = testCfg.RootDir + logLines := testFrameworkWithBackgroundNodeExec(t, testCfg, func() { + err = execDefraCmdWithArgs(cfg, []string{"version"}) + }) + + assert.NoError(t, err) + assert.True(t, strings.Contains(logLines[0], "defradb")) + assert.True(t, strings.Contains(logLines[0], "built with")) +}