a37cd6c4be472da306899a0db9801ed81403980e

Author
Matthew Greenwald <mdgreenwald@gmail.com>
Committer
Christian Rocha <christian@rocha.is>
Date

Message

test: adding test coverage for new feature

Signed-off-by: Matthew Greenwald <mdgreenwald@gmail.com>

Diff

  1diff --git a/cmd/soft/serve/server_test.go b/cmd/soft/serve/server_test.go
  2new file mode 100644
  3index 0000000000000000000000000000000000000000..ce7c9745094e1fb1672f008181dfc3a79bca2172
  4--- /dev/null
  5+++ b/cmd/soft/serve/server_test.go
  6@@ -0,0 +1,80 @@
  7+package serve
  8+
  9+import (
 10+	"bytes"
 11+	"context"
 12+	"strings"
 13+	"testing"
 14+
 15+	"charm.land/log/v2"
 16+	"github.com/charmbracelet/soft-serve/pkg/access"
 17+	"github.com/charmbracelet/soft-serve/pkg/backend"
 18+	"github.com/charmbracelet/soft-serve/pkg/config"
 19+	"github.com/charmbracelet/soft-serve/pkg/db"
 20+	"github.com/charmbracelet/soft-serve/pkg/db/migrate"
 21+	"github.com/charmbracelet/soft-serve/pkg/store"
 22+	"github.com/charmbracelet/soft-serve/pkg/store/database"
 23+	"github.com/matryer/is"
 24+	_ "modernc.org/sqlite"
 25+)
 26+
 27+// newTestBackend returns a Backend backed by a real, freshly migrated
 28+// SQLite database, along with the *config.Config it was constructed with,
 29+// so tests can set AnonAccess/AllowKeyless overrides directly.
 30+func newTestBackend(t *testing.T) (*backend.Backend, *config.Config) {
 31+	t.Helper()
 32+	is := is.New(t)
 33+	ctx := context.Background()
 34+
 35+	dp := t.TempDir()
 36+	cfg := config.DefaultConfig()
 37+	cfg.DataPath = dp
 38+	cfg.DB.Driver = "sqlite"
 39+	cfg.DB.DataSource = dp + "/test.db"
 40+
 41+	ctx = config.WithContext(ctx, cfg)
 42+	dbx, err := db.Open(ctx, cfg.DB.Driver, cfg.DB.DataSource)
 43+	is.NoErr(err)
 44+	t.Cleanup(func() { dbx.Close() }) //nolint:errcheck
 45+
 46+	is.NoErr(migrate.Migrate(ctx, dbx))
 47+	dbstore := database.New(ctx, dbx)
 48+	ctx = store.WithContext(ctx, dbstore)
 49+	be := backend.New(ctx, cfg, dbx, dbstore)
 50+
 51+	return be, cfg
 52+}
 53+
 54+func TestWarnIfAnonAdminAccess(t *testing.T) {
 55+	cases := []struct {
 56+		name         string
 57+		allowKeyless bool
 58+		anonAccess   access.AccessLevel
 59+		wantWarning  bool
 60+	}{
 61+		{"defaults: keyless disabled, read-only anon", false, access.ReadOnlyAccess, false},
 62+		{"keyless allowed but anon access below admin", true, access.ReadWriteAccess, false},
 63+		{"admin anon access but keyless disallowed", false, access.AdminAccess, false},
 64+		{"keyless allowed with admin anon access: the dangerous combo", true, access.AdminAccess, true},
 65+	}
 66+
 67+	for _, c := range cases {
 68+		t.Run(c.name, func(t *testing.T) {
 69+			is := is.New(t)
 70+			be, cfg := newTestBackend(t)
 71+			ctx := context.Background()
 72+
 73+			allow := c.allowKeyless
 74+			cfg.AllowKeyless = &allow
 75+			cfg.AnonAccess = c.anonAccess.String()
 76+
 77+			var buf bytes.Buffer
 78+			logger := log.New(&buf)
 79+
 80+			warnIfAnonAdminAccess(ctx, be, logger)
 81+
 82+			gotWarning := strings.Contains(buf.String(), "WARNING")
 83+			is.Equal(gotWarning, c.wantWarning)
 84+		})
 85+	}
 86+}
 87diff --git a/pkg/backend/repo_test.go b/pkg/backend/repo_test.go
 88new file mode 100644
 89index 0000000000000000000000000000000000000000..57851fab6f6794de1711ea4e50950af5609c0651
 90--- /dev/null
 91+++ b/pkg/backend/repo_test.go
 92@@ -0,0 +1,45 @@
 93+package backend
 94+
 95+import (
 96+	"context"
 97+	"testing"
 98+
 99+	"github.com/charmbracelet/soft-serve/pkg/db"
100+	"github.com/charmbracelet/soft-serve/pkg/proto"
101+	"github.com/matryer/is"
102+)
103+
104+// TestCreateRepositoryAnonymousOwner verifies that a repository created with
105+// a nil user (an anon-access/allow-keyless override) is owned by the
106+// lowest-ID admin rather than failing the NOT NULL repos.user_id constraint.
107+func TestCreateRepositoryAnonymousOwner(t *testing.T) {
108+	is := is.New(t)
109+	be, _ := newTestBackend(t)
110+	ctx := context.Background()
111+
112+	admin, err := be.User(ctx, "admin")
113+	is.NoErr(err)
114+
115+	repo, err := be.CreateRepository(ctx, "anon-repo", nil, proto.RepositoryOptions{})
116+	is.NoErr(err)
117+	is.Equal(repo.UserID(), admin.ID())
118+}
119+
120+// TestDefaultAdminUserIDNoAdmin verifies that defaultAdminUserID surfaces an
121+// error rather than silently returning a zero user ID (which would violate
122+// the NOT NULL repos.user_id constraint) when the database has no admin.
123+func TestDefaultAdminUserIDNoAdmin(t *testing.T) {
124+	is := is.New(t)
125+	be, _ := newTestBackend(t)
126+	ctx := context.Background()
127+
128+	err := be.db.TransactionContext(ctx, func(tx *db.Tx) error {
129+		if _, err := tx.ExecContext(ctx, "UPDATE users SET admin = false"); err != nil {
130+			return err
131+		}
132+
133+		_, err := be.defaultAdminUserID(ctx, tx)
134+		return err
135+	})
136+	is.True(err != nil)
137+}