437 lines
12 KiB
Go
437 lines
12 KiB
Go
//go:build integration
|
|
|
|
package integration_test
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
_ "github.com/lib/pq"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"github.com/rwadurian/mpc-system/services/account/adapters/output/postgres"
|
|
"github.com/rwadurian/mpc-system/services/account/domain/entities"
|
|
"github.com/rwadurian/mpc-system/services/account/domain/value_objects"
|
|
)
|
|
|
|
type AccountRepositoryTestSuite struct {
|
|
suite.Suite
|
|
db *sql.DB
|
|
accountRepo *postgres.AccountPostgresRepo
|
|
shareRepo *postgres.AccountSharePostgresRepo
|
|
recoveryRepo *postgres.RecoverySessionPostgresRepo
|
|
ctx context.Context
|
|
}
|
|
|
|
func TestAccountRepositorySuite(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("Skipping integration test in short mode")
|
|
}
|
|
suite.Run(t, new(AccountRepositoryTestSuite))
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) SetupSuite() {
|
|
dsn := os.Getenv("TEST_DATABASE_URL")
|
|
if dsn == "" {
|
|
dsn = "postgres://mpc_user:mpc_password@localhost:5433/mpc_system_test?sslmode=disable"
|
|
}
|
|
|
|
var err error
|
|
s.db, err = sql.Open("postgres", dsn)
|
|
require.NoError(s.T(), err)
|
|
|
|
err = s.db.Ping()
|
|
require.NoError(s.T(), err, "Failed to connect to test database")
|
|
|
|
s.accountRepo = postgres.NewAccountPostgresRepo(s.db).(*postgres.AccountPostgresRepo)
|
|
s.shareRepo = postgres.NewAccountSharePostgresRepo(s.db).(*postgres.AccountSharePostgresRepo)
|
|
s.recoveryRepo = postgres.NewRecoverySessionPostgresRepo(s.db).(*postgres.RecoverySessionPostgresRepo)
|
|
s.ctx = context.Background()
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TearDownSuite() {
|
|
if s.db != nil {
|
|
s.db.Close()
|
|
}
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) SetupTest() {
|
|
s.cleanupTestData()
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) cleanupTestData() {
|
|
s.db.ExecContext(s.ctx, "DELETE FROM account_recovery_sessions WHERE account_id IN (SELECT id FROM accounts WHERE username LIKE 'test_%')")
|
|
s.db.ExecContext(s.ctx, "DELETE FROM account_shares WHERE account_id IN (SELECT id FROM accounts WHERE username LIKE 'test_%')")
|
|
s.db.ExecContext(s.ctx, "DELETE FROM accounts WHERE username LIKE 'test_%'")
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestCreateAccount() {
|
|
account := entities.NewAccount(
|
|
"test_user_1",
|
|
"test1@example.com",
|
|
[]byte("test-public-key-1"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Verify account was created
|
|
retrieved, err := s.accountRepo.GetByID(s.ctx, account.ID)
|
|
require.NoError(s.T(), err)
|
|
assert.Equal(s.T(), account.Username, retrieved.Username)
|
|
assert.Equal(s.T(), account.Email, retrieved.Email)
|
|
assert.Equal(s.T(), account.ThresholdN, retrieved.ThresholdN)
|
|
assert.Equal(s.T(), account.ThresholdT, retrieved.ThresholdT)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestGetByUsername() {
|
|
account := entities.NewAccount(
|
|
"test_user_2",
|
|
"test2@example.com",
|
|
[]byte("test-public-key-2"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
retrieved, err := s.accountRepo.GetByUsername(s.ctx, "test_user_2")
|
|
require.NoError(s.T(), err)
|
|
assert.True(s.T(), account.ID.Equals(retrieved.ID))
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestGetByEmail() {
|
|
account := entities.NewAccount(
|
|
"test_user_3",
|
|
"test3@example.com",
|
|
[]byte("test-public-key-3"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
retrieved, err := s.accountRepo.GetByEmail(s.ctx, "test3@example.com")
|
|
require.NoError(s.T(), err)
|
|
assert.True(s.T(), account.ID.Equals(retrieved.ID))
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestUpdateAccount() {
|
|
account := entities.NewAccount(
|
|
"test_user_4",
|
|
"test4@example.com",
|
|
[]byte("test-public-key-4"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Update account
|
|
phone := "+1234567890"
|
|
account.Phone = &phone
|
|
account.Status = value_objects.AccountStatusSuspended
|
|
|
|
err = s.accountRepo.Update(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Verify update
|
|
retrieved, err := s.accountRepo.GetByID(s.ctx, account.ID)
|
|
require.NoError(s.T(), err)
|
|
assert.Equal(s.T(), "+1234567890", *retrieved.Phone)
|
|
assert.Equal(s.T(), value_objects.AccountStatusSuspended, retrieved.Status)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestExistsByUsername() {
|
|
account := entities.NewAccount(
|
|
"test_user_5",
|
|
"test5@example.com",
|
|
[]byte("test-public-key-5"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
exists, err := s.accountRepo.ExistsByUsername(s.ctx, "test_user_5")
|
|
require.NoError(s.T(), err)
|
|
assert.True(s.T(), exists)
|
|
|
|
exists, err = s.accountRepo.ExistsByUsername(s.ctx, "nonexistent_user")
|
|
require.NoError(s.T(), err)
|
|
assert.False(s.T(), exists)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestExistsByEmail() {
|
|
account := entities.NewAccount(
|
|
"test_user_6",
|
|
"test6@example.com",
|
|
[]byte("test-public-key-6"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
exists, err := s.accountRepo.ExistsByEmail(s.ctx, "test6@example.com")
|
|
require.NoError(s.T(), err)
|
|
assert.True(s.T(), exists)
|
|
|
|
exists, err = s.accountRepo.ExistsByEmail(s.ctx, "nonexistent@example.com")
|
|
require.NoError(s.T(), err)
|
|
assert.False(s.T(), exists)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestListAccounts() {
|
|
// Create multiple accounts
|
|
for i := 0; i < 5; i++ {
|
|
account := entities.NewAccount(
|
|
"test_user_list_"+string(rune('a'+i)),
|
|
"testlist"+string(rune('a'+i))+"@example.com",
|
|
[]byte("test-public-key-list-"+string(rune('a'+i))),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
}
|
|
|
|
accounts, err := s.accountRepo.List(s.ctx, 0, 10)
|
|
require.NoError(s.T(), err)
|
|
assert.GreaterOrEqual(s.T(), len(accounts), 5)
|
|
|
|
count, err := s.accountRepo.Count(s.ctx)
|
|
require.NoError(s.T(), err)
|
|
assert.GreaterOrEqual(s.T(), count, int64(5))
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestDeleteAccount() {
|
|
account := entities.NewAccount(
|
|
"test_user_delete",
|
|
"testdelete@example.com",
|
|
[]byte("test-public-key-delete"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
err = s.accountRepo.Delete(s.ctx, account.ID)
|
|
require.NoError(s.T(), err)
|
|
|
|
_, err = s.accountRepo.GetByID(s.ctx, account.ID)
|
|
assert.Error(s.T(), err)
|
|
}
|
|
|
|
// Account Share Tests
|
|
|
|
func (s *AccountRepositoryTestSuite) TestCreateAccountShare() {
|
|
account := entities.NewAccount(
|
|
"test_user_share_1",
|
|
"testshare1@example.com",
|
|
[]byte("test-public-key-share-1"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
share := entities.NewAccountShare(
|
|
account.ID,
|
|
value_objects.ShareTypeUserDevice,
|
|
"party_1",
|
|
0,
|
|
)
|
|
share.SetDeviceInfo("iOS", "device123")
|
|
|
|
err = s.shareRepo.Create(s.ctx, share)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Verify share was created
|
|
retrieved, err := s.shareRepo.GetByID(s.ctx, share.ID.String())
|
|
require.NoError(s.T(), err)
|
|
assert.Equal(s.T(), share.PartyID, retrieved.PartyID)
|
|
assert.Equal(s.T(), "iOS", *retrieved.DeviceType)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestGetSharesByAccountID() {
|
|
account := entities.NewAccount(
|
|
"test_user_share_2",
|
|
"testshare2@example.com",
|
|
[]byte("test-public-key-share-2"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Create multiple shares
|
|
shareTypes := []value_objects.ShareType{
|
|
value_objects.ShareTypeUserDevice,
|
|
value_objects.ShareTypeServer,
|
|
value_objects.ShareTypeRecovery,
|
|
}
|
|
|
|
for i, st := range shareTypes {
|
|
share := entities.NewAccountShare(account.ID, st, "party_"+string(rune('a'+i)), i)
|
|
err = s.shareRepo.Create(s.ctx, share)
|
|
require.NoError(s.T(), err)
|
|
}
|
|
|
|
shares, err := s.shareRepo.GetByAccountID(s.ctx, account.ID)
|
|
require.NoError(s.T(), err)
|
|
assert.Len(s.T(), shares, 3)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestGetActiveSharesByAccountID() {
|
|
account := entities.NewAccount(
|
|
"test_user_share_3",
|
|
"testshare3@example.com",
|
|
[]byte("test-public-key-share-3"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Create active and inactive shares
|
|
activeShare := entities.NewAccountShare(account.ID, value_objects.ShareTypeUserDevice, "party_active", 0)
|
|
err = s.shareRepo.Create(s.ctx, activeShare)
|
|
require.NoError(s.T(), err)
|
|
|
|
inactiveShare := entities.NewAccountShare(account.ID, value_objects.ShareTypeServer, "party_inactive", 1)
|
|
inactiveShare.Deactivate()
|
|
err = s.shareRepo.Create(s.ctx, inactiveShare)
|
|
require.NoError(s.T(), err)
|
|
|
|
activeShares, err := s.shareRepo.GetActiveByAccountID(s.ctx, account.ID)
|
|
require.NoError(s.T(), err)
|
|
assert.Len(s.T(), activeShares, 1)
|
|
assert.Equal(s.T(), "party_active", activeShares[0].PartyID)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestDeactivateShareByAccountID() {
|
|
account := entities.NewAccount(
|
|
"test_user_share_4",
|
|
"testshare4@example.com",
|
|
[]byte("test-public-key-share-4"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
share1 := entities.NewAccountShare(account.ID, value_objects.ShareTypeUserDevice, "party_1", 0)
|
|
share2 := entities.NewAccountShare(account.ID, value_objects.ShareTypeServer, "party_2", 1)
|
|
err = s.shareRepo.Create(s.ctx, share1)
|
|
require.NoError(s.T(), err)
|
|
err = s.shareRepo.Create(s.ctx, share2)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Deactivate all shares
|
|
err = s.shareRepo.DeactivateByAccountID(s.ctx, account.ID)
|
|
require.NoError(s.T(), err)
|
|
|
|
activeShares, err := s.shareRepo.GetActiveByAccountID(s.ctx, account.ID)
|
|
require.NoError(s.T(), err)
|
|
assert.Len(s.T(), activeShares, 0)
|
|
}
|
|
|
|
// Recovery Session Tests
|
|
|
|
func (s *AccountRepositoryTestSuite) TestCreateRecoverySession() {
|
|
account := entities.NewAccount(
|
|
"test_user_recovery_1",
|
|
"testrecovery1@example.com",
|
|
[]byte("test-public-key-recovery-1"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
recovery := entities.NewRecoverySession(account.ID, value_objects.RecoveryTypeDeviceLost)
|
|
oldShareType := value_objects.ShareTypeUserDevice
|
|
recovery.SetOldShareType(oldShareType)
|
|
|
|
err = s.recoveryRepo.Create(s.ctx, recovery)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Verify recovery was created
|
|
retrieved, err := s.recoveryRepo.GetByID(s.ctx, recovery.ID.String())
|
|
require.NoError(s.T(), err)
|
|
assert.Equal(s.T(), recovery.RecoveryType, retrieved.RecoveryType)
|
|
assert.Equal(s.T(), value_objects.RecoveryStatusRequested, retrieved.Status)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestUpdateRecoverySession() {
|
|
account := entities.NewAccount(
|
|
"test_user_recovery_2",
|
|
"testrecovery2@example.com",
|
|
[]byte("test-public-key-recovery-2"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
recovery := entities.NewRecoverySession(account.ID, value_objects.RecoveryTypeDeviceLost)
|
|
err = s.recoveryRepo.Create(s.ctx, recovery)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Start keygen
|
|
keygenID := uuid.New()
|
|
recovery.StartKeygen(keygenID)
|
|
err = s.recoveryRepo.Update(s.ctx, recovery)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Verify update
|
|
retrieved, err := s.recoveryRepo.GetByID(s.ctx, recovery.ID.String())
|
|
require.NoError(s.T(), err)
|
|
assert.Equal(s.T(), value_objects.RecoveryStatusInProgress, retrieved.Status)
|
|
assert.NotNil(s.T(), retrieved.NewKeygenSessionID)
|
|
}
|
|
|
|
func (s *AccountRepositoryTestSuite) TestGetActiveRecoveryByAccountID() {
|
|
account := entities.NewAccount(
|
|
"test_user_recovery_3",
|
|
"testrecovery3@example.com",
|
|
[]byte("test-public-key-recovery-3"),
|
|
uuid.New(),
|
|
3,
|
|
2,
|
|
)
|
|
err := s.accountRepo.Create(s.ctx, account)
|
|
require.NoError(s.T(), err)
|
|
|
|
// Create active recovery
|
|
activeRecovery := entities.NewRecoverySession(account.ID, value_objects.RecoveryTypeDeviceLost)
|
|
err = s.recoveryRepo.Create(s.ctx, activeRecovery)
|
|
require.NoError(s.T(), err)
|
|
|
|
retrieved, err := s.recoveryRepo.GetActiveByAccountID(s.ctx, account.ID)
|
|
require.NoError(s.T(), err)
|
|
assert.Equal(s.T(), activeRecovery.ID, retrieved.ID)
|
|
}
|