Skip to content

Commit

Permalink
[SDP-1375] e2e tests on futurenet (#472)
Browse files Browse the repository at this point in the history
### What

Update e2e tests with a use case for futurenet.

### Why

So we can identify in advance if the features we use will break on protocol upgrades.
  • Loading branch information
marcelosalloum authored Dec 2, 2024
1 parent b7beb59 commit 4ff3fbb
Show file tree
Hide file tree
Showing 16 changed files with 236 additions and 49 deletions.
46 changes: 44 additions & 2 deletions .github/workflows/e2e_integration_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
matrix:
platform:
- "Stellar-phone" # Stellar distribution account where receivers are registered with their phone number
- "Stellar-phone-FUTURENET" # Stellar distribution account where receivers are registered with their phone number
- "Stellar-phone-wallet" # Stellar distribution account where receivers are registered with their phone number and wallet address
- "Stellar-email" # Stellar distribution account where receivers are registered with their email
- "Circle-phone" # Circle distribution account where receivers are registered with their email
Expand All @@ -31,26 +32,46 @@ jobs:
DISTRIBUTION_ACCOUNT_TYPE: "DISTRIBUTION_ACCOUNT.STELLAR.ENV"
DISBURSEMENT_CSV_FILE_NAME: "disbursement_instructions_phone.csv"
REGISTRATION_CONTACT_TYPE: "PHONE_NUMBER"
DISBURSED_ASSET_CODE: "USDC"
DISBURSED_ASSET_ISSUER: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
- platform: "Stellar-phone-wallet"
environment: "Receiver Registration - E2E Integration Tests (Stellar)"
DISTRIBUTION_ACCOUNT_TYPE: "DISTRIBUTION_ACCOUNT.STELLAR.ENV"
DISBURSEMENT_CSV_FILE_NAME: "disbursement_instructions_phone_with_wallet.csv"
REGISTRATION_CONTACT_TYPE: "PHONE_NUMBER_AND_WALLET_ADDRESS"
DISBURSED_ASSET_CODE: "USDC"
DISBURSED_ASSET_ISSUER: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
- platform: "Stellar-email"
environment: "Receiver Registration - E2E Integration Tests (Stellar)"
DISTRIBUTION_ACCOUNT_TYPE: "DISTRIBUTION_ACCOUNT.STELLAR.ENV"
DISBURSEMENT_CSV_FILE_NAME: "disbursement_instructions_email.csv"
REGISTRATION_CONTACT_TYPE: "EMAIL"
DISBURSED_ASSET_CODE: "USDC"
DISBURSED_ASSET_ISSUER: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
- platform: "Circle-phone"
environment: "Receiver Registration - E2E Integration Tests (Circle)"
DISTRIBUTION_ACCOUNT_TYPE: "DISTRIBUTION_ACCOUNT.CIRCLE.DB_VAULT"
DISBURSEMENT_CSV_FILE_NAME: "disbursement_instructions_phone.csv"
REGISTRATION_CONTACT_TYPE: "PHONE_NUMBER"
DISBURSED_ASSET_CODE: "USDC"
DISBURSED_ASSET_ISSUER: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
- platform: "Stellar-phone-FUTURENET"
environment: "Receiver Registration - E2E Integration Tests (Stellar)"
DISTRIBUTION_ACCOUNT_TYPE: "DISTRIBUTION_ACCOUNT.STELLAR.ENV"
DISBURSEMENT_CSV_FILE_NAME: "disbursement_instructions_phone.csv"
REGISTRATION_CONTACT_TYPE: "PHONE_NUMBER"
DISBURSED_ASSET_CODE: "XLM"
NETWORK_PASSPHRASE: "Test SDF Future Network ; October 2022"
HORIZON_URL: "https://horizon-futurenet.stellar.org"
environment: ${{ matrix.environment }}
env:
DISTRIBUTION_ACCOUNT_TYPE: ${{ matrix.DISTRIBUTION_ACCOUNT_TYPE }}
DISBURSEMENT_CSV_FILE_NAME: ${{ matrix.DISBURSEMENT_CSV_FILE_NAME }}
REGISTRATION_CONTACT_TYPE: ${{ matrix.REGISTRATION_CONTACT_TYPE }}
DISBURSED_ASSET_CODE: ${{ matrix.DISBURSED_ASSET_CODE }}
DISBURSED_ASSET_ISSUER: ${{ matrix.DISBURSED_ASSET_ISSUER }}
NETWORK_PASSPHRASE: ${{ matrix.NETWORK_PASSPHRASE }}
HORIZON_URL: ${{ matrix.HORIZON_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -69,6 +90,28 @@ jobs:
run: sudo apt-get update && sudo apt-get install -y curl
shell: bash

- name: Wait for the SDP to be up
run: |
wait_for_server() {
local endpoint=$1
local max_wait_time=$2
SECONDS=0
while ! curl -s $endpoint > /dev/null; do
echo "Waiting for server at $endpoint to be up... $SECONDS seconds elapsed"
sleep 4
if [ $SECONDS -ge $max_wait_time ]; then
echo "Server at $endpoint is not up after $max_wait_time seconds."
exit 1
fi
done
echo "Server at $endpoint is up."
}
wait_for_server http://localhost:8000/health 120
wait_for_server http://localhost:8003/health 120
shell: bash

- name: Create integration test data
run: |
docker exec e2e-sdp-api bash -c "./stellar-disbursement-platform integration-tests create-data"
Expand All @@ -79,7 +122,7 @@ jobs:
docker restart e2e-anchor-platform
shell: bash

- name: Wait for Anchor Platform and SDP to be up
- name: Wait for the Anchor Platform to be up
run: |
wait_for_server() {
local endpoint=$1
Expand All @@ -97,7 +140,6 @@ jobs:
echo "Server at $endpoint is up."
}
wait_for_server http://localhost:8000/health 120
wait_for_server http://localhost:8080/health 120
wait_for_server http://localhost:8085/health 120
shell: bash
Expand Down
3 changes: 3 additions & 0 deletions cmd/integration_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/stellar/go/support/config"
"github.com/stellar/go/support/log"

"github.com/stellar/stellar-disbursement-platform-backend/cmd/utils"
cmdUtils "github.com/stellar/stellar-disbursement-platform-backend/cmd/utils"
"github.com/stellar/stellar-disbursement-platform-backend/internal/data"
"github.com/stellar/stellar-disbursement-platform-backend/internal/integrationtests"
Expand Down Expand Up @@ -115,6 +116,8 @@ func (c *IntegrationTestsCommand) Command() *cobra.Command {
ConfigKey: &integrationTestsOpts.RegistrationContactType,
Required: true,
},
utils.HorizonURL(&integrationTestsOpts.HorizonURL),
utils.NetworkPassphrase(&integrationTestsOpts.NetworkPassphrase),
}
integrationTestsCmd := &cobra.Command{
Use: "integration-tests",
Expand Down
20 changes: 12 additions & 8 deletions cmd/utils/shared_config_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,7 @@ func TransactionSubmitterEngineConfigOptions(opts *di.TxSubmitterEngineOptions)
FlagDefault: 100 * txnbuild.MinBaseFee,
Required: true,
},
&config.ConfigOption{
Name: "horizon-url",
Usage: "The URL of the Stellar Horizon server where this application will communicate with.",
OptType: types.String,
ConfigKey: &opts.HorizonURL,
FlagDefault: horizonclient.DefaultTestNetClient.HorizonURL,
Required: true,
},
HorizonURL(&opts.HorizonURL),
)
}

