Parent directory

user_test.go

4536 bytes
  1package backend
  2
  3import (
  4	"context"
  5	"errors"
  6	"os"
  7	"testing"
  8
  9	"github.com/charmbracelet/soft-serve/pkg/access"
 10	"github.com/charmbracelet/soft-serve/pkg/config"
 11	"github.com/charmbracelet/soft-serve/pkg/db"
 12	"github.com/charmbracelet/soft-serve/pkg/proto"
 13	"github.com/charmbracelet/soft-serve/pkg/store"
 14	"github.com/matryer/is"
 15)
 16
 17// TestAccessLevelCollaboratorPrivateRepo verifies that the anonymous access
 18// floor does not raise a collaborator's explicit level on a private
 19// repository, while still applying on public repositories.
 20func TestAccessLevelCollaboratorPrivateRepo(t *testing.T) {
 21	tests := []struct {
 22		name    string
 23		private bool
 24		anon    access.AccessLevel
 25		collab  access.AccessLevel
 26		want    access.AccessLevel
 27	}{
 28		{"private no-access collab, anon read-only", true, access.ReadOnlyAccess, access.NoAccess, access.NoAccess},
 29		{"private read-only collab, anon read-write", true, access.ReadWriteAccess, access.ReadOnlyAccess, access.ReadOnlyAccess},
 30		{"private read-write collab, anon read-only", true, access.ReadOnlyAccess, access.ReadWriteAccess, access.ReadWriteAccess},
 31		{"public no-access collab, anon read-only", false, access.ReadOnlyAccess, access.NoAccess, access.ReadOnlyAccess},
 32		{"public read-only collab, anon read-write", false, access.ReadWriteAccess, access.ReadOnlyAccess, access.ReadWriteAccess},
 33		{"public no-access collab, anon no-access", false, access.NoAccess, access.NoAccess, access.NoAccess},
 34	}
 35
 36	for _, tt := range tests {
 37		t.Run(tt.name, func(t *testing.T) {
 38			is := is.New(t)
 39			be, _ := newTestBackend(t)
 40			ctx := context.Background()
 41
 42			is.NoErr(be.SetAnonAccess(ctx, tt.anon))
 43
 44			_, err := be.CreateRepository(ctx, "repo", nil, proto.RepositoryOptions{Private: tt.private})
 45			is.NoErr(err)
 46
 47			user, err := be.CreateUser(ctx, "collab", proto.UserOptions{})
 48			is.NoErr(err)
 49			is.NoErr(be.db.TransactionContext(ctx, func(tx *db.Tx) error {
 50				return be.store.AddCollabByUsernameAndRepo(ctx, tx, "collab", "repo", tt.collab)
 51			}))
 52
 53			is.Equal(be.AccessLevelForUser(ctx, "repo", user), tt.want)
 54		})
 55	}
 56}
 57
 58// TestAccessLevelPrivateRepoNonCollaborator verifies that a signed-in user
 59// who is not a collaborator has no access to a private repository.
 60func TestAccessLevelPrivateRepoNonCollaborator(t *testing.T) {
 61	is := is.New(t)
 62	be, _ := newTestBackend(t)
 63	ctx := context.Background()
 64
 65	_, err := be.CreateRepository(ctx, "repo", nil, proto.RepositoryOptions{Private: true})
 66	is.NoErr(err)
 67
 68	user, err := be.CreateUser(ctx, "stranger", proto.UserOptions{})
 69	is.NoErr(err)
 70
 71	is.Equal(be.AccessLevelForUser(ctx, "repo", user), access.NoAccess)
 72	is.Equal(be.AccessLevelForUser(ctx, "repo", nil), access.NoAccess)
 73}
 74
 75// TestDeleteUserWithRepositories verifies that a user who owns
 76// repositories is not deleted until those repositories are gone, and that
 77// their repositories are left untouched by the refusal.
 78func TestDeleteUserWithRepositories(t *testing.T) {
 79	is := is.New(t)
 80	be, cfg := newTestBackend(t)
 81
 82	ctx := context.Background()
 83	ctx = config.WithContext(ctx, cfg)
 84	ctx = db.WithContext(ctx, be.db)
 85	ctx = store.WithContext(ctx, be.store)
 86	admin, err := be.User(ctx, "admin")
 87	is.NoErr(err)
 88	ctx = proto.WithUserContext(ctx, admin)
 89
 90	owner, err := be.CreateUser(ctx, "owner", proto.UserOptions{})
 91	is.NoErr(err)
 92	_, err = be.CreateRepository(ctx, "owned", owner, proto.RepositoryOptions{})
 93	is.NoErr(err)
 94
 95	err = be.DeleteUser(ctx, "owner")
 96	is.True(errors.Is(err, proto.ErrUserOwnsRepos))
 97	_, err = be.User(ctx, "owner")
 98	is.NoErr(err)
 99	_, err = be.Repository(ctx, "owned")
100	is.NoErr(err)
101
102	is.NoErr(be.DeleteRepository(ctx, "owned"))
103	is.NoErr(be.DeleteUser(ctx, "owner"))
104	_, err = be.User(ctx, "owner")
105	is.True(errors.Is(err, proto.ErrUserNotFound))
106
107	is.True(errors.Is(be.DeleteUser(ctx, "owner"), proto.ErrUserNotFound))
108}
109
110// TestDeleteRepositoryWithoutDirectory verifies that a repository whose
111// directory is gone can still be deleted, and that deleting a repository
112// that does not exist at all reports it as not found.
113func TestDeleteRepositoryWithoutDirectory(t *testing.T) {
114	is := is.New(t)
115	be, cfg := newTestBackend(t)
116
117	ctx := context.Background()
118	ctx = config.WithContext(ctx, cfg)
119	ctx = db.WithContext(ctx, be.db)
120	ctx = store.WithContext(ctx, be.store)
121
122	_, err := be.CreateRepository(ctx, "orphan", nil, proto.RepositoryOptions{})
123	is.NoErr(err)
124	is.NoErr(os.RemoveAll(be.repoPath("orphan")))
125
126	is.NoErr(be.DeleteRepository(ctx, "orphan"))
127	is.True(errors.Is(be.DeleteRepository(ctx, "orphan"), proto.ErrRepoNotFound))
128}