package faucet_test import ( "context" "fmt" "net/http" "strings" "testing" "time" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/cosmosclient" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/cosmosfaucet" "git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/xurl" envtest "git.cw.tr/mukan-network/mukan-ignite/integration" ) const ( addr = "cosmos1zqr2gd7hwkyw55knad0l6ml6ngutd70878evqj" ) var ( defaultCoins = []string{"10token", "1stake"} maxCoins = []string{"102token", "100000000stake"} ) func TestRequestCoinsFromFaucet(t *testing.T) { var ( env = envtest.New(t) app = env.ScaffoldApp("github.com/test/faucetapp") servers = app.RandomizeServerPorts() faucetURL = app.EnableFaucet(defaultCoins, maxCoins) ctx, cancel = context.WithTimeout(env.Ctx(), envtest.ServeTimeout) faucetClient = cosmosfaucet.NewClient(faucetURL) ) isErrTransferRequest := func(err error, expectedCode int) { var errTransfer cosmosfaucet.ErrTransferRequest require.ErrorAs(t, err, &errTransfer) require.EqualValues(t, expectedCode, errTransfer.StatusCode) } // serve the app go func() { app.Serve("should serve app", envtest.ExecCtx(ctx)) }() // wait servers to be online defer cancel() app.WaitChainUp(ctx, servers.API) err := env.IsFaucetServed(ctx, faucetClient) require.NoError(t, err) // error "account doesn't have any balances" occurs if a sleep is not included time.Sleep(time.Second * 1) nodeAddr, err := xurl.HTTP(servers.RPC) require.NoError(t, err) cosmosClient, err := cosmosclient.New(ctx, cosmosclient.WithNodeAddress(nodeAddr)) require.NoError(t, err) // the faucet sends the default faucet coins value when not specified _, err = faucetClient.Transfer(ctx, cosmosfaucet.NewTransferRequest(addr, nil)) require.NoError(t, err) checkAccountBalance(ctx, t, cosmosClient, addr, defaultCoins) // the faucet can send a specified amount of coins _, err = faucetClient.Transfer(ctx, cosmosfaucet.NewTransferRequest(addr, []string{"20token", "2stake"})) require.NoError(t, err) checkAccountBalance(ctx, t, cosmosClient, addr, []string{"30token", "3stake"}) // faucet request fails on malformed coins _, err = faucetClient.Transfer(ctx, cosmosfaucet.NewTransferRequest(addr, []string{"no-token"})) isErrTransferRequest(err, http.StatusBadRequest) // faucet request fails when requesting more than max coins _, err = faucetClient.Transfer(ctx, cosmosfaucet.NewTransferRequest(addr, []string{"500token"})) isErrTransferRequest(err, http.StatusInternalServerError) // faucet request fails when transfer should fail _, err = faucetClient.Transfer(ctx, cosmosfaucet.NewTransferRequest(addr, []string{"500nonexistent"})) isErrTransferRequest(err, http.StatusInternalServerError) // send several request in parallel and check max coins is not overflown g, ctx := errgroup.WithContext(ctx) for i := 0; i < 10; i++ { g.Go(func() error { c := faucetClient index := i + 1 coins := []string{ sdk.NewCoin("token", math.NewInt(int64(index*2))).String(), sdk.NewCoin("stake", math.NewInt(int64(index*3))).String(), } _, err := c.Transfer(ctx, cosmosfaucet.NewTransferRequest(addr, coins)) return err }) } require.NoError(t, g.Wait()) checkAccountBalance(ctx, t, cosmosClient, addr, []string{"168stake", "140token"}) } func checkAccountBalance(ctx context.Context, t *testing.T, c cosmosclient.Client, accAddr string, coins []string) { t.Helper() resp, err := banktypes.NewQueryClient(c.Context()).AllBalances(ctx, &banktypes.QueryAllBalancesRequest{ Address: accAddr, }) require.NoError(t, err) require.Len(t, resp.Balances, len(coins)) expectedCoins, err := sdk.ParseCoinsNormalized(strings.Join(coins, ",")) require.NoError(t, err) expectedCoins = expectedCoins.Sort() gotCoins := resp.Balances.Sort() require.True(t, gotCoins.Equal(expectedCoins), fmt.Sprintf("%s should be equals to %s", gotCoins.String(), expectedCoins.String()), ) }