alby-hub/transactions/check_unsettled_transaction_test.go
Roland 0b0cbbd985
fix: make event assertions in tests wait for async event consumption (#2531)
The mock event consumer waited a fixed 10ms before returning consumed
events, which was not always enough on slow CI runners and caused flaky
failures (e.g. TestMarkSettled_App_BudgetWarning missing its
nwc_budget_warning event). It also appended to the events slice from
concurrent goroutines without synchronization, a data race that could
drop events.

- guard the consumed events slice with a mutex and return copies
- add WaitForConsumedEvents which polls until the expected number of
  events arrived (up to 5s) instead of relying on a fixed sleep
- use it in tests that assert on consumed events; tests asserting that
  no event was published keep the short grace period
- normalize event order in the keysend self-payment test, matching the
  existing approach in the self-payment test, since async publishing
  does not guarantee ordering

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 14:48:41 +07:00

100 lines
3.4 KiB
Go

package transactions
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/getAlby/hub/constants"
"github.com/getAlby/hub/db"
"github.com/getAlby/hub/lnclient"
"github.com/getAlby/hub/tests"
)
func TestCheckUnsettledTransaction(t *testing.T) {
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
dbTransaction := db.Transaction{
State: constants.TRANSACTION_STATE_PENDING,
Type: constants.TRANSACTION_TYPE_OUTGOING,
PaymentHash: tests.MockLNClientTransaction.PaymentHash,
AmountMsat: 123000,
}
svc.DB.Create(&dbTransaction)
mockEventConsumer := tests.NewMockEventConsumer()
svc.EventPublisher.RegisterSubscriber(mockEventConsumer)
transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
settledAt := time.Now().Unix()
svc.LNClient.(*tests.MockLn).MockTransaction = &lnclient.Transaction{
SettledAt: &settledAt,
Preimage: "dummy",
}
// do not allow checking unsettled transactions if notifications are supported
transactionsService.checkUnsettledTransaction(context.TODO(), &dbTransaction, svc.LNClient)
assert.Equal(t, constants.TRANSACTION_STATE_PENDING, dbTransaction.State)
svc.LNClient.(*tests.MockLn).SupportedNotificationTypes = &[]string{}
transactionsService.checkUnsettledTransaction(context.TODO(), &dbTransaction, svc.LNClient)
assert.NoError(t, err)
assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, dbTransaction.State)
consumedEvents := mockEventConsumer.WaitForConsumedEvents(1)
assert.Equal(t, 1, len(consumedEvents))
assert.Equal(t, "nwc_payment_sent", consumedEvents[0].Event)
settledTransaction := consumedEvents[0].Properties.(*db.Transaction)
assert.Equal(t, &dbTransaction, settledTransaction)
}
func TestCheckUnsettledTransactions(t *testing.T) {
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
dbTransaction := db.Transaction{
State: constants.TRANSACTION_STATE_PENDING,
Type: constants.TRANSACTION_TYPE_OUTGOING,
PaymentHash: tests.MockLNClientTransaction.PaymentHash,
AmountMsat: 123000,
CreatedAt: time.Now(),
}
svc.DB.Create(&dbTransaction)
mockEventConsumer := tests.NewMockEventConsumer()
svc.EventPublisher.RegisterSubscriber(mockEventConsumer)
transactionsService := NewTransactionsService(svc.DB, svc.EventPublisher)
settledAt := time.Now().Unix()
svc.LNClient.(*tests.MockLn).MockTransaction = &lnclient.Transaction{
SettledAt: &settledAt,
Preimage: "dummy",
}
// do not allow checking unsettled transactions if notifications are supported
transactionsService.checkUnsettledTransactions(context.TODO(), svc.LNClient)
svc.DB.Find(&dbTransaction, db.Transaction{
ID: dbTransaction.ID,
})
assert.Equal(t, constants.TRANSACTION_STATE_PENDING, dbTransaction.State)
svc.LNClient.(*tests.MockLn).SupportedNotificationTypes = &[]string{}
transactionsService.checkUnsettledTransactions(context.TODO(), svc.LNClient)
svc.DB.Find(&dbTransaction, db.Transaction{
ID: dbTransaction.ID,
})
assert.NoError(t, err)
assert.Equal(t, constants.TRANSACTION_STATE_SETTLED, dbTransaction.State)
consumedEvents := mockEventConsumer.WaitForConsumedEvents(1)
assert.Equal(t, 1, len(consumedEvents))
assert.Equal(t, "nwc_payment_sent", consumedEvents[0].Event)
settledTransaction := consumedEvents[0].Properties.(*db.Transaction)
assert.Equal(t, dbTransaction.ID, settledTransaction.ID)
}