storj/satellite/satellitedb/projectinvitations_test.go
Jeremy Wharton d18f4f7d99 satellite/console: don't delete expired project invitations
This change removes instances of project invitation deletion due to
expiration because we now want such invitations to be accessible beyond
their expiration date. In the future, project members will be able to
view and resend expired invitations within the Team page in the
satellite frontend.

References #5752

Change-Id: If24a9637945874d719b894a66c06f6e0e9805dfa
2023-06-20 22:42:50 -05:00

214 lines
6.4 KiB
Go

// 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)
})
}