storj/satellite/console/emailreminders/chore_test.go
Cameron 240b70b828 satellite/console: use new type UpdateUserRequest as arg to db users.Update
The users.Update method in the satellitedb package takes a console.User
as an argument. It reads some of the fields on this struct and assigns
the value to dbx.User_Update_Fields. However, you cannot optionally
update only some of the fields. They all will always be updated. This means
that if you only want to update FullName, you still need to read the
user info from the DB to avoid updating the rest of the fields to zero.
This is not good because concurrent updates can overwrite each other.

This change introduces a new struct type, UpdateUserRequest, which
contains pointers for all the fields that are updated by satellite db
users.Update. Now the update method will check if a field is nil before
assigning the value to be updated in the db, so you only need to set the
field you want updated. For nullable columns, the respective field is a
double pointer. This allows us to update a column to NULL if the outer
pointer is not nil, but the inner pointer is.

Change-Id: I27f842d283c2711e24d51dcab622e57eeb9157f1
2022-06-14 09:28:03 -04:00

172 lines
4.8 KiB
Go

// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package emailreminders_test
import (
"testing"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"storj.io/common/testcontext"
"storj.io/common/testrand"
"storj.io/storj/private/testplanet"
"storj.io/storj/satellite"
"storj.io/storj/satellite/console"
)
func TestEmailChoreUpdatesVerificationReminders(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
config.EmailReminders.FirstVerificationReminder = 0
config.EmailReminders.SecondVerificationReminder = 0
},
},
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
users := planet.Satellites[0].DB.Console().Users()
chore := planet.Satellites[0].Core.Mail.EmailReminders
chore.Loop.Pause()
// Overwrite link address in chore so the links don't work
// and we can test that the correct number of reminders are sent.
chore.TestSetLinkAddress("")
id1 := testrand.UUID()
_, err := users.Insert(ctx, &console.User{
ID: id1,
FullName: "test",
Email: "userone@mail.test",
PasswordHash: []byte("123a123"),
})
require.NoError(t, err)
id2 := testrand.UUID()
_, err = users.Insert(ctx, &console.User{
ID: id2,
FullName: "test",
Email: "usertwo@mail.test",
PasswordHash: []byte("123a123"),
})
require.NoError(t, err)
id3 := testrand.UUID()
_, err = users.Insert(ctx, &console.User{
ID: id3,
FullName: "test",
Email: "userthree@mail.test",
PasswordHash: []byte("123a123"),
})
require.NoError(t, err)
// This user will verify immediately and should not get reminders.
user1, err := users.Get(ctx, id1)
require.NoError(t, err)
require.Zero(t, user1.VerificationReminders)
// This user will get one reminder and then verify and should not get a second.
user2, err := users.Get(ctx, id2)
require.NoError(t, err)
require.Zero(t, user2.VerificationReminders)
// This user will not verify at all and should get 2 reminders and no more.
user3, err := users.Get(ctx, id3)
require.NoError(t, err)
require.Zero(t, user3.VerificationReminders)
user1.Status = 1
err = users.Update(ctx, user1.ID, console.UpdateUserRequest{
Status: &user1.Status,
})
require.NoError(t, err)
chore.Loop.TriggerWait()
user1, err = users.Get(ctx, id1)
require.NoError(t, err)
require.Zero(t, user1.VerificationReminders)
user2, err = users.Get(ctx, id2)
require.NoError(t, err)
require.Equal(t, 1, user2.VerificationReminders)
user3, err = users.Get(ctx, id3)
require.NoError(t, err)
require.Equal(t, 1, user3.VerificationReminders)
user2.Status = 1
err = users.Update(ctx, user2.ID, console.UpdateUserRequest{
Status: &user2.Status,
})
require.NoError(t, err)
chore.Loop.TriggerWait()
user1, err = users.Get(ctx, id1)
require.NoError(t, err)
require.Zero(t, user1.VerificationReminders)
user2, err = users.Get(ctx, id2)
require.NoError(t, err)
require.Equal(t, 1, user2.VerificationReminders)
user3, err = users.Get(ctx, id3)
require.NoError(t, err)
require.Equal(t, 2, user3.VerificationReminders)
// Check user is not reminded again after 2
chore.Loop.TriggerWait()
user1, err = users.Get(ctx, id1)
require.NoError(t, err)
require.Zero(t, user1.VerificationReminders)
user2, err = users.Get(ctx, id2)
require.NoError(t, err)
require.Equal(t, 1, user2.VerificationReminders)
user3, err = users.Get(ctx, id3)
require.NoError(t, err)
require.Equal(t, 2, user3.VerificationReminders)
})
}
func TestEmailChoreLinkActivatesAccount(t *testing.T) {
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 0,
Reconfigure: testplanet.Reconfigure{
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
config.EmailReminders.FirstVerificationReminder = 0
config.EmailReminders.SecondVerificationReminder = 0
},
},
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
users := planet.Satellites[0].DB.Console().Users()
chore := planet.Satellites[0].Core.Mail.EmailReminders
chore.Loop.Pause()
chore.TestUseBlockingSend()
id := testrand.UUID()
_, err := users.Insert(ctx, &console.User{
ID: id,
FullName: "test",
Email: "userone@mail.test",
PasswordHash: []byte("123a123"),
})
require.NoError(t, err)
u, err := users.Get(ctx, id)
require.NoError(t, err)
require.Equal(t, console.UserStatus(0), u.Status)
chore.Loop.TriggerWait()
u, err = users.Get(ctx, id)
require.NoError(t, err)
require.Equal(t, console.UserStatus(1), u.Status)
})
}