settings_test.go
3542 bytes
1package cmd
2
3import (
4 "bytes"
5 "context"
6 "strings"
7 "testing"
8
9 "github.com/charmbracelet/soft-serve/pkg/access"
10 "github.com/charmbracelet/soft-serve/pkg/backend"
11 "github.com/charmbracelet/soft-serve/pkg/config"
12 "github.com/charmbracelet/soft-serve/pkg/db"
13 "github.com/charmbracelet/soft-serve/pkg/db/migrate"
14 "github.com/charmbracelet/soft-serve/pkg/proto"
15 "github.com/charmbracelet/soft-serve/pkg/store"
16 "github.com/charmbracelet/soft-serve/pkg/store/database"
17 "github.com/matryer/is"
18 _ "modernc.org/sqlite"
19)
20
21// newSettingsTestContext returns a context wired with a config, a real
22// migrated SQLite-backed backend, and an authenticated admin user, ready to
23// execute SettingsCommand() against. Returns the config too, so tests can
24// mutate AnonAccess/AllowKeyless to simulate a config override.
25func newSettingsTestContext(t *testing.T) (context.Context, *config.Config) {
26 t.Helper()
27 is := is.New(t)
28 ctx := context.Background()
29
30 dp := t.TempDir()
31 cfg := config.DefaultConfig()
32 cfg.DataPath = dp
33 cfg.DB.Driver = "sqlite"
34 cfg.DB.DataSource = dp + "/test.db"
35
36 ctx = config.WithContext(ctx, cfg)
37 dbx, err := db.Open(ctx, cfg.DB.Driver, cfg.DB.DataSource)
38 is.NoErr(err)
39 t.Cleanup(func() { dbx.Close() }) //nolint:errcheck
40
41 is.NoErr(migrate.Migrate(ctx, dbx))
42 dbstore := database.New(ctx, dbx)
43 ctx = store.WithContext(ctx, dbstore)
44 be := backend.New(ctx, cfg, dbx, dbstore)
45 ctx = backend.WithContext(ctx, be)
46
47 // "admin" is already taken by the default user the migration seeds, so
48 // use a distinct username for the test's admin.
49 admin, err := be.CreateUser(ctx, "testadmin", proto.UserOptions{Admin: true})
50 is.NoErr(err)
51 ctx = proto.WithUserContext(ctx, admin)
52
53 return ctx, cfg
54}
55
56func runSettings(t *testing.T, ctx context.Context, args ...string) (stdout, stderr string, err error) {
57 t.Helper()
58 c := SettingsCommand()
59 var outBuf, errBuf bytes.Buffer
60 c.SetOut(&outBuf)
61 c.SetErr(&errBuf)
62 c.SetArgs(args)
63 err = c.ExecuteContext(ctx)
64 return outBuf.String(), errBuf.String(), err
65}
66
67func TestSettingsAnonAccessWarnsOnConfigOverride(t *testing.T) {
68 is := is.New(t)
69 ctx, cfg := newSettingsTestContext(t)
70
71 // No override active: setting anon-access should succeed silently.
72 _, stderr, err := runSettings(t, ctx, "anon-access", "read-write")
73 is.NoErr(err)
74 is.Equal(stderr, "")
75
76 // With a config override active, the write still succeeds (so it takes
77 // effect if the override is later removed), but must warn loudly that
78 // it currently has no effect.
79 adminAccess := access.AdminAccess
80 cfg.AnonAccess = &adminAccess
81 _, stderr, err = runSettings(t, ctx, "anon-access", "no-access")
82 is.NoErr(err)
83 if !strings.Contains(stderr, "override") {
84 t.Fatalf("expected override warning on stderr, got: %q", stderr)
85 }
86}
87
88func TestSettingsAllowKeylessWarnsOnConfigOverride(t *testing.T) {
89 is := is.New(t)
90 ctx, cfg := newSettingsTestContext(t)
91
92 // No override active: setting allow-keyless should succeed silently.
93 _, stderr, err := runSettings(t, ctx, "allow-keyless", "false")
94 is.NoErr(err)
95 is.Equal(stderr, "")
96
97 // With a config override active, the write still succeeds, but must
98 // warn that it currently has no effect. This is the dangerous
99 // direction: an admin trying to lock things down (false) while a
100 // config override forces it open (true).
101 allow := true
102 cfg.AllowKeyless = &allow
103 _, stderr, err = runSettings(t, ctx, "allow-keyless", "false")
104 is.NoErr(err)
105 if !strings.Contains(stderr, "override") {
106 t.Fatalf("expected override warning on stderr, got: %q", stderr)
107 }
108}