all repos — postern

@ 9799a3215ac0185fb9b4e7d6ec0645c2cb2ce55b

Modern mail management

clone
git clone https:///postern.git

internal/cli/admin_test.go (view raw)

  1package cli
  2
  3import (
  4	"bytes"
  5	"crypto/rand"
  6	"log"
  7	"os"
  8	"path"
  9	"strings"
 10	"testing"
 11	"time"
 12
 13	"postern/internal/db"
 14	"postern/internal/persistence"
 15
 16	"github.com/spf13/cobra"
 17)
 18
 19// executeCommand helps invoke a cobra command with specific arguments and captures its stdout/stderr.
 20func executeCommand(cmd *cobra.Command, args ...string) (string, error) {
 21	buf := new(bytes.Buffer)
 22	cmd.SetOut(buf)
 23	cmd.SetErr(buf)
 24	cmd.SetArgs(args)
 25
 26	err := cmd.Execute()
 27	return buf.String(), err
 28}
 29
 30// TestAddUserCommand checks the loop of creating a new user, finding it in the db and checking that the password works.
 31func TestAddRemoveUserCommand(t *testing.T) {
 32	f := t.TempDir()
 33
 34	// create temporary masterkey
 35	mkeyPath := path.Join(f, "masterkey")
 36	secretKey := make([]byte, 32)
 37	_, _ = rand.Read(secretKey)
 38	err := os.WriteFile(mkeyPath, secretKey, 0666)
 39	if err != nil {
 40		t.Fatal(err)
 41	}
 42
 43	p, err := persistence.New(persistence.Config{
 44		BlobRoot:      path.Join(f, "blobs"),
 45		MasterkeyFile: mkeyPath,
 46	})
 47	if err != nil {
 48		log.Fatal(err)
 49	}
 50
 51	posternDB, err := db.OpenDB(&db.Config{
 52		DBPath: path.Join(f, "meta.db"),
 53	})
 54	if err != nil {
 55		log.Fatal(err)
 56	}
 57
 58	c, err := New(&Config{
 59		DB:          posternDB,
 60		Persistence: p,
 61	})
 62	if err != nil {
 63		t.Fatal(err)
 64	}
 65
 66	// Start HTTP service on a temp socket for the test
 67	tempSocket := path.Join(f, "test.sock")
 68	c.socketPath = tempSocket
 69	c.httpClient = newUnixHTTPClient(tempSocket)
 70
 71	// Start the HTTP service in background
 72	service := NewHTTPService(tempSocket, c)
 73	go func() {
 74		_ = service.Start()
 75	}()
 76
 77	timeout := time.After(10 * time.Second)
 78	ticker := time.NewTicker(100 * time.Millisecond)
 79	defer ticker.Stop()
 80
 81	for service.Status() != "running" {
 82		select {
 83		case <-timeout:
 84			t.Fatal("timed out waiting for http service to start")
 85		case <-ticker.C:
 86			// Wait for next tick
 87		}
 88	}
 89
 90	// Run the cobra command
 91	output, err := executeCommand(c.rootCmd(), "user", "add", "user1")
 92	if err != nil {
 93		t.Fatalf("expected no error, got: %v", err)
 94	}
 95
 96	_, after, found := strings.Cut(output, "Password: ")
 97	password := strings.TrimSpace(after)
 98	if !found {
 99		t.Fatal("expected to find a password in output. Found none")
100	}
101
102	// Test that the user was created by directly accessing the DB
103	u, err := c.db.GetUser(t.Context(), "user1")
104	if err != nil {
105		t.Fatalf("expected no error, got: %v", err)
106	}
107
108	err = u.VerifyPassword([]byte(password))
109	if err != nil {
110		t.Fatalf("password mismatch, got: %v", err)
111	}
112
113	// Try removing user
114	output, err = executeCommand(c.rootCmd(), "user", "remove", "user1")
115	if err != nil {
116		t.Fatalf("expected no error, got: %v", err)
117	}
118	if !strings.Contains(output, "removed") {
119		t.Fatal("expected to find 'removed' in output. Found none")
120	}
121
122	// Try removing user again (failure)
123	_, err = executeCommand(c.rootCmd(), "user", "remove", "user1")
124	if err == nil {
125		t.Errorf("expected error when deleting non-existing user, got none")
126	}
127
128	// Clean up
129	_ = service.Stop()
130}