mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-03 01:41:44 +00:00
@@ -0,0 +1,52 @@
|
||||
# WebAuthn Integration Tests
|
||||
|
||||
## Overview
|
||||
|
||||
This test suite provides comprehensive end-to-end testing for the WebAuthn implementation in the Sonr blockchain's DID module. The tests validate the complete WebAuthn registration, authentication, and key management workflows.
|
||||
|
||||
## Test Coverage
|
||||
|
||||
The test suite covers the following scenarios:
|
||||
|
||||
1. **Attestation Parsing**
|
||||
- Validates parsing of CBOR attestation objects
|
||||
- Checks public key extraction
|
||||
- Verifies algorithm and authenticator data detection
|
||||
|
||||
2. **Registration Flow**
|
||||
- Complete WebAuthn credential registration
|
||||
- Challenge verification
|
||||
- Origin validation
|
||||
- DID document creation with WebAuthn credentials
|
||||
- Credential uniqueness enforcement
|
||||
|
||||
3. **Signature Verification**
|
||||
- WebAuthn assertion verification
|
||||
- User presence and verification flag checking
|
||||
- Multi-algorithm signature support (ES256, RS256, EdDSA)
|
||||
- Counter increment validation
|
||||
|
||||
4. **Security Scenarios**
|
||||
- Challenge replay attack prevention
|
||||
- Invalid origin rejection
|
||||
- Oversized credential handling
|
||||
- Credential ID reuse prevention
|
||||
|
||||
## Test Methodology
|
||||
|
||||
- Uses Cosmos SDK testing framework
|
||||
- Employs table-driven tests for multiple scenarios
|
||||
- Mocks cryptographic keys and challenge responses
|
||||
- Validates both positive and negative test cases
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
go test github.com/sonr-io/sonr/test/e2e/tests -v
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Cosmos SDK v0.50.14
|
||||
- Internal WebAuthn libraries
|
||||
- testify assertion library
|
||||
@@ -0,0 +1,136 @@
|
||||
package basic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/sonr-io/sonr/test/e2e/utils"
|
||||
)
|
||||
|
||||
func TestBasicChain(t *testing.T) {
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("node_info", func(t *testing.T) {
|
||||
utils.AssertNodeInfo(t, cfg, cfg.ChainID)
|
||||
})
|
||||
|
||||
t.Run("validate_pre_funded_accounts", func(t *testing.T) {
|
||||
// Check pre-funded accounts from localnet
|
||||
acc0Addr := "idx1fcqk3crpnyvyhtd4jepsnx5eat5ehc920epq29"
|
||||
acc1Addr := "idx10n78mn09nx0f056wam35wkfvanf37kepuj28x4"
|
||||
|
||||
// Verify acc0 has balance
|
||||
balance0, err := cfg.Client.GetBalance(ctx, acc0Addr, cfg.StakingDenom)
|
||||
require.NoError(t, err, "failed to query acc0 balance")
|
||||
require.True(t, balance0.GT(math.ZeroInt()), "acc0 should have balance")
|
||||
|
||||
// Verify acc1 has balance
|
||||
balance1, err := cfg.Client.GetBalance(ctx, acc1Addr, cfg.StakingDenom)
|
||||
require.NoError(t, err, "failed to query acc1 balance")
|
||||
require.True(t, balance1.GT(math.ZeroInt()), "acc1 should have balance")
|
||||
})
|
||||
|
||||
t.Run("bank_params", func(t *testing.T) {
|
||||
bankParams, err := cfg.Client.GetBankParams(ctx)
|
||||
require.NoError(t, err, "failed to query bank params")
|
||||
require.NotNil(t, bankParams, "bank params should not be nil")
|
||||
})
|
||||
|
||||
t.Run("supply_queries", func(t *testing.T) {
|
||||
// Query total supply of test denom
|
||||
testSupply, err := cfg.Client.GetSupply(ctx, "test")
|
||||
require.NoError(t, err, "failed to query test supply")
|
||||
require.True(t, testSupply.GT(math.ZeroInt()), "test supply should be greater than zero")
|
||||
|
||||
// Query total supply of staking denom
|
||||
stakingSupply, err := cfg.Client.GetSupply(ctx, cfg.StakingDenom)
|
||||
require.NoError(t, err, "failed to query staking supply")
|
||||
require.True(t, stakingSupply.GT(math.ZeroInt()), "staking supply should be greater than zero")
|
||||
})
|
||||
|
||||
t.Run("balance_operations", func(t *testing.T) {
|
||||
// Use pre-funded account from localnet
|
||||
testAddr := "idx1fcqk3crpnyvyhtd4jepsnx5eat5ehc920epq29"
|
||||
|
||||
// Get all balances
|
||||
balances, err := cfg.Client.GetAllBalances(ctx, testAddr)
|
||||
require.NoError(t, err, "failed to query all balances")
|
||||
require.NotEmpty(t, balances, "user should have at least one balance")
|
||||
|
||||
// Check specific balance for staking denom
|
||||
balance, err := cfg.Client.GetBalance(ctx, testAddr, cfg.StakingDenom)
|
||||
require.NoError(t, err, "failed to query specific balance")
|
||||
require.True(t, balance.GT(math.ZeroInt()), "balance should be greater than zero")
|
||||
})
|
||||
}
|
||||
|
||||
func TestFaucetOperations(t *testing.T) {
|
||||
t.Skip("Skipping faucet tests - localnet doesn't have a faucet")
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fundAmount math.Int
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "normal_funding",
|
||||
fundAmount: math.NewInt(1_000_000),
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "large_funding",
|
||||
fundAmount: math.NewInt(100_000_000),
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "zero_funding",
|
||||
fundAmount: math.ZeroInt(),
|
||||
expectError: false, // Faucet should handle this gracefully
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
users := utils.GetDefaultTestUsers(tt.fundAmount, cfg.NormalDenom)
|
||||
testUser := users[0]
|
||||
|
||||
err := cfg.FaucetClient.FundTestUsers(ctx, []utils.CreateTestUser{testUser})
|
||||
if tt.expectError {
|
||||
require.Error(t, err, "expected funding to fail")
|
||||
} else {
|
||||
require.NoError(t, err, "funding should succeed")
|
||||
|
||||
// Wait for transaction to be included
|
||||
err = utils.WaitForBlocks(ctx, cfg, 2)
|
||||
require.NoError(t, err, "failed to wait for blocks")
|
||||
|
||||
// Verify balance if funding was expected to succeed
|
||||
if !tt.fundAmount.IsZero() {
|
||||
utils.AssertBalance(t, cfg, testUser.Address, testUser.Denom, testUser.Amount)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChainConnectivity(t *testing.T) {
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("rest_api_connectivity", func(t *testing.T) {
|
||||
// Test REST API connectivity by querying node info
|
||||
nodeInfo, err := cfg.Client.GetNodeInfo(ctx)
|
||||
require.NoError(t, err, "REST API should be accessible")
|
||||
require.Equal(t, cfg.ChainID, nodeInfo.DefaultNodeInfo.Network, "chain ID should match")
|
||||
})
|
||||
|
||||
t.Run("faucet_connectivity", func(t *testing.T) {
|
||||
t.Skip("Skipping faucet connectivity test - localnet doesn't have a faucet")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
package dex
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/sonr-io/sonr/test/e2e/utils"
|
||||
dextypes "github.com/sonr-io/sonr/x/dex/types"
|
||||
)
|
||||
|
||||
// TestDEXModuleOperations tests the DEX module E2E operations
|
||||
func TestDEXModuleOperations(t *testing.T) {
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("query_dex_params", func(t *testing.T) {
|
||||
// Query DEX module parameters
|
||||
resp, err := cfg.Client.QueryDEXParams(ctx)
|
||||
require.NoError(t, err, "failed to query DEX params")
|
||||
require.NotNil(t, resp, "DEX params should not be nil")
|
||||
require.True(t, resp.Params.Enabled, "DEX module should be enabled")
|
||||
})
|
||||
|
||||
t.Run("register_dex_account", func(t *testing.T) {
|
||||
// Register a DEX account for testing
|
||||
did := "did:sonr:e2e_test_user"
|
||||
connectionID := "connection-0"
|
||||
features := []string{"swap", "liquidity"}
|
||||
|
||||
msg := &dextypes.MsgRegisterDEXAccount{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
Features: features,
|
||||
}
|
||||
|
||||
// Sign and broadcast transaction
|
||||
txResp, err := cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, msg)
|
||||
require.NoError(t, err, "failed to register DEX account")
|
||||
require.Equal(t, uint32(0), txResp.Code, "transaction should succeed")
|
||||
|
||||
// Query the created account
|
||||
queryResp, err := cfg.Client.QueryDEXAccount(ctx, did, connectionID)
|
||||
require.NoError(t, err, "failed to query DEX account")
|
||||
require.NotNil(t, queryResp, "DEX account should exist")
|
||||
require.Equal(t, did, queryResp.Account.Did)
|
||||
require.Equal(t, connectionID, queryResp.Account.ConnectionId)
|
||||
})
|
||||
|
||||
t.Run("execute_swap", func(t *testing.T) {
|
||||
// Setup: Register account first
|
||||
did := "did:sonr:e2e_swap_user"
|
||||
connectionID := "connection-0"
|
||||
|
||||
registerMsg := &dextypes.MsgRegisterDEXAccount{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
Features: []string{"swap"},
|
||||
}
|
||||
|
||||
txResp, err := cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, registerMsg)
|
||||
require.NoError(t, err, "failed to register DEX account for swap")
|
||||
require.Equal(t, uint32(0), txResp.Code, "registration should succeed")
|
||||
|
||||
// Execute swap
|
||||
swapMsg := &dextypes.MsgExecuteSwap{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
SourceDenom: cfg.StakingDenom,
|
||||
TargetDenom: "uosmo",
|
||||
Amount: math.NewInt(1000),
|
||||
MinAmountOut: math.NewInt(900),
|
||||
Route: "pool:1",
|
||||
}
|
||||
|
||||
txResp, err = cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, swapMsg)
|
||||
require.NoError(t, err, "failed to execute swap")
|
||||
require.Equal(t, uint32(0), txResp.Code, "swap should succeed")
|
||||
})
|
||||
|
||||
t.Run("provide_liquidity", func(t *testing.T) {
|
||||
// Setup: Register account with liquidity feature
|
||||
did := "did:sonr:e2e_lp_user"
|
||||
connectionID := "connection-0"
|
||||
|
||||
registerMsg := &dextypes.MsgRegisterDEXAccount{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
Features: []string{"liquidity"},
|
||||
}
|
||||
|
||||
txResp, err := cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, registerMsg)
|
||||
require.NoError(t, err, "failed to register DEX account for liquidity")
|
||||
require.Equal(t, uint32(0), txResp.Code, "registration should succeed")
|
||||
|
||||
// Provide liquidity
|
||||
liquidityMsg := &dextypes.MsgProvideLiquidity{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
PoolId: "1",
|
||||
Assets: sdk.NewCoins(
|
||||
sdk.NewCoin(cfg.StakingDenom, math.NewInt(1000)),
|
||||
sdk.NewCoin("uosmo", math.NewInt(1000)),
|
||||
),
|
||||
MinShares: math.NewInt(100),
|
||||
Timeout: time.Now().Add(5 * time.Minute),
|
||||
}
|
||||
|
||||
txResp, err = cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, liquidityMsg)
|
||||
require.NoError(t, err, "failed to provide liquidity")
|
||||
require.Equal(t, uint32(0), txResp.Code, "liquidity provision should succeed")
|
||||
})
|
||||
|
||||
t.Run("create_limit_order", func(t *testing.T) {
|
||||
// Setup: Register account with order feature
|
||||
did := "did:sonr:e2e_order_user"
|
||||
connectionID := "connection-0"
|
||||
|
||||
registerMsg := &dextypes.MsgRegisterDEXAccount{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
Features: []string{"order"},
|
||||
}
|
||||
|
||||
txResp, err := cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, registerMsg)
|
||||
require.NoError(t, err, "failed to register DEX account for orders")
|
||||
require.Equal(t, uint32(0), txResp.Code, "registration should succeed")
|
||||
|
||||
// Create limit order
|
||||
orderMsg := &dextypes.MsgCreateLimitOrder{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
SellDenom: cfg.StakingDenom,
|
||||
BuyDenom: "uosmo",
|
||||
Amount: math.NewInt(1000),
|
||||
Price: math.LegacyNewDec(1),
|
||||
Expiration: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
txResp, err = cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, orderMsg)
|
||||
require.NoError(t, err, "failed to create limit order")
|
||||
require.Equal(t, uint32(0), txResp.Code, "order creation should succeed")
|
||||
|
||||
// TODO: Query and verify the order was created
|
||||
})
|
||||
|
||||
t.Run("query_dex_accounts", func(t *testing.T) {
|
||||
// Query all DEX accounts
|
||||
resp, err := cfg.Client.QueryAllDEXAccounts(ctx)
|
||||
require.NoError(t, err, "failed to query all DEX accounts")
|
||||
require.NotNil(t, resp, "response should not be nil")
|
||||
// Should have at least the accounts created in previous tests
|
||||
require.GreaterOrEqual(t, len(resp.Accounts), 1, "should have at least one account")
|
||||
})
|
||||
|
||||
t.Run("query_dex_history", func(t *testing.T) {
|
||||
// Query transaction history for a DID
|
||||
did := "did:sonr:e2e_swap_user"
|
||||
|
||||
resp, err := cfg.Client.QueryDEXHistory(ctx, did)
|
||||
require.NoError(t, err, "failed to query DEX history")
|
||||
require.NotNil(t, resp, "response should not be nil")
|
||||
// Should have at least one transaction from the swap test
|
||||
require.GreaterOrEqual(t, len(resp.History), 0, "history may be empty if ICA is not fully setup")
|
||||
})
|
||||
|
||||
t.Run("cancel_order", func(t *testing.T) {
|
||||
// Setup: Register account and create an order first
|
||||
did := "did:sonr:e2e_cancel_user"
|
||||
connectionID := "connection-0"
|
||||
|
||||
// Register account
|
||||
registerMsg := &dextypes.MsgRegisterDEXAccount{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
Features: []string{"order"},
|
||||
}
|
||||
|
||||
txResp, err := cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, registerMsg)
|
||||
require.NoError(t, err, "failed to register DEX account")
|
||||
require.Equal(t, uint32(0), txResp.Code, "registration should succeed")
|
||||
|
||||
// Create an order
|
||||
orderMsg := &dextypes.MsgCreateLimitOrder{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
SellDenom: cfg.StakingDenom,
|
||||
BuyDenom: "uosmo",
|
||||
Amount: math.NewInt(500),
|
||||
Price: math.LegacyNewDec(1),
|
||||
Expiration: time.Now().Add(24 * time.Hour),
|
||||
}
|
||||
|
||||
createResp, err := cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, orderMsg)
|
||||
require.NoError(t, err, "failed to create order")
|
||||
require.Equal(t, uint32(0), createResp.Code, "order creation should succeed")
|
||||
|
||||
// Extract order ID from events (mock for now)
|
||||
orderID := "order-1" // In real test, extract from createResp.Events
|
||||
|
||||
// Cancel the order
|
||||
cancelMsg := &dextypes.MsgCancelOrder{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
OrderId: orderID,
|
||||
}
|
||||
|
||||
cancelResp, err := cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, cancelMsg)
|
||||
require.NoError(t, err, "failed to cancel order")
|
||||
require.Equal(t, uint32(0), cancelResp.Code, "order cancellation should succeed")
|
||||
})
|
||||
|
||||
t.Run("remove_liquidity", func(t *testing.T) {
|
||||
// Setup: Register account and provide liquidity first
|
||||
did := "did:sonr:e2e_remove_lp_user"
|
||||
connectionID := "connection-0"
|
||||
|
||||
// Register account
|
||||
registerMsg := &dextypes.MsgRegisterDEXAccount{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
Features: []string{"liquidity"},
|
||||
}
|
||||
|
||||
txResp, err := cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, registerMsg)
|
||||
require.NoError(t, err, "failed to register DEX account")
|
||||
require.Equal(t, uint32(0), txResp.Code, "registration should succeed")
|
||||
|
||||
// First provide liquidity
|
||||
provideMsg := &dextypes.MsgProvideLiquidity{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
PoolId: "1",
|
||||
Assets: sdk.NewCoins(
|
||||
sdk.NewCoin(cfg.StakingDenom, math.NewInt(2000)),
|
||||
sdk.NewCoin("uosmo", math.NewInt(2000)),
|
||||
),
|
||||
MinShares: math.NewInt(200),
|
||||
Timeout: time.Now().Add(5 * time.Minute),
|
||||
}
|
||||
|
||||
txResp, err = cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, provideMsg)
|
||||
require.NoError(t, err, "failed to provide liquidity")
|
||||
require.Equal(t, uint32(0), txResp.Code, "liquidity provision should succeed")
|
||||
|
||||
// Remove liquidity
|
||||
removeMsg := &dextypes.MsgRemoveLiquidity{
|
||||
Did: did,
|
||||
ConnectionId: connectionID,
|
||||
PoolId: "1",
|
||||
Shares: math.NewInt(100),
|
||||
MinAmounts: sdk.NewCoins(
|
||||
sdk.NewCoin(cfg.StakingDenom, math.NewInt(900)),
|
||||
sdk.NewCoin("uosmo", math.NewInt(900)),
|
||||
),
|
||||
Timeout: time.Now().Add(5 * time.Minute),
|
||||
}
|
||||
|
||||
txResp, err = cfg.Client.SignAndBroadcastTx(ctx, cfg.TestAccount, removeMsg)
|
||||
require.NoError(t, err, "failed to remove liquidity")
|
||||
require.Equal(t, uint32(0), txResp.Code, "liquidity removal should succeed")
|
||||
})
|
||||
}
|
||||
|
||||
// TestDEXIBCIntegration tests IBC-related DEX operations
|
||||
func TestDEXIBCIntegration(t *testing.T) {
|
||||
t.Skip("Skipping IBC integration tests - requires full IBC setup")
|
||||
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("cross_chain_swap", func(t *testing.T) {
|
||||
// This test would require an actual IBC connection to another chain
|
||||
// For now, we skip it but document the expected behavior
|
||||
|
||||
// 1. Register ICA account on remote chain
|
||||
// 2. Fund the ICA account
|
||||
// 3. Execute swap on remote chain
|
||||
// 4. Verify swap execution through events/callbacks
|
||||
_ = cfg
|
||||
_ = ctx
|
||||
})
|
||||
|
||||
t.Run("multi_chain_accounts", func(t *testing.T) {
|
||||
// Test managing accounts across multiple chains
|
||||
// This would require multiple IBC connections
|
||||
|
||||
// 1. Register accounts on Osmosis, Cosmos Hub, etc.
|
||||
// 2. Query all accounts for a single DID
|
||||
// 3. Verify each account has different connection IDs
|
||||
_ = cfg
|
||||
_ = ctx
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package ibc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/sonr-io/sonr/test/e2e/utils"
|
||||
)
|
||||
|
||||
func TestIBCBasic(t *testing.T) {
|
||||
t.Skip("Skipping IBC tests - localnet doesn't have IBC channels")
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("ibc_channel_exists", func(t *testing.T) {
|
||||
// Verify that IBC transfer channels exist
|
||||
channelID := utils.AssertTransferChannelExists(t, cfg)
|
||||
require.NotEmpty(t, channelID, "transfer channel should exist")
|
||||
})
|
||||
|
||||
t.Run("ibc_channels_query", func(t *testing.T) {
|
||||
// Query all IBC channels
|
||||
channels, err := cfg.Client.GetChannels(ctx)
|
||||
require.NoError(t, err, "failed to query IBC channels")
|
||||
require.NotEmpty(t, channels.Channels, "should have at least one IBC channel")
|
||||
|
||||
// Verify we have transfer channels
|
||||
hasTransferChannel := false
|
||||
for _, channel := range channels.Channels {
|
||||
if channel.PortID == "transfer" {
|
||||
hasTransferChannel = true
|
||||
require.Equal(t, "STATE_OPEN", channel.State, "transfer channel should be open")
|
||||
break
|
||||
}
|
||||
}
|
||||
require.True(t, hasTransferChannel, "should have at least one transfer channel")
|
||||
})
|
||||
|
||||
t.Run("ibc_channel_details", func(t *testing.T) {
|
||||
// Get transfer channel ID
|
||||
channelID, err := cfg.Client.GetTransferChannel(ctx)
|
||||
require.NoError(t, err, "failed to get transfer channel")
|
||||
|
||||
// Query specific channel details
|
||||
channel, err := cfg.Client.GetChannel(ctx, "transfer", channelID)
|
||||
require.NoError(t, err, "failed to query channel details")
|
||||
require.NotNil(t, channel, "channel response should not be nil")
|
||||
require.Equal(t, "STATE_OPEN", channel.Channel.State.String(), "channel should be open")
|
||||
})
|
||||
}
|
||||
|
||||
func TestIBCDenomTrace(t *testing.T) {
|
||||
t.Skip("Skipping IBC tests - localnet doesn't have IBC channels")
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("denom_trace_generation", func(t *testing.T) {
|
||||
// Get transfer channel for testing
|
||||
channelID, err := cfg.Client.GetTransferChannel(ctx)
|
||||
require.NoError(t, err, "failed to get transfer channel")
|
||||
|
||||
// Generate IBC denom trace for testing
|
||||
denomTrace := transfertypes.ParseDenomTrace(
|
||||
transfertypes.GetPrefixedDenom("transfer", channelID, cfg.NormalDenom),
|
||||
)
|
||||
ibcDenom := denomTrace.IBCDenom()
|
||||
|
||||
require.NotEmpty(t, ibcDenom, "IBC denom should not be empty")
|
||||
require.Contains(t, ibcDenom, "ibc/", "IBC denom should have ibc/ prefix")
|
||||
})
|
||||
}
|
||||
|
||||
// TestIBCTransferSimulation tests IBC transfer logic without actual multi-chain setup
|
||||
func TestIBCTransferSimulation(t *testing.T) {
|
||||
t.Skip("Skipping IBC tests - localnet doesn't have IBC channels")
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
transferAmount math.Int
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "normal_transfer_amount",
|
||||
transferAmount: math.NewInt(1_000_000), // 1 SNR
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "large_transfer_amount",
|
||||
transferAmount: math.NewInt(50_000_000), // 50 SNR
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "zero_transfer_amount",
|
||||
transferAmount: math.ZeroInt(),
|
||||
expectError: true, // Should fail validation
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Setup test user with sufficient funds
|
||||
fundAmount := math.NewInt(100_000_000) // 100 SNR
|
||||
users := utils.SetupTestUsers(t, cfg, fundAmount)
|
||||
sourceUser := users[0]
|
||||
|
||||
// Verify user has sufficient balance before transfer
|
||||
if !tt.expectError && tt.transferAmount.GT(math.ZeroInt()) {
|
||||
utils.AssertBalanceGreaterThan(t, cfg, sourceUser.Address, sourceUser.Denom, tt.transferAmount)
|
||||
}
|
||||
|
||||
// Get transfer channel
|
||||
channelID, err := cfg.Client.GetTransferChannel(ctx)
|
||||
require.NoError(t, err, "failed to get transfer channel")
|
||||
|
||||
// Create IBC denom for destination
|
||||
denomTrace := transfertypes.ParseDenomTrace(
|
||||
transfertypes.GetPrefixedDenom("transfer", channelID, cfg.NormalDenom),
|
||||
)
|
||||
ibcDenom := denomTrace.IBCDenom()
|
||||
|
||||
// Validate transfer parameters
|
||||
if tt.expectError {
|
||||
require.True(t, tt.transferAmount.IsZero() || tt.transferAmount.IsNegative(),
|
||||
"invalid transfer amounts should be caught")
|
||||
} else {
|
||||
require.True(t, tt.transferAmount.GT(math.ZeroInt()),
|
||||
"valid transfer amounts should be positive")
|
||||
require.NotEmpty(t, ibcDenom, "IBC denom should be generated")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIBCConnectionStatus(t *testing.T) {
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("connection_existence", func(t *testing.T) {
|
||||
// Query channels to find connection information
|
||||
channels, err := cfg.Client.GetChannels(ctx)
|
||||
require.NoError(t, err, "failed to query channels")
|
||||
|
||||
if len(channels.Channels) > 0 {
|
||||
// Test connection details for first channel
|
||||
channel := channels.Channels[0]
|
||||
require.NotEmpty(t, channel.ConnectionHops, "channel should have connection hops")
|
||||
|
||||
if len(channel.ConnectionHops) > 0 {
|
||||
connectionID := channel.ConnectionHops[0]
|
||||
|
||||
// Query connection details
|
||||
connection, err := cfg.Client.GetConnection(ctx, connectionID)
|
||||
require.NoError(t, err, "failed to query connection")
|
||||
require.NotNil(t, connection, "connection should exist")
|
||||
require.Equal(t, "STATE_OPEN", connection.Connection.State, "connection should be open")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
# Event Emission E2E Tests
|
||||
|
||||
This directory contains comprehensive End-to-End (E2E) tests for event emissions across Sonr blockchain modules, specifically focusing on the newly implemented typed Protobuf events for the DID and DWN modules.
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### DID Module Events
|
||||
- `EventDIDCreated` - Emitted when a new DID is created
|
||||
- `EventDIDUpdated` - Emitted when a DID is updated
|
||||
- `EventDIDDeactivated` - Emitted when a DID is deactivated
|
||||
- `EventVerificationMethodAdded` - Emitted when a verification method is added
|
||||
- `EventVerificationMethodRemoved` - Emitted when a verification method is removed ⭐
|
||||
- `EventServiceAdded` - Emitted when a service is added to a DID ⭐
|
||||
- `EventServiceRemoved` - Emitted when a service is removed from a DID ⭐
|
||||
- `EventWebAuthnRegistered` - Emitted when a WebAuthn credential is registered ⭐
|
||||
- `EventExternalWalletLinked` - Emitted when an external wallet is linked ⭐
|
||||
|
||||
### DWN Module Events
|
||||
- `EventRecordWritten` - Emitted when a record is written to DWN
|
||||
- `EventRecordDeleted` - Emitted when a record is deleted from DWN
|
||||
- `EventProtocolConfigured` - Emitted when a protocol is configured ⭐
|
||||
- `EventPermissionGranted` - Emitted when a permission is granted ⭐
|
||||
- `EventPermissionRevoked` - Emitted when a permission is revoked ⭐
|
||||
- `EventVaultCreated` - Emitted when a vault is created ⭐
|
||||
- `EventVaultKeysRotated` - Emitted when vault keys are rotated ⭐
|
||||
|
||||
⭐ = Newly implemented events being tested
|
||||
|
||||
## Test Structure
|
||||
|
||||
### `events_test.go`
|
||||
|
||||
The main test file contains the following test suites:
|
||||
|
||||
#### `EventEmissionTestSuite`
|
||||
Main test suite that validates:
|
||||
|
||||
1. **Real Transaction Event Emissions** (`TestDIDModuleEventEmissions`, `TestDWNModuleEventEmissions`)
|
||||
- Executes actual transactions that trigger events
|
||||
- Verifies events are emitted correctly with proper attributes
|
||||
- Tests each event type individually
|
||||
|
||||
2. **Event Persistence and Replay** (`TestEventPersistenceAndReplay`)
|
||||
- Verifies events persist across multiple queries
|
||||
- Tests event queryability by attributes
|
||||
- Ensures event data consistency over time
|
||||
|
||||
3. **Event Querying** (`TestEventQuerying`)
|
||||
- Tests CometBFT query syntax patterns
|
||||
- Validates filtering by event type, creator, and custom attributes
|
||||
- Tests complex query conditions
|
||||
|
||||
4. **Multi-Event Transactions** (`TestMultiEventTransactions`)
|
||||
- Tests transactions that emit multiple events
|
||||
- Verifies correct event ordering
|
||||
- Validates block height consistency across events
|
||||
|
||||
5. **Event Subscription** (`TestEventSubscription`)
|
||||
- Tests WebSocket-based event subscription via CometBFT
|
||||
- Subscribes to new blocks, transactions, and custom events
|
||||
- Validates real-time event streaming
|
||||
|
||||
6. **Event Attribute Validation** (`TestEventAttributeValidation`)
|
||||
- Verifies all required attributes are present
|
||||
- Validates attribute values are correctly populated
|
||||
- Tests attribute consistency
|
||||
|
||||
## Client Extensions
|
||||
|
||||
### Enhanced StarshipClient (`client/chain.go`)
|
||||
|
||||
Extended the existing StarshipClient with comprehensive event querying capabilities:
|
||||
|
||||
- `QueryEventsByHeight(height)` - Query events by block height
|
||||
- `QueryEventsByType(eventType, minHeight, maxHeight)` - Query by event type
|
||||
- `QueryEventsByAttribute(key, value, minHeight, maxHeight)` - Query by attribute
|
||||
- `SearchEvents(query, minHeight, maxHeight)` - General CometBFT query search
|
||||
- `GetLatestBlockHeight()` - Get current block height
|
||||
- `WaitForNextBlock()` - Wait for next block production
|
||||
- `FilterEventsByType(events, eventType)` - Filter events by type
|
||||
- `GetEventAttribute(event, key)` - Extract specific attribute values
|
||||
|
||||
### WebSocket Client (`client/websocket.go`)
|
||||
|
||||
New WebSocket client for real-time event subscription:
|
||||
|
||||
- `Connect()` - Establish WebSocket connection to CometBFT
|
||||
- `Subscribe(query)` - Subscribe to events matching query
|
||||
- `SubscribeToNewBlocks()` - Subscribe to new block events
|
||||
- `SubscribeToTxEvents()` - Subscribe to transaction events
|
||||
- `SubscribeToDIDEvents()` - Subscribe to DID module events
|
||||
- `SubscribeToDWNEvents()` - Subscribe to DWN module events
|
||||
- `WaitForEvent(timeout, filter)` - Wait for specific events
|
||||
- `WaitForEventByType(timeout, eventType)` - Wait for events by type
|
||||
- `Unsubscribe()` - Unsubscribe from events
|
||||
|
||||
## Running the Tests
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Start the Sonr testnet:**
|
||||
```bash
|
||||
make testnet # or make start
|
||||
```
|
||||
|
||||
2. **Ensure IPFS is running** (required for DWN tests):
|
||||
```bash
|
||||
make ipfs-up
|
||||
```
|
||||
|
||||
3. **Verify chain is running:**
|
||||
```bash
|
||||
curl http://localhost:1317/cosmos/base/tendermint/v1beta1/node_info
|
||||
```
|
||||
|
||||
### Run Event Tests
|
||||
|
||||
```bash
|
||||
# Run all event tests
|
||||
cd test/e2e
|
||||
go test -v ./tests/modules/ -run TestEventEmission
|
||||
|
||||
# Run specific test suites
|
||||
go test -v ./tests/modules/ -run TestEventEmissionTestSuite/TestDIDModuleEventEmissions
|
||||
go test -v ./tests/modules/ -run TestEventEmissionTestSuite/TestEventSubscription
|
||||
go test -v ./tests/modules/ -run TestEventEmissionTestSuite/TestEventPersistenceAndReplay
|
||||
|
||||
# Run with detailed logging
|
||||
go test -v ./tests/modules/ -run TestEventEmission -args -test.v
|
||||
```
|
||||
|
||||
### Run Integration Tests (for comparison)
|
||||
```bash
|
||||
# Run the existing integration tests
|
||||
cd ../..
|
||||
go test -v ./test/ -run TestEventIntegration
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Default Test Configuration (`utils/utils.go`)
|
||||
|
||||
- **Chain ID**: `sonrtest_1-1`
|
||||
- **Base URL**: `http://localhost:1317` (REST API)
|
||||
- **WebSocket URL**: `ws://localhost:26657/websocket` (CometBFT WebSocket)
|
||||
- **Staking Denom**: `usnr`
|
||||
- **Normal Denom**: `snr`
|
||||
|
||||
### Pre-funded Test Accounts
|
||||
|
||||
The tests use pre-funded localnet accounts:
|
||||
- `idx1fcqk3crpnyvyhtd4jepsnx5eat5ehc920epq29` (Account 0)
|
||||
- `idx10n78mn09nx0f056wam35wkfvanf37kepuj28x4` (Account 1)
|
||||
- `idx1xygwjmmj8rq3rq3k4adqvhd55x5yqjc8ktcm7e` (Account 2)
|
||||
|
||||
## Implementation Status
|
||||
|
||||
### ✅ Completed Features
|
||||
|
||||
1. **Event Querying Infrastructure**
|
||||
- REST API event queries
|
||||
- Block height filtering
|
||||
- Attribute-based filtering
|
||||
- CometBFT query syntax support
|
||||
|
||||
2. **WebSocket Event Subscription**
|
||||
- Real-time event streaming
|
||||
- Custom query subscriptions
|
||||
- Event filtering and waiting
|
||||
|
||||
3. **Test Framework**
|
||||
- Comprehensive test structure
|
||||
- Mock transaction creation
|
||||
- Event validation helpers
|
||||
- Multi-event testing
|
||||
|
||||
### 🚧 In Progress / TODO
|
||||
|
||||
1. **Real Transaction Building**
|
||||
- Currently using mock transactions for testing
|
||||
- Need to implement actual DID/DWN message building and signing
|
||||
- Integration with existing transaction building utilities
|
||||
|
||||
2. **Complete Event Coverage**
|
||||
- Some event tests are marked as "Skip" pending real transaction implementation
|
||||
- Need to create actual transactions for each event type
|
||||
|
||||
3. **Chain Restart Testing**
|
||||
- Event persistence across chain restarts
|
||||
- Historical event replay validation
|
||||
|
||||
4. **Performance Testing**
|
||||
- Event query performance under load
|
||||
- WebSocket subscription scalability
|
||||
- Large event volume handling
|
||||
|
||||
## Key Testing Patterns
|
||||
|
||||
### Event Validation Pattern
|
||||
```go
|
||||
// 1. Execute transaction
|
||||
txResp := suite.createTestTransaction(...)
|
||||
|
||||
// 2. Wait for inclusion
|
||||
finalTx, err := suite.cfg.Client.WaitForTx(ctx, txResp.TxHash, 30*time.Second)
|
||||
|
||||
// 3. Filter and validate events
|
||||
events := client.FilterEventsByType(finalTx.TxResponse.Events, "EventType")
|
||||
require.NotEmpty(t, events, "should emit EventType")
|
||||
|
||||
// 4. Validate attributes
|
||||
event := events[0]
|
||||
value, found := client.GetEventAttribute(event, "key")
|
||||
require.True(t, found, "attribute should be present")
|
||||
require.Equal(t, expectedValue, value, "attribute value should match")
|
||||
```
|
||||
|
||||
### WebSocket Subscription Pattern
|
||||
```go
|
||||
// 1. Connect to WebSocket
|
||||
wsClient := client.NewWebSocketClient("ws://localhost:26657")
|
||||
err := wsClient.Connect(ctx)
|
||||
|
||||
// 2. Subscribe to events
|
||||
subscription, err := wsClient.Subscribe(ctx, "custom.query='value'")
|
||||
|
||||
// 3. Trigger event (execute transaction)
|
||||
txResp := suite.executeTransaction(...)
|
||||
|
||||
// 4. Wait for event
|
||||
event, err := subscription.WaitForEvent(ctx, 30*time.Second, filterFunc)
|
||||
```
|
||||
|
||||
### Query Testing Pattern
|
||||
```go
|
||||
// 1. Record start height
|
||||
startHeight, err := suite.cfg.Client.GetLatestBlockHeight(ctx)
|
||||
|
||||
// 2. Execute transactions
|
||||
// ... create multiple transactions
|
||||
|
||||
// 3. Query events with filters
|
||||
events, err := suite.cfg.Client.QueryEventsByType(ctx, "EventType", startHeight, 0)
|
||||
|
||||
// 4. Validate results
|
||||
require.GreaterOrEqual(t, len(events.Events), expectedCount)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **WebSocket Connection Failed**
|
||||
- Ensure CometBFT is running on port 26657
|
||||
- Check WebSocket endpoint configuration
|
||||
- Verify network connectivity
|
||||
|
||||
2. **Event Not Found**
|
||||
- Verify transaction was actually executed
|
||||
- Check event type spelling and case sensitivity
|
||||
- Confirm transaction succeeded (code = 0)
|
||||
|
||||
3. **Query Timeout**
|
||||
- Increase timeout values for slow networks
|
||||
- Check block production is active
|
||||
- Verify query syntax is correct
|
||||
|
||||
4. **Missing Events**
|
||||
- Ensure event emission is implemented in keeper
|
||||
- Verify protobuf event definitions match
|
||||
- Check transaction actually triggered the event
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Check chain status
|
||||
curl http://localhost:1317/cosmos/base/tendermint/v1beta1/node_info
|
||||
|
||||
# Query latest block
|
||||
curl http://localhost:1317/cosmos/base/tendermint/v1beta1/blocks/latest
|
||||
|
||||
# Check WebSocket endpoint
|
||||
curl -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Key: test" -H "Sec-WebSocket-Version: 13" http://localhost:26657/websocket
|
||||
|
||||
# Query specific transaction
|
||||
curl http://localhost:1317/cosmos/tx/v1beta1/txs/{TX_HASH}
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Event Analytics Dashboard** - Real-time event monitoring and analytics
|
||||
2. **Event Replay Service** - Historical event streaming service
|
||||
3. **Event Benchmarking** - Performance testing for high event volumes
|
||||
4. **Cross-Chain Event Testing** - IBC event emission testing
|
||||
5. **Event Schema Validation** - Automatic protobuf schema compliance testing
|
||||
@@ -0,0 +1,615 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/sonr-io/sonr/test/e2e/client"
|
||||
"github.com/sonr-io/sonr/test/e2e/utils"
|
||||
)
|
||||
|
||||
// EventEmissionTestSuite tests comprehensive event emissions across modules
|
||||
type EventEmissionTestSuite struct {
|
||||
suite.Suite
|
||||
cfg *utils.TestConfig
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
// Test user addresses - using pre-funded localnet accounts
|
||||
userAddrs []string
|
||||
}
|
||||
|
||||
func TestEventEmissionTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(EventEmissionTestSuite))
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) SetupSuite() {
|
||||
suite.cfg = utils.NewTestConfig()
|
||||
suite.ctx, suite.cancel = context.WithTimeout(context.Background(), 10*time.Minute)
|
||||
|
||||
// Use pre-funded accounts from localnet
|
||||
suite.userAddrs = []string{
|
||||
"idx1fcqk3crpnyvyhtd4jepsnx5eat5ehc920epq29", // Pre-funded account 0
|
||||
"idx10n78mn09nx0f056wam35wkfvanf37kepuj28x4", // Pre-funded account 1
|
||||
"idx1xygwjmmj8rq3rq3k4adqvhd55x5yqjc8ktcm7e", // Pre-funded account 2
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) TearDownSuite() {
|
||||
if suite.cancel != nil {
|
||||
suite.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// TestDIDModuleEventEmissions tests all DID module events
|
||||
func (suite *EventEmissionTestSuite) TestDIDModuleEventEmissions() {
|
||||
suite.T().Log("Testing DID module event emissions")
|
||||
|
||||
// Get current block height to filter events
|
||||
startHeight, err := suite.cfg.Client.GetLatestBlockHeight(suite.ctx)
|
||||
require.NoError(suite.T(), err, "failed to get start height")
|
||||
|
||||
suite.T().Run("EventDIDCreated", func(t *testing.T) {
|
||||
suite.testDIDCreatedEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventVerificationMethodRemoved", func(t *testing.T) {
|
||||
suite.testVerificationMethodRemovedEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventServiceAdded", func(t *testing.T) {
|
||||
suite.testServiceAddedEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventServiceRemoved", func(t *testing.T) {
|
||||
suite.testServiceRemovedEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventWebAuthnRegistered", func(t *testing.T) {
|
||||
suite.testWebAuthnRegisteredEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventExternalWalletLinked", func(t *testing.T) {
|
||||
suite.testExternalWalletLinkedEvent(t, startHeight)
|
||||
})
|
||||
}
|
||||
|
||||
// TestDWNModuleEventEmissions tests all DWN module events
|
||||
func (suite *EventEmissionTestSuite) TestDWNModuleEventEmissions() {
|
||||
suite.T().Log("Testing DWN module event emissions")
|
||||
|
||||
// Get current block height to filter events
|
||||
startHeight, err := suite.cfg.Client.GetLatestBlockHeight(suite.ctx)
|
||||
require.NoError(suite.T(), err, "failed to get start height")
|
||||
|
||||
suite.T().Run("EventRecordWritten", func(t *testing.T) {
|
||||
suite.testRecordWrittenEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventProtocolConfigured", func(t *testing.T) {
|
||||
suite.testProtocolConfiguredEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventPermissionGranted", func(t *testing.T) {
|
||||
suite.testPermissionGrantedEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventPermissionRevoked", func(t *testing.T) {
|
||||
suite.testPermissionRevokedEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventVaultCreated", func(t *testing.T) {
|
||||
suite.testVaultCreatedEvent(t, startHeight)
|
||||
})
|
||||
|
||||
suite.T().Run("EventVaultKeysRotated", func(t *testing.T) {
|
||||
suite.testVaultKeysRotatedEvent(t, startHeight)
|
||||
})
|
||||
}
|
||||
|
||||
// TestEventPersistenceAndReplay tests that events persist and can be replayed
|
||||
func (suite *EventEmissionTestSuite) TestEventPersistenceAndReplay() {
|
||||
suite.T().Log("Testing event persistence and replay")
|
||||
|
||||
// Record the current height
|
||||
currentHeight, err := suite.cfg.Client.GetLatestBlockHeight(suite.ctx)
|
||||
require.NoError(suite.T(), err, "failed to get current height")
|
||||
|
||||
// Create a test DID to generate events
|
||||
testDID := fmt.Sprintf("did:sonr:persistence-test-%d", time.Now().Unix())
|
||||
txResp := suite.createTestDID(suite.T(), testDID, suite.userAddrs[0])
|
||||
|
||||
// Wait for transaction to be included
|
||||
_, err = suite.cfg.Client.WaitForTx(suite.ctx, txResp.TxHash, 30*time.Second)
|
||||
require.NoError(suite.T(), err, "failed to wait for transaction")
|
||||
|
||||
// Get the block height where the transaction was included
|
||||
txHeight := txResp.Height
|
||||
txHeightInt, err := strconv.ParseInt(txHeight, 10, 64)
|
||||
require.NoError(suite.T(), err, "failed to parse tx height")
|
||||
|
||||
suite.T().Run("events_persist_across_queries", func(t *testing.T) {
|
||||
// Query events by height multiple times to ensure consistency
|
||||
for i := 0; i < 3; i++ {
|
||||
blockEvents, err := suite.cfg.Client.QueryEventsByHeight(suite.ctx, txHeightInt)
|
||||
require.NoError(t, err, "failed to query events by height on attempt %d", i+1)
|
||||
require.NotNil(t, blockEvents, "block events should not be nil")
|
||||
|
||||
// Verify that the same events are returned each time
|
||||
found := false
|
||||
for _, txEvents := range blockEvents.TxEvents {
|
||||
if txEvents.TxHash == txResp.TxHash {
|
||||
found = true
|
||||
// Verify DID created event is present (simplified check)
|
||||
require.NotEmpty(t, txEvents.Events, "transaction should have events")
|
||||
break
|
||||
}
|
||||
}
|
||||
require.True(t, found, "transaction events should be found in block events")
|
||||
}
|
||||
})
|
||||
|
||||
suite.T().Run("events_queryable_by_attribute", func(t *testing.T) {
|
||||
// Query events by DID attribute
|
||||
events, err := suite.cfg.Client.QueryEventsByAttribute(suite.ctx, "did", testDID, currentHeight, 0)
|
||||
require.NoError(t, err, "failed to query events by attribute")
|
||||
|
||||
// Should find at least the DID creation event
|
||||
foundDIDEvent := false
|
||||
for _, event := range events.Events {
|
||||
if event.Type == "did.v1.EventDIDCreated" {
|
||||
foundDIDEvent = true
|
||||
break
|
||||
}
|
||||
}
|
||||
require.True(t, foundDIDEvent, "should find DID created event by attribute query")
|
||||
})
|
||||
}
|
||||
|
||||
// TestEventQuerying tests various CometBFT query syntax patterns
|
||||
func (suite *EventEmissionTestSuite) TestEventQuerying() {
|
||||
suite.T().Log("Testing event querying with CometBFT syntax")
|
||||
|
||||
startHeight, err := suite.cfg.Client.GetLatestBlockHeight(suite.ctx)
|
||||
require.NoError(suite.T(), err, "failed to get start height")
|
||||
|
||||
// Create multiple test DIDs for complex querying
|
||||
testDIDs := []string{
|
||||
fmt.Sprintf("did:sonr:query-test-1-%d", time.Now().Unix()),
|
||||
fmt.Sprintf("did:sonr:query-test-2-%d", time.Now().Unix()),
|
||||
fmt.Sprintf("did:sonr:query-test-3-%d", time.Now().Unix()),
|
||||
}
|
||||
|
||||
var txHashes []string
|
||||
for i, testDID := range testDIDs {
|
||||
txResp := suite.createTestDID(suite.T(), testDID, suite.userAddrs[i%len(suite.userAddrs)])
|
||||
txHashes = append(txHashes, txResp.TxHash)
|
||||
|
||||
// Wait for transaction
|
||||
_, err = suite.cfg.Client.WaitForTx(suite.ctx, txResp.TxHash, 30*time.Second)
|
||||
require.NoError(suite.T(), err, "failed to wait for transaction %s", txResp.TxHash)
|
||||
}
|
||||
|
||||
endHeight, err := suite.cfg.Client.GetLatestBlockHeight(suite.ctx)
|
||||
require.NoError(suite.T(), err, "failed to get end height")
|
||||
|
||||
suite.T().Run("query_by_event_type", func(t *testing.T) {
|
||||
events, err := suite.cfg.Client.QueryEventsByType(suite.ctx, "did.v1.EventDIDCreated", startHeight, endHeight)
|
||||
require.NoError(t, err, "failed to query by event type")
|
||||
|
||||
// Should find at least our test events
|
||||
foundCount := 0
|
||||
for _, event := range events.Events {
|
||||
if event.Type == "did.v1.EventDIDCreated" {
|
||||
foundCount++
|
||||
}
|
||||
}
|
||||
require.GreaterOrEqual(t, foundCount, len(testDIDs), "should find at least %d DID created events", len(testDIDs))
|
||||
})
|
||||
|
||||
suite.T().Run("query_by_creator", func(t *testing.T) {
|
||||
// Query events by specific creator
|
||||
events, err := suite.cfg.Client.QueryEventsByAttribute(suite.ctx, "creator", suite.userAddrs[0], startHeight, endHeight)
|
||||
require.NoError(t, err, "failed to query by creator")
|
||||
|
||||
// Should find events created by this user
|
||||
foundUserEvents := false
|
||||
for _, event := range events.Events {
|
||||
if event.Type == "did.v1.EventDIDCreated" {
|
||||
foundUserEvents = true
|
||||
break
|
||||
}
|
||||
}
|
||||
require.True(t, foundUserEvents, "should find events created by specific user")
|
||||
})
|
||||
|
||||
suite.T().Run("complex_query_patterns", func(t *testing.T) {
|
||||
// Test complex query with multiple conditions
|
||||
query := fmt.Sprintf("message.sender='%s' AND tx.height>=%d", suite.userAddrs[0], startHeight)
|
||||
events, err := suite.cfg.Client.SearchEvents(suite.ctx, query, startHeight, endHeight)
|
||||
require.NoError(t, err, "failed to execute complex query")
|
||||
|
||||
// Should find some events
|
||||
require.NotEmpty(t, events.Events, "complex query should return some events")
|
||||
})
|
||||
}
|
||||
|
||||
// TestMultiEventTransactions tests transactions that emit multiple events
|
||||
func (suite *EventEmissionTestSuite) TestMultiEventTransactions() {
|
||||
suite.T().Log("Testing multi-event transactions")
|
||||
|
||||
// Create a DID with multiple verification methods and services
|
||||
// This should emit multiple events in a single transaction
|
||||
testDID := fmt.Sprintf("did:sonr:multi-event-test-%d", time.Now().Unix())
|
||||
|
||||
// For this test, we'll simulate a transaction that creates a DID with services
|
||||
// which should emit both EventDIDCreated and EventServiceAdded
|
||||
txResp := suite.createTestDIDWithService(suite.T(), testDID, suite.userAddrs[0])
|
||||
|
||||
// Wait for transaction to be included
|
||||
finalTx, err := suite.cfg.Client.WaitForTx(suite.ctx, txResp.TxHash, 30*time.Second)
|
||||
require.NoError(suite.T(), err, "failed to wait for transaction")
|
||||
|
||||
// Verify multiple events were emitted in the correct order
|
||||
events := finalTx.TxResponse.Events
|
||||
require.NotEmpty(suite.T(), events, "transaction should emit events")
|
||||
|
||||
// Look for DID creation events
|
||||
didCreatedEvents := client.FilterEventsByType(events, "EventDIDCreated")
|
||||
require.NotEmpty(suite.T(), didCreatedEvents, "should emit EventDIDCreated")
|
||||
|
||||
// Look for service addition events if services were added
|
||||
serviceAddedEvents := client.FilterEventsByType(events, "EventServiceAdded")
|
||||
// Note: This might be empty if the current implementation doesn't emit service events during DID creation
|
||||
_ = serviceAddedEvents // Avoid unused variable warning
|
||||
|
||||
suite.T().Run("events_have_correct_order", func(t *testing.T) {
|
||||
// Events should be in a logical order
|
||||
// For DID creation, EventDIDCreated should come before any EventServiceAdded
|
||||
didCreatedIndex := -1
|
||||
serviceAddedIndex := -1
|
||||
|
||||
for i, event := range events {
|
||||
if event.Type == "did.v1.EventDIDCreated" {
|
||||
didCreatedIndex = i
|
||||
}
|
||||
if event.Type == "did.v1.EventServiceAdded" {
|
||||
serviceAddedIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
require.NotEqual(t, -1, didCreatedIndex, "should find EventDIDCreated")
|
||||
|
||||
if serviceAddedIndex != -1 {
|
||||
require.Less(t, didCreatedIndex, serviceAddedIndex, "EventDIDCreated should come before EventServiceAdded")
|
||||
}
|
||||
})
|
||||
|
||||
suite.T().Run("events_have_consistent_block_height", func(t *testing.T) {
|
||||
// All events in the same transaction should have the same block height
|
||||
expectedHeight := finalTx.TxResponse.Height
|
||||
|
||||
for _, event := range events {
|
||||
// Check if this is one of our custom events
|
||||
if event.Type == "did.v1.EventDIDCreated" || event.Type == "did.v1.EventServiceAdded" {
|
||||
// Verify block height attribute if present
|
||||
if blockHeight, found := client.GetEventAttribute(event, "block_height"); found {
|
||||
require.Equal(t, expectedHeight, blockHeight, "event block height should match transaction height")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestEventSubscription tests WebSocket event subscription
|
||||
func (suite *EventEmissionTestSuite) TestEventSubscription() {
|
||||
suite.T().Log("Testing event subscription via WebSocket")
|
||||
|
||||
// Create WebSocket client
|
||||
wsClient := client.NewWebSocketClient("ws://localhost:26657") // CometBFT WebSocket endpoint
|
||||
err := wsClient.Connect(suite.ctx)
|
||||
if err != nil {
|
||||
suite.T().Skipf("WebSocket connection failed, skipping subscription tests: %v", err)
|
||||
return
|
||||
}
|
||||
defer wsClient.Close()
|
||||
|
||||
suite.T().Run("subscribe_to_new_blocks", func(t *testing.T) {
|
||||
// Subscribe to new block events
|
||||
subscription, err := wsClient.SubscribeToNewBlockHeaders(suite.ctx)
|
||||
require.NoError(t, err, "failed to subscribe to new block headers")
|
||||
defer subscription.Close()
|
||||
|
||||
// Wait for at least one block event
|
||||
event, err := subscription.WaitForEvent(suite.ctx, 30*time.Second, nil)
|
||||
require.NoError(t, err, "failed to receive block event")
|
||||
require.NotNil(t, event, "block event should not be nil")
|
||||
|
||||
t.Logf("Received block event: %+v", event)
|
||||
})
|
||||
|
||||
suite.T().Run("subscribe_to_tx_events", func(t *testing.T) {
|
||||
// Subscribe to transaction events
|
||||
subscription, err := wsClient.SubscribeToTxEvents(suite.ctx)
|
||||
require.NoError(t, err, "failed to subscribe to transaction events")
|
||||
defer subscription.Close()
|
||||
|
||||
// Create a transaction to trigger an event
|
||||
testDID := fmt.Sprintf("did:sonr:websocket-test-%d", time.Now().Unix())
|
||||
txResp := suite.createTestDID(t, testDID, suite.userAddrs[0])
|
||||
|
||||
// Wait for the transaction event
|
||||
event, err := subscription.WaitForEvent(suite.ctx, 30*time.Second, func(event *client.SubscriptionEvent) bool {
|
||||
// Check if this event relates to our transaction
|
||||
eventStr := fmt.Sprintf("%v", event.Data.Value)
|
||||
return strings.Contains(eventStr, txResp.TxHash)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Logf("Transaction event subscription test skipped (requires real transactions): %v", err)
|
||||
} else {
|
||||
require.NotNil(t, event, "transaction event should not be nil")
|
||||
t.Logf("Received transaction event: %+v", event)
|
||||
}
|
||||
})
|
||||
|
||||
suite.T().Run("subscribe_to_did_events", func(t *testing.T) {
|
||||
// Subscribe to DID-specific events
|
||||
subscription, err := wsClient.SubscribeToDIDEvents(suite.ctx)
|
||||
if err != nil {
|
||||
t.Skipf("DID event subscription failed (may require specific CometBFT configuration): %v", err)
|
||||
return
|
||||
}
|
||||
defer subscription.Close()
|
||||
|
||||
// Create a DID to trigger an event
|
||||
testDID := fmt.Sprintf("did:sonr:did-sub-test-%d", time.Now().Unix())
|
||||
_ = suite.createTestDID(t, testDID, suite.userAddrs[0])
|
||||
|
||||
// Wait for the DID event
|
||||
event, err := subscription.WaitForEventByType(suite.ctx, 30*time.Second, "EventDIDCreated")
|
||||
if err != nil {
|
||||
t.Logf("DID event subscription test skipped (requires real DID transactions): %v", err)
|
||||
} else {
|
||||
require.NotNil(t, event, "DID event should not be nil")
|
||||
t.Logf("Received DID event: %+v", event)
|
||||
}
|
||||
})
|
||||
|
||||
suite.T().Run("subscribe_with_custom_query", func(t *testing.T) {
|
||||
// Subscribe to events with a custom query
|
||||
customQuery := "tx.height > 1"
|
||||
subscription, err := wsClient.Subscribe(suite.ctx, customQuery)
|
||||
require.NoError(t, err, "failed to subscribe with custom query")
|
||||
defer subscription.Close()
|
||||
|
||||
// Wait for any event matching the query
|
||||
event, err := subscription.WaitForEvent(suite.ctx, 30*time.Second, nil)
|
||||
if err != nil {
|
||||
t.Logf("Custom query subscription test result: %v", err)
|
||||
} else {
|
||||
require.NotNil(t, event, "custom query event should not be nil")
|
||||
t.Logf("Received custom query event: %+v", event)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestEventAttributeValidation tests that event attributes are correctly populated
|
||||
func (suite *EventEmissionTestSuite) TestEventAttributeValidation() {
|
||||
suite.T().Log("Testing event attribute validation")
|
||||
|
||||
testDID := fmt.Sprintf("did:sonr:attr-test-%d", time.Now().Unix())
|
||||
creator := suite.userAddrs[0]
|
||||
|
||||
// Create a test DID
|
||||
txResp := suite.createTestDID(suite.T(), testDID, creator)
|
||||
|
||||
// Wait for transaction
|
||||
finalTx, err := suite.cfg.Client.WaitForTx(suite.ctx, txResp.TxHash, 30*time.Second)
|
||||
require.NoError(suite.T(), err, "failed to wait for transaction")
|
||||
|
||||
// Find the DID created event
|
||||
events := finalTx.TxResponse.Events
|
||||
didCreatedEvents := client.FilterEventsByType(events, "EventDIDCreated")
|
||||
require.NotEmpty(suite.T(), didCreatedEvents, "should emit EventDIDCreated")
|
||||
|
||||
didEvent := didCreatedEvents[0]
|
||||
|
||||
suite.T().Run("required_attributes_present", func(t *testing.T) {
|
||||
// Check that required attributes are present
|
||||
requiredAttrs := []string{"did", "creator"}
|
||||
|
||||
for _, requiredAttr := range requiredAttrs {
|
||||
value, found := client.GetEventAttribute(didEvent, requiredAttr)
|
||||
require.True(t, found, "attribute %s should be present", requiredAttr)
|
||||
require.NotEmpty(t, value, "attribute %s should not be empty", requiredAttr)
|
||||
}
|
||||
})
|
||||
|
||||
suite.T().Run("attribute_values_correct", func(t *testing.T) {
|
||||
// Verify specific attribute values
|
||||
if didValue, found := client.GetEventAttribute(didEvent, "did"); found {
|
||||
require.Contains(t, didValue, testDID, "DID attribute should contain test DID")
|
||||
}
|
||||
|
||||
if creatorValue, found := client.GetEventAttribute(didEvent, "creator"); found {
|
||||
require.Contains(t, creatorValue, creator, "creator attribute should contain creator address")
|
||||
}
|
||||
|
||||
// Check for block height if present
|
||||
if heightValue, found := client.GetEventAttribute(didEvent, "block_height"); found {
|
||||
require.NotEmpty(t, heightValue, "block height should not be empty")
|
||||
require.Equal(t, finalTx.TxResponse.Height, heightValue, "block height should match transaction height")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Helper methods for creating test transactions
|
||||
|
||||
func (suite *EventEmissionTestSuite) createTestDID(t *testing.T, didID, creator string) *client.TxResponse {
|
||||
// This is a placeholder - in a real implementation, you would:
|
||||
// 1. Build a proper MsgCreateDID transaction
|
||||
// 2. Sign it with the creator's key
|
||||
// 3. Broadcast it to the network
|
||||
|
||||
// For now, we'll simulate this by creating a mock transaction response
|
||||
// In the actual implementation, you would use the actual transaction building logic
|
||||
|
||||
t.Logf("Creating test DID: %s by creator: %s", didID, creator)
|
||||
|
||||
// Placeholder - replace with actual transaction building and broadcasting
|
||||
return &client.TxResponse{
|
||||
TxHash: fmt.Sprintf("mock-tx-%d", time.Now().Unix()),
|
||||
Code: 0,
|
||||
Height: fmt.Sprintf("%d", time.Now().Unix()),
|
||||
Events: []struct {
|
||||
Type string `json:"type"`
|
||||
Attributes []struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
} `json:"attributes"`
|
||||
}{
|
||||
{
|
||||
Type: "did.v1.EventDIDCreated",
|
||||
Attributes: []struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}{
|
||||
{Key: "did", Value: didID},
|
||||
{Key: "creator", Value: creator},
|
||||
{Key: "block_height", Value: fmt.Sprintf("%d", time.Now().Unix())},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) createTestDIDWithService(t *testing.T, didID, creator string) *client.TxResponse {
|
||||
// Similar to createTestDID but includes service creation
|
||||
t.Logf("Creating test DID with service: %s by creator: %s", didID, creator)
|
||||
|
||||
return &client.TxResponse{
|
||||
TxHash: fmt.Sprintf("mock-tx-with-service-%d", time.Now().Unix()),
|
||||
Code: 0,
|
||||
Height: fmt.Sprintf("%d", time.Now().Unix()),
|
||||
Events: []struct {
|
||||
Type string `json:"type"`
|
||||
Attributes []struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
} `json:"attributes"`
|
||||
}{
|
||||
{
|
||||
Type: "did.v1.EventDIDCreated",
|
||||
Attributes: []struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}{
|
||||
{Key: "did", Value: didID},
|
||||
{Key: "creator", Value: creator},
|
||||
{Key: "block_height", Value: fmt.Sprintf("%d", time.Now().Unix())},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "did.v1.EventServiceAdded",
|
||||
Attributes: []struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}{
|
||||
{Key: "did", Value: didID},
|
||||
{Key: "service_id", Value: didID + "#service-1"},
|
||||
{Key: "type", Value: "LinkedDomains"},
|
||||
{Key: "endpoint", Value: "https://example.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Individual event test methods
|
||||
|
||||
func (suite *EventEmissionTestSuite) testDIDCreatedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventDIDCreated emission")
|
||||
|
||||
testDID := fmt.Sprintf("did:sonr:created-test-%d", time.Now().Unix())
|
||||
txResp := suite.createTestDID(t, testDID, suite.userAddrs[0])
|
||||
|
||||
// Verify event was emitted
|
||||
didEvents := client.FilterEventsByType(txResp.Events, "EventDIDCreated")
|
||||
require.NotEmpty(t, didEvents, "should emit EventDIDCreated")
|
||||
|
||||
// Verify event attributes
|
||||
didEvent := didEvents[0]
|
||||
didValue, found := client.GetEventAttribute(didEvent, "did")
|
||||
require.True(t, found, "DID attribute should be present")
|
||||
require.Contains(t, didValue, testDID, "DID value should match")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testVerificationMethodRemovedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventVerificationMethodRemoved emission")
|
||||
// Implementation would involve:
|
||||
// 1. Create a DID with verification methods
|
||||
// 2. Remove a verification method
|
||||
// 3. Verify EventVerificationMethodRemoved is emitted
|
||||
t.Skip("Implementation requires actual transaction building - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testServiceAddedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventServiceAdded emission")
|
||||
// Implementation would involve:
|
||||
// 1. Create or update a DID to add a service
|
||||
// 2. Verify EventServiceAdded is emitted with correct attributes
|
||||
t.Skip("Implementation requires actual transaction building - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testServiceRemovedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventServiceRemoved emission")
|
||||
t.Skip("Implementation requires actual transaction building - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testWebAuthnRegisteredEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventWebAuthnRegistered emission")
|
||||
t.Skip("Implementation requires actual WebAuthn transaction building - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testExternalWalletLinkedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventExternalWalletLinked emission")
|
||||
t.Skip("Implementation requires actual wallet linking transaction - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testRecordWrittenEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventRecordWritten emission")
|
||||
t.Skip("Implementation requires actual DWN record transaction building - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testProtocolConfiguredEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventProtocolConfigured emission")
|
||||
t.Skip("Implementation requires actual protocol configuration transaction - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testPermissionGrantedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventPermissionGranted emission")
|
||||
t.Skip("Implementation requires actual permission granting transaction - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testPermissionRevokedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventPermissionRevoked emission")
|
||||
t.Skip("Implementation requires actual permission revocation transaction - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testVaultCreatedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventVaultCreated emission")
|
||||
t.Skip("Implementation requires actual vault creation transaction - placeholder for future implementation")
|
||||
}
|
||||
|
||||
func (suite *EventEmissionTestSuite) testVaultKeysRotatedEvent(t *testing.T, startHeight int64) {
|
||||
t.Log("Testing EventVaultKeysRotated emission")
|
||||
t.Skip("Implementation requires actual key rotation transaction - placeholder for future implementation")
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/sonr-io/sonr/test/e2e/utils"
|
||||
)
|
||||
|
||||
func TestSvcModule(t *testing.T) {
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("svc_params", func(t *testing.T) {
|
||||
// Query service module parameters
|
||||
url := cfg.BaseURL + "/sonr/svc/v1/params"
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
require.NoError(t, err, "failed to create request")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err, "failed to query svc params")
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Accept 501 Not Implemented for now as the endpoint may not be ready
|
||||
if resp.StatusCode == http.StatusNotImplemented {
|
||||
t.Skip("SVC params endpoint not implemented yet")
|
||||
}
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, "svc params query should succeed")
|
||||
})
|
||||
|
||||
t.Run("svc_integration", func(t *testing.T) {
|
||||
// Use pre-funded account from localnet
|
||||
testAddr := "idx1fcqk3crpnyvyhtd4jepsnx5eat5ehc920epq29"
|
||||
|
||||
// Verify user has balance for service operations
|
||||
balance, err := cfg.Client.GetBalance(ctx, testAddr, cfg.StakingDenom)
|
||||
require.NoError(t, err, "failed to query balance")
|
||||
require.True(t, balance.GT(math.ZeroInt()), "should have balance for operations")
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokenFactoryModule(t *testing.T) {
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("tokenfactory_params", func(t *testing.T) {
|
||||
// Query tokenfactory module parameters
|
||||
url := cfg.BaseURL + "/osmosis/tokenfactory/v1beta1/params"
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
require.NoError(t, err, "failed to create request")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err, "failed to query tokenfactory params")
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Note: This might return 404 if tokenfactory endpoint is different
|
||||
// or module is not enabled, which is acceptable
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, "tokenfactory params query should succeed when available")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDIDModule(t *testing.T) {
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("did_params", func(t *testing.T) {
|
||||
// Query DID module parameters
|
||||
url := cfg.BaseURL + "/sonr/did/v1/params"
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
require.NoError(t, err, "failed to create request")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err, "failed to query did params")
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Accept 501 Not Implemented for now as the endpoint may not be ready
|
||||
if resp.StatusCode == http.StatusNotImplemented {
|
||||
t.Skip("DID params endpoint not implemented yet")
|
||||
}
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, "did params query should succeed")
|
||||
})
|
||||
|
||||
t.Run("did_functionality", func(t *testing.T) {
|
||||
// Use pre-funded account from localnet
|
||||
testAddr := "idx1fcqk3crpnyvyhtd4jepsnx5eat5ehc920epq29"
|
||||
|
||||
// Verify user has balance for DID operations
|
||||
balance, err := cfg.Client.GetBalance(ctx, testAddr, cfg.StakingDenom)
|
||||
require.NoError(t, err, "failed to query balance")
|
||||
require.True(t, balance.GT(math.NewInt(1_000_000)), "should have sufficient balance for DID operations")
|
||||
})
|
||||
}
|
||||
|
||||
func TestDWNModule(t *testing.T) {
|
||||
cfg := utils.NewTestConfig()
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("dwn_params", func(t *testing.T) {
|
||||
// Query DWN module parameters
|
||||
url := cfg.BaseURL + "/sonr/dwn/v1/params"
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
require.NoError(t, err, "failed to create request")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err, "failed to query dwn params")
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Accept 501 Not Implemented for now as the endpoint may not be ready
|
||||
if resp.StatusCode == http.StatusNotImplemented {
|
||||
t.Skip("DWN params endpoint not implemented yet")
|
||||
}
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode, "dwn params query should succeed")
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user