128 lines
4.1 KiB
Go
128 lines
4.1 KiB
Go
package command
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gochat/gochat/channels/shangwutong/internal/store"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func TestRootCommandExposesOnlyPlannedOperations(t *testing.T) {
|
|
root := NewRootCommand()
|
|
want := map[string]bool{"serve": false, "migrate": false, "reconcile": false, "backup": false, "doctor": false}
|
|
for _, command := range root.Commands() {
|
|
if _, ok := want[command.Name()]; ok {
|
|
want[command.Name()] = true
|
|
}
|
|
}
|
|
for name, found := range want {
|
|
if !found {
|
|
t.Fatalf("missing command %s", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBackupRequiresOutput(t *testing.T) {
|
|
root := NewRootCommand()
|
|
root.SetArgs([]string{"backup"})
|
|
root.SetOut(&bytes.Buffer{})
|
|
if err := root.Execute(); err == nil || !strings.Contains(err.Error(), "--output is required") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMigrateRejectsUnknownAction(t *testing.T) {
|
|
t.Setenv("SWT_CONNECTOR_DB_PATH", filepath.Join(t.TempDir(), "connector.db"))
|
|
root := NewRootCommand()
|
|
root.SetArgs([]string{"migrate", "down"})
|
|
if err := root.Execute(); err == nil || !strings.Contains(err.Error(), "unsupported migration action") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLocalAdminURLUsesLoopbackForWildcardListen(t *testing.T) {
|
|
got, err := localAdminURL(":9200")
|
|
if err != nil || got != "http://127.0.0.1:9200" {
|
|
t.Fatalf("URL = %q, %v", got, err)
|
|
}
|
|
}
|
|
|
|
func TestStartupReconcileRetriesUntilFirstCompleteSnapshot(t *testing.T) {
|
|
attempts := 0
|
|
logger := logrus.New()
|
|
logger.SetOutput(io.Discard)
|
|
reconcileUntilSuccessful(context.Background(), func(context.Context) error {
|
|
attempts++
|
|
if attempts == 1 {
|
|
return errors.New("GoChat unavailable")
|
|
}
|
|
return nil
|
|
}, logrus.NewEntry(logger), time.Millisecond)
|
|
if attempts != 2 {
|
|
t.Fatalf("attempts = %d", attempts)
|
|
}
|
|
}
|
|
|
|
func TestOperationalCommands(t *testing.T) {
|
|
directory := t.TempDir()
|
|
databasePath, backupPath := filepath.Join(directory, "connector.db"), filepath.Join(directory, "backup.db")
|
|
t.Setenv("SWT_CONNECTOR_DB_PATH", databasePath)
|
|
for _, args := range [][]string{{"migrate", "up"}, {"migrate", "status"}, {"backup", "--output", backupPath}} {
|
|
root, output := NewRootCommand(), &bytes.Buffer{}
|
|
root.SetArgs(args)
|
|
root.SetOut(output)
|
|
if err := root.Execute(); err != nil {
|
|
t.Fatalf("%v: %v", args, err)
|
|
}
|
|
if output.Len() == 0 {
|
|
t.Fatalf("%v produced no output", args)
|
|
}
|
|
}
|
|
if version, err := store.InspectDatabase(context.Background(), backupPath); err != nil || version != 8 {
|
|
t.Fatalf("backup version = %d, %v", version, err)
|
|
}
|
|
|
|
goChat := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
|
if request.URL.Path != "/api/v1/connector/shangwutong/inboxes" || request.Header.Get("Authorization") != "Bearer service-token" {
|
|
http.Error(response, "unexpected request", http.StatusBadRequest)
|
|
return
|
|
}
|
|
response.Header().Set("Content-Type", "application/json")
|
|
_, _ = io.WriteString(response, `{"data":[],"next_cursor":""}`)
|
|
}))
|
|
defer goChat.Close()
|
|
t.Setenv("GOCHAT_BASE_URL", goChat.URL)
|
|
t.Setenv("GOCHAT_CONNECTOR_SERVICE_TOKEN", "service-token")
|
|
root, output := NewRootCommand(), &bytes.Buffer{}
|
|
root.SetArgs([]string{"doctor"})
|
|
root.SetOut(output)
|
|
if err := root.Execute(); err != nil || !strings.Contains(output.String(), "inboxes=0") {
|
|
t.Fatalf("doctor output=%q err=%v", output.String(), err)
|
|
}
|
|
|
|
reconcile := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
|
if request.Method != http.MethodPost || request.URL.Path != "/internal/reconcile" {
|
|
http.Error(response, "unexpected request", http.StatusBadRequest)
|
|
return
|
|
}
|
|
response.WriteHeader(http.StatusAccepted)
|
|
}))
|
|
defer reconcile.Close()
|
|
t.Setenv("SWT_CONNECTOR_LISTEN", strings.TrimPrefix(reconcile.URL, "http://"))
|
|
root, output = NewRootCommand(), &bytes.Buffer{}
|
|
root.SetArgs([]string{"reconcile"})
|
|
root.SetOut(output)
|
|
if err := root.Execute(); err != nil || !strings.Contains(output.String(), "reconcile accepted") {
|
|
t.Fatalf("reconcile output=%q err=%v", output.String(), err)
|
|
}
|
|
}
|