storj/satellite/satellitedb/projectinvitations_test.go

214 lines
6.4 KiB
Go
Raw Normal View History

// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.
package satellitedb_test
import (
"database/sql"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"storj.io/common/testcontext"
"storj.io/common/testrand"
"storj.io/storj/satellite"
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/satellitedb/satellitedbtest"
)
func TestProjectInvitations(t *testing.T) {
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
invitesDB := db.Console().ProjectInvitations()
projectsDB := db.Console().Projects()
inviterID := testrand.UUID()
projID := testrand.UUID()
projID2 := testrand.UUID()
email := "user@mail.test"
email2 := "user2@mail.test"
_, err := projectsDB.Insert(ctx, &console.Project{ID: projID})
require.NoError(t, err)
_, err = projectsDB.Insert(ctx, &console.Project{ID: projID2})
require.NoError(t, err)
invite := &console.ProjectInvitation{
ProjectID: projID,
Email: email,
InviterID: &inviterID,
}
inviteSameEmail := &console.ProjectInvitation{
ProjectID: projID2,
Email: email,
}
inviteSameProject := &console.ProjectInvitation{
ProjectID: projID,
Email: email2,
}
if !t.Run("insert invitations", func(t *testing.T) {
// Expect failure because no user with inviterID exists.
_, err = invitesDB.Insert(ctx, invite)
require.Error(t, err)
_, err = db.Console().Users().Insert(ctx, &console.User{
ID: inviterID,
PasswordHash: testrand.Bytes(8),
})
require.NoError(t, err)
invite, err = invitesDB.Insert(ctx, invite)
require.NoError(t, err)
require.WithinDuration(t, time.Now(), invite.CreatedAt, time.Minute)
require.Equal(t, projID, invite.ProjectID)
require.Equal(t, strings.ToUpper(email), invite.Email)
// Duplicate invitations should be rejected.
_, err = invitesDB.Insert(ctx, invite)
require.Error(t, err)
inviteSameEmail, err = invitesDB.Insert(ctx, inviteSameEmail)
require.NoError(t, err)
inviteSameProject, err = invitesDB.Insert(ctx, inviteSameProject)
require.NoError(t, err)
}) {
// None of the following subtests will pass if invitation insertion failed.
return
}
t.Run("get invitation", func(t *testing.T) {
ctx := testcontext.New(t)
other, err := invitesDB.Get(ctx, projID, "nobody@mail.test")
require.ErrorIs(t, err, sql.ErrNoRows)
require.Nil(t, other)
other, err = invitesDB.Get(ctx, projID, email)
require.NoError(t, err)
require.Equal(t, invite, other)
})
t.Run("get invitations by email", func(t *testing.T) {
ctx := testcontext.New(t)
invites, err := invitesDB.GetByEmail(ctx, "nobody@mail.test")
require.NoError(t, err)
require.Empty(t, invites)
invites, err = invitesDB.GetByEmail(ctx, "uSeR@mAiL.tEsT")
require.NoError(t, err)
require.ElementsMatch(t, invites, []console.ProjectInvitation{*invite, *inviteSameEmail})
})
t.Run("get invitations by project ID", func(t *testing.T) {
ctx := testcontext.New(t)
invites, err := invitesDB.GetByProjectID(ctx, testrand.UUID())
require.NoError(t, err)
require.Empty(t, invites)
invites, err = invitesDB.GetByProjectID(ctx, projID)
require.NoError(t, err)
require.ElementsMatch(t, invites, []console.ProjectInvitation{*invite, *inviteSameProject})
})
t.Run("ensure inviter removal nullifies inviter ID", func(t *testing.T) {
ctx := testcontext.New(t)
require.NoError(t, db.Console().Users().Delete(ctx, inviterID))
invite, err := invitesDB.Get(ctx, projID, email)
require.NoError(t, err)
require.Nil(t, invite.InviterID)
})
t.Run("update invitation", func(t *testing.T) {
ctx := testcontext.New(t)
req := console.UpdateProjectInvitationRequest{}
newCreatedAt := invite.CreatedAt.Add(time.Hour)
req.CreatedAt = &newCreatedAt
newInvite, err := invitesDB.Update(ctx, projID, email, req)
require.NoError(t, err)
require.Equal(t, newCreatedAt, newInvite.CreatedAt)
inviter, err := db.Console().Users().Insert(ctx, &console.User{
ID: testrand.UUID(),
PasswordHash: testrand.Bytes(8),
})
require.NoError(t, err)
req.InviterID = &inviter.ID
newInvite, err = invitesDB.Update(ctx, projID, email, req)
require.NoError(t, err)
require.Equal(t, inviter.ID, *newInvite.InviterID)
})
t.Run("delete invitation", func(t *testing.T) {
ctx := testcontext.New(t)
require.NoError(t, invitesDB.Delete(ctx, projID, email))
invites, err := invitesDB.GetByEmail(ctx, email)
require.NoError(t, err)
require.Equal(t, invites, []console.ProjectInvitation{*inviteSameEmail})
})
t.Run("ensure project removal deletes invitations", func(t *testing.T) {
ctx := testcontext.New(t)
require.NoError(t, projectsDB.Delete(ctx, projID))
invites, err := invitesDB.GetByProjectID(ctx, projID)
require.NoError(t, err)
require.Empty(t, invites)
invites, err = invitesDB.GetByEmail(ctx, email)
require.NoError(t, err)
require.Equal(t, invites, []console.ProjectInvitation{*inviteSameEmail})
})
})
}
func TestDeleteBefore(t *testing.T) {
maxAge := time.Hour
now := time.Now()
expiration := now.Add(-maxAge)
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
invitesDB := db.Console().ProjectInvitations()
// Only positive page sizes should be allowed.
require.Error(t, invitesDB.DeleteBefore(ctx, time.Time{}, 0, 0))
require.Error(t, invitesDB.DeleteBefore(ctx, time.Time{}, 0, -1))
createInvite := func() *console.ProjectInvitation {
projID := testrand.UUID()
_, err := db.Console().Projects().Insert(ctx, &console.Project{ID: projID})
require.NoError(t, err)
invite, err := invitesDB.Insert(ctx, &console.ProjectInvitation{ProjectID: projID})
require.NoError(t, err)
return invite
}
newInvite := createInvite()
oldInvite := createInvite()
oldCreatedAt := expiration.Add(-time.Second)
oldInvite, err := invitesDB.Update(ctx, oldInvite.ProjectID, oldInvite.Email, console.UpdateProjectInvitationRequest{
CreatedAt: &oldCreatedAt,
})
require.NoError(t, err)
require.NoError(t, invitesDB.DeleteBefore(ctx, expiration, 0, 1))
// Ensure that the old invitation record was deleted and the other remains.
_, err = invitesDB.Get(ctx, oldInvite.ProjectID, oldInvite.Email)
require.ErrorIs(t, err, sql.ErrNoRows)
_, err = invitesDB.Get(ctx, newInvite.ProjectID, newInvite.Email)
require.NoError(t, err)
})
}