storj/cmd/nullify-bad-user-agents/main_test.go
Cameron 2b39df460c cmd/nullify-bad-user-agents: set user_agent to NULL where user_agent = partner_id
In the migration to migrate the corresponding name of the partner id to
user agent, part of the requirement was to migrate the partner id
itself if there was no partner name associated. This turned out to not
be so good. When we parse the user_agent column later, it is returning an
error if the user agent is one of these UUIDs.

Change-Id: I776ea458b82e1f99345005e5ba73d92264297bec
2022-03-31 16:57:50 -04:00

1189 lines
33 KiB
Go

// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package main_test
import (
"context"
"strings"
"testing"
pgx "github.com/jackc/pgx/v4"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.uber.org/zap/zaptest"
"storj.io/common/macaroon"
"storj.io/common/storj"
"storj.io/common/testcontext"
"storj.io/common/testrand"
"storj.io/common/uuid"
"storj.io/private/dbutil"
"storj.io/private/dbutil/tempdb"
migrator "storj.io/storj/cmd/nullify-bad-user-agents"
"storj.io/storj/satellite"
"storj.io/storj/satellite/attribution"
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/satellitedb/satellitedbtest"
)
// Test no entries in table doesn't error.
func TestMigrateUsersSelectNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateUsers, check, &migrator.Config{
Limit: 8,
})
}
// Test no entries in table doesn't error.
func TestMigrateUsersLimitedSelectNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateUsersLimited, check, &migrator.Config{
MaxUpdates: 1,
})
}
// Test no rows to update returns no error.
func TestMigrateUsersUpdateNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
userAgent := []byte("teststorj")
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
_, err := db.Console().Users().Insert(ctx, &console.User{
ID: testrand.UUID(),
Email: "test@storj.test",
FullName: "Test Test",
PasswordHash: []byte{0, 1, 2, 3},
UserAgent: userAgent,
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
_, users, err := db.Console().Users().GetByEmailWithUnverified(ctx, "test@storj.test")
require.NoError(t, err)
require.Len(t, users, 1)
require.Equal(t, userAgent, users[0].UserAgent)
}
test(t, prepare, migrator.MigrateUsers, check, &migrator.Config{
Limit: 8,
})
}
// Test select offset beyond final row.
// With only one row, selecting with an offset of 1 will return 0 rows.
// Test that this is accounted for and updates the row correctly.
func TestMigrateUsersSelectOffsetBeyondRowCount(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
userID := testrand.UUID()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
_, err := db.Console().Users().Insert(ctx, &console.User{
ID: userID,
Email: "test@storj.test",
FullName: "Test Test",
PasswordHash: []byte{0, 1, 2, 3},
PartnerID: userID,
UserAgent: userID.Bytes(),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
user, err := db.Console().Users().Get(ctx, userID)
require.NoError(t, err)
require.Nil(t, user.UserAgent)
}
test(t, prepare, migrator.MigrateUsers, check, &migrator.Config{
Limit: 8,
})
}
// Test user_agent field is updated correctly.
func TestMigrateUsers(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var n int
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
// insert with user_agent = partner_id
id := testrand.UUID()
_, err := db.Console().Users().Insert(ctx, &console.User{
ID: id,
Email: "test@storj.test",
FullName: "Test Test",
PasswordHash: []byte{0, 1, 2, 3},
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert with user_agent = partner_id
id = testrand.UUID()
_, err = db.Console().Users().Insert(ctx, &console.User{
ID: id,
Email: "test@storj.test",
FullName: "Test Test",
PasswordHash: []byte{0, 1, 2, 3},
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert an entry with something not matching
_, err = db.Console().Users().Insert(ctx, &console.User{
ID: testrand.UUID(),
Email: "test@storj.test",
FullName: "Test Test",
PasswordHash: []byte{0, 1, 2, 3},
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
_, users, err := db.Console().Users().GetByEmailWithUnverified(ctx, "test@storj.test")
require.NoError(t, err)
var updated int
for _, u := range users {
if u.UserAgent == nil {
updated++
}
}
require.Equal(t, n, updated)
n = 0
}
test(t, prepare, migrator.MigrateUsers, check, &migrator.Config{
Limit: 1,
})
}
// Test limited number of user_agent fields are updated correctly.
func TestMigrateUsersLimited(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
// insert an entry with valid user agent
_, err := db.Console().Users().Insert(ctx, &console.User{
ID: testrand.UUID(),
Email: "test@storj.test",
FullName: "Test Test",
PasswordHash: []byte{0, 1, 2, 3},
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
// insert matching user_agent and partner id
id := testrand.UUID()
_, err = db.Console().Users().Insert(ctx, &console.User{
ID: testrand.UUID(),
Email: "test@storj.test",
FullName: "Test Test",
PasswordHash: []byte{0, 1, 2, 3},
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
// insert '\x00000000000000000000000000000000' user_agent
id = testrand.UUID()
_, err = db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
PartnerID: id,
OwnerID: testrand.UUID(),
UserAgent: id.Bytes(),
})
require.NoError(t, err)
}
maxUpdates := 1
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
_, users, err := db.Console().Users().GetByEmailWithUnverified(ctx, "test@storj.test")
require.NoError(t, err)
var updated int
for _, u := range users {
if u.UserAgent == nil {
updated++
}
}
require.Equal(t, maxUpdates, updated)
}
test(t, prepare, migrator.MigrateUsersLimited, check, &migrator.Config{
MaxUpdates: maxUpdates,
})
}
// Test no entries in table doesn't error.
func TestMigrateProjectsSelectNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateProjects, check, &migrator.Config{
Limit: 8,
})
}
// Test no entries in table doesn't error.
func TestMigrateProjectsLimitedSelectNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateProjectsLimited, check, &migrator.Config{
MaxUpdates: 1,
})
}
// Test no rows to update returns no error.
func TestMigrateProjectsUpdateNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var id uuid.UUID
userAgent := []byte("teststorj")
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
proj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
UserAgent: userAgent,
})
require.NoError(t, err)
id = proj.ID
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
proj, err := db.Console().Projects().Get(ctx, id)
require.NoError(t, err)
require.Equal(t, userAgent, proj.UserAgent)
}
test(t, prepare, migrator.MigrateProjects, check, &migrator.Config{
Limit: 8,
})
}
// Test select offset beyond final row.
// With only one row, selecting with an offset of 1 will return 0 rows.
// Test that this is accounted for and updates the row correctly.
func TestMigrateProjectsSelectOffsetBeyondRowCount(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var projID uuid.UUID
id := testrand.UUID()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
prj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
PartnerID: id,
OwnerID: testrand.UUID(),
UserAgent: id.Bytes(),
})
require.NoError(t, err)
projID = prj.ID
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
proj, err := db.Console().Projects().Get(ctx, projID)
require.NoError(t, err)
require.Nil(t, proj.UserAgent)
}
test(t, prepare, migrator.MigrateProjects, check, &migrator.Config{
Limit: 8,
})
}
// Test user_agent field is updated correctly.
func TestMigrateProjects(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var n int
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
// insert matching user_agent partner_id
id := testrand.UUID()
_, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert matching user_agent
id = testrand.UUID()
_, err = db.Console().Projects().Insert(ctx, &console.Project{
Name: "test1",
Description: "test1",
OwnerID: testrand.UUID(),
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert an entry with something not zero
_, err = db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
PartnerID: testrand.UUID(),
OwnerID: testrand.UUID(),
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
projects, err := db.Console().Projects().GetAll(ctx)
require.NoError(t, err)
var updated int
for _, prj := range projects {
if prj.UserAgent == nil {
updated++
}
}
require.Equal(t, n, updated)
n = 0
}
test(t, prepare, migrator.MigrateProjects, check, &migrator.Config{
Limit: 1,
})
}
// Test user_agent field is updated correctly.
func TestMigrateProjectsLimited(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
// insert an entry with valid user agent
_, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
// insert matching user_agent
id := testrand.UUID()
_, err = db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
UserAgent: id.Bytes(),
PartnerID: id,
})
require.NoError(t, err)
// insert matching user_agent and partner id
id = testrand.UUID()
_, err = db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
UserAgent: id.Bytes(),
PartnerID: id,
})
require.NoError(t, err)
}
maxUpdates := 1
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
projects, err := db.Console().Projects().GetAll(ctx)
require.NoError(t, err)
var updated int
for _, prj := range projects {
if prj.UserAgent == nil {
updated++
}
}
require.Equal(t, maxUpdates, updated)
}
test(t, prepare, migrator.MigrateProjectsLimited, check, &migrator.Config{
MaxUpdates: maxUpdates,
})
}
// Test no entries in table doesn't error.
func TestMigrateAPIKeysSelectNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateAPIKeys, check, &migrator.Config{
Limit: 8,
})
}
// Test no entries in table doesn't error.
func TestMigrateAPIKeysLimitedSelectNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateAPIKeysLimited, check, &migrator.Config{
MaxUpdates: 1,
})
}
// Test no rows to update returns no error.
func TestMigrateAPIKeysUpdateNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var testID uuid.UUID
id := testrand.UUID()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
proj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
})
require.NoError(t, err)
apikey, err := db.Console().APIKeys().Create(ctx, testrand.UUID().Bytes(), console.APIKeyInfo{
ProjectID: proj.ID,
Name: "test0",
Secret: []byte("test"),
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
testID = apikey.ID
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
apikey, err := db.Console().APIKeys().Get(ctx, testID)
require.NoError(t, err)
require.Nil(t, apikey.UserAgent)
}
test(t, prepare, migrator.MigrateAPIKeys, check, &migrator.Config{
Limit: 8,
})
}
// Test select offset beyond final row.
// With only one row, selecting with an offset of 1 will return 0 rows.
// Test that this is accounted for and updates the row correctly.
func TestMigrateAPIKeysSelectOffsetBeyondRowCount(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var testID uuid.UUID
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
prj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
PartnerID: testrand.UUID(),
OwnerID: testrand.UUID(),
})
require.NoError(t, err)
id := testrand.UUID()
apiKey, err := db.Console().APIKeys().Create(ctx, testrand.UUID().Bytes(), console.APIKeyInfo{
ProjectID: prj.ID,
PartnerID: id,
Name: "test0",
Secret: []byte("test"),
UserAgent: id.Bytes(),
})
require.NoError(t, err)
testID = apiKey.ID
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
apiKey, err := db.Console().APIKeys().Get(ctx, testID)
require.NoError(t, err)
require.Nil(t, apiKey.UserAgent)
}
test(t, prepare, migrator.MigrateAPIKeys, check, &migrator.Config{
Limit: 8,
})
}
// Test user_agent field is updated correctly.
func TestMigrateAPIKeys(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var n int
var projID uuid.UUID
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
proj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
})
require.NoError(t, err)
projID = proj.ID
// insert matching user_agent and partner id
id := testrand.UUID()
_, err = db.Console().APIKeys().Create(ctx, testrand.UUID().Bytes(), console.APIKeyInfo{
ProjectID: projID,
Name: "test0",
Secret: []byte("test"),
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert another matching user_agent and partner id
id = testrand.UUID()
_, err = db.Console().APIKeys().Create(ctx, testrand.UUID().Bytes(), console.APIKeyInfo{
ProjectID: projID,
Name: "test1",
Secret: []byte("test1"),
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert an entry with something not zero
_, err = db.Console().APIKeys().Create(ctx, testrand.UUID().Bytes(), console.APIKeyInfo{
ProjectID: projID,
PartnerID: testrand.UUID(),
Name: "test2",
Secret: []byte("test"),
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
keyPage, err := db.Console().APIKeys().GetPagedByProjectID(ctx, projID, console.APIKeyCursor{Page: 1, Limit: 1000})
require.NoError(t, err)
var updated int
for _, key := range keyPage.APIKeys {
if key.UserAgent == nil {
updated++
}
}
require.Equal(t, n, updated)
n = 0
}
test(t, prepare, migrator.MigrateAPIKeys, check, &migrator.Config{
Limit: 8,
})
}
// Test user_agent field is updated correctly.
func TestMigrateAPIKeysLimited(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var projID uuid.UUID
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
proj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
})
require.NoError(t, err)
projID = proj.ID
// insert an entry with valid user agent
_, err = db.Console().APIKeys().Create(ctx, testrand.UUID().Bytes(), console.APIKeyInfo{
ProjectID: projID,
Name: "test0",
Secret: []byte("test"),
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
// insert matching user_agent and partner id
id := testrand.UUID()
_, err = db.Console().APIKeys().Create(ctx, testrand.UUID().Bytes(), console.APIKeyInfo{
ProjectID: projID,
Name: "test1",
Secret: []byte("test"),
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
// insert another matching user_agent and partner id
id = testrand.UUID()
_, err = db.Console().APIKeys().Create(ctx, testrand.UUID().Bytes(), console.APIKeyInfo{
ProjectID: projID,
PartnerID: id,
Name: "test2",
Secret: []byte("test"),
UserAgent: id.Bytes(),
})
require.NoError(t, err)
}
maxUpdates := 1
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
keyPage, err := db.Console().APIKeys().GetPagedByProjectID(ctx, projID, console.APIKeyCursor{Page: 1, Limit: 1000})
require.NoError(t, err)
var updated int
for _, key := range keyPage.APIKeys {
if key.UserAgent == nil {
updated++
}
}
require.Equal(t, maxUpdates, updated)
}
test(t, prepare, migrator.MigrateAPIKeysLimited, check, &migrator.Config{
MaxUpdates: maxUpdates,
})
}
// Test no entries in table doesn't error.
func TestMigrateBucketMetainfosSelectNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateBucketMetainfos, check, &migrator.Config{
Limit: 8,
})
}
// Test no entries in table doesn't error.
func TestMigrateBucketMetainfosLimitedSelectNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateBucketMetainfosLimited, check, &migrator.Config{
MaxUpdates: 1,
})
}
// Test no rows to update returns no error.
func TestMigrateBucketMetainfosUpdateNoRows(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
bName := "test1"
var projID uuid.UUID
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
proj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
})
require.NoError(t, err)
projID = proj.ID
_, err = db.Buckets().CreateBucket(ctx, storj.Bucket{
ID: testrand.UUID(),
Name: "test1",
ProjectID: projID,
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
b, err := db.Buckets().GetBucket(ctx, []byte(bName), projID)
require.NoError(t, err)
require.NotNil(t, b.UserAgent)
}
test(t, prepare, migrator.MigrateBucketMetainfos, check, &migrator.Config{
Limit: 8,
})
}
// Test select offset beyond final row.
// With only one row, selecting with an offset of 1 will return 0 rows.
// Test that this is accounted for and updates the row correctly.
func TestMigrateBucketMetainfosSelectOffsetBeyondRowCount(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var projID uuid.UUID
bucket := []byte("test")
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
prj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
})
require.NoError(t, err)
projID = prj.ID
id := testrand.UUID()
_, err = db.Buckets().CreateBucket(ctx, storj.Bucket{
ID: testrand.UUID(),
Name: string(bucket),
ProjectID: projID,
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
b, err := db.Buckets().GetBucket(ctx, bucket, projID)
require.NoError(t, err)
require.Nil(t, b.UserAgent)
}
test(t, prepare, migrator.MigrateBucketMetainfos, check, &migrator.Config{
Limit: 8,
})
}
// Test user_agent field is updated correctly.
func TestMigrateBucketMetainfos(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
var n int
var projID uuid.UUID
zeroedUUID := uuid.UUID{}.Bytes()
require.NotNil(t, zeroedUUID)
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
proj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
})
require.NoError(t, err)
projID = proj.ID
// insert matching user_agent and partner id
id := testrand.UUID()
_, err = db.Buckets().CreateBucket(ctx, storj.Bucket{
ID: id,
Name: "test0",
ProjectID: projID,
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert another matching user_agent and partner id
id = testrand.UUID()
_, err = db.Buckets().CreateBucket(ctx, storj.Bucket{
ID: id,
Name: "test1",
ProjectID: projID,
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert an entry with something not zero
_, err = db.Buckets().CreateBucket(ctx, storj.Bucket{
ID: testrand.UUID(),
Name: "test2",
ProjectID: projID,
PartnerID: testrand.UUID(),
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
list, err := db.Buckets().ListBuckets(ctx, projID, storj.BucketListOptions{Direction: storj.Forward}, macaroon.AllowedBuckets{All: true})
require.NoError(t, err)
var updated int
for _, b := range list.Items {
if b.UserAgent == nil {
updated++
}
}
require.Equal(t, n, updated)
n = 0
}
test(t, prepare, migrator.MigrateBucketMetainfos, check, &migrator.Config{
Limit: 8,
})
}
// Test user_agent field is updated correctly.
func TestMigrateBucketMetainfosLimited(t *testing.T) {
t.Parallel()
ctx := testcontext.New(t)
defer ctx.Cleanup()
testID := testrand.UUID()
zeroedUUID := uuid.UUID{}.Bytes()
require.NotNil(t, zeroedUUID)
var projID uuid.UUID
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
proj, err := db.Console().Projects().Insert(ctx, &console.Project{
Name: "test",
Description: "test",
OwnerID: testrand.UUID(),
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
projID = proj.ID
// insert matching user_agent
id := testrand.UUID()
_, err = db.Buckets().CreateBucket(ctx, storj.Bucket{
ID: testID,
Name: "test0",
ProjectID: projID,
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
// insert another matching user_agent and partner id
id = testrand.UUID()
_, err = db.Buckets().CreateBucket(ctx, storj.Bucket{
ID: testrand.UUID(),
Name: "test1",
ProjectID: projID,
PartnerID: id,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
}
maxUpdates := 1
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
list, err := db.Buckets().ListBuckets(ctx, projID, storj.BucketListOptions{Direction: storj.Forward}, macaroon.AllowedBuckets{All: true})
require.NoError(t, err)
var updated int
for _, b := range list.Items {
if b.UserAgent == nil {
updated++
}
}
require.Equal(t, maxUpdates, updated)
}
test(t, prepare, migrator.MigrateBucketMetainfosLimited, check, &migrator.Config{
MaxUpdates: maxUpdates,
})
}
// Test no entries in table doesn't error.
func TestMigrateValueAttributionsSelectNoRows(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateValueAttributions, check, &migrator.Config{
Limit: 8,
})
}
// Test no entries in table doesn't error.
func TestMigrateValueAttributionsLimitedSelectNoRows(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {}
test(t, prepare, migrator.MigrateValueAttributionsLimited, check, &migrator.Config{
MaxUpdates: 1,
})
}
// Test no rows to update returns no error.
func TestMigrateValueAttributionsUpdateNoRows(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
partnerID := testrand.UUID()
ua := []byte("test")
projID := testrand.UUID()
bName := []byte("test")
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
_, err := db.Attribution().Insert(ctx, &attribution.Info{
ProjectID: projID,
PartnerID: partnerID,
BucketName: bName,
UserAgent: ua,
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
att, err := db.Attribution().Get(ctx, projID, bName)
require.NoError(t, err)
require.Equal(t, partnerID, att.PartnerID)
require.Equal(t, ua, att.UserAgent)
}
test(t, prepare, migrator.MigrateValueAttributions, check, &migrator.Config{
Limit: 8,
})
}
// Test select offset beyond final row.
// With only one row, selecting with an offset of 1 will return 0 rows.
// Test that this is accounted for and updates the row correctly.
func TestMigrateValueAttributionsSelectOffsetBeyondRowCount(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
projID := testrand.UUID()
bucket := []byte("test")
id := testrand.UUID()
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
_, err := db.Attribution().Insert(ctx, &attribution.Info{
ProjectID: projID,
PartnerID: id,
BucketName: bucket,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
att, err := db.Attribution().Get(ctx, projID, bucket)
require.NoError(t, err)
require.Nil(t, att.UserAgent)
}
test(t, prepare, migrator.MigrateValueAttributions, check, &migrator.Config{
Limit: 8,
})
}
// Test user_agent field is updated correctly.
func TestMigrateValueAttributions(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
type info struct {
bucket []byte
project uuid.UUID
}
var n int
zeroedUUID := uuid.UUID{}.Bytes()
require.NotNil(t, zeroedUUID)
var infos []info
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
// insert matching user_agent partner id
id := testrand.UUID()
b := []byte("test0")
infos = append(infos, info{b, id})
_, err := db.Attribution().Insert(ctx, &attribution.Info{
ProjectID: id,
PartnerID: id,
BucketName: b,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert another matching user_agent partner id
id = testrand.UUID()
infos = append(infos, info{b, id})
_, err = db.Attribution().Insert(ctx, &attribution.Info{
ProjectID: id,
PartnerID: id,
BucketName: b,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
n++
// insert without zeroes
id = testrand.UUID()
_, err = db.Attribution().Insert(ctx, &attribution.Info{
ProjectID: id,
PartnerID: id,
BucketName: b,
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
}
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
var updated int
for _, in := range infos {
att, err := db.Attribution().Get(ctx, in.project, in.bucket)
require.NoError(t, err)
if att.UserAgent == nil {
updated++
}
}
require.Equal(t, n, updated)
n = 0
// clear infos for the subsequent CRDB test
infos = []info{}
}
test(t, prepare, migrator.MigrateValueAttributions, check, &migrator.Config{
Limit: 1,
})
}
// Test user_agent field is updated correctly.
func TestMigrateValueAttributionsLimited(t *testing.T) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
type info struct {
bucket []byte
project uuid.UUID
}
zeroedUUID := uuid.UUID{}.Bytes()
require.NotNil(t, zeroedUUID)
var infos []info
prepare := func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB) {
// insert with matching user agent and partner id
id := testrand.UUID()
b := []byte("test0")
infos = append(infos, info{b, id})
_, err := db.Attribution().Insert(ctx, &attribution.Info{
ProjectID: id,
PartnerID: id,
BucketName: b,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
// insert another with zeroes
id = testrand.UUID()
infos = append(infos, info{b, id})
_, err = db.Attribution().Insert(ctx, &attribution.Info{
ProjectID: id,
PartnerID: id,
BucketName: b,
UserAgent: id.Bytes(),
})
require.NoError(t, err)
// insert without zeroes
id = testrand.UUID()
infos = append(infos, info{b, id})
_, err = db.Attribution().Insert(ctx, &attribution.Info{
ProjectID: id,
PartnerID: id,
BucketName: b,
UserAgent: []byte("teststorj"),
})
require.NoError(t, err)
}
maxUpdates := 1
check := func(t *testing.T, ctx context.Context, db satellite.DB) {
var updated int
for _, in := range infos {
att, err := db.Attribution().Get(ctx, in.project, in.bucket)
require.NoError(t, err)
if att.UserAgent == nil {
updated++
}
}
require.Equal(t, maxUpdates, updated)
// clear infos for the subsequent CRDB test
infos = []info{}
}
test(t, prepare, migrator.MigrateValueAttributionsLimited, check, &migrator.Config{
MaxUpdates: maxUpdates,
})
}
func test(t *testing.T, prepare func(t *testing.T, ctx *testcontext.Context, rawDB *dbutil.TempDatabase, db satellite.DB),
migrate func(ctx context.Context, log *zap.Logger, conn *pgx.Conn, config migrator.Config) (err error),
check func(t *testing.T, ctx context.Context, db satellite.DB), config *migrator.Config) {
ctx := testcontext.New(t)
defer ctx.Cleanup()
log := zaptest.NewLogger(t)
for _, satelliteDB := range satellitedbtest.Databases() {
satelliteDB := satelliteDB
t.Run(satelliteDB.Name, func(t *testing.T) {
schemaSuffix := satellitedbtest.SchemaSuffix()
schema := satellitedbtest.SchemaName(t.Name(), "category", 0, schemaSuffix)
tempDB, err := tempdb.OpenUnique(ctx, satelliteDB.MasterDB.URL, schema)
require.NoError(t, err)
db, err := satellitedbtest.CreateMasterDBOnTopOf(ctx, log, tempDB)
require.NoError(t, err)
defer ctx.Check(db.Close)
err = db.TestingMigrateToLatest(ctx)
require.NoError(t, err)
prepare(t, ctx, tempDB, db)
mConnStr := strings.Replace(tempDB.ConnStr, "cockroach", "postgres", 1)
conn, err := pgx.Connect(ctx, mConnStr)
require.NoError(t, err)
err = migrate(ctx, log, conn, *config)
require.NoError(t, err)
require.NoError(t, err)
check(t, ctx, db)
})
}
}