From a79e170256ce3864892059f09a8fb0df6cfc7b1f Mon Sep 17 00:00:00 2001 From: Linh Vo Date: Mon, 29 May 2017 13:41:23 -1000 Subject: [PATCH] more ctl tests --- ctl/backup_test.go | 196 ++++++++++++++++++++++++++++++++++-- ctl/bench_test.go | 86 ++++++++++++++++ ctl/check_test.go | 98 ++++++++++++++++++ ctl/config_test.go | 44 ++++++++ ctl/export_test.go | 76 ++++++++++++++ ctl/generate_config_test.go | 41 ++++++++ ctl/import.go | 4 - ctl/import_test.go | 145 ++++++++++++++++++++++++++ ctl/inspect_test.go | 47 +++++++++ ctl/restore_test.go | 73 ++++++++++++++ ctl/server_test.go | 39 +++++++ ctl/sort_test.go | 83 +++++++++++++++ 12 files changed, 921 insertions(+), 11 deletions(-) create mode 100644 ctl/bench_test.go create mode 100644 ctl/check_test.go create mode 100644 ctl/config_test.go create mode 100644 ctl/export_test.go create mode 100644 ctl/generate_config_test.go create mode 100644 ctl/import_test.go create mode 100644 ctl/inspect_test.go create mode 100644 ctl/restore_test.go create mode 100644 ctl/server_test.go create mode 100644 ctl/sort_test.go diff --git a/ctl/backup_test.go b/ctl/backup_test.go index 149157953..512093a20 100644 --- a/ctl/backup_test.go +++ b/ctl/backup_test.go @@ -1,15 +1,197 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package ctl import ( + "bytes" + "context" + "fmt" + "github.com/pilosa/pilosa" + "github.com/pilosa/pilosa/pql" + "io/ioutil" + "net/http/httptest" + "net/url" "testing" - "golang.org/x/net/context" ) -func TestBackupCommand_FileRequired(t *testing.T){ - cm := BackupCommand{} - ctx := context.Background() - err := cm.Run(ctx) - if err.Error() != "output file required"{ - t.Fatalf("Command not working, expect: output file required, actual: '%s'", err) +func TestBackupCommand_FileRequired(t *testing.T) { + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + + cm := NewBackupCommand(stdin, stdout, stderr) + err := cm.Run(context.Background()) + if err.Error() != "output file required" { + t.Fatalf("expect error: output file required, actual: %s", err) + } + +} + +func TestBackupCommand_Run(t *testing.T) { + + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + + hldr := MustOpenHolder() + defer hldr.Close() + + s := NewServer() + defer s.Close() + s.Handler.Host = s.Host() + s.Handler.Cluster = NewCluster(1) + s.Handler.Cluster.Nodes[0].Host = s.Host() + s.Handler.Holder = hldr.Holder + cm := NewBackupCommand(stdin, stdout, stderr) + file, err := ioutil.TempFile("", "import.csv") + + cm.Index = "i" + cm.Host = s.Host() + cm.Frame = "f" + cm.View = pilosa.ViewStandard + cm.Path = file.Name() + err = cm.Run(context.Background()) + if err != nil { + t.Fatalf("Command not working, error: '%s'", err) } } + +// Server represents a test wrapper for httptest.Server. +type Server struct { + *httptest.Server + Handler *Handler +} + +// NewServer returns a test server running on a random port. +func NewServer() *Server { + s := &Server{ + Handler: NewHandler(), + } + s.Server = httptest.NewServer(s.Handler.Handler) + + // Update handler to use hostname. + s.Handler.Host = s.Host() + + // Handler test messages can no-op. + s.Handler.Broadcaster = pilosa.NopBroadcaster + // Create a default cluster on the handler + s.Handler.Cluster = NewCluster(1) + s.Handler.Cluster.Nodes[0].Host = s.Host() + + return s +} + +// Handler represents a test wrapper for pilosa.Handler. +type Handler struct { + *pilosa.Handler + Executor HandlerExecutor +} + +// NewHandler returns a new instance of Handler. +func NewHandler() *Handler { + h := &Handler{ + Handler: pilosa.NewHandler(), + } + h.Handler.Executor = &h.Executor + h.Handler.LogOutput = ioutil.Discard + + // Handler test messages can no-op. + h.Broadcaster = pilosa.NopBroadcaster + + return h +} + +// HandlerExecutor is a mock implementing pilosa.Handler.Executor. +type HandlerExecutor struct { + cluster *pilosa.Cluster + ExecuteFn func(ctx context.Context, index string, query *pql.Query, slices []uint64, opt *pilosa.ExecOptions) ([]interface{}, error) +} + +func (c *HandlerExecutor) Cluster() *pilosa.Cluster { return c.cluster } + +func (c *HandlerExecutor) Execute(ctx context.Context, index string, query *pql.Query, slices []uint64, opt *pilosa.ExecOptions) ([]interface{}, error) { + return c.ExecuteFn(ctx, index, query, slices, opt) +} + +// Host returns the hostname of the running server. +func (s *Server) Host() string { return MustParseURLHost(s.URL) } + +// MustParseURLHost parses rawurl and returns the hostname. Panic on error. +func MustParseURLHost(rawurl string) string { + u, err := url.Parse(rawurl) + if err != nil { + panic(err) + } + return u.Host +} + +func NewCluster(n int) *pilosa.Cluster { + c := pilosa.NewCluster() + c.ReplicaN = 1 + c.Hasher = NewModHasher() + + for i := 0; i < n; i++ { + c.Nodes = append(c.Nodes, &pilosa.Node{ + Host: fmt.Sprintf("host%d", i), + }) + } + + return c +} + +// ModHasher represents a simple, mod-based hashing. +type ModHasher struct{} + +// NewModHasher returns a new instance of ModHasher with n buckets. +func NewModHasher() *ModHasher { return &ModHasher{} } + +func (*ModHasher) Hash(key uint64, n int) int { return int(key) % n } + +// ConstHasher represents hash that always returns the same index. +type ConstHasher struct { + i int +} + +// NewConstHasher returns a new instance of ConstHasher that always returns i. +func NewConstHasher(i int) *ConstHasher { return &ConstHasher{i: i} } + +func (h *ConstHasher) Hash(key uint64, n int) int { return h.i } + +// Holder is a test wrapper for pilosa.Holder. +type Holder struct { + *pilosa.Holder + LogOutput bytes.Buffer +} + +// NewHolder returns a new instance of Holder with a temporary path. +func NewHolder() *Holder { + path, err := ioutil.TempDir("", "pilosa-") + if err != nil { + panic(err) + } + + h := &Holder{Holder: pilosa.NewHolder()} + h.Path = path + h.Holder.LogOutput = &h.LogOutput + + return h +} + +// MustOpenHolder creates and opens a holder at a temporary path. Panic on error. +func MustOpenHolder() *Holder { + h := NewHolder() + if err := h.Open(); err != nil { + panic(err) + } + return h +} diff --git a/ctl/bench_test.go b/ctl/bench_test.go new file mode 100644 index 000000000..c607e3301 --- /dev/null +++ b/ctl/bench_test.go @@ -0,0 +1,86 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "context" + "fmt" + "github.com/pilosa/pilosa" + "io" + "os" + "testing" +) + +func TestBenchCommand_InvalidOption(t *testing.T) { + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + + cm := NewBenchCommand(stdin, stdout, stderr) + err := cm.Run(context.Background()) + if err != pilosa.ErrHostRequired { + t.Fatalf("Expect err: %s, actual err: %s", pilosa.ErrHostRequired, err) + } + + cm.Host = "localhost:10101" + err = cm.Run(context.Background()) + if err.Error() != "op required" { + t.Fatalf("Expect err: %s, actual err: %s", "op required", err) + } + + cm.Op = "test" + err = cm.Run(context.Background()) + if err.Error() != "unknown bench op: \"test\"" { + t.Fatalf("Expect err: %s, actual err: %s", "unknown bench op: test", err) + } + +} + +func TestBenchCommand_Run(t *testing.T) { + rder := []byte{} + stdin := bytes.NewReader(rder) + r, w, _ := os.Pipe() + + cm := NewBenchCommand(stdin, w, w) + cm.Op = "set-bit" + cm.Host = "localhost:10101" + + err := cm.Run(context.Background()) + if err.Error() != "operation count required" { + t.Fatalf("Expect error: %s, actual err: %s", "operation count required", err) + } + + cm.N = 1 + err = cm.Run(context.Background()) + if err != pilosa.ErrIndexRequired { + t.Fatalf("Expect error: %s, actual err: %s", pilosa.ErrIndexRequired, err) + } + + cm.Index = "i" + err = cm.Run(context.Background()) + if err != pilosa.ErrFrameRequired { + t.Fatalf("Expect error: %s, actual err: %s", pilosa.ErrFrameRequired, err) + } + + cm.Frame = "f" + err = cm.Run(context.Background()) + w.Close() + var buf bytes.Buffer + io.Copy(&buf, r) + fmt.Println(buf.String()) + if err != nil { + fmt.Println(buf.String()) + } +} diff --git a/ctl/check_test.go b/ctl/check_test.go new file mode 100644 index 000000000..af223c18d --- /dev/null +++ b/ctl/check_test.go @@ -0,0 +1,98 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "encoding/hex" + "golang.org/x/net/context" + "io" + "io/ioutil" + "math/rand" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestCheckCommand_RunCacheFile(t *testing.T) { + cacheFile := TempFileName("test", ".cache") + + rder := []byte{} + stdin := bytes.NewReader(rder) + r, w, _ := os.Pipe() + cm := NewCheckCommand(stdin, w, w) + cm.Paths = []string{cacheFile} + + err := cm.Run(context.Background()) + w.Close() + var buf bytes.Buffer + io.Copy(&buf, r) + + if !strings.Contains(buf.String(), "ignoring cache file") { + t.Fatalf("expect: ignoring cache file, actual: '%s'", err) + } +} + +func TestCheckCommand_RunSnapshot(t *testing.T) { + snapshotFile := TempFileName("test", ".snapshotting") + + rder := []byte{} + stdin := bytes.NewReader(rder) + r, w, _ := os.Pipe() + cm := NewCheckCommand(stdin, w, w) + cm.Paths = []string{snapshotFile} + + err := cm.Run(context.Background()) + w.Close() + var buf bytes.Buffer + io.Copy(&buf, r) + + if !strings.Contains(buf.String(), "ignoring snapshot file") { + t.Fatalf("expect: ignoring snapshot file, actual: '%s'", err) + } +} + +func TestCheckCommand_Run(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatal(err) + } + file.Write([]byte("1234,1223")) + file.Close() + + rder := []byte{} + stdin := bytes.NewReader(rder) + r, w, _ := os.Pipe() + cm := NewCheckCommand(stdin, w, w) + cm.Paths = []string{file.Name()} + + err = cm.Run(context.Background()) + w.Close() + var buf bytes.Buffer + io.Copy(&buf, r) + + if err.Error() != "invalid roaring file" { + t.Fatalf("expect error: invalid roaring file, actual: '%s'", err) + } + // Todo: need correct roaring file for happy path +} + +// TempFileName generates a temporary filename with extension +func TempFileName(prefix, suffix string) string { + randBytes := make([]byte, 16) + rand.Read(randBytes) + return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+suffix) +} diff --git a/ctl/config_test.go b/ctl/config_test.go new file mode 100644 index 000000000..a3bd035ac --- /dev/null +++ b/ctl/config_test.go @@ -0,0 +1,44 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "context" + "github.com/pilosa/pilosa" + "io" + "os" + "strings" + "testing" +) + +func TestConfigCommand_Run(t *testing.T) { + rder := []byte{} + stdin := bytes.NewReader(rder) + r, w, _ := os.Pipe() + cm := NewConfigCommand(stdin, w, os.Stderr) + cm.Config = pilosa.NewConfig() + + err := cm.Run(context.Background()) + w.Close() + var buf bytes.Buffer + io.Copy(&buf, r) + + if err != nil { + t.Fatalf("Config Run doesn't work: %s", err) + } else if !strings.Contains(buf.String(), pilosa.DefaultHost) { + t.Fatalf("Unexpected config: %s", buf.String()) + } +} diff --git a/ctl/export_test.go b/ctl/export_test.go new file mode 100644 index 000000000..20fef5cea --- /dev/null +++ b/ctl/export_test.go @@ -0,0 +1,76 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "github.com/pilosa/pilosa" + "golang.org/x/net/context" + "net/http" + "strings" + "testing" +) + +func TestExportCommand_Validation(t *testing.T) { + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + + cm := NewExportCommand(stdin, stdout, stderr) + + err := cm.Run(context.Background()) + if err != pilosa.ErrIndexRequired { + t.Fatalf("Command not working, expect: %s, actual: '%s'", pilosa.ErrIndexRequired, err) + } + + cm.Index = "i" + err = cm.Run(context.Background()) + if err != pilosa.ErrFrameRequired { + t.Fatalf("Command not working, expect: %s, actual: '%s'", pilosa.ErrFrameRequired, err) + } + + cm.Frame = "f" + cm.View = "test" + err = cm.Run(context.Background()) + if err != pilosa.ErrInvalidView { + t.Fatalf("Command not working, expect: %s, actual: '%s'", pilosa.ErrInvalidView, err) + } +} + +func TestExportCommand_Run(t *testing.T) { + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + cm := NewExportCommand(stdin, stdout, stderr) + + hldr := MustOpenHolder() + defer hldr.Close() + s := NewServer() + defer s.Close() + s.Handler.Host = s.Host() + s.Handler.Cluster = NewCluster(1) + s.Handler.Cluster.Nodes[0].Host = s.Host() + s.Handler.Holder = hldr.Holder + cm.Host = s.Host() + + http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/index/i", strings.NewReader(""))) + http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/index/i/frame/f", strings.NewReader(""))) + + cm.Index = "i" + cm.Frame = "f" + cm.View = pilosa.ViewStandard + err := cm.Run(context.Background()) + if err != nil { + t.Fatalf("Export Run doesn't work: %s", err) + } +} diff --git a/ctl/generate_config_test.go b/ctl/generate_config_test.go new file mode 100644 index 000000000..801ab4055 --- /dev/null +++ b/ctl/generate_config_test.go @@ -0,0 +1,41 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "context" + "github.com/pilosa/pilosa" + "io" + "os" + "strings" + "testing" +) + +func TestGenerateConfigCommand_Run(t *testing.T) { + rder := []byte{} + stdin := bytes.NewReader(rder) + r, w, _ := os.Pipe() + cm := NewGenerateConfigCommand(stdin, w, os.Stderr) + err := cm.Run(context.Background()) + w.Close() + var buf bytes.Buffer + io.Copy(&buf, r) + if err != nil { + t.Fatalf("Config Run doesn't work: %s", err) + } else if !strings.Contains(buf.String(), pilosa.DefaultHost) { + t.Fatalf("Unexpected config: %s", buf.String()) + } +} diff --git a/ctl/import.go b/ctl/import.go index 55337d980..3b4a74d9d 100644 --- a/ctl/import.go +++ b/ctl/import.go @@ -59,10 +59,6 @@ func NewImportCommand(stdin io.Reader, stdout, stderr io.Writer) *ImportCommand } } -func (cmd *ImportCommand) String() string { - return fmt.Sprint(*cmd) -} - // Run executes the main program execution. func (cmd *ImportCommand) Run(ctx context.Context) error { logger := log.New(cmd.Stderr, "", log.LstdFlags) diff --git a/ctl/import_test.go b/ctl/import_test.go new file mode 100644 index 000000000..e80a0ce5c --- /dev/null +++ b/ctl/import_test.go @@ -0,0 +1,145 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "github.com/pilosa/pilosa" + "golang.org/x/net/context" + "io" + "io/ioutil" + "net/http" + "strings" + "testing" +) + +func TestImportCommand_Validation(t *testing.T) { + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + cm := NewImportCommand(stdin, stdout, stderr) + err := cm.Run(context.Background()) + if err != pilosa.ErrIndexRequired { + t.Fatalf("Command not working, expect: %s, actual: '%s'", pilosa.ErrIndexRequired, err) + } + + cm.Index = "i" + err = cm.Run(context.Background()) + if err != pilosa.ErrFrameRequired { + t.Fatalf("Command not working, expect: %s, actual: '%s'", pilosa.ErrFrameRequired, err) + } + + cm.Frame = "f" + err = cm.Run(context.Background()) + if err.Error() != "path required" { + t.Fatalf("Command not working, expect: %s, actual: '%s'", "path required", err) + } +} + +func TestImportCommand_Run(t *testing.T) { + + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + cm := NewImportCommand(stdin, stdout, stderr) + file, err := ioutil.TempFile("", "import.csv") + file.Write([]byte("1,2\n3,4\n5,6")) + ctx := context.Background() + if err != nil { + t.Fatal(err) + } + + hldr := MustOpenHolder() + defer hldr.Close() + s := NewServer() + defer s.Close() + s.Handler.Host = s.Host() + s.Handler.Cluster = NewCluster(1) + s.Handler.Cluster.Nodes[0].Host = s.Host() + s.Handler.Holder = hldr.Holder + cm.Host = s.Host() + + http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/index/i", strings.NewReader(""))) + http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/index/i/frame/f", strings.NewReader(""))) + + cm.Index = "i" + cm.Frame = "f" + cm.Paths = []string{file.Name()} + err = cm.Run(ctx) + if err != nil { + t.Fatalf("Import Run doesn't work: %s", err) + } +} + +func TestImportCommand_InvalidFile(t *testing.T) { + + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + cm := NewImportCommand(stdin, stdout, stderr) + cm.Host = pilosa.DefaultHost + cm.Index = "i" + cm.Frame = "f" + file, err := ioutil.TempFile("", "import.csv") + file.Write([]byte("a,2\n3,5\n5,6")) + if err != nil { + t.Fatal(err) + } + cm.Paths = []string{file.Name()} + err = cm.Run(context.Background()) + if !strings.Contains(err.Error(), "invalid row id on row") { + t.Fatalf("expect error: invalid row id on row, actual: %s", err) + } + + file, err = ioutil.TempFile("", "import1.csv") + file.Write([]byte("1,\n3,\n5,6")) + if err != nil { + t.Fatal(err) + } + cm.Paths = []string{file.Name()} + err = cm.Run(context.Background()) + if !strings.Contains(err.Error(), "invalid column id on row") { + t.Fatalf("expect error: invalid column id on row, actual: %s", err) + } + + file, err = ioutil.TempFile("", "import1.csv") + file.Write([]byte("1,2,34343\n1,3,54565,\n5,6,565")) + if err != nil { + t.Fatal(err) + } + cm.Paths = []string{file.Name()} + err = cm.Run(context.Background()) + if !strings.Contains(err.Error(), "invalid timestamp on row") { + t.Fatalf("expect error: invalid timestamp on row, actual: %s", err) + } + + file, err = ioutil.TempFile("", "import1.csv") + file.Write([]byte("1\n3\n5")) + if err != nil { + t.Fatal(err) + } + cm.Paths = []string{file.Name()} + err = cm.Run(context.Background()) + if !strings.Contains(err.Error(), "bad column count on row") { + t.Fatalf("expect error: bad column count on row, actual: %s", err) + } + +} + +// MustNewHTTPRequest creates a new HTTP request. Panic on error. +func MustNewHTTPRequest(method, urlStr string, body io.Reader) *http.Request { + req, err := http.NewRequest(method, urlStr, body) + if err != nil { + panic(err) + } + return req +} diff --git a/ctl/inspect_test.go b/ctl/inspect_test.go new file mode 100644 index 000000000..5cf34481d --- /dev/null +++ b/ctl/inspect_test.go @@ -0,0 +1,47 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "context" + "io" + "io/ioutil" + "os" + "strings" + "testing" +) + +func TestInspectCommand_Run(t *testing.T) { + rder := []byte{} + stdin := bytes.NewReader(rder) + r, w, _ := os.Pipe() + + cm := NewInspectCommand(stdin, w, w) + file, err := ioutil.TempFile("", "inspectTest") + file.Write([]byte("12358267538963")) + file.Close() + cm.Path = file.Name() + err = cm.Run(context.Background()) + + w.Close() + var buf bytes.Buffer + io.Copy(&buf, r) + if !strings.Contains(buf.String(), "unmarshaling bitmap...") { + t.Fatalf("Inspect doesn't work: %s", err) + } + + // Todo: need correct roaring file for happy path +} diff --git a/ctl/restore_test.go b/ctl/restore_test.go new file mode 100644 index 000000000..093ded22f --- /dev/null +++ b/ctl/restore_test.go @@ -0,0 +1,73 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bufio" + "bytes" + "github.com/pilosa/pilosa" + "golang.org/x/net/context" + "io" + "io/ioutil" + "testing" +) + +func TestRestoreCommand_FileRequired(t *testing.T) { + cm := RestoreCommand{} + ctx := context.Background() + err := cm.Run(ctx) + if err.Error() != "backup file required" { + t.Fatalf("expect error: output file required, actual: '%s'", err) + } +} + +func TestRestoreCommand_Run(t *testing.T) { + file, err := ioutil.TempFile("", "restore.csv") + if err != nil { + t.Fatal(err) + } + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + + hldr := MustOpenHolder() + defer hldr.Close() + + s := NewServer() + defer s.Close() + s.Handler.Host = s.Host() + s.Handler.Cluster = NewCluster(1) + s.Handler.Cluster.Nodes[0].Host = s.Host() + s.Handler.Holder = hldr.Holder + + cm := NewRestoreCommand(stdin, stdout, stderr) + cm.Path = file.Name() + cm.Index = "i" + cm.Frame = "f" + cm.View = pilosa.ViewStandard + cm.Host = s.Host() + cm.Run(context.Background()) + if err != nil { + t.Fatalf("Backup Run doesn't work: %s", err) + } +} + +// declare stdin, stdout, stderr +func GetIO(buf bytes.Buffer) (io.Reader, io.Writer, io.Writer) { + rder := []byte{} + stdin := bytes.NewReader(rder) + stdout := bufio.NewWriter(&buf) + stderr := bufio.NewWriter(&buf) + return stdin, stdout, stderr +} diff --git a/ctl/server_test.go b/ctl/server_test.go new file mode 100644 index 000000000..b39c894b1 --- /dev/null +++ b/ctl/server_test.go @@ -0,0 +1,39 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "github.com/pilosa/pilosa/server" + "github.com/spf13/cobra" + "testing" +) + +func TestBuildServerFlags(t *testing.T) { + cm := &cobra.Command{} + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + Server := server.NewCommand(stdin, stdout, stderr) + BuildServerFlags(cm, Server) + if cm.Flags().Lookup("cluster.internal-port").Name == "" { + t.Fatal("cluster.internal-port flag is missed ") + } + if cm.Flags().Lookup("data-dir").Name == "" { + t.Fatal("data-dir flag is missed ") + } + if cm.Flags().Lookup("log-path").Name == "" { + t.Fatal("log-path is missed ") + } +} diff --git a/ctl/sort_test.go b/ctl/sort_test.go new file mode 100644 index 000000000..1f12a5220 --- /dev/null +++ b/ctl/sort_test.go @@ -0,0 +1,83 @@ +// Copyright 2017 Pilosa Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ctl + +import ( + "bytes" + "golang.org/x/net/context" + "io" + "io/ioutil" + "os" + "strings" + "testing" +) + +func TestSortCommand_Run(t *testing.T) { + file, _ := ioutil.TempFile("", "file.csv") + content := "3,3\n1,2\n2,4" + file.Write([]byte(content)) + file.Close() + + rder := []byte{} + stdin := bytes.NewReader(rder) + r, w, _ := os.Pipe() + + cm := NewSortCommand(stdin, w, w) + cm.Path = file.Name() + err := cm.Run(context.Background()) + w.Close() + var buf bytes.Buffer + io.Copy(&buf, r) + if err != nil { + t.Fatal(err) + } else if !strings.Contains(buf.String(), "1,2\n2,4\n3,3") { + t.Fatalf("File is not sorted, actual result: %s", buf.String()) + } +} + +func TestSortCommand_InvalidFile(t *testing.T) { + buf := bytes.Buffer{} + stdin, stdout, stderr := GetIO(buf) + file, _ := ioutil.TempFile("", "file.csv") + file.Write([]byte("3,3\na,8\n2,4")) + file.Close() + + cm := NewSortCommand(stdin, stdout, stderr) + cm.Path = file.Name() + err := cm.Run(context.Background()) + if !strings.Contains(err.Error(), "invalid row id") { + t.Fatalf("expect err: invalid row id, actual: %s", err) + + } + + file, _ = ioutil.TempFile("", "file.csv") + file.Write([]byte("3,3\n1,a\n2,4")) + file.Close() + cm.Path = file.Name() + err = cm.Run(context.Background()) + if !strings.Contains(err.Error(), "invalid column id") { + t.Fatalf("expect err: invalid column id, actual: %s", err) + + } + + file, _ = ioutil.TempFile("", "file.csv") + file.Write([]byte("3,3,1234\n1,2,34345\n2,4")) + file.Close() + cm.Path = file.Name() + err = cm.Run(context.Background()) + if !strings.Contains(err.Error(), "invalid timestamp") { + t.Fatalf("expect err: invalid timestamp, actual: %s", err) + } +}