Expand Down Expand Up @@ -341,6 +334,17 @@ func NetworkPassphrase(targetPointer interface{}) *config.ConfigOption {
}
}

func HorizonURL(targetPointer interface{}) *config.ConfigOption {
return &config.ConfigOption{
Name: "horizon-url",
Usage: "The URL of the Stellar Horizon server where this application will communicate with.",
OptType: types.String,
ConfigKey: targetPointer,
FlagDefault: horizonclient.DefaultTestNetClient.HorizonURL,
Required: true,
}
}

func KafkaConfig(opts EventBrokerOptions) events.KafkaConfig {
return events.KafkaConfig{
Brokers: opts.BrokerURLs,
Expand Down
3 changes: 2 additions & 1 deletion internal/data/receivers_wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
"slices"
"strings"
"time"

Expand Down Expand Up @@ -402,7 +403,7 @@ func (rw *ReceiverWalletModel) GetByReceiverIDAndWalletDomain(ctx context.Contex

// VerifyReceiverWalletOTP validates the receiver wallet OTP.
func (rw *ReceiverWalletModel) VerifyReceiverWalletOTP(ctx context.Context, networkPassphrase string, receiverWallet ReceiverWallet, otp string) error {
if networkPassphrase == network.TestNetworkPassphrase {
if slices.Contains([]string{network.TestNetworkPassphrase, network.FutureNetworkPassphrase}, networkPassphrase) {
if otp == TestnetAlwaysValidOTP {
log.Ctx(ctx).Warnf("OTP is being approved because TestnetAlwaysValidOTP (%s) was used", TestnetAlwaysValidOTP)
return nil
Expand Down
16 changes: 16 additions & 0 deletions internal/data/receivers_wallet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,14 @@ func Test_VerifyReceiverWalletOTP(t *testing.T) {
otpCreatedAt: expiredOTPCreatedAt,
wantErr: nil,
},
{
name: "matching OTP fails when OTP is expired but we pass TestnetAlwaysValidOTP in Futurenet",
networkPassphrase: network.FutureNetworkPassphrase,
attemptedOTP: TestnetAlwaysValidOTP,
otp: "123456",
otpCreatedAt: expiredOTPCreatedAt,
wantErr: nil,
},

// OTP is valid 🎉
{
Expand All @@ -768,6 +776,14 @@ func Test_VerifyReceiverWalletOTP(t *testing.T) {
otpCreatedAt: validOTPTime,
wantErr: nil,
},
{
name: "OTP is valid 🎉 also when we pass TestnetAlwaysValidOTP in Futurenet",
networkPassphrase: network.FutureNetworkPassphrase,
attemptedOTP: TestnetAlwaysValidOTP,
otp: TestnetAlwaysValidOTP,
otpCreatedAt: validOTPTime,
wantErr: nil,
},
}

for _, tc := range testCases {
Expand Down
14 changes: 9 additions & 5 deletions internal/integrationtests/docker/docker-compose-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ services:
METRICS_TYPE: PROMETHEUS
EMAIL_SENDER_TYPE: DRY_RUN
SMS_SENDER_TYPE: DRY_RUN
NETWORK_PASSPHRASE: "Test SDF Network ; September 2015"
NETWORK_PASSPHRASE: ${NETWORK_PASSPHRASE:-Test SDF Network ; September 2015}
HORIZON_URL: ${HORIZON_URL:-https://horizon-testnet.stellar.org}
EC256_PUBLIC_KEY: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ3HNphPAEKHvtRjsl5Kjwc9tTMqS\n2pmYNybrLsxZ6cuQvg2yiEoXZixP2cJ77csHClXC6cb1wQp/BNGDvGKoPg==\n-----END PUBLIC KEY-----"
SEP10_SIGNING_PUBLIC_KEY: ${SEP10_SIGNING_PUBLIC_KEY}
ANCHOR_PLATFORM_BASE_SEP_URL: http://anchor-platform:8080
Expand Down Expand Up @@ -60,8 +61,8 @@ services:
TENANT_NAME: "integration-tests"
USER_EMAIL: ${USER_EMAIL}
USER_PASSWORD: ${USER_PASSWORD}
DISBURSED_ASSET_CODE: USDC
DISBURSED_ASSET_ISSUER: GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
DISBURSED_ASSET_CODE: ${DISBURSED_ASSET_CODE} # e.g. USDC, XLM, etc.
DISBURSED_ASSET_ISSUER: ${DISBURSED_ASSET_ISSUER} # e.g. GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
RECEIVER_ACCOUNT_PUBLIC_KEY: GCDYFAJSZPH3RCXL6NWMMOY54CXNUBYFTDCBW7GGG6VPBW3WSDKSB2NU
RECEIVER_ACCOUNT_PRIVATE_KEY: SDSAVUWVNOFG2JEHKIWEUHAYIA6PLGEHLMHX2TMVKEQGZKOFQ7XXKDFE
DISTRIBUTION_ACCOUNT_TYPE: ${DISTRIBUTION_ACCOUNT_TYPE}
Expand Down Expand Up @@ -122,8 +123,8 @@ services:
environment:
QUEUE_POLLING_INTERVAL: "6"
DATABASE_URL: postgres://postgres@db:5432/e2e-sdp?sslmode=disable
NETWORK_PASSPHRASE: "Test SDF Network ; September 2015"
HORIZON_URL: "https://horizon-testnet.stellar.org"
NETWORK_PASSPHRASE: ${NETWORK_PASSPHRASE:-Test SDF Network ; September 2015}
HORIZON_URL: ${HORIZON_URL:-https://horizon-testnet.stellar.org}
NUM_CHANNEL_ACCOUNTS: "1"
MAX_BASE_FEE: "1000000"
TSS_METRICS_PORT: "9002"
Expand Down Expand Up @@ -199,6 +200,9 @@ services:
SEP24_INTERACTIVE_URL_BASE_URL: http://sdp-api:8000/wallet-registration/start
SEP24_INTERACTIVE_URL_JWT_EXPIRATION: 1800 # 1800 seconds is 30 minutes
SEP24_MORE_INFO_URL_BASE_URL: http://sdp-api:8000/wallet-registration/start
STELLAR_NETWORK_NETWORK: ${NETWORK_NETWORK:-TESTNET}
STELLAR_NETWORK_NETWORK_PASSPHRASE: ${NETWORK_PASSPHRASE:-Test SDF Network ; September 2015}
STELLAR_NETWORK_HORIZON_URL: ${HORIZON_URL:-https://horizon-testnet.stellar.org}
SEP1_ENABLED: "true"
SEP1_TOML_TYPE: url
SEP1_TOML_VALUE: http://sdp-api:8000/.well-known/stellar.toml
Expand Down
9 changes: 7 additions & 2 deletions internal/integrationtests/integration_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ type IntegrationTestsOpts struct {
AdminServerApiKey string
CircleUSDCWalletID string
CircleAPIKey string
HorizonURL string
NetworkPassphrase string
}

type IntegrationTestsService struct {
Expand Down Expand Up @@ -116,7 +118,10 @@ func NewIntegrationTestsService(opts IntegrationTestsOpts) (*IntegrationTestsSer

func (it *IntegrationTestsService) initServices(_ context.Context, opts IntegrationTestsOpts) {
// initialize default testnet horizon client
it.horizonClient = horizonclient.DefaultTestNetClient
it.horizonClient = &horizonclient.Client{
HorizonURL: opts.HorizonURL,
HTTP: httpclient.DefaultClient(),
}

// initialize anchor platform integration tests service
it.anchorPlatform = &AnchorPlatformIntegrationTests{
Expand Down Expand Up @@ -309,7 +314,7 @@ func (it *IntegrationTestsService) ensureTransactionCompletion(ctx context.Conte
return fmt.Errorf("payment was not processed successfully by TSS: %+v", payment)
}

log.Ctx(ctx).Info("Validating transaction on Stellar network...")
log.Ctx(ctx).Infof("Validating transaction %s is on the Stellar network...", payment.StellarTransactionID)
hPayment, getPaymentErr := getTransactionOnHorizon(it.horizonClient, payment.StellarTransactionID)
if getPaymentErr != nil {
return fmt.Errorf("getting transaction on Stellar network: %w", getPaymentErr)
Expand Down
79 changes: 63 additions & 16 deletions internal/integrationtests/scripts/e2e_integration_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,77 @@ wait_for_server() {
echo "Server at $endpoint is up."
}

# Configuration arrays with key-value strings
Config_StellarEnvPhoneUSDCTestnet=(
"platform=Stellar"
"DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.STELLAR.ENV"
"DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_phone.csv"
"REGISTRATION_CONTACT_TYPE=PHONE_NUMBER"
"DISBURSED_ASSET_CODE=USDC"
"DISBURSED_ASSET_ISSUER=GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
)

Config_CircleDBVaultPhoneUSDCTestnet=(
"platform=Circle"
"DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.CIRCLE.DB_VAULT"
"DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_phone.csv"
"REGISTRATION_CONTACT_TYPE=PHONE_NUMBER"
"DISBURSED_ASSET_CODE=USDC"
"DISBURSED_ASSET_ISSUER=GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
)

Config_StellarEnvEmailUSDCTestnet=(
"platform=Stellar"
"DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.STELLAR.ENV"
"DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_email.csv"
"REGISTRATION_CONTACT_TYPE=EMAIL"
"DISBURSED_ASSET_CODE=USDC"
"DISBURSED_ASSET_ISSUER=GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
)

Config_StellarEnvPhoneWithWalletUSDCTestnet=(
"platform=Stellar"
"DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.STELLAR.ENV"
"DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_phone_with_wallet.csv"
"REGISTRATION_CONTACT_TYPE=PHONE_NUMBER_AND_WALLET_ADDRESS"
"DISBURSED_ASSET_CODE=USDC"
"DISBURSED_ASSET_ISSUER=GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
)

Config_StellarEnvPhoneXLMFuturenet=(
"platform=Stellar"
"DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.STELLAR.ENV"
"DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_phone.csv"
"REGISTRATION_CONTACT_TYPE=PHONE_NUMBER"
"DISBURSED_ASSET_CODE=XLM"
"NETWORK_PASSPHRASE=Test SDF Future Network ; October 2022"
"HORIZON_URL=https://horizon-futurenet.stellar.org"
)

options=(
"platform=Stellar;DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.STELLAR.ENV;DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_phone.csv;REGISTRATION_CONTACT_TYPE=PHONE_NUMBER"
"platform=Circle;DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.CIRCLE.DB_VAULT;DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_phone.csv;REGISTRATION_CONTACT_TYPE=PHONE_NUMBER"
"platform=Stellar;DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.STELLAR.ENV;DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_email.csv;REGISTRATION_CONTACT_TYPE=EMAIL"
"platform=Stellar;DISTRIBUTION_ACCOUNT_TYPE=DISTRIBUTION_ACCOUNT.STELLAR.ENV;DISBURSEMENT_CSV_FILE_NAME=disbursement_instructions_phone_with_wallet.csv;REGISTRATION_CONTACT_TYPE=PHONE_NUMBER_AND_WALLET_ADDRESS"
Config_StellarEnvPhoneUSDCTestnet[@]
Config_CircleDBVaultPhoneUSDCTestnet[@]
Config_StellarEnvEmailUSDCTestnet[@]
Config_StellarEnvPhoneWithWalletUSDCTestnet[@]
Config_StellarEnvPhoneXLMFuturenet[@]
)

for option in "${options[@]}"; do
# Parse the properties in the option
IFS=';' read -r -a properties <<< "$option"
# Iterate over each configuration
for config_name in "${options[@]}"; do
# Use indirect variable reference to get the array
config=("${!config_name}")

echo -e "\n====> 👀 Starting e2e setup and integration test for ${config_name}"

for property in "${properties[@]}"; do
# Split each property into key and value
IFS='=' read -r key value <<< "$property"
# Parse and export key-value pairs
for pair in "${config[@]}"; do
IFS="=" read -r key value <<< "$pair"
echo -e "\t- $key=$value"
export "$key"="$value"
done

# Example of using the exported variables
export DESCRIPTION="$platform - $DISTRIBUTION_ACCOUNT_TYPE - $REGISTRATION_CONTACT_TYPE"
echo -e "\n====> 👀Starting e2e setup and integration test ($DESCRIPTION)"
echo -e "\t- Platform: $platform"
echo -e "\t- DISTRIBUTION_ACCOUNT_TYPE: $DISTRIBUTION_ACCOUNT_TYPE"
echo -e "\t- DISBURSEMENT_CSV_FILE_NAME: $DISBURSEMENT_CSV_FILE_NAME"
echo -e "\t- REGISTRATION_CONTACT_TYPE: $REGISTRATION_CONTACT_TYPE"
DESCRIPTION="$platform - $DISTRIBUTION_ACCOUNT_TYPE - $REGISTRATION_CONTACT_TYPE"

echo $DIVIDER
echo "====> 👀Step 1: start preparation"
Expand Down
4 changes: 2 additions & 2 deletions internal/integrationtests/server_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (sa *ServerApiIntegrationTests) StartDisbursement(ctx context.Context, auth

if resp.StatusCode/100 != 2 {
logErrorResponses(ctx, resp.Body)
return fmt.Errorf("error trying to start the disbursement on the server API")
return fmt.Errorf("error trying to start the disbursement on the server API (statusCode=%d)", resp.StatusCode)
}

return nil
Expand Down Expand Up @@ -256,7 +256,7 @@ func (sa *ServerApiIntegrationTests) ReceiverRegistration(ctx context.Context, a

if resp.StatusCode/100 != 2 {
logErrorResponses(ctx, resp.Body)
return fmt.Errorf("error trying to complete receiver registration on the server API")
return fmt.Errorf("trying to complete receiver registration on the server API (statusCode=%d)", resp.StatusCode)
}

return nil
Expand Down
Loading

0 comments on commit 4ff3fbb

Please sign in to comment.